Merge branch 'master' of ssh://gerrit.opencord.org:29418/xos
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..302c3f5
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,4 @@
+views/
+applications/
+xos/tests/api/node_modules
+xos/configurations/cord-pod/images
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..617f1f9
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,26 @@
+*.orig
+*.pyc
+*.swp
+profile
+*.moved-aside
+.idea
+setup/*
+setup/id_rsa/*
+xos/configurations/frontend/Dockerfile
+xos/configurations/mcord/admin-openrc.sh
+xos/configurations/setup/*
+xos/configurations/common/*
+xos/core/xoslib/karma-*
+xos/core/xoslib/docs
+xos/core/xoslib/coverage
+node_modules
+xos/xos_configuration/*
+.idea/*
+*.iml
+npm-debug.log
+xos/core/static/*.css
+!xos/core/static/xos.css
+.DS_Store
+xos/configurations/setup/
+migrations/
+xos/configurations/frontend/onboarding-docker-compose/
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..54c4c55
--- /dev/null
+++ b/README.md
@@ -0,0 +1,19 @@
+## Getting Started with XOS and CORD
+
+For a general introduction to XOS and how it is used in CORD, see
+http://guide.xosproject.org. The "Developer Guide" at that URL is
+especially helpful, although it isn't perfectly sync'ed with master. 
+Additional design notes, presentations, and other collateral are 
+also available at http://xosproject.org and http://opencord.org.
+
+The best way to get started is to look at the collection of
+canned configurations in `xos/configurations/`. The `cord` 
+configuration in that directory corresponds to our current 
+CORD development environment, and the `README.md` you'll find there
+will help you get started.
+
+Source tree layout:
+ * applications -- stand-alone applications that run on top of XOS.
+ * containers -- common Dockerfiles used by various XOS configurations
+ * views -- mechanisms to extend XOS with customized views
+ * xos -- XOS internals
diff --git a/apiary.apib b/apiary.apib
new file mode 100644
index 0000000..0f9632d
--- /dev/null
+++ b/apiary.apib
@@ -0,0 +1,1184 @@
+FORMAT: 1A
+
+# XOS
+ 
+ 
+# Group Deployments
+
+List of the XOS deployments
+
+## Deployments [/api/core/deployments/{id}/]
+
+### List all deployments [GET]
+
++ Response 200 (application/json)
+
+        [
+            {
+                "humanReadableName": "MyDeployment",
+                "id": 1,
+                "created": "2016-04-29T16:19:03.549901Z",
+                "updated": "2016-04-29T16:19:05.624151Z",
+                "enacted": null,
+                "policed": null,
+                "backend_register": "{}",
+                "backend_status": "0 - Provisioning in progress",
+                "deleted": false,
+                "write_protect": false,
+                "lazy_blocked": false,
+                "no_sync": true,
+                "name": "MyDeployment",
+                "accessControl": "allow all",
+                "images": [
+                    "1"
+                ],
+                "sites": [
+                    "1"
+                ],
+                "flavors": [
+                    "1",
+                    "2",
+                    "3"
+                ],
+                "dashboardviews": [
+                    "1"
+                ]
+            }
+        ]
+
+### Create a deployment [POST]
+
++ Request (application/json)
+
+        {
+            "humanReadableName": "MyDeployment",
+        }
+
++ Response 200 (application/json)
+
+        {
+            "humanReadableName": "MyDeployment",
+            "id": 1,
+            "created": "2016-04-29T16:19:03.549901Z",
+            "updated": "2016-04-29T16:19:05.624151Z",
+            "enacted": null,
+            "policed": null,
+            "backend_register": "{}",
+            "backend_status": "0 - Provisioning in progress",
+            "deleted": false,
+            "write_protect": false,
+            "lazy_blocked": false,
+            "no_sync": true,
+            "name": "MyDeployment",
+            "accessControl": "allow all",
+            "images": [
+                "1"
+            ],
+            "sites": [
+                "1"
+            ],
+            "flavors": [
+                "1",
+                "2",
+                "3"
+            ],
+            "dashboardviews": [
+                "1"
+            ]
+        }
+
+### View a Deployment Detail [GET]
+
++ Parameters
+    + id: 1 (number) - ID of the Deployment in the form of an integer
+
++ Response 200 (application/json)
+
+        {
+            "humanReadableName": "MyDeployment",
+            "id": 1,
+            "created": "2016-04-27T21:46:57.354544Z",
+            "updated": "2016-04-27T21:47:05.221720Z",
+            "enacted": null,
+            "policed": null,
+            "backend_register": "{}",
+            "backend_status": "0 - Provisioning in progress",
+            "deleted": false,
+            "write_protect": false,
+            "lazy_blocked": false,
+            "no_sync": true,
+            "name": "MyDeployment",
+            "accessControl": "allow all",
+            "images": [],
+            "sites": [
+                "1"
+            ],
+            "flavors": [
+                "3",
+                "2",
+                "1"
+            ],
+            "dashboardviews": [
+                "3"
+            ]
+        }
+
+### Delete a Deployment [DELETE]
+
++ Parameters
+    + id: 1 (number) - ID of the Deployment in the form of an integer
+
++ Response 204
+ 
+ 
+# Group Flavors
+
+List of the XOS flavors
+
+## Flavors [/api/core/flavors/{id}/]
+
+### List all flavors [GET]
+
++ Response 200 (application/json)
+
+        [
+            {
+                "humanReadableName": "m1.large",
+                "id": 1,
+                 "created": "2016-04-29T16:19:01.979548Z",
+                "updated": "2016-04-29T16:19:03.568238Z",
+                "enacted": null,
+                "policed": null,
+                "backend_register": "{}",
+                "backend_status": "0 - Provisioning in progress",
+                "deleted": false,
+                "write_protect": false,
+                "lazy_blocked": false,
+                "no_sync": true,
+                "name": "m1.large",
+                "description": null,
+                "flavor": "m1.large",
+                "order": 0,
+                "default": false,
+                "deployments": [
+                    "1"
+                ]
+            }
+        ]
+
+### Create a Flavor [POST]
+
++ Request (application/json)
+
+        {
+            "humanReadableName": "mq.test",
+        }
+
++ Response 200 (application/json)
+
+        {
+            "humanReadableName": "m1.large",
+            "id": 1,
+             "created": "2016-04-29T16:19:01.979548Z",
+            "updated": "2016-04-29T16:19:03.568238Z",
+            "enacted": null,
+            "policed": null,
+            "backend_register": "{}",
+            "backend_status": "0 - Provisioning in progress",
+            "deleted": false,
+            "write_protect": false,
+            "lazy_blocked": false,
+            "no_sync": true,
+            "name": "m1.large",
+            "description": null,
+            "flavor": "m1.large",
+            "order": 0,
+            "default": false,
+            "deployments": [
+                "1"
+            ]
+        }
+
+### View a Flavors Detail [GET]
+
++ Parameters
+    + id: 1 (number) - ID of the Flavors in the form of an integer
+
++ Response 200 (application/json)
+
+        {
+            "humanReadableName": "m1.large",
+            "id": 1,
+             "created": "2016-04-29T16:19:01.979548Z",
+            "updated": "2016-04-29T16:19:03.568238Z",
+            "enacted": null,
+            "policed": null,
+            "backend_register": "{}",
+            "backend_status": "0 - Provisioning in progress",
+            "deleted": false,
+            "write_protect": false,
+            "lazy_blocked": false,
+            "no_sync": true,
+            "name": "m1.large",
+            "description": null,
+            "flavor": "m1.large",
+            "order": 0,
+            "default": false,
+            "deployments": [
+                "1"
+            ]
+        }
+
+### Delete a Flavors Detail [DELETE]
+
++ Parameters
+    + id: 1 (number) - ID of the Flavors in the form of an integer
+
++ Response 204 
+ 
+ 
+# Group Instances
+
+List of the XOS instances
+
+## Instances Collection [/api/core/instances/{?no_hyperlinks}]
+
+    + no_hyperlinks (number, optional) - Wheter to return relation with links or ids
+        + Default: `0`
+
+### List all Instances [GET]
+
++ Response 200 (application/json)
+
+        [
+            {
+                "id": 1,
+                "humanReadableName": "uninstantiated-1",
+                "created": "2016-04-26T00:36:22.465259Z",
+                "updated": "2016-04-26T00:36:22.465288Z",
+                "enacted": null,
+                "policed": null,
+                "backend_register": "{}",
+                "backend_status": "0 - Provisioning in progress",
+                "deleted": false,
+                "write_protect": false,
+                "lazy_blocked": false,
+                "no_sync": false,
+                "instance_id": null,
+                "instance_uuid": null,
+                "name": "mysite_vcpe",
+                "instance_name": null,
+                "ip": null,
+                "image": "1",
+                "creator": "1",
+                "slice": "1",
+                "deployment": "1",
+                "node": "1",
+                "numberCores": 0,
+                "flavor": "1",
+                "userData": null,
+                "isolation": "vm",
+                "volumes": "/etc/dnsmasq.d,/etc/ufw",
+                "parent": null,
+                "networks": [
+                    "1"
+                ]
+            }
+        ]
+
+### Create an Instance [POST]
+
++ Parameters
+    + no_hyperlinks: 1
+
++ Request (application/json)
+
+        {
+            "name": "test-instance",
+            "image": 1,
+            "slice": 1,
+            "deployment": 1,
+            "node": 1
+        }
+
++ Response 200 (application/json)
+
+        {
+            "id": 1,
+            "humanReadableName": "uninstantiated-1",
+            "created": "2016-04-26T00:36:22.465259Z",
+            "updated": "2016-04-26T00:36:22.465288Z",
+            "enacted": null,
+            "policed": null,
+            "backend_register": "{}",
+            "backend_status": "0 - Provisioning in progress",
+            "deleted": false,
+            "write_protect": false,
+            "lazy_blocked": false,
+            "no_sync": false,
+            "instance_id": null,
+            "instance_uuid": null,
+            "name": "test-instance",
+            "instance_name": null,
+            "ip": null,
+            "image": "1",
+            "creator": "1",
+            "slice": "1",
+            "deployment": "1",
+            "node": "1",
+            "numberCores": 0,
+            "flavor": "1",
+            "userData": null,
+            "isolation": "vm",
+            "volumes": "/etc/dnsmasq.d,/etc/ufw",
+            "parent": null,
+            "networks": [
+                "1"
+            ]
+        }
+
+## Instances Detail [/api/core/instances/{id}/]
+
+### Get instance details [GET]
+
++ Parameters
+    + id: 1 (number) - ID of the Instance in the form of an integer
+
++ Response 200 (application/json)
+
+        {
+            "id": 1,
+            "humanReadableName": "uninstantiated-1",
+            "created": "2016-04-26T00:36:22.465259Z",
+            "updated": "2016-04-26T00:36:22.465288Z",
+            "enacted": null,
+            "policed": null,
+            "backend_register": "{}",
+            "backend_status": "0 - Provisioning in progress",
+            "deleted": false,
+            "write_protect": false,
+            "lazy_blocked": false,
+            "no_sync": false,
+            "instance_id": null,
+            "instance_uuid": null,
+            "name": "mysite_vcpe",
+            "instance_name": null,
+            "ip": null,
+            "image": "1",
+            "creator": "1",
+            "slice": "1",
+            "deployment": "1",
+            "node": "1",
+            "numberCores": 0,
+            "flavor": "1",
+            "userData": null,
+            "isolation": "vm",
+            "volumes": "/etc/dnsmasq.d,/etc/ufw",
+            "parent": null,
+            "networks": [
+                "1"
+            ]
+        }
+
+### Delete instance [DELETE]
+
++ Parameters
+    + id: 1 (number) - ID of the Instance in the form of an integer
+
++ Response 204
+ 
+ 
+# Group Nodes
+
+List of the XOS nodes
+
+## Nodes [/api/core/nodes/{id}/]
+
+### List all nodes [GET]
+
++ Response 200 (application/json)
+
+        [
+            {
+                "humanReadableName": "node2.opencloud.us",
+                "id": 1,
+                "created": "2016-04-29T16:19:05.661567Z",
+                "updated": "2016-04-29T16:19:05.661454Z",
+                "enacted": null,
+                "policed": null,
+                "backend_register": "{}",
+                "backend_status": "0 - Provisioning in progress",
+                "deleted": false,
+                "write_protect": false,
+                "lazy_blocked": false,
+                "no_sync": true,
+                "name": "node2.opencloud.us",
+                "site_deployment": "1",
+                "site": "1",
+                "nodelabels": []
+            }
+        ]
+
+ 
+ 
+# Group Services
+
+List of the XOS Services
+
+## Services [/api/core/services/{id}/]
+
+### List all Services [GET]
+
++ Response 200 (application/json)
+
+        [
+            {
+                "humanReadableName": "MyService",
+                "id": 1,
+                "created": "2016-05-05T23:06:33.835277Z",
+                "updated": "2016-05-05T23:06:33.835302Z",
+                "enacted": null,
+                "policed": null,
+                "backend_register": "{}",
+                "backend_status": "0 - Provisioning in progress",
+                "deleted": false,
+                "write_protect": false,
+                "lazy_blocked": false,
+                "no_sync": false,
+                "no_policy": false,
+                "description": null,
+                "enabled": true,
+                "kind": "vROUTER",
+                "name": "MyService",
+                "versionNumber": null,
+                "published": true,
+                "view_url": "/admin/vrouter/vrouterservice/$id$/",
+                "icon_url": null,
+                "public_key": null,
+                "private_key_fn": null,
+                "service_specific_id": null,
+                "service_specific_attribute": null
+            }
+        ]
+
+### Create a Service [POST]
+
++ Request (application/json)
+
+        {
+            "name": "MyService",
+            "kind": "vROUTER"
+        }
+
++ Response 200 (application/json)
+
+        {
+            "humanReadableName": "MyService",
+            "id": 1,
+            "created": "2016-05-05T23:06:33.835277Z",
+            "updated": "2016-05-05T23:06:33.835302Z",
+            "enacted": null,
+            "policed": null,
+            "backend_register": "{}",
+            "backend_status": "0 - Provisioning in progress",
+            "deleted": false,
+            "write_protect": false,
+            "lazy_blocked": false,
+            "no_sync": false,
+            "no_policy": false,
+            "description": null,
+            "enabled": true,
+            "kind": "vROUTER",
+            "name": "MyService",
+            "versionNumber": null,
+            "published": true,
+            "view_url": "/admin/vrouter/vrouterservice/$id$/",
+            "icon_url": null,
+            "public_key": null,
+            "private_key_fn": null,
+            "service_specific_id": null,
+            "service_specific_attribute": null
+        }
+
+### View a Service Detail [GET]
+
++ Parameters
+    + id: 1 (number) - ID of the Service in the form of an integer
+
++ Response 200 (application/json)
+
+        {
+                "humanReadableName": "MyService",
+                "id": 1,
+                "created": "2016-05-05T23:06:33.835277Z",
+                "updated": "2016-05-05T23:06:33.835302Z",
+                "enacted": null,
+                "policed": null,
+                "backend_register": "{}",
+                "backend_status": "0 - Provisioning in progress",
+                "deleted": false,
+                "write_protect": false,
+                "lazy_blocked": false,
+                "no_sync": false,
+                "no_policy": false,
+                "description": null,
+                "enabled": true,
+                "kind": "vROUTER",
+                "name": "MyService",
+                "versionNumber": null,
+                "published": true,
+                "view_url": "/admin/vrouter/vrouterservice/$id$/",
+                "icon_url": null,
+                "public_key": null,
+                "private_key_fn": null,
+                "service_specific_id": null,
+                "service_specific_attribute": null
+            }
+
+### Delete a Service [DELETE]
+
++ Parameters
+    + id: 1 (number) - ID of the Service in the form of an integer
+
++ Response 204
+
+ 
+ 
+# Group Sites
+
+List of the XOS sites
+
+## Sites [/api/core/sites/{id}/]
+
+### List all sites [GET]
+
++ Response 200 (application/json)
+
+        {
+            "humanReadableName": "MySite",
+            "id": 1,
+            "created": "2016-04-29T16:19:03.587770Z",
+            "updated": "2016-04-29T16:19:05.651933Z",
+            "enacted": null,
+            "policed": null,
+            "backend_register": "{}",
+            "backend_status": "0 - Provisioning in progress",
+            "deleted": false,
+            "write_protect": false,
+            "lazy_blocked": false,
+            "no_sync": false,
+            "name": "MySite",
+            "site_url": "http://opencord.us/",
+            "enabled": true,
+            "hosts_nodes": true,
+            "hosts_users": true,
+            "location": null,
+            "longitude": null,
+            "latitude": null,
+            "login_base": "mysite",
+            "is_public": true,
+            "abbreviated_name": "",
+            "deployments": [
+                "1"
+            ]
+        }
+ 
+ 
+# Group Slices
+
+List of the XOS slices
+
+## Slices [/api/core/slices/{id}/]
+
+### List all slices [GET]
+
++ Response 200 (application/json)
+
+        [
+            {
+                "humanReadableName": "mysite_slice",
+                "id": 1,
+                "created": "2016-04-29T16:23:22.505072Z",
+                "updated": "2016-04-29T16:23:22.504691Z",
+                "enacted": null,
+                "policed": "2016-04-29T16:23:22.781298Z",
+                "backend_register": "{}",
+                "backend_status": "0 - Provisioning in progress",
+                "deleted": false,
+                "write_protect": false,
+                "lazy_blocked": false,
+                "no_sync": false,
+                "name": "mysite_slice",
+                "enabled": true,
+                "omf_friendly": false,
+                "description": "",
+                "slice_url": "",
+                "site": "http://apt118.apt.emulab.net/api/core/sites/1/",
+                "max_instances": 10,
+                "service": null,
+                "network": null,
+                "exposed_ports": null,
+                "serviceClass": "http://apt118.apt.emulab.net/api/core/serviceclasses/1/",
+                "creator": "http://apt118.apt.emulab.net/api/core/users/1/",
+                "default_flavor": null,
+                "default_image": null,
+                "mount_data_sets": "GenBank",
+                "default_isolation": "vm",
+                "networks": [
+                    "http://apt118.apt.emulab.net/api/core/networks/1/"
+                ]
+            }
+        ]
+        
+ 
+ 
+# Group Users
+
+List of the XOS users
+
+## Users [/api/core/users/{id}/]
+
+### List all Users [GET]
+
++ Response 200 (application/json)
+
+        [
+            {
+                "id": 2,
+                "password": "pbkdf2_sha256$12000$9gn8DmZuIoz2$YPQkx3AOOV7jZNYr2ddrgUCkiuaPpvb8+aJR7RwLZNA=",
+                "last_login": "2016-04-12T18:50:45.880823Z",
+                "email": "johndoe@myhouse.com",
+                "username": "johndoe@myhouse.com",
+                "firstname": "john",
+                "lastname": "doe",
+                "phone": null,
+                "user_url": null,
+                "site": "http://xos.dev:9999/api/core/sites/1/",
+                "public_key": null,
+                "is_active": true,
+                "is_admin": false,
+                "is_staff": true,
+                "is_readonly": false,
+                "is_registering": false,
+                "is_appuser": false,
+                "login_page": null,
+                "created": "2016-04-12T18:50:45.912602Z",
+                "updated": "2016-04-12T18:50:45.912671Z",
+                "enacted": null,
+                "policed": null,
+                "backend_status": "Provisioning in progress",
+                "deleted": false,
+                "write_protect": false,
+                "timezone": "America/New_York"
+            }
+        ]
+        
+ 
+ 
+# Group Example
+
+## Example Services Collection [/api/service/exampleservice/]
+
+### List all Example Services [GET]
+
++ Response 200 (application/json)
+
+        [
+            {
+                "humanReadableName": "MyExample",
+                "id": 1,
+                "service_message": "This is the test message"
+            }
+        ]
+ 
+ 
+# Group ONOS Services
+
+List of the active onos services
+
+## ONOS Services Collection [/api/service/onos/]
+
+### List all ONOS Services [GET]
+
++ Response 200 (application/json)
+
+        [
+            {
+                "humanReadableName": "service_ONOS_vBNG",
+                "id": 5,
+                "rest_hostname": "",
+                "rest_port": "8181",
+                "no_container": false,
+                "node_key": ""
+            }
+        ]
+ 
+ 
+# Group vSG
+
+## vSG Collection [/api/service/vsg/]
+
+### List all vSGs [GET]
+
++ Response 200 (application/json)
+
+        [
+            {
+                "humanReadableName": "service_vsg",
+                "id": 2,
+                "dns_servers": "8.8.8.8",
+                "url_filter_kind": null,
+                "node_label": null
+            }
+        ]
+ 
+ 
+# Group Utility
+
+List of the XOS Utility API
+
+## Login [/api/utility/login/]
+
+### Log a user in the system [POST]
+
++ Request (application/json)
+
+        {
+            "username": "padmin@vicci.org",
+            "password": "letmein"
+        }
+
++ Response 200 (application/json)
+
+        {
+            "xoscsrftoken":"xuvsRC1jkXAsnrdRlgJvcXpmtthTAqqf",
+            "xossessionid":"7ds5a3wzjlgbjqo4odkd25qsm0j2s6zg",
+            "user": "{\"policed\": null, \"site\": 3, \"is_appuser\": false, \"is_staff\": true, \"backend_status\": \"Provisioning in progress\", \"id\": 3, \"is_registering\": false, \"last_login\": \"2016-04-30T22:51:04.788675+00:00\", \"email\": \"padmin@vicci.org\", \"no_sync\": false, \"username\": \"padmin@vicci.org\", \"dashboards\": [11], \"login_page\": null, \"firstname\": \"XOS\", \"user_url\": null, \"deleted\": false, \"lastname\": \"admin\", \"is_active\": true, \"lazy_blocked\": false, \"phone\": null, \"is_admin\": true, \"enacted\": null, \"public_key\": null, \"is_readonly\": false, \"no_policy\": false, \"write_protect\": false}"
+        }
+
+## Logout [/api/utility/logout/]
+
+### Log a user out of the system [POST]
+
++ Request (application/json)
+        {xossessionid: "sessionId"}
+
++ Response 200 (application/json)
+
+ 
+ 
+# Group Subscribers
+
+Resource related to the CORD Subscribers.
+
+## Subscribers [/api/tenant/cord/subscriber/{subscriber_id}/]
+
+### List All Subscribers [GET]
+
++ Response 200 (application/json)
+
+        [
+            {
+                "humanReadableName": "cordSubscriber-1",
+                "id": 1,
+                "features": {
+                    "cdn": false,
+                    "uplink_speed": 1000000000,
+                    "downlink_speed": 1000000000,
+                    "uverse": false,
+                    "status": "enabled"
+                },
+                "identity": {
+                    "account_num": "123",
+                    "name": "My House"
+                },
+                "related": {
+                    "instance_name": "mysite_vcpe",
+                    "vsg_id": 4,
+                    "compute_node_name": "node2.opencloud.us",
+                    "c_tag": "432",
+                    "instance_id": 1,
+                    "wan_container_ip": null,
+                    "volt_id": 3,
+                    "s_tag": "222"
+                }
+            }
+        ]
+
+
+### View a Subscriber Detail [GET]
+
++ Parameters
+    + subscriber_id: 1 (number) - ID of the Subscriber in the form of an integer
+
++ Response 200 (application/json)
+ 
+        {
+            "humanReadableName": "cordSubscriber-1", 
+            "id": 1, 
+            "features": { 
+                "cdn": false, 
+                "uplink_speed": 1000000000, 
+                "downlink_speed": 1000000000, 
+                "uverse": false, 
+                "status": "enabled" 
+            }, 
+            "identity": { 
+                "account_num": "123",
+                "name": "My House"
+            }, 
+            "related": { 
+                "instance_name": "mysite_vcpe", 
+                "vsg_id": 4, 
+                "compute_node_name": "node2.opencloud.us",
+                "c_tag": "432", 
+                "instance_id": 1, 
+                "wan_container_ip": null, 
+                "volt_id": 3, 
+                "s_tag": "222" 
+            } 
+        }
+
+### Delete a Subscriber [DELETE]
+
++ Parameters
+    + subscriber_id: 1 (number) - ID of the Subscriber in the form of an integer
+
++ Response 204
+
+### Subscriber features [/api/tenant/cord/subscriber/{subscriber_id}/features/]
+
++ Parameters
+    + subscriber_id: 1 (number) - ID of the Subscriber in the form of an integer
+
+### View a Subscriber Features Detail [GET]
+
++ Response 200 (application/json)
+
+        {
+            "cdn": false, 
+            "uplink_speed": 1000000000, 
+            "downlink_speed": 1000000000, 
+            "uverse": true, 
+            "status": "enabled"
+        }
+
+#### Subscriber features uplink_speed [/api/tenant/cord/subscriber/{subscriber_id}/features/uplink_speed/]
+
++ Parameters
+    + subscriber_id: 1 (number) - ID of the Subscriber in the form of an integer
+
+#### Read Subscriber uplink_speed [GET]
+
++ Response 200 (application/json)
+
+        {
+            "uplink_speed": 1000000000
+        }
+
+#### Update Subscriber uplink_speed [PUT]
+
++ Request 200 (application/json)
+
+        {
+            "uplink_speed": 1000000000
+        }
+
++ Response 200 (application/json)
+
+        {
+            "uplink_speed": 1000000000
+        }
+
+#### Subscriber features downlink_speed [/api/tenant/cord/subscriber/{subscriber_id}/features/downlink_speed/]
+
++ Parameters
+    + subscriber_id: 1 (number) - ID of the Subscriber in the form of an integer
+
+#### Read Subscriber downlink_speed [GET]
+
++ Response 200 (application/json)
+
+        {
+            "downlink_speed": 1000000000
+        }
+
+#### Update Subscriber downlink_speed [PUT]
+
++ Request 200 (application/json)
+
+        {
+            "downlink_speed": 1000000000
+        }
+
++ Response 200 (application/json)
+
+        {
+            "downlink_speed": 1000000000
+        }
+
+#### Subscriber features cdn [/api/tenant/cord/subscriber/{subscriber_id}/features/cdn/]
+
++ Parameters
+    + subscriber_id: 1 (number) - ID of the Subscriber in the form of an integer
+
+#### Read Subscriber cdn [GET]
+
++ Response 200 (application/json)
+
+        {
+            "cdn": false
+        }
+
+#### Update Subscriber cdn [PUT]
+
++ Request 200 (application/json)
+
+        {
+            "cdn": false
+        }
+
++ Response 200 (application/json)
+
+        {
+            "cdn": false
+        }
+
+#### Subscriber features uverse [/api/tenant/cord/subscriber/{subscriber_id}/features/uverse/]
+
++ Parameters
+    + subscriber_id: 1 (number) - ID of the Subscriber in the form of an integer
+
+#### Read Subscriber uverse [GET]
+
++ Response 200 (application/json)
+
+        {
+            "uverse": false
+        }
+
+#### Update Subscriber uverse [PUT]
+
++ Request 200 (application/json)
+
+        {
+            "uverse": false
+        }
+
++ Response 200 (application/json)
+
+        {
+            "uverse": false
+        }
+
+#### Subscriber features status [/api/tenant/cord/subscriber/{subscriber_id}/features/status/]
+
++ Parameters
+    + subscriber_id: 1 (number) - ID of the Subscriber in the form of an integer
+
+#### Read Subscriber status [GET]
+
++ Response 200 (application/json)
+
+        {
+            "status": "enabled"
+        }
+
+#### Update Subscriber status [PUT]
+
++ Request 200 (application/json)
+
+        {
+            "status": "enabled"
+        }
+
++ Response 200 (application/json)
+
+        {
+            "status": "enabled"
+        }
+ 
+ 
+# Group Truckroll
+
+Virtual Truckroll, enable to perform basic test on user connectivity such as ping, traceroute and tcpdump.
+
+## Truckroll Collection [/api/tenant/truckroll/{truckroll_id}/]
+
+### List all Truckroll [GET]
+
++ Response 200 (application/json)
+
+        [
+            {
+                "humanReadableName": "vTR-tenant-9",
+                "id": 9,
+                "provider_service": 6,
+                "target_id": 2,
+                "scope": "container",
+                "test": "ping",
+                "argument": "8.8.8.8",
+                "result": "",
+                "result_code": "",
+                "is_synced": false,
+                "backend_status": "2 - Exception('Unreachable results in ansible recipe',)"
+            }
+        ]
+
+### Create a Truckroll [POST]
+
+A virtual truckroll is complete once is_synced equal true
+
++ Request (application/json)
+
+        {
+            "target_id": 2,
+            "scope": "container",
+            "test": "ping",
+            "argument": "8.8.8.8"
+        }
+
++ Response 201 (application/json)
+
+        {
+            "humanReadableName": "vTR-tenant-1",
+            "id": 1,
+            "provider_service": 6,
+            "target_id": 2,
+            "scope": "container",
+            "test": "ping",
+            "argument": "8.8.8.8",
+            "result": null,
+            "result_code": null,
+            "is_synced": false,
+            "backend_status": "0 - Provisioning in progress"
+        }
+
+
+### View a Truckroll Detail [GET]
+
++ Parameters
+    + truckroll_id: 1 (number) - ID of the Truckroll in the form of an integer
+
++ Response 200 (application/json)
+
+        {
+            "humanReadableName": "vTR-tenant-10",
+            "id": 10,
+            "provider_service": 6,
+            "target_id": 2,
+            "scope": "container",
+            "test": "ping",
+            "argument": "8.8.8.8",
+            "result": null,
+            "result_code": null,
+            "is_synced": false,
+            "backend_status": "0 - Provisioning in progress"
+        }
+
+### Delete a Truckroll Detail [DELETE]
+
++ Parameters
+    + truckroll_id: 1 (number) - ID of the Truckroll in the form of an integer
+
++ Response 204
+
+ 
+ 
+# Group vOLT
+
+OLT devices aggregate a set of subscriber connections
+
+## vOLT Collection [/api/tenant/cord/volt/{volt_id}/]
+
+### List all vOLT [GET]
+
++ Response 200 (application/json)
+
+        [
+            {
+                "humanReadableName": "vOLT-tenant-1",
+                "id": 1,
+                "service_specific_id": "123",
+                "s_tag": "222",
+                "c_tag": "432",
+                "subscriber": 1,
+                "related": {
+                    "instance_id": 1,
+                    "instance_name": "mysite_vcpe",
+                    "vsg_id": 4,
+                    "wan_container_ip": null,
+                    "compute_node_name": "node2.opencloud.us"
+                }
+            }
+        ]
+
+### Create a vOLT [POST]
+
++ Request (application/json)
+
+        {
+            "s_tag": "222",
+            "c_tag": "432",
+            "subscriber": 1
+        }
+
++ Response 201 (application/json)
+
+        {
+                "humanReadableName": "vOLT-tenant-1",
+                "id": 1,
+                "service_specific_id": "123",
+                "s_tag": "222",
+                "c_tag": "432",
+                "subscriber": 1,
+                "related": {
+                    "instance_id": 1,
+                    "instance_name": "mysite_vcpe",
+                    "vsg_id": 4,
+                    "wan_container_ip": null,
+                    "compute_node_name": "node2.opencloud.us"
+                }
+            }
+
+### View a vOLT Detail [GET]
+
++ Parameters
+    + volt_id: 1 (number) - ID of the vOLT in the form of an integer
+
++ Response 200 (application/json)
+
+        {
+            "humanReadableName": "vOLT-tenant-1",
+            "id": 1,
+            "service_specific_id": "123",
+            "s_tag": "222",
+            "c_tag": "432",
+            "subscriber": 1,
+            "related": {
+                "instance_id": 1,
+                "instance_name": "mysite_vcpe",
+                "vsg_id": 4,
+                "wan_container_ip": null,
+                "compute_node_name": "node2.opencloud.us"
+            }
+        }
+
+ 
+ 
+# Group ONOS Apps
+
+## ONOS App Collection [/api/tenant/onos/app/]
+
+### List all apps [GET]
+
++ Response 200 (application/json)
+
+        [
+            {
+                "humanReadableName": "onos-tenant-7",
+                "id": 7,
+                "name": "vBNG_ONOS_app",
+                "dependencies": "org.onosproject.proxyarp, org.onosproject.virtualbng, org.onosproject.openflow, org.onosproject.fwd"
+            }
+        ]
\ No newline at end of file
diff --git a/containers/Makefile b/containers/Makefile
new file mode 100644
index 0000000..92685e7
--- /dev/null
+++ b/containers/Makefile
@@ -0,0 +1,18 @@
+.PHONY: xos
+xos: nodes.yaml images.yaml
+	sudo docker-compose up -d
+	../xos/configurations/common/wait_for_xos_port.sh 8000
+	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/setup.yaml
+	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/nodes.yaml
+	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/images.yaml
+
+nodes.yaml:
+	export SETUPDIR=.; bash ../xos/configurations/common/make-nodes-yaml.sh
+
+images.yaml:
+	export SETUPDIR=.; bash ../xos/configurations/common/make-images-yaml.sh
+
+.PHONY: local_containers
+local_containers:
+	cd containers/xos; make devel
+	cd containers/synchronizer; make
diff --git a/containers/README.md b/containers/README.md
new file mode 100644
index 0000000..b4a8ea8
--- /dev/null
+++ b/containers/README.md
@@ -0,0 +1,81 @@
+# XOS Docker Images
+
+## Introduction
+
+ XOS is comprised of 3 core services:
+
+  * A database backend (postgres)
+  * A webserver front end (django)
+  * A synchronizer daemon that interacts with the openstack backend.
+
+We have created separate dockerfiles for each of these services, making it
+easier to build the services independently and also deploy and run them in
+isolated environments.
+
+#### Database Container
+
+To build the database container:
+
+```
+$ cd postgresql; make build
+```
+
+#### XOS Container
+
+To build the XOS webserver container:
+
+```
+$ cd xos; make build
+```
+
+#### Synchronizer Container
+
+The Synchronizer shares many of the same dependencies as the XOS container. The
+synchronizer container takes advantage of this by building itself on top of the
+XOS image. This means you must build the XOS image before building the
+synchronizer image.  Assuming you have already built the XOS container,
+executing the following will build the Synchronizer container:
+
+```
+$ cd synchronizer; make build
+```
+
+#### Solution Compose File
+
+[Docker Compose](https://docs.docker.com/compose/) is a tool for defining and
+running multi-container Docker applications. With Compose, you use a Compose
+file to configure your application’s services. Then, using a single command, you
+create, start, scale, and manage all the services from your configuration.
+
+Included is a compose file in *YAML* format with content defined by the [Docker
+Compose Format](https://docs.docker.com/compose/compose-file/). With the compose
+file a complete XOS solution based on Docker containers can be instantiated
+using a single command. To start the instance you can use the command:
+
+```
+$ docker-compose up -d
+```
+
+You should now be able to access the login page by visiting
+`http://localhost:8000` and log in using the default `padmin@vicci.org` account
+with password `letmein`.
+
+## Configuring XOS for OpenStack
+
+There are many possible configurations of XOS. The best way to get started
+is to find the configuration that best matches your needs and modify it as
+necessary. The available "canned" configurations can be found i `../xos/configurations/`.
+
+If you have your own OpenStack cluster, and you would like to configure XOS to
+control it, then take the following steps. Copy the `admin-openrc.sh` credentials 
+file for your cluster to this directory.  Make sure that OpenStack commands work 
+from the local machine using the credentials, e.g., `source ./admin-openrc.sh; nova list`.  Then run:
+
+```
+$ make
+```
+
+XOS will be launched (the Makefile will run the `docker-compose up -d` command
+for you) and configured with the nodes and images available in your
+OpenStack cloud.  You can then log in to XOS as described above and start creating
+slices and instances.
diff --git a/containers/admin-openrc.sh b/containers/admin-openrc.sh
new file mode 100644
index 0000000..f27fdac
--- /dev/null
+++ b/containers/admin-openrc.sh
@@ -0,0 +1,6 @@
+# Replace with the OpenStack admin credentials for your cluster
+export OS_TENANT_NAME=admin
+export OS_USERNAME=admin
+export OS_PASSWORD=admin
+export OS_AUTH_URL=http://localhost:35357/v2.0
+
diff --git a/containers/docker-compose.yml b/containers/docker-compose.yml
new file mode 100644
index 0000000..24596a3
--- /dev/null
+++ b/containers/docker-compose.yml
@@ -0,0 +1,32 @@
+xos_db:
+    image: xosproject/xos-postgres
+    expose:
+        - "5432"
+
+xos_synchronizer_openstack:
+    command: bash -c "sleep 120; python /opt/xos/synchronizers/openstack/xos-synchronizer.py"
+    image: xosproject/xos-synchronizer-openstack
+    labels:
+        org.xosproject.kind: synchronizer
+        org.xosproject.target: openstack
+    links:
+        - xos_db
+    volumes:
+        - .:/root/setup:ro
+
+# FUTURE
+#xos_swarm_synchronizer:
+#    image: xosproject/xos-swarm-synchronizer
+#    labels:
+#        org.xosproject.kind: synchronizer
+#        org.xosproject.target: swarm
+
+xos:
+    command: python /opt/xos/manage.py runserver 0.0.0.0:8000 --insecure --makemigrations
+    image: xosproject/xos
+    links:
+        - xos_db
+    ports:
+        - "8000:8000"
+    volumes:
+        - .:/root/setup:ro
diff --git a/containers/elk/README.md b/containers/elk/README.md
new file mode 100644
index 0000000..676e718
--- /dev/null
+++ b/containers/elk/README.md
@@ -0,0 +1,53 @@
+# XOS ELK Stack Containers
+
+## Introduction
+
+ELK Stack is comprised of 3 core services:
+
+  * A Elasticsearch database backend
+  * A Logstash log collector 
+  * A Kibana front end
+
+We have created separate dockerfiles for each of these services, making it
+easier to build and deploy the services independently.
+
+#### Elasticsearch
+
+To build the Elasticsearch container:
+
+```
+$ cd elasticsearch; make build && make run
+```
+
+#### Logstash
+
+To build the Logstash container:
+
+```
+$ cd logstash; make build && make run
+```
+
+#### Kibana
+
+To build the Kibana container:
+
+```
+$ cd kibana; make build && make run
+```
+
+### Forwarding logs to Logstash
+
+Now that we have elk stack setup we need to start sending it some log files to process. We've provided a logstash-forwarder container that can be deployed on any host that has log files which you would like to have processed. 
+
+#### Logstash-forwarder
+
+The logstash-forwarder container is configured to mount the /var/log/ directory of the host machine, which means all files in /var/log are visible to the container. Modify the "files" section conf/config.json to include the files you want logstash-forwarder to handle. 
+
+You can modify the mount options in the Makefile if you need to access files that live in a directory other than /var/log/.
+
+To build the Loststash-forwarder container
+
+```
+$ cd logstash-forwarder; make build && make run
+```
+
diff --git a/containers/elk/elasticsearch/Dockerfile b/containers/elk/elasticsearch/Dockerfile
new file mode 100644
index 0000000..33206b8
--- /dev/null
+++ b/containers/elk/elasticsearch/Dockerfile
@@ -0,0 +1,23 @@
+FROM ubuntu:14.04.2
+
+RUN echo "deb http://packages.elastic.co/elasticsearch/1.7/debian stable main" | sudo tee -a /etc/apt/sources.list.d/elasticsearch-1.7.list
+
+RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y --force-yes\
+    openjdk-7-jre-headless \
+    wget \
+    elasticsearch
+
+VOLUME ["/data"]
+
+ADD conf/elasticsearch.yml /etc/elasticsearch/elasticsearch.yml
+ADD conf/elasticsearch.yml /usr/share/elasticsearch/config
+
+WORKDIR /data
+
+# Expose ports.
+#   - 9200: HTTP
+#   - 9300: transport
+EXPOSE 9200
+EXPOSE 9300     
+
+CMD ["/usr/share/elasticsearch/bin/elasticsearch"]
diff --git a/containers/elk/elasticsearch/Makefile b/containers/elk/elasticsearch/Makefile
new file mode 100644
index 0000000..9b01b93
--- /dev/null
+++ b/containers/elk/elasticsearch/Makefile
@@ -0,0 +1,11 @@
+.PHONY: build
+build: ; docker build --rm -t elasticsearch .
+
+.PHONY: run
+run: ; docker run -d -p 9200:9200 --name elasticsearch_server elasticsearch
+
+.PHONY: stop
+stop: ; docker stop elasticsearch_server
+
+.PHONY: rmcontainer
+rmcontainer: ; docker rm elasticsearch_server
diff --git a/containers/elk/elasticsearch/conf/elasticsearch.yml b/containers/elk/elasticsearch/conf/elasticsearch.yml
new file mode 100644
index 0000000..72be0f9
--- /dev/null
+++ b/containers/elk/elasticsearch/conf/elasticsearch.yml
@@ -0,0 +1,5 @@
+path:
+  data: /data/data
+  logs: /data/log
+  plugins: /data/plugins
+  work: /data/work
diff --git a/containers/elk/kibana/Dockerfile b/containers/elk/kibana/Dockerfile
new file mode 100644
index 0000000..fcfe625
--- /dev/null
+++ b/containers/elk/kibana/Dockerfile
@@ -0,0 +1,37 @@
+FROM ubuntu:14.04.2
+
+ENV KIBANA_VERSION kibana-4.0.1-linux-x64
+ENV KIBANA_SECURE true
+ENV KIBANA_USER kibana
+ENV KIBANA_PASSWORD kibana
+
+RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y \
+    wget \ 
+    nginx-full \
+    apache2-utils \
+    supervisor
+
+WORKDIR /opt
+
+RUN wget --no-check-certificate -O- https://download.elasticsearch.org/kibana/kibana/${KIBANA_VERSION}.tar.gz | tar xvfz -
+
+RUN mkdir /etc/kibana # This is where the htpasswd file is placed by the run script
+
+ADD conf/kibana /etc/nginx/sites-available/kibana
+
+ADD conf/kibana-secure /etc/nginx/sites-available/kibana-secure
+
+RUN rm /etc/nginx/sites-enabled/*
+
+RUN echo "daemon off;" >> /etc/nginx/nginx.conf
+
+ADD conf/supervisord.conf /etc/supervisor/conf.d/kibana.conf
+
+ADD run_kibana /opt/${KIBANA_VERSION}/run_kibana
+
+RUN chmod +x /opt/${KIBANA_VERSION}/run_kibana
+
+EXPOSE 80
+EXPOSE 5601
+
+CMD /opt/${KIBANA_VERSION}/run_kibana
diff --git a/containers/elk/kibana/Makefile b/containers/elk/kibana/Makefile
new file mode 100644
index 0000000..c44491a
--- /dev/null
+++ b/containers/elk/kibana/Makefile
@@ -0,0 +1,14 @@
+.PHONY: build
+build: ; docker build --rm -t kibana .
+
+.PHONY: run
+run: ; docker run -d --link elasticsearch_server:elasticsearch -p 8000:80 -e KIBANA_SECURE=false --name kibana_server kibana
+
+.PHONY: runsecure
+runsecure: ; docker run -d --link elasticsearch_server:elasticsearch -p 5601:80  --name kibana_server kibana
+
+.PHONY: stop
+stop: ; docker stop kibana_server
+
+.PHONY: rmcontainer
+rmcontainer: ; docker rm kibana_server
diff --git a/containers/elk/kibana/conf/kibana b/containers/elk/kibana/conf/kibana
new file mode 100644
index 0000000..c5c3031
--- /dev/null
+++ b/containers/elk/kibana/conf/kibana
@@ -0,0 +1,17 @@
+server {
+  listen   80; ## listen for ipv4; this line is default and implied
+  listen   [::]:80 default ipv6only=on; ## listen for ipv6
+
+  # Make site accessible from http://localhost/
+  server_name localhost;
+
+  location = /health {
+    return 200;
+    access_log off;
+  }
+
+  location / {
+    proxy_pass http://kibana:5601;
+    proxy_read_timeout 90;
+  }
+}
diff --git a/containers/elk/kibana/conf/kibana-secure b/containers/elk/kibana/conf/kibana-secure
new file mode 100644
index 0000000..760f161
--- /dev/null
+++ b/containers/elk/kibana/conf/kibana-secure
@@ -0,0 +1,24 @@
+server {
+  listen   80; ## listen for ipv4; this line is default and implied
+  listen   [::]:80 default ipv6only=on; ## listen for ipv6
+
+  # Make site accessible from http://localhost/
+  server_name localhost;
+
+  location = /health {
+    return 200;
+    access_log off;
+  }
+
+  location / {
+    proxy_pass http://kibana:5601;
+    proxy_read_timeout 90;
+
+    if ($http_x_forwarded_proto != "https") {
+      rewrite ^ https://$host$uri permanent;
+    }
+
+    auth_basic "Restricted";
+    auth_basic_user_file /etc/kibana/htpasswd;
+  }
+}
diff --git a/containers/elk/kibana/conf/supervisord.conf b/containers/elk/kibana/conf/supervisord.conf
new file mode 100644
index 0000000..deff0c7
--- /dev/null
+++ b/containers/elk/kibana/conf/supervisord.conf
@@ -0,0 +1,14 @@
+[supervisord]
+nodaemon=true
+
+[program:kibana]
+command=/opt/kibana-4.0.1-linux-x64/bin/kibana
+autorestart=true
+stderr_logfile=/var/log/supervisor/kibana.err.log
+stdout_logfile=/var/log/supervisor/kibana.out.log
+
+[program:nginx]
+command=/usr/sbin/nginx
+autorestart=true
+stderr_logfile=/var/log/supervisor/nginx.err.log
+stdout_logfile=/var/log/supervisor/nginx.out.log
diff --git a/containers/elk/kibana/run_kibana b/containers/elk/kibana/run_kibana
new file mode 100644
index 0000000..8723bba
--- /dev/null
+++ b/containers/elk/kibana/run_kibana
@@ -0,0 +1,10 @@
+#!/bin/bash
+sed -i "s/localhost:9200/elasticsearch:9200/g" /opt/${KIBANA_VERSION}/config/kibana.yml
+if [ "$KIBANA_SECURE" = "true" ] ; then
+    ln -s /etc/nginx/sites-available/kibana-secure /etc/nginx/sites-enabled/kibana
+    htpasswd -bc /etc/kibana/htpasswd ${KIBANA_USER} ${KIBANA_PASSWORD}
+else
+    ln -s /etc/nginx/sites-available/kibana /etc/nginx/sites-enabled/kibana
+fi
+sed -i "s/kibana:5601/$HOSTNAME:5601/g" /etc/nginx/sites-enabled/kibana
+/usr/bin/supervisord -c /etc/supervisor/conf.d/kibana.conf
diff --git a/containers/elk/logstash-forwarder/Dockerfile b/containers/elk/logstash-forwarder/Dockerfile
new file mode 100644
index 0000000..05979c9
--- /dev/null
+++ b/containers/elk/logstash-forwarder/Dockerfile
@@ -0,0 +1,27 @@
+FROM ubuntu:14.04.2
+
+ENV LOGSTASH_HOST 66.228.36.77
+
+RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y --force-yes \
+    git \
+    golang \
+    supervisor
+
+RUN git clone git://github.com/elasticsearch/logstash-forwarder.git /tmp/logstash-forwarder
+RUN cd /tmp/logstash-forwarder && git checkout v0.4.0 && go build
+
+RUN mkdir /opt/logstash-forwarder && cp /tmp/logstash-forwarder/logstash-forwarder /opt/logstash-forwarder/logstash-forwarder
+
+ADD conf/config.json /opt/logstash-forwarder/config.json
+ADD conf/supervisord.conf /etc/supervisor/conf.d/logstash-forwarder.conf
+ADD run_logstash-forwarder /opt/logstash-forwarder/run_logstash-forwarder
+
+RUN chmod +x /opt/logstash-forwarder/run_logstash-forwarder
+
+RUN rm -rf /tmp/*
+
+VOLUME ["/opt/certs", "/var/log/"]
+
+CMD /opt/logstash-forwarder/run_logstash-forwarder
+
+
diff --git a/containers/elk/logstash-forwarder/Makefile b/containers/elk/logstash-forwarder/Makefile
new file mode 100644
index 0000000..cc52790
--- /dev/null
+++ b/containers/elk/logstash-forwarder/Makefile
@@ -0,0 +1,11 @@
+.PHONY: build
+build: ; docker build --rm -t logstash-forwarder .
+
+.PHONY: run
+run: ; docker run --rm -v `pwd`/../logstash/certs:/opt/certs -v /var/log/:/var/log --name logstash-forwarder_server -i -t logstash-forwarder
+
+.PHONY: stop
+stop: ; docker stop logstash-forwarder_server 
+
+.PHONY: rmcontainer
+rmcontainer: ; docker rm logstash-forwarder_server 
diff --git a/containers/elk/logstash-forwarder/conf/config.json b/containers/elk/logstash-forwarder/conf/config.json
new file mode 100644
index 0000000..71a9975
--- /dev/null
+++ b/containers/elk/logstash-forwarder/conf/config.json
@@ -0,0 +1,15 @@
+{
+  "network": {
+    "servers": [ "logstash:5043" ],
+    "ssl certificate": "/opt/certs/logstash-forwarder.crt",
+    "ssl key": "/opt/certs/logstash-forwarder.key",
+    "ssl ca": "/opt/certs/logstash-forwarder.crt",
+    "timeout": 15
+  },
+  "files": [
+    {
+      "paths": [ "/var/log/message", "/var/log/syslog" ],
+      "fields": { "type": "stdin" }
+    }
+  ]
+}
diff --git a/containers/elk/logstash-forwarder/conf/supervisord.conf b/containers/elk/logstash-forwarder/conf/supervisord.conf
new file mode 100644
index 0000000..c91b37c
--- /dev/null
+++ b/containers/elk/logstash-forwarder/conf/supervisord.conf
@@ -0,0 +1,9 @@
+[supervisord]
+nodaemon=true
+
+[program:logstash-forwarder]
+command=/opt/logstash-forwarder/logstash-forwarder -config /opt/logstash-forwarder/config.json 
+autorestart=true
+stderr_logfile=/var/log/logstash.err.log
+stdout_logfile=/var/log/logstash.out.log
+
diff --git a/containers/elk/logstash-forwarder/extfile.cnf b/containers/elk/logstash-forwarder/extfile.cnf
new file mode 100644
index 0000000..337a5f4
--- /dev/null
+++ b/containers/elk/logstash-forwarder/extfile.cnf
@@ -0,0 +1 @@
+subjectAltName = IP:66.228.36.77
diff --git a/containers/elk/logstash-forwarder/run_logstash-forwarder b/containers/elk/logstash-forwarder/run_logstash-forwarder
new file mode 100644
index 0000000..e97edc4
--- /dev/null
+++ b/containers/elk/logstash-forwarder/run_logstash-forwarder
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+sed -i "s/logstash:5043/${LOGSTASH_HOST}:5043/g" /opt/logstash-forwarder/config.json
+
+/usr/bin/supervisord -c /etc/supervisor/conf.d/logstash-forwarder.conf
diff --git a/containers/elk/logstash/Dockerfile b/containers/elk/logstash/Dockerfile
new file mode 100644
index 0000000..2c9ad7b
--- /dev/null
+++ b/containers/elk/logstash/Dockerfile
@@ -0,0 +1,26 @@
+FROM ubuntu:14.04.2
+
+RUN echo "deb http://packages.elasticsearch.org/logstash/1.5/debian stable main" | sudo tee -a /etc/apt/sources.list
+
+RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y --force-yes \
+    wget \
+    ca-certificates \
+    openjdk-7-jre-headless \
+    supervisor \
+    logstash
+
+
+
+RUN mkdir /opt/logstash/plugins
+ADD conf/supervisord.conf /etc/supervisor/conf.d/logstash.conf
+ADD conf/logstash.conf /opt/logstash/logstash.conf
+ADD conf/collectd-types.db /opt/logstash/collectd-types.db
+ADD conf/filter_rsyslog.conf /etc/logstash/plugins/filter_rsyslog.conf
+
+VOLUME ["/opt/logstash/certs"]
+
+EXPOSE 514
+EXPOSE 5043
+EXPOSE 9292
+
+CMD /usr/bin/supervisord -c /etc/supervisor/conf.d/logstash.conf
diff --git a/containers/elk/logstash/Makefile b/containers/elk/logstash/Makefile
new file mode 100644
index 0000000..9e04234
--- /dev/null
+++ b/containers/elk/logstash/Makefile
@@ -0,0 +1,18 @@
+IP=`curl icanhazip.com`
+IP=66.228.36.77
+SUBJECT="/C=US/ST=NY/O=Internet Widgits Pty Ltd/subjectAltName=IP:${IP}"
+
+.PHONY: certs
+certs: ; [ ! -d certs  ] && mkdir certs && cd certs && openssl req -x509 -batch -nodes -newkey rsa:2048 -keyout logstash-forwarder.key -out logstash-forwarder.crt
+
+.PHONY: build
+build: ; docker build --rm -t logstash .
+
+.PHONY: run
+run: ; docker run -d --link elasticsearch_server:elasticsearch -p 5043:5043 -p 514:514 -v `pwd`/certs:/opt/logstash/certs -v `pwd`/conf:/opt/logstash/conf --name logstash_server -i -t logstash
+
+.PHONY: stop
+stop: ; docker stop logstash_server 
+
+.PHONY: rmcontainer
+rmcontainer: ; docker rm logstash_server
diff --git a/containers/elk/logstash/certs/logstash-forwarder.crt b/containers/elk/logstash/certs/logstash-forwarder.crt
new file mode 100644
index 0000000..1ecccc4
--- /dev/null
+++ b/containers/elk/logstash/certs/logstash-forwarder.crt
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDbjCCAlagAwIBAgIJAKAHY7+C/K7gMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
+BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
+aWRnaXRzIFB0eSBMdGQwHhcNMTUwOTA1MjMyNDQ3WhcNMTUxMDA1MjMyNDQ3WjBF
+MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
+ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEA2/e7hjfGFSp5EqB2Su4ZHNHABxInxoPGpl7Yn3jnDH/RmrXWyUcAyrVm
+DTDUZ38NQ0LORFuuyR6EdHoBiD4KEzzP8fMpqTdviyhbqDB2Ijc2FsFLKlHB4zIb
+E8JpBoBKl49Mk9Hhb0y/Ce1vjYdhUW1kgo0icvabtX9rTzweyogZC/EEBS6yz4rx
+CG1VwGWplpBioMSJkzaWQgqpoOLf6L5GaiXjuYgFdYBv4DpY+HoySJvIdYKAOgGy
+a84KQCv5Syx5BNgq/Tk6MX3dCGRheI6BLmZuu5Zpm7EY/dWTbHzTcuT/NhGUhqR7
+G0BPQfYRkfvkrdUIOWFPJdVJDz5NwQIDAQABo2EwXzAPBgNVHREECDAGhwRC5CRN
+MB0GA1UdDgQWBBS6sPxnCknyoMFBAKoo9FT59a0WfzAfBgNVHSMEGDAWgBS6sPxn
+CknyoMFBAKoo9FT59a0WfzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IB
+AQAw2oy3fDa1PuRueeWaEERtRysgVR/Z41GrOxkSW/wnbI2kxIMvnMFXCsfqgfof
+MStVdfP0ZgqNbnVFgbQ4egbgcH6qfpTPpNGxz4C//od24+T6nQWVWuujiSpmQF8e
+sv1HXT6HduYvQAl1II0UaZ0LZBTgP0P7O4Em7gjtMVWdnscdj+qFzZnY187HUchr
++ngjUa5uJtVgKtX+a0oEh24EmUdQbEB+2wEwV7zJoA9k8WUHY7QxCpIMBD5b9aLs
+C27t0J8mBmPv3C9pEfJiRKdq/fhiwxuZWqXfIuLo8oTZJOcceLnLvxaMXpAilKva
+HK0aeVmnOiey6bbwddE6hr6R
+-----END CERTIFICATE-----
diff --git a/containers/elk/logstash/certs/logstash-forwarder.key b/containers/elk/logstash/certs/logstash-forwarder.key
new file mode 100644
index 0000000..40d3dfa
--- /dev/null
+++ b/containers/elk/logstash/certs/logstash-forwarder.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDb97uGN8YVKnkS
+oHZK7hkc0cAHEifGg8amXtifeOcMf9GatdbJRwDKtWYNMNRnfw1DQs5EW67JHoR0
+egGIPgoTPM/x8ympN2+LKFuoMHYiNzYWwUsqUcHjMhsTwmkGgEqXj0yT0eFvTL8J
+7W+Nh2FRbWSCjSJy9pu1f2tPPB7KiBkL8QQFLrLPivEIbVXAZamWkGKgxImTNpZC
+Cqmg4t/ovkZqJeO5iAV1gG/gOlj4ejJIm8h1goA6AbJrzgpAK/lLLHkE2Cr9OTox
+fd0IZGF4joEuZm67lmmbsRj91ZNsfNNy5P82EZSGpHsbQE9B9hGR++St1Qg5YU8l
+1UkPPk3BAgMBAAECggEBAMF+8LSmh1bDH/HkuWo8fFa/o/4UWGzmKm7bbA8MWaLD
+JWzEnIY+MVIfs//SfmX0e4Q5Vh0H0X8Vm0qisIpamJ5HllytnG5AV5zACbCvwJtk
+me32Ztp5ROdIgk0lbSHM5NDhu2kk7PvtNPfUp5aGCnOImSvGXxFmIZ7M0WbH6gYZ
+hNuMCIWiTYjNVHLgl59vU55cz2Ze8a2lAqLD0UcvQtUDceqfxakBES7WcsmxSV24
+v5WheID0jX1BGkkSKZYkg+CagBGvoMei6HudkQz7xZnS27u2xrsGKi7zOMIC6cu4
+O+okPk+XHd9uleeb4klWFGx3w8HtXfEhY683jqUIeEkCgYEA86VEBamZ/FXi+vfw
+J7gyKtHUDwOrjU9pRTnZ0m1iRfbVYcR03egA9YWq4KhRp1l9Ofb1+3dCynaEyJXu
+d3vayQhKvRN2QymvETP2+3dXIdhqjgrhjRn0cZkWivTmjz20GnVvQ2X2wSNIl1tS
+B5Ym+v/G71HfAAuX+UD/FSQ017cCgYEA5x8bdRd58tg1zksnR2D5JCMvYiNVySar
+L1Z580dt6Ak0LwSWmZbGfaWAGPcBRbFGJSZCJ0AtlOCiIvDO1pdQ1UuVaknbrGEE
+rOr92/yd8CiWvbBzxjUJ3UXayy9q0iJuIt6tUaXlJDIOtxOXqYuRkb3kfnNSjDsc
+d/fhn+bZVkcCgYEA81zvPcyzf4V2TAIdgj8M9RJTg4/B6ksYtknblcEmeQXdC2PE
+6+YSFyuli/L0ZHkRiTVxa/Uq5LpPVV/VKsmutkCvDn8DEIDxWfiSyYjhom/dtvWN
+Z3g2XsVv6+pE5WzXmdoVAbg2KaKJno1buTI0y19yoJchbJUn/pL6d26Lza8CgYEA
+mrqNpEdSQg0TgId5xWSbhuDzYO0tClyT8D4hqIgigVxgDjYxKKPzQLzi1FPRCzpS
+Lp69XQ+vNGNqyJ+Uqb9lw1Y1spG9ulq9SZKM35Dwn45c1KNj7sclUnjosGyPRBz+
+xON0/xtkG2ZTyacZOs2QaBTL+wfztKQCPCK8b1OaHxMCgYAjz/psH+XbdcK/hFUk
+Ndh68Odw7pydVaIXg3woa4yDlbl5Ca69+P0sSwYYdDNKum6VEiclXlZOdhK/Pzx1
+D/KIPlOwcVcvx1Yog+eF/bZ/aDZj5uBfFDodNk0ohlwnw/2naOtOmYrbgviFznEb
+5P2U3UcClITRrgY9pc4VuFsz5Q==
+-----END PRIVATE KEY-----
diff --git a/containers/elk/logstash/conf/collectd-types.db b/containers/elk/logstash/conf/collectd-types.db
new file mode 100644
index 0000000..ec6ff93
--- /dev/null
+++ b/containers/elk/logstash/conf/collectd-types.db
@@ -0,0 +1,191 @@
+absolute        value:ABSOLUTE:0:U
+apache_bytes        value:DERIVE:0:U
+apache_connections  value:GAUGE:0:65535
+apache_idle_workers value:GAUGE:0:65535
+apache_requests     value:DERIVE:0:U
+apache_scoreboard   value:GAUGE:0:65535
+ath_nodes       value:GAUGE:0:65535
+ath_stat        value:DERIVE:0:U
+bitrate         value:GAUGE:0:4294967295
+bytes           value:GAUGE:0:U
+cache_eviction      value:DERIVE:0:U
+cache_operation     value:DERIVE:0:U
+cache_ratio     value:GAUGE:0:100
+cache_result        value:DERIVE:0:U
+cache_size      value:GAUGE:0:4294967295
+charge          value:GAUGE:0:U
+compression_ratio   value:GAUGE:0:2
+compression     uncompressed:DERIVE:0:U, compressed:DERIVE:0:U
+connections     value:DERIVE:0:U
+conntrack       value:GAUGE:0:4294967295
+contextswitch       value:DERIVE:0:U
+counter         value:COUNTER:U:U
+cpufreq         value:GAUGE:0:U
+cpu         value:DERIVE:0:U
+current_connections value:GAUGE:0:U
+current_sessions    value:GAUGE:0:U
+current         value:GAUGE:U:U
+delay           value:GAUGE:-1000000:1000000
+derive          value:DERIVE:0:U
+df_complex      value:GAUGE:0:U
+df_inodes       value:GAUGE:0:U
+df          used:GAUGE:0:1125899906842623, free:GAUGE:0:1125899906842623
+disk_latency        read:GAUGE:0:U, write:GAUGE:0:U
+disk_merged     read:DERIVE:0:U, write:DERIVE:0:U
+disk_octets     read:DERIVE:0:U, write:DERIVE:0:U
+disk_ops_complex    value:DERIVE:0:U
+disk_ops        read:DERIVE:0:U, write:DERIVE:0:U
+disk_time       read:DERIVE:0:U, write:DERIVE:0:U
+dns_answer      value:DERIVE:0:U
+dns_notify      value:DERIVE:0:U
+dns_octets      queries:DERIVE:0:U, responses:DERIVE:0:U
+dns_opcode      value:DERIVE:0:U
+dns_qtype_cached    value:GAUGE:0:4294967295
+dns_qtype       value:DERIVE:0:U
+dns_query       value:DERIVE:0:U
+dns_question        value:DERIVE:0:U
+dns_rcode       value:DERIVE:0:U
+dns_reject      value:DERIVE:0:U
+dns_request     value:DERIVE:0:U
+dns_resolver        value:DERIVE:0:U
+dns_response        value:DERIVE:0:U
+dns_transfer        value:DERIVE:0:U
+dns_update      value:DERIVE:0:U
+dns_zops        value:DERIVE:0:U
+email_check     value:GAUGE:0:U
+email_count     value:GAUGE:0:U
+email_size      value:GAUGE:0:U
+entropy         value:GAUGE:0:4294967295
+fanspeed        value:GAUGE:0:U
+file_size       value:GAUGE:0:U
+files           value:GAUGE:0:U
+fork_rate       value:DERIVE:0:U
+frequency       value:GAUGE:0:U
+frequency_offset    value:GAUGE:-1000000:1000000
+fscache_stat        value:DERIVE:0:U
+gauge           value:GAUGE:U:U
+hash_collisions     value:DERIVE:0:U
+http_request_methods    value:DERIVE:0:U
+http_requests       value:DERIVE:0:U
+http_response_codes value:DERIVE:0:U
+humidity        value:GAUGE:0:100
+if_collisions       value:DERIVE:0:U
+if_dropped      rx:DERIVE:0:U, tx:DERIVE:0:U
+if_errors       rx:DERIVE:0:U, tx:DERIVE:0:U
+if_multicast        value:DERIVE:0:U
+if_octets       rx:DERIVE:0:U, tx:DERIVE:0:U
+if_packets      rx:DERIVE:0:U, tx:DERIVE:0:U
+if_rx_errors        value:DERIVE:0:U
+if_tx_errors        value:DERIVE:0:U
+invocations     value:DERIVE:0:U
+io_octets       rx:DERIVE:0:U, tx:DERIVE:0:U
+io_packets      rx:DERIVE:0:U, tx:DERIVE:0:U
+ipt_bytes       value:DERIVE:0:U
+ipt_packets     value:DERIVE:0:U
+irq         value:DERIVE:0:U
+latency         value:GAUGE:0:65535
+links           value:GAUGE:0:U
+load            shortterm:GAUGE:0:100, midterm:GAUGE:0:100, longterm:GAUGE:0:100
+md_disks        value:GAUGE:0:U
+memcached_command   value:DERIVE:0:U
+memcached_connections   value:GAUGE:0:U
+memcached_items     value:GAUGE:0:U
+memcached_octets    rx:DERIVE:0:U, tx:DERIVE:0:U
+memcached_ops       value:DERIVE:0:U
+memory          value:GAUGE:0:281474976710656
+multimeter      value:GAUGE:U:U
+mutex_operations    value:DERIVE:0:U
+mysql_commands      value:DERIVE:0:U
+mysql_handler       value:DERIVE:0:U
+mysql_locks     value:DERIVE:0:U
+mysql_log_position  value:DERIVE:0:U
+mysql_octets        rx:DERIVE:0:U, tx:DERIVE:0:U
+nfs_procedure       value:DERIVE:0:U
+nginx_connections   value:GAUGE:0:U
+nginx_requests      value:DERIVE:0:U
+node_octets     rx:DERIVE:0:U, tx:DERIVE:0:U
+node_rssi       value:GAUGE:0:255
+node_stat       value:DERIVE:0:U
+node_tx_rate        value:GAUGE:0:127
+operations      value:DERIVE:0:U
+percent         value:GAUGE:0:100.1
+pg_blks         value:DERIVE:0:U
+pg_db_size      value:GAUGE:0:U
+pg_n_tup_c      value:DERIVE:0:U
+pg_n_tup_g      value:GAUGE:0:U
+pg_numbackends      value:GAUGE:0:U
+pg_scan         value:DERIVE:0:U
+pg_xact         value:DERIVE:0:U
+ping_droprate       value:GAUGE:0:100
+ping            value:GAUGE:0:65535
+ping_stddev     value:GAUGE:0:65535
+players         value:GAUGE:0:1000000
+power           value:GAUGE:0:U
+protocol_counter    value:DERIVE:0:U
+ps_code         value:GAUGE:0:9223372036854775807
+ps_count        processes:GAUGE:0:1000000, threads:GAUGE:0:1000000
+ps_cputime      user:DERIVE:0:U, syst:DERIVE:0:U
+ps_data         value:GAUGE:0:9223372036854775807
+ps_disk_octets      read:DERIVE:0:U, write:DERIVE:0:U
+ps_disk_ops     read:DERIVE:0:U, write:DERIVE:0:U
+ps_pagefaults       minflt:DERIVE:0:U, majflt:DERIVE:0:U
+ps_rss          value:GAUGE:0:9223372036854775807
+ps_stacksize        value:GAUGE:0:9223372036854775807
+ps_state        value:GAUGE:0:65535
+ps_vm           value:GAUGE:0:9223372036854775807
+queue_length        value:GAUGE:0:U
+records         value:GAUGE:0:U
+requests        value:GAUGE:0:U
+response_time       value:GAUGE:0:U
+route_etx       value:GAUGE:0:U
+route_metric        value:GAUGE:0:U
+routes          value:GAUGE:0:U
+serial_octets       rx:DERIVE:0:U, tx:DERIVE:0:U
+signal_noise        value:GAUGE:U:0
+signal_power        value:GAUGE:U:0
+signal_quality      value:GAUGE:0:U
+snr         value:GAUGE:0:U
+spam_check      value:GAUGE:0:U
+spam_score      value:GAUGE:U:U
+swap_io         value:DERIVE:0:U
+swap            value:GAUGE:0:1099511627776
+tcp_connections     value:GAUGE:0:4294967295
+temperature     value:GAUGE:-273.15:U
+threads         value:GAUGE:0:U
+time_dispersion     value:GAUGE:-1000000:1000000
+timeleft        value:GAUGE:0:3600
+time_offset     value:GAUGE:-1000000:1000000
+total_bytes     value:DERIVE:0:U
+total_connections   value:DERIVE:0:U
+total_operations    value:DERIVE:0:U
+total_requests      value:DERIVE:0:U
+total_sessions      value:DERIVE:0:U
+total_threads       value:DERIVE:0:U
+total_time_in_ms    value:DERIVE:0:U
+total_values        value:DERIVE:0:U
+uptime          value:GAUGE:0:4294967295
+users           value:GAUGE:0:65535
+vcpu            value:GAUGE:0:U
+virt_cpu_total      value:DERIVE:0:U
+virt_vcpu       value:DERIVE:0:U
+vmpage_action       value:DERIVE:0:U
+vmpage_faults       minflt:DERIVE:0:U, majflt:DERIVE:0:U
+vmpage_io       in:DERIVE:0:U, out:DERIVE:0:U
+vmpage_number       value:GAUGE:0:4294967295
+volatile_changes    value:GAUGE:0:U
+voltage_threshold   value:GAUGE:U:U, threshold:GAUGE:U:U
+voltage         value:GAUGE:U:U
+vs_memory       value:GAUGE:0:9223372036854775807
+vs_processes        value:GAUGE:0:65535
+vs_threads      value:GAUGE:0:65535
+#
+# Legacy types
+# (required for the v5 upgrade target)
+#
+arc_counts      demand_data:COUNTER:0:U, demand_metadata:COUNTER:0:U, prefetch_data:COUNTER:0:U, prefetch_metadata:COUNTER:0:U
+arc_l2_bytes        read:COUNTER:0:U, write:COUNTER:0:U
+arc_l2_size     value:GAUGE:0:U
+arc_ratio       value:GAUGE:0:U
+arc_size        current:GAUGE:0:U, target:GAUGE:0:U, minlimit:GAUGE:0:U, maxlimit:GAUGE:0:U
+mysql_qcache        hits:COUNTER:0:U, inserts:COUNTER:0:U, not_cached:COUNTER:0:U, lowmem_prunes:COUNTER:0:U, queries_in_cache:GAUGE:0:U
+mysql_threads       running:GAUGE:0:U, connected:GAUGE:0:U, cached:GAUGE:0:U, created:COUNTER:0:U
diff --git a/containers/elk/logstash/conf/filter_rsyslog.conf b/containers/elk/logstash/conf/filter_rsyslog.conf
new file mode 100644
index 0000000..d64be71
--- /dev/null
+++ b/containers/elk/logstash/conf/filter_rsyslog.conf
@@ -0,0 +1,13 @@
+filter {
+  if [type] == “syslog” {
+    grok {
+      match => { "message" => "%{SYSLOGTIMESTAMP:syslog_timestamp} %{SYSLOGHOST:syslog_hostname} %{DATA:syslog_program}(?:\[%{POSINT:syslog_pid}\])?: %{GREEDYDATA:syslog_message}" }
+      add_field => [ "received_at", "%{@timestamp}" ]
+      add_field => [ "received_from", "%{host}" ]
+    }
+    syslog_pri { }
+    date {
+      match => [ “syslog_timestamp”, “MMM d HH:mm:ss”, “MMM dd HH:mm:ss” ]
+    }  
+  }
+}                                                            
diff --git a/containers/elk/logstash/conf/logstash.conf b/containers/elk/logstash/conf/logstash.conf
new file mode 100644
index 0000000..8d3f57c
--- /dev/null
+++ b/containers/elk/logstash/conf/logstash.conf
@@ -0,0 +1,28 @@
+input {
+  syslog {
+    type => syslog
+    port => 514
+  }
+  lumberjack {
+    port => 5043
+    type => "logs"
+    ssl_certificate => "/opt/logstash/certs/logstash-forwarder.crt"
+    ssl_key => "/opt/logstash/certs/logstash-forwarder.key"
+  }
+  udp {
+    port => 25826
+    buffer_size => 1452
+    codec => collectd { }
+  }
+}
+output {
+
+stdout {
+    codec => json
+}
+
+elasticsearch {
+      host => "elasticsearch"
+      port => "9300"
+  }
+}
diff --git a/containers/elk/logstash/conf/supervisord.conf b/containers/elk/logstash/conf/supervisord.conf
new file mode 100644
index 0000000..1f3ede3
--- /dev/null
+++ b/containers/elk/logstash/conf/supervisord.conf
@@ -0,0 +1,8 @@
+[supervisord]
+nodaemon=true
+
+[program:logstash
+command=/opt/logstash/bin/logstash -f /opt/logstash/logstash.conf -p /opt/logstash/plugins/  
+autorestart=true
+stderr_logfile=/var/log/logstash.err.log
+stdout_logfile=/var/log/logstash.out.log
diff --git a/containers/nagios/Dockerfile b/containers/nagios/Dockerfile
new file mode 100644
index 0000000..c33f71c
--- /dev/null
+++ b/containers/nagios/Dockerfile
@@ -0,0 +1,63 @@
+FROM cpuguy83/ubuntu
+ENV NAGIOS_HOME /opt/nagios
+ENV NAGIOS_USER nagios
+ENV NAGIOS_GROUP nagios
+ENV NAGIOS_CMDUSER nagios
+ENV NAGIOS_CMDGROUP nagios
+ENV NAGIOSADMIN_USER nagiosadmin
+ENV NAGIOSADMIN_PASS nagios
+ENV APACHE_RUN_USER nagios
+ENV APACHE_RUN_GROUP nagios
+ENV NAGIOS_TIMEZONE UTC
+
+RUN sed -i 's/universe/universe multiverse/' /etc/apt/sources.list
+RUN apt-get update && apt-get install -y iputils-ping netcat build-essential snmp snmpd snmp-mibs-downloader php5-cli apache2 libapache2-mod-php5 runit bc postfix bsd-mailx
+RUN ( egrep -i  "^${NAGIOS_GROUP}" /etc/group || groupadd $NAGIOS_GROUP ) && ( egrep -i "^${NAGIOS_CMDGROUP}" /etc/group || groupadd $NAGIOS_CMDGROUP )
+RUN ( id -u $NAGIOS_USER || useradd --system $NAGIOS_USER -g $NAGIOS_GROUP -d $NAGIOS_HOME ) && ( id -u $NAGIOS_CMDUSER || useradd --system -d $NAGIOS_HOME -g $NAGIOS_CMDGROUP $NAGIOS_CMDUSER )
+
+ADD http://downloads.sourceforge.net/project/nagios/nagios-3.x/nagios-3.5.1/nagios-3.5.1.tar.gz?r=http%3A%2F%2Fwww.nagios.org%2Fdownload%2Fcore%2Fthanks%2F%3Ft%3D1398863696&ts=1398863718&use_mirror=superb-dca3 /tmp/nagios.tar.gz
+RUN cd /tmp && tar -zxvf nagios.tar.gz && cd nagios  && ./configure --prefix=${NAGIOS_HOME} --exec-prefix=${NAGIOS_HOME} --enable-event-broker --with-nagios-command-user=${NAGIOS_CMDUSER} --with-command-group=${NAGIOS_CMDGROUP} --with-nagios-user=${NAGIOS_USER} --with-nagios-group=${NAGIOS_GROUP} && make all && make install && make install-config && make install-commandmode && cp sample-config/httpd.conf /etc/apache2/conf.d/nagios.conf
+ADD http://www.nagios-plugins.org/download/nagios-plugins-1.5.tar.gz /tmp/
+RUN cd /tmp && tar -zxvf nagios-plugins-1.5.tar.gz && cd nagios-plugins-1.5 && ./configure --prefix=${NAGIOS_HOME} && make && make install
+
+RUN sed -i.bak 's/.*\=www\-data//g' /etc/apache2/envvars
+RUN export DOC_ROOT="DocumentRoot $(echo $NAGIOS_HOME/share)"; sed -i "s,DocumentRoot.*,$DOC_ROOT," /etc/apache2/sites-available/default
+
+RUN ln -s ${NAGIOS_HOME}/bin/nagios /usr/local/bin/nagios && mkdir -p /usr/share/snmp/mibs && chmod 0755 /usr/share/snmp/mibs && touch /usr/share/snmp/mibs/.foo
+
+RUN echo "use_timezone=$NAGIOS_TIMEZONE" >> ${NAGIOS_HOME}/etc/nagios.cfg && echo "SetEnv TZ \"${NAGIOS_TIMEZONE}\"" >> /etc/apache2/conf.d/nagios.conf
+
+RUN mkdir -p ${NAGIOS_HOME}/etc/conf.d && mkdir -p ${NAGIOS_HOME}/etc/monitor && ln -s /usr/share/snmp/mibs ${NAGIOS_HOME}/libexec/mibs
+RUN echo "cfg_dir=${NAGIOS_HOME}/etc/conf.d" >> ${NAGIOS_HOME}/etc/nagios.cfg
+RUN echo "cfg_dir=${NAGIOS_HOME}/etc/monitor" >> ${NAGIOS_HOME}/etc/nagios.cfg
+RUN download-mibs && echo "mibs +ALL" > /etc/snmp/snmp.conf
+
+RUN sed -i 's,/bin/mail,/usr/bin/mail,' /opt/nagios/etc/objects/commands.cfg && \
+  sed -i 's,/usr/usr,/usr,' /opt/nagios/etc/objects/commands.cfg
+RUN cp /etc/services /var/spool/postfix/etc/
+
+RUN mkdir -p /etc/sv/nagios && mkdir -p /etc/sv/apache && rm -rf /etc/sv/getty-5 && mkdir -p /etc/sv/postfix
+ADD nagios.init /etc/sv/nagios/run
+ADD apache.init /etc/sv/apache/run
+ADD postfix.init /etc/sv/postfix/run
+ADD postfix.stop /etc/sv/postfix/finish
+
+ADD start.sh /usr/local/bin/start_nagios
+
+# install slack alert notification plugin
+ADD slack_nagios.cfg ${NAGIOS_HOME}/etc/conf.d/slack_nagios.cfg
+ADD slack_nagios.sh  /usr/local/bin/slack_nagios.sh
+RUN chmod +x /usr/local/bin/slack_nagios.sh
+
+ENV APACHE_LOCK_DIR /var/run
+ENV APACHE_LOG_DIR /var/log/apache2
+
+EXPOSE 80
+
+VOLUME /opt/nagios/var
+VOLUME /opt/nagios/etc
+VOLUME /opt/nagios/libexec
+VOLUME /var/log/apache2
+VOLUME /usr/share/snmp/mibs
+
+CMD ["/usr/local/bin/start_nagios"]
diff --git a/containers/nagios/Makefile b/containers/nagios/Makefile
new file mode 100644
index 0000000..0c6cb32
--- /dev/null
+++ b/containers/nagios/Makefile
@@ -0,0 +1,12 @@
+.PHONY: build
+	build: ; docker build --rm -t xosproject/nagios .
+
+.PHONY: run
+	run: ; docker run -d --name xosproject_nagios -p 8001:80 -t xosproject/nagios
+
+.PHONY: stop
+	stop: ; docker stop xosproject_nagios
+
+.PHONY: rm
+	rm: ; docker rm xosproject_nagios
+
diff --git a/containers/nagios/README.md b/containers/nagios/README.md
new file mode 100644
index 0000000..e6c2c0e
--- /dev/null
+++ b/containers/nagios/README.md
@@ -0,0 +1,14 @@
+## Docker-Nagios  [![Docker Build Status](http://72.14.176.28/cpuguy83/nagios)](https://registry.hub.docker.com/u/cpuguy83/nagios)
+
+Basic Docker image for running Nagios.<br />
+This is running Nagios 3.5.1
+
+You should either link a mail container in as "mail" or set MAIL_SERVER, otherwise
+mail will not work.
+
+### Knobs ###
+- NAGIOSADMIN_USER=nagiosadmin
+- NAGIOSAMDIN_PASS=nagios
+
+### Web UI ###
+The Nagios Web UI is available on port 80 of the container<br />
diff --git a/containers/nagios/apache.init b/containers/nagios/apache.init
new file mode 100755
index 0000000..9cb9a38
--- /dev/null
+++ b/containers/nagios/apache.init
@@ -0,0 +1,4 @@
+#!/bin/bash
+. /etc/default/apache2
+
+exec /usr/sbin/apache2 -D FOREGROUND
diff --git a/containers/nagios/nagios.init b/containers/nagios/nagios.init
new file mode 100755
index 0000000..30448f9
--- /dev/null
+++ b/containers/nagios/nagios.init
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+exec ${NAGIOS_HOME}/bin/nagios ${NAGIOS_HOME}/etc/nagios.cfg
diff --git a/containers/nagios/postfix.init b/containers/nagios/postfix.init
new file mode 100755
index 0000000..29bf50b
--- /dev/null
+++ b/containers/nagios/postfix.init
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+: ${MAIL_SERVER=$MAIL_PORT_25_TCP_ADDR}
+
+
+sed -i "s/relayhost =.*/relayhost = ${MAIL_SERVER}/" /etc/postfix/main.cf
+sed -i "s/myhostname =.*/myhostname = `hostname`/" /etc/postfix/main.cf
+
+exec /usr/lib/postfix/master -d -c /etc/postfix
diff --git a/containers/nagios/postfix.stop b/containers/nagios/postfix.stop
new file mode 100755
index 0000000..50646e8
--- /dev/null
+++ b/containers/nagios/postfix.stop
@@ -0,0 +1 @@
+postfix stop
diff --git a/containers/nagios/slack_nagios.cfg b/containers/nagios/slack_nagios.cfg
new file mode 100644
index 0000000..8840c87
--- /dev/null
+++ b/containers/nagios/slack_nagios.cfg
@@ -0,0 +1,21 @@
+define contact {
+      contact_name                             slack
+      alias                                    Slack
+      service_notification_period              24x7
+      host_notification_period                 24x7
+      service_notification_options             w,u,c,r
+      host_notification_options                d,r
+      service_notification_commands            notify-service-by-slack
+      host_notification_commands               notify-host-by-slack
+}
+
+define command {
+      command_name     notify-service-by-slack
+      command_line     /usr/local/bin/slack_nagios.sh > /tmp/slack.log 2>&1
+}
+
+define command {
+      command_name     notify-host-by-slack
+      command_line     /usr/local/bin/slack_nagios.sh > /tmp/slack.log 2>&1
+}
+
diff --git a/containers/nagios/slack_nagios.sh b/containers/nagios/slack_nagios.sh
new file mode 100755
index 0000000..7c5e205
--- /dev/null
+++ b/containers/nagios/slack_nagios.sh
@@ -0,0 +1,46 @@
+#!/bin/bash
+
+# This script is used by Nagios to post alerts into a Slack channel
+# using the Incoming WebHooks integration. Create the channel, botname
+# and integration first and then add this notification script in your
+# Nagios configuration.
+#
+# All variables that start with NAGIOS_ are provided by Nagios as
+# environment variables when an notification is generated.
+# A list of the env variables is available here:
+#   http://nagios.sourceforge.net/docs/3_0/macrolist.html
+#
+# More info on Slack
+# Website: https://slack.com/
+# Twitter: @slackhq, @slackapi
+#
+# My info
+# Website: http://matthewcmcmillan.blogspot.com/
+# Twitter: @matthewmcmillan
+
+#Modify these variables for your environment
+MY_NAGIOS_HOSTNAME=""        # This server's hostname
+SLACK_HOSTNAME=""               
+SLACK_CHANNEL="#alerts"      
+SLACK_BOTNAME="nagios"
+WEBHOOK_URL=""               # Incomming webhook url for the slack account 
+
+#Set the message icon based on Nagios service state
+if [ "$NAGIOS_SERVICESTATE" = "CRITICAL" ]
+then
+    ICON=":exclamation:"
+elif [ "$NAGIOS_SERVICESTATE" = "WARNING" ]
+then
+    ICON=":warning:"
+elif [ "$NAGIOS_SERVICESTATE" = "OK" ]
+then
+    ICON=":white_check_mark:"
+elif [ "$NAGIOS_SERVICESTATE" = "UNKNOWN" ]
+then
+    ICON=":question:"
+else
+    ICON=":white_medium_square:"
+fi
+
+#Send message to Slack
+curl -X POST --data-urlencode "payload={\"channel\": \"${SLACK_CHANNEL}\", \"username\": \"${SLACK_USERNAME}\", \"text\": \"${ICON} HOST: ${MY_NAGIOS_HOSTNAME}   SERVICE: ${NAGIOS_SERVICEDISPLAYNAME}     MESSAGE: ${NAGIOS_SERVICEOUTPUT} <https://${MY_NAGIOS_HOSTNAME}/cgi-bin/nagios3/extinfo.cgi?type=1&host=${NAGIOS_HOSTNAME}|See Nagios>\"}" $WEBHOOK_URL
diff --git a/containers/nagios/start.sh b/containers/nagios/start.sh
new file mode 100755
index 0000000..f295e5b
--- /dev/null
+++ b/containers/nagios/start.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+if [ ! -f ${NAGIOS_HOME}/etc/htpasswd.users ] ; then
+  htpasswd -c -b -s ${NAGIOS_HOME}/etc/htpasswd.users ${NAGIOSADMIN_USER} ${NAGIOSADMIN_PASS}
+  chown -R nagios.nagios ${NAGIOS_HOME}/etc/htpasswd.users
+fi
+
+exec runsvdir /etc/sv
+
+/etc/init.d/apache2 start
diff --git a/containers/onboarding_synchronizer/Dockerfile b/containers/onboarding_synchronizer/Dockerfile
new file mode 100644
index 0000000..b86cbb1
--- /dev/null
+++ b/containers/onboarding_synchronizer/Dockerfile
@@ -0,0 +1,48 @@
+FROM       xosproject/xos-synchronizer-openstack
+
+# Install docker-in-docker (dind). See https://hub.docker.com/_/docker/. The docker git repo
+# currently only has 1.10 and 1.11, but it's possible to get the dockerfiles for earlier
+# versions by using:
+#        docker pull centurylink/dockerfile-from-image
+#        alias dfimage="docker run -v /var/run/docker.sock:/var/run/docker.sock --rm centurylink/dockerfile-from-image"
+#        dgimage <name of image>
+
+# This container must be started in privileged mode. 
+
+RUN apt-get install -y curl
+
+# XXX version 1.10.3
+ENV DOCKER_BUCKET get.docker.com
+ENV DOCKER_VERSION 1.10.3

+ENV DOCKER_SHA256 d0df512afa109006a450f41873634951e19ddabf8c7bd419caeb5a526032d86d

+RUN curl -fSL "https://${DOCKER_BUCKET}/builds/Linux/x86_64/docker-$DOCKER_VERSION" -o /usr/local/bin/docker && echo "${DOCKER_SHA256}  /usr/local/bin/docker" | sha256sum -c - && chmod +x /usr/local/bin/docker

+
+# XXX vserioin 1.8.3
+#ENV DOCKER_BUCKET=get.docker.com
+#ENV DOCKER_VERSION=1.8.3
+#ENV DOCKER_SHA256=f024bc65c45a3778cf07213d26016075e8172de8f6e4b5702bedde06c241650f
+#RUN curl -fSL "https://${DOCKER_BUCKET}/builds/Linux/x86_64/docker-$DOCKER_VERSION" -o /usr/local/bin/docker && echo "${DOCKER_SHA256} /usr/local/bin/docker" | sha256sum -c - && chmod +x /usr/local/bin/docker
+
+# XXX version 1.8.3
+# XXX uncomment the following 6 lines to run docker-in-docker
+#     comment them out if using the docker socket in a volume instead
+#ENV DIND_COMMIT=3b5fac462d21ca164b3778647420016315289034
+#RUN wget "https://raw.githubusercontent.com/docker/docker/${DIND_COMMIT}/hack/dind" -O /usr/local/bin/dind && chmod +x /usr/local/bin/dind
+#COPY start-dockerd.sh /usr/local/bin/
+#VOLUME /var/lib/docker
+#EXPOSE 2375
+#ENTRYPOINT ["start-dockerd.sh"]
+
+# Instead of using docker-in-docker, we can just attach ourselves
+# to the docker socket via a volume in the docker-compose:
+#     - /var/run/docker.sock:/var/run/docker.sock
+# This is more convenient, allowing us to build directly into our
+# parent's docker build system, making the images available for
+# instantiation on the parent. 
+
+# Now install docker-compose
+
+RUN bash -c "curl -L https://github.com/docker/compose/releases/download/1.5.2/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose"
+RUN chmod +x /usr/local/bin/docker-compose
+
+CMD update-ca-certificates && /usr/bin/supervisord -c /etc/supervisor/conf.d/synchronizer.conf
diff --git a/containers/onboarding_synchronizer/Makefile b/containers/onboarding_synchronizer/Makefile
new file mode 100644
index 0000000..6532196
--- /dev/null
+++ b/containers/onboarding_synchronizer/Makefile
@@ -0,0 +1,15 @@
+IMAGE_NAME:=xosproject/xos-synchronizer-onboarding
+CONTAINER_NAME:=xos-synchronizer
+NO_DOCKER_CACHE?=false
+
+.PHONY: build
+build: ; sudo docker build --no-cache=${NO_DOCKER_CACHE} --rm -t ${IMAGE_NAME} .
+
+.PHONY: run
+run: ; sudo docker run -d --name ${CONTAINER_NAME} -v /usr/local/share/ca-certificates:/usr/local/share/ca-certificates:ro ${IMAGE_NAME}
+
+.PHONY: stop
+stop: ; sudo docker stop ${CONTAINER_NAME}
+
+.PHONY: rm
+rm: ; sudo docker rm ${CONTAINER_NAME}
diff --git a/containers/onboarding_synchronizer/start-dockerd.sh b/containers/onboarding_synchronizer/start-dockerd.sh
new file mode 100755
index 0000000..bb97341
--- /dev/null
+++ b/containers/onboarding_synchronizer/start-dockerd.sh
@@ -0,0 +1,3 @@
+#! /bin/bash
+
+docker daemon --host=unix:///var/run/docker.sock --host=tcp://0.0.0.0:2375 --storage-driver=aufs
diff --git a/containers/onos/Dockerfile b/containers/onos/Dockerfile
new file mode 100644
index 0000000..d00b8e2
--- /dev/null
+++ b/containers/onos/Dockerfile
@@ -0,0 +1,57 @@
+FROM debian:jessie
+MAINTAINER Zack Williams <zdw@cs.arizona.edu>
+
+# Add Java 8 repository
+ENV DEBIAN_FRONTEND noninteractive
+RUN echo debconf shared/accepted-oracle-license-v1-1 select true | debconf-set-selections && \
+    echo "deb http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main" | tee /etc/apt/sources.list.d/webupd8team-java.list && \
+    echo "deb-src http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main" | tee -a /etc/apt/sources.list.d/webupd8team-java.list && \
+    apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys EEA14886
+
+# Set the environment variables
+ENV HOME /root
+ENV JAVA_HOME /usr/lib/jvm/java-8-oracle
+ENV ONOS_ROOT /src/onos
+ENV KARAF_VERSION 3.0.5
+ENV KARAF_ROOT /root/onos/apache-karaf-3.0.5
+ENV KARAF_LOG /root/onos/apache-karaf-3.0.5/data/log/karaf.log
+ENV BUILD_NUMBER docker
+ENV PATH $PATH:$KARAF_ROOT/bin
+
+#Download and Build ONOS
+WORKDIR /src
+RUN     apt-get update && apt-get install -y python maven git curl oracle-java8-installer oracle-java8-set-default && \
+        git clone https://github.com/opennetworkinglab/onos.git && cd onos && \
+        git checkout f503a62372ffa55150936628689d1435109ffccb && \
+        mkdir -p /root/Downloads && \
+        mvn clean install && \
+        tools/build/onos-package && \
+        rm -rf /root/.m2 && cd .. && \
+        rm -rf onos && \
+        apt-get remove --purge -y `apt-mark showauto` && \
+        apt-get install oracle-java8-set-default -y && \
+        apt-get clean && apt-get purge -y && apt-get autoremove -y && \
+        rm -rf /var/lib/apt/lists/* && \
+        rm -rf /var/cache/oracle-jdk8-installer && \
+        rm -rf /root/Downloads
+
+# Change to /root directory
+WORKDIR /root
+
+#Install ONOS
+RUN mkdir onos && \
+   mv /tmp/onos-*.docker.tar.gz . && \
+   tar -xf onos-*.docker.tar.gz -C onos --strip-components=1 && \
+   rm -rf onos-*.docker.tar.gz
+
+# Ports
+# 6653 - OpenFlow
+# 8181 - GUI
+# 8101 - ONOS CLI
+# 9876 - ONOS CLUSTER COMMUNICATION
+EXPOSE 6653 8181 8101 9876
+
+# Get ready to run command
+WORKDIR /root/onos
+ENTRYPOINT ["./bin/onos-service"]
+
diff --git a/containers/onos/Makefile b/containers/onos/Makefile
new file mode 100644
index 0000000..4db1a9b
--- /dev/null
+++ b/containers/onos/Makefile
@@ -0,0 +1,15 @@
+IMAGE_NAME:=xosproject/onos-fork
+CONTAINER_NAME:=onos-fork
+NO_DOCKER_CACHE?=false
+
+.PHONY: build
+build: ; sudo docker build --no-cache=${NO_DOCKER_CACHE} --rm -t ${IMAGE_NAME} .
+
+.PHONY: run
+run: ; sudo docker run -d --name ${CONTAINER_NAME} ${IMAGE_NAME}
+
+.PHONY: stop
+stop: ; sudo docker stop ${CONTAINER_NAME}
+
+.PHONY: rm
+rm: ; sudo docker rm ${CONTAINER_NAME}
diff --git a/containers/openvpn/Dockerfile b/containers/openvpn/Dockerfile
new file mode 100644
index 0000000..8ae8484
--- /dev/null
+++ b/containers/openvpn/Dockerfile
@@ -0,0 +1,12 @@
+FROM       xosproject/xos-synchronizer-openstack
+
+RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y \
+    openvpn
+
+# for OpenVPN
+RUN mkdir -p /opt/openvpn
+RUN chmod 777 /opt/openvpn
+RUN git clone https://github.com/OpenVPN/easy-rsa.git /opt/openvpn
+RUN git -C /opt/openvpn pull origin master
+RUN echo 'set_var EASYRSA	"/opt/openvpn/easyrsa3"' | tee /opt/openvpn/vars
+RUN echo 'set_var EASYRSA_BATCH	"true"' | tee -a /opt/openvpn/vars
diff --git a/containers/openvpn/Makefile b/containers/openvpn/Makefile
new file mode 100644
index 0000000..bdfb126
--- /dev/null
+++ b/containers/openvpn/Makefile
@@ -0,0 +1,18 @@
+IMAGE_NAME:=xosproject/xos-openvpn
+CONTAINER_NAME:=xos-synchronizer
+NO_DOCKER_CACHE?=true
+
+.PHONY: build
+build: ; sudo docker build --no-cache=${NO_DOCKER_CACHE} --rm -t ${IMAGE_NAME} .
+
+.PHONY: run
+run: ; sudo docker run -d --name ${CONTAINER_NAME} -v /usr/local/share/ca-certificates:/usr/local/share/ca-certificates:ro ${IMAGE_NAME}
+
+.PHONY: stop
+stop: ; sudo docker stop ${CONTAINER_NAME}
+
+.PHONY: rm
+rm: ; sudo docker rm ${CONTAINER_NAME}
+
+.PHONY: rmi
+rmi: ; docker rmi ${IMAGE_NAME}
diff --git a/containers/openvpn/conf/ansible-hosts b/containers/openvpn/conf/ansible-hosts
new file mode 100644
index 0000000..0dd74f1
--- /dev/null
+++ b/containers/openvpn/conf/ansible-hosts
@@ -0,0 +1,2 @@
+[localhost]
+127.0.0.1
diff --git a/containers/openvpn/conf/synchronizer.conf b/containers/openvpn/conf/synchronizer.conf
new file mode 100644
index 0000000..2131a25
--- /dev/null
+++ b/containers/openvpn/conf/synchronizer.conf
@@ -0,0 +1,9 @@
+[supervisord]
+logfile=/var/log/supervisord.log ; (main log file;default $CWD/supervisord.log)
+pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid)
+nodaemon=true
+
+[program:synchronizer]
+command=python /opt/xos/synchronizers/openstack/xos-synchronizer.py
+stderr_logfile=/var/log/supervisor/synchronizer.err.log
+stdout_logfile=/var/log/supervisor/synchronizer.out.log
diff --git a/containers/postgresql/Dockerfile b/containers/postgresql/Dockerfile
new file mode 100644
index 0000000..4d4ebfd
--- /dev/null
+++ b/containers/postgresql/Dockerfile
@@ -0,0 +1,35 @@
+FROM ubuntu
+
+RUN apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys B97B0AFCAA1A47F044F244A07FCC7D46ACCC4CF8
+
+RUN echo "deb http://apt.postgresql.org/pub/repos/apt/ precise-pgdg main" > /etc/apt/sources.list.d/pgdg.list
+
+RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y --force-yes\
+    python-software-properties \
+    software-properties-common \
+    postgresql-9.3 \
+    postgresql-client-9.3 \
+    postgresql-contrib-9.3
+
+# Workaround for AUFS issue
+# https://github.com/docker/docker/issues/783#issuecomment-56013588
+RUN mkdir /etc/ssl/private-copy; mv /etc/ssl/private/* /etc/ssl/private-copy/; rm -r /etc/ssl/private; mv /etc/ssl/private-copy /etc/ssl/private; chmod -R 0700 /etc/ssl/private; chown -R postgres /etc/ssl/private
+
+USER postgres
+
+RUN /etc/init.d/postgresql start && \
+    psql --command "ALTER USER postgres WITH SUPERUSER PASSWORD 'password' " && \
+    psql --command "CREATE DATABASE xos"
+
+# Allow remote connections. 
+RUN echo "host all  all    0.0.0.0/0  md5" >> /etc/postgresql/9.3/main/pg_hba.conf
+RUN echo "host all  all    0.0.0.0/0  password" >> /etc/postgresql/9.3/main/pg_hba.conf
+
+RUN echo "listen_addresses='*'" >> /etc/postgresql/9.3/main/postgresql.conf
+
+# Expose the PostgreSQL port
+EXPOSE 5432
+
+VOLUME  ["/etc/postgresql", "/var/log/postgresql", "/var/lib/postgresql"]
+
+CMD ["/usr/lib/postgresql/9.3/bin/postgres", "-D", "/var/lib/postgresql/9.3/main", "-c", "config_file=/etc/postgresql/9.3/main/postgresql.conf"]
diff --git a/containers/postgresql/Makefile b/containers/postgresql/Makefile
new file mode 100644
index 0000000..8f483f8
--- /dev/null
+++ b/containers/postgresql/Makefile
@@ -0,0 +1,25 @@
+IMAGE_NAME:=xosproject/xos-postgres
+CONTAINER_NAME:=xos-db-postgres
+NO_DOCKER_CACHE?=false
+
+.PHONY: build
+build: ; docker build --no-cache=${NO_DOCKER_CACHE} --rm -t ${IMAGE_NAME} .
+
+.PHONY: run
+run: ; docker run -d -p 5432:5432 --name ${CONTAINER_NAME} ${IMAGE_NAME}
+
+.PHONY: stop
+stop: ; docker stop ${CONTAINER_NAME}
+
+.PHONY: rm
+rm: ; docker rm ${CONTAINER_NAME}
+
+.PHONY: rmi
+rmi: ; docker rmi ${IMAGE_NAME}
+
+.PHONY: backup
+backupvol: ; docker run --volumes-from ${CONTAINER_NAME} -v /backup:/backup postgres tar cvf /backup/backup-postgres.tar /var/lib/postgresql
+
+.PHONY: restore
+restorevol: ; docker run --volumes-from ${CONTAINER_NAME} -v /backup:/backup postgres cd /var/lib/postgresql && tar xvf /backup/backup-postgres.tar
+
diff --git a/containers/setup.yaml b/containers/setup.yaml
new file mode 100644
index 0000000..c13f0eb
--- /dev/null
+++ b/containers/setup.yaml
@@ -0,0 +1,61 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+    * Adds OpenCloud Sites, Deployments, and Controllers.
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+
+    MyDeployment:
+      type: tosca.nodes.Deployment
+      properties:
+          flavors: m1.large, m1.medium, m1.small
+
+    MyOpenStack:
+      type: tosca.nodes.Controller
+      requirements:
+          - deployment:
+              node: MyDeployment
+              relationship: tosca.relationships.ControllerDeployment
+      properties:
+          backend_type: OpenStack
+          version: Kilo
+          auth_url: { get_script_env: [ SELF, adminrc, OS_AUTH_URL, LOCAL_FILE] }
+          admin_user: { get_script_env: [ SELF, adminrc, OS_USERNAME, LOCAL_FILE] }
+          admin_password: { get_script_env: [ SELF, adminrc, OS_PASSWORD, LOCAL_FILE] }
+          admin_tenant: { get_script_env: [ SELF, adminrc, OS_TENANT_NAME, LOCAL_FILE] }
+          domain: Default
+      artifacts:
+          adminrc: /root/setup/admin-openrc.sh
+
+    mysite:
+      type: tosca.nodes.Site
+      properties:
+          display_name: MySite
+          site_url: http://xosproject.org/
+      requirements:
+          - deployment:
+               node: MyDeployment
+               relationship: tosca.relationships.SiteDeployment
+               requirements:
+                   - controller:
+                       node: MyOpenStack
+                       relationship: tosca.relationships.UsesController
+
+    # This user already exists in XOS with this password
+    # It's an example of how to create new users
+    padmin@vicci.org:
+      type: tosca.nodes.User
+      requirements:
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+      properties:
+          is_admin: true
+          is_active: true
+          firstname: XOS
+          lastname: admin
+          password: letmein
diff --git a/containers/synchronizer/Dockerfile b/containers/synchronizer/Dockerfile
new file mode 100644
index 0000000..2f1e092
--- /dev/null
+++ b/containers/synchronizer/Dockerfile
@@ -0,0 +1,6 @@
+FROM       xosproject/xos
+
+# Supervisor
+COPY conf/synchronizer.conf /etc/supervisor/conf.d/
+
+CMD /usr/bin/supervisord -c /etc/supervisor/conf.d/synchronizer.conf
diff --git a/containers/synchronizer/Makefile b/containers/synchronizer/Makefile
new file mode 100644
index 0000000..352616a
--- /dev/null
+++ b/containers/synchronizer/Makefile
@@ -0,0 +1,15 @@
+IMAGE_NAME:=xosproject/xos-synchronizer-openstack
+CONTAINER_NAME:=xos-synchronizer
+NO_DOCKER_CACHE?=false
+
+.PHONY: build
+build: ; sudo docker build --no-cache=${NO_DOCKER_CACHE} --rm -t ${IMAGE_NAME} .
+
+.PHONY: run
+run: ; sudo docker run -d --name ${CONTAINER_NAME} -v /usr/local/share/ca-certificates:/usr/local/share/ca-certificates:ro ${IMAGE_NAME}
+
+.PHONY: stop
+stop: ; sudo docker stop ${CONTAINER_NAME}
+
+.PHONY: rm
+rm: ; sudo docker rm ${CONTAINER_NAME}
diff --git a/containers/synchronizer/conf/ansible-hosts b/containers/synchronizer/conf/ansible-hosts
new file mode 100644
index 0000000..0dd74f1
--- /dev/null
+++ b/containers/synchronizer/conf/ansible-hosts
@@ -0,0 +1,2 @@
+[localhost]
+127.0.0.1
diff --git a/containers/synchronizer/conf/synchronizer.conf b/containers/synchronizer/conf/synchronizer.conf
new file mode 100644
index 0000000..2131a25
--- /dev/null
+++ b/containers/synchronizer/conf/synchronizer.conf
@@ -0,0 +1,9 @@
+[supervisord]
+logfile=/var/log/supervisord.log ; (main log file;default $CWD/supervisord.log)
+pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid)
+nodaemon=true
+
+[program:synchronizer]
+command=python /opt/xos/synchronizers/openstack/xos-synchronizer.py
+stderr_logfile=/var/log/supervisor/synchronizer.err.log
+stdout_logfile=/var/log/supervisor/synchronizer.out.log
diff --git a/containers/syndicate-ms/Dockerfile b/containers/syndicate-ms/Dockerfile
new file mode 100644
index 0000000..e74db92
--- /dev/null
+++ b/containers/syndicate-ms/Dockerfile
@@ -0,0 +1,51 @@
+# Syndicate Metadata Server
+# See also https://github.com/syndicate-storage/syndicate-docker
+
+FROM ubuntu:14.04.4
+MAINTAINER Zack Williams <zdw@cs.arizona.edu>
+
+# vars
+ENV APT_KEY butler_opencloud_cs_arizona_edu_pub.gpg
+ENV MS_PORT 8080
+ENV GAE_SDK google_appengine_1.9.35.zip
+
+# Prep apt to be able to download over https
+RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y --force-yes\
+    apt-transport-https
+
+# copy over and trust https cert
+COPY butler.crt /usr/local/share/ca-certificates
+RUN update-ca-certificates
+
+# Install Syndicate MS
+COPY $APT_KEY /tmp/
+RUN apt-key add /tmp/$APT_KEY
+
+RUN echo "deb https://butler.opencloud.cs.arizona.edu/repos/release/syndicate syndicate main" > /etc/apt/sources.list.d/butler.list
+
+RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y --force-yes\
+    syndicate-core \
+    syndicate-ms \
+    wget \
+    unzip
+
+# setup syndicate user
+RUN groupadd -r syndicate && useradd -m -r -g syndicate syndicate
+USER syndicate
+ENV HOME /home/syndicate
+WORKDIR $HOME
+
+# setup GAE
+RUN wget -nv https://storage.googleapis.com/appengine-sdks/featured/$GAE_SDK
+RUN unzip -q $GAE_SDK
+
+# Expose the MS port
+EXPOSE $MS_PORT
+
+# Create a storage location
+RUN mkdir $HOME/datastore
+
+# run the MS under GAE
+CMD $HOME/google_appengine/dev_appserver.py --admin_host=0.0.0.0 --host=0.0.0.0 --storage_path=$HOME/datastore --skip_sdk_update_check=true /usr/src/syndicate/ms
+
+
diff --git a/containers/syndicate-ms/Makefile b/containers/syndicate-ms/Makefile
new file mode 100644
index 0000000..2c24afc
--- /dev/null
+++ b/containers/syndicate-ms/Makefile
@@ -0,0 +1,19 @@
+IMAGE_NAME:=xosproject/syndicate-ms
+CONTAINER_NAME:=xos-syndicate-ms
+NO_DOCKER_CACHE?=false
+
+.PHONY: build
+build: ; docker build --no-cache=${NO_DOCKER_CACHE} --rm -t ${IMAGE_NAME} .
+
+.PHONY: run
+run: ; docker run -d -p 8080:8080 --name ${CONTAINER_NAME} ${IMAGE_NAME}
+
+.PHONY: stop
+stop: ; docker stop ${CONTAINER_NAME}
+
+.PHONY: rm
+rm: ; docker rm ${CONTAINER_NAME}
+
+.PHONY: rmi
+rmi: ; docker rmi ${IMAGE_NAME}
+
diff --git a/containers/syndicate-ms/butler.crt b/containers/syndicate-ms/butler.crt
new file mode 100644
index 0000000..be60161
--- /dev/null
+++ b/containers/syndicate-ms/butler.crt
@@ -0,0 +1,37 @@
+-----BEGIN CERTIFICATE-----
+MIIGgjCCBWqgAwIBAgIRAJ26ZC+oEixlqDU7+7cazpIwDQYJKoZIhvcNAQELBQAw
+djELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAk1JMRIwEAYDVQQHEwlBbm4gQXJib3Ix
+EjAQBgNVBAoTCUludGVybmV0MjERMA8GA1UECxMISW5Db21tb24xHzAdBgNVBAMT
+FkluQ29tbW9uIFJTQSBTZXJ2ZXIgQ0EwHhcNMTYwMzIyMDAwMDAwWhcNMTkwMzIy
+MjM1OTU5WjCBqzELMAkGA1UEBhMCVVMxDjAMBgNVBBETBTg1NzIxMQswCQYDVQQI
+EwJBWjEPMA0GA1UEBxMGVHVjc29uMSIwIAYDVQQKExlUaGUgVW5pdmVyc2l0eSBv
+ZiBBcml6b25hMSAwHgYDVQQLExdDb21wdXRlciBTY2llbmNlICgwNDEyKTEoMCYG
+A1UEAxMfYnV0bGVyLm9wZW5jbG91ZC5jcy5hcml6b25hLmVkdTCCAiIwDQYJKoZI
+hvcNAQEBBQADggIPADCCAgoCggIBAKHUqBxVP6fvTm015n8hXfe53B2IHbMbkwCj
+6eqc2mak8PEVIoD1Ds2TlrvS6xWtFJfNdKlMTNQMh3dVjUC8xcB+OUdr1Q3qv9to
+qiUJC+kTnJNDtOqYqJzX9koH+tHD0zr5/cqyT4vLkJZJXiZ5NGKyHUeh9INTj/ZG
+yHHVrDiF5gUyNl7HrN53AMPpJAxO0rurN5tI3ozK8TE60sslVdxE5zWwnSGazS+0
+hcz7uIyDTpyuo8H6iA/F5L5/USLqAYHLTk10Hg/7vnbRMbaz6sdXPFm+gtZPm5mG
+L2P9I4GM6L/TBXL7+etUtPAgVMoYrdDGZ3wmWOrWukD6ax3BVaX+dJxFNUTju2MZ
+1By6nJIzBBezHE7j4dhjRDaGwsxmdvEjn8weoeWS8ngT3fnm6btFgzO0O2CC3QN9
+M6pk5kJGm8kyhcc8nX4gv/Tkl1gHAd9VNgEJPY3YFXWigtjK7fSYGe9GDQsploUG
+OubK5S8eelSej1u9XW/NgqdxwgQWmxeppWxSwWb4wVyunVX03UHFmk6XnSdtF54E
+iy8VIuItRYyZGni8gAyCx8z6ke2zd8+wWgzsjxQ3dHjbLFxV1O57ZyNyb8TuZ5hk
+0QoJqdR0X6EXc+z4+tV+yYQGQZ5L3vgz7REp3TnlgG8acp3JfZpH8gng05cX6sBi
+I+NbZEmPAgMBAAGjggHTMIIBzzAfBgNVHSMEGDAWgBQeBaN3j2yW4luHS6a0hqxx
+AAznODAdBgNVHQ4EFgQUDfCqsiaVDm70iLaq32jUEmKr9pIwDgYDVR0PAQH/BAQD
+AgWgMAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC
+MGcGA1UdIARgMF4wUgYMKwYBBAGuIwEEAwEBMEIwQAYIKwYBBQUHAgEWNGh0dHBz
+Oi8vd3d3LmluY29tbW9uLm9yZy9jZXJ0L3JlcG9zaXRvcnkvY3BzX3NzbC5wZGYw
+CAYGZ4EMAQICMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwuaW5jb21tb24t
+cnNhLm9yZy9JbkNvbW1vblJTQVNlcnZlckNBLmNybDB1BggrBgEFBQcBAQRpMGcw
+PgYIKwYBBQUHMAKGMmh0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9JbkNvbW1vblJT
+QVNlcnZlckNBXzIuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1
+c3QuY29tMCoGA1UdEQQjMCGCH2J1dGxlci5vcGVuY2xvdWQuY3MuYXJpem9uYS5l
+ZHUwDQYJKoZIhvcNAQELBQADggEBACUaI/yYc0pxAuwIWi0985f06MdKEMJo+qEO
+YLXENApQrJhTPdV9OaChlzI4x2ExmffPZEmhyD0q7z57mT9QkBYQwEJqwbRqfY2v
+0iQ4nLLkyXh7SJSS7J4WSG+cFEN1nFZ8/YGg/TD8spEIPeUGsUvRoJmJm9z90uqd
++ETDc+79TZHxserOY3AJtlvzPScJa1HAqgDJGzgwGdUn82+bKZF5WGsGbfwUS6uS
+Ua2SsOxVZOn5ukF2g9vYs3dcO8u5ITAWrR1s6ACg/wGxvfvXwazpeiFx/RxilpcV
+6W7mTwbE76ZbkafrXbnZ6ihhIPARsVJhJsnClnf5OM7IqrX5g80=
+-----END CERTIFICATE-----
diff --git a/containers/syndicate-ms/butler_opencloud_cs_arizona_edu_pub.gpg b/containers/syndicate-ms/butler_opencloud_cs_arizona_edu_pub.gpg
new file mode 100644
index 0000000..92a2ae4
--- /dev/null
+++ b/containers/syndicate-ms/butler_opencloud_cs_arizona_edu_pub.gpg
@@ -0,0 +1,29 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1
+
+mQINBFb+uuwBEADgmbb2CPnQ2LofLdx5rJN4O75TAjYjJAPyyyIZL2bKmhhuRYwK
+a/gZAlOy5Y/4o5pRgG5s1BFkrSvWRIP+Y3D+PHz7wppjlo31NGm4+34stzlzGu4K
+EEUZpCiUiD1tCxX/H9jZTo5Dm2YvdLxnkWSkbf1ZkIzwNjM3bnYily2a/1NwMmqt
+18Hsy+3ivvUEZO0FmO2reP1l7Eb0hLR2QPxSA4/PxQ81+EJ3CObRYaUZ9KjgIRah
+eyP+PsXaFnxkoikGHod9ll2iWPzpkOUh+xXAu73YK4ikCrIUZ5Oe98Euja8h856H
+xiRRLGVL3iqzgAQJxG/0cXbiobN7bNYGlvLLyp+qRNbmgSYonsJxON4aVG+wjiLi
+gYCOQ/FQT0tYGeDprPBWRj6iGiic6K7W9BDXkxPqlYIYomMrjrqW5kX0YGMp+V7c
+2QG3yfh4+3pfpM+ZYfrAtCdgklYmCYBhoaieMrjIYw31PWqMuzxeb3xBS6++6ksH
+d9TlJKLgJ1UPiKLgDOEyIbYVWhPs2sQoRRstuKfPF9Gdv0UUAnqlyA8siVrvZfB2
+7D05PM4mv83GshoZ8ZAkV7uS6PFJIg6JM11dUM50LTfvHe7ig93CBvbFzm+RqxjQ
+JYf1XWd19912TW7NcNz6lg5jxEYLh8WYJin2xC2aLLb+hpy5NHE/Ien2aQARAQAB
+tCVPcGVuQ2xvdWQgQnV0bGVyIDxzaXRlc0BvcGVuY2xvdWQudXM+iQI9BBMBCgAn
+BQJW/rrsAhsDBQkDwmcABQsJCAcDBRUKCQgLBRYDAgEAAh4BAheAAAoJELvMx3QD
+/Cyyc2UQAIw2A8qrNMQt4skrR/87uKQjfJ/OXC7MEBDTLSL0Ed0VIuRrA/E1s1D/
+YJpdsFfKJyDbZ2Id25L+1QclvEjnsEDCIiURGcRmXLLsqjHCw4N2C16P2JasQVWo
+i1lkqUHC8kCzvR75u+agzpn16Qhb8FqLQxBSxd8vhMEw2LnrjRsjHGwErKhpYfOg
+LFXyurKKBb4KYOLortICgcE3Wz6eqgbNInrTMrSOSf5P7nsPINCFTyemzUyT53IU
+07RmJwTOrcgqJR5klghHQnFXJBkB55EMvFLjUrL4dpnAmlbkKhyFX8aRsBD5Frt2
+93LkHWDa35SELEzfIQznIsfok1rHgDR8kAh7m+tEbmn/Qk3llJ7c/r4JqG0RVGfe
+OfYZDT4I12H6ZWIoLjktnAP4QlDf+olILEYAD0PvKEQU7sQpMmex5QBMt6vvGAj6
+RfPn1iFhUZdOPB7GyWtUn8hmBCEfLAoAAntgoW9NC+PI/chFrm6Nugjz60TbMMOd
+i4s5J998AuJeF2RJogIi61a4VYcprSMTkF5b8kxBhV4N4J5jJQEQxo3ztdw7USvj
+ce8/3/69mBT7rIXgk39FvqnSIz9SmyQ+wgLb94Gcpy1id64yab2P1LNm3pORafSN
+F59uVqgEv5W2g/frt5QMSBO06dvzNjStIV7/uxlOHuSNooIClr//
+=JFDF
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/containers/xos/Dockerfile b/containers/xos/Dockerfile
new file mode 100644
index 0000000..cbaad65
--- /dev/null
+++ b/containers/xos/Dockerfile
@@ -0,0 +1,26 @@
+FROM xosproject/xos-base
+
+# Include certificates from Openstack
+ADD local_certs.crt /usr/local/share/ca-certificates/local_certs.crt
+RUN update-ca-certificates
+
+# Install and boostrap XOS and Tosca
+ENV XOS_GIT_REPO git://github.com/open-cloud/xos.git
+ENV XOS_GIT_BRANCH master
+
+RUN git clone $XOS_GIT_REPO -b $XOS_GIT_BRANCH /tmp/xos && \
+    mv /tmp/xos/xos /opt/ && \
+    chmod +x /opt/xos/tools/xos-manage && \
+    /opt/xos/tools/xos-manage genkeys
+
+EXPOSE 8000
+
+# Set environment variables
+ENV HOME /root
+
+# Define working directory
+WORKDIR /opt/xos
+
+# Define default command
+CMD python /opt/xos/manage.py runserver 0.0.0.0:8000 --insecure --makemigrations
+
diff --git a/containers/xos/Dockerfile.base b/containers/xos/Dockerfile.base
new file mode 100644
index 0000000..e653b5a
--- /dev/null
+++ b/containers/xos/Dockerfile.base
@@ -0,0 +1,142 @@
+# Dockerfile.base
+# This image isn't used, but installs the prereqs for the other XOS images
+
+FROM       ubuntu:14.04.3
+
+# XXX Workaround for docker bug:
+# https://github.com/docker/docker/issues/6345
+# Kernel 3.15 breaks docker, uss the line below as a workaround
+# until there is a fix
+RUN ln -s -f /bin/true /usr/bin/chfn
+# XXX End workaround
+
+# Install apt packages
+RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y \
+    apt-transport-https \
+    curl \
+    gcc \
+    geoip-database \
+    git \
+    graphviz \
+    graphviz-dev \
+    libgeoip1 \
+    libxslt1-dev \
+    libxslt1.1 \
+    libyaml-dev \
+    m4 \
+    openssh-client \
+    pkg-config \
+    python-ceilometerclient \
+    python-crypto \
+    python-dev \
+    python-glanceclient \
+    python-httplib2 \
+    python-jinja2 \
+    python-keystoneclient \
+    python-neutronclient \
+    python-novaclient \
+    python-paramiko \
+    python-pip \
+    python-psycopg2 \
+    python-pycurl \
+    python-setuptools \
+    python-yaml \
+    rsync \
+    supervisor \
+    tar \
+    wget \
+ && rm -rf /var/lib/apt/lists/*
+
+# Install python pacakges with pip
+RUN pip install \
+    django==1.7 \
+    django-bitfield \
+    django-crispy-forms \
+    django-encrypted-fields \
+    django-extensions \
+    django-filter==0.11.0 \
+    django-geoposition \
+    django-ipware \
+    django_rest_swagger \
+    django-suit==0.3a1 \
+    django-timezones \
+    djangorestframework==3.3.3 \
+    dnslib \
+    jinja2 \
+    lxml \
+    markdown \
+    netaddr \
+    pyOpenSSL \
+    psycopg2 \
+    python-ceilometerclient \
+    python-dateutil \
+    python-keyczar \
+    python-logstash \
+    pygraphviz \
+    pytz \
+    pyyaml \
+    requests
+
+# Upgrade jinja2
+RUN pip install -U \
+    jinja2
+
+# Installs with Easy install (should be incorporated into pip?)
+RUN easy_install --upgrade httplib2
+
+RUN easy_install \
+    python_gflags \
+    google_api_python_client \
+    httplib2.ca_certs_locater
+
+# jQuery download w/checksum
+ENV JQUERY_VERSION jquery-1.9.1.min.js
+ENV JQUERY_DL_URL http://code.jquery.com/jquery-1.9.1.min.js
+ENV JQUERY_SHA256 c12f6098e641aaca96c60215800f18f5671039aecf812217fab3c0d152f6adb4
+
+RUN wget $JQUERY_DL_URL && \
+  echo "$JQUERY_SHA256  $JQUERY_VERSION" | sha256sum -c - && \
+  mv $JQUERY_VERSION /usr/local/lib/python2.7/dist-packages/suit/static/suit/js/
+
+# Install heat-translator for TOSCA support
+ENV HT_REPO_URL https://github.com/openstack/heat-translator.git
+ENV HT_REF a951b93c16e54046ed2d233d814860181c772e30
+
+RUN git clone $HT_REPO_URL /tmp/heat-translator && \
+    cd /tmp/heat-translator && \
+    git checkout $HT_REF && \
+    mkdir -p /opt/tosca && \
+    mv /tmp/heat-translator/translator /opt/tosca/translator && \
+    echo > /opt/tosca/translator/__init__.py && \
+    rm -rf /tmp/heat-translator
+
+# Install custom Ansible
+RUN \
+    git clone -b release1.8.2 git://github.com/ansible/ansible.git /opt/ansible && \
+    git clone -b release1.8.2 git://github.com/ansible/ansible-modules-extras.git /opt/ansible/lib/ansible/modules/extras && \
+    git clone -b release1.8.2 git://github.com/ansible/ansible-modules-extras.git /opt/ansible/v2/ansible/modules/extras && \
+    git clone git://github.com/sb98052/ansible-modules-core.git /opt/ansible/lib/ansible/modules/core && \
+    git clone git://github.com/sb98052/ansible-modules-core.git /opt/ansible/v2/ansible/modules/core && \
+    # git clone uses cached copy, doesn't pick up latest
+    git -C /opt/ansible pull && \
+    git -C /opt/ansible/lib/ansible/modules/core pull && \
+    git -C /opt/ansible/v2/ansible/modules/core pull && \
+    mkdir -p /usr/local/share /bin /etc/ansible
+
+COPY ansible-hosts /etc/ansible/hosts
+
+# For Synchronizer
+# ENV PHANTOMJS_DL_URL http://phantomjs.googlecode.com/files/phantomjs-1.7.0-linux-x86_64.tar.bz2
+# ENV PHANTOMJS_SHA256 a7658f5f2d9464f86891afdb979eb60b754d5f404801db624368ac11e16724d4
+
+# RUN curl -fLsS $PHANTOMJS_DL_URL -o phantomjs.tar.bz2 && \
+#  echo "$PHANTOMJS_SHA256  phantomjs.tar.bz2" | sha256sum -c - && \
+#  tar -C /usr/local/share -xjf phantomjs.tar.bz2 && \
+#  ln -s /usr/local/share/phantomjs-* /usr/local/share/phantomjs && \
+#  ln -s /usr/local/share/phantomjs/bin/phantomjs /bin/phantomjs && \
+#  rm phantomjs.tar.bz2
+
+#RUN git clone git://git.planet-lab.org/fofum.git /tmp/fofum && \
+#    cd /tmp/fofum; python setup.py install && \
+#    rm -rf /tmp/fofum
+
diff --git a/containers/xos/Dockerfile.devel b/containers/xos/Dockerfile.devel
new file mode 100644
index 0000000..6d1c510
--- /dev/null
+++ b/containers/xos/Dockerfile.devel
@@ -0,0 +1,23 @@
+FROM xosproject/xos-base
+
+# Include certificates from Openstack
+ADD containers/xos/local_certs.crt /usr/local/share/ca-certificates/local_certs.crt
+RUN update-ca-certificates
+
+# Install XOS
+ADD xos /opt/xos
+
+RUN chmod +x /opt/xos/tools/xos-manage && sync && \
+    /opt/xos/tools/xos-manage genkeys
+
+EXPOSE 8000
+
+# Set environment variables
+ENV HOME /root
+
+# Define working directory
+WORKDIR /opt/xos
+
+# Define default command
+CMD python /opt/xos/manage.py runserver 0.0.0.0:8000 --insecure --makemigrations
+
diff --git a/containers/xos/Dockerfile.test b/containers/xos/Dockerfile.test
new file mode 100644
index 0000000..ac3c14c
--- /dev/null
+++ b/containers/xos/Dockerfile.test
@@ -0,0 +1,17 @@
+FROM       xosproject/xos
+
+# install nodejs
+COPY containers/xos/nodesource.gpg.key /tmp/nodesource.gpg.key
+
+RUN apt-key add /tmp/nodesource.gpg.key && \
+    echo "deb https://deb.nodesource.com/node_4.x trusty main" \
+    > /etc/apt/sources.list.d/nodesource.list
+
+RUN apt-get update && apt-get install -y --force-yes nodejs && \
+    rm -rf /var/lib/apt/lists/*
+
+RUN node -v
+
+# install node modules
+# RUN cd /opt/xos/tests/api; npm install
+
diff --git a/containers/xos/Makefile b/containers/xos/Makefile
new file mode 100644
index 0000000..1f856b7
--- /dev/null
+++ b/containers/xos/Makefile
@@ -0,0 +1,63 @@
+# Docker container Makefile for XOS
+#
+# Targets:
+#
+#  `base`   - XOS prerequistie files, no XOS code, builds xosproject/xos-base
+#  `build`  - base + XOS code, git pulled in Dockerfile from main repo,
+#             builds xosproject/xos
+#  `custom` - base + XOS code, git pulled in Dockerfile from selectable repo,
+#             builds xosproject/xos
+#  `devel`  - base + XOS code from local directory, builds xosproject/xos
+#  `test`   - xosproject/xos + nodejs testing frameworks, builds
+#             xosproject/xos-test
+#
+
+NO_DOCKER_CACHE    ?= false
+
+CONTAINER_NAME     ?= xos-server
+IMAGE_NAME         ?= xosproject/xos
+
+XOS_GIT_REPO       ?= git://github.com/open-cloud/xos.git
+XOS_GIT_BRANCH     ?= master
+
+TOSCA_CONFIG_PATH  ?= /opt/xos/configurations/opencloud/opencloud.yaml
+
+base:
+	sudo docker build --no-cache=${NO_DOCKER_CACHE} --rm \
+	-f Dockerfile.base -t xosproject/xos-base .
+
+build:
+	sudo docker build --no-cache=${NO_DOCKER_CACHE} --rm \
+	-f Dockerfile -t ${IMAGE_NAME} .
+
+custom:
+	docker build --no-cache=${NO_DOCKER_CACHE} --rm \
+	--build-arg XOS_GIT_REPO=${XOS_GIT_REPO} \
+	--build-arg XOS_GIT_BRANCH=${XOS_GIT_BRANCH} \
+	-f Dockerfile -t ${IMAGE_NAME} .
+
+devel:
+	sudo docker build --no-cache=${NO_DOCKER_CACHE} --rm \
+	-f Dockerfile.devel -t ${IMAGE_NAME} ../..
+
+test:
+	sudo docker build --no-cache=${NO_DOCKER_CACHE} --rm \
+	-f Dockerfile.test -t xosproject/xos-test ../..
+
+run:
+	sudo docker run -d --name ${CONTAINER_NAME} -p 80:8000 \
+	${IMAGE_NAME}
+
+runtosca:
+	sudo docker exec -it ${CONTAINER_NAME} \
+  /usr/bin/python /opt/xos/tosca/run.py padmin@vicci.org ${TOSCA_CONFIG_PATH}
+
+stop:
+	sudo docker stop ${CONTAINER_NAME}
+
+rm:
+	sudo docker rm ${CONTAINER_NAME}
+
+rmi:
+	sudo docker rmi `docker images | grep "^<none>" | awk '{print $$3}'`
+
diff --git a/containers/xos/ansible-hosts b/containers/xos/ansible-hosts
new file mode 100644
index 0000000..0dd74f1
--- /dev/null
+++ b/containers/xos/ansible-hosts
@@ -0,0 +1,2 @@
+[localhost]
+127.0.0.1
diff --git a/containers/xos/initdb b/containers/xos/initdb
new file mode 100755
index 0000000..b90a570
--- /dev/null
+++ b/containers/xos/initdb
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+IMAGE_NAME=xosproject/xos
+CONTAINER_NAME=xos_build_helper_$$
+DB_HOST=$(wget http://ipinfo.io/ip -qO -)
+
+# configure db host
+docker run -it --name=$CONTAINER_NAME $IMAGE_NAME sed -i '0,/host/{s/host=localhost/host='$DB_HOST'/}' /opt/xos/xos_configuration/xos_common_config
+docker commit $CONTAINER_NAME $IMAGE_NAME
+docker rm $CONTAINER_NAME
+
+# init db schema
+docker run -it --name=$CONTAINER_NAME $IMAGE_NAME /opt/xos/tools/xos-manage makemigrations
+# run overrides the CMD specifed in the Dockerfile, so we re-set the CMD in the final commit"
+docker commit --change="CMD python /opt/xos/manage.py runserver 0.0.0.0:8000 --insecure" $CONTAINER_NAME $IMAGE_NAME
+docker rm $CONTAINER_NAME
diff --git a/containers/xos/local_certs.crt b/containers/xos/local_certs.crt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/containers/xos/local_certs.crt
diff --git a/containers/xos/nodesource.gpg.key b/containers/xos/nodesource.gpg.key
new file mode 100644
index 0000000..1dc1d10
--- /dev/null
+++ b/containers/xos/nodesource.gpg.key
@@ -0,0 +1,52 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1
+Comment: GPGTools - https://gpgtools.org
+
+mQINBFObJLYBEADkFW8HMjsoYRJQ4nCYC/6Eh0yLWHWfCh+/9ZSIj4w/pOe2V6V+
+W6DHY3kK3a+2bxrax9EqKe7uxkSKf95gfns+I9+R+RJfRpb1qvljURr54y35IZgs
+fMG22Np+TmM2RLgdFCZa18h0+RbH9i0b+ZrB9XPZmLb/h9ou7SowGqQ3wwOtT3Vy
+qmif0A2GCcjFTqWW6TXaY8eZJ9BCEqW3k/0Cjw7K/mSy/utxYiUIvZNKgaG/P8U7
+89QyvxeRxAf93YFAVzMXhoKxu12IuH4VnSwAfb8gQyxKRyiGOUwk0YoBPpqRnMmD
+Dl7SdmY3oQHEJzBelTMjTM8AjbB9mWoPBX5G8t4u47/FZ6PgdfmRg9hsKXhkLJc7
+C1btblOHNgDx19fzASWX+xOjZiKpP6MkEEzq1bilUFul6RDtxkTWsTa5TGixgCB/
+G2fK8I9JL/yQhDc6OGY9mjPOxMb5PgUlT8ox3v8wt25erWj9z30QoEBwfSg4tzLc
+Jq6N/iepQemNfo6Is+TG+JzI6vhXjlsBm/Xmz0ZiFPPObAH/vGCY5I6886vXQ7ft
+qWHYHT8jz/R4tigMGC+tvZ/kcmYBsLCCI5uSEP6JJRQQhHrCvOX0UaytItfsQfLm
+EYRd2F72o1yGh3yvWWfDIBXRmaBuIGXGpajC0JyBGSOWb9UxMNZY/2LJEwARAQAB
+tB9Ob2RlU291cmNlIDxncGdAbm9kZXNvdXJjZS5jb20+iQI4BBMBAgAiBQJTmyS2
+AhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRAWVaCraFdigHTmD/9OKhUy
+jJ+h8gMRg6ri5EQxOExccSRU0i7UHktecSs0DVC4lZG9AOzBe+Q36cym5Z1di6JQ
+kHl69q3zBdV3KTW+H1pdmnZlebYGz8paG9iQ/wS9gpnSeEyx0Enyi167Bzm0O4A1
+GK0prkLnz/yROHHEfHjsTgMvFwAnf9uaxwWgE1d1RitIWgJpAnp1DZ5O0uVlsPPm
+XAhuBJ32mU8S5BezPTuJJICwBlLYECGb1Y65Cil4OALU7T7sbUqfLCuaRKxuPtcU
+VnJ6/qiyPygvKZWhV6Od0Yxlyed1kftMJyYoL8kPHfeHJ+vIyt0s7cropfiwXoka
+1iJB5nKyt/eqMnPQ9aRpqkm9ABS/r7AauMA/9RALudQRHBdWIzfIg0Mlqb52yyTI
+IgQJHNGNX1T3z1XgZhI+Vi8SLFFSh8x9FeUZC6YJu0VXXj5iz+eZmk/nYjUt4Mtc
+pVsVYIB7oIDIbImODm8ggsgrIzqxOzQVP1zsCGek5U6QFc9GYrQ+Wv3/fG8hfkDn
+xXLww0OGaEQxfodm8cLFZ5b8JaG3+Yxfe7JkNclwvRimvlAjqIiW5OK0vvfHco+Y
+gANhQrlMnTx//IdZssaxvYytSHpPZTYw+qPEjbBJOLpoLrz8ZafN1uekpAqQjffI
+AOqW9SdIzq/kSHgl0bzWbPJPw86XzzftewjKNbkCDQRTmyS2ARAAxSSdQi+WpPQZ
+fOflkx9sYJa0cWzLl2w++FQnZ1Pn5F09D/kPMNh4qOsyvXWlekaV/SseDZtVziHJ
+Km6V8TBG3flmFlC3DWQfNNFwn5+pWSB8WHG4bTA5RyYEEYfpbekMtdoWW/Ro8Kmh
+41nuxZDSuBJhDeFIp0ccnN2Lp1o6XfIeDYPegyEPSSZqrudfqLrSZhStDlJgXjea
+JjW6UP6txPtYaaila9/Hn6vF87AQ5bR2dEWB/xRJzgNwRiax7KSU0xca6xAuf+TD
+xCjZ5pp2JwdCjquXLTmUnbIZ9LGV54UZ/MeiG8yVu6pxbiGnXo4Ekbk6xgi1ewLi
+vGmz4QRfVklV0dba3Zj0fRozfZ22qUHxCfDM7ad0eBXMFmHiN8hg3IUHTO+UdlX/
+aH3gADFAvSVDv0v8t6dGc6XE9Dr7mGEFnQMHO4zhM1HaS2Nh0TiL2tFLttLbfG5o
+QlxCfXX9/nasj3K9qnlEg9G3+4T7lpdPmZRRe1O8cHCI5imVg6cLIiBLPO16e0fK
+yHIgYswLdrJFfaHNYM/SWJxHpX795zn+iCwyvZSlLfH9mlegOeVmj9cyhN/VOmS3
+QRhlYXoA2z7WZTNoC6iAIlyIpMTcZr+ntaGVtFOLS6fwdBqDXjmSQu66mDKwU5Ek
+fNlbyrpzZMyFCDWEYo4AIR/18aGZBYUAEQEAAYkCHwQYAQIACQUCU5sktgIbDAAK
+CRAWVaCraFdigIPQEACcYh8rR19wMZZ/hgYv5so6Y1HcJNARuzmffQKozS/rxqec
+0xM3wceL1AIMuGhlXFeGd0wRv/RVzeZjnTGwhN1DnCDy1I66hUTgehONsfVanuP1
+PZKoL38EAxsMzdYgkYH6T9a4wJH/IPt+uuFTFFy3o8TKMvKaJk98+Jsp2X/QuNxh
+qpcIGaVbtQ1bn7m+k5Qe/fz+bFuUeXPivafLLlGc6KbdgMvSW9EVMO7yBy/2JE15
+ZJgl7lXKLQ31VQPAHT3an5IV2C/ie12eEqZWlnCiHV/wT+zhOkSpWdrheWfBT+ac
+hR4jDH80AS3F8jo3byQATJb3RoCYUCVc3u1ouhNZa5yLgYZ/iZkpk5gKjxHPudFb
+DdWjbGflN9k17VCf4Z9yAb9QMqHzHwIGXrb7ryFcuROMCLLVUp07PrTrRxnO9A/4
+xxECi0l/BzNxeU1gK88hEaNjIfviPR/h6Gq6KOcNKZ8rVFdwFpjbvwHMQBWhrqfu
+G3KaePvbnObKHXpfIKoAM7X2qfO+IFnLGTPyhFTcrl6vZBTMZTfZiC1XDQLuGUnd
+sckuXINIU3DFWzZGr0QrqkuE/jyr7FXeUJj9B7cLo+s/TXo+RaVfi3kOc9BoxIvy
+/qiNGs/TKy2/Ujqp/affmIMoMXSozKmga81JSwkADO1JMgUy6dApXz9kP4EE3g==
+=CLGF
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/views/.yo-rc.json b/views/.yo-rc.json
new file mode 100644
index 0000000..33606db
--- /dev/null
+++ b/views/.yo-rc.json
@@ -0,0 +1,6 @@
+{
+  "generator-xos": {
+    "name": "sampleView",
+    "folder": "ngXosViews"
+  }
+}
\ No newline at end of file
diff --git a/views/README.md b/views/README.md
new file mode 100644
index 0000000..34915a3
--- /dev/null
+++ b/views/README.md
@@ -0,0 +1,141 @@
+# ngXosLib
+
+This is a collection of helpers to develop views as Angular SPA.
+
+## Tools
+
+These tools are designed to help develop a graphical view. They assume XOS is running on your system and responding at: `localhost:9999`. The `xos/configurations/frontend` is normally sufficient for GUI development.
+
+### Vendors
+
+XOS comes with a set of common libraries, as listed in `bower.json`:
+- angular
+- angular-route
+- angular-resource
+- angular-cookie
+- ng-lodash
+
+These libraries are served through Django, so they are not included in your minified vendor file. To add a library and generate a new file (that will override the old one):
+- enter `ngXosLib` folder
+- run `bower install [myPackage] --save`
+- rebuild the file with `gulp vendor`
+
+>_NOTE before adding libraries please discuss it on the devel list to avoid this file becoming too big_
+
+### Helpers
+
+XOS comes with a helper library that is automatically loaded in the Django template.
+
+To use it, add `xos.helpers` to your required modules:
+
+```
+angular.module('xos.myView', [
+  'xos.helpers'
+])
+```
+
+It will automatically add a `token` to all your requests. Eventually you can take advantage of some other services:
+
+- **NoHyperlinks Interceptor**: will add a `?no_hyperlinks=1` to your request, to tell Django to return ids instead of links.
+- **XosApi** wrapper for `/xos` endpoints.
+- **XoslibApi** wrapper for `/xoslib` endpoints.
+- **HpcApi** wrapper for `/hpcapi` endpoints.
+
+>_NOTE: for the API related service, check the documentation in Section [Apigen](#apigen)._
+
+# ngXosViews
+
+In addition to auto-generated Django Admin Views and developer-defined Service Views, a set of custom views can be generate in XOS.
+
+These views are based on AngularJs and they communicate with XOS through the REST APIs, providing a powerful and flexible way to present and manage data.
+
+## How to Create a View
+
+### Environment setup
+
+Before getting started with new views you should create a configuration file to define the backend environment to be used. This file have to be in `views/env/default.js` and it content have to be:
+
+```
+module.exports = {
+  host: 'XOS Url',
+  xoscsrftoken: 'CSRF Token',
+  xossessionid: 'Sessio ID'
+};
+```
+
+You can define multiple environment creating other configurations (eg: `views/env/production.js`) with the same structure.
+
+### Getting Started
+
+We have created a [yeoman](http://yeoman.io/) generator to help scaffold views.
+
+>As it is in an early stage of development, you should manually link it to your system. To do this enter `/views/ngXosLib/generator-xos` and run `npm link`.
+
+#### To Generate a New View
+
+From `/views` run `yo xos`. This command will create a new folder with the provided name in `/views/ngXosViews` that contains your application.
+
+>If you left View name empty it should be `/views/ngXosViews/sampleView`
+
+#### Run a Development Server
+
+In your `view` folder run `npm start`.
+
+This will install the required dependencies and start a local server with [BrowserSync](http://www.browsersync.io/).
+
+>If you want to use a different backend environment you can call the command with an environment variable: `NODE_ENV=production.js npm start`
+
+#### Publish Your View
+
+Once your view is done, from your view root folder, run: `npm run build`.
+
+This will build your application and copy files in the appropriate directories for use by Django.
+
+At this point you can enter: `http://localhost:9999/admin/core/dashboardview/add/` and add your custom view.
+
+>_NOTE: url field should be `template:xosSampleView`_
+
+##### Add This View to a Configuration Setup
+
+You can easily set this as a default view in a configuration by editing the `{config}.yml` file for that configuration. Add these lines:
+
+```
+{TabName}:                                    
+  type: tosca.nodes.DashboardView              
+  properties:                                  
+      url: template:{viewName}     
+```
+
+Then edit the _User_ section (normally it starts with `padmin@vicci.org`) as follows:
+
+```
+padmin@vicci.org:                                          
+  type: tosca.nodes.User                                   
+  properties:                                              
+      firstname: XOS                                       
+      lastname: admin                                      
+      is_admin: true                                       
+  requirements:                                            
+      - tenant_dashboard:                                  
+          node: Tenant                                     
+          relationship: tosca.relationships.UsesDashboard  
+      - {custom_dashboard}:                              
+          node: {TabName}                                 
+          relationship: tosca.relationships.UsesDashboard  
+```
+
+#### Install Dependencies in Your App
+
+To install a local dependency use bower with `--save`. Common modules are saved in `devDependencies` as they already loaded in the Django template.
+
+The `npm start` command watches your dependencies and will automatically inject it in your `index.html`.
+
+#### Linting
+
+A styleguide is enforced through [EsLint](http://eslint.org/) and is checked during the build process. We **highly** recommend installing the linter in your editor to have realtime hints.
+
+#### Test
+
+The generator sets up a test environment with a default test.
+To run it, execute: `npm test`
+
diff --git a/views/env/.gitignore b/views/env/.gitignore
new file mode 100644
index 0000000..5edb50a
--- /dev/null
+++ b/views/env/.gitignore
@@ -0,0 +1,3 @@
+*
+!.gitignore
+!sample-config.js
\ No newline at end of file
diff --git a/views/env/sample-config.js b/views/env/sample-config.js
new file mode 100644
index 0000000..05809f0
--- /dev/null
+++ b/views/env/sample-config.js
@@ -0,0 +1,12 @@
+// This is a default configuration for your development environment.
+// You can duplicate this configuration for any of your Backend Environments.
+// Different configurations are loaded setting a NODE_ENV variable that contain the config file name.
+// `NODE_ENV=local npm start`
+
+// You can retrieve token and sessionId from your browser cookies.
+
+module.exports = {
+  host: 'http://localhost:9999/', // XOS Url
+  xoscsrftoken: 'ogrMpnJgOGq43OxGd8jIKIx2aY1vl1Ci', // XOS token
+  xossessionid: 'l49h474keq0vsk6car6l1quz0oeyvohh' // XOS session id
+};
diff --git a/views/ngXosLib/.bowerrc b/views/ngXosLib/.bowerrc
new file mode 100644
index 0000000..637d54e
--- /dev/null
+++ b/views/ngXosLib/.bowerrc
@@ -0,0 +1,3 @@
+{
+  "directory": "./bower_components"
+}
\ No newline at end of file
diff --git a/views/ngXosLib/.eslintrc b/views/ngXosLib/.eslintrc
new file mode 100644
index 0000000..6a8ce79
--- /dev/null
+++ b/views/ngXosLib/.eslintrc
@@ -0,0 +1,44 @@
+{
+    "ecmaFeatures": {
+        "blockBindings": true,
+        "forOf": true,
+        "destructuring": true,
+        "arrowFunctions": true,
+        "templateStrings": true
+    },
+    "env": { 
+        "browser": true,
+        "node": true,
+        "es6": true
+    },
+    "plugins": [
+        "angular"
+    ],
+    "rules": {
+        "quotes": [2, "single"],
+        "camelcase": [0, {"properties": "always"}],
+        "no-underscore-dangle": 0,
+        "eqeqeq": [2, "smart"],
+        "no-alert": 1,
+        "key-spacing": [1, { "beforeColon": false, "afterColon": true }],
+        "indent": [2, 2],
+        "no-irregular-whitespace": 1,
+        "eol-last": 0,
+        "comma-spacing": [1, {"before": false, "after": true}],
+        "no-trailing-spaces": [1, { skipBlankLines: true }],
+        "no-unused-vars": [1, {"vars": "all", "args": "after-used"}],
+        "new-cap": 0,
+        "no-multiple-empty-lines": 2,
+
+        "angular/ng_module_name": [2, '/^xos\.*[a-z]*$/'],
+//        "angular/ng_controller_name": [2, '/^[a-z].*Ctrl$/'],
+        //"angular/ng_service_name": [2, '/^[A-Z].*Service$/'],
+        "angular/ng_directive_name": [2, '/^[xos[[A-Z].*]*$/'],
+        "angular/ng_di": [0, "function or array"],
+        "angular/ng_angularelement": 0,
+        "angular/ng_on_watch": 1
+    },
+    "globals" :{
+        "angular": true
+    } 
+}
\ No newline at end of file
diff --git a/views/ngXosLib/.gitignore b/views/ngXosLib/.gitignore
new file mode 100644
index 0000000..24b9855
--- /dev/null
+++ b/views/ngXosLib/.gitignore
@@ -0,0 +1,7 @@
+node_modules
+bower_components
+docs
+xosHelpers/.tmp
+xos
+coverage
+test-result
\ No newline at end of file
diff --git a/views/ngXosLib/README.md b/views/ngXosLib/README.md
new file mode 100644
index 0000000..958b721
--- /dev/null
+++ b/views/ngXosLib/README.md
@@ -0,0 +1,94 @@
+# ngXosLib
+
+This is a collection of helpers to develop views as Angular SPA.
+
+## Tools
+
+This tools are designed to help you developing UI for XOS. As they born for this purpose if often necessary that a XOS instance is running on your sistem and responding at: `localhost:9999`. The `xos/configurations/frontend` is normally enough.
+
+### Vendors
+
+Xos comes with a preset of common libraries, as listed in `bower.json`:
+- angular
+- angular-route
+- angular-resource
+- angular-cookie
+- angular-animate
+- ng-lodash
+
+This libraries are served through Django, so they will not be included in your minified vendor file. To add a library and generate a new file (that will override the old one), you should:
+- enter `ngXosLib` folder
+- run `bower install [myPackage] --save`
+- rebuild the file with `gulp vendor`
+
+>_NOTE before adding libraries please discuss it to avoid this file to became huge_
+
+### Helpers
+
+XOS comes with an helper library that is automatically loaded in the Django template. It a set of Services and UI Components
+
+To use it, add `xos.helpers` to your required modules:
+
+```
+angular.module('xos.myView', [
+  'xos.helpers'
+])
+```
+
+It will automatically ad a `token` to all your request, eventually you can take advantage of some other services:
+
+To develop components inside this folder there is a particular command: `npm run dev`, this will watch the helpers file and rebuild them with sourcemaps. For this reason remember to build them when done developing.
+
+>While developing components in this library you should execute the test. The `npm test` command will run Jasmine test for the whole complete library.
+>If you want to specify a single test file to be execute, you can add it to the command like: `npm test smart-pie`, the tool will now read only the test specified in the `smart-pie.test.js` file.
+
+When some changes are applied to this common library it should be rebuilt with: `npm run build`
+
+To generate the relative documentation use: `npm run doc`
+
+### Yo Xos
+
+We have created a [yeoman](http://yeoman.io/) generator to help you scaffolding views.
+
+>As it is in an early stage of development you should manually link it to your system, to do this enter `xos/views/ngXosLib/generator-xos` and run `npm install && npm link`.
+
+#### To generate a new view
+
+From `xos/views` run `yo xos`. This command will create a new folder with the provided name in: `xos/views/ngXosViews` that contain your application.
+
+>If you left empty the view name it should be `xos/views/ngXosViews/sampleView`
+
+#### Run a development server
+
+In your `view` folder and run `npm start`.
+
+_This will install required dependencies and start a local server with [BrowserSync](http://www.browsersync.io/)_
+
+#### Publish your view
+
+Once your view is done, from your view root folder, run: `npm run build`.
+
+This will build your application and copy files in the appropriate locations to be used by django.
+
+At this point you can enter: `http://localhost:9999/admin/core/dashboardview/add/` and add your custom view.
+
+>_NOTE url field should be `template:xosSampleView`_
+
+#### Install dependencies in your app
+
+To install a local dependency use bower with `--save`. Common modules are saved in `devDependencies` as they already loaded in the Django template.
+
+The `npm start` command is watching your dependencies and will automatically inject them in your `index.html`.
+
+#### Linting
+
+A styleguide is enforced trough [EsLint](http://eslint.org/) and is checked during the build process. We **highly** suggest to install the linter in your editor to have realtime hint.
+
+#### Test
+
+The generator set up a test environment with a default test.
+To run it execute: `npm test`
+
+## TODO
+
+- Define styleguide (both visual and js) and if needed define some UI components
\ No newline at end of file
diff --git a/views/ngXosLib/bower.json b/views/ngXosLib/bower.json
new file mode 100644
index 0000000..351756c
--- /dev/null
+++ b/views/ngXosLib/bower.json
@@ -0,0 +1,35 @@
+{
+  "name": "ngXosVendor",
+  "version": "1.0.0",
+  "authors": [
+    "Matteo Scandolo <matteo.scandolo@link-me.it>"
+  ],
+  "description": "List of common used library in XOS environment",
+  "license": "MIT",
+  "ignore": [
+    "**/.*",
+    "node_modules",
+    "bower_components",
+    "test",
+    "tests"
+  ],
+  "dependencies": {
+    "angular": "1.4.7",
+    "angular-ui-router": "0.2.15",
+    "angular-resource": "1.4.7",
+    "angular-cookies": "1.4.7",
+    "angular-animate": "1.4.7",
+    "lodash": "~4.11.1",
+    "angular-chart.js": "~0.10.2",
+    "d3": "~3.5.17",
+    "angular-recursion": "~1.0.5"
+  },
+  "devDependencies": {
+    "angular-mocks": "1.4.7",
+    "jasmine-jquery": "~2.1.1",
+    "jquery": "~3.0.0"
+  },
+  "resolutions": {
+    "angular": "1.4.7"
+  }
+}
diff --git a/views/ngXosLib/generator-xos/app/index.js b/views/ngXosLib/generator-xos/app/index.js
new file mode 100755
index 0000000..0368fd2
--- /dev/null
+++ b/views/ngXosLib/generator-xos/app/index.js
@@ -0,0 +1,127 @@
+'use strict';
+
+var generators = require('yeoman-generator');
+var user = require('../node_modules/yeoman-generator/lib/actions/user');
+
+var config = {};
+var userName;
+
+module.exports = generators.Base.extend({
+  _fistCharToUpper: function(string){
+    return string.replace(/^./, string[0].toUpperCase());
+  },
+  prompting: {
+    name: function(){
+      var done = this.async();
+      this.prompt({
+        type: 'input',
+        name: 'name',
+        message: 'Your project name',
+        default: this.config.get('name') // value set in .yo-rc.json
+      }, function (answers) {
+        // TODO check if this view already exist
+        config.name = answers.name;
+        done();
+      }.bind(this));
+    }
+  },
+  writing: {
+    rcFiles: function(){
+      if (!user.git.name()){
+        userName = ['', '']
+      }
+      else {
+        userName = user.git.name().split(' ');
+      }
+      this.fs.copy(this.templatePath('.bowerrc'), this.destinationPath(`${this.config.get('folder')}/${config.name}/.bowerrc`));
+      this.fs.copy(this.templatePath('.gitignore'), this.destinationPath(`${this.config.get('folder')}/${config.name}/.gitignore`));
+    },
+    packageJson: function(){
+      this.fs.copyTpl(
+        this.templatePath('package.json'),
+        this.destinationPath(`${this.config.get('folder')}/${config.name}/package.json`),
+        { name: config.name, author: {name: user.git.name()} }
+      );
+    },
+    bowerJson: function(){
+      this.fs.copyTpl(
+        this.templatePath('bower.json'),
+        this.destinationPath(`${this.config.get('folder')}/${config.name}/bower.json`),
+        { name: config.name, author: {name: user.git.name(), email: user.git.email()} }
+      );
+    },
+    index: function(){
+      this.fs.copyTpl(
+        this.templatePath('src/index.html'),
+        this.destinationPath(`${this.config.get('folder')}/${config.name}/src/index.html`),
+        { name: config.name, fileName: this._fistCharToUpper(config.name), user: {firstname: userName[0]}}
+      );
+    },
+    css: function(){
+      this.fs.copyTpl(
+        this.templatePath('src/css/dev.css'),
+        this.destinationPath(`${this.config.get('folder')}/${config.name}/src/css/dev.css`),
+        {fileName: this._fistCharToUpper(config.name)}
+      );
+    },
+    css: function(){
+      this.fs.copyTpl(
+        this.templatePath('src/sass/main.scss'),
+        this.destinationPath(`${this.config.get('folder')}/${config.name}/src/sass/main.scss`),
+        {fileName: this._fistCharToUpper(config.name)}
+      );
+    },
+    mainJs: function(){
+      this.fs.copyTpl(
+        this.templatePath('src/js/main.js'),
+        this.destinationPath(`${this.config.get('folder')}/${config.name}/src/js/main.js`),
+        { name: config.name, fileName: this._fistCharToUpper(config.name) }
+      );
+    },
+    template: function(){
+      this.fs.copy(this.templatePath('src/templates/users-list.tpl.html'), this.destinationPath(`${this.config.get('folder')}/${config.name}/src/templates/users-list.tpl.html`));
+    },
+    gulp: function(){
+      this.fs.copyTpl(
+        this.templatePath('gulp/*.js'),
+        this.destinationPath(`${this.config.get('folder')}/${config.name}/gulp`),
+        {name: config.name, fileName: this._fistCharToUpper(config.name)}
+      );
+      this.fs.copy(this.templatePath('gulpfile.js'), this.destinationPath(`${this.config.get('folder')}/${config.name}/gulpfile.js`));
+    },
+    karma: function(){
+      this.fs.copy(
+        this.templatePath('karma.conf.js'),
+        this.destinationPath(`${this.config.get('folder')}/${config.name}/karma.conf.js`)
+      );
+    },
+    spec: function(){
+      this.fs.copyTpl(
+        this.templatePath('spec/sample.test.js'),
+        this.destinationPath(`${this.config.get('folder')}/${config.name}/spec/sample.test.js`),
+        { name: config.name, user: {email: user.git.email(), firstname: userName[0], lastname: userName[1] } }
+      );
+    },
+    lint: function(){
+      this.fs.copy(
+        this.templatePath('.eslintrc'),
+        this.destinationPath(`${this.config.get('folder')}/${config.name}/.eslintrc`)
+      );
+    }
+  },
+  install: function(){
+    var done = this.async();
+    this.prompt({
+      type: 'confirm',
+      name: 'deps',
+      message: 'Install dependecies?',
+      default: false // value set in .yo-rc.json
+    }, function (answers) {
+      if(answers.deps){
+        process.chdir(`${this.config.get('folder')}/${config.name}`);
+        this.installDependencies();
+      }
+      done();
+    }.bind(this));
+  }
+});
diff --git a/views/ngXosLib/generator-xos/app/templates/.bowerrc b/views/ngXosLib/generator-xos/app/templates/.bowerrc
new file mode 100644
index 0000000..e491038
--- /dev/null
+++ b/views/ngXosLib/generator-xos/app/templates/.bowerrc
@@ -0,0 +1,3 @@
+{
+  "directory": "src/vendor/"
+}
\ No newline at end of file
diff --git a/views/ngXosLib/generator-xos/app/templates/.eslintrc b/views/ngXosLib/generator-xos/app/templates/.eslintrc
new file mode 100644
index 0000000..c852748
--- /dev/null
+++ b/views/ngXosLib/generator-xos/app/templates/.eslintrc
@@ -0,0 +1,42 @@
+{
+    "ecmaFeatures": {
+        "blockBindings": true,
+        "forOf": true,
+        "destructuring": true,
+        "arrowFunctions": true,
+        "templateStrings": true
+    },
+    "env": { 
+        "browser": true,
+        "node": true,
+        "es6": true
+    },
+    "plugins": [
+        //"angular"
+    ],
+    "rules": {
+        "quotes": [2, "single"],
+        "camelcase": [1, {"properties": "always"}],
+        "no-underscore-dangle": 1,
+        "eqeqeq": [2, "smart"],
+        "no-alert": 1,
+        "key-spacing": [1, { "beforeColon": false, "afterColon": true }],
+        "indent": [2, 2],
+        "no-irregular-whitespace": 1,
+        "eol-last": 0,
+        "max-nested-callbacks": [2, 4],
+        "comma-spacing": [1, {"before": false, "after": true}],
+        "no-trailing-spaces": [1, { skipBlankLines: true }],
+        "no-unused-vars": [1, {"vars": "all", "args": "after-used"}],
+        "new-cap": 0,
+
+        //"angular/ng_module_name": [2, '/^xos\.*[a-z]*$/'],
+        //"angular/ng_controller_name": [2, '/^[a-z].*Ctrl$/'],
+        //"angular/ng_service_name": [2, '/^[A-Z].*Service$/'],
+        //"angular/ng_directive_name": [2, '/^[a-z]+[[A-Z].*]*$/'],
+        //"angular/ng_di": [0, "function or array"]
+    },
+    "globals" :{
+        "angular": true
+    } 
+}
\ No newline at end of file
diff --git a/views/ngXosLib/generator-xos/app/templates/.gitignore b/views/ngXosLib/generator-xos/app/templates/.gitignore
new file mode 100644
index 0000000..567aee4
--- /dev/null
+++ b/views/ngXosLib/generator-xos/app/templates/.gitignore
@@ -0,0 +1,6 @@
+dist/
+src/vendor
+.tmp
+node_modules
+npm-debug.log
+dist/
\ No newline at end of file
diff --git a/views/ngXosLib/generator-xos/app/templates/bower.json b/views/ngXosLib/generator-xos/app/templates/bower.json
new file mode 100644
index 0000000..0abca60
--- /dev/null
+++ b/views/ngXosLib/generator-xos/app/templates/bower.json
@@ -0,0 +1,33 @@
+{
+  "name": "xos-<%= name %>",
+  "version": "0.0.0",
+  "authors": [
+    "<%= author.name %> <<%= author.email %>>"
+  ],
+  "description": "The <%= name %> view",
+  "license": "MIT",
+  "ignore": [
+    "**/.*",
+    "node_modules",
+    "bower_components",
+    "static/js/vendor/",
+    "test",
+    "tests"
+  ],
+  "dependencies": {
+  },
+  "devDependencies": {
+    "jquery": "2.1.4",
+    "angular-mocks": "1.4.7",
+    "angular": "1.4.7",
+    "angular-ui-router": "0.2.15",
+    "angular-cookies": "1.4.7",
+    "angular-animate": "1.4.7",
+    "angular-resource": "1.4.7",
+    "lodash": "~4.11.1",
+    "bootstrap-css": "3.3.6",
+    "angular-chart.js": "~0.10.2",
+    "d3": "~3.5.17",
+    "angular-recursion": "~1.0.5"
+  }
+}
diff --git a/views/ngXosLib/generator-xos/app/templates/gulp/build.js b/views/ngXosLib/generator-xos/app/templates/gulp/build.js
new file mode 100644
index 0000000..b66cdbc
--- /dev/null
+++ b/views/ngXosLib/generator-xos/app/templates/gulp/build.js
@@ -0,0 +1,164 @@
+'use strict';
+
+// BUILD
+//
+// The only purpose of this gulpfile is to build a XOS view and copy the correct files into
+// .html => dashboards
+// .js (minified and concat) => static/js
+//
+// The template are parsed and added to js with angular $templateCache
+
+var gulp = require('gulp');
+var ngAnnotate = require('gulp-ng-annotate');
+var uglify = require('gulp-uglify');
+var templateCache = require('gulp-angular-templatecache');
+var runSequence = require('run-sequence');
+var concat = require('gulp-concat-util');
+var del = require('del');
+var wiredep = require('wiredep');
+var angularFilesort = require('gulp-angular-filesort');
+var _ = require('lodash');
+var eslint = require('gulp-eslint');
+var inject = require('gulp-inject');
+var rename = require('gulp-rename');
+var replace = require('gulp-replace');
+var postcss = require('gulp-postcss');
+var autoprefixer = require('autoprefixer');
+var mqpacker = require('css-mqpacker');
+var csswring = require('csswring');
+
+const TEMPLATE_FOOTER = `
+angular.module('xos.<%= name %>')
+.run(['$location', function(a){
+  a.path('/');
+}])
+`
+
+module.exports = function(options){
+  
+  // delete previous builded file
+  gulp.task('clean', function(){
+    return del(
+      [
+        options.dashboards + 'xos<%= fileName %>.html',
+        options.static + 'css/xos<%= fileName %>.css'
+      ],
+      {force: true}
+    );
+  });
+
+  // minify css
+  gulp.task('css', function () {
+    var processors = [
+      autoprefixer({browsers: ['last 1 version']}),
+      mqpacker,
+      csswring
+    ];
+
+    gulp.src([
+      `${options.css}**/*.css`,
+      `!${options.css}dev.css`
+    ])
+    .pipe(postcss(processors))
+    .pipe(gulp.dest(options.tmp + '/css/'));
+  });
+
+  // copy css in correct folder
+  gulp.task('copyCss', ['wait'], function(){
+    return gulp.src([`${options.tmp}/css/*.css`])
+    .pipe(concat('xos<%= fileName %>.css'))
+    .pipe(gulp.dest(options.static + 'css/'))
+  });
+
+  // compile and minify scripts
+  gulp.task('scripts', function() {
+    return gulp.src([
+      options.tmp + '**/*.js'
+    ])
+    .pipe(ngAnnotate())
+    .pipe(angularFilesort())
+    .pipe(concat('xos<%= fileName %>.js'))
+    .pipe(concat.header('//Autogenerated, do not edit!!!\n'))
+    .pipe(concat.footer(TEMPLATE_FOOTER))
+    .pipe(uglify())
+    .pipe(gulp.dest(options.static + 'js/'));
+  });
+
+  // set templates in cache
+  gulp.task('templates', function(){
+    return gulp.src('./src/templates/*.html')
+      .pipe(templateCache({
+        module: 'xos.<%= name %>',
+        root: 'templates/'
+      }))
+      .pipe(gulp.dest(options.tmp));
+  });
+
+  // copy html index to Django Folder
+  gulp.task('copyHtml', function(){
+    return gulp.src(options.src + 'index.html')
+      // remove dev dependencies from html
+      .pipe(replace(/<!-- bower:css -->(\n^<link.*)*\n<!-- endbower -->/gmi, ''))
+      .pipe(replace(/<!-- bower:js -->(\n^<script.*)*\n<!-- endbower -->/gmi, ''))
+      // injecting minified files
+      .pipe(
+        inject(
+          gulp.src([
+            options.static + 'js/vendor/xos<%= fileName %>Vendor.js',
+            options.static + 'js/xos<%= fileName %>.js',
+            options.static + 'css/xos<%= fileName %>.css'
+          ]),
+          {ignorePath: '/../../../xos/core/xoslib'}
+        )
+      )
+      .pipe(rename('xos<%= fileName %>.html'))
+      .pipe(gulp.dest(options.dashboards));
+  });
+
+  // minify vendor js files
+  gulp.task('wiredep', function(){
+    var bowerDeps = wiredep().js;
+    if(!bowerDeps){
+      return;
+    }
+
+    // remove angular (it's already loaded)
+    _.remove(bowerDeps, function(dep){
+      return dep.indexOf('angular/angular.js') !== -1;
+    });
+
+    return gulp.src(bowerDeps)
+      .pipe(concat('xos<%= fileName %>Vendor.js'))
+      .pipe(uglify())
+      .pipe(gulp.dest(options.static + 'js/vendor/'));
+  });
+
+  gulp.task('lint', function () {
+    return gulp.src(['src/js/**/*.js'])
+      .pipe(eslint())
+      .pipe(eslint.format())
+      .pipe(eslint.failAfterError());
+  });
+
+  gulp.task('wait', function (cb) {
+    // setTimeout could be any async task
+    setTimeout(function () {
+      cb();
+    }, 1000);
+  });
+
+  gulp.task('build', function() {
+    runSequence(
+      'clean',
+      'sass',
+      'templates',
+      'babel',
+      'scripts',
+      'wiredep',
+      'css',
+      'copyCss',
+      'copyHtml',
+      'cleanTmp'
+    );
+  });
+};
\ No newline at end of file
diff --git a/views/ngXosLib/generator-xos/app/templates/gulp/server.js b/views/ngXosLib/generator-xos/app/templates/gulp/server.js
new file mode 100644
index 0000000..1e40a34
--- /dev/null
+++ b/views/ngXosLib/generator-xos/app/templates/gulp/server.js
@@ -0,0 +1,170 @@
+'use strict';
+
+var gulp = require('gulp');
+var browserSync = require('browser-sync').create();
+var inject = require('gulp-inject');
+var runSequence = require('run-sequence');
+var angularFilesort = require('gulp-angular-filesort');
+var babel = require('gulp-babel');
+var wiredep = require('wiredep').stream;
+var httpProxy = require('http-proxy');
+var del = require('del');
+var sass = require('gulp-sass');
+var fs = require('fs');
+var path = require('path');
+
+const environment = process.env.NODE_ENV;
+
+if(!fs.existsSync(path.join(__dirname, `../../../env/${environment || 'default'}.js`))){
+  if(!environment){
+    throw new Error('You should define a default.js config in /views/env folder.');
+  }
+  else{
+    throw new Error(`Since you are loading a custom environment, you should define a ${environment}.js config in /views/env folder.`);
+  }
+}
+
+var conf = require(path.join(__dirname, `../../../env/${environment || 'default'}.js`));
+
+var proxy = httpProxy.createProxyServer({
+  target: conf.host
+});
+
+
+proxy.on('error', function(error, req, res) {
+  res.writeHead(500, {
+    'Content-Type': 'text/plain'
+  });
+
+  console.error('[Proxy]', error);
+});
+
+module.exports = function(options){
+
+  gulp.task('browser', function() {
+    browserSync.init({
+      startPath: '#/',
+      snippetOptions: {
+        rule: {
+          match: /<!-- browserSync -->/i
+        }
+      },
+      server: {
+        baseDir: options.src,
+        routes: {
+          '/xos/core/xoslib/static/js/vendor': options.helpers,
+          '/xos/core/static': options.static + '../../static/'
+        },
+        middleware: function(req, res, next){
+          if(
+            req.url.indexOf('/api/') !== -1
+          ){
+            if(conf.xoscsrftoken && conf.xossessionid){
+              req.headers.cookie = `xoscsrftoken=${conf.xoscsrftoken}; xossessionid=${conf.xossessionid}`;
+              req.headers['x-csrftoken'] = conf.xoscsrftoken;
+            }
+            proxy.web(req, res);
+          }
+          else{
+            next();
+          }
+        }
+      }
+    });
+
+    gulp.watch(options.src + 'js/**/*.js', ['js-watch']);
+    gulp.watch(options.src + 'vendor/**/*.js', ['bower'], function(){
+      browserSync.reload();
+    });
+    gulp.watch(options.src + '**/*.html', function(){
+      browserSync.reload();
+    });
+    gulp.watch(options.css + '**/*.css', function(){
+      browserSync.reload();
+    });
+    gulp.watch(`${options.sass}/**/*.scss`, ['sass'], function(){
+      browserSync.reload();
+    });
+
+    gulp.watch([
+      options.helpers + 'ngXosHelpers.js',
+      options.static + '../../static/xosNgLib.css'
+    ], function(){
+      browserSync.reload();
+    });
+  });
+
+  // compile sass
+  gulp.task('sass', function () {
+    return gulp.src(`${options.sass}/**/*.scss`)
+      .pipe(sass().on('error', sass.logError))
+      .pipe(gulp.dest(options.css));
+  });
+
+  // transpile js with sourceMaps
+  gulp.task('babel', function(){
+    return gulp.src(options.scripts + '**/*.js')
+      .pipe(babel({sourceMaps: true}))
+      .pipe(gulp.dest(options.tmp));
+  });
+
+  // inject scripts
+  gulp.task('injectScript', ['cleanTmp', 'babel'], function(){
+    return gulp.src(options.src + 'index.html')
+      .pipe(
+        inject(
+          gulp.src([
+            options.tmp + '**/*.js',
+            options.helpers + 'ngXosHelpers.js'
+          ])
+          .pipe(angularFilesort()),
+          {
+            ignorePath: [options.src, '/../../ngXosLib']
+          }
+        )
+      )
+      .pipe(gulp.dest(options.src));
+  });
+
+  // inject CSS
+  gulp.task('injectCss', function(){
+    return gulp.src(options.src + 'index.html')
+      .pipe(
+        inject(
+          gulp.src([
+            options.src + 'css/*.css',
+            options.static + '../../static/xosNgLib.css'
+          ]),
+          {
+            ignorePath: [options.src]
+          }
+          )
+        )
+      .pipe(gulp.dest(options.src));
+  });
+
+  // inject bower dependencies with wiredep
+  gulp.task('bower', function () {
+    return gulp.src(options.src + 'index.html')
+    .pipe(wiredep({devDependencies: true}))
+    .pipe(gulp.dest(options.src));
+  });
+
+  gulp.task('js-watch', ['injectScript'], function(){
+    browserSync.reload();
+  });
+
+  gulp.task('cleanTmp', function(){
+    return del([options.tmp + '**/*']);
+  });
+
+  gulp.task('serve', function() {
+    runSequence(
+      'sass',
+      'bower',
+      'injectScript',
+      'injectCss',
+      ['browser']
+    );
+  });
+};
diff --git a/views/ngXosLib/generator-xos/app/templates/gulpfile.js b/views/ngXosLib/generator-xos/app/templates/gulpfile.js
new file mode 100644
index 0000000..08df554
--- /dev/null
+++ b/views/ngXosLib/generator-xos/app/templates/gulpfile.js
@@ -0,0 +1,26 @@
+'use strict';
+
+var gulp = require('gulp');
+var wrench = require('wrench');
+
+var options = {
+  src: 'src/',
+  css: 'src/css/',
+  sass: 'src/sass/',
+  scripts: 'src/js/',
+  tmp: 'src/.tmp',
+  dist: 'dist/',
+  api: '../../ngXosLib/api/',
+  helpers: '../../../xos/core/xoslib/static/js/vendor/',
+  static: '../../../xos/core/xoslib/static/', // this is the django static folder
+  dashboards: '../../../xos/core/xoslib/dashboards/' // this is the django html folder
+};
+
+wrench.readdirSyncRecursive('./gulp')
+.map(function(file) {
+  require('./gulp/' + file)(options);
+});
+
+gulp.task('default', function () {
+  gulp.start('build');
+});
diff --git a/views/ngXosLib/generator-xos/app/templates/karma.conf.js b/views/ngXosLib/generator-xos/app/templates/karma.conf.js
new file mode 100644
index 0000000..4123be9
--- /dev/null
+++ b/views/ngXosLib/generator-xos/app/templates/karma.conf.js
@@ -0,0 +1,88 @@
+// Karma configuration
+// Generated on Tue Oct 06 2015 09:27:10 GMT+0000 (UTC)
+
+/* eslint indent: [2,2], quotes: [2, "single"]*/
+
+/*eslint-disable*/
+var wiredep = require('wiredep');
+var path = require('path');
+
+var bowerComponents = wiredep( {devDependencies: true} )[ 'js' ].map(function( file ){
+  return path.relative(process.cwd(), file);
+});
+
+module.exports = function(config) {
+/*eslint-enable*/
+  config.set({
+
+    // base path that will be used to resolve all patterns (eg. files, exclude)
+    basePath: '',
+
+
+    // frameworks to use
+    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
+    frameworks: ['jasmine'],
+
+
+    // list of files / patterns to load in the browser
+    files: bowerComponents.concat([
+      '../../../xos/core/xoslib/static/js/vendor/ngXosVendor.js',
+      '../../../xos/core/xoslib/static/js/vendor/ngXosHelpers.js',
+      'src/js/**/*.js',
+      'spec/**/*.mock.js',
+      'spec/**/*.test.js',
+      'src/**/*.html'
+    ]),
+
+
+    // list of files to exclude
+    exclude: [
+    ],
+
+
+    // preprocess matching files before serving them to the browser
+    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
+    preprocessors: {
+      'src/js/**/*.js': ['babel'],
+      'spec/**/*.test.js': ['babel'],
+      'src/**/*.html': ['ng-html2js']
+    },
+
+    ngHtml2JsPreprocessor: {
+      stripPrefix: 'src/', //strip the src path from template url (http://stackoverflow.com/questions/22869668/karma-unexpected-request-when-testing-angular-directive-even-with-ng-html2js)
+      moduleName: 'templates' // define the template module name
+    },
+
+    // test results reporter to use
+    // possible values: 'dots', 'progress'
+    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
+    reporters: ['mocha'],
+
+
+    // web server port
+    port: 9876,
+
+
+    // enable / disable colors in the output (reporters and logs)
+    colors: true,
+
+
+    // level of logging
+    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+    logLevel: config.LOG_INFO,
+
+
+    // enable / disable watching file and executing tests whenever any file changes
+    autoWatch: true,
+
+
+    // start these browsers
+    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
+    browsers: ['PhantomJS'],
+
+
+    // Continuous Integration mode
+    // if true, Karma captures browsers, runs the tests and exits
+    singleRun: false
+  });
+};
diff --git a/views/ngXosLib/generator-xos/app/templates/package.json b/views/ngXosLib/generator-xos/app/templates/package.json
new file mode 100644
index 0000000..b0f77f9
--- /dev/null
+++ b/views/ngXosLib/generator-xos/app/templates/package.json
@@ -0,0 +1,63 @@
+{
+  "name": "xos-<%= name %>",
+  "version": "1.0.0",
+  "description": "Angular Application for XOS, created with generator-xos",
+  "scripts": {
+    "prestart": "npm install && bower install",
+    "start": "gulp serve",
+    "prebuild": "npm install && bower install",
+    "build": "gulp",
+    "test": "karma start",
+    "test:ci": "karma start --single-run",
+    "lint": "eslint src/js/"
+  },
+  "keywords": [
+    "XOS",
+    "Angular",
+    "XOSlib"
+  ],
+  "author": "<%= author.name %>",
+  "license": "MIT",
+  "dependencies": {},
+  "devDependencies": {
+    "autoprefixer": "^6.3.3",
+    "browser-sync": "^2.9.11",
+    "css-mqpacker": "^4.0.0",
+    "csswring": "^4.2.1",
+    "del": "^2.0.2",
+    "easy-mocker": "^1.2.0",
+    "eslint": "^1.8.0",
+    "eslint-plugin-angular": "linkmesrl/eslint-plugin-angular",
+    "gulp": "^3.9.0",
+    "gulp-angular-filesort": "^1.1.1",
+    "gulp-angular-templatecache": "^1.8.0",
+    "gulp-babel": "^5.3.0",
+    "gulp-concat": "^2.6.0",
+    "gulp-concat-util": "^0.5.5",
+    "gulp-eslint": "^1.0.0",
+    "gulp-inject": "^3.0.0",
+    "gulp-minify-html": "^1.0.4",
+    "gulp-ng-annotate": "^1.1.0",
+    "gulp-postcss": "^6.0.1",
+    "gulp-rename": "^1.2.2",
+    "gulp-replace": "^0.5.4",
+    "gulp-sass": "^2.2.0",
+    "gulp-uglify": "^1.4.2",
+    "http-proxy": "^1.12.0",
+    "ink-docstrap": "^0.5.2",
+    "jasmine-core": "~2.3.4",
+    "karma": "^0.13.14",
+    "karma-babel-preprocessor": "~5.2.2",
+    "karma-coverage": "^0.5.3",
+    "karma-jasmine": "~0.3.6",
+    "karma-mocha-reporter": "~1.1.1",
+    "karma-ng-html2js-preprocessor": "^0.2.0",
+    "karma-phantomjs-launcher": "~0.2.1",
+    "lodash": "^3.10.1",
+    "phantomjs": "^1.9.19",
+    "proxy-middleware": "^0.15.0",
+    "run-sequence": "^1.1.4",
+    "wiredep": "^3.0.0-beta",
+    "wrench": "^1.5.8"
+  }
+}
diff --git a/views/ngXosLib/generator-xos/app/templates/spec/sample.test.js b/views/ngXosLib/generator-xos/app/templates/spec/sample.test.js
new file mode 100644
index 0000000..b00fa5e
--- /dev/null
+++ b/views/ngXosLib/generator-xos/app/templates/spec/sample.test.js
@@ -0,0 +1,37 @@
+'use strict';
+
+describe('The User List', () => {
+  
+  var scope, element, isolatedScope, httpBackend;
+
+  beforeEach(module('xos.<%= name %>'));
+  beforeEach(module('templates'));
+
+  beforeEach(inject(function($httpBackend, $compile, $rootScope){
+    
+    httpBackend = $httpBackend;
+    // Setting up mock request
+    $httpBackend.expectGET('/api/core/users/?no_hyperlinks=1').respond([
+      {
+        email: '<%= user.email %>',
+        firstname: '<%= user.firstname %>',
+        lastname: '<%= user.lastname %>' 
+      }
+    ]);
+  
+    scope = $rootScope.$new();
+    element = angular.element('<users-list></users-list>');
+    $compile(element)(scope);
+    scope.$digest();
+    isolatedScope = element.isolateScope().vm;
+  }));
+
+  it('should load 1 users', () => {
+    httpBackend.flush();
+    expect(isolatedScope.users.length).toBe(1);
+    expect(isolatedScope.users[0].email).toEqual('<%= user.email %>');
+    expect(isolatedScope.users[0].firstname).toEqual('<%= user.firstname %>');
+    expect(isolatedScope.users[0].lastname).toEqual('<%= user.lastname %>');
+  });
+
+});
\ No newline at end of file
diff --git a/views/ngXosLib/generator-xos/app/templates/src/css/dev.css b/views/ngXosLib/generator-xos/app/templates/src/css/dev.css
new file mode 100644
index 0000000..d7bc2d9
--- /dev/null
+++ b/views/ngXosLib/generator-xos/app/templates/src/css/dev.css
@@ -0,0 +1,5 @@
+#xos<%=fileName%>{
+  position: absolute;
+  top: 100px;
+  left: 200px;
+}
\ No newline at end of file
diff --git a/views/ngXosLib/generator-xos/app/templates/src/index.html b/views/ngXosLib/generator-xos/app/templates/src/index.html
new file mode 100644
index 0000000..504bc7c
--- /dev/null
+++ b/views/ngXosLib/generator-xos/app/templates/src/index.html
@@ -0,0 +1,91 @@
+<!-- browserSync -->
+<!-- bower:css -->
+<!-- endbower -->
+<!-- endcss -->
+<!-- inject:css -->
+<!-- endinject -->
+
+<div ng-app="xos.<%= name %>" id="xos<%= fileName %>" class="container-fluid">
+  <div class="row">
+    <div class="col-xs-12">
+      <h1>Hi <%= user.firstname %>!</h1>
+      <h3>Welcome to you development environment.</h3>
+      <p>
+        We provided this environment to help you creating a custom view.
+      </p>
+      <p>
+        When the environment is running you will have an
+        <code>auto-reload</code>
+        feature enabled, so any time you update one of your files, the browser will be reloaded.
+      </p>
+      <p> <i>Note that is environment is already functional and that it is loading information from the XOS APIs and presenting them using the
+          <code>xos-table</code>
+          component.</i> 
+      </p>
+      <h3>Development notes:</h3>
+      <p>
+        This views are designed using
+        <a href="https://angularjs.org/" target="_blank">Angular Js</a>
+        version 1.4.7 and
+        <a href="http://getbootstrap.com/" target="_blank">Bootstrap</a>
+        3.3.6 is included.
+      </p>
+      <p>
+        We just want to remind you that this development environment provide you three helper command:
+        <ul>
+          <li>
+            <code>npm start</code>
+            - will start your setup (you should already be familiar with it)
+          </li>
+          <li>
+            <code>npm test</code>
+            - will execute your unit tests defined with
+            <a href="https://karma-runner.github.io/0.13/index.html" target="_blank">Karma</a>
+            and
+            <a href="jasmine.github.io" target="_blank">Jasmine</a>
+            . You can check the
+            <code>spec/</code>
+            folder to see an example of your first test.
+          </li>
+          <li>
+            <code>npm run build</code>
+            - will build your dashboard and make it available to XOS
+          </li>
+        </ul>
+      </p>
+      <h3>Helpers:</h3>
+      <p>
+        We provide a set of helpers that you can leverage in your dashboard:
+        <ul>
+          <li>
+            <code>xos.helpers</code>
+            - A set of
+            <a href="https://docs.angularjs.org/guide/services" target="_blank">Angular Services</a>
+          </li>
+          <li>
+            <code>xos.uiComponents</code>
+            - A set of
+            <a href="https://docs.angularjs.org/guide/directive" target="_blank">Angular Directives</a>
+          </li>
+          <li>
+            <code>xos.rest</code>
+            - A set of
+            <a href="https://docs.angularjs.org/api/ngResource/service/$resource" target="_blank">Angular $resources</a>
+          </li>
+        </ul>
+        To know more about this helpers you can naviate to
+        <code>/views/ngXosLib/</code>
+        and generate the documentation with
+        <code>npm run doc</code>
+      </p>
+      <h3>Example:</h3>
+    </div>
+  </div>
+  <div ui-view></div>
+</div>
+
+<!-- bower:js -->
+<!-- endbower -->
+<!-- endjs -->
+<!-- inject:js -->
+<!-- endinject -->
\ No newline at end of file
diff --git a/views/ngXosLib/generator-xos/app/templates/src/js/main.js b/views/ngXosLib/generator-xos/app/templates/src/js/main.js
new file mode 100644
index 0000000..803f344
--- /dev/null
+++ b/views/ngXosLib/generator-xos/app/templates/src/js/main.js
@@ -0,0 +1,63 @@
+'use strict';
+
+angular.module('xos.<%= name %>', [
+  'ngResource',
+  'ngCookies',
+  'ui.router',
+  'xos.helpers'
+])
+.config(($stateProvider) => {
+  $stateProvider
+  .state('user-list', {
+    url: '/',
+    template: '<users-list></users-list>'
+  });
+})
+.config(function($httpProvider){
+  $httpProvider.interceptors.push('NoHyperlinks');
+})
+.directive('usersList', function(){
+  return {
+    restrict: 'E',
+    scope: {},
+    bindToController: true,
+    controllerAs: 'vm',
+    templateUrl: 'templates/users-list.tpl.html',
+    controller: function(Users){
+
+      this.tableConfig = {
+        columns: [
+          {
+            label: 'E-Mail',
+            prop: 'email'
+          },
+          {
+            label: 'First Name',
+            prop: 'firstname'
+          },
+          {
+            label: 'Last Name',
+            prop: 'lastname'
+          },
+          {
+            label: 'Created',
+            prop: 'created'
+          },
+          {
+            label: 'Is Admin',
+            prop: 'is_admin'
+          }
+        ]
+      };
+      
+      // retrieving user list
+      Users.query().$promise
+      .then((users) => {
+        this.users = users;
+      })
+      .catch((e) => {
+        throw new Error(e);
+      });
+    }
+  };
+});
\ No newline at end of file
diff --git a/views/ngXosLib/generator-xos/app/templates/src/sass/main.scss b/views/ngXosLib/generator-xos/app/templates/src/sass/main.scss
new file mode 100644
index 0000000..6f8a791
--- /dev/null
+++ b/views/ngXosLib/generator-xos/app/templates/src/sass/main.scss
@@ -0,0 +1,5 @@
+@import '../../../../style/sass/lib/_variables.scss';
+
+#xos<%=fileName%> {
+  
+}
\ No newline at end of file
diff --git a/views/ngXosLib/generator-xos/app/templates/src/templates/users-list.tpl.html b/views/ngXosLib/generator-xos/app/templates/src/templates/users-list.tpl.html
new file mode 100644
index 0000000..1fee0e2
--- /dev/null
+++ b/views/ngXosLib/generator-xos/app/templates/src/templates/users-list.tpl.html
@@ -0,0 +1 @@
+<xos-table config="vm.tableConfig" data="vm.users"></xos-table>
\ No newline at end of file
diff --git a/views/ngXosLib/generator-xos/package.json b/views/ngXosLib/generator-xos/package.json
new file mode 100644
index 0000000..0098496
--- /dev/null
+++ b/views/ngXosLib/generator-xos/package.json
@@ -0,0 +1,25 @@
+{
+  "name": "generator-xos",
+  "version": "1.0.0",
+  "description": "View generator for XOS",
+  "main": "index.js",
+  "scripts": {
+    "test": "mocha test"
+  },
+  "author": "Matteo Scandolo",
+  "license": "ISC",
+  "dependencies": {
+    "yeoman-generator": "^0.21.1"
+  },
+  "files": [
+    "app"
+  ],
+  "devDependencies": {
+    "mocha": "^2.4.5",
+    "mockery": "^1.7.0",
+    "rimraf": "^2.5.2",
+    "wiredep": "^4.0.0",
+    "yeoman-assert": "^2.2.1",
+    "yeoman-test": "^1.4.0"
+  }
+}
diff --git a/views/ngXosLib/generator-xos/test/build.spec.js b/views/ngXosLib/generator-xos/test/build.spec.js
new file mode 100644
index 0000000..19c338b
--- /dev/null
+++ b/views/ngXosLib/generator-xos/test/build.spec.js
@@ -0,0 +1,191 @@
+'use strict';
+var path = require('path');
+var helpers = require('yeoman-test');
+var assert = require('yeoman-assert');
+var exec = require('child_process').exec;
+var fs = require('fs');
+const rimraf = require('rimraf');
+
+const getMillisec = min => min * 60 * 1000;
+const deleteFile = file => {
+  if(fs.existsSync(file)){
+    // console.log(`deleting: ${file}`);
+    fs.unlinkSync(file);
+  }
+}
+
+// config files
+const cfg = path.join(__dirname, `../../../env/default.js`);
+
+// source files
+const viewName = 'testDashboard';
+const fileName = viewName.replace(/^./, viewName[0].toUpperCase());
+const sourcePath = path.join(__dirname, `../../../ngXosViews/${viewName}/`);
+
+// dest files
+const basePath = '../../../../xos/core/xoslib';
+const destHtml = path.join(__dirname, basePath + '/dashboards/xosTestDashboard.html');
+const destJs = path.join(__dirname, basePath + '/static/js/xosTestDashboard.js');
+const destVendor = path.join(__dirname, basePath + '/static/js/vendor/xosTestDashboardVendor.js');
+const destCss = path.join(__dirname, basePath + '/static/css/xosTestDashboard.css');
+
+describe('The XOS Build script', function(){
+  const buildCmd = 'gulp build';
+  
+  this.timeout(getMillisec(5));
+
+  before(done => {
+    // if `default.js` config is not present
+    // create one (we check to avoid screwing up local envs)
+    if(!fs.existsSync(cfg)){
+      fs.writeFileSync(cfg, 'module.exports = {}');
+    }
+    
+    console.log('Running generator');
+    this.generator = helpers
+      .run(require.resolve('../app'))
+      .inDir(sourcePath)
+      .withOptions({ 'skip-install': false })
+      .withPrompts({
+        name: viewName,
+        host: 'test-host',
+        token: 'test-token',
+        session: 'test-session'
+      })
+      .on('end', () => {
+        process.stdout.write('Installing Node Modules');
+        let npmInstall = setInterval(() => {
+          process.stdout.write('.');
+        }, 1000);
+        exec('npm install', {
+          cwd: sourcePath
+        }, (err) => {
+          clearInterval(npmInstall);
+          process.stdout.write('\nInstalling Bower Components');
+          let bowerInstall = setInterval(() => {
+            process.stdout.write('.');
+          }, 1000);
+          exec('bower install', {
+            cwd: sourcePath
+          }, (err) => {
+            clearInterval(bowerInstall);
+            done(err);
+          });
+        });
+      });
+  });
+
+  describe('when no styles or vendors are added', () => {
+    
+    before((done) => {
+      process.stdout.write('\nBuilding App');
+      let appBuild = setInterval(() => {
+        process.stdout.write('.');
+      }, 1000);
+      exec(buildCmd, {
+        cwd: sourcePath
+      }, (err) => {
+        console.log(err);
+        clearInterval(appBuild);
+        done(err);
+      });
+    });
+
+    it('should have build the app', () => {
+      assert.file([destHtml, destJs]);
+    });
+
+    it('should include only minified files in the index', () => {
+      assert.fileContent(destHtml, `<script src="/static/js/xos${fileName}.js"></script>`);
+      assert.noFileContent(destHtml, `<!-- bower:css -->`);
+      assert.noFileContent(destHtml, `<!-- bower:js -->`);
+    });
+  });
+
+  describe('when a third party library is added', () => {
+    before((done) => {
+    process.stdout.write('\nInstalling 3rd party library');
+      let bowerInstall = setInterval(() => {
+        process.stdout.write('.');
+      }, 1000);
+      exec('bower install d3 --save', {
+        cwd: sourcePath
+      }, (err, out) => {
+        clearInterval(bowerInstall);
+        process.stdout.write('\nBuilding App');
+        let appBuild = setInterval(() => {
+          process.stdout.write('.');
+        }, 1000);
+        exec(buildCmd, {
+          cwd: sourcePath
+        }, (err) => {
+          console.log(err);
+          clearInterval(appBuild);
+          done(err);
+        }); 
+      });
+    });
+
+    it('should have build the app with a vendor file', () => {
+      assert.file([destHtml, destJs, destVendor]);
+    });
+
+    it('should include only minified files and minified deps in the index', () => {
+      assert.fileContent(destHtml, `<script src="/static/js/xos${fileName}.js"></script>`);
+      assert.fileContent(destHtml, `<script src="/static/js/vendor/xos${fileName}Vendor.js"></script>`);
+      assert.noFileContent(destHtml, `<!-- bower:css -->`);
+      assert.noFileContent(destHtml, `<!-- bower:js -->`);
+    });
+  });
+
+  describe('when some styles are added', () => {
+    before((done) => {
+      let styleContent = `
+        @import '../../../../style/sass/lib/_variables.scss';
+
+        #xosTestDashboard {
+          background: $brand-primary;
+        }
+      `;
+
+      fs.writeFile(`${sourcePath}src/sass/main.scss`, styleContent, function(err) {
+        process.stdout.write('\nBuilding the Application');
+        let appBuild = setInterval(() => {
+          process.stdout.write('.');
+        }, 1000);
+        exec('bower uninstall d3 --save', {
+          cwd: sourcePath
+        }, (err, out) => {
+          exec(buildCmd, {
+            cwd: sourcePath
+          }, (err, out) => {
+            clearInterval(appBuild);
+            done();
+          })
+        })
+      });
+    });
+
+    it('should have build the app with a css file', () => {
+      assert.file([destHtml, destJs, destCss]);
+    });
+
+    it('should include only minified files and minified deps in the index', () => {
+      assert.fileContent(destHtml, `<script src="/static/js/xos${fileName}.js"></script>`);
+      assert.fileContent(destHtml, `<link rel="stylesheet" href="/static/css/xos${fileName}.css">`);
+      assert.noFileContent(destHtml, `<!-- bower:css -->`);
+      assert.noFileContent(destHtml, `<!-- bower:js -->`);
+
+      assert.fileContent(destCss, `background:#337ab7`);
+    });
+  });
+
+  after(done => {
+    // deleting the folder used for test
+    deleteFile(destHtml);
+    deleteFile(destJs);
+    deleteFile(destVendor);
+    deleteFile(destCss);
+    rimraf(sourcePath, {}, done);
+  });
+});
\ No newline at end of file
diff --git a/views/ngXosLib/generator-xos/test/generator.spec.js b/views/ngXosLib/generator-xos/test/generator.spec.js
new file mode 100644
index 0000000..2c7abb5
--- /dev/null
+++ b/views/ngXosLib/generator-xos/test/generator.spec.js
@@ -0,0 +1,113 @@
+'use strict';
+
+const path = require('path');
+const helpers = require('yeoman-test');
+const assert = require('yeoman-assert');
+const rimraf = require('rimraf');
+const mockery = require('mockery');
+const wiredep = require('wiredep');
+
+const firstCharTouppercase = string => string.replace(/^./, string[0].toUpperCase())
+
+// get bower deps installed in ngXosLib
+let bowerDeps = wiredep({
+  cwd: path.join(__dirname, '../../'), // pretending to be in the ngXosLib root
+  exclude: ['Chart.js']
+});
+bowerDeps = bowerDeps.js.map(d => {
+  let path = d.match(/bower_components\/([1-9a-zA-Z\-`.]+)\//);
+  if(path){
+    return path[1];
+  }
+});
+
+// test values
+const viewName = 'testDashboard';
+const fileName = firstCharTouppercase(viewName);
+const testPath = path.join(__dirname, `../../../ngXosViews/${viewName}/`);
+
+const getDefaultFiles = () => {
+  return [
+    '.bowerrc',
+    '.eslintrc',
+    '.gitignore',
+    'bower.json',
+    'gulpfile.js',
+    'karma.conf.js',
+    'package.json',
+    'src/index.html',
+  ].map(i => `${testPath}${i}`);
+};
+
+const yeomanUserMock = {
+  git: {
+    name: () => 'Test User',
+    email: () => 'test@mail.org'
+  }
+}
+
+mockery.enable({
+  warnOnReplace: false,
+  warnOnUnregistered: false,
+  useCleanCache: true,
+});
+mockery.resetCache();
+mockery.registerMock('../node_modules/yeoman-generator/lib/actions/user', yeomanUserMock);
+
+describe('Yeoman XOS generator', function () {
+
+  beforeEach(() => {
+  });
+
+  before(done => {
+    this.generator = helpers
+      .run(require.resolve('../app'))
+      .inDir(testPath)
+      .withOptions({ 'skip-install': true })
+      .withPrompts({
+        name: viewName
+      })
+      .on('end', done);
+  });
+
+
+  it('should generate base files in the correct directory', () => {
+    assert.file(getDefaultFiles());
+  });
+
+  it('should write username in package & bower json', () => {
+    assert.fileContent(`${testPath}package.json`, '"author": "Test User"');
+    assert.fileContent(`${testPath}bower.json`, '"Test User <test@mail.org>"')
+  });
+
+  it('should add all xosLib dependencies in the dev section of bower.json', () => {
+    bowerDeps.forEach(d => {
+      assert.fileContent(`${testPath}bower.json`, d);
+    });
+  });
+
+  it('should set the right module name in all the files', () => {
+    assert.fileContent(`${testPath}src/index.html`, `ng-app="xos.${viewName}"`)
+    assert.fileContent(`${testPath}src/index.html`, `id="xos${fileName}"`)
+    assert.fileContent(`${testPath}src/js/main.js`, `angular.module('xos.${viewName}', [`)
+    assert.fileContent(`${testPath}src/sass/main.scss`, `#xos${fileName}`)
+  });
+
+  it('should set correct paths in build file', () => {
+    assert.fileContent(`${testPath}gulp/build.js`, `angular.module('xos.${viewName}')`)
+    assert.fileContent(`${testPath}gulp/build.js`, `options.dashboards + 'xos${fileName}.html'`)
+    assert.fileContent(`${testPath}gulp/build.js`, `options.static + 'css/xos${fileName}.css'`)
+    assert.fileContent(`${testPath}gulp/build.js`, `.pipe(concat('xos${fileName}.css'))`)
+    assert.fileContent(`${testPath}gulp/build.js`, `.pipe(concat('xos${fileName}.js'))`)
+    assert.fileContent(`${testPath}gulp/build.js`, `module: 'xos.${viewName}'`)
+    assert.fileContent(`${testPath}gulp/build.js`, `options.static + 'js/vendor/xos${fileName}Vendor.js'`)
+    assert.fileContent(`${testPath}gulp/build.js`, `options.static + 'js/xos${fileName}.js'`)
+    assert.fileContent(`${testPath}gulp/build.js`, `options.static + 'css/xos${fileName}.css'`)
+    assert.fileContent(`${testPath}gulp/build.js`, `.pipe(concat('xos${fileName}Vendor.js'))`)
+  });
+
+  after(done => {
+    // deleting the folder used for test
+    rimraf(testPath, {}, done)
+  });
+});
\ No newline at end of file
diff --git a/views/ngXosLib/gulp/ngXosHelpers.js b/views/ngXosLib/gulp/ngXosHelpers.js
new file mode 100644
index 0000000..a19d85e
--- /dev/null
+++ b/views/ngXosLib/gulp/ngXosHelpers.js
@@ -0,0 +1,136 @@
+var gulp = require('gulp');
+var uglify = require('gulp-uglify');
+var concat = require('gulp-concat');
+var ngAnnotate = require('gulp-ng-annotate');
+var angularFilesort = require('gulp-angular-filesort');
+var gulpDocs = require('gulp-ngdocs');
+var del = require('del');
+var babel = require('gulp-babel');
+const sourcemaps = require('gulp-sourcemaps');
+var browserSync = require('browser-sync').create();
+var rename = require('gulp-rename');
+var sass = require('gulp-sass');
+
+module.exports = function(options){
+
+  gulp.task('style', function(){
+    return gulp.src(`${options.xosHelperSource}styles/main.scss`)
+      .pipe(sourcemaps.init())
+      .pipe(sass().on('error', sass.logError))
+      .pipe(rename('xosNgLib.css'))
+      .pipe(sourcemaps.write())
+      .pipe(gulp.dest(options.ngXosStyles));
+  });
+
+  // transpile js with sourceMaps
+  gulp.task('babel', function(){
+    return gulp.src(options.xosHelperSource + '**/*.js')
+      .pipe(babel({
+        presets: ['es2015']
+      }))
+      .pipe(gulp.dest(options.xosHelperTmp));
+  });
+
+  gulp.task('babelDev', function(){
+    return gulp.src(options.xosHelperSource + '**/*.js')
+      .pipe(sourcemaps.init())
+      .pipe(babel({
+        presets: ['es2015']
+      }))
+      .pipe(sourcemaps.write('./maps'))
+      .pipe(gulp.dest(options.xosHelperTmp));
+  });
+
+  // build
+  gulp.task('helpers', ['babel', 'style'], function(){
+    return gulp.src([options.xosHelperTmp + '**/*.js'])
+      .pipe(angularFilesort())
+      .pipe(concat('ngXosHelpers.js'))
+      .pipe(ngAnnotate())
+      .pipe(uglify())
+      .pipe(gulp.dest(options.ngXosVendor));
+  });
+
+  // build Dev (no minify, sourcemaps)
+  gulp.task('helpersDev', ['babelDev'], function(){
+    return gulp.src([options.xosHelperTmp + '**/*.js'])
+      .pipe(angularFilesort())
+      .pipe(concat('ngXosHelpers.js'))
+      .pipe(ngAnnotate())
+      .pipe(gulp.dest(options.ngXosVendor));
+  });
+
+  gulp.task('cleanDocs', function(){
+    return del([options.docs + '**/*']);
+  });
+
+  gulp.task('makeDocs', ['cleanDocs'], function(){
+
+    var ngOptions = {
+      scripts: [].concat([
+        `./${options.ngXosVendor}ngXosVendor.js`,
+        `./${options.ngXosVendor}ngXosHelpers.js`,
+          'https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.7/angular-mocks.js',
+      ]),
+      styles: [
+        `./${options.ngXosStyles}xosNgLib.css`,
+        'https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.css',
+      ],
+      html5Mode: false,
+      title: 'XOS Helpers documentation',
+      startPage: '/module',
+    }
+
+    return gulpDocs.sections({
+      module: {
+        glob: [
+          options.xosHelperSource + '*.js',
+          options.xosHelperSource + 'services/helpers/**/*.js',
+          options.xosHelperSource + 'services/*.js',
+          options.xosHelperSource + 'ui_components/**/*.js'
+        ],
+        title: 'Module Documentation',
+      },
+      'rest-api': {
+        glob: [
+          options.xosHelperSource + 'services/rest/*.js'
+        ],
+        api: true,
+        title: 'API Documentation',
+      }
+    }).pipe(gulpDocs.process(ngOptions)).pipe(gulp.dest('./docs'));
+  });
+
+  gulp.task('serveDocs', function(){
+    browserSync.init({
+      server: {
+        baseDir: './docs',
+        routes: {
+          '/xos/core/xoslib/static/js/vendor': options.ngXosVendor,
+          '/xos/core/static': options.ngXosStyles,
+        }
+      }
+    });
+  });
+
+  gulp.task('docs', ['makeDocs', 'serveDocs'], function(){
+    
+    var files = [
+      options.xosHelperSource + '**/*.js'
+    ];
+
+    gulp.watch(files, ['makeDocs']);
+
+    // uncomment to enable autoreload, now it is broken (reload a wrong page)
+    // https://github.com/nikhilmodak/gulp-ngdocs/issues/81
+
+    // gulp.watch(files, function(){
+    //   browserSync.reload();
+    // });
+  })
+
+  gulp.task('dev', function(){
+    gulp.watch(`${options.xosHelperSource}**/*.scss`, ['style']);
+    gulp.watch(options.xosHelperSource + '**/*.js', ['helpersDev']);
+  });
+};
\ No newline at end of file
diff --git a/views/ngXosLib/gulp/ngXosVendor.js b/views/ngXosLib/gulp/ngXosVendor.js
new file mode 100644
index 0000000..c11ef9e
--- /dev/null
+++ b/views/ngXosLib/gulp/ngXosVendor.js
@@ -0,0 +1,14 @@
+var gulp = require('gulp');
+var uglify = require('gulp-uglify');
+var concat = require('gulp-concat');
+var wiredep = require('wiredep');
+
+module.exports = function(options){
+  gulp.task('vendor', function(){
+    var bowerDeps = wiredep().js;
+    return gulp.src(bowerDeps)
+      .pipe(concat('ngXosVendor.js'))
+      .pipe(uglify())
+      .pipe(gulp.dest(options.ngXosVendor));
+  });
+};
\ No newline at end of file
diff --git a/views/ngXosLib/gulpfile.js b/views/ngXosLib/gulpfile.js
new file mode 100644
index 0000000..e030ad9
--- /dev/null
+++ b/views/ngXosLib/gulpfile.js
@@ -0,0 +1,22 @@
+'use strict';
+
+var gulp = require('gulp');
+var wrench = require('wrench');
+var path = require('path');
+
+var options = {
+  ngXosVendor: '../../xos/core/xoslib/static/js/vendor/', //save here the minfied vendor file, this is automatically loaded in the django page
+  ngXosStyles: '../../xos/core/static/', // TODO move in xoslib
+  xosHelperSource: './xosHelpers/src/',
+  xosHelperTmp: './xosHelpers/.tmp/',
+  docs: './docs'
+};
+
+wrench.readdirSyncRecursive(path.join(__dirname, './gulp'))
+.map(function(file) {
+  require(path.join(__dirname, './gulp/' + file))(options);
+});
+
+gulp.task('default', function () {
+  gulp.start('vendor');
+});
diff --git a/views/ngXosLib/karma.conf.ci.js b/views/ngXosLib/karma.conf.ci.js
new file mode 100644
index 0000000..0726edd
--- /dev/null
+++ b/views/ngXosLib/karma.conf.ci.js
@@ -0,0 +1,144 @@
+'use strict';
+
+// THIS KARMA CONF WILL ITERATE THE VIEW FOLDER AND PERFORM ALL THE TESTS!!!
+
+// Karma configuration
+// Generated on Tue Oct 06 2015 09:27:10 GMT+0000 (UTC)
+
+/* eslint indent: [2,2], quotes: [2, "single"]*/
+
+const babelPreset = require('babel-preset-es2015');
+const fs = require('fs');
+
+const viewDir = '../../xos/core/xoslib/static/js/';
+const vendorDir = '../../xos/core/xoslib/static/js/vendor/';
+let viewFiles = fs.readdirSync(viewDir);
+let vendorFiles = fs.readdirSync(vendorDir);
+
+// hack to avoid testing backbone implementation (they need to be removed)
+viewFiles = viewFiles
+              .filter(f => f.indexOf('xosAdminSite') === -1)
+              .filter(f => f.indexOf('xosCord') === -1);
+
+viewFiles = viewFiles.filter(f => f.indexOf('js') >= 0).filter(f => f.match(/^xos[A-Z][a-z]+/)).map(f => `${viewDir}${f}`);
+
+vendorFiles = vendorFiles.filter(f => f.indexOf('js') >= 0).filter(f => f.match(/^xos[A-Z][a-z]+/)).map(f => `${vendorDir}${f}`);
+
+/*eslint-disable*/
+
+var files = [
+  'node_modules/babel-polyfill/dist/polyfill.js',
+
+
+  // loading jquery (it's used in tests)
+  `./bower_components/jquery/dist/jquery.js`,
+  `./bower_components/jasmine-jquery/lib/jasmine-jquery.js`,
+
+  // loading helpers and vendors
+  `../../xos/core/xoslib/static/js/vendor/ngXosVendor.js`,
+  `../../xos/core/xoslib/static/js/vendor/ngXosHelpers.js`,
+
+  // loading ngMock
+  'template.module.js',
+  `./bower_components/angular-mocks/angular-mocks.js`,
+]
+.concat(vendorFiles)
+.concat(viewFiles)
+.concat([
+  // loading tests
+  `xosHelpers/spec/test_helpers.js`,
+  `../ngXosViews/*/spec/*.test.js`,
+  `../ngXosViews/*/spec/**/*.mock.js`,
+  'xosHelpers/spec/**/*.test.js'
+]);
+
+
+module.exports = function(config) {
+/*eslint-enable*/
+  config.set({
+
+    // base path that will be used to resolve all patterns (eg. files, exclude)
+    basePath: '',
+
+
+    // frameworks to use
+    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
+    frameworks: ['jasmine'],
+
+
+    // list of files / patterns to load in the browser
+    files: files,
+
+
+    // list of files to exclude
+    exclude: [
+    ],
+
+
+    // preprocess matching files before serving them to the browser
+    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
+    preprocessors: {
+      '../ngXosViews/**/spec/*.test.js': ['babel'],
+      '../ngXosViews/**/spec/*.mock.js': ['babel'],
+      'xosHelpers/spec/**/*.test.js': ['babel'],
+    },
+
+    babelPreprocessor: {
+      options: {
+        presets: [babelPreset],
+        sourceMap: 'inline'
+      }
+    },
+
+    //ngHtml2JsPreprocessor: {
+    //  stripPrefix: 'src/', //strip the src path from template url (http://stackoverflow.com/questions/22869668/karma-unexpected-request-when-testing-angular-directive-even-with-ng-html2js)
+    //  moduleName: 'templates' // define the template module name
+    //},
+
+    // test results reporter to use
+    // possible values: 'dots', 'progress'
+    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
+    reporters: ['dots', 'mocha', 'junit', 'coverage'],
+
+    junitReporter: {
+      outputDir: 'test-result',
+      useBrowserName: false,
+      outputFile: 'test-results.xml'
+    },
+
+    coverageReporter: {
+      type: 'cobertura',
+      subdir: '.',
+      dir: 'test-result/'
+    },
+
+    // web server port
+    port: 9876,
+
+
+    // enable / disable colors in the output (reporters and logs)
+    colors: true,
+
+
+    // level of logging
+    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+    logLevel: config.LOG_INFO,
+
+
+    // enable / disable watching file and executing tests whenever any file changes
+    autoWatch: true,
+
+
+    // start these browsers
+    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
+    browsers: [
+      'PhantomJS',
+      // 'Chrome'
+    ],
+
+
+    // Continuous Integration mode
+    // if true, Karma captures browsers, runs the tests and exits
+    singleRun: true
+  });
+};
diff --git a/views/ngXosLib/karma.conf.js b/views/ngXosLib/karma.conf.js
new file mode 100644
index 0000000..4032b49
--- /dev/null
+++ b/views/ngXosLib/karma.conf.js
@@ -0,0 +1,106 @@
+// Karma configuration
+// Generated on Tue Oct 06 2015 09:27:10 GMT+0000 (UTC)
+
+/* eslint indent: [2,2], quotes: [2, "single"]*/
+
+// this is to load a different suite of test while developing
+var testFiles = '*';
+if(process.argv[4]){
+  testFiles = process.argv[4];
+}
+
+/*eslint-disable*/
+var wiredep = require('wiredep');
+var path = require('path');
+
+var bowerComponents = wiredep({devDependencies: true})[ 'js' ].map(function( file ){
+  return path.relative(process.cwd(), file);
+});
+
+var files = bowerComponents.concat([
+  'node_modules/babel-polyfill/dist/polyfill.js',
+  'xosHelpers/src/**/*.module.js',
+  'xosHelpers/src/**/*.js',
+  `xosHelpers/spec/test_helpers.js`,
+  `xosHelpers/spec/**/${testFiles}.test.js`
+]);
+
+module.exports = function(config) {
+/*eslint-enable*/
+  config.set({
+
+    // base path that will be used to resolve all patterns (eg. files, exclude)
+    basePath: '',
+
+
+    // frameworks to use
+    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
+    frameworks: ['jasmine'],
+
+
+    // list of files / patterns to load in the browser
+    files: files,
+
+
+    // list of files to exclude
+    exclude: [
+    ],
+
+
+    // preprocess matching files before serving them to the browser
+    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
+    preprocessors: {
+      'xosHelpers/**/*.js': ['babel'],
+    },
+
+    babelPreprocessor: {
+      options: {
+        presets: ['es2015'],
+        sourceMap: 'both'
+      },
+      filename: function (file) {
+        return file.originalPath;
+      },
+    },
+
+    //ngHtml2JsPreprocessor: {
+    //  stripPrefix: 'src/', //strip the src path from template url (http://stackoverflow.com/questions/22869668/karma-unexpected-request-when-testing-angular-directive-even-with-ng-html2js)
+    //  moduleName: 'templates' // define the template module name
+    //},
+
+    // test results reporter to use
+    // possible values: 'dots', 'progress'
+    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
+    reporters: ['mocha'],
+
+
+    // web server port
+    port: 9876,
+
+
+    // enable / disable colors in the output (reporters and logs)
+    colors: true,
+
+
+    // level of logging
+    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+    logLevel: config.LOG_INFO,
+
+
+    // enable / disable watching file and executing tests whenever any file changes
+    autoWatch: true,
+
+
+    // start these browsers
+    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
+    browsers: [
+      'PhantomJS',
+       //'Chrome'
+    ],
+
+
+    // Continuous Integration mode
+    // if true, Karma captures browsers, runs the tests and exits
+    singleRun: false
+  });
+};
diff --git a/views/ngXosLib/package.json b/views/ngXosLib/package.json
new file mode 100644
index 0000000..ba25551
--- /dev/null
+++ b/views/ngXosLib/package.json
@@ -0,0 +1,60 @@
+{
+  "name": "ng-xos-lib",
+  "version": "1.0.0",
+  "description": "Angular Version of XosLib, containing Helpers and ngResources",
+  "main": "index.js",
+  "scripts": {
+    "test": "karma start karma.conf.js",
+    "test:ci": "karma start karma.conf.ci.js",
+    "test:views": "karma start karma.conf.views.js",
+    "apigen": "node apigen/blueprintToNgResource.js",
+    "swagger": "node xos-swagger-def.js",
+    "doc": "gulp docs; cd ./docs",
+    "doc:ci": "gulp makeDocs;",
+    "build": "gulp vendor && gulp helpers",
+    "dev": "gulp dev",
+    "lint": "eslint xosHelpers/"
+  },
+  "author": "Matteo Scandolo",
+  "license": "ISC",
+  "dependencies": {
+    "bluebird": "^3.0.5",
+    "chalk": "^1.1.1",
+    "concat": "^2.0.0",
+    "eslint": "^1.8.0",
+    "eslint-plugin-angular": "linkmesrl/eslint-plugin-angular",
+    "fetch-swagger-schema": "^0.1.2",
+    "jsdoc": "^3.3.3",
+    "swagger-js-codegen": "^1.1.5"
+  },
+  "devDependencies": {
+    "babel-polyfill": "^6.7.4",
+    "babel-preset-es2015": "^6.6.0",
+    "browser-sync": "^2.12.3",
+    "concat": "^2.0.0",
+    "del": "^2.2.0",
+    "gulp": "^3.9.0",
+    "gulp-angular-filesort": "^1.1.1",
+    "gulp-babel": "^6.1.2",
+    "gulp-concat": "^2.6.0",
+    "gulp-ng-annotate": "^1.1.0",
+    "gulp-ngdocs": "^0.2.13",
+    "gulp-rename": "^1.2.2",
+    "gulp-sass": "^2.3.1",
+    "gulp-sourcemaps": "^1.6.0",
+    "gulp-uglify": "^1.4.2",
+    "jasmine-core": "^2.4.1",
+    "karma": "^0.13.22",
+    "karma-babel-preprocessor": "^6.0.1",
+    "karma-chrome-launcher": "^0.2.3",
+    "karma-coverage": "^0.5.5",
+    "karma-jasmine": "^0.3.6",
+    "karma-junit-reporter": "^0.4.2",
+    "karma-mocha-reporter": "^1.1.3",
+    "karma-ng-html2js-preprocessor": "^0.2.0",
+    "karma-phantomjs-launcher": "^0.2.1",
+    "phantomjs": "^2.1.3",
+    "wiredep": "^3.0.0-beta",
+    "wrench": "^1.5.8"
+  }
+}
diff --git a/views/ngXosLib/template.module.js b/views/ngXosLib/template.module.js
new file mode 100644
index 0000000..1775ed0
--- /dev/null
+++ b/views/ngXosLib/template.module.js
@@ -0,0 +1,3 @@
+'use strict';
+
+angular.module('templates', []);
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/spec/.eslintrc b/views/ngXosLib/xosHelpers/spec/.eslintrc
new file mode 100644
index 0000000..de1e44b
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/spec/.eslintrc
@@ -0,0 +1,7 @@
+{
+  "rules": {
+    "angular/ng_angularelement": 0,
+    "angular/ng_no_digest": 0,
+    "angular/ng_json_functions": 0
+  }
+}
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/spec/csrftoken.test.js b/views/ngXosLib/xosHelpers/spec/csrftoken.test.js
new file mode 100644
index 0000000..8901bde
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/spec/csrftoken.test.js
@@ -0,0 +1,51 @@
+'use strict';
+describe('The xos.helper module', function(){
+  var SetCSRFToken, httpProviderObj, httpBackend, http, cookies;
+
+  const fakeToken = 'aiuhsnds98234ndASd';
+
+  beforeEach(function() {
+    module(
+      'xos.helpers',
+      function ($httpProvider) {
+        //save our interceptor
+        httpProviderObj = $httpProvider;
+      }
+    );
+
+    inject(function (_SetCSRFToken_, _$httpBackend_, _$http_, _$cookies_) {
+      SetCSRFToken = _SetCSRFToken_;
+      httpBackend = _$httpBackend_;
+      http = _$http_;
+      cookies = _$cookies_
+
+      // mocking $cookie service
+      spyOn(cookies, 'get').and.returnValue(fakeToken);
+    });
+
+  });
+
+  describe('the SetCSRFToken', () => {
+    it('should exist', () => {
+      expect(SetCSRFToken).toBeDefined();
+    });
+
+    it('should attach token the request', (done) => {
+      httpBackend.when('POST', 'http://example.com', null, function(headers) {
+        expect(headers['X-CSRFToken']).toBe(fakeToken);
+        done();
+        return headers;
+      }).respond(200, {name: 'example' });
+
+      http.post('http://example.com');
+
+      httpBackend.flush();
+    });
+  });
+  
+  it('should set SetCSRFToken interceptor', () => {
+    expect(httpProviderObj).toBeDefined();
+    expect(httpProviderObj.interceptors).toContain('SetCSRFToken');
+  });
+
+});
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/spec/label_formatter.test.js b/views/ngXosLib/xosHelpers/spec/label_formatter.test.js
new file mode 100644
index 0000000..119f4ce
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/spec/label_formatter.test.js
@@ -0,0 +1,42 @@
+(function () {
+  'use strict';
+
+  describe('The xos.helper module', function(){
+    describe('The label formatter service', () => {
+
+      let service;
+
+      // load the application module
+      beforeEach(module('xos.helpers'));
+
+      // inject the cartService
+      beforeEach(inject(function (_LabelFormatter_) {
+        // The injector unwraps the underscores (_) from around the parameter names when matching
+        service = _LabelFormatter_;
+      }));
+
+      it('should replace underscores in a string', () => {
+        expect(service._formatByUnderscore('my_test')).toEqual('my test');
+        expect(service._formatByUnderscore('_test')).toEqual('test');
+      });
+
+      it('should split a camel case string', () => {
+        expect(service._formatByUppercase('myTest')).toEqual('my test');
+      });
+
+      it('should capitalize a string', () => {
+        expect(service._capitalize('my test')).toEqual('My test');
+      });
+
+      it('should format an object property to a label', () => {
+        expect(service.format('myWeird_String')).toEqual('My weird string:');
+      });
+
+      it('should not add column if already present', () => {
+        expect(service.format('myWeird_String:')).toEqual('My weird string:');
+      });
+
+    });
+  });
+
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/spec/log.test.js b/views/ngXosLib/xosHelpers/spec/log.test.js
new file mode 100644
index 0000000..21085c6
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/spec/log.test.js
@@ -0,0 +1,57 @@
+/**
+ * © OpenCORD
+ *
+ * Created by teone on 4/18/16.
+ */
+/* eslint-disable angular/ng_window_service*/
+
+// TODO write tests for log
+// NODE Actually the code is working, the tests are not.
+
+(function () {
+  'use strict';
+
+  xdescribe('The xos.helper module', function(){
+
+    let log, window;
+
+    let mockLog;
+
+    beforeEach(function() {
+      mockLog = jasmine.createSpyObj('logMock', ['info']);
+    });
+
+    beforeEach(function() {
+      angular.mock.module('xos.helpers', function($injector, $provide) {
+        // console.log('$injector',$injector.get('logDecorator'));
+        $provide.value('$log', mockLog);
+        // $provide.decorator('$log', $injector.get('logDecorator'));
+      });
+    });
+
+    beforeEach(inject(($log, $window) => {
+      log = $log;
+      window = $window;
+      // log.reset();
+    }));
+
+    describe('The log decorator', () => {
+      it('should not print anything', inject(($log) => {
+        // spyOn(log, 'info');
+        $log.info('test');
+        expect(mockLog.info).not.toHaveBeenCalled();
+      }));
+
+    });
+    describe('if logging is enabled', () => {
+      beforeEach(() => {
+        window.location.href += '?debug=true'
+      });
+
+      it('should should log', () => {
+        log.info('test');
+        console.log(log.info.logs);
+      });
+    });
+  });
+})();
diff --git a/views/ngXosLib/xosHelpers/spec/noHyperlinks.test.js b/views/ngXosLib/xosHelpers/spec/noHyperlinks.test.js
new file mode 100644
index 0000000..7b6e9d0
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/spec/noHyperlinks.test.js
@@ -0,0 +1,51 @@
+/**
+ * © OpenCORD
+ *
+ * Visit http://guide.xosproject.org/devguide/addview/ for more information
+ *
+ * Created by teone on 3/24/16.
+ */
+
+(function () {
+  'use strict';
+
+  describe('The xos.helper module', function(){
+    describe('The NoHyperlinks factory', () => {
+
+      let httpProviderObj, noHyperlinks;
+
+      beforeEach(() => {
+        module(
+          'xos.helpers',
+          ($httpProvider) => {
+            //save our interceptor
+            httpProviderObj = $httpProvider;
+          }
+        );
+
+        inject(function (_NoHyperlinks_) {
+          noHyperlinks = _NoHyperlinks_
+        });
+
+        httpProviderObj.interceptors.push('NoHyperlinks');
+
+      });
+
+      it('should set NoHyperlinks interceptor', () => {
+        expect(httpProviderObj.interceptors).toContain('NoHyperlinks');
+      });
+
+      it('should attach ?no_hyperlinks=1 to the request url', () => {
+        let result = noHyperlinks.request({url: 'sample.url'});
+        expect(result.url).toEqual('sample.url?no_hyperlinks=1');
+      });
+
+      it('should NOT attach ?no_hyperlinks=1 to the request url if is HTML', () => {
+        let result = noHyperlinks.request({url: 'sample.html'});
+        expect(result.url).toEqual('sample.html');
+      });
+
+    });
+  });
+})();
+
diff --git a/views/ngXosLib/xosHelpers/spec/notification.test.js b/views/ngXosLib/xosHelpers/spec/notification.test.js
new file mode 100644
index 0000000..cbc1e56
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/spec/notification.test.js
@@ -0,0 +1,63 @@
+(function () {
+  'use strict';
+
+  describe('The xos.helper module', function(){
+    describe('The xosNotification service', () => {
+
+      let service, scope;
+
+      const options = {icon: 'icon', body: 'message'};
+
+      let notificationMock = {
+        requestPermission: () => {
+          return {
+            then: cb => cb('granted')
+          }
+        },
+        permission: 'granted'
+      }
+
+
+      // load the application module
+      beforeEach(module('xos.helpers', ($provide) => {
+        $provide.value('Notification', notificationMock);
+      }));
+
+      // inject the cartService
+      beforeEach(inject(function (_xosNotification_, $rootScope) {
+        // The injector unwraps the underscores (_) from around the parameter names when matching
+        service = _xosNotification_;
+        scope = $rootScope;
+        spyOn(service, 'sendNotification');
+        spyOn(service, 'checkPermission').and.callThrough();
+        spyOn(notificationMock, 'requestPermission').and.callThrough();
+      }));
+
+      it('should exist', () => {
+        expect(service).toBeDefined();
+      });
+
+      describe('when permission are granted', () => {
+        it('should send the notification', () => {
+          service.notify('Test', options);
+          expect(service.sendNotification).toHaveBeenCalledWith('Test', options);
+        });
+      });
+
+      describe('when permission are not granted', () => {
+        beforeEach(() => {
+          notificationMock.permission = false;
+        });
+
+        it('should request permission', () => {
+          service.notify('Test', options);
+          expect(service.checkPermission).toHaveBeenCalled();
+          scope.$apply(); // this resolve the promise
+          expect(service.sendNotification).toHaveBeenCalledWith('Test', options);
+        });
+      });
+
+    });
+  });
+
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/spec/services/helpers/comparator.test.js b/views/ngXosLib/xosHelpers/spec/services/helpers/comparator.test.js
new file mode 100644
index 0000000..66e26d3
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/spec/services/helpers/comparator.test.js
@@ -0,0 +1,60 @@
+(function () {
+  'use strict';
+
+  describe('The xos.helper module', function(){
+    describe('The Comparator service', () => {
+
+      let service;
+
+      // load the application module
+      beforeEach(module('xos.helpers'));
+
+      // inject the cartService
+      beforeEach(inject(function (_Comparator_) {
+        // The injector unwraps the underscores (_) from around the parameter names when matching
+        service = _Comparator_;
+      }));
+
+      describe('given a string', () => {
+        it('should return true if expected is substring of actual', () => {
+          const res = service('test', 'te');
+          expect(res).toBeTruthy();
+        });
+
+        it('should return false if expected is not substring of actual', () => {
+          const res = service('test', 'ab');
+          expect(res).toBeFalsy();
+        });
+      });
+
+      describe('given a boolean', () => {
+        it('should return true if values match', () => {
+          expect(service(false, false)).toBeTruthy();
+          expect(service(true, true)).toBeTruthy();
+          expect(service(0, false)).toBeTruthy();
+          expect(service(1, true)).toBeTruthy();
+        });
+
+        it('should return false if values doesn\'t match', () => {
+          expect(service(false, true)).toBeFalsy();
+          expect(service(true, false)).toBeFalsy();
+          expect(service(1, false)).toBeFalsy();
+          expect(service(0, true)).toBeFalsy();
+        });
+      });
+
+      describe('given a number', () => {
+        // NOTE if numbers should we compare with === ??
+        it('should return true if expected is substring of actual', () => {
+          expect(service(12, 1)).toBeTruthy();
+        });
+
+        it('should return false if expected is not substring of actual', () => {
+          expect(service(12, 3)).toBeFalsy();
+        });
+      });
+
+    });
+  });
+
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/spec/services/helpers/form.helpers.test.js b/views/ngXosLib/xosHelpers/spec/services/helpers/form.helpers.test.js
new file mode 100644
index 0000000..a126db5
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/spec/services/helpers/form.helpers.test.js
@@ -0,0 +1,335 @@
+/**
+ * © OpenCORD
+ *
+ * Created by teone on 5/25/16.
+ */
+
+(function () {
+  'use strict';
+
+  describe('The xos.helper module', function(){
+
+    describe('The XosFormHelper service', () => {
+      let service;
+
+      let fields = [
+        'id',
+        'name',
+        'mail',
+        'active',
+        'created'
+      ];
+
+      let modelField = {
+        id: {},
+        name: {},
+        mail: {},
+        active: {},
+        created: {}
+      };
+
+      let model = {
+        id: 1,
+        name: 'test',
+        mail: 'test@onlab.us',
+        active: true,
+        created: '2016-04-18T23:44:16.883181Z',
+        custom: 'MyCustomValue'
+      };
+
+      let customField = {
+        id: {
+          label: 'Id',
+          type: 'number',
+          validators: {
+            required: true
+          },
+          hint: ''
+        },
+        custom: {
+          label: 'Custom Label',
+          type: 'number',
+          validators: {},
+          hint: 'Test Hint'
+        }
+      };
+
+      let formObject = {
+        id: {
+          label: 'Id:',
+          type: 'number',
+          validators: {
+            required: true
+          },
+          hint: ''
+        },
+        name: {
+          label: 'Name:',
+          type: 'text',
+          validators: {},
+          hint: ''
+        },
+        mail: {
+          label: 'Mail:',
+          type: 'email',
+          validators: {},
+          hint: ''
+        },
+        active: {
+          label: 'Active:',
+          type: 'boolean',
+          validators: {},
+          hint: ''
+        },
+        created: {
+          label: 'Created:',
+          type: 'date',
+          validators: {},
+          hint: ''
+        },
+        custom: {
+          label: 'Custom Label:',
+          type: 'number',
+          validators: {},
+          hint: 'Test Hint'
+        }
+      };
+
+      // load the application module
+      beforeEach(module('xos.helpers'));
+
+      // inject the cartService
+      beforeEach(inject(function (_XosFormHelpers_) {
+        // The injector unwraps the underscores (_) from around the parameter names when matching
+        service = _XosFormHelpers_;
+      }));
+
+      describe('the _isEmail method', () => {
+        it('should return true', () => {
+          expect(service._isEmail('test@onlab.us')).toEqual(true);
+        });
+        it('should return false', () => {
+          expect(service._isEmail('testonlab.us')).toEqual(false);
+          expect(service._isEmail('test@onlab')).toEqual(false);
+        });
+      });
+
+      describe('the _getFieldFormat method', () => {
+        it('should return text', () => {
+          expect(service._getFieldFormat('a random text')).toEqual('text');
+          expect(service._getFieldFormat(null)).toEqual('text');
+          expect(service._getFieldFormat('1')).toEqual('text');
+        });
+        it('should return mail', () => {
+          expect(service._getFieldFormat('test@onlab.us')).toEqual('email');
+        });
+        it('should return number', () => {
+          expect(service._getFieldFormat(1)).toEqual('number');
+        });
+        it('should return boolean', () => {
+          expect(service._getFieldFormat(false)).toEqual('boolean');
+          expect(service._getFieldFormat(true)).toEqual('boolean');
+        });
+
+        it('should return date', () => {
+          expect(service._getFieldFormat('2016-04-19T23:09:1092Z')).toEqual('text');
+          expect(service._getFieldFormat(new Date())).toEqual('date');
+          expect(service._getFieldFormat('2016-04-19T23:09:10.208092Z')).toEqual('date');
+        });
+
+        it('should return array', () => {
+          expect(service._getFieldFormat([])).toEqual('array');
+          expect(service._getFieldFormat(['a', 'b'])).toEqual('array');
+        });
+
+        it('should return object', () => {
+          expect(service._getFieldFormat({})).toEqual('object');
+          expect(service._getFieldFormat({foo: 'bar'})).toEqual('object');
+        });
+      });
+
+      describe('the parseModelField mehtod', () => {
+        it('should convert the fields array in an empty form object', () => {
+          expect(service.parseModelField(fields)).toEqual(modelField);
+        });
+
+        xit('should handle nested config', () => {
+          
+        });
+      });
+
+      describe('when modelField are provided', () => {
+        it('should combine modelField and customField in a form object', () => {
+          const form = service.buildFormStructure(modelField, customField, model);
+          expect(form).toEqual(formObject);
+        });
+
+        it('should override modelField properties whith customField properties', () => {
+          const customFieldOverride = {
+            id: {
+              hint: 'something',
+              type: 'select',
+              options: [
+                {id: 1, label: 'one'},
+                {id: 2, label: 'two'}
+              ],
+              validators: {
+                required: true
+              }
+            }
+          };
+          const form = service.buildFormStructure({id: {}}, customFieldOverride, model);
+          
+          expect(form).toEqual({
+            id: {
+              label: 'Id:',
+              validators: {required: true},
+              hint: customFieldOverride.id.hint,
+              type: customFieldOverride.id.type,
+              options: customFieldOverride.id.options
+            }
+          });
+        });
+      });
+
+      describe('when model field is an empty array', () => {
+        let empty_modelField = {
+          // 5: {}
+        };
+        let empty_customFields = {
+          id: {
+            label: 'Id',
+            type: 'number'
+          },
+          name: {
+            label: 'Name',
+            type: 'text'
+          },
+          mail: {
+            label: 'Mail',
+            type: 'email'
+          },
+          active: {
+            label: 'Active',
+            type: 'boolean'
+          },
+          created: {
+            label: 'Created',
+            type: 'date'
+          },
+          custom: {
+            label: 'Custom Label',
+            type: 'number',
+            hint: 'Test Hint'
+          },
+          select: {
+            label: 'Select Label',
+            type: 'select',
+            hint: 'Select Hint',
+            options: [
+              {id: 1, label: 'something'}
+            ]
+          },
+          object: {
+            label: 'Object Label',
+            type: 'object',
+            hint: 'Object Hint',
+            properties: {
+              foo: {
+                type: 'string',
+                label: 'FooLabel',
+                validators: {
+                  required: true
+                }
+              },
+              bar: {
+                type: 'number'
+              }
+            }
+          }
+        };
+
+        let empty_formObject = {
+          id: {
+            label: 'Id:',
+            type: 'number',
+            validators: {},
+            hint: ''
+          },
+          name: {
+            label: 'Name:',
+            type: 'text',
+            validators: {},
+            hint: ''
+          },
+          mail: {
+            label: 'Mail:',
+            type: 'email',
+            validators: {},
+            hint: ''
+          },
+          active: {
+            label: 'Active:',
+            type: 'boolean',
+            validators: {},
+            hint: ''
+          },
+          created: {
+            label: 'Created:',
+            type: 'date',
+            validators: {},
+            hint: ''
+          },
+          custom: {
+            label: 'Custom Label:',
+            type: 'number',
+            validators: {},
+            hint: 'Test Hint'
+          },
+          select: {
+            label: 'Select Label:',
+            type: 'select',
+            hint: 'Select Hint',
+            validators: {},
+            options: [
+              {id: 1, label: 'something'}
+            ]
+          },
+          object: {
+            label: 'Object Label:',
+            type: 'object',
+            hint: 'Object Hint',
+            validators: {},
+            properties: {
+              foo: {
+                type: 'string',
+                label: 'FooLabel',
+                validators: {
+                  required: true
+                }
+              },
+              bar: {
+                type: 'number'
+              }
+            }
+          }
+        };
+
+        let empty_model = {5: 'Nan'}
+
+        it('should create a form object', () => {
+          let res = service.buildFormStructure(empty_modelField, empty_customFields, empty_model);
+          expect(res.id).toEqual(empty_formObject.id);
+          expect(res.name).toEqual(empty_formObject.name);
+          expect(res.mail).toEqual(empty_formObject.mail);
+          expect(res.active).toEqual(empty_formObject.active);
+          expect(res.created).toEqual(empty_formObject.created);
+          expect(res.custom).toEqual(empty_formObject.custom);
+          expect(res.select).toEqual(empty_formObject.select);
+          expect(res.object).toEqual(empty_formObject.object);
+          expect(res).toEqual(empty_formObject);
+        });
+      });
+    });
+  });
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/spec/services/helpers/user-prefs.test.js b/views/ngXosLib/xosHelpers/spec/services/helpers/user-prefs.test.js
new file mode 100644
index 0000000..4c76484
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/spec/services/helpers/user-prefs.test.js
@@ -0,0 +1,113 @@
+/**
+ * © OpenCORD
+ *
+ * Created by teone on 5/25/16.
+ */
+
+(function () {
+  'use strict';
+  let service;
+  let cookies = {
+    xosUserPrefs: JSON.stringify({test: true})
+  };
+
+  const cookieMock = {
+    get: (name) => {
+      return cookies[name]
+    },
+    put: (name, value) => {
+      cookies[name] = value
+    }
+  };
+
+  describe('The xos.helper module', function(){
+
+    describe('The XosUserPrefs service', () => {
+
+      // load the application module
+      beforeEach(module('xos.helpers', ($provide) => {
+        $provide.value('$cookies', cookieMock);
+      }));
+
+      // inject the cartService
+      beforeEach(inject(function (_XosUserPrefs_) {
+        // The injector unwraps the underscores (_) from around the parameter names when matching
+        service = _XosUserPrefs_;
+        spyOn(cookieMock, 'put').and.callThrough();
+      }));
+
+      it('should exists and have methods', () => {
+        expect(service).toBeDefined();
+        expect(service.getAll).toBeDefined();
+        expect(service.setAll).toBeDefined();
+        expect(service.getSynchronizerNotificationStatus).toBeDefined();
+        expect(service.setSynchronizerNotificationStatus).toBeDefined();
+      });
+
+      describe('the getAll method', () => {
+        it('should return all the stored prefs', () => {
+          let prefs = service.getAll();
+          expect(prefs).toEqual(JSON.parse(cookies.xosUserPrefs));
+        });
+      });
+
+      describe('the setAll method', () => {
+        it('should override all preferences', () => {
+          service.setAll({test: true, updated: true});
+          expect(JSON.parse(cookies.xosUserPrefs)).toEqual({test: true, updated: true});
+        });
+      });
+
+      describe('the synchronizers status', () => {
+        let syncNotification;
+        beforeEach(() => {
+          syncNotification = {
+            synchronizers: {
+              notification: {
+                first: true,
+                second: false
+              }
+            }
+          }
+          cookies.xosUserPrefs = JSON.stringify(syncNotification);
+        });
+
+        describe('the getSynchronizerNotificationStatus method', () => {
+          it('should return notification status for all synchronizers', () => {
+            expect(service.getSynchronizerNotificationStatus()).toEqual(syncNotification.synchronizers.notification);
+          });
+
+          it('should return notification status for a single synchronizers', () => {
+            expect(service.getSynchronizerNotificationStatus('first')).toEqual(syncNotification.synchronizers.notification.first);
+            expect(service.getSynchronizerNotificationStatus('second')).toEqual(syncNotification.synchronizers.notification.second);
+          });
+        });
+
+        describe('the setSynchronizerNotificationStatus', () => {
+          
+          it('should throw an error if called without synchronizer name', () => {
+            function wrapper (){
+              service.setSynchronizerNotificationStatus();
+            }
+            expect(wrapper).toThrowError('[XosUserPrefs] When updating a synchronizer is mandatory to provide a name.');
+          });
+
+          it('should update a synchronizer notification status', () => {
+            service.setSynchronizerNotificationStatus('second', true);
+            expect(service.getSynchronizerNotificationStatus('second')).toEqual(true);
+            expect(service.getSynchronizerNotificationStatus('first')).toEqual(true);
+
+            // should persist the change
+            expect(cookieMock.put).toHaveBeenCalledWith('xosUserPrefs', '{"synchronizers":{"notification":{"first":true,"second":true}}}');
+          });
+
+          it('should handle empty cookies', () => {
+            cookies.xosUserPrefs = '';
+            service.setSynchronizerNotificationStatus('second', true);
+            expect(service.getSynchronizerNotificationStatus('second')).toEqual(true);
+          });
+        });
+      });
+    });
+  });
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/spec/test_helpers.js b/views/ngXosLib/xosHelpers/spec/test_helpers.js
new file mode 100644
index 0000000..b78bf3d
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/spec/test_helpers.js
@@ -0,0 +1,17 @@
+/**
+ * Collection of helpers for xos tests
+ */
+
+const clickElement = function (el){
+  var ev = document.createEvent("MouseEvent");
+  ev.initMouseEvent(
+    "click",
+    true /* bubble */, true /* cancelable */,
+    window, null,
+    0, 0, 0, 0, /* coordinates */
+    false, false, false, false, /* modifier keys */
+    0 /*left*/, null
+  );
+  el.dispatchEvent(ev);
+};
+console.log('---------------------- Test Helpers Loaded!! -----------------------');
diff --git a/views/ngXosLib/xosHelpers/spec/ui/alert.test.js b/views/ngXosLib/xosHelpers/spec/ui/alert.test.js
new file mode 100644
index 0000000..c67d03a
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/spec/ui/alert.test.js
@@ -0,0 +1,131 @@
+/**
+ * © OpenCORD
+ *
+ * Created by teone on 4/15/16.
+ */
+
+(function () {
+  'use strict';
+
+  describe('The xos.helper module', function(){
+    describe('The xos-alert component', () => {
+
+      let element, scope, isolatedScope;
+
+      let message = 'Test Error Message';
+
+      beforeEach(module('xos.helpers'));
+
+      it('should throw an error if no config is specified', inject(($compile, $rootScope) => {
+        function errorFunctionWrapper(){
+          $compile(angular.element('<xos-alert></xos-alert>'))($rootScope);
+          $rootScope.$digest();
+        }
+        expect(errorFunctionWrapper).toThrow(new Error('[xosAlert] Please provide a configuration via the "config" attribute'));
+      }));
+
+      describe('when correctly configured', () => {
+        beforeEach(inject(($compile, $rootScope) => {
+
+          scope = $rootScope.$new();
+
+          scope.config = {
+            type: 'danger',
+            closeBtn: true
+          };
+
+          element = angular.element(`<xos-alert config="config">${message}</xos-alert>`);
+          $compile(element)(scope);
+          scope.$digest();
+          isolatedScope = element.isolateScope().vm;
+        }));
+
+        it('should transclude the message', () => {
+          let textContainer = element[0].getElementsByTagName('p')[0];
+          let text = angular.element(textContainer).text();
+          expect(text).toEqual(message)
+        });
+
+        it('should have a close button', () => {
+          let btn = element[0].getElementsByTagName('button');
+          expect(btn.length).toEqual(1);
+        });
+
+        describe('when the close button is clicked', () => {
+          it('should hide the alert', () => {
+            let btn = element[0].getElementsByTagName('button')[0];
+            btn.click();
+            let alert = angular.element(element[0].querySelectorAll('.alert')[0]);
+            expect(alert.hasClass('ng-hide')).toBeTruthy();
+          });
+        });
+
+        describe('when autoHide is set', () => {
+
+          let to;
+
+          beforeEach(inject(($compile, $rootScope, $timeout) => {
+            scope = $rootScope.$new();
+
+            scope.config = {
+              type: 'danger',
+              closeBtn: true,
+              autoHide: 500
+            };
+
+            to = $timeout;
+
+            element = angular.element(`<xos-alert config="config">${message}</xos-alert>`);
+            $compile(element)(scope);
+            scope.$digest();
+            isolatedScope = element.isolateScope().vm;
+          }));
+
+          it('should hide the alert', () => {
+            to.flush();
+            expect(isolatedScope.show).toBeFalsy();
+            let alert = angular.element(element[0].querySelectorAll('.alert')[0]);
+            expect(alert.hasClass('ng-hide')).toBeTruthy();
+          });
+        });
+
+        describe('when show is set to false', () => {
+
+          beforeEach(inject(($compile, $rootScope) => {
+            scope = $rootScope.$new();
+
+            scope.config = {
+              type: 'danger',
+              closeBtn: true
+            };
+
+            scope.show = false;
+
+            element = angular.element(`<xos-alert config="config" show="show">${message}</xos-alert>`);
+            $compile(element)(scope);
+            scope.$digest();
+            isolatedScope = element.isolateScope().vm;
+          }));
+
+          it('should hide the alert', () => {
+            let alert = angular.element(element[0].querySelectorAll('.alert')[0]);
+            expect(alert.hasClass('ng-hide')).toBeTruthy();
+          });
+
+          describe('when show is changed to true', () => {
+            beforeEach(() => {
+              scope.show = true;
+              scope.$digest();
+            });
+
+            it('should show the alert', () => {
+              let alert = angular.element(element[0].querySelectorAll('.alert')[0]);
+              expect(alert.hasClass('ng-hide')).toBeFalsy();
+            });
+          });
+        });
+
+      });
+    });
+  });
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/spec/ui/custom-validator.test.js b/views/ngXosLib/xosHelpers/spec/ui/custom-validator.test.js
new file mode 100644
index 0000000..76f41a9
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/spec/ui/custom-validator.test.js
@@ -0,0 +1,107 @@
+/**
+ * © OpenCORD
+ *
+ * Created by teone on 5/25/16.
+ */
+
+(function () {
+  'use strict';
+
+  describe('The xos.helper module', function () {
+    describe('The xosCustomValidator directive', () => {
+      let element, scope, isolatedScope, rootScope, compile, form, input;
+      const compileElement = (el) => {
+        element = el;
+
+        if(!scope){
+          scope = rootScope.$new();
+        }
+        if(angular.isUndefined(element)){
+          element = angular.element(`
+            <form name="form">
+              <input name="testInput" type="text" ng-model="value" xos-custom-validator custom-validator="validator"/>
+            </form>
+          `);
+        }
+        compile(element)(scope);
+        scope.$digest();
+        input = $(element).find('input');
+        isolatedScope = angular.element(input).isolateScope();
+        form = scope.form;
+      };
+
+      beforeEach(module('xos.helpers'));
+
+      beforeEach(inject(function ($compile, $rootScope) {
+        compile = $compile;
+        rootScope = $rootScope;
+      }));
+
+      beforeEach(() => {
+        scope = rootScope.$new();
+        scope.validator = 'validator';
+        scope.value = '';
+        compileElement();
+      });
+
+      it('should bind the validator', () => {
+        expect(isolatedScope.fn).toEqual('validator');
+      });
+
+      describe('given a validator function', () => {
+
+        beforeEach(() => {
+          scope = rootScope.$new();
+          scope.value = '';
+          scope.validator = (model) => angular.equals(model, 'test');
+          spyOn(scope, 'validator').and.callThrough();
+          compileElement();
+        });
+
+        it('should call the validator function on value change', () => {
+          form.testInput.$setViewValue('something');
+          scope.$digest();
+          expect(scope.validator).toHaveBeenCalledWith('something');
+          expect(scope.value).toEqual('something');
+        });
+
+        it('should set the field invalid', () => {
+          form.testInput.$setViewValue('something');
+          scope.$digest();
+          expect(scope.validator).toHaveBeenCalledWith('something');
+          expect(input).toHaveClass('ng-invalid');
+          expect(input).toHaveClass('ng-invalid-custom-validation');
+        });
+
+        it('should set the field valid', () => {
+          form.testInput.$setViewValue('test');
+          scope.$digest();
+          expect(scope.validator).toHaveBeenCalledWith('test');
+          expect(input).not.toHaveClass('ng-invalid');
+          expect(input).not.toHaveClass('ng-invalid-custom-validation');
+        });
+
+        describe('if the validation function return an array', () => {
+
+          beforeEach(() => {
+            scope = rootScope.$new();
+            scope.value = '';
+            scope.validator = (model) => {
+              return ['randomTest', angular.equals(model, 'test')];
+            };
+            spyOn(scope, 'validator').and.callThrough();
+            compileElement();
+          });
+
+          it('should set the field invalid', () => {
+            form.testInput.$setViewValue('something');
+            scope.$digest();
+            expect(scope.validator).toHaveBeenCalledWith('something');
+            expect(input).toHaveClass('ng-invalid');
+            expect(input).toHaveClass('ng-invalid-random-test');
+          });
+        });
+      });
+    });
+  });
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/spec/ui/field.test.js b/views/ngXosLib/xosHelpers/spec/ui/field.test.js
new file mode 100644
index 0000000..8a02d4d
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/spec/ui/field.test.js
@@ -0,0 +1,330 @@
+/**
+ * © OpenCORD
+ *
+ * Created by teone on 5/25/16.
+ */
+
+(function () {
+  'use strict';
+
+  describe('The xos.helper module', function(){
+
+    describe('The xosField component', () => {
+      let element, scope, isolatedScope, rootScope, compile;
+      const compileElement = (el) => {
+        element = el;
+
+        if(!scope){
+          scope = rootScope.$new();
+        }
+        if(angular.isUndefined(element)){
+          element = angular.element('<xos-field name="name" field="field" ng-model="ngModel"></xos-field>');
+        }
+        compile(element)(scope);
+        scope.$digest();
+        isolatedScope = element.isolateScope().vm;
+      };
+
+      beforeEach(module('xos.helpers'));
+
+      beforeEach(inject(function ($compile, $rootScope) {
+        compile = $compile;
+        rootScope = $rootScope;
+      }));
+
+      it('should throw an error if no name is passed', inject(($compile, $rootScope) => {
+        function errorFunctionWrapper(){
+          // setup the parent scope
+          scope = $rootScope.$new();
+          scope.field = {
+            label: 'Label',
+            type: 'number',
+            validators: {}
+          };
+          scope.ngModel = 1;
+          compileElement();
+        }
+        expect(errorFunctionWrapper).toThrow(new Error('[xosField] Please provide a field name'));
+      }));
+
+      it('should throw an error if no field definition is passed', inject(($compile, $rootScope) => {
+        function errorFunctionWrapper(){
+          // setup the parent scope
+          scope = $rootScope.$new();
+          scope.name = 'label';
+          scope.ngModel = 1;
+          compileElement();
+        }
+        expect(errorFunctionWrapper).toThrow(new Error('[xosField] Please provide a field definition'));
+      }));
+
+      it('should throw an error if no field type is passed', inject(($compile, $rootScope) => {
+        function errorFunctionWrapper(){
+          // setup the parent scope
+          scope = $rootScope.$new();
+          scope.name = 'label';
+          scope.ngModel = 1;
+          scope.field = {label: 'Label:'}
+          compileElement();
+        }
+        expect(errorFunctionWrapper).toThrow(new Error('[xosField] Please provide a type in the field definition'));
+      }));
+
+      it('should throw an error if no field model is passed', inject(($compile, $rootScope) => {
+        function errorFunctionWrapper(){
+          // setup the parent scope
+          scope = $rootScope.$new();
+          scope.name = 'label';
+          scope.field = {
+            label: 'Label',
+            type: 'number',
+            validators: {}
+          };
+          compileElement(angular.element('<xos-field name="name" field="field"></xos-field>'));
+        }
+        expect(errorFunctionWrapper).toThrow(new Error('[xosField] Please provide an ng-model'));
+      }));
+
+      describe('when a text input is passed', () => {
+        beforeEach(() => {
+          scope = rootScope.$new();
+          scope.name = 'label';
+          scope.field = {
+            label: 'Label',
+            type: 'text',
+            validators: {
+              custom: 'fake'
+            }
+          };
+          scope.ngModel = 'label';
+          compileElement();
+        });
+
+        it('should print a text field', () => {
+          expect($(element).find('[name="label"]')).toHaveAttr('type', 'text');
+        });
+
+        it('should attach the custom validator directive', () => {
+          let input = $(element).find('[name="label"]');
+          expect(input).toHaveAttr('xos-custom-validator');
+          expect(input).toHaveAttr('custom-validator', 'vm.field.validators.custom || null');
+        });
+      });
+
+      describe('when a option is selected in dropdown', () => {
+        beforeEach(() => {
+          scope = rootScope.$new();
+          scope.name = 'label';
+          scope.field = {
+            label: 'Label',
+            type: 'select',
+            validators: {},
+            options: [
+              {
+                id: 0,
+                label: '---Site---'
+              },
+              {
+                id: 1,
+                label: '---Site1---'
+              }
+            ]
+          };
+          scope.ngModel = 0;
+          compileElement();
+        });
+
+        it('No of select elements', () => {
+          expect($(element).find('select').children('option').length).toEqual(2);
+        });
+
+        it('should show the selected value', () => {
+          var elem =  angular.element($(element).find('select').children('option')[0]);
+          expect(elem.text()).toEqual('---Site---');
+          expect(elem).toHaveAttr('selected');
+        });
+      });
+
+      describe('when a number input is passed', () => {
+        beforeEach(() => {
+          scope = rootScope.$new();
+          scope.name = 'label';
+          scope.field = {
+            label: 'Label',
+            type: 'number',
+            validators: {}
+          };
+          scope.ngModel = 10;
+          compileElement();
+        });
+
+        it('should print a number field', () => {
+          expect($(element).find('[name="label"]')).toHaveAttr('type', 'number');
+        });
+      });
+
+      describe('when a boolean input is passed', () => {
+        beforeEach(() => {
+          scope = rootScope.$new();
+          scope.name = 'label';
+          scope.field = {
+            label: 'Label',
+            type: 'boolean',
+            validators: {}
+          };
+          scope.ngModel = true;
+          compileElement();
+        });
+
+        let setFalse, setTrue;
+
+        beforeEach(() => {
+          setFalse= $(element).find('.boolean-field > a:first-child');
+          setTrue = $(element).find('.boolean-field > a:last-child');
+        });
+
+        it('should print two buttons', () => {
+          expect($(element).find('.boolean-field > a').length).toEqual(2)
+        });
+
+        it('should change value to false', () => {
+          expect(isolatedScope.ngModel).toEqual(true);
+          clickElement(setFalse[0]);
+          expect(isolatedScope.ngModel).toEqual(false);
+        });
+
+        it('should change value to true', () => {
+          isolatedScope.ngModel = false;
+          scope.$apply();
+          expect(isolatedScope.ngModel).toEqual(false);
+          clickElement(setTrue[0]);
+          expect(isolatedScope.ngModel).toEqual(true);
+        });
+      });
+
+      describe('when an object input is passed', () => {
+        beforeEach(() => {
+          scope = rootScope.$new();
+          scope.name = 'label';
+          scope.field = {
+            label: 'Label',
+            type: 'object',
+            validators: {}
+          };
+          scope.ngModel = {
+            baz: true,
+            foo: 'bar',
+            foz: 1,
+          };
+          compileElement();
+        });
+
+        it('should print a panel to contain object property field', () => {
+          expect($(element).find('.panel.object-field')).toExist()
+        });
+
+        it('should print the right input type for each property', () => {
+          expect($(element).find('input').length).toBe(2);
+          expect($(element).find('.boolean-field > a').length).toEqual(2);
+        });
+
+        it('should format labels', () => {
+          expect($(element).find('input[name="foo"]').parent().find('label').text()).toBe('Foo:');
+        });
+
+        describe('and the model is empty', () => {
+          beforeEach(() => {
+            scope.ngModel = {
+            };
+            compileElement();
+          });
+
+          it('should not print the panel', () => {
+            expect($(element).find('.panel.object-field')).not.toExist()
+          });
+
+          describe('but field is configured', () => {
+            beforeEach(() => {
+              scope.field.properties = {
+                foo: {
+                  label: 'FooLabel:',
+                  type: 'string',
+                  validators: {
+                    required: true
+                  }
+                },
+                bar: {
+                  type: 'number'
+                }
+              };
+              compileElement();
+            });
+            it('should render panel and configured fields', () => {
+              expect($(element).find('.panel.object-field')).toExist();
+              expect($(element).find('input[name="foo"]').parent().find('label').text()).toBe('FooLabel:');
+              expect($(element).find('input[name="foo"]')).toHaveAttr('type', 'string');
+              expect($(element).find('input[name="foo"]')).toHaveAttr('required');
+
+              expect($(element).find('input[name="bar"]').parent().find('label').text()).toBe('Bar:');
+              expect($(element).find('input[name="bar"]')).toHaveAttr('type', 'number');
+
+            });
+          });
+        });
+      });
+
+      describe('when validation options are passed', () => {
+        let input;
+        describe('given a a text field', () => {
+          beforeEach(() => {
+            scope.field = {
+              label: 'Label',
+              type: 'text',
+              validators: {
+                minlength: 10,
+                maxlength: 15,
+                required: true
+              }
+            };
+
+            scope.$digest();
+            input = $(element).find('input');
+          });
+
+          it('should validate required', () => {
+            scope.ngModel= null;
+            scope.$digest();
+            expect(input).toHaveClass('ng-invalid-required');
+
+            scope.ngModel= 'not too short';
+            scope.$digest();
+            expect(input).not.toHaveClass('ng-invalid-required');
+            expect(input).not.toHaveClass('ng-invalid');
+          });
+
+          it('should validate minlength', () => {
+            scope.ngModel= 'short';
+            scope.$digest();
+            expect(input).toHaveClass('ng-invalid-minlength');
+
+            scope.ngModel= 'not too short';
+            scope.$digest();
+            expect(input).not.toHaveClass('ng-invalid-minlength');
+            expect(input).not.toHaveClass('ng-invalid');
+          });
+
+          it('should validate maxlength', () => {
+            scope.ngModel= 'this is definitely too long!!';
+            scope.$digest();
+            expect(input).toHaveClass('ng-invalid-maxlength');
+
+            scope.ngModel= 'not too short';
+            scope.$digest();
+            expect(input).not.toHaveClass('ng-invalid-maxlength');
+            expect(input).not.toHaveClass('ng-invalid');
+          });
+        });
+      });
+    });
+  });
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/spec/ui/form.test.js b/views/ngXosLib/xosHelpers/spec/ui/form.test.js
new file mode 100644
index 0000000..87f671a
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/spec/ui/form.test.js
@@ -0,0 +1,269 @@
+/**
+ * © OpenCORD
+ *
+ * Created by teone on 4/18/16.
+ */
+
+(function () {
+  'use strict';
+
+  let element, scope, isolatedScope, rootScope, compile;
+
+  const compileElement = () => {
+
+    if(!scope){
+      scope = rootScope.$new();
+    }
+
+    element = angular.element(`<xos-form config="config" ng-model="model"></xos-form>`);
+    compile(element)(scope);
+    scope.$digest();
+    isolatedScope = element.isolateScope().vm;
+  }
+
+  describe('The xos.helper module', function(){
+
+    describe('The xos-form component', () => {
+
+
+      beforeEach(module('xos.helpers'));
+
+      beforeEach(inject(($compile, $rootScope) => {
+        rootScope = $rootScope;
+        compile = $compile;
+      }));
+
+      it('should throw an error if no config is specified', () => {
+        function errorFunctionWrapper(){
+          compileElement();
+        }
+        expect(errorFunctionWrapper).toThrow(new Error('[xosForm] Please provide a configuration via the "config" attribute'));
+      });
+
+      it('should throw an error if no actions is specified', () => {
+        function errorFunctionWrapper(){
+          scope = rootScope.$new();
+          scope.config = 'green';
+          compileElement();
+        }
+        expect(errorFunctionWrapper).toThrow(new Error('[xosForm] Please provide an action list in the configuration'));
+      });
+
+      describe('when correctly configured', () => {
+        
+        let cb = jasmine.createSpy('callback');
+
+        beforeEach(inject(($rootScope) => {
+
+          scope = $rootScope.$new();
+
+          scope.config = {
+            exclude: ['excludedField'],
+            formName: 'testForm',
+            actions: [
+              {
+                label: 'Save',
+                icon: 'ok', // refers to bootstraps glyphicon
+                cb: cb,
+                class: 'success'
+              }
+            ],
+            fields: {
+              first_name: {
+                label: 'Custom Label'
+              }
+            }
+          };
+
+          scope.model = {
+            id: 1,
+            first_name: 'Jhon',
+            last_name: 'Snow',
+            age: 25,
+            email: 'test@onlab.us',
+            birthDate: '2016-04-18T23:44:16.883181Z',
+            enabled: true,
+            role: 'user', //select
+            a_permissions: [
+            ],
+            object_field: {
+              string: 'bar',
+              number: 1,
+              email: 'teo@onlab.us'
+            }
+          };
+
+          compileElement();
+        }));
+
+        it('should add excluded properties to the list', () => {
+          let expected = ['id', 'validators', 'created', 'updated', 'deleted', 'backend_status', 'excludedField'];
+          expect(isolatedScope.excludedField).toEqual(expected);
+        });
+
+        it('should render 10 input field', () => {
+          // boolean are in the form model, but are not input
+          expect(Object.keys(isolatedScope.formField).length).toEqual(9);
+          var field = element[0].getElementsByTagName('input');
+          expect(field.length).toEqual(10);
+        });
+
+        it('should render 1 boolean field', () => {
+          expect($(element).find('.boolean-field > a').length).toEqual(2)
+        });
+
+        it('when clicking on action should invoke callback', () => {
+          var link = $(element).find('[role="button"]');
+          //console.log(link);
+          link.click();
+          // TODO : Check correct parameters
+          expect(cb).toHaveBeenCalled();
+
+        });
+
+        it('should set a custom label', () => {
+          let nameField = element[0].getElementsByClassName('form-group')[0];
+          let label = angular.element(nameField.getElementsByTagName('label')[0]).text()
+          expect(label).toEqual('Custom Label:');
+        });
+
+        it('should use the correct input type', () => {
+          expect($(element).find('[name="age"]')).toHaveAttr('type', 'number');
+          expect($(element).find('[name="birthDate"]')).toHaveAttr('type', 'date');
+          expect($(element).find('[name="email"]')).toHaveAttr('type', 'email');
+        });
+
+        xdescribe('the boolean field test', () => {
+
+          let setFalse, setTrue;
+
+          beforeEach(() => {
+            setFalse= $(element).find('.boolean-field > button:first-child');
+            setTrue = $(element).find('.boolean-field > button:last-child');
+          });
+
+          it('should change value to false', () => {
+            expect(isolatedScope.ngModel.enabled).toEqual(true);
+            setFalse.click();
+            expect(isolatedScope.ngModel.enabled).toEqual(false);
+          });
+
+          it('should change value to true', () => {
+            isolatedScope.ngModel.enabled = false;
+            scope.$apply();
+            expect(isolatedScope.ngModel.enabled).toEqual(false);
+            setTrue.click()
+            expect(isolatedScope.ngModel.enabled).toEqual(true);
+          });
+        });
+
+        describe('when a deep model is passed', () => {
+
+          beforeEach(inject(($rootScope) => {
+
+            scope = $rootScope.$new();
+
+            scope.config = {
+              exclude: ['excludedField'],
+              formName: 'testForm',
+              actions: [
+                {
+                  label: 'Save',
+                  icon: 'ok', // refers to bootstraps glyphicon
+                  cb: cb,
+                  class: 'success'
+                }
+              ],
+              fields: {
+                object_field: {
+                  field_one: {
+                    label: 'Custom Label'
+                  }
+                }
+              }
+            };
+
+            scope.model = {
+              object_field: {
+                field_one: 'bar',
+                number: 1,
+                email: 'teo@onlab.us'
+              }
+            };
+
+            compileElement();
+          }));
+
+          it('should print nested field', () => {
+            expect($(element).find('input').length).toBe(3);
+          });
+
+          xit('should configure nested fields', () => {
+            let custom_label = $(element).find('input[name=field_one]').parent().find('label');
+            expect(custom_label.text()).toBe('Custom Label');
+          });
+        });
+      });
+      describe('when correctly configured for feedback', () => {
+
+        let fb = jasmine.createSpy('feedback').and.callFake(function(statusFlag) {
+          if(statusFlag){
+            scope.config.feedback.show = true;
+            scope.config.feedback.message = 'Form Submitted';
+            scope.config.feedback.type = 'success';
+          }
+          else {
+            scope.config.feedback.show = true;
+            scope.config.feedback.message = 'Error';
+            scope.config.feedback.type = 'danger';
+
+          }
+        });
+
+        beforeEach(()=> {
+          scope = rootScope.$new();
+          scope.config =
+          {
+
+            feedback: {
+              show: false,
+              message: 'Form submitted successfully !!!',
+              type: 'success'
+            },
+            actions: [
+              {
+                label: 'Save',
+                icon: 'ok', // refers to bootstraps glyphicon
+                cb: () => {},
+                class: 'success'
+              }
+            ]
+          };
+          scope.model={};
+          compileElement();
+        });
+
+        it('should not show feedback when loaded', () => {
+          expect($(element).find('xos-alert > div')).toHaveClass('alert alert-success ng-hide');
+        });
+
+        it('should show a success feedback', () => {
+          fb(true);
+          scope.$digest();
+          expect(isolatedScope.config.feedback.type).toEqual('success');
+          expect(fb).toHaveBeenCalledWith(true);
+          expect($(element).find('xos-alert > div')).toHaveClass('alert alert-success');
+        });
+
+        it('should show an error feedback', function() {
+          fb(false);
+          scope.$digest();
+          expect(isolatedScope.config.feedback.type).toEqual('danger');
+          expect(fb).toHaveBeenCalledWith(false);
+          expect($(element).find('xos-alert > div')).toHaveClass('alert alert-danger');
+        });
+      });
+
+    });
+  });
+})();
diff --git a/views/ngXosLib/xosHelpers/spec/ui/pagination.test.js b/views/ngXosLib/xosHelpers/spec/ui/pagination.test.js
new file mode 100644
index 0000000..a8a7482
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/spec/ui/pagination.test.js
@@ -0,0 +1,53 @@
+(function () {
+  'use strict';
+
+  describe('The xos.helper module', function(){
+    describe('The xos-pagination component', () => {
+
+      let scope, element, isolatedScope;
+      let cb = jasmine.createSpy('callback')
+
+      beforeEach(module('xos.helpers'));
+
+      beforeEach(inject(function ($compile, $rootScope) {
+        scope = $rootScope.$new();
+
+        scope.pageSize = 2;
+
+        scope.totalElements = 5;
+
+        scope.change = cb;
+
+        element = angular.element('<xos-pagination page-size="pageSize" total-elements="totalElements" change="change"></xos-table>');
+        $compile(element)(scope);
+        scope.$digest();
+        isolatedScope = element.isolateScope().vm;
+      }));
+
+      it('should contain 3 pages', function() {
+        var li = element[0].getElementsByTagName('li');
+        expect(li.length).toEqual(5);
+      });
+
+      it('should call the change function', () => {
+        var li = element[0].getElementsByTagName('li')[3];
+        let link = li.getElementsByTagName('a')[0];
+        link.click();
+        expect(cb).toHaveBeenCalledWith(2);
+      });
+
+      describe('when elements number is less than page size', () => {
+        beforeEach(() => {
+          isolatedScope.pageSize = 10;
+          isolatedScope.totalElements = 9;
+          scope.$digest();
+        });
+
+        it('should not be rendered', () => {
+          var pagination = element[0].getElementsByClassName('pagination');
+          expect(pagination.length).toEqual(0);
+        });
+      });
+    });
+  });
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/spec/ui/smart-pie.test.js b/views/ngXosLib/xosHelpers/spec/ui/smart-pie.test.js
new file mode 100644
index 0000000..2b3476a
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/spec/ui/smart-pie.test.js
@@ -0,0 +1,210 @@
+/**
+ * © OpenCORD
+ *
+ * Created by teone on 3/24/16.
+ */
+
+(function () {
+  'use strict';
+
+  let mockData, compile, rootScope, spy, scope, isolatedScope, element, interval;
+
+  const compileElement = () => {
+
+    if(!scope){
+      scope = rootScope.$new();
+    }
+
+    element = angular.element('<xos-smart-pie config="config"></xos-smart-pie>');
+    compile(element)(scope);
+    scope.$digest();
+    isolatedScope = element.isolateScope().vm;
+  }
+
+  describe('The xos.helper module', function(){
+    describe('The xos-smart-pie component', () => {
+      
+      beforeEach(module('xos.helpers'));
+
+      beforeEach(function(){
+        module(function($provide){
+          $provide.service('MockResource', function(){
+            return {
+              query: ''
+            }
+          });
+        });
+      });
+
+      beforeEach(inject(function ($compile, $rootScope) {
+
+        // set mockData
+        mockData = [
+          {
+            id: 1,
+            first_name: 'Jon',
+            last_name: 'Snow',
+            category: 1
+          },
+          {
+            id: 2,
+            first_name: 'Danaerys',
+            last_name: 'Targaryen',
+            category: 2
+          },
+          {
+            id: 3,
+            first_name: 'Aria',
+            last_name: 'Stark',
+            category: 1
+          }
+        ]
+
+        compile = $compile;
+        rootScope = $rootScope;
+      }));
+
+      it('should throw an error if no resource and no data are passed in the config', inject(($compile, $rootScope) => {
+        function errorFunctionWrapper(){
+          // setup the parent scope
+          scope = $rootScope.$new();
+          scope.config = {};
+          compileElement();
+        }
+        expect(errorFunctionWrapper).toThrow(new Error('[xosSmartPie] Please provide a resource or an array of data in the configuration'));
+      }));
+
+      describe('when data are passed in the configuration', () => {
+        beforeEach(inject(function ($compile, $rootScope) {
+          scope = $rootScope.$new();
+
+          scope.config = {
+            data: mockData,
+            groupBy: 'category',
+            classes: 'my-test-class'
+          };
+
+          compileElement();
+        }));
+        
+
+        it('should attach provided classes', () => {
+          expect($(element).find('canvas')).toHaveClass('my-test-class');
+        });
+
+        it('should group elements', () => {
+          let groupedData = [2, 1];
+          expect(isolatedScope.data).toEqual(groupedData);
+        });
+
+        describe('when a labelFormatter function is provided', () => {
+          beforeEach(() => {
+            scope.config.labelFormatter = (labels) => {
+              return labels.map(l => l === '1' ? 'First' : 'Second');
+            };
+            compileElement();
+          });
+          it('should format labels', () => {
+            expect(isolatedScope.labels).toEqual(['First', 'Second'])
+          });
+        });
+
+        describe('when provided data changes', () => {
+          beforeEach(() => {
+            scope.config.data.push({
+              id: 2,
+              first_name: 'Danaerys',
+              last_name: 'Targaryen',
+              category: 1
+            });
+            scope.$digest();
+          });
+          it('should calculate again the data', () => {
+            expect(isolatedScope.data).toEqual([3, 1]);
+          });
+        });
+      });
+
+      
+      describe('when a resource is specified in the configuration', () => {
+
+        beforeEach(inject(function ($compile, $rootScope, $q, MockResource) {
+          scope = $rootScope.$new();
+
+          scope.config = {
+            resource: 'MockResource',
+            groupBy: 'category',
+            classes: 'my-test-class'
+          };
+
+          spy = MockResource;
+
+          spyOn(MockResource, 'query').and.callFake(function() {
+            var deferred = $q.defer();
+            deferred.resolve(mockData);
+            return {$promise: deferred.promise};
+          });
+
+          compileElement();
+        }));
+
+
+        it('should call the server and group elements', () => {
+          let groupedData = [2, 1];
+          expect(spy.query).toHaveBeenCalled();
+          expect(isolatedScope.data).toEqual(groupedData);
+        });
+
+        describe('when a labelFormatter function is provided', () => {
+          beforeEach(inject(function ($compile, $rootScope){
+            scope = $rootScope.$new();
+            scope.config = {
+              resource: 'MockResource',
+              groupBy: 'category',
+              classes: 'label-formatter-test',
+              labelFormatter: (labels) => {
+                return labels.map(l => l === '1' ? 'First' : 'Second');
+              }
+            };
+            compileElement();
+          }));
+
+          it('should format labels', () => {
+            expect(isolatedScope.labels).toEqual(['First', 'Second'])
+          });
+        });
+
+        describe('when polling is enabled', () => {
+          beforeEach(inject(function ($compile, $rootScope, $interval){
+
+            //mocked $interval (by ngMock)
+            interval = $interval;
+
+            // cleaning the spy
+            spy.query.calls.reset()
+
+            scope = $rootScope.$new();
+            scope.config = {
+              resource: 'MockResource',
+              groupBy: 'category',
+              classes: 'label-formatter-test',
+              poll: 2
+            };
+            compileElement();
+          }));
+
+          it('should call the backend every 2 second', () => {
+            expect(spy.query).toHaveBeenCalled();
+            expect(spy.query.calls.count()).toEqual(1);
+            interval.flush(2000);
+            expect(spy.query.calls.count()).toEqual(2);
+            interval.flush(2000);
+            expect(spy.query.calls.count()).toEqual(3)
+          });
+        });
+      });
+
+
+    });
+  });
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/spec/ui/smart-table.test.js b/views/ngXosLib/xosHelpers/spec/ui/smart-table.test.js
new file mode 100644
index 0000000..d579ce6
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/spec/ui/smart-table.test.js
@@ -0,0 +1,224 @@
+/**
+ * © OpenCORD
+ *
+ * Created by teone on 3/24/16.
+ */
+
+(function () {
+  'use strict';
+
+  let mockData;
+
+  describe('The xos.helper module', function(){
+    describe('The xos-smart-table component', () => {
+
+      var spy, emptySpy, scope, isolatedScope, element;
+
+      beforeEach(module('xos.helpers'));
+
+      beforeEach(function() {
+
+        // set mockData
+        mockData = [
+          {
+            id: 1,
+            first_name: 'Jon',
+            last_name: 'Snow',
+            hidden_field: 'hidden'
+          }
+        ];
+
+        jasmine.addMatchers({
+          toBeInstanceOf: function() {
+
+            return {
+              compare: (actual, expected) => {
+                var actual = actual;
+                var result = {};
+                result.pass = actual instanceof expected.constructor;
+
+                result.message = 'Expected ' + actual + ' to be instance of ' + expected;
+
+                return result;
+              },
+              negativeCompare: (actual, expected) => {
+                var actual = actual;
+                var result = {};
+                result.pass = actual instanceof expected.constructor === false;
+
+                result.message = 'Expected ' + actual + ' to be instance of ' + expected;
+
+                return result;
+              }
+            }
+          }
+        });
+      });
+
+      // mock the service
+      beforeEach(function(){
+        module(function($provide){
+          $provide.service('MockResource', function(){
+            return {
+              query: '',
+              delete: ''
+            }
+          });
+
+          $provide.service('EmptyResource', function(){
+            return {
+              query: ''
+            }
+          });
+        });
+      })
+
+      beforeEach(inject(function ($compile, $rootScope, $q, MockResource) {
+        scope = $rootScope.$new();
+
+        scope.config = {
+          resource: 'MockResource',
+          hiddenFields: ['hidden_field']
+        };
+
+        spy = MockResource;
+
+        spyOn(MockResource, 'query').and.callFake(function() {
+          var deferred = $q.defer();
+          deferred.resolve(mockData);
+          return {$promise: deferred.promise};
+        });
+
+        spyOn(MockResource, 'delete').and.callFake(function() {
+          var deferred = $q.defer();
+          deferred.resolve();
+          return {$promise: deferred.promise};
+        });
+
+        element = angular.element('<xos-smart-table config="config"></xos-smart-table>');
+        $compile(element)(scope);
+        scope.$digest();
+        isolatedScope = element.isolateScope().vm;
+      }));
+
+      it('should query elements', () => {
+        expect(spy.query).toHaveBeenCalled();
+        expect($(element).find('.alert').parent().parent()).toHaveClass('ng-hide');
+      });
+
+      it('should hide hidden fields', () => {
+        // the 4th field is the mocked save method
+        expect($(element).find('thead th').length).toEqual(3);
+        expect($(element).find('thead th')[0]).toContainText('First name:');
+        expect($(element).find('thead th')[1]).toContainText('Last name:');
+        expect($(element).find('thead th')[2]).toContainText('Actions:');
+      });
+
+      it('should delete a model', () => {
+        // saving mockData (they are going to be deleted)
+        let mock = angular.copy(mockData);
+        $(element).find('a[title="delete"]')[0].click();
+        expect(spy.delete).toHaveBeenCalledWith({id: mock[0].id});
+        expect($(element).find('.alert')).toContainText(`MockResource with id ${mock[0].id} successfully deleted`);
+      });
+
+      it('should show the form', () => {
+        expect($(element).find('.panel')[0]).toHaveClass('ng-hide');
+        $(element).find('a[title="details"]')[0].click();
+        expect($(element).find('.panel')).not.toHaveClass('ng-hide');
+      });
+
+      it('should hide the form', () => {
+        isolatedScope.detailedItem = {
+          some: 'model'
+        };
+        scope.$apply();
+        expect($(element).find('.panel')).not.toHaveClass('ng-hide');
+        $(element).find('.panel .col-xs-1 a')[0].click();
+        expect($(element).find('.panel')[0]).toHaveClass('ng-hide');
+      });
+
+      it('should save an item', inject(($q) => {
+
+        let model = {
+          id: 1,
+          first_name: 'Jon',
+          last_name: 'Snow',
+          hidden_field: 'hidden',
+          $save: '',
+          $update: ''
+        };
+
+        spyOn(model, '$save').and.callFake(function() {
+          var deferred = $q.defer();
+          deferred.resolve();
+          return deferred.promise;
+        });
+
+        spyOn(model, '$update').and.callFake(function() {
+          var deferred = $q.defer();
+          deferred.resolve();
+          return deferred.promise;
+        });
+
+        isolatedScope.detailedItem = model;
+        scope.$apply();
+        $(element).find('xos-form .btn.btn-success').click();
+        expect(model.$update).toHaveBeenCalled();
+      }));
+
+      it('should have an add button', () => {
+        let addBtn = $(element).find('.row .btn.btn-success');
+        expect(addBtn.parent().parent()).not.toHaveClass('ng-hide');
+      });
+
+      describe('when the add button is clicked', () => {
+        beforeEach(() => {
+          let btn = $(element).find('.row .btn.btn-success')
+          btn[0].click();
+        });
+
+        xit('should create a new model', () => {
+          expect(isolatedScope.detailedItem).toBeDefined();
+          expect(isolatedScope.detailedItem).toBeInstanceOf('Resource');
+        });
+      });
+
+      describe('when fetching an empty collection', () => {
+        beforeEach(inject(function ($compile, $rootScope, $q, EmptyResource) {
+          scope = $rootScope.$new();
+
+          scope.config = {
+            resource: 'EmptyResource'
+          };
+
+          emptySpy = EmptyResource;
+
+          spyOn(EmptyResource, 'query').and.callFake(function() {
+            var deferred = $q.defer();
+            deferred.resolve([]);
+            return {$promise: deferred.promise};
+          });
+
+          element = angular.element('<xos-smart-table config="config"></xos-smart-table>');
+          $compile(element)(scope);
+          scope.$digest();
+          isolatedScope = element.isolateScope().vm;
+        }));
+
+        it('should display an alert', () => {
+          expect(emptySpy.query).toHaveBeenCalled();
+          expect($(element).find('.alert').parent().parent()).not.toHaveClass('ng-hide');
+          expect($(element).find('.alert')).toContainText('No data to show');
+        });
+
+        it('should not have an add button', () => {
+          let addBtn = $(element).find('.row .btn.btn-success');
+          expect(addBtn.parent().parent()).toHaveClass('ng-hide');
+        });
+      });
+
+
+    });
+  });
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/spec/ui/table.test.js b/views/ngXosLib/xosHelpers/spec/ui/table.test.js
new file mode 100644
index 0000000..0ecdd2f
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/spec/ui/table.test.js
@@ -0,0 +1,574 @@
+/**
+ * © OpenCORD
+ *
+ * Created by teone on 3/24/16.
+ */
+
+(function () {
+  'use strict';
+
+  var scope, element, isolatedScope, rootScope, compile;
+  const compileElement = () => {
+
+    if(!scope){
+      scope = rootScope.$new();
+    }
+
+    element = angular.element('<xos-table config="config" data="data"></xos-table>');
+    compile(element)(scope);
+    scope.$digest();
+    isolatedScope = element.isolateScope().vm;
+  }
+
+
+  describe('The xos.helper module', function(){
+    describe('The xos-table component', () => {
+
+      beforeEach(module('xos.helpers'));
+
+      beforeEach(inject(function ($compile, $rootScope) {
+        compile = $compile;
+        rootScope = $rootScope;
+      }));
+
+      it('should throw an error if no config is specified', () => {
+        function errorFunctionWrapper(){
+          compileElement();
+        }
+        expect(errorFunctionWrapper).toThrow(new Error('[xosTable] Please provide a configuration via the "config" attribute'));
+      });
+
+      it('should throw an error if no config columns are specified', () => {
+        function errorFunctionWrapper(){
+          // setup the parent scope
+          scope = rootScope.$new();
+          scope.config = 'green';
+          compileElement();
+        }
+        expect(errorFunctionWrapper).toThrow(new Error('[xosTable] Please provide a columns list in the configuration'));
+      });
+
+      describe('when basically configured', function() {
+
+        beforeEach(inject(function ($compile, $rootScope) {
+
+          scope = $rootScope.$new();
+
+          scope.config = {
+            columns: [
+              {
+                label: 'Label 1',
+                prop: 'label-1'
+              },
+              {
+                label: 'Label 2',
+                prop: 'label-2'
+              }
+            ]
+          };
+
+          scope.data = [
+            {
+              'label-1': 'Sample 1.1',
+              'label-2': 'Sample 1.2'
+            },
+            {
+              'label-1': 'Sample 2.1',
+              'label-2': 'Sample 2.2'
+            }
+          ]
+
+          element = angular.element('<xos-table config="config" data="data"></xos-table>');
+          $compile(element)(scope);
+          scope.$digest();
+          isolatedScope = element.isolateScope().vm;
+        }));
+
+        it('should contain 2 columns', function() {
+          var th = element[0].getElementsByTagName('th');
+          expect(th.length).toEqual(2);
+          expect(isolatedScope.columns.length).toEqual(2);
+        });
+
+        it('should contain 3 rows', function() {
+          var tr = element[0].getElementsByTagName('tr');
+          expect(tr.length).toEqual(3);
+        });
+
+        it('should render labels', () => {
+          let label1 = $(element).find('thead tr th')[0]
+          let label2 = $(element).find('thead tr th')[1]
+          expect($(label1).text().trim()).toEqual('Label 1');
+          expect($(label2).text().trim()).toEqual('Label 2');
+        });
+
+        describe('when no data are provided', () => {
+          beforeEach(() => {
+            isolatedScope.data = [];
+            scope.$digest();
+          });
+          it('should render an alert', () => {
+            let alert = element[0].getElementsByClassName('alert');
+            let table = element[0].getElementsByTagName('table');
+            expect(alert.length).toEqual(1);
+            expect(table.length).toEqual(1);
+          });
+        });
+
+        describe('when a field type is provided', () => {
+          describe('and is boolean', () => {
+            beforeEach(() => {
+              scope.config = {
+                columns: [
+                  {
+                    label: 'Label 1',
+                    prop: 'label-1',
+                    type: 'boolean'
+                  },
+                  {
+                    label: 'Label 2',
+                    prop: 'label-2',
+                    type: 'boolean'
+                  }
+                ]
+              };
+              scope.data = [
+                {
+                  'label-1': true,
+                  'label-2': 1
+                },
+                {
+                  'label-1': false,
+                  'label-2': 0
+                }
+              ];
+              compileElement();
+            });
+
+            it('should render an incon', () => {
+              let td1 = $(element).find('tbody tr:first-child td')[0];
+              let td2 = $(element).find('tbody tr:last-child td')[0];
+              expect($(td1).find('i')).toHaveClass('glyphicon-ok');
+              expect($(td2).find('i')).toHaveClass('glyphicon-remove');
+            });
+
+            describe('with field filters', () => {
+              beforeEach(() => {
+                scope.config.filter = 'field';
+                compileElement();
+              });
+
+              it('should render a dropdown for filtering', () => {
+                let td1 = $(element).find('table tbody tr td')[0];
+                expect(td1).toContainElement('select');
+                expect(td1).not.toContainElement('input');
+              });
+
+              it('should correctly filter results', () => {
+                isolatedScope.query = {
+                  'label-1': false
+                };
+                scope.$digest();
+                expect(isolatedScope.query['label-1']).toBeFalsy();
+                var tr = $(element).find('tbody:last-child > tr');
+                var icon = $(tr[0]).find('td i');
+                expect(tr.length).toEqual(1);
+                expect(icon).toHaveClass('glyphicon-remove');
+              });
+
+              it('should correctly filter results if the field is in the form of 0|1', () => {
+                isolatedScope.query = {
+                  'label-2': false
+                };
+                scope.$digest();
+                expect(isolatedScope.query['label-1']).toBeFalsy();
+                var tr = $(element).find('tbody:last-child > tr');
+                var icon = $(tr[0]).find('td i');
+                expect(tr.length).toEqual(1);
+                expect(icon).toHaveClass('glyphicon-remove');
+              });
+            });
+          });
+
+          describe('and is date', () => {
+            beforeEach(() => {
+              scope.config = {
+                columns: [
+                  {
+                    label: 'Label 1',
+                    prop: 'label-1',
+                    type: 'date'
+                  }
+                ]
+              };
+              scope.data = [
+                {
+                  'label-1': '2015-02-17T22:06:38.059000Z'
+                }
+              ];
+              compileElement();
+            });
+
+            it('should render an formatted date', () => {
+              let td1 = $(element).find('tbody tr:first-child td')[0];
+              expect($(td1).text().trim()).toEqual('14:06 Feb 17, 2015');
+            });
+          });
+
+          describe('and is array', () => {
+            beforeEach(() => {
+              scope.data = [
+                {categories: ['Film', 'Music']}
+              ];
+              scope.config = {
+                filter: 'field',
+                columns: [
+                  {
+                    label: 'Categories',
+                    prop: 'categories',
+                    type: 'array'
+                  }
+                ]
+              }
+              compileElement();
+            });
+            it('should render a comma separated list', () => {
+              let td1 = $(element).find('tbody:last-child tr:first-child')[0];
+              expect($(td1).text().trim()).toEqual('Film, Music');
+            });
+
+            it('should not render the filter field', () => {
+              let filter = $(element).find('tbody tr td')[0];
+              expect($(filter)).not.toContainElement('input');
+            });
+          });
+
+          describe('and is object', () => {
+            beforeEach(() => {
+              scope.data = [
+                {
+                  attributes: {
+                    age: 20,
+                    height: 50
+                  }
+                }
+              ];
+              scope.config = {
+                filter: 'field',
+                columns: [
+                  {
+                    label: 'Categories',
+                    prop: 'attributes',
+                    type: 'object'
+                  }
+                ]
+              }
+              compileElement();
+            });
+            it('should render a list of key-values', () => {
+              let td = $(element).find('tbody:last-child tr:first-child')[0];
+              let ageLabel = $(td).find('dl dt')[0];
+              let ageValue = $(td).find('dl dd')[0];
+              let heightLabel = $(td).find('dl dt')[1];
+              let heightValue = $(td).find('dl dd')[1];
+              expect($(ageLabel).text().trim()).toEqual('age');
+              expect($(ageValue).text().trim()).toEqual('20');
+              expect($(heightLabel).text().trim()).toEqual('height');
+              expect($(heightValue).text().trim()).toEqual('50');
+            });
+
+            it('should not render the filter field', () => {
+              let filter = $(element).find('tbody tr td')[0];
+              expect($(filter)).not.toContainElement('input');
+            });
+          });
+
+          describe('and is custom', () => {
+
+            let formatterFn = jasmine.createSpy('formatter').and.returnValue('Formatted Content');
+
+            beforeEach(() => {
+              scope.data = [
+                {categories: ['Film', 'Music']}
+              ];
+              scope.config = {
+                filter: 'field',
+                columns: [
+                  {
+                    label: 'Categories',
+                    prop: 'categories',
+                    type: 'custom',
+                    formatter: formatterFn
+                  }
+                ]
+              }
+              compileElement();
+            });
+
+            it('should check for a formatter property', () => {
+              function errorFunctionWrapper(){
+                // setup the parent scope
+                scope = rootScope.$new();
+                scope.config = {
+                  columns: [
+                    {
+                      label: 'Categories',
+                      prop: 'categories',
+                      type: 'custom'
+                    }
+                  ]
+                };
+                compileElement();
+              }
+              expect(errorFunctionWrapper).toThrow(new Error('[xosTable] You have provided a custom field type, a formatter function should provided too.'));
+            });
+
+            it('should check that the formatter property is a function', () => {
+              function errorFunctionWrapper(){
+                // setup the parent scope
+                scope = rootScope.$new();
+                scope.config = {
+                  columns: [
+                    {
+                      label: 'Categories',
+                      prop: 'categories',
+                      type: 'custom',
+                      formatter: 'formatter'
+                    }
+                  ]
+                };
+                compileElement();
+              }
+              expect(errorFunctionWrapper).toThrow(new Error('[xosTable] You have provided a custom field type, a formatter function should provided too.'));
+            });
+
+            it('should format data using the formatter property', () => {
+              let td1 = $(element).find('tbody:last-child tr:first-child')[0];
+              expect($(td1).text().trim()).toEqual('Formatted Content');
+              // the custom formatted should receive the entire object, otherwise is not so custom
+              expect(formatterFn).toHaveBeenCalledWith({categories: ['Film', 'Music']});
+            });
+
+            it('should not render the filter field', () => {
+              // displayed value is different from model val, filter would not work
+              let filter = $(element).find('tbody tr td')[0];
+              expect($(filter)).not.toContainElement('input');
+            });
+          });
+
+          describe('and is icon', () => {
+
+            beforeEach(() => {
+              scope.config = {
+                columns: [
+                  {
+                    label: 'Label 1',
+                    prop: 'label-1',
+                    type: 'icon',
+                    formatter: item => {
+                      switch (item['label-1']){
+                      case 1:
+                        return 'ok';
+                      case 2:
+                        return 'remove';
+                      case 3:
+                        return 'plus'
+                      }
+                    }
+                  }
+                ]
+              };
+              scope.data = [
+                {
+                  'label-1': 1
+                },
+                {
+                  'label-1': 2
+                },
+                {
+                  'label-1': 3
+                }
+              ];
+              compileElement();
+            });
+
+            it('should render a custom icon', () => {
+              let td1 = $(element).find('tbody tr:first-child td')[0];
+              let td2 = $(element).find('tbody tr:nth-child(2) td')[0];
+              let td3 = $(element).find('tbody tr:last-child td')[0];
+              expect($(td1).find('i')).toHaveClass('glyphicon-ok');
+              expect($(td2).find('i')).toHaveClass('glyphicon-remove');
+              expect($(td3).find('i')).toHaveClass('glyphicon-plus');
+            });
+          });
+        });
+
+        describe('when a link property is provided', () => {
+          beforeEach(() => {
+            scope.data = [
+              {
+                id: 1}
+            ];
+            scope.config = {
+              columns: [
+                {
+                  label: 'Id',
+                  prop: 'id',
+                  link: (item) => {
+                    return `/link/${item.id}`;
+                  }
+                }
+              ]
+            }
+            compileElement();
+          });
+
+          it('should check that the link property is a function', () => {
+            function errorFunctionWrapper(){
+              // setup the parent scope
+              scope = rootScope.$new();
+              scope.config = {
+                columns: [
+                  {
+                    label: 'Categories',
+                    prop: 'categories',
+                    link: 'custom'
+                  }
+                ]
+              };
+              compileElement();
+            }
+            expect(errorFunctionWrapper).toThrow(new Error('[xosTable] The link property should be a function.'));
+          });
+
+          it('should render a link with the correct url', () => {
+            let link = $(element).find('tbody tr:first-child td a')[0];
+            expect($(link).attr('href')).toEqual('/link/1');
+          });
+        });
+
+        describe('when actions are passed', () => {
+
+          let cb = jasmine.createSpy('callback')
+
+          beforeEach(() => {
+            isolatedScope.config.actions = [
+              {
+                label: 'delete',
+                icon: 'remove',
+                cb: cb,
+                color: 'red'
+              }
+            ];
+            scope.$digest();
+          });
+
+          it('should have 3 columns', () => {
+            var th = element[0].getElementsByTagName('th');
+            expect(th.length).toEqual(3);
+            expect(isolatedScope.columns.length).toEqual(2);
+          });
+
+          it('when clicking on action should invoke callback', () => {
+            var link = element[0].getElementsByTagName('a')[0];
+            link.click();
+            expect(cb).toHaveBeenCalledWith(scope.data[0]);
+          });
+        });
+
+        describe('when filter is fulltext', () => {
+          beforeEach(() => {
+            isolatedScope.config.filter = 'fulltext';
+            scope.$digest();
+          });
+
+          it('should render a text field', () => {
+            var textField = element[0].getElementsByTagName('input');
+            expect(textField.length).toEqual(1);
+          });
+
+          describe('and a value is enterd', () => {
+            beforeEach(() => {
+              isolatedScope.query = '2.2';
+              scope.$digest();
+            });
+
+            it('should contain 2 rows', function() {
+              var tr = element[0].getElementsByTagName('tr');
+              expect(tr.length).toEqual(2);
+            });
+          });
+        });
+
+        describe('when filter is field', () => {
+          beforeEach(() => {
+            isolatedScope.config.filter = 'field';
+            scope.$digest();
+          });
+
+          it('should render a text field for each column', () => {
+            var textField = element[0].getElementsByTagName('input');
+            expect(textField.length).toEqual(2);
+          });
+
+          describe('and a value is enterd', () => {
+            beforeEach(() => {
+              isolatedScope.query = {'label-1': '2.1'};
+              scope.$digest();
+            });
+
+            it('should contain 3 rows', function() {
+              var tr = element[0].getElementsByTagName('tr');
+              expect(tr.length).toEqual(3);
+            });
+          });
+        });
+
+        describe('when order is true', () => {
+          beforeEach(() => {
+            isolatedScope.config.order = true;
+            scope.$digest();
+          });
+
+          it('should render a arrows beside', () => {
+            var arrows = element[0].getElementsByTagName('i');
+            expect(arrows.length).toEqual(4);
+          });
+
+          describe('and a default ordering is passed', () => {
+
+            beforeEach(() => {
+              scope.config.order = {
+                field: 'label-1',
+                reverse: true
+              };
+              compileElement();
+            });
+
+            it('should orderBy the default order', () => {
+              var tr = $(element).find('tr');
+              expect($(tr[1]).text()).toContain('Sample 2.2');
+              expect($(tr[2]).text()).toContain('Sample 1.1');
+            });
+          });
+
+          describe('and an order is set', () => {
+            beforeEach(() => {
+              isolatedScope.orderBy = 'label-1';
+              isolatedScope.reverse = true;
+              scope.$digest();
+            });
+
+            it('should orderBy', function() {
+              // console.log($(element).find('table'));
+              var tr = $(element).find('tr');
+              expect($(tr[1]).text()).toContain('Sample 2.2');
+              expect($(tr[2]).text()).toContain('Sample 1.1');
+            });
+          });
+        });
+      });
+    });
+  });
+})();
+
diff --git a/views/ngXosLib/xosHelpers/spec/ui/validation.test.js b/views/ngXosLib/xosHelpers/spec/ui/validation.test.js
new file mode 100644
index 0000000..1029f2d
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/spec/ui/validation.test.js
@@ -0,0 +1,86 @@
+/**
+ * © OpenCORD
+ *
+ * Created by teone on 4/15/16.
+ */
+
+(function () {
+  'use strict';
+
+  let compile, element, scope;
+
+  const compileElement = (el) => {
+    element = el;
+
+    if(!scope){
+      scope = rootScope.$new();
+    }
+    if(angular.isUndefined(element)){
+      element = angular.element('<xos-validation field="field" form="form"></xos-validation>');
+    }
+    compile(element)(scope);
+    scope.$digest();
+  }
+
+  describe('The xos.helper module', function(){
+    describe('The xos-validation component', () => {
+
+      beforeEach(module('xos.helpers'));
+
+      describe('when the form has no errors', () => {
+        beforeEach(inject(($compile, $rootScope) => {
+          compile = $compile;
+          scope = $rootScope.$new();
+
+          scope.field = {
+            $error: {}
+          };
+
+          scope.form = {
+            $submitted: true
+          }
+
+          compileElement();
+        }));
+
+        it('should not show an alert by default', () => {
+          expect($(element).find('xos-alert > .alert')[0]).toHaveClass('ng-hide');
+        });
+      });
+
+      let availableErrors = [
+        {
+          type: 'required',
+          message: 'Field required'
+        },
+        {
+          type: 'email',
+          message: 'This is not a valid email'
+        },
+        {
+          type: 'minlength',
+          message: 'Too short'
+        },
+        {
+          type: 'maxlength',
+          message: 'Too long'
+        },
+        {
+          type: 'custom',
+          message: 'Field invalid'
+        },
+      ];
+
+      // use a loop to generate similar test
+      availableErrors.forEach((e, i) => {
+        it(`should show an alert for ${e.type} errors`, () => {
+          scope.field.$error[e.type] = true;
+          compileElement();
+          let alert = $(element).find('xos-alert > .alert')[i];
+          expect(alert).not.toHaveClass('ng-hide');
+          expect(alert).toHaveText(e.message);
+        });
+      });
+    });
+  });
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/services/csrfToken.interceptor.js b/views/ngXosLib/xosHelpers/src/services/csrfToken.interceptor.js
new file mode 100644
index 0000000..5f87de5
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/services/csrfToken.interceptor.js
@@ -0,0 +1,24 @@
+(function() {
+  'use strict';
+
+  /**
+  * @ngdoc service
+  * @name xos.helpers.SetCSRFToken
+  * @description This factory is automatically loaded trough xos.helpers and will add an $http interceptor that will the CSRF-Token to your request headers
+  **/
+
+  angular
+      .module('xos.helpers')
+      .factory('SetCSRFToken', setCSRFToken);
+
+  function setCSRFToken($cookies) {
+    return {
+      request: function(request){
+        if(request.method !== 'GET'){
+          request.headers['X-CSRFToken'] = $cookies.get('xoscsrftoken');
+        }
+        return request;
+      }
+    };
+  }
+})();
diff --git a/views/ngXosLib/xosHelpers/src/services/helpers/ui/comparator.service.js b/views/ngXosLib/xosHelpers/src/services/helpers/ui/comparator.service.js
new file mode 100644
index 0000000..77e6210
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/services/helpers/ui/comparator.service.js
@@ -0,0 +1,96 @@
+(function() {
+  'use strict';
+
+  /**
+   * @ngdoc service
+   * @name xos.uiComponents.Comparator
+   * @description
+   * This factory define a function that replace the native angular.filter comparator.
+   *
+   * It is done to allow the comparation between (0|1) values with booleans.
+   * >Note that this factory return a single function, not an object.
+   *
+   * The tipical usage of this factory is inside an `ng-repeat`
+   * @example
+   * <example module="comparator">
+   *   <file name="index.html">
+   *     <div ng-controller="sample as vm">
+   *       <div class="row">
+   *         <div class="col-xs-6">
+   *           <label>Filter by name:</label>
+   *           <input class="form-control" type="text" ng-model="vm.query.name"/>
+   *         </div>
+   *         <div class="col-xs-6">
+   *           <label>Filter by status:</label>
+   *           <select
+   *            ng-model="vm.query.status"
+   *            ng-options="i for i in [true, false]">
+   *           </select>
+   *         </div>
+   *       </div>
+   *       <div ng-repeat="item in vm.data | filter:vm.query:vm.comparator">
+   *         <div class="row">
+   *           <div class="col-xs-6">{{item.name}}</div>
+   *           <div class="col-xs-6">{{item.status}}</div>
+   *         </div>
+   *       </div>
+   *     </div>
+   *   </file>
+   *   <file name="script.js">
+   *     angular.module('comparator', ['xos.uiComponents'])
+   *     .controller('sample', function(Comparator){
+   *       this.comparator = Comparator;
+   *       this.data = [
+   *         {name: 'Jhon', status: 1},
+   *         {name: 'Jack', status: 0},
+   *         {name: 'Mike', status: 1},
+   *         {name: 'Scott', status: 0}
+   *       ];
+   *     });
+   *   </file>
+   * </example>
+   **/
+
+  angular
+    .module('xos.uiComponents')
+    .factory('Comparator', comparator);
+
+  function comparator() {
+
+    return function(actual, expected){
+
+      if (angular.isUndefined(actual)) {
+        // No substring matching against `undefined`
+        return false;
+      }
+      if ((actual === null) || (expected === null)) {
+        // No substring matching against `null`; only match against `null`
+        return actual === expected;
+      }
+      if (angular.isObject(expected) || (angular.isObject(actual))){
+        return angular.equals(expected, actual);
+      }
+
+      if(_.isBoolean(actual) || _.isBoolean(expected)){
+        if(actual === 0 || actual === 1){
+          actual = !!actual;
+        }
+        return angular.equals(expected, actual);
+      }
+
+      if(!angular.isString(actual) || !angular.isString(expected)){
+        if(angular.isDefined(actual.toString) && angular.isDefined(expected.toString)){
+          actual = actual.toString();
+          expected = expected.toString();
+        }
+        else {
+          return actual === expected;
+        }
+      }
+
+      actual = actual.toLowerCase() + '';
+      expected = expected.toLowerCase() + '';
+      return actual.indexOf(expected) !== -1;
+    };
+  }
+})();
diff --git a/views/ngXosLib/xosHelpers/src/services/helpers/ui/form.helpers.js b/views/ngXosLib/xosHelpers/src/services/helpers/ui/form.helpers.js
new file mode 100644
index 0000000..0a9d3ec
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/services/helpers/ui/form.helpers.js
@@ -0,0 +1,153 @@
+(function () {
+  
+  angular.module('xos.uiComponents')
+
+  /**
+  * @ngdoc service
+  * @name xos.uiComponents.XosFormHelpers
+  * @requires xos.uiComponents.LabelFormatter
+  * @requires xos.helpers._
+  **/
+
+  .service('XosFormHelpers', function(_, LabelFormatter){
+
+    /**
+    * @ngdoc method
+    * @name xos.uiComponents.XosFormHelpers#_isEmail
+    * @methodOf xos.uiComponents.XosFormHelpers
+    * @description
+    * Return true if the string is an email address
+    * @param {string} text The string to be evaluated
+    * @returns {boolean} If the string match an email format
+    **/
+
+
+    this._isEmail = (text) => {
+      var re = /(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))/;
+      return re.test(text);
+    };
+
+    /**
+    * @ngdoc method
+    * @name xos.uiComponents.XosFormHelpers#_getFieldFormat
+    * @methodOf xos.uiComponents.XosFormHelpers
+    * @description
+    * Return the type of the input
+    * @param {mixed} value The data to be evaluated
+    * @returns {string} The type of the input
+    **/
+
+    this._getFieldFormat = (value) => {
+
+      if(angular.isArray(value)){
+        return 'array';
+      }
+
+      // check if is date
+      if (_.isDate(value) || (!Number.isNaN(Date.parse(value)) && new Date(value).getTime() > 631180800000)){
+        return 'date';
+      }
+
+      // check if is boolean
+      // isNaN(false) = false, false is a number (0), true is a number (1)
+      if(typeof value  === 'boolean'){
+        return 'boolean';
+      }
+
+      // check if a string is an email
+      if(this._isEmail(value)){
+        return 'email';
+      }
+
+      // if null return string
+      if(angular.isString(value) || value === null){
+        return 'text';
+      }
+
+      return typeof value;
+    };
+
+    /**
+    * @ngdoc method
+    * @name xos.uiComponents.XosFormHelpers#buildFormStructure
+    * @methodOf xos.uiComponents.XosFormHelpers
+    * @description
+    * Return the type of the input
+    * @param {object} modelField An object containing one property for each field of the model
+    * @param {object} customField An object containing one property for each field custom field
+    * @param {object} model The actual model on wich build the form structure (it is used to determine the type of the input)
+    * @returns {object} An object describing the form structure in the form of:
+    * ```
+    * {
+    *   'field-name': {
+    *     label: 'Label',
+    *     type: 'number', //typeof field
+    *     validators: {}, // see xosForm for more details
+    *     hint: 'A Custom hint for the field'
+    *   }
+    * }
+    * ```
+    **/
+
+    this.buildFormStructure = (modelField, customField, model) => {
+
+      modelField = angular.extend(modelField, customField);
+      customField = customField || {};
+
+      return _.reduce(Object.keys(modelField), (form, f) => {
+
+        form[f] = {
+          label: (customField[f] && customField[f].label) ? `${customField[f].label}:` : LabelFormatter.format(f),
+          type: (customField[f] && customField[f].type) ? customField[f].type : this._getFieldFormat(model[f]),
+          validators: (customField[f] && customField[f].validators) ? customField[f].validators : {},
+          hint: (customField[f] && customField[f].hint)? customField[f].hint : '',
+        };
+
+        if(customField[f] && customField[f].options){
+          form[f].options = customField[f].options;
+        }
+        if(customField[f] && customField[f].properties){
+          form[f].properties = customField[f].properties;
+        }
+        if(form[f].type === 'date'){
+          model[f] = new Date(model[f]);
+        }
+
+        if(form[f].type === 'number'){
+          model[f] = parseInt(model[f], 10);
+        }
+
+        return form;
+      }, {});
+    };
+
+    /**
+    * @ngdoc method
+    * @name xos.uiComponents.XosFormHelpers#parseModelField
+    * @methodOf xos.uiComponents.XosFormHelpers
+    * @description
+    * Helpers for buildFormStructure, convert a list of model properties in an object used to build the form structure, eg:
+    * ```
+    * // input:
+    * ['id', 'name'm 'mail']
+    *
+    * // output
+    * {
+    *   id: {},
+    *   name: {},
+    *   mail: {}
+    * }
+    * ```
+    * @param {array} fields An array of fields representing the model properties
+    * @returns {object} An object containing one property for each field of the model
+    **/
+
+    this.parseModelField = (fields) => {
+      return _.reduce(fields, (form, f) => {
+        form[f] = {};
+        return form;
+      }, {});
+    }
+
+  });
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/services/helpers/ui/label_formatter.service.js b/views/ngXosLib/xosHelpers/src/services/helpers/ui/label_formatter.service.js
new file mode 100644
index 0000000..bb1d279
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/services/helpers/ui/label_formatter.service.js
@@ -0,0 +1,39 @@
+(function() {
+  'use strict';
+
+  /**
+  * @ngdoc service
+  * @name xos.uiComponents.LabelFormatter
+  * @description This factory define a set of helper function to format label started from an object property
+  **/
+
+  angular
+      .module('xos.uiComponents')
+      .factory('LabelFormatter', labelFormatter);
+
+  function labelFormatter() {
+
+    const _formatByUnderscore = string => string.split('_').join(' ').trim();
+
+    const _formatByUppercase = string => string.split(/(?=[A-Z])/).map(w => w.toLowerCase()).join(' ');
+
+    const _capitalize = string => string.slice(0, 1).toUpperCase() + string.slice(1);
+
+    const format = (string) => {
+      string = _formatByUnderscore(string);
+      string = _formatByUppercase(string);
+
+      string = _capitalize(string).replace(/\s\s+/g, ' ') + ':';
+      return string.replace('::', ':');
+    };
+
+    return {
+      // test export
+      _formatByUnderscore: _formatByUnderscore,
+      _formatByUppercase: _formatByUppercase,
+      _capitalize: _capitalize,
+      // export to use
+      format: format
+    };
+  }
+})();
diff --git a/views/ngXosLib/xosHelpers/src/services/helpers/user-prefs.service.js b/views/ngXosLib/xosHelpers/src/services/helpers/user-prefs.service.js
new file mode 100644
index 0000000..7bf8ae1
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/services/helpers/user-prefs.service.js
@@ -0,0 +1,95 @@
+(function () {
+  
+  angular.module('xos.helpers')
+
+  /**
+  * @ngdoc service
+  * @name xos.helpers.XosUserPrefs
+  * @description
+  * This service is used to store the user preferences in cookies, so that they survive to page changes.
+  * The structure of the user preference is:
+  * ```
+  * {
+  *   synchronizers: {
+  *     notification: {
+  *       'volt': boolean,
+  *       'openstack': boolean,
+  *       ...
+  *     }
+  *   }
+  * }
+  * ```
+  **/
+
+  .service('XosUserPrefs', function($cookies){
+
+    let userPrefs = $cookies.get('xosUserPrefs') ? angular.fromJson($cookies.get('xosUserPrefs')) : {};
+
+    /**
+    * @ngdoc method
+    * @name xos.helpers.XosUserPrefs#getAll
+    * @methodOf xos.helpers.XosUserPrefs
+    * @description
+    * Return all the user preferences stored in cookies
+    * @returns {object} The user preferences
+    **/
+    this.getAll = () => {
+      userPrefs = $cookies.get('xosUserPrefs') ? angular.fromJson($cookies.get('xosUserPrefs')) : {};
+      return userPrefs;
+    };
+
+    /**
+    * @ngdoc method
+    * @name xos.helpers.XosUserPrefs#setAll
+    * @methodOf xos.helpers.XosUserPrefs
+    * @description
+    * Override all user preferences
+    * @param {object} prefs The user preferences
+    **/
+    this.setAll = (prefs) => {
+      $cookies.put('xosUserPrefs', angular.toJson(prefs));
+    };
+
+    /**
+    * @ngdoc method
+    * @name xos.helpers.XosUserPrefs#getSynchronizerNotificationStatus
+    * @methodOf xos.helpers.XosUserPrefs
+    * @description
+    * Return the synchronizer notification status, if name is not provided return the status for all synchronizers
+    * @param {string=} prefs The synchronizer name
+    * @returns {object | string} The synchronizer status
+    **/
+    this.getSynchronizerNotificationStatus = (name = false) => {
+      if(name){
+        return this.getAll().synchronizers.notification[name];
+      }
+      return this.getAll().synchronizers.notification;
+    };
+
+    /**
+    * @ngdoc method
+    * @name xos.helpers.XosUserPrefs#setSynchronizerNotificationStatus
+    * @methodOf xos.helpers.XosUserPrefs
+    * @description
+    * Update the notification status for a single synchronizer
+    * @param {string} name The synchronizer name
+    * @param {boolean} value The notification status (true means that it has been sent)
+    **/
+    this.setSynchronizerNotificationStatus = (name = false, value) => {
+      if(!name){
+        throw new Error('[XosUserPrefs] When updating a synchronizer is mandatory to provide a name.')
+      }
+
+      let cookies = this.getAll();
+
+      if(!cookies.synchronizers){
+        cookies.synchronizers = {
+          notification: {}
+        }
+      }
+
+      cookies.synchronizers.notification[name] = value;
+      this.setAll(cookies);
+    }
+  });
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/services/log.decorator.js b/views/ngXosLib/xosHelpers/src/services/log.decorator.js
new file mode 100644
index 0000000..e6bd621
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/services/log.decorator.js
@@ -0,0 +1,58 @@
+// TODO write tests for log
+
+/* eslint-disable  angular/ng_window_service*/
+
+angular.module('xos.helpers')
+.config([ '$provide', function( $provide )
+{
+  // Use the `decorator` solution to substitute or attach behaviors to
+  // original service instance; @see angular-mocks for more examples....
+
+  $provide.decorator( '$log', [ '$delegate', function( $delegate )
+  {
+
+    const isLogEnabled = () => {
+      return window.location.href.indexOf('debug=true') >= 0;
+    };
+    // Save the original $log.debug()
+    let logFn = $delegate.log;
+    let infoFn = $delegate.info;
+    let warnFn = $delegate.warn;
+    let errorFn = $delegate.error;
+    let debugFn = $delegate.debug;
+
+    // create the replacement function
+    const replacement = (fn) => {
+      return function(){
+        // console.log(`Is Log Enabled: ${isLogEnabled()}`)
+        if(!isLogEnabled()){
+          // console.log('logging is disabled');
+          return;
+        }
+        let args    = [].slice.call(arguments);
+        let now     = new Date();
+
+        // Prepend timestamp
+        args[0] = `[${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}] ${args[0]}`;
+
+        // HACK awfull fix for angular mock implementation whithin jasmine test failing issue
+        if (angular.isFunction($delegate.reset) && !($delegate.debug.logs instanceof Array)) {
+          // if we are within the mock and did not reset yet, we call it to avoid issue
+          // console.log('mock log impl fix to avoid logs array not existing...');
+          $delegate.reset();
+        }
+
+        // Call the original with the output prepended with formatted timestamp
+        fn.apply(null, args)
+      };
+    };
+
+    $delegate.info = replacement(infoFn);
+    $delegate.log = replacement(logFn);
+    $delegate.warn = replacement(warnFn);
+    $delegate.error = replacement(errorFn);
+    $delegate.debug = replacement(debugFn);
+
+    return $delegate;
+  }]);
+}]);
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/services/noHyperlinks.interceptor.js b/views/ngXosLib/xosHelpers/src/services/noHyperlinks.interceptor.js
new file mode 100644
index 0000000..af3dd63
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/services/noHyperlinks.interceptor.js
@@ -0,0 +1,24 @@
+(function() {
+  'use strict';
+
+  /**
+  * @ngdoc service
+  * @name xos.helpers.NoHyperlinks
+  * @description This factory is automatically loaded trough xos.helpers and will add an $http interceptor that will add ?no_hyperlinks=1 to your api request, that is required by django
+  **/
+
+  angular
+      .module('xos.helpers')
+      .factory('NoHyperlinks', noHyperlinks);
+
+  function noHyperlinks() {
+    return {
+      request: function(request){
+        if(request.url.indexOf('.html') === -1){
+          request.url += '?no_hyperlinks=1';
+        }
+        return request;
+      }
+    };
+  }
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/services/notification.service.js b/views/ngXosLib/xosHelpers/src/services/notification.service.js
new file mode 100644
index 0000000..9a1598e
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/services/notification.service.js
@@ -0,0 +1,62 @@
+/* eslint-disable  angular/ng_window_service*/
+(function() {
+  'use strict';
+
+  angular
+  .module('xos.helpers')
+  .factory('Notification', function(){
+    return window.Notification;
+  })
+  /**
+  * @ngdoc service
+  * @name xos.helpers.xosNotification
+  * @description This factory define a set of helper function to trigger desktop notification
+  **/
+  .service('xosNotification', function($q, $log, Notification) {
+
+    this.checkPermission = () => {
+      const deferred = $q.defer();
+      Notification.requestPermission()
+      .then(permission => {
+        if (permission === 'granted') {
+          deferred.resolve(permission);
+        }
+        else {
+          deferred.reject(permission);
+        }
+      });
+      return deferred.promise;
+    };
+
+    this.sendNotification = (title, options) => {
+      const notification = new Notification(title, options);
+      notification.onerror = function(err){
+        $log.error(err);
+      };
+    };
+
+    /**
+    * @ngdoc method
+    * @name xos.helpers.xosNotification#notify
+    * @methodOf xos.helpers.xosNotification
+    * @description
+    * This method will check for user permission and if granted will send a browser notification.
+    * @param {string} title The notification title
+    * @param {object} options The notification options: `{icon: 'url', body: 'Notification body'}`
+    **/
+
+    this.notify = (title, options) => {
+      if (!('Notification' in window)) {
+        $log.info('This browser does not support desktop notification');
+      }
+      else if (Notification.permission !== 'granted') {
+        this.checkPermission()
+        .then(() => this.sendNotification(title, options));
+      }
+      else if (Notification.permission === 'granted') {
+        this.sendNotification(title, options);
+      }
+    }
+
+  })
+})();
diff --git a/views/ngXosLib/xosHelpers/src/services/rest/Deployments.js b/views/ngXosLib/xosHelpers/src/services/rest/Deployments.js
new file mode 100644
index 0000000..4fecbc2
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/services/rest/Deployments.js
@@ -0,0 +1,15 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.Deployments
+  * @description Angular resource to fetch /api/core/deployments/:id/
+  **/
+  .service('Deployments', function($resource){
+    return $resource('/api/core/deployments/:id/', { id: '@id' }, {
+      update: { method: 'PUT' }
+    });
+  })
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/services/rest/Example.js b/views/ngXosLib/xosHelpers/src/services/rest/Example.js
new file mode 100644
index 0000000..b13ccda
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/services/rest/Example.js
@@ -0,0 +1,13 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.Example-Services-Collection
+  * @description Angular resource to fetch /api/service/exampleservice/
+  **/
+  .service('Example-Services-Collection', function($resource){
+    return $resource('/api/service/exampleservice/');
+  })
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/services/rest/Flavors.js b/views/ngXosLib/xosHelpers/src/services/rest/Flavors.js
new file mode 100644
index 0000000..348b770
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/services/rest/Flavors.js
@@ -0,0 +1,15 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.Flavors
+  * @description Angular resource to fetch /api/core/flavors/:id/
+  **/
+  .service('Flavors', function($resource){
+    return $resource('/api/core/flavors/:id/', { id: '@id' }, {
+      update: { method: 'PUT' }
+    });
+  })
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/services/rest/Images.js b/views/ngXosLib/xosHelpers/src/services/rest/Images.js
new file mode 100644
index 0000000..4fe9cb3
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/services/rest/Images.js
@@ -0,0 +1,15 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.Images
+  * @description Angular resource to fetch /api/core/images/
+  **/
+  .service('Images', function($resource){
+    return $resource('/api/core/images/:id/', { id: '@id' }, {
+      update: { method: 'PUT' }
+    });
+  })
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/services/rest/Instances.js b/views/ngXosLib/xosHelpers/src/services/rest/Instances.js
new file mode 100644
index 0000000..f1e8521
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/services/rest/Instances.js
@@ -0,0 +1,15 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.Instances
+  * @description Angular resource to fetch /api/core/instances/:id/
+  **/
+  .service('Instances', function($resource){
+    return $resource('/api/core/instances/:id/', { id: '@id' }, {
+      update: { method: 'PUT' }
+    });
+  })
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/services/rest/Networks.js b/views/ngXosLib/xosHelpers/src/services/rest/Networks.js
new file mode 100644
index 0000000..74b73b6
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/services/rest/Networks.js
@@ -0,0 +1,15 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.Networks
+  * @description Angular resource to fetch /api/core/networks/:id/
+  **/
+  .service('Networks', function($resource){
+    return $resource('/api/core/networks/:id/', { id: '@id' }, {
+      update: { method: 'PUT' }
+    });
+  })
+})();
diff --git a/views/ngXosLib/xosHelpers/src/services/rest/Nodes.js b/views/ngXosLib/xosHelpers/src/services/rest/Nodes.js
new file mode 100644
index 0000000..bf2e387
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/services/rest/Nodes.js
@@ -0,0 +1,15 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.Nodes
+  * @description Angular resource to fetch /api/core/nodes/:id/
+  **/
+  .service('Nodes', function($resource){
+    return $resource('/api/core/nodes/:id/', { id: '@id' }, {
+      update: { method: 'PUT' }
+    });
+  })
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/services/rest/ONOS-Apps.js b/views/ngXosLib/xosHelpers/src/services/rest/ONOS-Apps.js
new file mode 100644
index 0000000..8d4c104
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/services/rest/ONOS-Apps.js
@@ -0,0 +1,13 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.ONOS-App-Collection
+  * @description Angular resource to fetch /api/tenant/onos/app/
+  **/
+  .service('ONOS-App-Collection', function($resource){
+    return $resource('/api/tenant/onos/app/');
+  })
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/services/rest/ONOS-Services.js b/views/ngXosLib/xosHelpers/src/services/rest/ONOS-Services.js
new file mode 100644
index 0000000..19270e1
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/services/rest/ONOS-Services.js
@@ -0,0 +1,13 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.ONOS-Services-Collection
+  * @description Angular resource to fetch /api/service/onos/
+  **/
+  .service('ONOS-Services-Collection', function($resource){
+    return $resource('/api/service/onos/');
+  })
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/services/rest/Services.js b/views/ngXosLib/xosHelpers/src/services/rest/Services.js
new file mode 100644
index 0000000..eda57e4
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/services/rest/Services.js
@@ -0,0 +1,15 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.Services
+  * @description Angular resource to fetch /api/core/services/:id/
+  **/
+  .service('Services', function($resource){
+    return $resource('/api/core/services/:id/', { id: '@id' }, {
+      update: { method: 'PUT' }
+    });
+  })
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/services/rest/Sites.js b/views/ngXosLib/xosHelpers/src/services/rest/Sites.js
new file mode 100644
index 0000000..818d741
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/services/rest/Sites.js
@@ -0,0 +1,15 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.Sites
+  * @description Angular resource to fetch /api/core/sites/:id/
+  **/
+  .service('Sites', function($resource){
+    return $resource('/api/core/sites/:id/', { id: '@id' }, {
+      update: { method: 'PUT' }
+    });
+  })
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/services/rest/Slices.js b/views/ngXosLib/xosHelpers/src/services/rest/Slices.js
new file mode 100644
index 0000000..5a0da11
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/services/rest/Slices.js
@@ -0,0 +1,15 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.Slices
+  * @description Angular resource to fetch /api/core/slices/:id/
+  **/
+  .service('Slices', function($resource){
+    return $resource('/api/core/slices/:id/', { id: '@id' }, {
+      update: { method: 'PUT' }
+    });
+  })
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/services/rest/Slices_plus.js b/views/ngXosLib/xosHelpers/src/services/rest/Slices_plus.js
new file mode 100644
index 0000000..8213b11
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/services/rest/Slices_plus.js
@@ -0,0 +1,40 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.SlicesPlus
+  * @description Angular resource to fetch /api/utility/slicesplus/
+  * This is a read-only API and only the `query` method is currently supported.
+  **/
+  .service('SlicesPlus', function($http, $q){
+    this.query = (params) => {
+      let deferred = $q.defer();
+
+      $http.get('/api/utility/slicesplus/', {params: params})
+      .then(res => {
+        deferred.resolve(res.data);
+      })
+      .catch(res => {
+        deferred.reject(res.data);
+      });
+
+      return {$promise: deferred.promise};
+    }
+
+    this.get = (id, params) => {
+      let deferred = $q.defer();
+
+      $http.get(`/api/utility/slicesplus/${id}`, {params: params})
+      .then(res => {
+        deferred.resolve(res.data);
+      })
+      .catch(res => {
+        deferred.reject(res.data);
+      });
+      return {$promise: deferred.promise};
+      
+    }
+  })
+})();
diff --git a/views/ngXosLib/xosHelpers/src/services/rest/Subscribers.js b/views/ngXosLib/xosHelpers/src/services/rest/Subscribers.js
new file mode 100644
index 0000000..945e1e8
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/services/rest/Subscribers.js
@@ -0,0 +1,147 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.Subscribers
+  * @description Angular resource to fetch Subscribers
+  **/
+  .service('Subscribers', function($resource){
+    return $resource('/api/tenant/cord/subscriber/:id/', { id: '@id' }, {
+      update: { method: 'PUT' },
+      /**
+      * @ngdoc method
+      * @name xos.helpers.Subscribers#View-a-Subscriber-Features-Detail
+      * @methodOf xos.helpers.Subscribers
+      * @description
+      * View-a-Subscriber-Features-Detail
+      **/
+      'View-a-Subscriber-Features-Detail': {
+        method: 'GET',
+        isArray: false,
+        url: '/api/tenant/cord/subscriber/:id/features/'
+      },
+      /**
+      * @ngdoc method
+      * @name xos.helpers.Subscribers#Read-Subscriber-uplink_speed
+      * @methodOf xos.helpers.Subscribers
+      * @description
+      * Read-Subscriber-uplink_speed
+      **/
+      'Read-Subscriber-uplink_speed': {
+        method: 'GET',
+        isArray: false,
+        url: '/api/tenant/cord/subscriber/:id/features/uplink_speed/'
+      },
+      /**
+      * @ngdoc method
+      * @name xos.helpers.Subscribers#Update-Subscriber-uplink_speed
+      * @methodOf xos.helpers.Subscribers
+      * @description
+      * Update-Subscriber-uplink_speed
+      **/
+      'Update-Subscriber-uplink_speed': {
+        method: 'PUT',
+        isArray: false,
+        url: '/api/tenant/cord/subscriber/:id/features/uplink_speed/'
+      },
+      /**
+      * @ngdoc method
+      * @name xos.helpers.Subscribers#Read-Subscriber-downlink_speed
+      * @methodOf xos.helpers.Subscribers
+      * @description
+      * Read-Subscriber-downlink_speed
+      **/
+      'Read-Subscriber-downlink_speed': {
+        method: 'GET',
+        isArray: false,
+        url: '/api/tenant/cord/subscriber/:id/features/downlink_speed/'
+      },
+      /**
+      * @ngdoc method
+      * @name xos.helpers.Subscribers#Update-Subscriber-downlink_speed
+      * @methodOf xos.helpers.Subscribers
+      * @description
+      * Update-Subscriber-downlink_speed
+      **/
+      'Update-Subscriber-downlink_speed': {
+        method: 'PUT',
+        isArray: false,
+        url: '/api/tenant/cord/subscriber/:id/features/downlink_speed/'
+      },
+      /**
+      * @ngdoc method
+      * @name xos.helpers.Subscribers#Read-Subscriber-cdn
+      * @methodOf xos.helpers.Subscribers
+      * @description
+      * Read-Subscriber-cdn
+      **/
+      'Read-Subscriber-cdn': {
+        method: 'GET',
+        isArray: false,
+        url: '/api/tenant/cord/subscriber/:id/features/cdn/'
+      },
+      /**
+      * @ngdoc method
+      * @name xos.helpers.Subscribers#Update-Subscriber-cdn
+      * @methodOf xos.helpers.Subscribers
+      * @description
+      * Update-Subscriber-cdn
+      **/
+      'Update-Subscriber-cdn': {
+        method: 'PUT',
+        isArray: false,
+        url: '/api/tenant/cord/subscriber/:id/features/cdn/'
+      },
+      /**
+      * @ngdoc method
+      * @name xos.helpers.Subscribers#Read-Subscriber-uverse
+      * @methodOf xos.helpers.Subscribers
+      * @description
+      * Read-Subscriber-uverse
+      **/
+      'Read-Subscriber-uverse': {
+        method: 'GET',
+        isArray: false,
+        url: '/api/tenant/cord/subscriber/:id/features/uverse/'
+      },
+      /**
+      * @ngdoc method
+      * @name xos.helpers.Subscribers#Update-Subscriber-uverse
+      * @methodOf xos.helpers.Subscribers
+      * @description
+      * Update-Subscriber-uverse
+      **/
+      'Update-Subscriber-uverse': {
+        method: 'PUT',
+        isArray: false,
+        url: '/api/tenant/cord/subscriber/:id/features/uverse/'
+      },
+      /**
+      * @ngdoc method
+      * @name xos.helpers.Subscribers#Read-Subscriber-status
+      * @methodOf xos.helpers.Subscribers
+      * @description
+      * Read-Subscriber-status
+      **/
+      'Read-Subscriber-status': {
+        method: 'GET',
+        isArray: false,
+        url: '/api/tenant/cord/subscriber/:id/features/status/'
+      },
+      /**
+      * @ngdoc method
+      * @name xos.helpers.Subscribers#Update-Subscriber-status
+      * @methodOf xos.helpers.Subscribers
+      * @description
+      * Update-Subscriber-status
+      **/
+      'Update-Subscriber-status': {
+        method: 'PUT',
+        isArray: false,
+        url: '/api/tenant/cord/subscriber/:id/features/status/'
+      }
+    })
+  })
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/services/rest/Tenant.js b/views/ngXosLib/xosHelpers/src/services/rest/Tenant.js
new file mode 100644
index 0000000..8feb102
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/services/rest/Tenant.js
@@ -0,0 +1,15 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.Tenant
+  * @description Angular resource to fetch /api/core/tenant/:id/
+  **/
+  .service('Tenants', function($resource){
+    return $resource('/api/core/tenants/:id/', { id: '@id' }, {
+      update: { method: 'PUT' }
+    });
+  })
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/services/rest/Truckroll.js b/views/ngXosLib/xosHelpers/src/services/rest/Truckroll.js
new file mode 100644
index 0000000..7af9016
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/services/rest/Truckroll.js
@@ -0,0 +1,15 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.Truckroll
+  * @description Angular resource to fetch /api/tenant/truckroll/:id/
+  **/
+  .service('Truckroll', function($resource){
+    return $resource('/api/tenant/truckroll/:id/', { id: '@id' }, {
+      update: { method: 'PUT' }
+    });
+  })
+})();
diff --git a/views/ngXosLib/xosHelpers/src/services/rest/Users.js b/views/ngXosLib/xosHelpers/src/services/rest/Users.js
new file mode 100644
index 0000000..8be0fdd
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/services/rest/Users.js
@@ -0,0 +1,15 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.Users
+  * @description Angular resource to fetch /api/core/users/:id/
+  **/
+  .service('Users', function($resource){
+    return $resource('/api/core/users/:id/', { id: '@id' }, {
+      update: { method: 'PUT' }
+    });
+  })
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/services/rest/Utility.js b/views/ngXosLib/xosHelpers/src/services/rest/Utility.js
new file mode 100644
index 0000000..a735c46
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/services/rest/Utility.js
@@ -0,0 +1,21 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.Login
+  * @description Angular resource to fetch /api/utility/login/
+  **/
+  .service('Login', function($resource){
+    return $resource('/api/utility/login/');
+  })
+  /**
+  * @ngdoc service
+  * @name xos.helpers.Logout
+  * @description Angular resource to fetch /api/utility/logout/
+  **/
+  .service('Logout', function($resource){
+    return $resource('/api/utility/logout/');
+  })
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/services/rest/vOLT.js b/views/ngXosLib/xosHelpers/src/services/rest/vOLT.js
new file mode 100644
index 0000000..424c48d
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/services/rest/vOLT.js
@@ -0,0 +1,15 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.vOLT-Collection
+  * @description Angular resource to fetch /api/tenant/cord/volt/:volt_id/
+  **/
+  .service('vOLT-Collection', function($resource){
+    return $resource('/api/tenant/cord/volt/:volt_id/', { volt_id: '@id' }, {
+      update: { method: 'PUT' }
+    });
+  })
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/services/rest/vSG.js b/views/ngXosLib/xosHelpers/src/services/rest/vSG.js
new file mode 100644
index 0000000..121b5a3
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/services/rest/vSG.js
@@ -0,0 +1,13 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.vSG-Collection
+  * @description Angular resource to fetch /api/service/vsg/
+  **/
+  .service('vSG-Collection', function($resource){
+    return $resource('/api/service/vsg/');
+  })
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/services/service_graph.service.js b/views/ngXosLib/xosHelpers/src/services/service_graph.service.js
new file mode 100644
index 0000000..8a732a2
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/services/service_graph.service.js
@@ -0,0 +1,44 @@
+(function() {
+  'use strict';
+
+  /**
+  * @ngdoc service
+  * @name xos.helpers.ServiceGraph
+  * @description This factory define a set of helper function to query the service tenancy graph
+  **/
+
+  angular
+  .module('xos.helpers')
+  .service('GraphService', function($q, Tenants, Services) {
+
+    this.loadCoarseData = () => {
+
+      let services;
+
+      let deferred = $q.defer();
+
+      Services.query().$promise
+      .then((res) => {
+        services = res;
+        return Tenants.query({kind: 'coarse'}).$promise;
+      })
+      .then((tenants) => {
+        deferred.resolve({
+          tenants: tenants,
+          services: services
+        });
+      })
+
+      return deferred.promise;
+    }
+
+    this.getCoarseGraph = () => {
+      this.loadCoarseData()
+      .then((res) => {
+        console.log(res);
+      })
+      return 'ciao';
+    };
+
+  })
+})();
diff --git a/views/ngXosLib/xosHelpers/src/styles/animations.scss b/views/ngXosLib/xosHelpers/src/styles/animations.scss
new file mode 100644
index 0000000..f565ff7
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/styles/animations.scss
@@ -0,0 +1,44 @@
+@keyframes slideInRight {
+  from {
+    transform: translate3d(100%, 0, 0);
+    visibility: visible;
+  }
+
+  to {
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+@keyframes slideOutRight {
+  from {
+    transform: translate3d(0, 0, 0);
+  }
+
+  to {
+    visibility: hidden;
+    transform: translate3d(100%, 0, 0);
+  }
+}
+
+@keyframes fadeInUp {
+  from {
+    opacity: 0;
+    transform: translate3d(0, 100%, 0);
+  }
+
+  to {
+    opacity: 1;
+    transform: none;
+  }
+}
+
+@keyframes fadeOutDown {
+  from {
+    opacity: 1;
+  }
+
+  to {
+    opacity: 0;
+    transform: translate3d(0, 100%, 0);
+  }
+}
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/styles/loader.scss b/views/ngXosLib/xosHelpers/src/styles/loader.scss
new file mode 100644
index 0000000..66297df
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/styles/loader.scss
@@ -0,0 +1,51 @@
+.loader {
+  font-size: 10px;
+  margin: 0 auto;
+  text-indent: -9999em;
+  width: 11em;
+  height: 11em;
+  border-radius: 50%;
+  background: #ffffff;
+  background: -moz-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
+  background: -webkit-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
+  background: -o-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
+  background: -ms-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
+  background: linear-gradient(to right, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
+  position: relative;
+  animation: loaderSpinner 1.4s infinite linear;
+  transform: translateZ(0);
+}
+.loader:before {
+  width: 50%;
+  height: 50%;
+  background: $brand-primary;
+  border-radius: 100% 0 0 0;
+  position: absolute;
+  top: 0;
+  left: 0;
+  content: '';
+}
+.loader:after {
+  background: #fff;
+  width: 75%;
+  height: 75%;
+  border-radius: 50%;
+  content: '';
+  margin: auto;
+  position: absolute;
+  top: 0;
+  left: 0;
+  bottom: 0;
+  right: 0;
+}
+
+@keyframes loaderSpinner {
+  0% {
+    -webkit-transform: rotate(0deg);
+    transform: rotate(0deg);
+  }
+  100% {
+    -webkit-transform: rotate(360deg);
+    transform: rotate(360deg);
+  }
+}
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/styles/main.scss b/views/ngXosLib/xosHelpers/src/styles/main.scss
new file mode 100644
index 0000000..5768ad0
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/styles/main.scss
@@ -0,0 +1,20 @@
+@import './animations.scss';
+@import '../../../../../views/style/sass/bootstrap/bootstrap/_variables.scss';
+@import './loader.scss';
+
+@import '../ui_components/dumbComponents/table/table.scss';
+@import '../ui_components/dumbComponents/alert/alert.scss';
+@import '../ui_components/dumbComponents/validation/validation.scss';
+@import '../ui_components/dumbComponents/field/field.scss';
+@import '../ui_components/dumbComponents/form/form.scss';
+
+@import '../ui_components/smartComponents/smartTable/smartTable.scss';
+
+[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
+  display: none !important;
+}
+
+.row + .row {
+  /* TODO move in xos.scss*/ 
+  margin-top: $form-group-margin-bottom;
+}
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/alert/alert.component.js b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/alert/alert.component.js
new file mode 100644
index 0000000..9b60def
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/alert/alert.component.js
@@ -0,0 +1,145 @@
+/**
+ * © OpenCORD
+ *
+ * Visit http://guide.xosproject.org/devguide/addview/ for more information
+ *
+ * Created by teone on 4/15/16.
+ */
+
+(function () {
+  'use strict';
+
+  angular.module('xos.uiComponents')
+
+  /**
+    * @ngdoc directive
+    * @name xos.uiComponents.directive:xosAlert
+    * @restrict E
+    * @description The xos-alert directive
+    * @param {Object} config The configuration object
+    * ```
+    * {
+    *   type: 'danger', //info, success, warning
+    *   closeBtn: true, //default false
+    *   autoHide: 3000 //delay to automatically hide the alert
+    * }
+    * ```
+    * @param {Boolean=} show Binding to show and hide the alert, default to true
+    * @element ANY
+    * @scope
+    * @example
+  <example module="sampleAlert1">
+    <file name="index.html">
+      <div ng-controller="SampleCtrl1 as vm">
+        <xos-alert config="vm.config1">
+          A sample alert message
+        </xos-alert>
+        <xos-alert config="vm.config2">
+          A sample alert message (with close button)
+        </xos-alert>
+        <xos-alert config="vm.config3">
+          A sample info message
+        </xos-alert>
+        <xos-alert config="vm.config4">
+          A sample success message
+        </xos-alert>
+        <xos-alert config="vm.config5">
+          A sample warning message
+        </xos-alert>
+      </div>
+    </file>
+    <file name="script.js">
+      angular.module('sampleAlert1', ['xos.uiComponents'])
+      .controller('SampleCtrl1', function(){
+        this.config1 = {
+          type: 'danger'
+        };
+
+        this.config2 = {
+          type: 'danger',
+          closeBtn: true
+        };
+
+        this.config3 = {
+          type: 'info'
+        };
+
+        this.config4 = {
+          type: 'success'
+        };
+
+        this.config5 = {
+          type: 'warning'
+        };
+      });
+    </file>
+  </example>
+
+  <example module="sampleAlert2" animations="true">
+    <file name="index.html">
+      <div ng-controller="SampleCtrl as vm" class="row">
+        <div class="col-sm-4">
+          <a class="btn btn-default btn-block" ng-show="!vm.show" ng-click="vm.show = true">Show Alert</a>
+          <a class="btn btn-default btn-block" ng-show="vm.show" ng-click="vm.show = false">Hide Alert</a>
+        </div>
+        <div class="col-sm-8">
+          <xos-alert config="vm.config1" show="vm.show">
+            A sample alert message, not displayed by default.
+          </xos-alert>
+        </div>
+      </div>
+    </file>
+    <file name="script.js">
+      angular.module('sampleAlert2', ['xos.uiComponents', 'ngAnimate'])
+      .controller('SampleCtrl', function(){
+        this.config1 = {
+          type: 'success'
+        };
+
+        this.show = false;
+      });
+    </file>
+  </example>
+  **/
+
+  .directive('xosAlert', function(){
+    return {
+      restrict: 'E',
+      scope: {
+        config: '=',
+        show: '=?'
+      },
+      template: `
+        <div ng-cloak class="alert alert-{{vm.config.type}}" ng-hide="!vm.show">
+          <button type="button" class="close" ng-if="vm.config.closeBtn" ng-click="vm.dismiss()">
+            <span aria-hidden="true">&times;</span>
+          </button>
+          <p ng-transclude></p>
+        </div>
+      `,
+      transclude: true,
+      bindToController: true,
+      controllerAs: 'vm',
+      controller: function($timeout){
+
+        if(!this.config){
+          throw new Error('[xosAlert] Please provide a configuration via the "config" attribute');
+        }
+
+        // default the value to true
+        this.show = this.show !== false;
+        
+        this.dismiss = () => {
+          this.show = false;
+        }
+
+        if(this.config.autoHide){
+          let to = $timeout(() => {
+            this.dismiss();
+            $timeout.cancel(to);
+          }, this.config.autoHide);
+        }
+      }
+    }
+  })
+})();
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/alert/alert.scss b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/alert/alert.scss
new file mode 100644
index 0000000..f031ba6
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/alert/alert.scss
@@ -0,0 +1,12 @@
+@import '../../../styles/animations.scss';
+
+xos-alert {
+  margin-top: $form-group-margin-bottom;
+  display: block;
+
+  /* when hiding */
+  .ng-hide-add         { animation:0.5s fadeOutDown ease-in-out; }
+
+  /* when showing */
+  .ng-hide-remove      { animation:0.5s fadeInUp ease-in-out; }
+}
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/field/field.component.js b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/field/field.component.js
new file mode 100644
index 0000000..2719bb3
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/field/field.component.js
@@ -0,0 +1,279 @@
+/**
+ * © OpenCORD
+ *
+ * Visit http://guide.xosproject.org/devguide/addview/ for more information
+ *
+ * Created by teone on 5/25/16.
+ */
+
+(function () {
+  'use strict';
+
+  angular.module('xos.uiComponents')
+  /**
+    * @ngdoc directive
+    * @name xos.uiComponents.directive:xosField
+    * @restrict E
+    * @description The xos-field directive.
+    * This component decide, give a field wich kind of input it need to print.
+    * @param {string} name The field name
+    * @param {object} field The field configuration:
+    * ```
+    * {
+    *   label: 'Label',
+    *   type: 'number', //typeof field
+    *   validators: {} // see xosForm for more details
+    * }
+    * ```
+    * @param {mixed} ngModel The field value
+    *
+    * @example
+    
+    # Basic Example
+    
+      <example module="sampleField1">
+        <file name="script.js">
+          angular.module('sampleField1', ['xos.uiComponents'])
+          .factory('_', function($window){
+            return $window._;
+          })
+          .controller('SampleCtrl', function(){
+            this.name = 'input-name';
+            this.field = {label: 'My String Value:', type: 'string'};
+            this.model = 'my string';
+          });
+        </file>
+        <file name="index.html">
+          <div ng-controller="SampleCtrl as vm">
+            <xos-field ng-model="vm.model" name="vm.name" field="vm.field"></xos-field>
+          </div>
+        </file>
+      </example>
+      
+      # Possible Values
+
+      <example module="sampleField2">
+        <file name="script.js">
+          angular.module('sampleField2', ['xos.uiComponents'])
+          .factory('_', function($window){
+            return $window._;
+          })
+          .controller('SampleCtrl', function(){
+            this.field1 = {
+              name: 'number-field',
+              field: {label: 'My Number Value:', type: 'number'},
+              model: 2
+            };
+
+            this.field2 = {
+              name: 'date-field',
+              field: {label: 'My Date Value:', type: 'date'},
+              model: new Date()
+            };
+
+            this.field3 = {
+              name: 'boolean-field',
+              field: {label: 'My Boolean Value:', type: 'boolean'},
+              model: true
+            };
+
+            this.field4 = {
+              name: 'email-field',
+              field: {label: 'My Email Value:', type: 'email'},
+              model: 'sample@domain.us'
+            };
+          });
+        </file>
+        <file name="index.html">
+          <div ng-controller="SampleCtrl as vm">
+            <xos-field ng-model="vm.field1.model" name="vm.field1.name" field="vm.field1.field"></xos-field>
+            <xos-field ng-model="vm.field2.model" name="vm.field2.name" field="vm.field2.field"></xos-field>
+            <xos-field ng-model="vm.field3.model" name="vm.field3.name" field="vm.field3.field"></xos-field>
+            <xos-field ng-model="vm.field4.model" name="vm.field4.name" field="vm.field4.field"></xos-field>
+          </div>
+        </file>
+      </example>
+
+      # This element is recursive
+
+      <example module="sampleField3">
+        <file name="script.js">
+          angular.module('sampleField3', ['xos.uiComponents'])
+          .factory('_', function($window){
+            return $window._;
+          })
+          .controller('SampleCtrl', function(){
+            this.name1 = 'input-name';
+            this.field1 = {label: 'My Object Field:', type: 'object'};
+            this.model1 = {
+              name: 'Jhon',
+              age: '25',
+              email: 'jhon@thewall.ru',
+              active: true
+            };
+
+            this.name2 = 'another-name';
+            this.field2 = {
+              label: 'Empty Object Field',
+              type: 'object',
+              properties: {
+                foo: {
+                  label: 'FooLabel:',
+                  type: 'string',
+                  validators: {
+                    required: true
+                  }
+                },
+                bar: {
+                  type: 'number'
+                }
+              }
+            }
+          });
+        </file>
+        <file name="index.html">
+          <div ng-controller="SampleCtrl as vm">
+            <h4>Autogenerated object field</h4>
+            <xos-field ng-model="vm.model1" name="vm.name1" field="vm.field1"></xos-field>
+
+            <h4>Configured object field</h4>
+            <xos-field ng-model="vm.model2" name="vm.name2" field="vm.field2"></xos-field>
+          </div>
+        </file>
+      </example>
+    */
+  .directive('xosField', function(RecursionHelper){
+    return {
+      restrict: 'E',
+      scope: {
+        name: '=',
+        field: '=',
+        ngModel: '='
+      },
+      template: `
+        <label ng-if="vm.field.type !== 'object'">{{vm.field.label}}</label>
+            <input
+              xos-custom-validator custom-validator="vm.field.validators.custom || null"
+              ng-if="vm.field.type !== 'boolean' && vm.field.type !== 'object' && vm.field.type !== 'select'"
+              type="{{vm.field.type}}"
+              name="{{vm.name}}"
+              class="form-control"
+              ng-model="vm.ngModel"
+              ng-minlength="vm.field.validators.minlength || 0"
+              ng-maxlength="vm.field.validators.maxlength || 2000"
+              ng-required="vm.field.validators.required || false" />
+              <select class="form-control" ng-if ="vm.field.type === 'select'"
+                name = "{{vm.name}}"
+                ng-options="item.id as item.label for item in vm.field.options"
+                ng-model="vm.ngModel"
+                ng-required="vm.field.validators.required || false">
+                </select>
+            <span class="boolean-field" ng-if="vm.field.type === 'boolean'">
+              <a href="#"
+                class="btn btn-success"
+                ng-show="vm.ngModel"
+                ng-click="vm.ngModel = false">
+                <i class="glyphicon glyphicon-ok"></i>
+              </a>
+              <a href="#"
+                class="btn btn-danger"
+                ng-show="!vm.ngModel"
+                ng-click="vm.ngModel = true">
+                <i class="glyphicon glyphicon-remove"></i>
+              </a>
+            </span>
+            <div
+              class="panel panel-default object-field"
+              ng-if="vm.field.type == 'object' && (!vm.isEmptyObject(vm.ngModel) || !vm.isEmptyObject(vm.field.properties))"
+              >
+              <div class="panel-heading">{{vm.field.label}}</div>
+              <div class="panel-body">
+                <div ng-if="!vm.field.properties" ng-repeat="(k, v) in vm.ngModel">
+                  <xos-field
+                    name="k"
+                    field="{label: vm.formatLabel(k), type: vm.getType(v)}"
+                    ng-model="v">
+                  </xos-field>
+                </div>
+                <div ng-if="vm.field.properties" ng-repeat="(k, v) in vm.field.properties">
+                  <xos-field
+                    name="k"
+                    field="{
+                      label: v.label || vm.formatLabel(k),
+                      type: v.type,
+                      validators: v.validators
+                    }"
+                    ng-model="vm.ngModel[k]">
+                  </xos-field>
+                </div>
+              </div>
+            </div>
+      `,
+      bindToController: true,
+      controllerAs: 'vm',
+      // the compile cicle is needed to support recursion
+      compile: function (element) {
+        return RecursionHelper.compile(element);
+      },
+      controller: function($attrs, XosFormHelpers, LabelFormatter){
+
+        if(!this.name){
+          throw new Error('[xosField] Please provide a field name');
+        }
+        if(!this.field){
+          throw new Error('[xosField] Please provide a field definition');
+        }
+        if(!this.field.type){
+          throw new Error('[xosField] Please provide a type in the field definition');
+        }
+        if(!$attrs.ngModel){
+          throw new Error('[xosField] Please provide an ng-model');
+        }
+        this.getType = XosFormHelpers._getFieldFormat;
+        this.formatLabel = LabelFormatter.format;
+
+        this.isEmptyObject = o => o ? Object.keys(o).length === 0 : true;
+      }
+    }
+  })
+
+/**
+ * @ngdoc directive
+ * @name xos.uiComponents.directive:xosCustomValidator
+ * @restrict A
+ * @description The xosCustomValidator directive.
+ * This component apply a custom validation function
+ * @param {function} customValidator The function that execute the validation.
+ *
+ * You should do your validation here and return true | false,
+ * or alternatively you can return an array [errorName, true|false]
+ */
+  .directive('xosCustomValidator', function(){
+    return {
+      restrict: 'A',
+      scope: {
+        fn: '=customValidator'
+      },
+      require: 'ngModel',
+      link: function(scope, element, attr, ctrl){
+        if(!angular.isFunction(scope.fn)){
+          return;
+        }
+
+        function customValidatorWrapper(ngModelValue) {
+          const valid = scope.fn(ngModelValue);
+          if(angular.isArray(valid)){
+            // ES6 spread rocks over fn.apply()
+            ctrl.$setValidity(...valid);
+          }
+          else{
+            ctrl.$setValidity('customValidation', valid);
+          }
+          return ngModelValue;
+        }
+
+        ctrl.$parsers.push(customValidatorWrapper);
+      }
+    };
+  });
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/field/field.scss b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/field/field.scss
new file mode 100644
index 0000000..8dd7ca4
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/field/field.scss
@@ -0,0 +1,3 @@
+xos-field {
+  display: block;
+}
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/form/form.component.js b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/form/form.component.js
new file mode 100644
index 0000000..4d9169b
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/form/form.component.js
@@ -0,0 +1,285 @@
+/**
+ * © OpenCORD
+ *
+ * Visit http://guide.xosproject.org/devguide/addview/ for more information
+ *
+ * Created by teone on 4/18/16.
+ */
+
+(function () {
+  'use strict';
+
+
+  angular.module('xos.uiComponents')
+
+  /**
+    * @ngdoc directive
+    * @name xos.uiComponents.directive:xosForm
+    * @restrict E
+    * @description The xos-form directive.
+    * This components have two usage, given a model it is able to autogenerate a form or it can be configured to create a custom form.
+    * @param {Object} config The configuration object
+    * ```
+    * {
+    *   exclude: ['id', 'validators', 'created', 'updated', 'deleted'], //field to be skipped in the form, the provide values are concatenated
+    *   actions: [ // define the form buttons with related callback
+    *     {
+            label: 'save',
+            icon: 'ok', // refers to bootstraps glyphicon
+            cb: (user) => { // receive the model
+              console.log(user);
+            },
+            class: 'success'
+          }
+    *   ],
+    *   feedback: {
+          show: false,
+          message: 'Form submitted successfully !!!',
+          type: 'success'  //refers to bootstrap class
+        },
+    *   fields: {
+    *     field_name: {
+    *       label: 'Field Label',
+    *       type: 'string' // options are: [date, boolean, number, email, string, select],
+    *       validators: {
+    *         minlength: number,
+              maxlength: number,
+              required: boolean,
+              min: number,
+              max: number,
+              custom: (value) => {
+                // do your validation here and return true | false
+                // alternatively you can return an array [errorName, true|false]
+              }
+    *       }
+    *     }
+    *   }
+    * }
+    * ```
+    * @element ANY
+    * @scope
+    * @requires xos.uiComponents.directive:xosField
+    * @requires xos.uiComponents.XosFormHelpers
+    * @requires xos.helpers._
+    * @example
+    
+    Autogenerated form
+
+  <example module="sampleForm">
+    <file name="script.js">
+      angular.module('sampleForm', ['xos.uiComponents'])
+      .factory('_', function($window){
+        return $window._;
+      })
+      .controller('SampleCtrl', function(){
+        this.model = {
+          first_name: 'Jhon',
+          last_name: 'Doe',
+          email: 'jhon.doe@sample.com',
+          active: true,
+          birthDate: '2015-02-17T22:06:38.059000Z'
+        }
+        this.config = {
+          exclude: ['password', 'last_login'],
+          formName: 'sampleForm',
+          actions: [
+            {
+              label: 'Save',
+              icon: 'ok', // refers to bootstraps glyphicon
+              cb: (user) => { // receive the model
+                console.log(user);
+              },
+              class: 'success'
+            }
+          ]
+        };
+      });
+    </file>
+    <file name="index.html">
+      <div ng-controller="SampleCtrl as vm">
+        <xos-form ng-model="vm.model" config="vm.config"></xos-form>
+      </div>
+    </file>
+  </example>
+
+  Configuration defined form
+
+  <example module="sampleForm1">
+    <file name="script.js">
+      angular.module('sampleForm1', ['xos.uiComponents','ngResource', 'ngMockE2E'])
+      .factory('_', function($window){
+        return $window._;
+      })
+      .controller('SampleCtrl1', function(SampleResource){
+
+
+        this.model = {
+        };
+
+        this.config = {
+          exclude: ['password', 'last_login'],
+          formName: 'sampleForm1',
+          feedback: {
+            show: false,
+            message: 'Form submitted successfully !!!',
+            type: 'success'
+          },
+          actions: [
+            {
+              label: 'Save',
+              icon: 'ok', // refers to bootstraps glyphicon
+              cb: (user) => { // receive the model
+                console.log(user);
+                this.config.feedback.show = true;
+                this.config.feedback.type='success';
+              },
+              class: 'success'
+            }
+          ],
+          fields: {
+            first_name: {
+              type: 'string',
+              validators: {
+                required: true
+              }
+            },
+            last_name: {
+              label: 'Surname',
+              type: 'string',
+              validators: {
+                required: true,
+                minlength: 10
+              }
+            },
+            age: {
+              type: 'number',
+              validators: {
+                required: true,
+                min: 21
+              }
+            },
+
+            site: {
+            label: 'Site',
+            type: 'select',
+            validators: { required: true},
+            hint: 'The Site this Slice belongs to',
+            options: []
+            },
+         }
+        };
+        SampleResource.query().$promise
+          .then((users) => {
+          //this.users_site = users;
+        //console.log(users);
+          this.optionVal = users;
+          this.config.fields['site'].options = this.optionVal;
+        //= this.optionVal;
+
+      })
+      .catch((e) => {
+        throw new Error(e);
+      });
+
+      });
+    </file>
+   <file name="backend.js">
+     angular.module('sampleForm1')
+     .run(function($httpBackend, _){
+        let datas = [{id: 1, label: 'site1'},{id: 4, label: 'site4'},{id: 3, label: 'site3'}];
+        let paramsUrl = new RegExp(/\/test\/(.+)/);
+        $httpBackend.whenGET('/test').respond(200, datas)
+      })
+      .service('SampleResource', function($resource){
+        return $resource('/test/:id', {id: '@id'});
+      });
+
+    </file>
+    <file name="index.html">
+      <div ng-controller="SampleCtrl1 as vm">
+        <xos-form ng-model="vm.model" config="vm.config"></xos-form>
+      </div>
+    </file>
+  </example>
+
+  **/
+
+  .directive('xosForm', function(){
+    return {
+      restrict: 'E',
+      scope: {
+        config: '=',
+        ngModel: '='
+      },
+      template: `
+        <form name="vm.{{vm.config.formName || 'form'}}" novalidate>
+          <div class="form-group" ng-repeat="(name, field) in vm.formField">
+            <xos-field name="name" field="field" ng-model="vm.ngModel[name]"></xos-field>
+            <xos-validation field="vm[vm.config.formName || 'form'][name]" form = "vm[vm.config.formName || 'form']"></xos-validation>
+            <div class="alert alert-info" ng-show="(field.hint).length >0" role="alert">{{field.hint}}</div>
+          </div>
+          <div class="form-group" ng-if="vm.config.actions">
+          <xos-alert config="vm.config.feedback" show="vm.config.feedback.show">{{vm.config.feedback.message}}</xos-alert>
+
+            <button role="button" href=""
+              ng-repeat="action in vm.config.actions"
+              ng-click="action.cb(vm.ngModel, vm[vm.config.formName || 'form'])"
+              class="btn btn-{{action.class}}"
+              title="{{action.label}}">
+              <i class="glyphicon glyphicon-{{action.icon}}"></i>
+              {{action.label}}
+            </button>
+          </div>
+        </form>
+      `,
+      bindToController: true,
+      controllerAs: 'vm',
+      controller: function($scope, $log, _, XosFormHelpers){
+
+        if(!this.config){
+          throw new Error('[xosForm] Please provide a configuration via the "config" attribute');
+        }
+
+        if(!this.config.actions){
+          throw new Error('[xosForm] Please provide an action list in the configuration');
+        }
+
+        if(!this.config.feedback){
+          this.config.feedback =  {
+            show: false,
+            message: 'Form submitted successfully !!!',
+            type: 'success'
+          }
+        }
+
+        this.excludedField = ['id', 'validators', 'created', 'updated', 'deleted', 'backend_status'];
+        if(this.config && this.config.exclude){
+          this.excludedField = this.excludedField.concat(this.config.exclude);
+        }
+
+        this.formField = [];
+
+        $scope.$watch(() => this.config, ()=> {
+          if(!this.ngModel){
+            return;
+          }
+          let diff = _.difference(Object.keys(this.ngModel), this.excludedField);
+          let modelField = XosFormHelpers.parseModelField(diff);
+          this.formField = XosFormHelpers.buildFormStructure(modelField, this.config.fields, this.ngModel);
+        }, true);
+
+        $scope.$watch(() => this.ngModel, (model) => {
+          // empty from old stuff
+          this.formField = {};
+          if(!model){
+            return;
+          }
+          let diff = _.difference(Object.keys(model), this.excludedField);
+          let modelField = XosFormHelpers.parseModelField(diff);
+          this.formField = XosFormHelpers.buildFormStructure(modelField, this.config.fields, model);
+        });
+
+      }
+    }
+  });
+})();
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/form/form.scss b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/form/form.scss
new file mode 100644
index 0000000..b61f8e2
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/form/form.scss
@@ -0,0 +1,8 @@
+@import '../../../styles/animations.scss';
+@import '../../../../../../style/sass/bootstrap/bootstrap/_variables.scss';
+
+xos-form {
+  button {
+    margin-bottom: $form-group-margin-bottom;
+  }
+}
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/pagination/pagination.component.js b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/pagination/pagination.component.js
new file mode 100644
index 0000000..b7b1701
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/pagination/pagination.component.js
@@ -0,0 +1,122 @@
+/**
+ * © OpenCORD
+ *
+ * Visit http://guide.xosproject.org/devguide/addview/ for more information
+ *
+ * Created by teone on 4/15/16.
+ */
+
+(function () {
+  'use strict';
+
+  angular.module('xos.uiComponents')
+
+  /**
+    * @ngdoc directive
+    * @name xos.uiComponents.directive:xosPagination
+    * @restrict E
+    * @description The xos-table directive
+    * @param {Number} pageSize Number of elements per page
+    * @param {Number} totalElements Number of total elements in the collection
+    * @param {Function} change The callback to be triggered on page change.
+    * * @element ANY
+    * @scope
+    * @example
+  <example module="samplePagination">
+    <file name="index.html">
+      <div ng-controller="SampleCtrl1 as vm">
+        <xos-pagination
+          page-size="vm.pageSize"
+          total-elements="vm.totalElements"
+          change="vm.change">
+        </xos-pagination>
+      </div>
+    </file>
+    <file name="script.js">
+      angular.module('samplePagination', ['xos.uiComponents'])
+      .controller('SampleCtrl1', function(){
+        this.pageSize = 10;
+        this.totalElements = 35;
+        this.change = (pageNumber) => {
+          console.log(pageNumber);
+        }
+      });
+    </file>
+  </example>
+  **/
+
+  .directive('xosPagination', function(){
+    return {
+      restrict: 'E',
+      scope: {
+        pageSize: '=',
+        totalElements: '=',
+        change: '='
+      },
+      template: `
+        <div class="row" ng-if="vm.pageList.length > 1">
+          <div class="col-xs-12 text-center">
+            <ul class="pagination">
+              <li
+                ng-click="vm.goToPage(vm.currentPage - 1)"
+                ng-class="{disabled: vm.currentPage == 0}">
+                <a href="" aria-label="Previous">
+                    <span aria-hidden="true">&laquo;</span>
+                </a>
+              </li>
+              <li ng-repeat="i in vm.pageList" ng-class="{active: i === vm.currentPage}">
+                <a href="" ng-click="vm.goToPage(i)">{{i + 1}}</a>
+              </li>
+              <li
+                ng-click="vm.goToPage(vm.currentPage + 1)"
+                ng-class="{disabled: vm.currentPage == vm.pages - 1}">
+                <a href="" aria-label="Next">
+                    <span aria-hidden="true">&raquo;</span>
+                </a>
+              </li>
+            </ul>
+          </div>
+        </div>
+      `,
+      bindToController: true,
+      controllerAs: 'vm',
+      controller: function($scope){
+        
+        this.currentPage = 0;
+
+        this.goToPage = (n) => {
+          if(n < 0 || n === this.pages){
+            return;
+          }
+          this.currentPage = n;
+          this.change(n);
+        }
+
+        this.createPages = (pages) => {
+          let arr = [];
+          for(var i = 0; i < pages; i++){
+            arr.push(i);
+          }
+          return arr;
+        }
+
+        // watch for data changes
+        $scope.$watch(() => this.totalElements, () => {
+          if(this.totalElements){
+            this.pages = Math.ceil(this.totalElements / this.pageSize);
+            this.pageList = this.createPages(this.pages);
+          }
+        });
+      }
+    }
+  })
+  .filter('pagination', function(){
+    return function(input, start) {
+      if(!input || !angular.isArray(input)){
+        return input;
+      }
+      start = parseInt(start, 10);
+      return input.slice(start);
+    };
+  });
+})();
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/table/table.component.js b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/table/table.component.js
new file mode 100644
index 0000000..1e60458
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/table/table.component.js
@@ -0,0 +1,549 @@
+/**
+ * © OpenCORD
+ *
+ * Visit http://guide.xosproject.org/devguide/addview/ for more information
+ *
+ * Created by teone on 3/24/16.
+ */
+
+(function () {
+  'use strict';
+
+  angular.module('xos.uiComponents')
+
+    /**
+    * @ngdoc directive
+    * @name xos.uiComponents.directive:xosTable
+    * @restrict E
+    * @description The xos-table directive
+    * @param {Object} config The configuration for the component.
+    * ```
+    * {
+    *   columns: [
+    *     {
+    *       label: 'Human readable name',
+    *       prop: 'Property to read in the model object',
+    *       type: 'boolean'| 'array'| 'object'| 'custom'| 'date' | 'icon' // see examples for more details
+            formatter: fn(), // receive the whole item if tipe is custom and return a string
+            link: fn() // receive the whole item and return an url
+    *     }
+    *   ],
+    *   classes: 'table table-striped table-bordered',
+    *   actions: [ // if defined add an action column
+          {
+            label: 'delete',
+            icon: 'remove', // refers to bootstraps glyphicon
+            cb: (user) => { // receive the model
+              console.log(user);
+            },
+            color: 'red'
+          }
+        ],
+        filter: 'field', // can be by `field` or `fulltext`
+        order: true | {field: 'property name', reverse: true | false} // whether to show ordering arrows, or a configuration for a default ordering
+    * }
+    * ```
+    * @param {Array} data The data that should be rendered
+    * @element ANY
+    * @scope
+    * @example
+  
+  # Basic usage
+  <example module="sampleTable1">
+    <file name="index.html">
+      <div ng-controller="SampleCtrl1 as vm">
+        <xos-table data="vm.data" config="vm.config"></xos-table>
+      </div>
+    </file>
+    <file name="script.js">
+      angular.module('sampleTable1', ['xos.uiComponents'])
+      .factory('_', function($window){
+        return $window._;
+      })
+      .controller('SampleCtrl1', function(){
+        this.config = {
+          columns: [
+            {
+              label: 'First Name', // column title
+              prop: 'name' // property to read in the data array
+            },
+            {
+              label: 'Last Name',
+              prop: 'lastname'
+            }
+          ]
+        };
+
+        this.data = [
+          {
+            name: 'John',
+            lastname: 'Doe'
+          },
+          {
+            name: 'Gili',
+            lastname: 'Fereydoun'
+          }
+        ]
+      });
+    </file>
+  </example>
+  
+  # Filtering
+  <example module="sampleTable2" animations="true">
+    <file name="index.html">
+      <div ng-controller="SampleCtrl2 as vm">
+        <xos-table data="vm.data" config="vm.config"></xos-table>
+      </div>
+    </file>
+    <file name="script.js">
+      angular.module('sampleTable2', ['xos.uiComponents', 'ngAnimate'])
+      .factory('_', function($window){
+        return $window._;
+      })
+      .controller('SampleCtrl2', function(){
+        this.config = {
+          columns: [
+            {
+              label: 'First Name', // column title
+              prop: 'name' // property to read in the data array
+            },
+            {
+              label: 'Last Name',
+              prop: 'lastname'
+            }
+          ],
+          classes: 'table table-striped table-condensed', // table classes, default to `table table-striped table-bordered`
+          actions: [ // if defined add an action column
+            {
+              label: 'delete', // label
+              icon: 'remove', // icons, refers to bootstraps glyphicon
+              cb: (user) => { // callback, get feeded with the full object
+                console.log(user);
+              },
+              color: 'red' // icon color
+            }
+          ],
+          filter: 'field', // can be by `field` or `fulltext`
+          order: true
+        };
+
+        this.data = [
+          {
+            name: 'John',
+            lastname: 'Doe'
+          },
+          {
+            name: 'Gili',
+            lastname: 'Fereydoun'
+          }
+        ]
+      });
+    </file>
+  </example>
+  
+  # Pagination
+  <example module="sampleTable3">
+    <file name="index.html">
+      <div ng-controller="SampleCtrl3 as vm">
+        <xos-table data="vm.data" config="vm.config"></xos-table>
+      </div>
+    </file>
+    <file name="script.js">
+      angular.module('sampleTable3', ['xos.uiComponents'])
+      .factory('_', function($window){
+        return $window._;
+      })
+      .controller('SampleCtrl3', function(){
+        this.config = {
+          columns: [
+            {
+              label: 'First Name', // column title
+              prop: 'name' // property to read in the data array
+            },
+            {
+              label: 'Last Name',
+              prop: 'lastname'
+            }
+          ],
+          pagination: {
+            pageSize: 2
+          }
+        };
+
+        this.data = [
+          {
+            name: 'John',
+            lastname: 'Doe'
+          },
+          {
+            name: 'Gili',
+            lastname: 'Fereydoun'
+          },
+          {
+            name: 'Lucky',
+            lastname: 'Clarkson'
+          },
+          {
+            name: 'Tate',
+            lastname: 'Spalding'
+          }
+        ]
+      });
+    </file>
+  </example>
+  
+  # Field formatter
+  <example module="sampleTable4">
+    <file name="index.html">
+      <div ng-controller="SampleCtrl as vm">
+        <xos-table data="vm.data" config="vm.config"></xos-table>
+      </div>
+    </file>
+    <file name="script.js">
+      angular.module('sampleTable4', ['xos.uiComponents'])
+      .factory('_', function($window){
+        return $window._;
+      })
+      .controller('SampleCtrl', function(){
+        this.config = {
+          columns: [
+            {
+              label: 'First Name',
+              prop: 'name',
+              link: item => `https://www.google.it/#q=${item.name}`
+            },
+            {
+              label: 'Enabled',
+              prop: 'enabled',
+              type: 'boolean'
+            },
+            {
+              label: 'Services',
+              prop: 'services',
+              type: 'array'
+            },
+            {
+              label: 'Details',
+              prop: 'details',
+              type: 'object'
+            },
+            {
+              label: 'Created',
+              prop: 'created',
+              type: 'date'
+            },
+            {
+              label: 'Icon',
+              type: 'icon',
+              formatter: item => item.icon //note that this refer to [Bootstrap Glyphicon](http://getbootstrap.com/components/#glyphicons)
+            }
+          ]
+        };
+
+        this.data = [
+          {
+            name: 'John',
+            enabled: true,
+            services: ['Cdn', 'IpTv'],
+            details: {
+              c_tag: '243',
+              s_tag: '444'
+            },
+            created: new Date('December 17, 1995 03:24:00'),
+            icon: 'music'
+          },
+          {
+            name: 'Gili',
+            enabled: false,
+            services: ['Cdn', 'IpTv', 'Cache'],
+            details: {
+              c_tag: '675',
+              s_tag: '893'
+            },
+            created: new Date(),
+            icon: 'camera'
+          }
+        ]
+      });
+    </file>
+  </example>
+
+  # Custom formatter
+  <example module="sampleTable5">
+    <file name="index.html">
+      <div ng-controller="SampleCtrl as vm">
+        <xos-table data="vm.data" config="vm.config"></xos-table>
+      </div>
+    </file>
+    <file name="script.js">
+      angular.module('sampleTable5', ['xos.uiComponents'])
+      .factory('_', function($window){
+        return $window._;
+      })
+      .controller('SampleCtrl', function(){
+        this.config = {
+          columns: [
+            {
+              label: 'Username',
+              prop: 'username'
+            },
+            {
+              label: 'Features',
+              type: 'custom',
+              formatter: (val) => {
+                
+                let cdnEnabled = val.features.cdn ? 'enabled' : 'disabled';
+                return `
+                  Cdn is ${cdnEnabled},
+                  uplink speed is ${val.features.uplink_speed}
+                  and downlink speed is ${val.features.downlink_speed}
+                `;
+              }
+            }
+          ]
+        };
+
+        this.data = [
+          {
+            username: 'John',
+            features: {
+              "cdn": false,
+              "uplink_speed": 1000000000,
+              "downlink_speed": 1000000000,
+              "uverse": true,
+              "status": "enabled"
+            }
+          },
+          {
+            username: 'Gili',
+            features: {
+              "cdn": true,
+              "uplink_speed": 3000000000,
+              "downlink_speed": 2000000000,
+              "uverse": true,
+              "status": "enabled"
+            }
+          }
+        ]
+      });
+    </file>
+  </example>
+    **/
+
+    .directive('xosTable', function(){
+      return {
+        restrict: 'E',
+        scope: {
+          data: '=',
+          config: '='
+        },
+        template: `
+          <div ng-show="vm.data.length > 0 && vm.loader == false">
+            <div class="row" ng-if="vm.config.filter == 'fulltext'">
+              <div class="col-xs-12">
+                <input
+                  class="form-control"
+                  placeholder="Type to search.."
+                  type="text"
+                  ng-model="vm.query"/>
+              </div>
+            </div>
+            <table ng-class="vm.classes" ng-hide="vm.data.length == 0">
+              <thead>
+                <tr>
+                  <th ng-repeat="col in vm.columns">
+                    {{col.label}}
+                    <span ng-if="vm.config.order">
+                      <a href="" ng-click="vm.orderBy = col.prop; vm.reverse = false">
+                        <i class="glyphicon glyphicon-chevron-up"></i>
+                      </a>
+                      <a href="" ng-click="vm.orderBy = col.prop; vm.reverse = true">
+                        <i class="glyphicon glyphicon-chevron-down"></i>
+                      </a>
+                    </span>
+                  </th>
+                  <th ng-if="vm.config.actions">Actions:</th>
+                </tr>
+              </thead>
+              <tbody ng-if="vm.config.filter == 'field'">
+                <tr>
+                  <td ng-repeat="col in vm.columns">
+                    <input
+                      ng-if="col.type !== 'boolean' && col.type !== 'array' && col.type !== 'object' && col.type !== 'custom'"
+                      class="form-control"
+                      placeholder="Type to search by {{col.label}}"
+                      type="text"
+                      ng-model="vm.query[col.prop]"/>
+                    <select
+                      ng-if="col.type === 'boolean'"
+                      class="form-control"
+                      ng-model="vm.query[col.prop]">
+                      <option value="">-</option>
+                      <option value="true">True</option>
+                      <option value="false">False</option>
+                    </select>
+                  </td>
+                  <td ng-if="vm.config.actions"></td>
+                </tr>
+              </tbody>
+              <tbody>
+                <tr ng-repeat="item in vm.data | filter:vm.query:vm.comparator | orderBy:vm.orderBy:vm.reverse | pagination:vm.currentPage * vm.config.pagination.pageSize | limitTo: (vm.config.pagination.pageSize || vm.data.length) track by $index">
+                  <td ng-repeat="col in vm.columns" xos-link-wrapper>
+                    <span ng-if="!col.type">{{item[col.prop]}}</span>
+                    <span ng-if="col.type === 'boolean'">
+                      <i class="glyphicon"
+                        ng-class="{'glyphicon-ok': item[col.prop], 'glyphicon-remove': !item[col.prop]}">
+                      </i>
+                    </span>
+                    <span ng-if="col.type === 'date'">
+                      {{item[col.prop] | date:'H:mm MMM d, yyyy'}}
+                    </span>
+                    <span ng-if="col.type === 'array'">
+                      {{item[col.prop] | arrayToList}}
+                    </span>
+                    <span ng-if="col.type === 'object'">
+                      <dl class="dl-horizontal">
+                        <span ng-repeat="(k,v) in item[col.prop]">
+                          <dt>{{k}}</dt>
+                          <dd>{{v}}</dd>
+                        </span>
+                      </dl>
+                    </span>
+                    <span ng-if="col.type === 'custom'">
+                      {{col.formatter(item)}}
+                    </span>
+                    <span ng-if="col.type === 'icon'">
+                      <i class="glyphicon glyphicon-{{col.formatter(item)}}">
+                      </i>
+                    </span>
+                  </td>
+                  <td ng-if="vm.config.actions">
+                    <a href=""
+                      ng-repeat="action in vm.config.actions"
+                      ng-click="action.cb(item)"
+                      title="{{action.label}}">
+                      <i
+                        class="glyphicon glyphicon-{{action.icon}}"
+                        style="color: {{action.color}};"></i>
+                    </a>
+                  </td>
+                </tr>
+              </tbody>
+            </table>
+            <xos-pagination
+              ng-if="vm.config.pagination"
+              page-size="vm.config.pagination.pageSize"
+              total-elements="vm.data.length"
+              change="vm.goToPage">
+              </xos-pagination>
+          </div>
+          <div ng-show="(vm.data.length == 0 || !vm.data) && vm.loader == false">
+             <xos-alert config="{type: 'info'}">
+              No data to show.
+            </xos-alert>
+          </div>
+          <div ng-show="vm.loader == true">
+            <div class="loader"></div>
+          </div>
+        `,
+        bindToController: true,
+        controllerAs: 'vm',
+        controller: function(_, $scope, Comparator){
+
+          this.comparator = Comparator;
+
+          this.loader = true;
+
+          $scope.$watch(() => this.data, data => {
+            if(angular.isDefined(data)){
+              this.loader = false;
+            }
+          });
+
+          if(!this.config){
+            throw new Error('[xosTable] Please provide a configuration via the "config" attribute');
+          }
+
+          if(!this.config.columns){
+            throw new Error('[xosTable] Please provide a columns list in the configuration');
+          }
+
+          // handle default ordering
+          if(this.config.order && angular.isObject(this.config.order)){
+            this.reverse = this.config.order.reverse || false;
+            this.orderBy = this.config.order.field || 'id';
+          }
+
+          // if columns with type 'custom' are provided
+          // check that a custom formatte3 is provided too
+          let customCols = _.filter(this.config.columns, {type: 'custom'});
+          if(angular.isArray(customCols) && customCols.length > 0){
+            _.forEach(customCols, (col) => {
+              if(!col.formatter || !angular.isFunction(col.formatter)){
+                throw new Error('[xosTable] You have provided a custom field type, a formatter function should provided too.');
+              }
+            })
+          }
+
+          // if columns with type 'icon' are provided
+          // check that a custom formatte3 is provided too
+          let iconCols = _.filter(this.config.columns, {type: 'icon'});
+          if(angular.isArray(iconCols) && iconCols.length > 0){
+            _.forEach(iconCols, (col) => {
+              if(!col.formatter || !angular.isFunction(col.formatter)){
+                throw new Error('[xosTable] You have provided an icon field type, a formatter function should provided too.');
+              }
+            })
+          }
+
+          // if a link property is passed,
+          // it should be a function
+          let linkedColumns = _.filter(this.config.columns, col => angular.isDefined(col.link));
+          if(angular.isArray(linkedColumns) && linkedColumns.length > 0){
+            _.forEach(linkedColumns, (col) => {
+              if(!angular.isFunction(col.link)){
+                throw new Error('[xosTable] The link property should be a function.');
+              }
+            })
+          }
+
+          this.columns = this.config.columns;
+          this.classes = this.config.classes || 'table table-striped table-bordered';
+
+          if(this.config.actions){
+            // TODO validate action format
+          }
+          if(this.config.pagination){
+            this.currentPage = 0;
+            this.goToPage = (n) => {
+              this.currentPage = n;
+            };
+          }
+
+        }
+      }
+    })
+    // TODO move in separate files
+    // TODO test
+    .filter('arrayToList', function(){
+      return (input) => {
+        if(!angular.isArray(input)){
+          return input;
+        }
+        return input.join(', ');
+      }
+    })
+    // TODO test
+    .directive('xosLinkWrapper', function() {
+      return {
+        restrict: 'A',
+        transclude: true,
+        template: `
+          <a ng-if="col.link" href="{{col.link(item)}}">
+            <div ng-transclude></div>
+          </a>
+          <div ng-transclude ng-if="!col.link"></div>
+        `
+      };
+    });
+})();
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/table/table.scss b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/table/table.scss
new file mode 100644
index 0000000..d9830d8
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/table/table.scss
@@ -0,0 +1,44 @@
+@import '../../../styles/animations.scss';
+
+xos-table {
+
+  display: block;
+
+  tr.ng-move,
+  tr.ng-enter,
+  tr.ng-leave {
+    transition:all linear 0.5s;
+  }
+
+  tr.ng-leave.ng-leave-active,
+  tr.ng-move,
+  tr.ng-enter {
+    opacity:0;
+    animation: 0.5s slideOutRight ease-in-out;
+  }
+
+  tr.ng-leave,
+  tr.ng-move.ng-move-active,
+  tr.ng-enter.ng-enter-active {
+    opacity:1;
+    animation: 0.5s slideInRight ease-in-out;
+  }
+
+  td dl {
+    margin-bottom: 0;
+
+    dt {
+      width: auto !important;
+      margin-right: 10px;
+    }
+    
+    dt:after {
+      /*display: block;*/
+      content: ':';
+    }
+
+    dd {
+      margin-left: 0 !important;
+    }
+  }
+}
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/validation/validation.component.js b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/validation/validation.component.js
new file mode 100644
index 0000000..91610e1
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/validation/validation.component.js
@@ -0,0 +1,112 @@
+/**
+ * © OpenCORD
+ *
+ * Visit http://guide.xosproject.org/devguide/addview/ for more information
+ *
+ * Created by teone on 4/15/16.
+ */
+
+(function () {
+  'use strict';
+
+  angular.module('xos.uiComponents')
+
+  /**
+    * @ngdoc directive
+    * @name xos.uiComponents.directive:xosValidation
+    * @restrict E
+    * @description The xos-validation directive
+    * @param {Object} errors The error object
+    * @element ANY
+    * @scope
+  * @example
+  <example module="sampleValidation">
+    <file name="index.html">
+      <div ng-controller="SampleCtrl as vm">
+        <div class="row">
+          <div class="col-xs-12">
+            <label>Set an error type:</label>
+          </div>
+          <div class="col-xs-2">
+            <a class="btn"
+              ng-click="vm.field.$error.required = !vm.field.$error.required"
+              ng-class="{'btn-default': !vm.field.$error.required, 'btn-success': vm.field.$error.required}">
+              Required
+            </a>
+          </div>
+          <div class="col-xs-2">
+            <a class="btn"
+              ng-click="vm.field.$error.email = !vm.field.$error.email"
+              ng-class="{'btn-default': !vm.field.$error.email, 'btn-success': vm.field.$error.email}">
+              Email
+            </a>
+          </div>
+          <div class="col-xs-2">
+            <a class="btn"
+              ng-click="vm.field.$error.minlength = !vm.field.$error.minlength"
+              ng-class="{'btn-default': !vm.field.$error.minlength, 'btn-success': vm.field.$error.minlength}">
+              Min Length
+            </a>
+          </div>
+          <div class="col-xs-2">
+            <a class="btn"
+              ng-click="vm.field.$error.maxlength = !vm.field.$error.maxlength"
+              ng-class="{'btn-default': !vm.field.$error.maxlength, 'btn-success': vm.field.$error.maxlength}">
+              Max Length
+            </a>
+          </div>
+        </div>
+        <xos-validation field ="vm.field" form = "vm.form"></xos-validation>
+      </div>
+    </file>
+    <file name="script.js">
+      angular.module('sampleValidation', ['xos.uiComponents'])
+      .controller('SampleCtrl', function(){
+        this.field = {
+          $error: {}
+        };
+        this.form= {
+        $submitted:true
+        }
+      });
+    </file>
+  </example>
+    */
+
+  .directive('xosValidation', function(){
+    return {
+      restrict: 'E',
+      scope: {
+        field: '=',
+        form: '='
+      },
+      template: `
+        <div ng-cloak>
+          <xos-alert config="vm.config" show="vm.field.$error.required !== undefined && vm.field.$error.required !== false  && (vm.field.$touched || vm.form.$submitted)">
+            Field required
+          </xos-alert>
+          <xos-alert config="vm.config" show="vm.field.$error.email !== undefined && vm.field.$error.email !== false && (vm.field.$touched || vm.form.$submitted)">
+            This is not a valid email
+          </xos-alert>
+          <xos-alert config="vm.config" show="vm.field.$error.minlength !== undefined && vm.field.$error.minlength !== false && (vm.field.$touched || vm.form.$submitted)">
+            Too short
+          </xos-alert>
+          <xos-alert config="vm.config" show="vm.field.$error.maxlength !== undefined && vm.field.$error.maxlength !== false && (vm.field.$touched || vm.form.$submitted)">
+            Too long
+          </xos-alert>
+          <xos-alert config="vm.config" show="vm.field.$error.custom !== undefined && vm.field.$error.custom !== false && (vm.field.$touched || vm.form.$submitted)">
+            Field invalid
+          </xos-alert>
+        </div>
+      `,
+      transclude: true,
+      bindToController: true,
+      controllerAs: 'vm',
+      controller: function(){
+        this.config = {
+          type: 'danger'
+        }
+      }
+    }
+  })
+})();
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/validation/validation.scss b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/validation/validation.scss
new file mode 100644
index 0000000..aaf6e2f
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/validation/validation.scss
@@ -0,0 +1,7 @@
+@import '../../../styles/animations.scss';
+@import '../../../../../../style/sass/bootstrap/bootstrap/_variables.scss';
+
+input + xos-validation {
+  margin-top: $form-group-margin-bottom;
+  display: block;
+}
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/smartComponents/smartPie/smartPie.component.js b/views/ngXosLib/xosHelpers/src/ui_components/smartComponents/smartPie/smartPie.component.js
new file mode 100644
index 0000000..f8a3985
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/ui_components/smartComponents/smartPie/smartPie.component.js
@@ -0,0 +1,248 @@
+/**
+ * © OpenCORD
+ *
+ * Visit http://guide.xosproject.org/devguide/addview/ for more information
+ *
+ * Created by teone on 3/24/16.
+ */
+
+(function () {
+  'use strict';
+
+  angular.module('xos.uiComponents')
+  /**
+    * @ngdoc directive
+    * @name xos.uiComponents.directive:xosSmartPie
+    * @restrict E
+    * @description The xos-table directive
+    * @param {Object} config The configuration for the component,
+    * it is composed by the name of an angular [$resource](https://docs.angularjs.org/api/ngResource/service/$resource)
+    * and a field name that is used to group the data.
+    * ```
+    * {
+        resource: 'Users',
+        groupBy: 'fieldName',
+        classes: 'my-custom-class',
+        labelFormatter: (labels) => {
+          // here you can format your label,
+          // you should return an array with the same order
+          return labels;
+        }
+      }
+    * ```
+    * @scope
+    * @example
+    
+    Displaying Local data
+
+    <example module="sampleSmartPieLocal">
+      <file name="index.html">
+        <div ng-controller="SampleCtrlLocal as vm">
+          <xos-smart-pie config="vm.configLocal"></xos-smart-pie>
+        </div>
+      </file>
+      <file name="script.js">
+        angular.module('sampleSmartPieLocal', ['xos.uiComponents'])
+        .factory('_', function($window){
+          return $window._;
+        })
+        .controller('SampleCtrlLocal', function($timeout){
+          
+          this.datas = [
+            {id: 1, first_name: 'Jon', last_name: 'aaa', category: 2},
+            {id: 2, first_name: 'Danaerys', last_name: 'Targaryen', category: 1},
+            {id: 3, first_name: 'Aria', last_name: 'Stark', category: 2}
+          ];
+
+          this.configLocal = {
+            data: [],
+            groupBy: 'category',
+            classes: 'local',
+            labelFormatter: (labels) => {
+              return labels.map(l => l === '1' ? 'North' : 'Dragon');
+            }
+          };
+          
+          $timeout(() => {
+            // this need to be triggered in this way just because of ngDoc,
+            // otherwise you can assign data directly in the config
+            this.configLocal.data = this.datas;
+          }, 1)
+        });
+      </file>
+    </example>
+
+    Fetching data from API
+
+    <example module="sampleSmartPieResource">
+      <file name="index.html">
+        <div ng-controller="SampleCtrl as vm">
+          <xos-smart-pie config="vm.config"></xos-smart-pie>
+        </div>
+      </file>
+      <file name="script.js">
+        angular.module('sampleSmartPieResource', ['xos.uiComponents', 'ngResource', 'ngMockE2E'])
+        .controller('SampleCtrl', function(){
+          this.config = {
+            resource: 'SampleResource',
+            groupBy: 'category',
+            classes: 'resource',
+            labelFormatter: (labels) => {
+              return labels.map(l => l === '1' ? 'North' : 'Dragon');
+            }
+          };
+        });
+      </file>
+      <file name="backendPoll.js">
+        angular.module('sampleSmartPieResource')
+        .run(function($httpBackend, _){
+          let datas = [
+            {id: 1, first_name: 'Jon', last_name: 'Snow', category: 1},
+            {id: 2, first_name: 'Danaerys', last_name: 'Targaryen', category: 2},
+            {id: 3, first_name: 'Aria', last_name: 'Stark', category: 1}
+          ];
+
+          $httpBackend.whenGET('/test').respond(200, datas)
+        })
+        .factory('_', function($window){
+          return $window._;
+        })
+        .service('SampleResource', function($resource){
+          return $resource('/test/:id', {id: '@id'});
+        })
+      </file>
+    </example>
+
+    Polling data from API
+
+    <example module="sampleSmartPiePoll">
+      <file name="index.html">
+        <div ng-controller="SampleCtrl as vm">
+          <xos-smart-pie config="vm.config"></xos-smart-pie>
+        </div>
+      </file>
+      <file name="script.js">
+        angular.module('sampleSmartPiePoll', ['xos.uiComponents', 'ngResource', 'ngMockE2E'])
+        .controller('SampleCtrl', function(){
+          this.config = {
+            resource: 'SampleResource',
+            groupBy: 'category',
+            poll: 2,
+            labelFormatter: (labels) => {
+              return labels.map(l => l === '1' ? 'Active' : 'Banned');
+            }
+          };
+        });
+      </file>
+      <file name="backend.js">
+        angular.module('sampleSmartPiePoll')
+        .run(function($httpBackend, _){
+          let mock = [
+            [
+              {id: 1, first_name: 'Jon', last_name: 'Snow', category: 1},
+              {id: 2, first_name: 'Danaerys', last_name: 'Targaryen', category: 2},
+              {id: 3, first_name: 'Aria', last_name: 'Stark', category: 1},
+              {id: 3, first_name: 'Tyrion', last_name: 'Lannister', category: 1}
+            ],
+
+            [
+              {id: 1, first_name: 'Jon', last_name: 'Snow', category: 1},
+              {id: 2, first_name: 'Danaerys', last_name: 'Targaryen', category: 2},
+              {id: 3, first_name: 'Aria', last_name: 'Stark', category: 2},
+              {id: 3, first_name: 'Tyrion', last_name: 'Lannister', category: 2}
+            ],
+
+            [
+              {id: 1, first_name: 'Jon', last_name: 'Snow', category: 1},
+              {id: 2, first_name: 'Danaerys', last_name: 'Targaryen', category: 2},
+              {id: 3, first_name: 'Aria', last_name: 'Stark', category: 1},
+              {id: 3, first_name: 'Tyrion', last_name: 'Lannister', category: 2}
+            ]
+          ];
+          $httpBackend.whenGET('/test').respond(function(method, url, data, headers, params) {
+            return [200, mock[Math.round(Math.random() * 3)]];
+          });
+        })
+        .factory('_', function($window){
+          return $window._;
+        })
+        .service('SampleResource', function($resource){
+          return $resource('/test/:id', {id: '@id'});
+        })
+      </file>
+    </example>
+    */
+  .directive('xosSmartPie', function(){
+    return {
+      restrict: 'E',
+      scope: {
+        config: '='
+      },
+      template: `
+        <canvas
+          class="chart chart-pie {{vm.config.classes}}"
+          chart-data="vm.data" chart-labels="vm.labels"
+          chart-legend="{{vm.config.legend}}">
+        </canvas>
+      `,
+      bindToController: true,
+      controllerAs: 'vm',
+      controller: function($injector, $interval, $scope, $timeout, _){
+
+        if(!this.config.resource && !this.config.data){
+          throw new Error('[xosSmartPie] Please provide a resource or an array of data in the configuration');
+        }
+
+        const groupData = (data) => _.groupBy(data, this.config.groupBy);
+        const formatData = (data) => _.reduce(Object.keys(data), (list, group) => list.concat(data[group].length), []);
+        const formatLabels = (data) => angular.isFunction(this.config.labelFormatter) ? this.config.labelFormatter(Object.keys(data)) : Object.keys(data);
+
+        const prepareData = (data) => {
+          // group data
+          let grouped = groupData(data);
+          this.data = formatData(grouped);
+          // create labels
+          this.labels = formatLabels(grouped);
+        }
+
+        if(this.config.resource){
+
+          this.Resource = $injector.get(this.config.resource);
+          const getData = () => {
+            this.Resource.query().$promise
+            .then((res) => {
+
+              if(!res[0]){
+                return;
+              }
+
+              prepareData(res);
+            });
+          }
+
+          getData();
+
+          if(this.config.poll){
+            $interval(() => {getData()}, this.config.poll * 1000)
+          }
+        }
+        else {
+          $scope.$watch(() => this.config.data, (data) => {
+            if(data){
+              prepareData(this.config.data);
+            }
+          }, true);
+        }
+
+        $scope.$on('create', function (event, chart) {
+          console.log(`create: ${chart.id}`);
+        });
+
+        $scope.$on('destroy', function (event, chart) {
+          console.log(`destroy: ${chart.id}`);
+        });
+
+      }
+    };
+  });
+})();
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/smartComponents/smartTable/smartTable.component.js b/views/ngXosLib/xosHelpers/src/ui_components/smartComponents/smartTable/smartTable.component.js
new file mode 100644
index 0000000..622952f
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/ui_components/smartComponents/smartTable/smartTable.component.js
@@ -0,0 +1,269 @@
+/**
+ * © OpenCORD
+ *
+ * Visit http://guide.xosproject.org/devguide/addview/ for more information
+ *
+ * Created by teone on 3/24/16.
+ */
+
+(function () {
+  'use strict';
+
+  angular.module('xos.uiComponents')
+
+    /**
+    * @ngdoc directive
+    * @name xos.uiComponents.directive:xosSmartTable
+    * @link xos.uiComponents.directive:xosTable xosTable
+    * @link xos.uiComponents.directive:xosForm xosForm
+    * @restrict E
+    * @description The xos-table directive
+    * @param {Object} config The configuration for the component,
+    * it is composed by the name of an angular [$resource](https://docs.angularjs.org/api/ngResource/service/$resource)
+    * and an array of fields that shouldn't be printed.
+    * ```
+    * {
+        resource: 'Users',
+        hiddenFields: []
+      }
+    * ```
+    * @scope
+    * @example
+
+    <example module="sampleSmartTable">
+      <file name="index.html">
+        <div ng-controller="SampleCtrl as vm">
+          <xos-smart-table config="vm.config"></xos-smart-table>
+        </div>
+      </file>
+      <file name="script.js">
+        angular.module('sampleSmartTable', ['xos.uiComponents', 'ngResource', 'ngMockE2E'])
+        // This is only for documentation purpose
+        .run(function($httpBackend, _){
+          let datas = [{id: 1, name: 'Jhon', surname: 'Doe'}];
+          let count = 1;
+
+          let paramsUrl = new RegExp(/\/test\/(.+)/);
+
+          $httpBackend.whenDELETE(paramsUrl, undefined, ['id']).respond((method, url, data, headers, params) => {
+            data = angular.fromJson(data);
+            let id = url.match(paramsUrl)[1];
+            _.remove(datas, (d) => {
+              return d.id === parseInt(id);
+            })
+            return [204];
+          });
+
+          $httpBackend.whenGET('/test').respond(200, datas)
+          $httpBackend.whenPOST('/test').respond((method, url, data) => {
+            data = angular.fromJson(data);
+            data.id = ++count;
+            datas.push(data);
+            return [201, data, {}];
+          });
+        })
+        .factory('_', function($window){
+          return $window._;
+        })
+        .service('SampleResource', function($resource){
+          return $resource('/test/:id', {id: '@id'});
+        })
+        // End of documentation purpose, example start
+        .controller('SampleCtrl', function(){
+          this.config = {
+            resource: 'SampleResource'
+          };
+        });
+      </file>
+    </example>
+    */
+   
+  .directive('xosSmartTable', function(){
+    return {
+      restrict: 'E',
+      scope: {
+        config: '='
+      },
+      template: `
+        <div class="row" ng-show="vm.data.length > 0">
+          <div class="col-xs-12 text-right">
+            <a href="" class="btn btn-success" ng-click="vm.createItem()">
+              Add
+            </a>
+          </div>
+        </div>
+        <div class="row">
+          <div class="col-xs-12 table-responsive">
+            <xos-table config="vm.tableConfig" data="vm.data"></xos-table>
+          </div>
+        </div>
+        <div class="panel panel-default" ng-show="vm.detailedItem">
+          <div class="panel-heading">
+            <div class="row">
+              <div class="col-xs-11">
+                <h3 class="panel-title" ng-show="vm.detailedItem.id">Update {{vm.config.resource}} {{vm.detailedItem.id}}</h3>
+                <h3 class="panel-title" ng-show="!vm.detailedItem.id">Create {{vm.config.resource}} item</h3>
+              </div>
+              <div class="col-xs-1">
+                <a href="" ng-click="vm.cleanForm()">
+                  <i class="glyphicon glyphicon-remove pull-right"></i>
+                </a>
+              </div>
+            </div>
+          </div>
+          <div class="panel-body">
+            <xos-form config="vm.formConfig" ng-model="vm.detailedItem"></xos-form>
+          </div>
+        </div>
+        <xos-alert config="{type: 'success', closeBtn: true}" show="vm.responseMsg">{{vm.responseMsg}}</xos-alert>
+        <xos-alert config="{type: 'danger', closeBtn: true}" show="vm.responseErr">{{vm.responseErr}}</xos-alert>
+      `,
+      bindToController: true,
+      controllerAs: 'vm',
+      controller: function($injector, LabelFormatter, _, XosFormHelpers){
+        
+        // TODO
+        // - Validate the config (what if resource does not exist?)
+
+        // NOTE
+        // Corner case
+        // - if response is empty, how can we generate a form ?
+
+        this.responseMsg = false;
+        this.responseErr = false;
+
+        this.tableConfig = {
+          columns: [
+          ],
+          actions: [
+            {
+              label: 'delete',
+              icon: 'remove',
+              cb: (item) => {
+                this.Resource.delete({id: item.id}).$promise
+                .then(() => {
+                  _.remove(this.data, (d) => d.id === item.id);
+                  this.responseMsg = `${this.config.resource} with id ${item.id} successfully deleted`;
+                })
+                .catch(err => {
+                  this.responseErr = err.data.detail || `Error while deleting ${this.config.resource} with id ${item.id}`;
+                });
+              },
+              color: 'red'
+            },
+            {
+              label: 'details',
+              icon: 'search',
+              cb: (item) => {
+                this.detailedItem = item;
+              }
+            }
+          ],
+          classes: 'table table-striped table-bordered table-responsive',
+          filter: 'field',
+          order: true,
+          pagination: {
+            pageSize: 10
+          }
+        };
+
+        this.formConfig = {
+          exclude: this.config.hiddenFields,
+          fields: {},
+          formName: `${this.config.resource}Form`,
+          actions: [
+            {
+              label: 'Save',
+              icon: 'ok',
+              cb: (item) => {
+                let p;
+                let isNew = true;
+
+                if(item.id){
+                  p = item.$update();
+                  isNew = false;
+                }
+                else {
+                  p = item.$save();
+                }
+
+                p.then((res) => {
+                  if(isNew){
+                    this.data.push(angular.copy(res));
+                  }
+                  delete this.detailedItem;
+                  this.responseMsg = `${this.config.resource} with id ${item.id} successfully saved`;
+                })
+                .catch((err) => {
+                  this.responseErr = err.data.detail || `Error while saving ${this.config.resource} with id ${item.id}`;
+                })
+              },
+              class: 'success'
+            }
+          ]
+        };
+
+        this.cleanForm = () => {
+          delete this.detailedItem;
+        };
+
+        this.createItem = () => {
+          this.detailedItem = new this.Resource();
+        };
+
+        this.Resource = $injector.get(this.config.resource);
+
+        const getData = () => {
+          this.Resource.query().$promise
+          .then((res) => {
+
+            if(!res[0]){
+              this.data = res;
+              return;
+            }
+
+            let item = res[0];
+            let props = Object.keys(item);
+
+            _.remove(props, p => {
+              return p === 'id' || p === 'validators'
+            });
+
+            // TODO move out cb,  non sense triggering a lot of times
+            if(angular.isArray(this.config.hiddenFields)){
+              props = _.difference(props, this.config.hiddenFields)
+            }
+
+            let labels = props.map(p => LabelFormatter.format(p));
+
+            props.forEach((p, i) => {
+              let fieldConfig = {
+                label: labels[i],
+                prop: p
+              };
+
+              if(angular.isString(item[p]) && typeof item[p] !== 'undefined'){
+                fieldConfig.type = typeof item[p];
+              }
+
+              this.tableConfig.columns.push(fieldConfig);
+            });
+
+            // build form structure
+            // TODO move in a pure function for testing purposes
+            props.forEach((p, i) => {
+              this.formConfig.fields[p] = {
+                label: LabelFormatter.format(labels[i]).replace(':', ''),
+                type: XosFormHelpers._getFieldFormat(item[p])
+              };
+            });
+
+            this.data = res;
+          });
+        }
+
+        getData();
+      }
+    };
+  });
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/smartComponents/smartTable/smartTable.scss b/views/ngXosLib/xosHelpers/src/ui_components/smartComponents/smartTable/smartTable.scss
new file mode 100644
index 0000000..fc63fdf
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/ui_components/smartComponents/smartTable/smartTable.scss
@@ -0,0 +1,3 @@
+xos-smart-table{
+  
+}
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/ui-components.module.js b/views/ngXosLib/xosHelpers/src/ui_components/ui-components.module.js
new file mode 100644
index 0000000..d94e59d
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/ui_components/ui-components.module.js
@@ -0,0 +1,30 @@
+/**
+ * © OpenCORD
+ *
+ * Visit http://guide.xosproject.org/devguide/addview/ for more information
+ *
+ * Created by teone on 3/24/16.
+ */
+
+(function () {
+  'use strict';
+
+  /**
+  * @ngdoc overview
+  * @name xos.uiComponents
+  * @description
+  * A collection of UI components useful for Dashboard development.
+  * Currently available components are:
+  * - [xosAlert](/#/module/xos.uiComponents.directive:xosAlert)
+  * - [xosForm](/#/module/xos.uiComponents.directive:xosForm)
+  * - [xosPagination](/#/module/xos.uiComponents.directive:xosPagination)
+  * - [xosSmartTable](/#/module/xos.uiComponents.directive:xosSmartTable)
+  * - [xosTable](/#/module/xos.uiComponents.directive:xosTable)
+  * - [xosValidation](/#/module/xos.uiComponents.directive:xosValidation)
+  **/
+
+  angular.module('xos.uiComponents', [
+    'chart.js',
+    'RecursionHelper'
+  ])
+})();
diff --git a/views/ngXosLib/xosHelpers/src/xosHelpers.module.js b/views/ngXosLib/xosHelpers/src/xosHelpers.module.js
new file mode 100644
index 0000000..3d534b9
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/xosHelpers.module.js
@@ -0,0 +1,52 @@
+(function() {
+  'use strict';
+
+  /* eslint-disable angular/ng_module_name */
+
+  angular.module('bugSnag', []).factory('$exceptionHandler', function () {
+    return function (exception, cause) {
+      if( window.Bugsnag ){
+        Bugsnag.notifyException(exception, {diagnostics: {cause: cause}});
+      }
+      else{
+        console.error(exception, cause, exception.stack);
+      }
+    };
+  });
+
+  /* eslint-enable angular/ng_module_name */
+
+  /**
+  * @ngdoc overview
+  * @name xos.helpers
+  * @description this is the module that group all the helpers service and components for XOS
+  **/
+
+  angular
+      .module('xos.helpers', [
+        'ngCookies',
+        'ngResource',
+        'ngAnimate',
+        'bugSnag',
+        'xos.uiComponents'
+      ])
+      .config(config)
+
+      /**
+      * @ngdoc service
+      * @name xos.helpers._
+      * @description Wrap [lodash](https://lodash.com/docs) in an Angular Service
+      **/
+
+      .factory('_', $window => $window._ );
+
+  function config($httpProvider, $interpolateProvider, $resourceProvider) {
+    $httpProvider.interceptors.push('SetCSRFToken');
+
+    $interpolateProvider.startSymbol('{$');
+    $interpolateProvider.endSymbol('$}');
+
+    // NOTE http://www.masnun.com/2013/09/18/django-rest-framework-angularjs-resource-trailing-slash-problem.html
+    $resourceProvider.defaults.stripTrailingSlashes = false;
+  }
+})();
\ No newline at end of file
diff --git a/views/ngXosViews/.gitignore b/views/ngXosViews/.gitignore
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/views/ngXosViews/.gitignore
diff --git a/views/ngXosViews/ceilometerDashboard/.bowerrc b/views/ngXosViews/ceilometerDashboard/.bowerrc
new file mode 100644
index 0000000..e491038
--- /dev/null
+++ b/views/ngXosViews/ceilometerDashboard/.bowerrc
@@ -0,0 +1,3 @@
+{
+  "directory": "src/vendor/"
+}
\ No newline at end of file
diff --git a/views/ngXosViews/ceilometerDashboard/.eslintrc b/views/ngXosViews/ceilometerDashboard/.eslintrc
new file mode 100644
index 0000000..c852748
--- /dev/null
+++ b/views/ngXosViews/ceilometerDashboard/.eslintrc
@@ -0,0 +1,42 @@
+{
+    "ecmaFeatures": {
+        "blockBindings": true,
+        "forOf": true,
+        "destructuring": true,
+        "arrowFunctions": true,
+        "templateStrings": true
+    },
+    "env": { 
+        "browser": true,
+        "node": true,
+        "es6": true
+    },
+    "plugins": [
+        //"angular"
+    ],
+    "rules": {
+        "quotes": [2, "single"],
+        "camelcase": [1, {"properties": "always"}],
+        "no-underscore-dangle": 1,
+        "eqeqeq": [2, "smart"],
+        "no-alert": 1,
+        "key-spacing": [1, { "beforeColon": false, "afterColon": true }],
+        "indent": [2, 2],
+        "no-irregular-whitespace": 1,
+        "eol-last": 0,
+        "max-nested-callbacks": [2, 4],
+        "comma-spacing": [1, {"before": false, "after": true}],
+        "no-trailing-spaces": [1, { skipBlankLines: true }],
+        "no-unused-vars": [1, {"vars": "all", "args": "after-used"}],
+        "new-cap": 0,
+
+        //"angular/ng_module_name": [2, '/^xos\.*[a-z]*$/'],
+        //"angular/ng_controller_name": [2, '/^[a-z].*Ctrl$/'],
+        //"angular/ng_service_name": [2, '/^[A-Z].*Service$/'],
+        //"angular/ng_directive_name": [2, '/^[a-z]+[[A-Z].*]*$/'],
+        //"angular/ng_di": [0, "function or array"]
+    },
+    "globals" :{
+        "angular": true
+    } 
+}
\ No newline at end of file
diff --git a/views/ngXosViews/ceilometerDashboard/.gitignore b/views/ngXosViews/ceilometerDashboard/.gitignore
new file mode 100644
index 0000000..567aee4
--- /dev/null
+++ b/views/ngXosViews/ceilometerDashboard/.gitignore
@@ -0,0 +1,6 @@
+dist/
+src/vendor
+.tmp
+node_modules
+npm-debug.log
+dist/
\ No newline at end of file
diff --git a/views/ngXosViews/ceilometerDashboard/bower.json b/views/ngXosViews/ceilometerDashboard/bower.json
new file mode 100644
index 0000000..6a054cf
--- /dev/null
+++ b/views/ngXosViews/ceilometerDashboard/bower.json
@@ -0,0 +1,40 @@
+{
+  "name": "xos-ceilometerDashboard",
+  "version": "0.0.0",
+  "authors": [
+    "Matteo Scandolo <teo@onlab.us>"
+  ],
+  "description": "The ceilometerDashboard view",
+  "license": "MIT",
+  "ignore": [
+    "**/.*",
+    "node_modules",
+    "bower_components",
+    "static/js/vendor/",
+    "test",
+    "tests"
+  ],
+  "dependencies": {},
+  "devDependencies": {
+    "jquery": "2.1.4",
+    "angular-mocks": "1.4.7",
+    "angular": "1.4.7",
+    "angular-ui-router": "0.2.15",
+    "angular-cookies": "1.4.7",
+    "angular-animate": "1.4.7",
+    "angular-resource": "1.4.7",
+    "lodash": "~4.11.1",
+    "bootstrap-css": "3.3.6",
+    "angular-chart.js": "~0.10.2",
+    "d3": "~3.5.17",
+    "ui.bootstrap": "0.14.3"
+  },
+  "overrides": {
+    "ui.bootstrap": {
+      "main": ["src/accordion/accordion.js", "src/collapse/collapse.js"]
+    }
+  },
+  "resolutions": {
+    "Chart.js": "~1.1.1"
+  }
+}
diff --git a/views/ngXosViews/ceilometerDashboard/gulp/build.js b/views/ngXosViews/ceilometerDashboard/gulp/build.js
new file mode 100644
index 0000000..d9736c4
--- /dev/null
+++ b/views/ngXosViews/ceilometerDashboard/gulp/build.js
@@ -0,0 +1,164 @@
+'use strict';
+
+// BUILD
+//
+// The only purpose of this gulpfile is to build a XOS view and copy the correct files into
+// .html => dashboards
+// .js (minified and concat) => static/js
+//
+// The template are parsed and added to js with angular $templateCache
+
+var gulp = require('gulp');
+var ngAnnotate = require('gulp-ng-annotate');
+var uglify = require('gulp-uglify');
+var templateCache = require('gulp-angular-templatecache');
+var runSequence = require('run-sequence');
+var concat = require('gulp-concat-util');
+var del = require('del');
+var wiredep = require('wiredep');
+var angularFilesort = require('gulp-angular-filesort');
+var _ = require('lodash');
+var eslint = require('gulp-eslint');
+var inject = require('gulp-inject');
+var rename = require('gulp-rename');
+var replace = require('gulp-replace');
+var postcss = require('gulp-postcss');
+var autoprefixer = require('autoprefixer');
+var mqpacker = require('css-mqpacker');
+var csswring = require('csswring');
+
+const TEMPLATE_FOOTER = `
+angular.module('xos.ceilometerDashboard')
+.run(['$location', function(a){
+  a.path('/');
+}])
+`
+
+module.exports = function(options){
+  
+  // delete previous builded file
+  gulp.task('clean', function(){
+    return del(
+      [
+        options.dashboards + 'xosCeilometerDashboard.html',
+        options.static + 'css/xosCeilometerDashboard.css'
+      ],
+      {force: true}
+    );
+  });
+
+  // minify css
+  gulp.task('css', function () {
+    var processors = [
+      autoprefixer({browsers: ['last 1 version']}),
+      mqpacker,
+      csswring
+    ];
+
+    gulp.src([
+      `${options.css}**/*.css`,
+      `!${options.css}dev.css`
+    ])
+    .pipe(postcss(processors))
+    .pipe(gulp.dest(options.tmp + '/css/'));
+  });
+
+  // copy css in correct folder
+  gulp.task('copyCss', ['wait'], function(){
+    return gulp.src([`${options.tmp}/css/*.css`])
+    .pipe(concat('xosCeilometerDashboard.css'))
+    .pipe(gulp.dest(options.static + 'css/'))
+  });
+
+  // compile and minify scripts
+  gulp.task('scripts', function() {
+    return gulp.src([
+      options.tmp + '**/*.js'
+    ])
+    .pipe(ngAnnotate())
+    .pipe(angularFilesort())
+    .pipe(concat('xosCeilometerDashboard.js'))
+    .pipe(concat.header('//Autogenerated, do not edit!!!\n'))
+    .pipe(concat.footer(TEMPLATE_FOOTER))
+    .pipe(uglify())
+    .pipe(gulp.dest(options.static + 'js/'));
+  });
+
+  // set templates in cache
+  gulp.task('templates', function(){
+    return gulp.src('./src/templates/*.html')
+      .pipe(templateCache({
+        module: 'xos.ceilometerDashboard',
+        root: 'templates/'
+      }))
+      .pipe(gulp.dest(options.tmp));
+  });
+
+  // copy html index to Django Folder
+  gulp.task('copyHtml', function(){
+    return gulp.src(options.src + 'index.html')
+      // remove dev dependencies from html
+      .pipe(replace(/<!-- bower:css -->(\n^<link.*)*\n<!-- endbower -->/gmi, ''))
+      .pipe(replace(/<!-- bower:js -->(\n^<script.*)*\n<!-- endbower -->/gmi, ''))
+      // injecting minified files
+      .pipe(
+        inject(
+          gulp.src([
+            options.static + 'js/vendor/xosCeilometerDashboardVendor.js',
+            options.static + 'js/xosCeilometerDashboard.js',
+            options.static + 'css/xosCeilometerDashboard.css'
+          ]),
+          {ignorePath: '/../../../xos/core/xoslib'}
+        )
+      )
+      .pipe(rename('xosCeilometerDashboard.html'))
+      .pipe(gulp.dest(options.dashboards));
+  });
+
+  // minify vendor js files
+  gulp.task('wiredep', function(){
+    var bowerDeps = wiredep().js;
+    if(!bowerDeps){
+      return;
+    }
+
+    // remove angular (it's already loaded)
+    _.remove(bowerDeps, function(dep){
+      return dep.indexOf('angular/angular.js') !== -1;
+    });
+
+    return gulp.src(bowerDeps)
+      .pipe(concat('xosCeilometerDashboardVendor.js'))
+      .pipe(uglify())
+      .pipe(gulp.dest(options.static + 'js/vendor/'));
+  });
+
+  gulp.task('lint', function () {
+    return gulp.src(['src/js/**/*.js'])
+      .pipe(eslint())
+      .pipe(eslint.format())
+      .pipe(eslint.failAfterError());
+  });
+
+  gulp.task('wait', function (cb) {
+    // setTimeout could be any async task
+    setTimeout(function () {
+      cb();
+    }, 1000);
+  });
+
+  gulp.task('build', function() {
+    runSequence(
+      'clean',
+      'sass',
+      'templates',
+      'babel',
+      'scripts',
+      'wiredep',
+      'css',
+      'copyCss',
+      'copyHtml',
+      'cleanTmp'
+    );
+  });
+};
\ No newline at end of file
diff --git a/views/ngXosViews/ceilometerDashboard/gulp/server.js b/views/ngXosViews/ceilometerDashboard/gulp/server.js
new file mode 100644
index 0000000..19caf89
--- /dev/null
+++ b/views/ngXosViews/ceilometerDashboard/gulp/server.js
@@ -0,0 +1,170 @@
+'use strict';
+
+var gulp = require('gulp');
+var browserSync = require('browser-sync').create();
+var inject = require('gulp-inject');
+var runSequence = require('run-sequence');
+var angularFilesort = require('gulp-angular-filesort');
+var babel = require('gulp-babel');
+var wiredep = require('wiredep').stream;
+var httpProxy = require('http-proxy');
+var del = require('del');
+var sass = require('gulp-sass');
+var fs = require('fs');
+var path = require('path');
+
+const environment = process.env.NODE_ENV;
+
+if(!fs.existsSync(path.join(__dirname, `../../../env/${environment || 'default'}.js`))){
+  if(!environment){
+    throw new Error('You should define a default.js config in /views/env folder.');
+  }
+  else{
+    throw new Error(`Since you are loading a custom environment, you should define a ${environment}.js config in /views/env folder.`);
+  }
+}
+
+var conf = require(path.join(__dirname, `../../../env/${environment || 'default'}.js`));
+
+var proxy = httpProxy.createProxyServer({
+  target: conf.host
+});
+
+proxy.on('error', function(error, req, res) {
+  res.writeHead(500, {
+    'Content-Type': 'text/plain'
+  });
+
+  console.error('[Proxy]', error);
+});
+
+module.exports = function(options){
+
+  gulp.task('browser', function() {
+    browserSync.init({
+      startPath: '#/',
+      snippetOptions: {
+        rule: {
+          match: /<!-- browserSync -->/i
+        }
+      },
+      server: {
+        baseDir: options.src,
+        routes: {
+          '/xos/core/xoslib/static/js/vendor': options.helpers,
+          '/xos/core/static': options.static + '../../static/'
+        },
+        middleware: function(req, res, next){
+          if(
+            req.url.indexOf('?no_hyperlinks=1') !== -1 ||
+            req.url.indexOf('/api/') !== -1
+          ){
+            if(conf.xoscsrftoken && conf.xossessionid){
+              req.headers.cookie = `xoscsrftoken=${conf.xoscsrftoken}; xossessionid=${conf.xossessionid}`;
+              req.headers['x-csrftoken'] = conf.xoscsrftoken;
+            }
+            proxy.web(req, res);
+          }
+          else{
+            next();
+          }
+        }
+      }
+    });
+
+    gulp.watch(options.src + 'js/**/*.js', ['js-watch']);
+    gulp.watch(options.src + 'vendor/**/*.js', ['bower'], function(){
+      browserSync.reload();
+    });
+    gulp.watch(options.src + '**/*.html', function(){
+      browserSync.reload();
+    });
+    gulp.watch(options.css + '**/*.css', function(){
+      browserSync.reload();
+    });
+    gulp.watch(`${options.sass}/**/*.scss`, ['sass'], function(){
+      browserSync.reload();
+    });
+
+    gulp.watch([
+      options.helpers + 'ngXosHelpers.js',
+      options.static + '../../static/xosNgLib.css'
+    ], function(){
+      browserSync.reload();
+    });
+  });
+
+  // compile sass
+  gulp.task('sass', function () {
+    return gulp.src(`${options.sass}/**/*.scss`)
+      .pipe(sass().on('error', sass.logError))
+      .pipe(gulp.dest(options.css));
+  });
+
+  // transpile js with sourceMaps
+  gulp.task('babel', function(){
+    return gulp.src(options.scripts + '**/*.js')
+      .pipe(babel({sourceMaps: true}))
+      .pipe(gulp.dest(options.tmp));
+  });
+
+  // inject scripts
+  gulp.task('injectScript', ['cleanTmp', 'babel'], function(){
+    return gulp.src(options.src + 'index.html')
+      .pipe(
+        inject(
+          gulp.src([
+            options.tmp + '**/*.js',
+            options.helpers + 'ngXosHelpers.js'
+          ])
+          .pipe(angularFilesort()),
+          {
+            ignorePath: [options.src, '/../../ngXosLib']
+          }
+        )
+      )
+      .pipe(gulp.dest(options.src));
+  });
+
+  // inject CSS
+  gulp.task('injectCss', function(){
+    return gulp.src(options.src + 'index.html')
+      .pipe(
+        inject(
+          gulp.src([
+            options.src + 'css/*.css',
+            options.static + '../../static/xosNgLib.css'
+          ]),
+          {
+            ignorePath: [options.src]
+          }
+          )
+        )
+      .pipe(gulp.dest(options.src));
+  });
+
+  // inject bower dependencies with wiredep
+  gulp.task('bower', function () {
+    return gulp.src(options.src + 'index.html')
+    .pipe(wiredep({devDependencies: true}))
+    .pipe(gulp.dest(options.src));
+  });
+
+  gulp.task('js-watch', ['injectScript'], function(){
+    browserSync.reload();
+  });
+
+  gulp.task('cleanTmp', function(){
+    return del([options.tmp + '**/*']);
+  });
+
+  gulp.task('serve', function() {
+    runSequence(
+      'sass',
+      'bower',
+      'injectScript',
+      'injectCss',
+      ['browser']
+    );
+  });
+};
diff --git a/views/ngXosViews/ceilometerDashboard/gulpfile.js b/views/ngXosViews/ceilometerDashboard/gulpfile.js
new file mode 100644
index 0000000..08df554
--- /dev/null
+++ b/views/ngXosViews/ceilometerDashboard/gulpfile.js
@@ -0,0 +1,26 @@
+'use strict';
+
+var gulp = require('gulp');
+var wrench = require('wrench');
+
+var options = {
+  src: 'src/',
+  css: 'src/css/',
+  sass: 'src/sass/',
+  scripts: 'src/js/',
+  tmp: 'src/.tmp',
+  dist: 'dist/',
+  api: '../../ngXosLib/api/',
+  helpers: '../../../xos/core/xoslib/static/js/vendor/',
+  static: '../../../xos/core/xoslib/static/', // this is the django static folder
+  dashboards: '../../../xos/core/xoslib/dashboards/' // this is the django html folder
+};
+
+wrench.readdirSyncRecursive('./gulp')
+.map(function(file) {
+  require('./gulp/' + file)(options);
+});
+
+gulp.task('default', function () {
+  gulp.start('build');
+});
diff --git a/views/ngXosViews/ceilometerDashboard/karma.conf.js b/views/ngXosViews/ceilometerDashboard/karma.conf.js
new file mode 100644
index 0000000..f9cc95b
--- /dev/null
+++ b/views/ngXosViews/ceilometerDashboard/karma.conf.js
@@ -0,0 +1,90 @@
+// Karma configuration
+// Generated on Tue Oct 06 2015 09:27:10 GMT+0000 (UTC)
+
+/* eslint indent: [2,2], quotes: [2, "single"]*/
+
+/*eslint-disable*/
+var wiredep = require('wiredep');
+var path = require('path');
+
+var bowerComponents = wiredep( {devDependencies: true} )[ 'js' ].map(function( file ){
+  return path.relative(process.cwd(), file);
+});
+
+module.exports = function(config) {
+/*eslint-enable*/
+  config.set({
+
+    // base path that will be used to resolve all patterns (eg. files, exclude)
+    basePath: '',
+
+
+    // frameworks to use
+    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
+    frameworks: ['jasmine'],
+
+
+    // list of files / patterns to load in the browser
+    files: bowerComponents.concat([
+      '../../../xos/core/xoslib/static/js/vendor/ngXosVendor.js',
+      '../../../xos/core/xoslib/static/js/vendor/ngXosHelpers.js',
+      'src/js/main.js',
+      'src/js/**/*.js',
+      'spec/**/*.mock.js',
+      'spec/**/*.test.js',
+      'src/**/*.html'
+    ]),
+
+
+    // list of files to exclude
+    exclude: [
+    ],
+
+
+    // preprocess matching files before serving them to the browser
+    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
+    preprocessors: {
+      'src/js/**/*.js': ['babel'],
+      'spec/**/*.test.js': ['babel'],
+      'spec/**/*.mock.js': ['babel'],
+      'src/**/*.html': ['ng-html2js']
+    },
+
+    ngHtml2JsPreprocessor: {
+      stripPrefix: 'src/', //strip the src path from template url (http://stackoverflow.com/questions/22869668/karma-unexpected-request-when-testing-angular-directive-even-with-ng-html2js)
+      moduleName: 'templates' // define the template module name
+    },
+
+    // test results reporter to use
+    // possible values: 'dots', 'progress'
+    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
+    reporters: ['mocha'],
+
+
+    // web server port
+    port: 9876,
+
+
+    // enable / disable colors in the output (reporters and logs)
+    colors: true,
+
+
+    // level of logging
+    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+    logLevel: config.LOG_INFO,
+
+
+    // enable / disable watching file and executing tests whenever any file changes
+    autoWatch: true,
+
+
+    // start these browsers
+    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
+    browsers: ['PhantomJS'],
+
+
+    // Continuous Integration mode
+    // if true, Karma captures browsers, runs the tests and exits
+    singleRun: false
+  });
+};
diff --git a/views/ngXosViews/ceilometerDashboard/package.json b/views/ngXosViews/ceilometerDashboard/package.json
new file mode 100644
index 0000000..1aa661d
--- /dev/null
+++ b/views/ngXosViews/ceilometerDashboard/package.json
@@ -0,0 +1,63 @@
+{
+  "name": "xos-ceilometerDashboard",
+  "version": "1.0.0",
+  "description": "Angular Application for XOS, created with generator-xos",
+  "scripts": {
+    "prestart": "npm install && bower install",
+    "start": "gulp serve",
+    "prebuild": "npm install && bower install",
+    "build": "gulp",
+    "test": "karma start",
+    "test:ci": "karma start --single-run",
+    "lint": "eslint src/js/"
+  },
+  "keywords": [
+    "XOS",
+    "Angular",
+    "XOSlib"
+  ],
+  "author": "Matteo Scandolo",
+  "license": "MIT",
+  "dependencies": {},
+  "devDependencies": {
+    "autoprefixer": "^6.3.3",
+    "browser-sync": "^2.9.11",
+    "css-mqpacker": "^4.0.0",
+    "csswring": "^4.2.1",
+    "del": "^2.0.2",
+    "easy-mocker": "^1.2.0",
+    "eslint": "^1.8.0",
+    "eslint-plugin-angular": "linkmesrl/eslint-plugin-angular",
+    "gulp": "^3.9.0",
+    "gulp-angular-filesort": "^1.1.1",
+    "gulp-angular-templatecache": "^1.8.0",
+    "gulp-babel": "^5.3.0",
+    "gulp-concat": "^2.6.0",
+    "gulp-concat-util": "^0.5.5",
+    "gulp-eslint": "^1.0.0",
+    "gulp-inject": "^3.0.0",
+    "gulp-minify-html": "^1.0.4",
+    "gulp-ng-annotate": "^1.1.0",
+    "gulp-postcss": "^6.0.1",
+    "gulp-rename": "^1.2.2",
+    "gulp-replace": "^0.5.4",
+    "gulp-sass": "^2.2.0",
+    "gulp-uglify": "^1.4.2",
+    "http-proxy": "^1.12.0",
+    "ink-docstrap": "^0.5.2",
+    "jasmine-core": "~2.3.4",
+    "karma": "^0.13.14",
+    "karma-babel-preprocessor": "~5.2.2",
+    "karma-coverage": "^0.5.3",
+    "karma-jasmine": "~0.3.6",
+    "karma-mocha-reporter": "~1.1.1",
+    "karma-ng-html2js-preprocessor": "^0.2.0",
+    "karma-phantomjs-launcher": "~0.2.1",
+    "lodash": "^3.10.1",
+    "phantomjs": "^1.9.19",
+    "proxy-middleware": "^0.15.0",
+    "run-sequence": "^1.1.4",
+    "wiredep": "^3.0.0-beta",
+    "wrench": "^1.5.8"
+  }
+}
diff --git a/views/ngXosViews/ceilometerDashboard/spec/.eslintrc b/views/ngXosViews/ceilometerDashboard/spec/.eslintrc
new file mode 100644
index 0000000..e456ddf
--- /dev/null
+++ b/views/ngXosViews/ceilometerDashboard/spec/.eslintrc
@@ -0,0 +1,13 @@
+{
+    "globals" :{
+        "describe": true,
+        "xdescribe": true,
+        "beforeEach": true,
+        "it": true,
+        "inject": true,
+        "expect": true
+    },
+    "rules": {
+      "max-nested-callbacks": [0, 4]
+    }
+}
diff --git a/views/ngXosViews/ceilometerDashboard/spec/backend.mock.js b/views/ngXosViews/ceilometerDashboard/spec/backend.mock.js
new file mode 100644
index 0000000..2908041
--- /dev/null
+++ b/views/ngXosViews/ceilometerDashboard/spec/backend.mock.js
@@ -0,0 +1,105 @@
+'use strict';
+(function () {
+
+  const meters = [
+    {
+      service: 'service-a',
+      slice: 'slice-a-1',
+      name: 'network.outgoing.packets.rate',
+      resource_name: 'resource-1'
+    },
+    {
+      service: 'service-a',
+      slice: 'slice-a-1',
+      name: 'network.incoming.packets.rate',
+      resource_name: 'resource-1'
+    },
+    {
+      service: 'service-a',
+      slice: 'slice-a-1',
+      name: 'network.incoming.packets.rate',
+      resource_name: 'resource-2'
+    }
+  ];
+
+  const samples = [
+    {
+      meter: 'cpu',
+      resource_name: 'fakeName',
+      resource_id: 'fakeTenant',
+      timestamp: '2015-12-15T00:34:08',
+      volume: 110
+    },
+    {
+      meter: 'cpu',
+      resource_name: 'fakeName',
+      resource_id: 'fakeTenant',
+      timestamp: '2015-12-15T00:44:08',
+      volume: 120
+    },
+    {
+      meter: 'cpu',
+      resource_name: 'anotherName',
+      resource_id: 'anotherTenant',
+      timestamp: '2015-12-15T00:24:08',
+      volume: 210
+    },
+    {
+      meter: 'cpu',
+      resource_name: 'anotherName',
+      resource_id: 'anotherTenant',
+      timestamp: '2015-12-15T00:34:08',
+      volume: 220
+    },
+    {
+      meter: 'cpu',
+      resource_name: 'anotherName',
+      resource_id: 'anotherTenant',
+      timestamp: '2015-12-15T00:44:08',
+      volume: 230
+    },
+    {
+      meter: 'cpu',
+      resource_name: 'thirdName',
+      resource_id: 'thirdTenant',
+      timestamp: '2015-12-15T00:44:08',
+      volume: 310
+    }
+  ];
+
+  const mapping = [
+    {
+      service: 'service-a',
+      slices: [
+        {
+          project_id: 'id-a-1',
+          slice: 'slice-a-1'
+        },
+        {
+          project_id: 'id-a-2',
+          slice: 'slice-a-2'
+        }
+      ]
+    },
+    {
+      service: 'service-b',
+      slices: [
+        {
+          project_id: 'id-b-1',
+          slice: 'slice-b-1'
+        },
+        {
+          project_id: 'id-b-2',
+          slice: 'slice-b-2'
+        }
+      ]
+    }
+  ]
+
+  angular.module('xos.ceilometerDashboard')
+  .run(($httpBackend) => {
+    $httpBackend.whenGET(/metersamples/).respond(samples);
+    $httpBackend.whenGET(/xos-slice-service-mapping/).respond(mapping);
+    $httpBackend.whenGET(/meters/).respond(meters);
+  });
+})();
diff --git a/views/ngXosViews/ceilometerDashboard/spec/ceilometer.test.js b/views/ngXosViews/ceilometerDashboard/spec/ceilometer.test.js
new file mode 100644
index 0000000..3eeaf81
--- /dev/null
+++ b/views/ngXosViews/ceilometerDashboard/spec/ceilometer.test.js
@@ -0,0 +1,124 @@
+'use strict';
+
+describe('In Ceilometer View', () => {
+
+  var scope, element, vm, httpBackend;
+
+  beforeEach(module('xos.ceilometerDashboard'));
+  beforeEach(module('templates'));
+
+  beforeEach(inject(($httpBackend, $rootScope) => {
+    httpBackend = $httpBackend;
+    scope = $rootScope.$new();
+  }))
+
+  describe('The dashboard', () => {
+    beforeEach(inject(function($httpBackend, $compile){
+      element = angular.element('<ceilometer-dashboard></ceilometer-dashboard>');
+      $compile(element)(scope);
+      scope.$digest();
+      vm = element.isolateScope().vm;
+      httpBackend.flush();
+    }));
+
+    describe('when loading service list', () => {
+      it('should append the list to the scope', inject(() => {
+        expect(vm.services.length).toBe(2);
+        expect(vm.services[0].slices.length).toBe(2);
+        expect(vm.services[1].slices.length).toBe(2);
+      }));
+    });
+
+    describe('when a slice is selected', () => {
+      it('should load corresponding meters', () => {
+        vm.loadSliceMeter(vm.services[0].slices[0]);
+
+        httpBackend.flush();
+
+        expect(vm.selectedSlice).toEqual('slice-a-1');
+        expect(vm.selectedTenant).toEqual('id-a-1');
+
+        expect(Object.keys(vm.selectedResources).length).toBe(2);
+        expect(vm.selectedResources['resource-1'].length).toBe(2);
+        expect(vm.selectedResources['resource-2'].length).toBe(1);
+      });
+    });
+  });
+
+  describe('the sample view', () => {
+    beforeEach(inject(function($httpBackend, $compile, $stateParams){
+
+      $stateParams.name = 'fakeName';
+      $stateParams.tenant = 'fakeTenant';
+
+      element = angular.element('<ceilometer-samples></ceilometer-samples>');
+      $compile(element)(scope);
+      scope.$digest();
+      vm = element.isolateScope().vm;
+      httpBackend.flush();
+    }));
+
+    it('should group samples by resource_id', () => {
+      expect(Object.keys(vm.samplesList.fakeTenant).length).toBe(2)
+      expect(Object.keys(vm.samplesList.anotherTenant).length).toBe(3)
+      expect(Object.keys(vm.samplesList.thirdTenant).length).toBe(1)
+    });
+
+    xit('should add the comparable samples to the dropdown list', () => {
+      console.log(vm.sampleLabels);
+      expect(vm.sampleLabels[0].id).toEqual('anotherTenant')
+      expect(vm.sampleLabels[1].id).toEqual('thirdTenant')
+    });
+
+    it('should add the selected meter to the chart', () => {
+      expect(vm.chart.labels.length).toBe(2);
+      expect(vm.chart.series[0]).toBe('fakeTenant');
+      expect(vm.chart.data[0].length).toBe(2);
+      expect(vm.chart.data[0][0]).toBe(110);
+      expect(vm.chart.data[0][1]).toBe(120);
+      expect(vm.chartMeters[0].resource_id).toBe('fakeTenant')
+      expect(vm.chartMeters[0].resource_name).toBe('fakeName')
+    });
+
+    it('should add a sample to the chart', () => {
+      vm.addMeterToChart('anotherTenant');
+      expect(vm.chart.labels.length).toBe(3);
+      expect(vm.chart.data[1].length).toBe(3);
+      expect(vm.chart.data[1][0]).toBe(210);
+      expect(vm.chart.data[1][1]).toBe(220);
+      expect(vm.chart.data[1][2]).toBe(230);
+      expect(vm.chartMeters[1].resource_id).toBe('anotherTenant')
+      expect(vm.chartMeters[1].resource_name).toBe('anotherName')
+    });
+
+    it('should remove a sample from the chart', () => {
+      // for simplyvity add a tenant (it's tested)
+      vm.addMeterToChart('anotherTenant');
+      vm.removeFromChart(vm.chartMeters[0]);
+      expect(vm.chart.data[0].length).toBe(3);
+      expect(vm.chart.data[0][0]).toBe(210);
+      expect(vm.chart.data[0][1]).toBe(220);
+      expect(vm.chart.data[0][2]).toBe(230);
+      expect(vm.chartMeters[0].resource_id).toBe('anotherTenant')
+      expect(vm.chartMeters[0].resource_name).toBe('anotherName')
+    });
+
+    describe('The format sample labels method', () => {
+      xit('should create an array of unique labels', () => {
+        // unique because every resource has multiple samples (time-series)
+        const samples = [
+          {resource_id: 1, resource_name: 'fakeName'},
+          {resource_id: 1, resource_name: 'fakeName'},
+          {resource_id: 2, resource_name: 'anotherName'},
+          {resource_id: 2, resource_name: 'anotherName'}
+        ];
+
+        const result = vm.formatSamplesLabels(samples);
+
+        expect(result.length).toBe(2);
+        expect(result[0]).toEqual({id: 1, name: 'fakeName'});
+        expect(result[1]).toEqual({id: 2, name: 'anotherName'});
+      });
+    });
+  });
+});
\ No newline at end of file
diff --git a/views/ngXosViews/ceilometerDashboard/src/css/ceilometerDashboard.css b/views/ngXosViews/ceilometerDashboard/src/css/ceilometerDashboard.css
new file mode 100644
index 0000000..4e6fa88
--- /dev/null
+++ b/views/ngXosViews/ceilometerDashboard/src/css/ceilometerDashboard.css
@@ -0,0 +1,265 @@
+#xosCeilometerDashboard{
+  position: relative;
+}
+
+/* Panel Layout */
+.panel {
+  margin-top: 10px;
+}
+
+.panel-body:not(:first-child) {
+  border-top: 1px solid #e3e3e3;
+}
+
+.panel-body .row {
+  margin-top: 10px;
+}
+
+/* Chart details */
+.chart {
+  width: 100%;
+  height: 300px;
+}
+
+.btn-chart, .btn-chart:hover {
+  color: #fff;
+}
+
+.side-container {
+  position: relative;
+}
+
+.service-list {
+  margin-top: -10px;
+}
+
+.service-list h3 {
+  margin-top: 0px;
+  margin-bottom: 0px;
+}
+
+.service-list a {
+  text-decoration: none;
+  color: #333;
+}
+
+.meters, .stats {
+  margin-top: 25px;
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  margin-bottom: 50px;
+}
+
+/* LOADER */
+.loader {
+  font-size: 10px;
+  margin: 150px auto;
+  text-indent: -9999em;
+  width: 11em;
+  height: 11em;
+  border-radius: 50%;
+  background: #ffffff;
+  background: -moz-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
+  background: -webkit-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
+  background: -o-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
+  background: -ms-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
+  background: linear-gradient(to right, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
+  position: relative;
+  -webkit-animation: load3 1.4s infinite linear;
+  animation: load3 1.4s infinite linear;
+  -webkit-transform: translateZ(0);
+  -ms-transform: translateZ(0);
+  transform: translateZ(0);
+}
+.loader:before {
+  width: 50%;
+  height: 50%;
+  background: #105E9E;
+  border-radius: 100% 0 0 0;
+  position: absolute;
+  top: 0;
+  left: 0;
+  content: '';
+}
+.loader:after {
+  background: #fff;
+  width: 75%;
+  height: 75%;
+  border-radius: 50%;
+  content: '';
+  margin: auto;
+  position: absolute;
+  top: 0;
+  left: 0;
+  bottom: 0;
+  right: 0;
+}
+@-webkit-keyframes load3 {
+  0% {
+    -webkit-transform: rotate(0deg);
+    transform: rotate(0deg);
+  }
+  100% {
+    -webkit-transform: rotate(360deg);
+    transform: rotate(360deg);
+  }
+}
+@keyframes load3 {
+  0% {
+    -webkit-transform: rotate(0deg);
+    transform: rotate(0deg);
+  }
+  100% {
+    -webkit-transform: rotate(360deg);
+    transform: rotate(360deg);
+  }
+}
+
+/* VIEW ANIMATION */
+
+[ui-view] {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  margin-bottom: 100px;
+}
+
+/* FROM DASHBOARD TO DETAIL */
+
+/* dash out */
+[ui-view].ceilometerDashboard.ng-leave {
+  animation:1s bounceOutLeft ease; 
+}
+/* samples in */
+[ui-view].samples.ng-enter {
+  animation:1s bounceInRight ease;
+}
+
+/* FROM DETAIL TO DASHBOARD */
+
+/* samples out */
+[ui-view].samples.ng-leave {
+  animation:1s bounceOutRight ease; 
+}
+/* dash in */
+[ui-view].ceilometerDashboard.ng-enter {
+  animation:1s bounceInLeft ease;
+}
+
+/* COLUMS ANIMATION */
+/* when showing the thing */
+.animate .animate-slide-left.ng-hide-remove { 
+  animation:0.5s bounceInRight ease; 
+}
+
+/* when hiding the picture */
+.animate .animate-slide-left.ng-hide-add {
+  animation:0.5s bounceOutRight ease;
+}
+
+/* ANIMATIONS */
+
+@keyframes bounceInRight {
+  from, 60%, 75%, 90%, to {
+    animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+  }
+
+  from {
+    opacity: 0;
+    transform: translate3d(3000px, 0, 0);
+  }
+
+  60% {
+    opacity: 1;
+    transform: translate3d(-25px, 0, 0);
+  }
+
+  75% {
+    transform: translate3d(10px, 0, 0);
+  }
+
+  90% {
+    transform: translate3d(-5px, 0, 0);
+  }
+
+  to {
+    transform: none;
+  }
+}
+
+@keyframes bounceInLeft {
+  from, 60%, 75%, 90%, to {
+    animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+  }
+
+  0% {
+    opacity: 0;
+    transform: translate3d(-3000px, 0, 0);
+  }
+
+  60% {
+    opacity: 1;
+    transform: translate3d(25px, 0, 0);
+  }
+
+  75% {
+    transform: translate3d(-10px, 0, 0);
+  }
+
+  90% {
+    transform: translate3d(5px, 0, 0);
+  }
+
+  to {
+    transform: none;
+  }
+}
+
+@keyframes slideInUp {
+  from {
+    transform: translate3d(0, 100%, 0);
+    visibility: visible;
+  }
+
+  to {
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+@keyframes bounceOutRight {
+  20% {
+    opacity: 1;
+    transform: translate3d(-20px, 0, 0);
+  }
+
+  to {
+    opacity: 0;
+    transform: translate3d(2000px, 0, 0);
+  }
+}
+
+@keyframes bounceOutLeft {
+  20% {
+    opacity: 1;
+    transform: translate3d(20px, 0, 0);
+  }
+
+  to {
+    opacity: 0;
+    transform: translate3d(-2000px, 0, 0);
+  }
+}
+
+@keyframes slideOutDown {
+  from {
+    transform: translate3d(0, 0, 0);
+  }
+
+  to {
+    visibility: hidden;
+    transform: translate3d(0, 100%, 0);
+  }
+}
\ No newline at end of file
diff --git a/views/ngXosViews/ceilometerDashboard/src/css/dev.css b/views/ngXosViews/ceilometerDashboard/src/css/dev.css
new file mode 100644
index 0000000..228d394
--- /dev/null
+++ b/views/ngXosViews/ceilometerDashboard/src/css/dev.css
@@ -0,0 +1,14 @@
+@media (min-width: 768px) {
+  #xosCeilometerDashboard {
+    position: absolute;
+    top: 100px;
+    left: 20%;
+    width: 80%;
+  }
+}
+
+@media (min-width: 768px) {
+  #xosCeilometerDashboard {
+    margin: 10px
+  }
+}
\ No newline at end of file
diff --git a/views/ngXosViews/ceilometerDashboard/src/css/main.css b/views/ngXosViews/ceilometerDashboard/src/css/main.css
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/views/ngXosViews/ceilometerDashboard/src/css/main.css
diff --git a/views/ngXosViews/ceilometerDashboard/src/index.html b/views/ngXosViews/ceilometerDashboard/src/index.html
new file mode 100644
index 0000000..40bc603
--- /dev/null
+++ b/views/ngXosViews/ceilometerDashboard/src/index.html
@@ -0,0 +1,42 @@
+<meta http-equiv="X-UA-Compatible" content="IE=edge">
+<meta name="viewport" content="width=device-width, initial-scale=1, max-scale=1">
+<!-- browserSync -->
+<!-- bower:css -->
+<link rel="stylesheet" href="vendor/bootstrap-css/css/bootstrap.min.css" />
+<link rel="stylesheet" href="vendor/angular-chart.js/dist/angular-chart.css" />
+<!-- endbower --><!-- endcss -->
+<!-- inject:css -->
+<link rel="stylesheet" href="/css/ceilometerDashboard.css">
+<link rel="stylesheet" href="/css/dev.css">
+<link rel="stylesheet" href="/css/main.css">
+<link rel="stylesheet" href="/../../../xos/core/static/xosNgLib.css">
+<!-- endinject -->
+<div ng-app="xos.ceilometerDashboard" id="xosCeilometerDashboard">
+  <div ui-view ng-class="stateName"></div>
+</div>
+
+<!-- bower:js -->
+<script src="vendor/jquery/dist/jquery.js"></script>
+<script src="vendor/angular/angular.js"></script>
+<script src="vendor/angular-mocks/angular-mocks.js"></script>
+<script src="vendor/angular-ui-router/release/angular-ui-router.js"></script>
+<script src="vendor/angular-cookies/angular-cookies.js"></script>
+<script src="vendor/angular-animate/angular-animate.js"></script>
+<script src="vendor/angular-resource/angular-resource.js"></script>
+<script src="vendor/lodash/lodash.js"></script>
+<script src="vendor/bootstrap-css/js/bootstrap.min.js"></script>
+<script src="vendor/Chart.js/Chart.js"></script>
+<script src="vendor/angular-chart.js/dist/angular-chart.js"></script>
+<script src="vendor/d3/d3.js"></script>
+<script src="vendor/ui.bootstrap/src/accordion/accordion.js"></script>
+<script src="vendor/ui.bootstrap/src/collapse/collapse.js"></script>
+<!-- endbower --><!-- endjs -->
+
+<!-- inject:js -->
+<script src="/../../../xos/core/xoslib/static/js/vendor/ngXosHelpers.js"></script>
+<script src="/.tmp/main.js"></script>
+<script src="/.tmp/stats.directive.js"></script>
+<script src="/.tmp/samples.directive.js"></script>
+<script src="/.tmp/rest.js"></script>
+<script src="/.tmp/dashboard.directive.js"></script>
+<!-- endinject -->
diff --git a/views/ngXosViews/ceilometerDashboard/src/js/dashboard.directive.js b/views/ngXosViews/ceilometerDashboard/src/js/dashboard.directive.js
new file mode 100644
index 0000000..6a65732
--- /dev/null
+++ b/views/ngXosViews/ceilometerDashboard/src/js/dashboard.directive.js
@@ -0,0 +1,162 @@
+/**
+ * © OpenCORD
+ *
+ * Visit http://guide.xosproject.org/devguide/addview/ for more information
+ *
+ * Created by teone on 3/21/16.
+ */
+
+(function () {
+  'use strict';
+
+  angular.module('xos.ceilometerDashboard')
+    .directive('ceilometerDashboard', function(_){
+      return {
+        restrict: 'E',
+        scope: {},
+        bindToController: true,
+        controllerAs: 'vm',
+        templateUrl: 'templates/ceilometer-dashboard.tpl.html',
+        controller: function(Ceilometer){
+
+          this.showStats = false;
+
+          // this open the accordion
+          this.accordion = {
+            open: {}
+          };
+
+          /**
+           * Open the active panel base on the service stored values
+           */
+          this.openPanels = () => {
+            if(Ceilometer.selectedService){
+              this.accordion.open[Ceilometer.selectedService] = true;
+              if(Ceilometer.selectedSlice){
+                this.loadSliceMeter(Ceilometer.selectedSlice, Ceilometer.selectedService);
+                this.selectedSlice = Ceilometer.selectedSlice;
+                if(Ceilometer.selectedResource){
+                  this.selectedResource = Ceilometer.selectedResource;
+                }
+              }
+            }
+          };
+
+          /**
+           * Load the list of service and slices
+           */
+          this.loadMappings = () => {
+            this.loader = true;
+            Ceilometer.getMappings()
+              .then((services) => {
+
+                // rename thing in UI
+                services.map((service) => {
+                  if(service.service === 'service_ONOS_vBNG'){
+                    service.service = 'ONOS_FABRIC';
+                  }
+                  if(service.service === 'service_ONOS_vOLT'){
+                    service.service = 'ONOS_CORD';
+                  }
+
+                  service.slices.map(s => {
+                    if(s.slice === 'mysite_onos_volt'){
+                      s.slice = 'ONOS_CORD';
+                    }
+                    if(s.slice === 'mysite_onos_vbng'){
+                      s.slice = 'ONOS_FABRIC';
+                    }
+                    if(s.slice === 'mysite_vbng'){
+                      s.slice = 'mysite_vRouter';
+                    }
+                  });
+
+                  return service;
+                });
+                // end rename thing in UI
+
+                this.services = services;
+                this.openPanels();
+              })
+              .catch(err => {
+                this.error = (err.data && err.data.detail) ? err.data.detail : 'An Error occurred. Please try again later.';
+              })
+              .finally(() => {
+                this.loader = false;
+              });
+          };
+
+          this.loadMappings();
+
+          /**
+           * Load the list of a single slice
+           */
+          this.loadSliceMeter = (slice, service_name) => {
+
+            Ceilometer.selectedSlice = null;
+            Ceilometer.selectedService = null;
+            Ceilometer.selectedResources = null;
+
+            // visualization info
+            this.loader = true;
+            this.error = null;
+            this.ceilometerError = null;
+
+            Ceilometer.getMeters({tenant: slice.project_id})
+              .then((sliceMeters) => {
+                this.selectedSlice = slice.slice;
+                this.selectedTenant = slice.project_id;
+
+                // store the status
+                Ceilometer.selectedSlice = slice;
+                Ceilometer.selectedService = service_name;
+
+                // rename things in UI
+                sliceMeters.map(m => {
+                  m.resource_name = m.resource_name.replace('mysite_onos_vbng', 'ONOS_FABRIC');
+                  m.resource_name = m.resource_name.replace('mysite_onos_volt', 'ONOS_CORD');
+                  m.resource_name = m.resource_name.replace('mysite_vbng', 'mysite_vRouter');
+                  return m;
+                });
+                // end rename things in UI
+
+                this.selectedResources = _.groupBy(sliceMeters, 'resource_name');
+
+                // hacky
+                if(Ceilometer.selectedResource){
+                  this.selectedMeters = this.selectedResources[Ceilometer.selectedResource];
+                }
+              })
+              .catch(err => {
+
+                // this means that ceilometer is not yet ready
+                if(err.status === 503){
+                  return this.ceilometerError = err.data.detail.specific_error;
+                }
+
+                this.ceilometerError = (err.data && err.data.detail && err.data.detail.specific_error) ? err.data.detail.specific_error : 'An Error occurred. Please try again later.';
+              })
+              .finally(() => {
+                this.loader = false;
+              });
+          };
+
+          /**
+           * Select Meters for a resource
+           *
+           * @param Array meters The list of selected resources
+           * @returns void
+           */
+          this.selectedMeters = null;
+          this.selectMeters = (meters, resource) => {
+            this.selectedMeters = meters;
+
+            Ceilometer.selectedResource = resource;
+            this.selectedResource = resource;
+          }
+
+        }
+      };
+    })
+})();
+
diff --git a/views/ngXosViews/ceilometerDashboard/src/js/main.js b/views/ngXosViews/ceilometerDashboard/src/js/main.js
new file mode 100644
index 0000000..43a8a14
--- /dev/null
+++ b/views/ngXosViews/ceilometerDashboard/src/js/main.js
@@ -0,0 +1,32 @@
+'use strict';
+
+angular.module('xos.ceilometerDashboard', [
+  'ngResource',
+  'ngCookies',
+  'ui.router',
+  'xos.helpers',
+  'ngAnimate',
+  'chart.js',
+  'ui.bootstrap.accordion'
+])
+.config(($stateProvider, $urlRouterProvider) => {
+  $stateProvider
+  .state('ceilometerDashboard', {
+    url: '/',
+    template: '<ceilometer-dashboard></ceilometer-dashboard>'
+  })
+  .state('samples', {
+    url: '/:name/:tenant/samples',
+    template: '<ceilometer-samples></ceilometer-samples>'
+  });
+  $urlRouterProvider.otherwise('/');
+})
+.config(function($httpProvider){
+  $httpProvider.interceptors.push('NoHyperlinks');
+})
+.run(function($rootScope){
+  $rootScope.stateName = 'ceilometerDashboard';
+  $rootScope.$on('$stateChangeStart', (event, toState) => {
+    $rootScope.stateName = toState.name;
+  })
+});
diff --git a/views/ngXosViews/ceilometerDashboard/src/js/rest.js b/views/ngXosViews/ceilometerDashboard/src/js/rest.js
new file mode 100644
index 0000000..24737c3
--- /dev/null
+++ b/views/ngXosViews/ceilometerDashboard/src/js/rest.js
@@ -0,0 +1,79 @@
+/**
+ * © OpenCORD
+ *
+ * Visit http://guide.xosproject.org/devguide/addview/ for more information
+ *
+ * Created by teone on 3/21/16.
+ */
+
+(function () {
+  'use strict';
+
+  angular.module('xos.ceilometerDashboard')
+    .service('Ceilometer', function($http, $q){
+
+      this.getMappings = () => {
+        let deferred = $q.defer();
+
+        $http.get('/xoslib/xos-slice-service-mapping/')
+          .then((res) => {
+            deferred.resolve(res.data)
+          })
+          .catch((e) => {
+            deferred.reject(e);
+          });
+
+        return deferred.promise;
+      };
+
+      this.getMeters = (params) => {
+        let deferred = $q.defer();
+
+        $http.get('/xoslib/meters/', {cache: true, params: params})
+          // $http.get('../meters_mock.json', {cache: true})
+          .then((res) => {
+            deferred.resolve(res.data)
+          })
+          .catch((e) => {
+            deferred.reject(e);
+          });
+
+        return deferred.promise;
+      };
+
+      this.getSamples = (name, tenant) => {
+        let deferred = $q.defer();
+
+        $http.get(`/xoslib/metersamples/`, {params: {meter: name, tenant: tenant}})
+          .then((res) => {
+            deferred.resolve(res.data)
+          })
+          .catch((e) => {
+            deferred.reject(e);
+          });
+
+        return deferred.promise;
+      };
+
+      this.getStats = (options) => {
+        let deferred = $q.defer();
+
+        $http.get('/xoslib/meterstatistics/', {cache: true, params: options})
+          // $http.get('../stats_mock.son', {cache: true})
+          .then((res) => {
+            deferred.resolve(res.data);
+          })
+          .catch((e) => {
+            deferred.reject(e);
+          });
+
+        return deferred.promise;
+      };
+
+      // hold dashboard status (opened service, slice, resource)
+      this.selectedService = null;
+      this.selectedSlice = null;
+      this.selectedResource = null;
+    });
+})();
+
diff --git a/views/ngXosViews/ceilometerDashboard/src/js/samples.directive.js b/views/ngXosViews/ceilometerDashboard/src/js/samples.directive.js
new file mode 100644
index 0000000..9f2dcea
--- /dev/null
+++ b/views/ngXosViews/ceilometerDashboard/src/js/samples.directive.js
@@ -0,0 +1,162 @@
+/**
+ * © OpenCORD
+ *
+ * Visit http://guide.xosproject.org/devguide/addview/ for more information
+ *
+ * Created by teone on 3/21/16.
+ */
+
+(function () {
+  'use strict';
+
+  angular.module('xos.ceilometerDashboard')
+  .directive('ceilometerSamples', function(_, $stateParams){
+    return {
+      restrict: 'E',
+      scope: {},
+      bindToController: true,
+      controllerAs: 'vm',
+      templateUrl: 'templates/ceilometer-samples.tpl.html',
+      controller: function(Ceilometer) {
+
+        this.chartColors = [
+          '#286090',
+          '#F7464A',
+          '#46BFBD',
+          '#FDB45C',
+          '#97BBCD',
+          '#4D5360',
+          '#8c4f9f'
+        ];
+
+        this.chart = {
+          series: [],
+          labels: [],
+          data: []
+        }
+
+        Chart.defaults.global.colours = this.chartColors;
+
+        this.chartType = 'line';
+
+        if($stateParams.name && $stateParams.tenant){
+          this.name = $stateParams.name;
+          this.tenant = $stateParams.tenant;
+          // TODO rename tenant in resource_id
+        }
+        else{
+          throw new Error('Missing Name and Tenant Params!');
+        }
+
+        /**
+         * Goes trough the array and format date to be used as labels
+         *
+         * @param Array data
+         * @returns Array a list of labels
+         */
+
+        this.getLabels = (data) => {
+          return data.reduce((list, item) => {
+            let date = new Date(item.timestamp);
+            list.push(`${date.getHours()}:${(date.getMinutes()<10?'0':'') + date.getMinutes()}:${date.getSeconds()}`);
+            return list;
+          }, []);
+        };
+
+        /**
+         * Goes trough the array and return a flat array of values
+         *
+         * @param Array data
+         * @returns Array a list of values
+         */
+
+        this.getData = (data) => {
+          return data.reduce((list, item) => {
+            list.push(item.volume);
+            return list;
+          }, []);
+        }
+
+        /**
+         * Add a samples to the chart
+         *
+         * @param string resource_id
+         */
+        this.chartMeters = [];
+        this.addMeterToChart = (resource_id) => {
+          this.chart['labels'] = this.getLabels(_.sortBy(this.samplesList[resource_id], 'timestamp'));
+          this.chart['series'].push(resource_id);
+          this.chart['data'].push(this.getData(_.sortBy(this.samplesList[resource_id], 'timestamp')));
+          this.chartMeters.push(this.samplesList[resource_id][0]); //use the 0 as are all samples for the same resource and I need the name
+          _.remove(this.sampleLabels, {id: resource_id});
+        }
+
+        this.removeFromChart = (meter) => {
+          this.chart.data.splice(this.chart.series.indexOf(meter.resource_id), 1);
+          this.chart.series.splice(this.chart.series.indexOf(meter.resource_id), 1);
+          this.chartMeters.splice(_.findIndex(this.chartMeters, {resource_id: meter.resource_id}), 1);
+          this.sampleLabels.push({
+            id: meter.resource_id,
+            name: meter.resource_name || meter.resource_id
+          })
+        };
+
+        /**
+         * Format samples to create a list of labels and ids
+         */
+
+        this.formatSamplesLabels = (samples) => {
+
+          return _.uniq(samples, 'resource_id')
+            .reduce((labels, item) => {
+              labels.push({
+                id: item.resource_id,
+                name: item.resource_name || item.resource_id
+              });
+
+              return labels;
+            }, []);
+        }
+
+
+        /**
+         * Load the samples and format data
+         */
+
+        this.showSamples = () => {
+          this.loader = true;
+          // Ceilometer.getSamples(this.name, this.tenant) //fetch one
+          Ceilometer.getSamples(this.name) //fetch all
+            .then(res => {
+
+              // rename things in UI
+              res.map(m => {
+                m.resource_name = m.resource_name.replace('mysite_onos_vbng', 'ONOS_FABRIC');
+                m.resource_name = m.resource_name.replace('mysite_onos_volt', 'ONOS_CORD');
+                m.resource_name = m.resource_name.replace('mysite_vbng', 'mysite_vRouter');
+                return m;
+              });
+              // end rename things in UI
+
+              // setup data for visualization
+              this.samplesList = _.groupBy(res, 'resource_id');
+              this.sampleLabels = this.formatSamplesLabels(res);
+
+              // add current meter to chart
+              this.addMeterToChart(this.tenant);
+
+            })
+            .catch(err => {
+              this.error = err.data.detail;
+            })
+            .finally(() => {
+              this.loader = false;
+            });
+        };
+
+        this.showSamples();
+      }
+    }
+  });
+})();
+
diff --git a/views/ngXosViews/ceilometerDashboard/src/js/stats.directive.js b/views/ngXosViews/ceilometerDashboard/src/js/stats.directive.js
new file mode 100644
index 0000000..7f0b1f8
--- /dev/null
+++ b/views/ngXosViews/ceilometerDashboard/src/js/stats.directive.js
@@ -0,0 +1,54 @@
+/**
+ * © OpenCORD
+ *
+ * Visit http://guide.xosproject.org/devguide/addview/ for more information
+ *
+ * Created by teone on 3/21/16.
+ */
+
+(function () {
+  'use strict';
+
+  angular.module('xos.ceilometerDashboard')
+    .directive('ceilometerStats', function(){
+      return {
+        restrict: 'E',
+        scope: {
+          name: '=name',
+          tenant: '=tenant'
+        },
+        bindToController: true,
+        controllerAs: 'vm',
+        templateUrl: 'templates/ceilometer-stats.tpl.html',
+        controller: function($scope, Ceilometer) {
+
+          this.getStats = (tenant) => {
+            this.loader = true;
+            Ceilometer.getStats({tenant: tenant})
+              .then(res => {
+                res.map(m => {
+                  m.resource_name = m.resource_name.replace('mysite_onos_vbng', 'ONOS_FABRIC');
+                  m.resource_name = m.resource_name.replace('mysite_onos_volt', 'ONOS_CORD');
+                  m.resource_name = m.resource_name.replace('mysite_vbng', 'mysite_vRouter');
+                  return m;
+                });
+                this.stats = res;
+              })
+              .catch(err => {
+                this.error = err.data;
+              })
+              .finally(() => {
+                this.loader = false;
+              });
+          };
+
+          $scope.$watch(() => this.name, (val) => {
+            if(val){
+              this.getStats(this.tenant);
+            }
+          });
+        }
+      }
+    });
+})();
+
diff --git a/views/ngXosViews/ceilometerDashboard/src/meters_mock.json b/views/ngXosViews/ceilometerDashboard/src/meters_mock.json
new file mode 100644
index 0000000..7ff0c68
--- /dev/null
+++ b/views/ngXosViews/ceilometerDashboard/src/meters_mock.json
@@ -0,0 +1,1266 @@
+[
+    {
+        "category": "Nova", 
+        "slice": "mysite_onos_volt", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "instance", 
+        "service": "service_ONOS_vOLT", 
+        "resource_id": "197bc772-ff13-4b68-96e6-d4a4b1730fe7", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "mysite_onos_volt-4", 
+        "meter_id": "MTk3YmM3NzItZmYxMy00YjY4LTk2ZTYtZDRhNGIxNzMwZmU3K2luc3RhbmNl\n", 
+        "project_id": "bfef8341327245d682c7bada50aceecb", 
+        "type": "gauge", 
+        "unit": "instance", 
+        "description": "Existence of instance"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_onos_vbng", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "instance", 
+        "service": "service_ONOS_vBNG", 
+        "resource_id": "bde67a22-7579-4097-9406-c15eb2b9ae27", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "mysite_onos_vbng-2", 
+        "meter_id": "YmRlNjdhMjItNzU3OS00MDk3LTk0MDYtYzE1ZWIyYjlhZTI3K2luc3RhbmNl\n", 
+        "project_id": "7c918e6765c24ee281f3ee8692fd102c", 
+        "type": "gauge", 
+        "unit": "instance", 
+        "description": "Existence of instance"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_volt", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "instance", 
+        "service": "Other", 
+        "resource_id": "0a802169-5918-4c28-9014-635ae6602cdb", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "mysite_volt-5", 
+        "meter_id": "MGE4MDIxNjktNTkxOC00YzI4LTkwMTQtNjM1YWU2NjAyY2RiK2luc3RhbmNl\n", 
+        "project_id": "f506380a49a24389ae0d8469274e3279", 
+        "type": "gauge", 
+        "unit": "instance", 
+        "description": "Existence of instance"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_vcpe", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "instance", 
+        "service": "service_vcpe", 
+        "resource_id": "f71e7c55-2435-45a4-aa9a-073f97ceccbc", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "mysite_vcpe-7", 
+        "meter_id": "ZjcxZTdjNTUtMjQzNS00NWE0LWFhOWEtMDczZjk3Y2VjY2JjK2luc3RhbmNl\n", 
+        "project_id": "61a5d4b37b5d43718854916079760c0d", 
+        "type": "gauge", 
+        "unit": "instance", 
+        "description": "Existence of instance"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_vbng", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "instance", 
+        "service": "Other", 
+        "resource_id": "98535996-e184-4996-a28e-61647e5d31d0", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "mysite_vbng-6", 
+        "meter_id": "OTg1MzU5OTYtZTE4NC00OTk2LWEyOGUtNjE2NDdlNWQzMWQwK2luc3RhbmNl\n", 
+        "project_id": "c92cf450df4640d6952c0276730e5048", 
+        "type": "gauge", 
+        "unit": "instance", 
+        "description": "Existence of instance"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_clients", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "instance", 
+        "service": "Other", 
+        "resource_id": "f5c71396-9092-42da-91ec-434259bde2ef", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "mysite_clients-3", 
+        "meter_id": "ZjVjNzEzOTYtOTA5Mi00MmRhLTkxZWMtNDM0MjU5YmRlMmVmK2luc3RhbmNl\n", 
+        "project_id": "f884c440474b40808a8adcdece5f45ef", 
+        "type": "gauge", 
+        "unit": "instance", 
+        "description": "Existence of instance"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_ceilometer", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "instance", 
+        "service": "service_ceilometer", 
+        "resource_id": "bdb0ff14-e848-446c-acb4-63e232487dc0", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "mysite_ceilometer-8", 
+        "meter_id": "YmRiMGZmMTQtZTg0OC00NDZjLWFjYjQtNjNlMjMyNDg3ZGMwK2luc3RhbmNl\n", 
+        "project_id": "920d70bc63574552bbb3c3fb262ee1bc", 
+        "type": "gauge", 
+        "unit": "instance", 
+        "description": "Existence of instance"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_onos_volt", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "memory", 
+        "service": "service_ONOS_vOLT", 
+        "resource_id": "197bc772-ff13-4b68-96e6-d4a4b1730fe7", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "mysite_onos_volt-4", 
+        "meter_id": "MTk3YmM3NzItZmYxMy00YjY4LTk2ZTYtZDRhNGIxNzMwZmU3K21lbW9yeQ==\n", 
+        "project_id": "bfef8341327245d682c7bada50aceecb", 
+        "type": "gauge", 
+        "unit": "MB", 
+        "description": "Volume of RAM"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_onos_vbng", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "memory", 
+        "service": "service_ONOS_vBNG", 
+        "resource_id": "bde67a22-7579-4097-9406-c15eb2b9ae27", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "mysite_onos_vbng-2", 
+        "meter_id": "YmRlNjdhMjItNzU3OS00MDk3LTk0MDYtYzE1ZWIyYjlhZTI3K21lbW9yeQ==\n", 
+        "project_id": "7c918e6765c24ee281f3ee8692fd102c", 
+        "type": "gauge", 
+        "unit": "MB", 
+        "description": "Volume of RAM"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_volt", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "memory", 
+        "service": "Other", 
+        "resource_id": "0a802169-5918-4c28-9014-635ae6602cdb", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "mysite_volt-5", 
+        "meter_id": "MGE4MDIxNjktNTkxOC00YzI4LTkwMTQtNjM1YWU2NjAyY2RiK21lbW9yeQ==\n", 
+        "project_id": "f506380a49a24389ae0d8469274e3279", 
+        "type": "gauge", 
+        "unit": "MB", 
+        "description": "Volume of RAM"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_vcpe", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "memory", 
+        "service": "service_vcpe", 
+        "resource_id": "f71e7c55-2435-45a4-aa9a-073f97ceccbc", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "mysite_vcpe-7", 
+        "meter_id": "ZjcxZTdjNTUtMjQzNS00NWE0LWFhOWEtMDczZjk3Y2VjY2JjK21lbW9yeQ==\n", 
+        "project_id": "61a5d4b37b5d43718854916079760c0d", 
+        "type": "gauge", 
+        "unit": "MB", 
+        "description": "Volume of RAM"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_vbng", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "memory", 
+        "service": "Other", 
+        "resource_id": "98535996-e184-4996-a28e-61647e5d31d0", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "mysite_vbng-6", 
+        "meter_id": "OTg1MzU5OTYtZTE4NC00OTk2LWEyOGUtNjE2NDdlNWQzMWQwK21lbW9yeQ==\n", 
+        "project_id": "c92cf450df4640d6952c0276730e5048", 
+        "type": "gauge", 
+        "unit": "MB", 
+        "description": "Volume of RAM"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_clients", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "memory", 
+        "service": "Other", 
+        "resource_id": "f5c71396-9092-42da-91ec-434259bde2ef", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "mysite_clients-3", 
+        "meter_id": "ZjVjNzEzOTYtOTA5Mi00MmRhLTkxZWMtNDM0MjU5YmRlMmVmK21lbW9yeQ==\n", 
+        "project_id": "f884c440474b40808a8adcdece5f45ef", 
+        "type": "gauge", 
+        "unit": "MB", 
+        "description": "Volume of RAM"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_ceilometer", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "memory", 
+        "service": "service_ceilometer", 
+        "resource_id": "bdb0ff14-e848-446c-acb4-63e232487dc0", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "mysite_ceilometer-8", 
+        "meter_id": "YmRiMGZmMTQtZTg0OC00NDZjLWFjYjQtNjNlMjMyNDg3ZGMwK21lbW9yeQ==\n", 
+        "project_id": "920d70bc63574552bbb3c3fb262ee1bc", 
+        "type": "gauge", 
+        "unit": "MB", 
+        "description": "Volume of RAM"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_onos_volt", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "memory.usage", 
+        "service": "service_ONOS_vOLT", 
+        "resource_id": "197bc772-ff13-4b68-96e6-d4a4b1730fe7", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "mysite_onos_volt-4", 
+        "meter_id": "MTk3YmM3NzItZmYxMy00YjY4LTk2ZTYtZDRhNGIxNzMwZmU3K21lbW9yeS51c2FnZQ==\n", 
+        "project_id": "bfef8341327245d682c7bada50aceecb", 
+        "type": "gauge", 
+        "unit": "MB", 
+        "description": "Volume of RAM used"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_onos_vbng", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "memory.usage", 
+        "service": "service_ONOS_vBNG", 
+        "resource_id": "bde67a22-7579-4097-9406-c15eb2b9ae27", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "mysite_onos_vbng-2", 
+        "meter_id": "YmRlNjdhMjItNzU3OS00MDk3LTk0MDYtYzE1ZWIyYjlhZTI3K21lbW9yeS51c2FnZQ==\n", 
+        "project_id": "7c918e6765c24ee281f3ee8692fd102c", 
+        "type": "gauge", 
+        "unit": "MB", 
+        "description": "Volume of RAM used"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_volt", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "memory.usage", 
+        "service": "Other", 
+        "resource_id": "0a802169-5918-4c28-9014-635ae6602cdb", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "mysite_volt-5", 
+        "meter_id": "MGE4MDIxNjktNTkxOC00YzI4LTkwMTQtNjM1YWU2NjAyY2RiK21lbW9yeS51c2FnZQ==\n", 
+        "project_id": "f506380a49a24389ae0d8469274e3279", 
+        "type": "gauge", 
+        "unit": "MB", 
+        "description": "Volume of RAM used"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_vcpe", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "memory.usage", 
+        "service": "service_vcpe", 
+        "resource_id": "f71e7c55-2435-45a4-aa9a-073f97ceccbc", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "mysite_vcpe-7", 
+        "meter_id": "ZjcxZTdjNTUtMjQzNS00NWE0LWFhOWEtMDczZjk3Y2VjY2JjK21lbW9yeS51c2FnZQ==\n", 
+        "project_id": "61a5d4b37b5d43718854916079760c0d", 
+        "type": "gauge", 
+        "unit": "MB", 
+        "description": "Volume of RAM used"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_vbng", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "memory.usage", 
+        "service": "Other", 
+        "resource_id": "98535996-e184-4996-a28e-61647e5d31d0", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "mysite_vbng-6", 
+        "meter_id": "OTg1MzU5OTYtZTE4NC00OTk2LWEyOGUtNjE2NDdlNWQzMWQwK21lbW9yeS51c2FnZQ==\n", 
+        "project_id": "c92cf450df4640d6952c0276730e5048", 
+        "type": "gauge", 
+        "unit": "MB", 
+        "description": "Volume of RAM used"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_clients", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "memory.usage", 
+        "service": "Other", 
+        "resource_id": "f5c71396-9092-42da-91ec-434259bde2ef", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "mysite_clients-3", 
+        "meter_id": "ZjVjNzEzOTYtOTA5Mi00MmRhLTkxZWMtNDM0MjU5YmRlMmVmK21lbW9yeS51c2FnZQ==\n", 
+        "project_id": "f884c440474b40808a8adcdece5f45ef", 
+        "type": "gauge", 
+        "unit": "MB", 
+        "description": "Volume of RAM used"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_ceilometer", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "memory.usage", 
+        "service": "service_ceilometer", 
+        "resource_id": "bdb0ff14-e848-446c-acb4-63e232487dc0", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "mysite_ceilometer-8", 
+        "meter_id": "YmRiMGZmMTQtZTg0OC00NDZjLWFjYjQtNjNlMjMyNDg3ZGMwK21lbW9yeS51c2FnZQ==\n", 
+        "project_id": "920d70bc63574552bbb3c3fb262ee1bc", 
+        "type": "gauge", 
+        "unit": "MB", 
+        "description": "Volume of RAM used"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_onos_volt", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "cpu", 
+        "service": "service_ONOS_vOLT", 
+        "resource_id": "197bc772-ff13-4b68-96e6-d4a4b1730fe7", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "mysite_onos_volt-4", 
+        "meter_id": "MTk3YmM3NzItZmYxMy00YjY4LTk2ZTYtZDRhNGIxNzMwZmU3K2NwdQ==\n", 
+        "project_id": "bfef8341327245d682c7bada50aceecb", 
+        "type": "cumulative", 
+        "unit": "ns", 
+        "description": "CPU time used"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_onos_vbng", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "cpu", 
+        "service": "service_ONOS_vBNG", 
+        "resource_id": "bde67a22-7579-4097-9406-c15eb2b9ae27", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "mysite_onos_vbng-2", 
+        "meter_id": "YmRlNjdhMjItNzU3OS00MDk3LTk0MDYtYzE1ZWIyYjlhZTI3K2NwdQ==\n", 
+        "project_id": "7c918e6765c24ee281f3ee8692fd102c", 
+        "type": "cumulative", 
+        "unit": "ns", 
+        "description": "CPU time used"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_volt", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "cpu", 
+        "service": "Other", 
+        "resource_id": "0a802169-5918-4c28-9014-635ae6602cdb", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "mysite_volt-5", 
+        "meter_id": "MGE4MDIxNjktNTkxOC00YzI4LTkwMTQtNjM1YWU2NjAyY2RiK2NwdQ==\n", 
+        "project_id": "f506380a49a24389ae0d8469274e3279", 
+        "type": "cumulative", 
+        "unit": "ns", 
+        "description": "CPU time used"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_vcpe", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "cpu", 
+        "service": "service_vcpe", 
+        "resource_id": "f71e7c55-2435-45a4-aa9a-073f97ceccbc", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "mysite_vcpe-7", 
+        "meter_id": "ZjcxZTdjNTUtMjQzNS00NWE0LWFhOWEtMDczZjk3Y2VjY2JjK2NwdQ==\n", 
+        "project_id": "61a5d4b37b5d43718854916079760c0d", 
+        "type": "cumulative", 
+        "unit": "ns", 
+        "description": "CPU time used"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_vbng", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "cpu", 
+        "service": "Other", 
+        "resource_id": "98535996-e184-4996-a28e-61647e5d31d0", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "mysite_vbng-6", 
+        "meter_id": "OTg1MzU5OTYtZTE4NC00OTk2LWEyOGUtNjE2NDdlNWQzMWQwK2NwdQ==\n", 
+        "project_id": "c92cf450df4640d6952c0276730e5048", 
+        "type": "cumulative", 
+        "unit": "ns", 
+        "description": "CPU time used"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_clients", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "cpu", 
+        "service": "Other", 
+        "resource_id": "f5c71396-9092-42da-91ec-434259bde2ef", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "mysite_clients-3", 
+        "meter_id": "ZjVjNzEzOTYtOTA5Mi00MmRhLTkxZWMtNDM0MjU5YmRlMmVmK2NwdQ==\n", 
+        "project_id": "f884c440474b40808a8adcdece5f45ef", 
+        "type": "cumulative", 
+        "unit": "ns", 
+        "description": "CPU time used"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_ceilometer", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "cpu", 
+        "service": "service_ceilometer", 
+        "resource_id": "bdb0ff14-e848-446c-acb4-63e232487dc0", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "mysite_ceilometer-8", 
+        "meter_id": "YmRiMGZmMTQtZTg0OC00NDZjLWFjYjQtNjNlMjMyNDg3ZGMwK2NwdQ==\n", 
+        "project_id": "920d70bc63574552bbb3c3fb262ee1bc", 
+        "type": "cumulative", 
+        "unit": "ns", 
+        "description": "CPU time used"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_onos_volt", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "cpu_util", 
+        "service": "service_ONOS_vOLT", 
+        "resource_id": "197bc772-ff13-4b68-96e6-d4a4b1730fe7", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "mysite_onos_volt-4", 
+        "meter_id": "MTk3YmM3NzItZmYxMy00YjY4LTk2ZTYtZDRhNGIxNzMwZmU3K2NwdV91dGls\n", 
+        "project_id": "bfef8341327245d682c7bada50aceecb", 
+        "type": "gauge", 
+        "unit": "%", 
+        "description": "Average CPU utilization"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_onos_vbng", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "cpu_util", 
+        "service": "service_ONOS_vBNG", 
+        "resource_id": "bde67a22-7579-4097-9406-c15eb2b9ae27", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "mysite_onos_vbng-2", 
+        "meter_id": "YmRlNjdhMjItNzU3OS00MDk3LTk0MDYtYzE1ZWIyYjlhZTI3K2NwdV91dGls\n", 
+        "project_id": "7c918e6765c24ee281f3ee8692fd102c", 
+        "type": "gauge", 
+        "unit": "%", 
+        "description": "Average CPU utilization"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_volt", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "cpu_util", 
+        "service": "Other", 
+        "resource_id": "0a802169-5918-4c28-9014-635ae6602cdb", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "mysite_volt-5", 
+        "meter_id": "MGE4MDIxNjktNTkxOC00YzI4LTkwMTQtNjM1YWU2NjAyY2RiK2NwdV91dGls\n", 
+        "project_id": "f506380a49a24389ae0d8469274e3279", 
+        "type": "gauge", 
+        "unit": "%", 
+        "description": "Average CPU utilization"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_vcpe", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "cpu_util", 
+        "service": "service_vcpe", 
+        "resource_id": "f71e7c55-2435-45a4-aa9a-073f97ceccbc", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "mysite_vcpe-7", 
+        "meter_id": "ZjcxZTdjNTUtMjQzNS00NWE0LWFhOWEtMDczZjk3Y2VjY2JjK2NwdV91dGls\n", 
+        "project_id": "61a5d4b37b5d43718854916079760c0d", 
+        "type": "gauge", 
+        "unit": "%", 
+        "description": "Average CPU utilization"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_vbng", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "cpu_util", 
+        "service": "Other", 
+        "resource_id": "98535996-e184-4996-a28e-61647e5d31d0", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "mysite_vbng-6", 
+        "meter_id": "OTg1MzU5OTYtZTE4NC00OTk2LWEyOGUtNjE2NDdlNWQzMWQwK2NwdV91dGls\n", 
+        "project_id": "c92cf450df4640d6952c0276730e5048", 
+        "type": "gauge", 
+        "unit": "%", 
+        "description": "Average CPU utilization"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_clients", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "cpu_util", 
+        "service": "Other", 
+        "resource_id": "f5c71396-9092-42da-91ec-434259bde2ef", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "mysite_clients-3", 
+        "meter_id": "ZjVjNzEzOTYtOTA5Mi00MmRhLTkxZWMtNDM0MjU5YmRlMmVmK2NwdV91dGls\n", 
+        "project_id": "f884c440474b40808a8adcdece5f45ef", 
+        "type": "gauge", 
+        "unit": "%", 
+        "description": "Average CPU utilization"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_ceilometer", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "cpu_util", 
+        "service": "service_ceilometer", 
+        "resource_id": "bdb0ff14-e848-446c-acb4-63e232487dc0", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "mysite_ceilometer-8", 
+        "meter_id": "YmRiMGZmMTQtZTg0OC00NDZjLWFjYjQtNjNlMjMyNDg3ZGMwK2NwdV91dGls\n", 
+        "project_id": "920d70bc63574552bbb3c3fb262ee1bc", 
+        "type": "gauge", 
+        "unit": "%", 
+        "description": "Average CPU utilization"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_onos_volt", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.incoming.bytes.rate", 
+        "service": "service_ONOS_vOLT", 
+        "resource_id": "instance-00000002-197bc772-ff13-4b68-96e6-d4a4b1730fe7-tap27815de2-07", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tap27815de2-07", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDItMTk3YmM3NzItZmYxMy00YjY4LTk2ZTYtZDRhNGIxNzMwZmU3LXRh\ncDI3ODE1ZGUyLTA3K25ldHdvcmsuaW5jb21pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "bfef8341327245d682c7bada50aceecb", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_onos_volt", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.incoming.bytes.rate", 
+        "service": "service_ONOS_vOLT", 
+        "resource_id": "instance-00000002-197bc772-ff13-4b68-96e6-d4a4b1730fe7-tap8f02bde6-e4", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tap8f02bde6-e4", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDItMTk3YmM3NzItZmYxMy00YjY4LTk2ZTYtZDRhNGIxNzMwZmU3LXRh\ncDhmMDJiZGU2LWU0K25ldHdvcmsuaW5jb21pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "bfef8341327245d682c7bada50aceecb", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_onos_vbng", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.incoming.bytes.rate", 
+        "service": "service_ONOS_vBNG", 
+        "resource_id": "instance-00000004-bde67a22-7579-4097-9406-c15eb2b9ae27-tap265bab7b-93", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tap265bab7b-93", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDQtYmRlNjdhMjItNzU3OS00MDk3LTk0MDYtYzE1ZWIyYjlhZTI3LXRh\ncDI2NWJhYjdiLTkzK25ldHdvcmsuaW5jb21pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "7c918e6765c24ee281f3ee8692fd102c", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_onos_vbng", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.incoming.bytes.rate", 
+        "service": "service_ONOS_vBNG", 
+        "resource_id": "instance-00000004-bde67a22-7579-4097-9406-c15eb2b9ae27-tap6d838c10-05", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tap6d838c10-05", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDQtYmRlNjdhMjItNzU3OS00MDk3LTk0MDYtYzE1ZWIyYjlhZTI3LXRh\ncDZkODM4YzEwLTA1K25ldHdvcmsuaW5jb21pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "7c918e6765c24ee281f3ee8692fd102c", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_volt", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.incoming.bytes.rate", 
+        "service": "Other", 
+        "resource_id": "instance-00000001-0a802169-5918-4c28-9014-635ae6602cdb-tap5ef062b7-1d", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tap5ef062b7-1d", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDEtMGE4MDIxNjktNTkxOC00YzI4LTkwMTQtNjM1YWU2NjAyY2RiLXRh\ncDVlZjA2MmI3LTFkK25ldHdvcmsuaW5jb21pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "f506380a49a24389ae0d8469274e3279", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_volt", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.incoming.bytes.rate", 
+        "service": "Other", 
+        "resource_id": "instance-00000001-0a802169-5918-4c28-9014-635ae6602cdb-tap905990b8-db", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tap905990b8-db", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDEtMGE4MDIxNjktNTkxOC00YzI4LTkwMTQtNjM1YWU2NjAyY2RiLXRh\ncDkwNTk5MGI4LWRiK25ldHdvcmsuaW5jb21pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "f506380a49a24389ae0d8469274e3279", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_volt", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.incoming.bytes.rate", 
+        "service": "Other", 
+        "resource_id": "instance-00000001-0a802169-5918-4c28-9014-635ae6602cdb-tapa216d1f0-3e", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tapa216d1f0-3e", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDEtMGE4MDIxNjktNTkxOC00YzI4LTkwMTQtNjM1YWU2NjAyY2RiLXRh\ncGEyMTZkMWYwLTNlK25ldHdvcmsuaW5jb21pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "f506380a49a24389ae0d8469274e3279", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_volt", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.incoming.bytes.rate", 
+        "service": "Other", 
+        "resource_id": "instance-00000001-0a802169-5918-4c28-9014-635ae6602cdb-tapd80be99a-b6", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tapd80be99a-b6", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDEtMGE4MDIxNjktNTkxOC00YzI4LTkwMTQtNjM1YWU2NjAyY2RiLXRh\ncGQ4MGJlOTlhLWI2K25ldHdvcmsuaW5jb21pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "f506380a49a24389ae0d8469274e3279", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_vcpe", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.incoming.bytes.rate", 
+        "service": "service_vcpe", 
+        "resource_id": "instance-00000006-f71e7c55-2435-45a4-aa9a-073f97ceccbc-tap5afd137f-19", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tap5afd137f-19", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDYtZjcxZTdjNTUtMjQzNS00NWE0LWFhOWEtMDczZjk3Y2VjY2JjLXRh\ncDVhZmQxMzdmLTE5K25ldHdvcmsuaW5jb21pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "61a5d4b37b5d43718854916079760c0d", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_vcpe", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.incoming.bytes.rate", 
+        "service": "service_vcpe", 
+        "resource_id": "instance-00000006-f71e7c55-2435-45a4-aa9a-073f97ceccbc-tap9a6306b4-7e", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tap9a6306b4-7e", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDYtZjcxZTdjNTUtMjQzNS00NWE0LWFhOWEtMDczZjk3Y2VjY2JjLXRh\ncDlhNjMwNmI0LTdlK25ldHdvcmsuaW5jb21pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "61a5d4b37b5d43718854916079760c0d", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_vcpe", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.incoming.bytes.rate", 
+        "service": "service_vcpe", 
+        "resource_id": "instance-00000006-f71e7c55-2435-45a4-aa9a-073f97ceccbc-tapc59abc32-a4", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tapc59abc32-a4", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDYtZjcxZTdjNTUtMjQzNS00NWE0LWFhOWEtMDczZjk3Y2VjY2JjLXRh\ncGM1OWFiYzMyLWE0K25ldHdvcmsuaW5jb21pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "61a5d4b37b5d43718854916079760c0d", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_vcpe", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.incoming.bytes.rate", 
+        "service": "service_vcpe", 
+        "resource_id": "instance-00000006-f71e7c55-2435-45a4-aa9a-073f97ceccbc-tapf1e00a14-22", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tapf1e00a14-22", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDYtZjcxZTdjNTUtMjQzNS00NWE0LWFhOWEtMDczZjk3Y2VjY2JjLXRh\ncGYxZTAwYTE0LTIyK25ldHdvcmsuaW5jb21pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "61a5d4b37b5d43718854916079760c0d", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_vbng", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.incoming.bytes.rate", 
+        "service": "Other", 
+        "resource_id": "instance-00000007-98535996-e184-4996-a28e-61647e5d31d0-tapabf29bde-bc", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tapabf29bde-bc", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDctOTg1MzU5OTYtZTE4NC00OTk2LWEyOGUtNjE2NDdlNWQzMWQwLXRh\ncGFiZjI5YmRlLWJjK25ldHdvcmsuaW5jb21pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "c92cf450df4640d6952c0276730e5048", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_vbng", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.incoming.bytes.rate", 
+        "service": "Other", 
+        "resource_id": "instance-00000007-98535996-e184-4996-a28e-61647e5d31d0-tapbc16b000-82", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tapbc16b000-82", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDctOTg1MzU5OTYtZTE4NC00OTk2LWEyOGUtNjE2NDdlNWQzMWQwLXRh\ncGJjMTZiMDAwLTgyK25ldHdvcmsuaW5jb21pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "c92cf450df4640d6952c0276730e5048", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_vbng", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.incoming.bytes.rate", 
+        "service": "Other", 
+        "resource_id": "instance-00000007-98535996-e184-4996-a28e-61647e5d31d0-tape44bc1cc-46", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tape44bc1cc-46", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDctOTg1MzU5OTYtZTE4NC00OTk2LWEyOGUtNjE2NDdlNWQzMWQwLXRh\ncGU0NGJjMWNjLTQ2K25ldHdvcmsuaW5jb21pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "c92cf450df4640d6952c0276730e5048", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_vbng", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.incoming.bytes.rate", 
+        "service": "Other", 
+        "resource_id": "instance-00000007-98535996-e184-4996-a28e-61647e5d31d0-tape4f20024-47", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tape4f20024-47", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDctOTg1MzU5OTYtZTE4NC00OTk2LWEyOGUtNjE2NDdlNWQzMWQwLXRh\ncGU0ZjIwMDI0LTQ3K25ldHdvcmsuaW5jb21pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "c92cf450df4640d6952c0276730e5048", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_clients", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.incoming.bytes.rate", 
+        "service": "Other", 
+        "resource_id": "instance-00000003-f5c71396-9092-42da-91ec-434259bde2ef-tap3518d7f8-9f", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tap3518d7f8-9f", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDMtZjVjNzEzOTYtOTA5Mi00MmRhLTkxZWMtNDM0MjU5YmRlMmVmLXRh\ncDM1MThkN2Y4LTlmK25ldHdvcmsuaW5jb21pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "f884c440474b40808a8adcdece5f45ef", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_clients", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.incoming.bytes.rate", 
+        "service": "Other", 
+        "resource_id": "instance-00000003-f5c71396-9092-42da-91ec-434259bde2ef-tap7409a9c5-e0", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tap7409a9c5-e0", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDMtZjVjNzEzOTYtOTA5Mi00MmRhLTkxZWMtNDM0MjU5YmRlMmVmLXRh\ncDc0MDlhOWM1LWUwK25ldHdvcmsuaW5jb21pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "f884c440474b40808a8adcdece5f45ef", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_clients", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.incoming.bytes.rate", 
+        "service": "Other", 
+        "resource_id": "instance-00000003-f5c71396-9092-42da-91ec-434259bde2ef-tapde69764f-3d", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tapde69764f-3d", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDMtZjVjNzEzOTYtOTA5Mi00MmRhLTkxZWMtNDM0MjU5YmRlMmVmLXRh\ncGRlNjk3NjRmLTNkK25ldHdvcmsuaW5jb21pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "f884c440474b40808a8adcdece5f45ef", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_ceilometer", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.incoming.bytes.rate", 
+        "service": "service_ceilometer", 
+        "resource_id": "instance-00000005-bdb0ff14-e848-446c-acb4-63e232487dc0-tap8d13e0d5-d2", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tap8d13e0d5-d2", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDUtYmRiMGZmMTQtZTg0OC00NDZjLWFjYjQtNjNlMjMyNDg3ZGMwLXRh\ncDhkMTNlMGQ1LWQyK25ldHdvcmsuaW5jb21pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "920d70bc63574552bbb3c3fb262ee1bc", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_ceilometer", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.incoming.bytes.rate", 
+        "service": "service_ceilometer", 
+        "resource_id": "instance-00000005-bdb0ff14-e848-446c-acb4-63e232487dc0-tapa5d252a8-ae", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tapa5d252a8-ae", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDUtYmRiMGZmMTQtZTg0OC00NDZjLWFjYjQtNjNlMjMyNDg3ZGMwLXRh\ncGE1ZDI1MmE4LWFlK25ldHdvcmsuaW5jb21pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "920d70bc63574552bbb3c3fb262ee1bc", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_ceilometer", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.incoming.bytes.rate", 
+        "service": "service_ceilometer", 
+        "resource_id": "instance-00000005-bdb0ff14-e848-446c-acb4-63e232487dc0-tapb06a526b-03", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tapb06a526b-03", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDUtYmRiMGZmMTQtZTg0OC00NDZjLWFjYjQtNjNlMjMyNDg3ZGMwLXRh\ncGIwNmE1MjZiLTAzK25ldHdvcmsuaW5jb21pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "920d70bc63574552bbb3c3fb262ee1bc", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_onos_volt", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.outgoing.bytes.rate", 
+        "service": "service_ONOS_vOLT", 
+        "resource_id": "instance-00000002-197bc772-ff13-4b68-96e6-d4a4b1730fe7-tap27815de2-07", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tap27815de2-07", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDItMTk3YmM3NzItZmYxMy00YjY4LTk2ZTYtZDRhNGIxNzMwZmU3LXRh\ncDI3ODE1ZGUyLTA3K25ldHdvcmsub3V0Z29pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "bfef8341327245d682c7bada50aceecb", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_onos_volt", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.outgoing.bytes.rate", 
+        "service": "service_ONOS_vOLT", 
+        "resource_id": "instance-00000002-197bc772-ff13-4b68-96e6-d4a4b1730fe7-tap8f02bde6-e4", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tap8f02bde6-e4", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDItMTk3YmM3NzItZmYxMy00YjY4LTk2ZTYtZDRhNGIxNzMwZmU3LXRh\ncDhmMDJiZGU2LWU0K25ldHdvcmsub3V0Z29pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "bfef8341327245d682c7bada50aceecb", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_onos_vbng", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.outgoing.bytes.rate", 
+        "service": "service_ONOS_vBNG", 
+        "resource_id": "instance-00000004-bde67a22-7579-4097-9406-c15eb2b9ae27-tap265bab7b-93", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tap265bab7b-93", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDQtYmRlNjdhMjItNzU3OS00MDk3LTk0MDYtYzE1ZWIyYjlhZTI3LXRh\ncDI2NWJhYjdiLTkzK25ldHdvcmsub3V0Z29pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "7c918e6765c24ee281f3ee8692fd102c", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_onos_vbng", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.outgoing.bytes.rate", 
+        "service": "service_ONOS_vBNG", 
+        "resource_id": "instance-00000004-bde67a22-7579-4097-9406-c15eb2b9ae27-tap6d838c10-05", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tap6d838c10-05", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDQtYmRlNjdhMjItNzU3OS00MDk3LTk0MDYtYzE1ZWIyYjlhZTI3LXRh\ncDZkODM4YzEwLTA1K25ldHdvcmsub3V0Z29pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "7c918e6765c24ee281f3ee8692fd102c", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_volt", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.outgoing.bytes.rate", 
+        "service": "Other", 
+        "resource_id": "instance-00000001-0a802169-5918-4c28-9014-635ae6602cdb-tap5ef062b7-1d", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tap5ef062b7-1d", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDEtMGE4MDIxNjktNTkxOC00YzI4LTkwMTQtNjM1YWU2NjAyY2RiLXRh\ncDVlZjA2MmI3LTFkK25ldHdvcmsub3V0Z29pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "f506380a49a24389ae0d8469274e3279", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_volt", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.outgoing.bytes.rate", 
+        "service": "Other", 
+        "resource_id": "instance-00000001-0a802169-5918-4c28-9014-635ae6602cdb-tap905990b8-db", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tap905990b8-db", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDEtMGE4MDIxNjktNTkxOC00YzI4LTkwMTQtNjM1YWU2NjAyY2RiLXRh\ncDkwNTk5MGI4LWRiK25ldHdvcmsub3V0Z29pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "f506380a49a24389ae0d8469274e3279", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_volt", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.outgoing.bytes.rate", 
+        "service": "Other", 
+        "resource_id": "instance-00000001-0a802169-5918-4c28-9014-635ae6602cdb-tapa216d1f0-3e", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tapa216d1f0-3e", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDEtMGE4MDIxNjktNTkxOC00YzI4LTkwMTQtNjM1YWU2NjAyY2RiLXRh\ncGEyMTZkMWYwLTNlK25ldHdvcmsub3V0Z29pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "f506380a49a24389ae0d8469274e3279", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_volt", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.outgoing.bytes.rate", 
+        "service": "Other", 
+        "resource_id": "instance-00000001-0a802169-5918-4c28-9014-635ae6602cdb-tapd80be99a-b6", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tapd80be99a-b6", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDEtMGE4MDIxNjktNTkxOC00YzI4LTkwMTQtNjM1YWU2NjAyY2RiLXRh\ncGQ4MGJlOTlhLWI2K25ldHdvcmsub3V0Z29pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "f506380a49a24389ae0d8469274e3279", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_vcpe", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.outgoing.bytes.rate", 
+        "service": "service_vcpe", 
+        "resource_id": "instance-00000006-f71e7c55-2435-45a4-aa9a-073f97ceccbc-tap5afd137f-19", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tap5afd137f-19", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDYtZjcxZTdjNTUtMjQzNS00NWE0LWFhOWEtMDczZjk3Y2VjY2JjLXRh\ncDVhZmQxMzdmLTE5K25ldHdvcmsub3V0Z29pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "61a5d4b37b5d43718854916079760c0d", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_vcpe", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.outgoing.bytes.rate", 
+        "service": "service_vcpe", 
+        "resource_id": "instance-00000006-f71e7c55-2435-45a4-aa9a-073f97ceccbc-tap9a6306b4-7e", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tap9a6306b4-7e", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDYtZjcxZTdjNTUtMjQzNS00NWE0LWFhOWEtMDczZjk3Y2VjY2JjLXRh\ncDlhNjMwNmI0LTdlK25ldHdvcmsub3V0Z29pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "61a5d4b37b5d43718854916079760c0d", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_vcpe", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.outgoing.bytes.rate", 
+        "service": "service_vcpe", 
+        "resource_id": "instance-00000006-f71e7c55-2435-45a4-aa9a-073f97ceccbc-tapc59abc32-a4", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tapc59abc32-a4", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDYtZjcxZTdjNTUtMjQzNS00NWE0LWFhOWEtMDczZjk3Y2VjY2JjLXRh\ncGM1OWFiYzMyLWE0K25ldHdvcmsub3V0Z29pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "61a5d4b37b5d43718854916079760c0d", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_vcpe", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.outgoing.bytes.rate", 
+        "service": "service_vcpe", 
+        "resource_id": "instance-00000006-f71e7c55-2435-45a4-aa9a-073f97ceccbc-tapf1e00a14-22", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tapf1e00a14-22", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDYtZjcxZTdjNTUtMjQzNS00NWE0LWFhOWEtMDczZjk3Y2VjY2JjLXRh\ncGYxZTAwYTE0LTIyK25ldHdvcmsub3V0Z29pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "61a5d4b37b5d43718854916079760c0d", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_vbng", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.outgoing.bytes.rate", 
+        "service": "Other", 
+        "resource_id": "instance-00000007-98535996-e184-4996-a28e-61647e5d31d0-tapabf29bde-bc", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tapabf29bde-bc", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDctOTg1MzU5OTYtZTE4NC00OTk2LWEyOGUtNjE2NDdlNWQzMWQwLXRh\ncGFiZjI5YmRlLWJjK25ldHdvcmsub3V0Z29pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "c92cf450df4640d6952c0276730e5048", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_vbng", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.outgoing.bytes.rate", 
+        "service": "Other", 
+        "resource_id": "instance-00000007-98535996-e184-4996-a28e-61647e5d31d0-tapbc16b000-82", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tapbc16b000-82", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDctOTg1MzU5OTYtZTE4NC00OTk2LWEyOGUtNjE2NDdlNWQzMWQwLXRh\ncGJjMTZiMDAwLTgyK25ldHdvcmsub3V0Z29pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "c92cf450df4640d6952c0276730e5048", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_vbng", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.outgoing.bytes.rate", 
+        "service": "Other", 
+        "resource_id": "instance-00000007-98535996-e184-4996-a28e-61647e5d31d0-tape44bc1cc-46", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tape44bc1cc-46", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDctOTg1MzU5OTYtZTE4NC00OTk2LWEyOGUtNjE2NDdlNWQzMWQwLXRh\ncGU0NGJjMWNjLTQ2K25ldHdvcmsub3V0Z29pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "c92cf450df4640d6952c0276730e5048", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_vbng", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.outgoing.bytes.rate", 
+        "service": "Other", 
+        "resource_id": "instance-00000007-98535996-e184-4996-a28e-61647e5d31d0-tape4f20024-47", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tape4f20024-47", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDctOTg1MzU5OTYtZTE4NC00OTk2LWEyOGUtNjE2NDdlNWQzMWQwLXRh\ncGU0ZjIwMDI0LTQ3K25ldHdvcmsub3V0Z29pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "c92cf450df4640d6952c0276730e5048", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_clients", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.outgoing.bytes.rate", 
+        "service": "Other", 
+        "resource_id": "instance-00000003-f5c71396-9092-42da-91ec-434259bde2ef-tap3518d7f8-9f", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tap3518d7f8-9f", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDMtZjVjNzEzOTYtOTA5Mi00MmRhLTkxZWMtNDM0MjU5YmRlMmVmLXRh\ncDM1MThkN2Y4LTlmK25ldHdvcmsub3V0Z29pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "f884c440474b40808a8adcdece5f45ef", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_clients", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.outgoing.bytes.rate", 
+        "service": "Other", 
+        "resource_id": "instance-00000003-f5c71396-9092-42da-91ec-434259bde2ef-tap7409a9c5-e0", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tap7409a9c5-e0", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDMtZjVjNzEzOTYtOTA5Mi00MmRhLTkxZWMtNDM0MjU5YmRlMmVmLXRh\ncDc0MDlhOWM1LWUwK25ldHdvcmsub3V0Z29pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "f884c440474b40808a8adcdece5f45ef", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_clients", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.outgoing.bytes.rate", 
+        "service": "Other", 
+        "resource_id": "instance-00000003-f5c71396-9092-42da-91ec-434259bde2ef-tapde69764f-3d", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tapde69764f-3d", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDMtZjVjNzEzOTYtOTA5Mi00MmRhLTkxZWMtNDM0MjU5YmRlMmVmLXRh\ncGRlNjk3NjRmLTNkK25ldHdvcmsub3V0Z29pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "f884c440474b40808a8adcdece5f45ef", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_ceilometer", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.outgoing.bytes.rate", 
+        "service": "service_ceilometer", 
+        "resource_id": "instance-00000005-bdb0ff14-e848-446c-acb4-63e232487dc0-tap8d13e0d5-d2", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tap8d13e0d5-d2", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDUtYmRiMGZmMTQtZTg0OC00NDZjLWFjYjQtNjNlMjMyNDg3ZGMwLXRh\ncDhkMTNlMGQ1LWQyK25ldHdvcmsub3V0Z29pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "920d70bc63574552bbb3c3fb262ee1bc", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_ceilometer", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.outgoing.bytes.rate", 
+        "service": "service_ceilometer", 
+        "resource_id": "instance-00000005-bdb0ff14-e848-446c-acb4-63e232487dc0-tapa5d252a8-ae", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tapa5d252a8-ae", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDUtYmRiMGZmMTQtZTg0OC00NDZjLWFjYjQtNjNlMjMyNDg3ZGMwLXRh\ncGE1ZDI1MmE4LWFlK25ldHdvcmsub3V0Z29pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "920d70bc63574552bbb3c3fb262ee1bc", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "category": "Nova", 
+        "slice": "mysite_ceilometer", 
+        "user_id": "36e376b1072443758a0314f62fa8a414", 
+        "name": "network.outgoing.bytes.rate", 
+        "service": "service_ceilometer", 
+        "resource_id": "instance-00000005-bdb0ff14-e848-446c-acb4-63e232487dc0-tapb06a526b-03", 
+        "label": "", 
+        "source": "openstack", 
+        "resource_name": "tapb06a526b-03", 
+        "meter_id": "aW5zdGFuY2UtMDAwMDAwMDUtYmRiMGZmMTQtZTg0OC00NDZjLWFjYjQtNjNlMjMyNDg3ZGMwLXRh\ncGIwNmE1MjZiLTAzK25ldHdvcmsub3V0Z29pbmcuYnl0ZXMucmF0ZQ==\n", 
+        "project_id": "920d70bc63574552bbb3c3fb262ee1bc", 
+        "type": "gauge", 
+        "unit": "B/s", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }
+]
\ No newline at end of file
diff --git a/views/ngXosViews/ceilometerDashboard/src/sass/main.scss b/views/ngXosViews/ceilometerDashboard/src/sass/main.scss
new file mode 100644
index 0000000..b65f4aa
--- /dev/null
+++ b/views/ngXosViews/ceilometerDashboard/src/sass/main.scss
@@ -0,0 +1,5 @@
+@import '../../../../style/sass/lib/_variables.scss';
+
+#xosCeilometerDashboard {
+  
+}
\ No newline at end of file
diff --git a/views/ngXosViews/ceilometerDashboard/src/stats_mock.json b/views/ngXosViews/ceilometerDashboard/src/stats_mock.json
new file mode 100644
index 0000000..5dd083a
--- /dev/null
+++ b/views/ngXosViews/ceilometerDashboard/src/stats_mock.json
@@ -0,0 +1,950 @@
+[
+    {
+        "value": 1.0, 
+        "unit": "instance", 
+        "slice": "mysite_ceilometer", 
+        "name": "none", 
+        "service": "service_ceilometer", 
+        "resource_id": "c7f44959-490b-4d24-8043-66a096c7cae0", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "instance", 
+        "description": "Existence of instance"
+    }, 
+    {
+        "value": 1.0, 
+        "unit": "instance", 
+        "slice": "mysite_vcpe", 
+        "name": "none", 
+        "service": "service_vcpe", 
+        "resource_id": "afac5cb6-72c7-4c25-b281-7a442835b395", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "instance", 
+        "description": "Existence of instance"
+    }, 
+    {
+        "value": 1.0, 
+        "unit": "instance", 
+        "slice": "mysite_vbng", 
+        "name": "none", 
+        "service": "Other", 
+        "resource_id": "9ec8c981-feb8-46c1-a1f6-3438702ee170", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "instance", 
+        "description": "Existence of instance"
+    }, 
+    {
+        "value": 1.0, 
+        "unit": "instance", 
+        "slice": "mysite_onos_volt", 
+        "name": "none", 
+        "service": "service_ONOS_vOLT", 
+        "resource_id": "274134cc-700a-4392-8226-447a2f35cc1e", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "instance", 
+        "description": "Existence of instance"
+    }, 
+    {
+        "value": 1.0, 
+        "unit": "instance", 
+        "slice": "mysite_onos_vbng", 
+        "name": "none", 
+        "service": "service_ONOS_vBNG", 
+        "resource_id": "e66d524e-9ce1-4ec2-81bb-c95043fb8e4f", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "instance", 
+        "description": "Existence of instance"
+    }, 
+    {
+        "value": 1.0, 
+        "unit": "instance", 
+        "slice": "mysite_clients", 
+        "name": "none", 
+        "service": "Other", 
+        "resource_id": "a8214ed9-e222-484b-93c2-9245e4712a99", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "instance", 
+        "description": "Existence of instance"
+    }, 
+    {
+        "value": 1.0, 
+        "unit": "instance", 
+        "slice": "mysite_volt", 
+        "name": "none", 
+        "service": "Other", 
+        "resource_id": "7d483484-a660-4307-b081-af1e4dd07eae", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "instance", 
+        "description": "Existence of instance"
+    }, 
+    {
+        "value": 2048.0, 
+        "unit": "MB", 
+        "slice": "mysite_ceilometer", 
+        "name": "none", 
+        "service": "service_ceilometer", 
+        "resource_id": "c7f44959-490b-4d24-8043-66a096c7cae0", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "memory", 
+        "description": "Volume of RAM"
+    }, 
+    {
+        "value": 2048.0, 
+        "unit": "MB", 
+        "slice": "mysite_vcpe", 
+        "name": "none", 
+        "service": "service_vcpe", 
+        "resource_id": "afac5cb6-72c7-4c25-b281-7a442835b395", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "memory", 
+        "description": "Volume of RAM"
+    }, 
+    {
+        "value": 2048.0, 
+        "unit": "MB", 
+        "slice": "mysite_vbng", 
+        "name": "none", 
+        "service": "Other", 
+        "resource_id": "9ec8c981-feb8-46c1-a1f6-3438702ee170", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "memory", 
+        "description": "Volume of RAM"
+    }, 
+    {
+        "value": 2048.0, 
+        "unit": "MB", 
+        "slice": "mysite_onos_volt", 
+        "name": "none", 
+        "service": "service_ONOS_vOLT", 
+        "resource_id": "274134cc-700a-4392-8226-447a2f35cc1e", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "memory", 
+        "description": "Volume of RAM"
+    }, 
+    {
+        "value": 2048.0, 
+        "unit": "MB", 
+        "slice": "mysite_onos_vbng", 
+        "name": "none", 
+        "service": "service_ONOS_vBNG", 
+        "resource_id": "e66d524e-9ce1-4ec2-81bb-c95043fb8e4f", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "memory", 
+        "description": "Volume of RAM"
+    }, 
+    {
+        "value": 2048.0, 
+        "unit": "MB", 
+        "slice": "mysite_clients", 
+        "name": "none", 
+        "service": "Other", 
+        "resource_id": "a8214ed9-e222-484b-93c2-9245e4712a99", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "memory", 
+        "description": "Volume of RAM"
+    }, 
+    {
+        "value": 2048.0, 
+        "unit": "MB", 
+        "slice": "mysite_volt", 
+        "name": "none", 
+        "service": "Other", 
+        "resource_id": "7d483484-a660-4307-b081-af1e4dd07eae", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "memory", 
+        "description": "Volume of RAM"
+    }, 
+    {
+        "value": 1507.9379310344827, 
+        "unit": "MB", 
+        "slice": "mysite_ceilometer", 
+        "name": "none", 
+        "service": "service_ceilometer", 
+        "resource_id": "c7f44959-490b-4d24-8043-66a096c7cae0", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "memory.usage", 
+        "description": "Volume of RAM used"
+    }, 
+    {
+        "value": 374.6965517241379, 
+        "unit": "MB", 
+        "slice": "mysite_vcpe", 
+        "name": "none", 
+        "service": "service_vcpe", 
+        "resource_id": "afac5cb6-72c7-4c25-b281-7a442835b395", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "memory.usage", 
+        "description": "Volume of RAM used"
+    }, 
+    {
+        "value": 375.1655172413793, 
+        "unit": "MB", 
+        "slice": "mysite_vbng", 
+        "name": "none", 
+        "service": "Other", 
+        "resource_id": "9ec8c981-feb8-46c1-a1f6-3438702ee170", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "memory.usage", 
+        "description": "Volume of RAM used"
+    }, 
+    {
+        "value": 1786.7310344827586, 
+        "unit": "MB", 
+        "slice": "mysite_onos_volt", 
+        "name": "none", 
+        "service": "service_ONOS_vOLT", 
+        "resource_id": "274134cc-700a-4392-8226-447a2f35cc1e", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "memory.usage", 
+        "description": "Volume of RAM used"
+    }, 
+    {
+        "value": 1797.2413793103449, 
+        "unit": "MB", 
+        "slice": "mysite_onos_vbng", 
+        "name": "none", 
+        "service": "service_ONOS_vBNG", 
+        "resource_id": "e66d524e-9ce1-4ec2-81bb-c95043fb8e4f", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "memory.usage", 
+        "description": "Volume of RAM used"
+    }, 
+    {
+        "value": 376.36551724137934, 
+        "unit": "MB", 
+        "slice": "mysite_clients", 
+        "name": "none", 
+        "service": "Other", 
+        "resource_id": "a8214ed9-e222-484b-93c2-9245e4712a99", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "memory.usage", 
+        "description": "Volume of RAM used"
+    }, 
+    {
+        "value": 373.5448275862069, 
+        "unit": "MB", 
+        "slice": "mysite_volt", 
+        "name": "none", 
+        "service": "Other", 
+        "resource_id": "7d483484-a660-4307-b081-af1e4dd07eae", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "memory.usage", 
+        "description": "Volume of RAM used"
+    }, 
+    {
+        "value": 194620344827.5862, 
+        "unit": "ns", 
+        "slice": "mysite_ceilometer", 
+        "name": "none", 
+        "service": "service_ceilometer", 
+        "resource_id": "c7f44959-490b-4d24-8043-66a096c7cae0", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "cpu", 
+        "description": "CPU time used"
+    }, 
+    {
+        "value": 93601310344.82759, 
+        "unit": "ns", 
+        "slice": "mysite_vcpe", 
+        "name": "none", 
+        "service": "service_vcpe", 
+        "resource_id": "afac5cb6-72c7-4c25-b281-7a442835b395", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "cpu", 
+        "description": "CPU time used"
+    }, 
+    {
+        "value": 93402206896.55173, 
+        "unit": "ns", 
+        "slice": "mysite_vbng", 
+        "name": "none", 
+        "service": "Other", 
+        "resource_id": "9ec8c981-feb8-46c1-a1f6-3438702ee170", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "cpu", 
+        "description": "CPU time used"
+    }, 
+    {
+        "value": 4394690965517.241, 
+        "unit": "ns", 
+        "slice": "mysite_onos_volt", 
+        "name": "none", 
+        "service": "service_ONOS_vOLT", 
+        "resource_id": "274134cc-700a-4392-8226-447a2f35cc1e", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "cpu", 
+        "description": "CPU time used"
+    }, 
+    {
+        "value": 4025309517241.3794, 
+        "unit": "ns", 
+        "slice": "mysite_onos_vbng", 
+        "name": "none", 
+        "service": "service_ONOS_vBNG", 
+        "resource_id": "e66d524e-9ce1-4ec2-81bb-c95043fb8e4f", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "cpu", 
+        "description": "CPU time used"
+    }, 
+    {
+        "value": 90704896551.72414, 
+        "unit": "ns", 
+        "slice": "mysite_clients", 
+        "name": "none", 
+        "service": "Other", 
+        "resource_id": "a8214ed9-e222-484b-93c2-9245e4712a99", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "cpu", 
+        "description": "CPU time used"
+    }, 
+    {
+        "value": 93930827586.2069, 
+        "unit": "ns", 
+        "slice": "mysite_volt", 
+        "name": "none", 
+        "service": "Other", 
+        "resource_id": "7d483484-a660-4307-b081-af1e4dd07eae", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "cpu", 
+        "description": "CPU time used"
+    }, 
+    {
+        "value": 0.2539938837459742, 
+        "unit": "%", 
+        "slice": "mysite_ceilometer", 
+        "name": "none", 
+        "service": "service_ceilometer", 
+        "resource_id": "c7f44959-490b-4d24-8043-66a096c7cae0", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "cpu_util", 
+        "description": "Average CPU utilization"
+    }, 
+    {
+        "value": 0.1430115727449207, 
+        "unit": "%", 
+        "slice": "mysite_vcpe", 
+        "name": "none", 
+        "service": "service_vcpe", 
+        "resource_id": "afac5cb6-72c7-4c25-b281-7a442835b395", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "cpu_util", 
+        "description": "Average CPU utilization"
+    }, 
+    {
+        "value": 0.14234621932639643, 
+        "unit": "%", 
+        "slice": "mysite_vbng", 
+        "name": "none", 
+        "service": "Other", 
+        "resource_id": "9ec8c981-feb8-46c1-a1f6-3438702ee170", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "cpu_util", 
+        "description": "Average CPU utilization"
+    }, 
+    {
+        "value": 9.501434897077173, 
+        "unit": "%", 
+        "slice": "mysite_onos_volt", 
+        "name": "none", 
+        "service": "service_ONOS_vOLT", 
+        "resource_id": "274134cc-700a-4392-8226-447a2f35cc1e", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "cpu_util", 
+        "description": "Average CPU utilization"
+    }, 
+    {
+        "value": 8.59252727701459, 
+        "unit": "%", 
+        "slice": "mysite_onos_vbng", 
+        "name": "none", 
+        "service": "service_ONOS_vBNG", 
+        "resource_id": "e66d524e-9ce1-4ec2-81bb-c95043fb8e4f", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "cpu_util", 
+        "description": "Average CPU utilization"
+    }, 
+    {
+        "value": 0.13846207922030151, 
+        "unit": "%", 
+        "slice": "mysite_clients", 
+        "name": "none", 
+        "service": "Other", 
+        "resource_id": "a8214ed9-e222-484b-93c2-9245e4712a99", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "cpu_util", 
+        "description": "Average CPU utilization"
+    }, 
+    {
+        "value": 0.14287395279840676, 
+        "unit": "%", 
+        "slice": "mysite_volt", 
+        "name": "none", 
+        "service": "Other", 
+        "resource_id": "7d483484-a660-4307-b081-af1e4dd07eae", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "cpu_util", 
+        "description": "Average CPU utilization"
+    }, 
+    {
+        "value": 88.53419771575258, 
+        "unit": "B/s", 
+        "slice": "mysite_ceilometer", 
+        "name": "none", 
+        "service": "service_ceilometer", 
+        "resource_id": "instance-0000001b-c7f44959-490b-4d24-8043-66a096c7cae0-tapcadfbd73-5b", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.incoming.bytes.rate", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "value": 0.009455996028375395, 
+        "unit": "B/s", 
+        "slice": "mysite_ceilometer", 
+        "name": "none", 
+        "service": "service_ceilometer", 
+        "resource_id": "instance-0000001b-c7f44959-490b-4d24-8043-66a096c7cae0-tap972eb016-96", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.incoming.bytes.rate", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "value": 0.009455996028375395, 
+        "unit": "B/s", 
+        "slice": "mysite_ceilometer", 
+        "name": "none", 
+        "service": "service_ceilometer", 
+        "resource_id": "instance-0000001b-c7f44959-490b-4d24-8043-66a096c7cae0-tapf56382ad-45", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.incoming.bytes.rate", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "value": 124.74842906323501, 
+        "unit": "B/s", 
+        "slice": "mysite_vcpe", 
+        "name": "none", 
+        "service": "service_vcpe", 
+        "resource_id": "instance-0000001a-afac5cb6-72c7-4c25-b281-7a442835b395-tap79d13f74-62", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.incoming.bytes.rate", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "value": 0.017425896307365425, 
+        "unit": "B/s", 
+        "slice": "mysite_vcpe", 
+        "name": "none", 
+        "service": "service_vcpe", 
+        "resource_id": "instance-0000001a-afac5cb6-72c7-4c25-b281-7a442835b395-tap25ae020a-23", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.incoming.bytes.rate", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "value": 0.0174337765740103, 
+        "unit": "B/s", 
+        "slice": "mysite_vcpe", 
+        "name": "none", 
+        "service": "service_vcpe", 
+        "resource_id": "instance-0000001a-afac5cb6-72c7-4c25-b281-7a442835b395-tap8382609c-7c", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.incoming.bytes.rate", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "value": 0.009424851354967827, 
+        "unit": "B/s", 
+        "slice": "mysite_vcpe", 
+        "name": "none", 
+        "service": "service_vcpe", 
+        "resource_id": "instance-0000001a-afac5cb6-72c7-4c25-b281-7a442835b395-tap7bbe02e0-09", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.incoming.bytes.rate", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "value": 127.2159155680703, 
+        "unit": "B/s", 
+        "slice": "mysite_vbng", 
+        "name": "none", 
+        "service": "Other", 
+        "resource_id": "instance-0000001c-9ec8c981-feb8-46c1-a1f6-3438702ee170-tap308ba38c-64", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.incoming.bytes.rate", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "value": 1.996809016615307, 
+        "unit": "B/s", 
+        "slice": "mysite_vbng", 
+        "name": "none", 
+        "service": "Other", 
+        "resource_id": "instance-0000001c-9ec8c981-feb8-46c1-a1f6-3438702ee170-tap2aadc958-57", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.incoming.bytes.rate", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "value": 0.00944055944055944, 
+        "unit": "B/s", 
+        "slice": "mysite_vbng", 
+        "name": "none", 
+        "service": "Other", 
+        "resource_id": "instance-0000001c-9ec8c981-feb8-46c1-a1f6-3438702ee170-tap0b518c8d-01", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.incoming.bytes.rate", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "value": 0.017428347945877158, 
+        "unit": "B/s", 
+        "slice": "mysite_vbng", 
+        "name": "none", 
+        "service": "Other", 
+        "resource_id": "instance-0000001c-9ec8c981-feb8-46c1-a1f6-3438702ee170-tapaf0c7436-e8", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.incoming.bytes.rate", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "value": 0.009471769187962845, 
+        "unit": "B/s", 
+        "slice": "mysite_onos_volt", 
+        "name": "none", 
+        "service": "service_ONOS_vOLT", 
+        "resource_id": "instance-00000017-274134cc-700a-4392-8226-447a2f35cc1e-tap4b98f4d2-7e", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.incoming.bytes.rate", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "value": 33.618374055863, 
+        "unit": "B/s", 
+        "slice": "mysite_onos_volt", 
+        "name": "none", 
+        "service": "service_ONOS_vOLT", 
+        "resource_id": "instance-00000017-274134cc-700a-4392-8226-447a2f35cc1e-tap35a9b09a-29", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.incoming.bytes.rate", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "value": 0.009448122592881327, 
+        "unit": "B/s", 
+        "slice": "mysite_onos_vbng", 
+        "name": "none", 
+        "service": "service_ONOS_vBNG", 
+        "resource_id": "instance-00000019-e66d524e-9ce1-4ec2-81bb-c95043fb8e4f-tap6717e37b-5a", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.incoming.bytes.rate", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "value": 33.6291738301644, 
+        "unit": "B/s", 
+        "slice": "mysite_onos_vbng", 
+        "name": "none", 
+        "service": "service_ONOS_vBNG", 
+        "resource_id": "instance-00000019-e66d524e-9ce1-4ec2-81bb-c95043fb8e4f-tap35b38817-7f", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.incoming.bytes.rate", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "value": 0.009463869463869463, 
+        "unit": "B/s", 
+        "slice": "mysite_clients", 
+        "name": "none", 
+        "service": "Other", 
+        "resource_id": "instance-00000018-a8214ed9-e222-484b-93c2-9245e4712a99-tapaf9418d8-68", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.incoming.bytes.rate", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "value": 0.017437164857185466, 
+        "unit": "B/s", 
+        "slice": "mysite_clients", 
+        "name": "none", 
+        "service": "Other", 
+        "resource_id": "instance-00000018-a8214ed9-e222-484b-93c2-9245e4712a99-tap56d0c6f9-27", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.incoming.bytes.rate", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "value": 124.61289583768621, 
+        "unit": "B/s", 
+        "slice": "mysite_clients", 
+        "name": "none", 
+        "service": "Other", 
+        "resource_id": "instance-00000018-a8214ed9-e222-484b-93c2-9245e4712a99-tap31f27f17-47", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.incoming.bytes.rate", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "value": 123.65339047759299, 
+        "unit": "B/s", 
+        "slice": "mysite_volt", 
+        "name": "none", 
+        "service": "Other", 
+        "resource_id": "instance-0000001d-7d483484-a660-4307-b081-af1e4dd07eae-tap4894ed8a-51", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.incoming.bytes.rate", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "value": 0.009440585664408507, 
+        "unit": "B/s", 
+        "slice": "mysite_volt", 
+        "name": "none", 
+        "service": "Other", 
+        "resource_id": "instance-0000001d-7d483484-a660-4307-b081-af1e4dd07eae-tap31c8ec21-34", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.incoming.bytes.rate", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "value": 0.01743467844779237, 
+        "unit": "B/s", 
+        "slice": "mysite_volt", 
+        "name": "none", 
+        "service": "Other", 
+        "resource_id": "instance-0000001d-7d483484-a660-4307-b081-af1e4dd07eae-tap2605ab77-0a", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.incoming.bytes.rate", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "value": 0.013442333959863174, 
+        "unit": "B/s", 
+        "slice": "mysite_volt", 
+        "name": "none", 
+        "service": "Other", 
+        "resource_id": "instance-0000001d-7d483484-a660-4307-b081-af1e4dd07eae-tapeea51a4b-f3", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.incoming.bytes.rate", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface"
+    }, 
+    {
+        "value": 22.145300578664518, 
+        "unit": "B/s", 
+        "slice": "mysite_ceilometer", 
+        "name": "none", 
+        "service": "service_ceilometer", 
+        "resource_id": "instance-0000001b-c7f44959-490b-4d24-8043-66a096c7cae0-tapcadfbd73-5b", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.outgoing.bytes.rate", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "value": 0.008951048951048951, 
+        "unit": "B/s", 
+        "slice": "mysite_ceilometer", 
+        "name": "none", 
+        "service": "service_ceilometer", 
+        "resource_id": "instance-0000001b-c7f44959-490b-4d24-8043-66a096c7cae0-tap972eb016-96", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.outgoing.bytes.rate", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "value": 0.008951048951048951, 
+        "unit": "B/s", 
+        "slice": "mysite_ceilometer", 
+        "name": "none", 
+        "service": "service_ceilometer", 
+        "resource_id": "instance-0000001b-c7f44959-490b-4d24-8043-66a096c7cae0-tapf56382ad-45", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.outgoing.bytes.rate", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "value": 1.3187296037296037, 
+        "unit": "B/s", 
+        "slice": "mysite_vcpe", 
+        "name": "none", 
+        "service": "service_vcpe", 
+        "resource_id": "instance-0000001a-afac5cb6-72c7-4c25-b281-7a442835b395-tap79d13f74-62", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.outgoing.bytes.rate", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "value": 0.008951048951048951, 
+        "unit": "B/s", 
+        "slice": "mysite_vcpe", 
+        "name": "none", 
+        "service": "service_vcpe", 
+        "resource_id": "instance-0000001a-afac5cb6-72c7-4c25-b281-7a442835b395-tap25ae020a-23", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.outgoing.bytes.rate", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "value": 0.008951048951048951, 
+        "unit": "B/s", 
+        "slice": "mysite_vcpe", 
+        "name": "none", 
+        "service": "service_vcpe", 
+        "resource_id": "instance-0000001a-afac5cb6-72c7-4c25-b281-7a442835b395-tap8382609c-7c", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.outgoing.bytes.rate", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "value": 0.008951048951048951, 
+        "unit": "B/s", 
+        "slice": "mysite_vcpe", 
+        "name": "none", 
+        "service": "service_vcpe", 
+        "resource_id": "instance-0000001a-afac5cb6-72c7-4c25-b281-7a442835b395-tap7bbe02e0-09", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.outgoing.bytes.rate", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "value": 3.087960372960373, 
+        "unit": "B/s", 
+        "slice": "mysite_vbng", 
+        "name": "none", 
+        "service": "Other", 
+        "resource_id": "instance-0000001c-9ec8c981-feb8-46c1-a1f6-3438702ee170-tap308ba38c-64", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.outgoing.bytes.rate", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "value": 0.008951048951048951, 
+        "unit": "B/s", 
+        "slice": "mysite_vbng", 
+        "name": "none", 
+        "service": "Other", 
+        "resource_id": "instance-0000001c-9ec8c981-feb8-46c1-a1f6-3438702ee170-tap2aadc958-57", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.outgoing.bytes.rate", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "value": 0.008951048951048951, 
+        "unit": "B/s", 
+        "slice": "mysite_vbng", 
+        "name": "none", 
+        "service": "Other", 
+        "resource_id": "instance-0000001c-9ec8c981-feb8-46c1-a1f6-3438702ee170-tap0b518c8d-01", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.outgoing.bytes.rate", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "value": 0.008951048951048951, 
+        "unit": "B/s", 
+        "slice": "mysite_vbng", 
+        "name": "none", 
+        "service": "Other", 
+        "resource_id": "instance-0000001c-9ec8c981-feb8-46c1-a1f6-3438702ee170-tapaf0c7436-e8", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.outgoing.bytes.rate", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "value": 0.008951048951048951, 
+        "unit": "B/s", 
+        "slice": "mysite_onos_volt", 
+        "name": "none", 
+        "service": "service_ONOS_vOLT", 
+        "resource_id": "instance-00000017-274134cc-700a-4392-8226-447a2f35cc1e-tap4b98f4d2-7e", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.outgoing.bytes.rate", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "value": 0.68399416060279, 
+        "unit": "B/s", 
+        "slice": "mysite_onos_volt", 
+        "name": "none", 
+        "service": "service_ONOS_vOLT", 
+        "resource_id": "instance-00000017-274134cc-700a-4392-8226-447a2f35cc1e-tap35a9b09a-29", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.outgoing.bytes.rate", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "value": 0.008951048951048951, 
+        "unit": "B/s", 
+        "slice": "mysite_onos_vbng", 
+        "name": "none", 
+        "service": "service_ONOS_vBNG", 
+        "resource_id": "instance-00000019-e66d524e-9ce1-4ec2-81bb-c95043fb8e4f-tap6717e37b-5a", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.outgoing.bytes.rate", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "value": 0.5502331002331002, 
+        "unit": "B/s", 
+        "slice": "mysite_onos_vbng", 
+        "name": "none", 
+        "service": "service_ONOS_vBNG", 
+        "resource_id": "instance-00000019-e66d524e-9ce1-4ec2-81bb-c95043fb8e4f-tap35b38817-7f", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.outgoing.bytes.rate", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "value": 0.008951048951048951, 
+        "unit": "B/s", 
+        "slice": "mysite_clients", 
+        "name": "none", 
+        "service": "Other", 
+        "resource_id": "instance-00000018-a8214ed9-e222-484b-93c2-9245e4712a99-tapaf9418d8-68", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.outgoing.bytes.rate", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "value": 0.008951048951048951, 
+        "unit": "B/s", 
+        "slice": "mysite_clients", 
+        "name": "none", 
+        "service": "Other", 
+        "resource_id": "instance-00000018-a8214ed9-e222-484b-93c2-9245e4712a99-tap56d0c6f9-27", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.outgoing.bytes.rate", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "value": 1.2715034965034964, 
+        "unit": "B/s", 
+        "slice": "mysite_clients", 
+        "name": "none", 
+        "service": "Other", 
+        "resource_id": "instance-00000018-a8214ed9-e222-484b-93c2-9245e4712a99-tap31f27f17-47", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.outgoing.bytes.rate", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "value": 0.441946386946387, 
+        "unit": "B/s", 
+        "slice": "mysite_volt", 
+        "name": "none", 
+        "service": "Other", 
+        "resource_id": "instance-0000001d-7d483484-a660-4307-b081-af1e4dd07eae-tap4894ed8a-51", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.outgoing.bytes.rate", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "value": 0.008951048951048951, 
+        "unit": "B/s", 
+        "slice": "mysite_volt", 
+        "name": "none", 
+        "service": "Other", 
+        "resource_id": "instance-0000001d-7d483484-a660-4307-b081-af1e4dd07eae-tap31c8ec21-34", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.outgoing.bytes.rate", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "value": 0.008951048951048951, 
+        "unit": "B/s", 
+        "slice": "mysite_volt", 
+        "name": "none", 
+        "service": "Other", 
+        "resource_id": "instance-0000001d-7d483484-a660-4307-b081-af1e4dd07eae-tap2605ab77-0a", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.outgoing.bytes.rate", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }, 
+    {
+        "value": 0.008951048951048951, 
+        "unit": "B/s", 
+        "slice": "mysite_volt", 
+        "name": "none", 
+        "service": "Other", 
+        "resource_id": "instance-0000001d-7d483484-a660-4307-b081-af1e4dd07eae-tapeea51a4b-f3", 
+        "time": "2015-12-10T00:44:10", 
+        "type": "Nova", 
+        "meter": "network.outgoing.bytes.rate", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface"
+    }
+]
\ No newline at end of file
diff --git a/views/ngXosViews/ceilometerDashboard/src/templates/accordion-group.html b/views/ngXosViews/ceilometerDashboard/src/templates/accordion-group.html
new file mode 100644
index 0000000..62e0ce9
--- /dev/null
+++ b/views/ngXosViews/ceilometerDashboard/src/templates/accordion-group.html
@@ -0,0 +1,10 @@
+<div class="panel {{panelClass || 'panel-default'}}">
+  <div class="panel-heading" ng-keypress="toggleOpen($event)">
+    <h5>
+      <a href tabindex="0" class="accordion-toggle" ng-click="toggleOpen()" uib-accordion-transclude="heading"><span ng-class="{'text-muted': isDisabled}">{{heading}}</span></a>
+    </h5>
+  </div>
+  <div class="panel-collapse collapse" uib-collapse="!isOpen">
+	  <div class="panel-body" ng-transclude></div>
+  </div>
+</div>
diff --git a/views/ngXosViews/ceilometerDashboard/src/templates/accordion.html b/views/ngXosViews/ceilometerDashboard/src/templates/accordion.html
new file mode 100644
index 0000000..ba428f3
--- /dev/null
+++ b/views/ngXosViews/ceilometerDashboard/src/templates/accordion.html
@@ -0,0 +1 @@
+<div class="panel-group" ng-transclude></div>
\ No newline at end of file
diff --git a/views/ngXosViews/ceilometerDashboard/src/templates/ceilometer-dashboard.tpl.html b/views/ngXosViews/ceilometerDashboard/src/templates/ceilometer-dashboard.tpl.html
new file mode 100644
index 0000000..2805dbd
--- /dev/null
+++ b/views/ngXosViews/ceilometerDashboard/src/templates/ceilometer-dashboard.tpl.html
@@ -0,0 +1,120 @@
+<div class="row">
+  <div class="col-sm-10">
+    <h3>XOS Monitoring Statistics</h3>
+  </div>
+  <div class="col-xs-2 text-right">
+    <a href="" class="btn btn-default" 
+      ng-show="vm.selectedSlice && !vm.showStats"
+      ng-click="vm.showStats = true">
+      <i class="glyphicon glyphicon-transfer"></i>
+    </a>
+    <a href="" class="btn btn-default" 
+      ng-show="vm.selectedSlice && vm.showStats"
+      ng-click="vm.showStats = false">
+      <i class="glyphicon glyphicon-transfer"></i>
+    </a>
+  </div>
+</div>
+
+<div class="row" ng-show="vm.loader">
+  <div class="col-xs-12">
+    <div class="loader">Loading</div>
+  </div>
+</div>
+
+<section ng-hide="vm.loader" ng-class="{animate: !vm.loader}">
+  <div class="row">
+    <div class="col-sm-3 service-list">
+        <h4>XOS Service: </h4>
+        <uib-accordion close-others="true" template-url="templates/accordion.html">
+          <uib-accordion-group
+            ng-repeat="service in vm.services | orderBy:'-service'"
+            template-url="templates/accordion-group.html"
+            is-open="vm.accordion.open[service.service]"
+            heading="{{service.service}}">
+            <h5>Slices:</h5>
+            <a ng-repeat="slice in service.slices" 
+              ng-class="{active: slice.slice === vm.selectedSlice}"
+              ng-click="vm.loadSliceMeter(slice, service.service)"
+              href="#" class="list-group-item" >
+              {{slice.slice}} <i class="glyphicon glyphicon-chevron-right pull-right"></i>
+            </a>
+          </uib-accordion-group>
+        </uib-accordion>
+    </div>
+    <section class="side-container col-sm-9">
+      <div class="row">
+        <!-- STATS -->
+        <article ng-hide="!vm.showStats" class="stats animate-slide-left">
+          <div class="col-xs-12">
+            <div class="list-group">
+              <div class="list-group-item">
+                <h4>Stats</h4>
+              </div>
+              <div class="list-group-item">
+                <ceilometer-stats ng-if="vm.selectedSlice" name="vm.selectedSlice" tenant="vm.selectedTenant"></ceilometer-stats>
+              </div>
+            </div>
+          </div>
+        </article>
+        <!-- METERS -->
+        <article ng-hide="vm.showStats" class="meters animate-slide-left">
+          <div class="alert alert-danger" ng-show="vm.ceilometerError">
+            {{vm.ceilometerError}}
+          </div>
+          <div class="col-sm-4 animate-slide-left" ng-hide="!vm.selectedSlice">
+            <div class="list-group">
+              <div class="list-group-item">
+                <h4>Resources</h4>
+              </div>
+              <a href="#" 
+                ng-click="vm.selectMeters(meters, resource)" 
+                class="list-group-item" 
+                ng-repeat="(resource, meters) in vm.selectedResources" 
+                ng-class="{active: resource === vm.selectedResource}">
+                {{resource}} <i class="glyphicon glyphicon-chevron-right pull-right"></i>
+              </a>
+            </div>
+          </div>
+          <div class="col-sm-8 animate-slide-left" ng-hide="!vm.selectedMeters">
+            <div class="list-group">
+              <div class="list-group-item">
+                <h4>Meters</h4>
+              </div>
+              <div class="list-group-item">
+                <div class="row">
+                  <div class="col-xs-6">
+                    <label>Name:</label>
+                  </div>
+                  <div class="col-xs-3">
+                    <label>Unit:</label>
+                  </div>
+                  <div class="col-xs-3"></div>
+                </div>
+                <div class="row" ng-repeat="meter in vm.selectedMeters" style="margin-bottom: 10px;">
+                  <div class="col-xs-6">
+                    {{meter.name}}
+                  </div>
+                  <div class="col-xs-3">
+                    {{meter.unit}}
+                  </div>
+                  <div class="col-xs-3">
+                    <!-- tenant: meter.resource_id -->
+                    <a ui-sref="samples({name: meter.name, tenant: meter.resource_id})" class="btn btn-primary">
+                      <i class="glyphicon glyphicon-search"></i>
+                    </a>
+                  </div>
+                </div>
+              </div>
+            </div>
+          </div>
+        </article>
+      </div>
+    </section>
+  </div>
+</section>
+<section ng-if="!vm.loader && vm.error">
+  <div class="alert alert-danger">
+    {{vm.error}}
+  </div>
+</section>
diff --git a/views/ngXosViews/ceilometerDashboard/src/templates/ceilometer-samples.tpl.html b/views/ngXosViews/ceilometerDashboard/src/templates/ceilometer-samples.tpl.html
new file mode 100644
index 0000000..b279123
--- /dev/null
+++ b/views/ngXosViews/ceilometerDashboard/src/templates/ceilometer-samples.tpl.html
@@ -0,0 +1,54 @@
+<!-- <pre>{{ vm | json}}</pre> -->
+
+<div class="row">
+  <div class="col-xs-10">
+    <h1>{{vm.name | uppercase}}</h1>
+  </div>
+  <div class="col-xs-2">
+    <a ui-sref="ceilometerDashboard" class="btn btn-primary pull-right">
+      <i class="glyphicon glyphicon-arrow-left"></i> Back to list
+    </a>
+  </div>
+</div>
+<div class="row" ng-show="vm.loader">
+  <div class="col-xs-12">
+    <div class="loader">Loading</div>
+  </div>
+</div>
+<section ng-if="!vm.loader && !vm.error">
+  <div class="row">
+    <form class="form-inline col-xs-8" ng-submit="vm.addMeterToChart(vm.addMeterValue)">
+      <select ng-model="vm.addMeterValue" class="form-control" ng-options="resource.id as resource.name for resource in vm.sampleLabels"></select>
+      <button class="btn btn-success"> 
+        <i class="glyphicon glyphicon-plus"></i> Add
+      </button>
+    </form>
+    <div class="col-xs-4 text-right">
+      <a ng-click="vm.chartType = 'line'" class="btn" ng-class="{'btn-default': vm.chartType != 'bar', 'btn-primary': vm.chartType == 'line'}">Lines</a>
+      <a ng-click="vm.chartType = 'bar'" class="btn" ng-class="{'btn-default': vm.chartType != 'line', 'btn-primary': vm.chartType == 'bar'}">Bars</a>
+    </div>
+  </div>
+  <div class="row" ng-if="!vm.loader">
+    <div class="col-xs-12">
+      <canvas ng-if="vm.chartType === 'line'" id="line" class="chart chart-line" chart-data="vm.chart.data" chart-options="{datasetFill: false}"
+        chart-labels="vm.chart.labels" chart-legend="false" chart-series="vm.chart.series">
+      </canvas>
+      <canvas ng-if="vm.chartType === 'bar'" id="bar" class="chart chart-bar" chart-data="vm.chart.data"
+        chart-labels="vm.chart.labels" chart-legend="false" chart-series="vm.chart.series">
+      </canvas>
+      <!-- <pre>{{vm.chartMeters | json}}</pre> -->
+    </div>
+  </div>
+  <div class="row" ng-if="!vm.loader">
+    <div class="col-xs-12">
+      <a ng-click="vm.removeFromChart(meter)" class="btn btn-chart" ng-style="{'background-color': vm.chartColors[$index]}" ng-repeat="meter in vm.chartMeters">
+        {{meter.resource_name || meter.resource_id}}
+      </a>
+    </div>
+  </div>
+</section>
+<section ng-if="!vm.loader && vm.error">
+  <div class="alert alert-danger">
+    {{vm.error}}
+  </div>
+</section>
\ No newline at end of file
diff --git a/views/ngXosViews/ceilometerDashboard/src/templates/ceilometer-stats.tpl.html b/views/ngXosViews/ceilometerDashboard/src/templates/ceilometer-stats.tpl.html
new file mode 100644
index 0000000..e07a87a
--- /dev/null
+++ b/views/ngXosViews/ceilometerDashboard/src/templates/ceilometer-stats.tpl.html
@@ -0,0 +1,58 @@
+<div ng-show="vm.loader" class="loader">Loading</div>
+
+<section ng-if="!vm.loader && !vm.error">
+
+  <div class="alert alert-danger" ng-if="vm.stats.length == 0">
+    No result
+  </div>  
+
+  <table class="table" ng-if="vm.stats.length > 0">
+    <tr>
+      <th>
+        <a ng-click="(order == 'category') ? order = '-category' : order = 'category'">Type:</a>
+      </th>
+      <th>
+        <a ng-click="(order == 'resource_name') ? order = '-resource_name' : order = 'resource_name'">Resource:</a>
+      </th>
+      <th>
+        <a ng-click="(order == 'meter') ? order = '-meter' : order = 'meter'">Meter:</a>
+      </th>
+      <th>
+        Unit:
+      </th>
+      <th>
+        Value:
+      </th>
+    </tr>
+    <!-- <tr>
+      <td>
+        <input type="text" ng-model="query.category">
+      </td>
+      <td>
+        <input type="text" ng-model="query.resource_name">
+      </td>
+      <td>
+        <input type="text" ng-model="query.meter">
+      </td>
+      <td>
+        <input type="text" ng-model="query.unit">
+      </td>
+      <td>
+        <input type="text" ng-model="query.value">
+      </td>
+    </tr> -->
+    <tr ng-repeat="item in vm.stats | orderBy:order">
+      <td>{{item.category}}</td>
+      <td>{{item.resource_name}}</td>
+      <td>{{item.meter}}</td>
+      <td>{{item.unit}}</td>
+      <td>{{item.value}}</td>
+    </tr>
+  </table>
+</section>
+
+<section ng-if="!vm.loader && vm.error">
+  <div class="alert alert-danger">
+    {{vm.error}}
+  </div>
+</section>
diff --git a/views/ngXosViews/ceilometerDashboard/src/templates/users-list.tpl.html b/views/ngXosViews/ceilometerDashboard/src/templates/users-list.tpl.html
new file mode 100644
index 0000000..1fee0e2
--- /dev/null
+++ b/views/ngXosViews/ceilometerDashboard/src/templates/users-list.tpl.html
@@ -0,0 +1 @@
+<xos-table config="vm.tableConfig" data="vm.users"></xos-table>
\ No newline at end of file
diff --git a/views/ngXosViews/ceilometerDashboard/teone@clnode015.clemson.cloudlab.us b/views/ngXosViews/ceilometerDashboard/teone@clnode015.clemson.cloudlab.us
new file mode 100644
index 0000000..8e990a2
--- /dev/null
+++ b/views/ngXosViews/ceilometerDashboard/teone@clnode015.clemson.cloudlab.us
@@ -0,0 +1,20 @@
+<meta http-equiv="X-UA-Compatible" content="IE=edge">
+<meta name="viewport" content="width=device-width, initial-scale=1, max-scale=1">
+<!-- browserSync -->
+
+<!-- inject:css -->
+<link rel="stylesheet" href="/css/ceilometerDashboard.css">
+<link rel="stylesheet" href="/css/dev.css">
+<!-- endinject -->
+<link rel="stylesheet" href="css/ceilometerDashboard.css">
+<div id="xosCeilometerDashboard">
+  <div ui-view ng-class="stateName"></div>
+</div>
+
+
+<script src="vendor/ui.bootstrap/src/collapse/collapse.js"></script>
+<script src="vendor/ui.bootstrap/src/accordion/accordion.js"></script>
+<!-- inject:js -->
+<script src="/../../static/js/vendor/xosCeilometerDashboardVendor.js"></script>
+<script src="/../../static/js/xosCeilometerDashboard.js"></script>
+<!-- endinject -->
diff --git a/views/ngXosViews/contentProvider/.bowerrc b/views/ngXosViews/contentProvider/.bowerrc
new file mode 100644
index 0000000..e491038
--- /dev/null
+++ b/views/ngXosViews/contentProvider/.bowerrc
@@ -0,0 +1,3 @@
+{
+  "directory": "src/vendor/"
+}
\ No newline at end of file
diff --git a/views/ngXosViews/contentProvider/.eslintrc b/views/ngXosViews/contentProvider/.eslintrc
new file mode 100644
index 0000000..c852748
--- /dev/null
+++ b/views/ngXosViews/contentProvider/.eslintrc
@@ -0,0 +1,42 @@
+{
+    "ecmaFeatures": {
+        "blockBindings": true,
+        "forOf": true,
+        "destructuring": true,
+        "arrowFunctions": true,
+        "templateStrings": true
+    },
+    "env": { 
+        "browser": true,
+        "node": true,
+        "es6": true
+    },
+    "plugins": [
+        //"angular"
+    ],
+    "rules": {
+        "quotes": [2, "single"],
+        "camelcase": [1, {"properties": "always"}],
+        "no-underscore-dangle": 1,
+        "eqeqeq": [2, "smart"],
+        "no-alert": 1,
+        "key-spacing": [1, { "beforeColon": false, "afterColon": true }],
+        "indent": [2, 2],
+        "no-irregular-whitespace": 1,
+        "eol-last": 0,
+        "max-nested-callbacks": [2, 4],
+        "comma-spacing": [1, {"before": false, "after": true}],
+        "no-trailing-spaces": [1, { skipBlankLines: true }],
+        "no-unused-vars": [1, {"vars": "all", "args": "after-used"}],
+        "new-cap": 0,
+
+        //"angular/ng_module_name": [2, '/^xos\.*[a-z]*$/'],
+        //"angular/ng_controller_name": [2, '/^[a-z].*Ctrl$/'],
+        //"angular/ng_service_name": [2, '/^[A-Z].*Service$/'],
+        //"angular/ng_directive_name": [2, '/^[a-z]+[[A-Z].*]*$/'],
+        //"angular/ng_di": [0, "function or array"]
+    },
+    "globals" :{
+        "angular": true
+    } 
+}
\ No newline at end of file
diff --git a/views/ngXosViews/contentProvider/.gitignore b/views/ngXosViews/contentProvider/.gitignore
new file mode 100644
index 0000000..567aee4
--- /dev/null
+++ b/views/ngXosViews/contentProvider/.gitignore
@@ -0,0 +1,6 @@
+dist/
+src/vendor
+.tmp
+node_modules
+npm-debug.log
+dist/
\ No newline at end of file
diff --git a/views/ngXosViews/contentProvider/README.md b/views/ngXosViews/contentProvider/README.md
new file mode 100644
index 0000000..2a34bd7
--- /dev/null
+++ b/views/ngXosViews/contentProvider/README.md
@@ -0,0 +1,9 @@
+# Content Provider Dashboard
+
+To enable the needed backend for this dashboard:
+
+- Enter `xos` with `make enter-xos` (from `xos/configuration/frontend` folder)
+- `cd /opt/xos/tosca`
+- `python ./run.py padmin@vicci.org samples/cdn.yaml`
+
+And it will enable the `xoslib/hpcapi` endpoint
\ No newline at end of file
diff --git a/views/ngXosViews/contentProvider/bower.json b/views/ngXosViews/contentProvider/bower.json
new file mode 100644
index 0000000..b8a92a7
--- /dev/null
+++ b/views/ngXosViews/contentProvider/bower.json
@@ -0,0 +1,32 @@
+{
+  "name": "xos-contentProvider",
+  "version": "0.0.0",
+  "authors": [
+    "Matteo Scandolo <teo@onlab.us>"
+  ],
+  "description": "The contentProvider view",
+  "license": "MIT",
+  "ignore": [
+    "**/.*",
+    "node_modules",
+    "bower_components",
+    "static/js/vendor/",
+    "test",
+    "tests"
+  ],
+  "dependencies": {
+  },
+  "devDependencies": {
+    "jquery": "2.1.4",
+    "angular-mocks": "1.4.7",
+    "angular": "1.4.7",
+    "angular-ui-router": "0.2.15",
+    "angular-cookies": "1.4.7",
+    "angular-animate": "1.4.7",
+    "angular-resource": "1.4.7",
+    "lodash": "~4.11.1",
+    "bootstrap-css": "3.3.6",
+    "angular-chart.js": "~0.10.2",
+    "d3": "~3.5.17"
+  }
+}
diff --git a/views/ngXosViews/contentProvider/gulp/build.js b/views/ngXosViews/contentProvider/gulp/build.js
new file mode 100644
index 0000000..6bef382
--- /dev/null
+++ b/views/ngXosViews/contentProvider/gulp/build.js
@@ -0,0 +1,164 @@
+'use strict';
+
+// BUILD
+//
+// The only purpose of this gulpfile is to build a XOS view and copy the correct files into
+// .html => dashboards
+// .js (minified and concat) => static/js
+//
+// The template are parsed and added to js with angular $templateCache
+
+var gulp = require('gulp');
+var ngAnnotate = require('gulp-ng-annotate');
+var uglify = require('gulp-uglify');
+var templateCache = require('gulp-angular-templatecache');
+var runSequence = require('run-sequence');
+var concat = require('gulp-concat-util');
+var del = require('del');
+var wiredep = require('wiredep');
+var angularFilesort = require('gulp-angular-filesort');
+var _ = require('lodash');
+var eslint = require('gulp-eslint');
+var inject = require('gulp-inject');
+var rename = require('gulp-rename');
+var replace = require('gulp-replace');
+var postcss = require('gulp-postcss');
+var autoprefixer = require('autoprefixer');
+var mqpacker = require('css-mqpacker');
+var csswring = require('csswring');
+
+const TEMPLATE_FOOTER = `
+angular.module('xos.contentProvider')
+.run(['$location', function(a){
+  a.path('/');
+}])
+`
+
+module.exports = function(options){
+  
+  // delete previous builded file
+  gulp.task('clean', function(){
+    return del(
+      [
+        options.dashboards + 'xosContentProvider.html',
+        options.static + 'css/xosContentProvider.css'
+      ],
+      {force: true}
+    );
+  });
+
+  // minify css
+  gulp.task('css', function () {
+    var processors = [
+      autoprefixer({browsers: ['last 1 version']}),
+      mqpacker,
+      csswring
+    ];
+
+    gulp.src([
+      `${options.css}**/*.css`,
+      `!${options.css}dev.css`
+    ])
+    .pipe(postcss(processors))
+    .pipe(gulp.dest(options.tmp + '/css/'));
+  });
+
+  // copy css in correct folder
+  gulp.task('copyCss', ['wait'], function(){
+    return gulp.src([`${options.tmp}/css/*.css`])
+    .pipe(concat('xosContentProvider.css'))
+    .pipe(gulp.dest(options.static + 'css/'))
+  });
+
+  // compile and minify scripts
+  gulp.task('scripts', function() {
+    return gulp.src([
+      options.tmp + '**/*.js'
+    ])
+    .pipe(ngAnnotate())
+    .pipe(angularFilesort())
+    .pipe(concat('xosContentProvider.js'))
+    .pipe(concat.header('//Autogenerated, do not edit!!!\n'))
+    .pipe(concat.footer(TEMPLATE_FOOTER))
+    .pipe(uglify())
+    .pipe(gulp.dest(options.static + 'js/'));
+  });
+
+  // set templates in cache
+  gulp.task('templates', function(){
+    return gulp.src('./src/templates/*.html')
+      .pipe(templateCache({
+        module: 'xos.contentProvider',
+        root: 'templates/'
+      }))
+      .pipe(gulp.dest(options.tmp));
+  });
+
+  // copy html index to Django Folder
+  gulp.task('copyHtml', function(){
+    return gulp.src(options.src + 'index.html')
+      // remove dev dependencies from html
+      .pipe(replace(/<!-- bower:css -->(\n^<link.*)*\n<!-- endbower -->/gmi, ''))
+      .pipe(replace(/<!-- bower:js -->(\n^<script.*)*\n<!-- endbower -->/gmi, ''))
+      // injecting minified files
+      .pipe(
+        inject(
+          gulp.src([
+            options.static + 'js/vendor/xosContentProviderVendor.js',
+            options.static + 'js/xosContentProvider.js',
+            options.static + 'css/xosContentProvider.css'
+          ]),
+          {ignorePath: '/../../../xos/core/xoslib'}
+        )
+      )
+      .pipe(rename('xosContentProvider.html'))
+      .pipe(gulp.dest(options.dashboards));
+  });
+
+  // minify vendor js files
+  gulp.task('wiredep', function(){
+    var bowerDeps = wiredep().js;
+    if(!bowerDeps){
+      return;
+    }
+
+    // remove angular (it's already loaded)
+    _.remove(bowerDeps, function(dep){
+      return dep.indexOf('angular/angular.js') !== -1;
+    });
+
+    return gulp.src(bowerDeps)
+      .pipe(concat('xosContentProviderVendor.js'))
+      .pipe(uglify())
+      .pipe(gulp.dest(options.static + 'js/vendor/'));
+  });
+
+  gulp.task('lint', function () {
+    return gulp.src(['src/js/**/*.js'])
+      .pipe(eslint())
+      .pipe(eslint.format())
+      .pipe(eslint.failAfterError());
+  });
+
+  gulp.task('wait', function (cb) {
+    // setTimeout could be any async task
+    setTimeout(function () {
+      cb();
+    }, 1000);
+  });
+
+  gulp.task('build', function() {
+    runSequence(
+      'clean',
+      'sass',
+      'templates',
+      'babel',
+      'scripts',
+      'wiredep',
+      'css',
+      'copyCss',
+      'copyHtml',
+      'cleanTmp'
+    );
+  });
+};
\ No newline at end of file
diff --git a/views/ngXosViews/contentProvider/gulp/server.js b/views/ngXosViews/contentProvider/gulp/server.js
new file mode 100644
index 0000000..0bc2bd3
--- /dev/null
+++ b/views/ngXosViews/contentProvider/gulp/server.js
@@ -0,0 +1,171 @@
+'use strict';
+
+var gulp = require('gulp');
+var browserSync = require('browser-sync').create();
+var inject = require('gulp-inject');
+var runSequence = require('run-sequence');
+var angularFilesort = require('gulp-angular-filesort');
+var babel = require('gulp-babel');
+var wiredep = require('wiredep').stream;
+var httpProxy = require('http-proxy');
+var del = require('del');
+var sass = require('gulp-sass');
+var fs = require('fs');
+var path = require('path');
+
+const environment = process.env.NODE_ENV;
+
+if(!fs.existsSync(path.join(__dirname, `../../../env/${environment || 'default'}.js`))){
+  if(!environment){
+    throw new Error('You should define a default.js config in /views/env folder.');
+  }
+  else{
+    throw new Error(`Since you are loading a custom environment, you should define a ${environment}.js config in /views/env folder.`);
+  }
+}
+
+var conf = require(path.join(__dirname, `../../../env/${environment || 'default'}.js`));
+
+var proxy = httpProxy.createProxyServer({
+  target: conf.host
+});
+
+
+proxy.on('error', function(error, req, res) {
+  res.writeHead(500, {
+    'Content-Type': 'text/plain'
+  });
+
+  console.error('[Proxy]', error);
+});
+
+module.exports = function(options){
+
+  gulp.task('browser', function() {
+    browserSync.init({
+      startPath: '#/',
+      snippetOptions: {
+        rule: {
+          match: /<!-- browserSync -->/i
+        }
+      },
+      server: {
+        baseDir: options.src,
+        routes: {
+          '/xos/core/xoslib/static/js/vendor': options.helpers,
+          '/xos/core/static': options.static + '../../static/'
+        },
+        middleware: function(req, res, next){
+          if(
+            req.url.indexOf('/api/') !== -1 ||
+            req.url.indexOf('/hpcapi/') !== -1
+          ){
+            if(conf.xoscsrftoken && conf.xossessionid){
+              req.headers.cookie = `xoscsrftoken=${conf.xoscsrftoken}; xossessionid=${conf.xossessionid}`;
+              req.headers['x-csrftoken'] = conf.xoscsrftoken;
+            }
+            proxy.web(req, res);
+          }
+          else{
+            next();
+          }
+        }
+      }
+    });
+
+    gulp.watch(options.src + 'js/**/*.js', ['js-watch']);
+    gulp.watch(options.src + 'vendor/**/*.js', ['bower'], function(){
+      browserSync.reload();
+    });
+    gulp.watch(options.src + '**/*.html', function(){
+      browserSync.reload();
+    });
+    gulp.watch(options.css + '**/*.css', function(){
+      browserSync.reload();
+    });
+    gulp.watch(`${options.sass}/**/*.scss`, ['sass'], function(){
+      browserSync.reload();
+    });
+
+    gulp.watch([
+      options.helpers + 'ngXosHelpers.js',
+      options.static + '../../static/xosNgLib.css'
+    ], function(){
+      browserSync.reload();
+    });
+  });
+
+  // compile sass
+  gulp.task('sass', function () {
+    return gulp.src(`${options.sass}/**/*.scss`)
+      .pipe(sass().on('error', sass.logError))
+      .pipe(gulp.dest(options.css));
+  });
+
+  // transpile js with sourceMaps
+  gulp.task('babel', function(){
+    return gulp.src(options.scripts + '**/*.js')
+      .pipe(babel({sourceMaps: true}))
+      .pipe(gulp.dest(options.tmp));
+  });
+
+  // inject scripts
+  gulp.task('injectScript', ['cleanTmp', 'babel'], function(){
+    return gulp.src(options.src + 'index.html')
+      .pipe(
+        inject(
+          gulp.src([
+            options.tmp + '**/*.js',
+            options.helpers + 'ngXosHelpers.js'
+          ])
+          .pipe(angularFilesort()),
+          {
+            ignorePath: [options.src, '/../../ngXosLib']
+          }
+        )
+      )
+      .pipe(gulp.dest(options.src));
+  });
+
+  // inject CSS
+  gulp.task('injectCss', function(){
+    return gulp.src(options.src + 'index.html')
+      .pipe(
+        inject(
+          gulp.src([
+            options.src + 'css/*.css',
+            options.static + '../../static/xosNgLib.css'
+          ]),
+          {
+            ignorePath: [options.src]
+          }
+          )
+        )
+      .pipe(gulp.dest(options.src));
+  });
+
+  // inject bower dependencies with wiredep
+  gulp.task('bower', function () {
+    return gulp.src(options.src + 'index.html')
+    .pipe(wiredep({devDependencies: true}))
+    .pipe(gulp.dest(options.src));
+  });
+
+  gulp.task('js-watch', ['injectScript'], function(){
+    browserSync.reload();
+  });
+
+  gulp.task('cleanTmp', function(){
+    return del([options.tmp + '**/*']);
+  });
+
+  gulp.task('serve', function() {
+    runSequence(
+      'sass',
+      'bower',
+      'injectScript',
+      'injectCss',
+      ['browser']
+    );
+  });
+};
diff --git a/views/ngXosViews/contentProvider/gulpfile.js b/views/ngXosViews/contentProvider/gulpfile.js
new file mode 100644
index 0000000..08df554
--- /dev/null
+++ b/views/ngXosViews/contentProvider/gulpfile.js
@@ -0,0 +1,26 @@
+'use strict';
+
+var gulp = require('gulp');
+var wrench = require('wrench');
+
+var options = {
+  src: 'src/',
+  css: 'src/css/',
+  sass: 'src/sass/',
+  scripts: 'src/js/',
+  tmp: 'src/.tmp',
+  dist: 'dist/',
+  api: '../../ngXosLib/api/',
+  helpers: '../../../xos/core/xoslib/static/js/vendor/',
+  static: '../../../xos/core/xoslib/static/', // this is the django static folder
+  dashboards: '../../../xos/core/xoslib/dashboards/' // this is the django html folder
+};
+
+wrench.readdirSyncRecursive('./gulp')
+.map(function(file) {
+  require('./gulp/' + file)(options);
+});
+
+gulp.task('default', function () {
+  gulp.start('build');
+});
diff --git a/views/ngXosViews/contentProvider/karma.conf.js b/views/ngXosViews/contentProvider/karma.conf.js
new file mode 100644
index 0000000..4123be9
--- /dev/null
+++ b/views/ngXosViews/contentProvider/karma.conf.js
@@ -0,0 +1,88 @@
+// Karma configuration
+// Generated on Tue Oct 06 2015 09:27:10 GMT+0000 (UTC)
+
+/* eslint indent: [2,2], quotes: [2, "single"]*/
+
+/*eslint-disable*/
+var wiredep = require('wiredep');
+var path = require('path');
+
+var bowerComponents = wiredep( {devDependencies: true} )[ 'js' ].map(function( file ){
+  return path.relative(process.cwd(), file);
+});
+
+module.exports = function(config) {
+/*eslint-enable*/
+  config.set({
+
+    // base path that will be used to resolve all patterns (eg. files, exclude)
+    basePath: '',
+
+
+    // frameworks to use
+    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
+    frameworks: ['jasmine'],
+
+
+    // list of files / patterns to load in the browser
+    files: bowerComponents.concat([
+      '../../../xos/core/xoslib/static/js/vendor/ngXosVendor.js',
+      '../../../xos/core/xoslib/static/js/vendor/ngXosHelpers.js',
+      'src/js/**/*.js',
+      'spec/**/*.mock.js',
+      'spec/**/*.test.js',
+      'src/**/*.html'
+    ]),
+
+
+    // list of files to exclude
+    exclude: [
+    ],
+
+
+    // preprocess matching files before serving them to the browser
+    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
+    preprocessors: {
+      'src/js/**/*.js': ['babel'],
+      'spec/**/*.test.js': ['babel'],
+      'src/**/*.html': ['ng-html2js']
+    },
+
+    ngHtml2JsPreprocessor: {
+      stripPrefix: 'src/', //strip the src path from template url (http://stackoverflow.com/questions/22869668/karma-unexpected-request-when-testing-angular-directive-even-with-ng-html2js)
+      moduleName: 'templates' // define the template module name
+    },
+
+    // test results reporter to use
+    // possible values: 'dots', 'progress'
+    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
+    reporters: ['mocha'],
+
+
+    // web server port
+    port: 9876,
+
+
+    // enable / disable colors in the output (reporters and logs)
+    colors: true,
+
+
+    // level of logging
+    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+    logLevel: config.LOG_INFO,
+
+
+    // enable / disable watching file and executing tests whenever any file changes
+    autoWatch: true,
+
+
+    // start these browsers
+    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
+    browsers: ['PhantomJS'],
+
+
+    // Continuous Integration mode
+    // if true, Karma captures browsers, runs the tests and exits
+    singleRun: false
+  });
+};
diff --git a/views/ngXosViews/contentProvider/package.json b/views/ngXosViews/contentProvider/package.json
new file mode 100644
index 0000000..b626ef7
--- /dev/null
+++ b/views/ngXosViews/contentProvider/package.json
@@ -0,0 +1,63 @@
+{
+  "name": "xos-contentProvider",
+  "version": "1.0.0",
+  "description": "Angular Application for XOS, created with generator-xos",
+  "scripts": {
+    "prestart": "npm install && bower install",
+    "start": "gulp serve",
+    "prebuild": "npm install && bower install",
+    "build": "gulp",
+    "test": "karma start",
+    "test:ci": "karma start --single-run",
+    "lint": "eslint src/js/"
+  },
+  "keywords": [
+    "XOS",
+    "Angular",
+    "XOSlib"
+  ],
+  "author": "Matteo Scandolo",
+  "license": "MIT",
+  "dependencies": {},
+  "devDependencies": {
+    "autoprefixer": "^6.3.3",
+    "browser-sync": "^2.9.11",
+    "css-mqpacker": "^4.0.0",
+    "csswring": "^4.2.1",
+    "del": "^2.0.2",
+    "easy-mocker": "^1.2.0",
+    "eslint": "^1.8.0",
+    "eslint-plugin-angular": "linkmesrl/eslint-plugin-angular",
+    "gulp": "^3.9.0",
+    "gulp-angular-filesort": "^1.1.1",
+    "gulp-angular-templatecache": "^1.8.0",
+    "gulp-babel": "^5.3.0",
+    "gulp-concat": "^2.6.0",
+    "gulp-concat-util": "^0.5.5",
+    "gulp-eslint": "^1.0.0",
+    "gulp-inject": "^3.0.0",
+    "gulp-minify-html": "^1.0.4",
+    "gulp-ng-annotate": "^1.1.0",
+    "gulp-postcss": "^6.0.1",
+    "gulp-rename": "^1.2.2",
+    "gulp-replace": "^0.5.4",
+    "gulp-sass": "^2.2.0",
+    "gulp-uglify": "^1.4.2",
+    "http-proxy": "^1.12.0",
+    "ink-docstrap": "^0.5.2",
+    "jasmine-core": "~2.3.4",
+    "karma": "^0.13.14",
+    "karma-babel-preprocessor": "~5.2.2",
+    "karma-coverage": "^0.5.3",
+    "karma-jasmine": "~0.3.6",
+    "karma-mocha-reporter": "~1.1.1",
+    "karma-ng-html2js-preprocessor": "^0.2.0",
+    "karma-phantomjs-launcher": "~0.2.1",
+    "lodash": "^3.10.1",
+    "phantomjs": "^1.9.19",
+    "proxy-middleware": "^0.15.0",
+    "run-sequence": "^1.1.4",
+    "wiredep": "^3.0.0-beta",
+    "wrench": "^1.5.8"
+  }
+}
diff --git a/views/ngXosViews/contentProvider/spec/contentprovider.test.js b/views/ngXosViews/contentProvider/spec/contentprovider.test.js
new file mode 100644
index 0000000..10b3b63
--- /dev/null
+++ b/views/ngXosViews/contentProvider/spec/contentprovider.test.js
@@ -0,0 +1,247 @@
+'use strict';
+
+describe('The Content Provider SPA', () => {
+
+  var scope, element, isolatedScope, httpBackend, mockLocation, httpProvider;
+
+  var token = 'fakeToken';
+
+  // injecting main module
+  beforeEach(module('xos.contentProvider'));
+
+  beforeEach(module('templates'));
+
+  beforeEach(function(){
+    module(function($provide, $httpProvider){
+
+      httpProvider = $httpProvider;
+
+      // mocking stateParams to pass 1 as id
+      $provide.provider('$stateParams', function(){
+        /* eslint-disable no-invalid-this*/
+        this.$get = function(){
+          return {id: 1};
+        };
+        /* eslint-enable no-invalid-this*/
+      });
+
+      //mock $cookie to return a fake xoscsrftoken
+      $provide.service('$cookies', function(){
+        /* eslint-disable no-invalid-this*/
+        this.get = () => {
+          return token;
+        };
+        /* eslint-enable no-invalid-this*/
+      });
+    });
+  });
+
+  beforeEach(inject(function(_$location_, $httpBackend){
+    spyOn(_$location_, 'url');
+    mockLocation = _$location_;
+    httpBackend = $httpBackend;
+    // Setting up mock request
+    $httpBackend.whenGET('/hpcapi/contentproviders/?no_hyperlinks=1').respond(CPmock.CPlist);
+    $httpBackend.whenGET('/hpcapi/serviceproviders/?no_hyperlinks=1').respond(CPmock.SPlist);
+    $httpBackend.whenDELETE('/hpcapi/contentproviders/1/?no_hyperlinks=1').respond();
+  }));
+
+  xit('should set the $http interceptor', () => {
+    expect(httpProvider.interceptors).toContain('SetCSRFToken');
+  });
+
+  xit('should add no_hyperlink param', inject(($http, $httpBackend) => {
+    $http.get('www.example.com');
+    $httpBackend.expectGET('www.example.com?no_hyperlinks=1').respond(200);
+    $httpBackend.flush();
+  }));
+
+  xit('should set token in the headers', inject(($http, $httpBackend) => {
+    $http.post('http://example.com');
+    $httpBackend.expectPOST('http://example.com?no_hyperlinks=1', undefined, function(headers){
+      // if this condition is false the httpBackend expectation fail
+      return headers['X-CSRFToken'] === token;
+    }).respond(200, {name: 'example'});
+    httpBackend.flush();
+  }));
+
+  describe('the action directive', () => {
+    beforeEach(inject(function($compile, $rootScope){
+      scope = $rootScope.$new();
+
+      element = angular.element('<cp-actions id="\'1\'"></cp-actions>');
+      $compile(element)(scope);
+      scope.$digest();
+      isolatedScope = element.isolateScope().vm;
+    }));
+
+    it('should delete an element and redirect to list', () => {
+      isolatedScope.deleteCp(1);
+      httpBackend.flush();
+      expect(mockLocation.url).toHaveBeenCalled();
+    });
+  });
+
+  describe('the contentProvider list', () => {
+    beforeEach(inject(function($compile, $rootScope){
+      scope = $rootScope.$new();
+
+      element = angular.element('<content-provider-list></content-provider-list>');
+      $compile(element)(scope);
+      scope.$digest();
+      httpBackend.flush();
+      isolatedScope = element.isolateScope().vm;
+    }));
+
+
+    it('should load 2 contentProvider', () => {
+      expect(isolatedScope.contentProviderList.length).toBe(2);
+    });
+
+    it('should delete a contentProvider', () => {
+      isolatedScope.deleteCp(1);
+      httpBackend.flush();
+      expect(isolatedScope.contentProviderList.length).toBe(1);
+    });
+  });
+
+  describe('the contentProviderDetail directive', () => {
+
+    beforeEach(inject(function($compile, $rootScope){
+      scope = $rootScope.$new();
+      element = angular.element('<content-provider-detail></content-provider-detail>');
+      $compile(element)(scope);
+      httpBackend.expectGET('/hpcapi/contentproviders/1/?no_hyperlinks=1').respond(CPmock.CPlist[0]);
+      scope.$digest();
+      httpBackend.flush();
+      isolatedScope = element.isolateScope().vm;
+    }));
+
+    describe('when an id is set in the route', () => {
+
+      beforeEach(() => {
+        // spy the instance update method
+        spyOn(isolatedScope.cp, '$update').and.callThrough();
+      });
+
+      it('should request the correct contentProvider', () => {
+        expect(isolatedScope.cp.name).toEqual(CPmock.CPlist[0].name);
+      });
+
+      it('should update a contentProvider', () => {
+        isolatedScope.cp.name = 'new name';
+        isolatedScope.saveContentProvider(isolatedScope.cp);
+        expect(isolatedScope.cp.$update).toHaveBeenCalled();
+      });
+    });
+  });
+
+  describe('the contentProviderCdn directive', () => {
+    beforeEach(inject(($compile, $rootScope) => {
+      scope = $rootScope.$new();
+      element = angular.element('<content-provider-cdn></content-provider-cdn>');
+      $compile(element)(scope);
+      httpBackend.expectGET('/hpcapi/contentproviders/1/?no_hyperlinks=1').respond(CPmock.CPlist[0]);
+      // httpBackend.expectGET('/hpcapi/cdnprefixs/?no_hyperlinks=1&contentProvider=1').respond([CPmock.CDNlist[0]]);
+      httpBackend.expectGET('/hpcapi/cdnprefixs/?no_hyperlinks=1').respond(CPmock.CDNlist);
+      httpBackend.whenPOST('/hpcapi/cdnprefixs/?no_hyperlinks=1').respond(CPmock.CDNlist[0]);
+      httpBackend.whenDELETE('/hpcapi/cdnprefixs/5/?no_hyperlinks=1').respond();
+      scope.$digest();
+      httpBackend.flush();
+      isolatedScope = element.isolateScope().vm;
+    }));
+
+    it('should load associated CDN prefix', () => {
+      expect(isolatedScope.cp_prf.length).toBe(1);
+      expect(isolatedScope.prf.length).toBe(2);
+    });
+
+    it('should add a CDN Prefix', () => {
+      isolatedScope.addPrefix({prefix: 'test.io', defaultOriginServer: '/hpcapi/originservers/2/'});
+      httpBackend.flush();
+      expect(isolatedScope.cp_prf.length).toBe(2);
+    });
+
+    it('should remove a CDN Prefix', () => {
+      isolatedScope.removePrefix(isolatedScope.cp_prf[0]);
+      httpBackend.flush();
+      expect(isolatedScope.cp_prf.length).toBe(0);
+    });
+  });
+
+  describe('the contentProviderServer directive', () => {
+    beforeEach(inject(($compile, $rootScope) => {
+      scope = $rootScope.$new();
+      element = angular.element('<content-provider-server></content-provider-server>');
+      $compile(element)(scope);
+      httpBackend.expectGET('/hpcapi/contentproviders/1/?no_hyperlinks=1').respond(CPmock.CPlist[0]);
+      httpBackend.expectGET('/hpcapi/originservers/?no_hyperlinks=1&contentProvider=1').respond(CPmock.OSlist);
+      httpBackend.whenPOST('/hpcapi/originservers/?no_hyperlinks=1').respond(CPmock.OSlist[0]);
+      httpBackend.whenDELETE('/hpcapi/originservers/8/?no_hyperlinks=1').respond();
+      scope.$digest();
+      httpBackend.flush();
+      isolatedScope = element.isolateScope().vm;
+    }));
+
+    it('should load associated OriginServer', () => {
+      expect(isolatedScope.cp_os.length).toBe(4);
+    });
+
+    it('should add a OriginServer', () => {
+      isolatedScope.addOrigin({protocol: 'http', url: 'test.io'});
+      httpBackend.flush();
+      expect(isolatedScope.cp_os.length).toBe(5);
+    });
+
+    it('should remove a OriginServer', () => {
+      isolatedScope.removeOrigin(isolatedScope.cp_os[0]);
+      httpBackend.flush();
+      expect(isolatedScope.cp_os.length).toBe(3);
+    });
+  });
+
+  describe('the contentProviderUsers directive', () => {
+    beforeEach(inject(($compile, $rootScope) => {
+      scope = $rootScope.$new();
+      element = angular.element('<content-provider-users></content-provider-users>');
+      $compile(element)(scope);
+      httpBackend.expectGET('/xos/users/?no_hyperlinks=1').respond(CPmock.UserList);
+      httpBackend.expectGET('/hpcapi/contentproviders/1/?no_hyperlinks=1').respond(CPmock.CPlist[0]);
+      httpBackend.whenPUT('/hpcapi/contentproviders/1/?no_hyperlinks=1').respond(CPmock.CPlist[0]);
+      scope.$digest();
+      httpBackend.flush();
+      isolatedScope = element.isolateScope().vm;
+    }));
+
+    it('should render one user', () => {
+      expect(isolatedScope.cp.users.length).toBe(1);
+      expect(typeof isolatedScope.cp.users[0]).toEqual('object');
+    });
+
+    it('should add a user', () => {
+      isolatedScope.addUserToCp({name: 'teo'});
+      expect(isolatedScope.cp.users.length).toBe(2);
+    });
+
+    it('should remove a user', () => {
+      isolatedScope.addUserToCp({name: 'teo'});
+      expect(isolatedScope.cp.users.length).toBe(2);
+      isolatedScope.removeUserFromCp({name: 'teo'});
+      expect(isolatedScope.cp.users.length).toBe(1);
+    });
+
+    it('should save and reformat users', () => {
+      // add a user
+      isolatedScope.cp.users.push(1);
+
+      //trigger save
+      isolatedScope.saveContentProvider(isolatedScope.cp);
+
+      httpBackend.flush();
+
+      // I'll get one as the BE is mocked, the important is to check the conversion
+      expect(isolatedScope.cp.users.length).toBe(1);
+      expect(typeof isolatedScope.cp.users[0]).toEqual('object');
+    });
+  });
+});
diff --git a/views/ngXosViews/contentProvider/spec/mocks/contentProvider.mock.js b/views/ngXosViews/contentProvider/spec/mocks/contentProvider.mock.js
new file mode 100644
index 0000000..46a0b0e
--- /dev/null
+++ b/views/ngXosViews/contentProvider/spec/mocks/contentProvider.mock.js
@@ -0,0 +1,910 @@
+/* eslint-disable key-spacing, no-unused-vars */
+
+var CPmock = {
+  CPlist: [
+    {
+      'humanReadableName':'on_lab_content',
+      'validators':{
+        'updated':[
+
+        ],
+        'policed':[
+
+        ],
+        'name':[
+          'notBlank'
+        ],
+        'created':[
+
+        ],
+        'deleted':[
+
+        ],
+        'serviceProvider':[
+          'notBlank'
+        ],
+        'description':[
+
+        ],
+        'enabled':[
+
+        ],
+        'lazy_blocked':[
+
+        ],
+        'backend_register':[
+          'notBlank'
+        ],
+        'write_protect':[
+
+        ],
+        'content_provider_id':[
+
+        ],
+        'backend_status':[
+          'notBlank'
+        ],
+        'id':[
+
+        ],
+        'no_sync':[
+
+        ],
+        'enacted':[
+
+        ]
+      },
+      'id':1,
+      'created':'2015-10-22T19:33:55.078Z',
+      'updated':'2015-10-22T19:33:55.078Z',
+      'enacted':null,
+      'policed':null,
+      'backend_register':'{}',
+      'backend_status':'0 - Provisioning in progress',
+      'deleted':false,
+      'write_protect':false,
+      'lazy_blocked':false,
+      'no_sync':false,
+      'content_provider_id':null,
+      'name':'on_lab_content',
+      'enabled':true,
+      'description':null,
+      users: [2],
+      'serviceProvider':'http://0.0.0.0:9000/hpcapi/serviceproviders/1/'
+    },
+    {
+      'humanReadableName':'test',
+      'validators':{
+        'updated':[
+
+        ],
+        'policed':[
+
+        ],
+        'name':[
+          'notBlank'
+        ],
+        'created':[
+
+        ],
+        'deleted':[
+
+        ],
+        'serviceProvider':[
+          'notBlank'
+        ],
+        'description':[
+
+        ],
+        'enabled':[
+
+        ],
+        'lazy_blocked':[
+
+        ],
+        'backend_register':[
+          'notBlank'
+        ],
+        'write_protect':[
+
+        ],
+        'content_provider_id':[
+
+        ],
+        'backend_status':[
+          'notBlank'
+        ],
+        'id':[
+
+        ],
+        'no_sync':[
+
+        ],
+        'enacted':[
+
+        ]
+      },
+      'id':2,
+      'created':'2015-10-23T10:50:37.482Z',
+      'updated':'2015-10-23T10:52:56.232Z',
+      'enacted':null,
+      'policed':null,
+      'backend_register':'{}',
+      'backend_status':'0 - Provisioning in progress',
+      'deleted':false,
+      'write_protect':false,
+      'lazy_blocked':false,
+      'no_sync':false,
+      'content_provider_id':null,
+      'name':'test',
+      'enabled':true,
+      'description':'',
+      'serviceProvider':'http://0.0.0.0:9000/hpcapi/serviceproviders/1/'
+    }
+  ],
+  SPlist: [
+    {
+      'humanReadableName':'main_service_provider',
+      'validators':{
+        'updated':[
+
+        ],
+        'policed':[
+
+        ],
+        'name':[
+          'notBlank'
+        ],
+        'created':[
+
+        ],
+        'deleted':[
+
+        ],
+        'hpcService':[
+          'notBlank'
+        ],
+        'description':[
+
+        ],
+        'enabled':[
+
+        ],
+        'service_provider_id':[
+
+        ],
+        'lazy_blocked':[
+
+        ],
+        'backend_register':[
+          'notBlank'
+        ],
+        'write_protect':[
+
+        ],
+        'backend_status':[
+          'notBlank'
+        ],
+        'id':[
+
+        ],
+        'no_sync':[
+
+        ],
+        'enacted':[
+
+        ]
+      },
+      'id':1,
+      'created':'2015-10-22T19:33:55.048Z',
+      'updated':'2015-10-22T19:33:55.048Z',
+      'enacted':null,
+      'policed':null,
+      'backend_register':'{}',
+      'backend_status':'0 - Provisioning in progress',
+      'deleted':false,
+      'write_protect':false,
+      'lazy_blocked':false,
+      'no_sync':false,
+      'hpcService':'http://0.0.0.0:9000/hpcapi/hpcservices/1/',
+      'service_provider_id':null,
+      'name':'main_service_provider',
+      'description':null,
+      'enabled':true
+    }
+  ],
+  CDNlist: [
+    {
+      'humanReadableName':'onlab.vicci.org',
+      'validators':{
+        'updated':[
+
+        ],
+        'contentProvider':[
+          'notBlank'
+        ],
+        'policed':[
+
+        ],
+        'created':[
+
+        ],
+        'deleted':[
+
+        ],
+        'description':[
+
+        ],
+        'enabled':[
+
+        ],
+        'cdn_prefix_id':[
+
+        ],
+        'lazy_blocked':[
+
+        ],
+        'backend_register':[
+          'notBlank'
+        ],
+        'write_protect':[
+
+        ],
+        'prefix':[
+          'notBlank'
+        ],
+        'defaultOriginServer':[
+
+        ],
+        'backend_status':[
+          'notBlank'
+        ],
+        'id':[
+
+        ],
+        'no_sync':[
+
+        ],
+        'enacted':[
+
+        ]
+      },
+      'id':5,
+      'created':'2015-10-26T13:09:44.343Z',
+      'updated':'2015-10-26T13:09:44.343Z',
+      'enacted':null,
+      'policed':null,
+      'backend_register':'{}',
+      'backend_status':'0 - Provisioning in progress',
+      'deleted':false,
+      'write_protect':false,
+      'lazy_blocked':false,
+      'no_sync':false,
+      'cdn_prefix_id':null,
+      'prefix':'onlab.vicci.org',
+      'contentProvider':1,
+      'description':null,
+      'defaultOriginServer':'http://0.0.0.0:9000/hpcapi/originservers/2/',
+      'enabled':true
+    },
+    {
+      'humanReadableName':'downloads.onosproject.org',
+      'validators':{
+        'updated':[
+
+        ],
+        'contentProvider':[
+          'notBlank'
+        ],
+        'policed':[
+
+        ],
+        'created':[
+
+        ],
+        'deleted':[
+
+        ],
+        'description':[
+
+        ],
+        'enabled':[
+
+        ],
+        'cdn_prefix_id':[
+
+        ],
+        'lazy_blocked':[
+
+        ],
+        'backend_register':[
+          'notBlank'
+        ],
+        'write_protect':[
+
+        ],
+        'prefix':[
+          'notBlank'
+        ],
+        'defaultOriginServer':[
+
+        ],
+        'backend_status':[
+          'notBlank'
+        ],
+        'id':[
+
+        ],
+        'no_sync':[
+
+        ],
+        'enacted':[
+
+        ]
+      },
+      'id':1,
+      'created':'2015-10-26T13:09:44.196Z',
+      'updated':'2015-10-26T13:09:44.196Z',
+      'enacted':null,
+      'policed':null,
+      'backend_register':'{}',
+      'backend_status':'0 - Provisioning in progress',
+      'deleted':false,
+      'write_protect':false,
+      'lazy_blocked':false,
+      'no_sync':false,
+      'cdn_prefix_id':null,
+      'prefix':'downloads.onosproject.org',
+      'contentProvider':2,
+      'description':null,
+      'defaultOriginServer':'http://0.0.0.0:9000/hpcapi/originservers/1/',
+      'enabled':true
+    }
+  ],
+  OSlist: [
+    {
+      'humanReadableName':'another.it',
+      'validators':{
+        'updated':[
+
+        ],
+        'contentProvider':[
+          'notBlank'
+        ],
+        'origin_server_id':[
+
+        ],
+        'policed':[
+
+        ],
+        'created':[
+
+        ],
+        'deleted':[
+
+        ],
+        'description':[
+
+        ],
+        'enabled':[
+
+        ],
+        'redirects':[
+
+        ],
+        'protocol':[
+          'notBlank'
+        ],
+        'lazy_blocked':[
+
+        ],
+        'backend_register':[
+          'notBlank'
+        ],
+        'write_protect':[
+
+        ],
+        'url':[
+          'notBlank'
+        ],
+        'authenticated':[
+
+        ],
+        'backend_status':[
+          'notBlank'
+        ],
+        'id':[
+
+        ],
+        'no_sync':[
+
+        ],
+        'enacted':[
+
+        ]
+      },
+      'id':8,
+      'created':'2015-10-26T13:40:36.878Z',
+      'updated':'2015-10-26T13:40:36.878Z',
+      'enacted':null,
+      'policed':null,
+      'backend_register':'{}',
+      'backend_status':'0 - Provisioning in progress',
+      'deleted':false,
+      'write_protect':false,
+      'lazy_blocked':false,
+      'no_sync':false,
+      'origin_server_id':null,
+      'url':'another.it',
+      'contentProvider':'http://0.0.0.0:9000/hpcapi/contentproviders/1/',
+      'authenticated':false,
+      'enabled':true,
+      'protocol':'http',
+      'redirects':true,
+      'description':null
+    },
+    {
+      'humanReadableName':'test.it',
+      'validators':{
+        'updated':[
+
+        ],
+        'contentProvider':[
+          'notBlank'
+        ],
+        'origin_server_id':[
+
+        ],
+        'policed':[
+
+        ],
+        'created':[
+
+        ],
+        'deleted':[
+
+        ],
+        'description':[
+
+        ],
+        'enabled':[
+
+        ],
+        'redirects':[
+
+        ],
+        'protocol':[
+          'notBlank'
+        ],
+        'lazy_blocked':[
+
+        ],
+        'backend_register':[
+          'notBlank'
+        ],
+        'write_protect':[
+
+        ],
+        'url':[
+          'notBlank'
+        ],
+        'authenticated':[
+
+        ],
+        'backend_status':[
+          'notBlank'
+        ],
+        'id':[
+
+        ],
+        'no_sync':[
+
+        ],
+        'enacted':[
+
+        ]
+      },
+      'id':7,
+      'created':'2015-10-26T13:36:42.567Z',
+      'updated':'2015-10-26T13:36:42.567Z',
+      'enacted':null,
+      'policed':null,
+      'backend_register':'{}',
+      'backend_status':'0 - Provisioning in progress',
+      'deleted':false,
+      'write_protect':false,
+      'lazy_blocked':false,
+      'no_sync':false,
+      'origin_server_id':null,
+      'url':'test.it',
+      'contentProvider':'http://0.0.0.0:9000/hpcapi/contentproviders/1/',
+      'authenticated':false,
+      'enabled':true,
+      'protocol':'http',
+      'redirects':true,
+      'description':null
+    },
+    {
+      'humanReadableName':'onlab.vicci.org',
+      'validators':{
+        'updated':[
+
+        ],
+        'contentProvider':[
+          'notBlank'
+        ],
+        'origin_server_id':[
+
+        ],
+        'policed':[
+
+        ],
+        'created':[
+
+        ],
+        'deleted':[
+
+        ],
+        'description':[
+
+        ],
+        'enabled':[
+
+        ],
+        'redirects':[
+
+        ],
+        'protocol':[
+          'notBlank'
+        ],
+        'lazy_blocked':[
+
+        ],
+        'backend_register':[
+          'notBlank'
+        ],
+        'write_protect':[
+
+        ],
+        'url':[
+          'notBlank'
+        ],
+        'authenticated':[
+
+        ],
+        'backend_status':[
+          'notBlank'
+        ],
+        'id':[
+
+        ],
+        'no_sync':[
+
+        ],
+        'enacted':[
+
+        ]
+      },
+      'id':2,
+      'created':'2015-10-26T13:09:44.286Z',
+      'updated':'2015-10-26T13:09:44.286Z',
+      'enacted':null,
+      'policed':null,
+      'backend_register':'{}',
+      'backend_status':'0 - Provisioning in progress',
+      'deleted':false,
+      'write_protect':false,
+      'lazy_blocked':false,
+      'no_sync':false,
+      'origin_server_id':null,
+      'url':'onlab.vicci.org',
+      'contentProvider':'http://0.0.0.0:9000/hpcapi/contentproviders/1/',
+      'authenticated':false,
+      'enabled':true,
+      'protocol':'HTTP',
+      'redirects':true,
+      'description':null
+    },
+    {
+      'humanReadableName':'downloads.onosproject.org',
+      'validators':{
+        'updated':[
+
+        ],
+        'contentProvider':[
+          'notBlank'
+        ],
+        'origin_server_id':[
+
+        ],
+        'policed':[
+
+        ],
+        'created':[
+
+        ],
+        'deleted':[
+
+        ],
+        'description':[
+
+        ],
+        'enabled':[
+
+        ],
+        'redirects':[
+
+        ],
+        'protocol':[
+          'notBlank'
+        ],
+        'lazy_blocked':[
+
+        ],
+        'backend_register':[
+          'notBlank'
+        ],
+        'write_protect':[
+
+        ],
+        'url':[
+          'notBlank'
+        ],
+        'authenticated':[
+
+        ],
+        'backend_status':[
+          'notBlank'
+        ],
+        'id':[
+
+        ],
+        'no_sync':[
+
+        ],
+        'enacted':[
+
+        ]
+      },
+      'id':1,
+      'created':'2015-10-26T13:09:44.182Z',
+      'updated':'2015-10-26T13:09:44.182Z',
+      'enacted':null,
+      'policed':null,
+      'backend_register':'{}',
+      'backend_status':'0 - Provisioning in progress',
+      'deleted':false,
+      'write_protect':false,
+      'lazy_blocked':false,
+      'no_sync':false,
+      'origin_server_id':null,
+      'url':'downloads.onosproject.org',
+      'contentProvider':'http://0.0.0.0:9000/hpcapi/contentproviders/1/',
+      'authenticated':false,
+      'enabled':true,
+      'protocol':'HTTP',
+      'redirects':true,
+      'description':null
+    }
+  ],
+  UserList: [
+    {
+      'humanReadableName':'teo@onlab.us',
+      'validators':{
+        'policed':[
+          'notBlank'
+        ],
+        'site':[
+          'notBlank'
+        ],
+        'is_appuser':[
+
+        ],
+        'is_staff':[
+
+        ],
+        'timezone':[
+          'notBlank'
+        ],
+        'backend_status':[
+          'notBlank'
+        ],
+        'id':[
+
+        ],
+        'is_registering':[
+
+        ],
+        'last_login':[
+          'notBlank'
+        ],
+        'email':[
+          'notBlank'
+        ],
+        'username':[
+          'notBlank'
+        ],
+        'updated':[
+
+        ],
+        'login_page':[
+
+        ],
+        'firstname':[
+          'notBlank'
+        ],
+        'user_url':[
+          'url'
+        ],
+        'deleted':[
+
+        ],
+        'lastname':[
+          'notBlank'
+        ],
+        'is_active':[
+
+        ],
+        'phone':[
+
+        ],
+        'is_admin':[
+
+        ],
+        'password':[
+          'notBlank'
+        ],
+        'enacted':[
+          'notBlank'
+        ],
+        'public_key':[
+
+        ],
+        'is_readonly':[
+
+        ],
+        'created':[
+
+        ],
+        'write_protect':[
+
+        ]
+      },
+      'id':2,
+      'password':'pbkdf2_sha256$12000$2Uzp1YCyjEBO$uU2irK//ZpEZYOIgLzanuApFoPnwfG1jNol2jD273wQ=',
+      'last_login':'2015-10-26T14:11:27.625Z',
+      'email':'teo@onlab.us',
+      'username':'teo@onlab.us',
+      'firstname':'Matteo',
+      'lastname':'Scandolo',
+      'phone':'',
+      'user_url':null,
+      'site':1,
+      'public_key':'',
+      'is_active':true,
+      'is_admin':false,
+      'is_staff':true,
+      'is_readonly':false,
+      'is_registering':false,
+      'is_appuser':false,
+      'login_page':null,
+      'created':'2015-10-26T14:11:27.699Z',
+      'updated':'2015-10-26T14:11:27.699Z',
+      'enacted':null,
+      'policed':null,
+      'backend_status':'Provisioning in progress',
+      'deleted':false,
+      'write_protect':false,
+      'timezone':'America/New_York'
+    },
+    {
+      'humanReadableName':'padmin@vicci.org',
+      'validators':{
+        'policed':[
+          'notBlank'
+        ],
+        'site':[
+          'notBlank'
+        ],
+        'is_appuser':[
+
+        ],
+        'is_staff':[
+
+        ],
+        'timezone':[
+          'notBlank'
+        ],
+        'backend_status':[
+          'notBlank'
+        ],
+        'id':[
+
+        ],
+        'is_registering':[
+
+        ],
+        'last_login':[
+          'notBlank'
+        ],
+        'email':[
+          'notBlank'
+        ],
+        'username':[
+          'notBlank'
+        ],
+        'updated':[
+
+        ],
+        'login_page':[
+
+        ],
+        'firstname':[
+          'notBlank'
+        ],
+        'user_url':[
+          'url'
+        ],
+        'deleted':[
+
+        ],
+        'lastname':[
+          'notBlank'
+        ],
+        'is_active':[
+
+        ],
+        'phone':[
+
+        ],
+        'is_admin':[
+
+        ],
+        'password':[
+          'notBlank'
+        ],
+        'enacted':[
+          'notBlank'
+        ],
+        'public_key':[
+
+        ],
+        'is_readonly':[
+
+        ],
+        'created':[
+
+        ],
+        'write_protect':[
+
+        ]
+      },
+      'id':1,
+      'password':'pbkdf2_sha256$12000$Qufx9iqtaYma$xs0YurPOcj9qYQna/Qrb3K+im9Yr2XEVr0J4Kqek7AE=',
+      'last_login':'2015-10-27T10:07:09.065Z',
+      'email':'padmin@vicci.org',
+      'username':'padmin@vicci.org',
+      'firstname':'XOS',
+      'lastname':'admin',
+      'phone':null,
+      'user_url':null,
+      'site':1,
+      'public_key':null,
+      'is_active':true,
+      'is_admin':true,
+      'is_staff':true,
+      'is_readonly':false,
+      'is_registering':false,
+      'is_appuser':false,
+      'login_page':null,
+      'created':'2015-02-17T22:06:38.059Z',
+      'updated':'2015-10-27T09:00:44.672Z',
+      'enacted':null,
+      'policed':null,
+      'backend_status':'Provisioning in progress',
+      'deleted':false,
+      'write_protect':false,
+      'timezone':'America/New_York'
+    }
+  ]
+};
\ No newline at end of file
diff --git a/views/ngXosViews/contentProvider/src/css/dev.css b/views/ngXosViews/contentProvider/src/css/dev.css
new file mode 100644
index 0000000..0ed8b4d
--- /dev/null
+++ b/views/ngXosViews/contentProvider/src/css/dev.css
@@ -0,0 +1,6 @@
+#xosContentProvider{
+  position: absolute;
+  top: 100px;
+  left: 200px;
+  width: 80%;
+}
\ No newline at end of file
diff --git a/views/ngXosViews/contentProvider/src/css/main.css b/views/ngXosViews/contentProvider/src/css/main.css
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/views/ngXosViews/contentProvider/src/css/main.css
diff --git a/views/ngXosViews/contentProvider/src/index.html b/views/ngXosViews/contentProvider/src/index.html
new file mode 100644
index 0000000..accd37d
--- /dev/null
+++ b/views/ngXosViews/contentProvider/src/index.html
@@ -0,0 +1,33 @@
+<!-- browserSync -->
+<!-- bower:css -->
+<link rel="stylesheet" href="vendor/bootstrap-css/css/bootstrap.min.css" />
+<link rel="stylesheet" href="vendor/angular-chart.js/dist/angular-chart.css" />
+<!-- endbower --><!-- endcss -->
+<!-- inject:css -->
+<link rel="stylesheet" href="/css/dev.css">
+<link rel="stylesheet" href="/css/main.css">
+<link rel="stylesheet" href="/../../../xos/core/static/xosNgLib.css">
+<!-- endinject -->
+
+<div ng-app="xos.contentProvider" id="xosContentProvider">
+    <div ui-view></div>
+</div>
+
+<!-- bower:js -->
+<script src="vendor/jquery/dist/jquery.js"></script>
+<script src="vendor/angular/angular.js"></script>
+<script src="vendor/angular-mocks/angular-mocks.js"></script>
+<script src="vendor/angular-ui-router/release/angular-ui-router.js"></script>
+<script src="vendor/angular-cookies/angular-cookies.js"></script>
+<script src="vendor/angular-animate/angular-animate.js"></script>
+<script src="vendor/angular-resource/angular-resource.js"></script>
+<script src="vendor/lodash/lodash.js"></script>
+<script src="vendor/bootstrap-css/js/bootstrap.min.js"></script>
+<script src="vendor/Chart.js/Chart.js"></script>
+<script src="vendor/angular-chart.js/dist/angular-chart.js"></script>
+<script src="vendor/d3/d3.js"></script>
+<!-- endbower --><!-- endjs -->
+<!-- inject:js -->
+<script src="/../../../xos/core/xoslib/static/js/vendor/ngXosHelpers.js"></script>
+<script src="/.tmp/main.js"></script>
+<!-- endinject -->
diff --git a/views/ngXosViews/contentProvider/src/js/main.js b/views/ngXosViews/contentProvider/src/js/main.js
new file mode 100644
index 0000000..e9142bb
--- /dev/null
+++ b/views/ngXosViews/contentProvider/src/js/main.js
@@ -0,0 +1,388 @@
+'use strict';
+
+angular.module('xos.contentProvider', [
+  'ngResource',
+  'ngCookies',
+  'xos.helpers',
+  'ui.router'
+])
+.config(($stateProvider) => {
+
+  $stateProvider
+  .state('list', {
+    url: '/',
+    template: '<content-provider-list></content-provider-list>',
+  })
+  .state('details', {
+    url: '/contentProvider/:id',
+    template: '<content-provider-detail></content-provider-detail>'
+  })
+  .state('cdn', {
+    url: '/contentProvider/:id/cdn_prefix',
+    template: '<content-provider-cdn></content-provider-cdn>'
+  })
+  .state('server', {
+    url: '/contentProvider/:id/origin_server',
+    template: '<content-provider-server></content-provider-server>'
+  })
+  .state('users', {
+    url: '/contentProvider/:id/users',
+    template: '<content-provider-users></content-provider-users>'
+  });
+})
+.config(function($httpProvider){
+  // add X-CSRFToken header for update, create, delete (!GET)
+  $httpProvider.interceptors.push('SetCSRFToken');
+  $httpProvider.interceptors.push('NoHyperlinks');
+})
+.service('ContentProvider', function($resource){
+  return $resource('/hpcapi/contentproviders/:id/', {id: '@id'}, {
+    'update': {method: 'PUT'}
+  });
+})
+.service('ServiceProvider', function($resource){
+  return $resource('/hpcapi/serviceproviders/:id/', {id: '@id'});
+})
+.service('CdnPrefix', function($resource){
+  return $resource('/hpcapi/cdnprefixs/:id/', {id: '@id'});
+})
+.service('OriginServer', function($resource){
+  return $resource('/hpcapi/originservers/:id/', {id: '@id'});
+})
+.service('User', function($resource){
+  return $resource('/xos/users/:id/', {id: '@id'});
+})
+.directive('cpActions', function(ContentProvider, $location){
+  return {
+    restrict: 'E',
+    scope: {
+      id: '=id',
+    },
+    bindToController: true,
+    controllerAs: 'vm',
+    templateUrl: 'templates/cp_actions.html',
+    controller: function(){
+      this.deleteCp = function(id){
+        ContentProvider.delete({id: id}).$promise
+        .then(function(){
+          $location.url('/');
+        });
+      };
+    }
+  };
+})
+.directive('contentProviderList', function(ContentProvider, _){
+  return {
+    restrict: 'E',
+    controllerAs: 'vm',
+    scope: {},
+    templateUrl: 'templates/cp_list.html',
+    controller: function(){
+      ['Name', 'Description', 'Status', 'Actions']
+      this.tableConfig = {
+        columns: [
+          {
+            label: 'Name',
+            field: 'humanReadableName'
+          },
+          {
+            label: 'Description',
+            field: 'description'
+          },
+          {
+            label: 'Status',
+            field: 'enabled'
+          }
+        ],
+        enableActions: true
+      };
+
+      var self = this;
+
+      ContentProvider.query().$promise
+      .then(function(cp){
+        self.contentProviderList = cp;
+      })
+      .catch(function(e){
+        throw new Error(e);
+      });
+
+      this.deleteCp = function(id){
+        ContentProvider.delete({id: id}).$promise
+        .then(function(){
+          _.remove(self.contentProviderList, {id: id});
+        });
+      };
+    }
+  };
+})
+.directive('contentProviderDetail', function(ContentProvider, ServiceProvider, $stateParams, $location){
+  return {
+    restrict: 'E',
+    controllerAs: 'vm',
+    scope: {},
+    templateUrl: 'templates/cp_detail.html',
+    controller: function(){
+      this.pageName = 'detail';
+      var self = this;
+
+      if($stateParams.id){
+        ContentProvider.get({id: $stateParams.id}).$promise
+        .then(function(cp){
+          self.cp = cp;
+        }).catch(function(e){
+          self.result = {
+            status: 0,
+            msg: e.data.detail
+          };
+        });
+      }
+      else{
+        self.cp = new ContentProvider();
+      }
+
+      ServiceProvider.query().$promise
+      .then(function(sp){
+        self.sp = sp;
+      });
+
+      this.saveContentProvider = function(cp){
+        var p, isNew = false;
+
+        if(cp.id){
+          p = cp.$update();
+        }
+        else{
+          isNew = true;
+          cp.name = cp.humanReadableName;
+          p = cp.$save();
+        }
+
+        p.then(function(res){
+          self.result = {
+            status: 1,
+            msg: 'Content Provider Saved'
+          };
+          if(isNew){
+            $location.url('contentProvider/' + res.id + '/');
+          }
+        })
+        .catch(function(e){
+          self.result = {
+            status: 0,
+            msg: e.data.detail
+          };
+        });
+      };
+    }
+  };
+})
+.directive('contentProviderCdn', function($stateParams, CdnPrefix, ContentProvider){
+  return{
+    restrict: 'E',
+    controllerAs: 'vm',
+    scope: {},
+    templateUrl: 'templates/cp_cdn_prefix.html',
+    controller: function(_){
+      var self = this;
+
+      this.pageName = 'cdn';
+
+      if($stateParams.id){
+        ContentProvider.get({id: $stateParams.id}).$promise
+        .then(function(cp){
+          self.cp = cp;
+        }).catch(function(e){
+          self.result = {
+            status: 0,
+            msg: e.data ? e.data.detail : ''
+          };
+        });
+      }
+
+      CdnPrefix.query().$promise
+      .then(function(prf){
+        self.prf = prf;
+        // console.log(prf, $stateParams.id);
+        // set the active CdnPrefix for this contentProvider
+        self.cp_prf = [];
+        self.cp_prf.push(_.find(prf, {contentProvider: parseInt($stateParams.id)}));
+      }).catch(function(e){
+        self.result = {
+          status: 0,
+          msg: e.data.detail
+        };
+      });
+
+      this.addPrefix = function(prf){
+        prf.contentProvider = $stateParams.id;
+
+        var item = new CdnPrefix(prf);
+
+        item.$save()
+        .then(function(res){
+          self.cp_prf.push(res);
+        })
+        .catch(function(e){
+          self.result = {
+            status: 0,
+            msg: e.data.detail
+          };
+        });
+      };
+
+      this.removePrefix = function(item){
+        item.$delete()
+        .then(function(){
+          _.remove(self.cp_prf, item);
+        })
+        .catch(function(e){
+          self.result = {
+            status: 0,
+            msg: e.data.detail
+          };
+        });
+      };
+    }
+  };
+})
+.directive('contentProviderServer', function($stateParams, OriginServer, ContentProvider){
+  return{
+    restrict: 'E',
+    controllerAs: 'vm',
+    scope: {},
+    templateUrl: 'templates/cp_origin_server.html',
+    controller: function(_){
+      this.pageName = 'server';
+      this.protocols = {'http': 'HTTP', 'rtmp': 'RTMP', 'rtp': 'RTP', 'shout': 'SHOUTcast'};
+
+      var self = this;
+
+      if($stateParams.id){
+        ContentProvider.get({id: $stateParams.id}).$promise
+        .then(function(cp){
+          self.cp = cp;
+        }).catch(function(e){
+          self.result = {
+            status: 0,
+            msg: e.data.detail
+          };
+        });
+      }
+
+      OriginServer.query({contentProvider: $stateParams.id}).$promise
+      .then(function(cp_os){
+        self.cp_os = cp_os;
+      }).catch(function(e){
+        self.result = {
+          status: 0,
+          msg: e.data.detail
+        };
+      });
+
+      this.addOrigin = function(os){
+        os.contentProvider = $stateParams.id;
+
+        var item = new OriginServer(os);
+
+        item.$save()
+        .then(function(res){
+          self.cp_os.push(res);
+        })
+        .catch(function(e){
+          self.result = {
+            status: 0,
+            msg: e.data.detail
+          };
+        });
+      };
+
+      this.removeOrigin = function(item){
+        item.$delete()
+        .then(function(){
+          _.remove(self.cp_os, item);
+        })
+        .catch(function(e){
+          self.result = {
+            status: 0,
+            msg: e.data.detail
+          };
+        });
+      };
+    }
+  };
+})
+.directive('contentProviderUsers', function($stateParams, ContentProvider, User){
+  return{
+    restrict: 'E',
+    controllerAs: 'vm',
+    scope: {},
+    templateUrl: 'templates/cp_user.html',
+    controller: function(_){
+      var self = this;
+
+      this.pageName = 'user';
+
+      this.cp_users = [];
+
+      if($stateParams.id){
+        User.query().$promise
+        .then(function(users){
+          self.users = users;
+          return ContentProvider.get({id: $stateParams.id}).$promise;
+        })
+        .then(function(res){
+          res.users = self.populateUser(res.users, self.users);
+          return res;
+        })
+        .then(function(cp){
+          self.cp = cp;
+        }).catch(function(e){
+          self.result = {
+            status: 0,
+            msg: e.data.detail
+          };
+        });
+      }
+
+      this.populateUser = function(ids, list){
+        for(var i = 0; i < ids.length; i++){
+          ids[i] = _.find(list, {id: ids[i]});
+        }
+        return ids;
+      };
+
+      this.addUserToCp = function(user){
+        self.cp.users.push(user);
+      };
+
+      this.removeUserFromCp = function(user){
+        _.remove(self.cp.users, user);
+      };
+
+      this.saveContentProvider = function(cp){
+
+        // flatten the user to id of array
+        cp.users = _.map(cp.users, 'id');
+
+        cp.$update()
+        .then(function(res){
+
+          self.cp.users = self.populateUser(res.users, self.users);
+
+          self.result = {
+            status: 1,
+            msg: 'Content Provider Saved'
+          };
+
+        })
+        .catch(function(e){
+          self.result = {
+            status: 0,
+            msg: e.data.detail
+          };
+        });
+      };
+    }
+  };
+});
\ No newline at end of file
diff --git a/views/ngXosViews/contentProvider/src/sass/main.scss b/views/ngXosViews/contentProvider/src/sass/main.scss
new file mode 100644
index 0000000..e9d81df
--- /dev/null
+++ b/views/ngXosViews/contentProvider/src/sass/main.scss
@@ -0,0 +1,5 @@
+@import '../../../../style/sass/lib/_variables.scss';
+
+#xosContentProvider {
+  
+}
\ No newline at end of file
diff --git a/views/ngXosViews/contentProvider/src/templates/cp_actions.html b/views/ngXosViews/contentProvider/src/templates/cp_actions.html
new file mode 100644
index 0000000..8c6ae97
--- /dev/null
+++ b/views/ngXosViews/contentProvider/src/templates/cp_actions.html
@@ -0,0 +1,9 @@
+<a href="#/" class="btn btn-default">
+  <i class="icon icon-arrow-left"></i>Back
+</a>
+<a href="#/contentProvider/" class="btn btn-success">
+  <i class="icon icon-plus"></i>Create
+</a>
+<a ng-click="vm.deleteCp(vm.id)" class="btn btn-danger">
+  <i class="icon icon-remove"></i>Remove
+</a>
\ No newline at end of file
diff --git a/views/ngXosViews/contentProvider/src/templates/cp_cdn_prefix.html b/views/ngXosViews/contentProvider/src/templates/cp_cdn_prefix.html
new file mode 100644
index 0000000..8532e6a
--- /dev/null
+++ b/views/ngXosViews/contentProvider/src/templates/cp_cdn_prefix.html
@@ -0,0 +1,55 @@
+<div class="row-fluid">
+  <div class="span6">
+    <h1>{$ vm.cp.humanReadableName $}</h1>
+  </div>
+  <div class="span6 text-right">
+    <cp-actions id="vm.cp.id"></cp-actions>
+  </div>
+</div>
+<hr>
+<div class="row-fluid">
+  <div class="span2">
+    <div ng-include="'templates/cp_side_nav.html'"></div>
+  </div>
+  <div class="span10">
+    <div ng-repeat="item in vm.cp_prf" class="well">
+      <div class="row-fluid">
+        <div class="span4">
+          {{item.humanReadableName}}
+        </div>
+        <div class="span6">
+          <!-- TODO show the name instead that id -->
+          {{item.defaultOriginServer}}
+        </div>
+        <div class="span2">
+          <a ng-click="vm.removePrefix(item)" class="btn btn-danger pull-right">
+            <i class="icon icon-remove"></i>
+          </a>
+        </div>
+      </div>
+    </div>
+    <hr>
+    <form ng-submit="vm.addPrefix(vm.new_prf)">
+      <div class="row-fluid">
+        <div class="span4">
+          <label>Prefix</label>
+          <input type="text" ng-model="vm.new_prf.prefix" required style="max-width: 90%">
+        </div>
+        <div class="span6">
+          <label>Default Origin Server</label>
+          <select ng-model="vm.new_prf.defaultOriginServer" style="max-width: 100%">
+            <option ng-repeat="prf in vm.prf" ng-value="prf.id">{$ prf.humanReadableName $}</option>
+          </select>
+        </div>
+        <div class="span2 text-right">
+          <button class="btn btn-success margin-wells">
+            <i class="icon icon-plus"></i>
+          </button>
+        </div>
+      </div>
+    </form>
+    <div class="alert" ng-show="vm.result" ng-class="{'alert-success': vm.result.status === 1,'alert-error': vm.result.status === 0}">
+      {$ vm.result.msg $}
+    </div>
+  </div>
+</div>
\ No newline at end of file
diff --git a/views/ngXosViews/contentProvider/src/templates/cp_detail.html b/views/ngXosViews/contentProvider/src/templates/cp_detail.html
new file mode 100644
index 0000000..1ae2299
--- /dev/null
+++ b/views/ngXosViews/contentProvider/src/templates/cp_detail.html
@@ -0,0 +1,55 @@
+<div class="row">
+  <div class="col-xs-6">
+    <h1>{$ vm.cp.humanReadableName $}</h1>
+  </div>
+  <div class="col-xs-6 text-right">
+    <cp-actions id="vm.cp.id"></cp-actions>
+  </div>
+</div>
+<hr>
+<div class="row">
+  <div ng-show="vm.cp.id" class="col-xs-2">
+    <div ng-include="'templates/cp_side_nav.html'"></div>
+  </div>
+  <div ng-class="{'col-xs-10': vm.cp.id, 'col-xs-12': !vm.cp.id}">
+  <!-- TODO hide form on not found -->
+    <form ng-submit="vm.saveContentProvider(vm.cp)">
+      <fieldset>
+        <div class="row">
+          <div class="col-xs-6">
+            <label>Name:</label>
+            <input class="form-control" type="text" ng-model="vm.cp.humanReadableName" required/>
+          </div>
+          <div class="col-xs-6">
+            <label class="checkbox">
+              <input class="form-control" type="checkbox" ng-model="vm.cp.enabled" /> Enabled
+            </label>
+          </div>
+        </div>
+        <div class="row">
+          <div class="col-xs-12">
+            <label>Description</label>
+            <textarea class="form-control" ng-model="vm.cp.description"></textarea>
+          </div>
+        </div>
+        <div class="row">
+          <div class="col-xs-12">
+            <label>Service provider</label>
+            <select class="form-control" required ng-model="vm.cp.serviceProvider" ng-options="sp.id as sp.humanReadableName for sp in vm.sp"></select>
+          </div>
+        </div>
+        <div class="row">
+          <div class="col-xs-12">
+            <button class="btn btn-success">
+              <span ng-show="vm.cp.id">Save</span>
+              <span ng-show="!vm.cp.id">Create</span>
+            </button>
+          </div>
+        </div>
+      </fieldset>
+    </form>
+    <div class="alert" ng-show="vm.result" ng-class="{'alert-success': vm.result.status === 1,'alert-danger': vm.result.status === 0}">
+      {$ vm.result.msg $}
+    </div>
+  </div>
+</div>
\ No newline at end of file
diff --git a/views/ngXosViews/contentProvider/src/templates/cp_list.html b/views/ngXosViews/contentProvider/src/templates/cp_list.html
new file mode 100644
index 0000000..9c22e8c
--- /dev/null
+++ b/views/ngXosViews/contentProvider/src/templates/cp_list.html
@@ -0,0 +1,36 @@
+<!-- <xos-table data="vm.contentProviderList" config="vm.config"/> -->
+
+<table class="table table-striped" ng-show="vm.contentProviderList.length > 0">
+  <thead>
+    <tr>
+      <th>
+        Name
+      </th>
+      <th>Description</th>
+      <th>Status</th>
+      <th></th>
+    </tr>
+  </thead>
+  <tr ng-repeat="item in vm.contentProviderList">
+    <td>
+      <a ui-sref="details({ id: item.id })">{$ item.humanReadableName $}</a>
+    </td>
+    <td>
+      {$ item.description $}
+    </td>
+    <td>
+      {$ item.enabled $}
+    </td>
+    <td class="text-right">
+      <a ng-click="vm.deleteCp(item.id)" class="btn btn-danger"><i class="glyphicon glyphicon-remove"></i></a></td>
+  </tr>
+</table>
+<div class="alert alert-error" ng-show="vm.contentProviderList.length == 0">
+  No Content Provider defined
+</div>
+
+<div class="row">
+  <div class="span12 text-right">
+    <a class="btn btn-success"href="#/contentProvider/">Create</a>
+  </div>
+</div>
\ No newline at end of file
diff --git a/views/ngXosViews/contentProvider/src/templates/cp_origin_server.html b/views/ngXosViews/contentProvider/src/templates/cp_origin_server.html
new file mode 100644
index 0000000..49cd175
--- /dev/null
+++ b/views/ngXosViews/contentProvider/src/templates/cp_origin_server.html
@@ -0,0 +1,53 @@
+<div class="row-fluid">
+  <div class="span6">
+    <h1>{$ vm.cp.humanReadableName $}</h1>
+  </div>
+  <div class="span6 text-right">
+    <cp-actions id="vm.cp.id"></cp-actions>
+  </div>
+</div>
+<hr>
+<div class="row-fluid">
+  <div class="span2">
+    <div ng-include="'templates/cp_side_nav.html'"></div>
+  </div>
+  <div class="span10">
+    <div ng-repeat="item in vm.cp_os" class="well">
+      <div class="row-fluid">
+        <div class="span4">
+          {{item.humanReadableName}}
+        </div>
+        <div class="span6">
+          <!-- TODO shoe the name instead that url -->
+          {{item.defaultOriginServer}}
+        </div>
+        <div class="span2">
+          <a ng-click="vm.removeOrigin(item)" class="btn btn-danger pull-right">
+            <i class="icon icon-remove"></i>
+          </a>
+        </div>
+      </div>
+    </div>
+    <hr>
+    <form ng-submit="vm.addOrigin(vm.new_os)">
+      <div class="row-fluid">
+        <div class="span4">
+          <label>Protocol</label>
+          <select ng-model="vm.new_os.protocol" ng-options="k as v for (k,v) in vm.protocols" style="max-width: 100%;"></select>
+        </div>
+        <div class="span6">
+          <label>Url</label>
+          <input type="text" ng-model="vm.new_os.url" required>
+        </div>
+        <div class="span2 text-right">
+          <button class="btn btn-success margin-wells">
+            <i class="icon icon-plus"></i>
+          </button>
+        </div>
+      </div>
+    </form>
+    <div class="alert" ng-show="vm.result" ng-class="{'alert-success': vm.result.status === 1,'alert-error': vm.result.status === 0}">
+      {$ vm.result.msg $}
+    </div>
+  </div>
+</div>
\ No newline at end of file
diff --git a/views/ngXosViews/contentProvider/src/templates/cp_side_nav.html b/views/ngXosViews/contentProvider/src/templates/cp_side_nav.html
new file mode 100644
index 0000000..a2c8633
--- /dev/null
+++ b/views/ngXosViews/contentProvider/src/templates/cp_side_nav.html
@@ -0,0 +1,14 @@
+<ul class="nav nav-list">
+  <li>
+    <a class="btn" ng-class="{'btn-primary': vm.pageName == 'detail'}" href="#/contentProvider/{$ vm.cp.id $}">Details</a>
+  </li>
+  <li>
+    <a class="btn" ng-class="{'btn-primary': vm.pageName == 'cdn'}" href="#/contentProvider/{$ vm.cp.id $}/cdn_prefix">Cdn Prexix</a>
+  </li>
+  <li>
+    <a class="btn" ng-class="{'btn-primary': vm.pageName == 'server'}" href="#/contentProvider/{$ vm.cp.id $}/origin_server">Origin Server</a>
+  </li>
+  <li>
+    <a class="btn" ng-class="{'btn-primary': vm.pageName == 'user'}" href="#/contentProvider/{$ vm.cp.id $}/users">Users</a>
+  </li>
+</ul>
\ No newline at end of file
diff --git a/views/ngXosViews/contentProvider/src/templates/cp_user.html b/views/ngXosViews/contentProvider/src/templates/cp_user.html
new file mode 100644
index 0000000..2b82e1c
--- /dev/null
+++ b/views/ngXosViews/contentProvider/src/templates/cp_user.html
@@ -0,0 +1,51 @@
+<div class="row-fluid">
+  <div class="span6">
+    <h1>{$ vm.cp.humanReadableName $}</h1>
+  </div>
+  <div class="span6 text-right">
+    <cp-actions id="vm.cp.id"></cp-actions>
+  </div>
+</div>
+<hr>
+<div class="row-fluid">
+  <div class="span2">
+    <div ng-include="'templates/cp_side_nav.html'"></div>
+  </div>
+  <div class="span10">
+    <div ng-repeat="item in vm.cp.users" class="well">
+      <div class="row-fluid">
+        <div class="span3">
+          {{item.firstname}}
+        </div>
+        <div class="span3">
+          {{item.lastname}}
+        </div>
+        <div class="span4">
+          {{item.email}}
+        </div>
+        <div class="span2">
+          <a ng-click="vm.removeUserFromCp(item)" class="btn btn-danger pull-right">
+            <i class="icon icon-remove"></i>
+          </a>
+        </div>
+      </div>
+    </div>
+    <hr>
+    <form ng-submit="vm.saveContentProvider(vm.cp)">
+      <div class="row-fluid">
+        <div class="span8">
+          <label>Select user:</label>
+          <select ng-model="vm.user" ng-options="u as u.username for u in vm.users" ng-change="vm.addUserToCp(vm.user)"></select>
+        </div>  
+        <div class="span4 text-right">
+          <button class="btn btn-success margin-wells">
+            Save
+          </button>
+        </div>
+      </div>
+    </form>
+    <div class="alert" ng-show="vm.result" ng-class="{'alert-success': vm.result.status === 1,'alert-error': vm.result.status === 0}">
+      {$ vm.result.msg $}
+    </div>
+  </div>
+</div>
\ No newline at end of file
diff --git a/views/ngXosViews/contentProvider/src/templates/users-list.tpl.html b/views/ngXosViews/contentProvider/src/templates/users-list.tpl.html
new file mode 100644
index 0000000..1fee0e2
--- /dev/null
+++ b/views/ngXosViews/contentProvider/src/templates/users-list.tpl.html
@@ -0,0 +1 @@
+<xos-table config="vm.tableConfig" data="vm.users"></xos-table>
\ No newline at end of file
diff --git a/views/ngXosViews/developer/.bowerrc b/views/ngXosViews/developer/.bowerrc
new file mode 100644
index 0000000..e491038
--- /dev/null
+++ b/views/ngXosViews/developer/.bowerrc
@@ -0,0 +1,3 @@
+{
+  "directory": "src/vendor/"
+}
\ No newline at end of file
diff --git a/views/ngXosViews/developer/.eslintrc b/views/ngXosViews/developer/.eslintrc
new file mode 100644
index 0000000..c852748
--- /dev/null
+++ b/views/ngXosViews/developer/.eslintrc
@@ -0,0 +1,42 @@
+{
+    "ecmaFeatures": {
+        "blockBindings": true,
+        "forOf": true,
+        "destructuring": true,
+        "arrowFunctions": true,
+        "templateStrings": true
+    },
+    "env": { 
+        "browser": true,
+        "node": true,
+        "es6": true
+    },
+    "plugins": [
+        //"angular"
+    ],
+    "rules": {
+        "quotes": [2, "single"],
+        "camelcase": [1, {"properties": "always"}],
+        "no-underscore-dangle": 1,
+        "eqeqeq": [2, "smart"],
+        "no-alert": 1,
+        "key-spacing": [1, { "beforeColon": false, "afterColon": true }],
+        "indent": [2, 2],
+        "no-irregular-whitespace": 1,
+        "eol-last": 0,
+        "max-nested-callbacks": [2, 4],
+        "comma-spacing": [1, {"before": false, "after": true}],
+        "no-trailing-spaces": [1, { skipBlankLines: true }],
+        "no-unused-vars": [1, {"vars": "all", "args": "after-used"}],
+        "new-cap": 0,
+
+        //"angular/ng_module_name": [2, '/^xos\.*[a-z]*$/'],
+        //"angular/ng_controller_name": [2, '/^[a-z].*Ctrl$/'],
+        //"angular/ng_service_name": [2, '/^[A-Z].*Service$/'],
+        //"angular/ng_directive_name": [2, '/^[a-z]+[[A-Z].*]*$/'],
+        //"angular/ng_di": [0, "function or array"]
+    },
+    "globals" :{
+        "angular": true
+    } 
+}
\ No newline at end of file
diff --git a/views/ngXosViews/developer/.gitignore b/views/ngXosViews/developer/.gitignore
new file mode 100644
index 0000000..567aee4
--- /dev/null
+++ b/views/ngXosViews/developer/.gitignore
@@ -0,0 +1,6 @@
+dist/
+src/vendor
+.tmp
+node_modules
+npm-debug.log
+dist/
\ No newline at end of file
diff --git a/views/ngXosViews/developer/bower.json b/views/ngXosViews/developer/bower.json
new file mode 100644
index 0000000..da4d6b3
--- /dev/null
+++ b/views/ngXosViews/developer/bower.json
@@ -0,0 +1,31 @@
+{
+  "name": "xos-developer",
+  "version": "0.0.0",
+  "authors": [
+    "Matteo Scandolo <teo@onlab.us>"
+  ],
+  "description": "The developer view",
+  "license": "MIT",
+  "ignore": [
+    "**/.*",
+    "node_modules",
+    "bower_components",
+    "static/js/vendor/",
+    "test",
+    "tests"
+  ],
+  "dependencies": {
+  },
+  "devDependencies": {
+    "jquery": "2.1.4",
+    "angular-mocks": "1.4.7",
+    "angular": "1.4.7",
+    "angular-ui-router": "0.2.15",
+    "angular-cookies": "1.4.7",
+    "angular-animate": "1.4.7",
+    "angular-resource": "1.4.7",
+    "lodash": "~4.11.1",
+    "bootstrap-css": "3.3.6",
+    "angular-chart.js": "~0.10.2"
+  }
+}
diff --git a/views/ngXosViews/developer/gulp/build.js b/views/ngXosViews/developer/gulp/build.js
new file mode 100644
index 0000000..87e68d8
--- /dev/null
+++ b/views/ngXosViews/developer/gulp/build.js
@@ -0,0 +1,164 @@
+'use strict';
+
+// BUILD
+//
+// The only purpose of this gulpfile is to build a XOS view and copy the correct files into
+// .html => dashboards
+// .js (minified and concat) => static/js
+//
+// The template are parsed and added to js with angular $templateCache
+
+var gulp = require('gulp');
+var ngAnnotate = require('gulp-ng-annotate');
+var uglify = require('gulp-uglify');
+var templateCache = require('gulp-angular-templatecache');
+var runSequence = require('run-sequence');
+var concat = require('gulp-concat-util');
+var del = require('del');
+var wiredep = require('wiredep');
+var angularFilesort = require('gulp-angular-filesort');
+var _ = require('lodash');
+var eslint = require('gulp-eslint');
+var inject = require('gulp-inject');
+var rename = require('gulp-rename');
+var replace = require('gulp-replace');
+var postcss = require('gulp-postcss');
+var autoprefixer = require('autoprefixer');
+var mqpacker = require('css-mqpacker');
+var csswring = require('csswring');
+
+const TEMPLATE_FOOTER = `
+angular.module('xos.developer')
+.run(['$location', function(a){
+  a.path('/');
+}])
+`
+
+module.exports = function(options){
+  
+  // delete previous builded file
+  gulp.task('clean', function(){
+    return del(
+      [
+        options.dashboards + 'xosDeveloper.html',
+        options.static + 'css/xosDeveloper.css'
+      ],
+      {force: true}
+    );
+  });
+
+  // minify css
+  gulp.task('css', function () {
+    var processors = [
+      autoprefixer({browsers: ['last 1 version']}),
+      mqpacker,
+      csswring
+    ];
+
+    gulp.src([
+      `${options.css}**/*.css`,
+      `!${options.css}dev.css`
+    ])
+    .pipe(postcss(processors))
+    .pipe(gulp.dest(options.tmp + '/css/'));
+  });
+
+  // copy css in correct folder
+  gulp.task('copyCss', ['wait'], function(){
+    return gulp.src([`${options.tmp}/css/*.css`])
+    .pipe(concat('xosDeveloper.css'))
+    .pipe(gulp.dest(options.static + 'css/'))
+  });
+
+  // compile and minify scripts
+  gulp.task('scripts', function() {
+    return gulp.src([
+      options.tmp + '**/*.js'
+    ])
+    .pipe(ngAnnotate())
+    .pipe(angularFilesort())
+    .pipe(concat('xosDeveloper.js'))
+    .pipe(concat.header('//Autogenerated, do not edit!!!\n'))
+    .pipe(concat.footer(TEMPLATE_FOOTER))
+    .pipe(uglify())
+    .pipe(gulp.dest(options.static + 'js/'));
+  });
+
+  // set templates in cache
+  gulp.task('templates', function(){
+    return gulp.src('./src/templates/*.html')
+      .pipe(templateCache({
+        module: 'xos.developer',
+        root: 'templates/'
+      }))
+      .pipe(gulp.dest(options.tmp));
+  });
+
+  // copy html index to Django Folder
+  gulp.task('copyHtml', function(){
+    return gulp.src(options.src + 'index.html')
+      // remove dev dependencies from html
+      .pipe(replace(/<!-- bower:css -->(\n^<link.*)*\n<!-- endbower -->/gmi, ''))
+      .pipe(replace(/<!-- bower:js -->(\n^<script.*)*\n<!-- endbower -->/gmi, ''))
+      // injecting minified files
+      .pipe(
+        inject(
+          gulp.src([
+            options.static + 'js/vendor/xosDeveloperVendor.js',
+            options.static + 'js/xosDeveloper.js',
+            options.static + 'css/xosDeveloper.css'
+          ]),
+          {ignorePath: '/../../../xos/core/xoslib'}
+        )
+      )
+      .pipe(rename('xosDeveloper.html'))
+      .pipe(gulp.dest(options.dashboards));
+  });
+
+  // minify vendor js files
+  gulp.task('wiredep', function(){
+    var bowerDeps = wiredep().js;
+    if(!bowerDeps){
+      return;
+    }
+
+    // remove angular (it's already loaded)
+    _.remove(bowerDeps, function(dep){
+      return dep.indexOf('angular/angular.js') !== -1;
+    });
+
+    return gulp.src(bowerDeps)
+      .pipe(concat('xosDeveloperVendor.js'))
+      .pipe(uglify())
+      .pipe(gulp.dest(options.static + 'js/vendor/'));
+  });
+
+  gulp.task('lint', function () {
+    return gulp.src(['src/js/**/*.js'])
+      .pipe(eslint())
+      .pipe(eslint.format())
+      .pipe(eslint.failAfterError());
+  });
+
+  gulp.task('wait', function (cb) {
+    // setTimeout could be any async task
+    setTimeout(function () {
+      cb();
+    }, 1000);
+  });
+
+  gulp.task('build', function() {
+    runSequence(
+      'clean',
+      'sass',
+      'templates',
+      'babel',
+      'scripts',
+      'wiredep',
+      'css',
+      'copyCss',
+      'copyHtml',
+      'cleanTmp'
+    );
+  });
+};
\ No newline at end of file
diff --git a/views/ngXosViews/developer/gulp/server.js b/views/ngXosViews/developer/gulp/server.js
new file mode 100644
index 0000000..1e40a34
--- /dev/null
+++ b/views/ngXosViews/developer/gulp/server.js
@@ -0,0 +1,170 @@
+'use strict';
+
+var gulp = require('gulp');
+var browserSync = require('browser-sync').create();
+var inject = require('gulp-inject');
+var runSequence = require('run-sequence');
+var angularFilesort = require('gulp-angular-filesort');
+var babel = require('gulp-babel');
+var wiredep = require('wiredep').stream;
+var httpProxy = require('http-proxy');
+var del = require('del');
+var sass = require('gulp-sass');
+var fs = require('fs');
+var path = require('path');
+
+const environment = process.env.NODE_ENV;
+
+if(!fs.existsSync(path.join(__dirname, `../../../env/${environment || 'default'}.js`))){
+  if(!environment){
+    throw new Error('You should define a default.js config in /views/env folder.');
+  }
+  else{
+    throw new Error(`Since you are loading a custom environment, you should define a ${environment}.js config in /views/env folder.`);
+  }
+}
+
+var conf = require(path.join(__dirname, `../../../env/${environment || 'default'}.js`));
+
+var proxy = httpProxy.createProxyServer({
+  target: conf.host
+});
+
+
+proxy.on('error', function(error, req, res) {
+  res.writeHead(500, {
+    'Content-Type': 'text/plain'
+  });
+
+  console.error('[Proxy]', error);
+});
+
+module.exports = function(options){
+
+  gulp.task('browser', function() {
+    browserSync.init({
+      startPath: '#/',
+      snippetOptions: {
+        rule: {
+          match: /<!-- browserSync -->/i
+        }
+      },
+      server: {
+        baseDir: options.src,
+        routes: {
+          '/xos/core/xoslib/static/js/vendor': options.helpers,
+          '/xos/core/static': options.static + '../../static/'
+        },
+        middleware: function(req, res, next){
+          if(
+            req.url.indexOf('/api/') !== -1
+          ){
+            if(conf.xoscsrftoken && conf.xossessionid){
+              req.headers.cookie = `xoscsrftoken=${conf.xoscsrftoken}; xossessionid=${conf.xossessionid}`;
+              req.headers['x-csrftoken'] = conf.xoscsrftoken;
+            }
+            proxy.web(req, res);
+          }
+          else{
+            next();
+          }
+        }
+      }
+    });
+
+    gulp.watch(options.src + 'js/**/*.js', ['js-watch']);
+    gulp.watch(options.src + 'vendor/**/*.js', ['bower'], function(){
+      browserSync.reload();
+    });
+    gulp.watch(options.src + '**/*.html', function(){
+      browserSync.reload();
+    });
+    gulp.watch(options.css + '**/*.css', function(){
+      browserSync.reload();
+    });
+    gulp.watch(`${options.sass}/**/*.scss`, ['sass'], function(){
+      browserSync.reload();
+    });
+
+    gulp.watch([
+      options.helpers + 'ngXosHelpers.js',
+      options.static + '../../static/xosNgLib.css'
+    ], function(){
+      browserSync.reload();
+    });
+  });
+
+  // compile sass
+  gulp.task('sass', function () {
+    return gulp.src(`${options.sass}/**/*.scss`)
+      .pipe(sass().on('error', sass.logError))
+      .pipe(gulp.dest(options.css));
+  });
+
+  // transpile js with sourceMaps
+  gulp.task('babel', function(){
+    return gulp.src(options.scripts + '**/*.js')
+      .pipe(babel({sourceMaps: true}))
+      .pipe(gulp.dest(options.tmp));
+  });
+
+  // inject scripts
+  gulp.task('injectScript', ['cleanTmp', 'babel'], function(){
+    return gulp.src(options.src + 'index.html')
+      .pipe(
+        inject(
+          gulp.src([
+            options.tmp + '**/*.js',
+            options.helpers + 'ngXosHelpers.js'
+          ])
+          .pipe(angularFilesort()),
+          {
+            ignorePath: [options.src, '/../../ngXosLib']
+          }
+        )
+      )
+      .pipe(gulp.dest(options.src));
+  });
+
+  // inject CSS
+  gulp.task('injectCss', function(){
+    return gulp.src(options.src + 'index.html')
+      .pipe(
+        inject(
+          gulp.src([
+            options.src + 'css/*.css',
+            options.static + '../../static/xosNgLib.css'
+          ]),
+          {
+            ignorePath: [options.src]
+          }
+          )
+        )
+      .pipe(gulp.dest(options.src));
+  });
+
+  // inject bower dependencies with wiredep
+  gulp.task('bower', function () {
+    return gulp.src(options.src + 'index.html')
+    .pipe(wiredep({devDependencies: true}))
+    .pipe(gulp.dest(options.src));
+  });
+
+  gulp.task('js-watch', ['injectScript'], function(){
+    browserSync.reload();
+  });
+
+  gulp.task('cleanTmp', function(){
+    return del([options.tmp + '**/*']);
+  });
+
+  gulp.task('serve', function() {
+    runSequence(
+      'sass',
+      'bower',
+      'injectScript',
+      'injectCss',
+      ['browser']
+    );
+  });
+};
diff --git a/views/ngXosViews/developer/gulpfile.js b/views/ngXosViews/developer/gulpfile.js
new file mode 100644
index 0000000..08df554
--- /dev/null
+++ b/views/ngXosViews/developer/gulpfile.js
@@ -0,0 +1,26 @@
+'use strict';
+
+var gulp = require('gulp');
+var wrench = require('wrench');
+
+var options = {
+  src: 'src/',
+  css: 'src/css/',
+  sass: 'src/sass/',
+  scripts: 'src/js/',
+  tmp: 'src/.tmp',
+  dist: 'dist/',
+  api: '../../ngXosLib/api/',
+  helpers: '../../../xos/core/xoslib/static/js/vendor/',
+  static: '../../../xos/core/xoslib/static/', // this is the django static folder
+  dashboards: '../../../xos/core/xoslib/dashboards/' // this is the django html folder
+};
+
+wrench.readdirSyncRecursive('./gulp')
+.map(function(file) {
+  require('./gulp/' + file)(options);
+});
+
+gulp.task('default', function () {
+  gulp.start('build');
+});
diff --git a/views/ngXosViews/developer/karma.conf.js b/views/ngXosViews/developer/karma.conf.js
new file mode 100644
index 0000000..4123be9
--- /dev/null
+++ b/views/ngXosViews/developer/karma.conf.js
@@ -0,0 +1,88 @@
+// Karma configuration
+// Generated on Tue Oct 06 2015 09:27:10 GMT+0000 (UTC)
+
+/* eslint indent: [2,2], quotes: [2, "single"]*/
+
+/*eslint-disable*/
+var wiredep = require('wiredep');
+var path = require('path');
+
+var bowerComponents = wiredep( {devDependencies: true} )[ 'js' ].map(function( file ){
+  return path.relative(process.cwd(), file);
+});
+
+module.exports = function(config) {
+/*eslint-enable*/
+  config.set({
+
+    // base path that will be used to resolve all patterns (eg. files, exclude)
+    basePath: '',
+
+
+    // frameworks to use
+    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
+    frameworks: ['jasmine'],
+
+
+    // list of files / patterns to load in the browser
+    files: bowerComponents.concat([
+      '../../../xos/core/xoslib/static/js/vendor/ngXosVendor.js',
+      '../../../xos/core/xoslib/static/js/vendor/ngXosHelpers.js',
+      'src/js/**/*.js',
+      'spec/**/*.mock.js',
+      'spec/**/*.test.js',
+      'src/**/*.html'
+    ]),
+
+
+    // list of files to exclude
+    exclude: [
+    ],
+
+
+    // preprocess matching files before serving them to the browser
+    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
+    preprocessors: {
+      'src/js/**/*.js': ['babel'],
+      'spec/**/*.test.js': ['babel'],
+      'src/**/*.html': ['ng-html2js']
+    },
+
+    ngHtml2JsPreprocessor: {
+      stripPrefix: 'src/', //strip the src path from template url (http://stackoverflow.com/questions/22869668/karma-unexpected-request-when-testing-angular-directive-even-with-ng-html2js)
+      moduleName: 'templates' // define the template module name
+    },
+
+    // test results reporter to use
+    // possible values: 'dots', 'progress'
+    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
+    reporters: ['mocha'],
+
+
+    // web server port
+    port: 9876,
+
+
+    // enable / disable colors in the output (reporters and logs)
+    colors: true,
+
+
+    // level of logging
+    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+    logLevel: config.LOG_INFO,
+
+
+    // enable / disable watching file and executing tests whenever any file changes
+    autoWatch: true,
+
+
+    // start these browsers
+    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
+    browsers: ['PhantomJS'],
+
+
+    // Continuous Integration mode
+    // if true, Karma captures browsers, runs the tests and exits
+    singleRun: false
+  });
+};
diff --git a/views/ngXosViews/developer/mocks/config.json b/views/ngXosViews/developer/mocks/config.json
new file mode 100644
index 0000000..827ddb5
--- /dev/null
+++ b/views/ngXosViews/developer/mocks/config.json
@@ -0,0 +1,14 @@
+{
+  "endpoints": [
+    {
+      "url": "slicesplus",
+      "base": "api/utility/",
+      "methods": ["GET"]
+    },
+    {
+      "url": "instances",
+      "base": "api/core/",
+      "methods": ["GET"]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/views/ngXosViews/developer/mocks/multi-site/instances.json b/views/ngXosViews/developer/mocks/multi-site/instances.json
new file mode 100644
index 0000000..6e1fad7
--- /dev/null
+++ b/views/ngXosViews/developer/mocks/multi-site/instances.json
@@ -0,0 +1,77 @@
+[
+   {
+      "humanReadableName":"Instance 1",
+      "id":1,
+      "slice":"1"
+   },
+   {
+      "humanReadableName":"Instance 2",
+      "id":2,
+      "slice":"1"
+   },
+   {
+      "humanReadableName":"Instance 3",
+      "id":3,
+      "slice":"1"
+   },
+   {
+      "humanReadableName":"Instance 4",
+      "id":4,
+      "slice":"1"
+   },
+   {
+      "humanReadableName":"Instance 5",
+      "id":5,
+      "slice":"1"
+   },
+   {
+      "humanReadableName":"Instance 6",
+      "id":6,
+      "slice":"1"
+   },
+   {
+      "humanReadableName":"Instance 7",
+      "id":7,
+      "slice":"1"
+   },
+   {
+      "humanReadableName":"Instance 8",
+      "id":8,
+      "slice":"1"
+   },
+   {
+      "humanReadableName":"Instance 9",
+      "id":9,
+      "slice":"1"
+   },
+   {
+      "humanReadableName":"Instance 10",
+      "id":10,
+      "slice":"2"
+   },
+   {
+      "humanReadableName":"Instance 11",
+      "id":11,
+      "slice":"2"
+   },
+   {
+      "humanReadableName":"Instance 12",
+      "id":12,
+      "slice":"2"
+   },
+   {
+      "humanReadableName":"Instance 13",
+      "id":13,
+      "slice":"2"
+   },
+   {
+      "humanReadableName":"Instance 14",
+      "id":14,
+      "slice":"2"
+   },
+   {
+      "humanReadableName":"Instance 15",
+      "id":15,
+      "slice":"2"
+   }
+]
\ No newline at end of file
diff --git a/views/ngXosViews/developer/mocks/multi-site/slicesplus.json b/views/ngXosViews/developer/mocks/multi-site/slicesplus.json
new file mode 100644
index 0000000..ba05da2
--- /dev/null
+++ b/views/ngXosViews/developer/mocks/multi-site/slicesplus.json
@@ -0,0 +1,48 @@
+[
+   {
+      "id":1,
+      "name":"mysite_management1",
+      "site":1,
+      "max_instances":10,
+      "networks":[1, 2],
+      "current_user_roles":[
+         "Admin"
+      ],
+      "instance_distribution":{
+         "mysite": 4,
+         "anothersite": 5
+      },
+      "instance_distribution_ready":{
+         "mysite": 3,
+         "anothersite": 1
+      },
+      "instance_total":9,
+      "instance_total_ready":4,
+      "instance_status":{
+
+      }
+   },
+   {
+      "id":2,
+      "name":"mysite_management2",
+      "site":1,
+      "max_instances":10,
+      "networks":[2, 3, 4],
+      "current_user_roles":[
+         "Access"
+      ],
+      "instance_distribution":{
+        "mysite": 3,
+        "anothersite": 3
+      },
+      "instance_distribution_ready":{
+         "mysite": 2,
+         "anothersite": 3
+      },
+      "instance_total":6,
+      "instance_total_ready":5,
+      "instance_status":{
+
+      }
+   }
+]
\ No newline at end of file
diff --git a/views/ngXosViews/developer/mocks/single-site/instances.json b/views/ngXosViews/developer/mocks/single-site/instances.json
new file mode 100644
index 0000000..6e1fad7
--- /dev/null
+++ b/views/ngXosViews/developer/mocks/single-site/instances.json
@@ -0,0 +1,77 @@
+[
+   {
+      "humanReadableName":"Instance 1",
+      "id":1,
+      "slice":"1"
+   },
+   {
+      "humanReadableName":"Instance 2",
+      "id":2,
+      "slice":"1"
+   },
+   {
+      "humanReadableName":"Instance 3",
+      "id":3,
+      "slice":"1"
+   },
+   {
+      "humanReadableName":"Instance 4",
+      "id":4,
+      "slice":"1"
+   },
+   {
+      "humanReadableName":"Instance 5",
+      "id":5,
+      "slice":"1"
+   },
+   {
+      "humanReadableName":"Instance 6",
+      "id":6,
+      "slice":"1"
+   },
+   {
+      "humanReadableName":"Instance 7",
+      "id":7,
+      "slice":"1"
+   },
+   {
+      "humanReadableName":"Instance 8",
+      "id":8,
+      "slice":"1"
+   },
+   {
+      "humanReadableName":"Instance 9",
+      "id":9,
+      "slice":"1"
+   },
+   {
+      "humanReadableName":"Instance 10",
+      "id":10,
+      "slice":"2"
+   },
+   {
+      "humanReadableName":"Instance 11",
+      "id":11,
+      "slice":"2"
+   },
+   {
+      "humanReadableName":"Instance 12",
+      "id":12,
+      "slice":"2"
+   },
+   {
+      "humanReadableName":"Instance 13",
+      "id":13,
+      "slice":"2"
+   },
+   {
+      "humanReadableName":"Instance 14",
+      "id":14,
+      "slice":"2"
+   },
+   {
+      "humanReadableName":"Instance 15",
+      "id":15,
+      "slice":"2"
+   }
+]
\ No newline at end of file
diff --git a/views/ngXosViews/developer/mocks/single-site/slicesplus.json b/views/ngXosViews/developer/mocks/single-site/slicesplus.json
new file mode 100644
index 0000000..9f7802c
--- /dev/null
+++ b/views/ngXosViews/developer/mocks/single-site/slicesplus.json
@@ -0,0 +1,44 @@
+[
+   {
+      "id":1,
+      "name":"mysite_management1",
+      "site":1,
+      "max_instances":10,
+      "networks":[1, 2],
+      "current_user_roles":[
+         "Admin"
+      ],
+      "instance_distribution":{
+         "mysite": 9
+      },
+      "instance_distribution_ready":{
+         "mysite": 4
+      },
+      "instance_total":9,
+      "instance_total_ready":4,
+      "instance_status":{
+
+      }
+   },
+   {
+      "id":2,
+      "name":"mysite_management2",
+      "site":1,
+      "max_instances":10,
+      "networks":[2, 3, 4],
+      "current_user_roles":[
+         "Access"
+      ],
+      "instance_distribution":{
+        "mysite": 6
+      },
+      "instance_distribution_ready":{
+         "mysite": 5
+      },
+      "instance_total":6,
+      "instance_total_ready":5,
+      "instance_status":{
+
+      }
+   }
+]
\ No newline at end of file
diff --git a/views/ngXosViews/developer/package.json b/views/ngXosViews/developer/package.json
new file mode 100644
index 0000000..f28682f
--- /dev/null
+++ b/views/ngXosViews/developer/package.json
@@ -0,0 +1,65 @@
+{
+  "name": "xos-developer",
+  "version": "1.0.0",
+  "description": "Angular Application for XOS, created with generator-xos",
+  "scripts": {
+    "prestart": "npm install && bower install",
+    "start": "gulp serve",
+    "prebuild": "npm install && bower install",
+    "build": "gulp",
+    "test": "karma start",
+    "test:ci": "karma start --single-run",
+    "lint": "eslint src/js/",
+    "single-site": "easy-mocker -c ./mocks/config.json -d ./mocks/single-site",
+    "multi-site": "easy-mocker -c ./mocks/config.json -d ./mocks/multi-site"
+  },
+  "keywords": [
+    "XOS",
+    "Angular",
+    "XOSlib"
+  ],
+  "author": "Matteo Scandolo",
+  "license": "MIT",
+  "dependencies": {},
+  "devDependencies": {
+    "autoprefixer": "^6.3.3",
+    "browser-sync": "^2.9.11",
+    "css-mqpacker": "^4.0.0",
+    "csswring": "^4.2.1",
+    "del": "^2.0.2",
+    "easy-mocker": "^1.3.0",
+    "eslint": "^1.8.0",
+    "eslint-plugin-angular": "linkmesrl/eslint-plugin-angular",
+    "gulp": "^3.9.0",
+    "gulp-angular-filesort": "^1.1.1",
+    "gulp-angular-templatecache": "^1.8.0",
+    "gulp-babel": "^5.3.0",
+    "gulp-concat": "^2.6.0",
+    "gulp-concat-util": "^0.5.5",
+    "gulp-eslint": "^1.0.0",
+    "gulp-inject": "^3.0.0",
+    "gulp-minify-html": "^1.0.4",
+    "gulp-ng-annotate": "^1.1.0",
+    "gulp-postcss": "^6.0.1",
+    "gulp-rename": "^1.2.2",
+    "gulp-replace": "^0.5.4",
+    "gulp-sass": "^2.2.0",
+    "gulp-uglify": "^1.4.2",
+    "http-proxy": "^1.12.0",
+    "ink-docstrap": "^0.5.2",
+    "jasmine-core": "~2.3.4",
+    "karma": "^0.13.14",
+    "karma-babel-preprocessor": "~5.2.2",
+    "karma-coverage": "^0.5.3",
+    "karma-jasmine": "~0.3.6",
+    "karma-mocha-reporter": "~1.1.1",
+    "karma-ng-html2js-preprocessor": "^0.2.0",
+    "karma-phantomjs-launcher": "~0.2.1",
+    "lodash": "^3.10.1",
+    "phantomjs": "^1.9.19",
+    "proxy-middleware": "^0.15.0",
+    "run-sequence": "^1.1.4",
+    "wiredep": "^3.0.0-beta",
+    "wrench": "^1.5.8"
+  }
+}
diff --git a/views/ngXosViews/developer/spec/sample.test.js b/views/ngXosViews/developer/spec/sample.test.js
new file mode 100644
index 0000000..8db0a13
--- /dev/null
+++ b/views/ngXosViews/developer/spec/sample.test.js
@@ -0,0 +1,37 @@
+'use strict';
+
+describe('The User List', () => {
+  
+  var scope, element, isolatedScope, httpBackend;
+
+  beforeEach(module('xos.developer'));
+  beforeEach(module('templates'));
+
+  beforeEach(inject(function($httpBackend, $compile, $rootScope){
+    
+    httpBackend = $httpBackend;
+    // Setting up mock request
+    $httpBackend.expectGET('/api/core/users/?no_hyperlinks=1').respond([
+      {
+        email: 'teo@onlab.us',
+        firstname: 'Matteo',
+        lastname: 'Scandolo' 
+      }
+    ]);
+  
+    scope = $rootScope.$new();
+    element = angular.element('<users-list></users-list>');
+    $compile(element)(scope);
+    scope.$digest();
+    isolatedScope = element.isolateScope().vm;
+  }));
+
+  xit('should load 1 users', () => {
+    httpBackend.flush();
+    expect(isolatedScope.users.length).toBe(1);
+    expect(isolatedScope.users[0].email).toEqual('teo@onlab.us');
+    expect(isolatedScope.users[0].firstname).toEqual('Matteo');
+    expect(isolatedScope.users[0].lastname).toEqual('Scandolo');
+  });
+
+});
\ No newline at end of file
diff --git a/views/ngXosViews/developer/src/css/main.css b/views/ngXosViews/developer/src/css/main.css
new file mode 100644
index 0000000..7b15d7c
--- /dev/null
+++ b/views/ngXosViews/developer/src/css/main.css
@@ -0,0 +1,18 @@
+#xosDeveloper .pie-legend li {
+  display: inline-block;
+  white-space: nowrap;
+  position: relative;
+  margin-bottom: 4px;
+  border-radius: 5px;
+  padding: 2px 8px 2px 28px;
+  font-size: smaller;
+  cursor: default; }
+
+#xosDeveloper .pie-legend-icon {
+  display: block;
+  position: absolute;
+  left: 0;
+  top: 0;
+  width: 20px;
+  height: 20px;
+  border-radius: 5px; }
diff --git a/views/ngXosViews/developer/src/index.html b/views/ngXosViews/developer/src/index.html
new file mode 100644
index 0000000..f8946e9
--- /dev/null
+++ b/views/ngXosViews/developer/src/index.html
@@ -0,0 +1,33 @@
+<!-- browserSync -->
+<!-- bower:css -->
+<link rel="stylesheet" href="vendor/bootstrap-css/css/bootstrap.min.css" />
+<link rel="stylesheet" href="vendor/angular-chart.js/dist/angular-chart.css" />
+<!-- endbower -->
+<!-- endcss -->
+<!-- inject:css -->
+<link rel="stylesheet" href="/css/main.css">
+<link rel="stylesheet" href="/../../../xos/core/static/xosNgLib.css">
+<!-- endinject -->
+
+<div ng-app="xos.developer" id="xosDeveloper" class="container-fluid">
+  <div ui-view></div>
+</div>
+
+<!-- bower:js -->
+<script src="vendor/jquery/dist/jquery.js"></script>
+<script src="vendor/angular/angular.js"></script>
+<script src="vendor/angular-mocks/angular-mocks.js"></script>
+<script src="vendor/angular-ui-router/release/angular-ui-router.js"></script>
+<script src="vendor/angular-cookies/angular-cookies.js"></script>
+<script src="vendor/angular-animate/angular-animate.js"></script>
+<script src="vendor/angular-resource/angular-resource.js"></script>
+<script src="vendor/lodash/lodash.js"></script>
+<script src="vendor/bootstrap-css/js/bootstrap.min.js"></script>
+<script src="vendor/Chart.js/Chart.js"></script>
+<script src="vendor/angular-chart.js/dist/angular-chart.js"></script>
+<!-- endbower -->
+<!-- endjs -->
+<!-- inject:js -->
+<script src="/../../../xos/core/xoslib/static/js/vendor/ngXosHelpers.js"></script>
+<script src="/.tmp/main.js"></script>
+<!-- endinject -->
\ No newline at end of file
diff --git a/views/ngXosViews/developer/src/js/main.js b/views/ngXosViews/developer/src/js/main.js
new file mode 100644
index 0000000..b09f1ef
--- /dev/null
+++ b/views/ngXosViews/developer/src/js/main.js
@@ -0,0 +1,135 @@
+'use strict';
+
+angular.module('xos.developer', [
+  'ngResource',
+  'ngCookies',
+  'ui.router',
+  'xos.helpers'
+])
+.config(($stateProvider) => {
+  $stateProvider
+  .state('developer', {
+    url: '/',
+    template: '<developer-dashboard></developer-dashboard>'
+  });
+})
+.config(function($httpProvider){
+  $httpProvider.interceptors.push('NoHyperlinks');
+})
+.directive('developerDashboard', function(){
+  return {
+    restrict: 'E',
+    scope: {},
+    bindToController: true,
+    controllerAs: 'vm',
+    templateUrl: 'templates/developer-dashboard.tpl.html',
+    controller: function($scope, $timeout, SlicesPlus, Instances, _){
+
+      this.instancePerSliceConfig = {
+        data: [],
+        groupBy: 'slice',
+        legend: true,
+        classes: 'instance per slice',
+        labelFormatter: (labels) => {
+          return labels.map(l => {
+            return _.find(this.slices, {id: parseInt(l)}).name
+          });
+        }
+      };
+
+      this.instancePerSiteConfig = {
+        data: [],
+        groupBy: 'site',
+        legend: true,
+        classes: 'instance per site',
+      };
+
+      this.networkPerSliceConfig = {
+        data: [],
+        groupBy: 'name',
+        legend: true,
+        classes: 'network per slice',
+      };
+
+      this.tableConfig = {
+        columns: [
+          {
+            label: 'Name',
+            prop: 'name'
+          },
+          {
+            label: 'Privileges',
+            prop: 'current_user_roles',
+            type: 'array'
+          },
+          {
+            label: 'Number of Instances (active / total)',
+            type: 'custom',
+            formatter: item => `${item.instance_total_ready} / ${item.instance_total}`
+          },
+          {
+            label: 'Active Instances per Sites',
+            type: 'object',
+            prop: 'instance_distribution_ready'
+          },
+          {
+            label: 'Total Instances per Sites',
+            type: 'object',
+            prop: 'instance_distribution'
+          },
+          {
+            label: 'Networks',
+            type: 'custom',
+            formatter: item => item.networks.length
+          }
+        ]
+      };
+
+      // retrieving user list
+      SlicesPlus.query().$promise
+      .then((slices) => {
+        this.slices = slices;
+        return Instances.query().$promise
+      })
+      .then(instances => {
+        
+        // formatting data in this way sucks.
+        // Provide a way to just pass data to the chart if needed [smartPie].
+
+        // retrieving network per slices
+        let networkPerSlice = _.reduce(this.slices, (list, s) => {
+          if( s.networks.length > 1){
+            // push s.neworks.length values in array
+            for(let i = 0; i < s.networks.length; i++){
+              list.push({id: s.id, name: s.name, network: s.networks[i]})
+            }
+          }
+          else if ( s.networks.length === 1){
+            list.push({id: s.id, name: s.name, network: s.networks[0]});
+          }
+          return list;
+        }, []);
+
+        // retrieving instance distribution across sites
+        let instancePerSite = _.reduce(this.slices, (list, s) => {
+          _.forEach(Object.keys(s.instance_distribution), k => {
+            for(let i = 0; i < s.instance_distribution[k]; i++){
+              list.push({site: k, instance: i})
+            }
+          })
+          return list;
+        }, []);
+
+        this.sites = Object.keys(_.groupBy(instancePerSite, 'site'));
+
+        this.instancePerSliceConfig.data = instances;
+        this.instancePerSiteConfig.data = instancePerSite;
+        this.networkPerSliceConfig.data = networkPerSlice;
+
+      })
+      .catch((e) => {
+        throw new Error(e);
+      });
+    }
+  };
+});
\ No newline at end of file
diff --git a/views/ngXosViews/developer/src/sass/main.scss b/views/ngXosViews/developer/src/sass/main.scss
new file mode 100644
index 0000000..043a334
--- /dev/null
+++ b/views/ngXosViews/developer/src/sass/main.scss
@@ -0,0 +1,25 @@
+@import '../../../../style/sass/lib/_variables.scss';
+
+#xosDeveloper {
+
+  .pie-legend li {
+      display: inline-block;
+    white-space: nowrap;
+    position: relative;
+    margin-bottom: 4px;
+    border-radius: 5px;
+    padding: 2px 8px 2px 28px;
+    font-size: smaller;
+    cursor: default;
+  }
+
+  .pie-legend-icon {
+    display: block;
+    position: absolute;
+    left: 0;
+    top: 0;
+    width: 20px;
+    height: 20px;
+    border-radius: 5px;
+  }
+}
\ No newline at end of file
diff --git a/views/ngXosViews/developer/src/templates/developer-dashboard.tpl.html b/views/ngXosViews/developer/src/templates/developer-dashboard.tpl.html
new file mode 100644
index 0000000..fd82f77
--- /dev/null
+++ b/views/ngXosViews/developer/src/templates/developer-dashboard.tpl.html
@@ -0,0 +1,16 @@
+<div class="row">
+  <div ng-class="{'col-sm-4': vm.sites.length > 1 || !vm.sites, 'col-sm-6': vm.sites.length <= 1}" class="text-center">
+    <h3>Instances per Slice</h3>
+    <xos-smart-pie ng-if="vm.instancePerSliceConfig.data.length > 0" config="vm.instancePerSliceConfig"></xos-smart-pie>
+  </div>
+  <div ng-if="vm.sites.length > 1" class="col-sm-4 text-center">
+    <h3>Instances per Site</h3>
+    <xos-smart-pie ng-if="vm.instancePerSiteConfig.data.length > 0" config="vm.instancePerSiteConfig"></xos-smart-pie>
+  </div>
+  <div ng-class="{'col-sm-4': vm.sites.length > 1 || !vm.sites, 'col-sm-6': vm.sites.length <= 1}" class="text-center">
+    <h3>Network per Slice</h3>
+    <xos-smart-pie ng-if="vm.networkPerSliceConfig.data.length > 0" config="vm.networkPerSliceConfig"></xos-smart-pie>
+  </div>
+</div>
+
+<xos-table config="vm.tableConfig" data="vm.slices"></xos-table>
\ No newline at end of file
diff --git a/views/ngXosViews/developer/src/templates/users-list.tpl.html b/views/ngXosViews/developer/src/templates/users-list.tpl.html
new file mode 100644
index 0000000..1fee0e2
--- /dev/null
+++ b/views/ngXosViews/developer/src/templates/users-list.tpl.html
@@ -0,0 +1 @@
+<xos-table config="vm.tableConfig" data="vm.users"></xos-table>
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/.bowerrc b/views/ngXosViews/diagnostic/.bowerrc
new file mode 100644
index 0000000..e491038
--- /dev/null
+++ b/views/ngXosViews/diagnostic/.bowerrc
@@ -0,0 +1,3 @@
+{
+  "directory": "src/vendor/"
+}
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/.eslintrc b/views/ngXosViews/diagnostic/.eslintrc
new file mode 100644
index 0000000..c852748
--- /dev/null
+++ b/views/ngXosViews/diagnostic/.eslintrc
@@ -0,0 +1,42 @@
+{
+    "ecmaFeatures": {
+        "blockBindings": true,
+        "forOf": true,
+        "destructuring": true,
+        "arrowFunctions": true,
+        "templateStrings": true
+    },
+    "env": { 
+        "browser": true,
+        "node": true,
+        "es6": true
+    },
+    "plugins": [
+        //"angular"
+    ],
+    "rules": {
+        "quotes": [2, "single"],
+        "camelcase": [1, {"properties": "always"}],
+        "no-underscore-dangle": 1,
+        "eqeqeq": [2, "smart"],
+        "no-alert": 1,
+        "key-spacing": [1, { "beforeColon": false, "afterColon": true }],
+        "indent": [2, 2],
+        "no-irregular-whitespace": 1,
+        "eol-last": 0,
+        "max-nested-callbacks": [2, 4],
+        "comma-spacing": [1, {"before": false, "after": true}],
+        "no-trailing-spaces": [1, { skipBlankLines: true }],
+        "no-unused-vars": [1, {"vars": "all", "args": "after-used"}],
+        "new-cap": 0,
+
+        //"angular/ng_module_name": [2, '/^xos\.*[a-z]*$/'],
+        //"angular/ng_controller_name": [2, '/^[a-z].*Ctrl$/'],
+        //"angular/ng_service_name": [2, '/^[A-Z].*Service$/'],
+        //"angular/ng_directive_name": [2, '/^[a-z]+[[A-Z].*]*$/'],
+        //"angular/ng_di": [0, "function or array"]
+    },
+    "globals" :{
+        "angular": true
+    } 
+}
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/.gitignore b/views/ngXosViews/diagnostic/.gitignore
new file mode 100644
index 0000000..567aee4
--- /dev/null
+++ b/views/ngXosViews/diagnostic/.gitignore
@@ -0,0 +1,6 @@
+dist/
+src/vendor
+.tmp
+node_modules
+npm-debug.log
+dist/
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/bower.json b/views/ngXosViews/diagnostic/bower.json
new file mode 100644
index 0000000..9279b8e
--- /dev/null
+++ b/views/ngXosViews/diagnostic/bower.json
@@ -0,0 +1,34 @@
+{
+  "name": "xos-diagnostic",
+  "version": "0.0.0",
+  "authors": [
+    "Matteo Scandolo <teo@onlab.us>"
+  ],
+  "description": "The diagnostic view",
+  "license": "MIT",
+  "ignore": [
+    "**/.*",
+    "node_modules",
+    "bower_components",
+    "static/js/vendor/",
+    "test",
+    "tests"
+  ],
+  "dependencies": {},
+  "devDependencies": {
+    "jquery": "2.1.4",
+    "angular-mocks": "1.4.7",
+    "angular": "1.4.7",
+    "angular-ui-router": "0.2.15",
+    "angular-cookies": "1.4.7",
+    "angular-animate": "1.4.7",
+    "angular-resource": "1.4.7",
+    "lodash": "~4.11.1",
+    "bootstrap-css": "3.3.6",
+    "angular-chart.js": "~0.10.2",
+    "d3": "~3.5.17"
+  },
+  "resolutions": {
+    "angular": "1.4.7"
+  }
+}
diff --git a/views/ngXosViews/diagnostic/gulp/build.js b/views/ngXosViews/diagnostic/gulp/build.js
new file mode 100644
index 0000000..20bbc14
--- /dev/null
+++ b/views/ngXosViews/diagnostic/gulp/build.js
@@ -0,0 +1,164 @@
+'use strict';
+
+// BUILD
+//
+// The only purpose of this gulpfile is to build a XOS view and copy the correct files into
+// .html => dashboards
+// .js (minified and concat) => static/js
+//
+// The template are parsed and added to js with angular $templateCache
+
+var gulp = require('gulp');
+var ngAnnotate = require('gulp-ng-annotate');
+var uglify = require('gulp-uglify');
+var templateCache = require('gulp-angular-templatecache');
+var runSequence = require('run-sequence');
+var concat = require('gulp-concat-util');
+var del = require('del');
+var wiredep = require('wiredep');
+var angularFilesort = require('gulp-angular-filesort');
+var _ = require('lodash');
+var eslint = require('gulp-eslint');
+var inject = require('gulp-inject');
+var rename = require('gulp-rename');
+var replace = require('gulp-replace');
+var postcss = require('gulp-postcss');
+var autoprefixer = require('autoprefixer');
+var mqpacker = require('css-mqpacker');
+var csswring = require('csswring');
+
+const TEMPLATE_FOOTER = `
+angular.module('xos.diagnostic')
+.run(['$location', function(a){
+  a.path('/');
+}])
+`
+
+module.exports = function(options){
+  
+  // delete previous builded file
+  gulp.task('clean', function(){
+    return del(
+      [
+        options.dashboards + 'xosDiagnostic.html',
+        options.static + 'css/xosDiagnostic.css'
+      ],
+      {force: true}
+    );
+  });
+
+  // minify css
+  gulp.task('css', function () {
+    var processors = [
+      autoprefixer({browsers: ['last 1 version']}),
+      mqpacker,
+      csswring
+    ];
+
+    gulp.src([
+      `${options.css}**/*.css`,
+      `!${options.css}dev.css`
+    ])
+    .pipe(postcss(processors))
+    .pipe(gulp.dest(options.tmp + '/css/'));
+  });
+
+  // copy css in correct folder
+  gulp.task('copyCss', ['wait'], function(){
+    return gulp.src([`${options.tmp}/css/*.css`])
+    .pipe(concat('xosDiagnostic.css'))
+    .pipe(gulp.dest(options.static + 'css/'))
+  });
+
+  // compile and minify scripts
+  gulp.task('scripts', function() {
+    return gulp.src([
+      options.tmp + '**/*.js'
+    ])
+    .pipe(ngAnnotate())
+    .pipe(angularFilesort())
+    .pipe(concat('xosDiagnostic.js'))
+    .pipe(concat.header('//Autogenerated, do not edit!!!\n'))
+    .pipe(concat.footer(TEMPLATE_FOOTER))
+    .pipe(uglify())
+    .pipe(gulp.dest(options.static + 'js/'));
+  });
+
+  // set templates in cache
+  gulp.task('templates', function(){
+    return gulp.src('./src/templates/*.html')
+      .pipe(templateCache({
+        module: 'xos.diagnostic',
+        root: 'templates/'
+      }))
+      .pipe(gulp.dest(options.tmp));
+  });
+
+  // copy html index to Django Folder
+  gulp.task('copyHtml', function(){
+    return gulp.src(options.src + 'index.html')
+      // remove dev dependencies from html
+      .pipe(replace(/<!-- bower:css -->(\n^<link.*)*\n<!-- endbower -->/gmi, ''))
+      .pipe(replace(/<!-- bower:js -->(\n^<script.*)*\n<!-- endbower -->/gmi, ''))
+      // injecting minified files
+      .pipe(
+        inject(
+          gulp.src([
+            options.static + 'js/vendor/xosDiagnosticVendor.js',
+            options.static + 'js/xosDiagnostic.js',
+            options.static + 'css/xosDiagnostic.css'
+          ]),
+          {ignorePath: '/../../../xos/core/xoslib'}
+        )
+      )
+      .pipe(rename('xosDiagnostic.html'))
+      .pipe(gulp.dest(options.dashboards));
+  });
+
+  // minify vendor js files
+  gulp.task('wiredep', function(){
+    var bowerDeps = wiredep().js;
+    if(!bowerDeps){
+      return;
+    }
+
+    // remove angular (it's already loaded)
+    _.remove(bowerDeps, function(dep){
+      return dep.indexOf('angular/angular.js') !== -1;
+    });
+
+    return gulp.src(bowerDeps)
+      .pipe(concat('xosDiagnosticVendor.js'))
+      .pipe(uglify())
+      .pipe(gulp.dest(options.static + 'js/vendor/'));
+  });
+
+  gulp.task('lint', function () {
+    return gulp.src(['src/js/**/*.js'])
+      .pipe(eslint())
+      .pipe(eslint.format())
+      .pipe(eslint.failAfterError());
+  });
+
+  gulp.task('wait', function (cb) {
+    // setTimeout could be any async task
+    setTimeout(function () {
+      cb();
+    }, 1000);
+  });
+
+  gulp.task('build', function() {
+    runSequence(
+      'clean',
+      'sass',
+      'templates',
+      'babel',
+      'scripts',
+      'wiredep',
+      'css',
+      'copyCss',
+      'copyHtml',
+      'cleanTmp'
+    );
+  });
+};
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/gulp/server.js b/views/ngXosViews/diagnostic/gulp/server.js
new file mode 100644
index 0000000..fbc605b
--- /dev/null
+++ b/views/ngXosViews/diagnostic/gulp/server.js
@@ -0,0 +1,171 @@
+'use strict';
+
+var gulp = require('gulp');
+var browserSync = require('browser-sync').create();
+var inject = require('gulp-inject');
+var runSequence = require('run-sequence');
+var angularFilesort = require('gulp-angular-filesort');
+var babel = require('gulp-babel');
+var wiredep = require('wiredep').stream;
+var httpProxy = require('http-proxy');
+var del = require('del');
+var sass = require('gulp-sass');
+var fs = require('fs');
+var path = require('path');
+
+const environment = process.env.NODE_ENV;
+
+if(!fs.existsSync(path.join(__dirname, `../../../env/${environment || 'default'}.js`))){
+  if(!environment){
+    throw new Error('You should define a default.js config in /views/env folder.');
+  }
+  else{
+    throw new Error(`Since you are loading a custom environment, you should define a ${environment}.js config in /views/env folder.`);
+  }
+}
+
+var conf = require(path.join(__dirname, `../../../env/${environment || 'default'}.js`));
+
+var proxy = httpProxy.createProxyServer({
+  target: conf.host
+});
+
+
+proxy.on('error', function(error, req, res) {
+  res.writeHead(500, {
+    'Content-Type': 'text/plain'
+  });
+
+  console.error('[Proxy]', error);
+});
+
+module.exports = function(options){
+
+  gulp.task('browser', function() {
+    browserSync.init({
+      startPath: '#/',
+      snippetOptions: {
+        rule: {
+          match: /<!-- browserSync -->/i
+        }
+      },
+      server: {
+        baseDir: options.src,
+        routes: {
+          '/xos/core/xoslib/static/js/vendor': options.helpers,
+          '/xos/core/static': options.static + '../../static/'
+        },
+        middleware: function(req, res, next){
+          if(
+            req.url.indexOf('/?no_hyperlinks') !== -1 ||
+            req.url.indexOf('/api/') !== -1
+          ){
+            if(conf.xoscsrftoken && conf.xossessionid){
+              req.headers.cookie = `xoscsrftoken=${conf.xoscsrftoken}; xossessionid=${conf.xossessionid}`;
+              req.headers['x-csrftoken'] = conf.xoscsrftoken;
+            }
+            proxy.web(req, res);
+          }
+          else{
+            next();
+          }
+        }
+      }
+    });
+
+    gulp.watch(options.src + 'js/**/*.js', ['js-watch']);
+    gulp.watch(options.src + 'vendor/**/*.js', ['bower'], function(){
+      browserSync.reload();
+    });
+    gulp.watch(options.src + '**/*.html', function(){
+      browserSync.reload();
+    });
+    gulp.watch(options.css + '**/*.css', function(){
+      browserSync.reload();
+    });
+    gulp.watch(`${options.sass}/**/*.scss`, ['sass'], function(){
+      browserSync.reload();
+    });
+
+    gulp.watch([
+      options.helpers + 'ngXosHelpers.js',
+      options.static + '../../static/xosNgLib.css'
+    ], function(){
+      browserSync.reload();
+    });
+  });
+
+  // compile sass
+  gulp.task('sass', function () {
+    return gulp.src(`${options.sass}/**/*.scss`)
+      .pipe(sass().on('error', sass.logError))
+      .pipe(gulp.dest(options.css));
+  });
+
+  // transpile js with sourceMaps
+  gulp.task('babel', function(){
+    return gulp.src(options.scripts + '**/*.js')
+      .pipe(babel({sourceMaps: true}))
+      .pipe(gulp.dest(options.tmp));
+  });
+
+  // inject scripts
+  gulp.task('injectScript', ['cleanTmp', 'babel'], function(){
+    return gulp.src(options.src + 'index.html')
+      .pipe(
+        inject(
+          gulp.src([
+            options.tmp + '**/*.js',
+            options.helpers + 'ngXosHelpers.js'
+          ])
+          .pipe(angularFilesort()),
+          {
+            ignorePath: [options.src, '/../../ngXosLib']
+          }
+        )
+      )
+      .pipe(gulp.dest(options.src));
+  });
+
+  // inject CSS
+  gulp.task('injectCss', function(){
+    return gulp.src(options.src + 'index.html')
+      .pipe(
+        inject(
+          gulp.src([
+            options.src + 'css/*.css',
+            options.static + '../../static/xosNgLib.css'
+          ]),
+          {
+            ignorePath: [options.src]
+          }
+          )
+        )
+      .pipe(gulp.dest(options.src));
+  });
+
+  // inject bower dependencies with wiredep
+  gulp.task('bower', function () {
+    return gulp.src(options.src + 'index.html')
+    .pipe(wiredep({devDependencies: true}))
+    .pipe(gulp.dest(options.src));
+  });
+
+  gulp.task('js-watch', ['injectScript'], function(){
+    browserSync.reload();
+  });
+
+  gulp.task('cleanTmp', function(){
+    return del([options.tmp + '**/*']);
+  });
+
+  gulp.task('serve', function() {
+    runSequence(
+      'sass',
+      'bower',
+      'injectScript',
+      'injectCss',
+      ['browser']
+    );
+  });
+};
diff --git a/views/ngXosViews/diagnostic/gulpfile.js b/views/ngXosViews/diagnostic/gulpfile.js
new file mode 100644
index 0000000..08df554
--- /dev/null
+++ b/views/ngXosViews/diagnostic/gulpfile.js
@@ -0,0 +1,26 @@
+'use strict';
+
+var gulp = require('gulp');
+var wrench = require('wrench');
+
+var options = {
+  src: 'src/',
+  css: 'src/css/',
+  sass: 'src/sass/',
+  scripts: 'src/js/',
+  tmp: 'src/.tmp',
+  dist: 'dist/',
+  api: '../../ngXosLib/api/',
+  helpers: '../../../xos/core/xoslib/static/js/vendor/',
+  static: '../../../xos/core/xoslib/static/', // this is the django static folder
+  dashboards: '../../../xos/core/xoslib/dashboards/' // this is the django html folder
+};
+
+wrench.readdirSyncRecursive('./gulp')
+.map(function(file) {
+  require('./gulp/' + file)(options);
+});
+
+gulp.task('default', function () {
+  gulp.start('build');
+});
diff --git a/views/ngXosViews/diagnostic/karma.conf.js b/views/ngXosViews/diagnostic/karma.conf.js
new file mode 100644
index 0000000..44283c8
--- /dev/null
+++ b/views/ngXosViews/diagnostic/karma.conf.js
@@ -0,0 +1,89 @@
+// Karma configuration
+// Generated on Tue Oct 06 2015 09:27:10 GMT+0000 (UTC)
+
+/* eslint indent: [2,2], quotes: [2, "single"]*/
+
+/*eslint-disable*/
+var wiredep = require('wiredep');
+var path = require('path');
+
+var bowerComponents = wiredep( {devDependencies: true} )[ 'js' ].map(function( file ){
+  return path.relative(process.cwd(), file);
+});
+
+module.exports = function(config) {
+/*eslint-enable*/
+  config.set({
+
+    // base path that will be used to resolve all patterns (eg. files, exclude)
+    basePath: '',
+
+
+    // frameworks to use
+    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
+    frameworks: ['jasmine'],
+
+
+    // list of files / patterns to load in the browser
+    files: bowerComponents.concat([
+      '../../../xos/core/xoslib/static/js/vendor/ngXosVendor.js',
+      '../../../xos/core/xoslib/static/js/vendor/ngXosHelpers.js',
+      'src/js/main.js',
+      'src/js/**/*.js',
+      'spec/**/*.mock.js',
+      'spec/**/*.test.js',
+      'src/**/*.html'
+    ]),
+
+
+    // list of files to exclude
+    exclude: [
+    ],
+
+
+    // preprocess matching files before serving them to the browser
+    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
+    preprocessors: {
+      'src/js/**/*.js': ['babel'],
+      'spec/**/*.test.js': ['babel'],
+      'src/**/*.html': ['ng-html2js']
+    },
+
+    ngHtml2JsPreprocessor: {
+      stripPrefix: 'src/', //strip the src path from template url (http://stackoverflow.com/questions/22869668/karma-unexpected-request-when-testing-angular-directive-even-with-ng-html2js)
+      moduleName: 'templates' // define the template module name
+    },
+
+    // test results reporter to use
+    // possible values: 'dots', 'progress'
+    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
+    reporters: ['mocha'],
+
+
+    // web server port
+    port: 9876,
+
+
+    // enable / disable colors in the output (reporters and logs)
+    colors: true,
+
+
+    // level of logging
+    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+    logLevel: config.LOG_INFO,
+
+
+    // enable / disable watching file and executing tests whenever any file changes
+    autoWatch: true,
+
+
+    // start these browsers
+    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
+    browsers: ['PhantomJS'],
+
+
+    // Continuous Integration mode
+    // if true, Karma captures browsers, runs the tests and exits
+    singleRun: false
+  });
+};
diff --git a/views/ngXosViews/diagnostic/mocks/data/cordsubscriber.json b/views/ngXosViews/diagnostic/mocks/data/cordsubscriber.json
new file mode 100644
index 0000000..9f5919a
--- /dev/null
+++ b/views/ngXosViews/diagnostic/mocks/data/cordsubscriber.json
@@ -0,0 +1,35 @@
+[
+     {
+          "humanReadableName": "cordSubscriber-1", 
+          "id": 1, 
+          "service_specific_id": "123", 
+          "s_tag": "222", 
+          "c_tag": "432", 
+          "vcpe_id": 4, 
+          "instance": 1, 
+          "instance_name": "mysite_vcpe", 
+          "image": 1, 
+          "image_name": "trusty-server-multi-nic", 
+          "firewall_enable": false, 
+          "firewall_rules": "accept all anywhere anywhere", 
+          "url_filter_enable": false, 
+          "url_filter_rules": "allow all", 
+          "url_filter_level": "R", 
+          "bbs_account": null, 
+          "ssh_command": null, 
+          "vcpe_synced": false, 
+          "cdn_enable": false, 
+          "vbng_id": 5, 
+          "routeable_subnet": "", 
+          "nat_ip": null, 
+          "lan_ip": null, 
+          "wan_ip": null, 
+          "private_ip": null, 
+          "wan_mac": null, 
+          "wan_container_ip": "10.0.1.24", 
+          "uplink_speed": "1000000000", 
+          "downlink_speed": "1000000000", 
+          "status": "copyrightviolation", 
+          "enable_uverse": true
+     }
+]
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/mocks/data/instances.json b/views/ngXosViews/diagnostic/mocks/data/instances.json
new file mode 100644
index 0000000..d9814f3
--- /dev/null
+++ b/views/ngXosViews/diagnostic/mocks/data/instances.json
@@ -0,0 +1,322 @@
+[
+    {
+        "humanReadableName": "sflow_service_instance", 
+        "id": 8, 
+        "created": "2016-02-17T22:01:02.663Z", 
+        "updated": "2016-02-17T22:05:58.270Z", 
+        "enacted": "2016-02-17T22:05:58.281Z", 
+        "policed": "2016-02-17T22:05:59.137Z", 
+        "backend_register": "{\"next_run\": 0, \"last_success\": 1455746758.281283, \"exponent\": 0}", 
+        "backend_status": "1 - OK", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": false, 
+        "instance_id": "instance-00000005", 
+        "instance_uuid": "42b75cb7-7205-4a68-9100-b2c1e3ea69b5", 
+        "name": "sflow_service_instance", 
+        "instance_name": "mysite_sflow-8", 
+        "ip": "130.127.133.93", 
+        "image": 1, 
+        "creator": 1, 
+        "slice": 8, 
+        "deployment": 1, 
+        "node": 2, 
+        "numberCores": 0, 
+        "flavor": 1, 
+        "userData": null, 
+        "networks": [
+            21, 
+            20
+        ]
+    }, 
+    {
+        "humanReadableName": "client1", 
+        "id": 4, 
+        "created": "2016-02-17T22:00:58.284Z", 
+        "updated": "2016-02-17T22:03:56.863Z", 
+        "enacted": "2016-02-17T22:03:56.872Z", 
+        "policed": "2016-02-17T22:03:56.953Z", 
+        "backend_register": "{\"next_run\": 0, \"last_success\": 1455746636.872524, \"exponent\": 0}", 
+        "backend_status": "1 - OK", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": false, 
+        "instance_id": "instance-00000001", 
+        "instance_uuid": "cca264bb-8136-45dd-a5a3-41902a4bcf5b", 
+        "name": "client1", 
+        "instance_name": "mysite_clients-4", 
+        "ip": "130.127.133.90", 
+        "image": 1, 
+        "creator": 1, 
+        "slice": 3, 
+        "deployment": 1, 
+        "node": 1, 
+        "numberCores": 0, 
+        "flavor": 1, 
+        "userData": null, 
+        "networks": [
+            10, 
+            4, 
+            11
+        ]
+    }, 
+    {
+        "humanReadableName": "mysite_ceilometer-7", 
+        "id": 7, 
+        "created": "2016-02-17T22:01:02.550Z", 
+        "updated": "2016-02-17T22:06:15.667Z", 
+        "enacted": "2016-02-17T22:06:15.672Z", 
+        "policed": "2016-02-17T22:06:15.818Z", 
+        "backend_register": "{\"next_run\": 0, \"last_success\": 1455746775.672678, \"exponent\": 0}", 
+        "backend_status": "1 - OK", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": false, 
+        "instance_id": "instance-00000006", 
+        "instance_uuid": "23d04870-5e0d-4b03-b2e2-032cbfec56fa", 
+        "name": "mysite_ceilometer", 
+        "instance_name": "mysite_ceilometer-7", 
+        "ip": "130.127.133.90", 
+        "image": 1, 
+        "creator": 1, 
+        "slice": 7, 
+        "deployment": 1, 
+        "node": 1, 
+        "numberCores": 0, 
+        "flavor": 1, 
+        "userData": null, 
+        "networks": [
+            18, 
+            19, 
+            5
+        ]
+    }, 
+    {
+        "humanReadableName": "onos_app_1", 
+        "id": 3, 
+        "created": "2016-02-17T22:00:58.258Z", 
+        "updated": "2016-02-17T22:04:43.301Z", 
+        "enacted": "2016-02-17T22:04:43.309Z", 
+        "policed": "2016-02-17T22:04:43.943Z", 
+        "backend_register": "{\"next_run\": 0, \"last_success\": 1455746683.309321, \"exponent\": 0}", 
+        "backend_status": "1 - OK", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": false, 
+        "instance_id": "instance-00000002", 
+        "instance_uuid": "c21dc52f-363e-47f6-9a2a-489c0af392fb", 
+        "name": "onos_app_1", 
+        "instance_name": "mysite_onos_vbng-3", 
+        "ip": "130.127.133.59", 
+        "image": 1, 
+        "creator": 1, 
+        "slice": 5, 
+        "deployment": 1, 
+        "node": 3, 
+        "numberCores": 0, 
+        "flavor": 1, 
+        "userData": null, 
+        "networks": [
+            15, 
+            14
+        ]
+    }, 
+    {
+        "humanReadableName": "ovs_vbng", 
+        "id": 6, 
+        "created": "2016-02-17T22:00:58.567Z", 
+        "updated": "2016-02-17T22:06:33.495Z", 
+        "enacted": "2016-02-17T22:06:33.562Z", 
+        "policed": "2016-02-17T22:06:34.619Z", 
+        "backend_register": "{\"next_run\": 0, \"last_success\": 1455746793.562678, \"exponent\": 0}", 
+        "backend_status": "1 - OK", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": false, 
+        "instance_id": "instance-00000007", 
+        "instance_uuid": "81dc0638-c9bc-4396-be17-ea805050e388", 
+        "name": "ovs_vbng", 
+        "instance_name": "mysite_vbng-6", 
+        "ip": "130.127.133.59", 
+        "image": 1, 
+        "creator": 1, 
+        "slice": 2, 
+        "deployment": 1, 
+        "node": 3, 
+        "numberCores": 0, 
+        "flavor": 1, 
+        "userData": null, 
+        "networks": [
+            8, 
+            3, 
+            9
+        ]
+    }, 
+    {
+        "humanReadableName": "onos_app_2", 
+        "id": 2, 
+        "created": "2016-02-17T22:00:58.199Z", 
+        "updated": "2016-02-17T22:05:26.512Z", 
+        "enacted": "2016-02-17T22:05:26.521Z", 
+        "policed": "2016-02-17T22:05:26.730Z", 
+        "backend_register": "{\"next_run\": 0, \"last_success\": 1455746726.521625, \"exponent\": 0}", 
+        "backend_status": "1 - OK", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": false, 
+        "instance_id": "instance-00000003", 
+        "instance_uuid": "8e3f00c5-0957-4505-ae69-e03e41306435", 
+        "name": "onos_app_2", 
+        "instance_name": "mysite_onos_volt-2", 
+        "ip": "130.127.133.93", 
+        "image": 1, 
+        "creator": 1, 
+        "slice": 4, 
+        "deployment": 1, 
+        "node": 2, 
+        "numberCores": 0, 
+        "flavor": 1, 
+        "userData": null, 
+        "networks": [
+            12, 
+            13
+        ]
+    }, 
+    {
+        "humanReadableName": "ovs_volt", 
+        "id": 5, 
+        "created": "2016-02-17T22:00:58.540Z", 
+        "updated": "2016-02-17T22:06:50.666Z", 
+        "enacted": "2016-02-17T22:06:50.680Z", 
+        "policed": "2016-02-17T22:06:51.342Z", 
+        "backend_register": "{\"next_run\": 0, \"last_success\": 1455746810.680553, \"exponent\": 0}", 
+        "backend_status": "1 - OK", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": false, 
+        "instance_id": "instance-00000008", 
+        "instance_uuid": "49c08f77-f05a-4c9b-859c-20c2982b19c6", 
+        "name": "ovs_volt", 
+        "instance_name": "mysite_volt-5", 
+        "ip": "130.127.133.93", 
+        "image": 1, 
+        "creator": 1, 
+        "slice": 6, 
+        "deployment": 1, 
+        "node": 2, 
+        "numberCores": 0, 
+        "flavor": 1, 
+        "userData": null, 
+        "networks": [
+            17, 
+            16, 
+            4
+        ]
+    }, 
+    {
+        "humanReadableName": "mysite_vsg-1", 
+        "id": 1, 
+        "created": "2016-02-17T22:00:58.015Z", 
+        "updated": "2016-02-17T22:05:44.877Z", 
+        "enacted": "2016-02-17T22:05:44.887Z", 
+        "policed": "2016-02-17T22:05:45.538Z", 
+        "backend_register": "{\"next_run\": 0, \"last_success\": 1455746744.887768, \"exponent\": 0}", 
+        "backend_status": "1 - OK", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": false, 
+        "instance_id": "instance-00000004", 
+        "instance_uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746", 
+        "name": "mysite_vsg", 
+        "instance_name": "mysite_vsg-1", 
+        "ip": "130.127.133.90", 
+        "image": 1, 
+        "creator": 1, 
+        "slice": 1, 
+        "deployment": 1, 
+        "node": 1, 
+        "numberCores": 0, 
+        "flavor": 1, 
+        "userData": null, 
+        "networks": [
+            1, 
+            6, 
+            7, 
+            2
+        ]
+    },
+    {
+        "humanReadableName": "mysite_vsg-2", 
+        "id": 11, 
+        "created": "2016-02-17T22:00:58.015Z", 
+        "updated": "2016-02-17T22:05:44.877Z", 
+        "enacted": "2016-02-17T22:05:44.887Z", 
+        "policed": "2016-02-17T22:05:45.538Z", 
+        "backend_register": "{\"next_run\": 0, \"last_success\": 1455746744.887768, \"exponent\": 0}", 
+        "backend_status": "0 - Provisioning in progress", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": false, 
+        "instance_id": "instance-00000004", 
+        "instance_uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746", 
+        "name": "mysite_vsg", 
+        "instance_name": "mysite_vsg-2", 
+        "ip": "130.127.133.90", 
+        "image": 1, 
+        "creator": 1, 
+        "slice": 1, 
+        "deployment": 1, 
+        "node": 2, 
+        "numberCores": 0, 
+        "flavor": 1, 
+        "userData": null, 
+        "networks": [
+            1, 
+            6, 
+            7, 
+            2
+        ]
+    },
+    {
+        "humanReadableName": "mysite_vsg-3", 
+        "id": 12, 
+        "created": "2016-02-17T22:00:58.015Z", 
+        "updated": "2016-02-17T22:05:44.877Z", 
+        "enacted": "2016-02-17T22:05:44.887Z", 
+        "policed": "2016-02-17T22:05:45.538Z", 
+        "backend_register": "{\"next_run\": 0, \"last_success\": 1455746744.887768, \"exponent\": 0}", 
+        "backend_status": "2 - Error", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": false, 
+        "instance_id": "instance-00000004", 
+        "instance_uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746", 
+        "name": "mysite_vsg", 
+        "instance_name": "mysite_vsg-3", 
+        "ip": "130.127.133.90", 
+        "image": 1, 
+        "creator": 1, 
+        "slice": 1, 
+        "deployment": 1, 
+        "node": 3, 
+        "numberCores": 0, 
+        "flavor": 1, 
+        "userData": null, 
+        "networks": [
+            1, 
+            6, 
+            7, 
+            2
+        ]
+    }
+]
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/mocks/data/meterstatistics.json b/views/ngXosViews/diagnostic/mocks/data/meterstatistics.json
new file mode 100644
index 0000000..8678222
--- /dev/null
+++ b/views/ngXosViews/diagnostic/mocks/data/meterstatistics.json
@@ -0,0 +1,242 @@
+[
+    {
+        "resource_name": "vcpe-222-432", 
+        "resource": "vcpe-222-432", 
+        "description": "Existence of vcpe instance", 
+        "resource_id": "vcpe-222-432", 
+        "meter": "vcpe", 
+        "unit": "vcpe", 
+        "category": "VCPE", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 1.0, 
+        "time": "2016-02-24T00:21:28", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "vcpe-222-432", 
+        "resource": "vcpe-222-432", 
+        "description": "Number of entries in DNS cache", 
+        "resource_id": "vcpe-222-432", 
+        "meter": "vcpe.dns.cache.size", 
+        "unit": "entries", 
+        "category": "VCPE", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 150.0, 
+        "time": "2016-02-24T00:21:28", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "vcpe-222-432", 
+        "resource": "vcpe-222-432", 
+        "description": "Unexpired entries that were thrown out of cache", 
+        "resource_id": "vcpe-222-432", 
+        "meter": "vcpe.dns.replaced_unexpired_entries", 
+        "unit": "entries", 
+        "category": "VCPE", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 0.0, 
+        "time": "2016-02-24T00:21:28", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "vcpe-222-432", 
+        "resource": "vcpe-222-432", 
+        "description": "Number of cache hits", 
+        "resource_id": "vcpe-222-432", 
+        "meter": "vcpe.dns.queries_answered_locally", 
+        "unit": "queries", 
+        "category": "VCPE", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 0.0, 
+        "time": "2016-02-24T00:21:28", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "vcpe-222-432", 
+        "resource": "vcpe-222-432", 
+        "description": "Number of cache misses", 
+        "resource_id": "vcpe-222-432", 
+        "meter": "vcpe.dns.queries_forwarded", 
+        "unit": "queries", 
+        "category": "VCPE", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 0.0, 
+        "time": "2016-02-24T00:21:28", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "vcpe-222-432", 
+        "resource": "vcpe-222-432", 
+        "description": "Volume of RAM", 
+        "resource_id": "vcpe-222-432", 
+        "meter": "memory", 
+        "unit": "MB", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 2099.0, 
+        "time": "2016-02-24T00:21:28", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "vcpe-222-432", 
+        "resource": "vcpe-222-432", 
+        "description": "Volume of RAM used", 
+        "resource_id": "vcpe-222-432", 
+        "meter": "memory.usage", 
+        "unit": "MB", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 31.1625, 
+        "time": "2016-02-24T00:21:28", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "vcpe-222-432", 
+        "resource": "vcpe-222-432", 
+        "description": "Average CPU utilization", 
+        "resource_id": "vcpe-222-432", 
+        "meter": "cpu_util", 
+        "unit": "%", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 4.845000000000001, 
+        "time": "2016-02-24T00:21:28", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    },
+    {
+        "resource_name": "vcpe-222-432-eth0", 
+        "resource": "vcpe-222-432-eth0", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface", 
+        "resource_id": "vcpe-222-432-eth0", 
+        "meter": "network.incoming.bytes.rate", 
+        "unit": "B/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 0.0, 
+        "time": "2016-02-24T01:19:25", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "vcpe-222-432-eth0", 
+        "resource": "vcpe-222-432-eth0", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface", 
+        "resource_id": "vcpe-222-432-eth0", 
+        "meter": "network.outgoing.bytes.rate", 
+        "unit": "B/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 0.00030304561114446413, 
+        "time": "2016-02-24T01:19:25", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "vcpe-222-432-eth0", 
+        "resource": "vcpe-222-432-eth0", 
+        "description": "Average rate per sec of incoming packets on a VM network interface", 
+        "resource_id": "vcpe-222-432-eth0", 
+        "meter": "network.incoming.packets.rate", 
+        "unit": "packet/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 0.0, 
+        "time": "2016-02-24T01:19:25", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "vcpe-222-432-eth0", 
+        "resource": "vcpe-222-432-eth0", 
+        "description": "Average rate per sec of outgoing packets on a VM network interface", 
+        "resource_id": "vcpe-222-432-eth0", 
+        "meter": "network.outgoing.packets.rate", 
+        "unit": "packet/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 4.714042840024997e-06, 
+        "time": "2016-02-24T01:19:25", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    },
+     {
+        "resource_name": "vcpe-222-432-eth1", 
+        "resource": "vcpe-222-432-eth1", 
+        "description": "Average rate per sec of incoming bytes on a VM network interface", 
+        "resource_id": "vcpe-222-432-eth1", 
+        "meter": "network.incoming.bytes.rate", 
+        "unit": "B/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 0.0, 
+        "time": "2016-02-24T01:19:25", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "vcpe-222-432-eth1", 
+        "resource": "vcpe-222-432-eth1", 
+        "description": "Average rate per sec of outgoing bytes on a VM network interface", 
+        "resource_id": "vcpe-222-432-eth1", 
+        "meter": "network.outgoing.bytes.rate", 
+        "unit": "B/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 0.00030304561114446413, 
+        "time": "2016-02-24T01:19:25", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "vcpe-222-432-eth1", 
+        "resource": "vcpe-222-432-eth1", 
+        "description": "Average rate per sec of incoming packets on a VM network interface", 
+        "resource_id": "vcpe-222-432-eth1", 
+        "meter": "network.incoming.packets.rate", 
+        "unit": "packet/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 0.0, 
+        "time": "2016-02-24T01:19:25", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "vcpe-222-432-eth1", 
+        "resource": "vcpe-222-432-eth1", 
+        "description": "Average rate per sec of outgoing packets on a VM network interface", 
+        "resource_id": "vcpe-222-432-eth1", 
+        "meter": "network.outgoing.packets.rate", 
+        "unit": "packet/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 4.714042840024997e-06, 
+        "time": "2016-02-24T01:19:25", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }
+]
diff --git a/views/ngXosViews/diagnostic/mocks/data/nodes.json b/views/ngXosViews/diagnostic/mocks/data/nodes.json
new file mode 100644
index 0000000..03ca1da
--- /dev/null
+++ b/views/ngXosViews/diagnostic/mocks/data/nodes.json
@@ -0,0 +1,53 @@
+[
+    {
+        "humanReadableName": "cp-3.teone-cord.xos-pg0.clemson.cloudlab.us", 
+        "id": 3, 
+        "created": "2016-02-17T22:00:53.717Z", 
+        "updated": "2016-02-17T22:01:24.890Z", 
+        "enacted": null, 
+        "policed": null, 
+        "backend_register": "{}", 
+        "backend_status": "0 - Provisioning in progress", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": true, 
+        "name": "cp-3.teone-cord.xos-pg0.clemson.cloudlab.us", 
+        "site_deployment": "http://clnode067.clemson.cloudlab.us:9999/xos/sitedeployments/1/", 
+        "site": "http://clnode067.clemson.cloudlab.us:9999/xos/sites/1/"
+    }, 
+    {
+        "humanReadableName": "cp-2.teone-cord.xos-pg0.clemson.cloudlab.us", 
+        "id": 2, 
+        "created": "2016-02-17T22:00:53.701Z", 
+        "updated": "2016-02-17T22:01:24.891Z", 
+        "enacted": null, 
+        "policed": null, 
+        "backend_register": "{}", 
+        "backend_status": "0 - Provisioning in progress", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": true, 
+        "name": "cp-2.teone-cord.xos-pg0.clemson.cloudlab.us", 
+        "site_deployment": "http://clnode067.clemson.cloudlab.us:9999/xos/sitedeployments/1/", 
+        "site": "http://clnode067.clemson.cloudlab.us:9999/xos/sites/1/"
+    }, 
+    {
+        "humanReadableName": "cp-1.teone-cord.xos-pg0.clemson.cloudlab.us", 
+        "id": 1, 
+        "created": "2016-02-17T22:00:53.680Z", 
+        "updated": "2016-02-17T22:01:24.892Z", 
+        "enacted": null, 
+        "policed": null, 
+        "backend_register": "{}", 
+        "backend_status": "0 - Provisioning in progress", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": true, 
+        "name": "cp-1.teone-cord.xos-pg0.clemson.cloudlab.us", 
+        "site_deployment": "http://clnode067.clemson.cloudlab.us:9999/xos/sitedeployments/1/", 
+        "site": "http://clnode067.clemson.cloudlab.us:9999/xos/sites/1/"
+    }
+]
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/mocks/data/services.json b/views/ngXosViews/diagnostic/mocks/data/services.json
new file mode 100644
index 0000000..b3ae7b7
--- /dev/null
+++ b/views/ngXosViews/diagnostic/mocks/data/services.json
@@ -0,0 +1,177 @@
+[
+   {
+      "humanReadableName":"service_vbng",
+      "id":1,
+      "created":"2016-02-17T19:36:04.242Z",
+      "updated":"2016-02-17T19:36:04.242Z",
+      "enacted":null,
+      "policed":null,
+      "backend_register":"{}",
+      "backend_status":"0 - Provisioning in progress",
+      "deleted":false,
+      "write_protect":false,
+      "lazy_blocked":false,
+      "no_sync":false,
+      "description":null,
+      "enabled":true,
+      "kind":"vBNG",
+      "name":"service_vbng",
+      "versionNumber":"",
+      "published":true,
+      "view_url":"/admin/cord/vbngservice/$id$/",
+      "icon_url":null,
+      "public_key":null,
+      "service_specific_id":null,
+      "service_specific_attribute":null
+   },
+   {
+      "humanReadableName":"service_vsg",
+      "id":2,
+      "created":"2016-02-17T19:36:04.249Z",
+      "updated":"2016-02-17T19:36:04.249Z",
+      "enacted":null,
+      "policed":null,
+      "backend_register":"{}",
+      "backend_status":"0 - Provisioning in progress",
+      "deleted":false,
+      "write_protect":false,
+      "lazy_blocked":false,
+      "no_sync":false,
+      "description":null,
+      "enabled":true,
+      "kind":"vCPE",
+      "name":"service_vsg",
+      "versionNumber":"",
+      "published":true,
+      "view_url":"/admin/cord/vsgservice/$id$/",
+      "icon_url":null,
+      "public_key":"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC0bhkFHg3DxtQY1S0bN4nV2USTO2scHIrTO/WhZYFB9cqxKJPPlayMzi7sJxZFjsEPG9+gUJn7942eObs0mWkn7eIbph1rgKDhh2ZT6GFdJojgaRr0E3HhjmdHXF3IkCEz0DZ1aiBRX0dAEcp+B7eHvcg9QmBUN9TWhMlN82EKwMtWlrMwAqycNEcPiKiwMC3SPNPrq5qTrxIlzMG8Q51Z1b0FYx2oP0E44zecquFF8qfwoVbA48qT0fdPIdcQ0otEdsGaOxxurOPA86q1zYg60w+Hsygl8L2UpyUqEuXKm0OuhckCmCkcPlEysMAty0bx/9M3DwSkMJdOj81Jl+Bd teone@ctl.teone.xos-pg0.clemson.cloudlab.us\n",
+      "service_specific_id":null,
+      "service_specific_attribute":"{\"backend_network_label\": \"hpc_client\"}"
+   },
+   {
+      "humanReadableName":"service_volt",
+      "id":3,
+      "created":"2016-02-17T19:36:04.585Z",
+      "updated":"2016-02-17T19:36:04.585Z",
+      "enacted":null,
+      "policed":null,
+      "backend_register":"{}",
+      "backend_status":"0 - Provisioning in progress",
+      "deleted":false,
+      "write_protect":false,
+      "lazy_blocked":false,
+      "no_sync":false,
+      "description":null,
+      "enabled":true,
+      "kind":"vOLT",
+      "name":"service_volt",
+      "versionNumber":"",
+      "published":true,
+      "view_url":"/admin/cord/voltservice/$id$/",
+      "icon_url":null,
+      "public_key":null,
+      "service_specific_id":null,
+      "service_specific_attribute":null
+   },
+   {
+      "humanReadableName":"service_ceilometer",
+      "id":6,
+      "created":"2016-02-17T19:36:09.291Z",
+      "updated":"2016-02-17T19:36:09.291Z",
+      "enacted":null,
+      "policed":null,
+      "backend_register":"{}",
+      "backend_status":"0 - Provisioning in progress",
+      "deleted":false,
+      "write_protect":false,
+      "lazy_blocked":false,
+      "no_sync":false,
+      "description":null,
+      "enabled":true,
+      "kind":"ceilometer",
+      "name":"service_ceilometer",
+      "versionNumber":"",
+      "published":true,
+      "view_url":"/admin/ceilometer/ceilometerservice/$id$/",
+      "icon_url":null,
+      "public_key":null,
+      "service_specific_id":null,
+      "service_specific_attribute":"{\"ceilometer_pub_sub_url\": \"http://10.11.10.1:4455/\"}"
+   },
+   {
+      "humanReadableName":"service_sflow",
+      "id":7,
+      "created":"2016-02-17T19:36:09.339Z",
+      "updated":"2016-02-17T20:01:35.518Z",
+      "enacted":null,
+      "policed":null,
+      "backend_register":"{\"next_run\": 1455768095.518195, \"last_failure\": 1455739295.518198, \"last_success\": 1455737795.306011, \"exponent\": 293, \"failures\": 293}",
+      "backend_status":"2 - Exception('defer object service_sflow due to waiting on instance.instance_name',)",
+      "deleted":false,
+      "write_protect":false,
+      "lazy_blocked":false,
+      "no_sync":false,
+      "description":null,
+      "enabled":true,
+      "kind":"sflow",
+      "name":"service_sflow",
+      "versionNumber":"",
+      "published":true,
+      "view_url":"/admin/ceilometer/sflowservice/$id$/",
+      "icon_url":null,
+      "public_key":null,
+      "service_specific_id":null,
+      "service_specific_attribute":"{\"sflow_api_port\": 33333, \"sflow_port\": 6343}"
+   },
+   {
+      "humanReadableName":"service_ONOS_vOLT",
+      "id":4,
+      "created":"2016-02-17T19:36:04.840Z",
+      "updated":"2016-02-17T20:01:35.987Z",
+      "enacted":null,
+      "policed":null,
+      "backend_register":"{\"next_run\": 1455768095.987071, \"failures\": 282, \"last_success\": 1455737792.664808, \"exponent\": 282, \"last_failure\": 1455739295.987074}",
+      "backend_status":"2 - Exception('defer object service_ONOS_vOLT due to waiting on instance.instance_name',)",
+      "deleted":false,
+      "write_protect":false,
+      "lazy_blocked":false,
+      "no_sync":false,
+      "description":null,
+      "enabled":true,
+      "kind":"onos",
+      "name":"service_ONOS_vOLT",
+      "versionNumber":"",
+      "published":true,
+      "view_url":"/admin/onos/onosservice/$id$/",
+      "icon_url":null,
+      "public_key":"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC0bhkFHg3DxtQY1S0bN4nV2USTO2scHIrTO/WhZYFB9cqxKJPPlayMzi7sJxZFjsEPG9+gUJn7942eObs0mWkn7eIbph1rgKDhh2ZT6GFdJojgaRr0E3HhjmdHXF3IkCEz0DZ1aiBRX0dAEcp+B7eHvcg9QmBUN9TWhMlN82EKwMtWlrMwAqycNEcPiKiwMC3SPNPrq5qTrxIlzMG8Q51Z1b0FYx2oP0E44zecquFF8qfwoVbA48qT0fdPIdcQ0otEdsGaOxxurOPA86q1zYg60w+Hsygl8L2UpyUqEuXKm0OuhckCmCkcPlEysMAty0bx/9M3DwSkMJdOj81Jl+Bd teone@ctl.teone.xos-pg0.clemson.cloudlab.us\n",
+      "service_specific_id":null,
+      "service_specific_attribute":"{\"no_container\": false}"
+   },
+   {
+      "humanReadableName":"service_ONOS_vBNG",
+      "id":5,
+      "created":"2016-02-17T19:36:04.917Z",
+      "updated":"2016-02-17T20:01:36.011Z",
+      "enacted":null,
+      "policed":null,
+      "backend_register":"{\"next_run\": 1455768096.011113, \"failures\": 282, \"last_success\": 1455737792.697535, \"exponent\": 282, \"last_failure\": 1455739296.011116}",
+      "backend_status":"2 - Exception('defer object service_ONOS_vBNG due to waiting on instance.instance_name',)",
+      "deleted":false,
+      "write_protect":false,
+      "lazy_blocked":false,
+      "no_sync":false,
+      "description":null,
+      "enabled":true,
+      "kind":"onos",
+      "name":"service_ONOS_vBNG",
+      "versionNumber":"",
+      "published":true,
+      "view_url":"/admin/onos/onosservice/$id$/",
+      "icon_url":null,
+      "public_key":"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC0bhkFHg3DxtQY1S0bN4nV2USTO2scHIrTO/WhZYFB9cqxKJPPlayMzi7sJxZFjsEPG9+gUJn7942eObs0mWkn7eIbph1rgKDhh2ZT6GFdJojgaRr0E3HhjmdHXF3IkCEz0DZ1aiBRX0dAEcp+B7eHvcg9QmBUN9TWhMlN82EKwMtWlrMwAqycNEcPiKiwMC3SPNPrq5qTrxIlzMG8Q51Z1b0FYx2oP0E44zecquFF8qfwoVbA48qT0fdPIdcQ0otEdsGaOxxurOPA86q1zYg60w+Hsygl8L2UpyUqEuXKm0OuhckCmCkcPlEysMAty0bx/9M3DwSkMJdOj81Jl+Bd teone@ctl.teone.xos-pg0.clemson.cloudlab.us\n",
+      "service_specific_id":null,
+      "service_specific_attribute":"{\"no_container\": false}"
+   }
+]
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/mocks/data/tenants.json b/views/ngXosViews/diagnostic/mocks/data/tenants.json
new file mode 100644
index 0000000..4e7557b
--- /dev/null
+++ b/views/ngXosViews/diagnostic/mocks/data/tenants.json
@@ -0,0 +1,232 @@
+[
+    {
+        "humanReadableName": "coarse-tenant-1", 
+        "id": 1, 
+        "created": "2016-02-17T19:36:04.259Z", 
+        "updated": "2016-02-17T19:36:04.259Z", 
+        "enacted": null, 
+        "policed": null, 
+        "backend_register": "{}", 
+        "backend_status": "0 - Provisioning in progress", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": false, 
+        "kind": "coarse", 
+        "provider_service": 1, 
+        "subscriber_service": 2, 
+        "subscriber_tenant": null, 
+        "subscriber_user": null, 
+        "subscriber_root": null, 
+        "service_specific_id": null, 
+        "service_specific_attribute": null, 
+        "connect_method": "na"
+    }, 
+    {
+        "humanReadableName": "coarse-tenant-2", 
+        "id": 2, 
+        "created": "2016-02-17T19:36:04.600Z", 
+        "updated": "2016-02-17T19:36:04.600Z", 
+        "enacted": null, 
+        "policed": null, 
+        "backend_register": "{}", 
+        "backend_status": "0 - Provisioning in progress", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": false, 
+        "kind": "coarse", 
+        "provider_service": 2, 
+        "subscriber_service": 3, 
+        "subscriber_tenant": null, 
+        "subscriber_user": null, 
+        "subscriber_root": null, 
+        "service_specific_id": null, 
+        "service_specific_attribute": null, 
+        "connect_method": "na"
+    }, 
+    {
+        "humanReadableName": "vCPE-tenant-4", 
+        "id": 4, 
+        "created": "2016-02-17T19:36:04.650Z", 
+        "updated": "2016-02-17T20:55:18.115Z", 
+        "enacted": null, 
+        "policed": null, 
+        "backend_register": "{\"next_run\": 1455771318.072057, \"last_failure\": 1455742518.072061, \"last_success\": 1455737797.006782, \"exponent\": 871, \"failures\": 871}", 
+        "backend_status": "2 - Exception('defer object vCPE-tenant-4 due to waiting on instance.instance_name',)", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": false, 
+        "kind": "vCPE", 
+        "provider_service": 2, 
+        "subscriber_service": null, 
+        "subscriber_tenant": 3, 
+        "subscriber_user": null, 
+        "subscriber_root": null, 
+        "service_specific_id": null, 
+        "service_specific_attribute": "{\"instance_id\": 1, \"creator_id\": 1, \"wan_container_ip\": \"10.0.1.24\"}", 
+        "connect_method": "na"
+    }, 
+    {
+        "humanReadableName": "ceilometer-tenant-8", 
+        "id": 8, 
+        "created": "2016-02-17T19:36:09.370Z", 
+        "updated": "2016-02-17T20:55:19.823Z", 
+        "enacted": null, 
+        "policed": null, 
+        "backend_register": "{\"next_run\": 1455771319.823556, \"failures\": 874, \"last_success\": 1455737795.314296, \"exponent\": 874, \"last_failure\": 1455742519.823559}", 
+        "backend_status": "2 - Exception('defer object ceilometer-tenant-8 due to waiting on instance.instance_name',)", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": false, 
+        "kind": "ceilometer", 
+        "provider_service": 6, 
+        "subscriber_service": null, 
+        "subscriber_tenant": null, 
+        "subscriber_user": null, 
+        "subscriber_root": null, 
+        "service_specific_id": null, 
+        "service_specific_attribute": "{\"instance_id\": 7, \"creator_id\": 1, \"use_same_instance_for_multiple_tenants\": true}", 
+        "connect_method": "na"
+    }, 
+    {
+        "humanReadableName": "vBNG-tenant-5", 
+        "id": 5, 
+        "created": "2016-02-17T19:36:04.769Z", 
+        "updated": "2016-02-17T20:55:21.385Z", 
+        "enacted": null, 
+        "policed": null, 
+        "backend_register": "{\"next_run\": 1455771321.384039, \"last_failure\": 1455742521.384043, \"last_success\": 1455737796.18277, \"exponent\": 881, \"failures\": 881}", 
+        "backend_status": "2 - Exception('defer object vBNG-tenant-5 due to does not have a WAN IP yet',)", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": false, 
+        "kind": "vBNG", 
+        "provider_service": 1, 
+        "subscriber_service": null, 
+        "subscriber_tenant": 4, 
+        "subscriber_user": null, 
+        "subscriber_root": null, 
+        "service_specific_id": null, 
+        "service_specific_attribute": null, 
+        "connect_method": "na"
+    }, 
+    {
+        "humanReadableName": "onos-tenant-6", 
+        "id": 6, 
+        "created": "2016-02-17T19:36:05.048Z", 
+        "updated": "2016-02-17T20:41:16.675Z", 
+        "enacted": "2016-02-17T20:41:16.729Z", 
+        "policed": null, 
+        "backend_register": "{\"next_run\": 0, \"last_success\": 1455741676.729897, \"exponent\": 0}", 
+        "backend_status": "1 - OK", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": false, 
+        "kind": "onos", 
+        "provider_service": 5, 
+        "subscriber_service": 1, 
+        "subscriber_tenant": null, 
+        "subscriber_user": null, 
+        "subscriber_root": null, 
+        "service_specific_id": null, 
+        "service_specific_attribute": "{\"creator_id\": 1, \"dependencies\": \"org.onosproject.proxyarp, org.onosproject.virtualbng, org.onosproject.openflow, org.onosproject.fwd\", \"name\": \"vBNG_ONOS_app\"}", 
+        "connect_method": "na"
+    }, 
+    {
+        "humanReadableName": "vOLT-tenant-3", 
+        "id": 3, 
+        "created": "2016-02-17T19:36:04.631Z", 
+        "updated": "2016-02-17T20:28:30.428Z", 
+        "enacted": null, 
+        "policed": null, 
+        "backend_register": "{}", 
+        "backend_status": "0 - Provisioning in progress", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": false, 
+        "kind": "vOLT", 
+        "provider_service": 3, 
+        "subscriber_service": null, 
+        "subscriber_tenant": null, 
+        "subscriber_user": null, 
+        "subscriber_root": 1, 
+        "service_specific_id": "123", 
+        "service_specific_attribute": "{\"creator_id\": 1, \"c_tag\": \"432\", \"s_tag\": \"222\"}", 
+        "connect_method": "na"
+    }, 
+    {
+        "humanReadableName": "onos-tenant-7", 
+        "id": 7, 
+        "created": "2016-02-17T19:36:05.089Z", 
+        "updated": "2016-02-17T20:40:54.451Z", 
+        "enacted": "2016-02-17T20:40:54.468Z", 
+        "policed": null, 
+        "backend_register": "{\"next_run\": 0, \"last_success\": 1455741654.468755, \"exponent\": 0}", 
+        "backend_status": "1 - OK", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": false, 
+        "kind": "onos", 
+        "provider_service": 4, 
+        "subscriber_service": 3, 
+        "subscriber_tenant": null, 
+        "subscriber_user": null, 
+        "subscriber_root": null, 
+        "service_specific_id": null, 
+        "service_specific_attribute": "{\"creator_id\": 1, \"dependencies\": \"org.onosproject.openflow-base, org.onosproject.olt, org.ciena.onos.ext_notifier, org.ciena.onos.volt_event_publisher\", \"name\": \"vOLT_ONOS_app\", \"install_dependencies\": \"onos-ext-notifier-1.0-SNAPSHOT.oar, onos-ext-volt-event-publisher-1.0-SNAPSHOT.oar\"}", 
+        "connect_method": "na"
+    },
+    {
+        "humanReadableName": "vCPE-tenant-4", 
+        "id": 14, 
+        "created": "2016-02-17T19:36:04.650Z", 
+        "updated": "2016-02-17T20:55:18.115Z", 
+        "enacted": null, 
+        "policed": null, 
+        "backend_register": "{\"next_run\": 1455771318.072057, \"last_failure\": 1455742518.072061, \"last_success\": 1455737797.006782, \"exponent\": 871, \"failures\": 871}", 
+        "backend_status": "2 - Exception('defer object vCPE-tenant-4 due to waiting on instance.instance_name',)", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": false, 
+        "kind": "vCPE", 
+        "provider_service": 2, 
+        "subscriber_service": null, 
+        "subscriber_tenant": 3, 
+        "subscriber_user": null, 
+        "subscriber_root": null, 
+        "service_specific_id": null, 
+        "service_specific_attribute": "{\"instance_id\": 11, \"creator_id\": 1}", 
+        "connect_method": "na"
+    },
+    {
+        "humanReadableName": "vCPE-tenant-5", 
+        "id": 14, 
+        "created": "2016-02-17T19:36:04.650Z", 
+        "updated": "2016-02-17T20:55:18.115Z", 
+        "enacted": null, 
+        "policed": null, 
+        "backend_register": "{\"next_run\": 1455771318.072057, \"last_failure\": 1455742518.072061, \"last_success\": 1455737797.006782, \"exponent\": 871, \"failures\": 871}", 
+        "backend_status": "2 - Exception('defer object vCPE-tenant-4 due to waiting on instance.instance_name',)", 
+        "deleted": false, 
+        "write_protect": false, 
+        "lazy_blocked": false, 
+        "no_sync": false, 
+        "kind": "vCPE", 
+        "provider_service": 2, 
+        "subscriber_service": null, 
+        "subscriber_tenant": 3, 
+        "subscriber_user": null, 
+        "subscriber_root": null, 
+        "service_specific_id": null, 
+        "service_specific_attribute": "{\"instance_id\": 12, \"creator_id\": 1}", 
+        "connect_method": "na"
+    }
+]
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/mocks/data/users.json b/views/ngXosViews/diagnostic/mocks/data/users.json
new file mode 100644
index 0000000..4cf36f7
--- /dev/null
+++ b/views/ngXosViews/diagnostic/mocks/data/users.json
@@ -0,0 +1,25 @@
+[
+  {
+    "mac": "01:02:03:04:05:06",
+    "level": "PG_13",
+    "id": 0,
+    "name": "Mom's PC"
+  },
+  {
+    "mac": "34:36:3B:C9:B6:A6",
+    "id": 1,
+    "level": "PG_13"
+  },
+  {
+    "mac": "68:5B:35:9D:91:D5",
+    "level": "PG_13",
+    "id": 2,
+    "name": "Jack's Laptop"
+  },
+  {
+    "id": 3,
+    "mac": "90:E2:BA:82:F9:75",
+    "name": "Dad's PC",
+    "level": "PG_13"
+  }
+]
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/mocks/data/xos-instance-statistics.json b/views/ngXosViews/diagnostic/mocks/data/xos-instance-statistics.json
new file mode 100644
index 0000000..7b83f5d
--- /dev/null
+++ b/views/ngXosViews/diagnostic/mocks/data/xos-instance-statistics.json
@@ -0,0 +1,557 @@
+[
+    {
+        "resource_name": "mysite_vsg-1", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Average CPU utilization", 
+        "resource_id": "075a3ae4-9e76-4198-8e6b-67c67b996745", 
+        "meter": "cpu_util", 
+        "unit": "%", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 34.39350127615451, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "mysite_vsg-1", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Number of VCPUs", 
+        "resource_id": "075a3ae4-9e76-4198-8e6b-67c67b996745", 
+        "meter": "vcpus", 
+        "unit": "vcpu", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 1.0, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "mysite_vsg-1", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Volume of RAM", 
+        "resource_id": "075a3ae4-9e76-4198-8e6b-67c67b996745", 
+        "meter": "memory", 
+        "unit": "MB", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 2048.0, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "mysite_vsg-1", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "CPU time used", 
+        "resource_id": "075a3ae4-9e76-4198-8e6b-67c67b996745", 
+        "meter": "cpu", 
+        "unit": "ns", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 199610924583333.34, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "mysite_vsg-1", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Volume of RAM used", 
+        "resource_id": "075a3ae4-9e76-4198-8e6b-67c67b996745", 
+        "meter": "memory.usage", 
+        "unit": "MB", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 1931.625, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tapcf5721c4-c6", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Average rate per sec of outgoing packets on a VM network interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tapcf5721c4-c6", 
+        "meter": "network.outgoing.packets.rate", 
+        "unit": "packet/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 0.0001851851851851852, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tapcf5721c4-c6", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Number of outgoing bytes on the network for a VM interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tapcf5721c4-c6", 
+        "meter": "network.outgoing.bytes", 
+        "unit": "B", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 14088.506944444445, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tapcf5721c4-c6", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Average rate per sec of incoming bytes on a VM network interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tapcf5721c4-c6", 
+        "meter": "network.incoming.bytes.rate", 
+        "unit": "B/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 0.015026113884266964, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tapcf5721c4-c6", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Average rate per sec of outgoing bytes on a VM network interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tapcf5721c4-c6", 
+        "meter": "network.outgoing.bytes.rate", 
+        "unit": "B/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 0.02625256131755716, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tapcf5721c4-c6", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Number of incoming packets for a VM interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tapcf5721c4-c6", 
+        "meter": "network.incoming.packets", 
+        "unit": "packet", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 66.71527777777777, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tapcf5721c4-c6", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Average rate per sec of incoming packets on a VM network interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tapcf5721c4-c6", 
+        "meter": "network.incoming.packets.rate", 
+        "unit": "packet/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 9.25925925925926e-05, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tapcf5721c4-c6", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Number of incoming bytes on the network for a VM interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tapcf5721c4-c6", 
+        "meter": "network.incoming.bytes", 
+        "unit": "B", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 8747.979166666666, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tapcf5721c4-c6", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Number of outgoing packets for a VM interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tapcf5721c4-c6", 
+        "meter": "network.outgoing.packets", 
+        "unit": "packet", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 111.22222222222223, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tap3f06c6d0-fb", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Average rate per sec of outgoing packets on a VM network interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tap3f06c6d0-fb", 
+        "meter": "network.outgoing.packets.rate", 
+        "unit": "packet/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 1.603090277777778, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tap3f06c6d0-fb", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Number of outgoing bytes on the network for a VM interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tap3f06c6d0-fb", 
+        "meter": "network.outgoing.bytes", 
+        "unit": "B", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 1486894584.4722223, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tap3f06c6d0-fb", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Average rate per sec of incoming bytes on a VM network interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tap3f06c6d0-fb", 
+        "meter": "network.incoming.bytes.rate", 
+        "unit": "B/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 1248.113658402975, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tap3f06c6d0-fb", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Average rate per sec of outgoing bytes on a VM network interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tap3f06c6d0-fb", 
+        "meter": "network.outgoing.bytes.rate", 
+        "unit": "B/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 143.5401912417864, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tap3f06c6d0-fb", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Number of incoming packets for a VM interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tap3f06c6d0-fb", 
+        "meter": "network.incoming.packets", 
+        "unit": "packet", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 12888749.868055556, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tap3f06c6d0-fb", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Average rate per sec of incoming packets on a VM network interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tap3f06c6d0-fb", 
+        "meter": "network.incoming.packets.rate", 
+        "unit": "packet/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 1.5918200296505445, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tap3f06c6d0-fb", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Number of incoming bytes on the network for a VM interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tap3f06c6d0-fb", 
+        "meter": "network.incoming.bytes", 
+        "unit": "B", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 28949696952.67361, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tap3f06c6d0-fb", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Number of outgoing packets for a VM interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tap3f06c6d0-fb", 
+        "meter": "network.outgoing.packets", 
+        "unit": "packet", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 13835573.3125, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tapb7ae5310-e2", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Average rate per sec of outgoing packets on a VM network interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tapb7ae5310-e2", 
+        "meter": "network.outgoing.packets.rate", 
+        "unit": "packet/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 6.944444444444444e-05, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tapb7ae5310-e2", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Number of outgoing bytes on the network for a VM interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tapb7ae5310-e2", 
+        "meter": "network.outgoing.bytes", 
+        "unit": "B", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 6808.0, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tapb7ae5310-e2", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Average rate per sec of incoming bytes on a VM network interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tapb7ae5310-e2", 
+        "meter": "network.incoming.bytes.rate", 
+        "unit": "B/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 0.014062500000000002, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tapb7ae5310-e2", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Average rate per sec of outgoing bytes on a VM network interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tapb7ae5310-e2", 
+        "meter": "network.outgoing.bytes.rate", 
+        "unit": "B/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 0.013333333333333332, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tapb7ae5310-e2", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Number of incoming packets for a VM interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tapb7ae5310-e2", 
+        "meter": "network.incoming.packets", 
+        "unit": "packet", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 42.958333333333336, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tapb7ae5310-e2", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Average rate per sec of incoming packets on a VM network interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tapb7ae5310-e2", 
+        "meter": "network.incoming.packets.rate", 
+        "unit": "packet/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 6.944444444444444e-05, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tapb7ae5310-e2", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Number of incoming bytes on the network for a VM interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tapb7ae5310-e2", 
+        "meter": "network.incoming.bytes", 
+        "unit": "B", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 7230.0625, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tapb7ae5310-e2", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Number of outgoing packets for a VM interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tapb7ae5310-e2", 
+        "meter": "network.outgoing.packets", 
+        "unit": "packet", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 40.958333333333336, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tap38f1f5be-89", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Average rate per sec of outgoing packets on a VM network interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tap38f1f5be-89", 
+        "meter": "network.outgoing.packets.rate", 
+        "unit": "packet/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 6.944444444444444e-05, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tap38f1f5be-89", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Number of outgoing bytes on the network for a VM interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tap38f1f5be-89", 
+        "meter": "network.outgoing.bytes", 
+        "unit": "B", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 6773.333333333333, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tap38f1f5be-89", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Average rate per sec of incoming bytes on a VM network interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tap38f1f5be-89", 
+        "meter": "network.incoming.bytes.rate", 
+        "unit": "B/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 0.014062500000000002, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tap38f1f5be-89", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Average rate per sec of outgoing bytes on a VM network interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tap38f1f5be-89", 
+        "meter": "network.outgoing.bytes.rate", 
+        "unit": "B/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 0.013325938251063044, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tap38f1f5be-89", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Number of incoming packets for a VM interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tap38f1f5be-89", 
+        "meter": "network.incoming.packets", 
+        "unit": "packet", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 44.77777777777778, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tap38f1f5be-89", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Average rate per sec of incoming packets on a VM network interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tap38f1f5be-89", 
+        "meter": "network.incoming.packets.rate", 
+        "unit": "packet/s", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 6.944444444444444e-05, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tap38f1f5be-89", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Number of incoming bytes on the network for a VM interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tap38f1f5be-89", 
+        "meter": "network.incoming.bytes", 
+        "unit": "B", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 7365.5, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }, 
+    {
+        "resource_name": "tap38f1f5be-89", 
+        "instance-uuid": "075a3ae4-9e76-4198-8e6b-67c67b996746",
+        "description": "Number of outgoing packets for a VM interface", 
+        "resource_id": "instance-00000004-075a3ae4-9e76-4198-8e6b-67c67b996745-tap38f1f5be-89", 
+        "meter": "network.outgoing.packets", 
+        "unit": "packet", 
+        "category": "Nova", 
+        "slice": "mysite_vsg", 
+        "name": "none", 
+        "service": "service_vsg", 
+        "value": 40.77777777777778, 
+        "time": "2016-02-23T22:30:34", 
+        "project_id": "718dd78532a24a74b0491437bbef398c"
+    }
+]
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/mocks/diagnostic.conf.json b/views/ngXosViews/diagnostic/mocks/diagnostic.conf.json
new file mode 100644
index 0000000..a346dc6
--- /dev/null
+++ b/views/ngXosViews/diagnostic/mocks/diagnostic.conf.json
@@ -0,0 +1,44 @@
+[
+  {
+    "url": "cordsubscriber",
+    "base": "xoslib/",
+    "methods": ["GET", "PUT"],
+    "param": "id"
+  },
+  {
+    "url": "users",
+    "base": "xoslib/rs/subscriber/1/",
+    "methods": ["GET"]
+  },
+  {
+    "url": "services",
+    "base": "xos/",
+    "methods": ["GET"]
+  },
+  {
+    "url": "tenants",
+    "base": "xos/",
+    "methods": ["GET"]
+  },
+  {
+    "url": "nodes",
+    "base": "xos/",
+    "methods": ["GET"]
+  },
+  {
+    "url": "instances",
+    "base": "xos/",
+    "methods": ["GET"],
+    "param": "id"
+  },
+  {
+    "url": "meterstatistics",
+    "base": "xoslib/",
+    "methods": ["GET"]
+  },
+  {
+    "url": "xos-instance-statistics",
+    "base": "xoslib/",
+    "methods": ["GET"]
+  }
+]
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/package.json b/views/ngXosViews/diagnostic/package.json
new file mode 100644
index 0000000..e5437b9
--- /dev/null
+++ b/views/ngXosViews/diagnostic/package.json
@@ -0,0 +1,64 @@
+{
+  "name": "xos-serviceTopology",
+  "version": "1.0.0",
+  "description": "Angular Application for XOS, created with generator-xos",
+  "scripts": {
+    "prestart": "npm install && bower install",
+    "start": "gulp serve",
+    "dev": "NODE_ENV=mock gulp serve",
+    "local": "NODE_ENV=local gulp serve",
+    "server": "easy-mocker -c ./mocks/diagnostic.conf.json -d ./mocks/data",
+    "build": "gulp",
+    "test": "karma start",
+    "lint": "eslint src/js/"
+  },
+  "keywords": [
+    "XOS",
+    "Angular",
+    "XOSlib"
+  ],
+  "author": "Matteo Scandolo",
+  "license": "MIT",
+  "dependencies": {},
+  "devDependencies": {
+    "autoprefixer": "^6.3.3",
+    "browser-sync": "^2.9.11",
+    "css-mqpacker": "^4.0.0",
+    "csswring": "^4.2.1",
+    "del": "^2.0.2",
+    "easy-mocker": "^1.2.0",
+    "eslint": "^1.8.0",
+    "eslint-plugin-angular": "linkmesrl/eslint-plugin-angular",
+    "gulp": "^3.9.0",
+    "gulp-angular-filesort": "^1.1.1",
+    "gulp-angular-templatecache": "^1.8.0",
+    "gulp-babel": "^5.3.0",
+    "gulp-concat": "^2.6.0",
+    "gulp-concat-util": "^0.5.5",
+    "gulp-eslint": "^1.0.0",
+    "gulp-inject": "^3.0.0",
+    "gulp-minify-html": "^1.0.4",
+    "gulp-ng-annotate": "^1.1.0",
+    "gulp-postcss": "^6.0.1",
+    "gulp-rename": "^1.2.2",
+    "gulp-replace": "^0.5.4",
+    "gulp-sass": "^2.2.0",
+    "gulp-uglify": "^1.4.2",
+    "http-proxy": "^1.12.0",
+    "ink-docstrap": "^0.5.2",
+    "jasmine-core": "~2.3.4",
+    "karma": "^0.13.14",
+    "karma-babel-preprocessor": "~5.2.2",
+    "karma-coverage": "^0.5.3",
+    "karma-jasmine": "~0.3.6",
+    "karma-mocha-reporter": "~1.1.1",
+    "karma-ng-html2js-preprocessor": "^0.2.0",
+    "karma-phantomjs-launcher": "~0.2.1",
+    "lodash": "^3.10.1",
+    "phantomjs": "^1.9.19",
+    "proxy-middleware": "^0.15.0",
+    "run-sequence": "^1.1.4",
+    "wiredep": "^3.0.0-beta",
+    "wrench": "^1.5.8"
+  }
+}
diff --git a/views/ngXosViews/diagnostic/spec/.eslintrc b/views/ngXosViews/diagnostic/spec/.eslintrc
new file mode 100644
index 0000000..c1764a5
--- /dev/null
+++ b/views/ngXosViews/diagnostic/spec/.eslintrc
@@ -0,0 +1,15 @@
+{
+    "globals" :{
+        "describe": true,
+        "xdescribe": true,
+        "beforeEach": true,
+        "it": true,
+        "inject": true,
+        "expect": true,
+        "jasmine": true
+    },
+    "rules": {
+      "max-nested-callbacks": [0, 4],
+      "camelcase": 0
+    }
+}
diff --git a/views/ngXosViews/diagnostic/spec/logicTopologyHelper.test.js b/views/ngXosViews/diagnostic/spec/logicTopologyHelper.test.js
new file mode 100644
index 0000000..dcce7e8
--- /dev/null
+++ b/views/ngXosViews/diagnostic/spec/logicTopologyHelper.test.js
@@ -0,0 +1,61 @@
+(function () {
+  'use strict';
+
+  describe('The Logic Topology Helper Service', () => {
+    
+    var Service, Config;
+
+    var x0, x1, x2, x3, x4;
+
+    var svgWidth = 900;
+
+    beforeEach(module('xos.diagnostic'));
+
+    // inject the rackHelper service
+    beforeEach(inject(function (_LogicTopologyHelper_, _serviceTopologyConfig_) {
+      // The injector unwraps the underscores (_) from around the parameter names when matching
+      Service = _LogicTopologyHelper_;
+      Config = _serviceTopologyConfig_;
+
+      // result
+      let totalElWidth = Config.elWidths.reduce((el, val) => val + el, 0);
+      let remainingSpace = svgWidth - totalElWidth - (Config.widthMargin * 2);
+      let step = remainingSpace / (Config.elWidths.length - 1);
+      x0 = Config.widthMargin;
+      x1 = x0 + Config.elWidths[0] + step;
+      x2 = x1 + Config.elWidths[1] + step;
+      x3 = x2 + Config.elWidths[2] + step;
+      x4 = x3 + Config.elWidths[3] + step;
+    }));
+
+    var customMatchers = {
+      toBeSimilar: () => {
+
+        const tolerance = 0.1;
+
+        return {
+          compare: (actual, expected) => {
+            return {
+              pass: (Math.abs(actual - expected) < tolerance),
+              message: `Expected ${actual} to be ${expected}`
+            }
+          }
+        }
+      }
+    };
+
+    beforeEach(function() {
+      jasmine.addMatchers(customMatchers);
+    });
+
+    it('should calculate horizontal position for each element', () => {
+      let [el0x, el1x, el2x, el3x, el4x] = Service.computeElementPosition(svgWidth);
+      expect(el0x).toBeSimilar(svgWidth - (x0 + (Config.elWidths[0] / 2)));
+      expect(el1x).toBeSimilar(svgWidth - (x1 + (Config.elWidths[1] / 2)));
+      expect(el2x).toBeSimilar(svgWidth - (x2 + (Config.elWidths[2] / 2)));
+      expect(el3x).toBeSimilar(svgWidth - (x3 + (Config.elWidths[3] / 2)));
+      expect(el4x).toBeSimilar(svgWidth - (x4 + (Config.elWidths[4] / 2)));
+    });
+  });
+
+})();
diff --git a/views/ngXosViews/diagnostic/spec/rackHelper.test.js b/views/ngXosViews/diagnostic/spec/rackHelper.test.js
new file mode 100644
index 0000000..145a2e5
--- /dev/null
+++ b/views/ngXosViews/diagnostic/spec/rackHelper.test.js
@@ -0,0 +1,187 @@
+(function () {
+  'use strict';
+
+  const computeNodes = [
+    {
+      humanReadableName: 'cp-1.teone.xos-pg0.clemson.cloudlab.us',
+      instances: [
+        {
+          instance_name: 'mysite_clients-3'
+        },
+        {
+          instance_name: 'mysite_clients-4'
+        },
+        {
+          instance_name: 'mysite_clients-5'
+        }
+      ]
+    },
+    {
+      humanReadableName: 'cp-2.teone.xos-pg0.clemson.cloudlab.us',
+      instances: [
+        {
+          instance_name: 'mysite_clients-1'
+        },
+        {
+          instance_name: 'mysite_clients-2'
+        }
+      ]
+    },
+    {
+      humanReadableName: 'cp-2.teone.xos-pg0.clemson.cloudlab.us',
+      instances: [
+        {
+          instance_name: 'mysite_clients-1'
+        },
+        {
+          instance_name: 'mysite_clients-2'
+        }
+      ]
+    }
+  ];
+
+  describe('The Rack Helper Service', () => {
+    
+    var Service, Config;
+
+    // results
+    var cp1, cp2, cp3, rack, instancePos, nodePos;
+
+    beforeEach(module('xos.diagnostic'));
+
+    // inject the rackHelper service
+    beforeEach(inject(function (_RackHelper_, _serviceTopologyConfig_) {
+      // The injector unwraps the underscores (_) from around the parameter names when matching
+      Service = _RackHelper_;
+      Config = _serviceTopologyConfig_;
+
+      cp1 = {
+        width: (Config.instance.width * 2) + (Config.instance.margin * 3),
+        height: (Config.instance.height * 2) + (Config.instance.margin * 5) + Config.computeNode.labelHeight
+      };
+
+      cp2 = {
+        width: (Config.instance.width * 2) + (Config.instance.margin * 3),
+        height: Config.instance.height + (Config.instance.margin * 4) + Config.computeNode.labelHeight
+      };
+
+      cp3 = {
+        width: (Config.instance.width * 2) + (Config.instance.margin * 3),
+        height: Config.instance.height + (Config.instance.margin * 4) + Config.computeNode.labelHeight
+      };
+
+      rack = {
+        width: cp1.width + (Config.computeNode.margin * 2),
+        height: cp1.height + cp2.height + cp3.height + (Config.computeNode.margin * 4)
+      }
+
+      instancePos = [
+        {
+          x: Config.instance.margin,
+          y: Config.instance.margin + Service.getComputeNodeLabelSize()
+        },
+        {
+          x: Config.instance.margin + (Config.instance.width * 1) + (Config.instance.margin * 1),
+          y: Config.instance.margin + Service.getComputeNodeLabelSize()
+        },
+        {
+          x: Config.instance.margin,
+          y: Config.instance.margin + Service.getComputeNodeLabelSize() + + (Config.instance.height * 1) + (Config.instance.margin * 1)
+        },
+        {
+          x: Config.instance.margin + (Config.instance.width * 1) + (Config.instance.margin * 1),
+          y: Config.instance.margin + Service.getComputeNodeLabelSize() + + (Config.instance.height * 1) + (Config.instance.margin * 1)
+        }
+      ];
+
+      nodePos = [
+        {
+          x: Config.computeNode.margin,
+          y: Config.computeNode.margin
+        },
+        {
+          x: Config.computeNode.margin,
+          y: (Config.computeNode.margin * 2) + cp1.height
+        },
+        {
+          x: Config.computeNode.margin,
+          y: (Config.computeNode.margin * 3) + cp1.height + cp2.height
+        }
+      ]
+    }));
+
+    describe('Given a list of instances', () => {
+      it('should calculate the first Compute Node Size', () => {
+        const [width, height] = Service.getComputeNodeSize(computeNodes[0].instances);
+        expect(width).toBe(cp1.width);
+        expect(height).toBe(cp1.height);
+      });
+
+      it('should calculate the second Compute Node Size', () => {
+        const [width, height] = Service.getComputeNodeSize(computeNodes[1].instances);
+        expect(width).toBe(cp2.width);
+        expect(height).toBe(cp2.height);
+      });
+
+      it('should calculate the third Compute Node Size', () => {
+        const [width, height] = Service.getComputeNodeSize(computeNodes[1].instances);
+        expect(width).toBe(cp3.width);
+        expect(height).toBe(cp3.height);
+      });
+    });
+
+    describe('Given a list of Compute Nodes', () => {
+      it('should return rack size', () => {
+        const [width, height] = Service.getRackSize(computeNodes);
+        expect(width).toBe(rack.width);
+        expect(height).toBe(rack.height);
+      });
+    });
+
+    describe('Given an instance index', () => {
+      it('should return the position for first instance', () => {
+        const [x, y] = Service.getInstancePosition(0);
+        expect(x).toBe(instancePos[0].x);
+        expect(y).toBe(instancePos[0].y);
+      })
+
+      it('should return the position for second instance', () => {
+        const [x, y] = Service.getInstancePosition(1);
+        expect(x).toBe(instancePos[1].x);
+        expect(y).toBe(instancePos[1].y);
+      });
+
+      it('should return the position for third instance', () => {
+        const [x, y] = Service.getInstancePosition(2);
+        expect(x).toBe(instancePos[2].x);
+        expect(y).toBe(instancePos[2].y);
+      });
+
+      it('should return the position for 4th instance', () => {
+        const [x, y] = Service.getInstancePosition(3);
+        expect(x).toBe(instancePos[3].x);
+        expect(y).toBe(instancePos[3].y);
+      });
+    });
+
+    describe('Given an ComputeNode index', () => {
+      it('should return the position for 1st node', () => {
+        const [x, y] = Service.getComputeNodePosition(computeNodes, 0);
+        expect(x).toBe(nodePos[0].x);
+        expect(y).toBe(nodePos[0].y);
+      })
+
+      it('should return the position for 2st node', () => {
+        const [x, y] = Service.getComputeNodePosition(computeNodes, 1);
+        expect(x).toBe(nodePos[1].x);
+        expect(y).toBe(nodePos[1].y);
+      });
+
+      it('should return the position for 2st node', () => {
+        const [x, y] = Service.getComputeNodePosition(computeNodes, 2);
+        expect(x).toBe(nodePos[2].x);
+        expect(y).toBe(nodePos[2].y);
+      });
+    });
+  });
+})();
diff --git a/views/ngXosViews/diagnostic/spec/serviceChain.test.js b/views/ngXosViews/diagnostic/spec/serviceChain.test.js
new file mode 100644
index 0000000..d8a3a23
--- /dev/null
+++ b/views/ngXosViews/diagnostic/spec/serviceChain.test.js
@@ -0,0 +1,211 @@
+'use strict';
+
+describe('The Service Relation Service', () => {
+  
+  var Service;
+
+  beforeEach(module('xos.diagnostic'));
+  beforeEach(module('templates'));
+
+  // inject the cartService
+  beforeEach(inject(function (_ServiceRelation_) {
+    // The injector unwraps the underscores (_) from around the parameter names when matching
+    Service = _ServiceRelation_;
+  }));
+
+  describe('given a service', () => {
+
+    const levelRelations = [
+      {
+        subscriber_service: 1
+      },
+      {
+        subscriber_service: 1
+      },
+      {
+        subscriber_service: 2
+      }
+    ];
+
+    it('should find all involved relations', () => {
+      expect(typeof Service.findLevelRelation).toBe('function');
+      let levelRelation = Service.findLevelRelation(levelRelations, 1);
+      expect(levelRelation.length).toBe(2);
+    });
+  });
+
+  describe('given a set of relation', () => {
+
+    const levelRelations = [
+      {
+        provider_service: 1,
+        service_specific_attribute: '{"instance_id": "instance1"}',
+        subscriber_tenant: 2
+      },
+      {
+        provider_service: 2
+      }
+    ];
+
+    const services = [
+      {
+        id: 1
+      },
+      {
+        id: 2
+      },
+      {
+        id: 3
+      }
+    ];
+
+    it('should find all the provider service', () => {
+      expect(typeof Service.findLevelServices).toBe('function');
+      let levelServices = Service.findLevelServices(levelRelations, services);
+      expect(levelServices.length).toBe(2);
+    });
+
+    it('should retrieve all service specific information', () => {
+      let info = Service.findSpecificInformation(levelRelations, 1);
+      expect(info.instance_id).toBe('instance1');
+    });
+  });
+
+
+
+  describe('given a list of services and a list of relations', () => {
+
+    const services = [
+      {
+        id: 1,
+        humanReadableName: 'service-1'
+      },
+      {
+        id: 2,
+        humanReadableName: 'service-2'
+      },
+      {
+        id: 3,
+        humanReadableName: 'service-3'
+      },
+      {
+        id: 4,
+        humanReadableName: 'service-4'
+      }
+    ];
+
+    const tenants = [
+      {
+        id: 1,
+        provider_service: 2,
+        subscriber_tenant: 4,
+        subscriber_service: 1,
+      },
+      {
+        id: 2,
+        provider_service: 3,
+        subscriber_tenant: 1,
+        subscriber_service: 2
+      },
+      {
+        id: 3,
+        provider_service: 4,
+        subscriber_tenant: 4,
+        subscriber_service: 1
+      },
+      {
+        id: 4,
+        subscriber_root: 1,
+        provider_service: 1
+      }
+    ];
+
+    it('should return a tree ordered by tenants', () => {
+      let tree = Service.buildSubscriberServiceTree(services, tenants);
+
+      expect(tree.name).toBe('fakeSubs');
+      expect(tree.parent).toBeNull();
+      expect(tree.children.length).toBe(1);
+
+      expect(tree.children[0].name).toBe('service-1');
+      expect(tree.children[0].parent).toBeNull();
+      expect(tree.children[0].tenant).toEqual({id: 4, subscriber_root: 1, provider_service: 1});
+      expect(tree.children[0].children.length).toBe(2);
+
+      expect(tree.children[0].children[0].name).toBe('service-2');
+      expect(tree.children[0].children[0].tenant).toEqual({ id: 1, provider_service: 2, subscriber_tenant: 4, subscriber_service: 1 });;
+      expect(tree.children[0].children[0].children[0].name).toBe('service-3');
+
+      // expect(tree.children[0].children[0].children[0].children[0].name).toBe('Router');
+
+      expect(tree.children[0].children[1].name).toBe('service-4');
+      // expect(tree.children[0].children[1].children[0].name).toBe('Router');
+    });
+  });
+
+  describe('given an object', () => {
+
+    const sample = {
+      name: '1',
+      children: [
+        {
+          name: '2',
+          children: [
+            {
+              name: '3'
+            }
+          ]
+        }
+      ]
+    };
+
+    it('should return the depth', () => {
+      expect(Service.depthOf(sample)).toBe(3);
+    });
+  });
+
+  describe('Given a list of services and COARSE tenant', () => {
+    
+    const coarseTenants = [
+      {
+        humanReadableName: 'coarse-1',
+        provider_service: 1,
+        subscriber_service: 2
+      },
+      {
+        humanReadableName: 'coarse-2',
+        provider_service: 2,
+        subscriber_service: 3
+      }
+    ];
+
+    const services = [
+      {
+        id: 1,
+        name: 'vbng',
+        humanReadableName: 'vbng'
+      },
+      {
+        id: 2,
+        name: 'vsg',
+        humanReadableName: 'vsg'
+      },
+      {
+        id: 3,
+        name: 'volt',
+        humanReadableName: 'volt'
+      }
+    ];
+
+    it('should build the tenancy graph', () => {
+      let tree = Service.buildServiceTree(services, coarseTenants);
+
+      expect(tree.type).toBe('subscriber');
+      expect(tree.children[0].name).toBe('volt');
+      expect(tree.children[0].service).toBeDefined();
+      expect(tree.children[0].children[0].name).toBe('vsg');
+      expect(tree.children[0].children[0].children[0].name).toBe('vbng');
+    });
+  });
+
+});
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/src/css/main.css b/views/ngXosViews/diagnostic/src/css/main.css
new file mode 100644
index 0000000..1cf0848
--- /dev/null
+++ b/views/ngXosViews/diagnostic/src/css/main.css
@@ -0,0 +1,281 @@
+/* CONTAINER */
+#xosDiagnostic, [ui-view] {
+  min-height: 700px;
+  position: relative; }
+
+diagnostic-container .form-control.small-padding {
+  padding: 6px; }
+
+diagnostic-container .half-height {
+  position: relative;
+  height: 50%; }
+
+diagnostic-container .onethird-height {
+  position: relative;
+  height: 33%;
+  border-bottom: 1px solid #999; }
+
+diagnostic-container .twothird-height {
+  position: relative;
+  height: 67%; }
+
+diagnostic-container .subscriber-select {
+  max-width: 200px;
+  position: absolute;
+  top: 20px;
+  right: 20px;
+  z-index: 1; }
+
+diagnostic-container .onethird-height .well,
+diagnostic-container .twothird-height .well {
+  font-weight: bold;
+  max-width: 165px;
+  text-align: center;
+  margin-top: 15px;
+  background: #eee;
+  border-color: steelblue;
+  padding: 10px; }
+
+diagnostic-container .onethird-height .well.pull-right {
+  position: absolute;
+  right: 0px;
+  top: -15px;
+  cursor: pointer;
+  z-index: 200; }
+
+/* subscriber-status-modal */
+subscriber-status-modal .row + .row {
+  margin-top: 20px; }
+
+.half-height + .half-height {
+  border-top: 1px solid black; }
+
+service-topology,
+logic-topology {
+  height: 100%;
+  width: 100%;
+  display: block;
+  position: absolute;
+  top: 0; }
+
+logic-topology .subscriber circle,
+logic-topology .device circle {
+  fill: #fff;
+  stroke: green;
+  stroke-width: 1px; }
+
+logic-topology > svg {
+  position: absolute;
+  top: 0; }
+
+/* CLOUDS */
+logic-topology .network .cloud {
+  fill: #fff;
+  stroke: green;
+  stroke-width: 1px; }
+
+/* RACK */
+logic-topology .node.rack > g > rect {
+  fill: #ccc;
+  stroke: steelblue;
+  stroke-width: 1px; }
+
+/* CP NODE */
+logic-topology .compute-node > rect {
+  fill: #fff;
+  stroke: steelblue;
+  stroke-width: 1px; }
+
+logic-topology .compute-node > text {
+  font-size: 16px; }
+
+/* INSTANCE */
+logic-topology .instance > rect {
+  fill: #eee;
+  stroke: steelblue;
+  stroke-width: 1px; }
+
+logic-topology .node .instance.active rect {
+  fill: lightsteelblue;
+  stroke: steelblue;
+  stroke-width: 1px; }
+
+logic-topology .node .instance.active.good > rect {
+  fill: green; }
+
+logic-topology .node .instance.active.provisioning > rect {
+  fill: yellow; }
+
+logic-topology .node .instance.active.bad > rect {
+  fill: red; }
+
+/* INSTANCE STATS */
+logic-topology .node .instance .stats-container rect {
+  fill: white; }
+
+logic-topology .node .instance .stats-container text.name {
+  font-weight: bold; }
+
+logic-topology .node .instance .stats-container text.ip {
+  font-style: italic;
+  font-size: 10px; }
+
+/* CONTAINERS */
+logic-topology .node .instance .stats-container .container rect {
+  fill: #eee;
+  stroke: steelblue;
+  stroke-width: 1px; }
+
+/* LEGEND */
+.legend {
+  fill: #fff;
+  stroke: #ccc;
+  stroke-width: 1px;
+  position: relative; }
+
+.legend text {
+  stroke: #000; }
+
+.node {
+  cursor: pointer; }
+
+.node circle,
+.node rect {
+  fill: #fff;
+  stroke: steelblue;
+  stroke-width: 1px; }
+
+.node.subscriber circle,
+.node.subscriber rect,
+.node.router circle,
+.node.router rect {
+  stroke: #05ffcb; }
+
+.node.slice rect {
+  stroke: #b01dff; }
+
+.node.instance rect {
+  stroke: #ccc; }
+
+.node.instance rect.active {
+  stroke: #ff8b00; }
+
+.node rect.slice-detail {
+  fill: #fff;
+  stroke: steelblue;
+  stroke-width: 3px; }
+
+.node text {
+  font: 18px sans-serif; }
+
+.node .instance text {
+  font: 12px sans-serif; }
+
+.node text.small {
+  font-size: 10px; }
+
+.link, .device-link {
+  fill: none;
+  stroke: #ccc;
+  stroke-width: 2px; }
+
+.link.slice {
+  stroke: rgba(157, 4, 183, 0.29); }
+
+.link.instance {
+  stroke: #ccc; }
+
+.link.instance.active {
+  stroke: rgba(255, 138, 0, 0.65); }
+
+.service-details {
+  width: 200px;
+  position: absolute;
+  top: 20px;
+  right: 20px; }
+
+/* when showing the thing */
+.animate.ng-hide-remove {
+  animation: 0.5s bounceInRight ease; }
+
+/* when hiding the picture */
+.animate.ng-hide-add {
+  animation: 0.5s bounceOutRight ease; }
+
+/* LOADER */
+.loader {
+  font-size: 10px;
+  margin: 150px auto;
+  text-indent: -9999em;
+  width: 11em;
+  height: 11em;
+  border-radius: 50%;
+  background: #ffffff;
+  background: -moz-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
+  background: -webkit-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
+  background: -o-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
+  background: -ms-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
+  background: linear-gradient(to right, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
+  position: relative;
+  animation: load3 1.4s infinite linear;
+  transform: translateZ(0); }
+
+.loader:before {
+  width: 50%;
+  height: 50%;
+  background: #105E9E;
+  border-radius: 100% 0 0 0;
+  position: absolute;
+  top: 0;
+  left: 0;
+  content: ''; }
+
+.loader:after {
+  background: #fff;
+  width: 75%;
+  height: 75%;
+  border-radius: 50%;
+  content: '';
+  margin: auto;
+  position: absolute;
+  top: 0;
+  left: 0;
+  bottom: 0;
+  right: 0; }
+
+@keyframes load3 {
+  0% {
+    -webkit-transform: rotate(0deg);
+    transform: rotate(0deg); }
+  100% {
+    -webkit-transform: rotate(360deg);
+    transform: rotate(360deg); } }
+
+/* MODALS */
+.modal.fade.in {
+  display: block; }
+
+/* ANIMATIONS */
+@keyframes bounceInRight {
+  from, 60%, 75%, 90%, to {
+    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); }
+  from {
+    opacity: 0;
+    transform: translate3d(3000px, 0, 0); }
+  60% {
+    opacity: 1;
+    transform: translate3d(-25px, 0, 0); }
+  75% {
+    transform: translate3d(10px, 0, 0); }
+  90% {
+    transform: translate3d(-5px, 0, 0); }
+  to {
+    transform: none; } }
+
+@keyframes bounceOutRight {
+  20% {
+    opacity: 1;
+    transform: translate3d(-20px, 0, 0); }
+  to {
+    opacity: 0;
+    transform: translate3d(2000px, 0, 0); } }
diff --git a/views/ngXosViews/diagnostic/src/index.html b/views/ngXosViews/diagnostic/src/index.html
new file mode 100644
index 0000000..f91ebbb
--- /dev/null
+++ b/views/ngXosViews/diagnostic/src/index.html
@@ -0,0 +1,44 @@
+<!-- browserSync -->
+<!-- bower:css -->
+<link rel="stylesheet" href="vendor/bootstrap-css/css/bootstrap.min.css" />
+<link rel="stylesheet" href="vendor/angular-chart.js/dist/angular-chart.css" />
+<!-- endbower --><!-- endcss -->
+<!-- inject:css -->
+<link rel="stylesheet" href="/css/main.css">
+<link rel="stylesheet" href="/../../../xos/core/static/xosNgLib.css">
+<!-- endinject -->
+
+<div ng-app="xos.diagnostic" id="xosDiagnostic">
+    <div ui-view></div>
+</div>
+
+<!-- bower:js -->
+<script src="vendor/jquery/dist/jquery.js"></script>
+<script src="vendor/angular/angular.js"></script>
+<script src="vendor/angular-mocks/angular-mocks.js"></script>
+<script src="vendor/angular-ui-router/release/angular-ui-router.js"></script>
+<script src="vendor/angular-cookies/angular-cookies.js"></script>
+<script src="vendor/angular-animate/angular-animate.js"></script>
+<script src="vendor/angular-resource/angular-resource.js"></script>
+<script src="vendor/lodash/lodash.js"></script>
+<script src="vendor/bootstrap-css/js/bootstrap.min.js"></script>
+<script src="vendor/Chart.js/Chart.js"></script>
+<script src="vendor/angular-chart.js/dist/angular-chart.js"></script>
+<script src="vendor/d3/d3.js"></script>
+<!-- endbower --><!-- endjs -->
+<!-- inject:js -->
+<script src="/../../../xos/core/xoslib/static/js/vendor/ngXosHelpers.js"></script>
+<script src="/.tmp/main.js"></script>
+<script src="/.tmp/subscriber-modal.js"></script>
+<script src="/.tmp/serviceTopologyHelper.js"></script>
+<script src="/.tmp/serviceTopology.js"></script>
+<script src="/.tmp/rest_services.js"></script>
+<script src="/.tmp/rackHelper.js"></script>
+<script src="/.tmp/nodeDrawer.js"></script>
+<script src="/.tmp/logicTopologyHelper.js"></script>
+<script src="/.tmp/logicTopology.js"></script>
+<script src="/.tmp/diagnostic.js"></script>
+<script src="/.tmp/d3.js"></script>
+<script src="/.tmp/config.js"></script>
+<script src="/.tmp/chart_data_service.js"></script>
+<!-- endinject -->
diff --git a/views/ngXosViews/diagnostic/src/js/chart_data_service.js b/views/ngXosViews/diagnostic/src/js/chart_data_service.js
new file mode 100644
index 0000000..63923e8
--- /dev/null
+++ b/views/ngXosViews/diagnostic/src/js/chart_data_service.js
@@ -0,0 +1,225 @@
+(function () {
+  'use strict';
+
+  angular.module('xos.diagnostic')
+  .service('ChartData', function($rootScope, $q, _, Tenant, Node, serviceTopologyConfig, Ceilometer, Instances) {
+    this.currentSubscriber = null;
+    this.currentServiceChain = null;
+
+    this.logicTopologyData = {
+      name: 'Router',
+      type: 'router',
+      children: [
+        {
+          name: 'WAN-Side',
+          subtitle: 'Virtual Network',
+          type: 'network',
+          children: [
+            {
+              name: 'Compute Servers',
+              type: 'rack',
+              computeNodes: [],
+              children: [
+                {
+                  name: 'LAN-Side',
+                  subtitle: 'Virtual Network',
+                  type: 'network',
+                  children: [{
+                    name: 'Subscriber',
+                    type: 'subscriber'
+                  }] //subscribers goes here
+                }
+              ]
+            }
+          ]
+        }
+      ]
+    };
+
+    this.getLogicTree = () => {
+      const deferred = $q.defer();
+
+      Node.queryWithInstances().$promise
+        .then((computeNodes) => {
+          this.logicTopologyData.children[0].children[0].computeNodes = computeNodes;
+          // LogicTopologyHelper.updateTree(svg);
+          deferred.resolve(this.logicTopologyData);
+        });
+
+      return deferred.promise;
+    };
+
+    /**
+    * Add Subscriber tag to LAN Network
+    */
+    this.addSubscriberTag = (tags) => {
+      this.logicTopologyData.children[0].children[0].children[0].subscriberTag = {
+        cTag: tags.cTag,
+        sTag: tags.sTag
+      };
+    };
+
+    /**
+    * Add Subscribers to the tree
+    */
+    this.addSubscriber = (subscriber) => {
+      subscriber.children = subscriber.devices;
+
+      // add subscriber to data tree
+      this.logicTopologyData.children[0].children[0].children[0].children = [subscriber];
+      return this.logicTopologyData;
+    };
+
+    /**
+    * Remove a subscriber from the tree
+    */
+   
+    this.removeSubscriber = () => {
+      this.logicTopologyData.children[0].children[0].children[0].children[0].humanReadableName = 'Subscriber';
+      this.currentSubscriber = null;
+      if(serviceTopologyConfig.elWidths[serviceTopologyConfig.elWidths.length - 1] === 160){
+        serviceTopologyConfig.elWidths.pop();
+      }
+
+      //remove tags and ip
+      delete this.logicTopologyData.children[0].children[0].children[0].subscriberTag;
+      delete this.logicTopologyData.children[0].subscriberIP;
+
+      this.highlightInstances([]);
+      delete this.logicTopologyData.children[0].children[0].children[0].children[0].children;
+    }
+
+    this.getSubscriberTag = (subscriber) => {
+      const tags = {
+        cTag: subscriber.c_tag,
+        sTag: subscriber.s_tag
+      };
+      
+      this.addSubscriberTag(tags);
+      // add tags info to current subscriber
+      this.currentSubscriber.tags = tags;
+
+    };
+
+    this.getSubscriberIP = (subscriber) => {
+      // const ip = JSON.parse(this.currentServiceChain.children[0].children[0].tenant.service_specific_attribute).wan_container_ip;
+      // const ip = this.currentServiceChain.children[0].children[0].tenant.wan_container_ip;
+      this.logicTopologyData.children[0].subscriberIP = subscriber.wan_container_ip;
+    };
+
+    this.selectSubscriber = (subscriber) => {
+      // append the device with to config settings
+      serviceTopologyConfig.elWidths.push(160);
+
+      this.addSubscriber(angular.copy(subscriber));
+
+      //clean selected instances
+      this.highlightInstances([]);
+
+      this.getSubscriberTag(subscriber);
+      this.getSubscriberIP(subscriber);
+
+    };
+
+    this.highlightInstances = (instances) => {
+
+      const computeNodes = this.logicTopologyData.children[0].children[0].computeNodes;
+
+      // unselect all
+      computeNodes.map((node) => {
+        node.instances.map((instance) => {
+          instance.selected = false
+          return instance;
+        });
+      });
+
+      _.forEach(instances, (instance) => {
+        computeNodes.map((node) => {
+          node.instances.map((d3instance) => {
+            if(d3instance.id === instance.id){
+              // console.log(d3instance, instance);
+              d3instance.selected = true;
+              d3instance.stats = instance.stats; //add stats to d3 node
+              d3instance.container = instance.container; // container info to d3 node
+            }
+            return d3instance;
+          });
+        });
+      });
+
+    }
+
+    this.getInstanceStatus = (service) => {
+      const deferred = $q.defer();
+
+      let p;
+
+      // subscriber specific
+      if(this.currentSubscriber){
+
+        let attr;
+        try {
+          attr = JSON.parse(service.tenant.service_specific_attribute);
+        }
+        catch(e){
+          attr = null;
+        }
+        
+        // if no instances are associated to the subscriber
+        if(!attr || !attr.instance_id){
+          let d = $q.defer();
+          d.resolve([]);
+          p = d.promise;
+        }
+        // if ther is an instance
+        else{
+          let instance = {};
+          p = Instances.get({id: attr.instance_id}).$promise
+          .then(function(_instance){
+            instance = _instance;
+            return Ceilometer.getInstanceStats(instance.instance_uuid);
+          })
+          .then((stats) => {
+            instance.stats = stats;
+            const containerName = `vcpe-${this.currentSubscriber.tags.sTag}-${this.currentSubscriber.tags.cTag}`;
+            // append containers
+            instance.container = {
+              name: containerName
+            };
+
+            // TODO fetch container stats
+            return Ceilometer.getContainerStats(containerName);
+          })
+          .then((containerStats) => {
+            instance.container.stats = containerStats.stats;
+            instance.container.port = containerStats.port;
+            return [instance];
+          });
+        }
+      }
+      // global scope
+      else {
+        const param = {
+          'service_vsg': {kind: 'vCPE'},
+          'service_vbng': {kind: 'vBNG'},
+          'service_volt': {kind: 'vOLT'}
+        };
+
+        p = Tenant.queryVsgInstances(param[service.name]).$promise
+        .then((instances) => {
+          return Ceilometer.getInstancesStats(_.uniq(instances));
+        });
+      }
+
+      p.then((instances) => {
+        this.highlightInstances(instances);
+        deferred.resolve(instances);
+      })
+      .catch((e) => {
+        deferred.reject(e);
+      });
+
+      return deferred.promise;
+    };
+  })
+})();
diff --git a/views/ngXosViews/diagnostic/src/js/config.js b/views/ngXosViews/diagnostic/src/js/config.js
new file mode 100644
index 0000000..ac0f989
--- /dev/null
+++ b/views/ngXosViews/diagnostic/src/js/config.js
@@ -0,0 +1,51 @@
+(function () {
+  'use strict';
+
+  angular.module('xos.diagnostic')
+  .constant('serviceTopologyConfig', {
+    widthMargin: 60,
+    heightMargin: 30,
+    duration: 750,
+    elWidths: [20, 104, 105, 104, 20], //this is not true
+    circle: {
+      radius: 10,
+      r: 10,
+      selectedRadius: 15
+    },
+    square: {
+      width: 20,
+      height: 20,
+      x: -10,
+      y: -10
+    },
+    rack: {
+      width: 105,
+      height: 50,
+      x: -30,
+      y: -25
+    },
+    computeNode: {
+      width: 50,
+      height: 20,
+      margin: 5,
+      labelHeight: 10,
+      x: -25,
+      y: -10
+    },
+    instance: {
+      width: 80,
+      height: 36,
+      margin: 5,
+      x: -40,
+      y: -18
+    },
+    container: {
+      width: 60,
+      height: 130,
+      margin: 5,
+      x: -30,
+      y: -15
+    }
+  })
+
+}());
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/src/js/d3.js b/views/ngXosViews/diagnostic/src/js/d3.js
new file mode 100644
index 0000000..b56ee8f
--- /dev/null
+++ b/views/ngXosViews/diagnostic/src/js/d3.js
@@ -0,0 +1,9 @@
+(function () {
+  'use strict';
+
+  angular.module('xos.diagnostic')
+  .factory('d3', function($window){
+    return $window.d3;
+  })
+
+}());
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/src/js/diagnostic.js b/views/ngXosViews/diagnostic/src/js/diagnostic.js
new file mode 100644
index 0000000..7d97fdb
--- /dev/null
+++ b/views/ngXosViews/diagnostic/src/js/diagnostic.js
@@ -0,0 +1,61 @@
+(function () {
+  'use strict';
+  angular.module('xos.diagnostic')
+  .directive('diagnosticContainer', function(){
+    return {
+      restrict: 'E',
+      templateUrl: 'templates/diagnostic.tpl.html',
+      controllerAs: 'vm',
+      controller: function(ChartData, Subscribers, ServiceRelation, $rootScope, $log){
+
+        this.loader = true;
+        this.error = false;
+        
+        const loadGlobalScope = () => {
+          Subscribers.query().$promise
+          .then((subscribers) => {
+            this.subscribers = subscribers;
+            return ServiceRelation.get();
+          })
+          .then((serviceChain) => {
+            this.serviceChain = serviceChain;
+            // debug helper
+            // loadSubscriber(this.subscribers[0]);
+          })
+          .catch(e => {
+            throw new Error(e);
+            this.error = e;
+          })
+          .finally(() => {
+            this.loader = false;
+          });
+        };
+
+        loadGlobalScope();
+
+        this.reloadGlobalScope = () => {
+          this.selectedSubscriber = null;
+          loadGlobalScope();
+        }
+
+        const loadSubscriber = (subscriber) => {
+          ServiceRelation.getBySubscriber(subscriber)
+          .then((serviceChain) => {
+            this.serviceChain = serviceChain;
+            ChartData.currentServiceChain = serviceChain;
+            return Subscribers.getWithDevices({id: subscriber.id}).$promise;
+          })
+          .then((subscriber) => {
+            this.selectedSubscriber = subscriber;
+            ChartData.currentSubscriber = subscriber;
+          });
+        };
+
+        $rootScope.$on('subscriber.selected', (evt, subscriber) => {
+          loadSubscriber(subscriber);
+        });
+
+      }
+    }
+  });
+})();
diff --git a/views/ngXosViews/diagnostic/src/js/logicTopology.js b/views/ngXosViews/diagnostic/src/js/logicTopology.js
new file mode 100644
index 0000000..5ab5d0f
--- /dev/null
+++ b/views/ngXosViews/diagnostic/src/js/logicTopology.js
@@ -0,0 +1,119 @@
+(function () {
+  'use strict';
+  angular.module('xos.diagnostic')
+  .directive('logicTopology', function(){
+    return {
+      restrict: 'E',
+      scope: {
+        subscribers: '=',
+        selected: '='
+      },
+      bindToController: true,
+      controllerAs: 'vm',
+      templateUrl: 'templates/logicTopology.tpl.html',
+      controller: function($element, $log, $scope, $rootScope, $timeout, d3, LogicTopologyHelper, Node, Tenant, Ceilometer, serviceTopologyConfig, ChartData){
+        $log.info('Logic Plane');
+
+        var svg;
+        this.selectedInstances = [];
+        this.hideInstanceStats = true;
+        var _this = this;
+
+        const handleSvg = (el) => {
+
+          d3.select($element[0]).select('svg').remove();
+
+          svg = d3.select(el)
+          .append('svg')
+          .style('width', `${el.clientWidth}px`)
+          .style('height', `${el.clientHeight}px`);
+        }
+
+        const loadGlobalScope = () => {
+          ChartData.getLogicTree()
+          .then((tree) => {
+            LogicTopologyHelper.updateTree(svg);
+          });
+        }
+        loadGlobalScope();
+
+        $scope.$watch(() => this.selected, (selected) => {
+          if(selected){
+            ChartData.selectSubscriber(selected);
+            LogicTopologyHelper.updateTree(svg);
+          }
+          else{
+            ChartData.removeSubscriber();
+            LogicTopologyHelper.updateTree(svg);
+          }
+        });
+
+        $rootScope.$on('instance.detail.hide', () => {
+          this.hideInstanceStats = true;
+          $timeout(() => {
+            this.selectedInstances = [];
+            ChartData.highlightInstances([]);
+            LogicTopologyHelper.updateTree(svg);
+          }, 500);
+        });
+
+        $rootScope.$on('instance.detail', (evt, service) => {
+          ChartData.getInstanceStatus(service)
+          .then((instances) => {
+            LogicTopologyHelper.updateTree(svg);
+          })
+          .catch(e => {
+            _this.error = 'Service statistics are not available at this time. Please try again later.'
+            $timeout(() => {
+              _this.error = null;
+            }, 2000);
+          })
+        });
+
+        d3.select(window)
+        .on('resize.logic', () => {
+          handleSvg($element[0]);
+          LogicTopologyHelper.setupTree(svg);
+          LogicTopologyHelper.updateTree(svg);
+        });
+
+        handleSvg($element[0]);
+        LogicTopologyHelper.setupTree(svg);
+
+        this.selectSubscriberModal = () => {
+          this.openSelectSubscriberModal = true;
+          $scope.$apply();
+        };
+
+        this.subscriberStatusModal = () => {
+          this.openSubscriberStatusModal = true;
+          $scope.$apply();
+        };
+
+        // listen for subscriber modal event
+        $rootScope.$on('subscriber.modal.open', () => {
+
+          if(ChartData.currentSubscriber){
+            this.subscriberStatusModal();
+          }
+          else{
+            this.selectSubscriberModal();
+          }
+        });
+
+        // listen for subscriber modal event
+        $rootScope.$on('subscriber.modal.open', () => {
+
+          if(ChartData.currentSubscriber){
+            this.currentSubscriber = ChartData.currentSubscriber;
+            this.subscriberStatusModal();
+          }
+          else{
+            this.selectSubscriberModal();
+          }
+        });
+
+      }
+    };
+  });
+})();
diff --git a/views/ngXosViews/diagnostic/src/js/logicTopologyHelper.js b/views/ngXosViews/diagnostic/src/js/logicTopologyHelper.js
new file mode 100644
index 0000000..6c85cdf
--- /dev/null
+++ b/views/ngXosViews/diagnostic/src/js/logicTopologyHelper.js
@@ -0,0 +1,177 @@
+(function () {
+  'use strict';
+
+  angular.module('xos.diagnostic')
+  .service('LogicTopologyHelper', function($window, $log, $rootScope, _, serviceTopologyConfig, NodeDrawer, ChartData){
+
+    var diagonal, nodes, links, i = 0, svgWidth, svgHeight, layout;
+
+    const baseData = ChartData.logicTopologyData;
+
+    /**
+     * Calculate the horizontal position for each element.
+     * subsrcribers, devices and routers have the same fixed width 20
+     * network have a fixed width 104
+     * rack have a fixed width 105
+     * build and array of 6 elements representing the position of each element in the svg
+     * to equally space them
+     */
+
+    this.computeElementPosition = (svgWidth) => {
+
+      let xPos = [];
+
+      let totalElWidth = _.reduce(serviceTopologyConfig.elWidths, (el, val) => val + el, 0);
+
+      let remainingSpace = svgWidth - totalElWidth - (serviceTopologyConfig.widthMargin * 2);
+
+      let step = remainingSpace / (serviceTopologyConfig.elWidths.length - 1);
+
+      _.forEach(serviceTopologyConfig.elWidths, (el, i) => {
+
+        // get half of the previous elements width
+        let previousElWidth = 0;
+        if(i !== 0){
+          previousElWidth = _.reduce(serviceTopologyConfig.elWidths.slice(0, i), (el, val) => val + el, 0);
+        }
+
+        let elPos =
+          serviceTopologyConfig.widthMargin // right margin
+          + (step * i) // space between elements
+          + (el / 2) // this el width
+          + previousElWidth; // previous elements width
+
+        xPos.push(svgWidth - elPos);
+      })
+
+      return xPos
+    };
+
+    /**
+    * from a nested data structure,
+    * create nodes and links for a D3 Tree Layout
+    */
+    const computeLayout = (data) => {
+      let nodes = layout.nodes(data);
+
+      // Normalize for fixed-depth.
+      nodes.forEach((d) => {
+        // position the child node horizontally
+        d.y = this.computeElementPosition(svgWidth)[d.depth];
+      });
+
+      let links = layout.links(nodes);
+
+      return [nodes, links];
+    };
+
+    /**
+    * Draw the containing group for any node or update the existing one
+    */
+    const drawNodes = (svg, nodes) => {
+      // Update the nodes…
+      var node = svg.selectAll('g.node')
+      .data(nodes, d => {
+        if(!angular.isString(d.d3Id)){
+          d.d3Id = `tree-${++i}`;
+        }
+        return d.d3Id;
+      });
+
+      // Enter any new nodes
+      var nodeEnter = node.enter().append('g')
+      .attr({
+        class: d => `node ${d.type}`,
+        transform: `translate(${svgWidth / 2}, ${svgHeight / 2})`
+      });
+
+      // create Nodes
+      NodeDrawer.addNetworks(node.filter('.network'));
+      NodeDrawer.addRack(node.filter('.rack'));
+      NodeDrawer.addPhisical(node.filter('.router'));
+      NodeDrawer.addPhisical(node.filter('.subscriber'));
+      NodeDrawer.addDevice(node.filter('.device'));
+
+      // add event listener to subscriber
+      node.filter('.subscriber')
+      .on('click', () => {
+        $rootScope.$emit('subscriber.modal.open');
+      });
+
+      //update nodes
+      // TODO if data change, only update them
+      // NodeDrawer.updateRack(node.filter('.rack'));
+
+      // Transition nodes to their new position.
+      var nodeUpdate = node.transition()
+        .duration(serviceTopologyConfig.duration)
+        .attr({
+          'transform': d => `translate(${d.y},${d.x})`
+        });
+
+      // TODO handle node remove
+      var nodeExit = node.exit().remove();
+    };
+
+    /**
+    * Handle links in the tree layout
+    */
+    const drawLinks = (svg, links) => {
+
+      diagonal = d3.svg.diagonal()
+      .projection(d => [d.y, d.x]);
+
+      // Update the links…
+      var link = svg.selectAll('path.link')
+        .data(links, d => {
+          return d.target.d3Id
+        });
+
+      // Enter any new links at the parent's previous position.
+      link.enter().insert('path', 'g')
+        .attr('class', d => `link ${d.target.type}`)
+        .attr('d', function(d) {
+          var o = {x: svgHeight / 2, y: svgWidth / 2};
+          return diagonal({source: o, target: o});
+        });
+
+      // Transition links to their new position.
+      link.transition()
+        .duration(serviceTopologyConfig.duration)
+        .attr('d', diagonal);
+
+      link.exit().remove();
+    };
+
+    /**
+    * Calculate the svg size and setup tree layout
+    */
+    this.setupTree = (svg) => {
+      
+
+      svgWidth = svg.node().getBoundingClientRect().width;
+      svgHeight = svg.node().getBoundingClientRect().height;
+
+      const width = svgWidth - (serviceTopologyConfig.widthMargin * 2);
+      const height = svgHeight - (serviceTopologyConfig.heightMargin * 2);
+
+      layout = d3.layout.tree()
+      .size([height, width]);
+    };
+
+    /**
+    * Update the tree layout
+    */
+
+    this.updateTree = (svg) => {
+      // Compute the new tree layout.
+      [nodes, links] = computeLayout(baseData);
+
+      // console.log(baseData);
+      drawNodes(svg, nodes);
+      drawLinks(svg, links);
+    }
+
+  });
+
+}());
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/src/js/main.js b/views/ngXosViews/diagnostic/src/js/main.js
new file mode 100644
index 0000000..210606a
--- /dev/null
+++ b/views/ngXosViews/diagnostic/src/js/main.js
@@ -0,0 +1,25 @@
+(function () {
+  'use strict';
+
+  angular.module('xos.diagnostic', [
+    'ngResource',
+    'ngCookies',
+    'ngAnimate',
+    'ui.router',
+    'xos.helpers'
+  ])
+  .config(($stateProvider) => {
+    $stateProvider
+    .state('home', {
+      url: '/',
+      template: '<diagnostic-container></diagnostic-container>'
+    });
+  })
+  .config(function($httpProvider){
+    $httpProvider.interceptors.push('NoHyperlinks');
+  })
+  .run(($log) => {
+    $log.info('Diagnostic Started');
+  });
+
+})();
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/src/js/nodeDrawer.js b/views/ngXosViews/diagnostic/src/js/nodeDrawer.js
new file mode 100644
index 0000000..a24483f
--- /dev/null
+++ b/views/ngXosViews/diagnostic/src/js/nodeDrawer.js
@@ -0,0 +1,567 @@
+(function () {
+  'use strict';
+
+  const shapes = {
+    cloud: ' M 79.72 49.60 C 86.00 37.29 98.57 29.01 111.96 26.42 C 124.27 24.11 137.53 26.15 148.18 32.90 C 158.08 38.78 165.39 48.87 167.65 60.20 C 176.20 57.90 185.14 56.01 194.00 57.73 C 206.08 59.59 217.92 66.01 224.37 76.66 C 227.51 81.54 228.85 87.33 229.23 93.06 C 237.59 93.33 246.22 95.10 253.04 100.19 C 256.69 103.13 259.87 107.67 258.91 112.59 C 257.95 118.43 252.78 122.38 247.78 124.82 C 235.27 130.43 220.23 130.09 207.98 123.93 C 199.33 127.88 189.76 129.43 180.30 128.57 C 173.70 139.92 161.70 147.65 148.86 149.93 C 133.10 153.26 116.06 148.15 104.42 137.08 C 92.98 143.04 78.96 143.87 66.97 139.04 C 57.75 135.41 49.70 128.00 46.60 118.43 C 43.87 109.95 45.81 100.29 51.30 93.32 C 57.38 85.18 67.10 80.44 76.99 78.89 C 74.38 69.20 74.87 58.52 79.72 49.60 Z'
+  }
+
+  var computeNodeId = 0;
+  var instanceId = 0;
+
+  angular.module('xos.diagnostic')
+  .service('NodeDrawer', function(d3, serviceTopologyConfig, RackHelper, _){
+
+    var _this = this;
+
+    this.addNetworks = (nodes) => {
+
+      // clean childs
+      nodes.selectAll('*').remove();
+
+      nodes.append('path')
+      .attr({
+        d: shapes.cloud,
+        transform: 'translate(-100, -72), scale(0.7)',
+        class: 'cloud'
+      });
+
+      nodes.append('text')
+      .attr({
+        'text-anchor': 'middle',
+        y: -5,
+        x: 5,
+      })
+      .text(d => d.name)
+
+      nodes.append('text')
+      .attr({
+        'text-anchor': 'middle',
+        y: 8,
+        x: 5,
+        class: 'small'
+      })
+      .text(d => d.subtitle)
+
+      nodes.each(function(n){
+        let currentNode = d3.select(this);
+        // cicle trouch node to add Tags and Public IP
+        if(n.name === 'LAN-Side' && angular.isDefined(n.subscriberTag)){
+          currentNode.append('text')
+          .attr({
+            'text-anchor': 'middle',
+            y: 50
+          })
+          .text(() => `C-Tag: ${n.subscriberTag.cTag}`);
+
+          currentNode.append('text')
+          .attr({
+            'text-anchor': 'middle',
+            y: 70
+          })
+          .text(() => `S-Tag: ${n.subscriberTag.sTag}`);
+        }
+
+        if(n.name === 'WAN-Side' && angular.isDefined(n.subscriberIP)){
+          currentNode.append('text')
+          .attr({
+            'text-anchor': 'middle',
+            y: 50
+          })
+          .text(() => `Public IP: ${n.subscriberIP}`);
+        }
+      });
+    }
+
+    this.addRack = (nodes) => {
+
+      // loop because of D3
+      // rack will be only one
+      nodes.each(d => {
+        let [w, h] = RackHelper.getRackSize(d.computeNodes);
+
+        // TODO update instead of delete and redraw
+        nodes.select('g').remove();
+
+        let rack = nodes
+        .append('g');
+
+        rack
+        .attr({
+          transform: `translate(0,0)`
+        })
+        .transition()
+        .duration(serviceTopologyConfig.duration)
+        .attr({
+          transform: () => `translate(${- (w / 2)}, ${- (h / 2)})`
+        });
+
+        rack
+        .append('rect')
+        .attr({
+          width: 0,
+          height: 0
+        })
+        .transition()
+        .duration(serviceTopologyConfig.duration)
+        .attr({
+          width: w,
+          height: h
+        });
+
+        rack.append('text')
+        .attr({
+          'text-anchor': 'middle',
+          y: - 10,
+          x: w / 2,
+          opacity: 0
+        })
+        .text(d => d.name)
+        .transition()
+        .duration(serviceTopologyConfig.duration)
+        .attr({
+          opacity: 1
+        })
+
+        this.drawComputeNodes(rack, d.computeNodes);
+
+      });
+
+    };
+
+    this.drawComputeNodes = (container, nodes) => {
+      
+      let elements = container.selectAll('.compute-nodes')
+      .data(nodes, d => {
+        if(!angular.isString(d.d3Id)){
+          d.d3Id = `compute-node-${++computeNodeId}`;
+        }
+        return d.d3Id;
+      });
+
+      let {width, height} = container.node().getBoundingClientRect();
+
+      var nodeContainer = elements.enter().append('g');
+
+      nodeContainer
+      .attr({
+        transform: `translate(${width / 2}, ${ height / 2})`,
+        class: 'compute-node',
+      })
+      .transition()
+      .duration(serviceTopologyConfig.duration)
+      .attr({
+        transform: (d) => `translate(${RackHelper.getComputeNodePosition(nodes, d.d3Id.replace('compute-node-', '') - 1)})`
+      });
+
+      nodeContainer.append('rect')
+      .attr({
+        width: 0,
+        height: 0
+      })
+      .transition()
+      .duration(serviceTopologyConfig.duration)
+      .attr({
+        width: d => RackHelper.getComputeNodeSize(d.instances)[0],
+        height: d => RackHelper.getComputeNodeSize(d.instances)[1],
+      });
+
+      nodeContainer.append('text')
+      .attr({
+        'text-anchor': 'start',
+        y: 17, //FIXME
+        x: 10, //FIXME
+        opacity: 0
+      })
+      .text(d => d.humanReadableName.split('.')[0])
+      .transition()
+      .duration(serviceTopologyConfig.duration)
+      .attr({
+        opacity: 1
+      })
+
+      // if there are Compute Nodes
+      if(nodeContainer.length > 0){
+        // draw instances for each compute node
+        nodeContainer.each(function(a){
+          _this.drawInstances(d3.select(this), a.instances);
+        })
+      }
+
+    };
+
+    // NOTE Stripping unuseful names to shorten labels.
+    // This is not elegant
+    const formatInstanceName = (name) => {
+      return name
+        .replace('app_', '')
+        .replace('service_', '')
+        // .replace('ovs_', '')
+        .replace('mysite_', '')
+        .replace('_instance', '');
+    };
+
+    const getInstanceStatusColor = (instance) => {
+      function startWith(val, string){
+        return string.substring(0, val.length) === val;
+      }
+
+      if(startWith('0 - ', instance.backend_status)){
+        return 'provisioning';
+      }
+      if(startWith('1 - ', instance.backend_status)){
+        return 'good';
+      }
+      if(startWith('2 - ', instance.backend_status)){
+        return 'bad';
+      }
+      else {
+        return '';
+      }
+    };
+
+    const drawContainer = (container, docker) => {
+
+      const containerBox = container.append('g')
+        .attr({
+          class: 'container',
+          transform: `translate(${serviceTopologyConfig.instance.margin}, 115)`
+        });
+
+      containerBox.append('rect')
+        .attr({
+          width: 250 - (serviceTopologyConfig.container.margin * 2),
+          height: serviceTopologyConfig.container.height,
+        });
+
+      containerBox.append('text')
+        .attr({
+          y: 20,
+          x: serviceTopologyConfig.instance.margin,
+          class: 'name'
+        })
+        .text(docker.name)
+
+      // add stats
+      const interestingMeters = ['memory', 'memory.usage', 'cpu_util'];
+
+      interestingMeters.forEach((m, i) => {
+        const meter = _.find(docker.stats, {meter: m});
+        // if there is no meter stats skip rendering
+        if(!angular.isDefined(meter)){
+          return;
+        }
+        containerBox.append('text')
+        .attr({
+          y: 40 + (i * 15),
+          x: serviceTopologyConfig.instance.margin,
+          opacity: 0
+        })
+        .text(`${meter.description}: ${Math.round(meter.value)} ${meter.unit}`)
+        .transition()
+        .duration(serviceTopologyConfig.duration)
+        .attr({
+          opacity: 1
+        });
+      });
+
+      // add port stats
+      const ports = ['eth0', 'eth1'];
+      const interestingPortMeters = [
+        {
+          meter: 'network.incoming.bytes.rate',
+          label: 'Incoming'
+        },
+        {
+          meter: 'network.outgoing.bytes.rate',
+          label: 'Outgoing'
+        }
+      ];
+      
+      ports.forEach((p, j) => {
+
+        // if there are no port stats skip rendering
+        if(docker.port[p].length === 0){
+          return;
+        }
+
+        containerBox.append('text')
+        .attr({
+          y: 90,
+          x: serviceTopologyConfig.instance.margin + (120 * j),
+          class: 'name'
+        })
+        .text(`${docker.name}-${p}`)
+
+        interestingPortMeters.forEach((m, i) => {
+
+          const meter = _.find(docker.port[p], {meter: m.meter});
+          // if there is no meter stats skip rendering
+          if(!angular.isDefined(meter)){
+            return;
+          }
+          containerBox.append('text')
+          .attr({
+            y: 105 + (i * 15),
+            x: serviceTopologyConfig.instance.margin + (120 * j),
+            opacity: 0
+          })
+          .text(`${m.label}: ${Math.round(meter.value)} ${meter.unit}`)
+          .transition()
+          .duration(serviceTopologyConfig.duration)
+          .attr({
+            opacity: 1
+          });
+        });
+      });
+    }
+
+    const showInstanceStats = (container, instance) => {
+
+      // NOTE this should be dinamically positioned
+      // base on the number of element present
+
+      // fake the position
+      let translation = {
+        'mysite_vsg-1': '200, -120',
+        'mysite_vsg-2': '-300, 30',
+        'mysite_vsg-3': '-300, -250',
+      };
+
+      const statsContainer = container.append('g')
+        .attr({
+          transform: `translate(${translation[instance.humanReadableName] || translation['mysite_vsg-1']})`,
+          class: 'stats-container'
+        })
+        .on('click', function(d) {
+          // toggling visisbility
+          d.fade = !d.fade;
+          let opacity;
+          if(d.fade){
+            opacity = 0.1;
+          }
+          else{
+            opacity = 1;
+          }
+
+          d3.select(this)
+          .transition()
+          .duration(serviceTopologyConfig.duration)
+          .attr({
+            opacity: opacity
+          })
+        });
+
+      let lines = {
+        'mysite_vsg-1': {
+          x1: -160,
+          y1: 120,
+          x2: 0,
+          y2: 50,
+        },
+        'mysite_vsg-2': {
+          x1: 250,
+          y1: 50,
+          x2: 300,
+          y2: -10
+        },
+        'mysite_vsg-3': {
+          x1: 250,
+          y1: 50,
+          x2: 300,
+          y2: 270
+        }
+      }
+
+      statsContainer.append('line')
+        .attr({
+          x1: d => lines[d.humanReadableName].x1 || lines['mysite_vsg-1'].x1,
+          y1: d => lines[d.humanReadableName].y1 || lines['mysite_vsg-1'].y1,
+          x2: d => lines[d.humanReadableName].x2 || lines['mysite_vsg-1'].x2,
+          y2: d => lines[d.humanReadableName].y2 || lines['mysite_vsg-1'].y2,
+          stroke: 'black',
+          opacity: 0
+        })
+        .transition()
+        .duration(serviceTopologyConfig.duration)
+        .attr({
+          opacity: 1
+        })
+
+      // NOTE rect should be dinamically sized base on the presence of a container
+      let statsHeight = 110;
+      let statsWidth = 250;
+
+      if (instance.container){
+        statsHeight += serviceTopologyConfig.container.height + (serviceTopologyConfig.container.margin * 2)
+      }
+
+      const statsVignette = statsContainer.append('rect')
+        .attr({
+          width: statsWidth,
+          height: statsHeight,
+          opacity: 0
+        })
+        .transition()
+        .duration(serviceTopologyConfig.duration)
+        .attr({
+          opacity: 1
+        });
+
+
+      // add instance info
+      statsContainer.append('text')
+        .attr({
+          y: 15,
+          x: serviceTopologyConfig.instance.margin,
+          class: 'name',
+          opacity: 0
+        })
+        .text(instance.humanReadableName)
+        .transition()
+        .duration(serviceTopologyConfig.duration)
+        .attr({
+          opacity: 1
+        })
+
+      statsContainer.append('text')
+        .attr({
+          y: 30,
+          x: serviceTopologyConfig.instance.margin,
+          class: 'ip',
+          opacity: 0
+        })
+        .text(instance.ip)
+        .transition()
+        .duration(serviceTopologyConfig.duration)
+        .attr({
+          opacity: 1
+        })
+
+      // add stats
+      const interestingMeters = ['memory', 'memory.usage', 'cpu', 'cpu_util'];
+
+      interestingMeters.forEach((m, i) => {
+        const meter = _.find(instance.stats, {meter: m});
+
+        if(meter){
+          
+          statsContainer.append('text')
+          .attr({
+            y: 55 + (i * 15),
+            x: serviceTopologyConfig.instance.margin,
+            opacity: 0
+          })
+          .text(`${meter.description}: ${Math.round(meter.value)} ${meter.unit}`)
+          .transition()
+          .duration(serviceTopologyConfig.duration)
+          .attr({
+            opacity: 1
+          });
+        }
+
+      });
+
+      if(instance.container){
+        // draw container
+        drawContainer(statsContainer, instance.container);
+      }
+
+    };
+
+    this.drawInstances = (container, instances) => {
+      
+      // TODO check for stats field in instance and draw popup
+
+      let {width, height} = container.node().getBoundingClientRect();
+
+      let elements = container.selectAll('.instances')
+      .data(instances, d => angular.isString(d.d3Id) ? d.d3Id : d.d3Id = `instance-${++instanceId}`)
+
+      var instanceContainer = elements.enter().append('g');
+
+      instanceContainer
+      .attr({
+        transform: `translate(${width / 2}, ${ height / 2})`,
+        class: d => `instance ${d.selected ? 'active' : ''} ${getInstanceStatusColor(d)}`,
+      })
+      .transition()
+      .duration(serviceTopologyConfig.duration)
+      .attr({
+        transform: (d, i) => `translate(${RackHelper.getInstancePosition(i)})`
+      });
+
+      instanceContainer.append('rect')
+      .attr({
+        width: 0,
+        height: 0
+      })
+      .transition()
+      .duration(serviceTopologyConfig.duration)
+      .attr({
+        width: serviceTopologyConfig.instance.width,
+        height: serviceTopologyConfig.instance.height
+      });
+
+      instanceContainer.append('text')
+      .attr({
+        'text-anchor': 'middle',
+        y: 23, //FIXME
+        x: 40, //FIXME
+        opacity: 0
+      })
+      .text(d => formatInstanceName(d.humanReadableName))
+      .transition()
+      .duration(serviceTopologyConfig.duration)
+      .attr({
+        opacity: 1
+      });
+
+      // if stats are attached and instance is active,
+      // draw stats
+      instanceContainer.each(function(instance, i){
+
+        const container = d3.select(this);
+
+        if(angular.isDefined(instance.stats) && instance.selected){
+          showInstanceStats(container, instance, i);
+        }
+      });
+
+      // instanceContainer
+      // .on('click', function(d){
+      //   console.log(`Draw vignette with stats for instance: ${d.name}`);
+      // });
+    };
+
+    this.addPhisical = (nodes) => {
+
+      nodes.select('rect').remove();
+      nodes.select('text').remove();
+
+      nodes.append('rect')
+      .attr(serviceTopologyConfig.square);
+
+      nodes.append('text')
+      .attr({
+        'text-anchor': 'middle',
+        y: serviceTopologyConfig.square.y - 10
+      })
+      .text(d => {
+        return d.name || d.humanReadableName
+      });
+    }
+
+    this.addDevice = (nodes) => {
+      nodes.append('circle')
+      .attr(serviceTopologyConfig.circle);
+
+      nodes.append('text')
+      .attr({
+        'text-anchor': 'end',
+        x: - serviceTopologyConfig.circle.r - 10,
+        y: serviceTopologyConfig.circle.r / 2
+      })
+      .text(d => d.name || d.mac); 
+    }
+  });
+})();
diff --git a/views/ngXosViews/diagnostic/src/js/rackHelper.js b/views/ngXosViews/diagnostic/src/js/rackHelper.js
new file mode 100644
index 0000000..af3eb30
--- /dev/null
+++ b/views/ngXosViews/diagnostic/src/js/rackHelper.js
@@ -0,0 +1,85 @@
+(function () {
+  angular.module('xos.diagnostic')
+  .service('RackHelper', function(serviceTopologyConfig, _){
+
+    this.getComputeNodeLabelSize = () => {
+      return serviceTopologyConfig.computeNode.labelHeight + (serviceTopologyConfig.instance.margin * 2)
+    }
+
+    /**
+    * Given a list of instance should get the Compute Node size.
+    * They are placed in rows of 2 with 5px margin on each side.
+    */
+   
+    this.getComputeNodeSize = _.memoize((instances) => {
+      const width = (serviceTopologyConfig.instance.margin * 3) + (serviceTopologyConfig.instance.width *2);
+
+      const rows = Math.round(instances.length / 2);
+
+      const labelSpace = this.getComputeNodeLabelSize();
+
+      const height = (serviceTopologyConfig.instance.height * rows) + (serviceTopologyConfig.instance.margin * (rows + 1)) + labelSpace;
+
+      return [width, height];
+    });
+
+    /**
+    * Give a list on Compute Node should calculate the Rack Size.
+    * Compute nodes are placed in a single column with 5px margin on each side.
+    */
+    this.getRackSize = (nodes) => {
+
+      let width = 0;
+      let height = serviceTopologyConfig.computeNode.margin;
+
+      _.forEach(nodes, (node) => {
+        let [nodeWidth, nodeHeight] = this.getComputeNodeSize(node.instances);
+
+        width = nodeWidth + (serviceTopologyConfig.computeNode.margin * 2);
+        height += (nodeHeight + serviceTopologyConfig.computeNode.margin);
+      });
+
+      return [width, height];
+    };
+
+    /**
+    * Given an instance index, return the coordinates
+    */
+   
+    this.getInstancePosition = (position) => {
+      const row = Math.floor(position / 2);
+      const column = (position % 2) ? 1 : 0;
+
+      // add ComputeNode label size
+      const labelSpace = this.getComputeNodeLabelSize();
+
+      // x = margin + (width * column) + ( maring * column)
+      const x = serviceTopologyConfig.instance.margin + (serviceTopologyConfig.instance.width * column) + (serviceTopologyConfig.instance.margin * column);
+
+      // y = label + margin + (height * row) + ( maring * row)
+      const y = labelSpace + serviceTopologyConfig.instance.margin + (serviceTopologyConfig.instance.height * row) + (serviceTopologyConfig.instance.margin * row);
+      return [x, y];
+    };
+
+    /**
+    * Given an Compute Node index, return the coordinates
+    */
+
+    this.getComputeNodePosition = (nodes, position) => {
+
+      const x = serviceTopologyConfig.computeNode.margin;
+
+      let previousElEight = _.reduce(nodes.slice(0, position), (val, node) => {
+        return val + this.getComputeNodeSize(node.instances)[1]
+      }, 0);
+
+      const y =
+        serviceTopologyConfig.computeNode.margin
+        + (serviceTopologyConfig.computeNode.margin * position)
+        + previousElEight;
+
+      return [x, y];
+    };
+
+  });
+})();
diff --git a/views/ngXosViews/diagnostic/src/js/rest_services.js b/views/ngXosViews/diagnostic/src/js/rest_services.js
new file mode 100644
index 0000000..fa2fc8f
--- /dev/null
+++ b/views/ngXosViews/diagnostic/src/js/rest_services.js
@@ -0,0 +1,461 @@
+(function () {
+  'use strict';
+
+  angular.module('xos.diagnostic')
+  .service('Services', function($resource){
+    return $resource('/api/core/services/:id', {id: '@id'});
+  })
+  .service('Tenant', function($resource){
+    return $resource('/api/core/tenants', {id: '@id'}, {
+      queryVsgInstances: {
+        method: 'GET',
+        isArray: true,
+        interceptor: {
+          response: (res) => {
+
+            // NOTE
+            // Note that VCPETenant is now VSGTenant.
+
+            let instances = [];
+
+            angular.forEach(res.data, (tenant) => {
+              let info = JSON.parse(tenant.service_specific_attribute);
+              if(info && info.instance_id){
+                instances.push(info.instance_id);
+              }
+            });
+
+            return instances;
+          }
+        }
+      },
+      getSubscriberTag: {
+        method: 'GET',
+        isArray: true,
+        interceptor: {
+          response: (res) => {
+            // NOTE we should receive only one vOLT tenant here
+            return JSON.parse(res.data[0].service_specific_attribute);
+          }
+        }
+      }
+    });
+  })
+  .service('Ceilometer', function($http, $q, Instances) {
+
+    /**
+    * Get stats for a single instance
+    */
+    this.getInstanceStats = (instanceUuid) => {
+      let deferred = $q.defer();
+
+      $http.get('/xoslib/xos-instance-statistics', {params: {'instance-uuid': instanceUuid}})
+      .then((res) => {
+        deferred.resolve(res.data);
+      })
+      .catch((e) => {
+        deferred.reject(e);
+      })
+
+      return deferred.promise;
+    };
+
+    /**
+    * Collect stats for an array of instances
+    */
+    this.getInstancesStats = (instances) => {
+      let deferred = $q.defer();
+      let instancePromises = [];
+      let instanceList = [];
+
+      // retrieve instance details
+      instances.forEach((instanceId) => {
+        instancePromises.push(Instances.get({id: instanceId}).$promise);
+      });
+
+      // get all instance data
+      $q.all(instancePromises)
+      .then((_instanceList) => {
+        instanceList = _instanceList;
+        let promises = [];
+        // foreach instance query stats
+        instanceList.forEach((instance) => {
+          promises.push(this.getInstanceStats(instance.instance_uuid));
+        });
+        return $q.all(promises);
+      })
+      .then(stats => {
+        // augment instance with stats information
+        instanceList.map((instance, i) => {
+          instance.stats = stats[i];
+        });
+        deferred.resolve(instanceList);
+      })
+      .catch(deferred.reject);
+
+      return deferred.promise;
+    };
+
+    this.getContainerStats = (containerName) => {
+      const deferred = $q.defer();
+
+      let res = {};
+
+      $http.get('/xoslib/meterstatistics', {params: {'resource': containerName}})
+      .then((containerStats) => {
+        res.stats = containerStats.data;
+        return $http.get('/xoslib/meterstatistics', {params: {'resource': `${containerName}-eth0`}})
+      })
+      .then((portStats) => {
+        res.port = {
+          eth0: portStats.data
+        };
+        return $http.get('/xoslib/meterstatistics', {params: {'resource': `${containerName}-eth1`}})
+      })
+      .then((portStats) => {
+        res.port.eth1 = portStats.data;
+        deferred.resolve(res);
+      })
+      .catch((e) => {
+        deferred.reject(e);
+      })
+
+      return deferred.promise;
+    }
+  })
+  .service('Slice', function($resource){
+    return $resource('/api/core/slices', {id: '@id'});
+  })
+  .service('Instances', function($resource){
+    return $resource('/api/core/instances/:id', {id: '@id'});
+  })
+  .service('Node', function($resource, $q, Instances){
+    return $resource('/api/core/nodes', {id: '@id'}, {
+      queryWithInstances: {
+        method: 'GET',
+        isArray: true,
+        interceptor: {
+          response: function(res){
+
+            // TODO update the API to include instances in nodes
+            // http://stackoverflow.com/questions/14573102/how-do-i-include-related-model-fields-using-django-rest-framework
+
+            const deferred = $q.defer();
+
+            let requests = [];
+
+            angular.forEach(res.data, (node) => {
+              requests.push(Instances.query({node: node.id}).$promise);
+            })
+
+            $q.all(requests)
+            .then((list) => {
+              res.data.map((node, i) => {
+                node.instances = list[i];
+                return node;
+              });
+              deferred.resolve(res.data);
+            })
+
+            return deferred.promise;
+          }
+        }
+      }
+    });
+  })
+  .service('Subscribers', function($resource, $q, SubscriberDevice){
+    return $resource('/xoslib/cordsubscriber/:id', {id: '@id'}, {
+      update: {
+        method: 'PUT',
+        isArray: false
+      },
+      queryWithDevices: {
+        method: 'GET',
+        isArray: true,
+        interceptor: {
+          response: function(res){
+
+            /**
+            * For each subscriber retrieve devices and append them
+            */
+
+            let deferred = $q.defer();
+
+            let requests = [];
+
+            angular.forEach(res.data, (subscriber) => {
+              requests.push(SubscriberDevice.query({id: subscriber.id}).$promise);
+            })
+
+            $q.all(requests)
+            .then((list) => {
+
+              // adding devices
+
+              res.data.map((subscriber, i) => {
+                subscriber.devices = list[i];
+                subscriber.type = 'subscriber';
+
+                subscriber.devices.map(d => d.type = 'device')
+
+                return subscriber;
+              });
+
+              // faking to have 2 subscriber
+              // res.data.push(angular.copy(res.data[0]));
+
+              deferred.resolve(res.data);
+            })
+
+            return deferred.promise;
+          }
+        }
+      },
+      getWithDevices: {
+        method: 'GET',
+        isArray: false,
+        interceptor: {
+          response: (res) => {
+            let d = $q.defer();
+
+            SubscriberDevice.query({id: res.data.id}).$promise
+            .then(devices => {
+              devices.map(d => d.type = 'device');
+              res.data.devices = devices;
+              res.data.type = 'subscriber';
+              d.resolve(res.data);
+            })
+            .catch(err => {
+              d.reject(err);
+            });
+
+            return d.promise;
+          }
+        }
+      }
+    });
+  })
+  .service('SubscriberDevice', function($resource){
+    return $resource('/xoslib/rs/subscriber/:id/users/', {id: '@id'});
+  })
+  .service('ServiceRelation', function($q, _, Services, Tenant, Slice, Instances){
+
+    // count the mas depth of an object
+    const depthOf = (obj) => {
+      var depth = 0;
+      if (obj.children) {
+        obj.children.forEach(function (d) {
+          var tmpDepth = depthOf(d);
+          if (tmpDepth > depth) {
+            depth = tmpDepth
+          }
+        })
+      }
+      return 1 + depth
+    };
+
+    // find all the relation defined for a given root
+    const findLevelRelation = (tenants, rootId) => {
+      return _.filter(tenants, service => {
+        return service.subscriber_service === rootId;
+      });
+    };
+
+    const findSpecificInformation = (tenants, rootId) => {
+      var tenants = _.filter(tenants, service => {
+        return service.provider_service === rootId && service.subscriber_tenant;
+      });
+
+      var info;
+
+      tenants.forEach((tenant) => {
+        if(tenant.service_specific_attribute){
+          info = JSON.parse(tenant.service_specific_attribute);
+        }
+      });
+
+      return info;
+    };
+
+    // find all the service defined by a given array of relations
+    const findLevelServices = (relations, services) => {
+      const levelServices = [];
+      _.forEach(relations, (tenant) => {
+        var service = _.find(services, {id: tenant.provider_service});
+        levelServices.push(service);
+      });
+      return levelServices;
+    };
+
+    const buildLevel = (tenants, services, rootService, rootTenant, parentName = null) => {
+
+      // build an array of unlinked services
+      // these are the services that should still placed in the tree
+      var unlinkedServices = _.difference(services, [rootService]);
+
+      // find all relations relative to this rootElement
+      const levelRelation = findLevelRelation(tenants, rootService.id);
+      // find all items related to rootElement
+      const levelServices = findLevelServices(levelRelation, services);
+
+      // remove this item from the list (performance
+      unlinkedServices = _.difference(unlinkedServices, levelServices);
+
+      rootService.service_specific_attribute = findSpecificInformation(tenants, rootService.id);
+
+      if(rootService.humanReadableName === 'service_vbng'){
+        rootService.humanReadableName = 'service_vrouter'
+      }
+
+      const tree = {
+        name: rootService.humanReadableName,
+        parent: parentName,
+        type: 'service',
+        service: rootService,
+        tenant: rootTenant,
+        children: []
+      };
+
+      _.forEach(levelServices, (service) => {
+        if(service.humanReadableName === 'service_ONOS_vBNG' || service.humanReadableName === 'service_ONOS_vOLT'){
+          // remove ONOSes from service chart
+          return;
+        }
+        let tenant = _.find(tenants, {subscriber_tenant: rootTenant.id, provider_service: service.id});
+        tree.children.push(buildLevel(tenants, unlinkedServices, service, tenant, rootService.humanReadableName));
+      });
+
+      // if it is the last element append internet
+      if(tree.children.length === 0){
+        tree.children.push({
+          name: 'Router',
+          type: 'router',
+          children: []
+        });
+      }
+
+      return tree;
+    };
+
+    const buildSubscriberServiceTree = (services, tenants, subscriber = {id: 1, name: 'fakeSubs'}) => {
+
+      // find the root service
+      // it is the one attached to subsriber_root
+      // as now we have only one root so this can work
+      const rootTenant = _.find(tenants, {subscriber_root: subscriber.id});
+      const rootService = _.find(services, {id: rootTenant.provider_service});
+
+      const serviceTree = buildLevel(tenants, services, rootService, rootTenant);
+
+      return {
+        name: subscriber.name || subscriber.humanReadableName,
+        parent: null,
+        type: 'subscriber',
+        children: [serviceTree]
+      };
+
+    };
+
+    // applying domain knowledge to build the global service tree
+    const buildServiceTree = (services, tenants) => {
+
+      // TODO refactor
+      const buildChild = (services, tenants, currentService) => {
+
+        if(currentService.humanReadableName === 'service_vbng'){
+          currentService.humanReadableName = 'service_vrouter'
+        }
+
+        const response = {
+          type: 'service',
+          name: currentService.humanReadableName,
+          service: currentService
+        };
+
+        let tenant = _.find(tenants, {subscriber_service: currentService.id});
+        if(tenant){
+          let next = _.find(services, {id: tenant.provider_service});
+          response.children = [buildChild(services, tenants, next)];
+        }
+        else {
+          response.children = [
+            {
+              name: 'Router',
+              type: 'router',
+              children: []
+            }
+          ]
+        }
+        delete currentService.id; // conflict with d3
+        return response;
+      }
+
+      let baseService = _.find(services, {id: 3});
+      
+      if(!angular.isDefined(baseService)){
+        console.error('Missing Base service!');
+        return;
+      }
+
+      const baseData = {
+        name: 'Subscriber',
+        type: 'subscriber',
+        parent: null,
+        children: [buildChild(services, tenants, baseService)]
+      };
+      return baseData;
+    };
+
+    const getBySubscriber = (subscriber) => {
+      var deferred = $q.defer();
+      var services, tenants;
+      Services.query().$promise
+      .then((res) => {
+        services = res;
+        return Tenant.query().$promise;
+      })
+      .then((res) => {
+        tenants = res;
+        deferred.resolve(buildSubscriberServiceTree(services, tenants, subscriber));
+      })
+      .catch((e) => {
+        throw new Error(e);
+      });
+
+      return deferred.promise;
+    };
+
+    const get = () => {
+      var deferred = $q.defer();
+      var services, tenants;
+      Services.query().$promise
+      .then((res) => {
+        services = res;
+        return Tenant.query({kind: 'coarse'}).$promise;
+      })
+      .then((res) => {
+        tenants = res;
+        deferred.resolve(buildServiceTree(services, tenants));
+      })
+      .catch((e) => {
+        throw new Error(e);
+      });
+
+      return deferred.promise;
+    }
+
+    // export APIs
+    return {
+      get: get,
+      buildServiceTree: buildServiceTree,
+      getBySubscriber: getBySubscriber,
+      buildLevel: buildLevel,
+      buildSubscriberServiceTree: buildSubscriberServiceTree,
+      findLevelRelation: findLevelRelation,
+      findLevelServices: findLevelServices,
+      depthOf: depthOf,
+      findSpecificInformation: findSpecificInformation
+    }
+  });
+
+}());
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/src/js/serviceTopology.js b/views/ngXosViews/diagnostic/src/js/serviceTopology.js
new file mode 100644
index 0000000..832e6fa
--- /dev/null
+++ b/views/ngXosViews/diagnostic/src/js/serviceTopology.js
@@ -0,0 +1,69 @@
+(function () {
+  'use strict';
+
+  angular.module('xos.diagnostic')
+  .directive('serviceTopology', function(){
+    return {
+      restrict: 'E',
+      scope: {
+        serviceChain: '='
+      },
+      bindToController: true,
+      controllerAs: 'vm',
+      template: '',
+      controller: function($element, $window, $scope, d3, serviceTopologyConfig, ServiceRelation, Slice, Instances, Subscribers, ServiceTopologyHelper){
+
+        const el = $element[0];
+
+        d3.select(window)
+        .on('resize.service', () => {
+          draw(this.serviceChain);
+        });
+
+        var root, svg;
+
+        const draw = (tree) => {
+
+          if(!tree){
+            console.error('Tree is missing');
+            return;
+          }
+
+          // TODO update instead clear and redraw
+
+          // clean
+          d3.select($element[0]).select('svg').remove();
+
+
+          const width = el.clientWidth - (serviceTopologyConfig.widthMargin * 2);
+          const height = el.clientHeight - (serviceTopologyConfig.heightMargin * 2);
+
+          const treeLayout = d3.layout.tree()
+            .size([height, width]);
+
+          svg = d3.select($element[0])
+            .append('svg')
+            .style('width', `${el.clientWidth}px`)
+            .style('height', `${el.clientHeight}px`)
+
+          const treeContainer = svg.append('g')
+            .attr('transform', `translate(${serviceTopologyConfig.widthMargin * 2},${serviceTopologyConfig.heightMargin})`);
+
+          root = tree;
+          root.x0 = height / 2;
+          root.y0 = width / 2;
+
+          // ServiceTopologyHelper.drawLegend(svg);
+          ServiceTopologyHelper.updateTree(treeContainer, treeLayout, root, el);
+        };
+        
+        $scope.$watch(() => this.serviceChain, (chain) => {
+          if(angular.isDefined(chain)){
+            draw(chain);
+          }
+        });
+      }
+    }
+  });
+
+}());
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/src/js/serviceTopologyHelper.js b/views/ngXosViews/diagnostic/src/js/serviceTopologyHelper.js
new file mode 100644
index 0000000..c903b3b
--- /dev/null
+++ b/views/ngXosViews/diagnostic/src/js/serviceTopologyHelper.js
@@ -0,0 +1,178 @@
+(function () {
+  'use strict';
+
+  angular.module('xos.diagnostic')
+  .service('ServiceTopologyHelper', function($rootScope, $window, $log, _, ServiceRelation, serviceTopologyConfig, d3){
+
+    var _svg, _layout, _source, _el;
+
+    var i = 0;
+
+    // given a canvas, a layout and a data source, draw a tree layout
+    const updateTree = (svg, layout, source, el = _el) => {
+      if(el){
+        _el = el;
+      }
+      
+      let targetWidth = _el.clientWidth - serviceTopologyConfig.widthMargin * 2;
+
+      //cache data
+      _svg = svg;
+      _layout = layout;
+      _source = source;
+
+      const maxDepth = ServiceRelation.depthOf(source);
+
+      const diagonal = d3.svg.diagonal()
+        .projection(d => [d.y, d.x]);
+
+      // Compute the new tree layout.
+      var nodes = layout.nodes(source).reverse(),
+        links = layout.links(nodes);
+
+      // Normalize for fixed-depth.
+      nodes.forEach(function(d) {
+        // position the child node horizontally
+        const step = ((targetWidth - (serviceTopologyConfig.widthMargin * 2)) / (maxDepth - 1));
+        d.y = d.depth * step;
+      });
+
+      // Update the nodes…
+      var node = svg.selectAll('g.node')
+        .data(nodes, function(d) { return d.id || (d.id = ++i); });
+
+      // Enter any new nodes at the parent's previous position.
+      var nodeEnter = node.enter().append('g')
+        .attr({
+          class: d => {
+            return `node ${d.type}`
+          },
+          transform: d => (d.x && d.y) ? `translate(${d.y}, ${d.x})` : `translate(${source.y0}, ${source.x0})`
+        });
+
+      const subscriberNodes = nodeEnter.filter('.subscriber');
+      const internetNodes = nodeEnter.filter('.router');
+      const serviceNodes = nodeEnter.filter('.service');
+
+      subscriberNodes.append('rect')
+        .attr(serviceTopologyConfig.square)
+        // add event listener to subscriber
+        .on('click', () => {
+          $rootScope.$emit('subscriber.modal.open');
+        });
+
+      internetNodes.append('rect')
+        .attr(serviceTopologyConfig.square);
+
+      serviceNodes.append('circle')
+        .attr('r', 1e-6)
+        .style('fill', d => d._children ? 'lightsteelblue' : '#fff')
+        .on('click', serviceClick);
+
+      nodeEnter.append('text')
+        .attr({
+          x: d => d.children ? -serviceTopologyConfig.circle.selectedRadius -5 : serviceTopologyConfig.circle.selectedRadius + 5,
+          dy: '.35em',
+          y: d => {
+            if (d.children && d.parent){
+              return '-5';
+            }
+          },
+          transform: d => {
+            if (d.children && d.parent){
+              if(d.parent.x < d.x){
+                return 'rotate(-30)';
+              }
+              return 'rotate(30)';
+            }
+          },
+          'text-anchor': d => d.children ? 'end' : 'start'
+        })
+        .text(d => d.name)
+        .style('fill-opacity', 1e-6);
+
+      // Transition nodes to their new position.
+      var nodeUpdate = node.transition()
+        .duration(serviceTopologyConfig.duration)
+        .attr({
+          'transform': d => `translate(${d.y},${d.x})`
+        });
+
+      nodeUpdate.select('circle')
+        .attr('r', d => {
+          return d.selected ? serviceTopologyConfig.circle.selectedRadius : serviceTopologyConfig.circle.radius
+        })
+        .style('fill', d => d.selected ? 'lightsteelblue' : '#fff');
+
+      nodeUpdate.select('text')
+        .style('fill-opacity', 1);
+
+      // Transition exiting nodes to the parent's new position.
+      var nodeExit = node.exit().transition()
+        .duration(serviceTopologyConfig.duration)
+        .remove();
+
+      nodeExit.select('circle')
+        .attr('r', 1e-6);
+
+      nodeExit.select('text')
+        .style('fill-opacity', 1e-6);
+
+      // Update the links…
+      var link = svg.selectAll('path.link')
+        .data(links, function(d) { return d.target.id; });
+
+      // Enter any new links at the parent's previous position.
+      link.enter().insert('path', 'g')
+        .attr('class', d => `link ${d.target.type} ${d.target.active ? '' : 'active'}`)
+        .attr('d', function(d) {
+          var o = {x: source.x0, y: source.y0};
+          return diagonal({source: o, target: o});
+        });
+
+      // Transition links to their new position.
+      link.transition()
+        .duration(serviceTopologyConfig.duration)
+        .attr('d', diagonal);
+
+      // Transition exiting nodes to the parent's new position.
+      link.exit().transition()
+        .duration(serviceTopologyConfig.duration)
+        .attr('d', function(d) {
+          var o = {x: source.x, y: source.y};
+          return diagonal({source: o, target: o});
+        })
+        .remove();
+
+      // Stash the old positions for transition.
+      nodes.forEach(function(d) {
+        d.x0 = d.x;
+        d.y0 = d.y;
+      });
+    };
+
+    const serviceClick = function(d) {
+
+      // if was selected
+      if(d.selected){
+        d.selected = !d.selected;
+        $rootScope.$emit('instance.detail.hide', {});
+        return updateTree(_svg, _layout, _source);
+      }
+      
+      $rootScope.$emit('instance.detail', {name: d.name, service: d.service, tenant: d.tenant});
+
+      // unselect all
+      _svg.selectAll('circle')
+      .each(d => d.selected = false);
+
+      // toggling selected status
+      d.selected = !d.selected;
+
+      updateTree(_svg, _layout, _source);
+    };
+
+    this.updateTree = updateTree;
+  });
+
+}());
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/src/js/subscriber-modal.js b/views/ngXosViews/diagnostic/src/js/subscriber-modal.js
new file mode 100644
index 0000000..773be70
--- /dev/null
+++ b/views/ngXosViews/diagnostic/src/js/subscriber-modal.js
@@ -0,0 +1,86 @@
+(function () {
+  'use strict';
+  angular.module('xos.diagnostic')
+  .directive('selectSubscriberModal', function(){
+    return {
+      scope: {
+        subscribers: '=',
+        open: '='
+      },
+      bindToController: true,
+      restrict: 'E',
+      templateUrl: 'templates/select-subscriber-modal.tpl.html',
+      controllerAs: 'vm',
+      controller: function($rootScope){
+
+        this.close = () => {
+          this.open = false;
+        };
+
+        this.select = (subscriber) => {
+          $rootScope.$emit('subscriber.selected', subscriber);
+          this.close();
+        };
+      }
+    };
+  })
+  .directive('subscriberStatusModal', function(){
+    return {
+      scope: {
+        open: '=',
+        subscriber: '='
+      },
+      bindToController: true,
+      restrict: 'E',
+      templateUrl: 'templates/subscriber-status-modal.tpl.html',
+      controllerAs: 'vm',
+      controller: function($log, $timeout, $scope, Subscribers){
+
+        const mb = 1000000;
+
+        $scope.$watch(() => this.open, () => {
+          this.success = null;
+          this.formError = null;
+        });
+
+        $scope.$watch(() => this.subscriber, (newVal, oldVal) => {
+          if(!this.subscriber){
+            return;
+          }
+          console.log(newVal, oldVal);
+          console.log('subscriber change', newVal === oldVal);
+          this.subscriber.uplink_speed = parseInt(this.subscriber.uplink_speed, 10) / mb;
+          this.subscriber.downlink_speed = parseInt(this.subscriber.downlink_speed, 10) / mb;
+        });
+
+        this.close = () => {
+          this.open = false;
+        };
+
+        this.updateSubscriber = (subscriber) => {
+
+          // TODO Copy the subscriber, this will update the GUI also and we don't want
+          // TODO Change GBps to MBps
+
+          let body = angular.copy(subscriber, body);
+
+          body.uplink_speed = body.uplink_speed * mb;
+          body.downlink_speed = body.downlink_speed * mb;
+
+          Subscribers.update(body).$promise
+          .then((res) => {
+            this.success = 'Subscriber successfully updated!';
+          })
+          .catch((e) => {
+            this.formError = e;
+          })
+          .finally(() => {
+            $timeout(() => {
+              this.close();
+            }, 1500);
+          });
+        };
+      }
+    };
+  });
+})();
diff --git a/views/ngXosViews/diagnostic/src/sass/main.scss b/views/ngXosViews/diagnostic/src/sass/main.scss
new file mode 100644
index 0000000..90f1c50
--- /dev/null
+++ b/views/ngXosViews/diagnostic/src/sass/main.scss
@@ -0,0 +1,356 @@
+/* CONTAINER */
+#xosDiagnostic, [ui-view] {
+    height: 100%;
+    min-height: 700px;
+    position: relative;
+}
+
+diagnostic-container .form-control.small-padding{
+  padding: 6px;
+}
+
+diagnostic-container .half-height {
+    position: relative;
+    height: 50%;
+}
+
+diagnostic-container .onethird-height {
+    position: relative;
+    height: 33%;
+    border-bottom: 1px solid #999;
+}
+
+diagnostic-container .twothird-height {
+    position: relative;
+    height: 67%;
+}
+
+diagnostic-container .subscriber-select{
+    max-width: 200px;
+    position: absolute;
+    top: 20px;
+    right: 20px;
+    z-index: 1;
+}
+
+diagnostic-container .onethird-height .well,
+diagnostic-container .twothird-height .well {
+  font-weight: bold;
+  max-width: 165px;
+  text-align: center;
+  margin-top: 15px;
+  background: #eee;
+  border-color: steelblue;
+  padding: 10px;
+}
+
+diagnostic-container .onethird-height .well.pull-right{
+  position: absolute;
+  right: 0px;
+  top: -15px;
+  cursor: pointer;
+  z-index: 200;
+}
+
+
+/* subscriber-status-modal */
+subscriber-status-modal .row + .row {
+  margin-top: 20px;
+}
+
+.half-height + .half-height {
+    border-top: 1px solid black;
+}
+
+service-topology,
+logic-topology {
+    height: 100%;
+    width: 100%;
+    display: block;
+    position: absolute;
+    top: 0;
+}
+
+logic-topology .subscriber circle,
+logic-topology .device circle{
+    fill: #fff;
+    stroke: green;
+    stroke-width: 1px;
+}
+
+logic-topology > svg {
+    position: absolute;
+    top: 0;
+}
+
+/* CLOUDS */
+
+logic-topology .network .cloud {
+    fill: #fff;
+    stroke: green;
+    stroke-width: 1px;   
+}
+
+/* RACK */
+logic-topology .node.rack > g > rect{
+    fill: #ccc;
+    stroke: steelblue;
+    stroke-width: 1px;
+}
+
+/* CP NODE */
+
+logic-topology .compute-node > rect{
+    fill: #fff;
+    stroke: steelblue;
+    stroke-width: 1px;
+}
+
+logic-topology .compute-node > text{
+    font-size: 16px;
+}
+
+/* INSTANCE */
+
+logic-topology .instance > rect{
+    fill: #eee;
+    stroke: steelblue;
+    stroke-width: 1px;
+}
+
+logic-topology .node .instance.active rect{
+    fill: lightsteelblue;
+    stroke: steelblue;
+    stroke-width: 1px;   
+}
+
+logic-topology .node .instance.active.good > rect{
+    fill: green;
+}
+
+logic-topology .node .instance.active.provisioning > rect{
+    fill: yellow;
+}
+
+logic-topology .node .instance.active.bad > rect{
+    fill: red;
+}
+
+/* INSTANCE STATS */
+
+logic-topology .node .instance .stats-container rect {
+  fill: white;
+}
+
+logic-topology .node .instance .stats-container text.name{
+  font-weight: bold;
+}
+
+logic-topology .node .instance .stats-container text.ip{
+  font-style: italic;
+  font-size: 10px;
+}
+
+/* CONTAINERS */
+logic-topology .node .instance .stats-container .container rect {
+  fill: #eee;
+  stroke: steelblue;
+  stroke-width: 1px;
+}
+
+/* LEGEND */
+
+.legend {
+    fill: #fff;
+    stroke: #ccc;
+    stroke-width: 1px;
+    position: relative;
+}
+
+.legend text {
+    stroke: #000;
+}
+
+.node {
+    cursor: pointer;
+}
+
+.node circle,
+.node rect{
+    fill: #fff;
+    stroke: steelblue;
+    stroke-width: 1px;
+}
+
+.node.subscriber circle,
+.node.subscriber rect,
+.node.router circle,
+.node.router rect {
+    stroke: #05ffcb;
+}
+
+.node.slice rect {
+    stroke: #b01dff;
+}
+
+.node.instance rect {
+    stroke: #ccc;
+}
+
+.node.instance rect.active {
+    stroke: #ff8b00;
+}
+
+.node rect.slice-detail{
+    fill: #fff;
+    stroke: steelblue;
+    stroke-width: 3px;
+}
+
+.node text {
+    font: 18px sans-serif;
+}
+
+.node .instance text {
+    font: 12px sans-serif;
+}
+
+.node text.small {
+    font-size: 10px;
+}
+
+.link, .device-link {
+    fill: none;
+    stroke: #ccc;
+    stroke-width: 2px;
+}
+
+.link.slice {
+    stroke: rgba(157, 4, 183, 0.29);
+}
+.link.instance{
+    stroke: #ccc;
+}
+
+.link.instance.active{
+    stroke: rgba(255, 138, 0, 0.65);
+}
+
+.service-details{
+    width: 200px;
+    position: absolute;
+    top: 20px;
+    right: 20px;
+}
+
+/* when showing the thing */
+
+.animate.ng-hide-remove {
+    animation:0.5s bounceInRight ease;
+}
+
+/* when hiding the picture */
+.animate.ng-hide-add {
+    animation:0.5s bounceOutRight ease;
+}
+
+/* LOADER */
+.loader {
+  font-size: 10px;
+  margin: 150px auto;
+  text-indent: -9999em;
+  width: 11em;
+  height: 11em;
+  border-radius: 50%;
+  background: #ffffff;
+  background: -moz-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
+  background: -webkit-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
+  background: -o-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
+  background: -ms-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
+  background: linear-gradient(to right, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
+  position: relative;
+  animation: load3 1.4s infinite linear;
+  transform: translateZ(0);
+}
+.loader:before {
+  width: 50%;
+  height: 50%;
+  background: #105E9E;
+  border-radius: 100% 0 0 0;
+  position: absolute;
+  top: 0;
+  left: 0;
+  content: '';
+}
+.loader:after {
+  background: #fff;
+  width: 75%;
+  height: 75%;
+  border-radius: 50%;
+  content: '';
+  margin: auto;
+  position: absolute;
+  top: 0;
+  left: 0;
+  bottom: 0;
+  right: 0;
+}
+
+@keyframes load3 {
+  0% {
+    -webkit-transform: rotate(0deg);
+    transform: rotate(0deg);
+  }
+  100% {
+    -webkit-transform: rotate(360deg);
+    transform: rotate(360deg);
+  }
+}
+
+/* MODALS */
+
+.modal.fade.in {
+  display: block;
+}
+
+/* ANIMATIONS */
+
+@keyframes bounceInRight {
+    from, 60%, 75%, 90%, to {
+        animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+    }
+
+    from {
+        opacity: 0;
+        transform: translate3d(3000px, 0, 0);
+    }
+
+    60% {
+        opacity: 1;
+        transform: translate3d(-25px, 0, 0);
+    }
+
+    75% {
+        transform: translate3d(10px, 0, 0);
+    }
+
+    90% {
+        transform: translate3d(-5px, 0, 0);
+    }
+
+    to {
+        transform: none;
+    }
+}
+
+@keyframes bounceOutRight {
+  20% {
+    opacity: 1;
+    transform: translate3d(-20px, 0, 0);
+  }
+
+  to {
+    opacity: 0;
+    transform: translate3d(2000px, 0, 0);
+  }
+}
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/src/templates/diagnostic.tpl.html b/views/ngXosViews/diagnostic/src/templates/diagnostic.tpl.html
new file mode 100644
index 0000000..bab176d
--- /dev/null
+++ b/views/ngXosViews/diagnostic/src/templates/diagnostic.tpl.html
@@ -0,0 +1,31 @@
+<div class="container-fluid">
+  <div ng-hide="vm.error && vm.loader" style="height: 900px">
+    <div class="onethird-height">
+      <div class="well">
+        Services Graph
+      </div>
+      <div class="well pull-right" ng-click="vm.reloadGlobalScope()" ng-show="vm.selectedSubscriber">
+        Reset subscriber
+      </div>
+      <service-topology service-chain="vm.serviceChain"></service-topology>
+    </div>
+    <div class="twothird-height">
+      <div class="well">
+        Logical Resources
+      </div>
+      <logic-topology ng-if="vm.subscribers" subscribers="vm.subscribers" selected="vm.selectedSubscriber"></logic-topology>
+    </div>
+  </div>
+  <div class="row" ng-if="vm.error">
+    <div class="col-xs-12">
+      <div class="alert alert-danger">
+        {{vm.error}}
+      </div>
+    </div>
+  </div>
+  <div class="row" ng-if="vm.loader">
+    <div class="col-xs-12">
+      <div class="loader">Loading</div>
+    </div>
+  </div>
+</div>
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/src/templates/logicTopology.tpl.html b/views/ngXosViews/diagnostic/src/templates/logicTopology.tpl.html
new file mode 100644
index 0000000..e942fca
--- /dev/null
+++ b/views/ngXosViews/diagnostic/src/templates/logicTopology.tpl.html
@@ -0,0 +1,27 @@
+<select-subscriber-modal open="vm.openSelectSubscriberModal" subscribers="vm.subscribers"></select-subscriber-modal>
+<subscriber-status-modal open="vm.openSubscriberStatusModal" subscriber="vm.currentSubscriber"></subscriber-status-modal>
+<div class="alert alert-danger animate" ng-hide="!vm.error">
+  {{vm.error}}
+</div>
+<!-- <div class="instances-stats animate" ng-hide="vm.hideInstanceStats">
+  <div class="row">
+    <div class="col-sm-3 col-sm-offset-8">
+      <div class="panel panel-primary" ng-repeat="instance in vm.selectedInstances">
+        <div class="panel-heading">
+          {{instance.humanReadableName}}
+        </div>
+          <ul class="list-group">
+            <li class="list-group-item">Backend Status: {{instance.backend_status}}</li>
+            <li class="list-group-item">IP Address: {{instance.ip}}</li>
+          </ul>
+          <ul class="list-group">
+            <li class="list-group-item" ng-repeat="stat in instance.stats">
+              <span class="badge">{{stat.value}}</span>
+              {{stat.meter}}
+            </li>
+          </ul>
+        </div>
+      </div>  
+    </div>
+  </div>
+</div> -->
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/src/templates/select-subscriber-modal.tpl.html b/views/ngXosViews/diagnostic/src/templates/select-subscriber-modal.tpl.html
new file mode 100644
index 0000000..7672a29
--- /dev/null
+++ b/views/ngXosViews/diagnostic/src/templates/select-subscriber-modal.tpl.html
@@ -0,0 +1,17 @@
+<div class="modal fade" ng-class="{in: vm.open}" tabindex="-1" role="dialog">
+  <div class="modal-dialog modal-sm">
+    <div class="modal-content">
+      <div class="modal-header">
+        <button ng-click="vm.close()"  type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+        <h4 class="modal-title">Select a subscriber:</h4>
+      </div>
+      <div class="modal-body">
+        <select class="form-control" ng-options="s as s.humanReadableName for s in vm.subscribers" ng-model="vm.selected"></select>
+      </div>
+      <div class="modal-footer">
+        <button ng-click="vm.close()" type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+        <button ng-click="vm.select(vm.selected)" type="button" class="btn btn-primary">Select</button>
+      </div>
+    </div><!-- /.modal-content -->
+  </div><!-- /.modal-dialog -->
+</div><!-- /.modal -->
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/src/templates/subscriber-status-modal.tpl.html b/views/ngXosViews/diagnostic/src/templates/subscriber-status-modal.tpl.html
new file mode 100644
index 0000000..1288ec8
--- /dev/null
+++ b/views/ngXosViews/diagnostic/src/templates/subscriber-status-modal.tpl.html
@@ -0,0 +1,87 @@
+<div class="modal fade" ng-class="{in: vm.open}" tabindex="-1" role="dialog">
+  <div class="modal-dialog modal-sm">
+    <div class="modal-content">
+      <div class="modal-header">
+        <button ng-click="vm.close()"  type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+        <h4 class="modal-title">Manage subscriber:</h4>
+      </div>
+      <form name="vm.subscriber-detail">
+        <div class="modal-body">
+          <div class="row">
+            <div class="col-xs-12">
+              <label>Status</label>
+            </div>
+            <div class="col-xs-6">
+              <a ng-click="vm.subscriber.status = 'enabled'"
+                class="btn btn-block"
+                ng-class="{'btn-primary': vm.subscriber.status === 'enabled' ,'btn-default': vm.subscriber.status !== 'enabled'}"
+                >Enabled</a>
+            </div>
+            <div class="col-xs-6">
+              <a ng-click="vm.subscriber.status = 'suspended'"
+                class="btn btn-block"
+                ng-class="{'btn-primary': vm.subscriber.status === 'suspended' ,'btn-default': vm.subscriber.status !== 'suspended'}"
+                >Suspended</a>
+            </div>
+          </div>
+          <div class="row">
+            <div class="col-xs-6">
+              <a ng-click="vm.subscriber.status = 'delinquent'"
+                class="btn btn-block"
+                ng-class="{'btn-primary': vm.subscriber.status === 'delinquent' ,'btn-default': vm.subscriber.status !== 'delinquent'}"
+                >Delinquent <br> payment</a>
+            </div>
+            <div class="col-xs-6">
+              <a ng-click="vm.subscriber.status = 'copyrightviolation'"
+                class="btn btn-block"
+                ng-class="{'btn-primary': vm.subscriber.status === 'copyrightviolation' ,'btn-default': vm.subscriber.status !== 'copyrightviolation'}"
+                >Copyright <br> violation</a>
+            </div>
+          </div>
+          <div class="row">
+            <div class="col-xs-6">
+              <label>Uplink Speed</label>
+              <div class="input-group">
+                <input type="number" class="form-control small-padding" ng-model="vm.subscriber.uplink_speed"/>
+                <span class="input-group-addon">Mbps</span>
+              </div>
+            </div>
+            <div class="col-xs-6">
+              <label>Downlink Speed</label>
+              <div class="input-group">
+                <input type="number" class="form-control small-padding" ng-model="vm.subscriber.downlink_speed"/>
+                <span class="input-group-addon">Mbps</span>
+              </div>
+            </div>
+          </div>
+          <div class="row">
+            <div class="col-xs-6">
+              <label>Enable Internet</label>
+            </div>
+            <div class="col-xs-6">
+              <a 
+                ng-click="vm.subscriber.enable_uverse = !vm.subscriber.enable_uverse" 
+                ng-class="{'btn-success': vm.subscriber.enable_uverse, 'btn-danger': !vm.subscriber.enable_uverse}"
+                class="btn btn-block">
+                <span ng-show="vm.subscriber.enable_uverse === true">Enabled</span>
+                <span ng-show="vm.subscriber.enable_uverse !== true">Disabled</span>
+              </a>
+            </div>
+          </div>
+        </div>
+        <div class="modal-footer" ng-show="vm.success || vm.formError">
+          <div class="alert alert-success" ng-show="vm.success">
+            {{vm.success}}
+          </div>
+          <div class="alert alert-danger" ng-show="vm.formError">
+            {{vm.formError}}
+          </div>
+        </div>
+        <div class="modal-footer">
+          <button ng-click="vm.close()" type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+          <button ng-click="vm.updateSubscriber(vm.subscriber)" type="button" class="btn btn-primary">Save</button>
+        </div>
+      </form>
+    </div><!-- /.modal-content -->
+  </div><!-- /.modal-dialog -->
+</div><!-- /.modal -->
\ No newline at end of file
diff --git a/views/ngXosViews/diagnostic/src/templates/users-list.tpl.html b/views/ngXosViews/diagnostic/src/templates/users-list.tpl.html
new file mode 100644
index 0000000..1fee0e2
--- /dev/null
+++ b/views/ngXosViews/diagnostic/src/templates/users-list.tpl.html
@@ -0,0 +1 @@
+<xos-table config="vm.tableConfig" data="vm.users"></xos-table>
\ No newline at end of file
diff --git a/views/ngXosViews/hpc/.bowerrc b/views/ngXosViews/hpc/.bowerrc
new file mode 100644
index 0000000..e491038
--- /dev/null
+++ b/views/ngXosViews/hpc/.bowerrc
@@ -0,0 +1,3 @@
+{
+  "directory": "src/vendor/"
+}
\ No newline at end of file
diff --git a/views/ngXosViews/hpc/.eslintrc b/views/ngXosViews/hpc/.eslintrc
new file mode 100644
index 0000000..c852748
--- /dev/null
+++ b/views/ngXosViews/hpc/.eslintrc
@@ -0,0 +1,42 @@
+{
+    "ecmaFeatures": {
+        "blockBindings": true,
+        "forOf": true,
+        "destructuring": true,
+        "arrowFunctions": true,
+        "templateStrings": true
+    },
+    "env": { 
+        "browser": true,
+        "node": true,
+        "es6": true
+    },
+    "plugins": [
+        //"angular"
+    ],
+    "rules": {
+        "quotes": [2, "single"],
+        "camelcase": [1, {"properties": "always"}],
+        "no-underscore-dangle": 1,
+        "eqeqeq": [2, "smart"],
+        "no-alert": 1,
+        "key-spacing": [1, { "beforeColon": false, "afterColon": true }],
+        "indent": [2, 2],
+        "no-irregular-whitespace": 1,
+        "eol-last": 0,
+        "max-nested-callbacks": [2, 4],
+        "comma-spacing": [1, {"before": false, "after": true}],
+        "no-trailing-spaces": [1, { skipBlankLines: true }],
+        "no-unused-vars": [1, {"vars": "all", "args": "after-used"}],
+        "new-cap": 0,
+
+        //"angular/ng_module_name": [2, '/^xos\.*[a-z]*$/'],
+        //"angular/ng_controller_name": [2, '/^[a-z].*Ctrl$/'],
+        //"angular/ng_service_name": [2, '/^[A-Z].*Service$/'],
+        //"angular/ng_directive_name": [2, '/^[a-z]+[[A-Z].*]*$/'],
+        //"angular/ng_di": [0, "function or array"]
+    },
+    "globals" :{
+        "angular": true
+    } 
+}
\ No newline at end of file
diff --git a/views/ngXosViews/hpc/.gitignore b/views/ngXosViews/hpc/.gitignore
new file mode 100644
index 0000000..567aee4
--- /dev/null
+++ b/views/ngXosViews/hpc/.gitignore
@@ -0,0 +1,6 @@
+dist/
+src/vendor
+.tmp
+node_modules
+npm-debug.log
+dist/
\ No newline at end of file
diff --git a/views/ngXosViews/hpc/bower.json b/views/ngXosViews/hpc/bower.json
new file mode 100644
index 0000000..085650b
--- /dev/null
+++ b/views/ngXosViews/hpc/bower.json
@@ -0,0 +1,33 @@
+{
+  "name": "xos-hpc",
+  "version": "0.0.0",
+  "authors": [
+    "Matteo Scandolo <matteo.scandolo@gmail.com>"
+  ],
+  "description": "The hpc view",
+  "license": "MIT",
+  "ignore": [
+    "**/.*",
+    "node_modules",
+    "bower_components",
+    "static/js/vendor/",
+    "test",
+    "tests"
+  ],
+  "dependencies": {
+  },
+  "devDependencies": {
+    "jquery": "2.1.4",
+    "angular-mocks": "1.4.7",
+    "angular": "1.4.7",
+    "angular-ui-router": "0.2.15",
+    "angular-cookies": "1.4.7",
+    "angular-animate": "1.4.7",
+    "angular-resource": "1.4.7",
+    "lodash": "~4.11.1",
+    "bootstrap-css": "3.3.6",
+    "angular-chart.js": "~0.10.2",
+    "d3": "~3.5.17",
+    "angular-recursion": "~1.0.5"
+  }
+}
diff --git a/views/ngXosViews/hpc/gulp/build.js b/views/ngXosViews/hpc/gulp/build.js
new file mode 100644
index 0000000..3cefc6b
--- /dev/null
+++ b/views/ngXosViews/hpc/gulp/build.js
@@ -0,0 +1,164 @@
+'use strict';
+
+// BUILD
+//
+// The only purpose of this gulpfile is to build a XOS view and copy the correct files into
+// .html => dashboards
+// .js (minified and concat) => static/js
+//
+// The template are parsed and added to js with angular $templateCache
+
+var gulp = require('gulp');
+var ngAnnotate = require('gulp-ng-annotate');
+var uglify = require('gulp-uglify');
+var templateCache = require('gulp-angular-templatecache');
+var runSequence = require('run-sequence');
+var concat = require('gulp-concat-util');
+var del = require('del');
+var wiredep = require('wiredep');
+var angularFilesort = require('gulp-angular-filesort');
+var _ = require('lodash');
+var eslint = require('gulp-eslint');
+var inject = require('gulp-inject');
+var rename = require('gulp-rename');
+var replace = require('gulp-replace');
+var postcss = require('gulp-postcss');
+var autoprefixer = require('autoprefixer');
+var mqpacker = require('css-mqpacker');
+var csswring = require('csswring');
+
+const TEMPLATE_FOOTER = `
+angular.module('xos.hpc')
+.run(['$location', function(a){
+  a.path('/');
+}])
+`
+
+module.exports = function(options){
+  
+  // delete previous builded file
+  gulp.task('clean', function(){
+    return del(
+      [
+        options.dashboards + 'xosHpc.html',
+        options.static + 'css/xosHpc.css'
+      ],
+      {force: true}
+    );
+  });
+
+  // minify css
+  gulp.task('css', function () {
+    var processors = [
+      autoprefixer({browsers: ['last 1 version']}),
+      mqpacker,
+      csswring
+    ];
+
+    gulp.src([
+      `${options.css}**/*.css`,
+      `!${options.css}dev.css`
+    ])
+    .pipe(postcss(processors))
+    .pipe(gulp.dest(options.tmp + '/css/'));
+  });
+
+  // copy css in correct folder
+  gulp.task('copyCss', ['wait'], function(){
+    return gulp.src([`${options.tmp}/css/*.css`])
+    .pipe(concat('xosHpc.css'))
+    .pipe(gulp.dest(options.static + 'css/'))
+  });
+
+  // compile and minify scripts
+  gulp.task('scripts', function() {
+    return gulp.src([
+      options.tmp + '**/*.js'
+    ])
+    .pipe(ngAnnotate())
+    .pipe(angularFilesort())
+    .pipe(concat('xosHpc.js'))
+    .pipe(concat.header('//Autogenerated, do not edit!!!\n'))
+    .pipe(concat.footer(TEMPLATE_FOOTER))
+    .pipe(uglify())
+    .pipe(gulp.dest(options.static + 'js/'));
+  });
+
+  // set templates in cache
+  gulp.task('templates', function(){
+    return gulp.src('./src/templates/*.html')
+      .pipe(templateCache({
+        module: 'xos.hpc',
+        root: 'templates/'
+      }))
+      .pipe(gulp.dest(options.tmp));
+  });
+
+  // copy html index to Django Folder
+  gulp.task('copyHtml', function(){
+    return gulp.src(options.src + 'index.html')
+      // remove dev dependencies from html
+      .pipe(replace(/<!-- bower:css -->(\n^<link.*)*\n<!-- endbower -->/gmi, ''))
+      .pipe(replace(/<!-- bower:js -->(\n^<script.*)*\n<!-- endbower -->/gmi, ''))
+      // injecting minified files
+      .pipe(
+        inject(
+          gulp.src([
+            options.static + 'js/vendor/xosHpcVendor.js',
+            options.static + 'js/xosHpc.js',
+            options.static + 'css/xosHpc.css'
+          ]),
+          {ignorePath: '/../../../xos/core/xoslib'}
+        )
+      )
+      .pipe(rename('xosHpc.html'))
+      .pipe(gulp.dest(options.dashboards));
+  });
+
+  // minify vendor js files
+  gulp.task('wiredep', function(){
+    var bowerDeps = wiredep().js;
+    if(!bowerDeps){
+      return;
+    }
+
+    // remove angular (it's already loaded)
+    _.remove(bowerDeps, function(dep){
+      return dep.indexOf('angular/angular.js') !== -1;
+    });
+
+    return gulp.src(bowerDeps)
+      .pipe(concat('xosHpcVendor.js'))
+      .pipe(uglify())
+      .pipe(gulp.dest(options.static + 'js/vendor/'));
+  });
+
+  gulp.task('lint', function () {
+    return gulp.src(['src/js/**/*.js'])
+      .pipe(eslint())
+      .pipe(eslint.format())
+      .pipe(eslint.failAfterError());
+  });
+
+  gulp.task('wait', function (cb) {
+    // setTimeout could be any async task
+    setTimeout(function () {
+      cb();
+    }, 1000);
+  });
+
+  gulp.task('build', function() {
+    runSequence(
+      'clean',
+      'sass',
+      'templates',
+      'babel',
+      'scripts',
+      'wiredep',
+      'css',
+      'copyCss',
+      'copyHtml',
+      'cleanTmp'
+    );
+  });
+};
\ No newline at end of file
diff --git a/views/ngXosViews/hpc/gulp/server.js b/views/ngXosViews/hpc/gulp/server.js
new file mode 100644
index 0000000..c748eb6
--- /dev/null
+++ b/views/ngXosViews/hpc/gulp/server.js
@@ -0,0 +1,171 @@
+'use strict';
+
+var gulp = require('gulp');
+var browserSync = require('browser-sync').create();
+var inject = require('gulp-inject');
+var runSequence = require('run-sequence');
+var angularFilesort = require('gulp-angular-filesort');
+var babel = require('gulp-babel');
+var wiredep = require('wiredep').stream;
+var httpProxy = require('http-proxy');
+var del = require('del');
+var sass = require('gulp-sass');
+var fs = require('fs');
+var path = require('path');
+
+const environment = process.env.NODE_ENV;
+
+if(!fs.existsSync(path.join(__dirname, `../../../env/${environment || 'default'}.js`))){
+  if(!environment){
+    throw new Error('You should define a default.js config in /views/env folder.');
+  }
+  else{
+    throw new Error(`Since you are loading a custom environment, you should define a ${environment}.js config in /views/env folder.`);
+  }
+}
+
+var conf = require(path.join(__dirname, `../../../env/${environment || 'default'}.js`));
+
+var proxy = httpProxy.createProxyServer({
+  target: conf.host
+});
+
+
+proxy.on('error', function(error, req, res) {
+  res.writeHead(500, {
+    'Content-Type': 'text/plain'
+  });
+
+  console.error('[Proxy]', error);
+});
+
+module.exports = function(options){
+
+  gulp.task('browser', function() {
+    browserSync.init({
+      startPath: '#/',
+      snippetOptions: {
+        rule: {
+          match: /<!-- browserSync -->/i
+        }
+      },
+      server: {
+        baseDir: options.src,
+        routes: {
+          '/xos/core/xoslib/static/js/vendor': options.helpers,
+          '/xos/core/static': options.static + '../../static/'
+        },
+        middleware: function(req, res, next){
+          if(
+            req.url.indexOf('/api/') !== -1,
+            req.url.indexOf('/xoslib/hpcview') !== -1
+          ){
+            if(conf.xoscsrftoken && conf.xossessionid){
+              req.headers.cookie = `xoscsrftoken=${conf.xoscsrftoken}; xossessionid=${conf.xossessionid}`;
+              req.headers['x-csrftoken'] = conf.xoscsrftoken;
+            }
+            proxy.web(req, res);
+          }
+          else{
+            next();
+          }
+        }
+      }
+    });
+
+    gulp.watch(options.src + 'js/**/*.js', ['js-watch']);
+    gulp.watch(options.src + 'vendor/**/*.js', ['bower'], function(){
+      browserSync.reload();
+    });
+    gulp.watch(options.src + '**/*.html', function(){
+      browserSync.reload();
+    });
+    gulp.watch(options.css + '**/*.css', function(){
+      browserSync.reload();
+    });
+    gulp.watch(`${options.sass}/**/*.scss`, ['sass'], function(){
+      browserSync.reload();
+    });
+
+    gulp.watch([
+      options.helpers + 'ngXosHelpers.js',
+      options.static + '../../static/xosNgLib.css'
+    ], function(){
+      browserSync.reload();
+    });
+  });
+
+  // compile sass
+  gulp.task('sass', function () {
+    return gulp.src(`${options.sass}/**/*.scss`)
+      .pipe(sass().on('error', sass.logError))
+      .pipe(gulp.dest(options.css));
+  });
+
+  // transpile js with sourceMaps
+  gulp.task('babel', function(){
+    return gulp.src(options.scripts + '**/*.js')
+      .pipe(babel({sourceMaps: true}))
+      .pipe(gulp.dest(options.tmp));
+  });
+
+  // inject scripts
+  gulp.task('injectScript', ['cleanTmp', 'babel'], function(){
+    return gulp.src(options.src + 'index.html')
+      .pipe(
+        inject(
+          gulp.src([
+            options.tmp + '**/*.js',
+            options.helpers + 'ngXosHelpers.js'
+          ])
+          .pipe(angularFilesort()),
+          {
+            ignorePath: [options.src, '/../../ngXosLib']
+          }
+        )
+      )
+      .pipe(gulp.dest(options.src));
+  });
+
+  // inject CSS
+  gulp.task('injectCss', function(){
+    return gulp.src(options.src + 'index.html')
+      .pipe(
+        inject(
+          gulp.src([
+            options.src + 'css/*.css',
+            options.static + '../../static/xosNgLib.css'
+          ]),
+          {
+            ignorePath: [options.src]
+          }
+          )
+        )
+      .pipe(gulp.dest(options.src));
+  });
+
+  // inject bower dependencies with wiredep
+  gulp.task('bower', function () {
+    return gulp.src(options.src + 'index.html')
+    .pipe(wiredep({devDependencies: true}))
+    .pipe(gulp.dest(options.src));
+  });
+
+  gulp.task('js-watch', ['injectScript'], function(){
+    browserSync.reload();
+  });
+
+  gulp.task('cleanTmp', function(){
+    return del([options.tmp + '**/*']);
+  });
+
+  gulp.task('serve', function() {
+    runSequence(
+      'sass',
+      'bower',
+      'injectScript',
+      'injectCss',
+      ['browser']
+    );
+  });
+};
diff --git a/views/ngXosViews/hpc/gulpfile.js b/views/ngXosViews/hpc/gulpfile.js
new file mode 100644
index 0000000..08df554
--- /dev/null
+++ b/views/ngXosViews/hpc/gulpfile.js
@@ -0,0 +1,26 @@
+'use strict';
+
+var gulp = require('gulp');
+var wrench = require('wrench');
+
+var options = {
+  src: 'src/',
+  css: 'src/css/',
+  sass: 'src/sass/',
+  scripts: 'src/js/',
+  tmp: 'src/.tmp',
+  dist: 'dist/',
+  api: '../../ngXosLib/api/',
+  helpers: '../../../xos/core/xoslib/static/js/vendor/',
+  static: '../../../xos/core/xoslib/static/', // this is the django static folder
+  dashboards: '../../../xos/core/xoslib/dashboards/' // this is the django html folder
+};
+
+wrench.readdirSyncRecursive('./gulp')
+.map(function(file) {
+  require('./gulp/' + file)(options);
+});
+
+gulp.task('default', function () {
+  gulp.start('build');
+});
diff --git a/views/ngXosViews/hpc/karma.conf.js b/views/ngXosViews/hpc/karma.conf.js
new file mode 100644
index 0000000..4123be9
--- /dev/null
+++ b/views/ngXosViews/hpc/karma.conf.js
@@ -0,0 +1,88 @@
+// Karma configuration
+// Generated on Tue Oct 06 2015 09:27:10 GMT+0000 (UTC)
+
+/* eslint indent: [2,2], quotes: [2, "single"]*/
+
+/*eslint-disable*/
+var wiredep = require('wiredep');
+var path = require('path');
+
+var bowerComponents = wiredep( {devDependencies: true} )[ 'js' ].map(function( file ){
+  return path.relative(process.cwd(), file);
+});
+
+module.exports = function(config) {
+/*eslint-enable*/
+  config.set({
+
+    // base path that will be used to resolve all patterns (eg. files, exclude)
+    basePath: '',
+
+
+    // frameworks to use
+    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
+    frameworks: ['jasmine'],
+
+
+    // list of files / patterns to load in the browser
+    files: bowerComponents.concat([
+      '../../../xos/core/xoslib/static/js/vendor/ngXosVendor.js',
+      '../../../xos/core/xoslib/static/js/vendor/ngXosHelpers.js',
+      'src/js/**/*.js',
+      'spec/**/*.mock.js',
+      'spec/**/*.test.js',
+      'src/**/*.html'
+    ]),
+
+
+    // list of files to exclude
+    exclude: [
+    ],
+
+
+    // preprocess matching files before serving them to the browser
+    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
+    preprocessors: {
+      'src/js/**/*.js': ['babel'],
+      'spec/**/*.test.js': ['babel'],
+      'src/**/*.html': ['ng-html2js']
+    },
+
+    ngHtml2JsPreprocessor: {
+      stripPrefix: 'src/', //strip the src path from template url (http://stackoverflow.com/questions/22869668/karma-unexpected-request-when-testing-angular-directive-even-with-ng-html2js)
+      moduleName: 'templates' // define the template module name
+    },
+
+    // test results reporter to use
+    // possible values: 'dots', 'progress'
+    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
+    reporters: ['mocha'],
+
+
+    // web server port
+    port: 9876,
+
+
+    // enable / disable colors in the output (reporters and logs)
+    colors: true,
+
+
+    // level of logging
+    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+    logLevel: config.LOG_INFO,
+
+
+    // enable / disable watching file and executing tests whenever any file changes
+    autoWatch: true,
+
+
+    // start these browsers
+    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
+    browsers: ['PhantomJS'],
+
+
+    // Continuous Integration mode
+    // if true, Karma captures browsers, runs the tests and exits
+    singleRun: false
+  });
+};
diff --git a/views/ngXosViews/hpc/package.json b/views/ngXosViews/hpc/package.json
new file mode 100644
index 0000000..ab43380
--- /dev/null
+++ b/views/ngXosViews/hpc/package.json
@@ -0,0 +1,63 @@
+{
+  "name": "xos-hpc",
+  "version": "1.0.0",
+  "description": "Angular Application for XOS, created with generator-xos",
+  "scripts": {
+    "prestart": "npm install && bower install",
+    "start": "gulp serve",
+    "prebuild": "npm install && bower install",
+    "build": "gulp",
+    "test": "karma start",
+    "test:ci": "karma start --single-run",
+    "lint": "eslint src/js/"
+  },
+  "keywords": [
+    "XOS",
+    "Angular",
+    "XOSlib"
+  ],
+  "author": "Matteo Scandolo",
+  "license": "MIT",
+  "dependencies": {},
+  "devDependencies": {
+    "autoprefixer": "^6.3.3",
+    "browser-sync": "^2.9.11",
+    "css-mqpacker": "^4.0.0",
+    "csswring": "^4.2.1",
+    "del": "^2.0.2",
+    "easy-mocker": "^1.2.0",
+    "eslint": "^1.8.0",
+    "eslint-plugin-angular": "linkmesrl/eslint-plugin-angular",
+    "gulp": "^3.9.0",
+    "gulp-angular-filesort": "^1.1.1",
+    "gulp-angular-templatecache": "^1.8.0",
+    "gulp-babel": "^5.3.0",
+    "gulp-concat": "^2.6.0",
+    "gulp-concat-util": "^0.5.5",
+    "gulp-eslint": "^1.0.0",
+    "gulp-inject": "^3.0.0",
+    "gulp-minify-html": "^1.0.4",
+    "gulp-ng-annotate": "^1.1.0",
+    "gulp-postcss": "^6.0.1",
+    "gulp-rename": "^1.2.2",
+    "gulp-replace": "^0.5.4",
+    "gulp-sass": "^2.2.0",
+    "gulp-uglify": "^1.4.2",
+    "http-proxy": "^1.12.0",
+    "ink-docstrap": "^0.5.2",
+    "jasmine-core": "~2.3.4",
+    "karma": "^0.13.14",
+    "karma-babel-preprocessor": "~5.2.2",
+    "karma-coverage": "^0.5.3",
+    "karma-jasmine": "~0.3.6",
+    "karma-mocha-reporter": "~1.1.1",
+    "karma-ng-html2js-preprocessor": "^0.2.0",
+    "karma-phantomjs-launcher": "~0.2.1",
+    "lodash": "^3.10.1",
+    "phantomjs": "^1.9.19",
+    "proxy-middleware": "^0.15.0",
+    "run-sequence": "^1.1.4",
+    "wiredep": "^3.0.0-beta",
+    "wrench": "^1.5.8"
+  }
+}
diff --git a/views/ngXosViews/hpc/spec/sample.test.js b/views/ngXosViews/hpc/spec/sample.test.js
new file mode 100644
index 0000000..9949b08
--- /dev/null
+++ b/views/ngXosViews/hpc/spec/sample.test.js
@@ -0,0 +1,24 @@
+'use strict';
+
+describe('The Hpc View', () => {
+  
+  var scope, element, isolatedScope, httpBackend;
+
+  beforeEach(module('xos.hpc'));
+  beforeEach(module('templates'));
+
+  beforeEach(inject(function($httpBackend, $compile, $rootScope){
+
+    scope = $rootScope.$new();
+    element = angular.element('<hpcs-list></hpcs-list>');
+    $compile(element)(scope);
+    scope.$digest();
+    isolatedScope = element.isolateScope().vm;
+  }));
+
+  it('should define 2 tables', () => {
+    expect(isolatedScope.routerConfig).toBeDefined();
+    expect(isolatedScope.cacheConfig).toBeDefined();
+  });
+
+});
\ No newline at end of file
diff --git a/views/ngXosViews/hpc/src/css/main.css b/views/ngXosViews/hpc/src/css/main.css
new file mode 100644
index 0000000..24f5982
--- /dev/null
+++ b/views/ngXosViews/hpc/src/css/main.css
@@ -0,0 +1,2 @@
+#xosHpc .btn.btn-reload {
+  margin-top: 20px; }
diff --git a/views/ngXosViews/hpc/src/index.html b/views/ngXosViews/hpc/src/index.html
new file mode 100644
index 0000000..c945c27
--- /dev/null
+++ b/views/ngXosViews/hpc/src/index.html
@@ -0,0 +1,35 @@
+<!-- browserSync -->
+<!-- bower:css -->
+<link rel="stylesheet" href="vendor/bootstrap-css/css/bootstrap.min.css" />
+<link rel="stylesheet" href="vendor/angular-chart.js/dist/angular-chart.css" />
+<!-- endbower -->
+<!-- endcss -->
+<!-- inject:css -->
+<link rel="stylesheet" href="/css/main.css">
+<link rel="stylesheet" href="/../../../xos/core/static/xosNgLib.css">
+<!-- endinject -->
+
+<div ng-app="xos.hpc" id="xosHpc" class="container-fluid">
+  <div ui-view></div>
+</div>
+
+<!-- bower:js -->
+<script src="vendor/jquery/dist/jquery.js"></script>
+<script src="vendor/angular/angular.js"></script>
+<script src="vendor/angular-mocks/angular-mocks.js"></script>
+<script src="vendor/angular-ui-router/release/angular-ui-router.js"></script>
+<script src="vendor/angular-cookies/angular-cookies.js"></script>
+<script src="vendor/angular-animate/angular-animate.js"></script>
+<script src="vendor/angular-resource/angular-resource.js"></script>
+<script src="vendor/lodash/lodash.js"></script>
+<script src="vendor/bootstrap-css/js/bootstrap.min.js"></script>
+<script src="vendor/Chart.js/Chart.js"></script>
+<script src="vendor/angular-chart.js/dist/angular-chart.js"></script>
+<script src="vendor/d3/d3.js"></script>
+<script src="vendor/angular-recursion/angular-recursion.js"></script>
+<!-- endbower -->
+<!-- endjs -->
+<!-- inject:js -->
+<script src="/../../../xos/core/xoslib/static/js/vendor/ngXosHelpers.js"></script>
+<script src="/.tmp/main.js"></script>
+<!-- endinject -->
\ No newline at end of file
diff --git a/views/ngXosViews/hpc/src/js/main.js b/views/ngXosViews/hpc/src/js/main.js
new file mode 100644
index 0000000..ca6a5a0
--- /dev/null
+++ b/views/ngXosViews/hpc/src/js/main.js
@@ -0,0 +1,134 @@
+'use strict';
+
+angular.module('xos.hpc', [
+  'ngResource',
+  'ngCookies',
+  'ui.router',
+  'xos.helpers'
+])
+.config(($stateProvider) => {
+  $stateProvider
+  .state('hpc-list', {
+    url: '/',
+    template: '<hpcs-list></hpcs-list>'
+  });
+})
+.config(function($httpProvider){
+  $httpProvider.interceptors.push('NoHyperlinks');
+})
+.service('Hpc', function($q, $http){
+  this.query = (params) => {
+    const d = $q.defer();
+
+    $http.get('/xoslib/hpcview', {params: params})
+      .then((res) => {
+        d.resolve(res.data);
+      })
+      .catch(d.reject);
+
+    return {$promise: d.promise};
+  };
+})
+.directive('hpcsList', function(){
+  return {
+    restrict: 'E',
+    scope: {},
+    bindToController: true,
+    controllerAs: 'vm',
+    templateUrl: 'templates/hpc-list.tpl.html',
+    controller: function(Hpc){
+
+      const secondsToHms = d => {
+        d = Number(d);
+        var h = Math.floor(d / 3600);
+        var m = Math.floor(d % 3600 / 60);
+        var s = Math.floor(d % 3600 % 60);
+        return ((h > 0 ? h + 'h ' + (m < 10 ? '0' :'') :'') + m + 'm ' + (s < 10 ? '0' :'') + s + 's');
+      };
+
+      const toDuration = (property) => {
+        return (item) => {
+          if(!angular.isNumber(item[property])){
+            return item[property]
+          }
+          return secondsToHms(item[property]);
+        }
+      };
+
+      this.routerConfig = {
+        filter: 'field',
+        order: true,
+        columns: [
+          {
+            label: 'Name',
+            prop: 'name'
+          },
+          {
+            label: 'Ip Address',
+            prop: 'ip'
+          },
+          {
+            label: 'Record Checker',
+            prop: 'watcher.DNS.msg'
+          },
+          {
+            label: 'Name Servers',
+            prop: 'nameservers',
+            type: 'array'
+          },
+          {
+            label: 'Dns Demux Config Age',
+            prop: 'dnsdemux_config_age',
+            type: 'custom',
+            formatter: toDuration('dnsdemux_config_age')
+          },
+          {
+            label: 'Dns Redir Config Age',
+            prop: 'dnsredir_config_age',
+            type: 'custom',
+            formatter: toDuration('dnsredir_config_age')
+          }
+        ]
+      };
+
+      this.cacheConfig = {
+        filter: 'field',
+        order: true,
+        columns: [
+          {
+            label: 'Name',
+            prop: 'name'
+          },
+          {
+            label: 'Prober',
+            prop: 'watcher.HPC-hb.msg'
+          },
+          {
+            label: 'Fetcher',
+            prop: 'watcher.HPC-fetch.msg'
+          },
+          {
+            label: 'Config Age',
+            prop: 'config_age',
+            type: 'custom',
+            formatter: toDuration('config_age')
+          }
+        ]
+      };
+
+
+      this.fetch = () => {
+        Hpc.query().$promise
+        .then((hpcs) => {
+          this.routers = hpcs[0].dnsdemux;
+          this.caches = hpcs[0].hpc;
+        })
+        .catch((e) => {
+          throw new Error(e);
+        });
+      };
+
+      this.fetch();
+    }
+  };
+});
\ No newline at end of file
diff --git a/views/ngXosViews/hpc/src/sass/main.scss b/views/ngXosViews/hpc/src/sass/main.scss
new file mode 100644
index 0000000..c646843
--- /dev/null
+++ b/views/ngXosViews/hpc/src/sass/main.scss
@@ -0,0 +1,7 @@
+@import '../../../../style/sass/lib/_variables.scss';
+
+#xosHpc {
+  .btn.btn-reload {
+    margin-top: $line-height-computed;
+  }
+}
\ No newline at end of file
diff --git a/views/ngXosViews/hpc/src/templates/hpc-list.tpl.html b/views/ngXosViews/hpc/src/templates/hpc-list.tpl.html
new file mode 100644
index 0000000..138323f
--- /dev/null
+++ b/views/ngXosViews/hpc/src/templates/hpc-list.tpl.html
@@ -0,0 +1,28 @@
+<div class="container-fluid">
+    <div class="row">
+        <div class="col-xs-10">
+            <h1>Request Routers</h1>
+        </div>
+        <div class="col-xs-2 text-right">
+            <a href="" ng-click="vm.fetch()" class="btn btn-primary btn-reload">
+                <i class="glyphicon glyphicon-refresh"></i>
+                Refresh
+            </a>
+        </div>
+    </div>
+    <div class="row">
+        <div class="col-xs-12">
+            <xos-table config="vm.routerConfig" data="vm.routers"></xos-table>
+        </div>
+    </div>
+    <div class="row">
+        <div class="col-xs-12">
+            <h1>HyperCache</h1>
+        </div>
+    </div>
+    <div class="row">
+        <div class="col-xs-12">
+            <xos-table config="vm.cacheConfig" data="vm.caches"></xos-table>
+        </div>
+    </div>
+</div>
\ No newline at end of file
diff --git a/views/ngXosViews/mcordTopology/.bowerrc b/views/ngXosViews/mcordTopology/.bowerrc
new file mode 100644
index 0000000..e491038
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/.bowerrc
@@ -0,0 +1,3 @@
+{
+  "directory": "src/vendor/"
+}
\ No newline at end of file
diff --git a/views/ngXosViews/mcordTopology/.eslintrc b/views/ngXosViews/mcordTopology/.eslintrc
new file mode 100644
index 0000000..c852748
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/.eslintrc
@@ -0,0 +1,42 @@
+{
+    "ecmaFeatures": {
+        "blockBindings": true,
+        "forOf": true,
+        "destructuring": true,
+        "arrowFunctions": true,
+        "templateStrings": true
+    },
+    "env": { 
+        "browser": true,
+        "node": true,
+        "es6": true
+    },
+    "plugins": [
+        //"angular"
+    ],
+    "rules": {
+        "quotes": [2, "single"],
+        "camelcase": [1, {"properties": "always"}],
+        "no-underscore-dangle": 1,
+        "eqeqeq": [2, "smart"],
+        "no-alert": 1,
+        "key-spacing": [1, { "beforeColon": false, "afterColon": true }],
+        "indent": [2, 2],
+        "no-irregular-whitespace": 1,
+        "eol-last": 0,
+        "max-nested-callbacks": [2, 4],
+        "comma-spacing": [1, {"before": false, "after": true}],
+        "no-trailing-spaces": [1, { skipBlankLines: true }],
+        "no-unused-vars": [1, {"vars": "all", "args": "after-used"}],
+        "new-cap": 0,
+
+        //"angular/ng_module_name": [2, '/^xos\.*[a-z]*$/'],
+        //"angular/ng_controller_name": [2, '/^[a-z].*Ctrl$/'],
+        //"angular/ng_service_name": [2, '/^[A-Z].*Service$/'],
+        //"angular/ng_directive_name": [2, '/^[a-z]+[[A-Z].*]*$/'],
+        //"angular/ng_di": [0, "function or array"]
+    },
+    "globals" :{
+        "angular": true
+    } 
+}
\ No newline at end of file
diff --git a/views/ngXosViews/mcordTopology/.gitignore b/views/ngXosViews/mcordTopology/.gitignore
new file mode 100644
index 0000000..567aee4
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/.gitignore
@@ -0,0 +1,6 @@
+dist/
+src/vendor
+.tmp
+node_modules
+npm-debug.log
+dist/
\ No newline at end of file
diff --git a/views/ngXosViews/mcordTopology/bower.json b/views/ngXosViews/mcordTopology/bower.json
new file mode 100644
index 0000000..ed83aa4
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/bower.json
@@ -0,0 +1,30 @@
+{
+  "name": "xos-mcordTopology",
+  "version": "0.0.0",
+  "authors": [
+    "Matteo Scandolo <teo@onlab.us>"
+  ],
+  "description": "The mcordTopology view",
+  "license": "MIT",
+  "ignore": [
+    "**/.*",
+    "node_modules",
+    "bower_components",
+    "static/js/vendor/",
+    "test",
+    "tests"
+  ],
+  "dependencies": {
+    "d3": "~3.5.16"
+  },
+  "devDependencies": {
+    "jquery": "2.1.4",
+    "angular-mocks": "1.4.7",
+    "angular": "1.4.7",
+    "angular-ui-router": "0.2.15",
+    "angular-cookies": "1.4.7",
+    "angular-resource": "1.4.7",
+    "lodash": "^3.10.1",
+    "bootstrap-css": "2.3.2"
+  }
+}
diff --git a/views/ngXosViews/mcordTopology/env/default.js b/views/ngXosViews/mcordTopology/env/default.js
new file mode 100644
index 0000000..acc8b5a
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/env/default.js
@@ -0,0 +1,13 @@
+// This is a default configuration for your development environment.
+// You can duplicate this configuration for any of your Backend Environments.
+// Different configurations are loaded setting a NODE_ENV variable that contain the config file name.
+// `NODE_ENV=local npm start`
+//
+// If xoscsrftoken or xossessionid are not specified the browser value are used
+// (works only for local environment as both application are served on the same domain)
+
+module.exports = {
+  host: 'http://xos.dev:9999/',
+  xoscsrftoken: 's1hmvk8d66UwxnRlDze64FrswXBeHjRD',
+  xossessionid: '4qgqwp46w5ln4q24vitc8f5gx6i66wyk'
+};
diff --git a/views/ngXosViews/mcordTopology/env/mock.js b/views/ngXosViews/mcordTopology/env/mock.js
new file mode 100644
index 0000000..610ad78
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/env/mock.js
@@ -0,0 +1,5 @@
+module.exports = {
+  host: 'http://localhost:4000',
+  xoscsrftoken: 'Pkq9PqoAsaMvrEiFAgxfw47IxTOtd0Y5',
+  xossessionid: 'qa1t49qeecdehofjkndqvxik71iwzfvf'
+};
\ No newline at end of file
diff --git a/views/ngXosViews/mcordTopology/gulp/build.js b/views/ngXosViews/mcordTopology/gulp/build.js
new file mode 100644
index 0000000..afc12dd
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/gulp/build.js
@@ -0,0 +1,163 @@
+'use strict';
+
+// BUILD
+//
+// The only purpose of this gulpfile is to build a XOS view and copy the correct files into
+// .html => dashboards
+// .js (minified and concat) => static/js
+//
+// The template are parsed and added to js with angular $templateCache
+
+var gulp = require('gulp');
+var ngAnnotate = require('gulp-ng-annotate');
+var uglify = require('gulp-uglify');
+var templateCache = require('gulp-angular-templatecache');
+var runSequence = require('run-sequence');
+var concat = require('gulp-concat-util');
+var del = require('del');
+var wiredep = require('wiredep');
+var angularFilesort = require('gulp-angular-filesort');
+var _ = require('lodash');
+var eslint = require('gulp-eslint');
+var inject = require('gulp-inject');
+var rename = require('gulp-rename');
+var replace = require('gulp-replace');
+var postcss = require('gulp-postcss');
+var autoprefixer = require('autoprefixer');
+var mqpacker = require('css-mqpacker');
+var csswring = require('csswring');
+
+const TEMPLATE_FOOTER = `
+angular.module('xos.mcordTopology')
+.run(['$location', function(a){
+  a.path('/');
+}])
+`
+
+module.exports = function(options){
+  
+  // delete previous builded file
+  gulp.task('clean', function(){
+    return del(
+      [
+        options.dashboards + 'xosMcordTopology.html',
+        options.static + 'css/xosMcordTopology.css'
+      ],
+      {force: true}
+    );
+  });
+
+  // minify css
+  gulp.task('css', function () {
+    var processors = [
+      autoprefixer({browsers: ['last 1 version']}),
+      mqpacker,
+      csswring
+    ];
+
+    gulp.src([
+      `${options.css}**/*.css`,
+      `!${options.css}dev.css`
+    ])
+    .pipe(postcss(processors))
+    .pipe(gulp.dest(options.tmp + '/css/'));
+  });
+
+  // copy css in correct folder
+  gulp.task('copyCss', ['wait'], function(){
+    return gulp.src([`${options.tmp}/css/*.css`])
+    .pipe(concat('xosMcordTopology.css'))
+    .pipe(gulp.dest(options.static + 'css/'))
+  });
+
+  // compile and minify scripts
+  gulp.task('scripts', function() {
+    return gulp.src([
+      options.tmp + '**/*.js'
+    ])
+    .pipe(ngAnnotate())
+    .pipe(angularFilesort())
+    .pipe(concat('xosMcordTopology.js'))
+    .pipe(concat.header('//Autogenerated, do not edit!!!\n'))
+    .pipe(concat.footer(TEMPLATE_FOOTER))
+    .pipe(uglify())
+    .pipe(gulp.dest(options.static + 'js/'));
+  });
+
+  // set templates in cache
+  gulp.task('templates', function(){
+    return gulp.src('./src/templates/*.html')
+      .pipe(templateCache({
+        module: 'xos.mcordTopology',
+        root: 'templates/'
+      }))
+      .pipe(gulp.dest(options.tmp));
+  });
+
+  // copy html index to Django Folder
+  gulp.task('copyHtml', function(){
+    return gulp.src(options.src + 'index.html')
+      // remove dev dependencies from html
+      .pipe(replace(/<!-- bower:css -->(\n.*)*\n<!-- endbower --><!-- endcss -->/, ''))
+      .pipe(replace(/<!-- bower:js -->(\n.*)*\n<!-- endbower --><!-- endjs -->/, ''))
+      // injecting minified files
+      .pipe(
+        inject(
+          gulp.src([
+            options.static + 'js/vendor/xosMcordTopologyVendor.js',
+            options.static + 'js/xosMcordTopology.js',
+            options.static + 'css/xosMcordTopology.css'
+          ]),
+          {ignorePath: '/../../../xos/core/xoslib'}
+        )
+      )
+      .pipe(rename('xosMcordTopology.html'))
+      .pipe(gulp.dest(options.dashboards));
+  });
+
+  // minify vendor js files
+  gulp.task('wiredep', function(){
+    var bowerDeps = wiredep().js;
+    if(!bowerDeps){
+      return;
+    }
+
+    // remove angular (it's already loaded)
+    _.remove(bowerDeps, function(dep){
+      return dep.indexOf('angular/angular.js') !== -1;
+    });
+
+    return gulp.src(bowerDeps)
+      .pipe(concat('xosMcordTopologyVendor.js'))
+      .pipe(uglify())
+      .pipe(gulp.dest(options.static + 'js/vendor/'));
+  });
+
+  gulp.task('lint', function () {
+    return gulp.src(['src/js/**/*.js'])
+      .pipe(eslint())
+      .pipe(eslint.format())
+      .pipe(eslint.failAfterError());
+  });
+
+  gulp.task('wait', function (cb) {
+    // setTimeout could be any async task
+    setTimeout(function () {
+      cb();
+    }, 1000);
+  });
+
+  gulp.task('build', function() {
+    runSequence(
+      'clean',
+      'templates',
+      'babel',
+      'scripts',
+      'wiredep',
+      'css',
+      'copyCss',
+      'copyHtml',
+      'cleanTmp'
+    );
+  });
+};
\ No newline at end of file
diff --git a/views/ngXosViews/mcordTopology/gulp/server.js b/views/ngXosViews/mcordTopology/gulp/server.js
new file mode 100644
index 0000000..167a5a9
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/gulp/server.js
@@ -0,0 +1,161 @@
+'use strict';
+
+var gulp = require('gulp');
+var browserSync = require('browser-sync').create();
+var inject = require('gulp-inject');
+var runSequence = require('run-sequence');
+var angularFilesort = require('gulp-angular-filesort');
+var babel = require('gulp-babel');
+var wiredep = require('wiredep').stream;
+var httpProxy = require('http-proxy');
+var del = require('del');
+var sass = require('gulp-sass');
+
+const environment = process.env.NODE_ENV;
+
+if (environment){
+  var conf = require(`../env/${environment}.js`);
+}
+else{
+  var conf = require('../env/default.js')
+}
+
+var proxy = httpProxy.createProxyServer({
+  target: conf.host || 'http://0.0.0.0:9999'
+});
+
+
+proxy.on('error', function(error, req, res) {
+  res.writeHead(500, {
+    'Content-Type': 'text/plain'
+  });
+
+  console.error('[Proxy]', error);
+});
+
+module.exports = function(options){
+
+  // open in browser with sync and proxy to 0.0.0.0
+  gulp.task('browser', function() {
+    browserSync.init({
+      // reloadDelay: 500,
+      // logLevel: 'debug',
+      // logConnections: true,
+      startPath: '#/',
+      snippetOptions: {
+        rule: {
+          match: /<!-- browserSync -->/i
+        }
+      },
+      server: {
+        baseDir: options.src,
+        routes: {
+          '/xos/core/xoslib/static/js/vendor': options.helpers
+        },
+        middleware: function(req, res, next){
+          if(
+            req.url.indexOf('/api/') !== -1
+          ){
+            if(conf.xoscsrftoken && conf.xossessionid){
+              req.headers.cookie = `xoscsrftoken=${conf.xoscsrftoken}; xossessionid=${conf.xossessionid}`;
+              req.headers['x-csrftoken'] = conf.xoscsrftoken;
+            }
+            proxy.web(req, res);
+          }
+          else if(req.url.indexOf('/videoLocal.txt') !== -1){
+            let a = (Math.random() * 10).toString();
+            res.end(a)
+          }
+          else{
+            next();
+          }
+        }
+      }
+    });
+
+    gulp.watch(options.src + 'js/**/*.js', ['js-watch']);
+    gulp.watch(options.src + 'vendor/**/*.js', ['bower'], function(){
+      browserSync.reload();
+    });
+    gulp.watch(options.src + '**/*.html', function(){
+      browserSync.reload();
+    });
+    gulp.watch(options.css + '**/*.css', function(){
+      browserSync.reload();
+    });
+    gulp.watch(`${options.sass}/**/*.scss`, ['sass'], function(){
+      browserSync.reload();
+    });
+  });
+
+  // compile sass
+  gulp.task('sass', function () {
+    return gulp.src(`${options.sass}/**/*.scss`)
+      .pipe(sass().on('error', sass.logError))
+      .pipe(gulp.dest(options.css));
+  });
+
+  // transpile js with sourceMaps
+  gulp.task('babel', function(){
+    return gulp.src(options.scripts + '**/*.js')
+      .pipe(babel({sourceMaps: true}))
+      .pipe(gulp.dest(options.tmp));
+  });
+
+  // inject scripts
+  gulp.task('injectScript', ['cleanTmp', 'babel'], function(){
+    return gulp.src(options.src + 'index.html')
+      .pipe(
+        inject(
+          gulp.src([
+            options.tmp + '**/*.js',
+            options.helpers + 'ngXosHelpers.js'
+          ])
+          .pipe(angularFilesort()),
+          {
+            ignorePath: [options.src, '/../../ngXosLib']
+          }
+        )
+      )
+      .pipe(gulp.dest(options.src));
+  });
+
+  // inject CSS
+  gulp.task('injectCss', function(){
+    return gulp.src(options.src + 'index.html')
+      .pipe(
+        inject(
+          gulp.src(options.src + 'css/*.css'),
+          {
+            ignorePath: [options.src]
+          }
+          )
+        )
+      .pipe(gulp.dest(options.src));
+  });
+
+  // inject bower dependencies with wiredep
+  gulp.task('bower', function () {
+    return gulp.src(options.src + 'index.html')
+    .pipe(wiredep({devDependencies: true}))
+    .pipe(gulp.dest(options.src));
+  });
+
+  gulp.task('js-watch', ['injectScript'], function(){
+    browserSync.reload();
+  });
+
+  gulp.task('cleanTmp', function(){
+    return del([options.tmp + '**/*']);
+  });
+
+  gulp.task('serve', function() {
+    runSequence(
+      'sass',
+      'bower',
+      'injectScript',
+      'injectCss',
+      ['browser']
+    );
+  });
+};
diff --git a/views/ngXosViews/mcordTopology/gulpfile.js b/views/ngXosViews/mcordTopology/gulpfile.js
new file mode 100644
index 0000000..08df554
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/gulpfile.js
@@ -0,0 +1,26 @@
+'use strict';
+
+var gulp = require('gulp');
+var wrench = require('wrench');
+
+var options = {
+  src: 'src/',
+  css: 'src/css/',
+  sass: 'src/sass/',
+  scripts: 'src/js/',
+  tmp: 'src/.tmp',
+  dist: 'dist/',
+  api: '../../ngXosLib/api/',
+  helpers: '../../../xos/core/xoslib/static/js/vendor/',
+  static: '../../../xos/core/xoslib/static/', // this is the django static folder
+  dashboards: '../../../xos/core/xoslib/dashboards/' // this is the django html folder
+};
+
+wrench.readdirSyncRecursive('./gulp')
+.map(function(file) {
+  require('./gulp/' + file)(options);
+});
+
+gulp.task('default', function () {
+  gulp.start('build');
+});
diff --git a/views/ngXosViews/mcordTopology/karma.conf.js b/views/ngXosViews/mcordTopology/karma.conf.js
new file mode 100644
index 0000000..4123be9
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/karma.conf.js
@@ -0,0 +1,88 @@
+// Karma configuration
+// Generated on Tue Oct 06 2015 09:27:10 GMT+0000 (UTC)
+
+/* eslint indent: [2,2], quotes: [2, "single"]*/
+
+/*eslint-disable*/
+var wiredep = require('wiredep');
+var path = require('path');
+
+var bowerComponents = wiredep( {devDependencies: true} )[ 'js' ].map(function( file ){
+  return path.relative(process.cwd(), file);
+});
+
+module.exports = function(config) {
+/*eslint-enable*/
+  config.set({
+
+    // base path that will be used to resolve all patterns (eg. files, exclude)
+    basePath: '',
+
+
+    // frameworks to use
+    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
+    frameworks: ['jasmine'],
+
+
+    // list of files / patterns to load in the browser
+    files: bowerComponents.concat([
+      '../../../xos/core/xoslib/static/js/vendor/ngXosVendor.js',
+      '../../../xos/core/xoslib/static/js/vendor/ngXosHelpers.js',
+      'src/js/**/*.js',
+      'spec/**/*.mock.js',
+      'spec/**/*.test.js',
+      'src/**/*.html'
+    ]),
+
+
+    // list of files to exclude
+    exclude: [
+    ],
+
+
+    // preprocess matching files before serving them to the browser
+    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
+    preprocessors: {
+      'src/js/**/*.js': ['babel'],
+      'spec/**/*.test.js': ['babel'],
+      'src/**/*.html': ['ng-html2js']
+    },
+
+    ngHtml2JsPreprocessor: {
+      stripPrefix: 'src/', //strip the src path from template url (http://stackoverflow.com/questions/22869668/karma-unexpected-request-when-testing-angular-directive-even-with-ng-html2js)
+      moduleName: 'templates' // define the template module name
+    },
+
+    // test results reporter to use
+    // possible values: 'dots', 'progress'
+    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
+    reporters: ['mocha'],
+
+
+    // web server port
+    port: 9876,
+
+
+    // enable / disable colors in the output (reporters and logs)
+    colors: true,
+
+
+    // level of logging
+    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+    logLevel: config.LOG_INFO,
+
+
+    // enable / disable watching file and executing tests whenever any file changes
+    autoWatch: true,
+
+
+    // start these browsers
+    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
+    browsers: ['PhantomJS'],
+
+
+    // Continuous Integration mode
+    // if true, Karma captures browsers, runs the tests and exits
+    singleRun: false
+  });
+};
diff --git a/views/ngXosViews/mcordTopology/mocks/data/instances.json b/views/ngXosViews/mcordTopology/mocks/data/instances.json
new file mode 100644
index 0000000..0f86876
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/mocks/data/instances.json
@@ -0,0 +1,29 @@
+[
+  {
+    "id": 1,
+    "humanReadableName": "BBU_service_instance-1",
+    "instance_id": "instance-00000001", 
+    "instance_uuid": "42b75cb7-7205-4a68-9100-b2c1e3ea69b5", 
+    "name": "BBU_service_instance-1", 
+    "instance_name": "mysite_BBU-1", 
+    "ip": "130.127.133.91"
+  },
+  {
+    "id": 2,
+    "humanReadableName": "BBU_service_instance-2",
+    "instance_id": "instance-00000002", 
+    "instance_uuid": "42b75cb7-7205-4a68-9200-b2c2e3ea69b5", 
+    "name": "BBU_service_instance-2", 
+    "instance_name": "mysite_BBU-2", 
+    "ip": "130.127.133.92"
+  },
+  {
+    "id": 5,
+    "humanReadableName": "vsg_service_instance-4",
+    "instance_id": "instance-00000004", 
+    "instance_uuid": "44b75cb7-7405-4a68-9400-b4c4e3ea69b5", 
+    "name": "vsg_service_instance-4", 
+    "instance_name": "mysite_vsg-4", 
+    "ip": "130.127.133.94"
+  }
+]
\ No newline at end of file
diff --git a/views/ngXosViews/mcordTopology/mocks/mcord.conf.json b/views/ngXosViews/mcordTopology/mocks/mcord.conf.json
new file mode 100644
index 0000000..7246775
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/mocks/mcord.conf.json
@@ -0,0 +1,8 @@
+[
+  {
+    "url": "instances",
+    "base": "xos/",
+    "methods": ["GET", "POST"],
+    "param": "id"
+  }
+]
\ No newline at end of file
diff --git a/views/ngXosViews/mcordTopology/package.json b/views/ngXosViews/mcordTopology/package.json
new file mode 100644
index 0000000..94bb877
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/package.json
@@ -0,0 +1,63 @@
+{
+  "name": "xos-mcordTopology",
+  "version": "1.0.0",
+  "description": "Angular Application for XOS, created with generator-xos",
+  "scripts": {
+    "prestart": "npm install && bower install",
+    "start": "gulp serve",
+    "prebuild": "npm install && bower install",
+    "build": "gulp",
+    "test": "karma start",
+    "test:ci": "karma start --single-run",
+    "lint": "eslint src/js/"
+  },
+  "keywords": [
+    "XOS",
+    "Angular",
+    "XOSlib"
+  ],
+  "author": "Matteo Scandolo",
+  "license": "MIT",
+  "dependencies": {},
+  "devDependencies": {
+    "autoprefixer": "^6.3.3",
+    "browser-sync": "^2.9.11",
+    "css-mqpacker": "^4.0.0",
+    "csswring": "^4.2.1",
+    "del": "^2.0.2",
+    "easy-mocker": "^1.2.0",
+    "eslint": "^1.8.0",
+    "eslint-plugin-angular": "linkmesrl/eslint-plugin-angular",
+    "gulp": "^3.9.0",
+    "gulp-angular-filesort": "^1.1.1",
+    "gulp-angular-templatecache": "^1.8.0",
+    "gulp-babel": "^5.3.0",
+    "gulp-concat": "^2.6.0",
+    "gulp-concat-util": "^0.5.5",
+    "gulp-eslint": "^1.0.0",
+    "gulp-inject": "^3.0.0",
+    "gulp-minify-html": "^1.0.4",
+    "gulp-ng-annotate": "^1.1.0",
+    "gulp-postcss": "^6.0.1",
+    "gulp-rename": "^1.2.2",
+    "gulp-replace": "^0.5.4",
+    "gulp-sass": "^2.2.0",
+    "gulp-uglify": "^1.4.2",
+    "http-proxy": "^1.12.0",
+    "ink-docstrap": "^0.5.2",
+    "jasmine-core": "~2.3.4",
+    "karma": "^0.13.14",
+    "karma-babel-preprocessor": "~5.2.2",
+    "karma-coverage": "^0.5.3",
+    "karma-jasmine": "~0.3.6",
+    "karma-mocha-reporter": "~1.1.1",
+    "karma-ng-html2js-preprocessor": "^0.2.0",
+    "karma-phantomjs-launcher": "~0.2.1",
+    "lodash": "^3.10.1",
+    "phantomjs": "^1.9.19",
+    "proxy-middleware": "^0.15.0",
+    "run-sequence": "^1.1.4",
+    "wiredep": "^3.0.0-beta",
+    "wrench": "^1.5.8"
+  }
+}
diff --git a/views/ngXosViews/mcordTopology/spec/sample.test.js b/views/ngXosViews/mcordTopology/spec/sample.test.js
new file mode 100644
index 0000000..80a0184
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/spec/sample.test.js
@@ -0,0 +1,37 @@
+'use strict';
+
+describe('The User List', () => {
+  
+  var scope, element, isolatedScope, httpBackend;
+
+  beforeEach(module('xos.mcordTopology'));
+  beforeEach(module('templates'));
+
+  beforeEach(inject(function($httpBackend, $compile, $rootScope){
+    
+    httpBackend = $httpBackend;
+    // Setting up mock request
+    $httpBackend.expectGET('/xos/users/?no_hyperlinks=1').respond([
+      {
+        email: 'teo@onlab.us',
+        firstname: 'Matteo',
+        lastname: 'Scandolo' 
+      }
+    ]);
+  
+    scope = $rootScope.$new();
+    element = angular.element('<users-list></users-list>');
+    $compile(element)(scope);
+    scope.$digest();
+    isolatedScope = element.isolateScope().vm;
+  }));
+
+  xit('should load 1 users', () => {
+    httpBackend.flush();
+    expect(isolatedScope.users.length).toBe(1);
+    expect(isolatedScope.users[0].email).toEqual('teo@onlab.us');
+    expect(isolatedScope.users[0].firstname).toEqual('Matteo');
+    expect(isolatedScope.users[0].lastname).toEqual('Scandolo');
+  });
+
+});
\ No newline at end of file
diff --git a/views/ngXosViews/mcordTopology/src/css/dev.css b/views/ngXosViews/mcordTopology/src/css/dev.css
new file mode 100644
index 0000000..32d915d
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/src/css/dev.css
@@ -0,0 +1,7 @@
+#xosMcordTopology{
+  position: absolute;
+  /*top: 100px;
+  left: 200px;*/
+  width: 100%;
+  height: 100%;
+}
\ No newline at end of file
diff --git a/views/ngXosViews/mcordTopology/src/css/main.css b/views/ngXosViews/mcordTopology/src/css/main.css
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/src/css/main.css
diff --git a/views/ngXosViews/mcordTopology/src/css/mcord.css b/views/ngXosViews/mcordTopology/src/css/mcord.css
new file mode 100644
index 0000000..8fb7540
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/src/css/mcord.css
@@ -0,0 +1,81 @@
+#xosMcordTopology {
+  height: 700px;
+}
+
+[ui-view],
+m-cord-topology{
+  width: 100%;
+  height: 100%;
+  display: block;
+}
+
+line {
+  stroke: blue;
+  /*stroke-width: 1;*/
+}
+
+line.big{
+  stroke-width: 2;
+}
+
+circle,
+rect {
+  fill: #fff;
+  stroke-width: 1; 
+}
+
+.fabric {
+  stroke: none;
+  fill: #123456;
+  fill-rule: evenodd;
+}
+
+.fabric-container {
+  fill: transparent;
+  stroke: #000;
+  stroke-width: 1;
+}
+
+.bbu {
+  stroke: black;
+  fill: #FF7F0E;
+}
+
+.rru {
+  stroke: #000;
+  fill: #FFBB78;
+}
+
+.rru.antenna {
+  stroke: #000;
+  fill: brown;
+}
+
+.rru-shadow {
+  fill: #FFBB78;
+  opacity: .4
+}
+
+.MME, .SGW, .PGW, .Vid {
+  fill: purple;
+  stroke: #000;
+}
+
+rect.MME,
+rect.SGW,
+rect.PGW,
+rect.bbu,
+rect.Vid {
+  fill: #fff;
+  stroke: #fff;
+}
+
+.bbu text, 
+.MME text,
+.SGW text,
+.PGW text, 
+.Vid text {
+  font-size: 10px;
+  stroke-width: 0;
+  fill: #000;
+}
\ No newline at end of file
diff --git a/views/ngXosViews/mcordTopology/src/index.html b/views/ngXosViews/mcordTopology/src/index.html
new file mode 100644
index 0000000..d8985de
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/src/index.html
@@ -0,0 +1,31 @@
+<!-- browserSync -->
+<!-- bower:css -->
+<link rel="stylesheet" href="vendor/bootstrap-css/css/bootstrap.css" />
+<!-- endbower --><!-- endcss -->
+<!-- inject:css -->
+<link rel="stylesheet" href="/css/dev.css">
+<link rel="stylesheet" href="/css/main.css">
+<link rel="stylesheet" href="/css/mcord.css">
+<!-- endinject -->
+
+<div ng-app="xos.mcordTopology" id="xosMcordTopology" class="container-fluid">
+    <div ui-view></div>
+</div>
+
+<!-- bower:js -->
+<script src="vendor/d3/d3.js"></script>
+<script src="vendor/jquery/dist/jquery.js"></script>
+<script src="vendor/angular/angular.js"></script>
+<script src="vendor/angular-mocks/angular-mocks.js"></script>
+<script src="vendor/angular-ui-router/release/angular-ui-router.js"></script>
+<script src="vendor/angular-cookies/angular-cookies.js"></script>
+<script src="vendor/angular-resource/angular-resource.js"></script>
+<script src="vendor/lodash/lodash.js"></script>
+<script src="vendor/bootstrap-css/js/bootstrap.js"></script>
+<!-- endbower --><!-- endjs -->
+<!-- inject:js -->
+<script src="/../../../xos/core/xoslib/static/js/vendor/ngXosHelpers.js"></script>
+<script src="/.tmp/main.js"></script>
+<script src="/.tmp/static.data.js"></script>
+<script src="/.tmp/node_drawer.js"></script>
+<!-- endinject -->
diff --git a/views/ngXosViews/mcordTopology/src/js/main.js b/views/ngXosViews/mcordTopology/src/js/main.js
new file mode 100644
index 0000000..6a38c3e
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/src/js/main.js
@@ -0,0 +1,354 @@
+'use strict';
+
+angular.module('xos.mcordTopology', [
+  'ngResource',
+  'ngCookies',
+  'ui.router',
+  'xos.helpers'
+])
+.config(($stateProvider) => {
+  $stateProvider
+  .state('topology', {
+    url: '/',
+    template: '<m-cord-topology></m-cord-topology>'
+  });
+})
+.config(function($httpProvider){
+  $httpProvider.interceptors.push('NoHyperlinks');
+})
+.factory('_', $window => $window._)
+.service('Traffic', function($http, $q){
+  this.get = () => {
+    var deferred = $q.defer();
+    $http.get('videoLocal.txt')
+    .then(res => {
+      deferred.resolve(res.data);
+    })
+    .catch(e => {
+      console.log(e);
+      deferred.resolve(Math.random() * 10)
+    });
+    return deferred.promise;
+  }
+})
+.directive('mCordTopology', function(){
+  return {
+    restrict: 'E',
+    scope: {},
+    bindToController: true,
+    controllerAs: 'vm',
+    template: '',
+    controller: function($element, $interval, $rootScope, _, $http, TopologyElements, NodeDrawer, Traffic){
+
+      const el = $element[0];
+
+      let nodes = [];
+      let links = [];
+      let traffic = 0;
+      let linkWidth = 1;
+      let trafficCorrection = 5;
+
+      const filterBBU = (instances) => {
+        return _.filter(instances, i => i.name.indexOf("bbu") >= 0);
+      };
+
+      const filterOthers = (instances) => {
+        return TopologyElements.fakedInstance;
+      };
+
+      // retrieving instances list
+      const getData = () => {
+
+        d3.select('svg')
+          .style('width', `${el.clientWidth}px`)
+          .style('height', `${el.clientHeight}px`);
+
+        nodes = TopologyElements.nodes;
+        links = TopologyElements.links;
+
+        Traffic.get()
+        .then((newTraffic) => {
+
+          // calculating link size
+          // it should change between 1 and 10
+          if(!traffic){
+            linkWidth = 2;
+          }
+          else if(newTraffic === traffic){
+            linkWidth = linkWidth;
+          }
+          else{
+            let delta = newTraffic - traffic;
+
+            if(delta > 0){
+              linkWidth = linkWidth + (delta / trafficCorrection);
+            }
+            else{
+              linkWidth = linkWidth - ((delta * -1) / trafficCorrection);
+            }
+
+          }
+
+          if(linkWidth < 0.2){
+            linkWidth = 0.2
+          };
+
+          traffic = newTraffic;
+
+          return $http.get('/api/core/xos/instances');
+          // return XosApi.Instance_List_GET()
+        })
+        .then((instances) => {
+
+          addBbuNodes(filterBBU(instances.data));
+          addOtherNodes(filterOthers(instances.data));
+
+          draw(svg, nodes, links);
+        })
+        .catch((e) => {
+          throw new Error(e);
+        });
+      };
+
+      const force = d3.layout.force();
+
+      // create svg elements
+      const svg = d3.select(el)
+        .append('svg')
+        .style('width', `${el.clientWidth}px`)
+        .style('height', `${el.clientHeight}px`);
+
+      const linkContainer = svg.append('g')
+        .attr({
+          class: 'link-container'
+        });
+
+      const nodeContainer = svg.append('g')
+        .attr({
+          class: 'node-container'
+        });
+
+      // replace human readable ids with d3 ids
+      // NOTE now ids are not manatined on update...
+      const buildLinks = (links, nodes) => {
+        return links.map((l) => {
+
+          console.log(_.find);
+          let source = _.findIndex(nodes, {id: l.source});
+          let target = _.findIndex(nodes, {id: l.target});
+          // console.log(`link-${source}-${target}`, source, target);
+          return {
+            source: source,
+            target: target,
+            value: 1,
+            id: `link-${source}-${target}`,
+            type: l.source.indexOf('fabric') >= 0 ? 'big':'small'
+          };
+
+        });
+      };
+
+      // find fabric nodes and center horizontally
+      const positionFabricNodes = (nodes) => {
+        return _.map(nodes, n => {
+          if(n.type !== 'fabric'){
+            return n;
+          }
+
+          n.x = n.x * hStep;
+          n.y = n.y * vStep;
+
+          return n;
+        });
+      };
+
+      const addBbuNodes = (instances) => {
+
+        // calculate bbu hStep
+        let bbuHStep = ((el.clientWidth / 2) / (instances.length + 1));
+
+        // create nodes
+        let bbuNodes = instances.map((n, i) => {
+          return {
+            type: 'bbu',
+            name: n.name,
+            id: `bbu-${n.id}`,
+            fixed: true,
+            y: vStep * 3,
+            x: bbuHStep * (i + 1)
+          };
+        });
+
+        // create links
+        let bbuLinks = bbuNodes.map(n => {
+          return {
+            source: n.id,
+            target: 'fabric4'
+          };
+        });
+
+        // fake RRU nodes and links
+        instances.forEach((n, i) => {
+          bbuNodes.push({
+            type: 'rru',
+            name: 'rru',
+            id: `rru-${n.id}`,
+            fixed: true,
+            y: vStep * 4,
+            x: bbuHStep * (i + 1)
+          });
+
+          bbuLinks.push({
+            source: `rru-${n.id}`,
+            target: `bbu-${n.id}`
+          });
+        })
+
+        nodes = nodes.concat(bbuNodes);
+
+
+        links = links.concat(bbuLinks);
+      };
+
+      // add MME, PGW, SGW nodes
+      const addOtherNodes = (instances) => {
+        let hStep = ((el.clientWidth / 2) / (instances.length + 1));
+
+        // create nodes
+        let otherNodes = instances.map((n, i) => {
+          return {
+            type: n.name.substring(0, 3),
+            name: n.name,
+            id: `${n.name.substring(0, 3)}-${n.id}`,
+            fixed: true,
+            y: vStep * 3,
+            x: (el.clientWidth / 2) + (hStep * (i + 1))
+          };
+        });
+
+        // create links
+        let otherLinks = otherNodes.map(n => {
+          return {
+            source: n.id,
+            target: 'fabric4'
+          };
+        });
+
+
+        nodes = nodes.concat(otherNodes);
+        links = links.concat(otherLinks);
+      }
+
+      let hStep, vStep;
+
+      hStep = el.clientWidth / 3;
+      vStep = el.clientHeight / 5;
+
+      const draw = (svg, nodes, links) => {
+
+        hStep = el.clientWidth / 3;
+        vStep = el.clientHeight / 5;
+
+        links = buildLinks(links, nodes);
+
+        nodes = positionFabricNodes(nodes);
+
+        console.log(nodes);
+        // start force layout
+        force
+          .nodes(nodes)
+          .links(links)
+          .size([el.clientWidth, el.clientHeight])
+          .charge(-20)
+          .chargeDistance(200)
+          .linkDistance(80)
+          .linkStrength(0.1)
+          .start();
+
+
+        const linkContainer = d3.select('.link-container');
+        const nodeContainer = d3.select('.node-container');
+
+        NodeDrawer.drawFabricBox(nodeContainer, hStep, vStep);
+
+        // draw links
+        var link = linkContainer.selectAll('.link')
+          .data(links, d => d.id);
+        
+        link.enter().append('line')
+          .attr({
+            class: d => `link ${d.type}`,
+            'stroke-width': linkWidth,
+            id: d => d.id,
+            opacity: 0
+          })
+          .transition()
+          .duration(1000)
+          .attr({
+            opacity: 1
+          });
+
+        link
+          .transition()
+          .duration(1000)
+          .attr({
+            'stroke-width': linkWidth,
+            opacity: 1
+          });
+
+        link.exit()
+        .remove();
+
+        //draw nodes
+        var node = nodeContainer.selectAll('.node')
+          .data(nodes, d => {
+            return d.id
+          });
+        
+        // append a group for any new node
+        var enter = node.enter()
+          .append('g', d => d.interfaceCfgIdentifier)
+          .attr({
+            class: d => `${d.type} node`,
+            transform: d => `translate(${d.x}, ${d.y})`
+          });
+
+        // draw nodes
+        NodeDrawer.drawBbus(enter.filter('.bbu'))
+        NodeDrawer.drawRrus(enter.filter('.rru'))
+        NodeDrawer.drawFabric(enter.filter('.fabric'))
+        NodeDrawer.drawOthers(enter.filter(d => {
+          console.log(d.type);
+          return (
+            d.type  === 'MME' ||
+            d.type === 'SGW' ||
+            d.type === 'PGW' ||
+            d.type === 'Vid'
+          )
+        }));
+
+        // remove nodes
+        var exit = node.exit();
+
+        NodeDrawer.removeElements(exit);
+
+        force.on('tick', function() {
+          link
+            .attr('x1', d => d.source.x )
+            .attr('y1', d => d.source.y )
+            .attr('x2', d => d.target.x )
+            .attr('y2', d => d.target.y );
+
+          node.attr('transform', (d) => `translate(${d.x},${d.y})`);
+        });
+      };
+      
+      // $interval(() => {
+      //   getData();
+      // }, 3000);
+      getData();
+
+      
+    }
+  };
+});
diff --git a/views/ngXosViews/mcordTopology/src/js/node_drawer.js b/views/ngXosViews/mcordTopology/src/js/node_drawer.js
new file mode 100644
index 0000000..b2dae65
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/src/js/node_drawer.js
@@ -0,0 +1,213 @@
+'use strict';
+
+angular.module('xos.mcordTopology')
+.service('NodeDrawer', function(TopologyElements){
+
+  const duration = 500;
+
+  let isFabricDrawed = false;
+
+  this.drawFabricBox = (svg, hStep, vStep) => {
+
+    if(isFabricDrawed){
+      return;
+    }
+
+    let fabric = svg.append('g')
+    .attr({
+      transform: `translate(${hStep - 25}, ${vStep - 25})`
+    });
+
+    fabric.append('rect')
+      .attr({
+        width: hStep + 50,
+        height: vStep + 50,
+        class: 'fabric-container'
+      });
+
+    // fabric.append('text')
+    // .text('Fabric')
+    // .attr({
+    //   'text-anchor': 'middle',
+    //   x: ((hStep + 50) / 2),
+    //   y: -10
+    // });
+
+    isFabricDrawed = true;
+  };
+
+  this.drawBbus = (nodes) => {
+
+    nodes.append('rect')
+      .attr({
+        class: d => d.type,
+        width: 30,
+        height: 30,
+        x: -15,
+        y: -15,
+        opacity: 0
+      })
+      .transition()
+      .duration(duration)
+      .attr({
+        r: 15,
+        opacity: 1
+      });
+
+    nodes
+      .append('path')
+      .attr({
+        class: d => `${d.type} antenna`,
+        opacity: 0,
+        d: () => TopologyElements.icons.bbu,
+        transform: `translate(-18, -18)`
+      })
+      .transition()
+      .duration(duration)
+      .attr({
+        opacity: 1
+      });
+
+    nodes.append('text')
+    .attr({
+      'text-anchor': 'start',
+      y: 25,
+      x: 5,
+      opacity: 0
+    })
+    .text(d => `BBU ${d.name.substr(d.name.length - 1, 1)}`)
+    .transition()
+    .duration(duration * 2)
+    .attr({
+      opacity: 1
+    });
+  };
+
+  this.drawRrus = (nodes) => {
+
+    nodes.append('circle')
+      .attr({
+        class: d => `${d.type}-shadow`,
+        r: 0,
+        opacity: 0
+      })
+      .transition()
+      .duration(duration * 2)
+      // .delay((d, i) => i * (duration / 2))
+      .attr({
+        r: 40,
+        opacity: 1
+      });
+
+    nodes
+      .append('path')
+      .attr({
+        class: d => `${d.type} antenna`,
+        opacity: 0,
+        d: () => TopologyElements.icons.rru,
+        transform: `translate(-18, -18)`
+      })
+      .transition()
+      .duration(duration)
+      .attr({
+        opacity: 1
+      });
+  
+    // nodes.append('circle')
+    //   .attr({
+    //     class: d => d.type,
+    //     r: 0,
+    //     opacity: 0
+    //   })
+    //   .transition()
+    //   .duration(duration)
+    //   // .delay((d, i) => i * (duration / 2))
+    //   .attr({
+    //     r: 10,
+    //     opacity: 1
+    //   });
+  };
+
+  this.drawFabric = (nodes) => {
+    nodes
+      .append('rect')
+      .attr({
+        width: 30,
+        height: 30,
+        x: -15,
+        y: -15
+      });
+
+    nodes
+      .append('path')
+      .attr({
+        class: d => d.type,
+        opacity: 0,
+        d: () => TopologyElements.icons.switch,
+        transform: `translate(-22, -22), scale(0.4)`
+      })
+      .transition()
+      .duration(duration)
+      // .delay((d, i) => i * (duration / 2))
+      .attr({
+        opacity: 1
+      });
+  };
+
+  this.drawOthers = (nodes) => {
+    nodes.append('rect')
+      .attr({
+        class: d => d.type,
+        width: 30,
+        height: 30,
+        x: -15,
+        y: -15,
+        opacity: 0
+      })
+      .transition()
+      .duration(duration)
+      .attr({
+        r: 15,
+        opacity: 1
+      });
+
+    nodes
+      .append('path')
+      .attr({
+        class: d => `${d.type} antenna`,
+        opacity: 0,
+        d: () => TopologyElements.icons.bbu,
+        transform: `translate(-18, -18)`
+      })
+      .transition()
+      .duration(duration)
+      .attr({
+        opacity: 1
+      });
+
+    nodes.append('text')
+    .attr({
+      'text-anchor': 'start',
+      y: 25,
+      x: -12,
+      opacity: 0
+    })
+    .text(d => d.name.toUpperCase())
+    .transition()
+    .duration(duration * 2)
+    .attr({
+      opacity: 1
+    });
+
+  };
+
+  this.removeElements = (nodes) => {
+    nodes
+    .transition()
+    .duration(duration)
+    .attr({
+      opacity: 0
+    })
+    .remove();
+  };
+});
\ No newline at end of file
diff --git a/views/ngXosViews/mcordTopology/src/js/static.data.js b/views/ngXosViews/mcordTopology/src/js/static.data.js
new file mode 100644
index 0000000..97ccf9d
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/src/js/static.data.js
@@ -0,0 +1,85 @@
+'use strict';
+
+angular.module('xos.mcordTopology')
+.constant('TopologyElements', {
+  nodes: [
+    // {
+    //   id: 'fabric1',
+    //   type: 'fabric',
+    //   name: 'fabric1',
+    //   fixed: true,
+    //   x: 1,
+    //   y: 1
+    // },
+    // {
+    //   id: 'fabric2',
+    //   type: 'fabric',
+    //   name: 'fabric2',
+    //   fixed: true,
+    //   x: 1,
+    //   y: 2
+    // },
+    // {
+    //   id: 'fabric3',
+    //   type: 'fabric',
+    //   name: 'fabric3',
+    //   fixed: true,
+    //   x: 2,
+    //   y: 1
+    // },
+    {
+      id: 'fabric4',
+      type: 'fabric',
+      name: 'fabric4',
+      fixed: true,
+      x: 1.5,
+      y: 1.5
+    }
+  ],
+  links: [
+    // {
+    //   source: 'fabric1',
+    //   target: 'fabric2'
+    // },
+    // {
+    //   source: 'fabric1',
+    //   target: 'fabric4'
+    // },
+    // {
+    //   source: 'fabric3',
+    //   target: 'fabric4'
+    // },
+    // {
+    //   source: 'fabric3',
+    //   target: 'fabric2'
+    // }
+  ],
+  fakedInstance: [
+    {
+      humanReadableName: 'MME',
+      name: 'MME'
+    },
+    {
+      humanReadableName: 'PGW',
+      name: 'PGW'
+    },
+    {
+      humanReadableName: 'SGW',
+      name: 'SGW'
+    },
+    {
+      humanReadableName: 'Video Server',
+      name: 'Video Server'
+    }
+  ],
+  icons: {
+    bbu: `M11.08,4.66H24.76l6.81,6.82H4.23Z M4.24,18.34V13.21H31.6v5.13H4.24Zm25.64-1.72V14.94H28.19v1.69h1.68Zm-13.65-1.7v1.69h1.69V14.93H16.22Zm-3.42,0v1.69h1.68V14.93H12.8Zm-3.42,0v1.69h1.68V14.93H9.38ZM6,14.93v1.69H7.64V14.93H6Z M32.8,33.23H3V11.42l0,0c1.17-1.16,2.54-2.5,3.87-3.8S9.59,5,10.72,3.87l0,0H25.08l0,0C26.25,5,27.6,6.32,28.9,7.61s2.68,2.63,3.83,3.78l0,0v0.06ZM3.3,33H32.53l0-21.43C31.36,10.39,30,9.07,28.71,7.8S26.09,5.22,25,4.1H10.86C9.75,5.21,8.41,6.52,7.12,7.77s-2.67,2.61-3.83,3.76V33Z M4.24,25.18V20.05H31.6v5.13H4.24Zm24-1.73h1.68V21.78H28.19v1.67Zm-12,0H17.9V21.78H16.21v1.68Zm-1.73-1.68H12.81v1.67h1.68V21.78Zm-3.43,1.68V21.78H9.38v1.69h1.68ZM6,23.46H7.64V21.78H6v1.68Z M31.6,26.89V32H4.24V26.89H31.6Zm-3.4,1.72V30.3h1.68V28.61H28.19Zm-10.28,0H16.22V30.3h1.68V28.62Zm-3.43,1.69V28.62H12.8v1.69h1.68Zm-3.42,0V28.62H9.38v1.69h1.68ZM7.65,28.62H6v1.67H7.65V28.62Z`,
+    // bbu: `M15,100a5,5,0,0,1-5-5v-65a5,5,0,0,1,5-5h80a5,5,0,0,1,5,5v65a5,5,0,0,1-5,5zM14,22.5l11-11a10,3,0,0,1,10-2h40a10,3,0,0,1,10,2l11,11zM16,35a5,5,0,0,1,10,0a5,5,0,0,1-10,0z`,
+    switch: `M10,20a10,10,0,0,1,10-10h70a10,10,0,0,1,10,10v70a10,10,
+            0,0,1-10,10h-70a10,10,0,0,1-10-10zM60,26l12,0,0-8,18,13-18,13,0
+            -8-12,0zM60,60l12,0,0-8,18,13-18,13,0-8-12,0zM50,40l-12,0,0-8
+            -18,13,18,13,0-8,12,0zM50,74l-12,0,0-8-18,13,18,13,0-8,12,0z`,
+    // rru: `M85,71.2c-8.9,10.5-29.6,8.7-45.3-3.5C23.9,55.4,19.8,37,28.6,26.5C29.9,38.6,71.5,69.9,85,71.2z M92.7,76.2M16.2,15 M69.5,100.7v-4c0-1.4-1.2-2.2-2.6-2.2H19.3c-1.4,0-2.8,0.7-2.8,2.2v3.9c0,0.7,0.8,1,1.5,1h50.3C69,101.5,69.5,101.3,69.5,100.7z M77.3,7.5l0,3.7c9,0.1,16.3,7.1,16.2,15.7l3.9,0C97.5,16.3,88.5,7.6,77.3,7.5z M77.6,14.7l0,2.5c5.3,0,9.7,4.2,9.6,9.3l2.6,0C89.9,20,84.4,14.7,77.6,14.7z M82.3,22.2c-1.3-1.2-2.9-1.9-4.7-1.9l0,1.2c1.4,0,2.8,0.6,3.8,1.5c1,1,1.6,2.3,1.6,3.7l1.3,0C84.3,25.1,83.6,23.4,82.3,22.2z M38.9,69.5l-5.1,23h16.5l-2.5-17.2C44.1,73.3,38.9,69.5,38.9,69.5zM58.1,54.1c13.7,10.1,26.5,16.8,29.2,13.7c2.7-3.1-5.6-13-19.3-24.4 M62.9,34.2 M62,37.9C47.7,27.3,33.7,20,31,23.1c-2.7,3.2,7,14.2,20.6,26 M73.9,25.7c-2.9,0.1-5.2,2.3-5.1,4.8c0,0.7,0.2,1.4,0.6,2l0,0L53.8,49.7l3.3,2.5L72.7,35l-0.4-0.3c0.6,0.2,1.3,0.3,1.9,0.3c2.9-0.1,5.2-2.3,5.1-4.9C79.3,27.6,76.8,25.6,73.9,25.7z`,
+    rru: `M18.11,11a2.25,2.25,0,0,1,2.13,1.53A2.2,2.2,0,0,1,19.52,15a0.74,0.74,0,0,0-.3.61A7.49,7.49,0,0,0,20,19.35c2,4.55,3.94,9.13,5.89,13.7a1.14,1.14,0,0,1-.59,1.64A1.11,1.11,0,0,1,23.86,34q-0.53-1.2-1-2.41a0.38,0.38,0,0,0-.41-0.28H13.78a0.36,0.36,0,0,0-.39.26q-0.51,1.24-1.06,2.47a1.11,1.11,0,0,1-1.14.67,1.07,1.07,0,0,1-1-.89,1.47,1.47,0,0,1,.1-0.75q2.84-6.66,5.7-13.32a4.06,4.06,0,0,1,.18-0.42A6.39,6.39,0,0,0,17,15.53,0.58,0.58,0,0,0,16.74,15,2.21,2.21,0,0,1,16,12.5,2.26,2.26,0,0,1,18.11,11ZM21.74,29.1c-0.32-.74-0.61-1.43-0.92-2.12a0.35,0.35,0,0,0-.27-0.14H15.66a0.33,0.33,0,0,0-.26.11c-0.32.7-.62,1.41-0.93,2.15h7.26Zm-5.31-4.55h3.37L18.1,20.63Z M2.23,13.56A16,16,0,0,1,6.76,2.16a1.68,1.68,0,0,1,.8-0.46,1.06,1.06,0,0,1,1.18.59,1.16,1.16,0,0,1-.23,1.37A14.48,14.48,0,0,0,6.19,6.77a13.57,13.57,0,0,0,1.9,15.59l0.46,0.49a1.16,1.16,0,1,1-1.68,1.59,15.6,15.6,0,0,1-4.41-8.64C2.32,14.95,2.28,14.07,2.23,13.56Z M34,13.84a15.51,15.51,0,0,1-4.54,10.52,1.19,1.19,0,0,1-1.65.18,1.17,1.17,0,0,1,0-1.77,13.81,13.81,0,0,0,2.79-4.1,13.6,13.6,0,0,0-2.7-14.91A1.8,1.8,0,0,1,27.41,3,1.08,1.08,0,0,1,28,1.8,1.15,1.15,0,0,1,29.38,2a15.59,15.59,0,0,1,2.51,3.28A16.47,16.47,0,0,1,34,13.84Z M10.93,21.6A1.33,1.33,0,0,1,9.87,21a11.06,11.06,0,0,1-2.8-5.27A11.22,11.22,0,0,1,9.8,5.51l0.27-.28a1.16,1.16,0,1,1,1.64,1.63,8.62,8.62,0,0,0-2.06,3.22A8.87,8.87,0,0,0,11.18,19c0.18,0.23.4,0.44,0.59,0.66A1.13,1.13,0,0,1,11.95,21,1.08,1.08,0,0,1,10.93,21.6Z M29.47,13.57a11.11,11.11,0,0,1-3.27,7.64,1.18,1.18,0,0,1-1.51.21,1.13,1.13,0,0,1-.43-1.4,2.06,2.06,0,0,1,.39-0.54,8.85,8.85,0,0,0,2.49-5.89A9,9,0,0,0,24.64,7a1.85,1.85,0,0,1-.44-0.85A1,1,0,0,1,24.82,5a1.07,1.07,0,0,1,1.3.21,20.11,20.11,0,0,1,1.79,2.31A11.09,11.09,0,0,1,29.47,13.57Z M11.3,13.18a6.73,6.73,0,0,1,2-4.73,1.15,1.15,0,0,1,1.45-.2,1.12,1.12,0,0,1,.49,1.32,1.58,1.58,0,0,1-.33.53,4.49,4.49,0,0,0,0,6.26,1.16,1.16,0,1,1-1.7,1.57A6.81,6.81,0,0,1,11.3,13.18Z M24.94,13.14A6.9,6.9,0,0,1,23,18a1.16,1.16,0,1,1-1.7-1.58,4.5,4.5,0,0,0,0-6.29A1.16,1.16,0,1,1,23,8.5,6.75,6.75,0,0,1,24.94,13.14Z`
+  }
+})
\ No newline at end of file
diff --git a/views/ngXosViews/mcordTopology/src/sass/main.scss b/views/ngXosViews/mcordTopology/src/sass/main.scss
new file mode 100644
index 0000000..78cf25b
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/src/sass/main.scss
@@ -0,0 +1,5 @@
+@import '../../../../style/sass/lib/_variables.scss';
+
+#xosMcordTopology {
+  
+}
\ No newline at end of file
diff --git a/views/ngXosViews/mcordTopology/src/templates/users-list.tpl.html b/views/ngXosViews/mcordTopology/src/templates/users-list.tpl.html
new file mode 100644
index 0000000..fd8d208
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/src/templates/users-list.tpl.html
@@ -0,0 +1,16 @@
+<div class="row">
+  <div class="col-xs-12">
+    <h1>Users List</h1>
+    <p>This is only an example view.</p>
+  </div>
+</div>
+<div class="row">
+  <div class="col-xs-4">Email</div>
+  <div class="col-xs-4">First Name</div>
+  <div class="col-xs-4">Last Name</div>
+</div>  
+<div class="row" ng-repeat="user in vm.users">
+  <div class="col-xs-4">{{user.email}}</div>
+  <div class="col-xs-4">{{user.firstname}}</div>
+  <div class="col-xs-4">{{user.lastname}}</div>
+</div>  
\ No newline at end of file
diff --git a/views/ngXosViews/openVPNDashboard/.bowerrc b/views/ngXosViews/openVPNDashboard/.bowerrc
new file mode 100644
index 0000000..e491038
--- /dev/null
+++ b/views/ngXosViews/openVPNDashboard/.bowerrc
@@ -0,0 +1,3 @@
+{
+  "directory": "src/vendor/"
+}
\ No newline at end of file
diff --git a/views/ngXosViews/openVPNDashboard/.eslintrc b/views/ngXosViews/openVPNDashboard/.eslintrc
new file mode 100644
index 0000000..c852748
--- /dev/null
+++ b/views/ngXosViews/openVPNDashboard/.eslintrc
@@ -0,0 +1,42 @@
+{
+    "ecmaFeatures": {
+        "blockBindings": true,
+        "forOf": true,
+        "destructuring": true,
+        "arrowFunctions": true,
+        "templateStrings": true
+    },
+    "env": { 
+        "browser": true,
+        "node": true,
+        "es6": true
+    },
+    "plugins": [
+        //"angular"
+    ],
+    "rules": {
+        "quotes": [2, "single"],
+        "camelcase": [1, {"properties": "always"}],
+        "no-underscore-dangle": 1,
+        "eqeqeq": [2, "smart"],
+        "no-alert": 1,
+        "key-spacing": [1, { "beforeColon": false, "afterColon": true }],
+        "indent": [2, 2],
+        "no-irregular-whitespace": 1,
+        "eol-last": 0,
+        "max-nested-callbacks": [2, 4],
+        "comma-spacing": [1, {"before": false, "after": true}],
+        "no-trailing-spaces": [1, { skipBlankLines: true }],
+        "no-unused-vars": [1, {"vars": "all", "args": "after-used"}],
+        "new-cap": 0,
+
+        //"angular/ng_module_name": [2, '/^xos\.*[a-z]*$/'],
+        //"angular/ng_controller_name": [2, '/^[a-z].*Ctrl$/'],
+        //"angular/ng_service_name": [2, '/^[A-Z].*Service$/'],
+        //"angular/ng_directive_name": [2, '/^[a-z]+[[A-Z].*]*$/'],
+        //"angular/ng_di": [0, "function or array"]
+    },
+    "globals" :{
+        "angular": true
+    } 
+}
\ No newline at end of file
diff --git a/views/ngXosViews/openVPNDashboard/.gitignore b/views/ngXosViews/openVPNDashboard/.gitignore
new file mode 100644
index 0000000..567aee4
--- /dev/null
+++ b/views/ngXosViews/openVPNDashboard/.gitignore
@@ -0,0 +1,6 @@
+dist/
+src/vendor
+.tmp
+node_modules
+npm-debug.log
+dist/
\ No newline at end of file
diff --git a/views/ngXosViews/openVPNDashboard/bower.json b/views/ngXosViews/openVPNDashboard/bower.json
new file mode 100644
index 0000000..66d7af1
--- /dev/null
+++ b/views/ngXosViews/openVPNDashboard/bower.json
@@ -0,0 +1,32 @@
+{
+  "name": "xos-openVPNDashboard",
+  "version": "0.0.0",
+  "authors": [
+    "Matteo Scandolo <teo@onlab.us>"
+  ],
+  "description": "The openVPNDashboard view",
+  "license": "MIT",
+  "ignore": [
+    "**/.*",
+    "node_modules",
+    "bower_components",
+    "static/js/vendor/",
+    "test",
+    "tests"
+  ],
+  "dependencies": {
+  },
+  "devDependencies": {
+    "jquery": "2.1.4",
+    "angular-mocks": "1.4.7",
+    "angular": "1.4.7",
+    "angular-ui-router": "0.2.15",
+    "angular-cookies": "1.4.7",
+    "angular-animate": "1.4.7",
+    "angular-resource": "1.4.7",
+    "lodash": "~4.11.1",
+    "bootstrap-css": "3.3.6",
+    "angular-chart.js": "~0.10.2",
+    "d3": "~3.5.17"
+  }
+}
diff --git a/views/ngXosViews/openVPNDashboard/gulp/build.js b/views/ngXosViews/openVPNDashboard/gulp/build.js
new file mode 100644
index 0000000..33a2cac
--- /dev/null
+++ b/views/ngXosViews/openVPNDashboard/gulp/build.js
@@ -0,0 +1,164 @@
+'use strict';
+
+// BUILD
+//
+// The only purpose of this gulpfile is to build a XOS view and copy the correct files into
+// .html => dashboards
+// .js (minified and concat) => static/js
+//
+// The template are parsed and added to js with angular $templateCache
+
+var gulp = require('gulp');
+var ngAnnotate = require('gulp-ng-annotate');
+var uglify = require('gulp-uglify');
+var templateCache = require('gulp-angular-templatecache');
+var runSequence = require('run-sequence');
+var concat = require('gulp-concat-util');
+var del = require('del');
+var wiredep = require('wiredep');
+var angularFilesort = require('gulp-angular-filesort');
+var _ = require('lodash');
+var eslint = require('gulp-eslint');
+var inject = require('gulp-inject');
+var rename = require('gulp-rename');
+var replace = require('gulp-replace');
+var postcss = require('gulp-postcss');
+var autoprefixer = require('autoprefixer');
+var mqpacker = require('css-mqpacker');
+var csswring = require('csswring');
+
+const TEMPLATE_FOOTER = `
+angular.module('xos.openVPNDashboard')
+.run(['$location', function(a){
+  a.path('/');
+}])
+`
+
+module.exports = function(options){
+  
+  // delete previous builded file
+  gulp.task('clean', function(){
+    return del(
+      [
+        options.dashboards + 'xosOpenVPNDashboard.html',
+        options.static + 'css/xosOpenVPNDashboard.css'
+      ],
+      {force: true}
+    );
+  });
+
+  // minify css
+  gulp.task('css', function () {
+    var processors = [
+      autoprefixer({browsers: ['last 1 version']}),
+      mqpacker,
+      csswring
+    ];
+
+    gulp.src([
+      `${options.css}**/*.css`,
+      `!${options.css}dev.css`
+    ])
+    .pipe(postcss(processors))
+    .pipe(gulp.dest(options.tmp + '/css/'));
+  });
+
+  // copy css in correct folder
+  gulp.task('copyCss', ['wait'], function(){
+    return gulp.src([`${options.tmp}/css/*.css`])
+    .pipe(concat('xosOpenVPNDashboard.css'))
+    .pipe(gulp.dest(options.static + 'css/'))
+  });
+
+  // compile and minify scripts
+  gulp.task('scripts', function() {
+    return gulp.src([
+      options.tmp + '**/*.js'
+    ])
+    .pipe(ngAnnotate())
+    .pipe(angularFilesort())
+    .pipe(concat('xosOpenVPNDashboard.js'))
+    .pipe(concat.header('//Autogenerated, do not edit!!!\n'))
+    .pipe(concat.footer(TEMPLATE_FOOTER))
+    .pipe(uglify())
+    .pipe(gulp.dest(options.static + 'js/'));
+  });
+
+  // set templates in cache
+  gulp.task('templates', function(){
+    return gulp.src('./src/templates/*.html')
+      .pipe(templateCache({
+        module: 'xos.openVPNDashboard',
+        root: 'templates/'
+      }))
+      .pipe(gulp.dest(options.tmp));
+  });
+
+  // copy html index to Django Folder
+  gulp.task('copyHtml', function(){
+    return gulp.src(options.src + 'index.html')
+      // remove dev dependencies from html
+      .pipe(replace(/<!-- bower:css -->(\n^<link.*)*\n<!-- endbower -->/gmi, ''))
+      .pipe(replace(/<!-- bower:js -->(\n^<script.*)*\n<!-- endbower -->/gmi, ''))
+      // injecting minified files
+      .pipe(
+        inject(
+          gulp.src([
+            options.static + 'js/vendor/xosOpenVPNDashboardVendor.js',
+            options.static + 'js/xosOpenVPNDashboard.js',
+            options.static + 'css/xosOpenVPNDashboard.css'
+          ]),
+          {ignorePath: '/../../../xos/core/xoslib'}
+        )
+      )
+      .pipe(rename('xosOpenVPNDashboard.html'))
+      .pipe(gulp.dest(options.dashboards));
+  });
+
+  // minify vendor js files
+  gulp.task('wiredep', function(){
+    var bowerDeps = wiredep().js;
+    if(!bowerDeps){
+      return;
+    }
+
+    // remove angular (it's already loaded)
+    _.remove(bowerDeps, function(dep){
+      return dep.indexOf('angular/angular.js') !== -1;
+    });
+
+    return gulp.src(bowerDeps)
+      .pipe(concat('xosOpenVPNDashboardVendor.js'))
+      .pipe(uglify())
+      .pipe(gulp.dest(options.static + 'js/vendor/'));
+  });
+
+  gulp.task('lint', function () {
+    return gulp.src(['src/js/**/*.js'])
+      .pipe(eslint())
+      .pipe(eslint.format())
+      .pipe(eslint.failAfterError());
+  });
+
+  gulp.task('wait', function (cb) {
+    // setTimeout could be any async task
+    setTimeout(function () {
+      cb();
+    }, 1000);
+  });
+
+  gulp.task('build', function() {
+    runSequence(
+      'clean',
+      'sass',
+      'templates',
+      'babel',
+      'scripts',
+      'wiredep',
+      'css',
+      'copyCss',
+      'copyHtml',
+      'cleanTmp'
+    );
+  });
+};
\ No newline at end of file
diff --git a/views/ngXosViews/openVPNDashboard/gulp/server.js b/views/ngXosViews/openVPNDashboard/gulp/server.js
new file mode 100644
index 0000000..1e40a34
--- /dev/null
+++ b/views/ngXosViews/openVPNDashboard/gulp/server.js
@@ -0,0 +1,170 @@
+'use strict';
+
+var gulp = require('gulp');
+var browserSync = require('browser-sync').create();
+var inject = require('gulp-inject');
+var runSequence = require('run-sequence');
+var angularFilesort = require('gulp-angular-filesort');
+var babel = require('gulp-babel');
+var wiredep = require('wiredep').stream;
+var httpProxy = require('http-proxy');
+var del = require('del');
+var sass = require('gulp-sass');
+var fs = require('fs');
+var path = require('path');
+
+const environment = process.env.NODE_ENV;
+
+if(!fs.existsSync(path.join(__dirname, `../../../env/${environment || 'default'}.js`))){
+  if(!environment){
+    throw new Error('You should define a default.js config in /views/env folder.');
+  }
+  else{
+    throw new Error(`Since you are loading a custom environment, you should define a ${environment}.js config in /views/env folder.`);
+  }
+}
+
+var conf = require(path.join(__dirname, `../../../env/${environment || 'default'}.js`));
+
+var proxy = httpProxy.createProxyServer({
+  target: conf.host
+});
+
+
+proxy.on('error', function(error, req, res) {
+  res.writeHead(500, {
+    'Content-Type': 'text/plain'
+  });
+
+  console.error('[Proxy]', error);
+});
+
+module.exports = function(options){
+
+  gulp.task('browser', function() {
+    browserSync.init({
+      startPath: '#/',
+      snippetOptions: {
+        rule: {
+          match: /<!-- browserSync -->/i
+        }
+      },
+      server: {
+        baseDir: options.src,
+        routes: {
+          '/xos/core/xoslib/static/js/vendor': options.helpers,
+          '/xos/core/static': options.static + '../../static/'
+        },
+        middleware: function(req, res, next){
+          if(
+            req.url.indexOf('/api/') !== -1
+          ){
+            if(conf.xoscsrftoken && conf.xossessionid){
+              req.headers.cookie = `xoscsrftoken=${conf.xoscsrftoken}; xossessionid=${conf.xossessionid}`;
+              req.headers['x-csrftoken'] = conf.xoscsrftoken;
+            }
+            proxy.web(req, res);
+          }
+          else{
+            next();
+          }
+        }
+      }
+    });
+
+    gulp.watch(options.src + 'js/**/*.js', ['js-watch']);
+    gulp.watch(options.src + 'vendor/**/*.js', ['bower'], function(){
+      browserSync.reload();
+    });
+    gulp.watch(options.src + '**/*.html', function(){
+      browserSync.reload();
+    });
+    gulp.watch(options.css + '**/*.css', function(){
+      browserSync.reload();
+    });
+    gulp.watch(`${options.sass}/**/*.scss`, ['sass'], function(){
+      browserSync.reload();
+    });
+
+    gulp.watch([
+      options.helpers + 'ngXosHelpers.js',
+      options.static + '../../static/xosNgLib.css'
+    ], function(){
+      browserSync.reload();
+    });
+  });
+
+  // compile sass
+  gulp.task('sass', function () {
+    return gulp.src(`${options.sass}/**/*.scss`)
+      .pipe(sass().on('error', sass.logError))
+      .pipe(gulp.dest(options.css));
+  });
+
+  // transpile js with sourceMaps
+  gulp.task('babel', function(){
+    return gulp.src(options.scripts + '**/*.js')
+      .pipe(babel({sourceMaps: true}))
+      .pipe(gulp.dest(options.tmp));
+  });
+
+  // inject scripts
+  gulp.task('injectScript', ['cleanTmp', 'babel'], function(){
+    return gulp.src(options.src + 'index.html')
+      .pipe(
+        inject(
+          gulp.src([
+            options.tmp + '**/*.js',
+            options.helpers + 'ngXosHelpers.js'
+          ])
+          .pipe(angularFilesort()),
+          {
+            ignorePath: [options.src, '/../../ngXosLib']
+          }
+        )
+      )
+      .pipe(gulp.dest(options.src));
+  });
+
+  // inject CSS
+  gulp.task('injectCss', function(){
+    return gulp.src(options.src + 'index.html')
+      .pipe(
+        inject(
+          gulp.src([
+            options.src + 'css/*.css',
+            options.static + '../../static/xosNgLib.css'
+          ]),
+          {
+            ignorePath: [options.src]
+          }
+          )
+        )
+      .pipe(gulp.dest(options.src));
+  });
+
+  // inject bower dependencies with wiredep
+  gulp.task('bower', function () {
+    return gulp.src(options.src + 'index.html')
+    .pipe(wiredep({devDependencies: true}))
+    .pipe(gulp.dest(options.src));
+  });
+
+  gulp.task('js-watch', ['injectScript'], function(){
+    browserSync.reload();
+  });
+
+  gulp.task('cleanTmp', function(){
+    return del([options.tmp + '**/*']);
+  });
+
+  gulp.task('serve', function() {
+    runSequence(
+      'sass',
+      'bower',
+      'injectScript',
+      'injectCss',
+      ['browser']
+    );
+  });
+};
diff --git a/views/ngXosViews/openVPNDashboard/gulpfile.js b/views/ngXosViews/openVPNDashboard/gulpfile.js
new file mode 100644
index 0000000..08df554
--- /dev/null
+++ b/views/ngXosViews/openVPNDashboard/gulpfile.js
@@ -0,0 +1,26 @@
+'use strict';
+
+var gulp = require('gulp');
+var wrench = require('wrench');
+
+var options = {
+  src: 'src/',
+  css: 'src/css/',
+  sass: 'src/sass/',
+  scripts: 'src/js/',
+  tmp: 'src/.tmp',
+  dist: 'dist/',
+  api: '../../ngXosLib/api/',
+  helpers: '../../../xos/core/xoslib/static/js/vendor/',
+  static: '../../../xos/core/xoslib/static/', // this is the django static folder
+  dashboards: '../../../xos/core/xoslib/dashboards/' // this is the django html folder
+};
+
+wrench.readdirSyncRecursive('./gulp')
+.map(function(file) {
+  require('./gulp/' + file)(options);
+});
+
+gulp.task('default', function () {
+  gulp.start('build');
+});
diff --git a/views/ngXosViews/openVPNDashboard/karma.conf.js b/views/ngXosViews/openVPNDashboard/karma.conf.js
new file mode 100644
index 0000000..4123be9
--- /dev/null
+++ b/views/ngXosViews/openVPNDashboard/karma.conf.js
@@ -0,0 +1,88 @@
+// Karma configuration
+// Generated on Tue Oct 06 2015 09:27:10 GMT+0000 (UTC)
+
+/* eslint indent: [2,2], quotes: [2, "single"]*/
+
+/*eslint-disable*/
+var wiredep = require('wiredep');
+var path = require('path');
+
+var bowerComponents = wiredep( {devDependencies: true} )[ 'js' ].map(function( file ){
+  return path.relative(process.cwd(), file);
+});
+
+module.exports = function(config) {
+/*eslint-enable*/
+  config.set({
+
+    // base path that will be used to resolve all patterns (eg. files, exclude)
+    basePath: '',
+
+
+    // frameworks to use
+    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
+    frameworks: ['jasmine'],
+
+
+    // list of files / patterns to load in the browser
+    files: bowerComponents.concat([
+      '../../../xos/core/xoslib/static/js/vendor/ngXosVendor.js',
+      '../../../xos/core/xoslib/static/js/vendor/ngXosHelpers.js',
+      'src/js/**/*.js',
+      'spec/**/*.mock.js',
+      'spec/**/*.test.js',
+      'src/**/*.html'
+    ]),
+
+
+    // list of files to exclude
+    exclude: [
+    ],
+
+
+    // preprocess matching files before serving them to the browser
+    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
+    preprocessors: {
+      'src/js/**/*.js': ['babel'],
+      'spec/**/*.test.js': ['babel'],
+      'src/**/*.html': ['ng-html2js']
+    },
+
+    ngHtml2JsPreprocessor: {
+      stripPrefix: 'src/', //strip the src path from template url (http://stackoverflow.com/questions/22869668/karma-unexpected-request-when-testing-angular-directive-even-with-ng-html2js)
+      moduleName: 'templates' // define the template module name
+    },
+
+    // test results reporter to use
+    // possible values: 'dots', 'progress'
+    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
+    reporters: ['mocha'],
+
+
+    // web server port
+    port: 9876,
+
+
+    // enable / disable colors in the output (reporters and logs)
+    colors: true,
+
+
+    // level of logging
+    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+    logLevel: config.LOG_INFO,
+
+
+    // enable / disable watching file and executing tests whenever any file changes
+    autoWatch: true,
+
+
+    // start these browsers
+    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
+    browsers: ['PhantomJS'],
+
+
+    // Continuous Integration mode
+    // if true, Karma captures browsers, runs the tests and exits
+    singleRun: false
+  });
+};
diff --git a/views/ngXosViews/openVPNDashboard/package.json b/views/ngXosViews/openVPNDashboard/package.json
new file mode 100644
index 0000000..093c76d
--- /dev/null
+++ b/views/ngXosViews/openVPNDashboard/package.json
@@ -0,0 +1,63 @@
+{
+  "name": "xos-openVPNDashboard",
+  "version": "1.0.0",
+  "description": "Angular Application for XOS, created with generator-xos",
+  "scripts": {
+    "prestart": "npm install && bower install",
+    "start": "gulp serve",
+    "prebuild": "npm install && bower install",
+    "build": "gulp",
+    "test": "karma start",
+    "test:ci": "karma start --single-run",
+    "lint": "eslint src/js/"
+  },
+  "keywords": [
+    "XOS",
+    "Angular",
+    "XOSlib"
+  ],
+  "author": "Matteo Scandolo",
+  "license": "MIT",
+  "dependencies": {},
+  "devDependencies": {
+    "autoprefixer": "^6.3.3",
+    "browser-sync": "^2.9.11",
+    "css-mqpacker": "^4.0.0",
+    "csswring": "^4.2.1",
+    "del": "^2.0.2",
+    "easy-mocker": "^1.2.0",
+    "eslint": "^1.8.0",
+    "eslint-plugin-angular": "linkmesrl/eslint-plugin-angular",
+    "gulp": "^3.9.0",
+    "gulp-angular-filesort": "^1.1.1",
+    "gulp-angular-templatecache": "^1.8.0",
+    "gulp-babel": "^5.3.0",
+    "gulp-concat": "^2.6.0",
+    "gulp-concat-util": "^0.5.5",
+    "gulp-eslint": "^1.0.0",
+    "gulp-inject": "^3.0.0",
+    "gulp-minify-html": "^1.0.4",
+    "gulp-ng-annotate": "^1.1.0",
+    "gulp-postcss": "^6.0.1",
+    "gulp-rename": "^1.2.2",
+    "gulp-replace": "^0.5.4",
+    "gulp-sass": "^2.2.0",
+    "gulp-uglify": "^1.4.2",
+    "http-proxy": "^1.12.0",
+    "ink-docstrap": "^0.5.2",
+    "jasmine-core": "~2.3.4",
+    "karma": "^0.13.14",
+    "karma-babel-preprocessor": "~5.2.2",
+    "karma-coverage": "^0.5.3",
+    "karma-jasmine": "~0.3.6",
+    "karma-mocha-reporter": "~1.1.1",
+    "karma-ng-html2js-preprocessor": "^0.2.0",
+    "karma-phantomjs-launcher": "~0.2.1",
+    "lodash": "^3.10.1",
+    "phantomjs": "^1.9.19",
+    "proxy-middleware": "^0.15.0",
+    "run-sequence": "^1.1.4",
+    "wiredep": "^3.0.0-beta",
+    "wrench": "^1.5.8"
+  }
+}
diff --git a/views/ngXosViews/openVPNDashboard/spec/sample.test.js b/views/ngXosViews/openVPNDashboard/spec/sample.test.js
new file mode 100644
index 0000000..522ce75
--- /dev/null
+++ b/views/ngXosViews/openVPNDashboard/spec/sample.test.js
@@ -0,0 +1,34 @@
+'use strict';
+
+describe('The User List', () => {
+  
+  var scope, element, isolatedScope, httpBackend;
+
+  beforeEach(module('xos.openVPNDashboard'));
+  beforeEach(module('templates'));
+
+  beforeEach(inject(function($httpBackend, $compile, $rootScope){
+    
+    httpBackend = $httpBackend;
+    // Setting up mock request
+    $httpBackend.expectGET('/api/tenant/openvpn/list/?no_hyperlinks=1').respond([
+      {
+        email: 'jermowery@email.arizona.edu',
+        firstname: 'Jeremy',
+        lastname: 'Mowery' 
+      }
+    ]);
+  
+    scope = $rootScope.$new();
+    element = angular.element('<vpn-list></vpn-list>');
+    $compile(element)(scope);
+    scope.$digest();
+    isolatedScope = element.isolateScope().vm;
+  }));
+
+  it('should load 1 vpn', () => {
+    httpBackend.flush();
+    expect(isolatedScope.vpns.length).toBe(1);
+  });
+
+});
\ No newline at end of file
diff --git a/views/ngXosViews/openVPNDashboard/src/css/main.css b/views/ngXosViews/openVPNDashboard/src/css/main.css
new file mode 100644
index 0000000..554a43a
--- /dev/null
+++ b/views/ngXosViews/openVPNDashboard/src/css/main.css
@@ -0,0 +1,10 @@
+#xosOpenVPNDashboard {
+  width: 70%;
+  margin: auto; }
+  #xosOpenVPNDashboard .vpn-row {
+    display: table-row; }
+  #xosOpenVPNDashboard .vpn-cell {
+    display: table-cell;
+    padding: 5px; }
+  #xosOpenVPNDashboard .vpn-header {
+    font-weight: bold; }
diff --git a/views/ngXosViews/openVPNDashboard/src/index.html b/views/ngXosViews/openVPNDashboard/src/index.html
new file mode 100644
index 0000000..8a97f14
--- /dev/null
+++ b/views/ngXosViews/openVPNDashboard/src/index.html
@@ -0,0 +1,32 @@
+<!-- browserSync -->
+<!-- bower:css -->
+<link rel="stylesheet" href="vendor/bootstrap-css/css/bootstrap.min.css" />
+<link rel="stylesheet" href="vendor/angular-chart.js/dist/angular-chart.css" />
+<!-- endbower --><!-- endcss -->
+<!-- inject:css -->
+<link rel="stylesheet" href="/css/main.css">
+<link rel="stylesheet" href="/../../../xos/core/static/xosNgLib.css">
+<!-- endinject -->
+
+<div ng-app="xos.openVPNDashboard" id="xosOpenVPNDashboard">
+    <div ui-view></div>
+</div>
+
+<!-- bower:js -->
+<script src="vendor/jquery/dist/jquery.js"></script>
+<script src="vendor/angular/angular.js"></script>
+<script src="vendor/angular-mocks/angular-mocks.js"></script>
+<script src="vendor/angular-ui-router/release/angular-ui-router.js"></script>
+<script src="vendor/angular-cookies/angular-cookies.js"></script>
+<script src="vendor/angular-animate/angular-animate.js"></script>
+<script src="vendor/angular-resource/angular-resource.js"></script>
+<script src="vendor/lodash/lodash.js"></script>
+<script src="vendor/bootstrap-css/js/bootstrap.min.js"></script>
+<script src="vendor/Chart.js/Chart.js"></script>
+<script src="vendor/angular-chart.js/dist/angular-chart.js"></script>
+<script src="vendor/d3/d3.js"></script>
+<!-- endbower --><!-- endjs -->
+<!-- inject:js -->
+<script src="/../../../xos/core/xoslib/static/js/vendor/ngXosHelpers.js"></script>
+<script src="/.tmp/main.js"></script>
+<!-- endinject -->
diff --git a/views/ngXosViews/openVPNDashboard/src/js/main.js b/views/ngXosViews/openVPNDashboard/src/js/main.js
new file mode 100644
index 0000000..6f6bce2
--- /dev/null
+++ b/views/ngXosViews/openVPNDashboard/src/js/main.js
@@ -0,0 +1,60 @@
+'use strict';
+
+angular.module('xos.openVPNDashboard', [
+  'ngResource',
+  'ngCookies',
+  'ui.router',
+  'xos.helpers'
+])
+.config(($stateProvider) => {
+  $stateProvider
+  .state('openVPNList', {
+    url: '/',
+    template: '<vpn-list></vpn-list>'
+  });
+})
+.config(($compileProvider) => {
+  $compileProvider.aHrefSanitizationWhitelist(
+    /^\s*(https?|ftp|mailto|tel|file|blob):/);
+})
+.service('Vpn', function($http, $q){
+
+  this.getOpenVpnTenants = () => {
+    let deferred = $q.defer();
+
+    $http.get('/api/tenant/openvpn/list/')
+    .then((res) => {
+      deferred.resolve(res.data)
+    })
+    .catch((e) => {
+      deferred.reject(e);
+    });
+
+    return deferred.promise;
+  }
+})
+.config(function($httpProvider){
+  $httpProvider.interceptors.push('NoHyperlinks');
+})
+.directive('vpnList', function(){
+  return {
+    restrict: 'E',
+    scope: {},
+    bindToController: true,
+    controllerAs: 'vm',
+    templateUrl: 'templates/openvpn-list.tpl.html',
+    controller: function(Vpn){
+      Vpn.getOpenVpnTenants()
+      .then((vpns) => {
+        this.vpns = vpns;
+        for (var i = 0; i < this.vpns.length; i++) {
+          var blob = new Blob([this.vpns[i].script_text], {type: 'text/plain'});
+          this.vpns[i].script_text = (window.URL || window.webkitURL).createObjectURL( blob );
+        }
+      })
+      .catch((e) => {
+        throw new Error(e);
+      });
+    }
+  };
+});
diff --git a/views/ngXosViews/openVPNDashboard/src/sass/main.scss b/views/ngXosViews/openVPNDashboard/src/sass/main.scss
new file mode 100644
index 0000000..96b8ce5
--- /dev/null
+++ b/views/ngXosViews/openVPNDashboard/src/sass/main.scss
@@ -0,0 +1,16 @@
+@import '../../../../style/sass/lib/_variables.scss';
+
+#xosOpenVPNDashboard {
+  width: 70%;
+  margin: auto;
+  .vpn-row {
+      display: table-row;
+  }
+  .vpn-cell {
+      display: table-cell;
+      padding: 5px;
+  }
+  .vpn-header {
+      font-weight: bold;
+  }
+}
\ No newline at end of file
diff --git a/views/ngXosViews/openVPNDashboard/src/templates/openvpn-list.tpl.html b/views/ngXosViews/openVPNDashboard/src/templates/openvpn-list.tpl.html
new file mode 100644
index 0000000..0c7635f
--- /dev/null
+++ b/views/ngXosViews/openVPNDashboard/src/templates/openvpn-list.tpl.html
@@ -0,0 +1,19 @@
+<div style="display: table;">
+  <div class="vpn-row">
+    <h1 class="vpn-cell">VPN List</h1>
+  </div>
+  <div class="vpn-row">
+    <div class="vpn-cell vpn-header">ID</div>
+    <div class="vpn-cell vpn-header">VPN Network</div>
+    <div class="vpn-cell vpn-header">VPN Subnet</div>
+    <div class="vpn-cell vpn-header">Script Link</div>
+  </div>
+  <div class="vpn-row" ng-repeat="vpn in vm.vpns">
+    <div class="vpn-cell">{{ vpn.id }}</div>
+    <div class="vpn-cell">{{ vpn.server_network }}</div>
+    <div class="vpn-cell">{{ vpn.vpn_subnet }}</div>
+    <div class="vpn-cell">
+      <a download="connect-{{ vpn.id }}.vpn" ng-href="{{ vpn.script_text }}">Script</a>
+    </div>
+  </div>
+</div>
diff --git a/views/ngXosViews/openVPNDashboard/src/templates/users-list.tpl.html b/views/ngXosViews/openVPNDashboard/src/templates/users-list.tpl.html
new file mode 100644
index 0000000..1fee0e2
--- /dev/null
+++ b/views/ngXosViews/openVPNDashboard/src/templates/users-list.tpl.html
@@ -0,0 +1 @@
+<xos-table config="vm.tableConfig" data="vm.users"></xos-table>
\ No newline at end of file
diff --git a/views/ngXosViews/serviceGrid/.bowerrc b/views/ngXosViews/serviceGrid/.bowerrc
new file mode 100644
index 0000000..e491038
--- /dev/null
+++ b/views/ngXosViews/serviceGrid/.bowerrc
@@ -0,0 +1,3 @@
+{
+  "directory": "src/vendor/"
+}
\ No newline at end of file
diff --git a/views/ngXosViews/serviceGrid/.eslintrc b/views/ngXosViews/serviceGrid/.eslintrc
new file mode 100644
index 0000000..c852748
--- /dev/null
+++ b/views/ngXosViews/serviceGrid/.eslintrc
@@ -0,0 +1,42 @@
+{
+    "ecmaFeatures": {
+        "blockBindings": true,
+        "forOf": true,
+        "destructuring": true,
+        "arrowFunctions": true,
+        "templateStrings": true
+    },
+    "env": { 
+        "browser": true,
+        "node": true,
+        "es6": true
+    },
+    "plugins": [
+        //"angular"
+    ],
+    "rules": {
+        "quotes": [2, "single"],
+        "camelcase": [1, {"properties": "always"}],
+        "no-underscore-dangle": 1,
+        "eqeqeq": [2, "smart"],
+        "no-alert": 1,
+        "key-spacing": [1, { "beforeColon": false, "afterColon": true }],
+        "indent": [2, 2],
+        "no-irregular-whitespace": 1,
+        "eol-last": 0,
+        "max-nested-callbacks": [2, 4],
+        "comma-spacing": [1, {"before": false, "after": true}],
+        "no-trailing-spaces": [1, { skipBlankLines: true }],
+        "no-unused-vars": [1, {"vars": "all", "args": "after-used"}],
+        "new-cap": 0,
+
+        //"angular/ng_module_name": [2, '/^xos\.*[a-z]*$/'],
+        //"angular/ng_controller_name": [2, '/^[a-z].*Ctrl$/'],
+        //"angular/ng_service_name": [2, '/^[A-Z].*Service$/'],
+        //"angular/ng_directive_name": [2, '/^[a-z]+[[A-Z].*]*$/'],
+        //"angular/ng_di": [0, "function or array"]
+    },
+    "globals" :{
+        "angular": true
+    } 
+}
\ No newline at end of file
diff --git a/views/ngXosViews/serviceGrid/.gitignore b/views/ngXosViews/serviceGrid/.gitignore
new file mode 100644
index 0000000..567aee4
--- /dev/null
+++ b/views/ngXosViews/serviceGrid/.gitignore
@@ -0,0 +1,6 @@
+dist/
+src/vendor
+.tmp
+node_modules
+npm-debug.log
+dist/
\ No newline at end of file
diff --git a/views/ngXosViews/serviceGrid/bower.json b/views/ngXosViews/serviceGrid/bower.json
new file mode 100644
index 0000000..bae4e4d
--- /dev/null
+++ b/views/ngXosViews/serviceGrid/bower.json
@@ -0,0 +1,32 @@
+{
+  "name": "xos-serviceGrid",
+  "version": "0.0.0",
+  "authors": [
+    "Matteo Scandolo <teo@onlab.us>"
+  ],
+  "description": "The serviceGrid view",
+  "license": "MIT",
+  "ignore": [
+    "**/.*",
+    "node_modules",
+    "bower_components",
+    "static/js/vendor/",
+    "test",
+    "tests"
+  ],
+  "dependencies": {
+  },
+  "devDependencies": {
+    "jquery": "2.1.4",
+    "angular-mocks": "1.4.7",
+    "angular": "1.4.7",
+    "angular-ui-router": "0.2.15",
+    "angular-cookies": "1.4.7",
+    "angular-animate": "1.4.7",
+    "angular-resource": "1.4.7",
+    "lodash": "~4.11.1",
+    "bootstrap-css": "3.3.6",
+    "angular-chart.js": "~0.10.2",
+    "d3": "~3.5.17"
+  }
+}
diff --git a/views/ngXosViews/serviceGrid/gulp/build.js b/views/ngXosViews/serviceGrid/gulp/build.js
new file mode 100644
index 0000000..2916028
--- /dev/null
+++ b/views/ngXosViews/serviceGrid/gulp/build.js
@@ -0,0 +1,164 @@
+'use strict';
+
+// BUILD
+//
+// The only purpose of this gulpfile is to build a XOS view and copy the correct files into
+// .html => dashboards
+// .js (minified and concat) => static/js
+//
+// The template are parsed and added to js with angular $templateCache
+
+var gulp = require('gulp');
+var ngAnnotate = require('gulp-ng-annotate');
+var uglify = require('gulp-uglify');
+var templateCache = require('gulp-angular-templatecache');
+var runSequence = require('run-sequence');
+var concat = require('gulp-concat-util');
+var del = require('del');
+var wiredep = require('wiredep');
+var angularFilesort = require('gulp-angular-filesort');
+var _ = require('lodash');
+var eslint = require('gulp-eslint');
+var inject = require('gulp-inject');
+var rename = require('gulp-rename');
+var replace = require('gulp-replace');
+var postcss = require('gulp-postcss');
+var autoprefixer = require('autoprefixer');
+var mqpacker = require('css-mqpacker');
+var csswring = require('csswring');
+
+const TEMPLATE_FOOTER = `
+angular.module('xos.serviceGrid')
+.run(['$location', function(a){
+  a.path('/');
+}])
+`
+
+module.exports = function(options){
+  
+  // delete previous builded file
+  gulp.task('clean', function(){
+    return del(
+      [
+        options.dashboards + 'xosServiceGrid.html',
+        options.static + 'css/xosServiceGrid.css'
+      ],
+      {force: true}
+    );
+  });
+
+  // minify css
+  gulp.task('css', function () {
+    var processors = [
+      autoprefixer({browsers: ['last 1 version']}),
+      mqpacker,
+      csswring
+    ];
+
+    gulp.src([
+      `${options.css}**/*.css`,
+      `!${options.css}dev.css`
+    ])
+    .pipe(postcss(processors))
+    .pipe(gulp.dest(options.tmp + '/css/'));
+  });
+
+  // copy css in correct folder
+  gulp.task('copyCss', ['wait'], function(){
+    return gulp.src([`${options.tmp}/css/*.css`])
+    .pipe(concat('xosServiceGrid.css'))
+    .pipe(gulp.dest(options.static + 'css/'))
+  });
+
+  // compile and minify scripts
+  gulp.task('scripts', function() {
+    return gulp.src([
+      options.tmp + '**/*.js'
+    ])
+    .pipe(ngAnnotate())
+    .pipe(angularFilesort())
+    .pipe(concat('xosServiceGrid.js'))
+    .pipe(concat.header('//Autogenerated, do not edit!!!\n'))
+    .pipe(concat.footer(TEMPLATE_FOOTER))
+    .pipe(uglify())
+    .pipe(gulp.dest(options.static + 'js/'));
+  });
+
+  // set templates in cache
+  gulp.task('templates', function(){
+    return gulp.src('./src/templates/*.html')
+      .pipe(templateCache({
+        module: 'xos.serviceGrid',
+        root: 'templates/'
+      }))
+      .pipe(gulp.dest(options.tmp));
+  });
+
+  // copy html index to Django Folder
+  gulp.task('copyHtml', function(){
+    return gulp.src(options.src + 'index.html')
+      // remove dev dependencies from html
+      .pipe(replace(/<!-- bower:css -->(\n^<link.*)*\n<!-- endbower -->/gmi, ''))
+      .pipe(replace(/<!-- bower:js -->(\n^<script.*)*\n<!-- endbower -->/gmi, ''))
+      // injecting minified files
+      .pipe(
+        inject(
+          gulp.src([
+            options.static + 'js/vendor/xosServiceGridVendor.js',
+            options.static + 'js/xosServiceGrid.js',
+            options.static + 'css/xosServiceGrid.css'
+          ]),
+          {ignorePath: '/../../../xos/core/xoslib'}
+        )
+      )
+      .pipe(rename('xosServiceGrid.html'))
+      .pipe(gulp.dest(options.dashboards));
+  });
+
+  // minify vendor js files
+  gulp.task('wiredep', function(){
+    var bowerDeps = wiredep().js;
+    if(!bowerDeps){
+      return;
+    }
+
+    // remove angular (it's already loaded)
+    _.remove(bowerDeps, function(dep){
+      return dep.indexOf('angular/angular.js') !== -1;
+    });
+
+    return gulp.src(bowerDeps)
+      .pipe(concat('xosServiceGridVendor.js'))
+      .pipe(uglify())
+      .pipe(gulp.dest(options.static + 'js/vendor/'));
+  });
+
+  gulp.task('lint', function () {
+    return gulp.src(['src/js/**/*.js'])
+      .pipe(eslint())
+      .pipe(eslint.format())
+      .pipe(eslint.failAfterError());
+  });
+
+  gulp.task('wait', function (cb) {
+    // setTimeout could be any async task
+    setTimeout(function () {
+      cb();
+    }, 1000);
+  });
+
+  gulp.task('build', function() {
+    runSequence(
+      'clean',
+      'sass',
+      'templates',
+      'babel',
+      'scripts',
+      'wiredep',
+      'css',
+      'copyCss',
+      'copyHtml',
+      'cleanTmp'
+    );
+  });
+};
\ No newline at end of file
diff --git a/views/ngXosViews/serviceGrid/gulp/server.js b/views/ngXosViews/serviceGrid/gulp/server.js
new file mode 100644
index 0000000..1e40a34
--- /dev/null
+++ b/views/ngXosViews/serviceGrid/gulp/server.js
@@ -0,0 +1,170 @@
+'use strict';
+
+var gulp = require('gulp');
+var browserSync = require('browser-sync').create();
+var inject = require('gulp-inject');
+var runSequence = require('run-sequence');
+var angularFilesort = require('gulp-angular-filesort');
+var babel = require('gulp-babel');
+var wiredep = require('wiredep').stream;
+var httpProxy = require('http-proxy');
+var del = require('del');
+var sass = require('gulp-sass');
+var fs = require('fs');
+var path = require('path');
+
+const environment = process.env.NODE_ENV;
+
+if(!fs.existsSync(path.join(__dirname, `../../../env/${environment || 'default'}.js`))){
+  if(!environment){
+    throw new Error('You should define a default.js config in /views/env folder.');
+  }
+  else{
+    throw new Error(`Since you are loading a custom environment, you should define a ${environment}.js config in /views/env folder.`);
+  }
+}
+
+var conf = require(path.join(__dirname, `../../../env/${environment || 'default'}.js`));
+
+var proxy = httpProxy.createProxyServer({
+  target: conf.host
+});
+
+
+proxy.on('error', function(error, req, res) {
+  res.writeHead(500, {
+    'Content-Type': 'text/plain'
+  });
+
+  console.error('[Proxy]', error);
+});
+
+module.exports = function(options){
+
+  gulp.task('browser', function() {
+    browserSync.init({
+      startPath: '#/',
+      snippetOptions: {
+        rule: {
+          match: /<!-- browserSync -->/i
+        }
+      },
+      server: {
+        baseDir: options.src,
+        routes: {
+          '/xos/core/xoslib/static/js/vendor': options.helpers,
+          '/xos/core/static': options.static + '../../static/'
+        },
+        middleware: function(req, res, next){
+          if(
+            req.url.indexOf('/api/') !== -1
+          ){
+            if(conf.xoscsrftoken && conf.xossessionid){
+              req.headers.cookie = `xoscsrftoken=${conf.xoscsrftoken}; xossessionid=${conf.xossessionid}`;
+              req.headers['x-csrftoken'] = conf.xoscsrftoken;
+            }
+            proxy.web(req, res);
+          }
+          else{
+            next();
+          }
+        }
+      }
+    });
+
+    gulp.watch(options.src + 'js/**/*.js', ['js-watch']);
+    gulp.watch(options.src + 'vendor/**/*.js', ['bower'], function(){
+      browserSync.reload();
+    });
+    gulp.watch(options.src + '**/*.html', function(){
+      browserSync.reload();
+    });
+    gulp.watch(options.css + '**/*.css', function(){
+      browserSync.reload();
+    });
+    gulp.watch(`${options.sass}/**/*.scss`, ['sass'], function(){
+      browserSync.reload();
+    });
+
+    gulp.watch([
+      options.helpers + 'ngXosHelpers.js',
+      options.static + '../../static/xosNgLib.css'
+    ], function(){
+      browserSync.reload();
+    });
+  });
+
+  // compile sass
+  gulp.task('sass', function () {
+    return gulp.src(`${options.sass}/**/*.scss`)
+      .pipe(sass().on('error', sass.logError))
+      .pipe(gulp.dest(options.css));
+  });
+
+  // transpile js with sourceMaps
+  gulp.task('babel', function(){
+    return gulp.src(options.scripts + '**/*.js')
+      .pipe(babel({sourceMaps: true}))
+      .pipe(gulp.dest(options.tmp));
+  });
+
+  // inject scripts
+  gulp.task('injectScript', ['cleanTmp', 'babel'], function(){
+    return gulp.src(options.src + 'index.html')
+      .pipe(
+        inject(
+          gulp.src([
+            options.tmp + '**/*.js',
+            options.helpers + 'ngXosHelpers.js'
+          ])
+          .pipe(angularFilesort()),
+          {
+            ignorePath: [options.src, '/../../ngXosLib']
+          }
+        )
+      )
+      .pipe(gulp.dest(options.src));
+  });
+
+  // inject CSS
+  gulp.task('injectCss', function(){
+    return gulp.src(options.src + 'index.html')
+      .pipe(
+        inject(
+          gulp.src([
+            options.src + 'css/*.css',
+            options.static + '../../static/xosNgLib.css'
+          ]),
+          {
+            ignorePath: [options.src]
+          }
+          )
+        )
+      .pipe(gulp.dest(options.src));
+  });
+
+  // inject bower dependencies with wiredep
+  gulp.task('bower', function () {
+    return gulp.src(options.src + 'index.html')
+    .pipe(wiredep({devDependencies: true}))
+    .pipe(gulp.dest(options.src));
+  });
+
+  gulp.task('js-watch', ['injectScript'], function(){
+    browserSync.reload();
+  });
+
+  gulp.task('cleanTmp', function(){
+    return del([options.tmp + '**/*']);
+  });
+
+  gulp.task('serve', function() {
+    runSequence(
+      'sass',
+      'bower',
+      'injectScript',
+      'injectCss',
+      ['browser']
+    );
+  });
+};
diff --git a/views/ngXosViews/serviceGrid/gulpfile.js b/views/ngXosViews/serviceGrid/gulpfile.js
new file mode 100644
index 0000000..08df554
--- /dev/null
+++ b/views/ngXosViews/serviceGrid/gulpfile.js
@@ -0,0 +1,26 @@
+'use strict';
+
+var gulp = require('gulp');
+var wrench = require('wrench');
+
+var options = {
+  src: 'src/',
+  css: 'src/css/',
+  sass: 'src/sass/',
+  scripts: 'src/js/',
+  tmp: 'src/.tmp',
+  dist: 'dist/',
+  api: '../../ngXosLib/api/',
+  helpers: '../../../xos/core/xoslib/static/js/vendor/',
+  static: '../../../xos/core/xoslib/static/', // this is the django static folder
+  dashboards: '../../../xos/core/xoslib/dashboards/' // this is the django html folder
+};
+
+wrench.readdirSyncRecursive('./gulp')
+.map(function(file) {
+  require('./gulp/' + file)(options);
+});
+
+gulp.task('default', function () {
+  gulp.start('build');
+});
diff --git a/views/ngXosViews/serviceGrid/karma.conf.js b/views/ngXosViews/serviceGrid/karma.conf.js
new file mode 100644
index 0000000..4123be9
--- /dev/null
+++ b/views/ngXosViews/serviceGrid/karma.conf.js
@@ -0,0 +1,88 @@
+// Karma configuration
+// Generated on Tue Oct 06 2015 09:27:10 GMT+0000 (UTC)
+
+/* eslint indent: [2,2], quotes: [2, "single"]*/
+
+/*eslint-disable*/
+var wiredep = require('wiredep');
+var path = require('path');
+
+var bowerComponents = wiredep( {devDependencies: true} )[ 'js' ].map(function( file ){
+  return path.relative(process.cwd(), file);
+});
+
+module.exports = function(config) {
+/*eslint-enable*/
+  config.set({
+
+    // base path that will be used to resolve all patterns (eg. files, exclude)
+    basePath: '',
+
+
+    // frameworks to use
+    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
+    frameworks: ['jasmine'],
+
+
+    // list of files / patterns to load in the browser
+    files: bowerComponents.concat([
+      '../../../xos/core/xoslib/static/js/vendor/ngXosVendor.js',
+      '../../../xos/core/xoslib/static/js/vendor/ngXosHelpers.js',
+      'src/js/**/*.js',
+      'spec/**/*.mock.js',
+      'spec/**/*.test.js',
+      'src/**/*.html'
+    ]),
+
+
+    // list of files to exclude
+    exclude: [
+    ],
+
+
+    // preprocess matching files before serving them to the browser
+    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
+    preprocessors: {
+      'src/js/**/*.js': ['babel'],
+      'spec/**/*.test.js': ['babel'],
+      'src/**/*.html': ['ng-html2js']
+    },
+
+    ngHtml2JsPreprocessor: {
+      stripPrefix: 'src/', //strip the src path from template url (http://stackoverflow.com/questions/22869668/karma-unexpected-request-when-testing-angular-directive-even-with-ng-html2js)
+      moduleName: 'templates' // define the template module name
+    },
+
+    // test results reporter to use
+    // possible values: 'dots', 'progress'
+    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
+    reporters: ['mocha'],
+
+
+    // web server port
+    port: 9876,
+
+
+    // enable / disable colors in the output (reporters and logs)
+    colors: true,
+
+
+    // level of logging
+    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+    logLevel: config.LOG_INFO,
+
+
+    // enable / disable watching file and executing tests whenever any file changes
+    autoWatch: true,
+
+
+    // start these browsers
+    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
+    browsers: ['PhantomJS'],
+
+
+    // Continuous Integration mode
+    // if true, Karma captures browsers, runs the tests and exits
+    singleRun: false
+  });
+};
diff --git a/views/ngXosViews/serviceGrid/package.json b/views/ngXosViews/serviceGrid/package.json
new file mode 100644
index 0000000..c33c615
--- /dev/null
+++ b/views/ngXosViews/serviceGrid/package.json
@@ -0,0 +1,63 @@
+{
+  "name": "xos-serviceGrid",
+  "version": "1.0.0",
+  "description": "Angular Application for XOS, created with generator-xos",
+  "scripts": {
+    "prestart": "npm install && bower install",
+    "start": "gulp serve",
+    "prebuild": "npm install && bower install",
+    "build": "gulp",
+    "test": "karma start",
+    "test:ci": "karma start --single-run",
+    "lint": "eslint src/js/"
+  },
+  "keywords": [
+    "XOS",
+    "Angular",
+    "XOSlib"
+  ],
+  "author": "Matteo Scandolo",
+  "license": "MIT",
+  "dependencies": {},
+  "devDependencies": {
+    "autoprefixer": "^6.3.3",
+    "browser-sync": "^2.9.11",
+    "css-mqpacker": "^4.0.0",
+    "csswring": "^4.2.1",
+    "del": "^2.0.2",
+    "easy-mocker": "^1.2.0",
+    "eslint": "^1.8.0",
+    "eslint-plugin-angular": "linkmesrl/eslint-plugin-angular",
+    "gulp": "^3.9.0",
+    "gulp-angular-filesort": "^1.1.1",
+    "gulp-angular-templatecache": "^1.8.0",
+    "gulp-babel": "^5.3.0",
+    "gulp-concat": "^2.6.0",
+    "gulp-concat-util": "^0.5.5",
+    "gulp-eslint": "^1.0.0",
+    "gulp-inject": "^3.0.0",
+    "gulp-minify-html": "^1.0.4",
+    "gulp-ng-annotate": "^1.1.0",
+    "gulp-postcss": "^6.0.1",
+    "gulp-rename": "^1.2.2",
+    "gulp-replace": "^0.5.4",
+    "gulp-sass": "^2.2.0",
+    "gulp-uglify": "^1.4.2",
+    "http-proxy": "^1.12.0",
+    "ink-docstrap": "^0.5.2",
+    "jasmine-core": "~2.3.4",
+    "karma": "^0.13.14",
+    "karma-babel-preprocessor": "~5.2.2",
+    "karma-coverage": "^0.5.3",
+    "karma-jasmine": "~0.3.6",
+    "karma-mocha-reporter": "~1.1.1",
+    "karma-ng-html2js-preprocessor": "^0.2.0",
+    "karma-phantomjs-launcher": "~0.2.1",
+    "lodash": "^3.10.1",
+    "phantomjs": "^1.9.19",
+    "proxy-middleware": "^0.15.0",
+    "run-sequence": "^1.1.4",
+    "wiredep": "^3.0.0-beta",
+    "wrench": "^1.5.8"
+  }
+}
diff --git a/views/ngXosViews/serviceGrid/spec/sample.test.js b/views/ngXosViews/serviceGrid/spec/sample.test.js
new file mode 100644
index 0000000..c026149
--- /dev/null
+++ b/views/ngXosViews/serviceGrid/spec/sample.test.js
@@ -0,0 +1,37 @@
+'use strict';
+
+describe('The User List', () => {
+  
+  var scope, element, isolatedScope, httpBackend;
+
+  beforeEach(module('xos.serviceGrid'));
+  beforeEach(module('templates'));
+
+  beforeEach(inject(function($httpBackend, $compile, $rootScope){
+    
+    httpBackend = $httpBackend;
+    // Setting up mock request
+    $httpBackend.expectGET('/api/core/users/?no_hyperlinks=1').respond([
+      {
+        email: 'teo@onlab.us',
+        firstname: 'Matteo',
+        lastname: 'Scandolo' 
+      }
+    ]);
+  
+    scope = $rootScope.$new();
+    element = angular.element('<users-list></users-list>');
+    $compile(element)(scope);
+    scope.$digest();
+    isolatedScope = element.isolateScope().vm;
+  }));
+
+  xit('should load 1 users', () => {
+    httpBackend.flush();
+    expect(isolatedScope.users.length).toBe(1);
+    expect(isolatedScope.users[0].email).toEqual('teo@onlab.us');
+    expect(isolatedScope.users[0].firstname).toEqual('Matteo');
+    expect(isolatedScope.users[0].lastname).toEqual('Scandolo');
+  });
+
+});
\ No newline at end of file
diff --git a/views/ngXosViews/serviceGrid/src/css/main.css b/views/ngXosViews/serviceGrid/src/css/main.css
new file mode 100644
index 0000000..ae13614
--- /dev/null
+++ b/views/ngXosViews/serviceGrid/src/css/main.css
@@ -0,0 +1,15 @@
+#xosServiceGrid service-graph {
+  display: block;
+  width: 100%;
+  height: 600px; }
+
+#xosServiceGrid .node {
+  stroke: #337ab7;
+  fill: white; }
+
+#xosServiceGrid .node.xos {
+  fill: #d9534f; }
+
+#xosServiceGrid .link {
+  stroke: black;
+  stroke-width: 2px; }
diff --git a/views/ngXosViews/serviceGrid/src/index.html b/views/ngXosViews/serviceGrid/src/index.html
new file mode 100644
index 0000000..d9e7fec
--- /dev/null
+++ b/views/ngXosViews/serviceGrid/src/index.html
@@ -0,0 +1,35 @@
+<!-- browserSync -->
+<!-- bower:css -->
+<link rel="stylesheet" href="vendor/bootstrap-css/css/bootstrap.min.css" />
+<link rel="stylesheet" href="vendor/angular-chart.js/dist/angular-chart.css" />
+<!-- endbower -->
+<!-- endcss -->
+<!-- inject:css -->
+<link rel="stylesheet" href="/css/main.css">
+<link rel="stylesheet" href="/../../../xos/core/static/xosNgLib.css">
+<!-- endinject -->
+
+<div ng-app="xos.serviceGrid" id="xosServiceGrid" class="container-fluid">
+  <div ui-view></div>
+</div>
+
+<!-- bower:js -->
+<script src="vendor/jquery/dist/jquery.js"></script>
+<script src="vendor/angular/angular.js"></script>
+<script src="vendor/angular-mocks/angular-mocks.js"></script>
+<script src="vendor/angular-ui-router/release/angular-ui-router.js"></script>
+<script src="vendor/angular-cookies/angular-cookies.js"></script>
+<script src="vendor/angular-animate/angular-animate.js"></script>
+<script src="vendor/angular-resource/angular-resource.js"></script>
+<script src="vendor/lodash/lodash.js"></script>
+<script src="vendor/bootstrap-css/js/bootstrap.min.js"></script>
+<script src="vendor/Chart.js/Chart.js"></script>
+<script src="vendor/angular-chart.js/dist/angular-chart.js"></script>
+<script src="vendor/d3/d3.js"></script>
+<!-- endbower -->
+<!-- endjs -->
+<!-- inject:js -->
+<script src="/../../../xos/core/xoslib/static/js/vendor/ngXosHelpers.js"></script>
+<script src="/.tmp/main.js"></script>
+<script src="/.tmp/service-graph.js"></script>
+<!-- endinject -->
\ No newline at end of file
diff --git a/views/ngXosViews/serviceGrid/src/js/main.js b/views/ngXosViews/serviceGrid/src/js/main.js
new file mode 100644
index 0000000..88a0f95
--- /dev/null
+++ b/views/ngXosViews/serviceGrid/src/js/main.js
@@ -0,0 +1,89 @@
+'use strict';
+
+angular.module('xos.serviceGrid', [
+  'ngResource',
+  'ngCookies',
+  'ui.router',
+  'xos.helpers'
+])
+.config(($stateProvider) => {
+  $stateProvider
+  .state('serviceGrid', {
+    url: '/',
+    template: '<service-grid></service-grid>'
+  })
+  .state('serviceGraph', {
+    url: '/graph',
+    template: '<service-graph></service-graph>'
+  });
+})
+.config(function($httpProvider){
+  $httpProvider.interceptors.push('NoHyperlinks');
+})
+.directive('serviceGrid', function(){
+  return {
+    restrict: 'E',
+    scope: {},
+    bindToController: true,
+    controllerAs: 'vm',
+    templateUrl: 'templates/service-grid.tpl.html',
+    controller: function(Services, _){
+
+      this.tableConfig = {
+        columns: [
+          {
+            label: 'Status',
+            prop: 'status',
+            type: 'icon',
+            formatter: item => {
+              let status = parseInt(item.backend_status.match(/^[0-9]/)[0]);
+              switch(status){
+              case 0:
+                return 'time';
+              case 1:
+                return 'ok';
+              case 2:
+                return 'remove';
+              }
+            }
+          },
+          {
+            label: 'Name',
+            prop: 'name',
+            link: item => `${item.view_url.replace(/\$[a-z]+\$/, item.id)}`
+          },
+          {
+            label: 'Kind',
+            prop: 'kind'
+          },
+          {
+            label: 'Enabled',
+            prop: 'enabled',
+            type: 'boolean'
+          }
+        ],
+        filter: 'field',
+        order: {
+          field: 'name'
+        }
+      };
+      
+      // retrieving user list
+      Services.query().$promise
+      .then((services) => {
+        this.services = _.map(services, s => {
+          // parse backend_status string in a boolean for display
+          // NOTE they are not boolean:
+          // - start with 0 = provisioning
+          // - start with 1 = good
+          // - start with 2 = error
+          s.status = parseInt(s.backend_status.match(/^[0-9]/)[0]) === 0 ? false : true;
+          return s;
+        })
+      })
+      .catch((e) => {
+        throw new Error(e);
+      });
+    }
+  };
+});
\ No newline at end of file
diff --git a/views/ngXosViews/serviceGrid/src/js/service-graph.js b/views/ngXosViews/serviceGrid/src/js/service-graph.js
new file mode 100644
index 0000000..51a711a
--- /dev/null
+++ b/views/ngXosViews/serviceGrid/src/js/service-graph.js
@@ -0,0 +1,180 @@
+(function () {
+  'use strict';
+
+  angular.module('xos.serviceGrid')
+  .directive('serviceGraph', function(){
+    return {
+      restrict: 'E',
+      scope: {},
+      bindToController: true,
+      controllerAs: 'vm',
+      templateUrl: 'templates/service-graph.tpl.html',
+      controller: function($element, GraphService){
+
+        let svg;
+        let el = $element[0];
+        let node;
+        let link;
+
+        const tick = (e) => {
+          // Push different nodes in different directions for clustering.
+          
+          node
+            // .attr('cx', d => d.x)
+            //   .attr('cy', d => d.y)
+              .attr({
+                transform: d => `translate(${d.x}, ${d.y})`
+              });
+          
+          link.attr('x1', d => d.source.x)
+              .attr('y1', d => d.source.y)
+              .attr('x2', d => d.target.x)
+              .attr('y2', d => d.target.y);
+        }
+
+        GraphService.loadCoarseData()
+        .then((res) => {
+
+          // build links
+          res.tenants = res.tenants.map(t => {
+            return {
+              source: t.provider_service,
+              target: t.subscriber_service
+            }
+          });
+
+          // add xos as a node
+          res.services.push({
+            name: 'XOS',
+            class: 'xos',
+            x: el.clientWidth / 2,
+            y: el.clientHeight / 2,
+            fixed: true
+          })
+
+          handleSvg(el);
+
+          var force = d3.layout.force()
+            .nodes(res.services)
+            .links(res.tenants)
+            .charge(-1060)
+            .gravity(0.1)
+            .linkDistance(200)
+            .size([el.clientWidth, el.clientHeight])
+            .on('tick', tick)
+            .start();
+
+          link = svg.selectAll('.link')
+          .data(res.tenants).enter().insert('line')
+                .attr('class', 'link');
+
+          node = svg.selectAll('.node')
+            .data(res.services)
+            .enter().append('g')
+            .call(force.drag)
+            .on("mousedown", function() { d3.event.stopPropagation(); });
+
+          node.append('circle')
+            .attr({
+              class: d => `node ${d.class || ''}`,
+              r: 10
+            });
+
+          node.append('text')
+            .attr({
+              'text-anchor': 'middle'
+            })
+            .text(d => d.name)
+
+          node.select('circle')
+            .attr({
+              r: function(d){
+                let parent = d3.select(this).node().parentNode;
+                let sib = d3.select(parent).select('text').node().getBBox()
+                return (sib.width / 2) + 10
+                
+              }
+            })
+
+        })
+
+        const handleSvg = (el) => {
+          d3.select(el).select('svg').remove();
+
+          svg = d3.select(el)
+          .append('svg')
+          .style('width', `${el.clientWidth}px`)
+          .style('height', `${el.clientHeight}px`);
+        }
+      }
+    };
+  })
+})();
+
+// Draw services around xos and calculate coarse tenant as links
+
+// var width = 960, height = 500;
+
+// var fill = d3.scale.category10();
+
+// var nodes = [
+//   {id: 1},
+//   {id: 2},
+//   {id: 3},
+//   {id: 4},
+//   {id: 5}
+// ];
+
+// var links = [
+//   {source: 1, target: 2},
+//   {source: 2, target: 3}
+// ];
+
+// var svg = d3.select("body").append("svg")
+//     .attr("width", width)
+//     .attr("height", height);
+
+// var force = d3.layout.force()
+//     .nodes(nodes)
+//     .links(links)
+//     .charge(-8*12)
+//     .gravity(0.1)
+//     .size([width, height])
+//     .on("tick", tick)
+//     .start();
+
+// svg.append('circle')
+// .attr({
+//   "class": "xos",
+//   r: 20,
+//   cx: () => width / 2,
+//   cy: () => height / 2,
+// })
+
+// var node = svg.selectAll(".node")
+//     .data(nodes)
+//   .enter().append("circle")
+//     .attr("class", "node")
+//     .attr("cx", ({ x }) => x)
+//     .attr("cy", ({ y }) => y)
+//     .attr("r", 8)
+//     .style("fill", ({}, index) => fill(index & 3))
+//     .style("stroke", ({}, index) => d3.rgb(fill(index & 3)).darker(2))
+//     .call(force.drag)
+//     .on("mousedown", ({}) => d3.event.stopPropagation());
+
+// var link = svg.selectAll(".link")
+// .data(links).enter().insert("line")
+//       .attr("class", "link");
+
+// function tick(e) {
+//   // Push different nodes in different directions for clustering.
+  
+//   node.attr("cx", function(d) { return d.x; })
+//       .attr("cy", function(d) { return d.y; });
+  
+//   link.attr("x1", function(d) { return d.source.x; })
+//       .attr("y1", function(d) { return d.source.y; })
+//       .attr("x2", function(d) { return d.target.x; })
+//       .attr("y2", function(d) { return d.target.y; });
+// }
diff --git a/views/ngXosViews/serviceGrid/src/sass/main.scss b/views/ngXosViews/serviceGrid/src/sass/main.scss
new file mode 100644
index 0000000..bc8d14a
--- /dev/null
+++ b/views/ngXosViews/serviceGrid/src/sass/main.scss
@@ -0,0 +1,23 @@
+@import '../../../../style/sass/lib/_variables.scss';
+
+#xosServiceGrid {
+  service-graph {
+    display: block;
+    width: 100%;
+    height: 600px;
+  }
+
+  .node {
+    stroke: $brand-primary;
+    fill: white;
+  }
+
+  .node.xos {
+    fill: $brand-danger;
+  }
+
+  .link {
+    stroke: black;
+    stroke-width: 2px;
+  }
+}
\ No newline at end of file
diff --git a/views/ngXosViews/serviceGrid/src/templates/service-graph.tpl.html b/views/ngXosViews/serviceGrid/src/templates/service-graph.tpl.html
new file mode 100644
index 0000000..c61da91
--- /dev/null
+++ b/views/ngXosViews/serviceGrid/src/templates/service-graph.tpl.html
@@ -0,0 +1,17 @@
+<div class="row">
+  <div class="col-sm-10">
+    <h1>Graph</h1>
+    <ul>
+      <li>Use D3 to create a service chart based on coarse services?</li>
+    </ul>
+  </div>
+  <div class="col-sm-2">
+    <a href="/admin/core/service/add" class="btn btn-success btn-block">
+      <i class="glyphicon glyphicon-plus"></i>
+      Add Service
+    </a>
+    <a href="#/" class="btn btn-default btn-block">
+      Service List
+    </a>
+  </div>
+</div>
\ No newline at end of file
diff --git a/views/ngXosViews/serviceGrid/src/templates/service-grid.tpl.html b/views/ngXosViews/serviceGrid/src/templates/service-grid.tpl.html
new file mode 100644
index 0000000..fa324b4
--- /dev/null
+++ b/views/ngXosViews/serviceGrid/src/templates/service-grid.tpl.html
@@ -0,0 +1,14 @@
+<div class="row">
+  <div class="col-md-10 table-responsive">
+    <xos-table config="vm.tableConfig" data="vm.services"></xos-table>
+  </div>
+  <div class="col-md-2">
+    <a href="/admin/core/service/add" class="btn btn-success btn-block">
+      <i class="glyphicon glyphicon-plus"></i>
+      Add Service
+    </a>
+    <!-- <a href="#/graph" class="btn btn-default btn-block">
+      Tenancy Graph
+    </a> -->
+  </div>
+</div>
\ No newline at end of file
diff --git a/views/ngXosViews/subscribers/.bowerrc b/views/ngXosViews/subscribers/.bowerrc
new file mode 100644
index 0000000..e491038
--- /dev/null
+++ b/views/ngXosViews/subscribers/.bowerrc
@@ -0,0 +1,3 @@
+{
+  "directory": "src/vendor/"
+}
\ No newline at end of file
diff --git a/views/ngXosViews/subscribers/.eslintrc b/views/ngXosViews/subscribers/.eslintrc
new file mode 100644
index 0000000..c852748
--- /dev/null
+++ b/views/ngXosViews/subscribers/.eslintrc
@@ -0,0 +1,42 @@
+{
+    "ecmaFeatures": {
+        "blockBindings": true,
+        "forOf": true,
+        "destructuring": true,
+        "arrowFunctions": true,
+        "templateStrings": true
+    },
+    "env": { 
+        "browser": true,
+        "node": true,
+        "es6": true
+    },
+    "plugins": [
+        //"angular"
+    ],
+    "rules": {
+        "quotes": [2, "single"],
+        "camelcase": [1, {"properties": "always"}],
+        "no-underscore-dangle": 1,
+        "eqeqeq": [2, "smart"],
+        "no-alert": 1,
+        "key-spacing": [1, { "beforeColon": false, "afterColon": true }],
+        "indent": [2, 2],
+        "no-irregular-whitespace": 1,
+        "eol-last": 0,
+        "max-nested-callbacks": [2, 4],
+        "comma-spacing": [1, {"before": false, "after": true}],
+        "no-trailing-spaces": [1, { skipBlankLines: true }],
+        "no-unused-vars": [1, {"vars": "all", "args": "after-used"}],
+        "new-cap": 0,
+
+        //"angular/ng_module_name": [2, '/^xos\.*[a-z]*$/'],
+        //"angular/ng_controller_name": [2, '/^[a-z].*Ctrl$/'],
+        //"angular/ng_service_name": [2, '/^[A-Z].*Service$/'],
+        //"angular/ng_directive_name": [2, '/^[a-z]+[[A-Z].*]*$/'],
+        //"angular/ng_di": [0, "function or array"]
+    },
+    "globals" :{
+        "angular": true
+    } 
+}
\ No newline at end of file
diff --git a/views/ngXosViews/subscribers/.gitignore b/views/ngXosViews/subscribers/.gitignore
new file mode 100644
index 0000000..567aee4
--- /dev/null
+++ b/views/ngXosViews/subscribers/.gitignore
@@ -0,0 +1,6 @@
+dist/
+src/vendor
+.tmp
+node_modules
+npm-debug.log
+dist/
\ No newline at end of file
diff --git a/views/ngXosViews/subscribers/bower.json b/views/ngXosViews/subscribers/bower.json
new file mode 100644
index 0000000..2fb2dab
--- /dev/null
+++ b/views/ngXosViews/subscribers/bower.json
@@ -0,0 +1,32 @@
+{
+  "name": "xos-subscribers",
+  "version": "0.0.0",
+  "authors": [
+    "Matteo Scandolo <matteo.scandolo@gmail.com>"
+  ],
+  "description": "The subscribers view",
+  "license": "MIT",
+  "ignore": [
+    "**/.*",
+    "node_modules",
+    "bower_components",
+    "static/js/vendor/",
+    "test",
+    "tests"
+  ],
+  "dependencies": {},
+  "devDependencies": {
+    "jquery": "2.1.4",
+    "angular-mocks": "1.4.7",
+    "angular": "1.4.7",
+    "angular-ui-router": "0.2.15",
+    "angular-cookies": "1.4.7",
+    "angular-animate": "1.4.7",
+    "angular-resource": "1.4.7",
+    "lodash": "~4.11.1",
+    "bootstrap-css": "3.3.6",
+    "angular-chart.js": "~0.10.2",
+    "d3": "~3.5.17",
+    "angular-recursion": "~1.0.5"
+  }
+}
diff --git a/views/ngXosViews/subscribers/gulp/build.js b/views/ngXosViews/subscribers/gulp/build.js
new file mode 100644
index 0000000..7f446ed
--- /dev/null
+++ b/views/ngXosViews/subscribers/gulp/build.js
@@ -0,0 +1,164 @@
+'use strict';
+
+// BUILD
+//
+// The only purpose of this gulpfile is to build a XOS view and copy the correct files into
+// .html => dashboards
+// .js (minified and concat) => static/js
+//
+// The template are parsed and added to js with angular $templateCache
+
+var gulp = require('gulp');
+var ngAnnotate = require('gulp-ng-annotate');
+var uglify = require('gulp-uglify');
+var templateCache = require('gulp-angular-templatecache');
+var runSequence = require('run-sequence');
+var concat = require('gulp-concat-util');
+var del = require('del');
+var wiredep = require('wiredep');
+var angularFilesort = require('gulp-angular-filesort');
+var _ = require('lodash');
+var eslint = require('gulp-eslint');
+var inject = require('gulp-inject');
+var rename = require('gulp-rename');
+var replace = require('gulp-replace');
+var postcss = require('gulp-postcss');
+var autoprefixer = require('autoprefixer');
+var mqpacker = require('css-mqpacker');
+var csswring = require('csswring');
+
+const TEMPLATE_FOOTER = `
+angular.module('xos.subscribers')
+.run(['$location', function(a){
+  a.path('/');
+}])
+`
+
+module.exports = function(options){
+  
+  // delete previous builded file
+  gulp.task('clean', function(){
+    return del(
+      [
+        options.dashboards + 'xosSubscribers.html',
+        options.static + 'css/xosSubscribers.css'
+      ],
+      {force: true}
+    );
+  });
+
+  // minify css
+  gulp.task('css', function () {
+    var processors = [
+      autoprefixer({browsers: ['last 1 version']}),
+      mqpacker,
+      csswring
+    ];
+
+    gulp.src([
+      `${options.css}**/*.css`,
+      `!${options.css}dev.css`
+    ])
+    .pipe(postcss(processors))
+    .pipe(gulp.dest(options.tmp + '/css/'));
+  });
+
+  // copy css in correct folder
+  gulp.task('copyCss', ['wait'], function(){
+    return gulp.src([`${options.tmp}/css/*.css`])
+    .pipe(concat('xosSubscribers.css'))
+    .pipe(gulp.dest(options.static + 'css/'))
+  });
+
+  // compile and minify scripts
+  gulp.task('scripts', function() {
+    return gulp.src([
+      options.tmp + '**/*.js'
+    ])
+    .pipe(ngAnnotate())
+    .pipe(angularFilesort())
+    .pipe(concat('xosSubscribers.js'))
+    .pipe(concat.header('//Autogenerated, do not edit!!!\n'))
+    .pipe(concat.footer(TEMPLATE_FOOTER))
+    .pipe(uglify())
+    .pipe(gulp.dest(options.static + 'js/'));
+  });
+
+  // set templates in cache
+  gulp.task('templates', function(){
+    return gulp.src('./src/templates/*.html')
+      .pipe(templateCache({
+        module: 'xos.subscribers',
+        root: 'templates/'
+      }))
+      .pipe(gulp.dest(options.tmp));
+  });
+
+  // copy html index to Django Folder
+  gulp.task('copyHtml', function(){
+    return gulp.src(options.src + 'index.html')
+      // remove dev dependencies from html
+      .pipe(replace(/<!-- bower:css -->(\n^<link.*)*\n<!-- endbower -->/gmi, ''))
+      .pipe(replace(/<!-- bower:js -->(\n^<script.*)*\n<!-- endbower -->/gmi, ''))
+      // injecting minified files
+      .pipe(
+        inject(
+          gulp.src([
+            options.static + 'js/vendor/xosSubscribersVendor.js',
+            options.static + 'js/xosSubscribers.js',
+            options.static + 'css/xosSubscribers.css'
+          ]),
+          {ignorePath: '/../../../xos/core/xoslib'}
+        )
+      )
+      .pipe(rename('xosSubscribers.html'))
+      .pipe(gulp.dest(options.dashboards));
+  });
+
+  // minify vendor js files
+  gulp.task('wiredep', function(){
+    var bowerDeps = wiredep().js;
+    if(!bowerDeps){
+      return;
+    }
+
+    // remove angular (it's already loaded)
+    _.remove(bowerDeps, function(dep){
+      return dep.indexOf('angular/angular.js') !== -1;
+    });
+
+    return gulp.src(bowerDeps)
+      .pipe(concat('xosSubscribersVendor.js'))
+      .pipe(uglify())
+      .pipe(gulp.dest(options.static + 'js/vendor/'));
+  });
+
+  gulp.task('lint', function () {
+    return gulp.src(['src/js/**/*.js'])
+      .pipe(eslint())
+      .pipe(eslint.format())
+      .pipe(eslint.failAfterError());
+  });
+
+  gulp.task('wait', function (cb) {
+    // setTimeout could be any async task
+    setTimeout(function () {
+      cb();
+    }, 1000);
+  });
+
+  gulp.task('build', function() {
+    runSequence(
+      'clean',
+      'sass',
+      'templates',
+      'babel',
+      'scripts',
+      'wiredep',
+      'css',
+      'copyCss',
+      'copyHtml',
+      'cleanTmp'
+    );
+  });
+};
\ No newline at end of file
diff --git a/views/ngXosViews/subscribers/gulp/server.js b/views/ngXosViews/subscribers/gulp/server.js
new file mode 100644
index 0000000..1e40a34
--- /dev/null
+++ b/views/ngXosViews/subscribers/gulp/server.js
@@ -0,0 +1,170 @@
+'use strict';
+
+var gulp = require('gulp');
+var browserSync = require('browser-sync').create();
+var inject = require('gulp-inject');
+var runSequence = require('run-sequence');
+var angularFilesort = require('gulp-angular-filesort');
+var babel = require('gulp-babel');
+var wiredep = require('wiredep').stream;
+var httpProxy = require('http-proxy');
+var del = require('del');
+var sass = require('gulp-sass');
+var fs = require('fs');
+var path = require('path');
+
+const environment = process.env.NODE_ENV;
+
+if(!fs.existsSync(path.join(__dirname, `../../../env/${environment || 'default'}.js`))){
+  if(!environment){
+    throw new Error('You should define a default.js config in /views/env folder.');
+  }
+  else{
+    throw new Error(`Since you are loading a custom environment, you should define a ${environment}.js config in /views/env folder.`);
+  }
+}
+
+var conf = require(path.join(__dirname, `../../../env/${environment || 'default'}.js`));
+
+var proxy = httpProxy.createProxyServer({
+  target: conf.host
+});
+
+
+proxy.on('error', function(error, req, res) {
+  res.writeHead(500, {
+    'Content-Type': 'text/plain'
+  });
+
+  console.error('[Proxy]', error);
+});
+
+module.exports = function(options){
+
+  gulp.task('browser', function() {
+    browserSync.init({
+      startPath: '#/',
+      snippetOptions: {
+        rule: {
+          match: /<!-- browserSync -->/i
+        }
+      },
+      server: {
+        baseDir: options.src,
+        routes: {
+          '/xos/core/xoslib/static/js/vendor': options.helpers,
+          '/xos/core/static': options.static + '../../static/'
+        },
+        middleware: function(req, res, next){
+          if(
+            req.url.indexOf('/api/') !== -1
+          ){
+            if(conf.xoscsrftoken && conf.xossessionid){
+              req.headers.cookie = `xoscsrftoken=${conf.xoscsrftoken}; xossessionid=${conf.xossessionid}`;
+              req.headers['x-csrftoken'] = conf.xoscsrftoken;
+            }
+            proxy.web(req, res);
+          }
+          else{
+            next();
+          }
+        }
+      }
+    });
+
+    gulp.watch(options.src + 'js/**/*.js', ['js-watch']);
+    gulp.watch(options.src + 'vendor/**/*.js', ['bower'], function(){
+      browserSync.reload();
+    });
+    gulp.watch(options.src + '**/*.html', function(){
+      browserSync.reload();
+    });
+    gulp.watch(options.css + '**/*.css', function(){
+      browserSync.reload();
+    });
+    gulp.watch(`${options.sass}/**/*.scss`, ['sass'], function(){
+      browserSync.reload();
+    });
+
+    gulp.watch([
+      options.helpers + 'ngXosHelpers.js',
+      options.static + '../../static/xosNgLib.css'
+    ], function(){
+      browserSync.reload();
+    });
+  });
+
+  // compile sass
+  gulp.task('sass', function () {
+    return gulp.src(`${options.sass}/**/*.scss`)
+      .pipe(sass().on('error', sass.logError))
+      .pipe(gulp.dest(options.css));
+  });
+
+  // transpile js with sourceMaps
+  gulp.task('babel', function(){
+    return gulp.src(options.scripts + '**/*.js')
+      .pipe(babel({sourceMaps: true}))
+      .pipe(gulp.dest(options.tmp));
+  });
+
+  // inject scripts
+  gulp.task('injectScript', ['cleanTmp', 'babel'], function(){
+    return gulp.src(options.src + 'index.html')
+      .pipe(
+        inject(
+          gulp.src([
+            options.tmp + '**/*.js',
+            options.helpers + 'ngXosHelpers.js'
+          ])
+          .pipe(angularFilesort()),
+          {
+            ignorePath: [options.src, '/../../ngXosLib']
+          }
+        )
+      )
+      .pipe(gulp.dest(options.src));
+  });
+
+  // inject CSS
+  gulp.task('injectCss', function(){
+    return gulp.src(options.src + 'index.html')
+      .pipe(
+        inject(
+          gulp.src([
+            options.src + 'css/*.css',
+            options.static + '../../static/xosNgLib.css'
+          ]),
+          {
+            ignorePath: [options.src]
+          }
+          )
+        )
+      .pipe(gulp.dest(options.src));
+  });
+
+  // inject bower dependencies with wiredep
+  gulp.task('bower', function () {
+    return gulp.src(options.src + 'index.html')
+    .pipe(wiredep({devDependencies: true}))
+    .pipe(gulp.dest(options.src));
+  });
+
+  gulp.task('js-watch', ['injectScript'], function(){
+    browserSync.reload();
+  });
+
+  gulp.task('cleanTmp', function(){
+    return del([options.tmp + '**/*']);
+  });
+
+  gulp.task('serve', function() {
+    runSequence(
+      'sass',
+      'bower',
+      'injectScript',
+      'injectCss',
+      ['browser']
+    );
+  });
+};
diff --git a/views/ngXosViews/subscribers/gulpfile.js b/views/ngXosViews/subscribers/gulpfile.js
new file mode 100644
index 0000000..08df554
--- /dev/null
+++ b/views/ngXosViews/subscribers/gulpfile.js
@@ -0,0 +1,26 @@
+'use strict';
+
+var gulp = require('gulp');
+var wrench = require('wrench');
+
+var options = {
+  src: 'src/',
+  css: 'src/css/',
+  sass: 'src/sass/',
+  scripts: 'src/js/',
+  tmp: 'src/.tmp',
+  dist: 'dist/',
+  api: '../../ngXosLib/api/',
+  helpers: '../../../xos/core/xoslib/static/js/vendor/',
+  static: '../../../xos/core/xoslib/static/', // this is the django static folder
+  dashboards: '../../../xos/core/xoslib/dashboards/' // this is the django html folder
+};
+
+wrench.readdirSyncRecursive('./gulp')
+.map(function(file) {
+  require('./gulp/' + file)(options);
+});
+
+gulp.task('default', function () {
+  gulp.start('build');
+});
diff --git a/views/ngXosViews/subscribers/karma.conf.js b/views/ngXosViews/subscribers/karma.conf.js
new file mode 100644
index 0000000..0e9c4d8
--- /dev/null
+++ b/views/ngXosViews/subscribers/karma.conf.js
@@ -0,0 +1,92 @@
+// Karma configuration
+// Generated on Tue Oct 06 2015 09:27:10 GMT+0000 (UTC)
+
+/* eslint indent: [2,2], quotes: [2, "single"]*/
+
+/*eslint-disable*/
+var wiredep = require('wiredep');
+var path = require('path');
+
+var bowerComponents = wiredep( {devDependencies: true} )[ 'js' ].map(function( file ){
+  return path.relative(process.cwd(), file);
+});
+
+module.exports = function(config) {
+/*eslint-enable*/
+  config.set({
+
+    // base path that will be used to resolve all patterns (eg. files, exclude)
+    basePath: '',
+
+
+    // frameworks to use
+    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
+    frameworks: ['jasmine'],
+
+
+    // list of files / patterns to load in the browser
+    files: bowerComponents.concat([
+      'node_modules/babel-polyfill/dist/polyfill.js',
+      '../../../xos/core/xoslib/static/js/vendor/ngXosVendor.js',
+      '../../../xos/core/xoslib/static/js/vendor/ngXosHelpers.js',
+      'src/js/**/*.js',
+      'spec/**/*.mock.js',
+      'spec/**/*.test.js',
+      'src/**/*.html'
+    ]),
+
+
+    // list of files to exclude
+    exclude: [
+    ],
+
+
+    // preprocess matching files before serving them to the browser
+    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
+    preprocessors: {
+      'src/js/**/*.js': ['babel'],
+      'spec/**/*.test.js': ['babel'],
+      'src/**/*.html': ['ng-html2js']
+    },
+
+    ngHtml2JsPreprocessor: {
+      stripPrefix: 'src/', //strip the src path from template url (http://stackoverflow.com/questions/22869668/karma-unexpected-request-when-testing-angular-directive-even-with-ng-html2js)
+      moduleName: 'templates' // define the template module name
+    },
+
+    // test results reporter to use
+    // possible values: 'dots', 'progress'
+    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
+    reporters: ['mocha'],
+
+
+    // web server port
+    port: 9876,
+
+
+    // enable / disable colors in the output (reporters and logs)
+    colors: true,
+
+
+    // level of logging
+    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+    logLevel: config.LOG_INFO,
+
+
+    // enable / disable watching file and executing tests whenever any file changes
+    autoWatch: true,
+
+
+    // start these browsers
+    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
+    browsers: [
+      'PhantomJS',
+      'Chrome'
+    ],
+
+
+    // Continuous Integration mode
+    // if true, Karma captures browsers, runs the tests and exits
+    singleRun: false
+  });
+};
diff --git a/views/ngXosViews/subscribers/package.json b/views/ngXosViews/subscribers/package.json
new file mode 100644
index 0000000..96a2326
--- /dev/null
+++ b/views/ngXosViews/subscribers/package.json
@@ -0,0 +1,65 @@
+{
+  "name": "xos-subscribers",
+  "version": "1.0.0",
+  "description": "Angular Application for XOS, created with generator-xos",
+  "scripts": {
+    "prestart": "npm install && bower install",
+    "start": "gulp serve",
+    "prebuild": "npm install && bower install",
+    "build": "gulp",
+    "test": "karma start",
+    "test:ci": "karma start --single-run",
+    "lint": "eslint src/js/"
+  },
+  "keywords": [
+    "XOS",
+    "Angular",
+    "XOSlib"
+  ],
+  "author": "Matteo Scandolo",
+  "license": "MIT",
+  "dependencies": {},
+  "devDependencies": {
+    "autoprefixer": "^6.3.3",
+    "babel-polyfill": "^6.9.0",
+    "browser-sync": "^2.9.11",
+    "css-mqpacker": "^4.0.0",
+    "csswring": "^4.2.1",
+    "del": "^2.0.2",
+    "easy-mocker": "^1.2.0",
+    "eslint": "^1.8.0",
+    "eslint-plugin-angular": "linkmesrl/eslint-plugin-angular",
+    "gulp": "^3.9.0",
+    "gulp-angular-filesort": "^1.1.1",
+    "gulp-angular-templatecache": "^1.8.0",
+    "gulp-babel": "^5.3.0",
+    "gulp-concat": "^2.6.0",
+    "gulp-concat-util": "^0.5.5",
+    "gulp-eslint": "^1.0.0",
+    "gulp-inject": "^3.0.0",
+    "gulp-minify-html": "^1.0.4",
+    "gulp-ng-annotate": "^1.1.0",
+    "gulp-postcss": "^6.0.1",
+    "gulp-rename": "^1.2.2",
+    "gulp-replace": "^0.5.4",
+    "gulp-sass": "^2.2.0",
+    "gulp-uglify": "^1.4.2",
+    "http-proxy": "^1.12.0",
+    "ink-docstrap": "^0.5.2",
+    "jasmine-core": "~2.3.4",
+    "karma": "^0.13.14",
+    "karma-babel-preprocessor": "~5.2.2",
+    "karma-chrome-launcher": "^1.0.1",
+    "karma-coverage": "^0.5.3",
+    "karma-jasmine": "~0.3.6",
+    "karma-mocha-reporter": "~1.1.1",
+    "karma-ng-html2js-preprocessor": "^0.2.0",
+    "karma-phantomjs-launcher": "~0.2.1",
+    "lodash": "^3.10.1",
+    "phantomjs": "^1.9.19",
+    "proxy-middleware": "^0.15.0",
+    "run-sequence": "^1.1.4",
+    "wiredep": "^3.0.0-beta",
+    "wrench": "^1.5.8"
+  }
+}
diff --git a/views/ngXosViews/subscribers/spec/sample.test.js b/views/ngXosViews/subscribers/spec/sample.test.js
new file mode 100644
index 0000000..1b7796c
--- /dev/null
+++ b/views/ngXosViews/subscribers/spec/sample.test.js
@@ -0,0 +1,53 @@
+'use strict';
+
+describe('The Subscriber View', () => {
+  
+  const subscribersList = [
+    {
+      humanReadableName: 'cordSubscriber-1',
+      features: {cdn: false, uplink_speed: 1000000000, downlink_speed: 1000000000, uverse: true, status: 'enabled'},
+      id: 1,
+      identity: {account_num: '123', name: 'Stanford'},
+      related: {}
+    }
+  ];
+
+  var scope, element, isolatedScope, httpBackend;
+
+  beforeEach(module('xos.subscribers'));
+  beforeEach(module('templates'));
+
+  beforeEach(inject(function($httpBackend, $compile, $rootScope){
+    
+    httpBackend = $httpBackend;
+    
+    httpBackend.whenGET('/api/tenant/cord/subscriber/?no_hyperlinks=1').respond(subscribersList);
+  
+    scope = $rootScope.$new();
+    element = angular.element('<subscribers-list></subscribers-list>');
+    $compile(element)(scope);
+    scope.$digest();
+    isolatedScope = element.isolateScope().vm;
+  }));
+
+  it('should load 1 subscriber', () => {
+    // this
+    httpBackend.flush();
+    scope.$digest();
+    let table = $(element).find('table');
+    let tr = table.find('tbody:last-child tr');
+    // let tds = $(tr[1]).find('td');
+    // console.log(tr);
+    expect(tr.length).toBe(1);
+    // expect($(tds[0]).html()).toBe('cordSubscriber-1')
+  });
+
+  it('should configure xos-smart-table', () => {
+    expect(isolatedScope.smartTableConfig).toEqual({resource: 'Subscribers'});
+  });
+
+  it('should render xos-smart-table', () => {
+    expect($(element).find('xos-smart-table').length).toBe(1);
+  });
+
+});
\ No newline at end of file
diff --git a/views/ngXosViews/subscribers/src/css/main.css b/views/ngXosViews/subscribers/src/css/main.css
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/views/ngXosViews/subscribers/src/css/main.css
diff --git a/views/ngXosViews/subscribers/src/index.html b/views/ngXosViews/subscribers/src/index.html
new file mode 100644
index 0000000..71cbddc
--- /dev/null
+++ b/views/ngXosViews/subscribers/src/index.html
@@ -0,0 +1,35 @@
+<!-- browserSync -->
+<!-- bower:css -->
+<link rel="stylesheet" href="vendor/bootstrap-css/css/bootstrap.min.css" />
+<link rel="stylesheet" href="vendor/angular-chart.js/dist/angular-chart.css" />
+<!-- endbower -->
+<!-- endcss -->
+<!-- inject:css -->
+<link rel="stylesheet" href="/css/main.css">
+<link rel="stylesheet" href="/../../../xos/core/static/xosNgLib.css">
+<!-- endinject -->
+
+<div ng-app="xos.subscribers" id="xosSubscribers" class="container-fluid">
+  <div ui-view></div>
+</div>
+
+<!-- bower:js -->
+<script src="vendor/jquery/dist/jquery.js"></script>
+<script src="vendor/angular/angular.js"></script>
+<script src="vendor/angular-mocks/angular-mocks.js"></script>
+<script src="vendor/angular-ui-router/release/angular-ui-router.js"></script>
+<script src="vendor/angular-cookies/angular-cookies.js"></script>
+<script src="vendor/angular-animate/angular-animate.js"></script>
+<script src="vendor/angular-resource/angular-resource.js"></script>
+<script src="vendor/lodash/lodash.js"></script>
+<script src="vendor/bootstrap-css/js/bootstrap.min.js"></script>
+<script src="vendor/Chart.js/Chart.js"></script>
+<script src="vendor/angular-chart.js/dist/angular-chart.js"></script>
+<script src="vendor/d3/d3.js"></script>
+<script src="vendor/angular-recursion/angular-recursion.js"></script>
+<!-- endbower -->
+<!-- endjs -->
+<!-- inject:js -->
+<script src="/../../../xos/core/xoslib/static/js/vendor/ngXosHelpers.js"></script>
+<script src="/.tmp/main.js"></script>
+<!-- endinject -->
\ No newline at end of file
diff --git a/views/ngXosViews/subscribers/src/js/main.js b/views/ngXosViews/subscribers/src/js/main.js
new file mode 100644
index 0000000..203e9ff
--- /dev/null
+++ b/views/ngXosViews/subscribers/src/js/main.js
@@ -0,0 +1,33 @@
+'use strict';
+
+angular.module('xos.subscribers', [
+  'ngResource',
+  'ngCookies',
+  'ui.router',
+  'xos.helpers'
+])
+.config(($stateProvider) => {
+  $stateProvider
+  .state('user-list', {
+    url: '/',
+    template: '<subscribers-list></subscribers-list>'
+  });
+})
+.config(function($httpProvider){
+  $httpProvider.interceptors.push('NoHyperlinks');
+})
+.directive('subscribersList', function(){
+  return {
+    restrict: 'E',
+    scope: {},
+    bindToController: true,
+    controllerAs: 'vm',
+    templateUrl: 'templates/subscribers-list.tpl.html',
+    controller: function(){
+
+      this.smartTableConfig = {
+        resource: 'Subscribers'
+      };
+    }
+  };
+});
\ No newline at end of file
diff --git a/views/ngXosViews/subscribers/src/sass/main.scss b/views/ngXosViews/subscribers/src/sass/main.scss
new file mode 100644
index 0000000..5f68212
--- /dev/null
+++ b/views/ngXosViews/subscribers/src/sass/main.scss
@@ -0,0 +1,5 @@
+@import '../../../../style/sass/lib/_variables.scss';
+
+#xosSubscribers {
+  
+}
\ No newline at end of file
diff --git a/views/ngXosViews/subscribers/src/templates/subscribers-list.tpl.html b/views/ngXosViews/subscribers/src/templates/subscribers-list.tpl.html
new file mode 100644
index 0000000..d6e755b
--- /dev/null
+++ b/views/ngXosViews/subscribers/src/templates/subscribers-list.tpl.html
@@ -0,0 +1 @@
+<xos-smart-table config="vm.smartTableConfig"></xos-smart-table>
\ No newline at end of file
diff --git a/views/ngXosViews/synchronizerNotifier/.bowerrc b/views/ngXosViews/synchronizerNotifier/.bowerrc
new file mode 100644
index 0000000..e491038
--- /dev/null
+++ b/views/ngXosViews/synchronizerNotifier/.bowerrc
@@ -0,0 +1,3 @@
+{
+  "directory": "src/vendor/"
+}
\ No newline at end of file
diff --git a/views/ngXosViews/synchronizerNotifier/.eslintrc b/views/ngXosViews/synchronizerNotifier/.eslintrc
new file mode 100644
index 0000000..c852748
--- /dev/null
+++ b/views/ngXosViews/synchronizerNotifier/.eslintrc
@@ -0,0 +1,42 @@
+{
+    "ecmaFeatures": {
+        "blockBindings": true,
+        "forOf": true,
+        "destructuring": true,
+        "arrowFunctions": true,
+        "templateStrings": true
+    },
+    "env": { 
+        "browser": true,
+        "node": true,
+        "es6": true
+    },
+    "plugins": [
+        //"angular"
+    ],
+    "rules": {
+        "quotes": [2, "single"],
+        "camelcase": [1, {"properties": "always"}],
+        "no-underscore-dangle": 1,
+        "eqeqeq": [2, "smart"],
+        "no-alert": 1,
+        "key-spacing": [1, { "beforeColon": false, "afterColon": true }],
+        "indent": [2, 2],
+        "no-irregular-whitespace": 1,
+        "eol-last": 0,
+        "max-nested-callbacks": [2, 4],
+        "comma-spacing": [1, {"before": false, "after": true}],
+        "no-trailing-spaces": [1, { skipBlankLines: true }],
+        "no-unused-vars": [1, {"vars": "all", "args": "after-used"}],
+        "new-cap": 0,
+
+        //"angular/ng_module_name": [2, '/^xos\.*[a-z]*$/'],
+        //"angular/ng_controller_name": [2, '/^[a-z].*Ctrl$/'],
+        //"angular/ng_service_name": [2, '/^[A-Z].*Service$/'],
+        //"angular/ng_directive_name": [2, '/^[a-z]+[[A-Z].*]*$/'],
+        //"angular/ng_di": [0, "function or array"]
+    },
+    "globals" :{
+        "angular": true
+    } 
+}
\ No newline at end of file
diff --git a/views/ngXosViews/synchronizerNotifier/.gitignore b/views/ngXosViews/synchronizerNotifier/.gitignore
new file mode 100644
index 0000000..567aee4
--- /dev/null
+++ b/views/ngXosViews/synchronizerNotifier/.gitignore
@@ -0,0 +1,6 @@
+dist/
+src/vendor
+.tmp
+node_modules
+npm-debug.log
+dist/
\ No newline at end of file
diff --git a/views/ngXosViews/synchronizerNotifier/bower.json b/views/ngXosViews/synchronizerNotifier/bower.json
new file mode 100644
index 0000000..8b0eb12
--- /dev/null
+++ b/views/ngXosViews/synchronizerNotifier/bower.json
@@ -0,0 +1,32 @@
+{
+  "name": "xos-synchronizerNotifier",
+  "version": "0.0.0",
+  "authors": [
+    "Matteo Scandolo <matteo.scandolo@gmail.com>"
+  ],
+  "description": "The synchronizerNotifier view",
+  "license": "MIT",
+  "ignore": [
+    "**/.*",
+    "node_modules",
+    "bower_components",
+    "static/js/vendor/",
+    "test",
+    "tests"
+  ],
+  "dependencies": {},
+  "devDependencies": {
+    "jquery": "2.1.4",
+    "angular-mocks": "1.4.7",
+    "angular": "1.4.7",
+    "angular-ui-router": "0.2.15",
+    "angular-cookies": "1.4.7",
+    "angular-animate": "1.4.7",
+    "angular-resource": "1.4.7",
+    "lodash": "~4.11.1",
+    "bootstrap-css": "3.3.6",
+    "angular-chart.js": "~0.10.2",
+    "d3": "~3.5.17",
+    "angular-recursion": "~1.0.5"
+  }
+}
diff --git a/views/ngXosViews/synchronizerNotifier/gulp/build.js b/views/ngXosViews/synchronizerNotifier/gulp/build.js
new file mode 100644
index 0000000..47cb69c
--- /dev/null
+++ b/views/ngXosViews/synchronizerNotifier/gulp/build.js
@@ -0,0 +1,164 @@
+'use strict';
+
+// BUILD
+//
+// The only purpose of this gulpfile is to build a XOS view and copy the correct files into
+// .html => dashboards
+// .js (minified and concat) => static/js
+//
+// The template are parsed and added to js with angular $templateCache
+
+var gulp = require('gulp');
+var ngAnnotate = require('gulp-ng-annotate');
+var uglify = require('gulp-uglify');
+var templateCache = require('gulp-angular-templatecache');
+var runSequence = require('run-sequence');
+var concat = require('gulp-concat-util');
+var del = require('del');
+var wiredep = require('wiredep');
+var angularFilesort = require('gulp-angular-filesort');
+var _ = require('lodash');
+var eslint = require('gulp-eslint');
+var inject = require('gulp-inject');
+var rename = require('gulp-rename');
+var replace = require('gulp-replace');
+var postcss = require('gulp-postcss');
+var autoprefixer = require('autoprefixer');
+var mqpacker = require('css-mqpacker');
+var csswring = require('csswring');
+
+const TEMPLATE_FOOTER = `
+angular.module('xos.synchronizerNotifier')
+.run(['$location', function(a){
+  a.path('/');
+}])
+`
+
+module.exports = function(options){
+  
+  // delete previous builded file
+  gulp.task('clean', function(){
+    return del(
+      [
+        options.dashboards + 'xosSynchronizerNotifier.html',
+        options.static + 'css/xosSynchronizerNotifier.css'
+      ],
+      {force: true}
+    );
+  });
+
+  // minify css
+  gulp.task('css', function () {
+    var processors = [
+      autoprefixer({browsers: ['last 1 version']}),
+      mqpacker,
+      csswring
+    ];
+
+    gulp.src([
+      `${options.css}**/*.css`,
+      `!${options.css}dev.css`
+    ])
+    .pipe(postcss(processors))
+    .pipe(gulp.dest(options.tmp + '/css/'));
+  });
+
+  // copy css in correct folder
+  gulp.task('copyCss', ['wait'], function(){
+    return gulp.src([`${options.tmp}/css/*.css`])
+    .pipe(concat('xosSynchronizerNotifier.css'))
+    .pipe(gulp.dest(options.static + 'css/'))
+  });
+
+  // compile and minify scripts
+  gulp.task('scripts', function() {
+    return gulp.src([
+      options.tmp + '**/*.js'
+    ])
+    .pipe(ngAnnotate())
+    .pipe(angularFilesort())
+    .pipe(concat('xosSynchronizerNotifier.js'))
+    .pipe(concat.header('//Autogenerated, do not edit!!!\n'))
+    .pipe(concat.footer(TEMPLATE_FOOTER))
+    .pipe(uglify())
+    .pipe(gulp.dest(options.static + 'js/'));
+  });
+
+  // set templates in cache
+  gulp.task('templates', function(){
+    return gulp.src('./src/templates/*.html')
+      .pipe(templateCache({
+        module: 'xos.synchronizerNotifier',
+        root: 'templates/'
+      }))
+      .pipe(gulp.dest(options.tmp));
+  });
+
+  // copy html index to Django Folder
+  gulp.task('copyHtml', function(){
+    return gulp.src(options.src + 'index.html')
+      // remove dev dependencies from html
+      .pipe(replace(/<!-- bower:css -->(\n^<link.*)*\n<!-- endbower -->/gmi, ''))
+      .pipe(replace(/<!-- bower:js -->(\n^<script.*)*\n<!-- endbower -->/gmi, ''))
+      // injecting minified files
+      .pipe(
+        inject(
+          gulp.src([
+            options.static + 'js/vendor/xosSynchronizerNotifierVendor.js',
+            options.static + 'js/xosSynchronizerNotifier.js',
+            options.static + 'css/xosSynchronizerNotifier.css'
+          ]),
+          {ignorePath: '/../../../xos/core/xoslib'}
+        )
+      )
+      .pipe(rename('xosSynchronizerNotifier.html'))
+      .pipe(gulp.dest(options.dashboards));
+  });
+
+  // minify vendor js files
+  gulp.task('wiredep', function(){
+    var bowerDeps = wiredep().js;
+    if(!bowerDeps){
+      return;
+    }
+
+    // remove angular (it's already loaded)
+    _.remove(bowerDeps, function(dep){
+      return dep.indexOf('angular/angular.js') !== -1;
+    });
+
+    return gulp.src(bowerDeps)
+      .pipe(concat('xosSynchronizerNotifierVendor.js'))
+      .pipe(uglify())
+      .pipe(gulp.dest(options.static + 'js/vendor/'));
+  });
+
+  gulp.task('lint', function () {
+    return gulp.src(['src/js/**/*.js'])
+      .pipe(eslint())
+      .pipe(eslint.format())
+      .pipe(eslint.failAfterError());
+  });
+
+  gulp.task('wait', function (cb) {
+    // setTimeout could be any async task
+    setTimeout(function () {
+      cb();
+    }, 1000);
+  });
+
+  gulp.task('build', function() {
+    runSequence(
+      'clean',
+      'sass',
+      'templates',
+      'babel',
+      'scripts',
+      'wiredep',
+      'css',
+      'copyCss',
+      'copyHtml',
+      'cleanTmp'
+    );
+  });
+};
\ No newline at end of file
diff --git a/views/ngXosViews/synchronizerNotifier/gulp/server.js b/views/ngXosViews/synchronizerNotifier/gulp/server.js
new file mode 100644
index 0000000..1e40a34
--- /dev/null
+++ b/views/ngXosViews/synchronizerNotifier/gulp/server.js
@@ -0,0 +1,170 @@
+'use strict';
+
+var gulp = require('gulp');
+var browserSync = require('browser-sync').create();
+var inject = require('gulp-inject');
+var runSequence = require('run-sequence');
+var angularFilesort = require('gulp-angular-filesort');
+var babel = require('gulp-babel');
+var wiredep = require('wiredep').stream;
+var httpProxy = require('http-proxy');
+var del = require('del');
+var sass = require('gulp-sass');
+var fs = require('fs');
+var path = require('path');
+
+const environment = process.env.NODE_ENV;
+
+if(!fs.existsSync(path.join(__dirname, `../../../env/${environment || 'default'}.js`))){
+  if(!environment){
+    throw new Error('You should define a default.js config in /views/env folder.');
+  }
+  else{
+    throw new Error(`Since you are loading a custom environment, you should define a ${environment}.js config in /views/env folder.`);
+  }
+}
+
+var conf = require(path.join(__dirname, `../../../env/${environment || 'default'}.js`));
+
+var proxy = httpProxy.createProxyServer({
+  target: conf.host
+});
+
+
+proxy.on('error', function(error, req, res) {
+  res.writeHead(500, {
+    'Content-Type': 'text/plain'
+  });
+
+  console.error('[Proxy]', error);
+});
+
+module.exports = function(options){
+
+  gulp.task('browser', function() {
+    browserSync.init({
+      startPath: '#/',
+      snippetOptions: {
+        rule: {
+          match: /<!-- browserSync -->/i
+        }
+      },
+      server: {
+        baseDir: options.src,
+        routes: {
+          '/xos/core/xoslib/static/js/vendor': options.helpers,
+          '/xos/core/static': options.static + '../../static/'
+        },
+        middleware: function(req, res, next){
+          if(
+            req.url.indexOf('/api/') !== -1
+          ){
+            if(conf.xoscsrftoken && conf.xossessionid){
+              req.headers.cookie = `xoscsrftoken=${conf.xoscsrftoken}; xossessionid=${conf.xossessionid}`;
+              req.headers['x-csrftoken'] = conf.xoscsrftoken;
+            }
+            proxy.web(req, res);
+          }
+          else{
+            next();
+          }
+        }
+      }
+    });
+
+    gulp.watch(options.src + 'js/**/*.js', ['js-watch']);
+    gulp.watch(options.src + 'vendor/**/*.js', ['bower'], function(){
+      browserSync.reload();
+    });
+    gulp.watch(options.src + '**/*.html', function(){
+      browserSync.reload();
+    });
+    gulp.watch(options.css + '**/*.css', function(){
+      browserSync.reload();
+    });
+    gulp.watch(`${options.sass}/**/*.scss`, ['sass'], function(){
+      browserSync.reload();
+    });
+
+    gulp.watch([
+      options.helpers + 'ngXosHelpers.js',
+      options.static + '../../static/xosNgLib.css'
+    ], function(){
+      browserSync.reload();
+    });
+  });
+
+  // compile sass
+  gulp.task('sass', function () {
+    return gulp.src(`${options.sass}/**/*.scss`)
+      .pipe(sass().on('error', sass.logError))
+      .pipe(gulp.dest(options.css));
+  });
+
+  // transpile js with sourceMaps
+  gulp.task('babel', function(){
+    return gulp.src(options.scripts + '**/*.js')
+      .pipe(babel({sourceMaps: true}))
+      .pipe(gulp.dest(options.tmp));
+  });
+
+  // inject scripts
+  gulp.task('injectScript', ['cleanTmp', 'babel'], function(){
+    return gulp.src(options.src + 'index.html')
+      .pipe(
+        inject(
+          gulp.src([
+            options.tmp + '**/*.js',
+            options.helpers + 'ngXosHelpers.js'
+          ])
+          .pipe(angularFilesort()),
+          {
+            ignorePath: [options.src, '/../../ngXosLib']
+          }
+        )
+      )
+      .pipe(gulp.dest(options.src));
+  });
+
+  // inject CSS
+  gulp.task('injectCss', function(){
+    return gulp.src(options.src + 'index.html')
+      .pipe(
+        inject(
+          gulp.src([
+            options.src + 'css/*.css',
+            options.static + '../../static/xosNgLib.css'
+          ]),
+          {
+            ignorePath: [options.src]
+          }
+          )
+        )
+      .pipe(gulp.dest(options.src));
+  });
+
+  // inject bower dependencies with wiredep
+  gulp.task('bower', function () {
+    return gulp.src(options.src + 'index.html')
+    .pipe(wiredep({devDependencies: true}))
+    .pipe(gulp.dest(options.src));
+  });
+
+  gulp.task('js-watch', ['injectScript'], function(){
+    browserSync.reload();
+  });
+
+  gulp.task('cleanTmp', function(){
+    return del([options.tmp + '**/*']);
+  });
+
+  gulp.task('serve', function() {
+    runSequence(
+      'sass',
+      'bower',
+      'injectScript',
+      'injectCss',
+      ['browser']
+    );
+  });
+};
diff --git a/views/ngXosViews/synchronizerNotifier/gulpfile.js b/views/ngXosViews/synchronizerNotifier/gulpfile.js
new file mode 100644
index 0000000..08df554
--- /dev/null
+++ b/views/ngXosViews/synchronizerNotifier/gulpfile.js
@@ -0,0 +1,26 @@
+'use strict';
+
+var gulp = require('gulp');
+var wrench = require('wrench');
+
+var options = {
+  src: 'src/',
+  css: 'src/css/',
+  sass: 'src/sass/',
+  scripts: 'src/js/',
+  tmp: 'src/.tmp',
+  dist: 'dist/',
+  api: '../../ngXosLib/api/',
+  helpers: '../../../xos/core/xoslib/static/js/vendor/',
+  static: '../../../xos/core/xoslib/static/', // this is the django static folder
+  dashboards: '../../../xos/core/xoslib/dashboards/' // this is the django html folder
+};
+
+wrench.readdirSyncRecursive('./gulp')
+.map(function(file) {
+  require('./gulp/' + file)(options);
+});
+
+gulp.task('default', function () {
+  gulp.start('build');
+});
diff --git a/views/ngXosViews/synchronizerNotifier/karma.conf.js b/views/ngXosViews/synchronizerNotifier/karma.conf.js
new file mode 100644
index 0000000..4123be9
--- /dev/null
+++ b/views/ngXosViews/synchronizerNotifier/karma.conf.js
@@ -0,0 +1,88 @@
+// Karma configuration
+// Generated on Tue Oct 06 2015 09:27:10 GMT+0000 (UTC)
+
+/* eslint indent: [2,2], quotes: [2, "single"]*/
+
+/*eslint-disable*/
+var wiredep = require('wiredep');
+var path = require('path');
+
+var bowerComponents = wiredep( {devDependencies: true} )[ 'js' ].map(function( file ){
+  return path.relative(process.cwd(), file);
+});
+
+module.exports = function(config) {
+/*eslint-enable*/
+  config.set({
+
+    // base path that will be used to resolve all patterns (eg. files, exclude)
+    basePath: '',
+
+
+    // frameworks to use
+    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
+    frameworks: ['jasmine'],
+
+
+    // list of files / patterns to load in the browser
+    files: bowerComponents.concat([
+      '../../../xos/core/xoslib/static/js/vendor/ngXosVendor.js',
+      '../../../xos/core/xoslib/static/js/vendor/ngXosHelpers.js',
+      'src/js/**/*.js',
+      'spec/**/*.mock.js',
+      'spec/**/*.test.js',
+      'src/**/*.html'
+    ]),
+
+
+    // list of files to exclude
+    exclude: [
+    ],
+
+
+    // preprocess matching files before serving them to the browser
+    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
+    preprocessors: {
+      'src/js/**/*.js': ['babel'],
+      'spec/**/*.test.js': ['babel'],
+      'src/**/*.html': ['ng-html2js']
+    },
+
+    ngHtml2JsPreprocessor: {
+      stripPrefix: 'src/', //strip the src path from template url (http://stackoverflow.com/questions/22869668/karma-unexpected-request-when-testing-angular-directive-even-with-ng-html2js)
+      moduleName: 'templates' // define the template module name
+    },
+
+    // test results reporter to use
+    // possible values: 'dots', 'progress'
+    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
+    reporters: ['mocha'],
+
+
+    // web server port
+    port: 9876,
+
+
+    // enable / disable colors in the output (reporters and logs)
+    colors: true,
+
+
+    // level of logging
+    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+    logLevel: config.LOG_INFO,
+
+
+    // enable / disable watching file and executing tests whenever any file changes
+    autoWatch: true,
+
+
+    // start these browsers
+    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
+    browsers: ['PhantomJS'],
+
+
+    // Continuous Integration mode
+    // if true, Karma captures browsers, runs the tests and exits
+    singleRun: false
+  });
+};
diff --git a/views/ngXosViews/synchronizerNotifier/package.json b/views/ngXosViews/synchronizerNotifier/package.json
new file mode 100644
index 0000000..ad76efe
--- /dev/null
+++ b/views/ngXosViews/synchronizerNotifier/package.json
@@ -0,0 +1,63 @@
+{
+  "name": "xos-synchronizerNotifier",
+  "version": "1.0.0",
+  "description": "Angular Application for XOS, created with generator-xos",
+  "scripts": {
+    "prestart": "npm install && bower install",
+    "start": "gulp serve",
+    "prebuild": "npm install && bower install",
+    "build": "gulp",
+    "test": "karma start",
+    "test:ci": "karma start --single-run",
+    "lint": "eslint src/js/"
+  },
+  "keywords": [
+    "XOS",
+    "Angular",
+    "XOSlib"
+  ],
+  "author": "Matteo Scandolo",
+  "license": "MIT",
+  "dependencies": {},
+  "devDependencies": {
+    "autoprefixer": "^6.3.3",
+    "browser-sync": "^2.9.11",
+    "css-mqpacker": "^4.0.0",
+    "csswring": "^4.2.1",
+    "del": "^2.0.2",
+    "easy-mocker": "^1.2.0",
+    "eslint": "^1.8.0",
+    "eslint-plugin-angular": "linkmesrl/eslint-plugin-angular",
+    "gulp": "^3.9.0",
+    "gulp-angular-filesort": "^1.1.1",
+    "gulp-angular-templatecache": "^1.8.0",
+    "gulp-babel": "^5.3.0",
+    "gulp-concat": "^2.6.0",
+    "gulp-concat-util": "^0.5.5",
+    "gulp-eslint": "^1.0.0",
+    "gulp-inject": "^3.0.0",
+    "gulp-minify-html": "^1.0.4",
+    "gulp-ng-annotate": "^1.1.0",
+    "gulp-postcss": "^6.0.1",
+    "gulp-rename": "^1.2.2",
+    "gulp-replace": "^0.5.4",
+    "gulp-sass": "^2.2.0",
+    "gulp-uglify": "^1.4.2",
+    "http-proxy": "^1.12.0",
+    "ink-docstrap": "^0.5.2",
+    "jasmine-core": "~2.3.4",
+    "karma": "^0.13.14",
+    "karma-babel-preprocessor": "~5.2.2",
+    "karma-coverage": "^0.5.3",
+    "karma-jasmine": "~0.3.6",
+    "karma-mocha-reporter": "~1.1.1",
+    "karma-ng-html2js-preprocessor": "^0.2.0",
+    "karma-phantomjs-launcher": "~0.2.1",
+    "lodash": "^3.10.1",
+    "phantomjs": "^1.9.19",
+    "proxy-middleware": "^0.15.0",
+    "run-sequence": "^1.1.4",
+    "wiredep": "^3.0.0-beta",
+    "wrench": "^1.5.8"
+  }
+}
diff --git a/views/ngXosViews/synchronizerNotifier/spec/notification.test.js b/views/ngXosViews/synchronizerNotifier/spec/notification.test.js
new file mode 100644
index 0000000..265b7b9
--- /dev/null
+++ b/views/ngXosViews/synchronizerNotifier/spec/notification.test.js
@@ -0,0 +1,76 @@
+'use strict';
+
+describe('The Synchronizer Notification Panel', () => {
+  
+  var scope, element, isolatedScope, XosUserPrefs;
+  const xosNotification = {
+    notify: jasmine.createSpy('notify')
+  };
+
+  const failureEvent = {
+    name: 'test',
+    status: false
+  };
+
+  const successEvent = {
+    name: 'test',
+    status: true
+  };
+
+  beforeEach(module('xos.synchronizerNotifier', ($provide) => {
+    $provide.value('Diag', {
+      start: () => null
+    });
+
+    $provide.value('xosNotification', xosNotification);
+  }));
+  beforeEach(module('templates'));
+
+  beforeEach(inject(function($compile, $rootScope, _XosUserPrefs_){
+
+    XosUserPrefs = _XosUserPrefs_;
+    scope = $rootScope.$new();
+    element = angular.element('<sync-status></sync-status>');
+    $compile(element)(scope);
+    scope.$digest();
+    isolatedScope = element.isolateScope().vm;
+  }));
+
+  describe('when an event is received', () => {
+
+    beforeEach(() => {
+      xosNotification.notify.calls.reset()
+    });
+
+    describe('and notification have not been sent', () => {
+      
+      beforeEach(() => {
+        XosUserPrefs.setSynchronizerNotificationStatus('test', false);
+        scope.$emit('diag', failureEvent);
+      });
+
+      it('should trigger notification', () => {
+        expect(xosNotification.notify).toHaveBeenCalled();
+      });
+
+      it('should update status in the scope', () => {
+        expect(isolatedScope.synchronizers.test).toEqual(failureEvent);
+        scope.$emit('diag', successEvent);
+        expect(isolatedScope.synchronizers.test).toEqual(successEvent);
+      });
+    });
+
+    describe('and notification have been sent', () => {
+      
+      beforeEach(() => {
+        XosUserPrefs.setSynchronizerNotificationStatus('test', true);
+        scope.$emit('diag', failureEvent);
+      });
+
+      it('should not trigger multiple notification for the same synchronizer', () => {
+        expect(xosNotification.notify).not.toHaveBeenCalled();
+      });
+    });
+  });
+
+});
\ No newline at end of file
diff --git a/views/ngXosViews/synchronizerNotifier/src/css/main.css b/views/ngXosViews/synchronizerNotifier/src/css/main.css
new file mode 100644
index 0000000..88a08e7
--- /dev/null
+++ b/views/ngXosViews/synchronizerNotifier/src/css/main.css
@@ -0,0 +1,14 @@
+#xosSynchronizerNotifier {
+  float: left; }
+  #xosSynchronizerNotifier .alert {
+    margin-bottom: 0px !important; }
+  #xosSynchronizerNotifier .sync-status-container {
+    position: relative;
+    z-index: 200; }
+  #xosSynchronizerNotifier .notification-panel {
+    position: absolute;
+    width: 200px; }
+  #xosSynchronizerNotifier sync-status .badge.success {
+    background-color: #5cb85c; }
+  #xosSynchronizerNotifier sync-status .badge.warning {
+    background-color: #f0ad4e; }
diff --git a/views/ngXosViews/synchronizerNotifier/src/index.html b/views/ngXosViews/synchronizerNotifier/src/index.html
new file mode 100644
index 0000000..cb9b7b5
--- /dev/null
+++ b/views/ngXosViews/synchronizerNotifier/src/index.html
@@ -0,0 +1,35 @@
+<!-- browserSync -->
+<!-- bower:css -->
+<link rel="stylesheet" href="vendor/bootstrap-css/css/bootstrap.min.css" />
+<link rel="stylesheet" href="vendor/angular-chart.js/dist/angular-chart.css" />
+<!-- endbower -->
+<!-- endcss -->
+<!-- inject:css -->
+<link rel="stylesheet" href="/css/main.css">
+<link rel="stylesheet" href="/../../../xos/core/static/xosNgLib.css">
+<!-- endinject -->
+
+<div id="xosSynchronizerNotifier">
+  <sync-status></sync-status>
+</div>
+
+<!-- bower:js -->
+<script src="vendor/jquery/dist/jquery.js"></script>
+<script src="vendor/angular/angular.js"></script>
+<script src="vendor/angular-mocks/angular-mocks.js"></script>
+<script src="vendor/angular-ui-router/release/angular-ui-router.js"></script>
+<script src="vendor/angular-cookies/angular-cookies.js"></script>
+<script src="vendor/angular-animate/angular-animate.js"></script>
+<script src="vendor/angular-resource/angular-resource.js"></script>
+<script src="vendor/lodash/lodash.js"></script>
+<script src="vendor/bootstrap-css/js/bootstrap.min.js"></script>
+<script src="vendor/Chart.js/Chart.js"></script>
+<script src="vendor/angular-chart.js/dist/angular-chart.js"></script>
+<script src="vendor/d3/d3.js"></script>
+<script src="vendor/angular-recursion/angular-recursion.js"></script>
+<!-- endbower -->
+<!-- endjs -->
+<!-- inject:js -->
+<script src="/../../../xos/core/xoslib/static/js/vendor/ngXosHelpers.js"></script>
+<script src="/.tmp/main.js"></script>
+<!-- endinject -->
\ No newline at end of file
diff --git a/views/ngXosViews/synchronizerNotifier/src/js/main.js b/views/ngXosViews/synchronizerNotifier/src/js/main.js
new file mode 100644
index 0000000..f65c4d1
--- /dev/null
+++ b/views/ngXosViews/synchronizerNotifier/src/js/main.js
@@ -0,0 +1,135 @@
+'use strict';
+
+angular.module('xos.synchronizerNotifier', [
+  'ngResource',
+  'ngCookies',
+  'xos.helpers'
+])
+.run(function($rootScope){
+  $rootScope.$on('$locationChangeStart', function(event) {
+    event.preventDefault();
+  });
+})
+.service('Diag', function($rootScope, $http, $q, $interval){
+
+  let isRunning = false;
+
+  this.getDiags = () => {
+    let d = $q.defer();
+    $http.get('/api/core/diags')
+    .then(res => {
+      d.resolve(res.data);
+    })
+    .catch(err => {
+      d.reject(err);
+    });
+
+    return d.promise;
+  };
+
+  this.sendEvents = (diags) => {
+    diags.forEach(d => {
+      let status = JSON.parse(d.backend_register);
+      status.last_run = new Date(status.last_run * 1000);
+      status.last_duration = status.last_duration * 1000;
+      status.last_synchronizer_start = new Date(status.last_synchronizer_start * 1000);
+      status.last_syncrecord_start = status.last_syncrecord_start ? new Date(status.last_syncrecord_start * 1000) : null;
+      $rootScope.$broadcast(`diag`, {
+        name: d.name,
+        updated: d.updated,
+        info: status,
+        status: this.getSyncStatus(status)
+      });
+    });
+  };
+
+  this.start = () => {
+    isRunning = true;
+    this.getDiags()
+    .then(diags => {
+      this.sendEvents(diags);
+    });
+    return isRunning;
+  };
+
+  this.stop = () => {
+    isRunning = false;
+    return isRunning;
+  };
+
+  this.getSyncStatus = (status) => {
+
+    const now = new Date();
+    const gap = 15 * 60 * 1000; /* ms */
+    // const gap = 1 * 60 * 1000; // for demo use 1 minute
+    // if all of this values are older than 15 min,
+    // probably something is wrong
+    if (
+      (now - status.last_synchronizer_start) > gap &&
+      (now - status.last_syncrecord_start) > gap &&
+      (now - status.last_run) > gap
+    ){
+      return false;
+    }
+    else{
+      return true;
+    }
+  }
+
+  $interval(() => {
+    if(isRunning){
+      this.getDiags()
+      .then(diags => {
+        this.sendEvents(diags);
+      });
+    }
+  }, 5 * 60 * 1000);
+})
+.directive('syncStatus', function() {
+  return {
+    restrict: 'E',
+    scope: {},
+    bindToController: true,
+    controllerAs: 'vm',
+    templateUrl: 'templates/sync-status.tpl.html',
+    controller: function($log, $rootScope, Diag, xosNotification, XosUserPrefs){
+      Diag.start();
+      // to debug set this to true,
+      // the panel will be opened by default
+      // this.showNotificationPanel = true;
+      this.synchronizers = {};
+
+      this.showNoSync = true;
+
+      $rootScope.$on('diag', (e, d) => {
+        this.synchronizers[d.name] = d;
+
+        // if errored
+        if(!d.status){
+          // and not already notified
+          if(!XosUserPrefs.getSynchronizerNotificationStatus(d.name)){
+            xosNotification.notify('CORD Synchronizer', {
+              icon: '/static/cord-logo.png',
+              body: `The ${d.name} synchronizer has not performed actions in the last 15 minutes.`
+            });
+          }
+          XosUserPrefs.setSynchronizerNotificationStatus(d.name, true);
+        }
+        else {
+          XosUserPrefs.setSynchronizerNotificationStatus(d.name, false);
+        }
+
+        // hide list if empty
+        this.showNoSync = false;
+        if(Object.keys(this.synchronizers).length === 0){
+          this.showNoSync = true;
+        }
+      });
+
+    }
+  }
+});
+
+angular.element(document).ready(function() {
+  angular.bootstrap('#xosSynchronizerNotifier', ['xos.synchronizerNotifier']);
+});
\ No newline at end of file
diff --git a/views/ngXosViews/synchronizerNotifier/src/sass/main.scss b/views/ngXosViews/synchronizerNotifier/src/sass/main.scss
new file mode 100644
index 0000000..d101d76
--- /dev/null
+++ b/views/ngXosViews/synchronizerNotifier/src/sass/main.scss
@@ -0,0 +1,32 @@
+@import '../../../../style/sass/lib/_variables.scss';
+
+#xosSynchronizerNotifier {
+  
+  float: left;
+
+  .alert {
+    margin-bottom: 0px !important;
+  }
+
+  .sync-status-container {
+    position: relative;
+    z-index: 200;
+  }
+
+  .notification-panel {
+    position: absolute;
+    width: 200px;
+  }
+
+  sync-status {
+    .badge {
+      &.success {
+        background-color: $brand-success;
+      }
+
+      &.warning {
+        background-color: $brand-warning;
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/views/ngXosViews/synchronizerNotifier/src/templates/sync-status.tpl.html b/views/ngXosViews/synchronizerNotifier/src/templates/sync-status.tpl.html
new file mode 100644
index 0000000..cbd794e
--- /dev/null
+++ b/views/ngXosViews/synchronizerNotifier/src/templates/sync-status.tpl.html
@@ -0,0 +1,21 @@
+<div class="sync-status-container">
+  <div class="btn btn-default" ng-click="vm.showNotificationPanel = !vm.showNotificationPanel">
+    <i class="glyphicon glyphicon-inbox"></i>
+  </div>
+  <div class="notification-panel panel panel-default" ng-show="vm.showNotificationPanel">
+    <ul class="list-group" ng-show="!vm.showNoSync">
+      <li class="list-group-item" ng-repeat="(syncName, syncStatus) in vm.synchronizers">
+        <span class="badge" ng-class="{success: syncStatus.status, warning: !syncStatus.status}">
+          <span ng-show="syncStatus.status"><i class="glyphicon glyphicon-ok"></i></span>
+          <span ng-hide="syncStatus.status"><i class="glyphicon glyphicon-time"></i></span>
+        </span>
+        <b>{{syncName}}</b>
+        <br/>
+        <small><i>{{syncStatus.info.last_run | date:'mediumTime'}}</i></small>
+      </li>
+    </ul>
+    <div class="alert alert-info" ng-show="vm.showNoSync">
+      No syncronizers are running.
+    </div>
+  </div>
+</div>
diff --git a/views/ngXosViews/tenant/.bowerrc b/views/ngXosViews/tenant/.bowerrc
new file mode 100644
index 0000000..e491038
--- /dev/null
+++ b/views/ngXosViews/tenant/.bowerrc
@@ -0,0 +1,3 @@
+{
+  "directory": "src/vendor/"
+}
\ No newline at end of file
diff --git a/views/ngXosViews/tenant/.eslintrc b/views/ngXosViews/tenant/.eslintrc
new file mode 100644
index 0000000..f9a952f
--- /dev/null
+++ b/views/ngXosViews/tenant/.eslintrc
@@ -0,0 +1,42 @@
+{
+    "ecmaFeatures": {
+        "blockBindings": true,
+        "forOf": true,
+        "destructuring": true,
+        "arrowFunctions": true,
+        "templateStrings": true
+    },
+    "env": { 
+        "browser": true,
+        "node": true,
+        "es6": true
+    },
+    "plugins": [
+        //"angular"
+    ],
+    "rules": {
+        "quotes": [2, "single"],
+        "camelcase": [0, {"properties": "always"}],
+        "no-underscore-dangle": 1,
+        "eqeqeq": [2, "smart"],
+        "no-alert": 1,
+        "key-spacing": [1, { "beforeColon": false, "afterColon": true }],
+        "indent": [2, 2],
+        "no-irregular-whitespace": 1,
+        "eol-last": 0,
+        "max-nested-callbacks": [2, 4],
+        "comma-spacing": [1, {"before": false, "after": true}],
+        "no-trailing-spaces": [1, { skipBlankLines: true }],
+        "no-unused-vars": [1, {"vars": "all", "args": "after-used"}],
+        "new-cap": 0,
+
+        //"angular/ng_module_name": [2, '/^xos\.*[a-z]*$/'],
+        //"angular/ng_controller_name": [2, '/^[a-z].*Ctrl$/'],
+        //"angular/ng_service_name": [2, '/^[A-Z].*Service$/'],
+        //"angular/ng_directive_name": [2, '/^[a-z]+[[A-Z].*]*$/'],
+        //"angular/ng_di": [0, "function or array"]
+    },
+    "globals" :{
+        "angular": true
+    } 
+}
\ No newline at end of file
diff --git a/views/ngXosViews/tenant/.gitignore b/views/ngXosViews/tenant/.gitignore
new file mode 100644
index 0000000..567aee4
--- /dev/null
+++ b/views/ngXosViews/tenant/.gitignore
@@ -0,0 +1,6 @@
+dist/
+src/vendor
+.tmp
+node_modules
+npm-debug.log
+dist/
\ No newline at end of file
diff --git a/views/ngXosViews/tenant/bower.json b/views/ngXosViews/tenant/bower.json
new file mode 100644
index 0000000..c37483b
--- /dev/null
+++ b/views/ngXosViews/tenant/bower.json
@@ -0,0 +1,32 @@
+{
+  "name": "xos-tenant",
+  "version": "0.0.0",
+  "authors": [
+    " <>"
+  ],
+  "description": "The tenant view",
+  "license": "MIT",
+  "ignore": [
+    "**/.*",
+    "node_modules",
+    "bower_components",
+    "static/js/vendor/",
+    "test",
+    "tests"
+  ],
+  "dependencies": {},
+  "devDependencies": {
+    "jquery": "2.1.4",
+    "angular-mocks": "1.4.7",
+    "angular": "1.4.7",
+    "angular-ui-router": "0.2.15",
+    "angular-cookies": "1.4.7",
+    "angular-animate": "1.4.7",
+    "angular-resource": "1.4.7",
+    "lodash": "~4.11.1",
+    "bootstrap-css": "3.3.6",
+    "angular-chart.js": "~0.10.2",
+    "d3": "~3.5.17",
+    "angular-recursion": "^1.0.5"
+  }
+}
diff --git a/views/ngXosViews/tenant/env/default.js b/views/ngXosViews/tenant/env/default.js
new file mode 100644
index 0000000..e8b1522
--- /dev/null
+++ b/views/ngXosViews/tenant/env/default.js
@@ -0,0 +1,13 @@
+// This is a default configuration for your development environment.
+// You can duplicate this configuration for any of your Backend Environments.
+// Different configurations are loaded setting a NODE_ENV variable that contain the config file name.
+// `NODE_ENV=local npm start`
+//
+// If xoscsrftoken or xossessionid are not specified the browser value are used
+// (works only for local environment as both application are served on the same domain)
+
+module.exports = {
+  host: 'http://xos.dev:9999',
+  xoscsrftoken: 'FIdWwEI8XNESlpH3Wr6Hu5ORJs2EkIYl',
+  xossessionid: 'six66atpd31hh0b131zh9bc05t6f77d4'
+};
diff --git a/views/ngXosViews/tenant/gulp/build.js b/views/ngXosViews/tenant/gulp/build.js
new file mode 100644
index 0000000..8a7b279
--- /dev/null
+++ b/views/ngXosViews/tenant/gulp/build.js
@@ -0,0 +1,164 @@
+'use strict';
+
+// BUILD
+//
+// The only purpose of this gulpfile is to build a XOS view and copy the correct files into
+// .html => dashboards
+// .js (minified and concat) => static/js
+//
+// The template are parsed and added to js with angular $templateCache
+
+var gulp = require('gulp');
+var ngAnnotate = require('gulp-ng-annotate');
+var uglify = require('gulp-uglify');
+var templateCache = require('gulp-angular-templatecache');
+var runSequence = require('run-sequence');
+var concat = require('gulp-concat-util');
+var del = require('del');
+var wiredep = require('wiredep');
+var angularFilesort = require('gulp-angular-filesort');
+var _ = require('lodash');
+var eslint = require('gulp-eslint');
+var inject = require('gulp-inject');
+var rename = require('gulp-rename');
+var replace = require('gulp-replace');
+var postcss = require('gulp-postcss');
+var autoprefixer = require('autoprefixer');
+var mqpacker = require('css-mqpacker');
+var csswring = require('csswring');
+
+const TEMPLATE_FOOTER = `
+angular.module('xos.tenant')
+.run(['$location', function(a){
+  a.path('/');
+}])
+`
+
+module.exports = function(options){
+  
+  // delete previous builded file
+  gulp.task('clean', function(){
+    return del(
+      [
+        options.dashboards + 'xosTenant.html',
+        options.static + 'css/xosTenant.css'
+      ],
+      {force: true}
+    );
+  });
+
+  // minify css
+  gulp.task('css', function () {
+    var processors = [
+      autoprefixer({browsers: ['last 1 version']}),
+      mqpacker,
+      csswring
+    ];
+
+    gulp.src([
+      `${options.css}**/*.css`,
+      `!${options.css}dev.css`
+    ])
+    .pipe(postcss(processors))
+    .pipe(gulp.dest(options.tmp + '/css/'));
+  });
+
+  // copy css in correct folder
+  gulp.task('copyCss', ['wait'], function(){
+    return gulp.src([`${options.tmp}/css/*.css`])
+    .pipe(concat('xosTenant.css'))
+    .pipe(gulp.dest(options.static + 'css/'))
+  });
+
+  // compile and minify scripts
+  gulp.task('scripts', function() {
+    return gulp.src([
+      options.tmp + '**/*.js'
+    ])
+    .pipe(ngAnnotate())
+    .pipe(angularFilesort())
+    .pipe(concat('xosTenant.js'))
+    .pipe(concat.header('//Autogenerated, do not edit!!!\n'))
+    .pipe(concat.footer(TEMPLATE_FOOTER))
+    .pipe(uglify())
+    .pipe(gulp.dest(options.static + 'js/'));
+  });
+
+  // set templates in cache
+  gulp.task('templates', function(){
+    return gulp.src('./src/templates/*.html')
+      .pipe(templateCache({
+        module: 'xos.tenant',
+        root: 'templates/'
+      }))
+      .pipe(gulp.dest(options.tmp));
+  });
+
+  // copy html index to Django Folder
+  gulp.task('copyHtml', function(){
+    return gulp.src(options.src + 'index.html')
+      // remove dev dependencies from html
+      .pipe(replace(/<!-- bower:css -->(\n^<link.*)*\n<!-- endbower -->/gmi, ''))
+      .pipe(replace(/<!-- bower:js -->(\n^<script.*)*\n<!-- endbower -->/gmi, ''))
+      // injecting minified files
+      .pipe(
+        inject(
+          gulp.src([
+            options.static + 'js/vendor/xosTenantVendor.js',
+            options.static + 'js/xosTenant.js',
+            options.static + 'css/xosTenant.css'
+          ]),
+          {ignorePath: '/../../../xos/core/xoslib'}
+        )
+      )
+      .pipe(rename('xosTenant.html'))
+      .pipe(gulp.dest(options.dashboards));
+  });
+
+  // minify vendor js files
+  gulp.task('wiredep', function(){
+    var bowerDeps = wiredep().js;
+    if(!bowerDeps){
+      return;
+    }
+
+    // remove angular (it's already loaded)
+    _.remove(bowerDeps, function(dep){
+      return dep.indexOf('angular/angular.js') !== -1;
+    });
+
+    return gulp.src(bowerDeps)
+      .pipe(concat('xosTenantVendor.js'))
+      .pipe(uglify())
+      .pipe(gulp.dest(options.static + 'js/vendor/'));
+  });
+
+  gulp.task('lint', function () {
+    return gulp.src(['src/js/**/*.js'])
+      .pipe(eslint())
+      .pipe(eslint.format())
+      .pipe(eslint.failAfterError());
+  });
+
+  gulp.task('wait', function (cb) {
+    // setTimeout could be any async task
+    setTimeout(function () {
+      cb();
+    }, 1000);
+  });
+
+  gulp.task('build', function() {
+    runSequence(
+      'clean',
+      'sass',
+      'templates',
+      'babel',
+      'scripts',
+      'wiredep',
+      'css',
+      'copyCss',
+      'copyHtml',
+      'cleanTmp'
+    );
+  });
+};
\ No newline at end of file
diff --git a/views/ngXosViews/tenant/gulp/server.js b/views/ngXosViews/tenant/gulp/server.js
new file mode 100644
index 0000000..c1f7608
--- /dev/null
+++ b/views/ngXosViews/tenant/gulp/server.js
@@ -0,0 +1,168 @@
+'use strict';
+
+var gulp = require('gulp');
+var browserSync = require('browser-sync').create();
+var inject = require('gulp-inject');
+var runSequence = require('run-sequence');
+var angularFilesort = require('gulp-angular-filesort');
+var babel = require('gulp-babel');
+var wiredep = require('wiredep').stream;
+var httpProxy = require('http-proxy');
+var del = require('del');
+var sass = require('gulp-sass');
+
+const environment = process.env.NODE_ENV;
+
+if (environment){
+  var conf = require(`../env/${environment}.js`);
+}
+else{
+  var conf = require('../env/default.js')
+}
+
+var proxy = httpProxy.createProxyServer({
+  target: conf.host || 'http://0.0.0.0:9999'
+});
+
+
+proxy.on('error', function(error, req, res) {
+  res.writeHead(500, {
+    'Content-Type': 'text/plain'
+  });
+
+  console.error('[Proxy]', error);
+});
+
+module.exports = function(options){
+
+  gulp.task('browser', function() {
+    browserSync.init({
+      startPath: '#/',
+      snippetOptions: {
+        rule: {
+          match: /<!-- browserSync -->/i
+        }
+      },
+      server: {
+        baseDir: options.src,
+        routes: {
+          '/xos/core/xoslib/static/js/vendor': options.helpers,
+          '/xos/core/static': options.static + '../../static/'
+        },
+        middleware: function(req, res, next){
+          if(
+            // to be removed, deprecated API
+            // req.url.indexOf('/xos/') !== -1 ||
+             req.url.indexOf('/xoslib/tenant') !== -1 ||
+            // req.url.indexOf('/hpcapi/') !== -1 ||
+            req.url.indexOf('/api/') !== -1
+          ){
+            if(conf.xoscsrftoken && conf.xossessionid){
+              req.headers.cookie = `xoscsrftoken=${conf.xoscsrftoken}; xossessionid=${conf.xossessionid}`;
+              req.headers['x-csrftoken'] = conf.xoscsrftoken;
+            }
+            proxy.web(req, res);
+          }
+          else{
+            next();
+          }
+        }
+      }
+    });
+
+    gulp.watch(options.src + 'js/**/*.js', ['js-watch']);
+    gulp.watch(options.src + 'vendor/**/*.js', ['bower'], function(){
+      browserSync.reload();
+    });
+    gulp.watch(options.src + '**/*.html', function(){
+      browserSync.reload();
+    });
+    gulp.watch(options.css + '**/*.css', function(){
+      browserSync.reload();
+    });
+    gulp.watch(`${options.sass}/**/*.scss`, ['sass'], function(){
+      browserSync.reload();
+    });
+
+    gulp.watch([
+      options.helpers + 'ngXosHelpers.js',
+      options.static + '../../static/xosNgLib.css'
+    ], function(){
+      browserSync.reload();
+    });
+  });
+
+  // compile sass
+  gulp.task('sass', function () {
+    return gulp.src(`${options.sass}/**/*.scss`)
+      .pipe(sass().on('error', sass.logError))
+      .pipe(gulp.dest(options.css));
+  });
+
+  // transpile js with sourceMaps
+  gulp.task('babel', function(){
+    return gulp.src(options.scripts + '**/*.js')
+      .pipe(babel({sourceMaps: true}))
+      .pipe(gulp.dest(options.tmp));
+  });
+
+  // inject scripts
+  gulp.task('injectScript', ['cleanTmp', 'babel'], function(){
+    return gulp.src(options.src + 'index.html')
+      .pipe(
+        inject(
+          gulp.src([
+            options.tmp + '**/*.js',
+            options.helpers + 'ngXosHelpers.js'
+          ])
+          .pipe(angularFilesort()),
+          {
+            ignorePath: [options.src, '/../../ngXosLib']
+          }
+        )
+      )
+      .pipe(gulp.dest(options.src));
+  });
+
+  // inject CSS
+  gulp.task('injectCss', function(){
+    return gulp.src(options.src + 'index.html')
+      .pipe(
+        inject(
+          gulp.src([
+            options.src + 'css/*.css',
+            options.static + '../../static/xosNgLib.css'
+          ]),
+          {
+            ignorePath: [options.src]
+          }
+          )
+        )
+      .pipe(gulp.dest(options.src));
+  });
+
+  // inject bower dependencies with wiredep
+  gulp.task('bower', function () {
+    return gulp.src(options.src + 'index.html')
+    .pipe(wiredep({devDependencies: true}))
+    .pipe(gulp.dest(options.src));
+  });
+
+  gulp.task('js-watch', ['injectScript'], function(){
+    browserSync.reload();
+  });
+
+  gulp.task('cleanTmp', function(){
+    return del([options.tmp + '**/*']);
+  });
+
+  gulp.task('serve', function() {
+    runSequence(
+      'sass',
+      'bower',
+      'injectScript',
+      'injectCss',
+      ['browser']
+    );
+  });
+};
diff --git a/views/ngXosViews/tenant/gulpfile.js b/views/ngXosViews/tenant/gulpfile.js
new file mode 100644
index 0000000..08df554
--- /dev/null
+++ b/views/ngXosViews/tenant/gulpfile.js
@@ -0,0 +1,26 @@
+'use strict';
+
+var gulp = require('gulp');
+var wrench = require('wrench');
+
+var options = {
+  src: 'src/',
+  css: 'src/css/',
+  sass: 'src/sass/',
+  scripts: 'src/js/',
+  tmp: 'src/.tmp',
+  dist: 'dist/',
+  api: '../../ngXosLib/api/',
+  helpers: '../../../xos/core/xoslib/static/js/vendor/',
+  static: '../../../xos/core/xoslib/static/', // this is the django static folder
+  dashboards: '../../../xos/core/xoslib/dashboards/' // this is the django html folder
+};
+
+wrench.readdirSyncRecursive('./gulp')
+.map(function(file) {
+  require('./gulp/' + file)(options);
+});
+
+gulp.task('default', function () {
+  gulp.start('build');
+});
diff --git a/views/ngXosViews/tenant/karma.conf.js b/views/ngXosViews/tenant/karma.conf.js
new file mode 100644
index 0000000..4123be9
--- /dev/null
+++ b/views/ngXosViews/tenant/karma.conf.js
@@ -0,0 +1,88 @@
+// Karma configuration
+// Generated on Tue Oct 06 2015 09:27:10 GMT+0000 (UTC)
+
+/* eslint indent: [2,2], quotes: [2, "single"]*/
+
+/*eslint-disable*/
+var wiredep = require('wiredep');
+var path = require('path');
+
+var bowerComponents = wiredep( {devDependencies: true} )[ 'js' ].map(function( file ){
+  return path.relative(process.cwd(), file);
+});
+
+module.exports = function(config) {
+/*eslint-enable*/
+  config.set({
+
+    // base path that will be used to resolve all patterns (eg. files, exclude)
+    basePath: '',
+
+
+    // frameworks to use
+    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
+    frameworks: ['jasmine'],
+
+
+    // list of files / patterns to load in the browser
+    files: bowerComponents.concat([
+      '../../../xos/core/xoslib/static/js/vendor/ngXosVendor.js',
+      '../../../xos/core/xoslib/static/js/vendor/ngXosHelpers.js',
+      'src/js/**/*.js',
+      'spec/**/*.mock.js',
+      'spec/**/*.test.js',
+      'src/**/*.html'
+    ]),
+
+
+    // list of files to exclude
+    exclude: [
+    ],
+
+
+    // preprocess matching files before serving them to the browser
+    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
+    preprocessors: {
+      'src/js/**/*.js': ['babel'],
+      'spec/**/*.test.js': ['babel'],
+      'src/**/*.html': ['ng-html2js']
+    },
+
+    ngHtml2JsPreprocessor: {
+      stripPrefix: 'src/', //strip the src path from template url (http://stackoverflow.com/questions/22869668/karma-unexpected-request-when-testing-angular-directive-even-with-ng-html2js)
+      moduleName: 'templates' // define the template module name
+    },
+
+    // test results reporter to use
+    // possible values: 'dots', 'progress'
+    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
+    reporters: ['mocha'],
+
+
+    // web server port
+    port: 9876,
+
+
+    // enable / disable colors in the output (reporters and logs)
+    colors: true,
+
+
+    // level of logging
+    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+    logLevel: config.LOG_INFO,
+
+
+    // enable / disable watching file and executing tests whenever any file changes
+    autoWatch: true,
+
+
+    // start these browsers
+    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
+    browsers: ['PhantomJS'],
+
+
+    // Continuous Integration mode
+    // if true, Karma captures browsers, runs the tests and exits
+    singleRun: false
+  });
+};
diff --git a/views/ngXosViews/tenant/package.json b/views/ngXosViews/tenant/package.json
new file mode 100644
index 0000000..ed04285
--- /dev/null
+++ b/views/ngXosViews/tenant/package.json
@@ -0,0 +1,63 @@
+{
+  "name": "xos-tenant",
+  "version": "1.0.0",
+  "description": "Angular Application for XOS, created with generator-xos",
+  "scripts": {
+    "prestart": "npm install && bower install",
+    "start": "gulp serve",
+    "prebuild": "npm install && bower install",
+    "build": "gulp",
+    "test": "karma start",
+    "test:ci": "karma start --single-run",
+    "lint": "eslint src/js/"
+  },
+  "keywords": [
+    "XOS",
+    "Angular",
+    "XOSlib"
+  ],
+  "author": "",
+  "license": "MIT",
+  "dependencies": {},
+  "devDependencies": {
+    "autoprefixer": "^6.3.3",
+    "browser-sync": "^2.9.11",
+    "css-mqpacker": "^4.0.0",
+    "csswring": "^4.2.1",
+    "del": "^2.0.2",
+    "easy-mocker": "^1.2.0",
+    "eslint": "^1.8.0",
+    "eslint-plugin-angular": "linkmesrl/eslint-plugin-angular",
+    "gulp": "^3.9.0",
+    "gulp-angular-filesort": "^1.1.1",
+    "gulp-angular-templatecache": "^1.8.0",
+    "gulp-babel": "^5.3.0",
+    "gulp-concat": "^2.6.0",
+    "gulp-concat-util": "^0.5.5",
+    "gulp-eslint": "^1.0.0",
+    "gulp-inject": "^3.0.0",
+    "gulp-minify-html": "^1.0.4",
+    "gulp-ng-annotate": "^1.1.0",
+    "gulp-postcss": "^6.0.1",
+    "gulp-rename": "^1.2.2",
+    "gulp-replace": "^0.5.4",
+    "gulp-sass": "^2.2.0",
+    "gulp-uglify": "^1.4.2",
+    "http-proxy": "^1.12.0",
+    "ink-docstrap": "^0.5.2",
+    "jasmine-core": "~2.3.4",
+    "karma": "^0.13.14",
+    "karma-babel-preprocessor": "~5.2.2",
+    "karma-coverage": "^0.5.3",
+    "karma-jasmine": "~0.3.6",
+    "karma-mocha-reporter": "~1.1.1",
+    "karma-ng-html2js-preprocessor": "^0.2.0",
+    "karma-phantomjs-launcher": "~0.2.1",
+    "lodash": "^3.10.1",
+    "phantomjs": "^1.9.19",
+    "proxy-middleware": "^0.15.0",
+    "run-sequence": "^1.1.4",
+    "wiredep": "^3.0.0-beta",
+    "wrench": "^1.5.8"
+  }
+}
diff --git a/views/ngXosViews/tenant/spec/sample.test.js b/views/ngXosViews/tenant/spec/sample.test.js
new file mode 100644
index 0000000..bd0fd92
--- /dev/null
+++ b/views/ngXosViews/tenant/spec/sample.test.js
@@ -0,0 +1,54 @@
+'use strict';
+
+describe('Tenant View', () => {
+  
+  var scope, element, isolatedScope, httpBackend;
+
+  beforeEach(module('xos.tenant'));
+  beforeEach(module('templates'));
+
+  beforeEach(inject(function($httpBackend, $compile, $rootScope){
+    
+    httpBackend = $httpBackend;
+    // Setting up mock request
+    scope = $rootScope.$new();
+    element = angular.element('<users-list></users-list>');
+    $compile(element)(scope);
+    scope.$digest();
+    isolatedScope = element.isolateScope().vm;
+  }));
+describe('site list table',() =>{
+  it('site list ', () => {
+    var sites = [
+      {
+        'name':'Mysite',
+        'id':'1'
+
+      }];
+    var slices = [{
+      'site':'1',
+      'instance_total':1,
+      'instance_total_ready':1
+    },
+      {
+      'site':'1',
+      'instance_total':2,
+      'instance_total_ready':3
+    },
+      {
+      'site':'2',
+      'instance_total':'1',
+      'instance_total_ready':'2'
+    }];
+    var result = isolatedScope.returnData(sites,slices);
+    expect(result).toEqual([{
+      'name':'Mysite',
+      'id':'1',
+      'instance_total':3,
+      'instance_total_ready':4
+    }
+])
+//httpBackend.flush();
+  });
+});
+});
\ No newline at end of file
diff --git a/views/ngXosViews/tenant/src/css/main.css b/views/ngXosViews/tenant/src/css/main.css
new file mode 100644
index 0000000..a22d515
--- /dev/null
+++ b/views/ngXosViews/tenant/src/css/main.css
@@ -0,0 +1,2 @@
+#xosTenant a {
+  margin-bottom: 15px; }
diff --git a/views/ngXosViews/tenant/src/index.html b/views/ngXosViews/tenant/src/index.html
new file mode 100644
index 0000000..e1a83d4
--- /dev/null
+++ b/views/ngXosViews/tenant/src/index.html
@@ -0,0 +1,36 @@
+<!-- browserSync -->
+<!-- bower:css -->
+<link rel="stylesheet" href="vendor/bootstrap-css/css/bootstrap.min.css" />
+<link rel="stylesheet" href="vendor/angular-chart.js/dist/angular-chart.css" />
+<!-- endbower -->
+<!-- endcss -->
+<!-- inject:css -->
+<link rel="stylesheet" href="/css/main.css">
+<link rel="stylesheet" href="/../../../xos/core/static/xosNgLib.css">
+<!-- endinject -->
+
+
+<div ng-app="xos.tenant" id="xosTenant" class="container-fluid">
+   <div ui-view></div>
+</div>
+
+<!-- bower:js -->
+<script src="vendor/jquery/dist/jquery.js"></script>
+<script src="vendor/angular/angular.js"></script>
+<script src="vendor/angular-mocks/angular-mocks.js"></script>
+<script src="vendor/angular-ui-router/release/angular-ui-router.js"></script>
+<script src="vendor/angular-cookies/angular-cookies.js"></script>
+<script src="vendor/angular-animate/angular-animate.js"></script>
+<script src="vendor/angular-resource/angular-resource.js"></script>
+<script src="vendor/lodash/lodash.js"></script>
+<script src="vendor/bootstrap-css/js/bootstrap.min.js"></script>
+<script src="vendor/Chart.js/Chart.js"></script>
+<script src="vendor/angular-chart.js/dist/angular-chart.js"></script>
+<script src="vendor/d3/d3.js"></script>
+<script src="vendor/angular-recursion/angular-recursion.js"></script>
+<!-- endbower -->
+<!-- endjs -->
+<!-- inject:js -->
+<script src="/../../../xos/core/xoslib/static/js/vendor/ngXosHelpers.js"></script>
+<script src="/.tmp/main.js"></script>
+<!-- endinject -->
\ No newline at end of file
diff --git a/views/ngXosViews/tenant/src/js/main.js b/views/ngXosViews/tenant/src/js/main.js
new file mode 100644
index 0000000..65fc90d
--- /dev/null
+++ b/views/ngXosViews/tenant/src/js/main.js
@@ -0,0 +1,418 @@
+'use strict';
+
+angular.module('xos.tenant', [
+  'ngResource',
+  'ngCookies',
+  'ui.router',
+  'xos.helpers'
+])
+.config(($stateProvider) => {
+  $stateProvider
+  .state('user-list', {
+    url: '/',
+    template: '<users-list></users-list>'
+  })
+    .state('site', {
+      url: '/site/:id',
+      template: '<site-detail></site-detail>'
+
+    })
+    .state('createslice', {
+      url: '/site/:site/slice/:id?',
+      template: '<create-slice></create-slice>'
+
+    });
+})
+.config(function($httpProvider){
+  $httpProvider.interceptors.push('NoHyperlinks');
+})
+.directive('usersList', function(){
+  return {
+    //sites : {},
+    restrict: 'E',
+    scope: {},
+    bindToController: true,
+    controllerAs: 'vm',
+    templateUrl: 'templates/users-list.tpl.html',
+    controller: function(Sites, SlicesPlus){
+
+
+
+      this.tableConfig = {
+        columns: [
+          {
+            label: 'Site1',
+            prop: 'name',
+            link: item => `/#/site/${item.id}`
+          },
+          {
+            label: 'Allocated',
+            prop: 'instance_total'
+          },
+          {
+            label: 'Ready',
+            prop: 'instance_total_ready'
+          }
+        ]
+      };
+
+      // retrieving user list
+      Sites.query().$promise
+      .then((users) => {
+        this.sites = users;
+        return  SlicesPlus.query().$promise
+      })
+      .then((users) => {
+        this.slices = users;
+        this.site_list = this.returnData(this.sites, this.slices);
+      })
+      .catch((e) => {
+        throw new Error(e);
+      });
+
+
+      this.returnData = (sites, slices) => {
+        var i, j=0;
+        var site_list=[];
+
+        for(i = 0; i<sites.length; i++){
+          var instance_t = 0;
+          var instance_t_r = 0;
+          for(j=0;j<slices.length;j++){
+            if (sites[i].id != null && slices[j].site !=null && sites[i].id === slices[j].site){
+              instance_t = instance_t + slices[j].instance_total;
+              instance_t_r = instance_t_r + slices[j].instance_total_ready;
+            }
+          }
+          var data_sites = {
+            'id': sites[i].id,
+            'name': sites[i].name,
+            'instance_total': instance_t,
+            'instance_total_ready': instance_t_r
+          };
+          site_list.push(data_sites);
+        }
+        return site_list;
+      }
+    }
+  };
+})
+.directive('siteDetail', function(){
+  return {
+    restrict: 'E',
+    scope: {},
+    bindToController: true,
+    controllerAs: 'sl',
+    templateUrl: 'templates/slicelist.html',
+    controller: function(SlicesPlus, $stateParams){
+      this.siteId  = $stateParams.id;
+      this.tableConfig = {
+        columns: [
+          {
+            label: 'Slice List',
+            prop: 'name',
+            link: item => `/#/site/${item.site}/slice/${item.id}`
+          },
+          {
+            label: 'Allocated',
+            prop: 'instance_total'
+          },
+          {
+            label: 'Ready',
+            prop: 'instance_total_ready'
+          }
+        ]
+      };
+
+      // retrieving user list
+      SlicesPlus.query({
+        site: $stateParams.id
+      }).$promise
+      .then((users) => {
+        this.sliceList = users;
+      })
+      .catch((e) => {
+        throw new Error(e);
+      });
+    }
+  };
+})
+.directive('createSlice', function(){
+  return {
+    //sites : {},
+    restrict: 'E',
+    scope: {},
+    bindToController: true,
+    controllerAs: 'cs',
+    templateUrl: 'templates/createslice.html',
+    controller: function(Slices, SlicesPlus, Sites, Images, $stateParams, $http, $state, $q){
+      this.config = {
+        exclude: ['site', 'password', 'last_login', 'mount_data_sets', 'default_flavor', 'creator', 'exposed_ports', 'networks', 'omf_friendly', 'omf_friendly', 'no_sync', 'no_policy', 'lazy_blocked', 'write_protect', 'deleted', 'backend_status', 'backend_register', 'policed', 'enacted', 'updated', 'created', 'validators', 'humanReadableName'],
+        formName: 'SliceDetails',
+        feedback: {
+          show: false,
+          message: 'Form submitted successfully !!!',
+          type: 'success'
+        },
+        actions: [
+          {
+            label: 'Save',
+            icon: 'ok', // refers to bootstraps glyphicon
+            cb: (model, form) => { // receive the model
+              saveform(model, form).then(()=> {
+                $state.go('site', {id: this.model.site});
+              });
+            },
+            class: 'success'
+          },  {
+            label: 'Save and continue editing',
+            icon: 'ok', // refers to bootstraps glyphicon
+            cb: (model, form) => { // receive the model
+              saveform(model,form);
+            },
+            class: 'primary'
+          },
+          {
+            label: 'Save and add another',
+            icon: 'ok', // refers to bootstraps glyphicon
+            cb: (model, form) => {
+              saveform(model,form).then(()=> {
+                $state.go('createslice',{site : this.model.site,id : ''});
+              });
+            },
+            class: 'primary'
+          }
+        ],
+        fields:
+        {
+          site: {
+            label: 'Site',
+            type: 'select',
+            validators: { required: true},
+            hint: 'The Site this Slice belongs to',
+            options: []
+
+          },
+          name: {
+            label: 'Name',
+            type: 'string',
+            hint: 'The Name of the Slice',
+            validators: {
+              required: true
+            }
+          },
+          serviceClass: {
+            label: 'ServiceClass',
+            type: 'select',
+            validators: {required: true},
+            hint: 'The Site this Slice belongs to',
+            options: [
+              {
+                id: 1,
+                label: 'Best effort'
+              }
+            ]
+          },
+          enabled: {
+            label: 'Enabled',
+            type: 'boolean',
+            hint: 'Status for this Slice'
+          },
+          description: {
+            label: 'Description',
+            type: 'string',
+            hint: 'High level description of the slice and expected activities',
+            validators: {
+              required: false,
+              minlength: 10
+            }
+          },
+          service: {
+            label: 'Service',
+            type: 'select',
+            validators: { required: false},
+            options: [
+              {
+                id: 0,
+                label: '--------'
+              }
+            ]
+          },
+          slice_url: {
+            label: 'Slice url',
+            type: 'string',
+            validators: {
+              required: false,
+              minlength: 10
+            }
+          },
+          max_instances: {
+            label: 'Max Instances',
+            type: 'number',
+            validators: {
+              required: false,
+              min: 0
+            }
+          },
+          default_isolation: {
+            label: 'Default Isolation',
+            type: 'select',
+            validators: { required: false},
+            options: [
+              {
+                id: 'vm',
+                label: 'Virtual Machine'
+              },
+              {
+                id: 'container',
+                label: 'Container'
+              },
+              {
+                id: 'container_vm',
+                label: 'Container in VM'
+              }
+            ]
+          },
+          default_image: {
+            label: 'Default image',
+            type: 'select',
+            validators: { required: false},
+            options: []
+          },
+          network: {
+            label: 'Network',
+            type: 'select',
+            validators: { required: false},
+            options: [
+              {
+                id: 'default',
+                label: 'Default'
+              },
+              {
+                id: 'host',
+                label: 'Host'
+              },
+              {
+                id: 'bridged',
+                label: 'Bridged'
+              },
+              {
+                id: 'noauto',
+                label: 'No Automatic Networks'
+              }
+            ]
+          }
+
+        }
+      };
+      var data;
+      Images.query().$promise
+          .then((users) => {
+            this.users = users;
+            data = this.users;
+            this.optionValImg = this.setData(data, {field1: 'id', field2: 'name'});
+            this.config.fields['default_image'].options = this.optionValImg;
+          })
+          .catch((e) => {
+            throw new Error(e);
+          });
+
+      // Use this method for select by seting object in fields variable of format { field1 : "val1", field2 : "val2"}
+      this.setData = (data, fields) => {
+        var i;
+        var retObj=[];
+        for(i = 0; i<data.length; i++){
+          var optVal = {id: data[i][fields.field1], label: data[i][fields.field2]};
+          retObj.push(optVal);
+
+        }
+        return retObj;
+      };
+
+      // retrieving user list
+
+      if ($stateParams.id)
+      {
+        delete this.config.fields['site'];
+        this.config.exclude.push('site');
+
+        Slices.get({id: $stateParams.id}).$promise
+          .then((users) => {
+            this.users = users;
+            data = users;
+
+            this.model = data;
+          })
+          .catch((e) => {
+            throw new Error(e);
+          });
+      }
+      else
+      {
+
+
+        this.model = {};
+        $http.get('/xoslib/tenantview/').
+        success((data) => {
+          this.userList = data;
+          this.model['creator'] = this.userList.current_user_id;
+
+        });
+
+
+
+
+
+
+        Sites.query().$promise
+      .then((users) => {
+        this.users_site = users;
+        this.optionVal = this.setData(this.users_site, {field1: 'id', field2: 'name'});
+        this.config.fields['site'].options = this.optionVal;
+        //= this.optionVal;
+
+      })
+      .catch((e) => {
+        throw new Error(e);
+      });
+
+      }
+
+      var  saveform = (model,form) =>
+      { // receive the model
+        var deferred = $q.defer();
+        delete model.networks;
+        if (form.$valid )
+        {
+          if(model.id){
+            var pr = Slices.update(model).$promise;
+          }
+          else{
+            var pr = Slices.save(model).$promise;
+          }
+          pr.then((users) => {
+            this.model = users;
+            //data = users;
+            //this.model = this.users;
+            this.config.feedback.show = true;
+            deferred.resolve(this.model);
+          })
+          .catch((e) => {
+            this.config.feedback.show = true;
+            this.config.feedback.type='danger';
+            if(e.data && e.data.detail )
+            {
+              this.config.feedback.message = e.data.detail;
+            }
+            else {
+              this.config.feedback.message=e.statusText;
+            }
+            deferred.reject(e);
+          });
+        }
+
+        return  deferred.promise;
+      }
+    }
+  };
+});
\ No newline at end of file
diff --git a/views/ngXosViews/tenant/src/sass/main.scss b/views/ngXosViews/tenant/src/sass/main.scss
new file mode 100644
index 0000000..268f1b4
--- /dev/null
+++ b/views/ngXosViews/tenant/src/sass/main.scss
@@ -0,0 +1,9 @@
+@import '../../../../style/sass/lib/_variables.scss';
+@import '../../../../../views/style/sass/bootstrap/bootstrap/_variables.scss';
+
+
+#xosTenant {
+  a{
+    margin-bottom: $form-group-margin-bottom;
+  }
+}
\ No newline at end of file
diff --git a/views/ngXosViews/tenant/src/templates/createslice.html b/views/ngXosViews/tenant/src/templates/createslice.html
new file mode 100644
index 0000000..b04ee28
--- /dev/null
+++ b/views/ngXosViews/tenant/src/templates/createslice.html
@@ -0,0 +1,11 @@
+<!--<xos-table config="cs.tableConfig" data="cs.sites"></xos-table>-->
+<h2>Slice Details</h2>
+<hr></hr>
+<xos-form ng-model="cs.model" config="cs.config" ></xos-form>
+
+<!--<pre>-->
+<!--&lt;!&ndash;{{cs.users | json}}&ndash;&gt;-->
+
+<!--{{cs.users.name | json}}-->
+
+<!--</pre>-->
\ No newline at end of file
diff --git a/views/ngXosViews/tenant/src/templates/slicelist.html b/views/ngXosViews/tenant/src/templates/slicelist.html
new file mode 100644
index 0000000..fb42315
--- /dev/null
+++ b/views/ngXosViews/tenant/src/templates/slicelist.html
@@ -0,0 +1,6 @@
+<!--<span ng-bind="siteNameSe"></span>-->
+<!--<xos-field></xos-field>-->
+<a class="addlink btn btn-info" ui-sref="createslice({site: sl.siteId})"><i class="glyphicon glyphicon-plus-sign"></i> Create Slice</a>
+<xos-table config="sl.tableConfig" data="sl.sliceList"></xos-table>
+<!--<div ui-view="sliceDetails"></div>-->
+<!--<pre>{{sl.users[0].site}}</pre>-->
diff --git a/views/ngXosViews/tenant/src/templates/users-list.tpl.html b/views/ngXosViews/tenant/src/templates/users-list.tpl.html
new file mode 100644
index 0000000..1242734
--- /dev/null
+++ b/views/ngXosViews/tenant/src/templates/users-list.tpl.html
@@ -0,0 +1 @@
+<xos-table config="vm.tableConfig" data="vm.site_list"></xos-table>
\ No newline at end of file
diff --git a/views/ngXosViews/truckroll/.bowerrc b/views/ngXosViews/truckroll/.bowerrc
new file mode 100644
index 0000000..e491038
--- /dev/null
+++ b/views/ngXosViews/truckroll/.bowerrc
@@ -0,0 +1,3 @@
+{
+  "directory": "src/vendor/"
+}
\ No newline at end of file
diff --git a/views/ngXosViews/truckroll/.eslintrc b/views/ngXosViews/truckroll/.eslintrc
new file mode 100644
index 0000000..c852748
--- /dev/null
+++ b/views/ngXosViews/truckroll/.eslintrc
@@ -0,0 +1,42 @@
+{
+    "ecmaFeatures": {
+        "blockBindings": true,
+        "forOf": true,
+        "destructuring": true,
+        "arrowFunctions": true,
+        "templateStrings": true
+    },
+    "env": { 
+        "browser": true,
+        "node": true,
+        "es6": true
+    },
+    "plugins": [
+        //"angular"
+    ],
+    "rules": {
+        "quotes": [2, "single"],
+        "camelcase": [1, {"properties": "always"}],
+        "no-underscore-dangle": 1,
+        "eqeqeq": [2, "smart"],
+        "no-alert": 1,
+        "key-spacing": [1, { "beforeColon": false, "afterColon": true }],
+        "indent": [2, 2],
+        "no-irregular-whitespace": 1,
+        "eol-last": 0,
+        "max-nested-callbacks": [2, 4],
+        "comma-spacing": [1, {"before": false, "after": true}],
+        "no-trailing-spaces": [1, { skipBlankLines: true }],
+        "no-unused-vars": [1, {"vars": "all", "args": "after-used"}],
+        "new-cap": 0,
+
+        //"angular/ng_module_name": [2, '/^xos\.*[a-z]*$/'],
+        //"angular/ng_controller_name": [2, '/^[a-z].*Ctrl$/'],
+        //"angular/ng_service_name": [2, '/^[A-Z].*Service$/'],
+        //"angular/ng_directive_name": [2, '/^[a-z]+[[A-Z].*]*$/'],
+        //"angular/ng_di": [0, "function or array"]
+    },
+    "globals" :{
+        "angular": true
+    } 
+}
\ No newline at end of file
diff --git a/views/ngXosViews/truckroll/.gitignore b/views/ngXosViews/truckroll/.gitignore
new file mode 100644
index 0000000..567aee4
--- /dev/null
+++ b/views/ngXosViews/truckroll/.gitignore
@@ -0,0 +1,6 @@
+dist/
+src/vendor
+.tmp
+node_modules
+npm-debug.log
+dist/
\ No newline at end of file
diff --git a/views/ngXosViews/truckroll/bower.json b/views/ngXosViews/truckroll/bower.json
new file mode 100644
index 0000000..0cc10f7
--- /dev/null
+++ b/views/ngXosViews/truckroll/bower.json
@@ -0,0 +1,32 @@
+{
+  "name": "xos-truckroll",
+  "version": "0.0.0",
+  "authors": [
+    "Matteo Scandolo <teo@onlab.us>"
+  ],
+  "description": "The truckroll view",
+  "license": "MIT",
+  "ignore": [
+    "**/.*",
+    "node_modules",
+    "bower_components",
+    "static/js/vendor/",
+    "test",
+    "tests"
+  ],
+  "dependencies": {
+  },
+  "devDependencies": {
+    "jquery": "2.1.4",
+    "angular-mocks": "1.4.7",
+    "angular": "1.4.7",
+    "angular-ui-router": "0.2.15",
+    "angular-cookies": "1.4.7",
+    "angular-animate": "1.4.7",
+    "angular-resource": "1.4.7",
+    "lodash": "~4.11.1",
+    "bootstrap-css": "3.3.6",
+    "angular-chart.js": "~0.10.2",
+    "d3": "~3.5.17"
+  }
+}
diff --git a/views/ngXosViews/truckroll/gulp/build.js b/views/ngXosViews/truckroll/gulp/build.js
new file mode 100644
index 0000000..ff48fac
--- /dev/null
+++ b/views/ngXosViews/truckroll/gulp/build.js
@@ -0,0 +1,164 @@
+'use strict';
+
+// BUILD
+//
+// The only purpose of this gulpfile is to build a XOS view and copy the correct files into
+// .html => dashboards
+// .js (minified and concat) => static/js
+//
+// The template are parsed and added to js with angular $templateCache
+
+var gulp = require('gulp');
+var ngAnnotate = require('gulp-ng-annotate');
+var uglify = require('gulp-uglify');
+var templateCache = require('gulp-angular-templatecache');
+var runSequence = require('run-sequence');
+var concat = require('gulp-concat-util');
+var del = require('del');
+var wiredep = require('wiredep');
+var angularFilesort = require('gulp-angular-filesort');
+var _ = require('lodash');
+var eslint = require('gulp-eslint');
+var inject = require('gulp-inject');
+var rename = require('gulp-rename');
+var replace = require('gulp-replace');
+var postcss = require('gulp-postcss');
+var autoprefixer = require('autoprefixer');
+var mqpacker = require('css-mqpacker');
+var csswring = require('csswring');
+
+const TEMPLATE_FOOTER = `
+angular.module('xos.truckroll')
+.run(['$location', function(a){
+  a.path('/');
+}])
+`
+
+module.exports = function(options){
+  
+  // delete previous builded file
+  gulp.task('clean', function(){
+    return del(
+      [
+        options.dashboards + 'xosTruckroll.html',
+        options.static + 'css/xosTruckroll.css'
+      ],
+      {force: true}
+    );
+  });
+
+  // minify css
+  gulp.task('css', function () {
+    var processors = [
+      autoprefixer({browsers: ['last 1 version']}),
+      mqpacker,
+      csswring
+    ];
+
+    gulp.src([
+      `${options.css}**/*.css`,
+      `!${options.css}dev.css`
+    ])
+    .pipe(postcss(processors))
+    .pipe(gulp.dest(options.tmp + '/css/'));
+  });
+
+  // copy css in correct folder
+  gulp.task('copyCss', ['wait'], function(){
+    return gulp.src([`${options.tmp}/css/*.css`])
+    .pipe(concat('xosTruckroll.css'))
+    .pipe(gulp.dest(options.static + 'css/'))
+  });
+
+  // compile and minify scripts
+  gulp.task('scripts', function() {
+    return gulp.src([
+      options.tmp + '**/*.js'
+    ])
+    .pipe(ngAnnotate())
+    .pipe(angularFilesort())
+    .pipe(concat('xosTruckroll.js'))
+    .pipe(concat.header('//Autogenerated, do not edit!!!\n'))
+    .pipe(concat.footer(TEMPLATE_FOOTER))
+    .pipe(uglify())
+    .pipe(gulp.dest(options.static + 'js/'));
+  });
+
+  // set templates in cache
+  gulp.task('templates', function(){
+    return gulp.src('./src/templates/*.html')
+      .pipe(templateCache({
+        module: 'xos.truckroll',
+        root: 'templates/'
+      }))
+      .pipe(gulp.dest(options.tmp));
+  });
+
+  // copy html index to Django Folder
+  gulp.task('copyHtml', function(){
+    return gulp.src(options.src + 'index.html')
+      // remove dev dependencies from html
+      .pipe(replace(/<!-- bower:css -->(\n^<link.*)*\n<!-- endbower -->/gmi, ''))
+      .pipe(replace(/<!-- bower:js -->(\n^<script.*)*\n<!-- endbower -->/gmi, ''))
+      // injecting minified files
+      .pipe(
+        inject(
+          gulp.src([
+            options.static + 'js/vendor/xosTruckrollVendor.js',
+            options.static + 'js/xosTruckroll.js',
+            options.static + 'css/xosTruckroll.css'
+          ]),
+          {ignorePath: '/../../../xos/core/xoslib'}
+        )
+      )
+      .pipe(rename('xosTruckroll.html'))
+      .pipe(gulp.dest(options.dashboards));
+  });
+
+  // minify vendor js files
+  gulp.task('wiredep', function(){
+    var bowerDeps = wiredep().js;
+    if(!bowerDeps){
+      return;
+    }
+
+    // remove angular (it's already loaded)
+    _.remove(bowerDeps, function(dep){
+      return dep.indexOf('angular/angular.js') !== -1;
+    });
+
+    return gulp.src(bowerDeps)
+      .pipe(concat('xosTruckrollVendor.js'))
+      .pipe(uglify())
+      .pipe(gulp.dest(options.static + 'js/vendor/'));
+  });
+
+  gulp.task('lint', function () {
+    return gulp.src(['src/js/**/*.js'])
+      .pipe(eslint())
+      .pipe(eslint.format())
+      .pipe(eslint.failAfterError());
+  });
+
+  gulp.task('wait', function (cb) {
+    // setTimeout could be any async task
+    setTimeout(function () {
+      cb();
+    }, 1000);
+  });
+
+  gulp.task('build', function() {
+    runSequence(
+      'clean',
+      'sass',
+      'templates',
+      'babel',
+      'scripts',
+      'wiredep',
+      'css',
+      'copyCss',
+      'copyHtml',
+      'cleanTmp'
+    );
+  });
+};
\ No newline at end of file
diff --git a/views/ngXosViews/truckroll/gulp/server.js b/views/ngXosViews/truckroll/gulp/server.js
new file mode 100644
index 0000000..1e40a34
--- /dev/null
+++ b/views/ngXosViews/truckroll/gulp/server.js
@@ -0,0 +1,170 @@
+'use strict';
+
+var gulp = require('gulp');
+var browserSync = require('browser-sync').create();
+var inject = require('gulp-inject');
+var runSequence = require('run-sequence');
+var angularFilesort = require('gulp-angular-filesort');
+var babel = require('gulp-babel');
+var wiredep = require('wiredep').stream;
+var httpProxy = require('http-proxy');
+var del = require('del');
+var sass = require('gulp-sass');
+var fs = require('fs');
+var path = require('path');
+
+const environment = process.env.NODE_ENV;
+
+if(!fs.existsSync(path.join(__dirname, `../../../env/${environment || 'default'}.js`))){
+  if(!environment){
+    throw new Error('You should define a default.js config in /views/env folder.');
+  }
+  else{
+    throw new Error(`Since you are loading a custom environment, you should define a ${environment}.js config in /views/env folder.`);
+  }
+}
+
+var conf = require(path.join(__dirname, `../../../env/${environment || 'default'}.js`));
+
+var proxy = httpProxy.createProxyServer({
+  target: conf.host
+});
+
+
+proxy.on('error', function(error, req, res) {
+  res.writeHead(500, {
+    'Content-Type': 'text/plain'
+  });
+
+  console.error('[Proxy]', error);
+});
+
+module.exports = function(options){
+
+  gulp.task('browser', function() {
+    browserSync.init({
+      startPath: '#/',
+      snippetOptions: {
+        rule: {
+          match: /<!-- browserSync -->/i
+        }
+      },
+      server: {
+        baseDir: options.src,
+        routes: {
+          '/xos/core/xoslib/static/js/vendor': options.helpers,
+          '/xos/core/static': options.static + '../../static/'
+        },
+        middleware: function(req, res, next){
+          if(
+            req.url.indexOf('/api/') !== -1
+          ){
+            if(conf.xoscsrftoken && conf.xossessionid){
+              req.headers.cookie = `xoscsrftoken=${conf.xoscsrftoken}; xossessionid=${conf.xossessionid}`;
+              req.headers['x-csrftoken'] = conf.xoscsrftoken;
+            }
+            proxy.web(req, res);
+          }
+          else{
+            next();
+          }
+        }
+      }
+    });
+
+    gulp.watch(options.src + 'js/**/*.js', ['js-watch']);
+    gulp.watch(options.src + 'vendor/**/*.js', ['bower'], function(){
+      browserSync.reload();
+    });
+    gulp.watch(options.src + '**/*.html', function(){
+      browserSync.reload();
+    });
+    gulp.watch(options.css + '**/*.css', function(){
+      browserSync.reload();
+    });
+    gulp.watch(`${options.sass}/**/*.scss`, ['sass'], function(){
+      browserSync.reload();
+    });
+
+    gulp.watch([
+      options.helpers + 'ngXosHelpers.js',
+      options.static + '../../static/xosNgLib.css'
+    ], function(){
+      browserSync.reload();
+    });
+  });
+
+  // compile sass
+  gulp.task('sass', function () {
+    return gulp.src(`${options.sass}/**/*.scss`)
+      .pipe(sass().on('error', sass.logError))
+      .pipe(gulp.dest(options.css));
+  });
+
+  // transpile js with sourceMaps
+  gulp.task('babel', function(){
+    return gulp.src(options.scripts + '**/*.js')
+      .pipe(babel({sourceMaps: true}))
+      .pipe(gulp.dest(options.tmp));
+  });
+
+  // inject scripts
+  gulp.task('injectScript', ['cleanTmp', 'babel'], function(){
+    return gulp.src(options.src + 'index.html')
+      .pipe(
+        inject(
+          gulp.src([
+            options.tmp + '**/*.js',
+            options.helpers + 'ngXosHelpers.js'
+          ])
+          .pipe(angularFilesort()),
+          {
+            ignorePath: [options.src, '/../../ngXosLib']
+          }
+        )
+      )
+      .pipe(gulp.dest(options.src));
+  });
+
+  // inject CSS
+  gulp.task('injectCss', function(){
+    return gulp.src(options.src + 'index.html')
+      .pipe(
+        inject(
+          gulp.src([
+            options.src + 'css/*.css',
+            options.static + '../../static/xosNgLib.css'
+          ]),
+          {
+            ignorePath: [options.src]
+          }
+          )
+        )
+      .pipe(gulp.dest(options.src));
+  });
+
+  // inject bower dependencies with wiredep
+  gulp.task('bower', function () {
+    return gulp.src(options.src + 'index.html')
+    .pipe(wiredep({devDependencies: true}))
+    .pipe(gulp.dest(options.src));
+  });
+
+  gulp.task('js-watch', ['injectScript'], function(){
+    browserSync.reload();
+  });
+
+  gulp.task('cleanTmp', function(){
+    return del([options.tmp + '**/*']);
+  });
+
+  gulp.task('serve', function() {
+    runSequence(
+      'sass',
+      'bower',
+      'injectScript',
+      'injectCss',
+      ['browser']
+    );
+  });
+};
diff --git a/views/ngXosViews/truckroll/gulpfile.js b/views/ngXosViews/truckroll/gulpfile.js
new file mode 100644
index 0000000..08df554
--- /dev/null
+++ b/views/ngXosViews/truckroll/gulpfile.js
@@ -0,0 +1,26 @@
+'use strict';
+
+var gulp = require('gulp');
+var wrench = require('wrench');
+
+var options = {
+  src: 'src/',
+  css: 'src/css/',
+  sass: 'src/sass/',
+  scripts: 'src/js/',
+  tmp: 'src/.tmp',
+  dist: 'dist/',
+  api: '../../ngXosLib/api/',
+  helpers: '../../../xos/core/xoslib/static/js/vendor/',
+  static: '../../../xos/core/xoslib/static/', // this is the django static folder
+  dashboards: '../../../xos/core/xoslib/dashboards/' // this is the django html folder
+};
+
+wrench.readdirSyncRecursive('./gulp')
+.map(function(file) {
+  require('./gulp/' + file)(options);
+});
+
+gulp.task('default', function () {
+  gulp.start('build');
+});
diff --git a/views/ngXosViews/truckroll/karma.conf.js b/views/ngXosViews/truckroll/karma.conf.js
new file mode 100644
index 0000000..4123be9
--- /dev/null
+++ b/views/ngXosViews/truckroll/karma.conf.js
@@ -0,0 +1,88 @@
+// Karma configuration
+// Generated on Tue Oct 06 2015 09:27:10 GMT+0000 (UTC)
+
+/* eslint indent: [2,2], quotes: [2, "single"]*/
+
+/*eslint-disable*/
+var wiredep = require('wiredep');
+var path = require('path');
+
+var bowerComponents = wiredep( {devDependencies: true} )[ 'js' ].map(function( file ){
+  return path.relative(process.cwd(), file);
+});
+
+module.exports = function(config) {
+/*eslint-enable*/
+  config.set({
+
+    // base path that will be used to resolve all patterns (eg. files, exclude)
+    basePath: '',
+
+
+    // frameworks to use
+    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
+    frameworks: ['jasmine'],
+
+
+    // list of files / patterns to load in the browser
+    files: bowerComponents.concat([
+      '../../../xos/core/xoslib/static/js/vendor/ngXosVendor.js',
+      '../../../xos/core/xoslib/static/js/vendor/ngXosHelpers.js',
+      'src/js/**/*.js',
+      'spec/**/*.mock.js',
+      'spec/**/*.test.js',
+      'src/**/*.html'
+    ]),
+
+
+    // list of files to exclude
+    exclude: [
+    ],
+
+
+    // preprocess matching files before serving them to the browser
+    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
+    preprocessors: {
+      'src/js/**/*.js': ['babel'],
+      'spec/**/*.test.js': ['babel'],
+      'src/**/*.html': ['ng-html2js']
+    },
+
+    ngHtml2JsPreprocessor: {
+      stripPrefix: 'src/', //strip the src path from template url (http://stackoverflow.com/questions/22869668/karma-unexpected-request-when-testing-angular-directive-even-with-ng-html2js)
+      moduleName: 'templates' // define the template module name
+    },
+
+    // test results reporter to use
+    // possible values: 'dots', 'progress'
+    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
+    reporters: ['mocha'],
+
+
+    // web server port
+    port: 9876,
+
+
+    // enable / disable colors in the output (reporters and logs)
+    colors: true,
+
+
+    // level of logging
+    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+    logLevel: config.LOG_INFO,
+
+
+    // enable / disable watching file and executing tests whenever any file changes
+    autoWatch: true,
+
+
+    // start these browsers
+    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
+    browsers: ['PhantomJS'],
+
+
+    // Continuous Integration mode
+    // if true, Karma captures browsers, runs the tests and exits
+    singleRun: false
+  });
+};
diff --git a/views/ngXosViews/truckroll/package.json b/views/ngXosViews/truckroll/package.json
new file mode 100644
index 0000000..128a229
--- /dev/null
+++ b/views/ngXosViews/truckroll/package.json
@@ -0,0 +1,63 @@
+{
+  "name": "xos-truckroll",
+  "version": "1.0.0",
+  "description": "Angular Application for XOS, created with generator-xos",
+  "scripts": {
+    "prestart": "npm install && bower install",
+    "start": "gulp serve",
+    "prebuild": "npm install && bower install",
+    "build": "gulp",
+    "test": "karma start",
+    "test:ci": "karma start --single-run",
+    "lint": "eslint src/js/"
+  },
+  "keywords": [
+    "XOS",
+    "Angular",
+    "XOSlib"
+  ],
+  "author": "Matteo Scandolo",
+  "license": "MIT",
+  "dependencies": {},
+  "devDependencies": {
+    "autoprefixer": "^6.3.3",
+    "browser-sync": "^2.9.11",
+    "css-mqpacker": "^4.0.0",
+    "csswring": "^4.2.1",
+    "del": "^2.0.2",
+    "easy-mocker": "^1.2.0",
+    "eslint": "^1.8.0",
+    "eslint-plugin-angular": "linkmesrl/eslint-plugin-angular",
+    "gulp": "^3.9.0",
+    "gulp-angular-filesort": "^1.1.1",
+    "gulp-angular-templatecache": "^1.8.0",
+    "gulp-babel": "^5.3.0",
+    "gulp-concat": "^2.6.0",
+    "gulp-concat-util": "^0.5.5",
+    "gulp-eslint": "^1.0.0",
+    "gulp-inject": "^3.0.0",
+    "gulp-minify-html": "^1.0.4",
+    "gulp-ng-annotate": "^1.1.0",
+    "gulp-postcss": "^6.0.1",
+    "gulp-rename": "^1.2.2",
+    "gulp-replace": "^0.5.4",
+    "gulp-sass": "^2.2.0",
+    "gulp-uglify": "^1.4.2",
+    "http-proxy": "^1.12.0",
+    "ink-docstrap": "^0.5.2",
+    "jasmine-core": "~2.3.4",
+    "karma": "^0.13.14",
+    "karma-babel-preprocessor": "~5.2.2",
+    "karma-coverage": "^0.5.3",
+    "karma-jasmine": "~0.3.6",
+    "karma-mocha-reporter": "~1.1.1",
+    "karma-ng-html2js-preprocessor": "^0.2.0",
+    "karma-phantomjs-launcher": "~0.2.1",
+    "lodash": "^3.10.1",
+    "phantomjs": "^1.9.19",
+    "proxy-middleware": "^0.15.0",
+    "run-sequence": "^1.1.4",
+    "wiredep": "^3.0.0-beta",
+    "wrench": "^1.5.8"
+  }
+}
diff --git a/views/ngXosViews/truckroll/spec/sample.test.js b/views/ngXosViews/truckroll/spec/sample.test.js
new file mode 100644
index 0000000..52ebe84
--- /dev/null
+++ b/views/ngXosViews/truckroll/spec/sample.test.js
@@ -0,0 +1,34 @@
+'use strict';
+
+describe('The User List', () => {
+  
+  var scope, element, isolatedScope, httpBackend;
+
+  beforeEach(module('xos.truckroll'));
+  beforeEach(module('templates'));
+
+  beforeEach(inject(function($httpBackend, $compile, $rootScope){
+    
+    httpBackend = $httpBackend;
+    // Setting up mock request
+    $httpBackend.expectGET('/api/tenant/cord/subscriber/?no_hyperlinks=1').respond([
+      {
+        email: 'teo@onlab.us',
+        firstname: 'Matteo',
+        lastname: 'Scandolo' 
+      }
+    ]);
+  
+    scope = $rootScope.$new();
+    element = angular.element('<truckroll></truckroll>');
+    $compile(element)(scope);
+    scope.$digest();
+    isolatedScope = element.isolateScope().vm;
+  }));
+
+  it('should load 1 subscriber', () => {
+    httpBackend.flush();
+    expect(isolatedScope.subscribers.length).toBe(1);
+  });
+
+});
\ No newline at end of file
diff --git a/views/ngXosViews/truckroll/src/css/dev.css b/views/ngXosViews/truckroll/src/css/dev.css
new file mode 100644
index 0000000..5842388
--- /dev/null
+++ b/views/ngXosViews/truckroll/src/css/dev.css
@@ -0,0 +1,6 @@
+#xosTruckroll{
+  position: absolute;
+  top: 100px;
+  left: 200px;
+  width: 80%;
+}
\ No newline at end of file
diff --git a/views/ngXosViews/truckroll/src/css/main.css b/views/ngXosViews/truckroll/src/css/main.css
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/views/ngXosViews/truckroll/src/css/main.css
diff --git a/views/ngXosViews/truckroll/src/css/truckroll.css b/views/ngXosViews/truckroll/src/css/truckroll.css
new file mode 100644
index 0000000..8ac0369
--- /dev/null
+++ b/views/ngXosViews/truckroll/src/css/truckroll.css
@@ -0,0 +1,89 @@
+.row + .row {
+  margin-top: 20px;
+}
+
+/* ANIMATIONS */
+.animate-vertical.ng-hide-add {
+  animation:0.5s slideOutDown ease-in-out;
+}
+.animate-vertical.ng-hide-remove {
+  animation:0.5s slideInUp ease-in-out;
+}
+
+@keyframes slideInUp {
+  from {
+    transform: translate3d(0, 100%, 0);
+    opacity: 0;
+  }
+
+  to {
+    transform: translate3d(0, 0, 0);
+    opacity: 1;
+  }
+}
+
+
+@keyframes slideOutDown {
+  from {
+    transform: translate3d(0, 0, 0);
+    opacity: 1;
+  }
+
+  to {
+    opacity: 0;
+    transform: translate3d(0, 100%, 0);
+  }
+}
+
+/* LOADER */
+.loader {
+  font-size: 10px;
+  margin: 0 auto;
+  text-indent: -9999em;
+  width: 11em;
+  height: 11em;
+  border-radius: 50%;
+  background: #ffffff;
+  background: -moz-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
+  background: -webkit-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
+  background: -o-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
+  background: -ms-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
+  background: linear-gradient(to right, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
+  position: relative;
+  animation: load3 1.4s infinite linear;
+  transform: translateZ(0);
+}
+.loader:before {
+  width: 50%;
+  height: 50%;
+  background: #105E9E;
+  border-radius: 100% 0 0 0;
+  position: absolute;
+  top: 0;
+  left: 0;
+  content: '';
+}
+.loader:after {
+  background: #fff;
+  width: 75%;
+  height: 75%;
+  border-radius: 50%;
+  content: '';
+  margin: auto;
+  position: absolute;
+  top: 0;
+  left: 0;
+  bottom: 0;
+  right: 0;
+}
+
+@keyframes load3 {
+  0% {
+    -webkit-transform: rotate(0deg);
+    transform: rotate(0deg);
+  }
+  100% {
+    -webkit-transform: rotate(360deg);
+    transform: rotate(360deg);
+  }
+}
\ No newline at end of file
diff --git a/views/ngXosViews/truckroll/src/index.html b/views/ngXosViews/truckroll/src/index.html
new file mode 100644
index 0000000..bb4f072
--- /dev/null
+++ b/views/ngXosViews/truckroll/src/index.html
@@ -0,0 +1,36 @@
+<!-- browserSync -->
+<!-- bower:css -->
+<link rel="stylesheet" href="vendor/bootstrap-css/css/bootstrap.min.css" />
+<link rel="stylesheet" href="vendor/angular-chart.js/dist/angular-chart.css" />
+<!-- endbower -->
+<!-- endcss -->
+<!-- inject:css -->
+<link rel="stylesheet" href="/css/dev.css">
+<link rel="stylesheet" href="/css/main.css">
+<link rel="stylesheet" href="/css/truckroll.css">
+<link rel="stylesheet" href="/../../../xos/core/static/xosNgLib.css">
+<!-- endinject -->
+
+<div ng-app="xos.truckroll" id="xosTruckroll" class="container-fluid">
+  <div ui-view></div>
+</div>
+
+<!-- bower:js -->
+<script src="vendor/jquery/dist/jquery.js"></script>
+<script src="vendor/angular/angular.js"></script>
+<script src="vendor/angular-mocks/angular-mocks.js"></script>
+<script src="vendor/angular-ui-router/release/angular-ui-router.js"></script>
+<script src="vendor/angular-cookies/angular-cookies.js"></script>
+<script src="vendor/angular-animate/angular-animate.js"></script>
+<script src="vendor/angular-resource/angular-resource.js"></script>
+<script src="vendor/lodash/lodash.js"></script>
+<script src="vendor/bootstrap-css/js/bootstrap.min.js"></script>
+<script src="vendor/Chart.js/Chart.js"></script>
+<script src="vendor/angular-chart.js/dist/angular-chart.js"></script>
+<script src="vendor/d3/d3.js"></script>
+<!-- endbower -->
+<!-- endjs -->
+<!-- inject:js -->
+<script src="/../../../xos/core/xoslib/static/js/vendor/ngXosHelpers.js"></script>
+<script src="/.tmp/main.js"></script>
+<!-- endinject -->
\ No newline at end of file
diff --git a/views/ngXosViews/truckroll/src/js/main.js b/views/ngXosViews/truckroll/src/js/main.js
new file mode 100644
index 0000000..1004cb1
--- /dev/null
+++ b/views/ngXosViews/truckroll/src/js/main.js
@@ -0,0 +1,75 @@
+'use strict';
+
+angular.module('xos.truckroll', [
+  'ngResource',
+  'ngCookies',
+  'ui.router',
+  'xos.helpers'
+])
+.config(($stateProvider) => {
+  $stateProvider
+  .state('user-list', {
+    url: '/',
+    template: '<truckroll></truckroll>'
+  });
+})
+.config(function($httpProvider){
+  $httpProvider.interceptors.push('NoHyperlinks');
+})
+.directive('truckroll', function(){
+  return {
+    restrict: 'E',
+    scope: {},
+    bindToController: true,
+    controllerAs: 'vm',
+    templateUrl: 'templates/truckroll.tpl.html',
+    controller: function($timeout, $log, Subscribers, Truckroll){
+      Subscribers.query().$promise
+      .then((subscribers) => {
+        this.subscribers = subscribers;
+      });
+
+      this.loader = false;
+
+      this.runTest = () => {
+
+        // clean previous tests
+        delete this.truckroll.result;
+        delete this.truckroll.is_synced;
+        delete this.truckroll.result_code;
+        delete this.truckroll.backend_status;
+
+        const test = new Truckroll(this.truckroll);
+        this.loader = true;
+        test.$save()
+        .then((res) => {
+          this.waitForTest(res.id);
+        })
+      };
+
+      this.waitForTest = (id) => {
+        Truckroll.get({id: id}).$promise
+        .then((testResult) => {
+          // if error
+          // or
+          // if is synced
+          if(
+              testResult.backend_status.indexOf('2') >= 0 ||
+              (testResult.result_code && testResult.result_code.indexOf('2') >= 0) ||
+              testResult.is_synced
+            ){
+            this.truckroll = angular.copy(testResult);
+            this.loader = false;
+            Truckroll.delete({id: id});
+          }
+          // else keep polling
+          else{
+            $timeout(() => {
+              this.waitForTest(id);
+            }, 2000)
+          }
+        })
+      };
+    }
+  };
+});
\ No newline at end of file
diff --git a/views/ngXosViews/truckroll/src/sass/main.scss b/views/ngXosViews/truckroll/src/sass/main.scss
new file mode 100644
index 0000000..d87a953
--- /dev/null
+++ b/views/ngXosViews/truckroll/src/sass/main.scss
@@ -0,0 +1,5 @@
+@import '../../../../style/sass/lib/_variables.scss';
+
+#xosTruckroll {
+  
+}
\ No newline at end of file
diff --git a/views/ngXosViews/truckroll/src/templates/truckroll.tpl.html b/views/ngXosViews/truckroll/src/templates/truckroll.tpl.html
new file mode 100644
index 0000000..f0c2dbe
--- /dev/null
+++ b/views/ngXosViews/truckroll/src/templates/truckroll.tpl.html
@@ -0,0 +1,106 @@
+<div class="row">
+  <div class="col-xs-12">
+    <h2>Virtual Truck Roll</h2>
+    <p>Use this page to run test against your subscriber</p>
+  </div>
+</div>
+<form ng-submit="vm.runTest()">
+  <div class="row">
+    <div class="col-xs-12">
+      <label>Target:</label>
+    </div>
+    <div class="col-xs-12">
+      <select class="form-control" ng-model="vm.truckroll.target_id" ng-options="s.id as s.humanReadableName for s in vm.subscribers"></select>
+    </div>
+  </div>
+  <div class="row">
+    <div class="col-xs-12">
+      <label>Scope:</label>
+    </div>
+    <div class="col-xs-6">
+      <a 
+      ng-click="vm.truckroll.scope = 'container'"
+      ng-class="{'btn-default': vm.truckroll.scope !== 'container', 'btn-primary': vm.truckroll.scope === 'container'}"
+      class="btn btn-block"
+      >
+        Container
+      </a>
+    </div>
+    <div class="col-xs-6">
+      <a 
+      ng-click="vm.truckroll.scope = 'vm'"
+      ng-class="{'btn-default': vm.truckroll.scope !== 'vm', 'btn-primary': vm.truckroll.scope === 'vm'}"
+      class="btn btn-block"
+      >
+        VM
+      </a>
+    </div>
+  </div>
+  <div class="row">
+    <div class="col-xs-12">
+      <label>Test:</label>
+    </div>
+    <div class="col-xs-4">
+      <a 
+      ng-click="vm.truckroll.test = 'ping'"
+      ng-class="{'btn-default': vm.truckroll.test !== 'ping', 'btn-primary': vm.truckroll.test === 'ping'}"
+      class="btn btn-block">Ping</a>
+    </div>
+    <div class="col-xs-4">
+      <a 
+      ng-click="vm.truckroll.test = 'traceroute'"
+      ng-class="{'btn-default': vm.truckroll.test !== 'traceroute', 'btn-primary': vm.truckroll.test === 'traceroute'}"
+      class="btn btn-block">Traceroute</a>
+    </div>
+    <div class="col-xs-4">
+      <a 
+      ng-click="vm.truckroll.test = 'tcpdump'"
+      ng-class="{'btn-default': vm.truckroll.test !== 'tcpdump', 'btn-primary': vm.truckroll.test === 'tcpdump'}"
+      class="btn btn-block">Tcp Dump</a>
+    </div>
+  </div>
+  <div class="row">
+    <div class="col-xs-12">
+      <label>Argument:</label>
+    </div>
+    <div class="col-xs-12">
+      <input type="text" class="form-control" ng-model="vm.truckroll.argument" required />
+    </div>
+  </div>
+  <div class="row">
+    <div class="col-xs-12" ng-show="!vm.loader">
+      <button class="btn btn-success btn-block">Run test</button>
+    </div>
+  </div>
+</form>
+<div class="row">
+    <div class="col-xs-12 animate-vertical" ng-show="vm.loader">
+      <div class="loader"></div>
+    </div>
+  </div>
+  <div class="row" ng-hide="!vm.truckroll.result_code">
+    <div class="col-xs-12">
+      <label>Result Code</label>
+    </div>
+    <div class="col-xs-12">
+      <pre>{{vm.truckroll.result_code}}</pre>
+    </div>
+  </div>
+  <div class="row" ng-hide="!vm.truckroll.result">
+    <div class="col-xs-12">
+      <label>
+        Result:
+      </label>
+    </div>
+    <div class="col-xs-12">
+      <pre>{{vm.truckroll.result}}</pre>
+    </div>
+  </div>
+  <div class="row" ng-hide="!vm.truckroll.backend_status">
+    <div class="col-xs-12">
+      <label>Backend Status</label>
+    </div>
+    <div class="col-xs-12">
+      <pre>{{vm.truckroll.backend_status}}</pre>
+    </div>
+  </div>
\ No newline at end of file
diff --git a/views/npm-debug.log b/views/npm-debug.log
new file mode 100644
index 0000000..38c9da9
--- /dev/null
+++ b/views/npm-debug.log
@@ -0,0 +1,20 @@
+0 info it worked if it ends with ok
+1 verbose cli [ '/usr/bin/nodejs', '/usr/bin/npm', 'start' ]
+2 info using npm@3.6.0
+3 info using node@v5.7.0
+4 verbose stack Error: ENOENT: no such file or directory, open '/home/jeremy/xos/views/package.json'
+4 verbose stack     at Error (native)
+5 verbose cwd /home/jeremy/xos/views
+6 error Linux 4.2.0-19-generic
+7 error argv "/usr/bin/nodejs" "/usr/bin/npm" "start"
+8 error node v5.7.0
+9 error npm  v3.6.0
+10 error path /home/jeremy/xos/views/package.json
+11 error code ENOENT
+12 error errno -2
+13 error syscall open
+14 error enoent ENOENT: no such file or directory, open '/home/jeremy/xos/views/package.json'
+15 error enoent ENOENT: no such file or directory, open '/home/jeremy/xos/views/package.json'
+15 error enoent This is most likely not a problem with npm itself
+15 error enoent and is related to npm not being able to find a file.
+16 verbose exit [ -2, true ]
diff --git a/views/style/README.md b/views/style/README.md
new file mode 100644
index 0000000..7086fd9
--- /dev/null
+++ b/views/style/README.md
@@ -0,0 +1,28 @@
+# XOS Styles
+
+This folder holds style definition for XOS and a collection of tools usefull to work with them.
+
+## Setup
+
+The best way to work with XOS styling and appearance is to have the `frontend` configuration running locally on your machine. In this way most of the GUI files are shared (see below). To use the provided tools as they are XOS should be available at `http://xos.dev:9999`.
+
+Before start working on the UI you should also install the dependencies, so enter `xos/views/style/` and execute `npm install` (NodeJs is required).
+
+## Developing
+
+When your environment is ready you could start it with `npm start`, this command will:
+  - Whatch styles in `xos/views/style/sass` and compile them on change
+  - Reload the broser on file changes (for more details see `xos/views/style/bs-config.js`)
+
+## Shared files:
+Shared files are defined in `xos/configurations/frontend/docker-compose.yml`, for the `frontend` configuration they are:
+```
+  - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config
+  - ../../core/xoslib:/opt/xos/core/xoslib
+  - ../../core/static:/opt/xos/core/static
+  - ../../core/dashboard:/opt/xos/core/dashboard
+  - ../../core/templatetags:/opt/xos/core/templatetags
+  - ../../templates/admin:/opt/xos/templates/admin
+  - ../../configurations:/opt/xos/configurations
+  - ../../xos:/opt/xos/xos
+```
diff --git a/views/style/bs-config.js b/views/style/bs-config.js
new file mode 100644
index 0000000..b2eedc4
--- /dev/null
+++ b/views/style/bs-config.js
@@ -0,0 +1,15 @@
+module.exports = {
+  "files": [
+    '../../xos/core/dashboard/*.html',
+    '../../xos/core/xoslib/**/*.html',
+    '../../xos/core/xoslib/static/**/*.js',
+    '../../xos/core/xoslib/static/**/*.css',
+    '../../xos/core/dashboard/views/*.py',
+    '../../xos/core/views/*.py',
+    '../../xos/templates/**/*.html',
+    '../../xos/core/static/xos.css',
+    '../../xos/xos/**/*.py'
+  ],
+  proxy: "xos.dev:9999",
+  open: true
+};
diff --git a/views/style/package.json b/views/style/package.json
new file mode 100644
index 0000000..4da2c4d
--- /dev/null
+++ b/views/style/package.json
@@ -0,0 +1,14 @@
+{
+  "name": "xos-styling",
+  "version": "0.0.1",
+  "scripts": {
+    "server": "browser-sync start --config bs-config.js",
+    "styles": "node-sass -w -r --include-path --source-map-embed -o ../../xos/core/static/ ./sass/xos.scss",
+    "start": "concurrently \"npm run styles\" \"npm run server\""
+  },
+  "devDependencies": {
+    "browser-sync": "^2.11.2",
+    "concurrently": "^2.0.0",
+    "node-sass": "^3.4.2"
+  }
+}
diff --git a/views/style/sass/bootstrap/_bootstrap-compass.scss b/views/style/sass/bootstrap/_bootstrap-compass.scss
new file mode 100644
index 0000000..8fbc3cd
--- /dev/null
+++ b/views/style/sass/bootstrap/_bootstrap-compass.scss
@@ -0,0 +1,9 @@
+@function twbs-font-path($path) {
+  @return font-url($path, true);
+}
+
+@function twbs-image-path($path) {
+  @return image-url($path, true);
+}
+
+$bootstrap-sass-asset-helper: true;
diff --git a/views/style/sass/bootstrap/_bootstrap-mincer.scss b/views/style/sass/bootstrap/_bootstrap-mincer.scss
new file mode 100644
index 0000000..0c4655e
--- /dev/null
+++ b/views/style/sass/bootstrap/_bootstrap-mincer.scss
@@ -0,0 +1,19 @@
+// Mincer asset helper functions
+//
+// This must be imported into a .css.ejs.scss file.
+// Then, <% %>-interpolations will be parsed as strings by Sass, and evaluated by EJS after Sass compilation.
+
+
+@function twbs-font-path($path) {
+  // do something like following
+  // from "path/to/font.ext#suffix" to "<%- asset_path(path/to/font.ext)) + #suffix %>"
+  // from "path/to/font.ext?#suffix" to "<%- asset_path(path/to/font.ext)) + ?#suffix %>"
+  // or from "path/to/font.ext" just "<%- asset_path(path/to/font.ext)) %>"
+  @return "<%- asset_path("#{$path}".replace(/[#?].*$/, '')) + "#{$path}".replace(/(^[^#?]*)([#?]?.*$)/, '$2') %>";
+}
+
+@function twbs-image-path($file) {
+  @return "<%- asset_path("#{$file}") %>";
+}
+
+$bootstrap-sass-asset-helper: true;
diff --git a/views/style/sass/bootstrap/_bootstrap-sprockets.scss b/views/style/sass/bootstrap/_bootstrap-sprockets.scss
new file mode 100644
index 0000000..9fffc1e
--- /dev/null
+++ b/views/style/sass/bootstrap/_bootstrap-sprockets.scss
@@ -0,0 +1,9 @@
+@function twbs-font-path($path) {
+  @return font-path($path);
+}
+
+@function twbs-image-path($path) {
+  @return image-path($path);
+}
+
+$bootstrap-sass-asset-helper: true;
diff --git a/views/style/sass/bootstrap/_bootstrap.scss b/views/style/sass/bootstrap/_bootstrap.scss
new file mode 100644
index 0000000..c773c8c
--- /dev/null
+++ b/views/style/sass/bootstrap/_bootstrap.scss
@@ -0,0 +1,56 @@
+/*!
+ * Bootstrap v3.3.6 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+
+// Core variables and mixins
+@import "bootstrap/variables";
+@import "bootstrap/mixins";
+
+// Reset and dependencies
+@import "bootstrap/normalize";
+@import "bootstrap/print";
+@import "bootstrap/glyphicons";
+
+// Core CSS
+@import "bootstrap/scaffolding";
+@import "bootstrap/type";
+@import "bootstrap/code";
+@import "bootstrap/grid";
+@import "bootstrap/tables";
+@import "bootstrap/forms";
+@import "bootstrap/buttons";
+
+// Components
+@import "bootstrap/component-animations";
+@import "bootstrap/dropdowns";
+@import "bootstrap/button-groups";
+@import "bootstrap/input-groups";
+@import "bootstrap/navs";
+@import "bootstrap/navbar";
+@import "bootstrap/breadcrumbs";
+@import "bootstrap/pagination";
+@import "bootstrap/pager";
+@import "bootstrap/labels";
+@import "bootstrap/badges";
+@import "bootstrap/jumbotron";
+@import "bootstrap/thumbnails";
+@import "bootstrap/alerts";
+@import "bootstrap/progress-bars";
+@import "bootstrap/media";
+@import "bootstrap/list-group";
+@import "bootstrap/panels";
+@import "bootstrap/responsive-embed";
+@import "bootstrap/wells";
+@import "bootstrap/close";
+
+// Components w/ JavaScript
+@import "bootstrap/modals";
+@import "bootstrap/tooltip";
+@import "bootstrap/popovers";
+@import "bootstrap/carousel";
+
+// Utility classes
+@import "bootstrap/utilities";
+@import "bootstrap/responsive-utilities";
diff --git a/views/style/sass/bootstrap/bootstrap/_alerts.scss b/views/style/sass/bootstrap/bootstrap/_alerts.scss
new file mode 100644
index 0000000..7d1e1fd
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/_alerts.scss
@@ -0,0 +1,73 @@
+//
+// Alerts
+// --------------------------------------------------
+
+
+// Base styles
+// -------------------------
+
+.alert {
+  padding: $alert-padding;
+  margin-bottom: $line-height-computed;
+  border: 1px solid transparent;
+  border-radius: $alert-border-radius;
+
+  // Headings for larger alerts
+  h4 {
+    margin-top: 0;
+    // Specified for the h4 to prevent conflicts of changing $headings-color
+    color: inherit;
+  }
+
+  // Provide class for links that match alerts
+  .alert-link {
+    font-weight: $alert-link-font-weight;
+  }
+
+  // Improve alignment and spacing of inner content
+  > p,
+  > ul {
+    margin-bottom: 0;
+  }
+
+  > p + p {
+    margin-top: 5px;
+  }
+}
+
+// Dismissible alerts
+//
+// Expand the right padding and account for the close button's positioning.
+
+.alert-dismissable, // The misspelled .alert-dismissable was deprecated in 3.2.0.
+.alert-dismissible {
+  padding-right: ($alert-padding + 20);
+
+  // Adjust close link position
+  .close {
+    position: relative;
+    top: -2px;
+    right: -21px;
+    color: inherit;
+  }
+}
+
+// Alternate styles
+//
+// Generate contextual modifier classes for colorizing the alert.
+
+.alert-success {
+  @include alert-variant($alert-success-bg, $alert-success-border, $alert-success-text);
+}
+
+.alert-info {
+  @include alert-variant($alert-info-bg, $alert-info-border, $alert-info-text);
+}
+
+.alert-warning {
+  @include alert-variant($alert-warning-bg, $alert-warning-border, $alert-warning-text);
+}
+
+.alert-danger {
+  @include alert-variant($alert-danger-bg, $alert-danger-border, $alert-danger-text);
+}
diff --git a/views/style/sass/bootstrap/bootstrap/_badges.scss b/views/style/sass/bootstrap/bootstrap/_badges.scss
new file mode 100644
index 0000000..70002e0
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/_badges.scss
@@ -0,0 +1,68 @@
+//
+// Badges
+// --------------------------------------------------
+
+
+// Base class
+.badge {
+  display: inline-block;
+  min-width: 10px;
+  padding: 3px 7px;
+  font-size: $font-size-small;
+  font-weight: $badge-font-weight;
+  color: $badge-color;
+  line-height: $badge-line-height;
+  vertical-align: middle;
+  white-space: nowrap;
+  text-align: center;
+  background-color: $badge-bg;
+  border-radius: $badge-border-radius;
+
+  // Empty badges collapse automatically (not available in IE8)
+  &:empty {
+    display: none;
+  }
+
+  // Quick fix for badges in buttons
+  .btn & {
+    position: relative;
+    top: -1px;
+  }
+
+  .btn-xs &,
+  .btn-group-xs > .btn & {
+    top: 0;
+    padding: 1px 5px;
+  }
+
+  // [converter] extracted a& to a.badge
+
+  // Account for badges in navs
+  .list-group-item.active > &,
+  .nav-pills > .active > a > & {
+    color: $badge-active-color;
+    background-color: $badge-active-bg;
+  }
+
+  .list-group-item > & {
+    float: right;
+  }
+
+  .list-group-item > & + & {
+    margin-right: 5px;
+  }
+
+  .nav-pills > li > a > & {
+    margin-left: 3px;
+  }
+}
+
+// Hover state, but only for links
+a.badge {
+  &:hover,
+  &:focus {
+    color: $badge-link-hover-color;
+    text-decoration: none;
+    cursor: pointer;
+  }
+}
diff --git a/views/style/sass/bootstrap/bootstrap/_breadcrumbs.scss b/views/style/sass/bootstrap/bootstrap/_breadcrumbs.scss
new file mode 100644
index 0000000..b61f0c7
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/_breadcrumbs.scss
@@ -0,0 +1,28 @@
+//
+// Breadcrumbs
+// --------------------------------------------------
+
+
+.breadcrumb {
+  padding: $breadcrumb-padding-vertical $breadcrumb-padding-horizontal;
+  margin-bottom: $line-height-computed;
+  list-style: none;
+  background-color: $breadcrumb-bg;
+  border-radius: $border-radius-base;
+
+  > li {
+    display: inline-block;
+
+    + li:before {
+      // [converter] Workaround for https://github.com/sass/libsass/issues/1115
+      $nbsp: "\00a0";
+      content: "#{$breadcrumb-separator}#{$nbsp}"; // Unicode space added since inline-block means non-collapsing white-space
+      padding: 0 5px;
+      color: $breadcrumb-color;
+    }
+  }
+
+  > .active {
+    color: $breadcrumb-active-color;
+  }
+}
diff --git a/views/style/sass/bootstrap/bootstrap/_button-groups.scss b/views/style/sass/bootstrap/bootstrap/_button-groups.scss
new file mode 100644
index 0000000..baaacc4
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/_button-groups.scss
@@ -0,0 +1,244 @@
+//
+// Button groups
+// --------------------------------------------------
+
+// Make the div behave like a button
+.btn-group,
+.btn-group-vertical {
+  position: relative;
+  display: inline-block;
+  vertical-align: middle; // match .btn alignment given font-size hack above
+  > .btn {
+    position: relative;
+    float: left;
+    // Bring the "active" button to the front
+    &:hover,
+    &:focus,
+    &:active,
+    &.active {
+      z-index: 2;
+    }
+  }
+}
+
+// Prevent double borders when buttons are next to each other
+.btn-group {
+  .btn + .btn,
+  .btn + .btn-group,
+  .btn-group + .btn,
+  .btn-group + .btn-group {
+    margin-left: -1px;
+  }
+}
+
+// Optional: Group multiple button groups together for a toolbar
+.btn-toolbar {
+  margin-left: -5px; // Offset the first child's margin
+  @include clearfix;
+
+  .btn,
+  .btn-group,
+  .input-group {
+    float: left;
+  }
+  > .btn,
+  > .btn-group,
+  > .input-group {
+    margin-left: 5px;
+  }
+}
+
+.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {
+  border-radius: 0;
+}
+
+// Set corners individual because sometimes a single button can be in a .btn-group and we need :first-child and :last-child to both match
+.btn-group > .btn:first-child {
+  margin-left: 0;
+  &:not(:last-child):not(.dropdown-toggle) {
+    @include border-right-radius(0);
+  }
+}
+// Need .dropdown-toggle since :last-child doesn't apply given a .dropdown-menu immediately after it
+.btn-group > .btn:last-child:not(:first-child),
+.btn-group > .dropdown-toggle:not(:first-child) {
+  @include border-left-radius(0);
+}
+
+// Custom edits for including btn-groups within btn-groups (useful for including dropdown buttons within a btn-group)
+.btn-group > .btn-group {
+  float: left;
+}
+.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {
+  border-radius: 0;
+}
+.btn-group > .btn-group:first-child:not(:last-child) {
+  > .btn:last-child,
+  > .dropdown-toggle {
+    @include border-right-radius(0);
+  }
+}
+.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {
+  @include border-left-radius(0);
+}
+
+// On active and open, don't show outline
+.btn-group .dropdown-toggle:active,
+.btn-group.open .dropdown-toggle {
+  outline: 0;
+}
+
+
+// Sizing
+//
+// Remix the default button sizing classes into new ones for easier manipulation.
+
+.btn-group-xs > .btn { @extend .btn-xs; }
+.btn-group-sm > .btn { @extend .btn-sm; }
+.btn-group-lg > .btn { @extend .btn-lg; }
+
+
+// Split button dropdowns
+// ----------------------
+
+// Give the line between buttons some depth
+.btn-group > .btn + .dropdown-toggle {
+  padding-left: 8px;
+  padding-right: 8px;
+}
+.btn-group > .btn-lg + .dropdown-toggle {
+  padding-left: 12px;
+  padding-right: 12px;
+}
+
+// The clickable button for toggling the menu
+// Remove the gradient and set the same inset shadow as the :active state
+.btn-group.open .dropdown-toggle {
+  @include box-shadow(inset 0 3px 5px rgba(0,0,0,.125));
+
+  // Show no shadow for `.btn-link` since it has no other button styles.
+  &.btn-link {
+    @include box-shadow(none);
+  }
+}
+
+
+// Reposition the caret
+.btn .caret {
+  margin-left: 0;
+}
+// Carets in other button sizes
+.btn-lg .caret {
+  border-width: $caret-width-large $caret-width-large 0;
+  border-bottom-width: 0;
+}
+// Upside down carets for .dropup
+.dropup .btn-lg .caret {
+  border-width: 0 $caret-width-large $caret-width-large;
+}
+
+
+// Vertical button groups
+// ----------------------
+
+.btn-group-vertical {
+  > .btn,
+  > .btn-group,
+  > .btn-group > .btn {
+    display: block;
+    float: none;
+    width: 100%;
+    max-width: 100%;
+  }
+
+  // Clear floats so dropdown menus can be properly placed
+  > .btn-group {
+    @include clearfix;
+    > .btn {
+      float: none;
+    }
+  }
+
+  > .btn + .btn,
+  > .btn + .btn-group,
+  > .btn-group + .btn,
+  > .btn-group + .btn-group {
+    margin-top: -1px;
+    margin-left: 0;
+  }
+}
+
+.btn-group-vertical > .btn {
+  &:not(:first-child):not(:last-child) {
+    border-radius: 0;
+  }
+  &:first-child:not(:last-child) {
+    @include border-top-radius($btn-border-radius-base);
+    @include border-bottom-radius(0);
+  }
+  &:last-child:not(:first-child) {
+    @include border-top-radius(0);
+    @include border-bottom-radius($btn-border-radius-base);
+  }
+}
+.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {
+  border-radius: 0;
+}
+.btn-group-vertical > .btn-group:first-child:not(:last-child) {
+  > .btn:last-child,
+  > .dropdown-toggle {
+    @include border-bottom-radius(0);
+  }
+}
+.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {
+  @include border-top-radius(0);
+}
+
+
+// Justified button groups
+// ----------------------
+
+.btn-group-justified {
+  display: table;
+  width: 100%;
+  table-layout: fixed;
+  border-collapse: separate;
+  > .btn,
+  > .btn-group {
+    float: none;
+    display: table-cell;
+    width: 1%;
+  }
+  > .btn-group .btn {
+    width: 100%;
+  }
+
+  > .btn-group .dropdown-menu {
+    left: auto;
+  }
+}
+
+
+// Checkbox and radio options
+//
+// In order to support the browser's form validation feedback, powered by the
+// `required` attribute, we have to "hide" the inputs via `clip`. We cannot use
+// `display: none;` or `visibility: hidden;` as that also hides the popover.
+// Simply visually hiding the inputs via `opacity` would leave them clickable in
+// certain cases which is prevented by using `clip` and `pointer-events`.
+// This way, we ensure a DOM element is visible to position the popover from.
+//
+// See https://github.com/twbs/bootstrap/pull/12794 and
+// https://github.com/twbs/bootstrap/pull/14559 for more information.
+
+[data-toggle="buttons"] {
+  > .btn,
+  > .btn-group > .btn {
+    input[type="radio"],
+    input[type="checkbox"] {
+      position: absolute;
+      clip: rect(0,0,0,0);
+      pointer-events: none;
+    }
+  }
+}
diff --git a/views/style/sass/bootstrap/bootstrap/_buttons.scss b/views/style/sass/bootstrap/bootstrap/_buttons.scss
new file mode 100644
index 0000000..6452b70
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/_buttons.scss
@@ -0,0 +1,168 @@
+//
+// Buttons
+// --------------------------------------------------
+
+
+// Base styles
+// --------------------------------------------------
+
+.btn {
+  display: inline-block;
+  margin-bottom: 0; // For input.btn
+  font-weight: $btn-font-weight;
+  text-align: center;
+  vertical-align: middle;
+  touch-action: manipulation;
+  cursor: pointer;
+  background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214
+  border: 1px solid transparent;
+  white-space: nowrap;
+  @include button-size($padding-base-vertical, $padding-base-horizontal, $font-size-base, $line-height-base, $btn-border-radius-base);
+  @include user-select(none);
+
+  &,
+  &:active,
+  &.active {
+    &:focus,
+    &.focus {
+      @include tab-focus;
+    }
+  }
+
+  &:hover,
+  &:focus,
+  &.focus {
+    color: $btn-default-color;
+    text-decoration: none;
+  }
+
+  &:active,
+  &.active {
+    outline: 0;
+    background-image: none;
+    @include box-shadow(inset 0 3px 5px rgba(0,0,0,.125));
+  }
+
+  &.disabled,
+  &[disabled],
+  fieldset[disabled] & {
+    cursor: $cursor-disabled;
+    @include opacity(.65);
+    @include box-shadow(none);
+  }
+
+  // [converter] extracted a& to a.btn
+}
+
+a.btn {
+  &.disabled,
+  fieldset[disabled] & {
+    pointer-events: none; // Future-proof disabling of clicks on `<a>` elements
+  }
+}
+
+
+// Alternate buttons
+// --------------------------------------------------
+
+.btn-default {
+  @include button-variant($btn-default-color, $btn-default-bg, $btn-default-border);
+}
+.btn-primary {
+  @include button-variant($btn-primary-color, $btn-primary-bg, $btn-primary-border);
+}
+// Success appears as green
+.btn-success {
+  @include button-variant($btn-success-color, $btn-success-bg, $btn-success-border);
+}
+// Info appears as blue-green
+.btn-info {
+  @include button-variant($btn-info-color, $btn-info-bg, $btn-info-border);
+}
+// Warning appears as orange
+.btn-warning {
+  @include button-variant($btn-warning-color, $btn-warning-bg, $btn-warning-border);
+}
+// Danger and error appear as red
+.btn-danger {
+  @include button-variant($btn-danger-color, $btn-danger-bg, $btn-danger-border);
+}
+
+
+// Link buttons
+// -------------------------
+
+// Make a button look and behave like a link
+.btn-link {
+  color: $link-color;
+  font-weight: normal;
+  border-radius: 0;
+
+  &,
+  &:active,
+  &.active,
+  &[disabled],
+  fieldset[disabled] & {
+    background-color: transparent;
+    @include box-shadow(none);
+  }
+  &,
+  &:hover,
+  &:focus,
+  &:active {
+    border-color: transparent;
+  }
+  &:hover,
+  &:focus {
+    color: $link-hover-color;
+    text-decoration: $link-hover-decoration;
+    background-color: transparent;
+  }
+  &[disabled],
+  fieldset[disabled] & {
+    &:hover,
+    &:focus {
+      color: $btn-link-disabled-color;
+      text-decoration: none;
+    }
+  }
+}
+
+
+// Button Sizes
+// --------------------------------------------------
+
+.btn-lg {
+  // line-height: ensure even-numbered height of button next to large input
+  @include button-size($padding-large-vertical, $padding-large-horizontal, $font-size-large, $line-height-large, $btn-border-radius-large);
+}
+.btn-sm {
+  // line-height: ensure proper height of button next to small input
+  @include button-size($padding-small-vertical, $padding-small-horizontal, $font-size-small, $line-height-small, $btn-border-radius-small);
+}
+.btn-xs {
+  @include button-size($padding-xs-vertical, $padding-xs-horizontal, $font-size-small, $line-height-small, $btn-border-radius-small);
+}
+
+
+// Block button
+// --------------------------------------------------
+
+.btn-block {
+  display: block;
+  width: 100%;
+}
+
+// Vertically space out multiple block buttons
+.btn-block + .btn-block {
+  margin-top: 5px;
+}
+
+// Specificity overrides
+input[type="submit"],
+input[type="reset"],
+input[type="button"] {
+  &.btn-block {
+    width: 100%;
+  }
+}
diff --git a/views/style/sass/bootstrap/bootstrap/_carousel.scss b/views/style/sass/bootstrap/bootstrap/_carousel.scss
new file mode 100644
index 0000000..753d881
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/_carousel.scss
@@ -0,0 +1,270 @@
+//
+// Carousel
+// --------------------------------------------------
+
+
+// Wrapper for the slide container and indicators
+.carousel {
+  position: relative;
+}
+
+.carousel-inner {
+  position: relative;
+  overflow: hidden;
+  width: 100%;
+
+  > .item {
+    display: none;
+    position: relative;
+    @include transition(.6s ease-in-out left);
+
+    // Account for jankitude on images
+    > img,
+    > a > img {
+      @include img-responsive;
+      line-height: 1;
+    }
+
+    // WebKit CSS3 transforms for supported devices
+    @media all and (transform-3d), (-webkit-transform-3d) {
+      @include transition-transform(0.6s ease-in-out);
+      @include backface-visibility(hidden);
+      @include perspective(1000px);
+
+      &.next,
+      &.active.right {
+        @include translate3d(100%, 0, 0);
+        left: 0;
+      }
+      &.prev,
+      &.active.left {
+        @include translate3d(-100%, 0, 0);
+        left: 0;
+      }
+      &.next.left,
+      &.prev.right,
+      &.active {
+        @include translate3d(0, 0, 0);
+        left: 0;
+      }
+    }
+  }
+
+  > .active,
+  > .next,
+  > .prev {
+    display: block;
+  }
+
+  > .active {
+    left: 0;
+  }
+
+  > .next,
+  > .prev {
+    position: absolute;
+    top: 0;
+    width: 100%;
+  }
+
+  > .next {
+    left: 100%;
+  }
+  > .prev {
+    left: -100%;
+  }
+  > .next.left,
+  > .prev.right {
+    left: 0;
+  }
+
+  > .active.left {
+    left: -100%;
+  }
+  > .active.right {
+    left: 100%;
+  }
+
+}
+
+// Left/right controls for nav
+// ---------------------------
+
+.carousel-control {
+  position: absolute;
+  top: 0;
+  left: 0;
+  bottom: 0;
+  width: $carousel-control-width;
+  @include opacity($carousel-control-opacity);
+  font-size: $carousel-control-font-size;
+  color: $carousel-control-color;
+  text-align: center;
+  text-shadow: $carousel-text-shadow;
+  background-color: rgba(0, 0, 0, 0); // Fix IE9 click-thru bug
+  // We can't have this transition here because WebKit cancels the carousel
+  // animation if you trip this while in the middle of another animation.
+
+  // Set gradients for backgrounds
+  &.left {
+    @include gradient-horizontal($start-color: rgba(0,0,0,.5), $end-color: rgba(0,0,0,.0001));
+  }
+  &.right {
+    left: auto;
+    right: 0;
+    @include gradient-horizontal($start-color: rgba(0,0,0,.0001), $end-color: rgba(0,0,0,.5));
+  }
+
+  // Hover/focus state
+  &:hover,
+  &:focus {
+    outline: 0;
+    color: $carousel-control-color;
+    text-decoration: none;
+    @include opacity(.9);
+  }
+
+  // Toggles
+  .icon-prev,
+  .icon-next,
+  .glyphicon-chevron-left,
+  .glyphicon-chevron-right {
+    position: absolute;
+    top: 50%;
+    margin-top: -10px;
+    z-index: 5;
+    display: inline-block;
+  }
+  .icon-prev,
+  .glyphicon-chevron-left {
+    left: 50%;
+    margin-left: -10px;
+  }
+  .icon-next,
+  .glyphicon-chevron-right {
+    right: 50%;
+    margin-right: -10px;
+  }
+  .icon-prev,
+  .icon-next {
+    width:  20px;
+    height: 20px;
+    line-height: 1;
+    font-family: serif;
+  }
+
+
+  .icon-prev {
+    &:before {
+      content: '\2039';// SINGLE LEFT-POINTING ANGLE QUOTATION MARK (U+2039)
+    }
+  }
+  .icon-next {
+    &:before {
+      content: '\203a';// SINGLE RIGHT-POINTING ANGLE QUOTATION MARK (U+203A)
+    }
+  }
+}
+
+// Optional indicator pips
+//
+// Add an unordered list with the following class and add a list item for each
+// slide your carousel holds.
+
+.carousel-indicators {
+  position: absolute;
+  bottom: 10px;
+  left: 50%;
+  z-index: 15;
+  width: 60%;
+  margin-left: -30%;
+  padding-left: 0;
+  list-style: none;
+  text-align: center;
+
+  li {
+    display: inline-block;
+    width:  10px;
+    height: 10px;
+    margin: 1px;
+    text-indent: -999px;
+    border: 1px solid $carousel-indicator-border-color;
+    border-radius: 10px;
+    cursor: pointer;
+
+    // IE8-9 hack for event handling
+    //
+    // Internet Explorer 8-9 does not support clicks on elements without a set
+    // `background-color`. We cannot use `filter` since that's not viewed as a
+    // background color by the browser. Thus, a hack is needed.
+    // See https://developer.mozilla.org/en-US/docs/Web/Events/click#Internet_Explorer
+    //
+    // For IE8, we set solid black as it doesn't support `rgba()`. For IE9, we
+    // set alpha transparency for the best results possible.
+    background-color: #000 \9; // IE8
+    background-color: rgba(0,0,0,0); // IE9
+  }
+  .active {
+    margin: 0;
+    width:  12px;
+    height: 12px;
+    background-color: $carousel-indicator-active-bg;
+  }
+}
+
+// Optional captions
+// -----------------------------
+// Hidden by default for smaller viewports
+.carousel-caption {
+  position: absolute;
+  left: 15%;
+  right: 15%;
+  bottom: 20px;
+  z-index: 10;
+  padding-top: 20px;
+  padding-bottom: 20px;
+  color: $carousel-caption-color;
+  text-align: center;
+  text-shadow: $carousel-text-shadow;
+  & .btn {
+    text-shadow: none; // No shadow for button elements in carousel-caption
+  }
+}
+
+
+// Scale up controls for tablets and up
+@media screen and (min-width: $screen-sm-min) {
+
+  // Scale up the controls a smidge
+  .carousel-control {
+    .glyphicon-chevron-left,
+    .glyphicon-chevron-right,
+    .icon-prev,
+    .icon-next {
+      width: ($carousel-control-font-size * 1.5);
+      height: ($carousel-control-font-size * 1.5);
+      margin-top: ($carousel-control-font-size / -2);
+      font-size: ($carousel-control-font-size * 1.5);
+    }
+    .glyphicon-chevron-left,
+    .icon-prev {
+      margin-left: ($carousel-control-font-size / -2);
+    }
+    .glyphicon-chevron-right,
+    .icon-next {
+      margin-right: ($carousel-control-font-size / -2);
+    }
+  }
+
+  // Show and left align the captions
+  .carousel-caption {
+    left: 20%;
+    right: 20%;
+    padding-bottom: 30px;
+  }
+
+  // Move up the indicators
+  .carousel-indicators {
+    bottom: 20px;
+  }
+}
diff --git a/views/style/sass/bootstrap/bootstrap/_close.scss b/views/style/sass/bootstrap/bootstrap/_close.scss
new file mode 100644
index 0000000..3b74d8a
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/_close.scss
@@ -0,0 +1,36 @@
+//
+// Close icons
+// --------------------------------------------------
+
+
+.close {
+  float: right;
+  font-size: ($font-size-base * 1.5);
+  font-weight: $close-font-weight;
+  line-height: 1;
+  color: $close-color;
+  text-shadow: $close-text-shadow;
+  @include opacity(.2);
+
+  &:hover,
+  &:focus {
+    color: $close-color;
+    text-decoration: none;
+    cursor: pointer;
+    @include opacity(.5);
+  }
+
+  // [converter] extracted button& to button.close
+}
+
+// Additional properties for button version
+// iOS requires the button element instead of an anchor tag.
+// If you want the anchor version, it requires `href="#"`.
+// See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile
+button.close {
+  padding: 0;
+  cursor: pointer;
+  background: transparent;
+  border: 0;
+  -webkit-appearance: none;
+}
diff --git a/views/style/sass/bootstrap/bootstrap/_code.scss b/views/style/sass/bootstrap/bootstrap/_code.scss
new file mode 100644
index 0000000..caa5f06
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/_code.scss
@@ -0,0 +1,69 @@
+//
+// Code (inline and block)
+// --------------------------------------------------
+
+
+// Inline and block code styles
+code,
+kbd,
+pre,
+samp {
+  font-family: $font-family-monospace;
+}
+
+// Inline code
+code {
+  padding: 2px 4px;
+  font-size: 90%;
+  color: $code-color;
+  background-color: $code-bg;
+  border-radius: $border-radius-base;
+}
+
+// User input typically entered via keyboard
+kbd {
+  padding: 2px 4px;
+  font-size: 90%;
+  color: $kbd-color;
+  background-color: $kbd-bg;
+  border-radius: $border-radius-small;
+  box-shadow: inset 0 -1px 0 rgba(0,0,0,.25);
+
+  kbd {
+    padding: 0;
+    font-size: 100%;
+    font-weight: bold;
+    box-shadow: none;
+  }
+}
+
+// Blocks of code
+pre {
+  display: block;
+  padding: (($line-height-computed - 1) / 2);
+  margin: 0 0 ($line-height-computed / 2);
+  font-size: ($font-size-base - 1); // 14px to 13px
+  line-height: $line-height-base;
+  word-break: break-all;
+  word-wrap: break-word;
+  color: $pre-color;
+  background-color: $pre-bg;
+  border: 1px solid $pre-border-color;
+  border-radius: $border-radius-base;
+
+  // Account for some code outputs that place code tags in pre tags
+  code {
+    padding: 0;
+    font-size: inherit;
+    color: inherit;
+    white-space: pre-wrap;
+    background-color: transparent;
+    border-radius: 0;
+  }
+}
+
+// Enable scrollable blocks of code
+.pre-scrollable {
+  max-height: $pre-scrollable-max-height;
+  overflow-y: scroll;
+}
diff --git a/views/style/sass/bootstrap/bootstrap/_component-animations.scss b/views/style/sass/bootstrap/bootstrap/_component-animations.scss
new file mode 100644
index 0000000..ca3b43c
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/_component-animations.scss
@@ -0,0 +1,37 @@
+//
+// Component animations
+// --------------------------------------------------
+
+// Heads up!
+//
+// We don't use the `.opacity()` mixin here since it causes a bug with text
+// fields in IE7-8. Source: https://github.com/twbs/bootstrap/pull/3552.
+
+.fade {
+  opacity: 0;
+  @include transition(opacity .15s linear);
+  &.in {
+    opacity: 1;
+  }
+}
+
+.collapse {
+  display: none;
+
+  &.in      { display: block; }
+  // [converter] extracted tr&.in to tr.collapse.in
+  // [converter] extracted tbody&.in to tbody.collapse.in
+}
+
+tr.collapse.in    { display: table-row; }
+
+tbody.collapse.in { display: table-row-group; }
+
+.collapsing {
+  position: relative;
+  height: 0;
+  overflow: hidden;
+  @include transition-property(height, visibility);
+  @include transition-duration(.35s);
+  @include transition-timing-function(ease);
+}
diff --git a/views/style/sass/bootstrap/bootstrap/_dropdowns.scss b/views/style/sass/bootstrap/bootstrap/_dropdowns.scss
new file mode 100644
index 0000000..aac8459
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/_dropdowns.scss
@@ -0,0 +1,216 @@
+//
+// Dropdown menus
+// --------------------------------------------------
+
+
+// Dropdown arrow/caret
+.caret {
+  display: inline-block;
+  width: 0;
+  height: 0;
+  margin-left: 2px;
+  vertical-align: middle;
+  border-top:   $caret-width-base dashed;
+  border-top:   $caret-width-base solid \9; // IE8
+  border-right: $caret-width-base solid transparent;
+  border-left:  $caret-width-base solid transparent;
+}
+
+// The dropdown wrapper (div)
+.dropup,
+.dropdown {
+  position: relative;
+}
+
+// Prevent the focus on the dropdown toggle when closing dropdowns
+.dropdown-toggle:focus {
+  outline: 0;
+}
+
+// The dropdown menu (ul)
+.dropdown-menu {
+  position: absolute;
+  top: 100%;
+  left: 0;
+  z-index: $zindex-dropdown;
+  display: none; // none by default, but block on "open" of the menu
+  float: left;
+  min-width: 160px;
+  padding: 5px 0;
+  margin: 2px 0 0; // override default ul
+  list-style: none;
+  font-size: $font-size-base;
+  text-align: left; // Ensures proper alignment if parent has it changed (e.g., modal footer)
+  background-color: $dropdown-bg;
+  border: 1px solid $dropdown-fallback-border; // IE8 fallback
+  border: 1px solid $dropdown-border;
+  border-radius: $border-radius-base;
+  @include box-shadow(0 6px 12px rgba(0,0,0,.175));
+  background-clip: padding-box;
+
+  // Aligns the dropdown menu to right
+  //
+  // Deprecated as of 3.1.0 in favor of `.dropdown-menu-[dir]`
+  &.pull-right {
+    right: 0;
+    left: auto;
+  }
+
+  // Dividers (basically an hr) within the dropdown
+  .divider {
+    @include nav-divider($dropdown-divider-bg);
+  }
+
+  // Links within the dropdown menu
+  > li > a {
+    display: block;
+    padding: 3px 20px;
+    clear: both;
+    font-weight: normal;
+    line-height: $line-height-base;
+    color: $dropdown-link-color;
+    white-space: nowrap; // prevent links from randomly breaking onto new lines
+  }
+}
+
+// Hover/Focus state
+.dropdown-menu > li > a {
+  &:hover,
+  &:focus {
+    text-decoration: none;
+    color: $dropdown-link-hover-color;
+    background-color: $dropdown-link-hover-bg;
+  }
+}
+
+// Active state
+.dropdown-menu > .active > a {
+  &,
+  &:hover,
+  &:focus {
+    color: $dropdown-link-active-color;
+    text-decoration: none;
+    outline: 0;
+    background-color: $dropdown-link-active-bg;
+  }
+}
+
+// Disabled state
+//
+// Gray out text and ensure the hover/focus state remains gray
+
+.dropdown-menu > .disabled > a {
+  &,
+  &:hover,
+  &:focus {
+    color: $dropdown-link-disabled-color;
+  }
+
+  // Nuke hover/focus effects
+  &:hover,
+  &:focus {
+    text-decoration: none;
+    background-color: transparent;
+    background-image: none; // Remove CSS gradient
+    @include reset-filter;
+    cursor: $cursor-disabled;
+  }
+}
+
+// Open state for the dropdown
+.open {
+  // Show the menu
+  > .dropdown-menu {
+    display: block;
+  }
+
+  // Remove the outline when :focus is triggered
+  > a {
+    outline: 0;
+  }
+}
+
+// Menu positioning
+//
+// Add extra class to `.dropdown-menu` to flip the alignment of the dropdown
+// menu with the parent.
+.dropdown-menu-right {
+  left: auto; // Reset the default from `.dropdown-menu`
+  right: 0;
+}
+// With v3, we enabled auto-flipping if you have a dropdown within a right
+// aligned nav component. To enable the undoing of that, we provide an override
+// to restore the default dropdown menu alignment.
+//
+// This is only for left-aligning a dropdown menu within a `.navbar-right` or
+// `.pull-right` nav component.
+.dropdown-menu-left {
+  left: 0;
+  right: auto;
+}
+
+// Dropdown section headers
+.dropdown-header {
+  display: block;
+  padding: 3px 20px;
+  font-size: $font-size-small;
+  line-height: $line-height-base;
+  color: $dropdown-header-color;
+  white-space: nowrap; // as with > li > a
+}
+
+// Backdrop to catch body clicks on mobile, etc.
+.dropdown-backdrop {
+  position: fixed;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  top: 0;
+  z-index: ($zindex-dropdown - 10);
+}
+
+// Right aligned dropdowns
+.pull-right > .dropdown-menu {
+  right: 0;
+  left: auto;
+}
+
+// Allow for dropdowns to go bottom up (aka, dropup-menu)
+//
+// Just add .dropup after the standard .dropdown class and you're set, bro.
+// TODO: abstract this so that the navbar fixed styles are not placed here?
+
+.dropup,
+.navbar-fixed-bottom .dropdown {
+  // Reverse the caret
+  .caret {
+    border-top: 0;
+    border-bottom: $caret-width-base dashed;
+    border-bottom: $caret-width-base solid \9; // IE8
+    content: "";
+  }
+  // Different positioning for bottom up menu
+  .dropdown-menu {
+    top: auto;
+    bottom: 100%;
+    margin-bottom: 2px;
+  }
+}
+
+
+// Component alignment
+//
+// Reiterate per navbar.less and the modified component alignment there.
+
+@media (min-width: $grid-float-breakpoint) {
+  .navbar-right {
+    .dropdown-menu {
+      right: 0; left: auto;
+    }
+    // Necessary for overrides of the default right aligned menu.
+    // Will remove come v4 in all likelihood.
+    .dropdown-menu-left {
+      left: 0; right: auto;
+    }
+  }
+}
diff --git a/views/style/sass/bootstrap/bootstrap/_forms.scss b/views/style/sass/bootstrap/bootstrap/_forms.scss
new file mode 100644
index 0000000..11ba109
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/_forms.scss
@@ -0,0 +1,617 @@
+//
+// Forms
+// --------------------------------------------------
+
+
+// Normalize non-controls
+//
+// Restyle and baseline non-control form elements.
+
+fieldset {
+  padding: 0;
+  margin: 0;
+  border: 0;
+  // Chrome and Firefox set a `min-width: min-content;` on fieldsets,
+  // so we reset that to ensure it behaves more like a standard block element.
+  // See https://github.com/twbs/bootstrap/issues/12359.
+  min-width: 0;
+}
+
+legend {
+  display: block;
+  width: 100%;
+  padding: 0;
+  margin-bottom: $line-height-computed;
+  font-size: ($font-size-base * 1.5);
+  line-height: inherit;
+  color: $legend-color;
+  border: 0;
+  border-bottom: 1px solid $legend-border-color;
+}
+
+label {
+  display: inline-block;
+  max-width: 100%; // Force IE8 to wrap long content (see https://github.com/twbs/bootstrap/issues/13141)
+  margin-bottom: 5px;
+  font-weight: bold;
+}
+
+
+// Normalize form controls
+//
+// While most of our form styles require extra classes, some basic normalization
+// is required to ensure optimum display with or without those classes to better
+// address browser inconsistencies.
+
+// Override content-box in Normalize (* isn't specific enough)
+input[type="search"] {
+  @include box-sizing(border-box);
+}
+
+// Position radios and checkboxes better
+input[type="radio"],
+input[type="checkbox"] {
+  margin: 4px 0 0;
+  margin-top: 1px \9; // IE8-9
+  line-height: normal;
+}
+
+input[type="file"] {
+  display: block;
+}
+
+// Make range inputs behave like textual form controls
+input[type="range"] {
+  display: block;
+  width: 100%;
+}
+
+// Make multiple select elements height not fixed
+select[multiple],
+select[size] {
+  height: auto;
+}
+
+// Focus for file, radio, and checkbox
+input[type="file"]:focus,
+input[type="radio"]:focus,
+input[type="checkbox"]:focus {
+  @include tab-focus;
+}
+
+// Adjust output element
+output {
+  display: block;
+  padding-top: ($padding-base-vertical + 1);
+  font-size: $font-size-base;
+  line-height: $line-height-base;
+  color: $input-color;
+}
+
+
+// Common form controls
+//
+// Shared size and type resets for form controls. Apply `.form-control` to any
+// of the following form controls:
+//
+// select
+// textarea
+// input[type="text"]
+// input[type="password"]
+// input[type="datetime"]
+// input[type="datetime-local"]
+// input[type="date"]
+// input[type="month"]
+// input[type="time"]
+// input[type="week"]
+// input[type="number"]
+// input[type="email"]
+// input[type="url"]
+// input[type="search"]
+// input[type="tel"]
+// input[type="color"]
+
+.form-control {
+  display: block;
+  width: 100%;
+  height: $input-height-base; // Make inputs at least the height of their button counterpart (base line-height + padding + border)
+  padding: $padding-base-vertical $padding-base-horizontal;
+  font-size: $font-size-base;
+  line-height: $line-height-base;
+  color: $input-color;
+  background-color: $input-bg;
+  background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214
+  border: 1px solid $input-border;
+  border-radius: $input-border-radius; // Note: This has no effect on <select>s in some browsers, due to the limited stylability of <select>s in CSS.
+  @include box-shadow(inset 0 1px 1px rgba(0,0,0,.075));
+  @include transition(border-color ease-in-out .15s, box-shadow ease-in-out .15s);
+
+  // Customize the `:focus` state to imitate native WebKit styles.
+  @include form-control-focus;
+
+  // Placeholder
+  @include placeholder;
+
+  // Unstyle the caret on `<select>`s in IE10+.
+  &::-ms-expand {
+    border: 0;
+    background-color: transparent;
+  }
+
+  // Disabled and read-only inputs
+  //
+  // HTML5 says that controls under a fieldset > legend:first-child won't be
+  // disabled if the fieldset is disabled. Due to implementation difficulty, we
+  // don't honor that edge case; we style them as disabled anyway.
+  &[disabled],
+  &[readonly],
+  fieldset[disabled] & {
+    background-color: $input-bg-disabled;
+    opacity: 1; // iOS fix for unreadable disabled content; see https://github.com/twbs/bootstrap/issues/11655
+  }
+
+  &[disabled],
+  fieldset[disabled] & {
+    cursor: $cursor-disabled;
+  }
+
+  // [converter] extracted textarea& to textarea.form-control
+}
+
+// Reset height for `textarea`s
+textarea.form-control {
+  height: auto;
+}
+
+
+// Search inputs in iOS
+//
+// This overrides the extra rounded corners on search inputs in iOS so that our
+// `.form-control` class can properly style them. Note that this cannot simply
+// be added to `.form-control` as it's not specific enough. For details, see
+// https://github.com/twbs/bootstrap/issues/11586.
+
+input[type="search"] {
+  -webkit-appearance: none;
+}
+
+
+// Special styles for iOS temporal inputs
+//
+// In Mobile Safari, setting `display: block` on temporal inputs causes the
+// text within the input to become vertically misaligned. As a workaround, we
+// set a pixel line-height that matches the given height of the input, but only
+// for Safari. See https://bugs.webkit.org/show_bug.cgi?id=139848
+//
+// Note that as of 8.3, iOS doesn't support `datetime` or `week`.
+
+@media screen and (-webkit-min-device-pixel-ratio: 0) {
+  input[type="date"],
+  input[type="time"],
+  input[type="datetime-local"],
+  input[type="month"] {
+    &.form-control {
+      line-height: $input-height-base;
+    }
+
+    &.input-sm,
+    .input-group-sm & {
+      line-height: $input-height-small;
+    }
+
+    &.input-lg,
+    .input-group-lg & {
+      line-height: $input-height-large;
+    }
+  }
+}
+
+
+// Form groups
+//
+// Designed to help with the organization and spacing of vertical forms. For
+// horizontal forms, use the predefined grid classes.
+
+.form-group {
+  margin-bottom: $form-group-margin-bottom;
+}
+
+
+// Checkboxes and radios
+//
+// Indent the labels to position radios/checkboxes as hanging controls.
+
+.radio,
+.checkbox {
+  position: relative;
+  display: block;
+  margin-top: 10px;
+  margin-bottom: 10px;
+
+  label {
+    min-height: $line-height-computed; // Ensure the input doesn't jump when there is no text
+    padding-left: 20px;
+    margin-bottom: 0;
+    font-weight: normal;
+    cursor: pointer;
+  }
+}
+.radio input[type="radio"],
+.radio-inline input[type="radio"],
+.checkbox input[type="checkbox"],
+.checkbox-inline input[type="checkbox"] {
+  position: absolute;
+  margin-left: -20px;
+  margin-top: 4px \9;
+}
+
+.radio + .radio,
+.checkbox + .checkbox {
+  margin-top: -5px; // Move up sibling radios or checkboxes for tighter spacing
+}
+
+// Radios and checkboxes on same line
+.radio-inline,
+.checkbox-inline {
+  position: relative;
+  display: inline-block;
+  padding-left: 20px;
+  margin-bottom: 0;
+  vertical-align: middle;
+  font-weight: normal;
+  cursor: pointer;
+}
+.radio-inline + .radio-inline,
+.checkbox-inline + .checkbox-inline {
+  margin-top: 0;
+  margin-left: 10px; // space out consecutive inline controls
+}
+
+// Apply same disabled cursor tweak as for inputs
+// Some special care is needed because <label>s don't inherit their parent's `cursor`.
+//
+// Note: Neither radios nor checkboxes can be readonly.
+input[type="radio"],
+input[type="checkbox"] {
+  &[disabled],
+  &.disabled,
+  fieldset[disabled] & {
+    cursor: $cursor-disabled;
+  }
+}
+// These classes are used directly on <label>s
+.radio-inline,
+.checkbox-inline {
+  &.disabled,
+  fieldset[disabled] & {
+    cursor: $cursor-disabled;
+  }
+}
+// These classes are used on elements with <label> descendants
+.radio,
+.checkbox {
+  &.disabled,
+  fieldset[disabled] & {
+    label {
+      cursor: $cursor-disabled;
+    }
+  }
+}
+
+
+// Static form control text
+//
+// Apply class to a `p` element to make any string of text align with labels in
+// a horizontal form layout.
+
+.form-control-static {
+  // Size it appropriately next to real form controls
+  padding-top: ($padding-base-vertical + 1);
+  padding-bottom: ($padding-base-vertical + 1);
+  // Remove default margin from `p`
+  margin-bottom: 0;
+  min-height: ($line-height-computed + $font-size-base);
+
+  &.input-lg,
+  &.input-sm {
+    padding-left: 0;
+    padding-right: 0;
+  }
+}
+
+
+// Form control sizing
+//
+// Build on `.form-control` with modifier classes to decrease or increase the
+// height and font-size of form controls.
+//
+// The `.form-group-* form-control` variations are sadly duplicated to avoid the
+// issue documented in https://github.com/twbs/bootstrap/issues/15074.
+
+@include input-size('.input-sm', $input-height-small, $padding-small-vertical, $padding-small-horizontal, $font-size-small, $line-height-small, $input-border-radius-small);
+.form-group-sm {
+  .form-control {
+    height: $input-height-small;
+    padding: $padding-small-vertical $padding-small-horizontal;
+    font-size: $font-size-small;
+    line-height: $line-height-small;
+    border-radius: $input-border-radius-small;
+  }
+  select.form-control {
+    height: $input-height-small;
+    line-height: $input-height-small;
+  }
+  textarea.form-control,
+  select[multiple].form-control {
+    height: auto;
+  }
+  .form-control-static {
+    height: $input-height-small;
+    min-height: ($line-height-computed + $font-size-small);
+    padding: ($padding-small-vertical + 1) $padding-small-horizontal;
+    font-size: $font-size-small;
+    line-height: $line-height-small;
+  }
+}
+
+@include input-size('.input-lg', $input-height-large, $padding-large-vertical, $padding-large-horizontal, $font-size-large, $line-height-large, $input-border-radius-large);
+.form-group-lg {
+  .form-control {
+    height: $input-height-large;
+    padding: $padding-large-vertical $padding-large-horizontal;
+    font-size: $font-size-large;
+    line-height: $line-height-large;
+    border-radius: $input-border-radius-large;
+  }
+  select.form-control {
+    height: $input-height-large;
+    line-height: $input-height-large;
+  }
+  textarea.form-control,
+  select[multiple].form-control {
+    height: auto;
+  }
+  .form-control-static {
+    height: $input-height-large;
+    min-height: ($line-height-computed + $font-size-large);
+    padding: ($padding-large-vertical + 1) $padding-large-horizontal;
+    font-size: $font-size-large;
+    line-height: $line-height-large;
+  }
+}
+
+
+// Form control feedback states
+//
+// Apply contextual and semantic states to individual form controls.
+
+.has-feedback {
+  // Enable absolute positioning
+  position: relative;
+
+  // Ensure icons don't overlap text
+  .form-control {
+    padding-right: ($input-height-base * 1.25);
+  }
+}
+// Feedback icon (requires .glyphicon classes)
+.form-control-feedback {
+  position: absolute;
+  top: 0;
+  right: 0;
+  z-index: 2; // Ensure icon is above input groups
+  display: block;
+  width: $input-height-base;
+  height: $input-height-base;
+  line-height: $input-height-base;
+  text-align: center;
+  pointer-events: none;
+}
+.input-lg + .form-control-feedback,
+.input-group-lg + .form-control-feedback,
+.form-group-lg .form-control + .form-control-feedback {
+  width: $input-height-large;
+  height: $input-height-large;
+  line-height: $input-height-large;
+}
+.input-sm + .form-control-feedback,
+.input-group-sm + .form-control-feedback,
+.form-group-sm .form-control + .form-control-feedback {
+  width: $input-height-small;
+  height: $input-height-small;
+  line-height: $input-height-small;
+}
+
+// Feedback states
+.has-success {
+  @include form-control-validation($state-success-text, $state-success-text, $state-success-bg);
+}
+.has-warning {
+  @include form-control-validation($state-warning-text, $state-warning-text, $state-warning-bg);
+}
+.has-error {
+  @include form-control-validation($state-danger-text, $state-danger-text, $state-danger-bg);
+}
+
+// Reposition feedback icon if input has visible label above
+.has-feedback label {
+
+  & ~ .form-control-feedback {
+    top: ($line-height-computed + 5); // Height of the `label` and its margin
+  }
+  &.sr-only ~ .form-control-feedback {
+    top: 0;
+  }
+}
+
+
+// Help text
+//
+// Apply to any element you wish to create light text for placement immediately
+// below a form control. Use for general help, formatting, or instructional text.
+
+.help-block {
+  display: block; // account for any element using help-block
+  margin-top: 5px;
+  margin-bottom: 10px;
+  color: lighten($text-color, 25%); // lighten the text some for contrast
+}
+
+
+// Inline forms
+//
+// Make forms appear inline(-block) by adding the `.form-inline` class. Inline
+// forms begin stacked on extra small (mobile) devices and then go inline when
+// viewports reach <768px.
+//
+// Requires wrapping inputs and labels with `.form-group` for proper display of
+// default HTML form controls and our custom form controls (e.g., input groups).
+//
+// Heads up! This is mixin-ed into `.navbar-form` in navbars.less.
+
+// [converter] extracted from `.form-inline` for libsass compatibility
+@mixin form-inline {
+
+  // Kick in the inline
+  @media (min-width: $screen-sm-min) {
+    // Inline-block all the things for "inline"
+    .form-group {
+      display: inline-block;
+      margin-bottom: 0;
+      vertical-align: middle;
+    }
+
+    // In navbar-form, allow folks to *not* use `.form-group`
+    .form-control {
+      display: inline-block;
+      width: auto; // Prevent labels from stacking above inputs in `.form-group`
+      vertical-align: middle;
+    }
+
+    // Make static controls behave like regular ones
+    .form-control-static {
+      display: inline-block;
+    }
+
+    .input-group {
+      display: inline-table;
+      vertical-align: middle;
+
+      .input-group-addon,
+      .input-group-btn,
+      .form-control {
+        width: auto;
+      }
+    }
+
+    // Input groups need that 100% width though
+    .input-group > .form-control {
+      width: 100%;
+    }
+
+    .control-label {
+      margin-bottom: 0;
+      vertical-align: middle;
+    }
+
+    // Remove default margin on radios/checkboxes that were used for stacking, and
+    // then undo the floating of radios and checkboxes to match.
+    .radio,
+    .checkbox {
+      display: inline-block;
+      margin-top: 0;
+      margin-bottom: 0;
+      vertical-align: middle;
+
+      label {
+        padding-left: 0;
+      }
+    }
+    .radio input[type="radio"],
+    .checkbox input[type="checkbox"] {
+      position: relative;
+      margin-left: 0;
+    }
+
+    // Re-override the feedback icon.
+    .has-feedback .form-control-feedback {
+      top: 0;
+    }
+  }
+}
+// [converter] extracted as `@mixin form-inline` for libsass compatibility
+.form-inline {
+  @include form-inline;
+}
+
+
+
+// Horizontal forms
+//
+// Horizontal forms are built on grid classes and allow you to create forms with
+// labels on the left and inputs on the right.
+
+.form-horizontal {
+
+  // Consistent vertical alignment of radios and checkboxes
+  //
+  // Labels also get some reset styles, but that is scoped to a media query below.
+  .radio,
+  .checkbox,
+  .radio-inline,
+  .checkbox-inline {
+    margin-top: 0;
+    margin-bottom: 0;
+    padding-top: ($padding-base-vertical + 1); // Default padding plus a border
+  }
+  // Account for padding we're adding to ensure the alignment and of help text
+  // and other content below items
+  .radio,
+  .checkbox {
+    min-height: ($line-height-computed + ($padding-base-vertical + 1));
+  }
+
+  // Make form groups behave like rows
+  .form-group {
+    @include make-row;
+  }
+
+  // Reset spacing and right align labels, but scope to media queries so that
+  // labels on narrow viewports stack the same as a default form example.
+  @media (min-width: $screen-sm-min) {
+    .control-label {
+      text-align: right;
+      margin-bottom: 0;
+      padding-top: ($padding-base-vertical + 1); // Default padding plus a border
+    }
+  }
+
+  // Validation states
+  //
+  // Reposition the icon because it's now within a grid column and columns have
+  // `position: relative;` on them. Also accounts for the grid gutter padding.
+  .has-feedback .form-control-feedback {
+    right: floor(($grid-gutter-width / 2));
+  }
+
+  // Form group sizes
+  //
+  // Quick utility class for applying `.input-lg` and `.input-sm` styles to the
+  // inputs and labels within a `.form-group`.
+  .form-group-lg {
+    @media (min-width: $screen-sm-min) {
+      .control-label {
+        padding-top: ($padding-large-vertical + 1);
+        font-size: $font-size-large;
+      }
+    }
+  }
+  .form-group-sm {
+    @media (min-width: $screen-sm-min) {
+      .control-label {
+        padding-top: ($padding-small-vertical + 1);
+        font-size: $font-size-small;
+      }
+    }
+  }
+}
diff --git a/views/style/sass/bootstrap/bootstrap/_glyphicons.scss b/views/style/sass/bootstrap/bootstrap/_glyphicons.scss
new file mode 100644
index 0000000..07a0fc9
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/_glyphicons.scss
@@ -0,0 +1,307 @@
+//
+// Glyphicons for Bootstrap
+//
+// Since icons are fonts, they can be placed anywhere text is placed and are
+// thus automatically sized to match the surrounding child. To use, create an
+// inline element with the appropriate classes, like so:
+//
+// <a href="#"><span class="glyphicon glyphicon-star"></span> Star</a>
+
+@at-root {
+  // Import the fonts
+  @font-face {
+    font-family: 'Glyphicons Halflings';
+    src: url(if($bootstrap-sass-asset-helper, twbs-font-path('#{$icon-font-path}#{$icon-font-name}.eot'), '#{$icon-font-path}#{$icon-font-name}.eot'));
+    src: url(if($bootstrap-sass-asset-helper, twbs-font-path('#{$icon-font-path}#{$icon-font-name}.eot?#iefix'), '#{$icon-font-path}#{$icon-font-name}.eot?#iefix')) format('embedded-opentype'),
+         url(if($bootstrap-sass-asset-helper, twbs-font-path('#{$icon-font-path}#{$icon-font-name}.woff2'), '#{$icon-font-path}#{$icon-font-name}.woff2')) format('woff2'),
+         url(if($bootstrap-sass-asset-helper, twbs-font-path('#{$icon-font-path}#{$icon-font-name}.woff'), '#{$icon-font-path}#{$icon-font-name}.woff')) format('woff'),
+         url(if($bootstrap-sass-asset-helper, twbs-font-path('#{$icon-font-path}#{$icon-font-name}.ttf'), '#{$icon-font-path}#{$icon-font-name}.ttf')) format('truetype'),
+         url(if($bootstrap-sass-asset-helper, twbs-font-path('#{$icon-font-path}#{$icon-font-name}.svg##{$icon-font-svg-id}'), '#{$icon-font-path}#{$icon-font-name}.svg##{$icon-font-svg-id}')) format('svg');
+  }
+}
+
+// Catchall baseclass
+.glyphicon {
+  position: relative;
+  top: 1px;
+  display: inline-block;
+  font-family: 'Glyphicons Halflings';
+  font-style: normal;
+  font-weight: normal;
+  line-height: 1;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+// Individual icons
+.glyphicon-asterisk               { &:before { content: "\002a"; } }
+.glyphicon-plus                   { &:before { content: "\002b"; } }
+.glyphicon-euro,
+.glyphicon-eur                    { &:before { content: "\20ac"; } }
+.glyphicon-minus                  { &:before { content: "\2212"; } }
+.glyphicon-cloud                  { &:before { content: "\2601"; } }
+.glyphicon-envelope               { &:before { content: "\2709"; } }
+.glyphicon-pencil                 { &:before { content: "\270f"; } }
+.glyphicon-glass                  { &:before { content: "\e001"; } }
+.glyphicon-music                  { &:before { content: "\e002"; } }
+.glyphicon-search                 { &:before { content: "\e003"; } }
+.glyphicon-heart                  { &:before { content: "\e005"; } }
+.glyphicon-star                   { &:before { content: "\e006"; } }
+.glyphicon-star-empty             { &:before { content: "\e007"; } }
+.glyphicon-user                   { &:before { content: "\e008"; } }
+.glyphicon-film                   { &:before { content: "\e009"; } }
+.glyphicon-th-large               { &:before { content: "\e010"; } }
+.glyphicon-th                     { &:before { content: "\e011"; } }
+.glyphicon-th-list                { &:before { content: "\e012"; } }
+.glyphicon-ok                     { &:before { content: "\e013"; } }
+.glyphicon-remove                 { &:before { content: "\e014"; } }
+.glyphicon-zoom-in                { &:before { content: "\e015"; } }
+.glyphicon-zoom-out               { &:before { content: "\e016"; } }
+.glyphicon-off                    { &:before { content: "\e017"; } }
+.glyphicon-signal                 { &:before { content: "\e018"; } }
+.glyphicon-cog                    { &:before { content: "\e019"; } }
+.glyphicon-trash                  { &:before { content: "\e020"; } }
+.glyphicon-home                   { &:before { content: "\e021"; } }
+.glyphicon-file                   { &:before { content: "\e022"; } }
+.glyphicon-time                   { &:before { content: "\e023"; } }
+.glyphicon-road                   { &:before { content: "\e024"; } }
+.glyphicon-download-alt           { &:before { content: "\e025"; } }
+.glyphicon-download               { &:before { content: "\e026"; } }
+.glyphicon-upload                 { &:before { content: "\e027"; } }
+.glyphicon-inbox                  { &:before { content: "\e028"; } }
+.glyphicon-play-circle            { &:before { content: "\e029"; } }
+.glyphicon-repeat                 { &:before { content: "\e030"; } }
+.glyphicon-refresh                { &:before { content: "\e031"; } }
+.glyphicon-list-alt               { &:before { content: "\e032"; } }
+.glyphicon-lock                   { &:before { content: "\e033"; } }
+.glyphicon-flag                   { &:before { content: "\e034"; } }
+.glyphicon-headphones             { &:before { content: "\e035"; } }
+.glyphicon-volume-off             { &:before { content: "\e036"; } }
+.glyphicon-volume-down            { &:before { content: "\e037"; } }
+.glyphicon-volume-up              { &:before { content: "\e038"; } }
+.glyphicon-qrcode                 { &:before { content: "\e039"; } }
+.glyphicon-barcode                { &:before { content: "\e040"; } }
+.glyphicon-tag                    { &:before { content: "\e041"; } }
+.glyphicon-tags                   { &:before { content: "\e042"; } }
+.glyphicon-book                   { &:before { content: "\e043"; } }
+.glyphicon-bookmark               { &:before { content: "\e044"; } }
+.glyphicon-print                  { &:before { content: "\e045"; } }
+.glyphicon-camera                 { &:before { content: "\e046"; } }
+.glyphicon-font                   { &:before { content: "\e047"; } }
+.glyphicon-bold                   { &:before { content: "\e048"; } }
+.glyphicon-italic                 { &:before { content: "\e049"; } }
+.glyphicon-text-height            { &:before { content: "\e050"; } }
+.glyphicon-text-width             { &:before { content: "\e051"; } }
+.glyphicon-align-left             { &:before { content: "\e052"; } }
+.glyphicon-align-center           { &:before { content: "\e053"; } }
+.glyphicon-align-right            { &:before { content: "\e054"; } }
+.glyphicon-align-justify          { &:before { content: "\e055"; } }
+.glyphicon-list                   { &:before { content: "\e056"; } }
+.glyphicon-indent-left            { &:before { content: "\e057"; } }
+.glyphicon-indent-right           { &:before { content: "\e058"; } }
+.glyphicon-facetime-video         { &:before { content: "\e059"; } }
+.glyphicon-picture                { &:before { content: "\e060"; } }
+.glyphicon-map-marker             { &:before { content: "\e062"; } }
+.glyphicon-adjust                 { &:before { content: "\e063"; } }
+.glyphicon-tint                   { &:before { content: "\e064"; } }
+.glyphicon-edit                   { &:before { content: "\e065"; } }
+.glyphicon-share                  { &:before { content: "\e066"; } }
+.glyphicon-check                  { &:before { content: "\e067"; } }
+.glyphicon-move                   { &:before { content: "\e068"; } }
+.glyphicon-step-backward          { &:before { content: "\e069"; } }
+.glyphicon-fast-backward          { &:before { content: "\e070"; } }
+.glyphicon-backward               { &:before { content: "\e071"; } }
+.glyphicon-play                   { &:before { content: "\e072"; } }
+.glyphicon-pause                  { &:before { content: "\e073"; } }
+.glyphicon-stop                   { &:before { content: "\e074"; } }
+.glyphicon-forward                { &:before { content: "\e075"; } }
+.glyphicon-fast-forward           { &:before { content: "\e076"; } }
+.glyphicon-step-forward           { &:before { content: "\e077"; } }
+.glyphicon-eject                  { &:before { content: "\e078"; } }
+.glyphicon-chevron-left           { &:before { content: "\e079"; } }
+.glyphicon-chevron-right          { &:before { content: "\e080"; } }
+.glyphicon-plus-sign              { &:before { content: "\e081"; } }
+.glyphicon-minus-sign             { &:before { content: "\e082"; } }
+.glyphicon-remove-sign            { &:before { content: "\e083"; } }
+.glyphicon-ok-sign                { &:before { content: "\e084"; } }
+.glyphicon-question-sign          { &:before { content: "\e085"; } }
+.glyphicon-info-sign              { &:before { content: "\e086"; } }
+.glyphicon-screenshot             { &:before { content: "\e087"; } }
+.glyphicon-remove-circle          { &:before { content: "\e088"; } }
+.glyphicon-ok-circle              { &:before { content: "\e089"; } }
+.glyphicon-ban-circle             { &:before { content: "\e090"; } }
+.glyphicon-arrow-left             { &:before { content: "\e091"; } }
+.glyphicon-arrow-right            { &:before { content: "\e092"; } }
+.glyphicon-arrow-up               { &:before { content: "\e093"; } }
+.glyphicon-arrow-down             { &:before { content: "\e094"; } }
+.glyphicon-share-alt              { &:before { content: "\e095"; } }
+.glyphicon-resize-full            { &:before { content: "\e096"; } }
+.glyphicon-resize-small           { &:before { content: "\e097"; } }
+.glyphicon-exclamation-sign       { &:before { content: "\e101"; } }
+.glyphicon-gift                   { &:before { content: "\e102"; } }
+.glyphicon-leaf                   { &:before { content: "\e103"; } }
+.glyphicon-fire                   { &:before { content: "\e104"; } }
+.glyphicon-eye-open               { &:before { content: "\e105"; } }
+.glyphicon-eye-close              { &:before { content: "\e106"; } }
+.glyphicon-warning-sign           { &:before { content: "\e107"; } }
+.glyphicon-plane                  { &:before { content: "\e108"; } }
+.glyphicon-calendar               { &:before { content: "\e109"; } }
+.glyphicon-random                 { &:before { content: "\e110"; } }
+.glyphicon-comment                { &:before { content: "\e111"; } }
+.glyphicon-magnet                 { &:before { content: "\e112"; } }
+.glyphicon-chevron-up             { &:before { content: "\e113"; } }
+.glyphicon-chevron-down           { &:before { content: "\e114"; } }
+.glyphicon-retweet                { &:before { content: "\e115"; } }
+.glyphicon-shopping-cart          { &:before { content: "\e116"; } }
+.glyphicon-folder-close           { &:before { content: "\e117"; } }
+.glyphicon-folder-open            { &:before { content: "\e118"; } }
+.glyphicon-resize-vertical        { &:before { content: "\e119"; } }
+.glyphicon-resize-horizontal      { &:before { content: "\e120"; } }
+.glyphicon-hdd                    { &:before { content: "\e121"; } }
+.glyphicon-bullhorn               { &:before { content: "\e122"; } }
+.glyphicon-bell                   { &:before { content: "\e123"; } }
+.glyphicon-certificate            { &:before { content: "\e124"; } }
+.glyphicon-thumbs-up              { &:before { content: "\e125"; } }
+.glyphicon-thumbs-down            { &:before { content: "\e126"; } }
+.glyphicon-hand-right             { &:before { content: "\e127"; } }
+.glyphicon-hand-left              { &:before { content: "\e128"; } }
+.glyphicon-hand-up                { &:before { content: "\e129"; } }
+.glyphicon-hand-down              { &:before { content: "\e130"; } }
+.glyphicon-circle-arrow-right     { &:before { content: "\e131"; } }
+.glyphicon-circle-arrow-left      { &:before { content: "\e132"; } }
+.glyphicon-circle-arrow-up        { &:before { content: "\e133"; } }
+.glyphicon-circle-arrow-down      { &:before { content: "\e134"; } }
+.glyphicon-globe                  { &:before { content: "\e135"; } }
+.glyphicon-wrench                 { &:before { content: "\e136"; } }
+.glyphicon-tasks                  { &:before { content: "\e137"; } }
+.glyphicon-filter                 { &:before { content: "\e138"; } }
+.glyphicon-briefcase              { &:before { content: "\e139"; } }
+.glyphicon-fullscreen             { &:before { content: "\e140"; } }
+.glyphicon-dashboard              { &:before { content: "\e141"; } }
+.glyphicon-paperclip              { &:before { content: "\e142"; } }
+.glyphicon-heart-empty            { &:before { content: "\e143"; } }
+.glyphicon-link                   { &:before { content: "\e144"; } }
+.glyphicon-phone                  { &:before { content: "\e145"; } }
+.glyphicon-pushpin                { &:before { content: "\e146"; } }
+.glyphicon-usd                    { &:before { content: "\e148"; } }
+.glyphicon-gbp                    { &:before { content: "\e149"; } }
+.glyphicon-sort                   { &:before { content: "\e150"; } }
+.glyphicon-sort-by-alphabet       { &:before { content: "\e151"; } }
+.glyphicon-sort-by-alphabet-alt   { &:before { content: "\e152"; } }
+.glyphicon-sort-by-order          { &:before { content: "\e153"; } }
+.glyphicon-sort-by-order-alt      { &:before { content: "\e154"; } }
+.glyphicon-sort-by-attributes     { &:before { content: "\e155"; } }
+.glyphicon-sort-by-attributes-alt { &:before { content: "\e156"; } }
+.glyphicon-unchecked              { &:before { content: "\e157"; } }
+.glyphicon-expand                 { &:before { content: "\e158"; } }
+.glyphicon-collapse-down          { &:before { content: "\e159"; } }
+.glyphicon-collapse-up            { &:before { content: "\e160"; } }
+.glyphicon-log-in                 { &:before { content: "\e161"; } }
+.glyphicon-flash                  { &:before { content: "\e162"; } }
+.glyphicon-log-out                { &:before { content: "\e163"; } }
+.glyphicon-new-window             { &:before { content: "\e164"; } }
+.glyphicon-record                 { &:before { content: "\e165"; } }
+.glyphicon-save                   { &:before { content: "\e166"; } }
+.glyphicon-open                   { &:before { content: "\e167"; } }
+.glyphicon-saved                  { &:before { content: "\e168"; } }
+.glyphicon-import                 { &:before { content: "\e169"; } }
+.glyphicon-export                 { &:before { content: "\e170"; } }
+.glyphicon-send                   { &:before { content: "\e171"; } }
+.glyphicon-floppy-disk            { &:before { content: "\e172"; } }
+.glyphicon-floppy-saved           { &:before { content: "\e173"; } }
+.glyphicon-floppy-remove          { &:before { content: "\e174"; } }
+.glyphicon-floppy-save            { &:before { content: "\e175"; } }
+.glyphicon-floppy-open            { &:before { content: "\e176"; } }
+.glyphicon-credit-card            { &:before { content: "\e177"; } }
+.glyphicon-transfer               { &:before { content: "\e178"; } }
+.glyphicon-cutlery                { &:before { content: "\e179"; } }
+.glyphicon-header                 { &:before { content: "\e180"; } }
+.glyphicon-compressed             { &:before { content: "\e181"; } }
+.glyphicon-earphone               { &:before { content: "\e182"; } }
+.glyphicon-phone-alt              { &:before { content: "\e183"; } }
+.glyphicon-tower                  { &:before { content: "\e184"; } }
+.glyphicon-stats                  { &:before { content: "\e185"; } }
+.glyphicon-sd-video               { &:before { content: "\e186"; } }
+.glyphicon-hd-video               { &:before { content: "\e187"; } }
+.glyphicon-subtitles              { &:before { content: "\e188"; } }
+.glyphicon-sound-stereo           { &:before { content: "\e189"; } }
+.glyphicon-sound-dolby            { &:before { content: "\e190"; } }
+.glyphicon-sound-5-1              { &:before { content: "\e191"; } }
+.glyphicon-sound-6-1              { &:before { content: "\e192"; } }
+.glyphicon-sound-7-1              { &:before { content: "\e193"; } }
+.glyphicon-copyright-mark         { &:before { content: "\e194"; } }
+.glyphicon-registration-mark      { &:before { content: "\e195"; } }
+.glyphicon-cloud-download         { &:before { content: "\e197"; } }
+.glyphicon-cloud-upload           { &:before { content: "\e198"; } }
+.glyphicon-tree-conifer           { &:before { content: "\e199"; } }
+.glyphicon-tree-deciduous         { &:before { content: "\e200"; } }
+.glyphicon-cd                     { &:before { content: "\e201"; } }
+.glyphicon-save-file              { &:before { content: "\e202"; } }
+.glyphicon-open-file              { &:before { content: "\e203"; } }
+.glyphicon-level-up               { &:before { content: "\e204"; } }
+.glyphicon-copy                   { &:before { content: "\e205"; } }
+.glyphicon-paste                  { &:before { content: "\e206"; } }
+// The following 2 Glyphicons are omitted for the time being because
+// they currently use Unicode codepoints that are outside the
+// Basic Multilingual Plane (BMP). Older buggy versions of WebKit can't handle
+// non-BMP codepoints in CSS string escapes, and thus can't display these two icons.
+// Notably, the bug affects some older versions of the Android Browser.
+// More info: https://github.com/twbs/bootstrap/issues/10106
+// .glyphicon-door                   { &:before { content: "\1f6aa"; } }
+// .glyphicon-key                    { &:before { content: "\1f511"; } }
+.glyphicon-alert                  { &:before { content: "\e209"; } }
+.glyphicon-equalizer              { &:before { content: "\e210"; } }
+.glyphicon-king                   { &:before { content: "\e211"; } }
+.glyphicon-queen                  { &:before { content: "\e212"; } }
+.glyphicon-pawn                   { &:before { content: "\e213"; } }
+.glyphicon-bishop                 { &:before { content: "\e214"; } }
+.glyphicon-knight                 { &:before { content: "\e215"; } }
+.glyphicon-baby-formula           { &:before { content: "\e216"; } }
+.glyphicon-tent                   { &:before { content: "\26fa"; } }
+.glyphicon-blackboard             { &:before { content: "\e218"; } }
+.glyphicon-bed                    { &:before { content: "\e219"; } }
+.glyphicon-apple                  { &:before { content: "\f8ff"; } }
+.glyphicon-erase                  { &:before { content: "\e221"; } }
+.glyphicon-hourglass              { &:before { content: "\231b"; } }
+.glyphicon-lamp                   { &:before { content: "\e223"; } }
+.glyphicon-duplicate              { &:before { content: "\e224"; } }
+.glyphicon-piggy-bank             { &:before { content: "\e225"; } }
+.glyphicon-scissors               { &:before { content: "\e226"; } }
+.glyphicon-bitcoin                { &:before { content: "\e227"; } }
+.glyphicon-btc                    { &:before { content: "\e227"; } }
+.glyphicon-xbt                    { &:before { content: "\e227"; } }
+.glyphicon-yen                    { &:before { content: "\00a5"; } }
+.glyphicon-jpy                    { &:before { content: "\00a5"; } }
+.glyphicon-ruble                  { &:before { content: "\20bd"; } }
+.glyphicon-rub                    { &:before { content: "\20bd"; } }
+.glyphicon-scale                  { &:before { content: "\e230"; } }
+.glyphicon-ice-lolly              { &:before { content: "\e231"; } }
+.glyphicon-ice-lolly-tasted       { &:before { content: "\e232"; } }
+.glyphicon-education              { &:before { content: "\e233"; } }
+.glyphicon-option-horizontal      { &:before { content: "\e234"; } }
+.glyphicon-option-vertical        { &:before { content: "\e235"; } }
+.glyphicon-menu-hamburger         { &:before { content: "\e236"; } }
+.glyphicon-modal-window           { &:before { content: "\e237"; } }
+.glyphicon-oil                    { &:before { content: "\e238"; } }
+.glyphicon-grain                  { &:before { content: "\e239"; } }
+.glyphicon-sunglasses             { &:before { content: "\e240"; } }
+.glyphicon-text-size              { &:before { content: "\e241"; } }
+.glyphicon-text-color             { &:before { content: "\e242"; } }
+.glyphicon-text-background        { &:before { content: "\e243"; } }
+.glyphicon-object-align-top       { &:before { content: "\e244"; } }
+.glyphicon-object-align-bottom    { &:before { content: "\e245"; } }
+.glyphicon-object-align-horizontal{ &:before { content: "\e246"; } }
+.glyphicon-object-align-left      { &:before { content: "\e247"; } }
+.glyphicon-object-align-vertical  { &:before { content: "\e248"; } }
+.glyphicon-object-align-right     { &:before { content: "\e249"; } }
+.glyphicon-triangle-right         { &:before { content: "\e250"; } }
+.glyphicon-triangle-left          { &:before { content: "\e251"; } }
+.glyphicon-triangle-bottom        { &:before { content: "\e252"; } }
+.glyphicon-triangle-top           { &:before { content: "\e253"; } }
+.glyphicon-console                { &:before { content: "\e254"; } }
+.glyphicon-superscript            { &:before { content: "\e255"; } }
+.glyphicon-subscript              { &:before { content: "\e256"; } }
+.glyphicon-menu-left              { &:before { content: "\e257"; } }
+.glyphicon-menu-right             { &:before { content: "\e258"; } }
+.glyphicon-menu-down              { &:before { content: "\e259"; } }
+.glyphicon-menu-up                { &:before { content: "\e260"; } }
diff --git a/views/style/sass/bootstrap/bootstrap/_grid.scss b/views/style/sass/bootstrap/bootstrap/_grid.scss
new file mode 100644
index 0000000..b15ca27
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/_grid.scss
@@ -0,0 +1,84 @@
+//
+// Grid system
+// --------------------------------------------------
+
+
+// Container widths
+//
+// Set the container width, and override it for fixed navbars in media queries.
+
+.container {
+  @include container-fixed;
+
+  @media (min-width: $screen-sm-min) {
+    width: $container-sm;
+  }
+  @media (min-width: $screen-md-min) {
+    width: $container-md;
+  }
+  @media (min-width: $screen-lg-min) {
+    width: $container-lg;
+  }
+}
+
+
+// Fluid container
+//
+// Utilizes the mixin meant for fixed width containers, but without any defined
+// width for fluid, full width layouts.
+
+.container-fluid {
+  @include container-fixed;
+}
+
+
+// Row
+//
+// Rows contain and clear the floats of your columns.
+
+.row {
+  @include make-row;
+}
+
+
+// Columns
+//
+// Common styles for small and large grid columns
+
+@include make-grid-columns;
+
+
+// Extra small grid
+//
+// Columns, offsets, pushes, and pulls for extra small devices like
+// smartphones.
+
+@include make-grid(xs);
+
+
+// Small grid
+//
+// Columns, offsets, pushes, and pulls for the small device range, from phones
+// to tablets.
+
+@media (min-width: $screen-sm-min) {
+  @include make-grid(sm);
+}
+
+
+// Medium grid
+//
+// Columns, offsets, pushes, and pulls for the desktop device range.
+
+@media (min-width: $screen-md-min) {
+  @include make-grid(md);
+}
+
+
+// Large grid
+//
+// Columns, offsets, pushes, and pulls for the large desktop device range.
+
+@media (min-width: $screen-lg-min) {
+  @include make-grid(lg);
+}
diff --git a/views/style/sass/bootstrap/bootstrap/_input-groups.scss b/views/style/sass/bootstrap/bootstrap/_input-groups.scss
new file mode 100644
index 0000000..f7c1d60
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/_input-groups.scss
@@ -0,0 +1,171 @@
+//
+// Input groups
+// --------------------------------------------------
+
+// Base styles
+// -------------------------
+.input-group {
+  position: relative; // For dropdowns
+  display: table;
+  border-collapse: separate; // prevent input groups from inheriting border styles from table cells when placed within a table
+
+  // Undo padding and float of grid classes
+  &[class*="col-"] {
+    float: none;
+    padding-left: 0;
+    padding-right: 0;
+  }
+
+  .form-control {
+    // Ensure that the input is always above the *appended* addon button for
+    // proper border colors.
+    position: relative;
+    z-index: 2;
+
+    // IE9 fubars the placeholder attribute in text inputs and the arrows on
+    // select elements in input groups. To fix it, we float the input. Details:
+    // https://github.com/twbs/bootstrap/issues/11561#issuecomment-28936855
+    float: left;
+
+    width: 100%;
+    margin-bottom: 0;
+    
+    &:focus {
+      z-index: 3;
+    }
+  }
+}
+
+// Sizing options
+//
+// Remix the default form control sizing classes into new ones for easier
+// manipulation.
+
+.input-group-lg > .form-control,
+.input-group-lg > .input-group-addon,
+.input-group-lg > .input-group-btn > .btn {
+  @extend .input-lg;
+}
+.input-group-sm > .form-control,
+.input-group-sm > .input-group-addon,
+.input-group-sm > .input-group-btn > .btn {
+  @extend .input-sm;
+}
+
+
+// Display as table-cell
+// -------------------------
+.input-group-addon,
+.input-group-btn,
+.input-group .form-control {
+  display: table-cell;
+
+  &:not(:first-child):not(:last-child) {
+    border-radius: 0;
+  }
+}
+// Addon and addon wrapper for buttons
+.input-group-addon,
+.input-group-btn {
+  width: 1%;
+  white-space: nowrap;
+  vertical-align: middle; // Match the inputs
+}
+
+// Text input groups
+// -------------------------
+.input-group-addon {
+  padding: $padding-base-vertical $padding-base-horizontal;
+  font-size: $font-size-base;
+  font-weight: normal;
+  line-height: 1;
+  color: $input-color;
+  text-align: center;
+  background-color: $input-group-addon-bg;
+  border: 1px solid $input-group-addon-border-color;
+  border-radius: $input-border-radius;
+
+  // Sizing
+  &.input-sm {
+    padding: $padding-small-vertical $padding-small-horizontal;
+    font-size: $font-size-small;
+    border-radius: $input-border-radius-small;
+  }
+  &.input-lg {
+    padding: $padding-large-vertical $padding-large-horizontal;
+    font-size: $font-size-large;
+    border-radius: $input-border-radius-large;
+  }
+
+  // Nuke default margins from checkboxes and radios to vertically center within.
+  input[type="radio"],
+  input[type="checkbox"] {
+    margin-top: 0;
+  }
+}
+
+// Reset rounded corners
+.input-group .form-control:first-child,
+.input-group-addon:first-child,
+.input-group-btn:first-child > .btn,
+.input-group-btn:first-child > .btn-group > .btn,
+.input-group-btn:first-child > .dropdown-toggle,
+.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),
+.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {
+  @include border-right-radius(0);
+}
+.input-group-addon:first-child {
+  border-right: 0;
+}
+.input-group .form-control:last-child,
+.input-group-addon:last-child,
+.input-group-btn:last-child > .btn,
+.input-group-btn:last-child > .btn-group > .btn,
+.input-group-btn:last-child > .dropdown-toggle,
+.input-group-btn:first-child > .btn:not(:first-child),
+.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {
+  @include border-left-radius(0);
+}
+.input-group-addon:last-child {
+  border-left: 0;
+}
+
+// Button input groups
+// -------------------------
+.input-group-btn {
+  position: relative;
+  // Jankily prevent input button groups from wrapping with `white-space` and
+  // `font-size` in combination with `inline-block` on buttons.
+  font-size: 0;
+  white-space: nowrap;
+
+  // Negative margin for spacing, position for bringing hovered/focused/actived
+  // element above the siblings.
+  > .btn {
+    position: relative;
+    + .btn {
+      margin-left: -1px;
+    }
+    // Bring the "active" button to the front
+    &:hover,
+    &:focus,
+    &:active {
+      z-index: 2;
+    }
+  }
+
+  // Negative margin to only have a 1px border between the two
+  &:first-child {
+    > .btn,
+    > .btn-group {
+      margin-right: -1px;
+    }
+  }
+  &:last-child {
+    > .btn,
+    > .btn-group {
+      z-index: 2;
+      margin-left: -1px;
+    }
+  }
+}
diff --git a/views/style/sass/bootstrap/bootstrap/_jumbotron.scss b/views/style/sass/bootstrap/bootstrap/_jumbotron.scss
new file mode 100644
index 0000000..a27da47
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/_jumbotron.scss
@@ -0,0 +1,54 @@
+//
+// Jumbotron
+// --------------------------------------------------
+
+
+.jumbotron {
+  padding-top:    $jumbotron-padding;
+  padding-bottom: $jumbotron-padding;
+  margin-bottom: $jumbotron-padding;
+  color: $jumbotron-color;
+  background-color: $jumbotron-bg;
+
+  h1,
+  .h1 {
+    color: $jumbotron-heading-color;
+  }
+
+  p {
+    margin-bottom: ($jumbotron-padding / 2);
+    font-size: $jumbotron-font-size;
+    font-weight: 200;
+  }
+
+  > hr {
+    border-top-color: darken($jumbotron-bg, 10%);
+  }
+
+  .container &,
+  .container-fluid & {
+    border-radius: $border-radius-large; // Only round corners at higher resolutions if contained in a container
+    padding-left:  ($grid-gutter-width / 2);
+    padding-right: ($grid-gutter-width / 2);
+  }
+
+  .container {
+    max-width: 100%;
+  }
+
+  @media screen and (min-width: $screen-sm-min) {
+    padding-top:    ($jumbotron-padding * 1.6);
+    padding-bottom: ($jumbotron-padding * 1.6);
+
+    .container &,
+    .container-fluid & {
+      padding-left:  ($jumbotron-padding * 2);
+      padding-right: ($jumbotron-padding * 2);
+    }
+
+    h1,
+    .h1 {
+      font-size: $jumbotron-heading-font-size;
+    }
+  }
+}
diff --git a/views/style/sass/bootstrap/bootstrap/_labels.scss b/views/style/sass/bootstrap/bootstrap/_labels.scss
new file mode 100644
index 0000000..42ed6ea
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/_labels.scss
@@ -0,0 +1,66 @@
+//
+// Labels
+// --------------------------------------------------
+
+.label {
+  display: inline;
+  padding: .2em .6em .3em;
+  font-size: 75%;
+  font-weight: bold;
+  line-height: 1;
+  color: $label-color;
+  text-align: center;
+  white-space: nowrap;
+  vertical-align: baseline;
+  border-radius: .25em;
+
+  // [converter] extracted a& to a.label
+
+  // Empty labels collapse automatically (not available in IE8)
+  &:empty {
+    display: none;
+  }
+
+  // Quick fix for labels in buttons
+  .btn & {
+    position: relative;
+    top: -1px;
+  }
+}
+
+// Add hover effects, but only for links
+a.label {
+  &:hover,
+  &:focus {
+    color: $label-link-hover-color;
+    text-decoration: none;
+    cursor: pointer;
+  }
+}
+
+// Colors
+// Contextual variations (linked labels get darker on :hover)
+
+.label-default {
+  @include label-variant($label-default-bg);
+}
+
+.label-primary {
+  @include label-variant($label-primary-bg);
+}
+
+.label-success {
+  @include label-variant($label-success-bg);
+}
+
+.label-info {
+  @include label-variant($label-info-bg);
+}
+
+.label-warning {
+  @include label-variant($label-warning-bg);
+}
+
+.label-danger {
+  @include label-variant($label-danger-bg);
+}
diff --git a/views/style/sass/bootstrap/bootstrap/_list-group.scss b/views/style/sass/bootstrap/bootstrap/_list-group.scss
new file mode 100644
index 0000000..7cb83aa
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/_list-group.scss
@@ -0,0 +1,130 @@
+//
+// List groups
+// --------------------------------------------------
+
+
+// Base class
+//
+// Easily usable on <ul>, <ol>, or <div>.
+
+.list-group {
+  // No need to set list-style: none; since .list-group-item is block level
+  margin-bottom: 20px;
+  padding-left: 0; // reset padding because ul and ol
+}
+
+
+// Individual list items
+//
+// Use on `li`s or `div`s within the `.list-group` parent.
+
+.list-group-item {
+  position: relative;
+  display: block;
+  padding: 10px 15px;
+  // Place the border on the list items and negative margin up for better styling
+  margin-bottom: -1px;
+  background-color: $list-group-bg;
+  border: 1px solid $list-group-border;
+
+  // Round the first and last items
+  &:first-child {
+    @include border-top-radius($list-group-border-radius);
+  }
+  &:last-child {
+    margin-bottom: 0;
+    @include border-bottom-radius($list-group-border-radius);
+  }
+}
+
+
+// Interactive list items
+//
+// Use anchor or button elements instead of `li`s or `div`s to create interactive items.
+// Includes an extra `.active` modifier class for showing selected items.
+
+a.list-group-item,
+button.list-group-item {
+  color: $list-group-link-color;
+
+  .list-group-item-heading {
+    color: $list-group-link-heading-color;
+  }
+
+  // Hover state
+  &:hover,
+  &:focus {
+    text-decoration: none;
+    color: $list-group-link-hover-color;
+    background-color: $list-group-hover-bg;
+  }
+}
+
+button.list-group-item {
+  width: 100%;
+  text-align: left;
+}
+
+.list-group-item {
+  // Disabled state
+  &.disabled,
+  &.disabled:hover,
+  &.disabled:focus {
+    background-color: $list-group-disabled-bg;
+    color: $list-group-disabled-color;
+    cursor: $cursor-disabled;
+
+    // Force color to inherit for custom content
+    .list-group-item-heading {
+      color: inherit;
+    }
+    .list-group-item-text {
+      color: $list-group-disabled-text-color;
+    }
+  }
+
+  // Active class on item itself, not parent
+  &.active,
+  &.active:hover,
+  &.active:focus {
+    z-index: 2; // Place active items above their siblings for proper border styling
+    color: $list-group-active-color;
+    background-color: $list-group-active-bg;
+    border-color: $list-group-active-border;
+
+    // Force color to inherit for custom content
+    .list-group-item-heading,
+    .list-group-item-heading > small,
+    .list-group-item-heading > .small {
+      color: inherit;
+    }
+    .list-group-item-text {
+      color: $list-group-active-text-color;
+    }
+  }
+}
+
+
+// Contextual variants
+//
+// Add modifier classes to change text and background color on individual items.
+// Organizationally, this must come after the `:hover` states.
+
+@include list-group-item-variant(success, $state-success-bg, $state-success-text);
+@include list-group-item-variant(info, $state-info-bg, $state-info-text);
+@include list-group-item-variant(warning, $state-warning-bg, $state-warning-text);
+@include list-group-item-variant(danger, $state-danger-bg, $state-danger-text);
+
+
+// Custom content options
+//
+// Extra classes for creating well-formatted content within `.list-group-item`s.
+
+.list-group-item-heading {
+  margin-top: 0;
+  margin-bottom: 5px;
+}
+.list-group-item-text {
+  margin-bottom: 0;
+  line-height: 1.3;
+}
diff --git a/views/style/sass/bootstrap/bootstrap/_media.scss b/views/style/sass/bootstrap/bootstrap/_media.scss
new file mode 100644
index 0000000..8c835e8
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/_media.scss
@@ -0,0 +1,66 @@
+.media {
+  // Proper spacing between instances of .media
+  margin-top: 15px;
+
+  &:first-child {
+    margin-top: 0;
+  }
+}
+
+.media,
+.media-body {
+  zoom: 1;
+  overflow: hidden;
+}
+
+.media-body {
+  width: 10000px;
+}
+
+.media-object {
+  display: block;
+
+  // Fix collapse in webkit from max-width: 100% and display: table-cell.
+  &.img-thumbnail {
+    max-width: none;
+  }
+}
+
+.media-right,
+.media > .pull-right {
+  padding-left: 10px;
+}
+
+.media-left,
+.media > .pull-left {
+  padding-right: 10px;
+}
+
+.media-left,
+.media-right,
+.media-body {
+  display: table-cell;
+  vertical-align: top;
+}
+
+.media-middle {
+  vertical-align: middle;
+}
+
+.media-bottom {
+  vertical-align: bottom;
+}
+
+// Reset margins on headings for tighter default spacing
+.media-heading {
+  margin-top: 0;
+  margin-bottom: 5px;
+}
+
+// Media list variation
+//
+// Undo default ul/ol styles
+.media-list {
+  padding-left: 0;
+  list-style: none;
+}
diff --git a/views/style/sass/bootstrap/bootstrap/_mixins.scss b/views/style/sass/bootstrap/bootstrap/_mixins.scss
new file mode 100644
index 0000000..78cd5aa
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/_mixins.scss
@@ -0,0 +1,40 @@
+// Mixins
+// --------------------------------------------------
+
+// Utilities
+@import "mixins/hide-text";
+@import "mixins/opacity";
+@import "mixins/image";
+@import "mixins/labels";
+@import "mixins/reset-filter";
+@import "mixins/resize";
+@import "mixins/responsive-visibility";
+@import "mixins/size";
+@import "mixins/tab-focus";
+@import "mixins/reset-text";
+@import "mixins/text-emphasis";
+@import "mixins/text-overflow";
+@import "mixins/vendor-prefixes";
+
+// Components
+@import "mixins/alerts";
+@import "mixins/buttons";
+@import "mixins/panels";
+@import "mixins/pagination";
+@import "mixins/list-group";
+@import "mixins/nav-divider";
+@import "mixins/forms";
+@import "mixins/progress-bar";
+@import "mixins/table-row";
+
+// Skins
+@import "mixins/background-variant";
+@import "mixins/border-radius";
+@import "mixins/gradients";
+
+// Layout
+@import "mixins/clearfix";
+@import "mixins/center-block";
+@import "mixins/nav-vertical-align";
+@import "mixins/grid-framework";
+@import "mixins/grid";
diff --git a/views/style/sass/bootstrap/bootstrap/_modals.scss b/views/style/sass/bootstrap/bootstrap/_modals.scss
new file mode 100644
index 0000000..823870f
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/_modals.scss
@@ -0,0 +1,150 @@
+//
+// Modals
+// --------------------------------------------------
+
+// .modal-open      - body class for killing the scroll
+// .modal           - container to scroll within
+// .modal-dialog    - positioning shell for the actual modal
+// .modal-content   - actual modal w/ bg and corners and shit
+
+// Kill the scroll on the body
+.modal-open {
+  overflow: hidden;
+}
+
+// Container that the modal scrolls within
+.modal {
+  display: none;
+  overflow: hidden;
+  position: fixed;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  z-index: $zindex-modal;
+  -webkit-overflow-scrolling: touch;
+
+  // Prevent Chrome on Windows from adding a focus outline. For details, see
+  // https://github.com/twbs/bootstrap/pull/10951.
+  outline: 0;
+
+  // When fading in the modal, animate it to slide down
+  &.fade .modal-dialog {
+    @include translate(0, -25%);
+    @include transition-transform(0.3s ease-out);
+  }
+  &.in .modal-dialog { @include translate(0, 0) }
+}
+.modal-open .modal {
+  overflow-x: hidden;
+  overflow-y: auto;
+}
+
+// Shell div to position the modal with bottom padding
+.modal-dialog {
+  position: relative;
+  width: auto;
+  margin: 10px;
+}
+
+// Actual modal
+.modal-content {
+  position: relative;
+  background-color: $modal-content-bg;
+  border: 1px solid $modal-content-fallback-border-color; //old browsers fallback (ie8 etc)
+  border: 1px solid $modal-content-border-color;
+  border-radius: $border-radius-large;
+  @include box-shadow(0 3px 9px rgba(0,0,0,.5));
+  background-clip: padding-box;
+  // Remove focus outline from opened modal
+  outline: 0;
+}
+
+// Modal background
+.modal-backdrop {
+  position: fixed;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  z-index: $zindex-modal-background;
+  background-color: $modal-backdrop-bg;
+  // Fade for backdrop
+  &.fade { @include opacity(0); }
+  &.in { @include opacity($modal-backdrop-opacity); }
+}
+
+// Modal header
+// Top section of the modal w/ title and dismiss
+.modal-header {
+  padding: $modal-title-padding;
+  border-bottom: 1px solid $modal-header-border-color;
+  @include clearfix;
+}
+// Close icon
+.modal-header .close {
+  margin-top: -2px;
+}
+
+// Title text within header
+.modal-title {
+  margin: 0;
+  line-height: $modal-title-line-height;
+}
+
+// Modal body
+// Where all modal content resides (sibling of .modal-header and .modal-footer)
+.modal-body {
+  position: relative;
+  padding: $modal-inner-padding;
+}
+
+// Footer (for actions)
+.modal-footer {
+  padding: $modal-inner-padding;
+  text-align: right; // right align buttons
+  border-top: 1px solid $modal-footer-border-color;
+  @include clearfix; // clear it in case folks use .pull-* classes on buttons
+
+  // Properly space out buttons
+  .btn + .btn {
+    margin-left: 5px;
+    margin-bottom: 0; // account for input[type="submit"] which gets the bottom margin like all other inputs
+  }
+  // but override that for button groups
+  .btn-group .btn + .btn {
+    margin-left: -1px;
+  }
+  // and override it for block buttons as well
+  .btn-block + .btn-block {
+    margin-left: 0;
+  }
+}
+
+// Measure scrollbar width for padding body during modal show/hide
+.modal-scrollbar-measure {
+  position: absolute;
+  top: -9999px;
+  width: 50px;
+  height: 50px;
+  overflow: scroll;
+}
+
+// Scale up the modal
+@media (min-width: $screen-sm-min) {
+  // Automatically set modal's width for larger viewports
+  .modal-dialog {
+    width: $modal-md;
+    margin: 30px auto;
+  }
+  .modal-content {
+    @include box-shadow(0 5px 15px rgba(0,0,0,.5));
+  }
+
+  // Modal sizes
+  .modal-sm { width: $modal-sm; }
+}
+
+@media (min-width: $screen-md-min) {
+  .modal-lg { width: $modal-lg; }
+}
diff --git a/views/style/sass/bootstrap/bootstrap/_navbar.scss b/views/style/sass/bootstrap/bootstrap/_navbar.scss
new file mode 100644
index 0000000..11e5c01
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/_navbar.scss
@@ -0,0 +1,662 @@
+//
+// Navbars
+// --------------------------------------------------
+
+
+// Wrapper and base class
+//
+// Provide a static navbar from which we expand to create full-width, fixed, and
+// other navbar variations.
+
+.navbar {
+  position: relative;
+  min-height: $navbar-height; // Ensure a navbar always shows (e.g., without a .navbar-brand in collapsed mode)
+  margin-bottom: $navbar-margin-bottom;
+  border: 1px solid transparent;
+
+  // Prevent floats from breaking the navbar
+  @include clearfix;
+
+  @media (min-width: $grid-float-breakpoint) {
+    border-radius: $navbar-border-radius;
+  }
+}
+
+
+// Navbar heading
+//
+// Groups `.navbar-brand` and `.navbar-toggle` into a single component for easy
+// styling of responsive aspects.
+
+.navbar-header {
+  @include clearfix;
+
+  @media (min-width: $grid-float-breakpoint) {
+    float: left;
+  }
+}
+
+
+// Navbar collapse (body)
+//
+// Group your navbar content into this for easy collapsing and expanding across
+// various device sizes. By default, this content is collapsed when <768px, but
+// will expand past that for a horizontal display.
+//
+// To start (on mobile devices) the navbar links, forms, and buttons are stacked
+// vertically and include a `max-height` to overflow in case you have too much
+// content for the user's viewport.
+
+.navbar-collapse {
+  overflow-x: visible;
+  padding-right: $navbar-padding-horizontal;
+  padding-left:  $navbar-padding-horizontal;
+  border-top: 1px solid transparent;
+  box-shadow: inset 0 1px 0 rgba(255,255,255,.1);
+  @include clearfix;
+  -webkit-overflow-scrolling: touch;
+
+  &.in {
+    overflow-y: auto;
+  }
+
+  @media (min-width: $grid-float-breakpoint) {
+    width: auto;
+    border-top: 0;
+    box-shadow: none;
+
+    &.collapse {
+      display: block !important;
+      height: auto !important;
+      padding-bottom: 0; // Override default setting
+      overflow: visible !important;
+    }
+
+    &.in {
+      overflow-y: visible;
+    }
+
+    // Undo the collapse side padding for navbars with containers to ensure
+    // alignment of right-aligned contents.
+    .navbar-fixed-top &,
+    .navbar-static-top &,
+    .navbar-fixed-bottom & {
+      padding-left: 0;
+      padding-right: 0;
+    }
+  }
+}
+
+.navbar-fixed-top,
+.navbar-fixed-bottom {
+  .navbar-collapse {
+    max-height: $navbar-collapse-max-height;
+
+    @media (max-device-width: $screen-xs-min) and (orientation: landscape) {
+      max-height: 200px;
+    }
+  }
+}
+
+
+// Both navbar header and collapse
+//
+// When a container is present, change the behavior of the header and collapse.
+
+.container,
+.container-fluid {
+  > .navbar-header,
+  > .navbar-collapse {
+    margin-right: -$navbar-padding-horizontal;
+    margin-left:  -$navbar-padding-horizontal;
+
+    @media (min-width: $grid-float-breakpoint) {
+      margin-right: 0;
+      margin-left:  0;
+    }
+  }
+}
+
+
+//
+// Navbar alignment options
+//
+// Display the navbar across the entirety of the page or fixed it to the top or
+// bottom of the page.
+
+// Static top (unfixed, but 100% wide) navbar
+.navbar-static-top {
+  z-index: $zindex-navbar;
+  border-width: 0 0 1px;
+
+  @media (min-width: $grid-float-breakpoint) {
+    border-radius: 0;
+  }
+}
+
+// Fix the top/bottom navbars when screen real estate supports it
+.navbar-fixed-top,
+.navbar-fixed-bottom {
+  position: fixed;
+  right: 0;
+  left: 0;
+  z-index: $zindex-navbar-fixed;
+
+  // Undo the rounded corners
+  @media (min-width: $grid-float-breakpoint) {
+    border-radius: 0;
+  }
+}
+.navbar-fixed-top {
+  top: 0;
+  border-width: 0 0 1px;
+}
+.navbar-fixed-bottom {
+  bottom: 0;
+  margin-bottom: 0; // override .navbar defaults
+  border-width: 1px 0 0;
+}
+
+
+// Brand/project name
+
+.navbar-brand {
+  float: left;
+  padding: $navbar-padding-vertical $navbar-padding-horizontal;
+  font-size: $font-size-large;
+  line-height: $line-height-computed;
+  height: $navbar-height;
+
+  &:hover,
+  &:focus {
+    text-decoration: none;
+  }
+
+  > img {
+    display: block;
+  }
+
+  @media (min-width: $grid-float-breakpoint) {
+    .navbar > .container &,
+    .navbar > .container-fluid & {
+      margin-left: -$navbar-padding-horizontal;
+    }
+  }
+}
+
+
+// Navbar toggle
+//
+// Custom button for toggling the `.navbar-collapse`, powered by the collapse
+// JavaScript plugin.
+
+.navbar-toggle {
+  position: relative;
+  float: right;
+  margin-right: $navbar-padding-horizontal;
+  padding: 9px 10px;
+  @include navbar-vertical-align(34px);
+  background-color: transparent;
+  background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214
+  border: 1px solid transparent;
+  border-radius: $border-radius-base;
+
+  // We remove the `outline` here, but later compensate by attaching `:hover`
+  // styles to `:focus`.
+  &:focus {
+    outline: 0;
+  }
+
+  // Bars
+  .icon-bar {
+    display: block;
+    width: 22px;
+    height: 2px;
+    border-radius: 1px;
+  }
+  .icon-bar + .icon-bar {
+    margin-top: 4px;
+  }
+
+  @media (min-width: $grid-float-breakpoint) {
+    display: none;
+  }
+}
+
+
+// Navbar nav links
+//
+// Builds on top of the `.nav` components with its own modifier class to make
+// the nav the full height of the horizontal nav (above 768px).
+
+.navbar-nav {
+  margin: ($navbar-padding-vertical / 2) (-$navbar-padding-horizontal);
+
+  > li > a {
+    padding-top:    10px;
+    padding-bottom: 10px;
+    line-height: $line-height-computed;
+  }
+
+  @media (max-width: $grid-float-breakpoint-max) {
+    // Dropdowns get custom display when collapsed
+    .open .dropdown-menu {
+      position: static;
+      float: none;
+      width: auto;
+      margin-top: 0;
+      background-color: transparent;
+      border: 0;
+      box-shadow: none;
+      > li > a,
+      .dropdown-header {
+        padding: 5px 15px 5px 25px;
+      }
+      > li > a {
+        line-height: $line-height-computed;
+        &:hover,
+        &:focus {
+          background-image: none;
+        }
+      }
+    }
+  }
+
+  // Uncollapse the nav
+  @media (min-width: $grid-float-breakpoint) {
+    float: left;
+    margin: 0;
+
+    > li {
+      float: left;
+      > a {
+        padding-top:    $navbar-padding-vertical;
+        padding-bottom: $navbar-padding-vertical;
+      }
+    }
+  }
+}
+
+
+// Navbar form
+//
+// Extension of the `.form-inline` with some extra flavor for optimum display in
+// our navbars.
+
+.navbar-form {
+  margin-left: -$navbar-padding-horizontal;
+  margin-right: -$navbar-padding-horizontal;
+  padding: 10px $navbar-padding-horizontal;
+  border-top: 1px solid transparent;
+  border-bottom: 1px solid transparent;
+  $shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);
+  @include box-shadow($shadow);
+
+  // Mixin behavior for optimum display
+  @include form-inline;
+
+  .form-group {
+    @media (max-width: $grid-float-breakpoint-max) {
+      margin-bottom: 5px;
+
+      &:last-child {
+        margin-bottom: 0;
+      }
+    }
+  }
+
+  // Vertically center in expanded, horizontal navbar
+  @include navbar-vertical-align($input-height-base);
+
+  // Undo 100% width for pull classes
+  @media (min-width: $grid-float-breakpoint) {
+    width: auto;
+    border: 0;
+    margin-left: 0;
+    margin-right: 0;
+    padding-top: 0;
+    padding-bottom: 0;
+    @include box-shadow(none);
+  }
+}
+
+
+// Dropdown menus
+
+// Menu position and menu carets
+.navbar-nav > li > .dropdown-menu {
+  margin-top: 0;
+  @include border-top-radius(0);
+}
+// Menu position and menu caret support for dropups via extra dropup class
+.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {
+  margin-bottom: 0;
+  @include border-top-radius($navbar-border-radius);
+  @include border-bottom-radius(0);
+}
+
+
+// Buttons in navbars
+//
+// Vertically center a button within a navbar (when *not* in a form).
+
+.navbar-btn {
+  @include navbar-vertical-align($input-height-base);
+
+  &.btn-sm {
+    @include navbar-vertical-align($input-height-small);
+  }
+  &.btn-xs {
+    @include navbar-vertical-align(22);
+  }
+}
+
+
+// Text in navbars
+//
+// Add a class to make any element properly align itself vertically within the navbars.
+
+.navbar-text {
+  @include navbar-vertical-align($line-height-computed);
+
+  @media (min-width: $grid-float-breakpoint) {
+    float: left;
+    margin-left: $navbar-padding-horizontal;
+    margin-right: $navbar-padding-horizontal;
+  }
+}
+
+
+// Component alignment
+//
+// Repurpose the pull utilities as their own navbar utilities to avoid specificity
+// issues with parents and chaining. Only do this when the navbar is uncollapsed
+// though so that navbar contents properly stack and align in mobile.
+//
+// Declared after the navbar components to ensure more specificity on the margins.
+
+@media (min-width: $grid-float-breakpoint) {
+  .navbar-left {
+    float: left !important;
+  }
+  .navbar-right {
+    float: right !important;
+  margin-right: -$navbar-padding-horizontal;
+
+    ~ .navbar-right {
+      margin-right: 0;
+    }
+  }
+}
+
+
+// Alternate navbars
+// --------------------------------------------------
+
+// Default navbar
+.navbar-default {
+  background-color: $navbar-default-bg;
+  border-color: $navbar-default-border;
+
+  .navbar-brand {
+    color: $navbar-default-brand-color;
+    &:hover,
+    &:focus {
+      color: $navbar-default-brand-hover-color;
+      background-color: $navbar-default-brand-hover-bg;
+    }
+  }
+
+  .navbar-text {
+    color: $navbar-default-color;
+  }
+
+  .navbar-nav {
+    > li > a {
+      color: $navbar-default-link-color;
+
+      &:hover,
+      &:focus {
+        color: $navbar-default-link-hover-color;
+        background-color: $navbar-default-link-hover-bg;
+      }
+    }
+    > .active > a {
+      &,
+      &:hover,
+      &:focus {
+        color: $navbar-default-link-active-color;
+        background-color: $navbar-default-link-active-bg;
+      }
+    }
+    > .disabled > a {
+      &,
+      &:hover,
+      &:focus {
+        color: $navbar-default-link-disabled-color;
+        background-color: $navbar-default-link-disabled-bg;
+      }
+    }
+  }
+
+  .navbar-toggle {
+    border-color: $navbar-default-toggle-border-color;
+    &:hover,
+    &:focus {
+      background-color: $navbar-default-toggle-hover-bg;
+    }
+    .icon-bar {
+      background-color: $navbar-default-toggle-icon-bar-bg;
+    }
+  }
+
+  .navbar-collapse,
+  .navbar-form {
+    border-color: $navbar-default-border;
+  }
+
+  // Dropdown menu items
+  .navbar-nav {
+    // Remove background color from open dropdown
+    > .open > a {
+      &,
+      &:hover,
+      &:focus {
+        background-color: $navbar-default-link-active-bg;
+        color: $navbar-default-link-active-color;
+      }
+    }
+
+    @media (max-width: $grid-float-breakpoint-max) {
+      // Dropdowns get custom display when collapsed
+      .open .dropdown-menu {
+        > li > a {
+          color: $navbar-default-link-color;
+          &:hover,
+          &:focus {
+            color: $navbar-default-link-hover-color;
+            background-color: $navbar-default-link-hover-bg;
+          }
+        }
+        > .active > a {
+          &,
+          &:hover,
+          &:focus {
+            color: $navbar-default-link-active-color;
+            background-color: $navbar-default-link-active-bg;
+          }
+        }
+        > .disabled > a {
+          &,
+          &:hover,
+          &:focus {
+            color: $navbar-default-link-disabled-color;
+            background-color: $navbar-default-link-disabled-bg;
+          }
+        }
+      }
+    }
+  }
+
+
+  // Links in navbars
+  //
+  // Add a class to ensure links outside the navbar nav are colored correctly.
+
+  .navbar-link {
+    color: $navbar-default-link-color;
+    &:hover {
+      color: $navbar-default-link-hover-color;
+    }
+  }
+
+  .btn-link {
+    color: $navbar-default-link-color;
+    &:hover,
+    &:focus {
+      color: $navbar-default-link-hover-color;
+    }
+    &[disabled],
+    fieldset[disabled] & {
+      &:hover,
+      &:focus {
+        color: $navbar-default-link-disabled-color;
+      }
+    }
+  }
+}
+
+// Inverse navbar
+
+.navbar-inverse {
+  background-color: $navbar-inverse-bg;
+  border-color: $navbar-inverse-border;
+
+  .navbar-brand {
+    color: $navbar-inverse-brand-color;
+    &:hover,
+    &:focus {
+      color: $navbar-inverse-brand-hover-color;
+      background-color: $navbar-inverse-brand-hover-bg;
+    }
+  }
+
+  .navbar-text {
+    color: $navbar-inverse-color;
+  }
+
+  .navbar-nav {
+    > li > a {
+      color: $navbar-inverse-link-color;
+
+      &:hover,
+      &:focus {
+        color: $navbar-inverse-link-hover-color;
+        background-color: $navbar-inverse-link-hover-bg;
+      }
+    }
+    > .active > a {
+      &,
+      &:hover,
+      &:focus {
+        color: $navbar-inverse-link-active-color;
+        background-color: $navbar-inverse-link-active-bg;
+      }
+    }
+    > .disabled > a {
+      &,
+      &:hover,
+      &:focus {
+        color: $navbar-inverse-link-disabled-color;
+        background-color: $navbar-inverse-link-disabled-bg;
+      }
+    }
+  }
+
+  // Darken the responsive nav toggle
+  .navbar-toggle {
+    border-color: $navbar-inverse-toggle-border-color;
+    &:hover,
+    &:focus {
+      background-color: $navbar-inverse-toggle-hover-bg;
+    }
+    .icon-bar {
+      background-color: $navbar-inverse-toggle-icon-bar-bg;
+    }
+  }
+
+  .navbar-collapse,
+  .navbar-form {
+    border-color: darken($navbar-inverse-bg, 7%);
+  }
+
+  // Dropdowns
+  .navbar-nav {
+    > .open > a {
+      &,
+      &:hover,
+      &:focus {
+        background-color: $navbar-inverse-link-active-bg;
+        color: $navbar-inverse-link-active-color;
+      }
+    }
+
+    @media (max-width: $grid-float-breakpoint-max) {
+      // Dropdowns get custom display
+      .open .dropdown-menu {
+        > .dropdown-header {
+          border-color: $navbar-inverse-border;
+        }
+        .divider {
+          background-color: $navbar-inverse-border;
+        }
+        > li > a {
+          color: $navbar-inverse-link-color;
+          &:hover,
+          &:focus {
+            color: $navbar-inverse-link-hover-color;
+            background-color: $navbar-inverse-link-hover-bg;
+          }
+        }
+        > .active > a {
+          &,
+          &:hover,
+          &:focus {
+            color: $navbar-inverse-link-active-color;
+            background-color: $navbar-inverse-link-active-bg;
+          }
+        }
+        > .disabled > a {
+          &,
+          &:hover,
+          &:focus {
+            color: $navbar-inverse-link-disabled-color;
+            background-color: $navbar-inverse-link-disabled-bg;
+          }
+        }
+      }
+    }
+  }
+
+  .navbar-link {
+    color: $navbar-inverse-link-color;
+    &:hover {
+      color: $navbar-inverse-link-hover-color;
+    }
+  }
+
+  .btn-link {
+    color: $navbar-inverse-link-color;
+    &:hover,
+    &:focus {
+      color: $navbar-inverse-link-hover-color;
+    }
+    &[disabled],
+    fieldset[disabled] & {
+      &:hover,
+      &:focus {
+        color: $navbar-inverse-link-disabled-color;
+      }
+    }
+  }
+}
diff --git a/views/style/sass/bootstrap/bootstrap/_navs.scss b/views/style/sass/bootstrap/bootstrap/_navs.scss
new file mode 100644
index 0000000..9d369f3
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/_navs.scss
@@ -0,0 +1,242 @@
+//
+// Navs
+// --------------------------------------------------
+
+
+// Base class
+// --------------------------------------------------
+
+.nav {
+  margin-bottom: 0;
+  padding-left: 0; // Override default ul/ol
+  list-style: none;
+  @include clearfix;
+
+  > li {
+    position: relative;
+    display: block;
+
+    > a {
+      position: relative;
+      display: block;
+      padding: $nav-link-padding;
+      &:hover,
+      &:focus {
+        text-decoration: none;
+        background-color: $nav-link-hover-bg;
+      }
+    }
+
+    // Disabled state sets text to gray and nukes hover/tab effects
+    &.disabled > a {
+      color: $nav-disabled-link-color;
+
+      &:hover,
+      &:focus {
+        color: $nav-disabled-link-hover-color;
+        text-decoration: none;
+        background-color: transparent;
+        cursor: $cursor-disabled;
+      }
+    }
+  }
+
+  // Open dropdowns
+  .open > a {
+    &,
+    &:hover,
+    &:focus {
+      background-color: $nav-link-hover-bg;
+      border-color: $link-color;
+    }
+  }
+
+  // Nav dividers (deprecated with v3.0.1)
+  //
+  // This should have been removed in v3 with the dropping of `.nav-list`, but
+  // we missed it. We don't currently support this anywhere, but in the interest
+  // of maintaining backward compatibility in case you use it, it's deprecated.
+  .nav-divider {
+    @include nav-divider;
+  }
+
+  // Prevent IE8 from misplacing imgs
+  //
+  // See https://github.com/h5bp/html5-boilerplate/issues/984#issuecomment-3985989
+  > li > a > img {
+    max-width: none;
+  }
+}
+
+
+// Tabs
+// -------------------------
+
+// Give the tabs something to sit on
+.nav-tabs {
+  border-bottom: 1px solid $nav-tabs-border-color;
+  > li {
+    float: left;
+    // Make the list-items overlay the bottom border
+    margin-bottom: -1px;
+
+    // Actual tabs (as links)
+    > a {
+      margin-right: 2px;
+      line-height: $line-height-base;
+      border: 1px solid transparent;
+      border-radius: $border-radius-base $border-radius-base 0 0;
+      &:hover {
+        border-color: $nav-tabs-link-hover-border-color $nav-tabs-link-hover-border-color $nav-tabs-border-color;
+      }
+    }
+
+    // Active state, and its :hover to override normal :hover
+    &.active > a {
+      &,
+      &:hover,
+      &:focus {
+        color: $nav-tabs-active-link-hover-color;
+        background-color: $nav-tabs-active-link-hover-bg;
+        border: 1px solid $nav-tabs-active-link-hover-border-color;
+        border-bottom-color: transparent;
+        cursor: default;
+      }
+    }
+  }
+  // pulling this in mainly for less shorthand
+  &.nav-justified {
+    @extend .nav-justified;
+    @extend .nav-tabs-justified;
+  }
+}
+
+
+// Pills
+// -------------------------
+.nav-pills {
+  > li {
+    float: left;
+
+    // Links rendered as pills
+    > a {
+      border-radius: $nav-pills-border-radius;
+    }
+    + li {
+      margin-left: 2px;
+    }
+
+    // Active state
+    &.active > a {
+      &,
+      &:hover,
+      &:focus {
+        color: $nav-pills-active-link-hover-color;
+        background-color: $nav-pills-active-link-hover-bg;
+      }
+    }
+  }
+}
+
+
+// Stacked pills
+.nav-stacked {
+  > li {
+    float: none;
+    + li {
+      margin-top: 2px;
+      margin-left: 0; // no need for this gap between nav items
+    }
+  }
+}
+
+
+// Nav variations
+// --------------------------------------------------
+
+// Justified nav links
+// -------------------------
+
+.nav-justified {
+  width: 100%;
+
+  > li {
+    float: none;
+    > a {
+      text-align: center;
+      margin-bottom: 5px;
+    }
+  }
+
+  > .dropdown .dropdown-menu {
+    top: auto;
+    left: auto;
+  }
+
+  @media (min-width: $screen-sm-min) {
+    > li {
+      display: table-cell;
+      width: 1%;
+      > a {
+        margin-bottom: 0;
+      }
+    }
+  }
+}
+
+// Move borders to anchors instead of bottom of list
+//
+// Mixin for adding on top the shared `.nav-justified` styles for our tabs
+.nav-tabs-justified {
+  border-bottom: 0;
+
+  > li > a {
+    // Override margin from .nav-tabs
+    margin-right: 0;
+    border-radius: $border-radius-base;
+  }
+
+  > .active > a,
+  > .active > a:hover,
+  > .active > a:focus {
+    border: 1px solid $nav-tabs-justified-link-border-color;
+  }
+
+  @media (min-width: $screen-sm-min) {
+    > li > a {
+      border-bottom: 1px solid $nav-tabs-justified-link-border-color;
+      border-radius: $border-radius-base $border-radius-base 0 0;
+    }
+    > .active > a,
+    > .active > a:hover,
+    > .active > a:focus {
+      border-bottom-color: $nav-tabs-justified-active-link-border-color;
+    }
+  }
+}
+
+
+// Tabbable tabs
+// -------------------------
+
+// Hide tabbable panes to start, show them when `.active`
+.tab-content {
+  > .tab-pane {
+    display: none;
+  }
+  > .active {
+    display: block;
+  }
+}
+
+
+// Dropdowns
+// -------------------------
+
+// Specific dropdowns
+.nav-tabs .dropdown-menu {
+  // make dropdown border overlap tab border
+  margin-top: -1px;
+  // Remove the top rounded corners here since there is a hard edge above the menu
+  @include border-top-radius(0);
+}
diff --git a/views/style/sass/bootstrap/bootstrap/_normalize.scss b/views/style/sass/bootstrap/bootstrap/_normalize.scss
new file mode 100644
index 0000000..9dddf73
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/_normalize.scss
@@ -0,0 +1,424 @@
+/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
+
+//
+// 1. Set default font family to sans-serif.
+// 2. Prevent iOS and IE text size adjust after device orientation change,
+//    without disabling user zoom.
+//
+
+html {
+  font-family: sans-serif; // 1
+  -ms-text-size-adjust: 100%; // 2
+  -webkit-text-size-adjust: 100%; // 2
+}
+
+//
+// Remove default margin.
+//
+
+body {
+  margin: 0;
+}
+
+// HTML5 display definitions
+// ==========================================================================
+
+//
+// Correct `block` display not defined for any HTML5 element in IE 8/9.
+// Correct `block` display not defined for `details` or `summary` in IE 10/11
+// and Firefox.
+// Correct `block` display not defined for `main` in IE 11.
+//
+
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+main,
+menu,
+nav,
+section,
+summary {
+  display: block;
+}
+
+//
+// 1. Correct `inline-block` display not defined in IE 8/9.
+// 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
+//
+
+audio,
+canvas,
+progress,
+video {
+  display: inline-block; // 1
+  vertical-align: baseline; // 2
+}
+
+//
+// Prevent modern browsers from displaying `audio` without controls.
+// Remove excess height in iOS 5 devices.
+//
+
+audio:not([controls]) {
+  display: none;
+  height: 0;
+}
+
+//
+// Address `[hidden]` styling not present in IE 8/9/10.
+// Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.
+//
+
+[hidden],
+template {
+  display: none;
+}
+
+// Links
+// ==========================================================================
+
+//
+// Remove the gray background color from active links in IE 10.
+//
+
+a {
+  background-color: transparent;
+}
+
+//
+// Improve readability of focused elements when they are also in an
+// active/hover state.
+//
+
+a:active,
+a:hover {
+  outline: 0;
+}
+
+// Text-level semantics
+// ==========================================================================
+
+//
+// Address styling not present in IE 8/9/10/11, Safari, and Chrome.
+//
+
+abbr[title] {
+  border-bottom: 1px dotted;
+}
+
+//
+// Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
+//
+
+b,
+strong {
+  font-weight: bold;
+}
+
+//
+// Address styling not present in Safari and Chrome.
+//
+
+dfn {
+  font-style: italic;
+}
+
+//
+// Address variable `h1` font-size and margin within `section` and `article`
+// contexts in Firefox 4+, Safari, and Chrome.
+//
+
+h1 {
+  font-size: 2em;
+  margin: 0.67em 0;
+}
+
+//
+// Address styling not present in IE 8/9.
+//
+
+mark {
+  background: #ff0;
+  color: #000;
+}
+
+//
+// Address inconsistent and variable font size in all browsers.
+//
+
+small {
+  font-size: 80%;
+}
+
+//
+// Prevent `sub` and `sup` affecting `line-height` in all browsers.
+//
+
+sub,
+sup {
+  font-size: 75%;
+  line-height: 0;
+  position: relative;
+  vertical-align: baseline;
+}
+
+sup {
+  top: -0.5em;
+}
+
+sub {
+  bottom: -0.25em;
+}
+
+// Embedded content
+// ==========================================================================
+
+//
+// Remove border when inside `a` element in IE 8/9/10.
+//
+
+img {
+  border: 0;
+}
+
+//
+// Correct overflow not hidden in IE 9/10/11.
+//
+
+svg:not(:root) {
+  overflow: hidden;
+}
+
+// Grouping content
+// ==========================================================================
+
+//
+// Address margin not present in IE 8/9 and Safari.
+//
+
+figure {
+  margin: 1em 40px;
+}
+
+//
+// Address differences between Firefox and other browsers.
+//
+
+hr {
+  box-sizing: content-box;
+  height: 0;
+}
+
+//
+// Contain overflow in all browsers.
+//
+
+pre {
+  overflow: auto;
+}
+
+//
+// Address odd `em`-unit font size rendering in all browsers.
+//
+
+code,
+kbd,
+pre,
+samp {
+  font-family: monospace, monospace;
+  font-size: 1em;
+}
+
+// Forms
+// ==========================================================================
+
+//
+// Known limitation: by default, Chrome and Safari on OS X allow very limited
+// styling of `select`, unless a `border` property is set.
+//
+
+//
+// 1. Correct color not being inherited.
+//    Known issue: affects color of disabled elements.
+// 2. Correct font properties not being inherited.
+// 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
+//
+
+button,
+input,
+optgroup,
+select,
+textarea {
+  color: inherit; // 1
+  font: inherit; // 2
+  margin: 0; // 3
+}
+
+//
+// Address `overflow` set to `hidden` in IE 8/9/10/11.
+//
+
+button {
+  overflow: visible;
+}
+
+//
+// Address inconsistent `text-transform` inheritance for `button` and `select`.
+// All other form control elements do not inherit `text-transform` values.
+// Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
+// Correct `select` style inheritance in Firefox.
+//
+
+button,
+select {
+  text-transform: none;
+}
+
+//
+// 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
+//    and `video` controls.
+// 2. Correct inability to style clickable `input` types in iOS.
+// 3. Improve usability and consistency of cursor style between image-type
+//    `input` and others.
+//
+
+button,
+html input[type="button"], // 1
+input[type="reset"],
+input[type="submit"] {
+  -webkit-appearance: button; // 2
+  cursor: pointer; // 3
+}
+
+//
+// Re-set default cursor for disabled elements.
+//
+
+button[disabled],
+html input[disabled] {
+  cursor: default;
+}
+
+//
+// Remove inner padding and border in Firefox 4+.
+//
+
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+  border: 0;
+  padding: 0;
+}
+
+//
+// Address Firefox 4+ setting `line-height` on `input` using `!important` in
+// the UA stylesheet.
+//
+
+input {
+  line-height: normal;
+}
+
+//
+// It's recommended that you don't attempt to style these elements.
+// Firefox's implementation doesn't respect box-sizing, padding, or width.
+//
+// 1. Address box sizing set to `content-box` in IE 8/9/10.
+// 2. Remove excess padding in IE 8/9/10.
+//
+
+input[type="checkbox"],
+input[type="radio"] {
+  box-sizing: border-box; // 1
+  padding: 0; // 2
+}
+
+//
+// Fix the cursor style for Chrome's increment/decrement buttons. For certain
+// `font-size` values of the `input`, it causes the cursor style of the
+// decrement button to change from `default` to `text`.
+//
+
+input[type="number"]::-webkit-inner-spin-button,
+input[type="number"]::-webkit-outer-spin-button {
+  height: auto;
+}
+
+//
+// 1. Address `appearance` set to `searchfield` in Safari and Chrome.
+// 2. Address `box-sizing` set to `border-box` in Safari and Chrome.
+//
+
+input[type="search"] {
+  -webkit-appearance: textfield; // 1
+  box-sizing: content-box; //2
+}
+
+//
+// Remove inner padding and search cancel button in Safari and Chrome on OS X.
+// Safari (but not Chrome) clips the cancel button when the search input has
+// padding (and `textfield` appearance).
+//
+
+input[type="search"]::-webkit-search-cancel-button,
+input[type="search"]::-webkit-search-decoration {
+  -webkit-appearance: none;
+}
+
+//
+// Define consistent border, margin, and padding.
+//
+
+fieldset {
+  border: 1px solid #c0c0c0;
+  margin: 0 2px;
+  padding: 0.35em 0.625em 0.75em;
+}
+
+//
+// 1. Correct `color` not being inherited in IE 8/9/10/11.
+// 2. Remove padding so people aren't caught out if they zero out fieldsets.
+//
+
+legend {
+  border: 0; // 1
+  padding: 0; // 2
+}
+
+//
+// Remove default vertical scrollbar in IE 8/9/10/11.
+//
+
+textarea {
+  overflow: auto;
+}
+
+//
+// Don't inherit the `font-weight` (applied by a rule above).
+// NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
+//
+
+optgroup {
+  font-weight: bold;
+}
+
+// Tables
+// ==========================================================================
+
+//
+// Remove most spacing between table cells.
+//
+
+table {
+  border-collapse: collapse;
+  border-spacing: 0;
+}
+
+td,
+th {
+  padding: 0;
+}
diff --git a/views/style/sass/bootstrap/bootstrap/_pager.scss b/views/style/sass/bootstrap/bootstrap/_pager.scss
new file mode 100644
index 0000000..c234217
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/_pager.scss
@@ -0,0 +1,54 @@
+//
+// Pager pagination
+// --------------------------------------------------
+
+
+.pager {
+  padding-left: 0;
+  margin: $line-height-computed 0;
+  list-style: none;
+  text-align: center;
+  @include clearfix;
+  li {
+    display: inline;
+    > a,
+    > span {
+      display: inline-block;
+      padding: 5px 14px;
+      background-color: $pager-bg;
+      border: 1px solid $pager-border;
+      border-radius: $pager-border-radius;
+    }
+
+    > a:hover,
+    > a:focus {
+      text-decoration: none;
+      background-color: $pager-hover-bg;
+    }
+  }
+
+  .next {
+    > a,
+    > span {
+      float: right;
+    }
+  }
+
+  .previous {
+    > a,
+    > span {
+      float: left;
+    }
+  }
+
+  .disabled {
+    > a,
+    > a:hover,
+    > a:focus,
+    > span {
+      color: $pager-disabled-color;
+      background-color: $pager-bg;
+      cursor: $cursor-disabled;
+    }
+  }
+}
diff --git a/views/style/sass/bootstrap/bootstrap/_pagination.scss b/views/style/sass/bootstrap/bootstrap/_pagination.scss
new file mode 100644
index 0000000..fecfa9c
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/_pagination.scss
@@ -0,0 +1,89 @@
+//
+// Pagination (multiple pages)
+// --------------------------------------------------
+.pagination {
+  display: inline-block;
+  padding-left: 0;
+  margin: $line-height-computed 0;
+  border-radius: $border-radius-base;
+
+  > li {
+    display: inline; // Remove list-style and block-level defaults
+    > a,
+    > span {
+      position: relative;
+      float: left; // Collapse white-space
+      padding: $padding-base-vertical $padding-base-horizontal;
+      line-height: $line-height-base;
+      text-decoration: none;
+      color: $pagination-color;
+      background-color: $pagination-bg;
+      border: 1px solid $pagination-border;
+      margin-left: -1px;
+    }
+    &:first-child {
+      > a,
+      > span {
+        margin-left: 0;
+        @include border-left-radius($border-radius-base);
+      }
+    }
+    &:last-child {
+      > a,
+      > span {
+        @include border-right-radius($border-radius-base);
+      }
+    }
+  }
+
+  > li > a,
+  > li > span {
+    &:hover,
+    &:focus {
+      z-index: 2;
+      color: $pagination-hover-color;
+      background-color: $pagination-hover-bg;
+      border-color: $pagination-hover-border;
+    }
+  }
+
+  > .active > a,
+  > .active > span {
+    &,
+    &:hover,
+    &:focus {
+      z-index: 3;
+      color: $pagination-active-color;
+      background-color: $pagination-active-bg;
+      border-color: $pagination-active-border;
+      cursor: default;
+    }
+  }
+
+  > .disabled {
+    > span,
+    > span:hover,
+    > span:focus,
+    > a,
+    > a:hover,
+    > a:focus {
+      color: $pagination-disabled-color;
+      background-color: $pagination-disabled-bg;
+      border-color: $pagination-disabled-border;
+      cursor: $cursor-disabled;
+    }
+  }
+}
+
+// Sizing
+// --------------------------------------------------
+
+// Large
+.pagination-lg {
+  @include pagination-size($padding-large-vertical, $padding-large-horizontal, $font-size-large, $line-height-large, $border-radius-large);
+}
+
+// Small
+.pagination-sm {
+  @include pagination-size($padding-small-vertical, $padding-small-horizontal, $font-size-small, $line-height-small, $border-radius-small);
+}
diff --git a/views/style/sass/bootstrap/bootstrap/_panels.scss b/views/style/sass/bootstrap/bootstrap/_panels.scss
new file mode 100644
index 0000000..be9410f
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/_panels.scss
@@ -0,0 +1,271 @@
+//
+// Panels
+// --------------------------------------------------
+
+
+// Base class
+.panel {
+  margin-bottom: $line-height-computed;
+  background-color: $panel-bg;
+  border: 1px solid transparent;
+  border-radius: $panel-border-radius;
+  @include box-shadow(0 1px 1px rgba(0,0,0,.05));
+}
+
+// Panel contents
+.panel-body {
+  padding: $panel-body-padding;
+  @include clearfix;
+}
+
+// Optional heading
+.panel-heading {
+  padding: $panel-heading-padding;
+  border-bottom: 1px solid transparent;
+  @include border-top-radius(($panel-border-radius - 1));
+
+  > .dropdown .dropdown-toggle {
+    color: inherit;
+  }
+}
+
+// Within heading, strip any `h*` tag of its default margins for spacing.
+.panel-title {
+  margin-top: 0;
+  margin-bottom: 0;
+  font-size: ceil(($font-size-base * 1.125));
+  color: inherit;
+
+  > a,
+  > small,
+  > .small,
+  > small > a,
+  > .small > a {
+    color: inherit;
+  }
+}
+
+// Optional footer (stays gray in every modifier class)
+.panel-footer {
+  padding: $panel-footer-padding;
+  background-color: $panel-footer-bg;
+  border-top: 1px solid $panel-inner-border;
+  @include border-bottom-radius(($panel-border-radius - 1));
+}
+
+
+// List groups in panels
+//
+// By default, space out list group content from panel headings to account for
+// any kind of custom content between the two.
+
+.panel {
+  > .list-group,
+  > .panel-collapse > .list-group {
+    margin-bottom: 0;
+
+    .list-group-item {
+      border-width: 1px 0;
+      border-radius: 0;
+    }
+
+    // Add border top radius for first one
+    &:first-child {
+      .list-group-item:first-child {
+        border-top: 0;
+        @include border-top-radius(($panel-border-radius - 1));
+      }
+    }
+
+    // Add border bottom radius for last one
+    &:last-child {
+      .list-group-item:last-child {
+        border-bottom: 0;
+        @include border-bottom-radius(($panel-border-radius - 1));
+      }
+    }
+  }
+  > .panel-heading + .panel-collapse > .list-group {
+    .list-group-item:first-child {
+      @include border-top-radius(0);
+    }
+  }
+}
+// Collapse space between when there's no additional content.
+.panel-heading + .list-group {
+  .list-group-item:first-child {
+    border-top-width: 0;
+  }
+}
+.list-group + .panel-footer {
+  border-top-width: 0;
+}
+
+// Tables in panels
+//
+// Place a non-bordered `.table` within a panel (not within a `.panel-body`) and
+// watch it go full width.
+
+.panel {
+  > .table,
+  > .table-responsive > .table,
+  > .panel-collapse > .table {
+    margin-bottom: 0;
+
+    caption {
+      padding-left: $panel-body-padding;
+      padding-right: $panel-body-padding;
+    }
+  }
+  // Add border top radius for first one
+  > .table:first-child,
+  > .table-responsive:first-child > .table:first-child {
+    @include border-top-radius(($panel-border-radius - 1));
+
+    > thead:first-child,
+    > tbody:first-child {
+      > tr:first-child {
+        border-top-left-radius: ($panel-border-radius - 1);
+        border-top-right-radius: ($panel-border-radius - 1);
+
+        td:first-child,
+        th:first-child {
+          border-top-left-radius: ($panel-border-radius - 1);
+        }
+        td:last-child,
+        th:last-child {
+          border-top-right-radius: ($panel-border-radius - 1);
+        }
+      }
+    }
+  }
+  // Add border bottom radius for last one
+  > .table:last-child,
+  > .table-responsive:last-child > .table:last-child {
+    @include border-bottom-radius(($panel-border-radius - 1));
+
+    > tbody:last-child,
+    > tfoot:last-child {
+      > tr:last-child {
+        border-bottom-left-radius: ($panel-border-radius - 1);
+        border-bottom-right-radius: ($panel-border-radius - 1);
+
+        td:first-child,
+        th:first-child {
+          border-bottom-left-radius: ($panel-border-radius - 1);
+        }
+        td:last-child,
+        th:last-child {
+          border-bottom-right-radius: ($panel-border-radius - 1);
+        }
+      }
+    }
+  }
+  > .panel-body + .table,
+  > .panel-body + .table-responsive,
+  > .table + .panel-body,
+  > .table-responsive + .panel-body {
+    border-top: 1px solid $table-border-color;
+  }
+  > .table > tbody:first-child > tr:first-child th,
+  > .table > tbody:first-child > tr:first-child td {
+    border-top: 0;
+  }
+  > .table-bordered,
+  > .table-responsive > .table-bordered {
+    border: 0;
+    > thead,
+    > tbody,
+    > tfoot {
+      > tr {
+        > th:first-child,
+        > td:first-child {
+          border-left: 0;
+        }
+        > th:last-child,
+        > td:last-child {
+          border-right: 0;
+        }
+      }
+    }
+    > thead,
+    > tbody {
+      > tr:first-child {
+        > td,
+        > th {
+          border-bottom: 0;
+        }
+      }
+    }
+    > tbody,
+    > tfoot {
+      > tr:last-child {
+        > td,
+        > th {
+          border-bottom: 0;
+        }
+      }
+    }
+  }
+  > .table-responsive {
+    border: 0;
+    margin-bottom: 0;
+  }
+}
+
+
+// Collapsable panels (aka, accordion)
+//
+// Wrap a series of panels in `.panel-group` to turn them into an accordion with
+// the help of our collapse JavaScript plugin.
+
+.panel-group {
+  margin-bottom: $line-height-computed;
+
+  // Tighten up margin so it's only between panels
+  .panel {
+    margin-bottom: 0;
+    border-radius: $panel-border-radius;
+
+    + .panel {
+      margin-top: 5px;
+    }
+  }
+
+  .panel-heading {
+    border-bottom: 0;
+
+    + .panel-collapse > .panel-body,
+    + .panel-collapse > .list-group {
+      border-top: 1px solid $panel-inner-border;
+    }
+  }
+
+  .panel-footer {
+    border-top: 0;
+    + .panel-collapse .panel-body {
+      border-bottom: 1px solid $panel-inner-border;
+    }
+  }
+}
+
+
+// Contextual variations
+.panel-default {
+  @include panel-variant($panel-default-border, $panel-default-text, $panel-default-heading-bg, $panel-default-border);
+}
+.panel-primary {
+  @include panel-variant($panel-primary-border, $panel-primary-text, $panel-primary-heading-bg, $panel-primary-border);
+}
+.panel-success {
+  @include panel-variant($panel-success-border, $panel-success-text, $panel-success-heading-bg, $panel-success-border);
+}
+.panel-info {
+  @include panel-variant($panel-info-border, $panel-info-text, $panel-info-heading-bg, $panel-info-border);
+}
+.panel-warning {
+  @include panel-variant($panel-warning-border, $panel-warning-text, $panel-warning-heading-bg, $panel-warning-border);
+}
+.panel-danger {
+  @include panel-variant($panel-danger-border, $panel-danger-text, $panel-danger-heading-bg, $panel-danger-border);
+}
diff --git a/views/style/sass/bootstrap/bootstrap/_popovers.scss b/views/style/sass/bootstrap/bootstrap/_popovers.scss
new file mode 100644
index 0000000..9b90a2e
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/_popovers.scss
@@ -0,0 +1,131 @@
+//
+// Popovers
+// --------------------------------------------------
+
+
+.popover {
+  position: absolute;
+  top: 0;
+  left: 0;
+  z-index: $zindex-popover;
+  display: none;
+  max-width: $popover-max-width;
+  padding: 1px;
+  // Our parent element can be arbitrary since popovers are by default inserted as a sibling of their target element.
+  // So reset our font and text properties to avoid inheriting weird values.
+  @include reset-text;
+  font-size: $font-size-base;
+
+  background-color: $popover-bg;
+  background-clip: padding-box;
+  border: 1px solid $popover-fallback-border-color;
+  border: 1px solid $popover-border-color;
+  border-radius: $border-radius-large;
+  @include box-shadow(0 5px 10px rgba(0,0,0,.2));
+
+  // Offset the popover to account for the popover arrow
+  &.top     { margin-top: -$popover-arrow-width; }
+  &.right   { margin-left: $popover-arrow-width; }
+  &.bottom  { margin-top: $popover-arrow-width; }
+  &.left    { margin-left: -$popover-arrow-width; }
+}
+
+.popover-title {
+  margin: 0; // reset heading margin
+  padding: 8px 14px;
+  font-size: $font-size-base;
+  background-color: $popover-title-bg;
+  border-bottom: 1px solid darken($popover-title-bg, 5%);
+  border-radius: ($border-radius-large - 1) ($border-radius-large - 1) 0 0;
+}
+
+.popover-content {
+  padding: 9px 14px;
+}
+
+// Arrows
+//
+// .arrow is outer, .arrow:after is inner
+
+.popover > .arrow {
+  &,
+  &:after {
+    position: absolute;
+    display: block;
+    width: 0;
+    height: 0;
+    border-color: transparent;
+    border-style: solid;
+  }
+}
+.popover > .arrow {
+  border-width: $popover-arrow-outer-width;
+}
+.popover > .arrow:after {
+  border-width: $popover-arrow-width;
+  content: "";
+}
+
+.popover {
+  &.top > .arrow {
+    left: 50%;
+    margin-left: -$popover-arrow-outer-width;
+    border-bottom-width: 0;
+    border-top-color: $popover-arrow-outer-fallback-color; // IE8 fallback
+    border-top-color: $popover-arrow-outer-color;
+    bottom: -$popover-arrow-outer-width;
+    &:after {
+      content: " ";
+      bottom: 1px;
+      margin-left: -$popover-arrow-width;
+      border-bottom-width: 0;
+      border-top-color: $popover-arrow-color;
+    }
+  }
+  &.right > .arrow {
+    top: 50%;
+    left: -$popover-arrow-outer-width;
+    margin-top: -$popover-arrow-outer-width;
+    border-left-width: 0;
+    border-right-color: $popover-arrow-outer-fallback-color; // IE8 fallback
+    border-right-color: $popover-arrow-outer-color;
+    &:after {
+      content: " ";
+      left: 1px;
+      bottom: -$popover-arrow-width;
+      border-left-width: 0;
+      border-right-color: $popover-arrow-color;
+    }
+  }
+  &.bottom > .arrow {
+    left: 50%;
+    margin-left: -$popover-arrow-outer-width;
+    border-top-width: 0;
+    border-bottom-color: $popover-arrow-outer-fallback-color; // IE8 fallback
+    border-bottom-color: $popover-arrow-outer-color;
+    top: -$popover-arrow-outer-width;
+    &:after {
+      content: " ";
+      top: 1px;
+      margin-left: -$popover-arrow-width;
+      border-top-width: 0;
+      border-bottom-color: $popover-arrow-color;
+    }
+  }
+
+  &.left > .arrow {
+    top: 50%;
+    right: -$popover-arrow-outer-width;
+    margin-top: -$popover-arrow-outer-width;
+    border-right-width: 0;
+    border-left-color: $popover-arrow-outer-fallback-color; // IE8 fallback
+    border-left-color: $popover-arrow-outer-color;
+    &:after {
+      content: " ";
+      right: 1px;
+      border-right-width: 0;
+      border-left-color: $popover-arrow-color;
+      bottom: -$popover-arrow-width;
+    }
+  }
+}
diff --git a/views/style/sass/bootstrap/bootstrap/_print.scss b/views/style/sass/bootstrap/bootstrap/_print.scss
new file mode 100644
index 0000000..66e54ab
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/_print.scss
@@ -0,0 +1,101 @@
+/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */
+
+// ==========================================================================
+// Print styles.
+// Inlined to avoid the additional HTTP request: h5bp.com/r
+// ==========================================================================
+
+@media print {
+    *,
+    *:before,
+    *:after {
+        background: transparent !important;
+        color: #000 !important; // Black prints faster: h5bp.com/s
+        box-shadow: none !important;
+        text-shadow: none !important;
+    }
+
+    a,
+    a:visited {
+        text-decoration: underline;
+    }
+
+    a[href]:after {
+        content: " (" attr(href) ")";
+    }
+
+    abbr[title]:after {
+        content: " (" attr(title) ")";
+    }
+
+    // Don't show links that are fragment identifiers,
+    // or use the `javascript:` pseudo protocol
+    a[href^="#"]:after,
+    a[href^="javascript:"]:after {
+        content: "";
+    }
+
+    pre,
+    blockquote {
+        border: 1px solid #999;
+        page-break-inside: avoid;
+    }
+
+    thead {
+        display: table-header-group; // h5bp.com/t
+    }
+
+    tr,
+    img {
+        page-break-inside: avoid;
+    }
+
+    img {
+        max-width: 100% !important;
+    }
+
+    p,
+    h2,
+    h3 {
+        orphans: 3;
+        widows: 3;
+    }
+
+    h2,
+    h3 {
+        page-break-after: avoid;
+    }
+
+    // Bootstrap specific changes start
+
+    // Bootstrap components
+    .navbar {
+        display: none;
+    }
+    .btn,
+    .dropup > .btn {
+        > .caret {
+            border-top-color: #000 !important;
+        }
+    }
+    .label {
+        border: 1px solid #000;
+    }
+
+    .table {
+        border-collapse: collapse !important;
+
+        td,
+        th {
+            background-color: #fff !important;
+        }
+    }
+    .table-bordered {
+        th,
+        td {
+            border: 1px solid #ddd !important;
+        }
+    }
+
+    // Bootstrap specific changes end
+}
diff --git a/views/style/sass/bootstrap/bootstrap/_progress-bars.scss b/views/style/sass/bootstrap/bootstrap/_progress-bars.scss
new file mode 100644
index 0000000..343df63
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/_progress-bars.scss
@@ -0,0 +1,87 @@
+//
+// Progress bars
+// --------------------------------------------------
+
+
+// Bar animations
+// -------------------------
+
+// WebKit
+@-webkit-keyframes progress-bar-stripes {
+  from  { background-position: 40px 0; }
+  to    { background-position: 0 0; }
+}
+
+// Spec and IE10+
+@keyframes progress-bar-stripes {
+  from  { background-position: 40px 0; }
+  to    { background-position: 0 0; }
+}
+
+
+// Bar itself
+// -------------------------
+
+// Outer container
+.progress {
+  overflow: hidden;
+  height: $line-height-computed;
+  margin-bottom: $line-height-computed;
+  background-color: $progress-bg;
+  border-radius: $progress-border-radius;
+  @include box-shadow(inset 0 1px 2px rgba(0,0,0,.1));
+}
+
+// Bar of progress
+.progress-bar {
+  float: left;
+  width: 0%;
+  height: 100%;
+  font-size: $font-size-small;
+  line-height: $line-height-computed;
+  color: $progress-bar-color;
+  text-align: center;
+  background-color: $progress-bar-bg;
+  @include box-shadow(inset 0 -1px 0 rgba(0,0,0,.15));
+  @include transition(width .6s ease);
+}
+
+// Striped bars
+//
+// `.progress-striped .progress-bar` is deprecated as of v3.2.0 in favor of the
+// `.progress-bar-striped` class, which you just add to an existing
+// `.progress-bar`.
+.progress-striped .progress-bar,
+.progress-bar-striped {
+  @include gradient-striped;
+  background-size: 40px 40px;
+}
+
+// Call animation for the active one
+//
+// `.progress.active .progress-bar` is deprecated as of v3.2.0 in favor of the
+// `.progress-bar.active` approach.
+.progress.active .progress-bar,
+.progress-bar.active {
+  @include animation(progress-bar-stripes 2s linear infinite);
+}
+
+
+// Variations
+// -------------------------
+
+.progress-bar-success {
+  @include progress-bar-variant($progress-bar-success-bg);
+}
+
+.progress-bar-info {
+  @include progress-bar-variant($progress-bar-info-bg);
+}
+
+.progress-bar-warning {
+  @include progress-bar-variant($progress-bar-warning-bg);
+}
+
+.progress-bar-danger {
+  @include progress-bar-variant($progress-bar-danger-bg);
+}
diff --git a/views/style/sass/bootstrap/bootstrap/_responsive-embed.scss b/views/style/sass/bootstrap/bootstrap/_responsive-embed.scss
new file mode 100644
index 0000000..080a511
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/_responsive-embed.scss
@@ -0,0 +1,35 @@
+// Embeds responsive
+//
+// Credit: Nicolas Gallagher and SUIT CSS.
+
+.embed-responsive {
+  position: relative;
+  display: block;
+  height: 0;
+  padding: 0;
+  overflow: hidden;
+
+  .embed-responsive-item,
+  iframe,
+  embed,
+  object,
+  video {
+    position: absolute;
+    top: 0;
+    left: 0;
+    bottom: 0;
+    height: 100%;
+    width: 100%;
+    border: 0;
+  }
+}
+
+// Modifier class for 16:9 aspect ratio
+.embed-responsive-16by9 {
+  padding-bottom: 56.25%;
+}
+
+// Modifier class for 4:3 aspect ratio
+.embed-responsive-4by3 {
+  padding-bottom: 75%;
+}
diff --git a/views/style/sass/bootstrap/bootstrap/_responsive-utilities.scss b/views/style/sass/bootstrap/bootstrap/_responsive-utilities.scss
new file mode 100644
index 0000000..f3f0c83
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/_responsive-utilities.scss
@@ -0,0 +1,179 @@
+//
+// Responsive: Utility classes
+// --------------------------------------------------
+
+
+// IE10 in Windows (Phone) 8
+//
+// Support for responsive views via media queries is kind of borked in IE10, for
+// Surface/desktop in split view and for Windows Phone 8. This particular fix
+// must be accompanied by a snippet of JavaScript to sniff the user agent and
+// apply some conditional CSS to *only* the Surface/desktop Windows 8. Look at
+// our Getting Started page for more information on this bug.
+//
+// For more information, see the following:
+//
+// Issue: https://github.com/twbs/bootstrap/issues/10497
+// Docs: http://getbootstrap.com/getting-started/#support-ie10-width
+// Source: http://timkadlec.com/2013/01/windows-phone-8-and-device-width/
+// Source: http://timkadlec.com/2012/10/ie10-snap-mode-and-responsive-design/
+
+@at-root {
+  @-ms-viewport {
+    width: device-width;
+  }
+}
+
+
+// Visibility utilities
+// Note: Deprecated .visible-xs, .visible-sm, .visible-md, and .visible-lg as of v3.2.0
+
+@include responsive-invisibility('.visible-xs');
+@include responsive-invisibility('.visible-sm');
+@include responsive-invisibility('.visible-md');
+@include responsive-invisibility('.visible-lg');
+
+.visible-xs-block,
+.visible-xs-inline,
+.visible-xs-inline-block,
+.visible-sm-block,
+.visible-sm-inline,
+.visible-sm-inline-block,
+.visible-md-block,
+.visible-md-inline,
+.visible-md-inline-block,
+.visible-lg-block,
+.visible-lg-inline,
+.visible-lg-inline-block {
+  display: none !important;
+}
+
+@media (max-width: $screen-xs-max) {
+  @include responsive-visibility('.visible-xs');
+}
+.visible-xs-block {
+  @media (max-width: $screen-xs-max) {
+    display: block !important;
+  }
+}
+.visible-xs-inline {
+  @media (max-width: $screen-xs-max) {
+    display: inline !important;
+  }
+}
+.visible-xs-inline-block {
+  @media (max-width: $screen-xs-max) {
+    display: inline-block !important;
+  }
+}
+
+@media (min-width: $screen-sm-min) and (max-width: $screen-sm-max) {
+  @include responsive-visibility('.visible-sm');
+}
+.visible-sm-block {
+  @media (min-width: $screen-sm-min) and (max-width: $screen-sm-max) {
+    display: block !important;
+  }
+}
+.visible-sm-inline {
+  @media (min-width: $screen-sm-min) and (max-width: $screen-sm-max) {
+    display: inline !important;
+  }
+}
+.visible-sm-inline-block {
+  @media (min-width: $screen-sm-min) and (max-width: $screen-sm-max) {
+    display: inline-block !important;
+  }
+}
+
+@media (min-width: $screen-md-min) and (max-width: $screen-md-max) {
+  @include responsive-visibility('.visible-md');
+}
+.visible-md-block {
+  @media (min-width: $screen-md-min) and (max-width: $screen-md-max) {
+    display: block !important;
+  }
+}
+.visible-md-inline {
+  @media (min-width: $screen-md-min) and (max-width: $screen-md-max) {
+    display: inline !important;
+  }
+}
+.visible-md-inline-block {
+  @media (min-width: $screen-md-min) and (max-width: $screen-md-max) {
+    display: inline-block !important;
+  }
+}
+
+@media (min-width: $screen-lg-min) {
+  @include responsive-visibility('.visible-lg');
+}
+.visible-lg-block {
+  @media (min-width: $screen-lg-min) {
+    display: block !important;
+  }
+}
+.visible-lg-inline {
+  @media (min-width: $screen-lg-min) {
+    display: inline !important;
+  }
+}
+.visible-lg-inline-block {
+  @media (min-width: $screen-lg-min) {
+    display: inline-block !important;
+  }
+}
+
+@media (max-width: $screen-xs-max) {
+  @include responsive-invisibility('.hidden-xs');
+}
+
+@media (min-width: $screen-sm-min) and (max-width: $screen-sm-max) {
+  @include responsive-invisibility('.hidden-sm');
+}
+
+@media (min-width: $screen-md-min) and (max-width: $screen-md-max) {
+  @include responsive-invisibility('.hidden-md');
+}
+
+@media (min-width: $screen-lg-min) {
+  @include responsive-invisibility('.hidden-lg');
+}
+
+
+// Print utilities
+//
+// Media queries are placed on the inside to be mixin-friendly.
+
+// Note: Deprecated .visible-print as of v3.2.0
+
+@include responsive-invisibility('.visible-print');
+
+@media print {
+  @include responsive-visibility('.visible-print');
+}
+.visible-print-block {
+  display: none !important;
+
+  @media print {
+    display: block !important;
+  }
+}
+.visible-print-inline {
+  display: none !important;
+
+  @media print {
+    display: inline !important;
+  }
+}
+.visible-print-inline-block {
+  display: none !important;
+
+  @media print {
+    display: inline-block !important;
+  }
+}
+
+@media print {
+  @include responsive-invisibility('.hidden-print');
+}
diff --git a/views/style/sass/bootstrap/bootstrap/_scaffolding.scss b/views/style/sass/bootstrap/bootstrap/_scaffolding.scss
new file mode 100644
index 0000000..83adb5d
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/_scaffolding.scss
@@ -0,0 +1,161 @@
+//
+// Scaffolding
+// --------------------------------------------------
+
+
+// Reset the box-sizing
+//
+// Heads up! This reset may cause conflicts with some third-party widgets.
+// For recommendations on resolving such conflicts, see
+// http://getbootstrap.com/getting-started/#third-box-sizing
+* {
+  @include box-sizing(border-box);
+}
+*:before,
+*:after {
+  @include box-sizing(border-box);
+}
+
+
+// Body reset
+
+html {
+  font-size: 10px;
+  -webkit-tap-highlight-color: rgba(0,0,0,0);
+}
+
+body {
+  font-family: $font-family-base;
+  font-size: $font-size-base;
+  line-height: $line-height-base;
+  color: $text-color;
+  background-color: $body-bg;
+}
+
+// Reset fonts for relevant elements
+input,
+button,
+select,
+textarea {
+  font-family: inherit;
+  font-size: inherit;
+  line-height: inherit;
+}
+
+
+// Links
+
+a {
+  color: $link-color;
+  text-decoration: none;
+
+  &:hover,
+  &:focus {
+    color: $link-hover-color;
+    text-decoration: $link-hover-decoration;
+  }
+
+  &:focus {
+    @include tab-focus;
+  }
+}
+
+
+// Figures
+//
+// We reset this here because previously Normalize had no `figure` margins. This
+// ensures we don't break anyone's use of the element.
+
+figure {
+  margin: 0;
+}
+
+
+// Images
+
+img {
+  vertical-align: middle;
+}
+
+// Responsive images (ensure images don't scale beyond their parents)
+.img-responsive {
+  @include img-responsive;
+}
+
+// Rounded corners
+.img-rounded {
+  border-radius: $border-radius-large;
+}
+
+// Image thumbnails
+//
+// Heads up! This is mixin-ed into thumbnails.less for `.thumbnail`.
+.img-thumbnail {
+  padding: $thumbnail-padding;
+  line-height: $line-height-base;
+  background-color: $thumbnail-bg;
+  border: 1px solid $thumbnail-border;
+  border-radius: $thumbnail-border-radius;
+  @include transition(all .2s ease-in-out);
+
+  // Keep them at most 100% wide
+  @include img-responsive(inline-block);
+}
+
+// Perfect circle
+.img-circle {
+  border-radius: 50%; // set radius in percents
+}
+
+
+// Horizontal rules
+
+hr {
+  margin-top:    $line-height-computed;
+  margin-bottom: $line-height-computed;
+  border: 0;
+  border-top: 1px solid $hr-border;
+}
+
+
+// Only display content to screen readers
+//
+// See: http://a11yproject.com/posts/how-to-hide-content/
+
+.sr-only {
+  position: absolute;
+  width: 1px;
+  height: 1px;
+  margin: -1px;
+  padding: 0;
+  overflow: hidden;
+  clip: rect(0,0,0,0);
+  border: 0;
+}
+
+// Use in conjunction with .sr-only to only display content when it's focused.
+// Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1
+// Credit: HTML5 Boilerplate
+
+.sr-only-focusable {
+  &:active,
+  &:focus {
+    position: static;
+    width: auto;
+    height: auto;
+    margin: 0;
+    overflow: visible;
+    clip: auto;
+  }
+}
+
+
+// iOS "clickable elements" fix for role="button"
+//
+// Fixes "clickability" issue (and more generally, the firing of events such as focus as well)
+// for traditionally non-focusable elements with role="button"
+// see https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile
+
+[role="button"] {
+  cursor: pointer;
+}
diff --git a/views/style/sass/bootstrap/bootstrap/_tables.scss b/views/style/sass/bootstrap/bootstrap/_tables.scss
new file mode 100644
index 0000000..affcc58
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/_tables.scss
@@ -0,0 +1,234 @@
+//
+// Tables
+// --------------------------------------------------
+
+
+table {
+  background-color: $table-bg;
+}
+caption {
+  padding-top: $table-cell-padding;
+  padding-bottom: $table-cell-padding;
+  color: $text-muted;
+  text-align: left;
+}
+th {
+  text-align: left;
+}
+
+
+// Baseline styles
+
+.table {
+  width: 100%;
+  max-width: 100%;
+  margin-bottom: $line-height-computed;
+  // Cells
+  > thead,
+  > tbody,
+  > tfoot {
+    > tr {
+      > th,
+      > td {
+        padding: $table-cell-padding;
+        line-height: $line-height-base;
+        vertical-align: top;
+        border-top: 1px solid $table-border-color;
+      }
+    }
+  }
+  // Bottom align for column headings
+  > thead > tr > th {
+    vertical-align: bottom;
+    border-bottom: 2px solid $table-border-color;
+  }
+  // Remove top border from thead by default
+  > caption + thead,
+  > colgroup + thead,
+  > thead:first-child {
+    > tr:first-child {
+      > th,
+      > td {
+        border-top: 0;
+      }
+    }
+  }
+  // Account for multiple tbody instances
+  > tbody + tbody {
+    border-top: 2px solid $table-border-color;
+  }
+
+  // Nesting
+  .table {
+    background-color: $body-bg;
+  }
+}
+
+
+// Condensed table w/ half padding
+
+.table-condensed {
+  > thead,
+  > tbody,
+  > tfoot {
+    > tr {
+      > th,
+      > td {
+        padding: $table-condensed-cell-padding;
+      }
+    }
+  }
+}
+
+
+// Bordered version
+//
+// Add borders all around the table and between all the columns.
+
+.table-bordered {
+  border: 1px solid $table-border-color;
+  > thead,
+  > tbody,
+  > tfoot {
+    > tr {
+      > th,
+      > td {
+        border: 1px solid $table-border-color;
+      }
+    }
+  }
+  > thead > tr {
+    > th,
+    > td {
+      border-bottom-width: 2px;
+    }
+  }
+}
+
+
+// Zebra-striping
+//
+// Default zebra-stripe styles (alternating gray and transparent backgrounds)
+
+.table-striped {
+  > tbody > tr:nth-of-type(odd) {
+    background-color: $table-bg-accent;
+  }
+}
+
+
+// Hover effect
+//
+// Placed here since it has to come after the potential zebra striping
+
+.table-hover {
+  > tbody > tr:hover {
+    background-color: $table-bg-hover;
+  }
+}
+
+
+// Table cell sizing
+//
+// Reset default table behavior
+
+table col[class*="col-"] {
+  position: static; // Prevent border hiding in Firefox and IE9-11 (see https://github.com/twbs/bootstrap/issues/11623)
+  float: none;
+  display: table-column;
+}
+table {
+  td,
+  th {
+    &[class*="col-"] {
+      position: static; // Prevent border hiding in Firefox and IE9-11 (see https://github.com/twbs/bootstrap/issues/11623)
+      float: none;
+      display: table-cell;
+    }
+  }
+}
+
+
+// Table backgrounds
+//
+// Exact selectors below required to override `.table-striped` and prevent
+// inheritance to nested tables.
+
+// Generate the contextual variants
+@include table-row-variant('active', $table-bg-active);
+@include table-row-variant('success', $state-success-bg);
+@include table-row-variant('info', $state-info-bg);
+@include table-row-variant('warning', $state-warning-bg);
+@include table-row-variant('danger', $state-danger-bg);
+
+
+// Responsive tables
+//
+// Wrap your tables in `.table-responsive` and we'll make them mobile friendly
+// by enabling horizontal scrolling. Only applies <768px. Everything above that
+// will display normally.
+
+.table-responsive {
+  overflow-x: auto;
+  min-height: 0.01%; // Workaround for IE9 bug (see https://github.com/twbs/bootstrap/issues/14837)
+
+  @media screen and (max-width: $screen-xs-max) {
+    width: 100%;
+    margin-bottom: ($line-height-computed * 0.75);
+    overflow-y: hidden;
+    -ms-overflow-style: -ms-autohiding-scrollbar;
+    border: 1px solid $table-border-color;
+
+    // Tighten up spacing
+    > .table {
+      margin-bottom: 0;
+
+      // Ensure the content doesn't wrap
+      > thead,
+      > tbody,
+      > tfoot {
+        > tr {
+          > th,
+          > td {
+            white-space: nowrap;
+          }
+        }
+      }
+    }
+
+    // Special overrides for the bordered tables
+    > .table-bordered {
+      border: 0;
+
+      // Nuke the appropriate borders so that the parent can handle them
+      > thead,
+      > tbody,
+      > tfoot {
+        > tr {
+          > th:first-child,
+          > td:first-child {
+            border-left: 0;
+          }
+          > th:last-child,
+          > td:last-child {
+            border-right: 0;
+          }
+        }
+      }
+
+      // Only nuke the last row's bottom-border in `tbody` and `tfoot` since
+      // chances are there will be only one `tr` in a `thead` and that would
+      // remove the border altogether.
+      > tbody,
+      > tfoot {
+        > tr:last-child {
+          > th,
+          > td {
+            border-bottom: 0;
+          }
+        }
+      }
+
+    }
+  }
+}
diff --git a/views/style/sass/bootstrap/bootstrap/_theme.scss b/views/style/sass/bootstrap/bootstrap/_theme.scss
new file mode 100644
index 0000000..c64b3d6
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/_theme.scss
@@ -0,0 +1,291 @@
+/*!
+ * Bootstrap v3.3.6 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+
+//
+// Load core variables and mixins
+// --------------------------------------------------
+
+@import "variables";
+@import "mixins";
+
+
+//
+// Buttons
+// --------------------------------------------------
+
+// Common styles
+.btn-default,
+.btn-primary,
+.btn-success,
+.btn-info,
+.btn-warning,
+.btn-danger {
+  text-shadow: 0 -1px 0 rgba(0,0,0,.2);
+  $shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 1px rgba(0,0,0,.075);
+  @include box-shadow($shadow);
+
+  // Reset the shadow
+  &:active,
+  &.active {
+    @include box-shadow(inset 0 3px 5px rgba(0,0,0,.125));
+  }
+
+  &.disabled,
+  &[disabled],
+  fieldset[disabled] & {
+    @include box-shadow(none);
+  }
+
+  .badge {
+    text-shadow: none;
+  }
+}
+
+// Mixin for generating new styles
+@mixin btn-styles($btn-color: #555) {
+  @include gradient-vertical($start-color: $btn-color, $end-color: darken($btn-color, 12%));
+  @include reset-filter; // Disable gradients for IE9 because filter bleeds through rounded corners; see https://github.com/twbs/bootstrap/issues/10620
+  background-repeat: repeat-x;
+  border-color: darken($btn-color, 14%);
+
+  &:hover,
+  &:focus  {
+    background-color: darken($btn-color, 12%);
+    background-position: 0 -15px;
+  }
+
+  &:active,
+  &.active {
+    background-color: darken($btn-color, 12%);
+    border-color: darken($btn-color, 14%);
+  }
+
+  &.disabled,
+  &[disabled],
+  fieldset[disabled] & {
+    &,
+    &:hover,
+    &:focus,
+    &.focus,
+    &:active,
+    &.active {
+      background-color: darken($btn-color, 12%);
+      background-image: none;
+    }
+  }
+}
+
+// Common styles
+.btn {
+  // Remove the gradient for the pressed/active state
+  &:active,
+  &.active {
+    background-image: none;
+  }
+}
+
+// Apply the mixin to the buttons
+.btn-default { @include btn-styles($btn-default-bg); text-shadow: 0 1px 0 #fff; border-color: #ccc; }
+.btn-primary { @include btn-styles($btn-primary-bg); }
+.btn-success { @include btn-styles($btn-success-bg); }
+.btn-info    { @include btn-styles($btn-info-bg); }
+.btn-warning { @include btn-styles($btn-warning-bg); }
+.btn-danger  { @include btn-styles($btn-danger-bg); }
+
+
+//
+// Images
+// --------------------------------------------------
+
+.thumbnail,
+.img-thumbnail {
+  @include box-shadow(0 1px 2px rgba(0,0,0,.075));
+}
+
+
+//
+// Dropdowns
+// --------------------------------------------------
+
+.dropdown-menu > li > a:hover,
+.dropdown-menu > li > a:focus {
+  @include gradient-vertical($start-color: $dropdown-link-hover-bg, $end-color: darken($dropdown-link-hover-bg, 5%));
+  background-color: darken($dropdown-link-hover-bg, 5%);
+}
+.dropdown-menu > .active > a,
+.dropdown-menu > .active > a:hover,
+.dropdown-menu > .active > a:focus {
+  @include gradient-vertical($start-color: $dropdown-link-active-bg, $end-color: darken($dropdown-link-active-bg, 5%));
+  background-color: darken($dropdown-link-active-bg, 5%);
+}
+
+
+//
+// Navbar
+// --------------------------------------------------
+
+// Default navbar
+.navbar-default {
+  @include gradient-vertical($start-color: lighten($navbar-default-bg, 10%), $end-color: $navbar-default-bg);
+  @include reset-filter; // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered
+  border-radius: $navbar-border-radius;
+  $shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 5px rgba(0,0,0,.075);
+  @include box-shadow($shadow);
+
+  .navbar-nav > .open > a,
+  .navbar-nav > .active > a {
+    @include gradient-vertical($start-color: darken($navbar-default-link-active-bg, 5%), $end-color: darken($navbar-default-link-active-bg, 2%));
+    @include box-shadow(inset 0 3px 9px rgba(0,0,0,.075));
+  }
+}
+.navbar-brand,
+.navbar-nav > li > a {
+  text-shadow: 0 1px 0 rgba(255,255,255,.25);
+}
+
+// Inverted navbar
+.navbar-inverse {
+  @include gradient-vertical($start-color: lighten($navbar-inverse-bg, 10%), $end-color: $navbar-inverse-bg);
+  @include reset-filter; // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered; see https://github.com/twbs/bootstrap/issues/10257
+  border-radius: $navbar-border-radius;
+  .navbar-nav > .open > a,
+  .navbar-nav > .active > a {
+    @include gradient-vertical($start-color: $navbar-inverse-link-active-bg, $end-color: lighten($navbar-inverse-link-active-bg, 2.5%));
+    @include box-shadow(inset 0 3px 9px rgba(0,0,0,.25));
+  }
+
+  .navbar-brand,
+  .navbar-nav > li > a {
+    text-shadow: 0 -1px 0 rgba(0,0,0,.25);
+  }
+}
+
+// Undo rounded corners in static and fixed navbars
+.navbar-static-top,
+.navbar-fixed-top,
+.navbar-fixed-bottom {
+  border-radius: 0;
+}
+
+// Fix active state of dropdown items in collapsed mode
+@media (max-width: $grid-float-breakpoint-max) {
+  .navbar .navbar-nav .open .dropdown-menu > .active > a {
+    &,
+    &:hover,
+    &:focus {
+      color: #fff;
+      @include gradient-vertical($start-color: $dropdown-link-active-bg, $end-color: darken($dropdown-link-active-bg, 5%));
+    }
+  }
+}
+
+
+//
+// Alerts
+// --------------------------------------------------
+
+// Common styles
+.alert {
+  text-shadow: 0 1px 0 rgba(255,255,255,.2);
+  $shadow: inset 0 1px 0 rgba(255,255,255,.25), 0 1px 2px rgba(0,0,0,.05);
+  @include box-shadow($shadow);
+}
+
+// Mixin for generating new styles
+@mixin alert-styles($color) {
+  @include gradient-vertical($start-color: $color, $end-color: darken($color, 7.5%));
+  border-color: darken($color, 15%);
+}
+
+// Apply the mixin to the alerts
+.alert-success    { @include alert-styles($alert-success-bg); }
+.alert-info       { @include alert-styles($alert-info-bg); }
+.alert-warning    { @include alert-styles($alert-warning-bg); }
+.alert-danger     { @include alert-styles($alert-danger-bg); }
+
+
+//
+// Progress bars
+// --------------------------------------------------
+
+// Give the progress background some depth
+.progress {
+  @include gradient-vertical($start-color: darken($progress-bg, 4%), $end-color: $progress-bg)
+}
+
+// Mixin for generating new styles
+@mixin progress-bar-styles($color) {
+  @include gradient-vertical($start-color: $color, $end-color: darken($color, 10%));
+}
+
+// Apply the mixin to the progress bars
+.progress-bar            { @include progress-bar-styles($progress-bar-bg); }
+.progress-bar-success    { @include progress-bar-styles($progress-bar-success-bg); }
+.progress-bar-info       { @include progress-bar-styles($progress-bar-info-bg); }
+.progress-bar-warning    { @include progress-bar-styles($progress-bar-warning-bg); }
+.progress-bar-danger     { @include progress-bar-styles($progress-bar-danger-bg); }
+
+// Reset the striped class because our mixins don't do multiple gradients and
+// the above custom styles override the new `.progress-bar-striped` in v3.2.0.
+.progress-bar-striped {
+  @include gradient-striped;
+}
+
+
+//
+// List groups
+// --------------------------------------------------
+
+.list-group {
+  border-radius: $border-radius-base;
+  @include box-shadow(0 1px 2px rgba(0,0,0,.075));
+}
+.list-group-item.active,
+.list-group-item.active:hover,
+.list-group-item.active:focus {
+  text-shadow: 0 -1px 0 darken($list-group-active-bg, 10%);
+  @include gradient-vertical($start-color: $list-group-active-bg, $end-color: darken($list-group-active-bg, 7.5%));
+  border-color: darken($list-group-active-border, 7.5%);
+
+  .badge {
+    text-shadow: none;
+  }
+}
+
+
+//
+// Panels
+// --------------------------------------------------
+
+// Common styles
+.panel {
+  @include box-shadow(0 1px 2px rgba(0,0,0,.05));
+}
+
+// Mixin for generating new styles
+@mixin panel-heading-styles($color) {
+  @include gradient-vertical($start-color: $color, $end-color: darken($color, 5%));
+}
+
+// Apply the mixin to the panel headings only
+.panel-default > .panel-heading   { @include panel-heading-styles($panel-default-heading-bg); }
+.panel-primary > .panel-heading   { @include panel-heading-styles($panel-primary-heading-bg); }
+.panel-success > .panel-heading   { @include panel-heading-styles($panel-success-heading-bg); }
+.panel-info > .panel-heading      { @include panel-heading-styles($panel-info-heading-bg); }
+.panel-warning > .panel-heading   { @include panel-heading-styles($panel-warning-heading-bg); }
+.panel-danger > .panel-heading    { @include panel-heading-styles($panel-danger-heading-bg); }
+
+
+//
+// Wells
+// --------------------------------------------------
+
+.well {
+  @include gradient-vertical($start-color: darken($well-bg, 5%), $end-color: $well-bg);
+  border-color: darken($well-bg, 10%);
+  $shadow: inset 0 1px 3px rgba(0,0,0,.05), 0 1px 0 rgba(255,255,255,.1);
+  @include box-shadow($shadow);
+}
diff --git a/views/style/sass/bootstrap/bootstrap/_thumbnails.scss b/views/style/sass/bootstrap/bootstrap/_thumbnails.scss
new file mode 100644
index 0000000..da0e1e7
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/_thumbnails.scss
@@ -0,0 +1,38 @@
+//
+// Thumbnails
+// --------------------------------------------------
+
+
+// Mixin and adjust the regular image class
+.thumbnail {
+  display: block;
+  padding: $thumbnail-padding;
+  margin-bottom: $line-height-computed;
+  line-height: $line-height-base;
+  background-color: $thumbnail-bg;
+  border: 1px solid $thumbnail-border;
+  border-radius: $thumbnail-border-radius;
+  @include transition(border .2s ease-in-out);
+
+  > img,
+  a > img {
+    @include img-responsive;
+    margin-left: auto;
+    margin-right: auto;
+  }
+
+  // [converter] extracted a&:hover, a&:focus, a&.active to a.thumbnail:hover, a.thumbnail:focus, a.thumbnail.active
+
+  // Image captions
+  .caption {
+    padding: $thumbnail-caption-padding;
+    color: $thumbnail-caption-color;
+  }
+}
+
+// Add a hover state for linked versions only
+a.thumbnail:hover,
+a.thumbnail:focus,
+a.thumbnail.active {
+  border-color: $link-color;
+}
diff --git a/views/style/sass/bootstrap/bootstrap/_tooltip.scss b/views/style/sass/bootstrap/bootstrap/_tooltip.scss
new file mode 100644
index 0000000..f0c1658
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/_tooltip.scss
@@ -0,0 +1,101 @@
+//
+// Tooltips
+// --------------------------------------------------
+
+
+// Base class
+.tooltip {
+  position: absolute;
+  z-index: $zindex-tooltip;
+  display: block;
+  // Our parent element can be arbitrary since tooltips are by default inserted as a sibling of their target element.
+  // So reset our font and text properties to avoid inheriting weird values.
+  @include reset-text;
+  font-size: $font-size-small;
+
+  @include opacity(0);
+
+  &.in     { @include opacity($tooltip-opacity); }
+  &.top    { margin-top:  -3px; padding: $tooltip-arrow-width 0; }
+  &.right  { margin-left:  3px; padding: 0 $tooltip-arrow-width; }
+  &.bottom { margin-top:   3px; padding: $tooltip-arrow-width 0; }
+  &.left   { margin-left: -3px; padding: 0 $tooltip-arrow-width; }
+}
+
+// Wrapper for the tooltip content
+.tooltip-inner {
+  max-width: $tooltip-max-width;
+  padding: 3px 8px;
+  color: $tooltip-color;
+  text-align: center;
+  background-color: $tooltip-bg;
+  border-radius: $border-radius-base;
+}
+
+// Arrows
+.tooltip-arrow {
+  position: absolute;
+  width: 0;
+  height: 0;
+  border-color: transparent;
+  border-style: solid;
+}
+// Note: Deprecated .top-left, .top-right, .bottom-left, and .bottom-right as of v3.3.1
+.tooltip {
+  &.top .tooltip-arrow {
+    bottom: 0;
+    left: 50%;
+    margin-left: -$tooltip-arrow-width;
+    border-width: $tooltip-arrow-width $tooltip-arrow-width 0;
+    border-top-color: $tooltip-arrow-color;
+  }
+  &.top-left .tooltip-arrow {
+    bottom: 0;
+    right: $tooltip-arrow-width;
+    margin-bottom: -$tooltip-arrow-width;
+    border-width: $tooltip-arrow-width $tooltip-arrow-width 0;
+    border-top-color: $tooltip-arrow-color;
+  }
+  &.top-right .tooltip-arrow {
+    bottom: 0;
+    left: $tooltip-arrow-width;
+    margin-bottom: -$tooltip-arrow-width;
+    border-width: $tooltip-arrow-width $tooltip-arrow-width 0;
+    border-top-color: $tooltip-arrow-color;
+  }
+  &.right .tooltip-arrow {
+    top: 50%;
+    left: 0;
+    margin-top: -$tooltip-arrow-width;
+    border-width: $tooltip-arrow-width $tooltip-arrow-width $tooltip-arrow-width 0;
+    border-right-color: $tooltip-arrow-color;
+  }
+  &.left .tooltip-arrow {
+    top: 50%;
+    right: 0;
+    margin-top: -$tooltip-arrow-width;
+    border-width: $tooltip-arrow-width 0 $tooltip-arrow-width $tooltip-arrow-width;
+    border-left-color: $tooltip-arrow-color;
+  }
+  &.bottom .tooltip-arrow {
+    top: 0;
+    left: 50%;
+    margin-left: -$tooltip-arrow-width;
+    border-width: 0 $tooltip-arrow-width $tooltip-arrow-width;
+    border-bottom-color: $tooltip-arrow-color;
+  }
+  &.bottom-left .tooltip-arrow {
+    top: 0;
+    right: $tooltip-arrow-width;
+    margin-top: -$tooltip-arrow-width;
+    border-width: 0 $tooltip-arrow-width $tooltip-arrow-width;
+    border-bottom-color: $tooltip-arrow-color;
+  }
+  &.bottom-right .tooltip-arrow {
+    top: 0;
+    left: $tooltip-arrow-width;
+    margin-top: -$tooltip-arrow-width;
+    border-width: 0 $tooltip-arrow-width $tooltip-arrow-width;
+    border-bottom-color: $tooltip-arrow-color;
+  }
+}
diff --git a/views/style/sass/bootstrap/bootstrap/_type.scss b/views/style/sass/bootstrap/bootstrap/_type.scss
new file mode 100644
index 0000000..620796a
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/_type.scss
@@ -0,0 +1,298 @@
+//
+// Typography
+// --------------------------------------------------
+
+
+// Headings
+// -------------------------
+
+h1, h2, h3, h4, h5, h6,
+.h1, .h2, .h3, .h4, .h5, .h6 {
+  font-family: $headings-font-family;
+  font-weight: $headings-font-weight;
+  line-height: $headings-line-height;
+  color: $headings-color;
+
+  small,
+  .small {
+    font-weight: normal;
+    line-height: 1;
+    color: $headings-small-color;
+  }
+}
+
+h1, .h1,
+h2, .h2,
+h3, .h3 {
+  margin-top: $line-height-computed;
+  margin-bottom: ($line-height-computed / 2);
+
+  small,
+  .small {
+    font-size: 65%;
+  }
+}
+h4, .h4,
+h5, .h5,
+h6, .h6 {
+  margin-top: ($line-height-computed / 2);
+  margin-bottom: ($line-height-computed / 2);
+
+  small,
+  .small {
+    font-size: 75%;
+  }
+}
+
+h1, .h1 { font-size: $font-size-h1; }
+h2, .h2 { font-size: $font-size-h2; }
+h3, .h3 { font-size: $font-size-h3; }
+h4, .h4 { font-size: $font-size-h4; }
+h5, .h5 { font-size: $font-size-h5; }
+h6, .h6 { font-size: $font-size-h6; }
+
+
+// Body text
+// -------------------------
+
+p {
+  margin: 0 0 ($line-height-computed / 2);
+}
+
+.lead {
+  margin-bottom: $line-height-computed;
+  font-size: floor(($font-size-base * 1.15));
+  font-weight: 300;
+  line-height: 1.4;
+
+  @media (min-width: $screen-sm-min) {
+    font-size: ($font-size-base * 1.5);
+  }
+}
+
+
+// Emphasis & misc
+// -------------------------
+
+// Ex: (12px small font / 14px base font) * 100% = about 85%
+small,
+.small {
+  font-size: floor((100% * $font-size-small / $font-size-base));
+}
+
+mark,
+.mark {
+  background-color: $state-warning-bg;
+  padding: .2em;
+}
+
+// Alignment
+.text-left           { text-align: left; }
+.text-right          { text-align: right; }
+.text-center         { text-align: center; }
+.text-justify        { text-align: justify; }
+.text-nowrap         { white-space: nowrap; }
+
+// Transformation
+.text-lowercase      { text-transform: lowercase; }
+.text-uppercase      { text-transform: uppercase; }
+.text-capitalize     { text-transform: capitalize; }
+
+// Contextual colors
+.text-muted {
+  color: $text-muted;
+}
+
+@include text-emphasis-variant('.text-primary', $brand-primary);
+
+@include text-emphasis-variant('.text-success', $state-success-text);
+
+@include text-emphasis-variant('.text-info', $state-info-text);
+
+@include text-emphasis-variant('.text-warning', $state-warning-text);
+
+@include text-emphasis-variant('.text-danger', $state-danger-text);
+
+// Contextual backgrounds
+// For now we'll leave these alongside the text classes until v4 when we can
+// safely shift things around (per SemVer rules).
+.bg-primary {
+  // Given the contrast here, this is the only class to have its color inverted
+  // automatically.
+  color: #fff;
+}
+@include bg-variant('.bg-primary', $brand-primary);
+
+@include bg-variant('.bg-success', $state-success-bg);
+
+@include bg-variant('.bg-info', $state-info-bg);
+
+@include bg-variant('.bg-warning', $state-warning-bg);
+
+@include bg-variant('.bg-danger', $state-danger-bg);
+
+
+// Page header
+// -------------------------
+
+.page-header {
+  padding-bottom: (($line-height-computed / 2) - 1);
+  margin: ($line-height-computed * 2) 0 $line-height-computed;
+  border-bottom: 1px solid $page-header-border-color;
+}
+
+
+// Lists
+// -------------------------
+
+// Unordered and Ordered lists
+ul,
+ol {
+  margin-top: 0;
+  margin-bottom: ($line-height-computed / 2);
+  ul,
+  ol {
+    margin-bottom: 0;
+  }
+}
+
+// List options
+
+// [converter] extracted from `.list-unstyled` for libsass compatibility
+@mixin list-unstyled {
+  padding-left: 0;
+  list-style: none;
+}
+// [converter] extracted as `@mixin list-unstyled` for libsass compatibility
+.list-unstyled {
+  @include list-unstyled;
+}
+
+
+// Inline turns list items into inline-block
+.list-inline {
+  @include list-unstyled;
+  margin-left: -5px;
+
+  > li {
+    display: inline-block;
+    padding-left: 5px;
+    padding-right: 5px;
+  }
+}
+
+// Description Lists
+dl {
+  margin-top: 0; // Remove browser default
+  margin-bottom: $line-height-computed;
+}
+dt,
+dd {
+  line-height: $line-height-base;
+}
+dt {
+  font-weight: bold;
+}
+dd {
+  margin-left: 0; // Undo browser default
+}
+
+// Horizontal description lists
+//
+// Defaults to being stacked without any of the below styles applied, until the
+// grid breakpoint is reached (default of ~768px).
+
+.dl-horizontal {
+  dd {
+    @include clearfix; // Clear the floated `dt` if an empty `dd` is present
+  }
+
+  @media (min-width: $dl-horizontal-breakpoint) {
+    dt {
+      float: left;
+      width: ($dl-horizontal-offset - 20);
+      clear: left;
+      text-align: right;
+      @include text-overflow;
+    }
+    dd {
+      margin-left: $dl-horizontal-offset;
+    }
+  }
+}
+
+
+// Misc
+// -------------------------
+
+// Abbreviations and acronyms
+abbr[title],
+// Add data-* attribute to help out our tooltip plugin, per https://github.com/twbs/bootstrap/issues/5257
+abbr[data-original-title] {
+  cursor: help;
+  border-bottom: 1px dotted $abbr-border-color;
+}
+.initialism {
+  font-size: 90%;
+  @extend .text-uppercase;
+}
+
+// Blockquotes
+blockquote {
+  padding: ($line-height-computed / 2) $line-height-computed;
+  margin: 0 0 $line-height-computed;
+  font-size: $blockquote-font-size;
+  border-left: 5px solid $blockquote-border-color;
+
+  p,
+  ul,
+  ol {
+    &:last-child {
+      margin-bottom: 0;
+    }
+  }
+
+  // Note: Deprecated small and .small as of v3.1.0
+  // Context: https://github.com/twbs/bootstrap/issues/11660
+  footer,
+  small,
+  .small {
+    display: block;
+    font-size: 80%; // back to default font-size
+    line-height: $line-height-base;
+    color: $blockquote-small-color;
+
+    &:before {
+      content: '\2014 \00A0'; // em dash, nbsp
+    }
+  }
+}
+
+// Opposite alignment of blockquote
+//
+// Heads up: `blockquote.pull-right` has been deprecated as of v3.1.0.
+.blockquote-reverse,
+blockquote.pull-right {
+  padding-right: 15px;
+  padding-left: 0;
+  border-right: 5px solid $blockquote-border-color;
+  border-left: 0;
+  text-align: right;
+
+  // Account for citation
+  footer,
+  small,
+  .small {
+    &:before { content: ''; }
+    &:after {
+      content: '\00A0 \2014'; // nbsp, em dash
+    }
+  }
+}
+
+// Addresses
+address {
+  margin-bottom: $line-height-computed;
+  font-style: normal;
+  line-height: $line-height-base;
+}
diff --git a/views/style/sass/bootstrap/bootstrap/_utilities.scss b/views/style/sass/bootstrap/bootstrap/_utilities.scss
new file mode 100644
index 0000000..8c99c71
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/_utilities.scss
@@ -0,0 +1,55 @@
+//
+// Utility classes
+// --------------------------------------------------
+
+
+// Floats
+// -------------------------
+
+.clearfix {
+  @include clearfix;
+}
+.center-block {
+  @include center-block;
+}
+.pull-right {
+  float: right !important;
+}
+.pull-left {
+  float: left !important;
+}
+
+
+// Toggling content
+// -------------------------
+
+// Note: Deprecated .hide in favor of .hidden or .sr-only (as appropriate) in v3.0.1
+.hide {
+  display: none !important;
+}
+.show {
+  display: block !important;
+}
+.invisible {
+  visibility: hidden;
+}
+.text-hide {
+  @include text-hide;
+}
+
+
+// Hide from screenreaders and browsers
+//
+// Credit: HTML5 Boilerplate
+
+.hidden {
+  display: none !important;
+}
+
+
+// For Affix plugin
+// -------------------------
+
+.affix {
+  position: fixed;
+}
diff --git a/views/style/sass/bootstrap/bootstrap/_variables.scss b/views/style/sass/bootstrap/bootstrap/_variables.scss
new file mode 100644
index 0000000..0703b0c
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/_variables.scss
@@ -0,0 +1,874 @@
+$bootstrap-sass-asset-helper: false !default;
+//
+// Variables
+// --------------------------------------------------
+
+
+//== Colors
+//
+//## Gray and brand colors for use across Bootstrap.
+
+$gray-base:              #000 !default;
+$gray-darker:            lighten($gray-base, 13.5%) !default; // #222
+$gray-dark:              lighten($gray-base, 20%) !default;   // #333
+$gray:                   lighten($gray-base, 33.5%) !default; // #555
+$gray-light:             lighten($gray-base, 46.7%) !default; // #777
+$gray-lighter:           lighten($gray-base, 93.5%) !default; // #eee
+
+$brand-primary:         darken(#428bca, 6.5%) !default; // #337ab7
+$brand-success:         #5cb85c !default;
+$brand-info:            #5bc0de !default;
+$brand-warning:         #f0ad4e !default;
+$brand-danger:          #d9534f !default;
+
+
+//== Scaffolding
+//
+//## Settings for some of the most global styles.
+
+//** Background color for `<body>`.
+$body-bg:               #fff !default;
+//** Global text color on `<body>`.
+$text-color:            $gray-dark !default;
+
+//** Global textual link color.
+$link-color:            $brand-primary !default;
+//** Link hover color set via `darken()` function.
+$link-hover-color:      darken($link-color, 15%) !default;
+//** Link hover decoration.
+$link-hover-decoration: underline !default;
+
+
+//== Typography
+//
+//## Font, line-height, and color for body text, headings, and more.
+
+$font-family-sans-serif:  "Helvetica Neue", Helvetica, Arial, sans-serif !default;
+$font-family-serif:       Georgia, "Times New Roman", Times, serif !default;
+//** Default monospace fonts for `<code>`, `<kbd>`, and `<pre>`.
+$font-family-monospace:   Menlo, Monaco, Consolas, "Courier New", monospace !default;
+$font-family-base:        $font-family-sans-serif !default;
+
+$font-size-base:          14px !default;
+$font-size-large:         ceil(($font-size-base * 1.25)) !default; // ~18px
+$font-size-small:         ceil(($font-size-base * 0.85)) !default; // ~12px
+
+$font-size-h1:            floor(($font-size-base * 2.6)) !default; // ~36px
+$font-size-h2:            floor(($font-size-base * 2.15)) !default; // ~30px
+$font-size-h3:            ceil(($font-size-base * 1.7)) !default; // ~24px
+$font-size-h4:            ceil(($font-size-base * 1.25)) !default; // ~18px
+$font-size-h5:            $font-size-base !default;
+$font-size-h6:            ceil(($font-size-base * 0.85)) !default; // ~12px
+
+//** Unit-less `line-height` for use in components like buttons.
+$line-height-base:        1.428571429 !default; // 20/14
+//** Computed "line-height" (`font-size` * `line-height`) for use with `margin`, `padding`, etc.
+$line-height-computed:    floor(($font-size-base * $line-height-base)) !default; // ~20px
+
+//** By default, this inherits from the `<body>`.
+$headings-font-family:    inherit !default;
+$headings-font-weight:    500 !default;
+$headings-line-height:    1.1 !default;
+$headings-color:          inherit !default;
+
+
+//== Iconography
+//
+//## Specify custom location and filename of the included Glyphicons icon font. Useful for those including Bootstrap via Bower.
+
+//** Load fonts from this directory.
+
+// [converter] If $bootstrap-sass-asset-helper if used, provide path relative to the assets load path.
+// [converter] This is because some asset helpers, such as Sprockets, do not work with file-relative paths.
+$icon-font-path: if($bootstrap-sass-asset-helper, "bootstrap/", "../fonts/bootstrap/") !default;
+
+//** File name for all font files.
+$icon-font-name:          "glyphicons-halflings-regular" !default;
+//** Element ID within SVG icon file.
+$icon-font-svg-id:        "glyphicons_halflingsregular" !default;
+
+
+//== Components
+//
+//## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).
+
+$padding-base-vertical:     6px !default;
+$padding-base-horizontal:   12px !default;
+
+$padding-large-vertical:    10px !default;
+$padding-large-horizontal:  16px !default;
+
+$padding-small-vertical:    5px !default;
+$padding-small-horizontal:  10px !default;
+
+$padding-xs-vertical:       1px !default;
+$padding-xs-horizontal:     5px !default;
+
+$line-height-large:         1.3333333 !default; // extra decimals for Win 8.1 Chrome
+$line-height-small:         1.5 !default;
+
+$border-radius-base:        4px !default;
+$border-radius-large:       6px !default;
+$border-radius-small:       3px !default;
+
+//** Global color for active items (e.g., navs or dropdowns).
+$component-active-color:    #fff !default;
+//** Global background color for active items (e.g., navs or dropdowns).
+$component-active-bg:       $brand-primary !default;
+
+//** Width of the `border` for generating carets that indicator dropdowns.
+$caret-width-base:          4px !default;
+//** Carets increase slightly in size for larger components.
+$caret-width-large:         5px !default;
+
+
+//== Tables
+//
+//## Customizes the `.table` component with basic values, each used across all table variations.
+
+//** Padding for `<th>`s and `<td>`s.
+$table-cell-padding:            8px !default;
+//** Padding for cells in `.table-condensed`.
+$table-condensed-cell-padding:  5px !default;
+
+//** Default background color used for all tables.
+$table-bg:                      transparent !default;
+//** Background color used for `.table-striped`.
+$table-bg-accent:               #f9f9f9 !default;
+//** Background color used for `.table-hover`.
+$table-bg-hover:                #f5f5f5 !default;
+$table-bg-active:               $table-bg-hover !default;
+
+//** Border color for table and cell borders.
+$table-border-color:            #ddd !default;
+
+
+//== Buttons
+//
+//## For each of Bootstrap's buttons, define text, background and border color.
+
+$btn-font-weight:                normal !default;
+
+$btn-default-color:              #333 !default;
+$btn-default-bg:                 #fff !default;
+$btn-default-border:             #ccc !default;
+
+$btn-primary-color:              #fff !default;
+$btn-primary-bg:                 $brand-primary !default;
+$btn-primary-border:             darken($btn-primary-bg, 5%) !default;
+
+$btn-success-color:              #fff !default;
+$btn-success-bg:                 $brand-success !default;
+$btn-success-border:             darken($btn-success-bg, 5%) !default;
+
+$btn-info-color:                 #fff !default;
+$btn-info-bg:                    $brand-info !default;
+$btn-info-border:                darken($btn-info-bg, 5%) !default;
+
+$btn-warning-color:              #fff !default;
+$btn-warning-bg:                 $brand-warning !default;
+$btn-warning-border:             darken($btn-warning-bg, 5%) !default;
+
+$btn-danger-color:               #fff !default;
+$btn-danger-bg:                  $brand-danger !default;
+$btn-danger-border:              darken($btn-danger-bg, 5%) !default;
+
+$btn-link-disabled-color:        $gray-light !default;
+
+// Allows for customizing button radius independently from global border radius
+$btn-border-radius-base:         $border-radius-base !default;
+$btn-border-radius-large:        $border-radius-large !default;
+$btn-border-radius-small:        $border-radius-small !default;
+
+
+//== Forms
+//
+//##
+
+//** `<input>` background color
+$input-bg:                       #fff !default;
+//** `<input disabled>` background color
+$input-bg-disabled:              $gray-lighter !default;
+
+//** Text color for `<input>`s
+$input-color:                    $gray !default;
+//** `<input>` border color
+$input-border:                   #ccc !default;
+
+// TODO: Rename `$input-border-radius` to `$input-border-radius-base` in v4
+//** Default `.form-control` border radius
+// This has no effect on `<select>`s in some browsers, due to the limited stylability of `<select>`s in CSS.
+$input-border-radius:            $border-radius-base !default;
+//** Large `.form-control` border radius
+$input-border-radius-large:      $border-radius-large !default;
+//** Small `.form-control` border radius
+$input-border-radius-small:      $border-radius-small !default;
+
+//** Border color for inputs on focus
+$input-border-focus:             #66afe9 !default;
+
+//** Placeholder text color
+$input-color-placeholder:        #999 !default;
+
+//** Default `.form-control` height
+$input-height-base:              ($line-height-computed + ($padding-base-vertical * 2) + 2) !default;
+//** Large `.form-control` height
+$input-height-large:             (ceil($font-size-large * $line-height-large) + ($padding-large-vertical * 2) + 2) !default;
+//** Small `.form-control` height
+$input-height-small:             (floor($font-size-small * $line-height-small) + ($padding-small-vertical * 2) + 2) !default;
+
+//** `.form-group` margin
+$form-group-margin-bottom:       15px !default;
+
+$legend-color:                   $gray-dark !default;
+$legend-border-color:            #e5e5e5 !default;
+
+//** Background color for textual input addons
+$input-group-addon-bg:           $gray-lighter !default;
+//** Border color for textual input addons
+$input-group-addon-border-color: $input-border !default;
+
+//** Disabled cursor for form controls and buttons.
+$cursor-disabled:                not-allowed !default;
+
+
+//== Dropdowns
+//
+//## Dropdown menu container and contents.
+
+//** Background for the dropdown menu.
+$dropdown-bg:                    #fff !default;
+//** Dropdown menu `border-color`.
+$dropdown-border:                rgba(0,0,0,.15) !default;
+//** Dropdown menu `border-color` **for IE8**.
+$dropdown-fallback-border:       #ccc !default;
+//** Divider color for between dropdown items.
+$dropdown-divider-bg:            #e5e5e5 !default;
+
+//** Dropdown link text color.
+$dropdown-link-color:            $gray-dark !default;
+//** Hover color for dropdown links.
+$dropdown-link-hover-color:      darken($gray-dark, 5%) !default;
+//** Hover background for dropdown links.
+$dropdown-link-hover-bg:         #f5f5f5 !default;
+
+//** Active dropdown menu item text color.
+$dropdown-link-active-color:     $component-active-color !default;
+//** Active dropdown menu item background color.
+$dropdown-link-active-bg:        $component-active-bg !default;
+
+//** Disabled dropdown menu item background color.
+$dropdown-link-disabled-color:   $gray-light !default;
+
+//** Text color for headers within dropdown menus.
+$dropdown-header-color:          $gray-light !default;
+
+//** Deprecated `$dropdown-caret-color` as of v3.1.0
+$dropdown-caret-color:           #000 !default;
+
+
+//-- Z-index master list
+//
+// Warning: Avoid customizing these values. They're used for a bird's eye view
+// of components dependent on the z-axis and are designed to all work together.
+//
+// Note: These variables are not generated into the Customizer.
+
+$zindex-navbar:            1000 !default;
+$zindex-dropdown:          1000 !default;
+$zindex-popover:           1060 !default;
+$zindex-tooltip:           1070 !default;
+$zindex-navbar-fixed:      1030 !default;
+$zindex-modal-background:  1040 !default;
+$zindex-modal:             1050 !default;
+
+
+//== Media queries breakpoints
+//
+//## Define the breakpoints at which your layout will change, adapting to different screen sizes.
+
+// Extra small screen / phone
+//** Deprecated `$screen-xs` as of v3.0.1
+$screen-xs:                  480px !default;
+//** Deprecated `$screen-xs-min` as of v3.2.0
+$screen-xs-min:              $screen-xs !default;
+//** Deprecated `$screen-phone` as of v3.0.1
+$screen-phone:               $screen-xs-min !default;
+
+// Small screen / tablet
+//** Deprecated `$screen-sm` as of v3.0.1
+$screen-sm:                  768px !default;
+$screen-sm-min:              $screen-sm !default;
+//** Deprecated `$screen-tablet` as of v3.0.1
+$screen-tablet:              $screen-sm-min !default;
+
+// Medium screen / desktop
+//** Deprecated `$screen-md` as of v3.0.1
+$screen-md:                  992px !default;
+$screen-md-min:              $screen-md !default;
+//** Deprecated `$screen-desktop` as of v3.0.1
+$screen-desktop:             $screen-md-min !default;
+
+// Large screen / wide desktop
+//** Deprecated `$screen-lg` as of v3.0.1
+$screen-lg:                  1200px !default;
+$screen-lg-min:              $screen-lg !default;
+//** Deprecated `$screen-lg-desktop` as of v3.0.1
+$screen-lg-desktop:          $screen-lg-min !default;
+
+// So media queries don't overlap when required, provide a maximum
+$screen-xs-max:              ($screen-sm-min - 1) !default;
+$screen-sm-max:              ($screen-md-min - 1) !default;
+$screen-md-max:              ($screen-lg-min - 1) !default;
+
+
+//== Grid system
+//
+//## Define your custom responsive grid.
+
+//** Number of columns in the grid.
+$grid-columns:              12 !default;
+//** Padding between columns. Gets divided in half for the left and right.
+$grid-gutter-width:         30px !default;
+// Navbar collapse
+//** Point at which the navbar becomes uncollapsed.
+$grid-float-breakpoint:     $screen-sm-min !default;
+//** Point at which the navbar begins collapsing.
+$grid-float-breakpoint-max: ($grid-float-breakpoint - 1) !default;
+
+
+//== Container sizes
+//
+//## Define the maximum width of `.container` for different screen sizes.
+
+// Small screen / tablet
+$container-tablet:             (720px + $grid-gutter-width) !default;
+//** For `$screen-sm-min` and up.
+$container-sm:                 $container-tablet !default;
+
+// Medium screen / desktop
+$container-desktop:            (940px + $grid-gutter-width) !default;
+//** For `$screen-md-min` and up.
+$container-md:                 $container-desktop !default;
+
+// Large screen / wide desktop
+$container-large-desktop:      (1140px + $grid-gutter-width) !default;
+//** For `$screen-lg-min` and up.
+$container-lg:                 $container-large-desktop !default;
+
+
+//== Navbar
+//
+//##
+
+// Basics of a navbar
+$navbar-height:                    50px !default;
+$navbar-margin-bottom:             $line-height-computed !default;
+$navbar-border-radius:             $border-radius-base !default;
+$navbar-padding-horizontal:        floor(($grid-gutter-width / 2)) !default;
+$navbar-padding-vertical:          (($navbar-height - $line-height-computed) / 2) !default;
+$navbar-collapse-max-height:       340px !default;
+
+$navbar-default-color:             #777 !default;
+$navbar-default-bg:                #f8f8f8 !default;
+$navbar-default-border:            darken($navbar-default-bg, 6.5%) !default;
+
+// Navbar links
+$navbar-default-link-color:                #777 !default;
+$navbar-default-link-hover-color:          #333 !default;
+$navbar-default-link-hover-bg:             transparent !default;
+$navbar-default-link-active-color:         #555 !default;
+$navbar-default-link-active-bg:            darken($navbar-default-bg, 6.5%) !default;
+$navbar-default-link-disabled-color:       #ccc !default;
+$navbar-default-link-disabled-bg:          transparent !default;
+
+// Navbar brand label
+$navbar-default-brand-color:               $navbar-default-link-color !default;
+$navbar-default-brand-hover-color:         darken($navbar-default-brand-color, 10%) !default;
+$navbar-default-brand-hover-bg:            transparent !default;
+
+// Navbar toggle
+$navbar-default-toggle-hover-bg:           #ddd !default;
+$navbar-default-toggle-icon-bar-bg:        #888 !default;
+$navbar-default-toggle-border-color:       #ddd !default;
+
+
+//=== Inverted navbar
+// Reset inverted navbar basics
+$navbar-inverse-color:                      lighten($gray-light, 15%) !default;
+$navbar-inverse-bg:                         #222 !default;
+$navbar-inverse-border:                     darken($navbar-inverse-bg, 10%) !default;
+
+// Inverted navbar links
+$navbar-inverse-link-color:                 lighten($gray-light, 15%) !default;
+$navbar-inverse-link-hover-color:           #fff !default;
+$navbar-inverse-link-hover-bg:              transparent !default;
+$navbar-inverse-link-active-color:          $navbar-inverse-link-hover-color !default;
+$navbar-inverse-link-active-bg:             darken($navbar-inverse-bg, 10%) !default;
+$navbar-inverse-link-disabled-color:        #444 !default;
+$navbar-inverse-link-disabled-bg:           transparent !default;
+
+// Inverted navbar brand label
+$navbar-inverse-brand-color:                $navbar-inverse-link-color !default;
+$navbar-inverse-brand-hover-color:          #fff !default;
+$navbar-inverse-brand-hover-bg:             transparent !default;
+
+// Inverted navbar toggle
+$navbar-inverse-toggle-hover-bg:            #333 !default;
+$navbar-inverse-toggle-icon-bar-bg:         #fff !default;
+$navbar-inverse-toggle-border-color:        #333 !default;
+
+
+//== Navs
+//
+//##
+
+//=== Shared nav styles
+$nav-link-padding:                          10px 15px !default;
+$nav-link-hover-bg:                         $gray-lighter !default;
+
+$nav-disabled-link-color:                   $gray-light !default;
+$nav-disabled-link-hover-color:             $gray-light !default;
+
+//== Tabs
+$nav-tabs-border-color:                     #ddd !default;
+
+$nav-tabs-link-hover-border-color:          $gray-lighter !default;
+
+$nav-tabs-active-link-hover-bg:             $body-bg !default;
+$nav-tabs-active-link-hover-color:          $gray !default;
+$nav-tabs-active-link-hover-border-color:   #ddd !default;
+
+$nav-tabs-justified-link-border-color:            #ddd !default;
+$nav-tabs-justified-active-link-border-color:     $body-bg !default;
+
+//== Pills
+$nav-pills-border-radius:                   $border-radius-base !default;
+$nav-pills-active-link-hover-bg:            $component-active-bg !default;
+$nav-pills-active-link-hover-color:         $component-active-color !default;
+
+
+//== Pagination
+//
+//##
+
+$pagination-color:                     $link-color !default;
+$pagination-bg:                        #fff !default;
+$pagination-border:                    #ddd !default;
+
+$pagination-hover-color:               $link-hover-color !default;
+$pagination-hover-bg:                  $gray-lighter !default;
+$pagination-hover-border:              #ddd !default;
+
+$pagination-active-color:              #fff !default;
+$pagination-active-bg:                 $brand-primary !default;
+$pagination-active-border:             $brand-primary !default;
+
+$pagination-disabled-color:            $gray-light !default;
+$pagination-disabled-bg:               #fff !default;
+$pagination-disabled-border:           #ddd !default;
+
+
+//== Pager
+//
+//##
+
+$pager-bg:                             $pagination-bg !default;
+$pager-border:                         $pagination-border !default;
+$pager-border-radius:                  15px !default;
+
+$pager-hover-bg:                       $pagination-hover-bg !default;
+
+$pager-active-bg:                      $pagination-active-bg !default;
+$pager-active-color:                   $pagination-active-color !default;
+
+$pager-disabled-color:                 $pagination-disabled-color !default;
+
+
+//== Jumbotron
+//
+//##
+
+$jumbotron-padding:              30px !default;
+$jumbotron-color:                inherit !default;
+$jumbotron-bg:                   $gray-lighter !default;
+$jumbotron-heading-color:        inherit !default;
+$jumbotron-font-size:            ceil(($font-size-base * 1.5)) !default;
+$jumbotron-heading-font-size:    ceil(($font-size-base * 4.5)) !default;
+
+
+//== Form states and alerts
+//
+//## Define colors for form feedback states and, by default, alerts.
+
+$state-success-text:             #3c763d !default;
+$state-success-bg:               #dff0d8 !default;
+$state-success-border:           darken(adjust-hue($state-success-bg, -10), 5%) !default;
+
+$state-info-text:                #31708f !default;
+$state-info-bg:                  #d9edf7 !default;
+$state-info-border:              darken(adjust-hue($state-info-bg, -10), 7%) !default;
+
+$state-warning-text:             #8a6d3b !default;
+$state-warning-bg:               #fcf8e3 !default;
+$state-warning-border:           darken(adjust-hue($state-warning-bg, -10), 5%) !default;
+
+$state-danger-text:              #a94442 !default;
+$state-danger-bg:                #f2dede !default;
+$state-danger-border:            darken(adjust-hue($state-danger-bg, -10), 5%) !default;
+
+
+//== Tooltips
+//
+//##
+
+//** Tooltip max width
+$tooltip-max-width:           200px !default;
+//** Tooltip text color
+$tooltip-color:               #fff !default;
+//** Tooltip background color
+$tooltip-bg:                  #000 !default;
+$tooltip-opacity:             .9 !default;
+
+//** Tooltip arrow width
+$tooltip-arrow-width:         5px !default;
+//** Tooltip arrow color
+$tooltip-arrow-color:         $tooltip-bg !default;
+
+
+//== Popovers
+//
+//##
+
+//** Popover body background color
+$popover-bg:                          #fff !default;
+//** Popover maximum width
+$popover-max-width:                   276px !default;
+//** Popover border color
+$popover-border-color:                rgba(0,0,0,.2) !default;
+//** Popover fallback border color
+$popover-fallback-border-color:       #ccc !default;
+
+//** Popover title background color
+$popover-title-bg:                    darken($popover-bg, 3%) !default;
+
+//** Popover arrow width
+$popover-arrow-width:                 10px !default;
+//** Popover arrow color
+$popover-arrow-color:                 $popover-bg !default;
+
+//** Popover outer arrow width
+$popover-arrow-outer-width:           ($popover-arrow-width + 1) !default;
+//** Popover outer arrow color
+$popover-arrow-outer-color:           fade_in($popover-border-color, 0.05) !default;
+//** Popover outer arrow fallback color
+$popover-arrow-outer-fallback-color:  darken($popover-fallback-border-color, 20%) !default;
+
+
+//== Labels
+//
+//##
+
+//** Default label background color
+$label-default-bg:            $gray-light !default;
+//** Primary label background color
+$label-primary-bg:            $brand-primary !default;
+//** Success label background color
+$label-success-bg:            $brand-success !default;
+//** Info label background color
+$label-info-bg:               $brand-info !default;
+//** Warning label background color
+$label-warning-bg:            $brand-warning !default;
+//** Danger label background color
+$label-danger-bg:             $brand-danger !default;
+
+//** Default label text color
+$label-color:                 #fff !default;
+//** Default text color of a linked label
+$label-link-hover-color:      #fff !default;
+
+
+//== Modals
+//
+//##
+
+//** Padding applied to the modal body
+$modal-inner-padding:         15px !default;
+
+//** Padding applied to the modal title
+$modal-title-padding:         15px !default;
+//** Modal title line-height
+$modal-title-line-height:     $line-height-base !default;
+
+//** Background color of modal content area
+$modal-content-bg:                             #fff !default;
+//** Modal content border color
+$modal-content-border-color:                   rgba(0,0,0,.2) !default;
+//** Modal content border color **for IE8**
+$modal-content-fallback-border-color:          #999 !default;
+
+//** Modal backdrop background color
+$modal-backdrop-bg:           #000 !default;
+//** Modal backdrop opacity
+$modal-backdrop-opacity:      .5 !default;
+//** Modal header border color
+$modal-header-border-color:   #e5e5e5 !default;
+//** Modal footer border color
+$modal-footer-border-color:   $modal-header-border-color !default;
+
+$modal-lg:                    900px !default;
+$modal-md:                    600px !default;
+$modal-sm:                    300px !default;
+
+
+//== Alerts
+//
+//## Define alert colors, border radius, and padding.
+
+$alert-padding:               15px !default;
+$alert-border-radius:         $border-radius-base !default;
+$alert-link-font-weight:      bold !default;
+
+$alert-success-bg:            $state-success-bg !default;
+$alert-success-text:          $state-success-text !default;
+$alert-success-border:        $state-success-border !default;
+
+$alert-info-bg:               $state-info-bg !default;
+$alert-info-text:             $state-info-text !default;
+$alert-info-border:           $state-info-border !default;
+
+$alert-warning-bg:            $state-warning-bg !default;
+$alert-warning-text:          $state-warning-text !default;
+$alert-warning-border:        $state-warning-border !default;
+
+$alert-danger-bg:             $state-danger-bg !default;
+$alert-danger-text:           $state-danger-text !default;
+$alert-danger-border:         $state-danger-border !default;
+
+
+//== Progress bars
+//
+//##
+
+//** Background color of the whole progress component
+$progress-bg:                 #f5f5f5 !default;
+//** Progress bar text color
+$progress-bar-color:          #fff !default;
+//** Variable for setting rounded corners on progress bar.
+$progress-border-radius:      $border-radius-base !default;
+
+//** Default progress bar color
+$progress-bar-bg:             $brand-primary !default;
+//** Success progress bar color
+$progress-bar-success-bg:     $brand-success !default;
+//** Warning progress bar color
+$progress-bar-warning-bg:     $brand-warning !default;
+//** Danger progress bar color
+$progress-bar-danger-bg:      $brand-danger !default;
+//** Info progress bar color
+$progress-bar-info-bg:        $brand-info !default;
+
+
+//== List group
+//
+//##
+
+//** Background color on `.list-group-item`
+$list-group-bg:                 #fff !default;
+//** `.list-group-item` border color
+$list-group-border:             #ddd !default;
+//** List group border radius
+$list-group-border-radius:      $border-radius-base !default;
+
+//** Background color of single list items on hover
+$list-group-hover-bg:           #f5f5f5 !default;
+//** Text color of active list items
+$list-group-active-color:       $component-active-color !default;
+//** Background color of active list items
+$list-group-active-bg:          $component-active-bg !default;
+//** Border color of active list elements
+$list-group-active-border:      $list-group-active-bg !default;
+//** Text color for content within active list items
+$list-group-active-text-color:  lighten($list-group-active-bg, 40%) !default;
+
+//** Text color of disabled list items
+$list-group-disabled-color:      $gray-light !default;
+//** Background color of disabled list items
+$list-group-disabled-bg:         $gray-lighter !default;
+//** Text color for content within disabled list items
+$list-group-disabled-text-color: $list-group-disabled-color !default;
+
+$list-group-link-color:         #555 !default;
+$list-group-link-hover-color:   $list-group-link-color !default;
+$list-group-link-heading-color: #333 !default;
+
+
+//== Panels
+//
+//##
+
+$panel-bg:                    #fff !default;
+$panel-body-padding:          15px !default;
+$panel-heading-padding:       10px 15px !default;
+$panel-footer-padding:        $panel-heading-padding !default;
+$panel-border-radius:         $border-radius-base !default;
+
+//** Border color for elements within panels
+$panel-inner-border:          #ddd !default;
+$panel-footer-bg:             #f5f5f5 !default;
+
+$panel-default-text:          $gray-dark !default;
+$panel-default-border:        #ddd !default;
+$panel-default-heading-bg:    #f5f5f5 !default;
+
+$panel-primary-text:          #fff !default;
+$panel-primary-border:        $brand-primary !default;
+$panel-primary-heading-bg:    $brand-primary !default;
+
+$panel-success-text:          $state-success-text !default;
+$panel-success-border:        $state-success-border !default;
+$panel-success-heading-bg:    $state-success-bg !default;
+
+$panel-info-text:             $state-info-text !default;
+$panel-info-border:           $state-info-border !default;
+$panel-info-heading-bg:       $state-info-bg !default;
+
+$panel-warning-text:          $state-warning-text !default;
+$panel-warning-border:        $state-warning-border !default;
+$panel-warning-heading-bg:    $state-warning-bg !default;
+
+$panel-danger-text:           $state-danger-text !default;
+$panel-danger-border:         $state-danger-border !default;
+$panel-danger-heading-bg:     $state-danger-bg !default;
+
+
+//== Thumbnails
+//
+//##
+
+//** Padding around the thumbnail image
+$thumbnail-padding:           4px !default;
+//** Thumbnail background color
+$thumbnail-bg:                $body-bg !default;
+//** Thumbnail border color
+$thumbnail-border:            #ddd !default;
+//** Thumbnail border radius
+$thumbnail-border-radius:     $border-radius-base !default;
+
+//** Custom text color for thumbnail captions
+$thumbnail-caption-color:     $text-color !default;
+//** Padding around the thumbnail caption
+$thumbnail-caption-padding:   9px !default;
+
+
+//== Wells
+//
+//##
+
+$well-bg:                     #f5f5f5 !default;
+$well-border:                 darken($well-bg, 7%) !default;
+
+
+//== Badges
+//
+//##
+
+$badge-color:                 #fff !default;
+//** Linked badge text color on hover
+$badge-link-hover-color:      #fff !default;
+$badge-bg:                    $gray-light !default;
+
+//** Badge text color in active nav link
+$badge-active-color:          $link-color !default;
+//** Badge background color in active nav link
+$badge-active-bg:             #fff !default;
+
+$badge-font-weight:           bold !default;
+$badge-line-height:           1 !default;
+$badge-border-radius:         10px !default;
+
+
+//== Breadcrumbs
+//
+//##
+
+$breadcrumb-padding-vertical:   8px !default;
+$breadcrumb-padding-horizontal: 15px !default;
+//** Breadcrumb background color
+$breadcrumb-bg:                 #f5f5f5 !default;
+//** Breadcrumb text color
+$breadcrumb-color:              #ccc !default;
+//** Text color of current page in the breadcrumb
+$breadcrumb-active-color:       $gray-light !default;
+//** Textual separator for between breadcrumb elements
+$breadcrumb-separator:          "/" !default;
+
+
+//== Carousel
+//
+//##
+
+$carousel-text-shadow:                        0 1px 2px rgba(0,0,0,.6) !default;
+
+$carousel-control-color:                      #fff !default;
+$carousel-control-width:                      15% !default;
+$carousel-control-opacity:                    .5 !default;
+$carousel-control-font-size:                  20px !default;
+
+$carousel-indicator-active-bg:                #fff !default;
+$carousel-indicator-border-color:             #fff !default;
+
+$carousel-caption-color:                      #fff !default;
+
+
+//== Close
+//
+//##
+
+$close-font-weight:           bold !default;
+$close-color:                 #000 !default;
+$close-text-shadow:           0 1px 0 #fff !default;
+
+
+//== Code
+//
+//##
+
+$code-color:                  #c7254e !default;
+$code-bg:                     #f9f2f4 !default;
+
+$kbd-color:                   #fff !default;
+$kbd-bg:                      #333 !default;
+
+$pre-bg:                      #f5f5f5 !default;
+$pre-color:                   $gray-dark !default;
+$pre-border-color:            #ccc !default;
+$pre-scrollable-max-height:   340px !default;
+
+
+//== Type
+//
+//##
+
+//** Horizontal offset for forms and lists.
+$component-offset-horizontal: 180px !default;
+//** Text muted color
+$text-muted:                  $gray-light !default;
+//** Abbreviations and acronyms border color
+$abbr-border-color:           $gray-light !default;
+//** Headings small color
+$headings-small-color:        $gray-light !default;
+//** Blockquote small color
+$blockquote-small-color:      $gray-light !default;
+//** Blockquote font size
+$blockquote-font-size:        ($font-size-base * 1.25) !default;
+//** Blockquote border color
+$blockquote-border-color:     $gray-lighter !default;
+//** Page header border color
+$page-header-border-color:    $gray-lighter !default;
+//** Width of horizontal description list titles
+$dl-horizontal-offset:        $component-offset-horizontal !default;
+//** Point at which .dl-horizontal becomes horizontal
+$dl-horizontal-breakpoint:    $grid-float-breakpoint !default;
+//** Horizontal line color.
+$hr-border:                   $gray-lighter !default;
diff --git a/views/style/sass/bootstrap/bootstrap/_wells.scss b/views/style/sass/bootstrap/bootstrap/_wells.scss
new file mode 100644
index 0000000..b865711
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/_wells.scss
@@ -0,0 +1,29 @@
+//
+// Wells
+// --------------------------------------------------
+
+
+// Base class
+.well {
+  min-height: 20px;
+  padding: 19px;
+  margin-bottom: 20px;
+  background-color: $well-bg;
+  border: 1px solid $well-border;
+  border-radius: $border-radius-base;
+  @include box-shadow(inset 0 1px 1px rgba(0,0,0,.05));
+  blockquote {
+    border-color: #ddd;
+    border-color: rgba(0,0,0,.15);
+  }
+}
+
+// Sizes
+.well-lg {
+  padding: 24px;
+  border-radius: $border-radius-large;
+}
+.well-sm {
+  padding: 9px;
+  border-radius: $border-radius-small;
+}
diff --git a/views/style/sass/bootstrap/bootstrap/mixins/_alerts.scss b/views/style/sass/bootstrap/bootstrap/mixins/_alerts.scss
new file mode 100644
index 0000000..3faf0b5
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/mixins/_alerts.scss
@@ -0,0 +1,14 @@
+// Alerts
+
+@mixin alert-variant($background, $border, $text-color) {
+  background-color: $background;
+  border-color: $border;
+  color: $text-color;
+
+  hr {
+    border-top-color: darken($border, 5%);
+  }
+  .alert-link {
+    color: darken($text-color, 10%);
+  }
+}
diff --git a/views/style/sass/bootstrap/bootstrap/mixins/_background-variant.scss b/views/style/sass/bootstrap/bootstrap/mixins/_background-variant.scss
new file mode 100644
index 0000000..4c7769e
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/mixins/_background-variant.scss
@@ -0,0 +1,12 @@
+// Contextual backgrounds
+
+// [converter] $parent hack
+@mixin bg-variant($parent, $color) {
+  #{$parent} {
+    background-color: $color;
+  }
+  a#{$parent}:hover,
+  a#{$parent}:focus {
+    background-color: darken($color, 10%);
+  }
+}
diff --git a/views/style/sass/bootstrap/bootstrap/mixins/_border-radius.scss b/views/style/sass/bootstrap/bootstrap/mixins/_border-radius.scss
new file mode 100644
index 0000000..ce19499
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/mixins/_border-radius.scss
@@ -0,0 +1,18 @@
+// Single side border-radius
+
+@mixin border-top-radius($radius) {
+  border-top-right-radius: $radius;
+   border-top-left-radius: $radius;
+}
+@mixin border-right-radius($radius) {
+  border-bottom-right-radius: $radius;
+     border-top-right-radius: $radius;
+}
+@mixin border-bottom-radius($radius) {
+  border-bottom-right-radius: $radius;
+   border-bottom-left-radius: $radius;
+}
+@mixin border-left-radius($radius) {
+  border-bottom-left-radius: $radius;
+     border-top-left-radius: $radius;
+}
diff --git a/views/style/sass/bootstrap/bootstrap/mixins/_buttons.scss b/views/style/sass/bootstrap/bootstrap/mixins/_buttons.scss
new file mode 100644
index 0000000..b93f84b
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/mixins/_buttons.scss
@@ -0,0 +1,65 @@
+// Button variants
+//
+// Easily pump out default styles, as well as :hover, :focus, :active,
+// and disabled options for all buttons
+
+@mixin button-variant($color, $background, $border) {
+  color: $color;
+  background-color: $background;
+  border-color: $border;
+
+  &:focus,
+  &.focus {
+    color: $color;
+    background-color: darken($background, 10%);
+        border-color: darken($border, 25%);
+  }
+  &:hover {
+    color: $color;
+    background-color: darken($background, 10%);
+        border-color: darken($border, 12%);
+  }
+  &:active,
+  &.active,
+  .open > &.dropdown-toggle {
+    color: $color;
+    background-color: darken($background, 10%);
+        border-color: darken($border, 12%);
+
+    &:hover,
+    &:focus,
+    &.focus {
+      color: $color;
+      background-color: darken($background, 17%);
+          border-color: darken($border, 25%);
+    }
+  }
+  &:active,
+  &.active,
+  .open > &.dropdown-toggle {
+    background-image: none;
+  }
+  &.disabled,
+  &[disabled],
+  fieldset[disabled] & {
+    &:hover,
+    &:focus,
+    &.focus {
+      background-color: $background;
+          border-color: $border;
+    }
+  }
+
+  .badge {
+    color: $background;
+    background-color: $color;
+  }
+}
+
+// Button sizes
+@mixin button-size($padding-vertical, $padding-horizontal, $font-size, $line-height, $border-radius) {
+  padding: $padding-vertical $padding-horizontal;
+  font-size: $font-size;
+  line-height: $line-height;
+  border-radius: $border-radius;
+}
diff --git a/views/style/sass/bootstrap/bootstrap/mixins/_center-block.scss b/views/style/sass/bootstrap/bootstrap/mixins/_center-block.scss
new file mode 100644
index 0000000..e06fb5e
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/mixins/_center-block.scss
@@ -0,0 +1,7 @@
+// Center-align a block level element
+
+@mixin center-block() {
+  display: block;
+  margin-left: auto;
+  margin-right: auto;
+}
diff --git a/views/style/sass/bootstrap/bootstrap/mixins/_clearfix.scss b/views/style/sass/bootstrap/bootstrap/mixins/_clearfix.scss
new file mode 100644
index 0000000..dc3e2ab
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/mixins/_clearfix.scss
@@ -0,0 +1,22 @@
+// Clearfix
+//
+// For modern browsers
+// 1. The space content is one way to avoid an Opera bug when the
+//    contenteditable attribute is included anywhere else in the document.
+//    Otherwise it causes space to appear at the top and bottom of elements
+//    that are clearfixed.
+// 2. The use of `table` rather than `block` is only necessary if using
+//    `:before` to contain the top-margins of child elements.
+//
+// Source: http://nicolasgallagher.com/micro-clearfix-hack/
+
+@mixin clearfix() {
+  &:before,
+  &:after {
+    content: " "; // 1
+    display: table; // 2
+  }
+  &:after {
+    clear: both;
+  }
+}
diff --git a/views/style/sass/bootstrap/bootstrap/mixins/_forms.scss b/views/style/sass/bootstrap/bootstrap/mixins/_forms.scss
new file mode 100644
index 0000000..277aa5f
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/mixins/_forms.scss
@@ -0,0 +1,88 @@
+// Form validation states
+//
+// Used in forms.less to generate the form validation CSS for warnings, errors,
+// and successes.
+
+@mixin form-control-validation($text-color: #555, $border-color: #ccc, $background-color: #f5f5f5) {
+  // Color the label and help text
+  .help-block,
+  .control-label,
+  .radio,
+  .checkbox,
+  .radio-inline,
+  .checkbox-inline,
+  &.radio label,
+  &.checkbox label,
+  &.radio-inline label,
+  &.checkbox-inline label  {
+    color: $text-color;
+  }
+  // Set the border and box shadow on specific inputs to match
+  .form-control {
+    border-color: $border-color;
+    @include box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); // Redeclare so transitions work
+    &:focus {
+      border-color: darken($border-color, 10%);
+      $shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 6px lighten($border-color, 20%);
+      @include box-shadow($shadow);
+    }
+  }
+  // Set validation states also for addons
+  .input-group-addon {
+    color: $text-color;
+    border-color: $border-color;
+    background-color: $background-color;
+  }
+  // Optional feedback icon
+  .form-control-feedback {
+    color: $text-color;
+  }
+}
+
+
+// Form control focus state
+//
+// Generate a customized focus state and for any input with the specified color,
+// which defaults to the `$input-border-focus` variable.
+//
+// We highly encourage you to not customize the default value, but instead use
+// this to tweak colors on an as-needed basis. This aesthetic change is based on
+// WebKit's default styles, but applicable to a wider range of browsers. Its
+// usability and accessibility should be taken into account with any change.
+//
+// Example usage: change the default blue border and shadow to white for better
+// contrast against a dark gray background.
+@mixin form-control-focus($color: $input-border-focus) {
+  $color-rgba: rgba(red($color), green($color), blue($color), .6);
+  &:focus {
+    border-color: $color;
+    outline: 0;
+    @include box-shadow(inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px $color-rgba);
+  }
+}
+
+// Form control sizing
+//
+// Relative text size, padding, and border-radii changes for form controls. For
+// horizontal sizing, wrap controls in the predefined grid classes. `<select>`
+// element gets special love because it's special, and that's a fact!
+// [converter] $parent hack
+@mixin input-size($parent, $input-height, $padding-vertical, $padding-horizontal, $font-size, $line-height, $border-radius) {
+  #{$parent} {
+    height: $input-height;
+    padding: $padding-vertical $padding-horizontal;
+    font-size: $font-size;
+    line-height: $line-height;
+    border-radius: $border-radius;
+  }
+
+  select#{$parent} {
+    height: $input-height;
+    line-height: $input-height;
+  }
+
+  textarea#{$parent},
+  select[multiple]#{$parent} {
+    height: auto;
+  }
+}
diff --git a/views/style/sass/bootstrap/bootstrap/mixins/_gradients.scss b/views/style/sass/bootstrap/bootstrap/mixins/_gradients.scss
new file mode 100644
index 0000000..a8939f5
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/mixins/_gradients.scss
@@ -0,0 +1,58 @@
+// Gradients
+
+
+
+// Horizontal gradient, from left to right
+//
+// Creates two color stops, start and end, by specifying a color and position for each color stop.
+// Color stops are not available in IE9 and below.
+@mixin gradient-horizontal($start-color: #555, $end-color: #333, $start-percent: 0%, $end-percent: 100%) {
+  background-image: -webkit-linear-gradient(left, $start-color $start-percent, $end-color $end-percent); // Safari 5.1-6, Chrome 10+
+  background-image: -o-linear-gradient(left, $start-color $start-percent, $end-color $end-percent); // Opera 12
+  background-image: linear-gradient(to right, $start-color $start-percent, $end-color $end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+
+  background-repeat: repeat-x;
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#{ie-hex-str($start-color)}', endColorstr='#{ie-hex-str($end-color)}', GradientType=1); // IE9 and down
+}
+
+// Vertical gradient, from top to bottom
+//
+// Creates two color stops, start and end, by specifying a color and position for each color stop.
+// Color stops are not available in IE9 and below.
+@mixin gradient-vertical($start-color: #555, $end-color: #333, $start-percent: 0%, $end-percent: 100%) {
+  background-image: -webkit-linear-gradient(top, $start-color $start-percent, $end-color $end-percent);  // Safari 5.1-6, Chrome 10+
+  background-image: -o-linear-gradient(top, $start-color $start-percent, $end-color $end-percent);  // Opera 12
+  background-image: linear-gradient(to bottom, $start-color $start-percent, $end-color $end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+
+  background-repeat: repeat-x;
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#{ie-hex-str($start-color)}', endColorstr='#{ie-hex-str($end-color)}', GradientType=0); // IE9 and down
+}
+
+@mixin gradient-directional($start-color: #555, $end-color: #333, $deg: 45deg) {
+  background-repeat: repeat-x;
+  background-image: -webkit-linear-gradient($deg, $start-color, $end-color); // Safari 5.1-6, Chrome 10+
+  background-image: -o-linear-gradient($deg, $start-color, $end-color); // Opera 12
+  background-image: linear-gradient($deg, $start-color, $end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+
+}
+@mixin gradient-horizontal-three-colors($start-color: #00b3ee, $mid-color: #7a43b6, $color-stop: 50%, $end-color: #c3325f) {
+  background-image: -webkit-linear-gradient(left, $start-color, $mid-color $color-stop, $end-color);
+  background-image: -o-linear-gradient(left, $start-color, $mid-color $color-stop, $end-color);
+  background-image: linear-gradient(to right, $start-color, $mid-color $color-stop, $end-color);
+  background-repeat: no-repeat;
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#{ie-hex-str($start-color)}', endColorstr='#{ie-hex-str($end-color)}', GradientType=1); // IE9 and down, gets no color-stop at all for proper fallback
+}
+@mixin gradient-vertical-three-colors($start-color: #00b3ee, $mid-color: #7a43b6, $color-stop: 50%, $end-color: #c3325f) {
+  background-image: -webkit-linear-gradient($start-color, $mid-color $color-stop, $end-color);
+  background-image: -o-linear-gradient($start-color, $mid-color $color-stop, $end-color);
+  background-image: linear-gradient($start-color, $mid-color $color-stop, $end-color);
+  background-repeat: no-repeat;
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#{ie-hex-str($start-color)}', endColorstr='#{ie-hex-str($end-color)}', GradientType=0); // IE9 and down, gets no color-stop at all for proper fallback
+}
+@mixin gradient-radial($inner-color: #555, $outer-color: #333) {
+  background-image: -webkit-radial-gradient(circle, $inner-color, $outer-color);
+  background-image: radial-gradient(circle, $inner-color, $outer-color);
+  background-repeat: no-repeat;
+}
+@mixin gradient-striped($color: rgba(255,255,255,.15), $angle: 45deg) {
+  background-image: -webkit-linear-gradient($angle, $color 25%, transparent 25%, transparent 50%, $color 50%, $color 75%, transparent 75%, transparent);
+  background-image: -o-linear-gradient($angle, $color 25%, transparent 25%, transparent 50%, $color 50%, $color 75%, transparent 75%, transparent);
+  background-image: linear-gradient($angle, $color 25%, transparent 25%, transparent 50%, $color 50%, $color 75%, transparent 75%, transparent);
+}
diff --git a/views/style/sass/bootstrap/bootstrap/mixins/_grid-framework.scss b/views/style/sass/bootstrap/bootstrap/mixins/_grid-framework.scss
new file mode 100644
index 0000000..16d038c
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/mixins/_grid-framework.scss
@@ -0,0 +1,81 @@
+// Framework grid generation
+//
+// Used only by Bootstrap to generate the correct number of grid classes given
+// any value of `$grid-columns`.
+
+// [converter] This is defined recursively in LESS, but Sass supports real loops
+@mixin make-grid-columns($i: 1, $list: ".col-xs-#{$i}, .col-sm-#{$i}, .col-md-#{$i}, .col-lg-#{$i}") {
+  @for $i from (1 + 1) through $grid-columns {
+    $list: "#{$list}, .col-xs-#{$i}, .col-sm-#{$i}, .col-md-#{$i}, .col-lg-#{$i}";
+  }
+  #{$list} {
+    position: relative;
+    // Prevent columns from collapsing when empty
+    min-height: 1px;
+    // Inner gutter via padding
+    padding-left:  ceil(($grid-gutter-width / 2));
+    padding-right: floor(($grid-gutter-width / 2));
+  }
+}
+
+
+// [converter] This is defined recursively in LESS, but Sass supports real loops
+@mixin float-grid-columns($class, $i: 1, $list: ".col-#{$class}-#{$i}") {
+  @for $i from (1 + 1) through $grid-columns {
+    $list: "#{$list}, .col-#{$class}-#{$i}";
+  }
+  #{$list} {
+    float: left;
+  }
+}
+
+
+@mixin calc-grid-column($index, $class, $type) {
+  @if ($type == width) and ($index > 0) {
+    .col-#{$class}-#{$index} {
+      width: percentage(($index / $grid-columns));
+    }
+  }
+  @if ($type == push) and ($index > 0) {
+    .col-#{$class}-push-#{$index} {
+      left: percentage(($index / $grid-columns));
+    }
+  }
+  @if ($type == push) and ($index == 0) {
+    .col-#{$class}-push-0 {
+      left: auto;
+    }
+  }
+  @if ($type == pull) and ($index > 0) {
+    .col-#{$class}-pull-#{$index} {
+      right: percentage(($index / $grid-columns));
+    }
+  }
+  @if ($type == pull) and ($index == 0) {
+    .col-#{$class}-pull-0 {
+      right: auto;
+    }
+  }
+  @if ($type == offset) {
+    .col-#{$class}-offset-#{$index} {
+      margin-left: percentage(($index / $grid-columns));
+    }
+  }
+}
+
+// [converter] This is defined recursively in LESS, but Sass supports real loops
+@mixin loop-grid-columns($columns, $class, $type) {
+  @for $i from 0 through $columns {
+    @include calc-grid-column($i, $class, $type);
+  }
+}
+
+
+// Create grid for specific class
+@mixin make-grid($class) {
+  @include float-grid-columns($class);
+  @include loop-grid-columns($grid-columns, $class, width);
+  @include loop-grid-columns($grid-columns, $class, pull);
+  @include loop-grid-columns($grid-columns, $class, push);
+  @include loop-grid-columns($grid-columns, $class, offset);
+}
diff --git a/views/style/sass/bootstrap/bootstrap/mixins/_grid.scss b/views/style/sass/bootstrap/bootstrap/mixins/_grid.scss
new file mode 100644
index 0000000..59551da
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/mixins/_grid.scss
@@ -0,0 +1,122 @@
+// Grid system
+//
+// Generate semantic grid columns with these mixins.
+
+// Centered container element
+@mixin container-fixed($gutter: $grid-gutter-width) {
+  margin-right: auto;
+  margin-left: auto;
+  padding-left:  floor(($gutter / 2));
+  padding-right: ceil(($gutter / 2));
+  @include clearfix;
+}
+
+// Creates a wrapper for a series of columns
+@mixin make-row($gutter: $grid-gutter-width) {
+  margin-left:  ceil(($gutter / -2));
+  margin-right: floor(($gutter / -2));
+  @include clearfix;
+}
+
+// Generate the extra small columns
+@mixin make-xs-column($columns, $gutter: $grid-gutter-width) {
+  position: relative;
+  float: left;
+  width: percentage(($columns / $grid-columns));
+  min-height: 1px;
+  padding-left:  ($gutter / 2);
+  padding-right: ($gutter / 2);
+}
+@mixin make-xs-column-offset($columns) {
+  margin-left: percentage(($columns / $grid-columns));
+}
+@mixin make-xs-column-push($columns) {
+  left: percentage(($columns / $grid-columns));
+}
+@mixin make-xs-column-pull($columns) {
+  right: percentage(($columns / $grid-columns));
+}
+
+// Generate the small columns
+@mixin make-sm-column($columns, $gutter: $grid-gutter-width) {
+  position: relative;
+  min-height: 1px;
+  padding-left:  ($gutter / 2);
+  padding-right: ($gutter / 2);
+
+  @media (min-width: $screen-sm-min) {
+    float: left;
+    width: percentage(($columns / $grid-columns));
+  }
+}
+@mixin make-sm-column-offset($columns) {
+  @media (min-width: $screen-sm-min) {
+    margin-left: percentage(($columns / $grid-columns));
+  }
+}
+@mixin make-sm-column-push($columns) {
+  @media (min-width: $screen-sm-min) {
+    left: percentage(($columns / $grid-columns));
+  }
+}
+@mixin make-sm-column-pull($columns) {
+  @media (min-width: $screen-sm-min) {
+    right: percentage(($columns / $grid-columns));
+  }
+}
+
+// Generate the medium columns
+@mixin make-md-column($columns, $gutter: $grid-gutter-width) {
+  position: relative;
+  min-height: 1px;
+  padding-left:  ($gutter / 2);
+  padding-right: ($gutter / 2);
+
+  @media (min-width: $screen-md-min) {
+    float: left;
+    width: percentage(($columns / $grid-columns));
+  }
+}
+@mixin make-md-column-offset($columns) {
+  @media (min-width: $screen-md-min) {
+    margin-left: percentage(($columns / $grid-columns));
+  }
+}
+@mixin make-md-column-push($columns) {
+  @media (min-width: $screen-md-min) {
+    left: percentage(($columns / $grid-columns));
+  }
+}
+@mixin make-md-column-pull($columns) {
+  @media (min-width: $screen-md-min) {
+    right: percentage(($columns / $grid-columns));
+  }
+}
+
+// Generate the large columns
+@mixin make-lg-column($columns, $gutter: $grid-gutter-width) {
+  position: relative;
+  min-height: 1px;
+  padding-left:  ($gutter / 2);
+  padding-right: ($gutter / 2);
+
+  @media (min-width: $screen-lg-min) {
+    float: left;
+    width: percentage(($columns / $grid-columns));
+  }
+}
+@mixin make-lg-column-offset($columns) {
+  @media (min-width: $screen-lg-min) {
+    margin-left: percentage(($columns / $grid-columns));
+  }
+}
+@mixin make-lg-column-push($columns) {
+  @media (min-width: $screen-lg-min) {
+    left: percentage(($columns / $grid-columns));
+  }
+}
+@mixin make-lg-column-pull($columns) {
+  @media (min-width: $screen-lg-min) {
+    right: percentage(($columns / $grid-columns));
+  }
+}
diff --git a/views/style/sass/bootstrap/bootstrap/mixins/_hide-text.scss b/views/style/sass/bootstrap/bootstrap/mixins/_hide-text.scss
new file mode 100644
index 0000000..1767e02
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/mixins/_hide-text.scss
@@ -0,0 +1,21 @@
+// CSS image replacement
+//
+// Heads up! v3 launched with only `.hide-text()`, but per our pattern for
+// mixins being reused as classes with the same name, this doesn't hold up. As
+// of v3.0.1 we have added `.text-hide()` and deprecated `.hide-text()`.
+//
+// Source: https://github.com/h5bp/html5-boilerplate/commit/aa0396eae757
+
+// Deprecated as of v3.0.1 (has been removed in v4)
+@mixin hide-text() {
+  font: 0/0 a;
+  color: transparent;
+  text-shadow: none;
+  background-color: transparent;
+  border: 0;
+}
+
+// New mixin to use as of v3.0.1
+@mixin text-hide() {
+  @include hide-text;
+}
diff --git a/views/style/sass/bootstrap/bootstrap/mixins/_image.scss b/views/style/sass/bootstrap/bootstrap/mixins/_image.scss
new file mode 100644
index 0000000..c8dcf5e
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/mixins/_image.scss
@@ -0,0 +1,33 @@
+// Image Mixins
+// - Responsive image
+// - Retina image
+
+
+// Responsive image
+//
+// Keep images from scaling beyond the width of their parents.
+@mixin img-responsive($display: block) {
+  display: $display;
+  max-width: 100%; // Part 1: Set a maximum relative to the parent
+  height: auto; // Part 2: Scale the height according to the width, otherwise you get stretching
+}
+
+
+// Retina image
+//
+// Short retina mixin for setting background-image and -size. Note that the
+// spelling of `min--moz-device-pixel-ratio` is intentional.
+@mixin img-retina($file-1x, $file-2x, $width-1x, $height-1x) {
+  background-image: url(if($bootstrap-sass-asset-helper, twbs-image-path("#{$file-1x}"), "#{$file-1x}"));
+
+  @media
+  only screen and (-webkit-min-device-pixel-ratio: 2),
+  only screen and (   min--moz-device-pixel-ratio: 2),
+  only screen and (     -o-min-device-pixel-ratio: 2/1),
+  only screen and (        min-device-pixel-ratio: 2),
+  only screen and (                min-resolution: 192dpi),
+  only screen and (                min-resolution: 2dppx) {
+    background-image: url(if($bootstrap-sass-asset-helper, twbs-image-path("#{$file-2x}"), "#{$file-2x}"));
+    background-size: $width-1x $height-1x;
+  }
+}
diff --git a/views/style/sass/bootstrap/bootstrap/mixins/_labels.scss b/views/style/sass/bootstrap/bootstrap/mixins/_labels.scss
new file mode 100644
index 0000000..eda6dfd
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/mixins/_labels.scss
@@ -0,0 +1,12 @@
+// Labels
+
+@mixin label-variant($color) {
+  background-color: $color;
+
+  &[href] {
+    &:hover,
+    &:focus {
+      background-color: darken($color, 10%);
+    }
+  }
+}
diff --git a/views/style/sass/bootstrap/bootstrap/mixins/_list-group.scss b/views/style/sass/bootstrap/bootstrap/mixins/_list-group.scss
new file mode 100644
index 0000000..c478eeb
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/mixins/_list-group.scss
@@ -0,0 +1,32 @@
+// List Groups
+
+@mixin list-group-item-variant($state, $background, $color) {
+  .list-group-item-#{$state} {
+    color: $color;
+    background-color: $background;
+
+    // [converter] extracted a&, button& to a.list-group-item-#{$state}, button.list-group-item-#{$state}
+  }
+
+  a.list-group-item-#{$state},
+  button.list-group-item-#{$state} {
+    color: $color;
+
+    .list-group-item-heading {
+      color: inherit;
+    }
+
+    &:hover,
+    &:focus {
+      color: $color;
+      background-color: darken($background, 5%);
+    }
+    &.active,
+    &.active:hover,
+    &.active:focus {
+      color: #fff;
+      background-color: $color;
+      border-color: $color;
+    }
+  }
+}
diff --git a/views/style/sass/bootstrap/bootstrap/mixins/_nav-divider.scss b/views/style/sass/bootstrap/bootstrap/mixins/_nav-divider.scss
new file mode 100644
index 0000000..2e6da02
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/mixins/_nav-divider.scss
@@ -0,0 +1,10 @@
+// Horizontal dividers
+//
+// Dividers (basically an hr) within dropdowns and nav lists
+
+@mixin nav-divider($color: #e5e5e5) {
+  height: 1px;
+  margin: (($line-height-computed / 2) - 1) 0;
+  overflow: hidden;
+  background-color: $color;
+}
diff --git a/views/style/sass/bootstrap/bootstrap/mixins/_nav-vertical-align.scss b/views/style/sass/bootstrap/bootstrap/mixins/_nav-vertical-align.scss
new file mode 100644
index 0000000..c8fbf1a
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/mixins/_nav-vertical-align.scss
@@ -0,0 +1,9 @@
+// Navbar vertical align
+//
+// Vertically center elements in the navbar.
+// Example: an element has a height of 30px, so write out `.navbar-vertical-align(30px);` to calculate the appropriate top margin.
+
+@mixin navbar-vertical-align($element-height) {
+  margin-top: (($navbar-height - $element-height) / 2);
+  margin-bottom: (($navbar-height - $element-height) / 2);
+}
diff --git a/views/style/sass/bootstrap/bootstrap/mixins/_opacity.scss b/views/style/sass/bootstrap/bootstrap/mixins/_opacity.scss
new file mode 100644
index 0000000..88e9a57
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/mixins/_opacity.scss
@@ -0,0 +1,8 @@
+// Opacity
+
+@mixin opacity($opacity) {
+  opacity: $opacity;
+  // IE8 filter
+  $opacity-ie: ($opacity * 100);
+  filter: alpha(opacity=$opacity-ie);
+}
diff --git a/views/style/sass/bootstrap/bootstrap/mixins/_pagination.scss b/views/style/sass/bootstrap/bootstrap/mixins/_pagination.scss
new file mode 100644
index 0000000..d4a5404
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/mixins/_pagination.scss
@@ -0,0 +1,24 @@
+// Pagination
+
+@mixin pagination-size($padding-vertical, $padding-horizontal, $font-size, $line-height, $border-radius) {
+  > li {
+    > a,
+    > span {
+      padding: $padding-vertical $padding-horizontal;
+      font-size: $font-size;
+      line-height: $line-height;
+    }
+    &:first-child {
+      > a,
+      > span {
+        @include border-left-radius($border-radius);
+      }
+    }
+    &:last-child {
+      > a,
+      > span {
+        @include border-right-radius($border-radius);
+      }
+    }
+  }
+}
diff --git a/views/style/sass/bootstrap/bootstrap/mixins/_panels.scss b/views/style/sass/bootstrap/bootstrap/mixins/_panels.scss
new file mode 100644
index 0000000..3ff31ae
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/mixins/_panels.scss
@@ -0,0 +1,24 @@
+// Panels
+
+@mixin panel-variant($border, $heading-text-color, $heading-bg-color, $heading-border) {
+  border-color: $border;
+
+  & > .panel-heading {
+    color: $heading-text-color;
+    background-color: $heading-bg-color;
+    border-color: $heading-border;
+
+    + .panel-collapse > .panel-body {
+      border-top-color: $border;
+    }
+    .badge {
+      color: $heading-bg-color;
+      background-color: $heading-text-color;
+    }
+  }
+  & > .panel-footer {
+    + .panel-collapse > .panel-body {
+      border-bottom-color: $border;
+    }
+  }
+}
diff --git a/views/style/sass/bootstrap/bootstrap/mixins/_progress-bar.scss b/views/style/sass/bootstrap/bootstrap/mixins/_progress-bar.scss
new file mode 100644
index 0000000..90a62af
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/mixins/_progress-bar.scss
@@ -0,0 +1,10 @@
+// Progress bars
+
+@mixin progress-bar-variant($color) {
+  background-color: $color;
+
+  // Deprecated parent class requirement as of v3.2.0
+  .progress-striped & {
+    @include gradient-striped;
+  }
+}
diff --git a/views/style/sass/bootstrap/bootstrap/mixins/_reset-filter.scss b/views/style/sass/bootstrap/bootstrap/mixins/_reset-filter.scss
new file mode 100644
index 0000000..bf73051
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/mixins/_reset-filter.scss
@@ -0,0 +1,8 @@
+// Reset filters for IE
+//
+// When you need to remove a gradient background, do not forget to use this to reset
+// the IE filter for IE9 and below.
+
+@mixin reset-filter() {
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+}
diff --git a/views/style/sass/bootstrap/bootstrap/mixins/_reset-text.scss b/views/style/sass/bootstrap/bootstrap/mixins/_reset-text.scss
new file mode 100644
index 0000000..c9c2841
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/mixins/_reset-text.scss
@@ -0,0 +1,18 @@
+@mixin reset-text() {
+  font-family: $font-family-base;
+  // We deliberately do NOT reset font-size.
+  font-style: normal;
+  font-weight: normal;
+  letter-spacing: normal;
+  line-break: auto;
+  line-height: $line-height-base;
+  text-align: left; // Fallback for where `start` is not supported
+  text-align: start;
+  text-decoration: none;
+  text-shadow: none;
+  text-transform: none;
+  white-space: normal;
+  word-break: normal;
+  word-spacing: normal;
+  word-wrap: normal;
+}
diff --git a/views/style/sass/bootstrap/bootstrap/mixins/_resize.scss b/views/style/sass/bootstrap/bootstrap/mixins/_resize.scss
new file mode 100644
index 0000000..83fa637
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/mixins/_resize.scss
@@ -0,0 +1,6 @@
+// Resize anything
+
+@mixin resizable($direction) {
+  resize: $direction; // Options: horizontal, vertical, both
+  overflow: auto; // Per CSS3 UI, `resize` only applies when `overflow` isn't `visible`
+}
diff --git a/views/style/sass/bootstrap/bootstrap/mixins/_responsive-visibility.scss b/views/style/sass/bootstrap/bootstrap/mixins/_responsive-visibility.scss
new file mode 100644
index 0000000..cbdf777
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/mixins/_responsive-visibility.scss
@@ -0,0 +1,21 @@
+// Responsive utilities
+
+//
+// More easily include all the states for responsive-utilities.less.
+// [converter] $parent hack
+@mixin responsive-visibility($parent) {
+  #{$parent} {
+    display: block !important;
+  }
+  table#{$parent}  { display: table !important; }
+  tr#{$parent}     { display: table-row !important; }
+  th#{$parent},
+  td#{$parent}     { display: table-cell !important; }
+}
+
+// [converter] $parent hack
+@mixin responsive-invisibility($parent) {
+  #{$parent} {
+    display: none !important;
+  }
+}
diff --git a/views/style/sass/bootstrap/bootstrap/mixins/_size.scss b/views/style/sass/bootstrap/bootstrap/mixins/_size.scss
new file mode 100644
index 0000000..abbe246
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/mixins/_size.scss
@@ -0,0 +1,10 @@
+// Sizing shortcuts
+
+@mixin size($width, $height) {
+  width: $width;
+  height: $height;
+}
+
+@mixin square($size) {
+  @include size($size, $size);
+}
diff --git a/views/style/sass/bootstrap/bootstrap/mixins/_tab-focus.scss b/views/style/sass/bootstrap/bootstrap/mixins/_tab-focus.scss
new file mode 100644
index 0000000..7df0ae7
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/mixins/_tab-focus.scss
@@ -0,0 +1,9 @@
+// WebKit-style focus
+
+@mixin tab-focus() {
+  // Default
+  outline: thin dotted;
+  // WebKit
+  outline: 5px auto -webkit-focus-ring-color;
+  outline-offset: -2px;
+}
diff --git a/views/style/sass/bootstrap/bootstrap/mixins/_table-row.scss b/views/style/sass/bootstrap/bootstrap/mixins/_table-row.scss
new file mode 100644
index 0000000..1367950
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/mixins/_table-row.scss
@@ -0,0 +1,28 @@
+// Tables
+
+@mixin table-row-variant($state, $background) {
+  // Exact selectors below required to override `.table-striped` and prevent
+  // inheritance to nested tables.
+  .table > thead > tr,
+  .table > tbody > tr,
+  .table > tfoot > tr {
+    > td.#{$state},
+    > th.#{$state},
+    &.#{$state} > td,
+    &.#{$state} > th {
+      background-color: $background;
+    }
+  }
+
+  // Hover states for `.table-hover`
+  // Note: this is not available for cells or rows within `thead` or `tfoot`.
+  .table-hover > tbody > tr {
+    > td.#{$state}:hover,
+    > th.#{$state}:hover,
+    &.#{$state}:hover > td,
+    &:hover > .#{$state},
+    &.#{$state}:hover > th {
+      background-color: darken($background, 5%);
+    }
+  }
+}
diff --git a/views/style/sass/bootstrap/bootstrap/mixins/_text-emphasis.scss b/views/style/sass/bootstrap/bootstrap/mixins/_text-emphasis.scss
new file mode 100644
index 0000000..3b446c4
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/mixins/_text-emphasis.scss
@@ -0,0 +1,12 @@
+// Typography
+
+// [converter] $parent hack
+@mixin text-emphasis-variant($parent, $color) {
+  #{$parent} {
+    color: $color;
+  }
+  a#{$parent}:hover,
+  a#{$parent}:focus {
+    color: darken($color, 10%);
+  }
+}
diff --git a/views/style/sass/bootstrap/bootstrap/mixins/_text-overflow.scss b/views/style/sass/bootstrap/bootstrap/mixins/_text-overflow.scss
new file mode 100644
index 0000000..1593b25
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/mixins/_text-overflow.scss
@@ -0,0 +1,8 @@
+// Text overflow
+// Requires inline-block or block for proper styling
+
+@mixin text-overflow() {
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
diff --git a/views/style/sass/bootstrap/bootstrap/mixins/_vendor-prefixes.scss b/views/style/sass/bootstrap/bootstrap/mixins/_vendor-prefixes.scss
new file mode 100644
index 0000000..b3d0371
--- /dev/null
+++ b/views/style/sass/bootstrap/bootstrap/mixins/_vendor-prefixes.scss
@@ -0,0 +1,222 @@
+// Vendor Prefixes
+//
+// All vendor mixins are deprecated as of v3.2.0 due to the introduction of
+// Autoprefixer in our Gruntfile. They have been removed in v4.
+
+// - Animations
+// - Backface visibility
+// - Box shadow
+// - Box sizing
+// - Content columns
+// - Hyphens
+// - Placeholder text
+// - Transformations
+// - Transitions
+// - User Select
+
+
+// Animations
+@mixin animation($animation) {
+  -webkit-animation: $animation;
+       -o-animation: $animation;
+          animation: $animation;
+}
+@mixin animation-name($name) {
+  -webkit-animation-name: $name;
+          animation-name: $name;
+}
+@mixin animation-duration($duration) {
+  -webkit-animation-duration: $duration;
+          animation-duration: $duration;
+}
+@mixin animation-timing-function($timing-function) {
+  -webkit-animation-timing-function: $timing-function;
+          animation-timing-function: $timing-function;
+}
+@mixin animation-delay($delay) {
+  -webkit-animation-delay: $delay;
+          animation-delay: $delay;
+}
+@mixin animation-iteration-count($iteration-count) {
+  -webkit-animation-iteration-count: $iteration-count;
+          animation-iteration-count: $iteration-count;
+}
+@mixin animation-direction($direction) {
+  -webkit-animation-direction: $direction;
+          animation-direction: $direction;
+}
+@mixin animation-fill-mode($fill-mode) {
+  -webkit-animation-fill-mode: $fill-mode;
+          animation-fill-mode: $fill-mode;
+}
+
+// Backface visibility
+// Prevent browsers from flickering when using CSS 3D transforms.
+// Default value is `visible`, but can be changed to `hidden`
+
+@mixin backface-visibility($visibility) {
+  -webkit-backface-visibility: $visibility;
+     -moz-backface-visibility: $visibility;
+          backface-visibility: $visibility;
+}
+
+// Drop shadows
+//
+// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's
+// supported browsers that have box shadow capabilities now support it.
+
+@mixin box-shadow($shadow...) {
+  -webkit-box-shadow: $shadow; // iOS <4.3 & Android <4.1
+          box-shadow: $shadow;
+}
+
+// Box sizing
+@mixin box-sizing($boxmodel) {
+  -webkit-box-sizing: $boxmodel;
+     -moz-box-sizing: $boxmodel;
+          box-sizing: $boxmodel;
+}
+
+// CSS3 Content Columns
+@mixin content-columns($column-count, $column-gap: $grid-gutter-width) {
+  -webkit-column-count: $column-count;
+     -moz-column-count: $column-count;
+          column-count: $column-count;
+  -webkit-column-gap: $column-gap;
+     -moz-column-gap: $column-gap;
+          column-gap: $column-gap;
+}
+
+// Optional hyphenation
+@mixin hyphens($mode: auto) {
+  word-wrap: break-word;
+  -webkit-hyphens: $mode;
+     -moz-hyphens: $mode;
+      -ms-hyphens: $mode; // IE10+
+       -o-hyphens: $mode;
+          hyphens: $mode;
+}
+
+// Placeholder text
+@mixin placeholder($color: $input-color-placeholder) {
+  // Firefox
+  &::-moz-placeholder {
+    color: $color;
+    opacity: 1; // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526
+  }
+  &:-ms-input-placeholder { color: $color; } // Internet Explorer 10+
+  &::-webkit-input-placeholder  { color: $color; } // Safari and Chrome
+}
+
+// Transformations
+@mixin scale($ratio...) {
+  -webkit-transform: scale($ratio);
+      -ms-transform: scale($ratio); // IE9 only
+       -o-transform: scale($ratio);
+          transform: scale($ratio);
+}
+
+@mixin scaleX($ratio) {
+  -webkit-transform: scaleX($ratio);
+      -ms-transform: scaleX($ratio); // IE9 only
+       -o-transform: scaleX($ratio);
+          transform: scaleX($ratio);
+}
+@mixin scaleY($ratio) {
+  -webkit-transform: scaleY($ratio);
+      -ms-transform: scaleY($ratio); // IE9 only
+       -o-transform: scaleY($ratio);
+          transform: scaleY($ratio);
+}
+@mixin skew($x, $y) {
+  -webkit-transform: skewX($x) skewY($y);
+      -ms-transform: skewX($x) skewY($y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+
+       -o-transform: skewX($x) skewY($y);
+          transform: skewX($x) skewY($y);
+}
+@mixin translate($x, $y) {
+  -webkit-transform: translate($x, $y);
+      -ms-transform: translate($x, $y); // IE9 only
+       -o-transform: translate($x, $y);
+          transform: translate($x, $y);
+}
+@mixin translate3d($x, $y, $z) {
+  -webkit-transform: translate3d($x, $y, $z);
+          transform: translate3d($x, $y, $z);
+}
+@mixin rotate($degrees) {
+  -webkit-transform: rotate($degrees);
+      -ms-transform: rotate($degrees); // IE9 only
+       -o-transform: rotate($degrees);
+          transform: rotate($degrees);
+}
+@mixin rotateX($degrees) {
+  -webkit-transform: rotateX($degrees);
+      -ms-transform: rotateX($degrees); // IE9 only
+       -o-transform: rotateX($degrees);
+          transform: rotateX($degrees);
+}
+@mixin rotateY($degrees) {
+  -webkit-transform: rotateY($degrees);
+      -ms-transform: rotateY($degrees); // IE9 only
+       -o-transform: rotateY($degrees);
+          transform: rotateY($degrees);
+}
+@mixin perspective($perspective) {
+  -webkit-perspective: $perspective;
+     -moz-perspective: $perspective;
+          perspective: $perspective;
+}
+@mixin perspective-origin($perspective) {
+  -webkit-perspective-origin: $perspective;
+     -moz-perspective-origin: $perspective;
+          perspective-origin: $perspective;
+}
+@mixin transform-origin($origin) {
+  -webkit-transform-origin: $origin;
+     -moz-transform-origin: $origin;
+      -ms-transform-origin: $origin; // IE9 only
+          transform-origin: $origin;
+}
+
+
+// Transitions
+
+@mixin transition($transition...) {
+  -webkit-transition: $transition;
+       -o-transition: $transition;
+          transition: $transition;
+}
+@mixin transition-property($transition-property...) {
+  -webkit-transition-property: $transition-property;
+          transition-property: $transition-property;
+}
+@mixin transition-delay($transition-delay) {
+  -webkit-transition-delay: $transition-delay;
+          transition-delay: $transition-delay;
+}
+@mixin transition-duration($transition-duration...) {
+  -webkit-transition-duration: $transition-duration;
+          transition-duration: $transition-duration;
+}
+@mixin transition-timing-function($timing-function) {
+  -webkit-transition-timing-function: $timing-function;
+          transition-timing-function: $timing-function;
+}
+@mixin transition-transform($transition...) {
+  -webkit-transition: -webkit-transform $transition;
+     -moz-transition: -moz-transform $transition;
+       -o-transition: -o-transform $transition;
+          transition: transform $transition;
+}
+
+
+// User select
+// For selecting text on the page
+
+@mixin user-select($select) {
+  -webkit-user-select: $select;
+     -moz-user-select: $select;
+      -ms-user-select: $select; // IE10+
+          user-select: $select;
+}
diff --git a/views/style/sass/lib/_variables.scss b/views/style/sass/lib/_variables.scss
new file mode 100644
index 0000000..ed9981e
--- /dev/null
+++ b/views/style/sass/lib/_variables.scss
@@ -0,0 +1,21 @@
+
+$icon-font-path: '/static/suit/bootstrap/fonts/';
+//== Colors
+//
+//## Gray and brand colors for use across Bootstrap.
+
+$gray-base:              #000 !default;
+$gray-darker:            lighten($gray-base, 13.5%) !default; // #222
+$gray-dark:              lighten($gray-base, 20%) !default;   // #333
+$gray:                   lighten($gray-base, 33.5%) !default; // #555
+$gray-light:             lighten($gray-base, 46.7%) !default; // #777
+$gray-lighter:           lighten($gray-base, 93.5%) !default; // #eee
+
+$brand-primary:         darken(#428bca, 6.5%) !default; // #337ab7
+$brand-success:         #5cb85c !default;
+$brand-info:            #5bc0de !default;
+$brand-warning:         #f0ad4e !default;
+$brand-danger:          #d9534f !default;
+
+// Tables
+$thead-background: #6e7277;
\ No newline at end of file
diff --git a/views/style/sass/lib/breadcrumb.scss b/views/style/sass/lib/breadcrumb.scss
new file mode 100644
index 0000000..12bc437
--- /dev/null
+++ b/views/style/sass/lib/breadcrumb.scss
@@ -0,0 +1,4 @@
+
+.breadcrumb li a {
+  font-weight:bold;
+}
\ No newline at end of file
diff --git a/views/style/sass/lib/data_table.scss b/views/style/sass/lib/data_table.scss
new file mode 100644
index 0000000..a572620
--- /dev/null
+++ b/views/style/sass/lib/data_table.scss
@@ -0,0 +1,24 @@
+table.dataTable thead{
+  th div.DataTables_sort_wrapper{
+    font-weight: normal !important;
+  }
+  tr {
+    background-color: $thead-background;
+
+    th.ui-state-default {
+      background: transparent !important;
+      color: #fff !important;
+    }
+  }
+}
+
+table.dataTable tr.odd,
+table.dataTable tr.odd td.sorting_1{
+  background-color: $gray-lighter !important;
+}
+table.dataTable tr.even td.sorting_1{
+  background-color: #fff;
+}
+table.dataTable thead th div.DataTables_sort_wrapper {
+  font-weight: bold;
+}
\ No newline at end of file
diff --git a/views/style/sass/lib/footer.scss b/views/style/sass/lib/footer.scss
new file mode 100644
index 0000000..565c356
--- /dev/null
+++ b/views/style/sass/lib/footer.scss
@@ -0,0 +1,24 @@
+/************************* FOOTER *************************/
+
+.footer{
+  z-index: 99;
+  position: fixed;
+}
+
+/* FIXME */
+@media(max-width:768px) {
+  .footer{
+    display: none;
+  }
+
+  #page-content-wrapper{
+    padding-bottom: 60px;
+  }
+}
+
+.footer .content .statusMsg {
+  float: right;
+  padding: 15px 20px 0 0;
+  display: block;
+}
+/************************* END FOOTER *************************/
\ No newline at end of file
diff --git a/views/style/sass/lib/form.scss b/views/style/sass/lib/form.scss
new file mode 100644
index 0000000..e8b74df
--- /dev/null
+++ b/views/style/sass/lib/form.scss
@@ -0,0 +1,4 @@
+.form-control {
+    width: auto;
+    min-width: 100%;
+}
\ No newline at end of file
diff --git a/views/style/sass/lib/header.scss b/views/style/sass/lib/header.scss
new file mode 100644
index 0000000..e219316
--- /dev/null
+++ b/views/style/sass/lib/header.scss
@@ -0,0 +1,31 @@
+/* ************************* HEADER STYLE ************************* */
+
+.header{
+  background-color: #ffffff !important;
+  border-bottom: 3px solid #C5CCD4;
+  margin-bottom: 14px;
+  height: 85px;
+
+  .logo{
+    max-height: 80px;
+  }
+
+  a {
+    font-weight: bold;
+  }
+
+  #user-tools {
+    padding: 12px 20px 0px 0px;
+    float: right;
+    margin-top: -5px;
+
+    // hiding links on mobile
+    @media (max-width: $screen-sm-max) {
+      .user-links *:not(:last-child){
+        display: none;
+      }
+    }
+  }
+}
+
+/************************* END HEADER *************************/
diff --git a/views/style/sass/lib/login.scss b/views/style/sass/lib/login.scss
new file mode 100644
index 0000000..ec79de2
--- /dev/null
+++ b/views/style/sass/lib/login.scss
@@ -0,0 +1,74 @@
+body.login img.logo{
+   width: 250px;
+   display: block;
+   margin: 20px auto;
+   padding-top: 20px;
+}
+.login {
+  background-image: url('bg.jpg');
+  background-size: cover;
+  background-position: center; 
+  background-repeat: no-repeat;
+}
+
+.login #content-main {
+  float: none;
+    height: 330px;
+    margin: 100px auto 0;
+    width: 265px;
+}
+.login{
+  #content-main {
+    background: rgba(255,255,255,0.82);
+  }
+
+  #content-main form input[type=text],
+  #content-main form input[type=password],
+  .requestDialog.ui-widget input{
+    background-color: rgb(250, 255, 189);
+  }
+  
+  /*#forgot_pwd{
+    font-size: 11px;
+    font-style: normal;
+    text-decoration: none;
+  }
+  
+  #create_acct{
+    font-size: 11px;
+    font-style: normal;
+    text-decoration: none;
+    padding-left: 45px;
+  }*/
+
+  .row + .row {
+    margin-top: 10px;
+  }
+
+  #content-main form {
+    margin: 5px 15px 0;
+  }
+
+  .btn-primary {
+    @include button-variant($btn-primary-color, $btn-primary-bg, $btn-primary-border);
+    background: $btn-primary-bg;
+  }
+
+  .forgotLink {
+    width: 45%;
+    text-align: left;
+    float: left;
+  }
+
+  #request-account-form{
+    display:none;
+  }
+
+  #requestAccountLink {
+    margin-top: 10px;
+    cursor: pointer;
+    color: $brand-primary;
+    text-decoration: underline;
+  }
+}
+
diff --git a/views/style/sass/lib/logout.scss b/views/style/sass/lib/logout.scss
new file mode 100644
index 0000000..0d2a5fb
--- /dev/null
+++ b/views/style/sass/lib/logout.scss
@@ -0,0 +1,47 @@
+body.logout img.logo{
+   width: 250px;
+   display: block;
+   margin: 20px auto;
+   padding-top: 20px;
+}
+
+h1.logouth1tag{
+  text-align: center;
+}
+
+.logout #content-main {
+  float: none;
+
+    width: 300px;
+  overflow-x: hidden;
+
+}
+.logout{
+
+  background: rgba(255,255,255,0.82);
+  float: none;
+  height: 330px;
+  margin: 100px auto 0;
+  width: 316px;
+  overflow-x: hidden;
+  overflow-y: hidden;
+  padding: 10px 0px 0px 10px;
+
+  .requestDialog.ui-widget input{
+    background-color: rgb(250, 255, 189);
+  }
+  .row + .row {
+    margin-top: 10px;
+  }
+
+  .btn-primary {
+    @include button-variant($btn-primary-color, $btn-primary-bg, $btn-primary-border);
+    background: $btn-primary-bg;
+  }
+  p.logoutptag {
+    margin: 20px 10px 20px;
+    font-size: 16px;
+    text-align: center;
+  }
+}
+
diff --git a/views/style/sass/lib/nav.scss b/views/style/sass/lib/nav.scss
new file mode 100644
index 0000000..7c011cf
--- /dev/null
+++ b/views/style/sass/lib/nav.scss
@@ -0,0 +1,81 @@
+/************************* NAV *************************/
+
+#sidebar-wrapper {
+  -webkit-box-shadow: 3px 0px 5px 0px rgba(50, 50, 50, 0.75);
+  -moz-box-shadow:    3px 0px 5px 0px rgba(50, 50, 50, 0.75);
+  box-shadow:         3px 0px 5px 0px rgba(50, 50, 50, 0.75);
+
+  .logo{
+    max-width: 100%;
+  }
+
+  a {
+    font-weight: bold;
+  }
+
+  // ICONS
+  .icon-app {
+    background-image: url("opencloudApp.png");
+  }
+  .icon-home {
+    /*  Going with darker standard color nav -- so using over png's background-image: url("Home.png"); */
+    background-image: url("Home.png");
+  }
+  .icon-deployment{
+    background-image: url("Deployments.png");
+  }
+  .icon-site{
+    background-image: url("Sites.png");
+  }
+  .icon-slice{
+    background-image: url("Slices.png");
+  }
+  .icon-user{
+    background-image: url("Users.png");
+  }
+  .icon-reservation{
+    background-image: url("Reservations.png");
+  }
+  .icon-cog{
+    background-image: url("Services.png");
+  }
+
+  // ACTIVE ICONS
+  li.active a,
+  li.focus a {
+    .icon-home{
+      background-image: url("Home_over.png");
+    }
+    .icon-deployment{
+      background-image: url("Deployments_over.png");
+    }
+    .icon-site{
+      background-image: url("Sites_over.png");
+    }
+    .icon-slice{
+      background-image: url("Slices_over.png");
+    }
+    .icon-user{
+      background-image: url("Users_over.png");
+    }
+    .icon-reservation{
+      background-image: url("Reservations_over.png");
+    }
+    .icon-cog{
+      background-image: url("Services_over.png");
+    }
+  }
+
+  [class^="icon-"]{
+    background-position: left center;
+    width:22px;
+    height:22px;
+    display: inline-block;
+    margin-right: 10px;
+    position: relative;
+    top: 5px;
+  }
+
+}
+
+/************************* END NAV *************************/
\ No newline at end of file
diff --git a/views/style/sass/lib/tabs.scss b/views/style/sass/lib/tabs.scss
new file mode 100644
index 0000000..5ed0640
--- /dev/null
+++ b/views/style/sass/lib/tabs.scss
@@ -0,0 +1,27 @@
+.nav-tabs-suit li.active a,
+.nav-tabs-suit li.active a:hover,
+.nav-tabs-suit li a:hover,
+.nav-tabs-suit > li.active > a:focus {
+  background-color: $brand-primary;
+  color: #fff;
+  outline: none;
+}
+
+.nav-tabs>li {
+  margin-bottom: 0px;
+}
+
+.nav-tabs-suit li a{
+  letter-spacing: 1px;
+}
+
+#suit_form_tabs {
+  border-bottom-width: 5px !important;
+  border-bottom-style: solid;
+  border-bottom-color: $brand-primary;
+}
+
+.ui-widget-header {
+  background: none !important;
+  border: none !important;
+}
\ No newline at end of file
diff --git a/views/style/sass/xos.scss b/views/style/sass/xos.scss
new file mode 100644
index 0000000..335101f
--- /dev/null
+++ b/views/style/sass/xos.scss
@@ -0,0 +1,777 @@
+@import './lib/_variables';
+@import "./bootstrap/_bootstrap";
+@import "lib/header";
+@import "lib/nav";
+@import "lib/footer";
+@import "lib/data_table";
+@import "lib/tabs";
+@import "lib/login";
+@import 'lib/breadcrumb';
+@import 'lib/form';
+@import "lib/logout";
+/************************
+colors:
+    tab - active/focus color
+    background-color: #105E9E !important;
+
+ONLab darker blue select :: background-color: #004775;
+#0170BB
+    left-nav
+    background-color: #448CCA;
+    background-color // normal: #B4CADF
+91BFE4
+
+*************************/
+
+html, body, body.login {
+  height: 100%;
+  min-height: 100%;
+  margin: 0;
+}
+
+body{
+  max-width: 100%;
+  overflow-x: hidden;
+}
+
+#wrap {
+  height: 100%;
+  min-height: 100%;
+  padding-bottom: 60px;
+}
+
+/* ************************* SIDENAV TOGGLE ************************* */
+
+#wrapper {
+    padding-left: 0;
+    transition: all 0.5s ease;
+    min-height: 100%;
+    height: 100%;
+}
+
+#wrapper.toggled {
+    padding-left: 250px;
+}
+
+#sidebar-wrapper {
+  z-index: 99;
+  position: fixed;
+  left: 250px;
+  width: 0;
+  height: 100%;
+  margin-left: -250px;
+  overflow-y: auto;
+  transition: all 0.5s ease;
+  background: white;
+}
+
+#wrapper.toggled #sidebar-wrapper {
+  width: 250px;
+  padding: 10px;
+}
+
+#page-content-wrapper {
+  width: 100%;
+  position: absolute;
+  padding: 15px;
+  min-height: 100%;
+  height: 100%;
+  .container-fluid, 
+  .content-wrapper, 
+  .content-wrapper .col-lg-12, 
+  .suit-columns,
+  #content {
+    min-height: 100%;
+    height: 100%;
+  }
+
+  #content {
+    padding-left:  ($grid-gutter-width / 2);
+    padding-right: ($grid-gutter-width / 2);
+  }
+
+  #content-main {
+    padding-bottom: 60px;
+  }
+}
+
+
+.ui-tabs-panel {
+    min-height: 700px;
+}
+
+#wrapper.toggled #page-content-wrapper {
+    position: absolute;
+    margin-right: -250px;
+}
+
+@media(min-width:768px) {
+    #wrapper {
+        padding-left: 250px;
+    }
+
+    #wrapper.toggled {
+        padding-left: 0;
+    }
+
+    #sidebar-wrapper {
+      width: 250px;
+      padding: 10px;
+    }
+
+    #wrapper.toggled #sidebar-wrapper {
+        width: 0;
+    }
+
+    #page-content-wrapper {
+        padding: 20px;
+        position: relative;
+    }
+
+    #wrapper.toggled #page-content-wrapper {
+        position: relative;
+        margin-right: 0;
+    }
+}
+
+.navbar-toggle{
+  border: 1px solid #08C;
+}
+
+.navbar-toggle .icon-bar{
+  background: #08C;
+}
+/* ************************* END SIDENAV TOGGLE ************************* */
+
+/************************* FORM TWEAKS *************************/
+@media (min-width: $screen-md){
+    .form-column.col-lg-4 {
+        width: 66.66666667%;
+    }
+}
+/************************* FORM TWEAKS *************************/
+
+/*   CSS for jquery Tabs */
+
+
+
+.alignCenter {
+    text-align: center !important;
+    align: center !important;
+}
+
+.ui-widget-overlay {
+    background: black !important;
+}
+.ui-corner-all {
+border-bottom-left-radius: 0px !important;
+border-bottom-right-radius: 0px !important;
+}
+
+#openCloudTopPage {
+   margin-top: -25px;
+   margin-right: -90;
+   float: right;
+}
+#minDashboard {
+  /*min-width:625px; */
+  display:inline;
+  float: right;
+  border: 2px darkGrey;
+}
+
+.save-box {
+  background-color: #ffffff;
+  margin: 2px;
+}
+.save-box .btn-info {
+  font-size: 14px;
+  padding: 10px 20px 10px 20px;
+}
+
+.required:after {
+  color: red !important;
+  font-size: 18px;
+}
+/*.btn-success {color:black}*/
+#suit-center {
+padding: 20px;
+width: 100%;
+/*min-width:650px;*/
+}
+.inner-two-columns .inner-center-column .tab-content {
+overflow-x: auto;
+margin-bottom: 15px;
+/*min-width: auto;*/
+width:100%;
+}
+/*.inner-two-columns .inner-center-column {
+  margin-right: 200px;
+  background-color: rgb(158, 163, 159);
+}*/
+label {
+display: block;
+font-weight: bold;
+margin-bottom: 5px;
+}
+
+/*For changing background color of suit center*/
+#suit-center {
+background-color: #ffffff;
+}
+
+/** Leave room for scroll bar now that contents can be appropriately scrolled **/
+.form-horizontal .inline-group .add-row {
+    margin: -1px -1px 15px 0px;
+}
+
+/** Setting overflow and 1kpx to deal with inlines/forms overlapping on 
+    browser resizes **/
+#content-main {
+    overflow-x:auto;
+    /*min-width: 1000px;*/
+}
+
+.tab-content tab-content-main {
+    overflow-x: auto !important;
+}
+
+#wrap{
+background:none;
+}
+
+.noclearfix {
+    display:block; clear:left; width:0px; height:0px;
+}
+
+body{
+background-color:#ffffff;
+}
+
+.suit-column{
+background-color:#ffffff;
+}
+
+
+
+.nav-tabs > .active > a, .nav-tabs > .active > a:hover, .nav-tabs > .active > a:focus {
+	/*background-color: #448CCA;*/
+	background-color: #105E9E;
+	color: #FFF;
+	border: none;
+}
+
+/*Added by Beena for adding the three components in dashboard*/
+.breadcrumb{
+	display:inline-block;
+	background-color: #fff;
+
+}
+
+.nodetextbox{
+	/*background-color: #ededed;*/
+	line-height: 25px;
+	width: 150px; 
+	text-align: center;
+	font-weight: bold;
+	margin-left:0px;
+	display:inline-block;
+	border:none;
+	font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
+	font-size: 8px;
+}
+
+.nodelabel{
+width: 20px;
+display: inline-block;
+border-radius: 0px;
+border:1px solid #000;
+/*line-height: 23px;*/
+text-align: center;
+font-weight: normal;
+}
+
+#user-tools {
+  font-weight: bold;
+}
+.header-content .header-column {
+	display: none;
+}
+.header .input-icon {
+    background-image: url("Search.png");
+    background-repeat: no-repeat;
+background-position:left center;
+opacity:1;
+    background-size: 100%;
+    vertical-align:middle;
+	margin-right: -30px;
+    /*margin-top: 5px;*/
+    position: relative;
+    height: 22px;
+    width: 22px;
+}
+
+.header .icon-search {
+	/*background-image: url("search.png") !important;
+    background-repeat: no-repeat !important;
+    background-size: 120% auto !important;
+    background-position: 0;*/
+}
+
+#dashboardHPC {
+    padding-bottom: 10px;
+}
+.summary-attr {
+    padding-right: 20px;
+}
+.summary-attr-util {
+    padding-right: 20px;
+    color: green;
+}
+.SiteDetail {
+color: darkBlue;
+    font-size: 1.5em;
+}
+#addInstances {
+ color: green;
+text-decoration: underline;
+    padding-right: 20px;
+}
+#remInstances {
+ color: red;
+ text-decoration: underline;
+}
+#map-us {
+    padding-top: 10px;
+    width: 700px;
+    height: 400px;
+}
+
+.minidashbutton {
+	-moz-box-shadow:inset 0px 1px 0px 0px #ffffff;
+	-webkit-box-shadow:inset 0px 1px 0px 0px #ffffff;
+	box-shadow:inset 0px 1px 0px 0px #ffffff;
+	background:-webkit-gradient(linear, left top, left bottom, color-stop(0.05, #ffffff), color-stop(1, #f6f6f6));
+	background:-moz-linear-gradient(top, #ffffff 5%, #f6f6f6 100%);
+	background:-webkit-linear-gradient(top, #ffffff 5%, #f6f6f6 100%);
+	background:-o-linear-gradient(top, #ffffff 5%, #f6f6f6 100%);
+	background:-ms-linear-gradient(top, #ffffff 5%, #f6f6f6 100%);
+	background:linear-gradient(to bottom, #ffffff 5%, #f6f6f6 100%);
+	filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f6f6f6',GradientType=0);
+	background-color:#ffffff;
+	-moz-border-radius:6px;
+	-webkit-border-radius:6px;
+	border-radius:6px;
+	border:1px solid #dcdcdc;
+	display:inline-block;
+	cursor:pointer;
+	color:#666666;
+	font-family:arial;
+	font-size:15px;
+	font-weight:bold;
+	padding:6px 24px;
+	text-decoration:none;
+	text-shadow:0px 1px 0px #ffffff;
+}
+.minidashbutton:hover {
+	background:-webkit-gradient(linear, left top, left bottom, color-stop(0.05, #f6f6f6), color-stop(1, #ffffff));
+	background:-moz-linear-gradient(top, #f6f6f6 5%, #ffffff 100%);
+	background:-webkit-linear-gradient(top, #f6f6f6 5%, #ffffff 100%);
+	background:-o-linear-gradient(top, #f6f6f6 5%, #ffffff 100%);
+	background:-ms-linear-gradient(top, #f6f6f6 5%, #ffffff 100%);
+	background:linear-gradient(to bottom, #f6f6f6 5%, #ffffff 100%);
+	filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f6f6f6', endColorstr='#ffffff',GradientType=0);
+	background-color:#f6f6f6;
+}
+
+.newMiniDashboard {
+    border: 1px solid green;
+    width: auto;
+}
+
+.endDashPair {
+    clear: left;
+}
+.miniDashPair {
+    float: left;
+    width: auto;
+    margin-left: 20px;
+}
+
+.miniDashPair label {
+ text-align: center;
+}
+/* Charts CSS */
+p.numeral
+{
+	font-size:32pt;
+	color:#ffffff;
+	opacity: 0.7;
+	font-family:Helvetica Neue;
+	font-weight:100;
+	text-align:center;
+	line-height:75%;
+}
+
+.helper-text
+{
+	border: 1px solid #fff;
+	padding: 7px;
+	border-radius: 18px;
+	font-size:13pt;
+	color:#ffffff;
+	opacity: 0.7;
+	font-family:Helvetica Neue;
+	font-weight:200;
+	text-align:center;
+	line-height:100%;
+}
+p.osobject
+{
+	font-size:12pt;
+	color:#ffffff;
+	opacity: 0.7;
+	font-family:Helvetica Neue;
+	font-weight:200;
+	text-align:center;
+	line-height:100%;
+}
+
+p.heading
+{
+	font-size:20px;
+        letter-spacing: 1px;
+	color: black;
+	font-family:Arial;
+	font-weight:bold;
+	text-align:center;
+}
+
+/*p.heading
+{
+	font-size:32pt;
+	color:#ffffff;
+	opacity: 0.7;
+	font-family:Helvetica Neue;
+	font-weight:200;
+	text-align:center;
+}*/
+
+div.graph 
+{
+	height:340px;
+}
+
+div.numeral 
+{
+	height:120px;
+}
+
+div.heading 
+{
+	height:10px;
+}
+
+div.padding 
+{
+	height:20px;
+}
+
+div.chartContainer
+{
+	/*background-image:url('chartsBg.jpg');*/
+	width:527px;
+	height:400px;
+	border:1px;
+}
+
+/* D3 */
+
+.axis path,
+.axis line {
+  fill: none;
+  stroke: #ffffff;
+  opacity: 0.7;
+  shape-rendering: crispEdges;
+}
+
+
+.x.axis path {
+  display: none;
+}
+
+.x.axis text {
+  fill: white;
+  opacity: 0.5;
+}
+
+.y.axis text {
+  opacity: 0.5;
+  fill: white;
+}
+
+.y.axis text.legend {
+  opacity: 1.0;
+  fill: white;
+  font-size:8pt;
+}
+
+.line {
+  fill: none;
+  stroke: white;
+  stroke-width: 3px;
+  opacity: 0.6;
+}
+
+
+/******  Added in so that we can have a loader show as charts get ready to render ***/
+.loading {
+    //background-color: orange;
+    background-image: url(spinner.gif) no-repeat center middle;
+    text-align: center;
+    font-size: 20px;
+    height: 100%;
+/*    width: auto;*/
+    float: left;
+    padding: 10px;
+}
+/* Charts CSS */
+
+#tabs-4 {
+    margin: 40px;
+    font-size: 24px;
+    font-weight: bold;
+}
+
+.tenant-row{
+   padding-bottom: 0.7%;
+}
+
+/***********TENANT VIEW*************/
+
+#image-dropdown,#slice-image-value,#adv-slice-image-value{
+ margin-left: 5%;
+}
+
+
+#adv-slice-image-value{
+margin-right: 0.5%;
+}
+
+#adv-network-value {
+margin-right: 0.3%;
+}
+
+#network-dropdown,#adv-network-dropdown,#adv-network-value{
+ margin-left: 3.7%;
+}
+
+#service-level-dropdown,#service-level-value,#adv-service-level-dropdown,#adv-service-level-value{
+ margin-left: 0.2% !important;
+}
+
+#slice-name-value,#adv-slice-name-value{
+   margin-left: 2%;
+}
+#adv-dataset-dropdown{
+margin-left: 3.7%;
+}
+#advanced-tenant,#basic-tenant,#instance-btn,#save-btn{
+  float:right;
+}
+ #delete-slice-btn,#download-details,#add-user-btn{
+	margin-left:1%;
+}
+
+#instance-btn,#save-btn,#create-slice-btn,#delete-slice-btn,#add-user-btn,#download-details{
+  margin-top:1%;
+}
+
+.tenantDialog.ui-widget input{
+        border-radius: 0px !important;
+	height: 12px !important;
+	width: 180px !important;
+	margin-right: 10% !important;
+	float: right;
+}
+
+.tenantDialog .ui-dialog-buttonset .ui-button{
+border-radius: 0 !important;
+background-color: grey !important;
+font-weight: bold !important;
+font-size: 0.9em !important;
+}
+
+.tenantDialog .ui-dialog-titlebar{
+border-radius: 0 !important;
+background-color: grey !important;
+}
+
+.create-slice-row{
+	margin-bottom: 4%;
+	clear: both;
+	height: 25px;
+}
+
+.create-slice-row label, .tenantDialog label{
+   margin-right:1%;
+   float:left;
+}
+
+.create-slice-row select{
+   height:24px;
+   width: 196px;
+   font-size: 0.9em !important;
+}
+
+.tenant-create-slice{
+	float:right;
+	margin-right: 10% !important;
+}
+
+#delete-slice{
+float: right;
+}
+
+#tooltip,#adv-tooltip,#basic-tooltip{
+font-size:0.7em;
+color:red;
+display:none;
+}
+
+#tenantSliceDataWrapper {
+	padding: 1% 0;
+}
+
+#advancedTenantSliceDataWrapper .help-inline{
+	font-size: 11px;
+	color: #999;
+	padding-bottom: 1%;
+}
+
+.create-slice-row label{
+	clear:both;
+	margin-right: 1%;
+}
+
+#advNumOfInstances{
+        margin-right: 1% !important;
+}
+
+#private-vol-checkbox{
+margin: 0 0 1% 1%;
+}
+
+.public-key-warning{
+text-align: center;
+display:none;
+}
+
+#private-vol{
+margin-right: 15% !important;
+}
+.customize_row {
+  display: table;
+}
+.customize_column {
+  display: table-cell;
+  padding: 10px;
+}
+
+.request-form-row{
+padding:1% 8%;
+}
+
+.requestDialog{
+background-color: white;
+border-radius: 8px;
+width: 30% !important;
+height: 40% !important;
+margin-top: -16%;
+top: -103.703125px !important;
+}
+
+.request-form-row label{
+	float: left;
+}
+
+
+.requestDialog .ui-dialog-buttonset .ui-button{
+border-radius: 0 !important;
+background-color: grey !important;
+font-weight: bold !important;
+font-size: 0.9em !important;
+}
+
+.requestDialog .ui-dialog-titlebar-close{
+float:right;
+}
+
+#request-signup{
+height: 40px !important;
+margin: 0 14%;
+float: left;
+background-color: #448CCA;
+background-image: none;
+width: 70% !important;
+}
+
+.requestDialog .ui-dialog-titlebar{
+border-radius: 0 !important;
+height: 25px;
+padding-top: 2%;
+}
+
+.requestDialog #ui-id-1{
+padding-left: 28%;
+font-size: medium;
+}
+
+#request-site-name{
+	width: 98%;
+}
+
+/* SUIT CHANGES */
+
+.form-buttons {
+    margin-top: 20px;
+    padding: 10px;
+    border-top: 1px solid #cccccc;
+}
+
+.form-horizontal .selector .selector-chooser li .selector-remove,
+.form-horizontal .selector .selector-chooser li .selector-remove:hover{
+  @include button-size($padding-base-vertical, $padding-base-horizontal, $font-size-base, $line-height-base, $btn-border-radius-base);
+  @include button-variant($btn-danger-color, $btn-danger-bg, $btn-danger-border);
+}
+
+.form-horizontal .selector .selector-chooser li .selector-add,
+.form-horizontal .selector .selector-chooser li .selector-add:hover{
+  margin-bottom: $form-group-margin-bottom;
+  @include button-size($padding-base-vertical, $padding-base-horizontal, $font-size-base, $line-height-base, $btn-border-radius-base);
+  @include button-variant($btn-success-color, $btn-success-bg, $btn-success-border);
+}
+
+/* MODAL */
+.ui-dialog{
+  z-index: 4000 !important;
+}
+
+button.ui-dialog-titlebar-close{
+  font-family: 'Glyphicons Halflings' !important;
+  display: inline-block;
+}
+
+button.ui-dialog-titlebar-close:after {
+    content: "\e014";
+}
+/* VCPe ADMIN FIX
+form#vcpeservice_form ul li {
+    display: inline-block;
+    background: red;
+    margin-top: 10px;
+    width: auto;
+    padding: 10px;
+    border-radius: 5px;
+}
+*/
\ No newline at end of file
diff --git a/xos/README.md b/xos/README.md
new file mode 100644
index 0000000..daec000
--- /dev/null
+++ b/xos/README.md
@@ -0,0 +1,21 @@
+## XOS Source Tree
+
+This is the main directory for XOS. Sub-directories include:
+
+* configurations -- collection of canned configurations
+* core -- core model definitions
+* generators -- tools to generate auxiliary structures from data model
+* model_policies -- invariants on the data model
+* nginx, uwsgi -- related to web server that runs XOS
+* openstack -- client-side interaction with OpenStack (to be depreciated)
+* services -- model definitions for a set of services
+* synchronizers -- collection of synchronizers
+* templates -- Django GUI templates
+* test -- system-wide tests to be collected here
+* tosca -- tosca modeling layer on top of RESTful API
+* tools -- assorted tools and scripts
+* xos -- common source code for all Django applications
+* xos_configuration -- top-level XOS configuration parameters
+
+Of these, configuration, services, and synchronizers are most
+relevant to developers.
diff --git a/xos/__init__.py b/xos/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xos/__init__.py
diff --git a/xos/api/README.md b/xos/api/README.md
new file mode 100644
index 0000000..eb2bd28
--- /dev/null
+++ b/xos/api/README.md
@@ -0,0 +1,24 @@
+## XOS REST API
+
+Source for the XOS REST API lives in directory `xos/api`. An importer
+tool, `import_methods.py`, auto-generates the REST API by searching
+this directory (and sub-directories) for valid API methods. These
+methods are descendents of the Django View class. This should include
+django_rest_framework based Views and Viewsets.
+
+We establish a convention for locating API methods within the XOS
+hierarchy. The root of the api is automatically `/api/`. Under that
+are the following paths:
+
+* `/api/service` ... API endpoints that are service-wide
+* `/api/tenant` ... API endpoints that are relative to a tenant within a service
+
+For example, `/api/tenant/cord/subscriber/` contains the Subscriber
+API for the CORD service.
+
+The API importer automatically constructs REST paths based on
+where files are placed within the directory hierarchy. For example,
+the files in `xos/api/tenant/cord/` will automatically appear at the
+API endpoint `http://server_name/api/tenant/cord/`.  The directory
+`examples` contains examples that demonstrate using the API from the
+Linux command line.
diff --git a/xos/api/__init__.py b/xos/api/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/xos/api/__init__.py
@@ -0,0 +1 @@
+
diff --git a/xos/api/examples/README.md b/xos/api/examples/README.md
new file mode 100644
index 0000000..0ec7b73
--- /dev/null
+++ b/xos/api/examples/README.md
@@ -0,0 +1,15 @@
+## XOS REST API Examples
+
+This directory contains examples that demonstrate using the XOS REST API using the `curl` command-line tool.
+
+To get started, edit `config.sh` so that it points to a valid XOS server.
+
+We recommend running the following examples in order:
+
+ * `add_subscriber.sh` ... add a cord subscriber using account number 1238
+ * `update_subscriber.sh` ... update the subscriber's upstream_bandwidth feature
+ * `add_volt_to_subscriber.sh` ... add a vOLT to the subscriber with s-tag 33 and c-tag 133
+ * `get_subscriber.sh` ... get an entire subscriber object
+ * `get_subscriber_features.sh` ... get the features of a subscriber
+ * `delete_volt_from_subscriber.sh` ... remove the vOLT from the subscriber
+ * `delete_subscriber.sh` ... delete the subscriber that has account number 1238
diff --git a/xos/api/examples/config.sh b/xos/api/examples/config.sh
new file mode 100644
index 0000000..79baa5f
--- /dev/null
+++ b/xos/api/examples/config.sh
@@ -0,0 +1,4 @@
+#HOST=apt187.apt.emulab.net:9999
+HOST=clnode076.clemson.cloudlab.us:9999
+
+AUTH=padmin@vicci.org:letmein
diff --git a/xos/api/examples/cord/add_device_to_subscriber.sh b/xos/api/examples/cord/add_device_to_subscriber.sh
new file mode 100755
index 0000000..260b652
--- /dev/null
+++ b/xos/api/examples/cord/add_device_to_subscriber.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+source ./config.sh
+source ./util.sh
+
+ACCOUNT_NUM=1238
+MAC="19:28:37:46:55"
+
+SUBSCRIBER_ID=$(lookup_account_num $ACCOUNT_NUM)
+if [[ $? != 0 ]]; then
+    exit -1
+fi
+
+DATA=$(cat <<EOF
+{"mac": "$MAC"}
+EOF
+)
+
+curl -H "Accept: application/json; indent=4" -H "Content-Type: application/json" -u $AUTH -X POST -d "$DATA" $HOST/api/tenant/cord/subscriber/$SUBSCRIBER_ID/devices/
diff --git a/xos/api/examples/cord/add_subscriber.sh b/xos/api/examples/cord/add_subscriber.sh
new file mode 100755
index 0000000..498a7c6
--- /dev/null
+++ b/xos/api/examples/cord/add_subscriber.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+source ./config.sh
+
+ACCOUNT_NUM=1238
+
+DATA=$(cat <<EOF
+{"identity": {"account_num": "$ACCOUNT_NUM", "name": "test-subscriber"},
+ "features": {"uplink_speed": 2000000000}}
+EOF
+)
+
+curl -H "Accept: application/json; indent=4" -H "Content-Type: application/json" -u $AUTH -X POST -d "$DATA" $HOST/api/tenant/cord/subscriber/   
diff --git a/xos/api/examples/cord/add_volt_to_subscriber.sh b/xos/api/examples/cord/add_volt_to_subscriber.sh
new file mode 100755
index 0000000..377ad65
--- /dev/null
+++ b/xos/api/examples/cord/add_volt_to_subscriber.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+source ./config.sh
+source ./util.sh
+
+ACCOUNT_NUM=1238
+S_TAG=34
+C_TAG=134
+
+SUBSCRIBER_ID=$(lookup_account_num $ACCOUNT_NUM)
+if [[ $? != 0 ]]; then
+    exit -1
+fi
+
+DATA=$(cat <<EOF
+{"s_tag": $S_TAG,
+ "c_tag": $C_TAG,
+ "subscriber": $SUBSCRIBER_ID}
+EOF
+)
+
+curl -H "Accept: application/json; indent=4" -H "Content-Type: application/json" -u $AUTH -X POST -d "$DATA" $HOST/api/tenant/cord/volt/
diff --git a/xos/api/examples/cord/all.sh b/xos/api/examples/cord/all.sh
new file mode 100644
index 0000000..88fce47
--- /dev/null
+++ b/xos/api/examples/cord/all.sh
@@ -0,0 +1,28 @@
+echo add_subscriber
+./add_subscriber.sh
+echo -e "\n update_subscriber"
+./update_subscriber.sh
+echo -e "\n add_volt_to_subscriber"
+./add_volt_to_subscriber.sh
+echo -e "\n get_subscriber"
+./get_subscriber.sh
+echo -e "\n delete_volt_from_subscriber"
+./delete_volt_from_subscriber.sh
+echo -e "\n add_device_to_subscriber"
+./add_device_to_subscriber.sh
+echo -e "\n set_subscriber_device_feature"
+./set_subscriber_device_feature.sh
+echo -e "\n set_subscriber_device_identity"
+./set_subscriber_device_identity.sh
+echo -e "\n get_subscriber_device_feature"
+./get_subscriber_device_feature.sh
+echo -e "\n get_subscriber_device_identity"
+./get_subscriber_device_identity.sh
+echo -e "\n get_subscriber"
+./get_subscriber.sh
+echo -e "\n list_subscriber_devices"
+./list_subscriber_devices.sh
+echo -e "\n delete_subscriber_device"
+./delete_subscriber_device.sh
+echo -e "\n delete_subscriber"
+./delete_subscriber.sh
diff --git a/xos/api/examples/cord/config.sh b/xos/api/examples/cord/config.sh
new file mode 100644
index 0000000..92d703c
--- /dev/null
+++ b/xos/api/examples/cord/config.sh
@@ -0,0 +1,2 @@
+# see config.sh in the parent directory
+source ../config.sh
diff --git a/xos/api/examples/cord/delete_subscriber.sh b/xos/api/examples/cord/delete_subscriber.sh
new file mode 100755
index 0000000..0b897f2
--- /dev/null
+++ b/xos/api/examples/cord/delete_subscriber.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+source ./config.sh
+source ./util.sh
+
+ACCOUNT_NUM=1238
+
+SUBSCRIBER_ID=$(lookup_account_num $ACCOUNT_NUM)
+if [[ $? != 0 ]]; then
+    exit -1
+fi
+
+curl -u $AUTH -X DELETE $HOST/api/tenant/cord/subscriber/$SUBSCRIBER_ID/
diff --git a/xos/api/examples/cord/delete_subscriber_device.sh b/xos/api/examples/cord/delete_subscriber_device.sh
new file mode 100755
index 0000000..13c357f
--- /dev/null
+++ b/xos/api/examples/cord/delete_subscriber_device.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+source ./config.sh
+source ./util.sh
+
+ACCOUNT_NUM=1238
+MAC="19:28:37:46:55"
+
+SUBSCRIBER_ID=$(lookup_account_num $ACCOUNT_NUM)
+if [[ $? != 0 ]]; then
+    exit -1
+fi
+
+curl -H "Accept: application/json; indent=4" -H "Content-Type: application/json" -u $AUTH -X DELETE $HOST/api/tenant/cord/subscriber/$SUBSCRIBER_ID/devices/$MAC/
diff --git a/xos/api/examples/cord/delete_volt_from_subscriber.sh b/xos/api/examples/cord/delete_volt_from_subscriber.sh
new file mode 100755
index 0000000..c3acd2e
--- /dev/null
+++ b/xos/api/examples/cord/delete_volt_from_subscriber.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+source ./config.sh
+source ./util.sh
+
+ACCOUNT_NUM=1238
+
+SUBSCRIBER_ID=$(lookup_account_num $ACCOUNT_NUM)
+if [[ $? != 0 ]]; then
+    exit -1
+fi
+
+VOLT_ID=$(lookup_subscriber_volt $SUBSCRIBER_ID)
+if [[ $? != 0 ]]; then
+    exit -1
+fi
+
+curl -u $AUTH -X DELETE $HOST/api/tenant/cord/volt/$VOLT_ID/
diff --git a/xos/api/examples/cord/get_subscriber.sh b/xos/api/examples/cord/get_subscriber.sh
new file mode 100755
index 0000000..d1c6c29
--- /dev/null
+++ b/xos/api/examples/cord/get_subscriber.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+source ./config.sh
+source ./util.sh
+
+ACCOUNT_NUM=1238
+
+SUBSCRIBER_ID=$(lookup_account_num $ACCOUNT_NUM)
+if [[ $? != 0 ]]; then
+    exit -1
+fi
+
+curl -H "Accept: application/json; indent=4" -u $AUTH -X GET $HOST/api/tenant/cord/subscriber/$SUBSCRIBER_ID/
diff --git a/xos/api/examples/cord/get_subscriber_device_feature.sh b/xos/api/examples/cord/get_subscriber_device_feature.sh
new file mode 100755
index 0000000..7c02c05
--- /dev/null
+++ b/xos/api/examples/cord/get_subscriber_device_feature.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+source ./config.sh
+source ./util.sh
+
+ACCOUNT_NUM=1238
+MAC="19:28:37:46:55"
+
+SUBSCRIBER_ID=$(lookup_account_num $ACCOUNT_NUM)
+if [[ $? != 0 ]]; then
+    exit -1
+fi
+
+curl -H "Accept: application/json; indent=4" -H "Content-Type: application/json" -u $AUTH -X GET $HOST/api/tenant/cord/subscriber/$SUBSCRIBER_ID/devices/$MAC/features/uplink_speed/
diff --git a/xos/api/examples/cord/get_subscriber_device_identity.sh b/xos/api/examples/cord/get_subscriber_device_identity.sh
new file mode 100755
index 0000000..e5cff59
--- /dev/null
+++ b/xos/api/examples/cord/get_subscriber_device_identity.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+source ./config.sh
+source ./util.sh
+
+ACCOUNT_NUM=1238
+MAC="19:28:37:46:55"
+
+SUBSCRIBER_ID=$(lookup_account_num $ACCOUNT_NUM)
+if [[ $? != 0 ]]; then
+    exit -1
+fi
+
+curl -H "Accept: application/json; indent=4" -H "Content-Type: application/json" -u $AUTH -X GET $HOST/api/tenant/cord/subscriber/$SUBSCRIBER_ID/devices/$MAC/identity/name/
diff --git a/xos/api/examples/cord/get_subscriber_features.sh b/xos/api/examples/cord/get_subscriber_features.sh
new file mode 100755
index 0000000..e50f2a7
--- /dev/null
+++ b/xos/api/examples/cord/get_subscriber_features.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+source ./config.sh
+source ./util.sh
+
+ACCOUNT_NUM=1238
+
+SUBSCRIBER_ID=$(lookup_account_num $ACCOUNT_NUM)
+if [[ $? != 0 ]]; then
+    exit -1
+fi
+
+curl -H "Accept: application/json; indent=4" -u $AUTH -X GET $HOST/api/tenant/cord/subscriber/$SUBSCRIBER_ID/features/
diff --git a/xos/api/examples/cord/set_subscriber_device_feature.sh b/xos/api/examples/cord/set_subscriber_device_feature.sh
new file mode 100755
index 0000000..73d84b0
--- /dev/null
+++ b/xos/api/examples/cord/set_subscriber_device_feature.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+source ./config.sh
+source ./util.sh
+
+ACCOUNT_NUM=1238
+MAC="19:28:37:46:55"
+
+SUBSCRIBER_ID=$(lookup_account_num $ACCOUNT_NUM)
+if [[ $? != 0 ]]; then
+    exit -1
+fi
+
+DATA=$(cat <<EOF
+{"uplink_speed": 111111}
+EOF
+)
+
+curl -H "Accept: application/json; indent=4" -H "Content-Type: application/json" -u $AUTH -X PUT -d "$DATA" $HOST/api/tenant/cord/subscriber/$SUBSCRIBER_ID/devices/$MAC/features/uplink_speed/
diff --git a/xos/api/examples/cord/set_subscriber_device_identity.sh b/xos/api/examples/cord/set_subscriber_device_identity.sh
new file mode 100755
index 0000000..faaeba1
--- /dev/null
+++ b/xos/api/examples/cord/set_subscriber_device_identity.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+source ./config.sh
+source ./util.sh
+
+ACCOUNT_NUM=1238
+MAC="19:28:37:46:55"
+
+SUBSCRIBER_ID=$(lookup_account_num $ACCOUNT_NUM)
+if [[ $? != 0 ]]; then
+    exit -1
+fi
+
+DATA=$(cat <<EOF
+{"name": "foo"}
+EOF
+)
+
+curl -H "Accept: application/json; indent=4" -H "Content-Type: application/json" -u $AUTH -X PUT -d "$DATA" $HOST/api/tenant/cord/subscriber/$SUBSCRIBER_ID/devices/$MAC/identity/name/
diff --git a/xos/api/examples/cord/update_subscriber.sh b/xos/api/examples/cord/update_subscriber.sh
new file mode 100755
index 0000000..9bbe501
--- /dev/null
+++ b/xos/api/examples/cord/update_subscriber.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+source ./config.sh
+source ./util.sh
+
+ACCOUNT_NUM=1238
+
+SUBSCRIBER_ID=$(lookup_account_num $ACCOUNT_NUM)
+if [[ $? != 0 ]]; then
+    exit -1
+fi
+
+DATA=$(cat <<EOF
+{"features": {"uplink_speed": 4000000000}}
+EOF
+)
+
+curl -H "Accept: application/json; indent=4" -H "Content-Type: application/json" -u $AUTH -X PUT -d "$DATA" $HOST/api/tenant/cord/subscriber/$SUBSCRIBER_ID/
diff --git a/xos/api/examples/cord/util.sh b/xos/api/examples/cord/util.sh
new file mode 100644
index 0000000..7b66903
--- /dev/null
+++ b/xos/api/examples/cord/util.sh
@@ -0,0 +1 @@
+source ../util.sh
diff --git a/xos/api/examples/exampleservice/add_exampletenant.sh b/xos/api/examples/exampleservice/add_exampletenant.sh
new file mode 100755
index 0000000..d9ab3e3
--- /dev/null
+++ b/xos/api/examples/exampleservice/add_exampletenant.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+source ./config.sh
+
+DATA=$(cat <<EOF
+{"tenant_message": "This is a test"}
+EOF
+)
+
+curl -H "Accept: application/json; indent=4" -H "Content-Type: application/json" -u $AUTH -X POST -d "$DATA" $HOST/api/tenant/exampletenant/   
diff --git a/xos/api/examples/exampleservice/config.sh b/xos/api/examples/exampleservice/config.sh
new file mode 100644
index 0000000..92d703c
--- /dev/null
+++ b/xos/api/examples/exampleservice/config.sh
@@ -0,0 +1,2 @@
+# see config.sh in the parent directory
+source ../config.sh
diff --git a/xos/api/examples/exampleservice/delete_exampletenant.sh b/xos/api/examples/exampleservice/delete_exampletenant.sh
new file mode 100755
index 0000000..6eaf8b7
--- /dev/null
+++ b/xos/api/examples/exampleservice/delete_exampletenant.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+source ./config.sh
+
+if [[ "$#" -ne 1 ]]; then
+    echo "Syntax: delete_exampletenant.sh <id>"
+    exit -1
+fi
+
+ID=$1
+
+curl -H "Accept: application/json; indent=4" -u $AUTH -X DELETE $HOST/api/tenant/exampletenant/$ID/
diff --git a/xos/api/examples/exampleservice/get_exampletenant_message.sh b/xos/api/examples/exampleservice/get_exampletenant_message.sh
new file mode 100755
index 0000000..96ce65c
--- /dev/null
+++ b/xos/api/examples/exampleservice/get_exampletenant_message.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+# this example illustrates using a custom REST API endpoint
+
+source ./config.sh
+
+if [[ "$#" -ne 1 ]]; then
+    echo "Syntax: get_exampletenant_message.sh <id>"
+    exit -1
+fi
+
+ID=$1
+
+curl -H "Accept: application/json; indent=4" -u $AUTH -X GET $HOST/api/tenant/exampletenant/$ID/message/
diff --git a/xos/api/examples/exampleservice/list_exampleservices.sh b/xos/api/examples/exampleservice/list_exampleservices.sh
new file mode 100755
index 0000000..e369dff
--- /dev/null
+++ b/xos/api/examples/exampleservice/list_exampleservices.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+source ./config.sh
+
+curl -H "Accept: application/json; indent=4" -u $AUTH -X GET $HOST/api/service/exampleservice/
diff --git a/xos/api/examples/exampleservice/list_exampletenants.sh b/xos/api/examples/exampleservice/list_exampletenants.sh
new file mode 100755
index 0000000..9e15968
--- /dev/null
+++ b/xos/api/examples/exampleservice/list_exampletenants.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+source ./config.sh
+
+curl -H "Accept: application/json; indent=4" -u $AUTH -X GET $HOST/api/tenant/exampletenant/   
diff --git a/xos/api/examples/exampleservice/put_exampletenant_message.sh b/xos/api/examples/exampleservice/put_exampletenant_message.sh
new file mode 100755
index 0000000..bf0810d
--- /dev/null
+++ b/xos/api/examples/exampleservice/put_exampletenant_message.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# this example illustrates using a custom REST API endpoint  
+
+source ./config.sh
+
+if [[ "$#" -ne 2 ]]; then
+    echo "Syntax: put_exampletenant_message.sh <id> <message>"
+    exit -1
+fi
+
+ID=$1
+NEW_MESSAGE=$2
+
+DATA=$(cat <<EOF
+{"tenant_message": "$NEW_MESSAGE"}
+EOF
+)
+
+curl -H "Accept: application/json; indent=4" -H "Content-Type: application/json" -u $AUTH -X PUT -d "$DATA" $HOST/api/tenant/exampletenant/$ID/message/
diff --git a/xos/api/examples/exampleservice/update_exampletenant.sh b/xos/api/examples/exampleservice/update_exampletenant.sh
new file mode 100755
index 0000000..7d5e9ce
--- /dev/null
+++ b/xos/api/examples/exampleservice/update_exampletenant.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+source ./config.sh
+
+if [[ "$#" -ne 2 ]]; then
+    echo "Syntax: delete_exampletenant.sh <id> <message>"
+    exit -1
+fi
+
+ID=$1
+NEW_MESSAGE=$2
+
+DATA=$(cat <<EOF
+{"tenant_message": "$NEW_MESSAGE"}
+EOF
+)
+
+curl -H "Accept: application/json; indent=4" -H "Content-Type: application/json" -u $AUTH -X PUT -d "$DATA" $HOST/api/tenant/exampletenant/$ID/
diff --git a/xos/api/examples/misc/add_slice.sh b/xos/api/examples/misc/add_slice.sh
new file mode 100755
index 0000000..b2d7adc
--- /dev/null
+++ b/xos/api/examples/misc/add_slice.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+source ./config.sh
+
+SITE_ID=1
+USER_ID=1
+
+DATA=$(cat <<EOF
+{"name": "mysite_test1",
+ "site": $SITE_ID,
+ "creator": $USER_ID
+}
+EOF
+)
+
+curl -H "Accept: application/json; indent=4" -H "Content-Type: application/json" -u $AUTH -X POST -d "$DATA" $HOST/xos/slices/?no_hyperlinks=1
diff --git a/xos/api/examples/misc/config.sh b/xos/api/examples/misc/config.sh
new file mode 100644
index 0000000..92d703c
--- /dev/null
+++ b/xos/api/examples/misc/config.sh
@@ -0,0 +1,2 @@
+# see config.sh in the parent directory
+source ../config.sh
diff --git a/xos/api/examples/misc/delete_slice.sh b/xos/api/examples/misc/delete_slice.sh
new file mode 100755
index 0000000..1113d4f
--- /dev/null
+++ b/xos/api/examples/misc/delete_slice.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+source ./config.sh
+source ./util.sh
+
+SLICE_NAME=mysite_test1
+
+SLICE_ID=$(lookup_slice_id $SLICE_NAME)
+if [[ $? != 0 ]]; then
+    exit -1
+fi
+
+curl -u $AUTH -X DELETE $HOST/xos/slices/$SLICE_ID/
diff --git a/xos/api/examples/misc/get_sshkeys.sh b/xos/api/examples/misc/get_sshkeys.sh
new file mode 100755
index 0000000..0ac14c0
--- /dev/null
+++ b/xos/api/examples/misc/get_sshkeys.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+source ./config.sh
+source ./util.sh
+
+curl -H "Accept: application/json; indent=4" -u $AUTH -X GET $HOST/api/utility/sshkeys/
diff --git a/xos/api/examples/misc/update_slice.sh b/xos/api/examples/misc/update_slice.sh
new file mode 100755
index 0000000..94e82cd
--- /dev/null
+++ b/xos/api/examples/misc/update_slice.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+source ./config.sh
+source ./util.sh
+
+SLICE_NAME=mysite_test1
+
+SLICE_ID=$(lookup_slice_id $SLICE_NAME)
+if [[ $? != 0 ]]; then
+    exit -1
+fi
+
+DATA=$(cat <<EOF
+{"description": "foo"}
+EOF
+)
+
+curl -H "Accept: application/json; indent=4" -H "Content-Type: application/json" -u $AUTH -X PATCH -d "$DATA" $HOST/xos/slices/$SLICE_ID/
diff --git a/xos/api/examples/misc/util.sh b/xos/api/examples/misc/util.sh
new file mode 100644
index 0000000..7b66903
--- /dev/null
+++ b/xos/api/examples/misc/util.sh
@@ -0,0 +1 @@
+source ../util.sh
diff --git a/xos/api/examples/util.sh b/xos/api/examples/util.sh
new file mode 100644
index 0000000..73cc039
--- /dev/null
+++ b/xos/api/examples/util.sh
@@ -0,0 +1,65 @@
+source ./config.sh
+
+function lookup_account_num {
+    ID=`curl -f -s -u $AUTH -X GET $HOST/api/tenant/cord/account_num_lookup/$1/`
+    if [[ $? != 0 ]]; then
+        echo "function lookup_account_num with arguments $1 failed" >&2
+        echo "See CURL output below:" >&2
+        curl -s -u $AUTH -X GET $HOST/api/tenant/cord/account_num_lookup/$1/ >&2
+        exit -1
+    fi
+    # echo "(mapped account_num $1 to id $ID)" >&2
+    echo $ID
+}
+
+function lookup_slice_id {
+    JSON=`curl -f -s -u $AUTH -X GET $HOST/xos/slices/?name=$1`
+    if [[ $? != 0 ]]; then
+        echo "function lookup_slice_id with arguments $1 failed" >&2
+        echo "See CURL output below:" >&2
+        curl -s -u $AUTH -X GET $HOST/xos/slices/?name=$1 >&2
+        exit -1
+    fi
+    ID=`echo $JSON | python -c "import json,sys; print json.load(sys.stdin)[0].get('id','')"`
+    #echo "(mapped slice_name to id $ID)" >&2
+    echo $ID
+}
+
+function lookup_subscriber_volt {
+    JSON=`curl -f -s -u $AUTH -X GET $HOST/api/tenant/cord/subscriber/$1/`
+    if [[ $? != 0 ]]; then
+        echo "function lookup_subscriber_volt failed to read subscriber with arg $1" >&2
+        echo "See CURL output below:" >&2
+        curl -s -u $AUTH -X GET $HOST/api/tenant/cord/account_num_lookup/$1/ >&2
+        exit -1
+    fi
+    ID=`echo $JSON | python -c "import json,sys; print json.load(sys.stdin)['related'].get('volt_id','')"`
+    if [[ $ID == "" ]]; then
+        echo "there is no volt for this subscriber" >&2
+        exit -1
+    fi
+
+    # echo "(found volt id %1)" >&2
+
+    echo $ID
+}
+
+function lookup_subscriber_vsg {
+    JSON=`curl -f -s -u $AUTH -X GET $HOST/api/tenant/cord/subscriber/$1/`
+    if [[ $? != 0 ]]; then
+        echo "function lookup_subscriber_vsg failed to read subscriber with arg $1" >&2
+        echo "See CURL output below:" >&2
+        curl -s -u $AUTH -X GET $HOST/api/tenant/cord/account_num_lookup/$1/ >&2
+        exit -1
+    fi
+    ID=`echo $JSON | python -c "import json,sys; print json.load(sys.stdin)['related'].get('vsg_id','')"`
+    if [[ $ID == "" ]]; then
+        echo "there is no vsg for this subscriber" >&2
+        exit -1
+    fi
+
+    # echo "(found vsg id %1)" >&2
+
+    echo $ID
+}
+
diff --git a/xos/api/examples/vtr/add_truckroll_for_subscriber.sh b/xos/api/examples/vtr/add_truckroll_for_subscriber.sh
new file mode 100755
index 0000000..3a3ec41
--- /dev/null
+++ b/xos/api/examples/vtr/add_truckroll_for_subscriber.sh
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+source ./config.sh
+source ./util.sh
+
+ACCOUNT_NUM=1238
+
+SUBSCRIBER_ID=$(lookup_account_num $ACCOUNT_NUM)
+if [[ $? != 0 ]]; then
+    exit -1
+fi
+
+VSG_ID=$(lookup_subscriber_vsg $SUBSCRIBER_ID)
+if [[ $? != 0 ]]; then
+    exit -1
+fi
+
+DATA=$(cat <<EOF
+{"target_id": $SUBSCRIBER_ID,
+ "scope": "container",
+ "test": "ping",
+ "argument": "8.8.8.8"}
+EOF
+)
+
+curl -H "Accept: application/json; indent=4" -H "Content-Type: application/json" -u $AUTH -X POST -d "$DATA" $HOST/api/tenant/truckroll/
diff --git a/xos/api/examples/vtr/config.sh b/xos/api/examples/vtr/config.sh
new file mode 100644
index 0000000..92d703c
--- /dev/null
+++ b/xos/api/examples/vtr/config.sh
@@ -0,0 +1,2 @@
+# see config.sh in the parent directory
+source ../config.sh
diff --git a/xos/api/examples/vtr/delete_truckroll.sh b/xos/api/examples/vtr/delete_truckroll.sh
new file mode 100755
index 0000000..ee31aeb
--- /dev/null
+++ b/xos/api/examples/vtr/delete_truckroll.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+source ./config.sh
+
+if [[ "$#" -ne 1 ]]; then
+    echo "Syntax: delete_truckroll.sh <id>"
+    exit -1
+fi
+
+ID=$1
+
+curl -H "Accept: application/json; indent=4" -u $AUTH -X DELETE $HOST/api/tenant/truckroll/$ID/
diff --git a/xos/api/examples/vtr/list_truckrolls.sh b/xos/api/examples/vtr/list_truckrolls.sh
new file mode 100755
index 0000000..f1d7e87
--- /dev/null
+++ b/xos/api/examples/vtr/list_truckrolls.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+source ./config.sh
+
+curl -H "Accept: application/json; indent=4" -u $AUTH -X GET $HOST/api/tenant/truckroll/
diff --git a/xos/api/examples/vtr/util.sh b/xos/api/examples/vtr/util.sh
new file mode 100644
index 0000000..7b66903
--- /dev/null
+++ b/xos/api/examples/vtr/util.sh
@@ -0,0 +1 @@
+source ../util.sh
diff --git a/xos/api/import_methods.py b/xos/api/import_methods.py
new file mode 100644
index 0000000..ec07be6
--- /dev/null
+++ b/xos/api/import_methods.py
@@ -0,0 +1,102 @@
+from django.views.generic import View
+from django.conf.urls import patterns, url, include
+from rest_framework.routers import DefaultRouter
+from xosapi_helpers import XOSIndexViewSet
+import os, sys
+import inspect
+import importlib
+
+try:
+    from rest_framework.serializers import DictField
+except:
+    raise Exception("Failed check for django-rest-framework >= 3.3.3")
+
+urlpatterns = []
+
+def import_module_from_filename(dirname, fn):
+    print "importing", dirname, fn
+    sys_path_save = sys.path
+    try:
+        # __import__() and importlib.import_module() both import modules from
+        # sys.path. So we make sure that the path where we can find the views is
+        # the first thing in sys.path.
+        sys.path = [dirname] + sys.path
+
+        module = __import__(fn[:-3])
+    finally:
+        sys.path = sys_path_save
+
+    return module
+
+def import_module_by_dotted_name(name):
+    print "import", name
+    try:
+        module = __import__(name)
+    except:
+        # django will eat the exception, and then fail later with
+        #  'conflicting models in application'
+        # when it tries to import the module a second time.
+        print "exception in import_model_by_dotted_name"
+        import traceback
+        traceback.print_exc()
+        raise
+    for part in name.split(".")[1:]:
+        module = getattr(module, part)
+    return module
+
+def import_api_methods(dirname=None, api_path="api", api_module="api"):
+    has_index_view = False
+    subdirs=[]
+    urlpatterns=[]
+
+    if not dirname:
+        dirname = os.path.dirname(os.path.abspath(__file__))
+
+    view_urls = []
+    for fn in os.listdir(dirname):
+        pathname = os.path.join(dirname,fn)
+        if os.path.isfile(pathname) and fn.endswith(".py") and (fn!="__init__.py") and (fn!="import_methods.py"):
+            #module = import_module_from_filename(dirname, fn)
+            module = import_module_by_dotted_name(api_module + "." + fn[:-3])
+            for classname in dir(module):
+#                print "  ",classname
+                c = getattr(module, classname, None)
+
+                if inspect.isclass(c) and issubclass(c, View) and (classname not in globals()):
+                    globals()[classname] = c
+
+                    method_kind = getattr(c, "method_kind", None)
+                    method_name = getattr(c, "method_name", None)
+                    if method_kind:
+                        if method_name:
+                            method_name = os.path.join(api_path, method_name)
+                        else:
+                            method_name = api_path
+                            has_index_view = True
+                        view_urls.append( (method_kind, method_name, classname, c) )
+
+        elif os.path.isdir(pathname):
+            urlpatterns.extend(import_api_methods(pathname, os.path.join(api_path, fn), api_module+"." + fn))
+            subdirs.append(fn)
+
+    for view_url in view_urls:
+        if view_url[0] == "list":
+           urlpatterns.append(url(r'^' + view_url[1] + '/$',  view_url[3].as_view(), name=view_url[1]+'list'))
+        elif view_url[0] == "detail":
+           urlpatterns.append(url(r'^' + view_url[1] + '/(?P<pk>[a-zA-Z0-9\-]+)/$',  view_url[3].as_view(), name=view_url[1]+'detail'))
+        elif view_url[0] == "viewset":
+           viewset = view_url[3]
+           urlpatterns.extend(viewset.get_urlpatterns(api_path="^"+api_path+"/"))
+
+    # Only add an index_view if 1) the is not already an index view, and
+    # 2) we have found some methods in this directory.
+    if (not has_index_view) and (urlpatterns):
+        # The browseable API uses the classname as the breadcrumb and page
+        # title, so try to create index views with descriptive classnames
+        viewset = type("IndexOf"+api_path.split("/")[-1].title(), (XOSIndexViewSet,), {})
+        urlpatterns.append(url('^' + api_path + '/$', viewset.as_view({'get': 'list'}, view_urls=view_urls, subdirs=subdirs, api_path=api_path), name=api_path+"_index"))
+
+    return urlpatterns
+
+urlpatterns = import_api_methods()
+
diff --git a/xos/api/service/__init__.py b/xos/api/service/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/xos/api/service/__init__.py
@@ -0,0 +1 @@
+
diff --git a/xos/api/service/hpc/__init__.py b/xos/api/service/hpc/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/xos/api/service/hpc/__init__.py
@@ -0,0 +1 @@
+
diff --git a/xos/api/service/hpc/hpcview.py b/xos/api/service/hpc/hpcview.py
new file mode 100644
index 0000000..3e31e73
--- /dev/null
+++ b/xos/api/service/hpc/hpcview.py
@@ -0,0 +1,210 @@
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+from rest_framework import serializers
+from rest_framework import generics
+from rest_framework.views import APIView
+from core.models import *
+from services.hpc.models import *
+from services.requestrouter.models import *
+from django.forms import widgets
+from django.core.exceptions import PermissionDenied
+from django.contrib.contenttypes.models import ContentType
+import json
+import socket
+import time
+
+def lookup_tag(service, instance, name, default=None):
+    instance_type = ContentType.objects.get_for_model(instance)
+    t = Tag.objects.filter(service=service, name=name, content_type__pk=instance_type.id, object_id=instance.id)
+    if t:
+        return t[0].value
+    else:
+        return default
+
+def lookup_time(service, instance, name):
+    v = lookup_tag(service, instance, name)
+    if v:
+        return str(time.time() - float(v))
+    else:
+        return None
+
+def json_default(d, default):
+    if not d:
+        return default
+    return json.loads(d)
+
+def compute_config_run(d):
+    if not d:
+        return "null"
+
+    try:
+        d = json.loads(d)
+    except:
+        return "error decoding json '%s'" % str(d)
+
+    status = d.get("status", "null")
+    if status!="success":
+        return status
+
+    config_run = d.get("config.run")
+    if not config_run:
+        return "null"
+
+    try:
+        config_run = max(0, int(time.time()) - int(float(config_run)))
+    except:
+        pass
+
+    return config_run
+
+# from hpc_watcher.py
+def get_public_ip(service, instance):
+    network_name = None
+    if "hpc" in instance.slice.name:
+        network_name = getattr(service, "watcher_hpc_network", None)
+    elif "demux" in instance.slice.name:
+        network_name = getattr(service, "watcher_dnsdemux_network", None)
+    elif "redir" in instance.slice.name:
+        network_name = getattr(service, "watcher_dnsredir_network", None)
+
+    if network_name and network_name.lower()=="nat":
+        return None
+
+    if (network_name is None) or (network_name=="") or (network_name.lower()=="public"):
+        return instance.get_public_ip()
+
+    for ns in instance.ports.all():
+        if (ns.ip) and (ns.network.name==network_name):
+            return ns.ip
+
+    raise ValueError("Couldn't find network %s" % str(network_name))
+
+def getHpcDict(user, pk):
+    hpc = HpcService.objects.get(pk=pk)
+    slices = hpc.slices.all()
+
+    dnsdemux_slice = None
+    dnsredir_slice = None
+    hpc_slice = None
+    for slice in slices:
+        if "dnsdemux" in slice.name:
+            dnsdemux_service = hpc
+            dnsdemux_slice = slice
+        if "dnsredir" in slice.name:
+            dnsredir_service = hpc
+            dnsredir_slice = slice
+        if "hpc" in slice.name:
+            hpc_service = hpc
+            hpc_slice = slice
+
+    if not dnsdemux_slice:
+        rr = RequestRouterService.objects.all()
+        if rr:
+            rr=rr[0]
+            slices = rr.slices.all()
+            for slice in slices:
+                if "dnsdemux" in slice.name:
+                    dnsdemux_service = rr
+                    dnsdemux_slice = slice
+                if "dnsredir" in slice.name:
+                    dnsredir_service = rr
+                    dnsredir_slice = slice
+
+    if not dnsredir_slice:
+        print "no dnsredir slice"
+        return
+
+    if not dnsdemux_slice:
+        print "no dnsdemux slice"
+        return
+
+    #dnsdemux_has_public_network = False
+    #for network in dnsdemux_slice.networks.all():
+    #    if (network.template) and (network.template.visibility=="public") and (network.template.translation=="none"):
+    #        dnsdemux_has_public_network = True
+
+    nameservers = {}
+    for nshc in hpc.hpchealthcheck_set.filter(kind="nameserver"):
+        nameserver = nshc.resource_name
+        try:
+            nameservers[nameserver] = {"name": nameserver, "ip": socket.gethostbyname(nameserver), "hit": False}
+        except:
+            nameservers[nameserver] = {"name": nameserver, "ip": "exception", "hit": False}
+
+    dnsdemux=[]
+    for instance in dnsdemux_slice.instances.all():
+        ip=None
+        try:
+            ip = get_public_ip(dnsdemux_service, instance)
+        except Exception, e:
+            ip = "Exception: " + str(e)
+        if not ip:
+            try:
+                ip = socket.gethostbyname(instance.node.name)
+            except:
+                ip = "??? " + instance.node.name
+
+        instance_nameservers = []
+        for ns in nameservers.values():
+            if ns["ip"]==ip:
+                instance_nameservers.append(ns["name"])
+                ns["hit"]=True
+
+        # now find the dnsredir instance that is also on this node
+        watcherd_dnsredir = "no-redir-instance"
+        for dnsredir_instance in dnsredir_slice.instances.all():
+            if dnsredir_instance.node == instance.node:
+                watcherd_dnsredir = lookup_tag(dnsredir_service, dnsredir_instance, "watcher.watcher.msg")
+
+        watcherd_dnsdemux = lookup_tag(dnsdemux_service, instance, "watcher.watcher.msg")
+
+        dnsdemux.append( {"name": instance.node.name,
+                       "watcher.DNS.msg": lookup_tag(dnsdemux_service, instance, "watcher.DNS.msg"),
+                       "watcher.DNS.time": lookup_time(dnsdemux_service, instance, "watcher.DNS.time"),
+                       "ip": ip,
+                       "nameservers": instance_nameservers,
+                       "dnsdemux_config_age": compute_config_run(watcherd_dnsdemux),
+                       "dnsredir_config_age": compute_config_run(watcherd_dnsredir) })
+
+    hpc=[]
+    for instance in hpc_slice.instances.all():
+        watcherd_hpc = lookup_tag(hpc_service, instance, "watcher.watcher.msg")
+
+        hpc.append( {"name": instance.node.name,
+                     "watcher.HPC-hb.msg": lookup_tag(hpc_service, instance, "watcher.HPC-hb.msg"),
+                     "watcher.HPC-hb.time": lookup_time(hpc_service, instance, "watcher.HPC-hb.time"),
+                     "watcher.HPC-fetch.msg": lookup_tag(hpc_service, instance, "watcher.HPC-fetch.msg"),
+                     "watcher.HPC-fetch.time": lookup_time(hpc_service, instance, "watcher.HPC-fetch.time"),
+                     "watcher.HPC-fetch.urls": json_default(lookup_tag(hpc_service, instance, "watcher.HPC-fetch-urls.msg"), []),
+                     "config_age": compute_config_run(watcherd_hpc),
+
+        })
+
+    return { "id": pk,
+             "dnsdemux": dnsdemux,
+             "hpc": hpc,
+             "nameservers": nameservers,}
+
+
+class HpcList(APIView):
+    method_kind = "list"
+    method_name = "hpcview"
+
+    def get(self, request, format=None):
+        if (not request.user.is_authenticated()):
+            raise PermissionDenied("You must be authenticated in order to use this API")
+        results = []
+        for hpc in HpcService.objects.all():
+            results.append(getHpcDict(request.user, hpc.pk))
+        return Response( results )
+
+class HpcDetail(APIView):
+    method_kind = "detail"
+    method_name = "hpcview"
+
+    def get(self, request, format=None, pk=0):
+        if (not request.user.is_authenticated()):
+            raise PermissionDenied("You must be authenticated in order to use this API")
+        return Response( [getHpcDict(request.user, pk)] )
+
diff --git a/xos/api/service/vbng/__init__.py b/xos/api/service/vbng/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/xos/api/service/vbng/__init__.py
@@ -0,0 +1 @@
+
diff --git a/xos/api/service/vsg/__init__.py b/xos/api/service/vsg/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/xos/api/service/vsg/__init__.py
@@ -0,0 +1 @@
+
diff --git a/xos/api/tenant/__init__.py b/xos/api/tenant/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/xos/api/tenant/__init__.py
@@ -0,0 +1 @@
+
diff --git a/xos/api/tenant/ceilometer/__init__.py b/xos/api/tenant/ceilometer/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/xos/api/tenant/ceilometer/__init__.py
@@ -0,0 +1 @@
+
diff --git a/xos/api/tenant/cord/__init__.py b/xos/api/tenant/cord/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/xos/api/tenant/cord/__init__.py
@@ -0,0 +1 @@
+
diff --git a/xos/api/tenant/onos/__init__.py b/xos/api/tenant/onos/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/xos/api/tenant/onos/__init__.py
@@ -0,0 +1 @@
+
diff --git a/xos/api/tenant/openvpn/__init__.py b/xos/api/tenant/openvpn/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/xos/api/tenant/openvpn/__init__.py
@@ -0,0 +1 @@
+
diff --git a/xos/api/utility/__init__.py b/xos/api/utility/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/xos/api/utility/__init__.py
@@ -0,0 +1 @@
+
diff --git a/xos/api/utility/loginview.py b/xos/api/utility/loginview.py
new file mode 100644
index 0000000..2dc79c6
--- /dev/null
+++ b/xos/api/utility/loginview.py
@@ -0,0 +1,101 @@
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+from rest_framework import serializers
+from rest_framework import generics
+from rest_framework.views import APIView
+from core.models import *
+from services.hpc.models import *
+from services.requestrouter.models import *
+from django.forms import widgets
+from django.core.exceptions import PermissionDenied
+from django.contrib.contenttypes.models import ContentType
+import json
+import socket
+import time
+import django.middleware.csrf
+from xos.exceptions import *
+from django.contrib.sessions.backends.db import SessionStore
+from django.contrib.sessions.models import Session
+from django.contrib.auth import authenticate
+
+def date_handler(obj):
+    return obj.isoformat() if hasattr(obj, 'isoformat') else obj
+
+def serialize_user(model):
+    serialized = model_to_dict(model)
+    del serialized['timezone']
+    del serialized['password']
+    return json.dumps(serialized, default=date_handler)
+
+class LoginView(APIView):
+    method_kind = "list"
+    method_name = "login"
+
+    def do_login(self, request, username, password):
+        if not username:
+            raise XOSMissingField("No username specified")
+
+        if not password:
+            raise XOSMissingField("No password specified")
+
+        u=authenticate(username=username, password=password)
+        if not u:
+            raise PermissionDenied("Failed to authenticate user %s" % username)
+
+        auth = {"username": username, "password": password}
+        request.session["auth"] = auth
+        request.session['_auth_user_id'] = u.pk
+        request.session['_auth_user_backend'] = u.backend
+        request.session.save()
+
+        return Response({
+            "xoscsrftoken": django.middleware.csrf.get_token(request),
+            "xossessionid": request.session.session_key,
+            "user": serialize_user(u)
+        })
+
+    def get(self, request, format=None):
+        username = request.GET.get("username", None)
+        password = request.GET.get("password", None)
+
+        return self.do_login(request, username, password)
+
+    def post(self, request, format=None):
+        username = request.data.get("username", None)
+        password = request.data.get("password", None)
+
+        return self.do_login(request, username, password)
+
+class LogoutView(APIView):
+    method_kind = "list"
+    method_name = "logout"
+
+    def do_logout(self, request, sessionid):
+        if not sessionid:
+            raise XOSMissingField("No xossessionid specified")
+
+        # Make sure the session exists. This prevents us from accidentally
+        # creating empty sessions with SessionStore()
+        session = Session.objects.filter(session_key=sessionid)
+        if not session:
+            # session doesn't exist
+            raise PermissionDenied("Session does not exist")
+
+        session = SessionStore(session_key=sessionid)
+        if "auth" in session:
+            del session["auth"]
+            session.save()
+        if "_auth_user_id" in session:
+            del session["_auth_user_id"]
+            session.save()
+
+        return Response("Logged Out")
+
+    def get(self, request, format=None):
+        sessionid = request.GET.get("xossessionid", None)
+        return self.do_logout(request, sessionid)
+
+    def post(self, request, format=None):
+        sessionid = request.data.get("xossessionid", None)
+        return self.do_logout(request, sessionid)
\ No newline at end of file
diff --git a/xos/api/utility/onboarding.py b/xos/api/utility/onboarding.py
new file mode 100644
index 0000000..dd66d6d
--- /dev/null
+++ b/xos/api/utility/onboarding.py
@@ -0,0 +1,97 @@
+import json
+from django.http import HttpResponse
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+from rest_framework import serializers
+from rest_framework import generics
+from rest_framework import status
+from core.models import *
+from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
+from api.xosapi_helpers import PlusModelSerializer, XOSViewSet, ReadOnlyField
+
+class OnboardingViewSet(XOSViewSet):
+    base_name = "onboarding"
+    method_name = "onboarding"
+    method_kind = "viewset"
+
+    @classmethod
+    def get_urlpatterns(self, api_path="^"):
+        patterns = [] #super(CordSubscriberViewSet, self).get_urlpatterns(api_path=api_path)
+
+        patterns.append( self.list_url("xos/ready/$", {"get": "get_xos_ready"}, "xos_ready") )
+
+        patterns.append( self.list_url("summary/$", {"get": "get_summary"}, "summary") )
+
+        patterns.append( self.list_url("services/$", {"get": "get_service_list"}, "service_list") )
+        patterns.append( self.list_url("services/(?P<service>[a-zA-Z0-9\-_]+)/ready/$", {"get": "get_service_ready"}, "service_ready") )
+
+
+        return patterns
+
+    def is_ready(self, obj):
+        return (obj.enacted is not None) and (obj.updated is not None) and (obj.enacted>=obj.updated) and (obj.backend_status.startswith("1"))
+
+    def get_xos_ready(self, request):
+        xos = XOS.objects.all()
+        if not xos:
+            return Response(false)
+
+        xos=xos[0]
+
+        result = (xos.enacted is not None) and (xos.updated is not None) and (xos.enacted>=xos.updated) and (xos.backend_status.startswith("1"))
+        return HttpResponse( json.dumps(result), content_type="application/javascript" )
+
+    def get_summary(self, request):
+        result = []
+
+        xos = XOS.objects.all()
+        if not xos:
+            result.append( ("XOS", false) )
+        else:
+            xos=xos[0]
+
+            result.append( ("XOS", self.is_ready(xos)) )
+
+            for sc in xos.service_controllers.all():
+                result.append( (sc.name, self.is_ready(sc)) )
+
+        result = "\n".join( ["%s: %s" % (x[0], x[1]) for x in result] )
+        if result:
+            result = result + "\n"
+
+        return HttpResponse( result, content_type="text/ascii" )
+
+    def get_service_list(self, request):
+        xos = XOS.objects.all()
+        if not xos:
+            return Response([])
+
+        xos=xos[0]
+
+        result = []
+        for sc in xos.service_controllers.all():
+            result.append(sc.name)
+
+        return HttpResponse( json.dumps(result), content_type="application/javascript")
+
+    def get_service_ready(self, request, service):
+        xos = XOS.objects.all()
+        if not xos:
+            return Response([])
+
+        xos=xos[0]
+
+        sc=xos.service_controllers.filter(name=service)
+        if not sc:
+            return HttpResponse("Not Found", status_code=404)
+
+        sc=sc[0]
+        result = self.is_ready(sc)
+
+        return HttpResponse( json.dumps(result), content_type="application/javascript")
+
+
+
+
+
diff --git a/xos/api/utility/portforwarding.py b/xos/api/utility/portforwarding.py
new file mode 100644
index 0000000..0bb7a93
--- /dev/null
+++ b/xos/api/utility/portforwarding.py
@@ -0,0 +1,49 @@
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+from rest_framework import serializers
+from rest_framework import generics
+from rest_framework.views import APIView
+from core.models import *
+from django.forms import widgets
+from django.core.exceptions import PermissionDenied
+from xos.exceptions import XOSNotFound
+from api.xosapi_helpers import PlusModelSerializer, XOSViewSet, ReadOnlyField
+from django.db.models import Q
+
+class PortForwardingSerializer(serializers.Serializer):
+    id = serializers.IntegerField(read_only=True)
+    ip = serializers.CharField(read_only=True)
+    ports = serializers.CharField(read_only=True, source="network.ports")
+    hostname = serializers.CharField(read_only=True, source="instance.node.name")
+
+    class Meta:
+        model = Port
+        fields = ('id', 'ip', 'ports', 'hostname')
+
+class PortForwardingViewSet(XOSViewSet):
+    base_name = "portforwarding"
+    method_name = "portforwarding"
+    method_kind = "viewset"
+    serializer_class = PortForwardingSerializer
+
+    def get_queryset(self):
+        queryset=Port.objects.exclude(Q(network__isnull=True) |
+                                                  Q(instance__isnull=True) |
+                                                  Q(instance__node__isnull=True) |
+                                                  Q(network__ports__isnull=True) | Q(network__ports__exact='') |
+                                                  Q(ip__isnull=True))
+
+        node_name = self.request.query_params.get('node_name', None)
+        if node_name is not None:
+            queryset = queryset.filter(instance__node__name = node_name)
+
+        if "" in [q.ip for q in list(queryset)]:
+            # Q(ip__exact=='') does not work right, so let's filter the hard way
+            queryset = [q for q in list(queryset) if q.ip!='']
+            queryset = [q.id for q in queryset]
+            queryset = Port.objects.filter(pk__in=queryset)
+
+        return queryset
+
+
diff --git a/xos/api/utility/sliceplus.py b/xos/api/utility/sliceplus.py
new file mode 100644
index 0000000..cecea4d
--- /dev/null
+++ b/xos/api/utility/sliceplus.py
@@ -0,0 +1,418 @@
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+from rest_framework import serializers
+from rest_framework import generics
+from rest_framework.exceptions import APIException
+from core.models import *
+from django.forms import widgets
+from core.xoslib.objects.sliceplus import SlicePlus
+from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
+import json
+from core.models import Slice, SlicePrivilege, SliceRole, Instance, Site, Node, User
+from operator import itemgetter, attrgetter
+from api.xosapi_helpers import PlusObjectMixin, PlusModelSerializer
+
+# rest_framework 3.x
+IdField = serializers.ReadOnlyField
+WritableField = serializers.Field
+DictionaryField = serializers.DictField
+ListField = serializers.ListField
+
+
+class SlicePlus(Slice, PlusObjectMixin):
+    class Meta:
+        proxy = True
+
+    def __init__(self, *args, **kwargs):
+        super(SlicePlus, self).__init__(*args, **kwargs)
+        self._update_users = None
+        self._sliceInfo = None
+        self.getSliceInfo()
+        self._instance_status = self._sliceInfo["instanceStatus"]
+        self._instance_distribution = self._sliceInfo["sitesUsed"]
+        self._initial_instance_distribution = self._instance_distribution
+        self._network_ports = self._sliceInfo["networkPorts"]
+        self._initial_network_ports = self._network_ports
+        self._current_user_roles = self._sliceInfo["roles"]
+
+    def getSliceInfo(self, user=None):
+        if not self._sliceInfo:
+            site_status = {}
+            used_sites = {}
+            ready_sites = {}
+            used_deployments = {}
+            instanceCount = 0
+            instance_status = {}
+            sshCommands = []
+            for instance in self.instances.all():
+                site = instance.node.site_deployment.site
+                deployment = instance.node.site_deployment.deployment
+                used_sites[site.name] = used_sites.get(site.name, 0) + 1
+                used_deployments[deployment.name] = used_deployments.get(deployment.name, 0) + 1
+                instanceCount = instanceCount + 1
+
+                if instance.backend_status:
+                    status = instance.backend_status[0]
+                else:
+                    status = "none"
+
+                if not status in instance_status:
+                    instance_status[status] = 0
+                instance_status[status] = instance_status[status] + 1
+
+                sshCommand = instance.get_ssh_command()
+                if sshCommand:
+                    sshCommands.append(sshCommand)
+                    ready_sites[site.name] = ready_sites.get(site.name, 0) + 1
+
+            users = {}
+            for priv in SlicePrivilege.objects.filter(slice=self):
+                if not (priv.user.id in users.keys()):
+                    users[priv.user.id] = {"name": priv.user.email, "id": priv.user.id, "roles": []}
+                users[priv.user.id]["roles"].append(priv.role.role)
+
+            # XXX this assumes there is only one network that can have ports bound
+            # to it for a given slice. This is intended for the tenant view, which
+            # will obey this field.
+            networkPorts = ""
+            for networkSlice in self.networkslices.all():
+                network = networkSlice.network
+                if (network.owner.id != self.id):
+                    continue
+                if network.ports:
+                    networkPorts = network.ports
+
+            self._sliceInfo = {
+                    "sitesUsed": used_sites,
+                    "sitesReady": ready_sites,
+                    "instanceStatus": instance_status,
+                    "deploymentsUsed": used_deployments,
+                    "instanceCount": instanceCount,
+                    "siteCount": len(used_sites.keys()),
+                    "users": users,
+                    "roles": [],
+                    "sshCommands": sshCommands,
+                    "networkPorts": networkPorts}
+
+        if user:
+            auser = self._sliceInfo["users"].get(user.id, None)
+            if (auser):
+                self._sliceInfo["roles"] = auser["roles"]
+
+        return self._sliceInfo
+
+    @property
+    def instance_distribution_ready(self):
+        return self._sliceInfo["sitesReady"]
+
+    @property
+    def instance_total_ready(self):
+        return sum(self._sliceInfo["sitesReady"].values())
+
+    @property
+    def current_user_roles(self):
+        return self._current_user_roles
+
+    @property
+    def instance_distribution(self):
+        return self._instance_distribution
+
+    @instance_distribution.setter
+    def instance_distribution(self, value):
+        self._instance_distribution = value
+
+    @property
+    def instance_total(self):
+        return sum(self._instance_distribution.values())
+
+    @property
+    def instance_status(self):
+        return self._instance_status
+
+    @property
+    def user_names(self):
+        return [user["name"] for user in self.getSliceInfo()["users"].values()]
+
+    @user_names.setter
+    def user_names(self, value):
+        pass  # it's read-only
+
+    @property
+    def users(self):
+        return [user["id"] for user in self.getSliceInfo()["users"].values()]
+
+    @users.setter
+    def users(self, value):
+        self._update_users = value
+
+    @property
+    def network_ports(self):
+        return self._network_ports
+
+    @network_ports.setter
+    def network_ports(self, value):
+        self._network_ports = value
+
+    @staticmethod
+    def select_by_user(user):
+        if user.is_admin:
+            qs = SlicePlus.objects.all()
+        else:
+            slice_ids = [sp.slice.id for sp in SlicePrivilege.objects.filter(user=user)]
+            qs = SlicePlus.objects.filter(id__in=slice_ids)
+        return qs
+
+    def get_node_allocation(self, siteList):
+        siteIDList = [site.id for site in siteList]
+        nodeList = []
+        for node in Node.objects.all():
+            if (node.site_deployment.site.id in siteIDList):
+                node.instanceCount = 0
+                for instance in node.instances.all():
+                    if instance.slice.id == self.id:
+                        node.instanceCount = node.instanceCount + 1
+                nodeList.append(node)
+        return nodeList
+
+    def save(self, *args, **kwargs):
+        if (not hasattr(self, "caller")) or self.caller==None:
+            raise APIException("no self.caller in SlicePlus.save")
+
+        updated_image = self.has_field_changed("default_image")
+        updated_flavor = self.has_field_changed("default_flavor")
+
+        super(SlicePlus, self).save(*args, **kwargs)
+
+        # try things out first
+
+        updated_sites = (self._instance_distribution != self._initial_instance_distribution) or updated_image or updated_flavor
+        if updated_sites:
+            self.save_instance_distribution(noAct=True, reset=(updated_image or updated_flavor))
+
+        if self._update_users:
+            self.save_users(noAct=True)
+
+        if (self._network_ports != self._initial_network_ports):
+            self.save_network_ports(noAct=True)
+
+        # now actually save them
+
+        if updated_sites:
+            self.save_instance_distribution(reset=(updated_image or updated_flavor))
+
+        if self._update_users:
+            self.save_users()
+
+        if (self._network_ports != self._initial_network_ports):
+            self.save_network_ports()
+
+    def save_instance_distribution(self, noAct = False, reset=False):
+        print "save_instance_distribution, reset=",reset
+
+        if (not self._instance_distribution):
+            # Must be a instance that was just created, and has not instance_distribution
+            # field.
+            return
+
+        all_slice_instances = self.instances.all()
+        for site_name in self._instance_distribution.keys():
+            desired_allocation = self._instance_distribution[site_name]
+
+            # make a list of the instances for this site
+            instances = []
+            for instance in all_slice_instances:
+                if instance.node.site_deployment.site.name == site_name:
+                    instances.append(instance)
+
+            # delete extra instances
+            while (reset and len(instances) > 0) or (len(instances) > desired_allocation):
+                instance = instances.pop()
+                if (not noAct):
+                    print "deleting instance", instance
+                    instance.delete()
+                else:
+                    print "would delete instance", instance
+
+            # add more instances
+            if (len(instances) < desired_allocation):
+                site = Site.objects.get(name=site_name)
+                nodes = self.get_node_allocation([site])
+
+                if (not nodes):
+                    raise APIException(detail="no nodes in site %s" % site_name)
+
+                while (len(instances) < desired_allocation):
+                    # pick the least allocated node
+                    nodes = sorted(nodes, key=attrgetter("instanceCount"))
+                    node = nodes[0]
+
+                    instance = Instance(name=node.name,
+                                        slice=self,
+                                        node=node,
+                                        image=self.default_image,
+                                        flavor=self.default_flavor,
+                                        creator=self.creator,
+                                        deployment=node.site_deployment.deployment)
+                    instance.caller = self.caller
+                    instances.append(instance)
+                    if (not noAct):
+                        print "added instance", instance
+                        instance.save()
+                    else:
+                        print "would add instance", instance
+
+                    node.instanceCount = node.instanceCount + 1
+
+    def save_users(self, noAct=False):
+        new_users = self._update_users
+
+        try:
+            default_role = SliceRole.objects.get(role="access")
+        except:
+            default_role = SliceRole.objects.get(role="default")
+
+        slice_privs = self.sliceprivileges.all()
+        slice_user_ids = [priv.user.id for priv in slice_privs]
+
+        for user_id in new_users:
+            if (user_id not in slice_user_ids):
+                priv = SlicePrivilege(slice=self, user=User.objects.get(id=user_id), role=default_role)
+                priv.caller = self.caller
+                if (not noAct):
+                    priv.save()
+
+                print "added user id", user_id
+
+        for priv in slice_privs:
+            if (priv.role.id != default_role.id):
+                # only mess with 'default' users; don't kill an admin
+                continue
+
+            if (priv.user.id not in new_users):
+                if (not noAct):
+                    priv.delete()
+
+                print "deleted user id", user_id
+
+    def save_network_ports(self, noAct=False):
+        # First search for any network that already has a filled in 'ports'
+        # field. We'll assume there can only be one, so it must be the right
+        # one.
+        for networkSlice in self.networkslices.all():
+            network = networkSlice.network
+            if (network.owner.id != self.id):
+                continue
+            if network.ports:
+                network.ports = self._network_ports
+                network.caller = self.caller
+                if (not noAct):
+                    network.save()
+                return
+
+        # Now try a network that is a "NAT", since setting ports on a non-NAT
+        # network doesn't make much sense.
+        for networkSlice in self.networkslices.all():
+            network = networkSlice.network
+            if (network.owner.id != self.id):
+                continue
+            if network.template.translation == "NAT":
+                network.ports = self._network_ports
+                network.caller = self.caller
+                if (not noAct):
+                    network.save()
+                return
+
+        # uh oh, we didn't find a network
+
+        raise APIException(detail="No network was found that ports could be set on")
+
+
+class SlicePlusIdSerializer(PlusModelSerializer):
+        id = IdField()
+
+        humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+        network_ports = serializers.CharField(required=False)
+        instance_distribution = DictionaryField(required=False)
+        instance_distribution_ready = DictionaryField(read_only=True)
+        instance_total = serializers.IntegerField(read_only=True)
+        instance_total_ready = serializers.IntegerField(read_only=True)
+        instance_status = DictionaryField(read_only=True)
+        users = ListField(required=False)
+        user_names = ListField(required=False)  # readonly = True ?
+        current_user_can_see = serializers.SerializerMethodField("getCurrentUserCanSee")
+
+        def getCurrentUserCanSee(self, slice):
+            # user can 'see' the slice if he is the creator or he has a role
+            current_user = self.context['request'].user
+            if (slice.creator and slice.creator == current_user):
+                return True
+            return (len(slice.getSliceInfo(current_user)["roles"]) > 0)
+
+        def getSliceInfo(self, slice):
+            return slice.getSliceInfo(user=self.context['request'].user)
+
+        def getHumanReadableName(self, obj):
+            return str(obj)
+
+        networks = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
+
+        class Meta:
+            model = SlicePlus
+            fields = ('humanReadableName', 'id', 'created', 'updated', 'enacted', 'name', 'enabled', 'omf_friendly',
+                      'description', 'slice_url', 'site', 'max_instances', 'service', 'network', 'mount_data_sets',
+                      'default_image', 'default_flavor',
+                      'serviceClass', 'creator',
+
+                      # these are the value-added fields from SlicePlus
+                      'networks', 'network_ports', 'backendIcon', 'backendHtml',
+                      'current_user_roles',  'instance_distribution', 'instance_distribution_ready', 'instance_total',
+                      'instance_total_ready', 'instance_status', 'users', "user_names", "current_user_can_see")
+
+
+class SlicePlusList(XOSListCreateAPIView):
+    queryset = SlicePlus.objects.select_related().all()
+    serializer_class = SlicePlusIdSerializer
+
+    method_kind = "list"
+    method_name = "slicesplus"
+
+    def get_queryset(self):
+        current_user_can_see = self.request.query_params.get('current_user_can_see', False)
+        site_filter = self.request.query_params.get('site', False)
+
+        if (not self.request.user.is_authenticated()):
+            raise XOSPermissionDenied("You must be authenticated in order to use this API")
+
+        slices = SlicePlus.select_by_user(self.request.user)
+
+        if (site_filter and not current_user_can_see):
+            slices = SlicePlus.objects.filter(site=site_filter)
+
+        # If current_user_can_see is set, then filter the queryset to return
+        # only those slices that the user is either creator or has privilege
+        # on.
+        if (current_user_can_see):
+            slice_ids = []
+            for slice in slices:
+                if (self.request.user == slice.creator) or (len(slice.getSliceInfo(self.request.user)["roles"]) > 0):
+                    slice_ids.append(slice.id)
+            if (site_filter):
+                slices = SlicePlus.objects.filter(id__in=slice_ids, site=site_filter)
+            else:
+                slices = SlicePlus.objects.filter(id__in=slice_ids)
+
+        return slices
+
+
+class SlicePlusDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = SlicePlus.objects.select_related().all()
+    serializer_class = SlicePlusIdSerializer
+
+    method_kind = "detail"
+    method_name = "slicesplus"
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSPermissionDenied("You must be authenticated in order to use this API")
+        return SlicePlus.select_by_user(self.request.user)
diff --git a/xos/api/utility/sshkeys.py b/xos/api/utility/sshkeys.py
new file mode 100644
index 0000000..6ddd1ef
--- /dev/null
+++ b/xos/api/utility/sshkeys.py
@@ -0,0 +1,42 @@
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+from rest_framework import serializers
+from rest_framework import generics
+from rest_framework.views import APIView
+from core.models import *
+from django.forms import widgets
+from django.core.exceptions import PermissionDenied
+from xos.exceptions import XOSNotFound
+from api.xosapi_helpers import PlusModelSerializer, XOSViewSet, ReadOnlyField
+from django.db.models import Q
+
+class SSHKeysSerializer(PlusModelSerializer):
+    id = serializers.CharField(read_only=True, source="instance_id")
+    public_keys = serializers.ListField(read_only=True, source="get_public_keys")
+    node_name = serializers.CharField(read_only=True, source="node.name")
+
+    class Meta:
+        model = Instance
+        fields = ('id', 'public_keys', 'node_name')
+
+class SSHKeysViewSet(XOSViewSet):
+    base_name = "sshkeys"
+    method_name = "sshkeys"
+    method_kind = "viewset"
+    serializer_class = SSHKeysSerializer
+    read_only = True
+
+    lookup_field = "instance_id"
+    lookup_url_kwarg = "pk"
+
+    def get_queryset(self):
+        queryset = queryset=Instance.objects.exclude(Q(instance_id__isnull=True) | Q(instance_id__exact=''))
+
+        node_name = self.request.query_params.get('node_name', None)
+        if node_name is not None:
+            queryset = queryset.filter(node__name = node_name)
+
+        return queryset
+
+
diff --git a/xos/api/utility/synchronizer.py b/xos/api/utility/synchronizer.py
new file mode 100644
index 0000000..84bae00
--- /dev/null
+++ b/xos/api/utility/synchronizer.py
@@ -0,0 +1,61 @@
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+from rest_framework import serializers
+from rest_framework import generics
+from rest_framework.exceptions import APIException
+from core.models import *
+from django.forms import widgets
+from core.xoslib.objects.sliceplus import SlicePlus
+from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
+import json
+from core.models import Slice, SlicePrivilege, SliceRole, Instance, Site, Node, User
+from operator import itemgetter, attrgetter
+from api.xosapi_helpers import PlusObjectMixin, PlusModelSerializer
+
+IdField = serializers.ReadOnlyField
+
+
+class SynchronizerSerializer(PlusModelSerializer):
+    id = IdField()
+
+    name = serializers.CharField(required=False)
+
+    class Meta:
+        model = Diag
+        fields = ('id', 'name', 'backend_status', 'backend_register')
+
+
+class SynchronizerList(XOSListCreateAPIView):
+    queryset = Diag.objects.all()
+    serializer_class = SynchronizerSerializer
+
+    method_kind = "list"
+    method_name = "synchronizer"
+
+    def get_queryset(self):
+        name = self.request.query_params.get('name', False)
+
+        if (not self.request.user.is_authenticated()):
+            raise XOSPermissionDenied("You must be authenticated in order to use this API")
+        if(name):
+            return Diag.objects.filter(name=name)
+        return Diag.objects.all()
+
+
+class SynchronizerDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = Diag.objects.all()
+    serializer_class = SynchronizerSerializer
+
+    method_kind = "detail"
+    method_name = "synchronizer"
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSPermissionDenied("You must be authenticated in order to use this API")
+
+        print "kwargs"
+        print self.request
+        print self.kwargs['pk']
+
+        return Diag.objects.filter(id=self.kwargs['pk'])
diff --git a/xos/api/xosapi_helpers.py b/xos/api/xosapi_helpers.py
new file mode 100644
index 0000000..b39ca22
--- /dev/null
+++ b/xos/api/xosapi_helpers.py
@@ -0,0 +1,181 @@
+from rest_framework import generics
+from rest_framework import serializers
+from rest_framework.response import Response
+from rest_framework import status
+from xos.apibase import XOSRetrieveUpdateDestroyAPIView, XOSListCreateAPIView
+from rest_framework import viewsets
+from django.conf.urls import patterns, url
+from xos.exceptions import *
+from rest_framework.reverse import reverse
+from django.core.urlresolvers import get_script_prefix, resolve, Resolver404
+
+# rest_framework 3.x
+ReadOnlyField = serializers.ReadOnlyField
+
+ICON_URLS = {"success": "/static/admin/img/icon_success.gif",
+            "clock": "/static/admin/img/icon_clock.gif",
+            "error": "/static/admin/img/icon_error.gif"}
+
+class PlusObjectMixin:
+    def getBackendIcon(self):
+        (icon, tooltip) = self.get_backend_icon()
+        icon_url = ICON_URLS.get(icon, "unknown")
+        return icon_url
+
+    def getBackendHtml(self):
+        (icon, tooltip) = self.get_backend_icon()
+        icon_url = ICON_URLS.get(icon, "unknown")
+
+        if tooltip:
+            return '<span title="%s"><img src="%s"></span>' % (tooltip, icon_url)
+        else:
+            return '<img src="%s">' % icon_url
+
+""" PlusSerializerMixin
+
+    Implements Serializer fields that are common to all OpenCloud objects. For
+    example, stuff related to backend fields.
+"""
+
+class PlusModelSerializer(serializers.ModelSerializer):
+    backendIcon = serializers.SerializerMethodField("getBackendIcon")
+    backendHtml = serializers.SerializerMethodField("getBackendHtml")
+
+    # This will cause a descendant class to pull in the methods defined
+    # above. See rest_framework/serializers.py: _get_declared_fields().
+    base_fields = {"backendIcon": backendIcon, "backendHtml": backendHtml}
+    # Rest_framework 3.0 uses _declared_fields instead of base_fields
+    _declared_fields = {"backendIcon": backendIcon, "backendHtml": backendHtml}
+
+    def getBackendIcon(self, obj):
+        return obj.getBackendIcon()
+
+    def getBackendHtml(self, obj):
+        return obj.getBackendHtml()
+
+    def create(self, validated_data):
+        property_fields = getattr(self, "property_fields", [])
+        create_fields = {}
+        for k in validated_data:
+            if not k in property_fields:
+                create_fields[k] = validated_data[k]
+        instance = self.Meta.model(**create_fields)
+
+        if instance and hasattr(instance,"can_update") and self.context.get('request',None):
+            user = self.context['request'].user
+            if user.__class__.__name__=="AnonymousUser":
+                raise XOSPermissionDenied()
+            if not instance.can_update(user):
+                raise XOSPermissionDenied()
+
+        for k in validated_data:
+            if k in property_fields:
+                setattr(instance, k, validated_data[k])
+
+        instance.caller = self.context['request'].user
+        instance.save()
+        return instance
+
+    def update(self, instance, validated_data):
+        nested_fields = getattr(self, "nested_fields", [])
+        for k in validated_data.keys():
+            v = validated_data[k]
+            if k in nested_fields:
+                d = getattr(instance,k)
+                d.update(v)
+                setattr(instance,k,d)
+            else:
+                setattr(instance, k, v)
+        instance.caller = self.context['request'].user
+        instance.save()
+        return instance
+
+class XOSViewSet(viewsets.ModelViewSet):
+    api_path=""
+    read_only=False
+
+    @classmethod
+    def get_api_method_path(self):
+        if self.method_name:
+            return self.api_path + self.method_name + "/"
+        else:
+            return self.api_path
+
+    @classmethod
+    def detail_url(self, pattern, viewdict, name):
+        return url(self.get_api_method_path() + r'(?P<pk>[a-zA-Z0-9\-_]+)/' + pattern,
+                   self.as_view(viewdict),
+                   name=self.base_name+"_"+name)
+
+    @classmethod
+    def list_url(self, pattern, viewdict, name):
+        return url(self.get_api_method_path() + pattern,
+                   self.as_view(viewdict),
+                   name=self.base_name+"_"+name)
+
+    @classmethod
+    def get_urlpatterns(self, api_path="^"):
+        self.api_path = api_path
+
+        patterns = []
+
+        if self.read_only:
+            patterns.append(url(self.get_api_method_path() + '$', self.as_view({'get': 'list'}), name=self.base_name+'_list'))
+            patterns.append(url(self.get_api_method_path() + '(?P<pk>[a-zA-Z0-9\-_]+)/$', self.as_view({'get': 'retrieve'}), name=self.base_name+'_detail'))
+        else:
+            patterns.append(url(self.get_api_method_path() + '$', self.as_view({'get': 'list', 'post': 'create'}), name=self.base_name+'_list'))
+            patterns.append(url(self.get_api_method_path() + '(?P<pk>[a-zA-Z0-9\-_]+)/$', self.as_view({'get': 'retrieve', 'put': 'update', 'post': 'update', 'delete': 'destroy', 'patch': 'partial_update'}), name=self.base_name+'_detail'))
+
+        return patterns
+
+    def get_serializer_class(self):
+        if hasattr(self, "custom_serializers") and hasattr(self, "action") and (self.action in self.custom_serializers):
+            return self.custom_serializers[self.action]
+        else:
+            return super(XOSViewSet, self).get_serializer_class()
+
+    def get_object(self):
+        obj = super(XOSViewSet, self).get_object()
+
+        if self.action=="update" or self.action=="destroy" or self.action.startswith("set_"):
+            if obj and hasattr(obj,"can_update"):
+                user = self.request.user
+                if user.__class__.__name__=="AnonymousUser":
+                    raise XOSPermissionDenied()
+                if not obj.can_update(user):
+                    raise XOSPermissionDenied()
+
+        return obj
+
+class XOSIndexViewSet(viewsets.ViewSet):
+    view_urls=[]
+    subdirs=[]
+    api_path = None
+
+    def __init__(self, view_urls, subdirs, api_path):
+        self.view_urls = view_urls
+        self.subdirs = subdirs
+        self.api_path = api_path
+        super(XOSIndexViewSet, self).__init__()
+
+    def list(self, request):
+        endpoints = {}
+        for view_url in self.view_urls:
+            method_name = view_url[1].split("/")[-1]
+            method_url = "http://" + request.get_host() + get_script_prefix() + self.api_path + "/" + method_name
+            endpoints[method_name] = method_url
+
+        for subdir in self.subdirs:
+            method_name = subdir
+            method_url = get_script_prefix() + self.api_path + "/" + subdir + "/"
+            # Check to make sure that an endpoint exists at this method_url. This
+            # prunes out subdirs that don't have any methods (like examples/)
+            try:
+                resolve(method_url)
+            except Resolver404:
+                continue
+            method_url = "http://" + request.get_host() + method_url
+            endpoints[method_name] = method_url
+
+        return Response(endpoints)
+
diff --git a/xos/backend-model-deps b/xos/backend-model-deps
new file mode 100644
index 0000000..9534f71
--- /dev/null
+++ b/xos/backend-model-deps
@@ -0,0 +1,11 @@
+{
+    "Instance": [
+	["SlicePrivilege","slice.sliceprivileges"],
+	["SitePrivilege","slice.site.siteprivileges"],
+	["ControllerImages","image.controllerimages"]
+    ] 
+    ,
+    "Network": [
+        ["Slice","network.slices"]
+    ]
+}
diff --git a/xos/configurations/acord/Makefile b/xos/configurations/acord/Makefile
new file mode 100644
index 0000000..e9b234c
--- /dev/null
+++ b/xos/configurations/acord/Makefile
@@ -0,0 +1,94 @@
+SETUPDIR:=../setup
+MYIP:=$(shell hostname -i)
+
+cloudlab: common_cloudlab cloudlab_ceilometer_custom_images ceilometer_cloudlab_cord_plugins acord
+
+devstack: upgrade_pkgs common_devstack devstack_net_fix devstack_images ceilometer_devstack_cord_plugins acord
+
+cord: 
+	sudo MYIP=$(MYIP) docker-compose up -d
+	bash ../common/wait_for_xos.sh
+	sudo MYIP=$(MYIP) docker-compose run xos python /opt/xos/tosca/run.py none /opt/xos/configurations/common/fixtures.yaml
+	sudo docker-compose run xos python /opt/xos/tosca/run.py none /opt/xos/configurations/common/mydeployment.yaml
+	sudo MYIP=$(MYIP) docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/common/cloudlab-openstack.yaml
+	sudo MYIP=$(MYIP) docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/nodes.yaml
+
+acord: cord exampleservice
+	sudo MYIP=$(MYIP) docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/acord/ceilometer.yaml
+
+exampleservice:
+	#Ensure exampleservice is enabled in xos/tools/xos-manage and xos/settings.py file before uncommenting below lines
+	#sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/acord/acord-exampleservice.yaml
+
+containers:
+	cd ../../../containers/xos; make devel
+	cd ../../../containers/synchronizer; make
+
+common_cloudlab:
+	make -C ../common -f Makefile.cloudlab
+
+common_devstack:
+	make -C ../common -f Makefile.devstack
+
+ceilometer_cloudlab_cord_plugins:
+	if [ -d ./ceilometer-plugins ]; then rm -fr ./ceilometer-plugins; fi
+	git clone https://github.com/srikanthvavila/ceilometer-plugins.git
+	sudo cp -r ceilometer-plugins/network/ext_services /usr/lib/python2.7/dist-packages/ceilometer/network/
+	sudo cp -r ceilometer-plugins/network/statistics/onos /usr/lib/python2.7/dist-packages/ceilometer/network/statistics/
+	sudo cp ceilometer-plugins/network/statistics/__init__.py /usr/lib/python2.7/dist-packages/ceilometer/network/statistics/ 
+	sudo cp ceilometer-plugins/entry_points.txt /usr/lib/python2.7/dist-packages/ceilometer-*egg-info/
+	sudo cp ceilometer-plugins/pipeline.yaml /etc/ceilometer/
+	echo "Restarting ceilometer-agent-notification"
+	sudo service ceilometer-agent-notification restart
+	echo "Restarting ceilometer-agent-central"
+	sudo service ceilometer-agent-central restart
+
+ceilometer_devstack_cord_plugins:
+	if [ -d ./ceilometer-plugins ]; then rm -fr ./ceilometer-plugins; fi
+	git clone https://github.com/srikanthvavila/ceilometer-plugins.git
+	sudo cp -r ceilometer-plugins/network/ext_services /opt/stack/ceilometer/ceilometer/network/
+	sudo cp ceilometer-plugins/entry_points.txt /opt/stack/ceilometer/ceilometer*egg-info/
+	sudo cp ceilometer-plugins/pipeline.yaml /etc/ceilometer/
+	echo "Remember to restart ceilometer-anotification ceilometer-acentral screens"
+
+ceilometer_pub_sub:
+	if [ -d ./pub-sub ]; then rm -fr ./pub-sub; fi
+	git clone https://github.com/srikanthvavila/pub-sub.git
+	echo "Starting Ceilometer PUB/SUB service...Ensure zookeeper and kafka services are launched (if required)"
+	cd pub-sub/ceilometer_pub_sub/ ; python sub_main.py & 
+	cd ../..
+
+stop:
+	sudo MYIP=$(MYIP) docker-compose stop
+
+rm: stop
+	sudo MYIP=$(MYIP) docker-compose rm
+
+showlogs:
+	sudo MYIP=$(MYIP) docker-compose logs
+
+ps:
+	sudo MYIP=$(MYIP) docker-compose ps
+
+cleanup: stop rm
+	./cleanup.sh
+	bash -c "source ../setup/admin-openrc.sh; nova list --all-tenants; neutron net-list"
+
+devstack_net_fix:
+	sudo ../common/devstack/net-fix.sh
+	sudo bash -c "source ../setup/admin-openrc.sh; neutron subnet-update private-subnet --dns-nameservers list=true 8.8.8.8 8.8.4.4"
+
+upgrade_pkgs:
+	sudo pip install httpie --upgrade
+
+rebuild_xos:
+	make -C ../../../containers/xos devel
+
+rebuild_synchronizer:
+	make -C ../../../containers/synchronizer
+
+devstack_images:
+	bash -c "source ../setup/admin-openrc.sh; glance image-show ceilometer-trusty-server-multi-nic || ! mkdir -p /opt/stack/images || ! wget http://www.vicci.org/cord/ceilometer-trusty-server-multi-nic.compressed.qcow2 -P /opt/stack/images || glance image-create --name ceilometer-trusty-server-multi-nic --disk-format qcow2 --file /opt/stack/images/ceilometer-trusty-server-multi-nic.compressed.qcow2 --container-format bare"
+
+cloudlab_ceilometer_custom_images:
+	bash -c "source ../setup/admin-openrc.sh; glance image-show ceilometer-trusty-server-multi-nic || if test -f /proj/xos-PG0/images/ceilometer-trusty-server-multi-nic.compressed.qcow2 ; then glance image-create --name ceilometer-trusty-server-multi-nic --disk-format qcow2 --file /proj/xos-PG0/images/ceilometer-trusty-server-multi-nic.compressed.qcow2 --container-format bare ; else mkdir -p /tmp/images && wget http://www.vicci.org/cord/ceilometer-trusty-server-multi-nic.compressed.qcow2 -P /tmp/images && glance image-create --name ceilometer-trusty-server-multi-nic --disk-format qcow2 --file /tmp/images/ceilometer-trusty-server-multi-nic.compressed.qcow2 --container-format bare ; fi "
diff --git a/xos/configurations/acord/acord-exampleservice.yaml b/xos/configurations/acord/acord-exampleservice.yaml
new file mode 100644
index 0000000..b6b23dd
--- /dev/null
+++ b/xos/configurations/acord/acord-exampleservice.yaml
@@ -0,0 +1,56 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Setup the ExampleService on the ACORD setup
+
+imports:
+   - custom_types/xos.yaml
+   - custom_types/exampleservice.yaml
+
+topology_template:
+  node_templates:
+
+    mysite:
+      type: tosca.nodes.Site
+
+    trusty-server-multi-nic:
+      type: tosca.nodes.Image
+
+    m1.small:
+      type: tosca.nodes.Flavor
+
+    mysite_exampleservice:
+      description: This slice holds the ExampleService
+      type: tosca.nodes.Slice
+      requirements:
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+          - exmapleservice:
+              node: service_example
+              relationship: tosca.relationships.MemberOfService
+          - default_image:
+                node: trusty-server-multi-nic
+                relationship: tosca.relationships.DefaultImage
+          - m1.small:
+                node: m1.small
+                relationship: tosca.relationships.DefaultFlavor
+
+    service_example:
+      type: tosca.nodes.ExampleService
+      properties:
+          view_url: /admin/exampleservice/exampleservice/$id$/
+          kind: exampleservice
+          public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }
+          private_key_fn: /opt/xos/synchronizers/exampleservice/exampleservice_private_key
+          service_message: hello
+      artifacts:
+          pubkey: /opt/xos/synchronizers/exampleservice/exampleservice_public_key
+
+    exampletenant1:
+        type: tosca.nodes.ExampleTenant
+        properties:
+            tenant_message: world
+        requirements:
+          - tenant:
+              node: service_example
+              relationship: tosca.relationships.TenantOfService
diff --git a/xos/configurations/acord/ceilometer.yaml b/xos/configurations/acord/ceilometer.yaml
new file mode 100644
index 0000000..089837d
--- /dev/null
+++ b/xos/configurations/acord/ceilometer.yaml
@@ -0,0 +1,262 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Setup CORD-related services -- vOLT, vCPE, vBNG.
+
+imports:
+   - custom_types/xos.yaml
+
+node_types:
+    tosca.nodes.SFlowService:
+        derived_from: tosca.nodes.Root
+        description: >
+            XOS SFlow Collection Service
+        capabilities:
+            scalable:
+                type: tosca.capabilities.Scalable
+            service:
+                type: tosca.capabilities.xos.Service
+        properties:
+            kind:
+                type: string
+                default: generic
+                description: Type of service.
+            view_url:
+                type: string
+                required: false
+                description: URL to follow when icon is clicked in the Service Directory.
+            icon_url:
+                type: string
+                required: false
+                description: ICON to display in the Service Directory.
+            enabled:
+                type: boolean
+                default: true
+            published:
+                type: boolean
+                default: true
+                description: If True then display this Service in the Service Directory.
+            public_key:
+                type: string
+                required: false
+                description: Public key to install into Instances to allows Services to SSH into them.
+            private_key_fn:
+                type: string
+                required: false
+                description: Location of private key file
+            versionNumber:
+                type: string
+                required: false
+                description: Version number of Service.
+            sflow_port:
+              type: integer
+              required: false
+              default: 6343
+              description: sFlow listening port
+            sflow_api_port:
+              type: integer
+              required: false
+              default: 33333
+              description: sFlow publish subscribe api listening port
+
+    tosca.nodes.CeilometerService:
+        derived_from: tosca.nodes.Root
+        description: >
+            XOS Ceilometer Service
+        capabilities:
+            scalable:
+                type: tosca.capabilities.Scalable
+            service:
+                type: tosca.capabilities.xos.Service
+        properties:
+            kind:
+                type: string
+                default: generic
+                description: Type of service.
+            view_url:
+                type: string
+                required: false
+                description: URL to follow when icon is clicked in the Service Directory.
+            icon_url:
+                type: string
+                required: false
+                description: ICON to display in the Service Directory.
+            enabled:
+                type: boolean
+                default: true
+            published:
+                type: boolean
+                default: true
+                description: If True then display this Service in the Service Directory.
+            public_key:
+                type: string
+                required: false
+                description: Public key to install into Instances to allows Services to SSH into them.
+            private_key_fn:
+                type: string
+                required: false
+                description: Location of private key file
+            versionNumber:
+                type: string
+                required: false
+                description: Version number of Service.
+            ceilometer_pub_sub_url:
+                type: string
+                required: false
+                description: REST URL of ceilometer PUB/SUB component
+
+    tosca.nodes.CeilometerTenant:
+        derived_from: tosca.nodes.Root
+        description: >
+            CORD: A Tenant of the Ceilometer Service.
+        properties:
+            kind:
+                type: string
+                default: generic
+                description: Kind of tenant
+
+topology_template:
+  node_templates:
+    service_ceilometer:
+      type: tosca.nodes.CeilometerService
+      requirements:
+      properties:
+          view_url: /admin/ceilometer/ceilometerservice/$id$/
+          kind: ceilometer
+          ceilometer_pub_sub_url: http://130.127.133.58:4455/
+          public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }
+      artifacts:
+          pubkey: /opt/xos/synchronizers/monitoring_channel/monitoring_channel_public_key
+
+    service_sflow:
+      type: tosca.nodes.SFlowService
+      requirements:
+      properties:
+          view_url: /admin/ceilometer/sflowservice/$id$/
+          kind: sflow
+          sflow_port: 6343
+          sflow_api_port: 33333
+
+    Private:
+      type: tosca.nodes.NetworkTemplate
+#
+#    ceilometer_network:
+#      type: tosca.nodes.network.Network.XOS
+#      properties:
+#          ip_version: 4
+#          labels: ceilometer_client_access
+#      requirements:
+#          - network_template:
+#              node: Private
+#              relationship: tosca.relationships.UsesNetworkTemplate
+#          - owner:
+#              node: mysite_ceilometer
+#              relationship: tosca.relationships.MemberOfSlice
+#          - connection:
+#              node: mysite_ceilometer
+#              relationship: tosca.relationships.ConnectsToSlice
+
+    mysite:
+      type: tosca.nodes.Site
+
+    trusty-server-multi-nic:
+      type: tosca.nodes.Image
+
+    ceilometer-trusty-server-multi-nic:
+      type: tosca.nodes.Image
+
+    m1.small:
+      type: tosca.nodes.Flavor
+
+    mysite_ceilometer:
+      description: Ceilometer Proxy Slice
+      type: tosca.nodes.Slice
+      requirements:
+          - ceilometer_service:
+              node: service_ceilometer
+              relationship: tosca.relationships.MemberOfService
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+          - default_image:
+                node: ceilometer-trusty-server-multi-nic
+                relationship: tosca.relationships.DefaultImage
+          - m1.small:
+                node: m1.small
+                relationship: tosca.relationships.DefaultFlavor
+      properties:
+          max_instances: 2
+
+    mysite_sflow:
+      description: Slice for sFlow service
+      type: tosca.nodes.Slice
+      requirements:
+          - sflow_service:
+              node: service_sflow
+              relationship: tosca.relationships.MemberOfService
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+          - default_image:
+                node: trusty-server-multi-nic
+                relationship: tosca.relationships.DefaultImage
+          - m1.small:
+                node: m1.small
+                relationship: tosca.relationships.DefaultFlavor
+      properties:
+          max_instances: 2
+
+    my_ceilometer_tenant:
+      description: Ceilometer Service default Tenant
+      type: tosca.nodes.CeilometerTenant
+      requirements:
+          - provider_service:
+              node: service_ceilometer
+              relationship: tosca.relationships.MemberOfService
+       
+    # Virtual machines
+    sflow_service_instance:
+      type: tosca.nodes.Compute
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+        # Guest Operating System properties
+        os:
+          properties:
+            # host Operating System image properties
+            architecture: x86_64
+            type: linux
+            distribution: Ubuntu
+            version: 14.10
+      requirements:
+          - slice:
+                node: mysite_sflow
+                relationship: tosca.relationships.MemberOfSlice
+
+    Ceilometer:
+      type: tosca.nodes.DashboardView
+      properties:
+          url: template:xosCeilometerDashboard
+    Tenant:
+      type: tosca.nodes.DashboardView
+      properties:
+          no-create: true
+          no-update: true
+          no-delete: true
+
+    padmin@vicci.org:
+      type: tosca.nodes.User
+      properties:
+          firstname: XOS
+          lastname: admin
+          is_admin: true
+      requirements:
+          - tenant_dashboard:
+              node: Tenant
+              relationship: tosca.relationships.UsesDashboard
+          - ceilometer_dashboard:
+              node: Ceilometer
+              relationship: tosca.relationships.UsesDashboard
diff --git a/xos/configurations/acord/cleanup.sh b/xos/configurations/acord/cleanup.sh
new file mode 100755
index 0000000..dfa1438
--- /dev/null
+++ b/xos/configurations/acord/cleanup.sh
@@ -0,0 +1,49 @@
+#!/bin/bash
+
+function cleanup_network {
+  NETWORK=$1
+  SUBNETS=`neutron net-show $NETWORK | grep -i subnets | awk '{print $4}'`
+  if [[ $SUBNETS != "" ]]; then
+      PORTS=`neutron port-list | grep -i $SUBNETS | awk '{print $2}'`
+      for PORT in $PORTS; do
+          echo "Deleting port $PORT"
+          neutron port-delete $PORT
+      done
+  fi
+  neutron net-delete $NETWORK
+}
+
+source ../setup/admin-openrc.sh
+
+echo "Deleting VMs"
+# Delete all VMs
+VMS=$( nova list --all-tenants|grep mysite|awk '{print $2}' )
+for VM in $VMS
+do
+    nova delete $VM
+done
+
+echo "Waiting 5 seconds..."
+sleep 5
+
+cleanup_network lan_network
+cleanup_network wan_network
+cleanup_network mysite_vsg-private
+cleanup_network mysite_vsg-access
+cleanup_network management
+
+echo "Deleting networks"
+# Delete all networks beginning with mysite_
+NETS=$( neutron net-list --all-tenants|grep mysite|awk '{print $2}' )
+for NET in $NETS
+do
+    neutron net-delete $NET
+done
+
+neutron net-delete lan_network || true
+neutron net-delete subscriber_network || true
+neutron net-delete public_network || true
+neutron net-delete hpc_client_network || true
+neutron net-delete ceilometer_network || true
+neutron net-delete management || true
+neutron net-delete mysite_vsg-access || true
diff --git a/xos/configurations/acord/docker-compose.yml b/xos/configurations/acord/docker-compose.yml
new file mode 100644
index 0000000..da9562e
--- /dev/null
+++ b/xos/configurations/acord/docker-compose.yml
@@ -0,0 +1,67 @@
+xos_db:
+    image: xosproject/xos-postgres
+    expose:
+        - "5432"
+
+xos_synchronizer_openstack:
+    command: bash -c "sleep 120; python /opt/xos/synchronizers/openstack/xos-synchronizer.py"
+    image: xosproject/xos-synchronizer-openstack
+    labels:
+        org.xosproject.kind: synchronizer
+        org.xosproject.target: openstack
+    links:
+        - xos_db
+    extra_hosts:
+        - ctl:${MYIP}
+    volumes:
+        - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
+        - ./xos_cord_config:/opt/xos/xos_configuration/xos_cord_config:ro
+        - ../setup:/root/setup:ro
+
+xos_synchronizer_monitoring_channel:
+    image: xosproject/xos-synchronizer-openstack
+    command: bash -c "sleep 120; python /opt/xos/synchronizers/monitoring_channel/monitoring_channel_synchronizer.py -C /opt/xos/synchronizers/monitoring_channel/monitoring_channel_synchronizer_config"
+    labels:
+        org.xosproject.kind: synchronizer
+        org.xosproject.target: monitoring_channel
+    links:
+        - xos_db
+    extra_hosts:
+        - ctl:${MYIP}
+    volumes:
+        - ../setup/id_rsa:/opt/xos/synchronizers/monitoring_channel/monitoring_channel_private_key:ro  # private key
+
+#Ensure exampleservice is enabled in xos/tools/xos-manage and xos/settings.py file before uncommenting below lines
+#xos_synchronizer_exampleservice:
+#    image: xosproject/xos-synchronizer-openstack
+#    command: bash -c "sleep 120; python /opt/xos/synchronizers/exampleservice/exampleservice-synchronizer.py -C /opt/xos/synchronizers/exampleservice/exampleservice_config"
+#    labels:
+#        org.xosproject.kind: synchronizer
+#        org.xosproject.target: exampleservice
+#    links:
+#        - xos_db
+#    volumes:
+#        - ../setup:/root/setup:ro
+#        - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
+#        - ../setup/id_rsa:/opt/xos/synchronizers/exampleservice/exampleservice_private_key:ro
+
+# FUTURE
+#xos_swarm_synchronizer:
+#    image: xosproject/xos-swarm-synchronizer
+#    labels:
+#        org.xosproject.kind: synchronizer
+#        org.xosproject.target: swarm
+
+xos:
+    image: xosproject/xos
+    command: python /opt/xos/manage.py runserver 0.0.0.0:8000 --insecure --makemigrations
+    ports:
+        - "9999:8000"
+    links:
+        - xos_db
+    volumes:
+      - ../setup:/root/setup:ro
+      - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
+      - ./xos_cord_config:/opt/xos/xos_configuration/xos_cord_config:ro
+      - ../setup/id_rsa.pub:/opt/xos/synchronizers/monitoring_channel/monitoring_channel_public_key:ro
+#      - ../setup/id_rsa.pub:/opt/xos/synchronizers/exampleservice/exampleservice_public_key:ro
diff --git a/xos/configurations/acord/xos_cord_config b/xos/configurations/acord/xos_cord_config
new file mode 100644
index 0000000..a5448f7
--- /dev/null
+++ b/xos/configurations/acord/xos_cord_config
@@ -0,0 +1,6 @@
+[gui]
+branding_name=CORD
+#branding_css=/static/cord.css
+branding_icon=/static/cord-logo.png
+branding_favicon=/static/cord-favicon.png
+branding_bg=/static/cord-bg.jpg
diff --git a/xos/configurations/common/Dockerfile.common b/xos/configurations/common/Dockerfile.common
new file mode 100644
index 0000000..aedd245
--- /dev/null
+++ b/xos/configurations/common/Dockerfile.common
@@ -0,0 +1,144 @@
+FROM       ubuntu:14.04.2
+MAINTAINER Andy Bavier <acb@cs.princeton.edu>
+
+# XXX Workaround for docker bug:
+# https://github.com/docker/docker/issues/6345
+# Kernel 3.15 breaks docker, uss the line below as a workaround
+# until there is a fix
+RUN ln -s -f /bin/true /usr/bin/chfn
+# XXX End workaround
+
+# Install.
+RUN apt-get update && apt-get install -y \
+    git \
+    postgresql \
+    python-psycopg2 \
+    graphviz \
+    graphviz-dev \
+    libxslt1.1 \
+    libxslt1-dev \
+    python-pip \
+    tar \
+    gcc \
+    python-httplib2 \
+    geoip-database \
+    libgeoip1 \
+    wget \
+    curl \
+    python-dev \
+    libyaml-dev \
+    pkg-config \
+    python-pycurl
+
+RUN pip install django==1.7
+RUN pip install djangorestframework==2.4.4
+RUN pip install markdown  # Markdown support for the browseable API.
+RUN pip install pyyaml    # YAML content-type support.
+RUN pip install django-filter==0.11.0  # Filtering support
+RUN pip install lxml  # XML manipulation library
+RUN pip install netaddr # IP Addr library
+RUN pip install pytz
+RUN pip install django-timezones
+RUN pip install requests
+RUN pip install python-logstash
+RUN pip install django-crispy-forms
+RUN pip install django-geoposition
+RUN pip install django-extensions
+RUN pip install django-suit==0.3a1
+RUN pip install django-bitfield
+RUN pip install django-ipware
+RUN pip install django-encrypted-fields
+RUN pip install python-keyczar
+RUN pip install pygraphviz --install-option="--include-path=/usr/include/graphviz" --install-option="--library-path=/usr/lib/graphviz/"
+RUN pip install dnslib
+
+RUN DEBIAN_FRONTEND=noninteractive apt-get install -y python-keystoneclient
+RUN DEBIAN_FRONTEND=noninteractive apt-get install -y python-novaclient
+RUN DEBIAN_FRONTEND=noninteractive apt-get install -y python-neutronclient
+RUN DEBIAN_FRONTEND=noninteractive apt-get install -y python-glanceclient
+RUN DEBIAN_FRONTEND=noninteractive apt-get install -y python-ceilometerclient
+
+RUN pip install django_rest_swagger
+
+RUN DEBIAN_FRONTEND=noninteractive apt-get install -y python-setuptools
+RUN easy_install python_gflags
+RUN easy_install --upgrade httplib2
+RUN easy_install google_api_python_client
+RUN easy_install httplib2.ca_certs_locater
+
+# Install custom Ansible
+RUN DEBIAN_FRONTEND=noninteractive apt-get install -y python-crypto
+RUN DEBIAN_FRONTEND=noninteractive apt-get install -y python-yaml
+RUN DEBIAN_FRONTEND=noninteractive apt-get install -y openssh-client
+RUN DEBIAN_FRONTEND=noninteractive apt-get install -y python-paramiko
+RUN DEBIAN_FRONTEND=noninteractive apt-get install -y python-jinja2
+RUN DEBIAN_FRONTEND=noninteractive apt-get install -y python-httplib2
+RUN git clone -b release1.8.2 git://github.com/ansible/ansible.git /opt/ansible
+RUN git clone -b release1.8.2 git://github.com/ansible/ansible-modules-extras.git /opt/ansible/lib/ansible/modules/extras
+RUN git clone -b release1.8.2 git://github.com/ansible/ansible-modules-extras.git /opt/ansible/v2/ansible/modules/extras
+RUN git clone git://github.com/sb98052/ansible-modules-core.git /opt/ansible/lib/ansible/modules/core
+RUN git clone git://github.com/sb98052/ansible-modules-core.git /opt/ansible/v2/ansible/modules/core
+ADD ansible-hosts /etc/ansible/hosts
+
+ADD http://code.jquery.com/jquery-1.9.1.min.js /usr/local/lib/python2.7/dist-packages/suit/static/suit/js/
+
+# For Observer
+RUN git clone git://git.planet-lab.org/fofum.git /tmp/fofum
+RUN cd /tmp/fofum; python setup.py install
+RUN rm -rf /tmp/fofum
+
+RUN mkdir -p /usr/local/share /bin
+ADD http://phantomjs.googlecode.com/files/phantomjs-1.7.0-linux-x86_64.tar.bz2 /usr/local/share/
+RUN tar jxvf /usr/local/share/phantomjs-1.7.0-linux-x86_64.tar.bz2 -C /usr/local/share/
+RUN rm -f /usr/local/share/phantomjs-1.7.0-linux-x86_64.tar.bz2
+RUN ln -s /usr/local/share/phantomjs-1.7.0-linux-x86_64 /usr/local/share/phantomjs
+RUN ln -s /usr/local/share/phantomjs/bin/phantomjs /bin/phantomjs
+
+# Supervisor
+RUN DEBIAN_FRONTEND=noninteractive apt-get install -y supervisor
+ADD observer.conf /etc/supervisor/conf.d/
+
+# Get XOS
+ADD xos /opt/xos
+
+# Initscript is broken in Ubuntu
+#ADD observer-initscript /etc/init.d/xosobserver
+
+RUN chmod +x /opt/xos/tools/xos-manage
+RUN /opt/xos/tools/xos-manage genkeys
+
+# Workaround for AUFS issue
+# https://github.com/docker/docker/issues/783#issuecomment-56013588
+RUN mkdir /etc/ssl/private-copy; mv /etc/ssl/private/* /etc/ssl/private-copy/; rm -r /etc/ssl/private; mv /etc/ssl/private-copy /etc/ssl/private; chmod -R 0700 /etc/ssl/private; chown -R postgres /etc/ssl/private
+
+# Set postgres password to match default value in settings.py
+RUN service postgresql start; sudo -u postgres psql -c "alter user postgres with password 'password';"
+
+# Turn DEBUG on so that devel server will serve static files
+#    (not necessary if --insecure is passed to 'manage.py runserver')
+# RUN sed -i 's/DEBUG = False/DEBUG = True/' /opt/xos/xos/settings.py
+
+# Cruft to workaround problems with migrations, should go away...
+RUN /opt/xos/tools/xos-manage remigrate
+
+# git clone uses cached copy, doesn't pick up latest
+RUN git -C /opt/ansible pull
+RUN git -C /opt/ansible/lib/ansible/modules/core pull
+RUN git -C /opt/ansible/v2/ansible/modules/core pull
+
+# install Tosca engine
+RUN apt-get install -y m4
+RUN pip install python-dateutil
+RUN bash /opt/xos/tosca/install_tosca.sh
+
+EXPOSE 8000
+
+# Set environment variables.
+ENV HOME /root
+
+# Define working directory.
+WORKDIR /root
+
+# Define default command.
+#CMD ["/bin/bash"]
+#CMD /opt/xos/tools/docker_start_xos
diff --git a/xos/configurations/common/Makefile.cloudlab b/xos/configurations/common/Makefile.cloudlab
new file mode 100644
index 0000000..7ab8a54
--- /dev/null
+++ b/xos/configurations/common/Makefile.cloudlab
@@ -0,0 +1,41 @@
+MYFLATLANIF:=$(shell netstat -i |grep "flat"|awk '{print $$1}' )
+ifndef MYFLATLANIF
+$(error MYFLATLANIF is empty)
+endif
+MYFLATLANIP:=$(shell ifconfig $(MYFLATLANIF) | grep "inet addr" | awk -F: '{print $$2}' | awk '{print $$1}' )
+SETUPDIR:=../setup
+
+all: prereqs admin-openrc flat_name nodes_yaml public_key private_key ceilometer_url other_keys
+
+prereqs:
+	make -f Makefile.prereqs
+	mkdir -p $(SETUPDIR)
+
+admin-openrc:
+	sudo cat /root/setup/admin-openrc.sh > $(SETUPDIR)/admin-openrc.sh
+	sudo cat /root/setup/settings > $(SETUPDIR)/controller_settings
+	echo 'CONTROLLER_FLAT_LAN_IP=$(MYFLATLANIP)' >> $(SETUPDIR)/controller_settings
+
+flat_name:
+	bash -c "source $(SETUPDIR)/admin-openrc.sh ; neutron net-list" |grep flat|awk '{printf "%s",$$4}' > $(SETUPDIR)/flat_net_name
+	[ -s $(SETUPDIR)/flat_net_name ] # throw error if flat_net_name is empty
+
+nodes_yaml:
+	export SETUPDIR=$(SETUPDIR); bash ./make-nodes-yaml.sh 
+
+ceilometer_url:
+	echo http://`hostname -i`/xosmetering/ > $(SETUPDIR)/ceilometer_url
+
+public_key: ~/.ssh/id_rsa.pub
+	cp ~/.ssh/id_rsa.pub $(SETUPDIR)
+
+private_key: ~/.ssh/id_rsa
+	cp ~/.ssh/id_rsa $(SETUPDIR)
+
+~/.ssh/id_rsa.pub:
+	cat /dev/zero | ssh-keygen -q -N ""
+
+other_keys: public_key private_key
+	sudo cat /root/setup/id_rsa > $(SETUPDIR)/node_key
+	sudo cat /root/setup/id_rsa.pub > $(SETUPDIR)/node_key.pub
+	sudo cp $(SETUPDIR)/id_rsa.pub $(SETUPDIR)/padmin_public_key
diff --git a/xos/configurations/common/Makefile.devstack b/xos/configurations/common/Makefile.devstack
new file mode 100644
index 0000000..0dff27c
--- /dev/null
+++ b/xos/configurations/common/Makefile.devstack
@@ -0,0 +1,42 @@
+# This shouldn't be hardcoded
+DEVSTACK_ROOT:=~/devstack
+SETUPDIR:=../setup
+
+all: prereqs admin-openrc flat_name nodes_yaml public_key private_key ceilometer_url other_keys net_fix
+
+prereqs:
+	make -f Makefile.prereqs
+	sudo pip install httpie --upgrade
+	mkdir -p $(SETUPDIR)
+
+admin-openrc:
+	bash ./devstack-creds.sh $(DEVSTACK_ROOT) > $(SETUPDIR)/admin-openrc.sh
+	touch $(SETUPDIR)/controller_settings
+
+flat_name:
+	echo private|tr -d '\n' > $(SETUPDIR)/flat_net_name
+	bash -c "source $(SETUPDIR)/admin-openrc.sh; neutron net-update private --shared"
+
+nodes_yaml:
+	export SETUPDIR=$(SETUPDIR); bash ./make-nodes-yaml.sh
+
+ceilometer_url:
+	echo http://`hostname -i`/xosmetering/ > $(SETUPDIR)/ceilometer_url
+
+public_key: ~/.ssh/id_rsa.pub
+	cp ~/.ssh/id_rsa.pub $(SETUPDIR)
+
+private_key: ~/.ssh/id_rsa
+	cp ~/.ssh/id_rsa $(SETUPDIR)
+
+~/.ssh/id_rsa.pub:
+	cat /dev/zero | ssh-keygen -q -N ""
+
+other_keys: public_key private_key
+	cp $(SETUPDIR)/id_rsa $(SETUPDIR)/node_key
+	cp $(SETUPDIR)/id_rsa.pub $(SETUPDIR)/node_key.pub
+	cp $(SETUPDIR)/id_rsa.pub $(SETUPDIR)/padmin_public_key
+
+net_fix:
+	sudo devstack/net-fix.sh
+	bash -c "source $(SETUPDIR)/admin-openrc.sh; neutron subnet-update private-subnet --dns-nameservers list=true 8.8.8.8 8.8.4.4"
diff --git a/xos/configurations/common/Makefile.opencloud b/xos/configurations/common/Makefile.opencloud
new file mode 100644
index 0000000..8cf9f29
--- /dev/null
+++ b/xos/configurations/common/Makefile.opencloud
@@ -0,0 +1,40 @@
+MYFLATLANIF:=$(shell netstat -i |grep "flat"|awk '{print $$1}' )
+MYFLATLANIP:=$(shell ifconfig $(MYFLATLANIF) | grep "inet addr" | awk -F: '{print $$2}' | awk '{print $$1}' )
+SETUPDIR:=../setup
+
+all: prereqs admin-openrc flat_name nodes_yaml public_key private_key ceilometer_url node_key
+
+prereqs:
+	make -f Makefile.prereqs
+	mkdir -p $(SETUPDIR)
+
+admin-openrc:
+	sudo cat /root/setup/admin-openrc.sh > $(SETUPDIR)/admin-openrc.sh
+	sudo cat /root/setup/settings > $(SETUPDIR)/controller_settings
+	echo 'CONTROLLER_FLAT_LAN_IP=$(MYFLATLANIP)' >> $(SETUPDIR)/controller_settings
+
+flat_name:
+	sudo bash -c "source /root/setup/admin-openrc.sh ; neutron net-list" |grep flat|awk '{printf "%s",$$4}' > $(SETUPDIR)/flat_net_name
+	[ -s $(SETUPDIR)/flat_net_name ] # throw error if flat_net_name is empty
+
+nodes_yaml:
+	bash ./make-nodes-yaml.sh > $(SETUPDIR)/nodes.yaml
+
+ceilometer_url:
+	echo http://`hostname -i`/xosmetering/ > $(SETUPDIR)/ceilometer_url
+
+public_key: ~/.ssh/id_rsa.pub
+	cp ~/.ssh/id_rsa.pub $(SETUPDIR)
+
+private_key: ~/.ssh/id_rsa
+	cp ~/.ssh/id_rsa $(SETUPDIR)
+
+~/.ssh/id_rsa.pub:
+	cat /dev/zero | ssh-keygen -q -N ""
+
+node_key:
+	sudo cat /root/setup/id_rsa > $(SETUPDIR)/node_key
+	sudo cat /root/setup/id_rsa.pub > $(SETUPDIR)/node_key.pub
+
+images:
+	source admin-openrc.sh; glance image-show trusty-server-multi-nic || glance image-create --name trusty-server-multi-nic --disk-format qcow2 --file /proj/xos-PG0/acb/images/trusty-server-multi-nic.img --container-format bare
diff --git a/xos/configurations/common/Makefile.prereqs b/xos/configurations/common/Makefile.prereqs
new file mode 100644
index 0000000..fce51be
--- /dev/null
+++ b/xos/configurations/common/Makefile.prereqs
@@ -0,0 +1,41 @@
+UBUNTU:=$(shell which apt > /dev/null 2>&1; echo $$?)
+
+ifeq ($(UBUNTU),0)
+
+# ******************* apt-based distros ***************************
+prereqs: /usr/bin/http docker /usr/bin/curl /usr/local/bin/docker-compose
+
+/usr/bin/http:
+	sudo apt-get -y install httpie
+
+/usr/bin/curl:
+	sudo apt-get -y install curl
+
+docker:
+	which docker > /dev/null || wget -qO- https://get.docker.com/ | sh
+	sudo usermod -aG docker $(shell whoami)
+
+else
+
+# ****************** RPM-based distros ******************
+
+# (untested / work-in-progress)
+
+prereqs: /usr/bin/pip /usr/bin/http docker /usr/local/bin/docker-compose
+
+/usr/bin/pip:
+	curl "https://bootstrap.pypa.io/get-pip.py" -o "get-pip.py"
+	sudo python ./get-pip.py
+
+docker:
+	which docker > /dev/null || wget -qO- https://get.docker.com/ | sh
+	sudo usermod -aG docker $(shell whoami)
+
+/usr/bin/http:
+	sudo pip install httpie
+
+endif
+
+/usr/local/bin/docker-compose:
+	sudo bash -c "curl -L https://github.com/docker/compose/releases/download/1.5.2/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose"
+	sudo chmod +x /usr/local/bin/docker-compose
diff --git a/xos/configurations/common/base.yaml b/xos/configurations/common/base.yaml
new file mode 100644
index 0000000..3638dd9
--- /dev/null
+++ b/xos/configurations/common/base.yaml
@@ -0,0 +1,89 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+# Note:
+#   assumes the following have been created and filled with appropriate data:
+#       /root/setup/admin_openrc
+#       /root/setup/flat_net_name
+#       /root/setup/padmin_public_key
+
+description: >
+    * Adds OpenCloud Sites, Deployments, and Controllers.
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    trusty-server-multi-nic:
+      type: tosca.nodes.Image
+      properties:
+         disk_format: QCOW2
+         container_format: BARE
+
+    MyDeployment:
+      type: tosca.nodes.Deployment
+      properties:
+          flavors: m1.large, m1.medium, m1.small
+      requirements:
+          - image:
+              node: trusty-server-multi-nic
+              relationship: tosca.relationships.SupportsImage
+
+    CloudLab:
+      type: tosca.nodes.Controller
+      requirements:
+          - deployment:
+              node: MyDeployment
+              relationship: tosca.relationships.ControllerDeployment
+      properties:
+          backend_type: OpenStack
+          version: Kilo
+          auth_url: { get_script_env: [ SELF, adminrc, OS_AUTH_URL, LOCAL_FILE] }
+          admin_user: { get_script_env: [ SELF, adminrc, OS_USERNAME, LOCAL_FILE] }
+          admin_password: { get_script_env: [ SELF, adminrc, OS_PASSWORD, LOCAL_FILE] }
+          admin_tenant: { get_script_env: [ SELF, adminrc, OS_TENANT_NAME, LOCAL_FILE] }
+          rabbit_user: { get_script_env: [ SELF, controller_settings, RABBIT_USER, LOCAL_FILE] }
+          rabbit_password: { get_script_env: [ SELF, controller_settings, RABBIT_PASS, LOCAL_FILE] }
+          rabbit_host: { get_script_env: [ SELF, controller_settings, CONTROLLER_FLAT_LAN_IP, LOCAL_FILE] }
+          domain: Default
+      artifacts:
+          adminrc: /root/setup/admin-openrc.sh
+          controller_settings: /root/setup/controller_settings
+
+    mysite:
+      type: tosca.nodes.Site
+      properties:
+          display_name: MySite
+          site_url: http://opencloud.us/
+      requirements:
+          - deployment:
+               node: MyDeployment
+               relationship: tosca.relationships.SiteDeployment
+               requirements:
+                   - controller:
+                       node: CloudLab
+                       relationship: tosca.relationships.UsesController
+
+    Public shared IPv4:
+      type: tosca.nodes.NetworkTemplate
+      properties:
+          visibility: private
+          translation: NAT
+          shared_network_name: { get_artifact: [ SELF, flat_net_name, LOCAL_FILE] }
+      artifacts:
+          flat_net_name: /root/setup/flat_net_name
+
+    padmin@vicci.org:
+      type: tosca.nodes.User
+      requirements:
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+      properties:
+          public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE ] }
+          is_admin: true
+          is_active: true
+          firstname: XOS
+          lastname: admin
+      artifacts:
+          pubkey: /root/setup/padmin_public_key
diff --git a/xos/configurations/common/cloudlab-openstack.yaml b/xos/configurations/common/cloudlab-openstack.yaml
new file mode 100644
index 0000000..969f84c
--- /dev/null
+++ b/xos/configurations/common/cloudlab-openstack.yaml
@@ -0,0 +1,89 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+# Note:
+#   assumes mydeployment.yaml has already been run, and the following exist:
+#       MyDeployment
+#       mysite
+#       padmin@vicci.org
+#       Public Shared IPv4
+#   assumes the following have been created and filled with appropriate data:
+#       /root/setup/admin_openrc
+#       /root/setup/flat_net_name
+#       /root/setup/padmin_public_key
+
+description: >
+    * Adds OpenCloud Sites, Deployments, and Controllers.
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    trusty-server-multi-nic:
+      type: tosca.nodes.Image
+      properties:
+         disk_format: QCOW2
+         container_format: BARE
+
+    MyDeployment:
+      type: tosca.nodes.Deployment
+      properties:
+          no-create: True
+          no-delete: True
+      requirements:
+          - image:
+              node: trusty-server-multi-nic
+              relationship: tosca.relationships.SupportsImage
+
+    CloudLab:
+      type: tosca.nodes.Controller
+      requirements:
+          - deployment:
+              node: MyDeployment
+              relationship: tosca.relationships.ControllerDeployment
+      properties:
+          backend_type: OpenStack
+          version: Kilo
+          auth_url: { get_script_env: [ SELF, adminrc, OS_AUTH_URL, LOCAL_FILE] }
+          admin_user: { get_script_env: [ SELF, adminrc, OS_USERNAME, LOCAL_FILE] }
+          admin_password: { get_script_env: [ SELF, adminrc, OS_PASSWORD, LOCAL_FILE] }
+          admin_tenant: { get_script_env: [ SELF, adminrc, OS_TENANT_NAME, LOCAL_FILE] }
+          rabbit_user: { get_script_env: [ SELF, controller_settings, RABBIT_USER, LOCAL_FILE] }
+          rabbit_password: { get_script_env: [ SELF, controller_settings, RABBIT_PASS, LOCAL_FILE] }
+          rabbit_host: { get_script_env: [ SELF, controller_settings, CONTROLLER_FLAT_LAN_IP, LOCAL_FILE] }
+          domain: Default
+      artifacts:
+          adminrc: /root/setup/admin-openrc.sh
+          controller_settings: /root/setup/controller_settings
+
+    mysite:
+      type: tosca.nodes.Site
+      properties:
+          no-create: True
+          no-delete: True
+      requirements:
+          - deployment:
+               node: MyDeployment
+               relationship: tosca.relationships.SiteDeployment
+               requirements:
+                   - controller:
+                       node: CloudLab
+                       relationship: tosca.relationships.UsesController
+
+    Public shared IPv4:
+      type: tosca.nodes.NetworkTemplate
+      properties:
+          no-create: True
+          no-delete: True
+          shared_network_name: { get_artifact: [ SELF, flat_net_name, LOCAL_FILE] }
+      artifacts:
+          flat_net_name: /root/setup/flat_net_name
+
+    padmin@vicci.org:
+      type: tosca.nodes.User
+      properties:
+          no-create: True
+          no-delete: True
+          public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE ] }
+      artifacts:
+          pubkey: /root/setup/padmin_public_key
diff --git a/xos/configurations/common/devstack-creds.sh b/xos/configurations/common/devstack-creds.sh
new file mode 100644
index 0000000..b90e6ec
--- /dev/null
+++ b/xos/configurations/common/devstack-creds.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+DEVSTACK_ROOT=$1
+
+source $DEVSTACK_ROOT/openrc admin admin
+echo export OS_TENANT_NAME=$OS_TENANT_NAME
+echo export OS_USERNAME=$OS_USERNAME
+echo export OS_PASSWORD=$OS_PASSWORD
+echo export OS_AUTH_URL=$OS_AUTH_URL
diff --git a/xos/configurations/common/devstack/local.conf b/xos/configurations/common/devstack/local.conf
new file mode 100644
index 0000000..15a95fb
--- /dev/null
+++ b/xos/configurations/common/devstack/local.conf
@@ -0,0 +1,32 @@
+# A single node devstack configuration for use with XOS
+[[local|localrc]]
+
+DOWNLOAD_DEFAULT_IMAGES=false
+IMAGE_URLS="http://www.planet-lab.org/cord/trusty-server-multi-nic.img,"
+#IMAGE_URLS+="http://www.vicci.org/cord/ceilometer-trusty-server-multi-nic.compressed.qcow2"
+LIBVIRT_FIREWALL_DRIVER=nova.virt.firewall.NoopFirewallDriver
+# Append the git branch name if you wish to download ceilometer from a specific branch
+#enable_plugin ceilometer https://git.openstack.org/openstack/ceilometer 
+
+disable_service n-net
+enable_service q-svc
+enable_service q-agt
+enable_service q-dhcp
+enable_service q-l3
+enable_service q-meta
+# Optional, to enable tempest configuration as part of devstack
+enable_service tempest
+
+# Uncomment below lines if you are installing kilo version of ceilometer
+#enable_service ceilometer-acentral
+#enable_service ceilometer-anotification
+#enable_service ceilometer-collector
+#enable_service ceilometer-alarm-singleton
+#enable_service ceilometer-alarm-notifier
+#enable_service ceilometer-alarm-evaluator
+#enable_service ceilometer-api
+#enable_service ceilometer-acompute
+#CEILOMETER_BACKEND=mongodb
+
+## Neutron options
+Q_USE_SECGROUP=False
diff --git a/xos/configurations/common/devstack/net-fix.sh b/xos/configurations/common/devstack/net-fix.sh
new file mode 100755
index 0000000..5b486bd
--- /dev/null
+++ b/xos/configurations/common/devstack/net-fix.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+PRIMARY=$( route | grep default | awk '{print $NF}' )
+RULE="POSTROUTING -t nat -o $PRIMARY -s 172.24.4.0/24 -j MASQUERADE"
+
+iptables -C $RULE || iptables -A $RULE
diff --git a/xos/configurations/common/devstack/setup-devstack.sh b/xos/configurations/common/devstack/setup-devstack.sh
new file mode 100644
index 0000000..bfbb8f8
--- /dev/null
+++ b/xos/configurations/common/devstack/setup-devstack.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+# If running on a CloudLab node, set up extra disk space
+if [ -e /usr/testbed/bin/mkextrafs ]
+then
+    sudo mkdir -p /opt/stack
+    sudo /usr/testbed/bin/mkextrafs -f /opt/stack
+fi
+
+cd ~
+git clone https://github.com/open-cloud/xos.git
+git clone https://git.openstack.org/openstack-dev/devstack
+cd ~/devstack
+git checkout stable/kilo
+cp ~/xos/xos/configurations/common/devstack/local.conf .
+./stack.sh
diff --git a/xos/configurations/common/disable-onboarding.yaml b/xos/configurations/common/disable-onboarding.yaml
new file mode 100644
index 0000000..acb75c8
--- /dev/null
+++ b/xos/configurations/common/disable-onboarding.yaml
@@ -0,0 +1,16 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Onboard the exampleservice
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    xos:
+      type: tosca.nodes.XOS
+      properties:
+        no-create: true
+        no-delete: true
+        enable_build: false
+
diff --git a/xos/configurations/common/enable-onboarding.yaml b/xos/configurations/common/enable-onboarding.yaml
new file mode 100644
index 0000000..98e433c
--- /dev/null
+++ b/xos/configurations/common/enable-onboarding.yaml
@@ -0,0 +1,16 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Onboard the exampleservice
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    xos:
+      type: tosca.nodes.XOS
+      properties:
+        no-create: true
+        no-delete: true
+        enable_build: true
+
diff --git a/xos/configurations/common/fixtures.yaml b/xos/configurations/common/fixtures.yaml
new file mode 100644
index 0000000..6b3234e
--- /dev/null
+++ b/xos/configurations/common/fixtures.yaml
@@ -0,0 +1,134 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Some basic fixtures
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+
+    xos:
+      type: tosca.nodes.XOS
+
+
+# -----------------------------------------------------------------------------
+# Network Parameter Types
+# -----------------------------------------------------------------------------
+
+    s_tag:
+      type: tosca.nodes.NetworkParameterType
+
+    c_tag:
+      type: tosca.nodes.NetworkParameterType
+
+    next_hop:
+      type: tosca.nodes.NetworkParameterType
+
+    device:
+      type: tosca.nodes.NetworkParameterType
+
+    bridge:
+      type: tosca.nodes.NetworkParameterType
+
+    neutron_port_name:
+      type: tosca.nodes.NetworkParameterType
+
+# ----------------------------------------------------------------------------
+# Roles
+# ----------------------------------------------------------------------------
+
+    siterole#admin:
+      type: tosca.nodes.SiteRole
+
+    siterole#pi:
+      type: tosca.nodes.SiteRole
+
+    siterole#tech:
+      type: tosca.nodes.SiteRole
+
+    tenantrole#admin:
+      type: tosca.nodes.TenantRole
+
+    tenantrole#access:
+      type: tosca.nodes.TenantRole
+
+    deploymentrole#admin:
+      type: tosca.nodes.DeploymentRole
+
+    slicerole#admin:
+      type: tosca.nodes.SliceRole
+
+    slicerole#access:
+      type: tosca.nodes.SliceRole
+
+# -----------------------------------------------------------------------------
+# Flavors
+# -----------------------------------------------------------------------------
+
+    m1.small:
+      type: tosca.nodes.Flavor
+
+    m1.medium:
+      type: tosca.nodes.Flavor
+
+    m1.large:
+      type: tosca.nodes.Flavor
+
+# -----------------------------------------------------------------------------
+# Dashboard Views
+# -----------------------------------------------------------------------------
+
+    xsh:
+      type: tosca.nodes.DashboardView
+      properties:
+          url: template:xsh
+
+    Customize:
+      type: tosca.nodes.DashboardView
+      properties:
+          url: template:customize
+
+    Tenant:
+      type: tosca.nodes.DashboardView
+      properties:
+          url: template:xosTenant
+
+    Developer:
+      type: tosca.nodes.DashboardView
+      properties:
+          url: template:xosDeveloper
+
+    Services Grid:
+      type: tosca.nodes.DashboardView
+      properties:
+          url: template:xosServiceGrid
+
+# -----------------------------------------------------------------------------
+# Network Templates
+# -----------------------------------------------------------------------------
+
+    Private:
+      type: tosca.nodes.NetworkTemplate
+      properties:
+          visibility: private
+          translation: none
+
+    Public shared IPv4:
+      type: tosca.nodes.NetworkTemplate
+      properties:
+          visibility: private
+          translation: NAT
+          shared_network_name: nat-net
+
+    Public dedicated IPv4:
+      type: tosca.nodes.NetworkTemplate
+      properties:
+          visibility: public
+          translation: none
+          shared_network_name: ext-net
+
+
+
+
+
diff --git a/xos/configurations/common/make-images-yaml.sh b/xos/configurations/common/make-images-yaml.sh
new file mode 100644
index 0000000..6321a9d
--- /dev/null
+++ b/xos/configurations/common/make-images-yaml.sh
@@ -0,0 +1,48 @@
+FN=$SETUPDIR/images.yaml
+
+rm -f $FN
+
+cat >> $FN <<EOF
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+imports:
+   - custom_types/xos.yaml
+
+description: autogenerated nodes file
+
+topology_template:
+  node_templates:
+    mysite:
+        type: tosca.nodes.Site
+
+EOF
+
+IMAGES=$( bash -c "source $SETUPDIR/admin-openrc.sh ; glance image-list" |grep -v ID|grep -v +|awk '{print $4}' )
+I=0
+for IMAGE in $IMAGES; do
+    echo $IMAGE
+    cat >> $FN <<EOF
+    $IMAGE:
+      type: tosca.nodes.Image
+      properties:
+         disk_format: QCOW2
+         container_format: BARE
+
+EOF
+done
+
+cat >> $FN <<EOF
+    MyDeployment:
+      type: tosca.nodes.Deployment
+      properties:
+          flavors: m1.large, m1.medium, m1.small
+      requirements:
+EOF
+
+for IMAGE in $IMAGES; do
+    cat >> $FN <<EOF
+          - image:
+              node: $IMAGE
+              relationship: tosca.relationships.SupportsImage
+EOF
+done
diff --git a/xos/configurations/common/make-nodes-yaml.sh b/xos/configurations/common/make-nodes-yaml.sh
new file mode 100644
index 0000000..65e16bb
--- /dev/null
+++ b/xos/configurations/common/make-nodes-yaml.sh
@@ -0,0 +1,36 @@
+FN=$SETUPDIR/nodes.yaml
+
+rm -f $FN
+
+cat >> $FN <<EOF
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+imports:
+   - custom_types/xos.yaml
+
+description: autogenerated nodes file
+
+topology_template:
+  node_templates:
+    MyDeployment:
+        type: tosca.nodes.Deployment
+    mysite:
+        type: tosca.nodes.Site
+EOF
+
+NODES=$( bash -c "source $SETUPDIR/admin-openrc.sh ; nova host-list" |grep compute|awk '{print $2}' )
+I=0
+for NODE in $NODES; do
+    echo $NODE
+    cat >> $FN <<EOF
+    $NODE:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: mysite
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: MyDeployment
+            relationship: tosca.relationships.MemberOfDeployment
+EOF
+done
diff --git a/xos/configurations/common/mydeployment.yaml b/xos/configurations/common/mydeployment.yaml
new file mode 100644
index 0000000..c81fd93
--- /dev/null
+++ b/xos/configurations/common/mydeployment.yaml
@@ -0,0 +1,75 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Some basic fixtures
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    m1.large:
+      type: tosca.nodes.Flavor
+
+    m1.medium:
+      type: tosca.nodes.Flavor
+
+    m1.small:
+      type: tosca.nodes.Flavor
+
+    m1.xlarge:
+      type: tosca.nodes.Flavor
+
+    MyDeployment:
+      type: tosca.nodes.Deployment
+      requirements:
+          - m1.xlarge:
+             node: m1.large
+             relationship: tosca.relationships.SupportsFlavor
+          - m1.large:
+             node: m1.large
+             relationship: tosca.relationships.SupportsFlavor
+          - m1.medium:
+             node: m1.medium
+             relationship: tosca.relationships.SupportsFlavor
+          - m1.small:
+             node: m1.small
+             relationship: tosca.relationships.SupportsFlavor
+
+    mysite:
+      type: tosca.nodes.Site
+      properties:
+          display_name: MySite
+      requirements:
+          - deployment:
+               node: MyDeployment
+               relationship: tosca.relationships.SiteDeployment
+
+    # Attach the Tenant view to the MyDeployment deployment
+    Tenant:
+      type: tosca.nodes.DashboardView
+      properties:
+          no-create: true
+          no-delete: true
+      requirements:
+          - deployment:
+              node: MyDeployment
+              relationship: tosca.relationships.SupportsDeployment
+
+    padmin@vicci.org:
+      type: tosca.nodes.User
+      properties:
+          password: letmein
+#          encrypted_password: pbkdf2_sha256$12000$Qufx9iqtaYma$xs0YurPOcj9qYQna/Qrb3K+im9Yr2XEVr0J4Kqek7AE=
+          firstname: XOS
+          lastname: admin
+          is_admin: true
+      requirements:
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+          - tenant_dashboard:
+              node: Tenant
+              relationship: tosca.relationships.UsesDashboard
+
+
+
diff --git a/xos/configurations/common/wait_for_onboarding_ready.sh b/xos/configurations/common/wait_for_onboarding_ready.sh
new file mode 100755
index 0000000..dbfdde8
--- /dev/null
+++ b/xos/configurations/common/wait_for_onboarding_ready.sh
@@ -0,0 +1,28 @@
+#! /bin/bash
+
+display_usage() { 
+    echo -e "\nUsage:\n$0 [xos-listen-port] [name] \n" 
+} 
+
+if [  $# -lt 2 ] 
+then 
+    display_usage
+    exit 1
+fi 
+
+echo "Waiting for $2 to be onboarded"
+while [[ 1 ]]; do
+    STATUS=`curl 0.0.0.0:$1/api/utility/onboarding/$2/ready/ 2> /dev/null`
+    if [[ "$STATUS" == "true" ]]; then
+        echo "$2 is onboarded"
+        exit 0
+    fi
+    echo -ne "."
+    sleep 1
+#    RUNNING_CONTAINER=`sudo docker ps|grep "xos"|awk '{print $$NF}'`
+#    if [[ $RUNNING_CONTAINER == "" ]]; then
+#        echo Container may have failed. check with \"make showlogs\'
+#        exit 1
+#    fi
+done
+
diff --git a/xos/configurations/common/wait_for_xos.sh b/xos/configurations/common/wait_for_xos.sh
new file mode 100644
index 0000000..362778b
--- /dev/null
+++ b/xos/configurations/common/wait_for_xos.sh
@@ -0,0 +1,12 @@
+#! /bin/bash
+echo "Waiting for XOS to come up"
+until http 0.0.0.0:9999 &> /dev/null
+do
+    sleep 1
+    RUNNING_CONTAINER=`sudo docker ps|grep "xos"|awk '{print $$NF}'`
+    if [[ $RUNNING_CONTAINER == "" ]]; then
+        echo Container may have failed. check with \"make showlogs\'
+        exit 1
+    fi
+done
+echo "XOS is ready"
diff --git a/xos/configurations/common/wait_for_xos_file.sh b/xos/configurations/common/wait_for_xos_file.sh
new file mode 100755
index 0000000..1214dc4
--- /dev/null
+++ b/xos/configurations/common/wait_for_xos_file.sh
@@ -0,0 +1,24 @@
+#! /bin/bash
+
+display_usage() { 
+    echo -e "\nUsage:\n$0 [fn] \n" 
+} 
+
+if [  $# -lt 1 ] 
+then 
+    display_usage
+    exit 1
+fi 
+
+echo "Waiting for XOS to create file $1"
+
+until find $1 &> /dev/null
+do
+    sleep 1
+    RUNNING_CONTAINER=`sudo docker ps|grep "xos"|awk '{print $$NF}'`
+    if [[ $RUNNING_CONTAINER == "" ]]; then
+        echo Container may have failed. check with \"make showlogs\'
+        exit 1
+    fi
+done
+echo "XOS is ready"
diff --git a/xos/configurations/common/wait_for_xos_port.sh b/xos/configurations/common/wait_for_xos_port.sh
new file mode 100755
index 0000000..9c9e041
--- /dev/null
+++ b/xos/configurations/common/wait_for_xos_port.sh
@@ -0,0 +1,23 @@
+#! /bin/bash
+
+display_usage() { 
+    echo -e "\nUsage:\n$0 [xos-listen-port] \n" 
+} 
+
+if [  $# -lt 1 ] 
+then 
+    display_usage
+    exit 1
+fi 
+
+echo "Waiting for XOS to start listening on port $1"
+until curl 0.0.0.0:$1 &> /dev/null
+do
+    sleep 1
+    RUNNING_CONTAINER=`sudo docker ps|grep "xos"|awk '{print $$NF}'`
+    if [[ $RUNNING_CONTAINER == "" ]]; then
+        echo Container may have failed. check with \"make showlogs\'
+        exit 1
+    fi
+done
+echo "XOS is ready"
diff --git a/xos/configurations/common/xos_common_config b/xos/configurations/common/xos_common_config
new file mode 100644
index 0000000..76ba747
--- /dev/null
+++ b/xos/configurations/common/xos_common_config
@@ -0,0 +1,47 @@
+[plc]
+name=plc
+deployment=plc
+
+[db]
+name=xos
+user=postgres
+password=password
+host=localhost
+port=5432
+
+[api]
+host=localhost
+port=8000
+ssl_key=None
+ssl_cert=None
+ca_ssl_cert=None
+ratelimit_enabled=0
+omf_enabled=0
+mail_support_address=support@localhost
+nova_enabled=True
+logfile=/var/log/xos.log
+
+[nova]
+admin_user=admin@domain.com
+admin_password=admin
+admin_tenant=admin
+url=http://localhost:5000/v2.0/
+default_image=None
+default_flavor=m1.small
+default_security_group=default
+ca_ssl_cert=/etc/ssl/certs/ca-certificates.crt
+
+[observer]
+pretend=False
+backoff_disabled=True
+images_directory=/opt/xos/images
+dependency_graph=/opt/xos/model-deps
+logfile=/var/log/xos_backend.log
+save_ansible_output=True
+
+[gui]
+disable_minidashboard=True
+branding_name=Open Cloud
+branding_icon=/static/logo.png
+branding_favicon=/static/favicon.png
+branding_bg=/static/bg.jpg
diff --git a/xos/configurations/cord-deprecated/Dockerfile.cord b/xos/configurations/cord-deprecated/Dockerfile.cord
new file mode 100644
index 0000000..3e63eb2
--- /dev/null
+++ b/xos/configurations/cord-deprecated/Dockerfile.cord
@@ -0,0 +1,27 @@
+RUN mkdir -p /root/setup
+ADD xos/configurations/common/admin-openrc.sh /root/setup/
+ADD xos/configurations/common/controller_settings /root/setup/
+ADD xos/configurations/common/flat_net_name /root/setup/
+ADD xos/configurations/common/nodes.yaml /opt/xos/configurations/commmon/
+ADD xos/configurations/common/id_rsa.pub /root/setup/padmin_public_key
+ADD xos/configurations/common/id_rsa.pub /opt/xos/synchronizers/vcpe/vcpe_public_key
+ADD xos/configurations/common/id_rsa /opt/xos/synchronizers/vcpe/vcpe_private_key
+ADD xos/configurations/common/id_rsa.pub /opt/xos/synchronizers/monitoring_channel/monitoring_channel_public_key
+ADD xos/configurations/common/id_rsa /opt/xos/synchronizers/monitoring_channel/monitoring_channel_private_key
+ADD xos/configurations/common/id_rsa.pub /opt/xos/synchronizers/onos/onos_key.pub
+ADD xos/configurations/common/id_rsa /opt/xos/synchronizers/onos/onos_key
+ADD xos/configurations/common/node_key.pub /root/setup/node_key.pub
+ADD xos/configurations/common/node_key /root/setup/node_key
+ADD xos/configurations/common/ceilometer_url /root/setup/ceilometer_url
+ADD xos/synchronizers/vcpe/supervisor/vcpe-observer.conf /etc/supervisor/conf.d/
+ADD xos/synchronizers/vbng/supervisor/vbng-observer.conf /etc/supervisor/conf.d/
+ADD xos/synchronizers/onos/supervisor/onos-observer.conf /etc/supervisor/conf.d/
+ADD xos/synchronizers/monitoring_channel/supervisor/monitoring_channel_observer.conf /etc/supervisor/conf.d/
+RUN sed -i 's/proxy_ssh=True/proxy_ssh=False/' /opt/xos/synchronizers/vcpe/vcpe_synchronizer_config
+RUN sed -i 's/proxy_ssh=True/proxy_ssh=False/' /opt/xos/synchronizers/monitoring_channel/monitoring_channel_synchronizer_config
+ADD xos/configurations/cord/virtualbng.json /root/setup/
+ADD xos/configurations/cord/vtn-network-cfg.json /root/setup/
+
+CMD /usr/bin/make -C /opt/xos/configurations/cord -f Makefile.inside; /bin/bash
+
+#CMD ["/bin/bash"]
diff --git a/xos/configurations/cord-deprecated/Makefile b/xos/configurations/cord-deprecated/Makefile
new file mode 100644
index 0000000..184f2d5
--- /dev/null
+++ b/xos/configurations/cord-deprecated/Makefile
@@ -0,0 +1,100 @@
+SETUPDIR:=../setup
+MYIP:=$(shell hostname -i)
+
+cloudlab: common_cloudlab cord acord
+
+devstack: upgrade_pkgs common_devstack devstack_net_fix cord
+
+cord: virtualbng_json vtn_network_cfg_json
+	sudo MYIP=$(MYIP) docker-compose up -d
+	bash ../common/wait_for_xos.sh
+	sudo MYIP=$(MYIP) docker-compose run xos python /opt/xos/tosca/run.py none /opt/xos/configurations/common/fixtures.yaml
+	sudo docker-compose run xos python /opt/xos/tosca/run.py none /opt/xos/configurations/common/mydeployment.yaml
+	sudo MYIP=$(MYIP) docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/common/cloudlab-openstack.yaml
+	sudo MYIP=$(MYIP) docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/nodes.yaml
+	sudo MYIP=$(MYIP) docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/cord/cord.yaml
+
+containers:
+	cd ../../../containers/xos; make devel
+	cd ../../../containers/synchronizer; make
+
+common_cloudlab:
+	make -C ../common -f Makefile.cloudlab
+
+common_devstack:
+	make -C ../common -f Makefile.devstack
+
+acord: cloudlab_ceilometer_custom_images ceilometer_cloudlab_cord_plugins
+	sudo MYIP=$(MYIP) docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/cord/ceilometer.yaml
+
+ceilometer_cloudlab_cord_plugins:
+	if [ -d ./ceilometer-plugins ]; then rm -fr ./ceilometer-plugins; fi
+	git clone https://github.com/srikanthvavila/ceilometer-plugins.git
+	sudo cp -r ceilometer-plugins/network/ext_services /usr/lib/python2.7/dist-packages/ceilometer/network/
+	sudo cp -r ceilometer-plugins/network/statistics/onos /usr/lib/python2.7/dist-packages/ceilometer/network/statistics/
+	sudo cp ceilometer-plugins/network/statistics/__init__.py /usr/lib/python2.7/dist-packages/ceilometer/network/statistics/ 
+	sudo cp ceilometer-plugins/entry_points.txt /usr/lib/python2.7/dist-packages/ceilometer-*egg-info/
+	sudo cp ceilometer-plugins/pipeline.yaml /etc/ceilometer/
+	echo "Restarting ceilometer-agent-notification"
+	sudo service ceilometer-agent-notification restart
+	echo "Restarting ceilometer-agent-central"
+	sudo service ceilometer-agent-central restart
+
+ceilometer_pub_sub:
+	if [ -d ./pub-sub ]; then rm -fr ./pub-sub; fi
+	git clone https://github.com/srikanthvavila/pub-sub.git
+	echo "Starting Ceilometer PUB/SUB service...Ensure zookeeper and kafka services are launched (if required)"
+	cd pub-sub/ceilometer_pub_sub/ ; python sub_main.py & 
+	cd ../..
+
+virtualbng_json:
+	export SETUPDIR=$(SETUPDIR); bash make-virtualbng-json.sh
+
+vtn_network_cfg_json:
+	export SETUPDIR=$(SETUPDIR); bash make-vtn-networkconfig-json.sh
+
+stop:
+	sudo MYIP=$(MYIP) docker-compose stop
+
+rm:
+	sudo MYIP=$(MYIP) docker-compose rm
+
+showlogs:
+	sudo MYIP=$(MYIP) docker-compose logs
+
+ps:
+	sudo MYIP=$(MYIP) docker-compose ps
+
+dataplane: etc_hosts
+	cd dataplane; ./gen-inventory.sh > hosts
+	cd dataplane; ansible-playbook -i hosts dataplane.yaml
+
+dataplane_bm: dataplane
+	cd dataplane; bash -c "./generate-bm.sh > hosts-bm"
+	cd dataplane; sudo bash -c "ansible-playbook -i hosts-bm dataplane-bm.yaml"
+
+etc_hosts:
+	sudo bash -c "sed -i '/^10.11.10/ d' /etc/hosts"
+	cd dataplane; sudo bash -c "./gen-etc-hosts.sh >> /etc/hosts"
+
+setup_client:
+	# add subscriber to vOLT?  Is there a REST API?
+	echo "Don't forget: add-subscriber-access of:0000000000000001 1 432"
+	cd dataplane; ansible -i hosts client -m shell -s -a "route del default gw 10.11.10.5; dhclient br-sub"
+	# reboot the vBNG ONOS
+	cd dataplane; ansible -i hosts onos_vbng -m shell -s -a "docker restart ONOS"
+
+cleanup: stop rm
+	cd dataplane; ./cleanup.sh
+	bash -c "source ../setup/admin-openrc.sh; nova list --all-tenants; neutron net-list"
+	echo "Don't forget to clean up vCPE containers"
+
+devstack_net_fix:
+	sudo ../common/devstack/net-fix.sh
+	sudo bash -c "source ../setup/admin-openrc.sh; neutron subnet-update private-subnet --dns-nameservers list=true 8.8.8.8 8.8.4.4"
+
+upgrade_pkgs:
+	sudo pip install httpie --upgrade
+
+cloudlab_ceilometer_custom_images:
+	bash -c "source ../setup/admin-openrc.sh; glance image-show ceilometer-trusty-server-multi-nic || if test -f /proj/xos-PG0/images/ceilometer-trusty-server-multi-nic.compressed.qcow2 ; then glance image-create --name ceilometer-trusty-server-multi-nic --disk-format qcow2 --file /proj/xos-PG0/images/ceilometer-trusty-server-multi-nic.compressed.qcow2 --container-format bare ; else mkdir -p /tmp/images && wget http://www.vicci.org/cord/ceilometer-trusty-server-multi-nic.compressed.qcow2 -P /tmp/images && glance image-create --name ceilometer-trusty-server-multi-nic --disk-format qcow2 --file /tmp/images/ceilometer-trusty-server-multi-nic.compressed.qcow2 --container-format bare ; fi "
diff --git a/xos/configurations/cord-deprecated/Makefile.inside b/xos/configurations/cord-deprecated/Makefile.inside
new file mode 100644
index 0000000..d7bdbaf
--- /dev/null
+++ b/xos/configurations/cord-deprecated/Makefile.inside
@@ -0,0 +1,12 @@
+all: setup_xos run_develserver
+
+setup_xos:
+	bash /opt/xos/tools/docker_setup_xos
+	python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/common/fixtures.yaml
+	python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/common/base.yaml
+	python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/common/nodes.yaml
+	python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/cord/cord.yaml
+	python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/cord/ceilometer.yaml
+
+run_develserver:
+	cd /opt/xos; python manage.py runserver 0.0.0.0:8000 --insecure
diff --git a/xos/configurations/cord-deprecated/README-VTN.md b/xos/configurations/cord-deprecated/README-VTN.md
new file mode 100644
index 0000000..a3c4e69
--- /dev/null
+++ b/xos/configurations/cord-deprecated/README-VTN.md
@@ -0,0 +1,156 @@
+# vtn notes:
+
+see also: https://github.com/hyunsun/documentations/wiki/Neutron-ONOS-Integration-for-CORD-VTN#onos-setup
+
+VTN doesn't seem to like cloudlab's networks (flat-net-1, ext-net, etc). I've placed a script in xos/scripts/ called destroy-all-networks.sh that will automate tearing down all of cloudlab's neutron networks.
+
+    cd xos/tools
+    ./destroy-all-networks.sh
+
+inside the xos container, update the configuration. Make sure to restart Openstack Synchronizer afterward. Might be a good idea to restart the XOS UI as well:
+
+    python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/tosca/samples/vtn.yaml
+    emacs /opt/xos/xos_configuration/xos_common_config
+        [networking]
+        use_vtn=True
+    supervisorctl restart observer
+
+### ctl node:
+
+    # set ONOS_VTN_HOSTNAME to the host where the VTN container was installed
+    ONOS_VTN_HOSTNAME="cp-2.smbaker-xos5.xos-pg0.clemson.cloudlab.us"
+    apt-get -y install python-pip
+    pip install -U setuptools pip
+    pip install testrepository
+    git clone https://github.com/openstack/networking-onos.git
+    cd networking-onos
+    python setup.py install
+    # the above fails the first time with an error about pbr.json
+    # I ran it again and it succeeded, but I am skeptical there's
+    # not still an issue lurking...
+    cat > /usr/local/etc/neutron/plugins/ml2/conf_onos.ini <<EOF
+    [onos]
+    url_path = http://$ONOS_VTN_HOSTNAME:8181/onos/cordvtn
+    username = karaf
+    password = karaf
+    EOF
+    emacs /etc/neutron/plugins/ml2/ml2_conf.ini
+        update settings as per vtn docs ([ml2] and [ml2_type_vxlan] sections)
+    systemctl stop neutron-server
+    # I started neutron manually to make sure it's using exactly the right config
+    # files. Maybe it can be restarted using systemctl instead...
+    /usr/bin/neutron-server --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/plugins/ml2/ml2_conf.ini --config-file /usr/local/etc/neutron/plugins/ml2/conf_onos.ini
+
+### Compute nodes and nm nodes:
+
+    cd xos/configurations/cord/dataplane
+    ./generate-bm.sh > hosts-bm
+    ansible-playbook -i hosts-bm dataplane-vtn.yaml
+    # the playbook will:
+    #  1) turn off neutron openvswitch-agent
+    #  2) set openvswitch to listen on port 6641
+    #  3) restart openvswitch
+    #  4) delete any existing br-int bridge
+    #  5) [nm only] turn off neutron-dhcp-agent
+
+Additional compute node stuff:
+
+I've been deleting any existing unused bridges. Not sure if it's necesary.
+
+    ovs-vsctl del-br br-tun
+    ovs-vsctl del-br br-flat-lan-1
+
+To get the management network working, we need to create management network template, slice, and network. configurations/cord/vtn.yaml will do this for you. Then add a connection to the management network for any slice that needs management connectivity.
+    
+### Notes:
+* I've configured the OpenvSwitch switches to use port 6641 instead of port 6640. This is because the VTN app listens on 6640
+itself, and since we're running it in docker 'host' networking mode now, it would conflict with an Openvswitch that was
+also listening on 6640.
+* Adding use_vtn=True to the [networking] section in the XOS config file has two effects: 1) it sets the gateway in sync_controller_networks, and 2) it disables automatic creation of nat-net for new slices. This is because VTN will fail if there is no gateway on a network, and because we don't have nat-net under the VTN configuration.
+* When using of-vfctl to look at flow rules, if you get a protocol error, try "ovs-ofctl show -O OpenFlow13 br-int "
+* Note that the VTN Synchronizer isn't started automatically. It's only use for inter-Service connectivity, so no need to mess with it until intra-Slice connectivity is working first. 
+* Note that the VTN Synchronizer won't connect non-access networks. Any network templates you want VTN to connect must have Access set to "Direct" or "Indirect". 
+
+In case management network isn't working, you can use a VNC tunnel, like this:
+
+    # on compute node, run the following and note the IP address and port number
+    virsh vncdisplay <instance-id>
+    
+    # from home
+    ssh -o "GatewayPorts yes"  -L <port+5900>:<IP>:<port+5900> <username>@<compute_node_hostname>
+    
+    # example
+    ssh -o "GatewayPorts yes"  -L 5901:192.168.0.7:5901 smbaker@cp-1.smbaker-xos3.xos-pg0.clemson.cloudlab.us
+
+Then open a VNC session to the local port on your local machine. You'll have a console on the Instance. The username is "Ubuntu" and the password can be obtained from your cloudlab experiment description
+
+### Things that can be tested:
+
+* Create an Instance, it should have a Private network, and there should be a tap attached from the instance to br-int
+* Two Instances in the same Slice can talk to one another. They can be on the same machine or different machines.
+* Two Slices can talk to one another if the slices are associated with Services and those Services have a Tenancy relationship between them. Note that 1) The VTN Synchronizer must be running, 2) There must be a Private network with Access=[Direct|Indirect], and 3) The connectivity is unidirectional, from subscriber service to provider service.
+
+### Testing service composition
+
+1. Change the private network template's 'Access' field from None to Direct
+2. Create a Service, Service-A
+3. Enter Slice Admin for Slice-1 and assign it to Service-A
+4. Create a Service, Service-B
+5. Enter Slice Admin for Slice-2 and assign it to Service-B
+6. Enter Service Admin for Service-B, Go to Tenancy Tab
+7. In the 'Provided Tenants' section of Service-B, create a Tenant with Subsciber-Service=Serivce-A. 
+8. Start the VTN Observer. It will send a REST request to VTN app.
+9. Launch tcpdump in one of Slice-2's instances
+10. From Slice-1, start pinging the instance in Slice-2 where you launched tcpdump
+11. You should see the pings arrive and responses sent out. Note that the ping responses will not reach Slice-1, since VTN traffic is unidirectional.
+12. Delete the Tenancy relation you created in Step #7. The ping traffic should no longer appear in the tcpdump.
+
+### Getting external connectivity working on cloudlab
+
+On head node:
+
+    ovs-vsctl del-br br-flat-lan-1
+    ifconfig eth2 10.123.0.1
+    iptables --table nat --append POSTROUTING --out-interface br-ex -j MASQUERADE
+    #arp -s 10.123.0.3 fa:16:3e:ea:11:0a
+    sysctl net.ipv4.conf.all.send_redirects
+    sysctl net.ipv4.conf.all.send_redirects=0
+    sysctl net.ipv4.conf.default.send_redirects=0
+    sysctl net.ipv4.conf.eth0.send_redirects=0
+    sysctl net.ipv4.conf.br-ex.send_redirects=0
+    
+Substitute for your installation:
+
+    10.123.0.3 = wan_ip of vSG
+    10.123.0.1 = wan gateway
+    fa:16:3e:ea:11:0a = wan_mac of vSG
+    00:8c:fa:5b:09:d8 = wan_mac of gateway
+    
+### Setting up a test-client
+
+Before setting up VTN, create a bridge and attach it to the dataplane device on each compute node:
+
+    brctl addbr br-inject
+    brctl addif br-inject eth3   # substitute dataplane eth device here, may be different on each compute node
+    ip link set br-inject up
+    ip link set dev br-inject promisc on
+    
+Then update the network-config attribute of the VTN ONOS App in XOS to use a dataplaneIntf of br-inject instead of the eth device. Bring up VTN and a VSG. WAN connectivity and everything else should be working fine. 
+
+Add a new slice, mysite_client, and make sure to give it both a private and a management network. Bring up an instance on the same node as the vSG you want to test. On the compute node, run the following:
+
+    $MAC=<make-up-some-mac>
+    $INSTANCE=<instance-id>
+    virsh attach-interface --domain $INSTANCE --type bridge --source br-inject --model virtio --mac $MAC --config --live
+    
+Log into the vSG via the management interface. Inside of the vSG run the following:
+
+    STAG=<your s-tag here>
+    CTAG=<your c-tag here>
+    ip link add link eth2 eth2.$STAG type vlan id $STAG
+    ip link add link eth2.$STAG eth2.$STAG.$CTAG type vlan id $CTAG
+    ip link set eth2.$STAG up
+    ip link set eth2.$STAG.$CTAG up
+    ip addr add 192.168.0.2/24 dev eth2.$STAG.$CTAG
+    ip route del default
+    ip route add default via 192.168.0.1
diff --git a/xos/configurations/cord-deprecated/README.md b/xos/configurations/cord-deprecated/README.md
new file mode 100644
index 0000000..64075d9
--- /dev/null
+++ b/xos/configurations/cord-deprecated/README.md
@@ -0,0 +1,151 @@
+# CORD development environment
+
+This configuration can be used to set up a CORD development environment.
+It does the following:
+
+* Sets up a basic dataplane for testing end-to-end packet flow between a subscriber client and the Internet
+* Brings up ONOS apps for controlling the dataplane: virtualbng, olt
+* Configures XOS with the CORD services: vCPE, vBNG, vOLT
+
+**NOTE: This configuration is stale and likely not working at present.  If you are looking to evaluate 
+and/or contribute to [CORD](http://opencord.org/), 
+you should look instead at the [cord-pod](../cord-pod) configuration. Almost
+all CORD developers have transitioned to [cord-pod](../cord-pod).**
+
+## End-to-end dataplane
+
+The configuration uses XOS to set up an end-to-end dataplane for development of the XOS services and ONOS apps
+used in CORD.  It abstracts away most of the complexity of the CORD hardware using virtual networks
+and Open vSwitch (OvS) switches.  At a high level the dataplane looks like this:
+
+```
+             olt                 virtualbng
+             ----                  ----
+             ONOS                  ONOS
+              |                     |
+client ----> CPqD ----> vCPE ----> OvS ----> Internet
+         1         2          3         4
+```
+
+On the datapath are two OvS switches, controlled by the `olt` and `virtualbng` ONOS applications.  Once all the pieces are in
+place, the client at left should be able to obtain an IP address via DHCP from the vCPE and send packets out to the Internet.
+
+All of the components in the above diagram (i.e., client, OvS switches, ONOS, and vCPE) currently run in distinct VMs
+created by XOS.  The numbers in the diagram correspond to networks set up by XOS:
+
+1. subscriber_network
+2. lan_network
+3. wan_network
+4. public_network
+
+## How to run it
+
+The configuration is intended to be run on [CloudLab](http://cloudlab.us).
+It launches an XOS container on Cloudlab that runs the XOS develserver.  The container is left running in the background.
+
+To get started on CloudLab:
+* Create an experiment using the *OpenStack-CORD* profile.  (You can also use the *OpenStack* profile, but choose *Kilo*
+with two compute nodes and disable security groups.)
+* Wait until you get an email from CloudLab with title "OpenStack Instance Finished Setting Up".
+* Login to the *ctl* node of your experiment and run:
+```
+ctl:~$ git clone https://github.com/open-cloud/xos.git
+ctl:~$ cd xos/xos/configurations/cord/
+ctl:~/xos/xos/configurations/cord$ make
+```
+
+Running `make` in this directory creates the XOS Docker container and runs the TOSCA engine with `cord.yaml` to
+configure XOS with the CORD services.  In addition, a number of VMs are created:
+
+1. *Slice mysite_onos*: runs the ONOS Docker container with `virtualbng` app loaded
+1. *Slice mysite_onos*: runs the ONOS Docker container with `olt` app loaded
+1. *Slice mysite_vbng*: for running OvS with the `virtualbng` app as controller
+1. *Slice mysite_volt*: for running the CPqD switch with the `olt` app as controller
+1. *Slice mysite_clients*: a subscriber client for end-to-end testing
+1. *Slice mysite_vcpe*: runs the vCPE Docker container (if not using containers on bare metal)
+
+Once all the VMs are up and the ONOS apps are configured, XOS should be able to get an address mapping from the `virtualbng`
+ONOS app for the vCPE. To verify that it has received an IP address mapping, look at the **Routeable subnet:** field in
+the appropriate *Vbng tenant* object in XOS.  It should contain an IP address in the 10.254.0.0/24 subnet.
+
+After launching the ONOS apps, it is necessary to configure software switches along the dataplane so that ONOS can control
+them.  To do this, from the `cord` configuration directory:
+```
+ctl:~/xos/xos/configurations/cord$ cd dataplane/
+ctl:~/xos/xos/configurations/cord/dataplane$ ./gen-inventory.sh > hosts
+ctl:~/xos/xos/configurations/cord/dataplane$ ansible-playbook -i hosts dataplane.yaml
+```
+
+To setup the dataplane for containers on bare metal, perform these steps in addition to the above (note: make sure to sudo when running the playbook):
+```
+ctl:~/xos/xos/configurations/cord/dataplane$ ./generate-bm.sh > hosts-bm   
+ctl:~/xos/xos/configurations/cord/dataplane$ sudo ansible-playbook -i hosts-bm dataplane-bm.yaml
+```
+
+Check that the vCPE container has started, by going into the XOS UI, selecting 'Services', 'service_vcpe', 'Administration', 'Vcpe Tenants', and make sure there's a green icon next to the vCPE.
+
+If the vCPE Tenant is still red, then the Instance could be exponentially backed-off due to errors while trying to sync before dataplane.yaml was run. You can reset the exponential backoff by tracking down the vCPE Instance (Slices->mysite_vcpe->Instances, and find the Instance associated with the vCPE Tenant) and hitting the save button.
+
+Now SSH into ONOS running the OLT app (see below) and activate the subscriber:
+```
+onos> add-subscriber-access of:0000000000000001 1 432
+```
+
+At this point the client should be able to get an IP address from the vCPE via
+DHCP.  To set up the IP address and default route on the client:
+```
+client:$ sudo route del default gw 10.11.10.5
+client:$ sudo dhclient br-sub
+```
+Once `dhclient` returns, the client should now be able to surf the Internet
+through the dataplane.
+
+## Setting up /etc/hosts
+
+To make it easy to log into the various VMs that make up the dataplane, add entries for them into `/etc/hosts` on the
+*ctl* node.  As root, run:
+```
+ctl:~/xos/xos/configurations/cord/dataplane$ ./gen-etc-hosts.sh >> /etc/hosts
+```
+For example, to log into the client:
+```
+ctl:~$ ssh ubuntu@client
+```
+
+## How to log into ONOS
+
+ONOS apps are run inside Docker containers hosted in VMs.  All ports exposed by the ONOS container are forwarded to the
+outside, and can be accessed from the *ctl* node over the `flat-lan-1-net` network.  Assuming that `/etc/hosts`
+has been configured as described above, it is possible to SSH to the ONOS running the `virtualbng` app as follows (password is *karaf*):
+
+```
+$ ssh -p 8101 karaf@onos_vbng
+Password authentication
+Password:
+Welcome to Open Network Operating System (ONOS)!
+     ____  _  ______  ____
+    / __ \/ |/ / __ \/ __/
+   / /_/ /    / /_/ /\ \
+   \____/_/|_/\____/___/
+
+
+Hit '<tab>' for a list of available commands
+and '[cmd] --help' for help on a specific command.
+Hit '<ctrl-d>' or type 'system:shutdown' or 'logout' to shutdown ONOS.
+
+onos>
+```
+
+For instance, to check the IP address mappings managed by the `virtualbng` app:
+
+```
+onos> vbngs
+   Private IP - Public IP
+   10.0.1.3 - 10.254.0.129
+```
+
+## Troubleshooting
+
+#### Problem: No external connectivity from vCPE container
+1. Make sure the hosts listed in `virtualbng.json` are the actual compute nodes used in your experiment.
+2. Try rebooting the ONOS container running the `virtualbng` app: `$ ssh ubuntu@onos-vbng "sudo docker restart ONOS"`
diff --git a/xos/configurations/cord-deprecated/ceilometer.yaml b/xos/configurations/cord-deprecated/ceilometer.yaml
new file mode 100644
index 0000000..464b07b
--- /dev/null
+++ b/xos/configurations/cord-deprecated/ceilometer.yaml
@@ -0,0 +1,270 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Setup CORD-related services -- vOLT, vCPE, vBNG.
+
+imports:
+   - custom_types/xos.yaml
+
+node_types:
+    tosca.nodes.SFlowService:
+        derived_from: tosca.nodes.Root
+        description: >
+            XOS SFlow Collection Service
+        capabilities:
+            scalable:
+                type: tosca.capabilities.Scalable
+            service:
+                type: tosca.capabilities.xos.Service
+        properties:
+            kind:
+                type: string
+                default: generic
+                description: Type of service.
+            view_url:
+                type: string
+                required: false
+                description: URL to follow when icon is clicked in the Service Directory.
+            icon_url:
+                type: string
+                required: false
+                description: ICON to display in the Service Directory.
+            enabled:
+                type: boolean
+                default: true
+            published:
+                type: boolean
+                default: true
+                description: If True then display this Service in the Service Directory.
+            public_key:
+                type: string
+                required: false
+                description: Public key to install into Instances to allows Services to SSH into them.
+            private_key_fn:
+                type: string
+                required: false
+                description: Location of private key file
+            versionNumber:
+                type: string
+                required: false
+                description: Version number of Service.
+            sflow_port:
+              type: integer
+              required: false
+              default: 6343
+              description: sFlow listening port
+            sflow_api_port:
+              type: integer
+              required: false
+              default: 33333
+              description: sFlow publish subscribe api listening port
+
+    tosca.nodes.CeilometerService:
+        derived_from: tosca.nodes.Root
+        description: >
+            XOS Ceilometer Service
+        capabilities:
+            scalable:
+                type: tosca.capabilities.Scalable
+            service:
+                type: tosca.capabilities.xos.Service
+        properties:
+            kind:
+                type: string
+                default: generic
+                description: Type of service.
+            view_url:
+                type: string
+                required: false
+                description: URL to follow when icon is clicked in the Service Directory.
+            icon_url:
+                type: string
+                required: false
+                description: ICON to display in the Service Directory.
+            enabled:
+                type: boolean
+                default: true
+            published:
+                type: boolean
+                default: true
+                description: If True then display this Service in the Service Directory.
+            public_key:
+                type: string
+                required: false
+                description: Public key to install into Instances to allows Services to SSH into them.
+            private_key_fn:
+                type: string
+                required: false
+                description: Location of private key file
+            versionNumber:
+                type: string
+                required: false
+                description: Version number of Service.
+            ceilometer_pub_sub_url:
+                type: string
+                required: false
+                description: REST URL of ceilometer PUB/SUB component
+
+    tosca.nodes.CeilometerTenant:
+        derived_from: tosca.nodes.Root
+        description: >
+            CORD: A Tenant of the Ceilometer Service.
+        properties:
+            kind:
+                type: string
+                default: generic
+                description: Kind of tenant
+
+topology_template:
+  node_templates:
+    service_ceilometer:
+      type: tosca.nodes.CeilometerService
+      requirements:
+      properties:
+          view_url: /admin/ceilometer/ceilometerservice/$id$/
+          kind: ceilometer
+          ceilometer_pub_sub_url: http://10.11.10.1:4455/
+          public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }
+      artifacts:
+          pubkey: /opt/xos/synchronizers/monitoring_channel/monitoring_channel_public_key
+
+#    service_sflow:
+#      type: tosca.nodes.SFlowService
+#      requirements:
+#      properties:
+#          view_url: /admin/ceilometer/sflowservice/$id$/
+#          kind: sflow
+#          sflow_port: 6343
+#          sflow_api_port: 33333
+
+    Private:
+      type: tosca.nodes.NetworkTemplate
+
+    ceilometer_network:
+      type: tosca.nodes.network.Network.XOS
+      properties:
+          ip_version: 4
+          labels: ceilometer_client_access
+      requirements:
+          - network_template:
+              node: Private
+              relationship: tosca.relationships.UsesNetworkTemplate
+          - owner:
+              node: mysite_ceilometer
+              relationship: tosca.relationships.MemberOfSlice
+          - connection:
+              node: mysite_ceilometer
+              relationship: tosca.relationships.ConnectsToSlice
+
+    mysite:
+      type: tosca.nodes.Site
+
+    trusty-server-multi-nic:
+      type: tosca.nodes.Image
+
+    ceilometer-trusty-server-multi-nic:
+      type: tosca.nodes.Image
+
+    m1.small:
+      type: tosca.nodes.Flavor
+
+    mysite_ceilometer:
+      description: Ceilometer Proxy Slice
+      type: tosca.nodes.Slice
+      requirements:
+          - ceilometer_service:
+              node: service_ceilometer
+              relationship: tosca.relationships.MemberOfService
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+          - default_image:
+                node: ceilometer-trusty-server-multi-nic
+                relationship: tosca.relationships.DefaultImage
+          - default_flavor:
+                node: m1.small
+                relationship: tosca.relationships.DefaultFlavor
+
+#    mysite_sflow:
+#      description: Slice for sFlow service
+#      type: tosca.nodes.Slice
+#      requirements:
+#          - sflow_service:
+#              node: service_sflow
+#              relationship: tosca.relationships.MemberOfService
+#          - site:
+#              node: mysite
+#              relationship: tosca.relationships.MemberOfSite
+
+    my_ceilometer_tenant:
+      description: Ceilometer Service default Tenant
+      type: tosca.nodes.CeilometerTenant
+      requirements:
+          - provider_service:
+              node: service_ceilometer
+              relationship: tosca.relationships.MemberOfService
+       
+    # Virtual machines
+#    sflow_service_instance:
+#      type: tosca.nodes.Compute
+#      capabilities:
+#        # Host container properties
+#        host:
+#         properties:
+#           num_cpus: 1
+#           disk_size: 10 GB
+#           mem_size: 4 MB
+#        # Guest Operating System properties
+#        os:
+#          properties:
+#            # host Operating System image properties
+#            architecture: x86_64
+#            type: linux
+#            distribution: Ubuntu
+#            version: 14.10
+#      requirements:
+#          - slice:
+#                node: mysite_sflow
+#                relationship: tosca.relationships.MemberOfSlice
+
+    Customer Care:
+      type: tosca.nodes.DashboardView
+      properties:
+          url: template:xosDiagnostic
+
+    TruckRoll:
+      type: tosca.nodes.DashboardView
+      properties:
+          url: template:xosTruckroll
+
+    Ceilometer:
+      type: tosca.nodes.DashboardView
+      properties:
+          url: template:xosCeilometerDashboard
+
+
+    Tenant:
+      type: tosca.nodes.DashboardView
+      properties:
+          no-create: true
+          no-update: true
+          no-delete: true
+
+    padmin@vicci.org:
+      type: tosca.nodes.User
+      properties:
+          firstname: XOS
+          lastname: admin
+          is_admin: true
+      requirements:
+          - customer_care_dashboard:
+              node: Customer Care
+              relationship: tosca.relationships.UsesDashboard
+          - truckroll_dashboard:
+              node: TruckRoll
+              relationship: tosca.relationships.UsesDashboard
+          - ceilometer_dashboard:
+              node: Ceilometer
+              relationship: tosca.relationships.UsesDashboard
+          - tenant_dashboard:
+              node: Tenant
+              relationship: tosca.relationships.UsesDashboard
diff --git a/xos/configurations/cord-deprecated/cord.yaml b/xos/configurations/cord-deprecated/cord.yaml
new file mode 100644
index 0000000..c708d8e
--- /dev/null
+++ b/xos/configurations/cord-deprecated/cord.yaml
@@ -0,0 +1,550 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Setup CORD-related services -- vOLT, vCPE, vBNG.
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    # CORD Services
+    service_vtr:
+      type: tosca.nodes.Service
+      properties:
+          view_url: /admin/vtr/vtrservice/$id$/
+          kind: vTR
+
+    service_volt:
+      type: tosca.nodes.Service
+      requirements:
+          - vsg_tenant:
+              node: service_vsg
+              relationship: tosca.relationships.TenantOfService
+          - lan_network:
+              node: lan_network
+              relationship: tosca.relationships.UsesNetwork
+          - wan_network:
+              node: wan_network
+              relationship: tosca.relationships.UsesNetwork
+      properties:
+          view_url: /admin/cord/voltservice/$id$/
+          kind: vOLT
+
+    # set a pool of addresses that we can hand out for the VSG Wan.
+    public_addresses:
+      type: tosca.nodes.AddressPool
+      properties:
+          addresses: 10.123.0.0/24 10.124.0.0/24
+
+    service_vsg:
+      type: tosca.nodes.VSGService
+      requirements:
+          - vbng_tenant:
+              node: service_vbng
+              relationship: tosca.relationships.TenantOfService
+      properties:
+          view_url: /admin/cord/vsgservice/$id$/
+          backend_network_label: hpc_client
+          public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }
+          private_key_fn: /opt/xos/synchronizers/vcpe/vcpe_private_key
+#          node_label: label_vsg
+      artifacts:
+          pubkey: /opt/xos/synchronizers/vcpe/vcpe_public_key
+
+    service_vbng:
+      type: tosca.nodes.VBNGService
+      properties:
+          view_url: /admin/cord/vbngservice/$id$/
+# if unspecified, vbng observer will look for an ONOSApp Tenant and
+# generate a URL from its IP address
+#          vbng_url: http://10.11.10.24:8181/onos/virtualbng/
+
+    service_ONOS_vBNG:
+      type: tosca.nodes.ONOSService
+      requirements:
+      properties:
+          kind: onos
+          view_url: /admin/onos/onosservice/$id$/
+          public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }
+      artifacts:
+          pubkey: /opt/xos/synchronizers/onos/onos_key.pub
+
+#
+# To actually bring up the vBNG app
+# - Set up the dataplane using the ansible script
+# - Log into the vBNG ONOS and run 'devices' to get switch dpID
+# - Change the dpID values in vBNG ONOS app in XOS GUI
+# - (Synchronizer should copy the files to ONOS container immediately)
+# - Log into service_ONOS_vBNG VM and restart ONOS Docker container
+#   (Should roll this step into a Synchronizer)
+#f
+    vBNG_ONOS_app:
+      type: tosca.nodes.ONOSvBNGApp
+      requirements:
+          - onos_tenant:
+              node: service_ONOS_vBNG
+              relationship: tosca.relationships.TenantOfService
+          - vbng_service:
+              node: service_vbng
+              relationship: tosca.relationships.UsedByService
+      properties:
+          dependencies: org.onosproject.proxyarp, org.onosproject.virtualbng, org.onosproject.openflow, org.onosproject.fwd
+          config_network-cfg.json: >
+            {
+              "ports" : {
+                "of:0000000000000001/1" : {
+                  "interfaces" : [
+                    {
+                      "ips"  : [ "10.0.1.253/24" ],
+                      "mac"  : "00:00:00:00:00:99"
+                    }
+                  ]
+                },
+                "of:0000000000000001/2" : {
+                  "interfaces" : [
+                    {
+                      "ips"  : [ "10.254.0.2/24" ],
+                      "mac"  : "00:00:00:00:00:98"
+                    }
+                  ]
+                }
+              }
+            }
+          config_virtualbng.json: { get_artifact: [ SELF, virtualbng_json, LOCAL_FILE] }
+      artifacts:
+          virtualbng_json: /root/setup/virtualbng.json
+
+    service_ONOS_vOLT:
+      type: tosca.nodes.ONOSService
+      requirements:
+      properties:
+          kind: onos
+          view_url: /admin/onos/onosservice/$id$/
+          public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }
+          rest_onos/v1/network/configuration/: >
+            {
+              "devices" : {
+                "of:0000000000000001" : {
+                  "accessDevice" : {
+                    "uplink" : "2",
+                    "vlan"   : "222",
+                    "defaultVlan" : "1"
+                  },
+                  "basic" : {
+                    "driver" : "pmc-olt"
+                  }
+                }
+              }
+            }
+      artifacts:
+          pubkey: /opt/xos/synchronizers/onos/onos_key.pub
+
+
+    vOLT_ONOS_app:
+      type: tosca.nodes.ONOSvOLTApp
+      requirements:
+          - onos_tenant:
+              node: service_ONOS_vOLT
+              relationship: tosca.relationships.TenantOfService
+          - volt_service:
+              node: service_volt
+              relationship: tosca.relationships.UsedByService
+      properties:
+          install_dependencies: onos-ext-notifier-1.0-SNAPSHOT.oar, onos-ext-volt-event-publisher-1.0-SNAPSHOT.oar
+          dependencies: org.onosproject.openflow-base, org.onosproject.olt, org.ciena.onos.ext_notifier, org.ciena.onos.volt_event_publisher
+          component_config: >
+             {
+                "org.ciena.onos.ext_notifier.KafkaNotificationBridge":{
+                   "rabbit.user": "<rabbit_user>",
+                   "rabbit.password": "<rabbit_password>",
+                   "rabbit.host": "<rabbit_host>",
+                   "publish.kafka": "false",
+                   "publish.rabbit": "true",
+                   "volt.events.rabbit.topic": "notifications.info",
+                   "volt.events.rabbit.exchange": "voltlistener",
+                   "volt.events.opaque.info": "{project_id: <keystone_tenant_id>, user_id: <keystone_user_id>}",
+                   "publish.volt.events": "true"
+                }
+             }
+#          config_network-cfg.json: >
+#            {
+#              "devices" : {
+#                "of:0000000000000001" : {
+#                  "accessDevice" : {
+#                    "uplink" : "2",
+#                    "vlan"   : "222",
+#                    "defaultVlan" : "1"
+#                  },
+#                  "basic" : {
+#                    "driver" : "default"
+#                  }
+#                }
+#              }
+#            }
+
+    # Network templates
+    Private:
+      type: tosca.nodes.NetworkTemplate
+
+    Public network hack:
+      type: tosca.nodes.NetworkTemplate
+      properties:
+          visibility: private
+          translation: NAT
+          shared_network_name: tun0-net
+
+
+    # Networks required by the CORD setup
+    lan_network:
+      type: tosca.nodes.network.Network
+      properties:
+          ip_version: 4
+      requirements:
+          - network_template:
+              node: Private
+              relationship: tosca.relationships.UsesNetworkTemplate
+          - owner:
+              node: mysite_vsg
+              relationship: tosca.relationships.MemberOfSlice
+          - connection:
+              node: mysite_vsg
+              relationship: tosca.relationships.ConnectsToSlice
+          - connection:
+              node: mysite_vsg
+              relationship: tosca.relationships.ConnectsToSlice
+
+    wan_network:
+      type: tosca.nodes.network.Network
+      properties:
+          ip_version: 4
+      requirements:
+          - network_template:
+              node: Private
+              relationship: tosca.relationships.UsesNetworkTemplate
+          - owner:
+              node: mysite_vsg
+              relationship: tosca.relationships.MemberOfSlice
+          - connection:
+              node: mysite_vsg
+              relationship: tosca.relationships.ConnectsToSlice
+          - connection:
+              node: mysite_vsg
+              relationship: tosca.relationships.ConnectsToSlice
+
+    Private-Direct:
+      type: tosca.nodes.NetworkTemplate
+      properties:
+          access: direct
+
+    Private-Indirect:
+      type: tosca.nodes.NetworkTemplate
+      properties:
+          access: indirect
+
+    subscriber_network:
+      type: tosca.nodes.network.Network
+      properties:
+          ip_version: 4
+      requirements:
+          - network_template:
+              node: Private
+              relationship: tosca.relationships.UsesNetworkTemplate
+          - owner:
+              node: mysite_volt
+              relationship: tosca.relationships.MemberOfSlice
+          - connection:
+              node: mysite_volt
+              relationship: tosca.relationships.ConnectsToSlice
+          - connection:
+              node: mysite_clients
+              relationship: tosca.relationships.ConnectsToSlice
+
+    public_network:
+      type: tosca.nodes.network.Network
+      properties:
+      requirements:
+          - network_template:
+              node: Public network hack
+              relationship: tosca.relationships.UsesNetworkTemplate
+          - owner:
+              node: mysite_vbng
+              relationship: tosca.relationships.MemberOfSlice
+          - connection:
+              node: mysite_vbng
+              relationship: tosca.relationships.ConnectsToSlice
+
+
+    mysite:
+      type: tosca.nodes.Site
+
+    label_vsg:
+      type: tosca.nodes.NodeLabel
+
+    # CORD Slices
+    mysite_vsg:
+      description: vSG Controller Slice
+      type: tosca.nodes.Slice
+      requirements:
+          - vsg_service:
+              node: service_vsg
+              relationship: tosca.relationships.MemberOfService
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+          - vsg_docker_image:
+              node: docker-vsg
+              relationship: tosca.relationships.UsesImage
+#      properties:
+#          default_isolation: container
+
+    mysite_onos_vbng:
+      description: ONOS Controller Slice for vBNG
+      type: tosca.nodes.Slice
+      requirements:
+          - ONOS:
+              node: service_ONOS_vBNG
+              relationship: tosca.relationships.MemberOfService
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+
+    mysite_onos_volt:
+      description: ONOS Controller Slice for vOLT
+      type: tosca.nodes.Slice
+      requirements:
+          - ONOS:
+              node: service_ONOS_vOLT
+              relationship: tosca.relationships.MemberOfService
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+
+    mysite_vbng:
+      description: slice running OVS controlled by vBNG
+      type: tosca.nodes.Slice
+      requirements:
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+
+    mysite_volt:
+      description: OVS controlled by vOLT
+      type: tosca.nodes.Slice
+      requirements:
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+
+    mysite_clients:
+      description: slice for clients at the subscriber
+      type: tosca.nodes.Slice
+      requirements:
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+
+
+    # Virtual machines
+    onos_app_1:
+      type: tosca.nodes.Compute
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+        # Guest Operating System properties
+        os:
+          properties:
+            # host Operating System image properties
+            architecture: x86_64
+            type: linux
+            distribution: Ubuntu
+            version: 14.10
+      requirements:
+          - slice:
+                node: mysite_onos_vbng
+                relationship: tosca.relationships.MemberOfSlice
+
+    onos_app_2:
+      type: tosca.nodes.Compute
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+        # Guest Operating System properties
+        os:
+          properties:
+            # host Operating System image properties
+            architecture: x86_64
+            type: linux
+            distribution: Ubuntu
+            version: 14.10
+      requirements:
+          - slice:
+                node: mysite_onos_volt
+                relationship: tosca.relationships.MemberOfSlice
+
+    # VM for running the OVS controlled by vBNG
+    ovs_vbng:
+      type: tosca.nodes.Compute
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+        # Guest Operating System properties
+        os:
+          properties:
+            # host Operating System image properties
+            architecture: x86_64
+            type: linux
+            distribution: ubuntu
+            version: 14.04
+      requirements:
+          - slice:
+                node: mysite_vbng
+                relationship: tosca.relationships.MemberOfSlice
+
+    # VM for running the OVS controlled by vOLT
+    ovs_volt:
+      type: tosca.nodes.Compute
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+        # Guest Operating System properties
+        os:
+          properties:
+            # host Operating System image properties
+            architecture: x86_64
+            type: linux
+            distribution: ubuntu
+            version: 14.04
+      requirements:
+          - slice:
+                node: mysite_volt
+                relationship: tosca.relationships.MemberOfSlice
+
+    # A subscriber client VM
+    client1:
+      type: tosca.nodes.Compute
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+        # Guest Operating System properties
+        os:
+          properties:
+            # host Operating System image properties
+            architecture: x86_64
+            type: linux
+            distribution: ubuntu
+            version: 14.04
+      requirements:
+          - slice:
+                node: mysite_clients
+                relationship: tosca.relationships.MemberOfSlice
+
+    # docker image for vsg containers
+    docker-vsg:
+      # TODO: need to attach this to mydeployment
+      type: tosca.nodes.Image
+      properties:
+        kind: container
+        container_format: na
+        disk_format: na
+        path: andybavier/docker-vcpe
+        tag: develop
+
+    # Let's add a user who can be administrator of the household
+    johndoe@myhouse.com:
+      type: tosca.nodes.User
+      properties:
+          password: letmein
+          firstname: john
+          lastname: doe
+      requirements:
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+
+    # A subscriber
+    My House:
+       type: tosca.nodes.CORDSubscriber
+       properties:
+           service_specific_id: 123
+           firewall_enable: false
+           cdn_enable: false
+           url_filter_enable: false
+           url_filter_level: R
+       requirements:
+          - house_admin:
+              node: johndoe@myhouse.com
+              relationship: tosca.relationships.AdminPrivilege
+
+    Mom's PC:
+       type: tosca.nodes.CORDUser
+       properties:
+           mac: 01:02:03:04:05:06
+           level: PG_13
+       requirements:
+           - household:
+               node: My House
+               relationship: tosca.relationships.SubscriberDevice
+
+    Dad's PC:
+       type: tosca.nodes.CORDUser
+       properties:
+           mac: 90:E2:BA:82:F9:75
+           level: PG_13
+       requirements:
+           - household:
+               node: My House
+               relationship: tosca.relationships.SubscriberDevice
+
+    Jack's Laptop:
+       type: tosca.nodes.CORDUser
+       properties:
+           mac: 68:5B:35:9D:91:D5
+           level: PG_13
+       requirements:
+           - household:
+               node: My House
+               relationship: tosca.relationships.SubscriberDevice
+
+    Jill's Laptop:
+       type: tosca.nodes.CORDUser
+       properties:
+           mac: 34:36:3B:C9:B6:A6
+           level: PG_13
+       requirements:
+           - household:
+               node: My House
+               relationship: tosca.relationships.SubscriberDevice
+
+    My Volt:
+        type: tosca.nodes.VOLTTenant
+        properties:
+            service_specific_id: 123
+            s_tag: 222
+            c_tag: 432
+        requirements:
+            - provider_service:
+                node: service_volt
+                relationship: tosca.relationships.MemberOfService
+            - subscriber:
+                node: My House
+                relationship: tosca.relationships.BelongsToSubscriber
diff --git a/xos/configurations/cord-deprecated/dataplane/ansible.cfg b/xos/configurations/cord-deprecated/dataplane/ansible.cfg
new file mode 100644
index 0000000..9100590
--- /dev/null
+++ b/xos/configurations/cord-deprecated/dataplane/ansible.cfg
@@ -0,0 +1,4 @@
+[defaults]
+remote_user = ubuntu
+private_key_file = ~/.ssh/id_rsa
+host_key_checking = false
\ No newline at end of file
diff --git a/xos/configurations/cord-deprecated/dataplane/change_controller.sh b/xos/configurations/cord-deprecated/dataplane/change_controller.sh
new file mode 100755
index 0000000..2b961ee
--- /dev/null
+++ b/xos/configurations/cord-deprecated/dataplane/change_controller.sh
@@ -0,0 +1,13 @@
+#! /bin/bash
+
+# put IP address of node running ONOS VTN App here
+DESIRED_CONTROLLER="tcp:130.127.133.24:6653"
+
+while [[ 1 ]]; do
+    CONTROLLER=`ovs-vsctl get-controller br-int`
+    if [[ "$CONTROLLER" == "tcp:172.17.0.2:6653" ]]; then
+       ovs-vsctl set-controller br-int $DESIRED_CONTROLLER
+       echo "changed controller from $CONTROLLER to $DESIRED_CONTROLLER"
+    fi
+    sleep 10s
+done
diff --git a/xos/configurations/cord-deprecated/dataplane/cleanup.sh b/xos/configurations/cord-deprecated/dataplane/cleanup.sh
new file mode 100755
index 0000000..91d821c
--- /dev/null
+++ b/xos/configurations/cord-deprecated/dataplane/cleanup.sh
@@ -0,0 +1,49 @@
+#!/bin/bash
+
+function cleanup_network {
+  NETWORK=$1
+  SUBNETS=`neutron net-show $NETWORK | grep -i subnets | awk '{print $4}'`
+  if [[ $SUBNETS != "" ]]; then
+      PORTS=`neutron port-list | grep -i $SUBNETS | awk '{print $2}'`
+      for PORT in $PORTS; do
+          echo "Deleting port $PORT"
+          neutron port-delete $PORT
+      done
+  fi
+  neutron net-delete $NETWORK
+}
+
+source ../../setup/admin-openrc.sh
+
+echo "Deleting VMs"
+# Delete all VMs
+VMS=$( nova list --all-tenants|grep mysite|awk '{print $2}' )
+for VM in $VMS
+do
+    nova delete $VM
+done
+
+echo "Waiting 5 seconds..."
+sleep 5
+
+cleanup_network lan_network
+cleanup_network wan_network
+cleanup_network mysite_vsg-private
+cleanup_network mysite_vsg-access
+cleanup_network management
+
+echo "Deleting networks"
+# Delete all networks beginning with mysite_
+NETS=$( neutron net-list --all-tenants|grep mysite|awk '{print $2}' )
+for NET in $NETS
+do
+    neutron net-delete $NET
+done
+
+neutron net-delete lan_network || true
+neutron net-delete subscriber_network || true
+neutron net-delete public_network || true
+neutron net-delete hpc_client_network || true
+neutron net-delete ceilometer_network || true
+neutron net-delete management || true
+neutron net-delete mysite_vsg-access || true
diff --git a/xos/configurations/cord-deprecated/dataplane/dataplane-bm.yaml b/xos/configurations/cord-deprecated/dataplane/dataplane-bm.yaml
new file mode 100644
index 0000000..e1e78ee
--- /dev/null
+++ b/xos/configurations/cord-deprecated/dataplane/dataplane-bm.yaml
@@ -0,0 +1,36 @@
+---
+- hosts: switch_volt
+  sudo: yes
+  tasks:
+  - name: Create tunnel port on br-lan
+    openvswitch_port:
+      bridge=br-lan
+      port={{ item }}
+      state=present
+    with_items: "grenames.split(' ')"
+
+  - name: Set up GRE tunnel to vCPE
+    shell: ovs-vsctl set Interface {{ item.0 }} type=gre options:remote_ip={{ item.1 }}
+    with_together:
+      - "grenames.split(' ')"
+      - "bm_ips.split(' ')"
+
+- hosts: baremetal
+
+  user: root
+  sudo: no
+  tasks:
+  - name: Create br-lan
+    openvswitch_bridge:
+      bridge=br-lan
+      state=present
+
+  - name: Create tunnel port
+    openvswitch_port:
+      bridge=br-lan
+      port={{ grename }}
+      state=present
+
+  - name: Configure GRE tunnel to vOLT switch
+    shell: ovs-vsctl set Interface {{ grename }} type=gre options:remote_ip={{ volt_addr }}
+
diff --git a/xos/configurations/cord-deprecated/dataplane/dataplane-vtn.yaml b/xos/configurations/cord-deprecated/dataplane/dataplane-vtn.yaml
new file mode 100644
index 0000000..f6561b5
--- /dev/null
+++ b/xos/configurations/cord-deprecated/dataplane/dataplane-vtn.yaml
@@ -0,0 +1,31 @@
+---
+- hosts: baremetal:nm
+
+  user: root
+  sudo: no
+  tasks:
+  - name: stop neutron openvswitch agent
+    service: name=neutron-plugin-openvswitch-agent state=stopped
+
+  - name: Update openvswitch config
+    lineinfile:
+      dest=/usr/share/openvswitch/scripts/ovs-ctl
+      insertafter="set ovsdb-server.*DB_FILE.*"
+      regexp=".*set.*--remote=ptcp.*"
+      line="        set \"$@\" --remote=ptcp:6641"
+      state=present
+
+  - name: Restart openvswitch
+    service: name=openvswitch-switch state=restarted
+
+  - name: Delete br-int
+    shell: ovs-vsctl show | grep -i br-int > /dev/null && ovs-vsctl del-br br-int
+    ignore_errors: yes
+
+- hosts: nm
+
+  user: root
+  sudo: no
+  tasks:
+  - name: stop neutron dhcp agent
+    service: name=neutron-dhcp-agent state=stopped
diff --git a/xos/configurations/cord-deprecated/dataplane/dataplane.yaml b/xos/configurations/cord-deprecated/dataplane/dataplane.yaml
new file mode 100644
index 0000000..3ca3bbe
--- /dev/null
+++ b/xos/configurations/cord-deprecated/dataplane/dataplane.yaml
@@ -0,0 +1,256 @@
+---
+- hosts: switch_vbng
+  sudo: yes
+  vars:
+    controller_ip: "{{ hostvars['onos_vbng']['ansible_ssh_host'] }}"
+    controller_port: 6653
+    ovs_dpid: "0000000000000001"
+  tags:
+  - vbng
+  tasks:
+  - name: Fix /etc/hosts
+    lineinfile:
+      dest=/etc/hosts
+      regexp="127.0.0.1 localhost"
+      line="127.0.0.1 localhost {{ ansible_hostname }}"
+
+  - name: Install packages
+    apt: name={{ item }}
+      state=latest
+      update_cache=yes
+    with_items:
+    - openvswitch-switch
+    - python-netifaces
+
+  - name: Create br-vbng
+    openvswitch_bridge:
+      bridge=br-vbng
+      state=present
+
+  - name: Find wan_network interface
+    script: scripts/if_from_ip.py {{ wan_ip }}
+    register: wan_net
+
+  - name: Find public_network interface
+    script: scripts/if_from_ip.py {{ public_ip }}
+    register: public_net
+
+  - name: Hook up wan-network to br-vbng
+    openvswitch_port:
+      bridge=br-vbng
+      port={{ wan_net.stdout }}
+      state=present
+
+  - name: Hook up public-network to OvS
+    openvswitch_port:
+      bridge=br-vbng
+      port={{ public_net.stdout }}
+      state=present
+
+  - name: Remove IP address on public_network
+    command: /sbin/ifconfig {{ public_net.stdout }} 0.0.0.0
+    when: public_net.stdout
+
+  - name: Change datapath ID of bridge to match config file
+    command: /usr/bin/ovs-vsctl set bridge br-vbng other-config:datapath-id={{ ovs_dpid }}
+
+  - name: Add controller to switch
+    command: /usr/bin/ovs-vsctl set-controller br-vbng tcp:{{ controller_ip }}:{{ controller_port }}
+
+- hosts: switch_volt
+  sudo: yes
+  vars:
+    controller_ip: "{{ hostvars['onos_volt']['ansible_ssh_host'] }}"
+    controller_port: 6653
+    vcpe_lan_ip: "{{ hostvars['vcpe']['lan_ip'] }}"
+  tags:
+  - volt
+  tasks:
+
+  - name: Fix /etc/hosts
+    lineinfile:
+      dest=/etc/hosts
+      regexp="127.0.0.1 localhost"
+      line="127.0.0.1 localhost {{ ansible_hostname }}"
+
+  - name: Install packages
+    apt: name={{ item }} state=present update_cache=yes
+    with_items:
+    - git
+    - python-netifaces
+    - openvswitch-switch
+
+  - name: Checkout the Mininet repo
+    git: repo=https://github.com/mininet/mininet.git
+      dest=/tmp/mininet
+
+  - name: Install the CPqD switch using Mininet install script
+    shell: /tmp/mininet/util/install.sh -3f
+      creates=/usr/local/bin/ofdatapath
+    ignore_errors: true
+
+  - name: Find subscriber_network interface
+    script: scripts/if_from_ip.py {{ subscriber_ip }}
+    register: subscriber_net
+
+  - name: Create bridge br-sub
+    openvswitch_bridge:
+      bridge=br-sub
+      state=present
+
+  - name: Add subscriber_net to br-sub
+    openvswitch_port:
+      bridge=br-sub
+      port={{ subscriber_net.stdout }}
+      state=present
+
+  # The CPqD switch is expecting that packets coming from the client have
+  # VLAN tag 1.  However Neutron's OvS configuration eats VLAN-tagged packets.
+  # So tag them with VLAN 1 here before sending to CPqD.
+  #
+  # Note that the VLAN tag is 0 in the real-world setup, but the CPqD switch
+  # seems to have a problem with these packets.
+
+  # Using OvS to tag packets with VLAN ID 1 is not quite working for some reason.
+  # The packets from the client get tagged OK, but only the first packet from the
+  # VCPE gets its tag stripped off.  Very weird.  That's why we are using veth
+  # devices instead.
+  #- name: Add tag 1 to br-sub port
+  #  shell: ovs-vsctl set port {{ subscriber_net.stdout }} tag=1
+
+  - name: Create a pair of veth devices
+    shell: ifconfig veth0 >> /dev/null || ip link add veth0 type veth peer name veth1
+
+  - name: Create veth0.1
+    shell: ifconfig veth0.1 >> /dev/null || ip link add link veth0 name veth0.1 type vlan id 1
+
+  - name: Bring the interfaces up
+    shell: ip link set {{ item }} up
+    with_items:
+    - veth0
+    - veth1
+    - veth0.1
+
+  - name: Add veth0.1 to br-sub
+    openvswitch_port:
+      bridge=br-sub
+      port=veth0.1
+      state=present
+
+  - name: Create bridge br-lan
+    openvswitch_bridge:
+      bridge=br-lan
+      state=present
+
+  - name: Create tunnel port on br-lan
+    openvswitch_port:
+      bridge=br-lan
+      port=gre0
+      state=present
+
+  - name: Set up GRE tunnel to vCPE
+    shell: ovs-vsctl set Interface gre0 type=gre options:remote_ip={{ vcpe_lan_ip }}
+
+  - name: Check if br-lan has an IPv6 address
+    shell: ip addr show br-lan|grep inet6|awk '{print $2}'
+    register: ipv6
+
+  - name: Remove br-lan IPv6 address if present
+    shell: ifconfig br-lan inet6 del {{ ipv6.stdout }}
+    when: ipv6.stdout != ""
+
+  - name: Check if veth1 has an IPv6 address
+    shell: ip addr show veth1|grep inet6|awk '{print $2}'
+    register: ipv6
+
+  - name: Remove veth1 IPv6 address if present
+    shell: ifconfig veth1 inet6 del {{ ipv6.stdout }}
+    when: ipv6.stdout != ""
+
+  - name: Run the datapath
+    command: /usr/local/bin/ofdatapath -i veth1,br-lan punix:/tmp/s1 -d 000000000001 --no-slicing -D -P
+      creates=/usr/local/var/run/ofdatapath.pid
+
+  - name: Run the control program
+    command: /usr/local/bin/ofprotocol unix:/tmp/s1 tcp:{{ controller_ip }}:{{ controller_port }} --fail=closed --listen=punix:/tmp/s1.listen -D -P
+      creates=/usr/local/var/run/ofprotocol.pid
+
+- hosts: client
+  sudo: yes
+  tags:
+  - client
+  tasks:
+
+  - name: Fix /etc/hosts
+    lineinfile:
+      dest=/etc/hosts
+      regexp="127.0.0.1 localhost"
+      line="127.0.0.1 localhost {{ ansible_hostname }}"
+
+  - name: Install packages
+    apt: name={{ item }}
+      state=latest
+      update_cache=yes
+    with_items:
+    - openvswitch-switch
+    - python-netifaces
+
+  - name: Create br-sub
+    openvswitch_bridge:
+      bridge=br-sub
+      state=present
+
+  - name: Find subscriber_network interface
+    script: scripts/if_from_ip.py {{ subscriber_ip }}
+    register: client_net
+
+  - name: Hook up subscriber-network to OvS
+    openvswitch_port:
+      bridge=br-sub
+      port={{ client_net.stdout }}
+      state=present
+
+  - name: Run some commands on br-sub
+    shell: "{{ item }}"
+    with_items:
+    - ifconfig br-sub 0.0.0.0 mtu 1400 up
+    - ethtool -K br-sub tso off
+    - ethtool -K br-sub tx off
+
+  # Run dhclient on br-sub internal interface to issue DHCP request to vCPE
+
+#
+# Need to set up a tunnel between vCPE and vOLT to keep VLAN-tagged
+# packets from being swallowed by the network.
+#
+- hosts: vcpe
+  sudo: yes
+  vars:
+    volt_lan_ip: "{{ hostvars['switch_volt']['lan_ip'] }}"
+  tags:
+  - vcpe
+  tasks:
+
+  - name: Install packages
+    apt: name={{ item }}
+      state=latest
+      update_cache=yes
+    with_items:
+    - openvswitch-switch
+
+  - name: Create br-lan
+    openvswitch_bridge:
+      bridge=br-lan
+      state=present
+
+  - name: Create tunnel port
+    openvswitch_port:
+      bridge=br-lan
+      port=gre0
+      state=present
+
+  - name: Configure GRE tunnel to vOLT switch
+    shell: ovs-vsctl set Interface gre0 type=gre options:remote_ip={{ volt_lan_ip }}
+
+  - name: Restart vCPEs
+    script: scripts/restart-vcpes.sh
diff --git a/xos/configurations/cord-deprecated/dataplane/gen-etc-hosts.sh b/xos/configurations/cord-deprecated/dataplane/gen-etc-hosts.sh
new file mode 100755
index 0000000..0d49706
--- /dev/null
+++ b/xos/configurations/cord-deprecated/dataplane/gen-etc-hosts.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+# set -x
+
+source ../../setup/admin-openrc.sh
+
+get_ip () {
+    LABEL=$1
+    NETWORK=$2
+    nova list --all-tenants|grep $LABEL|sed "s/^.*$NETWORK=//g"|sed 's/; .*$//g'|awk '{print $1}'
+}
+
+cat <<EOF
+$( get_ip mysite_onos_vbng flat-lan-1-net) onos_vbng
+$( get_ip mysite_vbng flat-lan-1-net) switch_vbng
+$( get_ip mysite_onos_volt flat-lan-1-net) onos_volt
+$( get_ip mysite_volt flat-lan-1-net) switch_volt
+$( get_ip mysite_clients flat-lan-1-net) client
+$( get_ip mysite_vsg flat-lan-1-net) vcpe
+EOF
diff --git a/xos/configurations/cord-deprecated/dataplane/gen-inventory.sh b/xos/configurations/cord-deprecated/dataplane/gen-inventory.sh
new file mode 100755
index 0000000..bacd2dd
--- /dev/null
+++ b/xos/configurations/cord-deprecated/dataplane/gen-inventory.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+# set -x
+
+source ../../setup/admin-openrc.sh
+
+get_ip () {
+    LABEL=$1
+    NETWORK=$2
+    nova list --all-tenants|grep $LABEL|sed "s/^.*$NETWORK=//g"|sed 's/; .*$//g'|awk '{print $1}'
+}
+
+cat <<EOF
+onos_vbng    ansible_ssh_host=$( get_ip mysite_onos_vbng flat-lan-1-net)
+switch_vbng  ansible_ssh_host=$( get_ip mysite_vbng flat-lan-1-net) wan_ip=$( get_ip mysite_vbng wan_network) public_ip=$( get_ip mysite_vbng tun0-net )
+
+onos_volt    ansible_ssh_host=$( get_ip mysite_onos_volt flat-lan-1-net)
+switch_volt  ansible_ssh_host=$( get_ip mysite_volt flat-lan-1-net) subscriber_ip=$( get_ip mysite_volt subscriber_network) lan_ip=$( get_ip mysite_volt lan_network)
+
+client       ansible_ssh_host=$( get_ip mysite_clients flat-lan-1-net) subscriber_ip=$( get_ip mysite_clients subscriber_network)
+vcpe         ansible_ssh_host=$( get_ip mysite_vsg flat-lan-1-net) lan_ip=$( get_ip mysite_vsg lan_network)
+EOF
diff --git a/xos/configurations/cord-deprecated/dataplane/generate-bm.sh b/xos/configurations/cord-deprecated/dataplane/generate-bm.sh
new file mode 100755
index 0000000..f9b8787
--- /dev/null
+++ b/xos/configurations/cord-deprecated/dataplane/generate-bm.sh
@@ -0,0 +1,44 @@
+source ../../setup/admin-openrc.sh
+
+get_ip () {
+    LABEL=$1
+    NETWORK=$2
+    nova list --all-tenants|grep $LABEL|sed "s/^.*$NETWORK=//g"|sed 's/; .*$//g'|awk '{print $1}'
+    }
+
+GRENAMES=()
+BM_IPS=()
+
+NODES=`sudo bash -c "source ../../setup/admin-openrc.sh ; nova hypervisor-list" |grep enabled|awk '{print $4}'`
+I=1
+for NODE in $NODES; do
+    BM_SSH_IP=`getent hosts $NODE | awk '{ print $1 }'`
+    IFS=. read BM_NAME BM_REMAINDER <<< $NODE
+    BM_IP=`sudo grep -i $BM_NAME /root/setup/data-hosts.flat-lan-1 | awk '{print $1}'`
+
+    GRE_NAMES+=("gre-bm-$I")
+    BM_IPS+=("$BM_IP")
+
+    #echo switch_volt$I    ansible_ssh_host=$( get_ip mysite_volt flat-lan-1-net) grename=gre-bm-$I bm_addr=$BM_IP
+    echo bm$I           ansible_ssh_host=$BM_SSH_IP grename=gre-bm-$I volt_addr=$( get_ip mysite_volt flat-lan-1-net)  ansible_ssh_private_key_file=/root/.ssh/id_rsa
+    I=$(( I+1 ))
+done
+
+GRE_NAMES=${GRE_NAMES[@]}
+BM_IPS=${BM_IPS[@]}
+
+echo switch_volt ansible_ssh_host=$( get_ip mysite_volt flat-lan-1-net) grenames=\"$GRE_NAMES\" bm_ips=\"$BM_IPS\"
+
+NM=`grep "^nm" /root/setup/fqdn.map | awk '{ print $2 }'`
+echo "nm1 ansible_ssh_host=$NM ansible_ssh_private_key_file=/root/.ssh/id_rsa"
+
+echo "[baremetal]"
+I=1
+for NODE in $NODES; do
+    echo bm$I
+    I=$((I+1))
+done
+
+# now for the network management node
+echo "[nm]"
+echo "nm1"
diff --git a/xos/configurations/cord-deprecated/dataplane/scripts/if_from_ip.py b/xos/configurations/cord-deprecated/dataplane/scripts/if_from_ip.py
new file mode 100644
index 0000000..28524fe
--- /dev/null
+++ b/xos/configurations/cord-deprecated/dataplane/scripts/if_from_ip.py
@@ -0,0 +1,14 @@
+#!/usr/bin/python
+
+import sys
+import netifaces
+
+def main (argv):
+    addr = argv[0]
+    for iface in netifaces.interfaces():
+        addrs = netifaces.ifaddresses(iface)
+        if 2 in addrs and addrs[2][0]['addr'] == addr:
+            sys.stdout.write(iface)
+
+if __name__ == "__main__":
+    main(sys.argv[1:])
diff --git a/xos/configurations/cord-deprecated/dataplane/scripts/restart-vcpes.sh b/xos/configurations/cord-deprecated/dataplane/scripts/restart-vcpes.sh
new file mode 100644
index 0000000..d1c9fce
--- /dev/null
+++ b/xos/configurations/cord-deprecated/dataplane/scripts/restart-vcpes.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+for VCPE in $( docker ps|grep vcpe|awk '{print $NF}' )
+do
+  service $VCPE stop
+  sleep 1
+  service $VCPE start
+done
diff --git a/xos/configurations/cord-deprecated/docker-compose.yml b/xos/configurations/cord-deprecated/docker-compose.yml
new file mode 100644
index 0000000..28eeeb4
--- /dev/null
+++ b/xos/configurations/cord-deprecated/docker-compose.yml
@@ -0,0 +1,106 @@
+xos_db:
+    image: xosproject/xos-postgres
+    expose:
+        - "5432"
+
+xos_synchronizer_openstack:
+    command: bash -c "sleep 120; python /opt/xos/synchronizers/openstack/xos-synchronizer.py"
+    image: xosproject/xos-synchronizer-openstack
+    labels:
+        org.xosproject.kind: synchronizer
+        org.xosproject.target: openstack
+    links:
+        - xos_db
+    extra_hosts:
+        - ctl:${MYIP}
+    volumes:
+        - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
+        - ./xos_cord_config:/opt/xos/xos_configuration/xos_cord_config:ro
+        - ../setup:/root/setup:ro
+
+xos_synchronizer_onos:
+    image: xosproject/xos-synchronizer-openstack
+    command: bash -c "sleep 120; python /opt/xos/synchronizers/onos/onos-synchronizer.py -C /opt/xos/synchronizers/onos/onos_synchronizer_config"
+    labels:
+        org.xosproject.kind: synchronizer
+        org.xosproject.target: onos
+    links:
+        - xos_db
+    extra_hosts:
+        - ctl:${MYIP}
+    volumes:
+        - ../setup/id_rsa:/opt/xos/synchronizers/onos/onos_key:ro  # private key
+
+xos_synchronizer_vcpe:
+    image: xosproject/xos-synchronizer-openstack
+    command: bash -c "sleep 120; python /opt/xos/synchronizers/vcpe/vcpe-synchronizer.py -C /opt/xos/synchronizers/vcpe/vcpe_synchronizer_config"
+    labels:
+        org.xosproject.kind: synchronizer
+        org.xosproject.target: vcpe
+    links:
+        - xos_db
+    extra_hosts:
+        - ctl:${MYIP}
+    volumes:
+        - ../setup/id_rsa:/opt/xos/synchronizers/vcpe/vcpe_private_key:ro  # private key
+        - ../setup:/root/setup:ro
+
+xos_synchronizer_vbng:
+    image: xosproject/xos-synchronizer-openstack
+    command: bash -c "sleep 120; python /opt/xos/synchronizers/vbng/vbng-synchronizer.py -C /opt/xos/synchronizers/vbng/vbng_synchronizer_config"
+    labels:
+        org.xosproject.kind: synchronizer
+        org.xosproject.target: vbng
+    links:
+        - xos_db
+    extra_hosts:
+        - ctl:${MYIP}
+
+xos_synchronizer_monitoring_channel:
+    image: xosproject/xos-synchronizer-openstack
+    command: bash -c "sleep 120; python /opt/xos/synchronizers/monitoring_channel/monitoring_channel_synchronizer.py -C /opt/xos/synchronizers/monitoring_channel/monitoring_channel_synchronizer_config"
+    labels:
+        org.xosproject.kind: synchronizer
+        org.xosproject.target: monitoring_channel
+    links:
+        - xos_db
+    extra_hosts:
+        - ctl:${MYIP}
+    volumes:
+        - ../setup/id_rsa:/opt/xos/synchronizers/monitoring_channel/monitoring_channel_private_key:ro  # private key
+
+xos_synchronizer_vtr:
+    image: xosproject/xos-synchronizer-openstack
+    command: bash -c "sleep 120; python /opt/xos/synchronizers/vtr/vtr-synchronizer.py -C /opt/xos/synchronizers/vtr/vtr_synchronizer_config"
+    labels:
+        org.xosproject.kind: synchronizer
+        org.xosproject.target: vtr
+    links:
+        - xos_db
+    extra_hosts:
+        - ctl:${MYIP}
+    volumes:
+        - ../setup/id_rsa:/opt/xos/synchronizers/vtr/vcpe_private_key:ro  # private key
+        - ../setup:/root/setup:ro
+
+# FUTURE
+#xos_swarm_synchronizer:
+#    image: xosproject/xos-swarm-synchronizer
+#    labels:
+#        org.xosproject.kind: synchronizer
+#        org.xosproject.target: swarm
+
+xos:
+    image: xosproject/xos
+    command: python /opt/xos/manage.py runserver 0.0.0.0:8000 --insecure --makemigrations
+    ports:
+        - "9999:8000"
+    links:
+        - xos_db
+    volumes:
+      - ../setup:/root/setup:ro
+      - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
+      - ./xos_cord_config:/opt/xos/xos_configuration/xos_cord_config:ro
+      - ../setup/id_rsa.pub:/opt/xos/synchronizers/onos/onos_key.pub:ro
+      - ../setup/id_rsa.pub:/opt/xos/synchronizers/vcpe/vcpe_public_key:ro
+      - ../setup/id_rsa.pub:/opt/xos/synchronizers/monitoring_channel/monitoring_channel_public_key:ro
diff --git a/xos/configurations/cord-deprecated/make-virtualbng-json.sh b/xos/configurations/cord-deprecated/make-virtualbng-json.sh
new file mode 100644
index 0000000..993643c
--- /dev/null
+++ b/xos/configurations/cord-deprecated/make-virtualbng-json.sh
@@ -0,0 +1,38 @@
+FN=$SETUPDIR/virtualbng.json
+
+rm -f $FN
+
+cat >> $FN <<EOF
+{
+    "localPublicIpPrefixes" : [
+        "10.254.0.128/25"
+    ],
+    "nextHopIpAddress" : "10.254.0.1",
+    "publicFacingMac" : "00:00:00:00:00:66",
+    "xosIpAddress" : "10.11.10.1",
+    "xosRestPort" : "9999",
+    "hosts" : {
+EOF
+
+NODES=$( sudo bash -c "source $SETUPDIR/admin-openrc.sh ; nova hypervisor-list" |grep -v ID|grep -v +|awk '{print $4}' )
+
+NODECOUNT=0
+for NODE in $NODES; do
+    ((NODECOUNT++))
+done
+
+I=0
+for NODE in $NODES; do
+    echo $NODE
+    ((I++))
+    if [[ "$I" -lt "$NODECOUNT" ]]; then
+        echo "      \"$NODE\" : \"of:0000000000000001/1\"," >> $FN
+    else
+        echo "      \"$NODE\" : \"of:0000000000000001/1\"" >> $FN
+    fi
+done
+
+cat >> $FN <<EOF
+    }
+}
+EOF
diff --git a/xos/configurations/cord-deprecated/make-vtn-networkconfig-json.sh b/xos/configurations/cord-deprecated/make-vtn-networkconfig-json.sh
new file mode 100644
index 0000000..77b855d
--- /dev/null
+++ b/xos/configurations/cord-deprecated/make-vtn-networkconfig-json.sh
@@ -0,0 +1,88 @@
+FN=$SETUPDIR/vtn-network-cfg.json
+
+echo "Writing to $FN"
+
+rm -f $FN
+
+cat >> $FN <<EOF
+{
+    "apps" : {
+        "org.onosproject.cordvtn" : {
+            "cordvtn" : {
+                "privateGatewayMac" : "00:00:00:00:00:01",
+                "localManagementIp": "172.27.0.1/24",
+                "ovsdbPort": "6641",
+                "sshPort": "22",
+                "sshUser": "root",
+                "sshKeyFile": "/root/node_key",
+                "publicGateways": [
+                    {
+                        "gatewayIp": "10.123.0.1",
+                        "gatewayMac": "00:8c:fa:5b:09:d8"
+                    }
+                ],
+                "nodes" : [
+EOF
+
+NODES=$( sudo bash -c "source $SETUPDIR/admin-openrc.sh ; nova hypervisor-list" |grep -v ID|grep -v +|awk '{print $4}' )
+
+# XXX disabled - we don't need or want the nm node at this time
+# also configure ONOS to manage the nm node
+# NM=`grep "^nm" /root/setup/fqdn.map | awk '{ print $2 }'`
+# NODES="$NODES $NM"
+
+NODECOUNT=0
+for NODE in $NODES; do
+    ((NODECOUNT++))
+done
+
+I=0
+for NODE in $NODES; do
+    echo $NODE
+    NODEIP=`getent hosts $NODE | awk '{ print $1 }'`
+
+    # This part is cloudlab-specific. It examines the flat-net-1 network and extracts
+    # the eth device and ip address that was assigned to flat-net-1.
+    sudo scp root@$NODE:/root/setup/info.flat-lan-1 $SETUPDIR/flat-lan-$NODE
+    PHYPORT=`bash -c "source $SETUPDIR/flat-lan-$NODE; echo \\\$DATADEV"`
+    LOCALIP=`bash -c "source $SETUPDIR/flat-lan-$NODE; echo \\\$DATAIP"`
+
+    ((I++))
+    cat >> $FN <<EOF
+                    {
+                      "hostname": "$NODE",
+                      "hostManagementIp": "$NODEIP/24",
+                      "bridgeId": "of:000000000000000$I",
+                      "dataPlaneIntf": "$PHYPORT",
+                      "dataPlaneIp": "$LOCALIP/24"
+EOF
+    if [[ "$I" -lt "$NODECOUNT" ]]; then
+        echo "                    }," >> $FN
+    else
+        echo "                    }" >> $FN
+    fi
+done
+
+# get the openstack admin password and username
+source $SETUPDIR/admin-openrc.sh
+
+HOSTNAME=`hostname`
+NEUTRONIP=`getent hosts $HOSTNAME | awk '{ print $1 }'`
+KEYSTONEIP=`getent hosts $HOSTNAME | awk '{ print $1 }'`
+
+cat >> $FN <<EOF
+                ]
+            }
+        },
+        "org.onosproject.openstackinterface" : {
+            "openstackinterface" : {
+                 "do_not_push_flows" : "true",
+                 "neutron_server" : "http://$NEUTRONIP:9696/v2.0/",
+                 "keystone_server" : "http://$KEYSTONEIP:5000/v2.0/",
+                 "user_name" : "$OS_USERNAME",
+                 "password" : "$OS_PASSWORD"
+             }
+        }
+    }
+}
+EOF
diff --git a/xos/configurations/cord-deprecated/xos_cord_config b/xos/configurations/cord-deprecated/xos_cord_config
new file mode 100644
index 0000000..a5448f7
--- /dev/null
+++ b/xos/configurations/cord-deprecated/xos_cord_config
@@ -0,0 +1,6 @@
+[gui]
+branding_name=CORD
+#branding_css=/static/cord.css
+branding_icon=/static/cord-logo.png
+branding_favicon=/static/cord-favicon.png
+branding_bg=/static/cord-bg.jpg
diff --git a/xos/configurations/cord-pod/Makefile b/xos/configurations/cord-pod/Makefile
new file mode 100644
index 0000000..1d5f68c
--- /dev/null
+++ b/xos/configurations/cord-pod/Makefile
@@ -0,0 +1,157 @@
+CONFIG_DIR:=$(shell pwd)
+DOCKER_COMPOSE_YML=./onboarding-docker-compose/docker-compose.yml
+BOOTSTRAP_YML=./docker-compose-bootstrap.yml
+DOCKER_PROJECT=cordpod
+
+.PHONY: xos
+xos: prereqs bootstrap onboarding podconfig
+
+prereqs:
+	sudo make -f ../common/Makefile.prereqs
+
+bootstrap:
+	echo "[BOOTSTRAP]"
+	sudo rm -f onboarding-docker-compose/docker-compose.yml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f docker-compose-bootstrap.yml up -d
+	bash ../common/wait_for_xos_port.sh 81
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(BOOTSTRAP_YML) run -e CONFIG_DIR=$(CONFIG_DIR) xos_bootstrap_ui python /opt/xos/tosca/run.py none /opt/xos/configurations/cord-pod/xos.yaml
+
+onboarding:
+	echo "[ONBOARDING]"
+	# on-board any services here
+	bash ../common/wait_for_onboarding_ready.sh 81 xos
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(BOOTSTRAP_YML) run xos_bootstrap_ui python /opt/xos/tosca/run.py None /opt/xos/configurations/common/disable-onboarding.yaml
+	sudo cp id_rsa key_import/vsg_rsa
+	sudo cp id_rsa.pub key_import/vsg_rsa.pub
+	sudo cp id_rsa key_import/volt_rsa
+	sudo cp id_rsa.pub key_import/volt_rsa.pub
+	sudo cp id_rsa key_import/onos_rsa
+	sudo cp id_rsa key_import/onos_rsa.pub
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(BOOTSTRAP_YML) run xos_bootstrap_ui python /opt/xos/tosca/run.py None /opt/xos/onboard/vrouter/vrouter-onboard.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(BOOTSTRAP_YML) run xos_bootstrap_ui python /opt/xos/tosca/run.py None /opt/xos/onboard/volt/volt-onboard.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(BOOTSTRAP_YML) run xos_bootstrap_ui python /opt/xos/tosca/run.py None /opt/xos/onboard/vsg/vsg-onboard.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(BOOTSTRAP_YML) run xos_bootstrap_ui python /opt/xos/tosca/run.py None /opt/xos/onboard/vtn/vtn-onboard.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(BOOTSTRAP_YML) run xos_bootstrap_ui python /opt/xos/tosca/run.py None /opt/xos/onboard/onos/onos-onboard.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(BOOTSTRAP_YML) run xos_bootstrap_ui python /opt/xos/tosca/run.py None /opt/xos/onboard/fabric/fabric-onboard.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(BOOTSTRAP_YML) run xos_bootstrap_ui python /opt/xos/tosca/run.py None /opt/xos/onboard/vtr/vtr-onboard.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(BOOTSTRAP_YML) run xos_bootstrap_ui python /opt/xos/tosca/run.py None /opt/xos/configurations/cord-pod/synchronizers.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(BOOTSTRAP_YML) run xos_bootstrap_ui python /opt/xos/tosca/run.py None /opt/xos/configurations/common/enable-onboarding.yaml
+	bash ../common/wait_for_onboarding_ready.sh 81 services/vrouter
+	bash ../common/wait_for_onboarding_ready.sh 81 services/volt
+	bash ../common/wait_for_onboarding_ready.sh 81 services/vsg
+	bash ../common/wait_for_onboarding_ready.sh 81 services/vtn
+	bash ../common/wait_for_onboarding_ready.sh 81 services/onos
+	bash ../common/wait_for_onboarding_ready.sh 81 services/fabric
+	bash ../common/wait_for_onboarding_ready.sh 81 services/vtr
+	bash ../common/wait_for_onboarding_ready.sh 81 xos
+	bash ../common/wait_for_xos_port.sh 80
+
+podconfig: nodes.yaml images.yaml
+	echo "[PODCONFIG]"
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py none /opt/xos/configurations/common/fixtures.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py none /opt/xos/configurations/common/mydeployment.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/setup.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/nodes.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/images.yaml
+
+vtn: vtn-external.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/vtn-external.yaml
+
+fabric: fabric.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/fabric.yaml
+
+cord: vsg_custom_images
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/mgmt-net.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/cord-vtn-vsg.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/cord-volt-devices.yaml
+
+clean-nodes:
+	rm -f nodes.yaml
+
+update-nodes: nodes.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/nodes.yaml
+
+new-nodes: clean-nodes update-nodes vtn
+
+exampleservice: onboard-exampleservice
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/pod-exampleservice.yaml
+
+onboard-exampleservice:
+	sudo cp id_rsa key_import/exampleservice_rsa
+	sudo cp id_rsa.pub key_import/exampleservice_rsa.pub
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(BOOTSTRAP_YML) run xos_bootstrap_ui python /opt/xos/tosca/run.py None /opt/xos/onboard/exampleservice/exampleservice-onboard.yaml
+	bash ../common/wait_for_onboarding_ready.sh 81 services/exampleservice
+	bash ../common/wait_for_onboarding_ready.sh 81 xos
+	bash ../common/wait_for_xos_port.sh 80
+
+cord-ceilometer: ceilometer_custom_images cord onboard-ceilometer
+	sudo docker-compose  -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/ceilometer.yaml
+
+onboard-ceilometer:
+	sudo cp id_rsa key_import/monitoring_channel_rsa
+	sudo cp id_rsa.pub key_import/monitoring_channel_rsa.pub
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(BOOTSTRAP_YML) run xos_bootstrap_ui python /opt/xos/tosca/run.py None /opt/xos/onboard/ceilometer/ceilometer-onboard.yaml
+	bash ../common/wait_for_onboarding_ready.sh 81 services/ceilometer
+	bash ../common/wait_for_onboarding_ready.sh 81 xos
+	bash ../common/wait_for_xos_port.sh 80
+
+nodes.yaml:
+	export SETUPDIR=.; bash ../common/make-nodes-yaml.sh
+
+images.yaml:
+	export SETUPDIR=.; bash ../common/make-images-yaml.sh
+
+vtn-external.yaml:
+	export SETUPDIR=.; bash ./make-vtn-external-yaml.sh
+
+fabric.yaml:
+	export SETUPDIR=.; bash ./make-fabric-yaml.sh
+
+virtualbng_json:
+	export SETUPDIR=.; bash ./make-virtualbng-json.sh
+
+vtn_network_cfg_json:
+	export SETUPDIR=.; bash ./make-vtn-networkconfig-json.sh
+
+stop:
+	test ! -s $(DOCKER_COMPOSE_YML) || sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) stop
+	sudo docker-compose -f $(BOOTSTRAP_YML) stop
+
+rm:
+	test ! -s $(DOCKER_COMPOSE_YML) || sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) rm
+	sudo docker-compose -f $(BOOTSTRAP_YML) rm
+
+showlogs:
+	sudo MYIP=$(MYIP) docker-compose logs
+
+cleanup: stop rm
+	./cleanup.sh
+	bash -c "source ./admin-openrc.sh; nova list --all-tenants; neutron net-list"
+
+ceilometer_custom_images: images/ceilometer-trusty-server-multi-nic.img
+	bash -c "source ./admin-openrc.sh; glance image-show ceilometer-trusty-server-multi-nic || glance image-create --name ceilometer-trusty-server-multi-nic --disk-format qcow2 --file ./images/ceilometer-trusty-server-multi-nic.img --container-format bare"
+
+vsg_custom_images: images/vsg-1.0.img
+	bash -c "source ./admin-openrc.sh; glance image-show vsg-1.0 || glance image-create --name vsg-1.0 --disk-format qcow2 --file ./images/vsg-1.0.img --container-format bare"
+
+images/ceilometer-trusty-server-multi-nic.img: images
+	wget http://www.vicci.org/cord/ceilometer-trusty-server-multi-nic.compressed.qcow2 -P ./images
+	mv ./images/ceilometer-trusty-server-multi-nic.compressed.qcow2 ./images/ceilometer-trusty-server-multi-nic.img
+
+images/vsg-1.0.img: images
+	wget http://www.vicci.org/cord/vsg-1.0.img -P ./images
+
+images:
+	mkdir -p ./images
+
+.PHONY: local_containers
+local_containers:
+	echo "" > ../../../containers/xos/local_certs.crt
+	for CRT in $$(ls /usr/local/share/ca-certificates/*) ; do \
+		echo Adding Certificate: $$CRT ;\
+		cat $$CRT >> ../../../containers/xos/local_certs.crt ;\
+		echo "" >> ../../../containers/xos/local_certs.crt ;\
+	done
+	cd ../../../containers/xos; make devel
+	cd ../../../containers/synchronizer; make
+	cd ../../../containers/onboarding_synchronizer; make
diff --git a/xos/configurations/cord-pod/NOTES.txt b/xos/configurations/cord-pod/NOTES.txt
new file mode 100644
index 0000000..d832f2b
--- /dev/null
+++ b/xos/configurations/cord-pod/NOTES.txt
@@ -0,0 +1,37 @@
+Notes on setup
+
+Requirements:
+* admin-openrc.sh: Admin credentials for your OpenStack cloud
+* id_rsa[.pub]: Keypair for use by the various services
+* node_key: Private key that allows root login to the compute nodes
+
+Steps for bringing up the POD:
+
+OpenStack
+* Configure management net
+  - mgmtbr on head nodes
+  - dnsmasq on head1 using cord config file
+* Install OpenStack using the openstack-cluster-install repo
+
+VTN
+* onos-cord VM is created by openstack-cluster-install
+* Bring up ONOS
+  # cd cord; docker-compose up -d
+* On each compute node it's necessary perform a few manual steps (FIX ME)
+  - Disable neutron-plugin-openvswitch-agent. As root:
+    # service neutron-plugin-openvswitch-agent stop
+    # echo manual > /etc/init/neutron-plugin-openvswitch-agent.override
+  - Clean up OVS: delete br-int and any other bridges
+  - Listen for connections from VTN:
+    # ovs-appctl -t ovsdb-server ovsdb-server/add-remote ptcp:6641
+
+XOS
+* xos VM is created by openstack-cluster-install
+  - requirements listed above should already be satisfied by install
+* cd xos/xos/configurations/cord-pod
+* Bring up XOS cord-pod configuration
+  # make
+  # make vtn
+  # make cord
+* Login to XOS at http://xos
+  - padmin@vicci.org / letmein
diff --git a/xos/configurations/cord-pod/README-Tutorial.md b/xos/configurations/cord-pod/README-Tutorial.md
new file mode 100644
index 0000000..9f8c9e9
--- /dev/null
+++ b/xos/configurations/cord-pod/README-Tutorial.md
@@ -0,0 +1,182 @@
+# Setting up the XOS Tutorial
+
+The XOS Tutorial demonstrates how to add a new subscriber-facing
+service to CORD.  
+
+## Prepare the development POD
+
+This tutorial runs on a single-node CORD POD development environment.
+For best results, prepare a clean Ubuntu 14.04
+LTS installation on a server with at least 48GB RAM and 12 CPU cores.
+Update the packages to the latest versions.
+
+To set up the POD, run
+[this script](https://github.com/open-cloud/openstack-cluster-setup/blob/master/scripts/single-node-pod.sh)
+with the `-e` option:
+
+```
+ubuntu@pod:~$ wget https://raw.githubusercontent.com/open-cloud/openstack-cluster-setup/master/scripts/single-node-pod.sh
+ubuntu@pod:~$ bash single-node-pod.sh -e
+```
+
+> NOTE: The above script can also automatically perform all tutoral steps if run as `bash single-node-pod -e -t`.  
+
+Be patient... it will take **at least one hour** to fully set up the single-node POD.
+
+## Include ExampleService in XOS
+
+On the POD, SSH into the XOS VM: `$ ssh ubuntu@xos`.  You will see the XOS repository
+checked out under `~/xos/`
+
+Change the XOS code as described in the
+[ExampleService Tutorial](http://guide.xosproject.org/devguide/exampleservice/)
+under the **Install the Service in Django** heading, and rebuild the XOS containers as
+follows:
+
+```
+ubuntu@xos:~$ cd xos/xos/configurations/cord-pod
+ubuntu@xos:~/xos/xos/configurations/cord-pod$ make local_containers
+```
+
+Modify the `docker-compose.yml` file in the `cord-pod` directory to include the synchronizer
+for ExampleService:
+
+```yaml
+xos_synchronizer_exampleservice:
+    image: xosproject/xos-synchronizer-openstack
+    command: bash -c "sleep 120; python /opt/xos/synchronizers/exampleservice/exampleservice-synchronizer.py -C /root/setup/files/exampleservice_config"
+    labels:
+        org.xosproject.kind: synchronizer
+        org.xosproject.target: exampleservice
+    links:
+        - xos_db
+    volumes:
+        - .:/root/setup:ro
+        - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
+        - ./id_rsa:/opt/xos/synchronizers/exampleservice/exampleservice_private_key:ro
+```
+
+Also, add ExampleService's public key to the `volumes` section of the `xos` docker container:
+
+```yaml
+xos:
+    ...
+    volumes:
+        ...
+        - ./id_rsa.pub:/opt/xos/synchronizers/exampleservice/exampleservice_public_key:ro 
+```
+
+## Bring up XOS
+
+Run the `make` commands described in the [Bringing up XOS](https://github.com/open-cloud/xos/blob/master/xos/configurations/cord-pod/README.md#bringing-up-xos)
+section of the README.md file.
+
+## Configure ExampleService in XOS
+
+The TOSCA file `pod-exampleservice.yaml` contains the service declaration.
+Tell XOS to process it by running:
+
+```
+ubuntu@xos:~/xos/xos/configurations/cord-pod$ make exampleservice
+```
+
+This will add the ExampleService to XOS.  It will also create an ExampleTenant,
+which causes a VM to be created with Apache running inside.
+
+
+## Set up a Subscriber Device
+
+The single-node POD does not include a virtual OLT, but a device at the
+subscriber’s premises can be simulated by an LXC container running on the
+nova-compute node.
+
+In the nova-compute VM:
+
+```
+ubuntu@nova-compute:~$ sudo apt-get install lxc
+```
+
+Next edit `/etc/lxc/default.conf` and change the default bridge name to `databr`:
+
+```
+  lxc.network.link = databr
+```
+
+Create the client container and attach to it:
+
+```
+ubuntu@nova-compute:~$ sudo lxc-create -t ubuntu -n testclient
+ubuntu@nova-compute:~$ sudo lxc-start -n testclient
+ubuntu@nova-compute:~$ sudo lxc-attach -n testclient
+```
+
+(The lxc-start command may throw an error but it seems to be unimportant.)
+
+Finally, inside the container set up an interface so that outgoing traffic
+is tagged with the s-tag (222) and c-tag (111) configured for the
+sample subscriber:
+
+```
+root@testclient:~# ip link add link eth0 name eth0.222 type vlan id 222
+root@testclient:~# ip link add link eth0.222 name eth0.222.111 type vlan id 111
+root@testclient:~# ifconfig eth0.222 up
+root@testclient:~# ifconfig eth0.222.111 up
+root@testclient:~# dhclient eth0.222.111
+```
+
+If the vSG is up and everything is working correctly, the eth0.222.111
+interface should acquire an IP address via DHCP and have external connectivity.
+
+## Access ExampleService from the Subscriber Device
+
+To test that the subscriber device can access the ExampleService, find the IP
+address of the ExampleService Instance in the XOS GUI, and then curl this
+address from inside the testclient container:
+
+```
+root@testclient:~# sudo apt-get install curl
+root@testclient:~# curl 10.168.1.3
+ExampleService
+ Service Message: "service_message"
+ Tenant Message: "tenant_message"
+```
+
+Hooray!  This shows that the subscriber (1) has external connectivity, and
+(2) can access the new service via the vSG.
+
+## Troubleshooting
+
+Sometimes the ExampleService instance comes up with the wrong default route.  If the 
+ExampleService instance is active but the `curl` command does not work, SSH to the
+instance and check its default gateway.  Assuming the management address of the `mysite_exampleservice`
+VM is 172.27.0.2:
+
+```
+ubuntu@pod:~$ ssh-agent bash
+ubuntu@pod:~$ ssh-add
+ubuntu@pod:~$ ssh -A ubuntu@nova-compute
+ubuntu@nova-compute:~$ ssh ubuntu@172.27.0.2
+ubuntu@mysite-exampleservice-2:~$ route -n
+Kernel IP routing table
+Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
+0.0.0.0         172.27.0.1      0.0.0.0         UG    0      0        0 eth1
+10.168.1.0      0.0.0.0         255.255.255.0   U     0      0        0 eth0
+172.27.0.0      0.0.0.0         255.255.255.0   U     0      0        0 eth1
+```
+
+If the default gateway is not `10.168.1.1`, manually set it to this value.
+
+```
+ubuntu@mysite-exampleservice-2:~$ sudo bash
+root@mysite-exampleservice-2:~# route del default gw 172.27.0.1
+root@mysite-exampleservice-2:~# route add default gw 10.168.1.1
+root@mysite-exampleservice-2:~# route -n
+Kernel IP routing table
+Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
+0.0.0.0         10.168.1.1      0.0.0.0         UG    0      0        0 eth0
+10.168.1.0      0.0.0.0         255.255.255.0   U     0      0        0 eth0
+172.27.0.0      0.0.0.0         255.255.255.0   U     0      0        0 eth1
+```
+
+Now the VM should have Internet connectivity and XOS will start downloading Apache. 
+A short while later the `curl` test should complete.
diff --git a/xos/configurations/cord-pod/README.md b/xos/configurations/cord-pod/README.md
new file mode 100644
index 0000000..8813d3e
--- /dev/null
+++ b/xos/configurations/cord-pod/README.md
@@ -0,0 +1,200 @@
+# XOS Configuration for CORD development POD
+
+## Introduction
+
+This directory holds files that are used to configure a development POD for
+CORD.  For more information on the CORD project, check out
+[the CORD website](http://cord.onosproject.org/).
+
+XOS is composed of several core services:
+
+  * A database backend (postgres)
+  * A webserver front end (django)
+  * A synchronizer daemon that interacts with the openstack backend
+  * A synchronizer for each configured XOS service
+
+Each service runs in a separate Docker container.  The containers are built
+automatically by [Docker Hub](https://hub.docker.com/u/xosproject/) using
+the HEAD of the XOS repository.
+
+## How to bring up CORD
+
+Installing a CORD POD involves these steps:
+ 1. Install OpenStack on a cluster
+ 2. Set up the ONOS VTN app and configuring OVS on the nova-compute nodes to be
+    controlled by VTN
+ 3. Set up external connectivity for VMs (if not using the CORD fabric)
+ 4. Bring up XOS with the CORD services
+
+### Install OpenStack
+
+To set up OpenStack, follow the instructions in the
+[README.md](https://github.com/open-cloud/openstack-cluster-setup/blob/master/README.md)
+file of the [open-cloud/openstack-cluster-setup](https://github.com/open-cloud/openstack-cluster-setup/)
+repository.  If you're just getting started with CORD, it's probably best to begin with the
+single-node CORD test environment to familiarize yourself with the overall setup.
+
+**NOTE: In order to use the cord-pod configuration, you must set up OpenStack using the above recipe.**
+
+### Set up ONOS VTN
+
+The OpenStack installer above creates a VM called *onos-cord* on the head node.
+To bring up ONOS in this VM, log into the head node and run:
+```
+$ ssh ubuntu@onos-cord
+ubuntu@onos-cord:~$ cd cord; sudo docker-compose up -d
+```
+
+### Set up external connectivity for VMs
+
+The CORD fabric is responsible for providing external (Internet) connectivity
+for VMs created on CORD.  If you are running on CloudLab (or another development
+environment) and want external connectivity without the fabric, download [this script](https://raw.githubusercontent.com/open-cloud/openstack-cluster-setup/master/scripts/compute-ext-net.sh)
+ and run it on the Nova compute node(s) as root:
+ ```
+ $ sudo compute-ext-net.sh
+ ```
+
+The script creates a bridge (*databr*) on the node as well as a veth pair
+(*veth0/veth1*).  The *veth0* interface is added as a port on *databr* and
+VTN is configured to use *veth1* as its data plane interface.  Traffic coming
+from *databr* is NAT'ed to the external network via `iptables`.  The configuration
+assumes that *databr* takes the MAC address of *veth0* when it is added as a port
+-- this seems to always be the case (though not sure why).
+
+Note that setting up the full fabric is beyond the scope of this README.
+
+### Bringing up XOS
+
+The OpenStack installer above creates a VM called *xos* on the head node.
+To bring up XOS in this VM, first log into the head node and run:
+```
+$ ssh ubuntu@xos
+ubuntu@xos:~$ cd xos/xos/configurations/cord-pod
+```
+
+Next, check that the following files exist in this directory
+(they will have been put there for you by the cluster installation scripts):
+
+ * *admin-openrc.sh*: Admin credentials for your OpenStack cloud
+ * *id_rsa[.pub]*: A keypair that will be used by the various services
+ * *node_key*: A private key that allows root login to the compute nodes
+
+XOS can then be brought up for CORD by running a few `make` commands.
+First, run:
+
+```
+ubuntu@xos:~/xos/xos/configurations/cord-pod$ make
+```
+
+Before proceeding, you should verify that objects in XOS are
+being sync'ed with OpenStack. [Login to the XOS GUI](#logging-into-xos-on-cloudlab-or-any-remote-host) 
+and select *Users* at left.  Make sure there is a green check next to `padmin@vicci.org`.
+
+> If you are **not** building the single-node development POD, the next
+> step is to create and edit the VTN configuration.  Run `make vtn-external.yaml`
+> then edit the `vtn-external.yml` TOSCA file.  The `rest_hostname:`
+> field points to the host where ONOS should run the VTN app.  The
+> fields in the `service_vtn` and the objects of type `tosca.nodes.Tag`
+> correspond to the VTN fields listed
+> on [the CORD VTN page on the ONOS Wiki](https://wiki.onosproject.org/display/ONOS/CORD+VTN),
+> under the **ONOS Settings** heading; refer there for the fields'
+> meanings.  
+
+Then run:
+
+```
+ubuntu@xos:~/xos/xos/configurations/cord-pod$ make vtn
+```
+The above step configures the ONOS VTN app by generating a configuration
+and pushing it to ONOS.  You are able to see and modify the configuration
+via the GUI as follows:
+
+* To see the generated configuration, go to *http://xos/admin/onos/onosapp/* 
+([caveat](#logging-into-xos-on-cloudlab-or-any-remote-host)), select
+*VTN_ONOS_app*, then the *Attributes* tab, and look for the
+`rest_onos/v1/network/configuration/` attribute.  
+
+* To change the VTN configuration, modify the fields of the VTN Service object
+and the Tag objects associated with Nodes.  Don't forget to select *Save*.
+
+* After modifying the above fields, delete the `rest_onos/v1/network/configuration/` attribute
+in the *ONOS_VTN_app* and select *Save*.  The attribute will be regenerated using the new information.
+
+* Alternatively, if you want to load your own VTN configuration manually, you can delete the
+`autogenerate` attribute from the *ONOS_VTN_app*, edit the configuration in the
+`rest_onos/v1/network/configuration/` attribute, and select *Save*.
+
+Before proceeding, check that the VTN app is controlling Open vSwitch on the compute nodes.  Log
+into ONOS and run the `cordvtn-nodes` command:
+
+```
+$ ssh -p 8101 karaf@onos-cord   # password is karaf
+onos> cordvtn-nodes
+hostname=nova-compute, hostMgmtIp=192.168.122.177/24, dpIp=192.168.199.1/24, br-int=of:0000000000000001, dpIntf=veth1, init=COMPLETE
+Total 1 nodes
+```
+The important part is the `init=COMPLETE` at the end.  If you do not see this, refer to
+[the CORD VTN page on the ONOS Wiki](https://wiki.onosproject.org/display/ONOS/CORD+VTN) for
+help fixing the problem.  This must be working to bring up VMs on the POD.
+
+> If you are **not** building the single-node development POD, modify `cord-vtn-vsg.yml` 
+> and change `addresses_vsg` so that it contains the IP address block,
+> gateway IP, and gateway MAC of the CORD fabric.  
+
+Then run:
+
+```
+ubuntu@xos:~/xos/xos/configurations/cord-pod$ make cord
+```
+
+
+### Inspecting the vSG
+
+The above series of `make` commands will spin up a vSG for a sample subscriber.  The
+vSG is implemented as a Docker container (using the
+[andybavier/docker-vcpe](https://hub.docker.com/r/andybavier/docker-vcpe/) image
+hosted on Docker Hub) running inside an Ubuntu VM.  Once the VM is created, you
+can login as the `ubuntu` user at the management network IP (172.27.0.x) on the compute node
+hosting the VM, using the private key generated on the head node by the install process.
+For example, in the single-node development POD configuration, you can login to the VM
+with management IP 172.27.0.2 using a ProxyCommand as follows:
+
+```
+ubuntu@pod:~$ ssh -o ProxyCommand="ssh -W %h:%p ubuntu@nova-compute" ubuntu@172.27.0.2
+```
+
+Alternatively, you could copy the generated private key to the compute node
+and login from there:
+
+```
+ubuntu@pod:~$ scp ~/.ssh/id_rsa ubuntu@nova-compute:~/.ssh
+ubuntu@pod:~$ ssh ubuntu@nova-compute
+ubuntu@nova-compute:~$ ssh ubuntu@172.27.0.2
+```
+
+Once logged in to the VM, you can run `sudo docker ps` to see the running
+vSG containers:
+
+```
+ubuntu@mysite-vsg-1:~$ sudo docker ps
+CONTAINER ID        IMAGE                    COMMAND             CREATED             STATUS              PORTS               NAMES
+2b0bfb3662c7        andybavier/docker-vcpe   "/sbin/my_init"     5 days ago          Up 5 days                               vcpe-222-111
+```
+
+### Logging into XOS on CloudLab (or any remote host)
+
+The XOS service is accessible on the POD at `http://xos/`, but `xos` maps to a private IP address
+on the management network.  If you install CORD on CloudLab 
+you will not be able to directly access the XOS GUI.
+In order to log into the XOS GUI in the browser on your local machine (desktop or laptop), 
+you can set up an SSH tunnel to your CloudLab node.  Assuming that 
+`<your-cloudlab-node>` is the DNS name of the CloudLab node hosting your experiment,
+run the following on your local machine to create the tunnel:
+
+```
+$ ssh -L 8888:xos:80 <your-cloudlab-node>
+```
+
+Then you should be able to access the XOS GUI by pointing your browser to
+`http://localhost:8888`.  Default username/password is `padmin@vicci.org/letmein`.
diff --git a/xos/configurations/cord-pod/admin-openrc.sh b/xos/configurations/cord-pod/admin-openrc.sh
new file mode 100644
index 0000000..bfc9eab
--- /dev/null
+++ b/xos/configurations/cord-pod/admin-openrc.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+# Replace with the OpenStack admin credentials for your cluster
+export OS_TENANT_NAME=admin
+export OS_USERNAME=admin
+export OS_PASSWORD=admin
+export OS_AUTH_URL=http://localhost:35357/v2.0
+
diff --git a/xos/configurations/cord-pod/cdn/README.md b/xos/configurations/cord-pod/cdn/README.md
new file mode 100644
index 0000000..be8c184
--- /dev/null
+++ b/xos/configurations/cord-pod/cdn/README.md
@@ -0,0 +1,77 @@
+## Set up a new CDN
+
+### CDN on VTN - headnode
+
+1. nova flavor-create --is-public true m1.cdnnode auto 8192 110 4
+2. in XOS create flavor m1.cdnnode and add to deployment
+
+### CDN on VTN - CMI
+
+1. Make sure plenty of glance space on ctl node
+2. Make sure plenty of instance space on compute nodes
+3. Install cmi-0.3.img into XOS images/ directory
+4. Install CentOS-6-cdnnode-0.3.img into XOS images/ directory
+5. Wait for these two images to be loaded into glance (check glance image-list for status)
+6. XOS UI: Add cmi and CentOS images to MyDeployment
+7. Run recipe xos/configurations/cord-pod/pod-cdn.yaml
+       * this will create mysite_cdn slice, cdn-public network, and add management and cdn-public networks to slice
+8. Instantiate CMI instance in mysite_cdn
+       * flavor: m1.large
+       * image: cmi-0.3.img
+9. edit configurations/cord-pod/cdn/cmi-settings.sh
+       * update COMPUTE_NODE and MGMT_IP to match CMI instance
+       * update NODE_KEY to match ssh key for root @ the compute node
+       * do not change VM_KEY; the pubkey is baked into the instance
+10. edit configurations/cord-pod/cdn/cmi.yaml
+       * update gateway_ip and gateway_mac to reflect public internet gateway CMI will use
+11. copy the keygen and allkeys.template to the private/ directory
+12. copy cmi_id_rsa
+13. run setup-cmi.sh
+       * this will SSH into the CMI and run setup, then modify some settings.
+       * it may take a long time, 10-20 minutes or more
+       * takeover script will be saved to takeovers/. Takeover script will be used in the next phase.
+
+### CDN on VTN - cdnnode
+
+1. Instantiate cdnnode instance in mysite_cdn
+       * flavor: m1.cdnnode
+       * CenOS-6-cdnnode-0.3.img
+2. Log into compute node and Attach disk
+       * virsh attach-disk <instance_name> /dev/sdc vdc --cache none
+       * (make sure this disk wasn't used anywhere else!)
+3. log into cdnnode VM
+       * make sure default gateway is good (check public connectivity)
+       * make sure arp table is good
+       * make sure CMI is reachable from cdnnode
+       * run takeover script that was created by the CMI 
+       * (I suggest commenting out the final reboot -f, and make sure the rest of it worked right before rebooting)
+       * Node will take a long time to install
+4. log into cdnnode
+       * to SSH into cdnnode, go into CMI, vserver coplc, cd /etc/planetlab, and use debug_ssh_key.rsa w/ root user
+       * check default gateway
+       * fix arp entry for default gateway
+
+### CDN on VTN - cmi part 2
+
+1. run setup-logicalinterfaces.sh
+
+### CDN on VTN - important notes
+
+We manually edited synchronizers/vcpe/templates/dnsasq_safe_servers.j2 inside the vcpe synchronizer VM:
+
+    # temporary for ONS demo
+    address=/z.cdn.turner.com/207.141.192.134
+    address=/cnn-vh.akamaihd.net/207.141.192.134
+
+### Test Commands
+
+* First, make sure the vSG is the only DNS server available in the test client. 
+* Second, make sure cdn_enable bit is set in CordSubscriber object for your vSG.
+* curl -L -vvvv http://downloads.onosproject.org/vm/onos-tutorial-1.1.0r220-ovf.zip > /dev/null
+* curl -L -vvvv http://onlab.vicci.org/onos-videos/Nov-planning-day1/Day1+00+Bill+-+Community+Growth.mp4 > /dev/null
+* curl -L -vvvv http://downloads.onosproject.org/release/onos-1.2.0.zip > /dev/null
+
+## Restart CDN after power-down
+
+To do...
+test
diff --git a/xos/configurations/cord-pod/cdn/cmi-logicalinterfaces.yaml b/xos/configurations/cord-pod/cdn/cmi-logicalinterfaces.yaml
new file mode 100644
index 0000000..d45b63a
--- /dev/null
+++ b/xos/configurations/cord-pod/cdn/cmi-logicalinterfaces.yaml
@@ -0,0 +1,11 @@
+---
+- hosts: cmi
+  connection: ssh
+  user: root
+  tasks:
+  - name: copy over cmi logical interface template
+    template: src=templates/setup_cmi_logicalinterfaces.sh dest=/vservers/coplc/root/setup_cmi_logicalinterfaces.sh
+
+  - name: run logical interface script
+    command: vserver coplc exec onevsh /root/setup_cmi_logicalinterfaces.sh
+
diff --git a/xos/configurations/cord-pod/cdn/cmi-settings.sh b/xos/configurations/cord-pod/cdn/cmi-settings.sh
new file mode 100644
index 0000000..db6c5f3
--- /dev/null
+++ b/xos/configurations/cord-pod/cdn/cmi-settings.sh
@@ -0,0 +1,12 @@
+# This holds the connection information necessary to talk to your CMI.
+# It will be used by setup-cmi.sh and ssh-cmi.sh
+
+#COMPUTE_NODE=cp-2.smbaker-xos-vtn.xos-pg0.clemson.cloudlab.us
+#MGMT_IP=172.27.0.22
+#NODE_KEY=/root/setup/id_rsa
+#VM_KEY=cmi_id_rsa
+
+COMPUTE_NODE=10.90.0.65
+MGMT_IP=172.27.0.17
+NODE_KEY=cord_pod_node_key
+VM_KEY=cmi_id_rsa
diff --git a/xos/configurations/cord-pod/cdn/cmi.yaml b/xos/configurations/cord-pod/cdn/cmi.yaml
new file mode 100644
index 0000000..62abe01
--- /dev/null
+++ b/xos/configurations/cord-pod/cdn/cmi.yaml
@@ -0,0 +1,69 @@
+---
+- hosts: cmi
+  connection: ssh
+  user: root
+  vars:
+    eth_device: eth0
+    eth_mac: 02:42:CF:8D:C0:82
+    cmi_password: XOScdn123$
+    cmi_hostname: xos-cloudlab-cmi-vtn.opencloud.us
+    cmi_dns: 8.8.8.8
+    cdn_site: CoBlitz Test
+    cdn_short_name: cobtest
+    cdn_name: CoBlitz
+#    gateway_ip: 10.124.0.1
+#    gateway_mac: 00:8c:fa:5b:09:d8
+    gateway_ip: 207.141.192.129
+    gateway_mac: a4:23:05:45:56:79
+    node_hostname: xos-cloudlab-node1-vtn.opencloud.us
+  tasks:
+  - name: fix the networking
+    shell: "{{ item }}"
+    with_items:
+      - ifconfig {{ eth_device }} hw ether {{ eth_mac }}
+      - ip route del default || true
+      - ip route add default via {{ gateway_ip }}
+      - arp -s {{ gateway_ip }} {{ gateway_mac }}
+
+  - name: copy over setup answers
+    template: src=templates/setup_answers.txt dest=/root/setup_answers.txt
+
+  - name: run the setup script
+    shell: /a/sbin/setup.sh < /root/setup_answers.txt
+    args:
+        creates: /a/var/log/setup.log
+
+  - name: fix onevapi CDNPrefix bug
+    shell: sed -i 's/hostname/str/g' /vservers/coplc/usr/share/cob_api/COB/PublicObjects/CDNPrefix.py
+
+  - name: fix onevapi OriginServer bug
+    shell: sed -i 's/attrToCheck = "edge_hosttype"/attrToCheck = "edge_hosttype_broken"/g' /vservers/coplc/usr/share/cob_api/COB/PublicObjects/OriginServer.py
+
+  - name: copy over cmi setup template
+    template: src=templates/setup_cmi_onevsh.sh dest=/vservers/coplc/root/setup_cmi_onevsh.sh
+
+  - name: run cmi setup script
+    command: vserver coplc exec onevsh /root/setup_cmi_onevsh.sh
+
+  - name: copy over cmi node setup template
+    template: src=templates/setup_cmi_node.sh dest=/vservers/coplc/root/setup_cmi_node.sh
+
+  - name: run node setup script
+    command: vserver coplc exec plcsh /root/setup_cmi_node.sh
+    args:
+        creates: /vservers/coplc/root/takeover-{{ node_hostname }}
+
+  - name: retrieve node takeover script
+    fetch: src=/vservers/coplc/root/takeover-{{ node_hostname }} dest=takeovers/takeover-{{ node_hostname }}
+
+  - name: update all keys script
+    copy: src=private/allkeys.template dest=/vservers/coplc/etc/onevantage/services/HPC/templates/usr/local/CoBlitz/var/allkeys.template
+
+  - name: install keygen
+    copy: src=private/keygen dest=/vservers/coplc/etc/onevantage/services/HPC/templates/usr/local/CoBlitz/var/keygen mode=0755
+
+  - name: download socat
+    get_url: url=http://pkgs.repoforge.org/socat/socat-1.7.2.1-1.el6.rf.x86_64.rpm dest=/root/socat-1.7.2.1-1.el6.rf.x86_64.rpm
+ 
+  - name: install socat
+    yum: name=/root/socat-1.7.2.1-1.el6.rf.x86_64.rpm state=present
diff --git a/xos/configurations/cord-pod/cdn/cmi_id_rsa.pub b/xos/configurations/cord-pod/cdn/cmi_id_rsa.pub
new file mode 100644
index 0000000..4acc08f
--- /dev/null
+++ b/xos/configurations/cord-pod/cdn/cmi_id_rsa.pub
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC+4THhqOmPNnFa/C/WbR7+BOvjJAZPRmB5d2c81CNHzkyk7OLaibEQ84Hkcaaj+KLQPKcyWhpyCLlXiaOufHQUqI4rKpFceEPpuaGRGvFrs6JRK1m3X+fj2Xw9Odg+SnJ+zHyJqwyh+8QTubFZfPXx0Gti5P6utkgzWqUmh0XuqC0JLVXBGs5M3ViIq7NemlUPcWPCLfsCzDMHMMvSeJfnT7+LB76YXqMNpmwyq9Dwv/MRd/8lV6C4q3ZmlwBBuXl4JxdUha6LtecLO+2Wdjoin+g3otCmgCnVZKAh2H1BLcZkHSy9ILs+vj22m8oB2ufyefP+R6Xsyne+G3kpJqWV smbaker@fc16-64.lan
diff --git a/xos/configurations/cord-pod/cdn/private/README b/xos/configurations/cord-pod/cdn/private/README
new file mode 100644
index 0000000..e5cfbc1
--- /dev/null
+++ b/xos/configurations/cord-pod/cdn/private/README
@@ -0,0 +1 @@
+Stuff in here is private and will not be uploaded to github. 
diff --git a/xos/configurations/cord-pod/cdn/setup-cmi-logicalinterfaces.sh b/xos/configurations/cord-pod/cdn/setup-cmi-logicalinterfaces.sh
new file mode 100644
index 0000000..b1acd65
--- /dev/null
+++ b/xos/configurations/cord-pod/cdn/setup-cmi-logicalinterfaces.sh
@@ -0,0 +1,18 @@
+#! /bin/bash
+
+source cmi-settings.sh
+
+echo "[ssh_connection]" > cmi.conf
+echo "ssh_args = -o \"ProxyCommand ssh -q -i $NODE_KEY -o StrictHostKeyChecking=no root@$COMPUTE_NODE nc $MGMT_IP 22\"" >> cmi.conf
+echo "scp_if_ssh = True" >> cmi.conf
+echo "pipelining = True" >> cmi.conf
+echo >> cmi.conf
+echo "[defaults]" >> cmi.conf
+echo "host_key_checking = False" >> cmi.conf
+
+echo "cmi ansible_ssh_private_key_file=$VM_KEY" > cmi.hosts
+
+export ANSIBLE_CONFIG=cmi.conf
+export ANSIBLE_HOSTS=cmi.hosts
+
+ansible-playbook -v --step cmi-logicalinterfaces.yaml
diff --git a/xos/configurations/cord-pod/cdn/setup-cmi.sh b/xos/configurations/cord-pod/cdn/setup-cmi.sh
new file mode 100644
index 0000000..8cfe11c
--- /dev/null
+++ b/xos/configurations/cord-pod/cdn/setup-cmi.sh
@@ -0,0 +1,20 @@
+#! /bin/bash
+
+source cmi-settings.sh
+
+#apt-get -y install sshpass
+
+echo "[ssh_connection]" > cmi.conf
+echo "ssh_args = -o \"ProxyCommand ssh -q -i $NODE_KEY -o StrictHostKeyChecking=no root@$COMPUTE_NODE nc $MGMT_IP 22\"" >> cmi.conf
+echo "scp_if_ssh = True" >> cmi.conf
+echo "pipelining = True" >> cmi.conf
+echo >> cmi.conf
+echo "[defaults]" >> cmi.conf
+echo "host_key_checking = False" >> cmi.conf
+
+echo "cmi ansible_ssh_private_key_file=$VM_KEY" > cmi.hosts
+
+export ANSIBLE_CONFIG=cmi.conf
+export ANSIBLE_HOSTS=cmi.hosts
+
+ansible-playbook -v cmi.yaml
diff --git a/xos/configurations/cord-pod/cdn/ssh-cmi.sh b/xos/configurations/cord-pod/cdn/ssh-cmi.sh
new file mode 100644
index 0000000..15a0408
--- /dev/null
+++ b/xos/configurations/cord-pod/cdn/ssh-cmi.sh
@@ -0,0 +1,5 @@
+#! /bin/bash
+
+source ./cmi-settings.sh
+
+ssh -i $VM_KEY -o "ProxyCommand ssh -q -i $NODE_KEY -o StrictHostKeyChecking=no root@$COMPUTE_NODE nc $MGMT_IP 22" root@cmi
diff --git a/xos/configurations/cord-pod/cdn/templates/setup_answers.txt b/xos/configurations/cord-pod/cdn/templates/setup_answers.txt
new file mode 100644
index 0000000..1c20be9
--- /dev/null
+++ b/xos/configurations/cord-pod/cdn/templates/setup_answers.txt
@@ -0,0 +1,18 @@
+y
+{{ cmi_password }}
+{{ cmi_password }}
+n
+{{ eth_device }}
+y
+{{ cmi_hostname }}
+{{ eth_device }}
+
+
+{{ cdn_site }}
+{{ cdn_short_name }}
+{{ cmi_dns }}
+
+{{ cdn_name }}
+{{ cmi_password }}
+{{ cmi_password }}
+y
diff --git a/xos/configurations/cord-pod/cdn/templates/setup_cmi_logicalinterfaces.sh b/xos/configurations/cord-pod/cdn/templates/setup_cmi_logicalinterfaces.sh
new file mode 100644
index 0000000..2ac8422
--- /dev/null
+++ b/xos/configurations/cord-pod/cdn/templates/setup_cmi_logicalinterfaces.sh
@@ -0,0 +1,14 @@
+lab="External"
+for service in ["HyperCache", "RequestRouter"]:
+    for node in ListAll("Node"):
+        node_id = node["node_id"]
+        for interface_id in node["interface_ids"]:
+            iface=Read("Interface", interface_id)
+            if iface["is_primary"] and len(iface["ip_address_ids"])==1:
+                ip_id = iface["ip_address_ids"][0]
+                if ListAll("LogicalInterface", {"node_id": node_id, "ip_address_ids": [ip_id], "label": lab, "service": service}):
+                    print "External label exists for node", node_id, "ip", ip_id, "service", service
+                else:
+                    print "Adding external label for node", node_id, "ip", ip_id, "service", service
+                    li = Create("LogicalInterface", {"node_id": node_id, "label": lab, "service": service})
+	            Bind("LogicalInterface", li, "IpAddress", ip_id)
diff --git a/xos/configurations/cord-pod/cdn/templates/setup_cmi_node.sh b/xos/configurations/cord-pod/cdn/templates/setup_cmi_node.sh
new file mode 100644
index 0000000..93435a3
--- /dev/null
+++ b/xos/configurations/cord-pod/cdn/templates/setup_cmi_node.sh
@@ -0,0 +1,20 @@
+site_id=GetSites()[0]["site_id"]
+nodeinfo = {'hostname': "{{ node_hostname }}", 'dns': "8.8.8.8"}
+n_id = AddNode(site_id, nodeinfo)
+mac = "DE:AD:BE:EF:00:01"
+interfacetemplate = {'mac': mac, 'kind': 'physical', 'method': 'static', 'is_primary': True, 'if_name': 'eth0'}
+i_id = AddInterface(n_id, interfacetemplate)
+ip_addr = "169.254.169.1" # TO DO: get this from Neutron in the future
+netmask = "255.255.255.254" # TO DO: get this from Neutron in the future
+ipinfo = {'ip_addr': ip_addr, 'netmask': netmask, 'type': 'ipv4'}
+ip_id = AddIpAddress(i_id, ipinfo)
+routeinfo = {'interface_id': i_id, 'next_hop': "127.0.0.127", 'subnet': '0.0.0.0', 'metric': 1}
+r_id = AddRoute(n_id, routeinfo)
+hpc_slice_id = GetSlices({"name": "co_coblitz"})[0]["slice_id"]
+AddSliceToNodes(hpc_slice_id, [n_id])
+dnsdemux_slice_id = GetSlices({"name": "co_dnsdemux"})[0]["slice_id"]
+dnsredir_slice_id = GetSlices({"name": "co_dnsredir_coblitz"})[0]["slice_id"]
+AddSliceToNodes(dnsdemux_slice_id, [n_id])
+AddSliceToNodes(dnsredir_slice_id, [n_id])
+takeoverscript=GetBootMedium(n_id, "node-cloudinit", '')
+file("/root/takeover-{{ node_hostname }}","w").write(takeoverscript)
diff --git a/xos/configurations/cord-pod/cdn/templates/setup_cmi_onevsh.sh b/xos/configurations/cord-pod/cdn/templates/setup_cmi_onevsh.sh
new file mode 100644
index 0000000..c517780
--- /dev/null
+++ b/xos/configurations/cord-pod/cdn/templates/setup_cmi_onevsh.sh
@@ -0,0 +1,19 @@
+def CreateOrFind(kind, args):
+    objs=ListAll(kind, args.copy())
+    if objs:
+        id_name = {"ServiceProvider": "service_provider_id",
+                   "ContentProvider": "content_provider_id",
+                   "OriginServer": "origin_server_id",
+                   "CDNPrefix": "cdn_prefix_id"}
+        print kind, "exists with args", args
+        return objs[0].get(id_name[kind])
+    else:
+	print "create", kind, "with args", args
+        return Create(kind, args)
+sp=CreateOrFind("ServiceProvider", {"account": "cord", "name": "cord", "enabled": True})
+cp=CreateOrFind("ContentProvider", {"account": "test", "name": "test", "enabled": True, "service_provider_id": sp})
+ors=CreateOrFind("OriginServer", {"url": "http://www.cs.arizona.edu", "content_provider_id": cp, "service_type": "HyperCache"})
+pre=CreateOrFind("CDNPrefix", {"service": "HyperCache", "enabled": True, "content_provider_id": cp, "cdn_prefix": "test.vicci.org", "default_origin_server": "http://www.cs.arizona.edu"})
+cp=CreateOrFind("ContentProvider", {"account": "onlab", "name": "onlab", "enabled": True, "service_provider_id": sp})
+ors=CreateOrFind("OriginServer", {"url": "http://onlab.vicci.org", "content_provider_id": cp, "service_type": "HyperCache"})
+pre=CreateOrFind("CDNPrefix", {"service": "HyperCache", "enabled": True, "content_provider_id": cp, "cdn_prefix": "onlab.vicci.org", "default_origin_server": "http://onlab.vicci.org"})
diff --git a/xos/configurations/cord-pod/ceilometer.yaml b/xos/configurations/cord-pod/ceilometer.yaml
new file mode 100644
index 0000000..07b163e
--- /dev/null
+++ b/xos/configurations/cord-pod/ceilometer.yaml
@@ -0,0 +1,263 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Setup CORD-related services -- vOLT, vCPE, vBNG.
+
+imports:
+   - custom_types/xos.yaml
+
+node_types:
+    tosca.nodes.SFlowService:
+        derived_from: tosca.nodes.Root
+        description: >
+            XOS SFlow Collection Service
+        capabilities:
+            scalable:
+                type: tosca.capabilities.Scalable
+            service:
+                type: tosca.capabilities.xos.Service
+        properties:
+            kind:
+                type: string
+                default: generic
+                description: Type of service.
+            view_url:
+                type: string
+                required: false
+                description: URL to follow when icon is clicked in the Service Directory.
+            icon_url:
+                type: string
+                required: false
+                description: ICON to display in the Service Directory.
+            enabled:
+                type: boolean
+                default: true
+            published:
+                type: boolean
+                default: true
+                description: If True then display this Service in the Service Directory.
+            public_key:
+                type: string
+                required: false
+                description: Public key to install into Instances to allows Services to SSH into them.
+            private_key_fn:
+                type: string
+                required: false
+                description: Location of private key file
+            versionNumber:
+                type: string
+                required: false
+                description: Version number of Service.
+            sflow_port:
+              type: integer
+              required: false
+              default: 6343
+              description: sFlow listening port
+            sflow_api_port:
+              type: integer
+              required: false
+              default: 33333
+              description: sFlow publish subscribe api listening port
+
+    tosca.nodes.CeilometerService:
+        derived_from: tosca.nodes.Root
+        description: >
+            XOS Ceilometer Service
+        capabilities:
+            scalable:
+                type: tosca.capabilities.Scalable
+            service:
+                type: tosca.capabilities.xos.Service
+        properties:
+            kind:
+                type: string
+                default: generic
+                description: Type of service.
+            view_url:
+                type: string
+                required: false
+                description: URL to follow when icon is clicked in the Service Directory.
+            icon_url:
+                type: string
+                required: false
+                description: ICON to display in the Service Directory.
+            enabled:
+                type: boolean
+                default: true
+            published:
+                type: boolean
+                default: true
+                description: If True then display this Service in the Service Directory.
+            public_key:
+                type: string
+                required: false
+                description: Public key to install into Instances to allows Services to SSH into them.
+            private_key_fn:
+                type: string
+                required: false
+                description: Location of private key file
+            versionNumber:
+                type: string
+                required: false
+                description: Version number of Service.
+            ceilometer_pub_sub_url:
+                type: string
+                required: false
+                description: REST URL of ceilometer PUB/SUB component
+
+    tosca.nodes.CeilometerTenant:
+        derived_from: tosca.nodes.Root
+        description: >
+            CORD: A Tenant of the Ceilometer Service.
+        properties:
+            kind:
+                type: string
+                default: generic
+                description: Kind of tenant
+
+topology_template:
+  node_templates:
+    service_ceilometer:
+      type: tosca.nodes.CeilometerService
+      requirements:
+      properties:
+          view_url: /admin/ceilometer/ceilometerservice/$id$/
+          kind: ceilometer
+          ceilometer_pub_sub_url: http://10.11.10.1:4455/
+          public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }
+          private_key_fn: /opt/xos/synchronizers/monitoring_channel/monitoring_channel_private_key
+      artifacts:
+          pubkey: /opt/xos/synchronizers/monitoring_channel/monitoring_channel_public_key
+
+#    service_sflow:
+#      type: tosca.nodes.SFlowService
+#      requirements:
+#      properties:
+#          view_url: /admin/ceilometer/sflowservice/$id$/
+#          kind: sflow
+#          sflow_port: 6343
+#          sflow_api_port: 33333
+
+    Private:
+      type: tosca.nodes.NetworkTemplate
+
+    management:
+      type: tosca.nodes.network.Network.XOS
+      properties:
+          no-create: true
+          no-delete: true
+          no-update: true
+
+#    ceilometer_network:
+#      type: tosca.nodes.network.Network.XOS
+#      properties:
+#          ip_version: 4
+#          labels: ceilometer_client_access
+#      requirements:
+#          - network_template:
+#              node: Private
+#              relationship: tosca.relationships.UsesNetworkTemplate
+#          - owner:
+#              node: mysite_ceilometer
+#              relationship: tosca.relationships.MemberOfSlice
+#          - connection:
+#              node: mysite_ceilometer
+#              relationship: tosca.relationships.ConnectsToSlice
+
+    mysite:
+      type: tosca.nodes.Site
+
+    trusty-server-multi-nic:
+      type: tosca.nodes.Image
+
+    ceilometer-trusty-server-multi-nic:
+      type: tosca.nodes.Image
+
+    m1.small:
+      type: tosca.nodes.Flavor
+
+    mysite_ceilometer:
+      description: Ceilometer Proxy Slice
+      type: tosca.nodes.Slice
+      requirements:
+          - ceilometer_service:
+              node: service_ceilometer
+              relationship: tosca.relationships.MemberOfService
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+          - default_image:
+                node: ceilometer-trusty-server-multi-nic
+                relationship: tosca.relationships.DefaultImage
+          - management:
+              node: management
+              relationship: tosca.relationships.ConnectsToNetwork
+          - m1.small:
+              node: m1.small
+              relationship: tosca.relationships.DefaultFlavor
+
+#    mysite_sflow:
+#      description: Slice for sFlow service
+#      type: tosca.nodes.Slice
+#      requirements:
+#          - sflow_service:
+#              node: service_sflow
+#              relationship: tosca.relationships.MemberOfService
+#          - site:
+#              node: mysite
+#              relationship: tosca.relationships.MemberOfSite
+
+    my_ceilometer_tenant:
+      description: Ceilometer Service default Tenant
+      type: tosca.nodes.CeilometerTenant
+      requirements:
+          - provider_service:
+              node: service_ceilometer
+              relationship: tosca.relationships.MemberOfService
+       
+    # Virtual machines
+#    sflow_service_instance:
+#      type: tosca.nodes.Compute
+#      capabilities:
+#        # Host container properties
+#        host:
+#         properties:
+#           num_cpus: 1
+#           disk_size: 10 GB
+#           mem_size: 4 MB
+#        # Guest Operating System properties
+#        os:
+#          properties:
+#            # host Operating System image properties
+#            architecture: x86_64
+#            type: linux
+#            distribution: Ubuntu
+#            version: 14.10
+#      requirements:
+#          - slice:
+#                node: mysite_sflow
+#                relationship: tosca.relationships.MemberOfSlice
+
+    Ceilometer:
+      type: tosca.nodes.DashboardView
+      properties:
+          url: template:xosCeilometerDashboard
+    Tenant:
+      type: tosca.nodes.DashboardView
+      properties:
+          no-create: true
+          no-update: true
+          no-delete: true
+
+    padmin@vicci.org:
+      type: tosca.nodes.User
+      properties:
+          firstname: XOS
+          lastname: admin
+          is_admin: true
+      requirements:
+          - tenant_dashboard:
+              node: Tenant
+              relationship: tosca.relationships.UsesDashboard
+          - ceilometer_dashboard:
+              node: Ceilometer
+              relationship: tosca.relationships.UsesDashboard
diff --git a/xos/configurations/cord-pod/cleanup.sh b/xos/configurations/cord-pod/cleanup.sh
new file mode 100755
index 0000000..704cacb
--- /dev/null
+++ b/xos/configurations/cord-pod/cleanup.sh
@@ -0,0 +1,50 @@
+#!/bin/bash
+
+function cleanup_network {
+  NETWORK=$1
+  SUBNETS=`neutron net-show $NETWORK | grep -i subnets | awk '{print $4}'`
+  if [[ $SUBNETS != "" ]]; then
+      PORTS=`neutron port-list | grep -i $SUBNETS | awk '{print $2}'`
+      for PORT in $PORTS; do
+          echo "Deleting port $PORT"
+          neutron port-delete $PORT
+      done
+  fi
+  neutron net-delete $NETWORK
+}
+
+source ./admin-openrc.sh
+
+echo "Deleting VMs"
+# Delete all VMs
+VMS=$( nova list --all-tenants|grep mysite|awk '{print $2}' )
+for VM in $VMS
+do
+    nova delete $VM
+done
+
+echo "Waiting 5 seconds..."
+sleep 5
+
+cleanup_network lan_network
+cleanup_network wan_network
+cleanup_network mysite_vcpe-private
+cleanup_network mysite_vsg-access
+cleanup_network management
+
+echo "Deleting networks"
+# Delete all networks beginning with mysite_
+NETS=$( neutron net-list --all-tenants|grep mysite|awk '{print $2}' )
+for NET in $NETS
+do
+    neutron net-delete $NET
+done
+
+neutron net-delete lan_network || true
+neutron net-delete subscriber_network || true
+neutron net-delete public_network || true
+neutron net-delete hpc_client_network || true
+neutron net-delete ceilometer_network || true
+neutron net-delete management || true
+neutron net-delete mysite_vsg-access || true
+neutron net-delete exampleservice-public || true
diff --git a/xos/configurations/cord-pod/cord-volt-devices.yaml b/xos/configurations/cord-pod/cord-volt-devices.yaml
new file mode 100644
index 0000000..8b41623
--- /dev/null
+++ b/xos/configurations/cord-pod/cord-volt-devices.yaml
@@ -0,0 +1,47 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Just enough Tosca to get the vSG slice running on the CORD POD
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    service#volt:
+      type: tosca.nodes.VOLTService
+      properties:
+          no-create: True
+          no-delete: True
+          no-update: True
+
+    voltdev-1:
+      type: tosca.nodes.VOLTDevice
+      properties:
+            driver: pmc-olt
+            openflow_id: of:1000000000000001
+            access_devices: >
+              2 222,
+              3 223,
+              4 224
+      requirements:
+          - volt_service:
+              node: service#volt
+              relationship: tosca.relationships.MemberOfService
+          - access_agent:
+              node: agent-1
+              relationship: tosca.relationships.UsesAgent
+
+    agent-1:
+      type: tosca.nodes.AccessAgent
+      properties:
+          mac: AA:BB:CC:DD:EE:FF
+          port_mappings: >
+            of:0000000000000002/2 DE:AD:BE:EF:BA:11,
+            of:0000000000000002/3 BE:EF:DE:AD:BE:EF
+      requirements:
+          - volt_service:
+              node: service#volt
+              relationship: tosca.relationships.MemberOfService
+
+
+
diff --git a/xos/configurations/cord-pod/cord-vtn-vsg.yaml b/xos/configurations/cord-pod/cord-vtn-vsg.yaml
new file mode 100644
index 0000000..6996527
--- /dev/null
+++ b/xos/configurations/cord-pod/cord-vtn-vsg.yaml
@@ -0,0 +1,257 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Just enough Tosca to get the vSG slice running on the CORD POD
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    # CORD Services
+    service#vtr:
+      type: tosca.nodes.Service
+      properties:
+          view_url: /admin/vtr/vtrservice/$id$/
+          kind: vTR
+          replaces: service_vtr
+
+    service#volt:
+      type: tosca.nodes.VOLTService
+      requirements:
+          - vsg_tenant:
+              node: service#vsg
+              relationship: tosca.relationships.TenantOfService
+      properties:
+          view_url: /admin/cord/voltservice/$id$/
+          kind: vOLT
+          replaces: service_volt
+          public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }
+          private_key_fn: /opt/xos/services/volt/keys/volt_rsa
+      artifacts:
+          pubkey: /opt/xos/services/volt/keys/volt_rsa.pub
+
+    addresses_vsg:
+      type: tosca.nodes.AddressPool
+      properties:
+          addresses: 10.168.0.0/24
+          gateway_ip: 10.168.0.1
+          gateway_mac: 02:42:0a:a8:00:01
+
+    addresses_exampleservice-public:
+      type: tosca.nodes.AddressPool
+      properties:
+          addresses: 10.168.1.0/24
+          gateway_ip: 10.168.1.1
+          gateway_mac: 02:42:0a:a8:00:01
+
+    service#vsg:
+      type: tosca.nodes.VSGService
+      requirements:
+          - vrouter_tenant:
+              node: service#vrouter
+              relationship: tosca.relationships.TenantOfService
+      properties:
+          view_url: /admin/cord/vsgservice/$id$/
+          backend_network_label: hpc_client
+          public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }
+          private_key_fn: /opt/xos/services/vsg/keys/vsg_rsa
+#          node_label: label_vsg
+          replaces: service_vsg
+      artifacts:
+          pubkey: /opt/xos/services/vsg/keys/vsg_rsa.pub
+
+    service#vrouter:
+      type: tosca.nodes.VRouterService
+      properties:
+          view_url: /admin/vrouter/vrouterservice/$id$/
+          replaces: service_vrouter
+      requirements:
+          - addresses_vsg:
+              node: addresses_vsg
+              relationship: tosca.relationships.ProvidesAddresses
+          - addresses_service1:
+              node: addresses_exampleservice-public
+              relationship: tosca.relationships.ProvidesAddresses
+
+
+    service#ONOS_CORD:
+      type: tosca.nodes.ONOSService
+      properties:
+          no-delete: true
+          no-create: true
+          no-update: true
+
+    service#ONOS_Fabric:
+      type: tosca.nodes.ONOSService
+      properties:
+          no-delete: true
+          no-create: true
+          no-update: true
+
+    vOLT_ONOS_app:
+      type: tosca.nodes.ONOSvOLTApp
+      requirements:
+          - onos_tenant:
+              node: service#ONOS_CORD
+              relationship: tosca.relationships.TenantOfService
+          - volt_service:
+              node: service#volt
+              relationship: tosca.relationships.UsedByService
+      properties:
+          install_dependencies: onos-ext-notifier-1.0-SNAPSHOT.oar, onos-ext-volt-event-publisher-1.0-SNAPSHOT.oar
+          dependencies: org.onosproject.openflow-base, org.onosproject.olt, org.ciena.onos.ext_notifier, org.ciena.onos.volt_event_publisher
+          autogenerate: volt-network-cfg
+
+    vRouter_ONOS_app:
+      type: tosca.nodes.ONOSvRouterApp
+      requirements:
+          - onos_tenant:
+              node: service#ONOS_Fabric
+              relationship: tosca.relationships.TenantOfService
+          - vrouter_service:
+              node: service#vrouter
+              relationship: tosca.relationships.UsedByService
+      properties:
+          dependencies: org.onosproject.vrouter
+          autogenerate: vrouter-network-cfg
+
+    Private:
+      type: tosca.nodes.NetworkTemplate
+
+    management:
+      type: tosca.nodes.network.Network.XOS
+      properties:
+          no-create: true
+          no-delete: true
+          no-update: true
+
+    image#vsg-1.0:
+      type: tosca.nodes.Image
+
+    mysite:
+      type: tosca.nodes.Site
+
+    label_vsg:
+      type: tosca.nodes.NodeLabel
+
+    # Networks required by the CORD setup
+    mysite_vsg-access:
+      type: tosca.nodes.network.Network
+      properties:
+          ip_version: 4
+      requirements:
+          - network_template:
+              node: Private
+              relationship: tosca.relationships.UsesNetworkTemplate
+          - owner:
+              node: mysite_vsg
+              relationship: tosca.relationships.MemberOfSlice
+          - connection:
+              node: mysite_vsg
+              relationship: tosca.relationships.ConnectsToSlice
+
+    # CORD Slices
+    mysite_vsg:
+      description: vSG Controller Slice
+      type: tosca.nodes.Slice
+      properties:
+          network: noauto
+      requirements:
+          - vsg_service:
+              node: service#vsg
+              relationship: tosca.relationships.MemberOfService
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+          - management:
+              node: management
+              relationship: tosca.relationships.ConnectsToNetwork
+          - image:
+              node: image#vsg-1.0
+              relationship: tosca.relationships.DefaultImage
+
+    # Let's add a user who can be administrator of the household
+    johndoe@myhouse.com:
+      type: tosca.nodes.User
+      properties:
+          password: letmein
+          firstname: john
+          lastname: doe
+      requirements:
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+          - dependency:
+                node: mysite_vsg
+                relationship: tosca.relationships.DependsOn
+
+    # A subscriber
+    My House:
+       type: tosca.nodes.CORDSubscriber
+       properties:
+           service_specific_id: 123
+           firewall_enable: false
+           cdn_enable: false
+           url_filter_enable: false
+           url_filter_level: R
+       requirements:
+          - house_admin:
+              node: johndoe@myhouse.com
+              relationship: tosca.relationships.AdminPrivilege
+
+    Mom's PC:
+       type: tosca.nodes.CORDUser
+       properties:
+           mac: 01:02:03:04:05:06
+           level: PG_13
+       requirements:
+           - household:
+               node: My House
+               relationship: tosca.relationships.SubscriberDevice
+
+    Dad's PC:
+       type: tosca.nodes.CORDUser
+       properties:
+           mac: 90:E2:BA:82:F9:75
+           level: PG_13
+       requirements:
+           - household:
+               node: My House
+               relationship: tosca.relationships.SubscriberDevice
+
+    Jack's Laptop:
+       type: tosca.nodes.CORDUser
+       properties:
+           mac: 68:5B:35:9D:91:D5
+           level: PG_13
+       requirements:
+           - household:
+               node: My House
+               relationship: tosca.relationships.SubscriberDevice
+
+    Jill's Laptop:
+       type: tosca.nodes.CORDUser
+       properties:
+           mac: 34:36:3B:C9:B6:A6
+           level: PG_13
+       requirements:
+           - household:
+               node: My House
+               relationship: tosca.relationships.SubscriberDevice
+
+    My Volt:
+        type: tosca.nodes.VOLTTenant
+        properties:
+            service_specific_id: 123
+            s_tag: 222
+            c_tag: 111
+        requirements:
+            - provider_service:
+                node: service#volt
+                relationship: tosca.relationships.MemberOfService
+            - subscriber:
+                node: My House
+                relationship: tosca.relationships.BelongsToSubscriber
+            - dependency:
+                node: mysite_vsg
+                relationship: tosca.relationships.DependsOn
diff --git a/xos/configurations/cord-pod/docker-compose-bootstrap.yml b/xos/configurations/cord-pod/docker-compose-bootstrap.yml
new file mode 100644
index 0000000..93ccb71
--- /dev/null
+++ b/xos/configurations/cord-pod/docker-compose-bootstrap.yml
@@ -0,0 +1,58 @@
+xos_db:
+    image: xosproject/xos-postgres
+    expose:
+        - "5432"
+
+xos_synchronizer_onboarding:
+    image: xosproject/xos-synchronizer-onboarding
+    command: bash -c "cd /opt/xos/synchronizers/onboarding; ./run.sh"
+    #command: sleep 86400
+    labels:
+        org.xosproject.kind: synchronizer
+        org.xosproject.target: onboarding
+    links:
+        - xos_db
+    volumes:
+        - /var/run/docker.sock:/var/run/docker.sock
+        - ./key_import:/opt/xos/key_import:ro
+        - ./onboarding-docker-compose:/opt/xos/synchronizers/onboarding/docker-compose
+    log_driver: "json-file"
+    log_opt:
+            max-size: "100k"
+            max-file: "5"
+
+xos_synchronizer_openstack:
+    command: bash -c "sleep 120; python /opt/xos/synchronizers/openstack/xos-synchronizer.py"
+    image: xosproject/xos-synchronizer-openstack
+    labels:
+        org.xosproject.kind: synchronizer
+        org.xosproject.target: openstack
+    links:
+        - xos_db
+    volumes:
+        - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
+        - ./xos_cord_config:/opt/xos/xos_configuration/xos_cord_config:ro
+        - .:/root/setup:ro
+        - ../vtn/files/xos_vtn_config:/opt/xos/xos_configuration/xos_vtn_config:ro
+        - ./images:/opt/xos/images:ro
+    log_driver: "json-file"
+    log_opt:
+            max-size: "100k"
+            max-file: "5"
+
+xos_bootstrap_ui:
+    command: python /opt/xos/manage.py runserver 0.0.0.0:81 --insecure --makemigrations
+    image: xosproject/xos
+    links:
+        - xos_db
+    ports:
+        - "81:81"
+    volumes:
+#        - .:/root/setup:ro
+        - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
+        - ./xos_cord_config:/opt/xos/xos_configuration/xos_cord_config:ro
+        - ../vtn/files/xos_vtn_config:/opt/xos/xos_configuration/xos_vtn_config:ro
+    log_driver: "json-file"
+    log_opt:
+            max-size: "100k"
+            max-file: "5"
diff --git a/xos/configurations/cord-pod/files/exampleservice_config b/xos/configurations/cord-pod/files/exampleservice_config
new file mode 100644
index 0000000..823e31d
--- /dev/null
+++ b/xos/configurations/cord-pod/files/exampleservice_config
@@ -0,0 +1,29 @@
+# Required by XOS
+[db]
+name=xos
+user=postgres
+password=password
+host=localhost
+port=5432
+
+# Required by XOS
+[api]
+nova_enabled=True
+
+# Sets options for the synchronizer
+[observer]
+name=exampleservice
+dependency_graph=/opt/xos/synchronizers/exampleservice/model-deps
+steps_dir=/opt/xos/synchronizers/exampleservice/steps
+sys_dir=/opt/xos/synchronizers/exampleservice/sys
+logfile=/var/log/xos_backend.log
+pretend=False
+backoff_disabled=True
+save_ansible_output=True
+proxy_ssh=True
+proxy_ssh_key=/root/setup/node_key
+proxy_ssh_user=root
+
+[networking]
+use_vtn=True
+
diff --git a/xos/configurations/cord-pod/files/monitoring_channel_synchronizer_config b/xos/configurations/cord-pod/files/monitoring_channel_synchronizer_config
new file mode 100644
index 0000000..fb3f22a
--- /dev/null
+++ b/xos/configurations/cord-pod/files/monitoring_channel_synchronizer_config
@@ -0,0 +1,43 @@
+
+[plc]
+name=plc
+deployment=VICCI
+
+[db]
+name=xos
+user=postgres
+password=password
+host=localhost
+port=5432
+
+[api]
+host=128.112.171.237
+port=8000
+ssl_key=None
+ssl_cert=None
+ca_ssl_cert=None
+ratelimit_enabled=0
+omf_enabled=0
+mail_support_address=support@localhost
+nova_enabled=True
+
+[observer]
+name=monitoring_channel
+dependency_graph=/opt/xos/synchronizers/monitoring_channel/model-deps
+steps_dir=/opt/xos/synchronizers/monitoring_channel/steps
+sys_dir=/opt/xos/synchronizers/monitoring_channel/sys
+deleters_dir=/opt/xos/synchronizers/monitoring_channel/deleters
+log_file=console
+driver=None
+pretend=False
+backoff_disabled=True
+save_ansible_output=True
+full_setup=True
+# For CORD_POD config, set proxy_ssh to True even on cloudlab
+proxy_ssh=True
+proxy_ssh_key=/root/setup/node_key
+proxy_ssh_user=root
+
+[feefie]
+client_id='vicci_dev_central'
+user_id='pl'
diff --git a/xos/configurations/cord-pod/files/vcpe_synchronizer_config b/xos/configurations/cord-pod/files/vcpe_synchronizer_config
new file mode 100644
index 0000000..9da6ede
--- /dev/null
+++ b/xos/configurations/cord-pod/files/vcpe_synchronizer_config
@@ -0,0 +1,47 @@
+
+[plc]
+name=plc
+deployment=VICCI
+
+[db]
+name=xos
+user=postgres
+password=password
+host=localhost
+port=5432
+
+[api]
+host=128.112.171.237
+port=8000
+ssl_key=None
+ssl_cert=None
+ca_ssl_cert=None
+ratelimit_enabled=0
+omf_enabled=0
+mail_support_address=support@localhost
+nova_enabled=True
+
+[observer]
+name=vcpe
+dependency_graph=/opt/xos/synchronizers/vsg/model-deps
+steps_dir=/opt/xos/synchronizers/vsg/steps
+sys_dir=/opt/xos/synchronizers/vsg/sys
+deleters_dir=/opt/xos/synchronizers/vsg/deleters
+log_file=console
+#/var/log/hpc.log
+driver=None
+pretend=False
+backoff_disabled=True
+save_ansible_output=True
+# set proxy_ssh to false on cloudlab
+full_setup=True
+proxy_ssh=True
+proxy_ssh_key=/root/setup/node_key
+proxy_ssh_user=root
+
+[networking]
+use_vtn=True
+
+[feefie]
+client_id='vicci_dev_central'
+user_id='pl'
diff --git a/xos/configurations/cord-pod/files/vtr_synchronizer_config b/xos/configurations/cord-pod/files/vtr_synchronizer_config
new file mode 100644
index 0000000..223ab00
--- /dev/null
+++ b/xos/configurations/cord-pod/files/vtr_synchronizer_config
@@ -0,0 +1,47 @@
+
+[plc]
+name=plc
+deployment=VICCI
+
+[db]
+name=xos
+user=postgres
+password=password
+host=localhost
+port=5432
+
+[api]
+host=128.112.171.237
+port=8000
+ssl_key=None
+ssl_cert=None
+ca_ssl_cert=None
+ratelimit_enabled=0
+omf_enabled=0
+mail_support_address=support@localhost
+nova_enabled=True
+
+[observer]
+name=vtr
+dependency_graph=/opt/xos/synchronizers/vtr/model-deps
+steps_dir=/opt/xos/synchronizers/vtr/steps
+sys_dir=/opt/xos/synchronizers/vtr/sys
+deleters_dir=/opt/xos/synchronizers/vtr/deleters
+log_file=console
+#/var/log/hpc.log
+driver=None
+pretend=False
+backoff_disabled=True
+save_ansible_output=True
+# set proxy_ssh to false on cloudlab
+full_setup=True
+proxy_ssh=True
+proxy_ssh_key=/root/setup/node_key
+proxy_ssh_user=root
+
+[networking]
+use_vtn=True
+
+[feefie]
+client_id='vicci_dev_central'
+user_id='pl'
diff --git a/xos/configurations/cord-pod/images/.gitignore b/xos/configurations/cord-pod/images/.gitignore
new file mode 100644
index 0000000..6949d1f
--- /dev/null
+++ b/xos/configurations/cord-pod/images/.gitignore
@@ -0,0 +1,3 @@
+*.img
+*.qcow2
+*.qcow
diff --git a/xos/configurations/cord-pod/images/README.md b/xos/configurations/cord-pod/images/README.md
new file mode 100644
index 0000000..aca55a9
--- /dev/null
+++ b/xos/configurations/cord-pod/images/README.md
@@ -0,0 +1,5 @@
+# VM images for XOS
+
+Any Cloud image files placed in this directory (with suffix .img) will be automatically
+imported by XOS and added to Glance (OpenStack's image repository).  For instance, the image
+`trusty-server-multi-nic.img` will be imported with name `trusty-server-multi-nic`.
diff --git a/xos/configurations/cord-pod/make-fabric-yaml.sh b/xos/configurations/cord-pod/make-fabric-yaml.sh
new file mode 100644
index 0000000..a829690
--- /dev/null
+++ b/xos/configurations/cord-pod/make-fabric-yaml.sh
@@ -0,0 +1,71 @@
+FN=$SETUPDIR/fabric.yaml
+
+rm -f $FN
+
+cat >> $FN <<EOF
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+imports:
+   - custom_types/xos.yaml
+
+description: generate fabric configuration
+
+topology_template:
+  node_templates:
+
+    service#ONOS_Fabric:
+      type: tosca.nodes.ONOSService
+      requirements:
+      properties:
+          kind: onos
+          view_url: /admin/onos/onosservice/\$id$/
+          no_container: true
+          rest_hostname: onos-fabric
+          replaces: service_ONOS_Fabric
+
+    service#fabric:
+      type: tosca.nodes.FabricService
+      properties:
+          view_url: /admin/fabric/fabricservice/\$id\$/
+          replaces: service_fabric
+
+
+EOF
+
+NODES=$( bash -c "source $SETUPDIR/admin-openrc.sh ; nova host-list" |grep compute|awk '{print $2}' )
+I=0
+for NODE in $NODES; do
+    echo $NODE
+    cat >> $FN <<EOF
+    $NODE:
+      type: tosca.nodes.Node
+
+    # Fabric location field for node $NODE
+    ${NODE}_location_tag:
+      type: tosca.nodes.Tag
+      properties:
+          name: location
+          value: of:0000000000000001/1
+      requirements:
+          - target:
+              node: $NODE
+              relationship: tosca.relationships.TagsObject
+          - service:
+              node: service#ONOS_Fabric
+              relationship: tosca.relationships.MemberOfService
+EOF
+done
+
+cat >> $FN <<EOF
+    Fabric_ONOS_app:
+      type: tosca.nodes.ONOSApp
+      requirements:
+          - onos_tenant:
+              node: service#ONOS_Fabric
+              relationship: tosca.relationships.TenantOfService
+          - fabric_service:
+              node: service#fabric
+              relationship: tosca.relationships.UsedByService
+      properties:
+          dependencies: org.onosproject.lldpprovider, org.onosproject.hostprovider, org.onosproject.openflow-base, org.onosproject.openflow, org.onosproject.drivers, org.onosproject.segmentrouting
+EOF
diff --git a/xos/configurations/cord-pod/make-virtualbng-json.sh b/xos/configurations/cord-pod/make-virtualbng-json.sh
new file mode 100644
index 0000000..993643c
--- /dev/null
+++ b/xos/configurations/cord-pod/make-virtualbng-json.sh
@@ -0,0 +1,38 @@
+FN=$SETUPDIR/virtualbng.json
+
+rm -f $FN
+
+cat >> $FN <<EOF
+{
+    "localPublicIpPrefixes" : [
+        "10.254.0.128/25"
+    ],
+    "nextHopIpAddress" : "10.254.0.1",
+    "publicFacingMac" : "00:00:00:00:00:66",
+    "xosIpAddress" : "10.11.10.1",
+    "xosRestPort" : "9999",
+    "hosts" : {
+EOF
+
+NODES=$( sudo bash -c "source $SETUPDIR/admin-openrc.sh ; nova hypervisor-list" |grep -v ID|grep -v +|awk '{print $4}' )
+
+NODECOUNT=0
+for NODE in $NODES; do
+    ((NODECOUNT++))
+done
+
+I=0
+for NODE in $NODES; do
+    echo $NODE
+    ((I++))
+    if [[ "$I" -lt "$NODECOUNT" ]]; then
+        echo "      \"$NODE\" : \"of:0000000000000001/1\"," >> $FN
+    else
+        echo "      \"$NODE\" : \"of:0000000000000001/1\"" >> $FN
+    fi
+done
+
+cat >> $FN <<EOF
+    }
+}
+EOF
diff --git a/xos/configurations/cord-pod/make-vtn-external-yaml.sh b/xos/configurations/cord-pod/make-vtn-external-yaml.sh
new file mode 100644
index 0000000..a7f04c1
--- /dev/null
+++ b/xos/configurations/cord-pod/make-vtn-external-yaml.sh
@@ -0,0 +1,109 @@
+FN=$SETUPDIR/vtn-external.yaml
+
+rm -f $FN
+
+cat >> $FN <<EOF
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+imports:
+   - custom_types/xos.yaml
+
+description: autogenerated node tags file for VTN configuration
+
+topology_template:
+  node_templates:
+
+    service#ONOS_CORD:
+      type: tosca.nodes.ONOSService
+      requirements:
+      properties:
+          kind: onos
+          view_url: /admin/onos/onosservice/\$id$/
+          no_container: true
+          rest_hostname: onos-cord
+          replaces: service_ONOS_CORD
+
+    service#vtn:
+      type: tosca.nodes.VTNService
+      properties:
+          view_url: /admin/vtn/vtnservice/\$id$/
+          privateGatewayMac: 00:00:00:00:00:01
+          localManagementIp: 172.27.0.1/24
+          ovsdbPort: 6641
+          sshUser: root
+          sshKeyFile: /root/node_key
+          sshPort: 22
+          xosEndpoint: http://xos/
+          xosUser: padmin@vicci.org
+          xosPassword: letmein
+          replaces: service_vtn
+
+EOF
+
+NODES=$( bash -c "source $SETUPDIR/admin-openrc.sh ; nova host-list" |grep compute|awk '{print $2}' )
+I=0
+for NODE in $NODES; do
+    echo $NODE
+    cat >> $FN <<EOF
+    $NODE:
+      type: tosca.nodes.Node
+
+    # VTN bridgeId field for node $NODE
+    ${NODE}_bridgeId_tag:
+      type: tosca.nodes.Tag
+      properties:
+          name: bridgeId
+          value: of:0000000000000001
+      requirements:
+          - target:
+              node: $NODE
+              relationship: tosca.relationships.TagsObject
+          - service:
+              node: service#ONOS_CORD
+              relationship: tosca.relationships.MemberOfService
+
+    # VTN dataPlaneIntf field for node $NODE
+    ${NODE}_dataPlaneIntf_tag:
+      type: tosca.nodes.Tag
+      properties:
+          name: dataPlaneIntf
+          value: veth1
+      requirements:
+          - target:
+              node: $NODE
+              relationship: tosca.relationships.TagsObject
+          - service:
+              node: service#ONOS_CORD
+              relationship: tosca.relationships.MemberOfService
+
+    # VTN dataPlaneIp field for node $NODE
+    ${NODE}_dataPlaneIp_tag:
+      type: tosca.nodes.Tag
+      properties:
+          name: dataPlaneIp
+          value: 10.168.0.253/24
+      requirements:
+          - target:
+              node: $NODE
+              relationship: tosca.relationships.TagsObject
+          - service:
+              node: service#ONOS_CORD
+              relationship: tosca.relationships.MemberOfService
+
+EOF
+done
+
+cat >> $FN <<EOF
+    VTN_ONOS_app:
+      type: tosca.nodes.ONOSVTNApp
+      requirements:
+          - onos_tenant:
+              node: service#ONOS_CORD
+              relationship: tosca.relationships.TenantOfService
+          - vtn_service:
+              node: service#vtn
+              relationship: tosca.relationships.UsedByService
+      properties:
+          dependencies: org.onosproject.drivers, org.onosproject.drivers.ovsdb, org.onosproject.openflow-base, org.onosproject.ovsdb-base, org.onosproject.dhcp, org.onosproject.cordvtn, org.onosproject.olt, org.onosproject.igmp, org.onosproject.cordmcast
+          autogenerate: vtn-network-cfg
+EOF
diff --git a/xos/configurations/cord-pod/mgmt-net.yaml b/xos/configurations/cord-pod/mgmt-net.yaml
new file mode 100644
index 0000000..2bd0173
--- /dev/null
+++ b/xos/configurations/cord-pod/mgmt-net.yaml
@@ -0,0 +1,40 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Set up management network for CORD POD
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+
+    management_template:
+      type: tosca.nodes.NetworkTemplate
+      properties:
+          visibility: private
+          translation: none
+
+    management:
+      type: tosca.nodes.network.Network
+      properties:
+          ip_version: 4
+          cidr: 172.27.0.0/24
+      requirements:
+          - network_template:
+              node: management_template
+              relationship: tosca.relationships.UsesNetworkTemplate
+          - owner:
+              node: mysite_management
+              relationship: tosca.relationships.MemberOfSlice
+
+    mysite:
+      type: tosca.nodes.Site
+
+    mysite_management:
+      description: This slice exists solely to own the management network
+      type: tosca.nodes.Slice
+      properties:
+          network: noauto
+      requirements:
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
diff --git a/xos/configurations/cord-pod/pod-cdn.yaml b/xos/configurations/cord-pod/pod-cdn.yaml
new file mode 100644
index 0000000..2229686
--- /dev/null
+++ b/xos/configurations/cord-pod/pod-cdn.yaml
@@ -0,0 +1,52 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Setup the CDN on the pod
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+
+    Private:
+      type: tosca.nodes.NetworkTemplate
+
+    management:
+      type: tosca.nodes.network.Network.XOS
+      properties:
+          no-create: true
+          no-delete: true
+          no-update: true
+
+    cdn-public:
+      type: tosca.nodes.network.Network
+      properties:
+          ip_version: 4
+          cidr: 207.141.192.128/28
+      requirements:
+          - network_template:
+              node: Private
+              relationship: tosca.relationships.UsesNetworkTemplate
+          - owner:
+              node: mysite_cdn
+              relationship: tosca.relationships.MemberOfSlice
+          - connection:
+              node: mysite_cdn
+              relationship: tosca.relationships.ConnectsToSlice
+
+    mysite:
+      type: tosca.nodes.Site
+
+    mysite_cdn:
+      description: This slice holds the CDN
+      type: tosca.nodes.Slice
+      properties:
+          network: noauto
+      requirements:
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+          - management:
+              node: management
+              relationship: tosca.relationships.ConnectsToNetwork
+
diff --git a/xos/configurations/cord-pod/pod-exampleservice.yaml b/xos/configurations/cord-pod/pod-exampleservice.yaml
new file mode 100644
index 0000000..0182a59
--- /dev/null
+++ b/xos/configurations/cord-pod/pod-exampleservice.yaml
@@ -0,0 +1,94 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Setup the ExampleService on the pod
+
+imports:
+   - custom_types/xos.yaml
+   - custom_types/exampleservice.yaml
+
+topology_template:
+  node_templates:
+
+    Private:
+      type: tosca.nodes.NetworkTemplate
+
+    management:
+      type: tosca.nodes.network.Network.XOS
+      properties:
+          no-create: true
+          no-delete: true
+          no-update: true
+
+    service#vrouter:
+      type: tosca.nodes.Service
+      properties:
+          no-create: true
+          no-delete: true
+          no-update: true
+
+    exampleservice-public:
+      type: tosca.nodes.network.Network
+      properties:
+          ip_version: 4
+      requirements:
+          - network_template:
+              node: Private
+              relationship: tosca.relationships.UsesNetworkTemplate
+          - owner:
+              node: mysite_exampleservice
+              relationship: tosca.relationships.MemberOfSlice
+          - connection:
+              node: mysite_exampleservice
+              relationship: tosca.relationships.ConnectsToSlice
+          - vrouter_tenant:
+              node: service#vrouter
+              relationship: tosca.relationships.TenantOfService
+
+    mysite:
+      type: tosca.nodes.Site
+
+    trusty-server-multi-nic:
+      type: tosca.nodes.Image
+
+    mysite_exampleservice:
+      description: This slice holds the ExampleService
+      type: tosca.nodes.Slice
+      properties:
+          network: noauto
+      requirements:
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+          - management:
+              node: management
+              relationship: tosca.relationships.ConnectsToNetwork
+          - exmapleserver:
+              node: service#exampleservice
+              relationship: tosca.relationships.MemberOfService
+          - image:
+              node: trusty-server-multi-nic
+              relationship: tosca.relationships.DefaultImage
+
+    service#exampleservice:
+      type: tosca.nodes.ExampleService
+      requirements:
+          - management:
+              node: management
+              relationship: tosca.relationships.UsesNetwork
+      properties:
+          view_url: /admin/exampleservice/exampleservice/$id$/
+          kind: exampleservice
+          public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }
+          private_key_fn: /opt/xos/services/exampleservice/keys/exampleservice_rsa
+          service_message: hello
+      artifacts:
+          pubkey: /opt/xos/services/exampleservice/keys/exampleservice_rsa.pub
+
+    tenant#exampletenant1:
+        type: tosca.nodes.ExampleTenant
+        properties:
+            tenant_message: world
+        requirements:
+          - tenant:
+              node: service#exampleservice
+              relationship: tosca.relationships.TenantOfService
diff --git a/xos/configurations/cord-pod/setup.yaml b/xos/configurations/cord-pod/setup.yaml
new file mode 100644
index 0000000..c13f0eb
--- /dev/null
+++ b/xos/configurations/cord-pod/setup.yaml
@@ -0,0 +1,61 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+    * Adds OpenCloud Sites, Deployments, and Controllers.
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+
+    MyDeployment:
+      type: tosca.nodes.Deployment
+      properties:
+          flavors: m1.large, m1.medium, m1.small
+
+    MyOpenStack:
+      type: tosca.nodes.Controller
+      requirements:
+          - deployment:
+              node: MyDeployment
+              relationship: tosca.relationships.ControllerDeployment
+      properties:
+          backend_type: OpenStack
+          version: Kilo
+          auth_url: { get_script_env: [ SELF, adminrc, OS_AUTH_URL, LOCAL_FILE] }
+          admin_user: { get_script_env: [ SELF, adminrc, OS_USERNAME, LOCAL_FILE] }
+          admin_password: { get_script_env: [ SELF, adminrc, OS_PASSWORD, LOCAL_FILE] }
+          admin_tenant: { get_script_env: [ SELF, adminrc, OS_TENANT_NAME, LOCAL_FILE] }
+          domain: Default
+      artifacts:
+          adminrc: /root/setup/admin-openrc.sh
+
+    mysite:
+      type: tosca.nodes.Site
+      properties:
+          display_name: MySite
+          site_url: http://xosproject.org/
+      requirements:
+          - deployment:
+               node: MyDeployment
+               relationship: tosca.relationships.SiteDeployment
+               requirements:
+                   - controller:
+                       node: MyOpenStack
+                       relationship: tosca.relationships.UsesController
+
+    # This user already exists in XOS with this password
+    # It's an example of how to create new users
+    padmin@vicci.org:
+      type: tosca.nodes.User
+      requirements:
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+      properties:
+          is_admin: true
+          is_active: true
+          firstname: XOS
+          lastname: admin
+          password: letmein
diff --git a/xos/configurations/cord-pod/synchronizers.yaml b/xos/configurations/cord-pod/synchronizers.yaml
new file mode 100644
index 0000000..02035e3
--- /dev/null
+++ b/xos/configurations/cord-pod/synchronizers.yaml
@@ -0,0 +1,19 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: This recipe provides additional configuration for the onboarded services.
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    servicecontroller#vsg:
+      type: tosca.nodes.ServiceController
+      properties:
+        no-create: true
+        synchronizer_config: /root/setup/files/vcpe_synchronizer_config
+    servicecontroller#vtr:
+      type: tosca.nodes.ServiceController
+      properties:
+        no-create: true
+        synchronizer_config: /root/setup/files/vtr_synchronizer_config
diff --git a/xos/configurations/cord-pod/xos.yaml b/xos/configurations/cord-pod/xos.yaml
new file mode 100644
index 0000000..95cbf18
--- /dev/null
+++ b/xos/configurations/cord-pod/xos.yaml
@@ -0,0 +1,85 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Onboard the exampleservice
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    xos:
+      type: tosca.nodes.XOS
+      properties:
+        ui_port: 80
+        bootstrap_ui_port: 81
+        docker_project_name: cordpod
+
+    /opt/xos/xos_configuration/xos_common_config:
+      type: tosca.nodes.XOSVolume
+      properties:
+          host_path: { path_join: [ SELF, CONFIG_DIR, ../common/xos_common_config, ENV_VAR ] }
+          read_only: true
+      requirements:
+          - xos:
+             node: xos
+             relationship: tosca.relationships.UsedByXOS
+
+    /opt/xos/xos_configuration/xos_cord_config:
+      type: tosca.nodes.XOSVolume
+      properties:
+          host_path: { path_join: [ SELF, CONFIG_DIR, xos_cord_config, ENV_VAR ] }
+          read_only: true
+      requirements:
+          - xos:
+             node: xos
+             relationship: tosca.relationships.UsedByXOS
+
+    /opt/xos/xos_configuration/xos_vtn_config:
+      type: tosca.nodes.XOSVolume
+      properties:
+          host_path: { path_join: [ SELF, CONFIG_DIR, ../vtn/files/xos_vtn_config, ENV_VAR ] }
+          read_only: true
+      requirements:
+          - xos:
+              node: xos
+              relationship: tosca.relationships.UsedByXOS
+
+    /root/setup:
+      type: tosca.nodes.XOSVolume
+      properties:
+          host_path: { path_join: [ SELF, CONFIG_DIR, ., ENV_VAR ] }
+          read_only: true
+      requirements:
+          - xos:
+             node: xos
+             relationship: tosca.relationships.UsedByXOS
+
+#    /opt/xos/synchronizers/onos/onos_key.pub:
+#      type: tosca.nodes.XOSVolume
+#      properties:
+#          host_path: { path_join: [ SELF, CONFIG_DIR, id_rsa.pub, ENV_VAR ] }
+#          read_only: true
+#      requirements:
+#          - xos:
+#             node: xos
+#             relationship: tosca.relationships.UsedByXOS
+
+#    /opt/xos/synchronizers/vcpe/vcpe_public_key:
+#      type: tosca.nodes.XOSVolume
+#      properties:
+#          host_path: { path_join: [ SELF, CONFIG_DIR, id_rsa.pub, ENV_VAR ] }
+#          read_only: true
+#      requirements:
+#          - xos:
+#             node: xos
+#             relationship: tosca.relationships.UsedByXOS
+
+    /opt/xos/synchronizers/monitoring_channel/monitoring_channel_public_key:
+      type: tosca.nodes.XOSVolume
+      properties:
+          host_path: { path_join: [ SELF, CONFIG_DIR, id_rsa.pub, ENV_VAR ] }                                                      
+          read_only: true
+      requirements:
+          - xos:
+             node: xos
+             relationship: tosca.relationships.UsedByXOS
diff --git a/xos/configurations/cord-pod/xos_cord_config b/xos/configurations/cord-pod/xos_cord_config
new file mode 100644
index 0000000..a5448f7
--- /dev/null
+++ b/xos/configurations/cord-pod/xos_cord_config
@@ -0,0 +1,6 @@
+[gui]
+branding_name=CORD
+#branding_css=/static/cord.css
+branding_icon=/static/cord-logo.png
+branding_favicon=/static/cord-favicon.png
+branding_bg=/static/cord-bg.jpg
diff --git a/xos/configurations/devel/Makefile b/xos/configurations/devel/Makefile
new file mode 100644
index 0000000..524e4cd
--- /dev/null
+++ b/xos/configurations/devel/Makefile
@@ -0,0 +1,54 @@
+MYIP:=$(shell hostname -i)
+
+cloudlab: common_cloudlab local_containers xos
+
+devstack: upgrade_pkgs common_devstack local_containers xos
+
+xos:
+	sudo MYIP=$(MYIP) docker-compose up -d
+	bash ../common/wait_for_xos.sh
+	sudo docker-compose run xos python /opt/xos/tosca/run.py none /opt/xos/configurations/common/fixtures.yaml
+	sudo docker-compose run xos python /opt/xos/tosca/run.py none /opt/xos/configurations/common/mydeployment.yaml
+	sudo MYIP=$(MYIP) docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/common/cloudlab-openstack.yaml
+	sudo MYIP=$(MYIP) docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/nodes.yaml
+
+common_cloudlab:
+	make -C ../common -f Makefile.cloudlab
+
+common_devstack:
+	make -C ../common -f Makefile.devstack
+
+base:
+	make -C ../../../containers/xos base
+
+local_containers:
+	echo "" > ../../../containers/xos/local_certs.crt
+	for CRT in $$(ls /usr/local/share/ca-certificates/*) ; do \
+		echo Adding Certificate: $$CRT ;\
+		cat $$CRT >> ../../../containers/xos/local_certs.crt ;\
+		echo "" >> ../../../containers/xos/local_certs.crt ;\
+	done
+	make -C ../../../containers/xos devel
+	make -C ../../../containers/synchronizer
+
+stop:
+	sudo MYIP=$(MYIP) docker-compose stop
+
+showlogs:
+	sudo MYIP=$(MYIP) docker-compose logs
+
+rm: stop
+	sudo MYIP=$(MYIP) docker-compose rm
+
+ps:
+	sudo MYIP=$(MYIP) docker-compose ps
+
+enter-xos:
+	sudo docker exec -it devel_xos_1 bash
+
+enter-synchronizer:
+	sudo docker exec -it devel_xos_synchronizer_openstack_1 bash
+
+upgrade_pkgs:
+	sudo pip install httpie --upgrade
+
diff --git a/xos/configurations/devel/README.md b/xos/configurations/devel/README.md
new file mode 100644
index 0000000..5dbad10
--- /dev/null
+++ b/xos/configurations/devel/README.md
@@ -0,0 +1,73 @@
+# XOS development environment
+
+This configuration can be used to do basic end-to-end development of XOS.  It launches
+XOS in three Docker containers (development GUI, Synchronizer, database) and configures XOS
+to talk to an OpenStack backend.  *docker-compose* is used to manage the containers.
+
+**NOTE: If your goal is to create a development environment for [CORD](http://opencord.org/), 
+this configuration is not what you want.  Look at the [cord-pod](../cord-pod) configuration instead!**
+
+## How to run it
+
+The configuration can be either run on [CloudLab](http://cloudlab.us) (controlling
+an OpenStack backend set up by a CloudLab profile) or used with a basic
+[DevStack](http://docs.openstack.org/developer/devstack/) configuration.
+
+### CloudLab
+
+To get started on CloudLab:
+* Create an experiment using the *OpenStack* profile.  Choose *Kilo* and
+disable security groups.
+* Wait until you get an email from CloudLab with title "OpenStack Instance Finished Setting Up".
+* Login to the *ctl* node of your experiment and run:
+```
+ctl:~$ git clone https://github.com/open-cloud/xos.git
+ctl:~$ cd xos/xos/configurations/devel/
+ctl:~/xos/xos/configurations/devel$ make cloudlab
+```
+
+### DevStack
+
+On a server with a fresh Ubuntu 14.04 install, 
+[this script](https://raw.githubusercontent.com/open-cloud/xos/master/xos/configurations/common/devstack/setup-devstack.sh)
+can be used to bootstrap a single-node DevStack environment that can be used
+for basic XOS development.
+The script installs DevStack and checks out the XOS repository.  Run the script
+and then invoke the XOS configuration for DevStack as follows:
+```
+~$ wget https://raw.githubusercontent.com/open-cloud/xos/master/xos/configurations/common/devstack/setup-devstack.sh
+~$ bash ./setup-devstack.sh
+~$ cd ../xos/xos/configurations/devel/
+~/xos/xos/configurations/devel$ make devstack
+```
+
+This setup has been run successfully in a VirtualBox VM with 2 CPUs and 4096 GB RAM.
+However it is recommended to use a dedicated server with more resources.
+
+
+## What you get
+
+XOS will be set up with a single Deployment and Site.  It should be in a state where
+you can create slices and associate instances with them.
+
+Note that there are some issues with the networking setup in this configuration:
+VMs do not have a working DNS configuration in `/etc/resolv.conf`.  If you fix this
+manually then everything should work.
+
+## Docker Helpers
+
+Stop the containers: `make stop`
+
+Restart the containers: `make stop; make [cloudlab|devstack]`
+
+Delete the containers and relaunch them: `make rm; make [cloudlab|devstack]`
+
+Build the containers from scratch using the local XOS source tree: `make containers`
+
+View logs: `make showlogs`
+
+See what containers are running: `make ps`
+
+Open a shell on the XOS container: `make enter-xos`
+
+Open a shell on the Synchronizer container: `make enter-synchronizer`
diff --git a/xos/configurations/devel/docker-compose.yml b/xos/configurations/devel/docker-compose.yml
new file mode 100644
index 0000000..9ef6fc7
--- /dev/null
+++ b/xos/configurations/devel/docker-compose.yml
@@ -0,0 +1,36 @@
+xos_db:
+    image: xosproject/xos-postgres
+    expose:
+        - "5432"
+
+xos_synchronizer_openstack:
+    image: xosproject/xos-synchronizer-openstack
+    command: bash -c "sleep 120; python /opt/xos/synchronizers/openstack/xos-synchronizer.py"
+    labels:
+        org.xosproject.kind: synchronizer
+        org.xosproject.target: openstack
+    links:
+        - xos_db
+    extra_hosts:
+        - ctl:${MYIP}
+    volumes:
+        - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
+        - ./images:/opt/xos/images:ro
+
+# FUTURE
+#xos_swarm_synchronizer:
+#    image: xosproject/xos-swarm-synchronizer
+#    labels:
+#        org.xosproject.kind: synchronizer
+#        org.xosproject.target: swarm
+
+xos:
+    image: xosproject/xos
+    command: python /opt/xos/manage.py runserver 0.0.0.0:8000 --insecure --makemigrations
+    ports:
+        - "9999:8000"
+    links:
+        - xos_db
+    volumes:
+      - ../setup:/root/setup:ro
+      - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
diff --git a/xos/configurations/frontend/Makefile b/xos/configurations/frontend/Makefile
new file mode 100644
index 0000000..b322ffe
--- /dev/null
+++ b/xos/configurations/frontend/Makefile
@@ -0,0 +1,101 @@
+MYIP:=$(shell hostname -i)
+CONFIG_DIR:=$(shell pwd)
+DOCKER_COMPOSE_YML=./onboarding-docker-compose/docker-compose.yml
+BOOTSTRAP_YML=./docker-compose-bootstrap.yml
+DOCKER_PROJECT=frontend
+XOS_BOOTSTRAP_PORT=9998
+XOS_UI_PORT=9999
+
+frontend: prereqs bootstrap onboarding frontendconfig
+
+prereqs:
+	sudo make -f ../common/Makefile.prereqs
+
+bootstrap:
+	echo "[BOOTSTRAP]"
+	sudo rm -f onboarding-docker-compose/docker-compose.yml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f docker-compose-bootstrap.yml up -d
+	bash ../common/wait_for_xos_port.sh $(XOS_BOOTSTRAP_PORT)
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(BOOTSTRAP_YML) run -e CONFIG_DIR=$(CONFIG_DIR) xos_bootstrap_ui python /opt/xos/tosca/run.py none /opt/xos/configurations/frontend/xos.yaml
+
+onboarding:
+	echo "[ONBOARDING]"
+	# on-board any services here
+	bash ../common/wait_for_onboarding_ready.sh $(XOS_BOOTSTRAP_PORT) xos
+	bash ../common/wait_for_xos_port.sh $(XOS_UI_PORT)
+
+frontendconfig:
+	echo "[FRONTENDCONFIG]"
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py none /opt/xos/configurations/common/fixtures.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py none /opt/xos/configurations/common/mydeployment.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/frontend/sample.yaml
+
+containers:
+	cd ../../../containers/xos; make devel
+	cd ../../../containers/synchronizer; make
+	cd ../../../containers/onboarding_synchronizer; make
+	#cd ../../../containers/xos; make devel
+
+stop:
+	test ! -s $(DOCKER_COMPOSE_YML) || sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) stop
+	sudo docker-compose -f $(BOOTSTRAP_YML) stop
+
+showlogs:
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(BOOTSTRAP_YML) logs
+
+rm: stop
+	test ! -s $(DOCKER_COMPOSE_YML) || sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) rm
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(BOOTSTRAP_YML) rm
+
+ps:
+	sudo docker-compose ps
+
+enter-xos:
+	sudo docker exec -ti frontend_xos_1 bash
+
+django-restart:
+	sudo docker exec frontend_xos_1 touch /opt/xos/xos/settings.py
+
+clean-config-folder:
+	sudo docker exec frontend_xos_1 rm -f /opt/xos/xos_configuration/xos_mcord_config
+	sudo docker exec frontend_xos_1 rm -f /opt/xos/xos_configuration/xos_cord_config
+
+mock-cord-pod: onboard-cord-pod
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/common/fixtures.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/cord-pod/mgmt-net.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/cord-pod/cord-vtn-vsg.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/cord-pod/cord-volt-devices.yaml
+	sudo docker exec frontend_xos_1 cp /opt/xos/configurations/cord-pod/xos_cord_config /opt/xos/xos_configuration/
+	sudo docker exec frontend_xos_1 touch /opt/xos/xos/settings.py
+
+onboard-cord-pod:
+	#sudo cp id_rsa key_import/vsg_rsa
+	#sudo cp id_rsa.pub key_import/vsg_rsa.pub
+	#sudo cp id_rsa key_import/volt_rsa
+	#sudo cp id_rsa.pub key_import/volt_rsa.pub
+	sudo bash -c "echo somekey > key_import/vsg_rsa"
+	sudo bash -c "echo somekey > key_import/vsg_rsa.pub"
+	sudo bash -c "echo somekey > key_import/volt_rsa"
+	sudo bash -c "echo somekey > key_import/volt_rsa.pub"
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py None /opt/xos/onboard/volt/volt-onboard.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py None /opt/xos/onboard/vsg/vsg-onboard.yaml
+	bash ../common/wait_for_onboarding_ready.sh 9998 services/volt
+	bash ../common/wait_for_onboarding_ready.sh 9998 services/vsg
+	bash ../common/wait_for_onboarding_ready.sh $(XOS_BOOTSTRAP_PORT) xos
+	bash ../common/wait_for_xos_port.sh $(XOS_UI_PORT)
+
+mock-mcord:
+	# check this
+	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/common/fixtures.yaml
+	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/cord-pod/mgmt-net.yaml
+	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/frontend/mocks/mcord.yaml
+	sudo docker exec frontend_xos_1 cp /opt/xos/configurations/mcord/xos_mcord_config /opt/xos/xos_configuration/
+	sudo docker exec frontend_xos_1 touch /opt/xos/xos/settings.py
+
+exampleservice:
+	mkdir -p key_import
+	# fake keys are fine
+	sudo bash -c "echo somekey > key_import/exampleservice_rsa"
+	sudo bash -c "echo somekey > key_import/exampleservice_rsa.pub"
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/onboard/exampleservice/exampleservice-onboard.yaml
+	bash ../common/wait_for_onboarding_ready.sh 9998 xos
diff --git a/xos/configurations/frontend/README.md b/xos/configurations/frontend/README.md
new file mode 100644
index 0000000..b1a689c
--- /dev/null
+++ b/xos/configurations/frontend/README.md
@@ -0,0 +1,52 @@
+# XOS UI Development
+
+This configuration launches the XOS GUI and database in separate containers
+using docker-compose.  The Synchronizer is not started and there is no openstack backend connected for XOS.  This configuration is intended for developing the XOS GUI.
+
+## Getting Started
+
+- Navigate to `/xos/configurations/frontend` folder
+- Run `make` command
+
+You'll be able to visit XOS at `0.0.0.0:9000` and the `xos/core/xoslib` folder is shared with the container. This means that any update to that folder is automatically reported in the container.
+
+If you need to work on the Django application itself, comment out the "sleep" command
+for the `xos` container in docker-compose.yml and run `make`.  Once the containers are
+up then type `make enter` to enter the running container.
+
+> _NOTE:
+> Please be careful and do not commit migrations, private keys or other autogenerated files._
+
+### Docker Helpers
+
+Stop the containers: `make stop`
+
+Restart the containers: `make stop; make`
+
+Delete the containers and relaunch them: `make rm; make`
+
+Build the containers from scratch using the local XOS source tree: `make containers`
+
+View logs: `make showlogs`
+
+See what containers are running: `make ps`
+
+Open a shell on the XOS container: `make enter-xos`
+
+## Docs
+
+You can find a Swagger documentation for endpoint at: `http://0.0.0.0:9000/docs/`
+
+## Populate the Data Model with custom data
+
+Sometimes while developing the GUI is usefull to have control over the DataModel. Sample `tosca` recipes for different configuration are defined in the `mocks` folder, and corresponding `make` commands are provided.
+
+- Bring up the **CORD** data model: `make mock-cord`
+- - Bring up the **M-CORD** data model: `make mock-mcord`
+
+## JS Styleguide
+
+This project is following [Google JavaScript Style Guide](https://google.github.io/styleguide/javascriptguide.xml). To contribute please install [Eslint](http://eslint.org/) in your editor and run `npm run eslint` before commit.
+
+> _NOTE_:
+> Many of the already present file were not Style compliant. Linting for them has been disabled as it was to time consuming fix all of them. If **you are going to work** on that files, please **start fixing style issues**, and then **remove the `/* eslint-disable */`** comment
diff --git a/xos/configurations/frontend/docker-compose-bootstrap.yml b/xos/configurations/frontend/docker-compose-bootstrap.yml
new file mode 100644
index 0000000..00a43f3
--- /dev/null
+++ b/xos/configurations/frontend/docker-compose-bootstrap.yml
@@ -0,0 +1,34 @@
+xos_db:
+    image: xosproject/xos-postgres
+    expose:
+        - "5432"
+
+xos_bootstrap_ui:
+    image: xosproject/xos
+    command: python /opt/xos/manage.py runserver 0.0.0.0:9998 --insecure --makemigrations
+    ports:
+        - "9998:9998"
+    links:
+        - xos_db
+    volumes:
+      - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config
+      - ../vtn/files/xos_vtn_config:/opt/xos/xos_configuration/xos_vtn_config:ro
+
+xos_synchronizer_onboarding:
+    image: xosproject/xos-synchronizer-onboarding
+    command: bash -c "cd /opt/xos/synchronizers/onboarding; ./run.sh"
+#    command: sleep 86400
+    labels:
+        org.xosproject.kind: synchronizer
+        org.xosproject.target: onboarding
+    links:
+        - xos_db
+    volumes:
+#        - .:/root/setup:ro
+        - /var/run/docker.sock:/var/run/docker.sock
+        - ./key_import:/opt/xos/key_import:ro
+        - ./onboarding-docker-compose:/opt/xos/synchronizers/onboarding/docker-compose
+    log_driver: "json-file"
+    log_opt:
+            max-size: "100k"
+            max-file: "5"
diff --git a/xos/configurations/frontend/mocks/MCORDServiceN.yaml b/xos/configurations/frontend/mocks/MCORDServiceN.yaml
new file mode 100644
index 0000000..bef7bb3
--- /dev/null
+++ b/xos/configurations/frontend/mocks/MCORDServiceN.yaml
@@ -0,0 +1,89 @@
+tosca_definitions_version: tosca_simple_yaml_1_0

+

+description: Setup MCORD-related services.

+

+imports:

+   - custom_types/xos.yaml

+

+node_types:

+    tosca.nodes.MCORDComponent:

+        derived_from: tosca.nodes.Root

+        description: >

+            CORD: A Service Component of MCORD Service.

+        properties:

+            kind:

+                type: string

+                default: generic

+                description: Kind of component

+

+topology_template:

+  node_templates:

+    service_mcord:

+      type: tosca.nodes.Service

+      requirements:

+      properties:

+          kind: mcordservice

+

+

+    Private:

+      type: tosca.nodes.NetworkTemplate

+

+    mcord_network:

+      type: tosca.nodes.network.Network.XOS

+      properties:

+          ip_version: 4

+          labels: mcord_service_internal_net

+          cidr: 172.16.16.0/24

+          start_ip: 172.16.16.1

+          end_ip: 172.16.16.5

+          gateway_ip: 172.16.16.1

+

+      requirements:

+          - network_template:

+              node: Private

+              relationship: tosca.relationships.UsesNetworkTemplate

+          - owner:

+              node: mysite_mcord_slice1

+              relationship: tosca.relationships.MemberOfSlice

+          - connection:

+              node: mysite_mcord_slice1

+              relationship: tosca.relationships.ConnectsToSlice

+

+    mysite:

+      type: tosca.nodes.Site

+

+

+    ubuntu-14.04-server-cloudimg-amd64-disk1:

+      type: tosca.nodes.Image

+

+    trusty-server-multi-nic:

+      type: tosca.nodes.Image

+

+    mysite_mcord_slice1:

+      description: MCORD Service Slice 1

+      type: tosca.nodes.Slice

+      requirements:

+          - mcord_service:

+              node: service_mcord

+              relationship: tosca.relationships.MemberOfService

+          - site:

+              node: mysite

+              relationship: tosca.relationships.MemberOfSite

+          - default_image:

+                node: ubuntu-14.04-server-cloudimg-amd64-disk1 

+#                node: mcord-server-image-s1

+                relationship: tosca.relationships.DefaultImage

+      properties:

+          default_flavor: m1.medium

+          default_node: compute9 

+

+    my_service_mcord_component1:

+      description: MCORD Service default Component

+      type: tosca.nodes.MCORDComponent

+      requirements:

+          - provider_service:

+              node: service_mcord

+              relationship: tosca.relationships.MemberOfService

+          - mcord_slice:

+              node: mysite_mcord_slice1

+              relationship: tosca.relationships.MemberOfSlice

diff --git a/xos/configurations/frontend/mocks/MCORDServiceN.yml b/xos/configurations/frontend/mocks/MCORDServiceN.yml
new file mode 100644
index 0000000..8f764d0
--- /dev/null
+++ b/xos/configurations/frontend/mocks/MCORDServiceN.yml
@@ -0,0 +1,106 @@
+tosca_definitions_version: tosca_simple_yaml_1_0

+

+description: Setup MCORD-related services.

+

+imports:

+   - custom_types/xos.yaml

+

+node_types:

+    tosca.nodes.MCORDComponent:

+        derived_from: tosca.nodes.Root

+        description: >

+            CORD: A Service Component of MCORD Service.

+        properties:

+            kind:

+                type: string

+                default: generic

+                description: Kind of component

+

+topology_template:

+  node_templates:

+    service_mcord:

+      type: tosca.nodes.Service

+      requirements:

+      properties:

+          kind: mcordservice

+

+

+    Private:

+      type: tosca.nodes.NetworkTemplate

+

+    mcord_network:

+      type: tosca.nodes.network.Network.XOS

+      properties:

+          ip_version: 4

+          labels: mcord_service_internal_net

+          cidr: 172.16.16.0/24

+          start_ip: 172.16.16.1

+          end_ip: 172.16.16.5

+          gateway_ip: 172.16.16.1

+

+      requirements:

+          - network_template:

+              node: Private

+              relationship: tosca.relationships.UsesNetworkTemplate

+          - owner:

+              node: mysite_mcord_slice1

+              relationship: tosca.relationships.MemberOfSlice

+          - connection:

+              node: mysite_mcord_slice1

+              relationship: tosca.relationships.ConnectsToSlice

+

+    mysite:

+      type: tosca.nodes.Site

+

+

+    mcord-server-image-s1:

+      type: tosca.nodes.Image

+

+    trusty-server-multi-nic:

+      type: tosca.nodes.Image

+

+    mysite_mcord_slice1:

+      description: MCORD Service Slice 1

+      type: tosca.nodes.Slice

+      requirements:

+          - mcord_service:

+              node: service_mcord

+              relationship: tosca.relationships.MemberOfService

+          - site:

+              node: mysite

+              relationship: tosca.relationships.MemberOfSite

+          - default_image:

+                node: trusty-server-multi-nic

+#                node: mcord-server-image-s1

+                relationship: tosca.relationships.DefaultImage

+      properties:

+          default_flavor: m1.medium

+          default_node: ip-10-0-10-125

+

+    my_service_mcord_component1:

+      description: MCORD Service default Component

+      type: tosca.nodes.MCORDComponent

+      # properties:

+      #     view_url: /mcord/?service=vBBU

+      #     kind: RAN

+      requirements:

+          - provider_service:

+              node: service_mcord

+              relationship: tosca.relationships.MemberOfService

+          - mcord_slice:

+              node: mysite_mcord_slice1

+              relationship: tosca.relationships.MemberOfSlice

+

+    # Nodes

+    compute9:

+      type: tosca.nodes.Node

+      properties:

+          view_url: /mcord/?service=vBBU

+          kind: RAN

+      requirements:

+        - site:

+            node: mysite

+            relationship: tosca.relationships.MemberOfSite

+        - deployment:

+            node: MyDeployment

+            relationship: tosca.relationships.MemberOfDeployment

diff --git a/xos/configurations/frontend/mocks/cord.yaml b/xos/configurations/frontend/mocks/cord.yaml
new file mode 100644
index 0000000..9d5aeaa
--- /dev/null
+++ b/xos/configurations/frontend/mocks/cord.yaml
@@ -0,0 +1,561 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Setup CORD-related services -- vOLT, vCPE, vBNG.
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+
+    addresses_vsg:
+      type: tosca.nodes.AddressPool
+      properties:
+          addresses: 10.168.0.0/24
+          gateway_ip: 10.168.0.1
+          gateway_mac: 02:42:0a:a8:00:01
+
+    addresses_exampleservice-public:
+      type: tosca.nodes.AddressPool
+      properties:
+          addresses: 10.168.1.0/24
+          gateway_ip: 10.168.1.1
+          gateway_mac: 02:42:0a:a8:00:01
+    
+    # CORD Services
+    service_volt:
+      type: tosca.nodes.Service
+      requirements:
+          - vcpe_tenant:
+              node: service_vsg
+              relationship: tosca.relationships.TenantOfService
+          - lan_network:
+              node: lan_network
+              relationship: tosca.relationships.UsesNetwork
+          - wan_network:
+              node: wan_network
+              relationship: tosca.relationships.UsesNetwork
+      properties:
+          view_url: /admin/cord/voltservice/$id$/
+          kind: vOLT
+
+    service_vrouter:
+      type: tosca.nodes.VRouterService
+      properties:
+          view_url: /admin/vrouter/vrouterservice/$id$/
+      requirements:
+          - addresses_vsg:
+              node: addresses_vsg
+              relationship: tosca.relationships.ProvidesAddresses
+          - addresses_service1:
+              node: addresses_exampleservice-public
+              relationship: tosca.relationships.ProvidesAddresses
+
+    service_vsg:
+      type: tosca.nodes.VSGService
+      requirements:
+          - vrouter_tenant:
+              node: service_vrouter
+              relationship: tosca.relationships.TenantOfService
+      properties:
+          view_url: /admin/cord/vsgservice/$id$/
+          backend_network_label: hpc_client
+          #public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }
+          #private_key_fn: /opt/xos/synchronizers/vcpe/vcpe_private_key
+      #artifacts:
+          #pubkey: /opt/xos/synchronizers/vcpe/vcpe_public_key
+
+    service_vbng:
+      type: tosca.nodes.VBNGService
+      properties:
+          view_url: /admin/cord/vbngservice/$id$/
+# if unspecified, vbng observer will look for an ONOSApp Tenant and
+# generate a URL from its IP address
+#          vbng_url: http://10.11.10.24:8181/onos/virtualbng/
+
+    service_ONOS_vBNG:
+      type: tosca.nodes.ONOSService
+      requirements:
+      properties:
+          kind: onos
+          view_url: /admin/onos/onosservice/$id$/
+          #public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }
+      #artifacts:
+          #pubkey: /opt/xos/synchronizers/onos/onos_key.pub
+
+#
+# To actually bring up the vBNG app
+# - Set up the dataplane using the ansible script
+# - Log into the vBNG ONOS and run 'devices' to get switch dpID
+# - Change the dpID values in vBNG ONOS app in XOS GUI
+# - (Synchronizer should copy the files to ONOS container immediately)
+# - Log into service_ONOS_vBNG VM and restart ONOS Docker container
+#   (Should roll this step into a Synchronizer)
+#f
+    vBNG_ONOS_app:
+      type: tosca.nodes.ONOSvBNGApp
+      requirements:
+          - onos_tenant:
+              node: service_ONOS_vBNG
+              relationship: tosca.relationships.TenantOfService
+          - vbng_service:
+              node: service_vbng
+              relationship: tosca.relationships.UsedByService
+      properties:
+          dependencies: org.onosproject.proxyarp, org.onosproject.virtualbng, org.onosproject.openflow, org.onosproject.fwd
+          config_network-cfg.json: >
+            {
+              "ports" : {
+                "of:0000000000000001/1" : {
+                  "interfaces" : [
+                    {
+                      "ips"  : [ "10.0.1.253/24" ],
+                      "mac"  : "00:00:00:00:00:99"
+                    }
+                  ]
+                },
+                "of:0000000000000001/2" : {
+                  "interfaces" : [
+                    {
+                      "ips"  : [ "10.254.0.2/24" ],
+                      "mac"  : "00:00:00:00:00:98"
+                    }
+                  ]
+                }
+              }
+            }
+          #config_virtualbng.json: { get_artifact: [ SELF, virtualbng_json, LOCAL_FILE] }
+      #artifacts:
+          #virtualbng_json: /root/setup/virtualbng.json
+
+    service_ONOS_vOLT:
+      type: tosca.nodes.ONOSService
+      requirements:
+      properties:
+          kind: onos
+          view_url: /admin/onos/onosservice/$id$/
+          #public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }
+          rest_onos/v1/network/configuration/: >
+            {
+              "devices" : {
+                "of:0000000000000001" : {
+                  "accessDevice" : {
+                    "uplink" : "2",
+                    "vlan"   : "222",
+                    "defaultVlan" : "1"
+                  },
+                  "basic" : {
+                    "driver" : "pmc-olt"
+                  }
+                }
+              }
+            }
+      #artifacts:
+          #pubkey: /opt/xos/synchronizers/onos/onos_key.pub
+
+
+    vOLT_ONOS_app:
+      type: tosca.nodes.ONOSvOLTApp
+      requirements:
+          - onos_tenant:
+              node: service_ONOS_vOLT
+              relationship: tosca.relationships.TenantOfService
+          - volt_service:
+              node: service_volt
+              relationship: tosca.relationships.UsedByService
+      properties:
+          install_dependencies: onos-ext-notifier-1.0-SNAPSHOT.oar, onos-ext-volt-event-publisher-1.0-SNAPSHOT.oar
+          dependencies: org.onosproject.openflow-base, org.onosproject.olt, org.ciena.onos.ext_notifier, org.ciena.onos.volt_event_publisher
+          component_config: >
+             {
+                "org.ciena.onos.ext_notifier.KafkaNotificationBridge":{
+                   "rabbit.user": "<rabbit_user>",
+                   "rabbit.password": "<rabbit_password>",
+                   "rabbit.host": "<rabbit_host>",
+                   "publish.rabbit": "true",
+                   "volt.events.rabbit.topic": "notifications.info",
+                   "volt.events.rabbit.exchange": "voltlistener",
+                   "volt.events.opaque.info": "{project_id: <keystone_tenant_id>, user_id: <keystone_user_id>}",
+                   "publish.volt.events": "true"
+                }
+             }
+#          config_network-cfg.json: >
+#            {
+#              "devices" : {
+#                "of:0000000000000001" : {
+#                  "accessDevice" : {
+#                    "uplink" : "2",
+#                    "vlan"   : "222",
+#                    "defaultVlan" : "1"
+#                  },
+#                  "basic" : {
+#                    "driver" : "default"
+#                  }
+#                }
+#              }
+#            }
+
+    # Network templates
+    Private:
+      type: tosca.nodes.NetworkTemplate
+
+    Public network hack:
+      type: tosca.nodes.NetworkTemplate
+      properties:
+          visibility: private
+          translation: NAT
+          shared_network_name: tun0-net
+
+
+    # Networks required by the CORD setup
+    lan_network:
+      type: tosca.nodes.network.Network
+      properties:
+          ip_version: 4
+      requirements:
+          - network_template:
+              node: Private
+              relationship: tosca.relationships.UsesNetworkTemplate
+          - owner:
+              node: mysite_vcpe
+              relationship: tosca.relationships.MemberOfSlice
+          - connection:
+              node: mysite_vcpe
+              relationship: tosca.relationships.ConnectsToSlice
+          - connection:
+              node: mysite_volt
+              relationship: tosca.relationships.ConnectsToSlice
+
+    wan_network:
+      type: tosca.nodes.network.Network
+      properties:
+          ip_version: 4
+      requirements:
+          - network_template:
+              node: Private
+              relationship: tosca.relationships.UsesNetworkTemplate
+          - owner:
+              node: mysite_vcpe
+              relationship: tosca.relationships.MemberOfSlice
+          - connection:
+              node: mysite_vcpe
+              relationship: tosca.relationships.ConnectsToSlice
+          - connection:
+              node: mysite_vbng
+              relationship: tosca.relationships.ConnectsToSlice
+
+    Private-Direct:
+      type: tosca.nodes.NetworkTemplate
+      properties:
+          access: direct
+
+    Private-Indirect:
+      type: tosca.nodes.NetworkTemplate
+      properties:
+          access: indirect
+
+    subscriber_network:
+      type: tosca.nodes.network.Network
+      properties:
+          ip_version: 4
+      requirements:
+          - network_template:
+              node: Private
+              relationship: tosca.relationships.UsesNetworkTemplate
+          - owner:
+              node: mysite_volt
+              relationship: tosca.relationships.MemberOfSlice
+          - connection:
+              node: mysite_volt
+              relationship: tosca.relationships.ConnectsToSlice
+          - connection:
+              node: mysite_clients
+              relationship: tosca.relationships.ConnectsToSlice
+
+    public_network:
+      type: tosca.nodes.network.Network
+      properties:
+      requirements:
+          - network_template:
+              node: Public network hack
+              relationship: tosca.relationships.UsesNetworkTemplate
+          - owner:
+              node: mysite_vbng
+              relationship: tosca.relationships.MemberOfSlice
+          - connection:
+              node: mysite_vbng
+              relationship: tosca.relationships.ConnectsToSlice
+
+
+    mysite:
+      type: tosca.nodes.Site
+
+
+    # CORD Slices
+    mysite_vcpe:
+      description: vCPE Controller Slice
+      type: tosca.nodes.Slice
+      requirements:
+          - vcpe_service:
+              node: service_vsg
+              relationship: tosca.relationships.MemberOfService
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+          - vcpe_docker_image:
+              node: docker-vcpe
+              relationship: tosca.relationships.UsesImage
+#      properties:
+#          default_isolation: container
+
+    mysite_onos_vbng:
+      description: ONOS Controller Slice for vBNG
+      type: tosca.nodes.Slice
+      requirements:
+          - ONOS:
+              node: service_ONOS_vBNG
+              relationship: tosca.relationships.MemberOfService
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+
+    mysite_onos_volt:
+      description: ONOS Controller Slice for vOLT
+      type: tosca.nodes.Slice
+      requirements:
+          - ONOS:
+              node: service_ONOS_vOLT
+              relationship: tosca.relationships.MemberOfService
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+
+    mysite_vbng:
+      description: slice running OVS controlled by vBNG
+      type: tosca.nodes.Slice
+      requirements:
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+
+    mysite_volt:
+      description: OVS controlled by vOLT
+      type: tosca.nodes.Slice
+      requirements:
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+
+    mysite_clients:
+      description: slice for clients at the subscriber
+      type: tosca.nodes.Slice
+      requirements:
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+
+
+    # Virtual machines
+    onos_app_1:
+      type: tosca.nodes.Compute
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+        # Guest Operating System properties
+        os:
+          properties:
+            # host Operating System image properties
+            architecture: x86_64
+            type: linux
+            distribution: Ubuntu
+            version: 14.10
+      requirements:
+          - slice:
+                node: mysite_onos_vbng
+                relationship: tosca.relationships.MemberOfSlice
+
+    onos_app_2:
+      type: tosca.nodes.Compute
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+        # Guest Operating System properties
+        os:
+          properties:
+            # host Operating System image properties
+            architecture: x86_64
+            type: linux
+            distribution: Ubuntu
+            version: 14.10
+      requirements:
+          - slice:
+                node: mysite_onos_volt
+                relationship: tosca.relationships.MemberOfSlice
+
+    # VM for running the OVS controlled by vBNG
+    ovs_vbng:
+      type: tosca.nodes.Compute
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+        # Guest Operating System properties
+        os:
+          properties:
+            # host Operating System image properties
+            architecture: x86_64
+            type: linux
+            distribution: ubuntu
+            version: 14.04
+      requirements:
+          - slice:
+                node: mysite_vbng
+                relationship: tosca.relationships.MemberOfSlice
+
+    # VM for running the OVS controlled by vOLT
+    ovs_volt:
+      type: tosca.nodes.Compute
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+        # Guest Operating System properties
+        os:
+          properties:
+            # host Operating System image properties
+            architecture: x86_64
+            type: linux
+            distribution: ubuntu
+            version: 14.04
+      requirements:
+          - slice:
+                node: mysite_volt
+                relationship: tosca.relationships.MemberOfSlice
+
+    # A subscriber client VM
+    client1:
+      type: tosca.nodes.Compute
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+        # Guest Operating System properties
+        os:
+          properties:
+            # host Operating System image properties
+            architecture: x86_64
+            type: linux
+            distribution: ubuntu
+            version: 14.04
+      requirements:
+          - slice:
+                node: mysite_clients
+                relationship: tosca.relationships.MemberOfSlice
+
+    # docker image for vcpe containers
+    docker-vcpe:
+      # TODO: need to attach this to mydeployment
+      type: tosca.nodes.Image
+      properties:
+        kind: container
+        container_format: na
+        disk_format: na
+        path: andybavier/docker-vcpe
+        tag: develop
+
+    # Let's add a user who can be administrator of the household
+    johndoe@myhouse.com:
+      type: tosca.nodes.User
+      properties:
+          password: letmein
+          firstname: john
+          lastname: doe
+      requirements:
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+
+    # A subscriber
+    My House:
+       type: tosca.nodes.CORDSubscriber
+       properties:
+           service_specific_id: 123
+           firewall_enable: false
+           cdn_enable: false
+           url_filter_enable: false
+           url_filter_level: R
+       requirements:
+          - house_admin:
+              node: johndoe@myhouse.com
+              relationship: tosca.relationships.AdminPrivilege
+
+    Mom's PC:
+       type: tosca.nodes.CORDUser
+       properties:
+           mac: 01:02:03:04:05:06
+           level: PG_13
+       requirements:
+           - household:
+               node: My House
+               relationship: tosca.relationships.SubscriberDevice
+
+    Dad's PC:
+       type: tosca.nodes.CORDUser
+       properties:
+           mac: 90:E2:BA:82:F9:75
+           level: PG_13
+       requirements:
+           - household:
+               node: My House
+               relationship: tosca.relationships.SubscriberDevice
+
+    Jack's Laptop:
+       type: tosca.nodes.CORDUser
+       properties:
+           mac: 68:5B:35:9D:91:D5
+           level: PG_13
+       requirements:
+           - household:
+               node: My House
+               relationship: tosca.relationships.SubscriberDevice
+
+    Jill's Laptop:
+       type: tosca.nodes.CORDUser
+       properties:
+           mac: 34:36:3B:C9:B6:A6
+           level: PG_13
+       requirements:
+           - household:
+               node: My House
+               relationship: tosca.relationships.SubscriberDevice
+
+    My Volt:
+        type: tosca.nodes.VOLTTenant
+        properties:
+            service_specific_id: 123
+            s_tag: 222
+            c_tag: 432
+        requirements:
+            - provider_service:
+                node: service_volt
+                relationship: tosca.relationships.MemberOfService
+            - subscriber:
+                node: My House
+                relationship: tosca.relationships.BelongsToSubscriber
diff --git a/xos/configurations/frontend/mocks/mcord.yaml b/xos/configurations/frontend/mocks/mcord.yaml
new file mode 100644
index 0000000..6c10ad3
--- /dev/null
+++ b/xos/configurations/frontend/mocks/mcord.yaml
@@ -0,0 +1,319 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Setup CORD-related services
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    # M-CORD Services
+    
+    # RAN
+    vBBU:
+      type: tosca.nodes.Service
+      properties:
+          view_url: /mcord/?service=vBBU
+          kind: RAN
+
+    eSON:
+      type: tosca.nodes.Service
+      properties:
+          view_url: http://www.google.com
+          kind: RAN
+
+    # EPC
+    vMME:
+      type: tosca.nodes.Service
+      properties:
+          view_url: /mcord/?service=vMME
+          kind: EPC
+
+    vSGW:
+      type: tosca.nodes.Service
+      properties:
+          view_url: /mcord/?service=vSGW
+          kind: EPC
+
+    vPGW:
+      type: tosca.nodes.Service
+      properties:
+          view_url: /mcord/?service=vPGW
+          kind: EPC
+
+    # EDGE
+    Cache:
+      type: tosca.nodes.Service
+      properties:
+          view_url: /mcord/?service=Cache
+          icon_url: /static/mCordServices/service_cache.png
+          kind: EDGE
+
+    Firewall:
+      type: tosca.nodes.Service
+      properties:
+          view_url: /mcord/?service=Firewall
+          icon_url: /static/mCordServices/service_firewall.png
+          kind: EDGE
+
+    Video Optimization:
+      type: tosca.nodes.Service
+      properties:
+          view_url: /mcord/?service=Video%20Optimization
+          icon_url: /static/mCordServices/service_video.png
+          kind: EDGE
+          
+    # Images
+    trusty-server-multi-nic:
+      type: tosca.nodes.Image
+      properties:
+         disk_format: QCOW2
+         container_format: BARE
+
+    # Deployments
+    StanfordDeployment:
+      type: tosca.nodes.Deployment
+      properties:
+          flavors: m1.large, m1.medium, m1.small
+      requirements:
+          - image:
+              node: trusty-server-multi-nic
+              relationship: tosca.relationships.SupportsImage
+
+    # Site
+    stanford:
+      type: tosca.nodes.Site
+      properties:
+          display_name: Stanford University
+          site_url: https://www.stanford.edu/
+      requirements:
+          - deployment:
+               node: StanfordDeployment
+               relationship: tosca.relationships.SiteDeployment
+               requirements:
+                   - controller:
+                       node: CloudLab
+                       relationship: tosca.relationships.UsesController
+
+
+    # Nodes
+    node1.stanford.edu:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: StanfordDeployment
+            relationship: tosca.relationships.MemberOfDeployment
+
+    # Slices
+    stanford_slice:
+      description: Slice that contains sample instances
+      type: tosca.nodes.Slice
+      requirements:
+          - site:
+              node: stanford
+              relationship: tosca.relationships.MemberOfSite
+
+    # Instances
+    BBU_service_instance1:
+      type: tosca.nodes.Compute
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+        # Guest Operating System properties
+        os:
+          properties:
+            # host Operating System image properties
+            architecture: x86_64
+            type: linux
+            distribution: ubuntu
+            version: 14.04
+      requirements:
+          - slice:
+                node: stanford_slice
+                relationship: tosca.relationships.MemberOfSlice
+
+    BBU_service_instance2:
+      type: tosca.nodes.Compute
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+        # Guest Operating System properties
+        os:
+          properties:
+            # host Operating System image properties
+            architecture: x86_64
+            type: linux
+            distribution: ubuntu
+            version: 14.04
+      requirements:
+          - slice:
+                node: stanford_slice
+                relationship: tosca.relationships.MemberOfSlice
+
+    MME_service_instance1:
+      type: tosca.nodes.Compute
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+        # Guest Operating System properties
+        os:
+          properties:
+            # host Operating System image properties
+            architecture: x86_64
+            type: linux
+            distribution: ubuntu
+            version: 14.04
+      requirements:
+          - slice:
+                node: stanford_slice
+                relationship: tosca.relationships.MemberOfSlice
+
+    SGW_service_instance1:
+      type: tosca.nodes.Compute
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+        # Guest Operating System properties
+        os:
+          properties:
+            # host Operating System image properties
+            architecture: x86_64
+            type: linux
+            distribution: ubuntu
+            version: 14.04
+      requirements:
+          - slice:
+                node: stanford_slice
+                relationship: tosca.relationships.MemberOfSlice
+
+    PGW_service_instance1:
+      type: tosca.nodes.Compute
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+        # Guest Operating System properties
+        os:
+          properties:
+            # host Operating System image properties
+            architecture: x86_64
+            type: linux
+            distribution: ubuntu
+            version: 14.04
+      requirements:
+          - slice:
+                node: stanford_slice
+                relationship: tosca.relationships.MemberOfSlice
+
+    # Let's add a user who can be administrator of the household
+    johndoe@stanford.us:
+      type: tosca.nodes.User
+      properties:
+          password: letmein
+          firstname: john
+          lastname: doe
+      requirements:
+          - site:
+              node: stanford
+              relationship: tosca.relationships.MemberOfSite
+
+    # A subscriber
+    Stanford:
+       type: tosca.nodes.CORDSubscriber
+       properties:
+           service_specific_id: 123
+           firewall_enable: false
+           cdn_enable: false
+           url_filter_enable: false
+           url_filter_level: R
+       requirements:
+          - house_admin:
+              node: johndoe@stanford.us
+              relationship: tosca.relationships.AdminPrivilege
+
+    Barbera Lapinski:
+       type: tosca.nodes.CORDUser
+       properties:
+           mac: 01:02:03:04:05:06
+           level: PG_13
+       requirements:
+           - household:
+               node: Stanford
+               relationship: tosca.relationships.SubscriberDevice
+
+    Norbert Shumway:
+       type: tosca.nodes.CORDUser
+       properties:
+           mac: 90:E2:BA:82:F9:75
+           level: PG_13
+       requirements:
+           - household:
+               node: Stanford
+               relationship: tosca.relationships.SubscriberDevice
+
+    Fay Muldoon:
+       type: tosca.nodes.CORDUser
+       properties:
+           mac: 68:5B:35:9D:91:D5
+           level: PG_13
+       requirements:
+           - household:
+               node: Stanford
+               relationship: tosca.relationships.SubscriberDevice
+
+    Janene Earnest:
+       type: tosca.nodes.CORDUser
+       properties:
+           mac: 34:36:3B:C9:B6:A6
+           level: PG_13
+       requirements:
+           - household:
+               node: Stanford
+               relationship: tosca.relationships.SubscriberDevice
+
+
+    Topology:
+      type: tosca.nodes.DashboardView
+      properties:
+          url: template:xosMcordTopology
+
+    Ceilometer:
+      type: tosca.nodes.DashboardView
+      properties:
+          url: template:xosCeilometerDashboard
+
+    padmin@vicci.org:
+      type: tosca.nodes.User
+      properties:
+          firstname: XOS
+          lastname: admin
+          is_admin: true
+      requirements:
+          - mcord_dashboard:
+              node: Topology
+              relationship: tosca.relationships.UsesDashboard
+          - ceilometer_dashboard:
+              node: Ceilometer
+              relationship: tosca.relationships.UsesDashboard
diff --git a/xos/configurations/frontend/sample.yaml b/xos/configurations/frontend/sample.yaml
new file mode 100644
index 0000000..0cc47ab
--- /dev/null
+++ b/xos/configurations/frontend/sample.yaml
@@ -0,0 +1,91 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+    * Some sample data to populate the demo frontend
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    trusty-server-multi-nic:
+      type: tosca.nodes.Image
+      properties:
+         disk_format: QCOW2
+         container_format: BARE
+
+    MyDeployment:
+      type: tosca.nodes.Deployment
+      properties:
+          flavors: m1.large, m1.medium, m1.small
+      requirements:
+          - image:
+              node: trusty-server-multi-nic
+              relationship: tosca.relationships.SupportsImage
+
+    CloudLab:
+      type: tosca.nodes.Controller
+      requirements:
+          - deployment:
+              node: MyDeployment
+              relationship: tosca.relationships.ControllerDeployment
+      properties:
+          backend_type: OpenStack
+          version: Juno
+          auth_url: http://sample/v2
+          admin_user: admin
+          admin_password: adminpassword
+          admin_tenant: admin
+          domain: Default
+
+    mysite:
+      type: tosca.nodes.Site
+      properties:
+          display_name: MySite
+          site_url: http://opencloud.us/
+      requirements:
+          - deployment:
+               node: MyDeployment
+               relationship: tosca.relationships.SiteDeployment
+               requirements:
+                   - controller:
+                       node: CloudLab
+                       relationship: tosca.relationships.UsesController
+
+    Public shared IPv4:
+      type: tosca.nodes.NetworkTemplate
+      properties:
+          visibility: private
+          translation: NAT
+
+    padmin@vicci.org:
+      type: tosca.nodes.User
+      requirements:
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+      properties:
+          is_admin: true
+          is_active: true
+          firstname: XOS
+          lastname: admin
+
+    node1.opencloud.us:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: mysite
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: MyDeployment
+            relationship: tosca.relationships.MemberOfDeployment
+
+    node2.opencloud.us:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: mysite
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: MyDeployment
+            relationship: tosca.relationships.MemberOfDeployment
\ No newline at end of file
diff --git a/xos/configurations/frontend/service_chain.yaml b/xos/configurations/frontend/service_chain.yaml
new file mode 100644
index 0000000..557f98e
--- /dev/null
+++ b/xos/configurations/frontend/service_chain.yaml
@@ -0,0 +1,204 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Setup two subscriber with related service chain, use for development of serviceTopology view.
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    # CORD Subscribers
+    Night's Watch:
+      type: tosca.nodes.CORDSubscriber
+      properties:
+        service_specific_id: 123
+        firewall_enable: false
+        cdn_enable: false
+        url_filter_enable: false
+        url_filter_level: R
+
+    # CORD Users for Night's Watch
+    Jhon Snow:
+      type: tosca.nodes.CORDUser
+      properties:
+        mac: 01:02:03:04:05:06
+        level: PG_13
+      requirements:
+        - household:
+            node: Night's Watch
+            relationship: tosca.relationships.SubscriberDevice
+
+    House Targaryen:
+      type: tosca.nodes.CORDSubscriber
+      properties:
+        service_specific_id: 321
+        firewall_enable: false
+        cdn_enable: false
+        url_filter_enable: false
+        url_filter_level: R
+
+    # CORD Users for House Targaryen
+    Daenerys:
+      type: tosca.nodes.CORDUser
+      properties:
+        mac: 06:05:04:03:02:01
+        level: PG_13
+      requirements:
+        - household:
+            node: House Targaryen
+            relationship: tosca.relationships.SubscriberDevice
+
+    # vOLT Tenants
+    Night's Watch vOLT:
+      type: tosca.nodes.VOLTTenant
+      properties:
+        service_specific_id: 123
+        s_tag: 123
+        c_tag: 456
+      requirements:
+        - provider_service:
+            node: service_volt
+            relationship: tosca.relationships.MemberOfService
+        - subscriber:
+            node: Night's Watch
+            relationship: tosca.relationships.BelongsToSubscriber
+
+    Targaryen vOLT:
+      type: tosca.nodes.VOLTTenant
+      properties:
+        service_specific_id: 321
+        s_tag: 321
+        c_tag: 654
+      requirements:
+        - provider_service:
+            node: service_volt
+            relationship: tosca.relationships.MemberOfService
+        - subscriber:
+            node: House Targaryen
+            relationship: tosca.relationships.BelongsToSubscriber
+
+    # CORD Services
+    service_volt:
+      type: tosca.nodes.Service
+      requirements:
+        - vcpe_tenant:
+            node: service_vcpe
+            relationship: tosca.relationships.TenantOfService
+        - lan_network:
+            node: lan_network
+            relationship: tosca.relationships.UsesNetwork
+        - wan_network:
+            node: wan_network
+            relationship: tosca.relationships.UsesNetwork
+      properties:
+        view_url: /admin/cord/voltservice/$id$/
+        kind: vOLT
+
+    service_vcpe:
+      type: tosca.nodes.VCPEService
+      requirements:
+        - vbng_tenant:
+            node: service_vbng
+            relationship: tosca.relationships.TenantOfService
+      properties:
+        view_url: /admin/cord/vcpeservice/$id$/
+        backend_network_label: hpc_client
+        public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }
+        private_key_fn: /opt/xos/observers/vcpe/vcpe_private_key
+      artifacts:
+        pubkey: /root/.ssh/id_rsa.pub #is this right?
+
+    service_vbng:
+      type: tosca.nodes.VBNGService
+      properties:
+        view_url: /admin/cord/vbngservice/$id$/
+
+    # Networks required
+    lan_network:
+      type: tosca.nodes.network.Network
+      properties:
+        ip_version: 4
+      requirements:
+        - network_template:
+            node: Private
+            relationship: tosca.relationships.UsesNetworkTemplate
+        - owner:
+            node: mysite_vcpe
+            relationship: tosca.relationships.MemberOfSlice
+        - connection:
+            node: mysite_vcpe
+            relationship: tosca.relationships.ConnectsToSlice
+        - connection:
+            node: mysite_volt
+            relationship: tosca.relationships.ConnectsToSlice
+
+    wan_network:
+      type: tosca.nodes.network.Network
+      properties:
+        ip_version: 4
+      requirements:
+        - network_template:
+            node: Private
+            relationship: tosca.relationships.UsesNetworkTemplate
+        - owner:
+            node: mysite_vcpe
+            relationship: tosca.relationships.MemberOfSlice
+        - connection:
+            node: mysite_vcpe
+            relationship: tosca.relationships.ConnectsToSlice
+        - connection:
+            node: mysite_vbng
+            relationship: tosca.relationships.ConnectsToSlice
+
+    # Network templates
+    Private:
+      type: tosca.nodes.NetworkTemplate
+
+    # Sites
+    mysite:
+      type: tosca.nodes.Site
+
+    # Slices
+    mysite_vcpe:
+      description: vCPE Controller Slice
+      type: tosca.nodes.Slice
+      requirements:
+        - vcpe_service:
+            node: service_vcpe
+            relationship: tosca.relationships.MemberOfService
+        - site:
+            node: mysite
+            relationship: tosca.relationships.MemberOfSite
+        - vcpe_docker_image:
+            node: docker-vcpe
+            relationship: tosca.relationships.UsesImage
+      properties:
+          default_isolation: container
+
+    mysite_vbng:
+      description: slice running OVS controlled by vBNG
+      type: tosca.nodes.Slice
+      requirements:
+        - site:
+            node: mysite
+            relationship: tosca.relationships.MemberOfSite
+
+    mysite_volt:
+      description: OVS controlled by vOLT
+      type: tosca.nodes.Slice
+      requirements:
+        - site:
+            node: mysite
+            relationship: tosca.relationships.MemberOfSite
+
+    # docker image for vcpe containers
+    docker-vcpe:
+      # TODO: need to attach this to mydeployment
+      type: tosca.nodes.Image
+      properties:
+        kind: container
+        container_format: na
+        disk_format: na
+        path: andybavier/docker-vcpe
+        tag: develop
+
diff --git a/xos/configurations/frontend/xos.sql b/xos/configurations/frontend/xos.sql
new file mode 100644
index 0000000..bbfd15a
--- /dev/null
+++ b/xos/configurations/frontend/xos.sql
@@ -0,0 +1,10017 @@
+--
+-- PostgreSQL database dump
+--
+
+SET statement_timeout = 0;
+SET lock_timeout = 0;
+SET client_encoding = 'SQL_ASCII';
+SET standard_conforming_strings = on;
+SET check_function_bodies = false;
+SET client_min_messages = warning;
+
+--
+-- Name: plpgsql; Type: EXTENSION; Schema: -; Owner: 
+--
+
+CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog;
+
+
+--
+-- Name: EXTENSION plpgsql; Type: COMMENT; Schema: -; Owner: 
+--
+
+COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language';
+
+
+SET search_path = public, pg_catalog;
+
+SET default_tablespace = '';
+
+SET default_with_oids = false;
+
+--
+-- Name: auth_group; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE auth_group (
+    id integer NOT NULL,
+    name character varying(80) NOT NULL
+);
+
+
+ALTER TABLE public.auth_group OWNER TO postgres;
+
+--
+-- Name: auth_group_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE auth_group_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.auth_group_id_seq OWNER TO postgres;
+
+--
+-- Name: auth_group_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE auth_group_id_seq OWNED BY auth_group.id;
+
+
+--
+-- Name: auth_group_permissions; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE auth_group_permissions (
+    id integer NOT NULL,
+    group_id integer NOT NULL,
+    permission_id integer NOT NULL
+);
+
+
+ALTER TABLE public.auth_group_permissions OWNER TO postgres;
+
+--
+-- Name: auth_group_permissions_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE auth_group_permissions_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.auth_group_permissions_id_seq OWNER TO postgres;
+
+--
+-- Name: auth_group_permissions_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE auth_group_permissions_id_seq OWNED BY auth_group_permissions.id;
+
+
+--
+-- Name: auth_permission; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE auth_permission (
+    id integer NOT NULL,
+    name character varying(50) NOT NULL,
+    content_type_id integer NOT NULL,
+    codename character varying(100) NOT NULL
+);
+
+
+ALTER TABLE public.auth_permission OWNER TO postgres;
+
+--
+-- Name: auth_permission_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE auth_permission_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.auth_permission_id_seq OWNER TO postgres;
+
+--
+-- Name: auth_permission_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE auth_permission_id_seq OWNED BY auth_permission.id;
+
+
+--
+-- Name: core_account; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_account (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    site_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_account OWNER TO postgres;
+
+--
+-- Name: core_account_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_account_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_account_id_seq OWNER TO postgres;
+
+--
+-- Name: core_account_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_account_id_seq OWNED BY core_account.id;
+
+
+--
+-- Name: core_addresspool; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_addresspool (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(32) NOT NULL,
+    addresses text,
+    inuse text
+);
+
+
+ALTER TABLE public.core_addresspool OWNER TO postgres;
+
+--
+-- Name: core_addresspool_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_addresspool_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_addresspool_id_seq OWNER TO postgres;
+
+--
+-- Name: core_addresspool_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_addresspool_id_seq OWNED BY core_addresspool.id;
+
+
+--
+-- Name: core_charge; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_charge (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    kind character varying(30) NOT NULL,
+    state character varying(30) NOT NULL,
+    date timestamp with time zone NOT NULL,
+    amount double precision NOT NULL,
+    "coreHours" double precision NOT NULL,
+    account_id integer NOT NULL,
+    invoice_id integer,
+    object_id integer NOT NULL,
+    slice_id integer
+);
+
+
+ALTER TABLE public.core_charge OWNER TO postgres;
+
+--
+-- Name: core_charge_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_charge_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_charge_id_seq OWNER TO postgres;
+
+--
+-- Name: core_charge_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_charge_id_seq OWNED BY core_charge.id;
+
+
+--
+-- Name: core_controller; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_controller (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(200) NOT NULL,
+    backend_type character varying(200) NOT NULL,
+    version character varying(200) NOT NULL,
+    auth_url character varying(200),
+    admin_user character varying(200),
+    admin_password character varying(200),
+    admin_tenant character varying(200),
+    domain character varying(200),
+    rabbit_host character varying(200),
+    rabbit_user character varying(200),
+    rabbit_password character varying(200),
+    deployment_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_controller OWNER TO postgres;
+
+--
+-- Name: core_controller_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_controller_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_controller_id_seq OWNER TO postgres;
+
+--
+-- Name: core_controller_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_controller_id_seq OWNED BY core_controller.id;
+
+
+--
+-- Name: core_controllercredential; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_controllercredential (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(128) NOT NULL,
+    key_id character varying(1024) NOT NULL,
+    enc_value text NOT NULL,
+    controller_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_controllercredential OWNER TO postgres;
+
+--
+-- Name: core_controllercredential_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_controllercredential_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_controllercredential_id_seq OWNER TO postgres;
+
+--
+-- Name: core_controllercredential_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_controllercredential_id_seq OWNED BY core_controllercredential.id;
+
+
+--
+-- Name: core_controllerdashboardview; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_controllerdashboardview (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    enabled boolean NOT NULL,
+    url character varying(1024) NOT NULL,
+    controller_id integer NOT NULL,
+    "dashboardView_id" integer NOT NULL
+);
+
+
+ALTER TABLE public.core_controllerdashboardview OWNER TO postgres;
+
+--
+-- Name: core_controllerdashboardview_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_controllerdashboardview_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_controllerdashboardview_id_seq OWNER TO postgres;
+
+--
+-- Name: core_controllerdashboardview_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_controllerdashboardview_id_seq OWNED BY core_controllerdashboardview.id;
+
+
+--
+-- Name: core_controllerimages; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_controllerimages (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    glance_image_id character varying(200),
+    controller_id integer NOT NULL,
+    image_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_controllerimages OWNER TO postgres;
+
+--
+-- Name: core_controllerimages_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_controllerimages_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_controllerimages_id_seq OWNER TO postgres;
+
+--
+-- Name: core_controllerimages_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_controllerimages_id_seq OWNED BY core_controllerimages.id;
+
+
+--
+-- Name: core_controllernetwork; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_controllernetwork (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    net_id character varying(256),
+    router_id character varying(256),
+    subnet_id character varying(256),
+    subnet character varying(32) NOT NULL,
+    controller_id integer NOT NULL,
+    network_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_controllernetwork OWNER TO postgres;
+
+--
+-- Name: core_controllernetwork_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_controllernetwork_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_controllernetwork_id_seq OWNER TO postgres;
+
+--
+-- Name: core_controllernetwork_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_controllernetwork_id_seq OWNED BY core_controllernetwork.id;
+
+
+--
+-- Name: core_controllerrole; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_controllerrole (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    role character varying(30) NOT NULL
+);
+
+
+ALTER TABLE public.core_controllerrole OWNER TO postgres;
+
+--
+-- Name: core_controllerrole_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_controllerrole_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_controllerrole_id_seq OWNER TO postgres;
+
+--
+-- Name: core_controllerrole_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_controllerrole_id_seq OWNED BY core_controllerrole.id;
+
+
+--
+-- Name: core_controllersite; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_controllersite (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    tenant_id character varying(200),
+    controller_id integer,
+    site_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_controllersite OWNER TO postgres;
+
+--
+-- Name: core_controllersite_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_controllersite_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_controllersite_id_seq OWNER TO postgres;
+
+--
+-- Name: core_controllersite_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_controllersite_id_seq OWNED BY core_controllersite.id;
+
+
+--
+-- Name: core_controllersiteprivilege; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_controllersiteprivilege (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    role_id character varying(200),
+    controller_id integer NOT NULL,
+    site_privilege_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_controllersiteprivilege OWNER TO postgres;
+
+--
+-- Name: core_controllersiteprivilege_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_controllersiteprivilege_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_controllersiteprivilege_id_seq OWNER TO postgres;
+
+--
+-- Name: core_controllersiteprivilege_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_controllersiteprivilege_id_seq OWNED BY core_controllersiteprivilege.id;
+
+
+--
+-- Name: core_controllerslice; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_controllerslice (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    tenant_id character varying(200),
+    controller_id integer NOT NULL,
+    slice_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_controllerslice OWNER TO postgres;
+
+--
+-- Name: core_controllerslice_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_controllerslice_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_controllerslice_id_seq OWNER TO postgres;
+
+--
+-- Name: core_controllerslice_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_controllerslice_id_seq OWNED BY core_controllerslice.id;
+
+
+--
+-- Name: core_controllersliceprivilege; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_controllersliceprivilege (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    role_id character varying(200),
+    controller_id integer NOT NULL,
+    slice_privilege_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_controllersliceprivilege OWNER TO postgres;
+
+--
+-- Name: core_controllersliceprivilege_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_controllersliceprivilege_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_controllersliceprivilege_id_seq OWNER TO postgres;
+
+--
+-- Name: core_controllersliceprivilege_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_controllersliceprivilege_id_seq OWNED BY core_controllersliceprivilege.id;
+
+
+--
+-- Name: core_controlleruser; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_controlleruser (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    kuser_id character varying(200),
+    controller_id integer NOT NULL,
+    user_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_controlleruser OWNER TO postgres;
+
+--
+-- Name: core_controlleruser_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_controlleruser_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_controlleruser_id_seq OWNER TO postgres;
+
+--
+-- Name: core_controlleruser_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_controlleruser_id_seq OWNED BY core_controlleruser.id;
+
+
+--
+-- Name: core_dashboardview; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_dashboardview (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(200) NOT NULL,
+    url character varying(1024) NOT NULL,
+    enabled boolean NOT NULL
+);
+
+
+ALTER TABLE public.core_dashboardview OWNER TO postgres;
+
+--
+-- Name: core_dashboardview_deployments; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_dashboardview_deployments (
+    id integer NOT NULL,
+    dashboardview_id integer NOT NULL,
+    deployment_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_dashboardview_deployments OWNER TO postgres;
+
+--
+-- Name: core_dashboardview_deployments_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_dashboardview_deployments_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_dashboardview_deployments_id_seq OWNER TO postgres;
+
+--
+-- Name: core_dashboardview_deployments_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_dashboardview_deployments_id_seq OWNED BY core_dashboardview_deployments.id;
+
+
+--
+-- Name: core_dashboardview_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_dashboardview_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_dashboardview_id_seq OWNER TO postgres;
+
+--
+-- Name: core_dashboardview_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_dashboardview_id_seq OWNED BY core_dashboardview.id;
+
+
+--
+-- Name: core_deployment; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_deployment (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(200) NOT NULL,
+    "accessControl" text NOT NULL
+);
+
+
+ALTER TABLE public.core_deployment OWNER TO postgres;
+
+--
+-- Name: core_deployment_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_deployment_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_deployment_id_seq OWNER TO postgres;
+
+--
+-- Name: core_deployment_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_deployment_id_seq OWNED BY core_deployment.id;
+
+
+--
+-- Name: core_deploymentprivilege; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_deploymentprivilege (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    deployment_id integer NOT NULL,
+    role_id integer NOT NULL,
+    user_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_deploymentprivilege OWNER TO postgres;
+
+--
+-- Name: core_deploymentprivilege_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_deploymentprivilege_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_deploymentprivilege_id_seq OWNER TO postgres;
+
+--
+-- Name: core_deploymentprivilege_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_deploymentprivilege_id_seq OWNED BY core_deploymentprivilege.id;
+
+
+--
+-- Name: core_deploymentrole; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_deploymentrole (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    role character varying(30) NOT NULL
+);
+
+
+ALTER TABLE public.core_deploymentrole OWNER TO postgres;
+
+--
+-- Name: core_deploymentrole_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_deploymentrole_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_deploymentrole_id_seq OWNER TO postgres;
+
+--
+-- Name: core_deploymentrole_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_deploymentrole_id_seq OWNED BY core_deploymentrole.id;
+
+
+--
+-- Name: core_diag; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_diag (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(200) NOT NULL
+);
+
+
+ALTER TABLE public.core_diag OWNER TO postgres;
+
+--
+-- Name: core_diag_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_diag_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_diag_id_seq OWNER TO postgres;
+
+--
+-- Name: core_diag_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_diag_id_seq OWNED BY core_diag.id;
+
+
+--
+-- Name: core_flavor; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_flavor (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(32) NOT NULL,
+    description character varying(1024),
+    flavor character varying(32) NOT NULL,
+    "order" integer NOT NULL,
+    "default" boolean NOT NULL
+);
+
+
+ALTER TABLE public.core_flavor OWNER TO postgres;
+
+--
+-- Name: core_flavor_deployments; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_flavor_deployments (
+    id integer NOT NULL,
+    flavor_id integer NOT NULL,
+    deployment_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_flavor_deployments OWNER TO postgres;
+
+--
+-- Name: core_flavor_deployments_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_flavor_deployments_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_flavor_deployments_id_seq OWNER TO postgres;
+
+--
+-- Name: core_flavor_deployments_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_flavor_deployments_id_seq OWNED BY core_flavor_deployments.id;
+
+
+--
+-- Name: core_flavor_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_flavor_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_flavor_id_seq OWNER TO postgres;
+
+--
+-- Name: core_flavor_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_flavor_id_seq OWNED BY core_flavor.id;
+
+
+--
+-- Name: core_image; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_image (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(256) NOT NULL,
+    kind character varying(30) NOT NULL,
+    disk_format character varying(256) NOT NULL,
+    container_format character varying(256) NOT NULL,
+    path character varying(256),
+    tag character varying(256)
+);
+
+
+ALTER TABLE public.core_image OWNER TO postgres;
+
+--
+-- Name: core_image_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_image_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_image_id_seq OWNER TO postgres;
+
+--
+-- Name: core_image_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_image_id_seq OWNED BY core_image.id;
+
+
+--
+-- Name: core_imagedeployments; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_imagedeployments (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    deployment_id integer NOT NULL,
+    image_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_imagedeployments OWNER TO postgres;
+
+--
+-- Name: core_imagedeployments_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_imagedeployments_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_imagedeployments_id_seq OWNER TO postgres;
+
+--
+-- Name: core_imagedeployments_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_imagedeployments_id_seq OWNED BY core_imagedeployments.id;
+
+
+--
+-- Name: core_instance; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_instance (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    instance_id character varying(200),
+    instance_uuid character varying(200),
+    name character varying(200) NOT NULL,
+    instance_name character varying(200),
+    ip inet,
+    "numberCores" integer NOT NULL,
+    "userData" text,
+    isolation character varying(30) NOT NULL,
+    volumes text,
+    creator_id integer,
+    deployment_id integer NOT NULL,
+    flavor_id integer NOT NULL,
+    image_id integer NOT NULL,
+    node_id integer NOT NULL,
+    parent_id integer,
+    slice_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_instance OWNER TO postgres;
+
+--
+-- Name: core_instance_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_instance_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_instance_id_seq OWNER TO postgres;
+
+--
+-- Name: core_instance_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_instance_id_seq OWNED BY core_instance.id;
+
+
+--
+-- Name: core_invoice; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_invoice (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    date timestamp with time zone NOT NULL,
+    account_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_invoice OWNER TO postgres;
+
+--
+-- Name: core_invoice_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_invoice_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_invoice_id_seq OWNER TO postgres;
+
+--
+-- Name: core_invoice_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_invoice_id_seq OWNED BY core_invoice.id;
+
+
+--
+-- Name: core_network; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_network (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(32) NOT NULL,
+    subnet character varying(32) NOT NULL,
+    ports character varying(1024),
+    labels character varying(1024),
+    guaranteed_bandwidth integer NOT NULL,
+    permit_all_slices boolean NOT NULL,
+    topology_parameters text,
+    controller_url character varying(1024),
+    controller_parameters text,
+    network_id character varying(256),
+    router_id character varying(256),
+    subnet_id character varying(256),
+    autoconnect boolean NOT NULL,
+    owner_id integer NOT NULL,
+    template_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_network OWNER TO postgres;
+
+--
+-- Name: core_network_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_network_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_network_id_seq OWNER TO postgres;
+
+--
+-- Name: core_network_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_network_id_seq OWNED BY core_network.id;
+
+
+--
+-- Name: core_network_permitted_slices; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_network_permitted_slices (
+    id integer NOT NULL,
+    network_id integer NOT NULL,
+    slice_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_network_permitted_slices OWNER TO postgres;
+
+--
+-- Name: core_network_permitted_slices_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_network_permitted_slices_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_network_permitted_slices_id_seq OWNER TO postgres;
+
+--
+-- Name: core_network_permitted_slices_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_network_permitted_slices_id_seq OWNED BY core_network_permitted_slices.id;
+
+
+--
+-- Name: core_networkparameter; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_networkparameter (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    value character varying(1024) NOT NULL,
+    object_id integer NOT NULL,
+    content_type_id integer NOT NULL,
+    parameter_id integer NOT NULL,
+    CONSTRAINT core_networkparameter_object_id_check CHECK ((object_id >= 0))
+);
+
+
+ALTER TABLE public.core_networkparameter OWNER TO postgres;
+
+--
+-- Name: core_networkparameter_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_networkparameter_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_networkparameter_id_seq OWNER TO postgres;
+
+--
+-- Name: core_networkparameter_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_networkparameter_id_seq OWNED BY core_networkparameter.id;
+
+
+--
+-- Name: core_networkparametertype; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_networkparametertype (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(128) NOT NULL,
+    description character varying(1024) NOT NULL
+);
+
+
+ALTER TABLE public.core_networkparametertype OWNER TO postgres;
+
+--
+-- Name: core_networkparametertype_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_networkparametertype_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_networkparametertype_id_seq OWNER TO postgres;
+
+--
+-- Name: core_networkparametertype_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_networkparametertype_id_seq OWNED BY core_networkparametertype.id;
+
+
+--
+-- Name: core_networkslice; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_networkslice (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    network_id integer NOT NULL,
+    slice_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_networkslice OWNER TO postgres;
+
+--
+-- Name: core_networkslice_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_networkslice_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_networkslice_id_seq OWNER TO postgres;
+
+--
+-- Name: core_networkslice_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_networkslice_id_seq OWNED BY core_networkslice.id;
+
+
+--
+-- Name: core_networktemplate; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_networktemplate (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(32) NOT NULL,
+    description character varying(1024),
+    guaranteed_bandwidth integer NOT NULL,
+    visibility character varying(30) NOT NULL,
+    translation character varying(30) NOT NULL,
+    access character varying(30),
+    shared_network_name character varying(30),
+    shared_network_id character varying(256),
+    topology_kind character varying(30) NOT NULL,
+    controller_kind character varying(30)
+);
+
+
+ALTER TABLE public.core_networktemplate OWNER TO postgres;
+
+--
+-- Name: core_networktemplate_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_networktemplate_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_networktemplate_id_seq OWNER TO postgres;
+
+--
+-- Name: core_networktemplate_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_networktemplate_id_seq OWNED BY core_networktemplate.id;
+
+
+--
+-- Name: core_node; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_node (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(200) NOT NULL,
+    site_id integer,
+    site_deployment_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_node OWNER TO postgres;
+
+--
+-- Name: core_node_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_node_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_node_id_seq OWNER TO postgres;
+
+--
+-- Name: core_node_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_node_id_seq OWNED BY core_node.id;
+
+
+--
+-- Name: core_nodelabel; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_nodelabel (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(200) NOT NULL
+);
+
+
+ALTER TABLE public.core_nodelabel OWNER TO postgres;
+
+--
+-- Name: core_nodelabel_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_nodelabel_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_nodelabel_id_seq OWNER TO postgres;
+
+--
+-- Name: core_nodelabel_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_nodelabel_id_seq OWNED BY core_nodelabel.id;
+
+
+--
+-- Name: core_nodelabel_node; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_nodelabel_node (
+    id integer NOT NULL,
+    nodelabel_id integer NOT NULL,
+    node_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_nodelabel_node OWNER TO postgres;
+
+--
+-- Name: core_nodelabel_node_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_nodelabel_node_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_nodelabel_node_id_seq OWNER TO postgres;
+
+--
+-- Name: core_nodelabel_node_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_nodelabel_node_id_seq OWNED BY core_nodelabel_node.id;
+
+
+--
+-- Name: core_payment; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_payment (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    amount double precision NOT NULL,
+    date timestamp with time zone NOT NULL,
+    account_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_payment OWNER TO postgres;
+
+--
+-- Name: core_payment_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_payment_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_payment_id_seq OWNER TO postgres;
+
+--
+-- Name: core_payment_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_payment_id_seq OWNED BY core_payment.id;
+
+
+--
+-- Name: core_port; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_port (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    ip inet,
+    port_id character varying(256),
+    mac character varying(256),
+    xos_created boolean NOT NULL,
+    instance_id integer,
+    network_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_port OWNER TO postgres;
+
+--
+-- Name: core_port_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_port_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_port_id_seq OWNER TO postgres;
+
+--
+-- Name: core_port_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_port_id_seq OWNED BY core_port.id;
+
+
+--
+-- Name: core_program; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_program (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(30) NOT NULL,
+    description text,
+    kind character varying(30) NOT NULL,
+    command character varying(30),
+    contents text,
+    output text,
+    messages text,
+    status text,
+    owner_id integer
+);
+
+
+ALTER TABLE public.core_program OWNER TO postgres;
+
+--
+-- Name: core_program_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_program_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_program_id_seq OWNER TO postgres;
+
+--
+-- Name: core_program_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_program_id_seq OWNED BY core_program.id;
+
+
+--
+-- Name: core_project; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_project (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(200) NOT NULL
+);
+
+
+ALTER TABLE public.core_project OWNER TO postgres;
+
+--
+-- Name: core_project_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_project_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_project_id_seq OWNER TO postgres;
+
+--
+-- Name: core_project_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_project_id_seq OWNED BY core_project.id;
+
+
+--
+-- Name: core_reservation; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_reservation (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    "startTime" timestamp with time zone NOT NULL,
+    duration integer NOT NULL,
+    slice_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_reservation OWNER TO postgres;
+
+--
+-- Name: core_reservation_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_reservation_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_reservation_id_seq OWNER TO postgres;
+
+--
+-- Name: core_reservation_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_reservation_id_seq OWNED BY core_reservation.id;
+
+
+--
+-- Name: core_reservedresource; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_reservedresource (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    quantity integer NOT NULL,
+    instance_id integer NOT NULL,
+    "reservationSet_id" integer NOT NULL,
+    resource_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_reservedresource OWNER TO postgres;
+
+--
+-- Name: core_reservedresource_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_reservedresource_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_reservedresource_id_seq OWNER TO postgres;
+
+--
+-- Name: core_reservedresource_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_reservedresource_id_seq OWNED BY core_reservedresource.id;
+
+
+--
+-- Name: core_role; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_role (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    role_type character varying(80) NOT NULL,
+    role character varying(80),
+    description character varying(120) NOT NULL,
+    content_type_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_role OWNER TO postgres;
+
+--
+-- Name: core_role_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_role_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_role_id_seq OWNER TO postgres;
+
+--
+-- Name: core_role_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_role_id_seq OWNED BY core_role.id;
+
+
+--
+-- Name: core_router; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_router (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(32) NOT NULL,
+    owner_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_router OWNER TO postgres;
+
+--
+-- Name: core_router_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_router_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_router_id_seq OWNER TO postgres;
+
+--
+-- Name: core_router_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_router_id_seq OWNED BY core_router.id;
+
+
+--
+-- Name: core_router_networks; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_router_networks (
+    id integer NOT NULL,
+    router_id integer NOT NULL,
+    network_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_router_networks OWNER TO postgres;
+
+--
+-- Name: core_router_networks_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_router_networks_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_router_networks_id_seq OWNER TO postgres;
+
+--
+-- Name: core_router_networks_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_router_networks_id_seq OWNED BY core_router_networks.id;
+
+
+--
+-- Name: core_router_permittedNetworks; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE "core_router_permittedNetworks" (
+    id integer NOT NULL,
+    router_id integer NOT NULL,
+    network_id integer NOT NULL
+);
+
+
+ALTER TABLE public."core_router_permittedNetworks" OWNER TO postgres;
+
+--
+-- Name: core_router_permittedNetworks_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE "core_router_permittedNetworks_id_seq"
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public."core_router_permittedNetworks_id_seq" OWNER TO postgres;
+
+--
+-- Name: core_router_permittedNetworks_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE "core_router_permittedNetworks_id_seq" OWNED BY "core_router_permittedNetworks".id;
+
+
+--
+-- Name: core_service; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_service (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    description text,
+    enabled boolean NOT NULL,
+    kind character varying(30) NOT NULL,
+    name character varying(30) NOT NULL,
+    "versionNumber" character varying(30) NOT NULL,
+    published boolean NOT NULL,
+    view_url character varying(1024),
+    icon_url character varying(1024),
+    public_key text,
+    private_key_fn character varying(1024),
+    service_specific_id character varying(30),
+    service_specific_attribute text
+);
+
+
+ALTER TABLE public.core_service OWNER TO postgres;
+
+--
+-- Name: core_service_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_service_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_service_id_seq OWNER TO postgres;
+
+--
+-- Name: core_service_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_service_id_seq OWNED BY core_service.id;
+
+
+--
+-- Name: core_serviceattribute; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_serviceattribute (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(128) NOT NULL,
+    value character varying(1024) NOT NULL,
+    service_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_serviceattribute OWNER TO postgres;
+
+--
+-- Name: core_serviceattribute_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_serviceattribute_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_serviceattribute_id_seq OWNER TO postgres;
+
+--
+-- Name: core_serviceattribute_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_serviceattribute_id_seq OWNED BY core_serviceattribute.id;
+
+
+--
+-- Name: core_serviceclass; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_serviceclass (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(32) NOT NULL,
+    description character varying(255) NOT NULL,
+    commitment integer NOT NULL,
+    "membershipFee" integer NOT NULL,
+    "membershipFeeMonths" integer NOT NULL,
+    "upgradeRequiresApproval" boolean NOT NULL
+);
+
+
+ALTER TABLE public.core_serviceclass OWNER TO postgres;
+
+--
+-- Name: core_serviceclass_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_serviceclass_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_serviceclass_id_seq OWNER TO postgres;
+
+--
+-- Name: core_serviceclass_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_serviceclass_id_seq OWNED BY core_serviceclass.id;
+
+
+--
+-- Name: core_serviceclass_upgradeFrom; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE "core_serviceclass_upgradeFrom" (
+    id integer NOT NULL,
+    from_serviceclass_id integer NOT NULL,
+    to_serviceclass_id integer NOT NULL
+);
+
+
+ALTER TABLE public."core_serviceclass_upgradeFrom" OWNER TO postgres;
+
+--
+-- Name: core_serviceclass_upgradeFrom_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE "core_serviceclass_upgradeFrom_id_seq"
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public."core_serviceclass_upgradeFrom_id_seq" OWNER TO postgres;
+
+--
+-- Name: core_serviceclass_upgradeFrom_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE "core_serviceclass_upgradeFrom_id_seq" OWNED BY "core_serviceclass_upgradeFrom".id;
+
+
+--
+-- Name: core_serviceprivilege; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_serviceprivilege (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    role_id integer NOT NULL,
+    service_id integer NOT NULL,
+    user_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_serviceprivilege OWNER TO postgres;
+
+--
+-- Name: core_serviceprivilege_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_serviceprivilege_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_serviceprivilege_id_seq OWNER TO postgres;
+
+--
+-- Name: core_serviceprivilege_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_serviceprivilege_id_seq OWNED BY core_serviceprivilege.id;
+
+
+--
+-- Name: core_serviceresource; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_serviceresource (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(32) NOT NULL,
+    "maxUnitsDeployment" integer NOT NULL,
+    "maxUnitsNode" integer NOT NULL,
+    "maxDuration" integer NOT NULL,
+    "bucketInRate" integer NOT NULL,
+    "bucketMaxSize" integer NOT NULL,
+    cost integer NOT NULL,
+    "calendarReservable" boolean NOT NULL,
+    "serviceClass_id" integer NOT NULL
+);
+
+
+ALTER TABLE public.core_serviceresource OWNER TO postgres;
+
+--
+-- Name: core_serviceresource_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_serviceresource_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_serviceresource_id_seq OWNER TO postgres;
+
+--
+-- Name: core_serviceresource_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_serviceresource_id_seq OWNED BY core_serviceresource.id;
+
+
+--
+-- Name: core_servicerole; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_servicerole (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    role character varying(30) NOT NULL
+);
+
+
+ALTER TABLE public.core_servicerole OWNER TO postgres;
+
+--
+-- Name: core_servicerole_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_servicerole_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_servicerole_id_seq OWNER TO postgres;
+
+--
+-- Name: core_servicerole_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_servicerole_id_seq OWNED BY core_servicerole.id;
+
+
+--
+-- Name: core_site; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_site (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(200) NOT NULL,
+    site_url character varying(512),
+    enabled boolean NOT NULL,
+    hosts_nodes boolean NOT NULL,
+    hosts_users boolean NOT NULL,
+    location character varying(42) NOT NULL,
+    longitude double precision,
+    latitude double precision,
+    login_base character varying(50) NOT NULL,
+    is_public boolean NOT NULL,
+    abbreviated_name character varying(80) NOT NULL
+);
+
+
+ALTER TABLE public.core_site OWNER TO postgres;
+
+--
+-- Name: core_site_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_site_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_site_id_seq OWNER TO postgres;
+
+--
+-- Name: core_site_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_site_id_seq OWNED BY core_site.id;
+
+
+--
+-- Name: core_sitecredential; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_sitecredential (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(128) NOT NULL,
+    key_id character varying(1024) NOT NULL,
+    enc_value text NOT NULL,
+    site_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_sitecredential OWNER TO postgres;
+
+--
+-- Name: core_sitecredential_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_sitecredential_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_sitecredential_id_seq OWNER TO postgres;
+
+--
+-- Name: core_sitecredential_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_sitecredential_id_seq OWNED BY core_sitecredential.id;
+
+
+--
+-- Name: core_sitedeployment; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_sitedeployment (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    availability_zone character varying(200),
+    controller_id integer,
+    deployment_id integer NOT NULL,
+    site_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_sitedeployment OWNER TO postgres;
+
+--
+-- Name: core_sitedeployment_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_sitedeployment_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_sitedeployment_id_seq OWNER TO postgres;
+
+--
+-- Name: core_sitedeployment_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_sitedeployment_id_seq OWNED BY core_sitedeployment.id;
+
+
+--
+-- Name: core_siteprivilege; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_siteprivilege (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    role_id integer NOT NULL,
+    site_id integer NOT NULL,
+    user_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_siteprivilege OWNER TO postgres;
+
+--
+-- Name: core_siteprivilege_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_siteprivilege_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_siteprivilege_id_seq OWNER TO postgres;
+
+--
+-- Name: core_siteprivilege_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_siteprivilege_id_seq OWNED BY core_siteprivilege.id;
+
+
+--
+-- Name: core_siterole; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_siterole (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    role character varying(30) NOT NULL
+);
+
+
+ALTER TABLE public.core_siterole OWNER TO postgres;
+
+--
+-- Name: core_siterole_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_siterole_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_siterole_id_seq OWNER TO postgres;
+
+--
+-- Name: core_siterole_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_siterole_id_seq OWNED BY core_siterole.id;
+
+
+--
+-- Name: core_slice; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_slice (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(80) NOT NULL,
+    enabled boolean NOT NULL,
+    omf_friendly boolean NOT NULL,
+    description text NOT NULL,
+    slice_url character varying(512) NOT NULL,
+    max_instances integer NOT NULL,
+    network character varying(256),
+    exposed_ports character varying(256),
+    mount_data_sets character varying(256),
+    default_isolation character varying(30) NOT NULL,
+    creator_id integer,
+    default_flavor_id integer,
+    default_image_id integer,
+    service_id integer,
+    "serviceClass_id" integer,
+    site_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_slice OWNER TO postgres;
+
+--
+-- Name: core_slice_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_slice_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_slice_id_seq OWNER TO postgres;
+
+--
+-- Name: core_slice_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_slice_id_seq OWNED BY core_slice.id;
+
+
+--
+-- Name: core_slicecredential; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_slicecredential (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(128) NOT NULL,
+    key_id character varying(1024) NOT NULL,
+    enc_value text NOT NULL,
+    slice_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_slicecredential OWNER TO postgres;
+
+--
+-- Name: core_slicecredential_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_slicecredential_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_slicecredential_id_seq OWNER TO postgres;
+
+--
+-- Name: core_slicecredential_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_slicecredential_id_seq OWNED BY core_slicecredential.id;
+
+
+--
+-- Name: core_sliceprivilege; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_sliceprivilege (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    role_id integer NOT NULL,
+    slice_id integer NOT NULL,
+    user_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_sliceprivilege OWNER TO postgres;
+
+--
+-- Name: core_sliceprivilege_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_sliceprivilege_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_sliceprivilege_id_seq OWNER TO postgres;
+
+--
+-- Name: core_sliceprivilege_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_sliceprivilege_id_seq OWNED BY core_sliceprivilege.id;
+
+
+--
+-- Name: core_slicerole; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_slicerole (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    role character varying(30) NOT NULL
+);
+
+
+ALTER TABLE public.core_slicerole OWNER TO postgres;
+
+--
+-- Name: core_slicerole_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_slicerole_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_slicerole_id_seq OWNER TO postgres;
+
+--
+-- Name: core_slicerole_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_slicerole_id_seq OWNED BY core_slicerole.id;
+
+
+--
+-- Name: core_slicetag; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_slicetag (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(30) NOT NULL,
+    value character varying(1024) NOT NULL,
+    slice_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_slicetag OWNER TO postgres;
+
+--
+-- Name: core_slicetag_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_slicetag_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_slicetag_id_seq OWNER TO postgres;
+
+--
+-- Name: core_slicetag_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_slicetag_id_seq OWNED BY core_slicetag.id;
+
+
+--
+-- Name: core_tag; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_tag (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(128) NOT NULL,
+    value character varying(1024) NOT NULL,
+    object_id integer NOT NULL,
+    content_type_id integer NOT NULL,
+    service_id integer NOT NULL,
+    CONSTRAINT core_tag_object_id_check CHECK ((object_id >= 0))
+);
+
+
+ALTER TABLE public.core_tag OWNER TO postgres;
+
+--
+-- Name: core_tag_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_tag_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_tag_id_seq OWNER TO postgres;
+
+--
+-- Name: core_tag_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_tag_id_seq OWNED BY core_tag.id;
+
+
+--
+-- Name: core_tenant; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_tenant (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    kind character varying(30) NOT NULL,
+    service_specific_id character varying(30),
+    service_specific_attribute text,
+    connect_method character varying(30) NOT NULL,
+    provider_service_id integer NOT NULL,
+    subscriber_root_id integer,
+    subscriber_service_id integer,
+    subscriber_tenant_id integer,
+    subscriber_user_id integer
+);
+
+
+ALTER TABLE public.core_tenant OWNER TO postgres;
+
+--
+-- Name: core_tenant_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_tenant_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_tenant_id_seq OWNER TO postgres;
+
+--
+-- Name: core_tenant_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_tenant_id_seq OWNED BY core_tenant.id;
+
+
+--
+-- Name: core_tenantattribute; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_tenantattribute (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(128) NOT NULL,
+    value text NOT NULL,
+    tenant_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_tenantattribute OWNER TO postgres;
+
+--
+-- Name: core_tenantattribute_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_tenantattribute_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_tenantattribute_id_seq OWNER TO postgres;
+
+--
+-- Name: core_tenantattribute_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_tenantattribute_id_seq OWNED BY core_tenantattribute.id;
+
+
+--
+-- Name: core_tenantroot; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_tenantroot (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    kind character varying(30) NOT NULL,
+    name character varying(255),
+    service_specific_attribute text,
+    service_specific_id character varying(30)
+);
+
+
+ALTER TABLE public.core_tenantroot OWNER TO postgres;
+
+--
+-- Name: core_tenantroot_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_tenantroot_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_tenantroot_id_seq OWNER TO postgres;
+
+--
+-- Name: core_tenantroot_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_tenantroot_id_seq OWNED BY core_tenantroot.id;
+
+
+--
+-- Name: core_tenantrootprivilege; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_tenantrootprivilege (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    role_id integer NOT NULL,
+    tenant_root_id integer NOT NULL,
+    user_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_tenantrootprivilege OWNER TO postgres;
+
+--
+-- Name: core_tenantrootprivilege_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_tenantrootprivilege_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_tenantrootprivilege_id_seq OWNER TO postgres;
+
+--
+-- Name: core_tenantrootprivilege_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_tenantrootprivilege_id_seq OWNED BY core_tenantrootprivilege.id;
+
+
+--
+-- Name: core_tenantrootrole; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_tenantrootrole (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    role character varying(30) NOT NULL
+);
+
+
+ALTER TABLE public.core_tenantrootrole OWNER TO postgres;
+
+--
+-- Name: core_tenantrootrole_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_tenantrootrole_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_tenantrootrole_id_seq OWNER TO postgres;
+
+--
+-- Name: core_tenantrootrole_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_tenantrootrole_id_seq OWNED BY core_tenantrootrole.id;
+
+
+--
+-- Name: core_usableobject; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_usableobject (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(1024) NOT NULL
+);
+
+
+ALTER TABLE public.core_usableobject OWNER TO postgres;
+
+--
+-- Name: core_usableobject_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_usableobject_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_usableobject_id_seq OWNER TO postgres;
+
+--
+-- Name: core_usableobject_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_usableobject_id_seq OWNED BY core_usableobject.id;
+
+
+--
+-- Name: core_user; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_user (
+    id integer NOT NULL,
+    password character varying(128) NOT NULL,
+    last_login timestamp with time zone NOT NULL,
+    email character varying(255) NOT NULL,
+    username character varying(255) NOT NULL,
+    firstname character varying(200) NOT NULL,
+    lastname character varying(200) NOT NULL,
+    phone character varying(100),
+    user_url character varying(200),
+    public_key text,
+    is_active boolean NOT NULL,
+    is_admin boolean NOT NULL,
+    is_staff boolean NOT NULL,
+    is_readonly boolean NOT NULL,
+    is_registering boolean NOT NULL,
+    is_appuser boolean NOT NULL,
+    login_page character varying(200),
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    timezone character varying(100) NOT NULL,
+    site_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_user OWNER TO postgres;
+
+--
+-- Name: core_user_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_user_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_user_id_seq OWNER TO postgres;
+
+--
+-- Name: core_user_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_user_id_seq OWNED BY core_user.id;
+
+
+--
+-- Name: core_usercredential; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_usercredential (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(128) NOT NULL,
+    key_id character varying(1024) NOT NULL,
+    enc_value text NOT NULL,
+    user_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_usercredential OWNER TO postgres;
+
+--
+-- Name: core_usercredential_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_usercredential_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_usercredential_id_seq OWNER TO postgres;
+
+--
+-- Name: core_usercredential_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_usercredential_id_seq OWNED BY core_usercredential.id;
+
+
+--
+-- Name: core_userdashboardview; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_userdashboardview (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    "order" integer NOT NULL,
+    "dashboardView_id" integer NOT NULL,
+    user_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_userdashboardview OWNER TO postgres;
+
+--
+-- Name: core_userdashboardview_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_userdashboardview_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_userdashboardview_id_seq OWNER TO postgres;
+
+--
+-- Name: core_userdashboardview_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_userdashboardview_id_seq OWNED BY core_userdashboardview.id;
+
+
+--
+-- Name: django_admin_log; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE django_admin_log (
+    id integer NOT NULL,
+    action_time timestamp with time zone NOT NULL,
+    object_id text,
+    object_repr character varying(200) NOT NULL,
+    action_flag smallint NOT NULL,
+    change_message text NOT NULL,
+    content_type_id integer,
+    user_id integer NOT NULL,
+    CONSTRAINT django_admin_log_action_flag_check CHECK ((action_flag >= 0))
+);
+
+
+ALTER TABLE public.django_admin_log OWNER TO postgres;
+
+--
+-- Name: django_admin_log_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE django_admin_log_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.django_admin_log_id_seq OWNER TO postgres;
+
+--
+-- Name: django_admin_log_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE django_admin_log_id_seq OWNED BY django_admin_log.id;
+
+
+--
+-- Name: django_content_type; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE django_content_type (
+    id integer NOT NULL,
+    name character varying(100) NOT NULL,
+    app_label character varying(100) NOT NULL,
+    model character varying(100) NOT NULL
+);
+
+
+ALTER TABLE public.django_content_type OWNER TO postgres;
+
+--
+-- Name: django_content_type_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE django_content_type_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.django_content_type_id_seq OWNER TO postgres;
+
+--
+-- Name: django_content_type_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE django_content_type_id_seq OWNED BY django_content_type.id;
+
+
+--
+-- Name: django_migrations; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE django_migrations (
+    id integer NOT NULL,
+    app character varying(255) NOT NULL,
+    name character varying(255) NOT NULL,
+    applied timestamp with time zone NOT NULL
+);
+
+
+ALTER TABLE public.django_migrations OWNER TO postgres;
+
+--
+-- Name: django_migrations_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE django_migrations_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.django_migrations_id_seq OWNER TO postgres;
+
+--
+-- Name: django_migrations_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE django_migrations_id_seq OWNED BY django_migrations.id;
+
+
+--
+-- Name: django_session; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE django_session (
+    session_key character varying(40) NOT NULL,
+    session_data text NOT NULL,
+    expire_date timestamp with time zone NOT NULL
+);
+
+
+ALTER TABLE public.django_session OWNER TO postgres;
+
+--
+-- Name: hpc_accessmap; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE hpc_accessmap (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(64) NOT NULL,
+    description text,
+    map character varying(100) NOT NULL,
+    "contentProvider_id" integer NOT NULL
+);
+
+
+ALTER TABLE public.hpc_accessmap OWNER TO postgres;
+
+--
+-- Name: hpc_accessmap_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE hpc_accessmap_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.hpc_accessmap_id_seq OWNER TO postgres;
+
+--
+-- Name: hpc_accessmap_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE hpc_accessmap_id_seq OWNED BY hpc_accessmap.id;
+
+
+--
+-- Name: hpc_cdnprefix; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE hpc_cdnprefix (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    cdn_prefix_id integer,
+    prefix character varying(200) NOT NULL,
+    description text,
+    enabled boolean NOT NULL,
+    "contentProvider_id" integer NOT NULL,
+    "defaultOriginServer_id" integer
+);
+
+
+ALTER TABLE public.hpc_cdnprefix OWNER TO postgres;
+
+--
+-- Name: hpc_cdnprefix_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE hpc_cdnprefix_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.hpc_cdnprefix_id_seq OWNER TO postgres;
+
+--
+-- Name: hpc_cdnprefix_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE hpc_cdnprefix_id_seq OWNED BY hpc_cdnprefix.id;
+
+
+--
+-- Name: hpc_contentprovider; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE hpc_contentprovider (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    content_provider_id integer,
+    name character varying(254) NOT NULL,
+    enabled boolean NOT NULL,
+    description text,
+    "serviceProvider_id" integer NOT NULL
+);
+
+
+ALTER TABLE public.hpc_contentprovider OWNER TO postgres;
+
+--
+-- Name: hpc_contentprovider_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE hpc_contentprovider_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.hpc_contentprovider_id_seq OWNER TO postgres;
+
+--
+-- Name: hpc_contentprovider_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE hpc_contentprovider_id_seq OWNED BY hpc_contentprovider.id;
+
+
+--
+-- Name: hpc_contentprovider_users; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE hpc_contentprovider_users (
+    id integer NOT NULL,
+    contentprovider_id integer NOT NULL,
+    user_id integer NOT NULL
+);
+
+
+ALTER TABLE public.hpc_contentprovider_users OWNER TO postgres;
+
+--
+-- Name: hpc_contentprovider_users_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE hpc_contentprovider_users_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.hpc_contentprovider_users_id_seq OWNER TO postgres;
+
+--
+-- Name: hpc_contentprovider_users_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE hpc_contentprovider_users_id_seq OWNED BY hpc_contentprovider_users.id;
+
+
+--
+-- Name: hpc_hpchealthcheck; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE hpc_hpchealthcheck (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    kind character varying(30) NOT NULL,
+    resource_name character varying(1024) NOT NULL,
+    result_contains character varying(1024),
+    result_min_size integer,
+    result_max_size integer,
+    "hpcService_id" integer
+);
+
+
+ALTER TABLE public.hpc_hpchealthcheck OWNER TO postgres;
+
+--
+-- Name: hpc_hpchealthcheck_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE hpc_hpchealthcheck_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.hpc_hpchealthcheck_id_seq OWNER TO postgres;
+
+--
+-- Name: hpc_hpchealthcheck_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE hpc_hpchealthcheck_id_seq OWNED BY hpc_hpchealthcheck.id;
+
+
+--
+-- Name: hpc_hpcservice; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE hpc_hpcservice (
+    service_ptr_id integer NOT NULL,
+    cmi_hostname character varying(254),
+    hpc_port80 boolean NOT NULL,
+    watcher_hpc_network character varying(254),
+    watcher_dnsdemux_network character varying(254),
+    watcher_dnsredir_network character varying(254)
+);
+
+
+ALTER TABLE public.hpc_hpcservice OWNER TO postgres;
+
+--
+-- Name: hpc_originserver; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE hpc_originserver (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    origin_server_id integer,
+    url character varying(1024) NOT NULL,
+    authenticated boolean NOT NULL,
+    enabled boolean NOT NULL,
+    protocol character varying(12) NOT NULL,
+    redirects boolean NOT NULL,
+    description text,
+    "contentProvider_id" integer NOT NULL
+);
+
+
+ALTER TABLE public.hpc_originserver OWNER TO postgres;
+
+--
+-- Name: hpc_originserver_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE hpc_originserver_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.hpc_originserver_id_seq OWNER TO postgres;
+
+--
+-- Name: hpc_originserver_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE hpc_originserver_id_seq OWNED BY hpc_originserver.id;
+
+
+--
+-- Name: hpc_serviceprovider; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE hpc_serviceprovider (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    service_provider_id integer,
+    name character varying(254) NOT NULL,
+    description text,
+    enabled boolean NOT NULL,
+    "hpcService_id" integer NOT NULL
+);
+
+
+ALTER TABLE public.hpc_serviceprovider OWNER TO postgres;
+
+--
+-- Name: hpc_serviceprovider_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE hpc_serviceprovider_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.hpc_serviceprovider_id_seq OWNER TO postgres;
+
+--
+-- Name: hpc_serviceprovider_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE hpc_serviceprovider_id_seq OWNED BY hpc_serviceprovider.id;
+
+
+--
+-- Name: hpc_sitemap; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE hpc_sitemap (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(64) NOT NULL,
+    description text,
+    map character varying(100) NOT NULL,
+    map_id integer,
+    "cdnPrefix_id" integer,
+    "contentProvider_id" integer,
+    "hpcService_id" integer,
+    "serviceProvider_id" integer
+);
+
+
+ALTER TABLE public.hpc_sitemap OWNER TO postgres;
+
+--
+-- Name: hpc_sitemap_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE hpc_sitemap_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.hpc_sitemap_id_seq OWNER TO postgres;
+
+--
+-- Name: hpc_sitemap_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE hpc_sitemap_id_seq OWNED BY hpc_sitemap.id;
+
+
+--
+-- Name: requestrouter_requestrouterservice; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE requestrouter_requestrouterservice (
+    service_ptr_id integer NOT NULL,
+    "behindNat" boolean NOT NULL,
+    "defaultTTL" integer NOT NULL,
+    "defaultAction" character varying(30) NOT NULL,
+    "lastResortAction" character varying(30) NOT NULL,
+    "maxAnswers" integer NOT NULL,
+    CONSTRAINT "requestrouter_requestrouterservice_defaultTTL_check" CHECK (("defaultTTL" >= 0)),
+    CONSTRAINT "requestrouter_requestrouterservice_maxAnswers_check" CHECK (("maxAnswers" >= 0))
+);
+
+
+ALTER TABLE public.requestrouter_requestrouterservice OWNER TO postgres;
+
+--
+-- Name: requestrouter_servicemap; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE requestrouter_servicemap (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(50) NOT NULL,
+    prefix character varying(256) NOT NULL,
+    "siteMap" character varying(100) NOT NULL,
+    "accessMap" character varying(100) NOT NULL,
+    owner_id integer NOT NULL,
+    slice_id integer NOT NULL
+);
+
+
+ALTER TABLE public.requestrouter_servicemap OWNER TO postgres;
+
+--
+-- Name: requestrouter_servicemap_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE requestrouter_servicemap_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.requestrouter_servicemap_id_seq OWNER TO postgres;
+
+--
+-- Name: requestrouter_servicemap_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE requestrouter_servicemap_id_seq OWNED BY requestrouter_servicemap.id;
+
+
+--
+-- Name: syndicate_storage_slicesecret; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE syndicate_storage_slicesecret (
+    id integer NOT NULL,
+    secret text NOT NULL,
+    slice_id_id integer NOT NULL
+);
+
+
+ALTER TABLE public.syndicate_storage_slicesecret OWNER TO postgres;
+
+--
+-- Name: syndicate_storage_slicesecret_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE syndicate_storage_slicesecret_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.syndicate_storage_slicesecret_id_seq OWNER TO postgres;
+
+--
+-- Name: syndicate_storage_slicesecret_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE syndicate_storage_slicesecret_id_seq OWNED BY syndicate_storage_slicesecret.id;
+
+
+--
+-- Name: syndicate_storage_syndicateprincipal; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE syndicate_storage_syndicateprincipal (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    principal_id text NOT NULL,
+    public_key_pem text NOT NULL,
+    sealed_private_key text NOT NULL
+);
+
+
+ALTER TABLE public.syndicate_storage_syndicateprincipal OWNER TO postgres;
+
+--
+-- Name: syndicate_storage_syndicateprincipal_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE syndicate_storage_syndicateprincipal_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.syndicate_storage_syndicateprincipal_id_seq OWNER TO postgres;
+
+--
+-- Name: syndicate_storage_syndicateprincipal_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE syndicate_storage_syndicateprincipal_id_seq OWNED BY syndicate_storage_syndicateprincipal.id;
+
+
+--
+-- Name: syndicate_storage_syndicateservice; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE syndicate_storage_syndicateservice (
+    service_ptr_id integer NOT NULL
+);
+
+
+ALTER TABLE public.syndicate_storage_syndicateservice OWNER TO postgres;
+
+--
+-- Name: syndicate_storage_volume; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE syndicate_storage_volume (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(64) NOT NULL,
+    description text,
+    blocksize integer NOT NULL,
+    private boolean NOT NULL,
+    archive boolean NOT NULL,
+    cap_read_data boolean NOT NULL,
+    cap_write_data boolean NOT NULL,
+    cap_host_data boolean NOT NULL,
+    owner_id_id integer NOT NULL,
+    CONSTRAINT syndicate_storage_volume_blocksize_check CHECK ((blocksize >= 0))
+);
+
+
+ALTER TABLE public.syndicate_storage_volume OWNER TO postgres;
+
+--
+-- Name: syndicate_storage_volume_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE syndicate_storage_volume_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.syndicate_storage_volume_id_seq OWNER TO postgres;
+
+--
+-- Name: syndicate_storage_volume_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE syndicate_storage_volume_id_seq OWNED BY syndicate_storage_volume.id;
+
+
+--
+-- Name: syndicate_storage_volumeaccessright; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE syndicate_storage_volumeaccessright (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    cap_read_data boolean NOT NULL,
+    cap_write_data boolean NOT NULL,
+    cap_host_data boolean NOT NULL,
+    owner_id_id integer NOT NULL,
+    volume_id integer NOT NULL
+);
+
+
+ALTER TABLE public.syndicate_storage_volumeaccessright OWNER TO postgres;
+
+--
+-- Name: syndicate_storage_volumeaccessright_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE syndicate_storage_volumeaccessright_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.syndicate_storage_volumeaccessright_id_seq OWNER TO postgres;
+
+--
+-- Name: syndicate_storage_volumeaccessright_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE syndicate_storage_volumeaccessright_id_seq OWNED BY syndicate_storage_volumeaccessright.id;
+
+
+--
+-- Name: syndicate_storage_volumeslice; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE syndicate_storage_volumeslice (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    cap_read_data boolean NOT NULL,
+    cap_write_data boolean NOT NULL,
+    cap_host_data boolean NOT NULL,
+    "UG_portnum" integer NOT NULL,
+    "RG_portnum" integer NOT NULL,
+    credentials_blob text,
+    slice_id_id integer NOT NULL,
+    volume_id_id integer NOT NULL,
+    CONSTRAINT "syndicate_storage_volumeslice_RG_portnum_check" CHECK (("RG_portnum" >= 0)),
+    CONSTRAINT "syndicate_storage_volumeslice_UG_portnum_check" CHECK (("UG_portnum" >= 0))
+);
+
+
+ALTER TABLE public.syndicate_storage_volumeslice OWNER TO postgres;
+
+--
+-- Name: syndicate_storage_volumeslice_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE syndicate_storage_volumeslice_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.syndicate_storage_volumeslice_id_seq OWNER TO postgres;
+
+--
+-- Name: syndicate_storage_volumeslice_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE syndicate_storage_volumeslice_id_seq OWNED BY syndicate_storage_volumeslice.id;
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY auth_group ALTER COLUMN id SET DEFAULT nextval('auth_group_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY auth_group_permissions ALTER COLUMN id SET DEFAULT nextval('auth_group_permissions_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY auth_permission ALTER COLUMN id SET DEFAULT nextval('auth_permission_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_account ALTER COLUMN id SET DEFAULT nextval('core_account_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_addresspool ALTER COLUMN id SET DEFAULT nextval('core_addresspool_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_charge ALTER COLUMN id SET DEFAULT nextval('core_charge_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controller ALTER COLUMN id SET DEFAULT nextval('core_controller_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllercredential ALTER COLUMN id SET DEFAULT nextval('core_controllercredential_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllerdashboardview ALTER COLUMN id SET DEFAULT nextval('core_controllerdashboardview_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllerimages ALTER COLUMN id SET DEFAULT nextval('core_controllerimages_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllernetwork ALTER COLUMN id SET DEFAULT nextval('core_controllernetwork_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllerrole ALTER COLUMN id SET DEFAULT nextval('core_controllerrole_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllersite ALTER COLUMN id SET DEFAULT nextval('core_controllersite_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllersiteprivilege ALTER COLUMN id SET DEFAULT nextval('core_controllersiteprivilege_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllerslice ALTER COLUMN id SET DEFAULT nextval('core_controllerslice_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllersliceprivilege ALTER COLUMN id SET DEFAULT nextval('core_controllersliceprivilege_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controlleruser ALTER COLUMN id SET DEFAULT nextval('core_controlleruser_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_dashboardview ALTER COLUMN id SET DEFAULT nextval('core_dashboardview_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_dashboardview_deployments ALTER COLUMN id SET DEFAULT nextval('core_dashboardview_deployments_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_deployment ALTER COLUMN id SET DEFAULT nextval('core_deployment_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_deploymentprivilege ALTER COLUMN id SET DEFAULT nextval('core_deploymentprivilege_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_deploymentrole ALTER COLUMN id SET DEFAULT nextval('core_deploymentrole_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_diag ALTER COLUMN id SET DEFAULT nextval('core_diag_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_flavor ALTER COLUMN id SET DEFAULT nextval('core_flavor_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_flavor_deployments ALTER COLUMN id SET DEFAULT nextval('core_flavor_deployments_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_image ALTER COLUMN id SET DEFAULT nextval('core_image_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_imagedeployments ALTER COLUMN id SET DEFAULT nextval('core_imagedeployments_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_instance ALTER COLUMN id SET DEFAULT nextval('core_instance_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_invoice ALTER COLUMN id SET DEFAULT nextval('core_invoice_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_network ALTER COLUMN id SET DEFAULT nextval('core_network_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_network_permitted_slices ALTER COLUMN id SET DEFAULT nextval('core_network_permitted_slices_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_networkparameter ALTER COLUMN id SET DEFAULT nextval('core_networkparameter_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_networkparametertype ALTER COLUMN id SET DEFAULT nextval('core_networkparametertype_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_networkslice ALTER COLUMN id SET DEFAULT nextval('core_networkslice_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_networktemplate ALTER COLUMN id SET DEFAULT nextval('core_networktemplate_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_node ALTER COLUMN id SET DEFAULT nextval('core_node_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_nodelabel ALTER COLUMN id SET DEFAULT nextval('core_nodelabel_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_nodelabel_node ALTER COLUMN id SET DEFAULT nextval('core_nodelabel_node_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_payment ALTER COLUMN id SET DEFAULT nextval('core_payment_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_port ALTER COLUMN id SET DEFAULT nextval('core_port_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_program ALTER COLUMN id SET DEFAULT nextval('core_program_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_project ALTER COLUMN id SET DEFAULT nextval('core_project_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_reservation ALTER COLUMN id SET DEFAULT nextval('core_reservation_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_reservedresource ALTER COLUMN id SET DEFAULT nextval('core_reservedresource_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_role ALTER COLUMN id SET DEFAULT nextval('core_role_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_router ALTER COLUMN id SET DEFAULT nextval('core_router_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_router_networks ALTER COLUMN id SET DEFAULT nextval('core_router_networks_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY "core_router_permittedNetworks" ALTER COLUMN id SET DEFAULT nextval('"core_router_permittedNetworks_id_seq"'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_service ALTER COLUMN id SET DEFAULT nextval('core_service_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_serviceattribute ALTER COLUMN id SET DEFAULT nextval('core_serviceattribute_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_serviceclass ALTER COLUMN id SET DEFAULT nextval('core_serviceclass_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY "core_serviceclass_upgradeFrom" ALTER COLUMN id SET DEFAULT nextval('"core_serviceclass_upgradeFrom_id_seq"'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_serviceprivilege ALTER COLUMN id SET DEFAULT nextval('core_serviceprivilege_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_serviceresource ALTER COLUMN id SET DEFAULT nextval('core_serviceresource_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_servicerole ALTER COLUMN id SET DEFAULT nextval('core_servicerole_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_site ALTER COLUMN id SET DEFAULT nextval('core_site_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_sitecredential ALTER COLUMN id SET DEFAULT nextval('core_sitecredential_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_sitedeployment ALTER COLUMN id SET DEFAULT nextval('core_sitedeployment_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_siteprivilege ALTER COLUMN id SET DEFAULT nextval('core_siteprivilege_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_siterole ALTER COLUMN id SET DEFAULT nextval('core_siterole_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_slice ALTER COLUMN id SET DEFAULT nextval('core_slice_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_slicecredential ALTER COLUMN id SET DEFAULT nextval('core_slicecredential_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_sliceprivilege ALTER COLUMN id SET DEFAULT nextval('core_sliceprivilege_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_slicerole ALTER COLUMN id SET DEFAULT nextval('core_slicerole_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_slicetag ALTER COLUMN id SET DEFAULT nextval('core_slicetag_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_tag ALTER COLUMN id SET DEFAULT nextval('core_tag_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_tenant ALTER COLUMN id SET DEFAULT nextval('core_tenant_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_tenantattribute ALTER COLUMN id SET DEFAULT nextval('core_tenantattribute_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_tenantroot ALTER COLUMN id SET DEFAULT nextval('core_tenantroot_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_tenantrootprivilege ALTER COLUMN id SET DEFAULT nextval('core_tenantrootprivilege_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_tenantrootrole ALTER COLUMN id SET DEFAULT nextval('core_tenantrootrole_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_usableobject ALTER COLUMN id SET DEFAULT nextval('core_usableobject_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_user ALTER COLUMN id SET DEFAULT nextval('core_user_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_usercredential ALTER COLUMN id SET DEFAULT nextval('core_usercredential_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_userdashboardview ALTER COLUMN id SET DEFAULT nextval('core_userdashboardview_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY django_admin_log ALTER COLUMN id SET DEFAULT nextval('django_admin_log_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY django_content_type ALTER COLUMN id SET DEFAULT nextval('django_content_type_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY django_migrations ALTER COLUMN id SET DEFAULT nextval('django_migrations_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_accessmap ALTER COLUMN id SET DEFAULT nextval('hpc_accessmap_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_cdnprefix ALTER COLUMN id SET DEFAULT nextval('hpc_cdnprefix_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_contentprovider ALTER COLUMN id SET DEFAULT nextval('hpc_contentprovider_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_contentprovider_users ALTER COLUMN id SET DEFAULT nextval('hpc_contentprovider_users_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_hpchealthcheck ALTER COLUMN id SET DEFAULT nextval('hpc_hpchealthcheck_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_originserver ALTER COLUMN id SET DEFAULT nextval('hpc_originserver_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_serviceprovider ALTER COLUMN id SET DEFAULT nextval('hpc_serviceprovider_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_sitemap ALTER COLUMN id SET DEFAULT nextval('hpc_sitemap_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY requestrouter_servicemap ALTER COLUMN id SET DEFAULT nextval('requestrouter_servicemap_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY syndicate_storage_slicesecret ALTER COLUMN id SET DEFAULT nextval('syndicate_storage_slicesecret_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY syndicate_storage_syndicateprincipal ALTER COLUMN id SET DEFAULT nextval('syndicate_storage_syndicateprincipal_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY syndicate_storage_volume ALTER COLUMN id SET DEFAULT nextval('syndicate_storage_volume_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY syndicate_storage_volumeaccessright ALTER COLUMN id SET DEFAULT nextval('syndicate_storage_volumeaccessright_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY syndicate_storage_volumeslice ALTER COLUMN id SET DEFAULT nextval('syndicate_storage_volumeslice_id_seq'::regclass);
+
+
+--
+-- Data for Name: auth_group; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY auth_group (id, name) FROM stdin;
+\.
+
+
+--
+-- Name: auth_group_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('auth_group_id_seq', 1, false);
+
+
+--
+-- Data for Name: auth_group_permissions; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY auth_group_permissions (id, group_id, permission_id) FROM stdin;
+\.
+
+
+--
+-- Name: auth_group_permissions_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('auth_group_permissions_id_seq', 1, false);
+
+
+--
+-- Data for Name: auth_permission; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY auth_permission (id, name, content_type_id, codename) FROM stdin;
+1	Can add permission	1	add_permission
+2	Can change permission	1	change_permission
+3	Can delete permission	1	delete_permission
+4	Can add group	2	add_group
+5	Can change group	2	change_group
+6	Can delete group	2	delete_group
+7	Can add content type	3	add_contenttype
+8	Can change content type	3	change_contenttype
+9	Can delete content type	3	delete_contenttype
+10	Can add session	4	add_session
+11	Can change session	4	change_session
+12	Can delete session	4	delete_session
+13	Can add log entry	5	add_logentry
+14	Can change log entry	5	change_logentry
+15	Can delete log entry	5	delete_logentry
+16	Can add project	6	add_project
+17	Can change project	6	change_project
+18	Can delete project	6	delete_project
+19	Can add service	7	add_service
+20	Can change service	7	change_service
+21	Can delete service	7	delete_service
+22	Can add service attribute	8	add_serviceattribute
+23	Can change service attribute	8	change_serviceattribute
+24	Can delete service attribute	8	delete_serviceattribute
+25	Can add service role	9	add_servicerole
+26	Can change service role	9	change_servicerole
+27	Can delete service role	9	delete_servicerole
+28	Can add service privilege	10	add_serviceprivilege
+29	Can change service privilege	10	change_serviceprivilege
+30	Can delete service privilege	10	delete_serviceprivilege
+31	Can add tenant root	11	add_tenantroot
+32	Can change tenant root	11	change_tenantroot
+33	Can delete tenant root	11	delete_tenantroot
+34	Can add tenant	12	add_tenant
+35	Can change tenant	12	change_tenant
+36	Can delete tenant	12	delete_tenant
+37	Can add tenant with container	12	add_tenantwithcontainer
+38	Can change tenant with container	12	change_tenantwithcontainer
+39	Can delete tenant with container	12	delete_tenantwithcontainer
+40	Can add coarse tenant	12	add_coarsetenant
+41	Can change coarse tenant	12	change_coarsetenant
+42	Can delete coarse tenant	12	delete_coarsetenant
+43	Can add subscriber	11	add_subscriber
+44	Can change subscriber	11	change_subscriber
+45	Can delete subscriber	11	delete_subscriber
+46	Can add provider	11	add_provider
+47	Can change provider	11	change_provider
+48	Can delete provider	11	delete_provider
+49	Can add tenant attribute	13	add_tenantattribute
+50	Can change tenant attribute	13	change_tenantattribute
+51	Can delete tenant attribute	13	delete_tenantattribute
+52	Can add tenant root role	14	add_tenantrootrole
+53	Can change tenant root role	14	change_tenantrootrole
+54	Can delete tenant root role	14	delete_tenantrootrole
+55	Can add tenant root privilege	15	add_tenantrootprivilege
+56	Can change tenant root privilege	15	change_tenantrootprivilege
+57	Can delete tenant root privilege	15	delete_tenantrootprivilege
+58	Can add tag	16	add_tag
+59	Can change tag	16	change_tag
+60	Can delete tag	16	delete_tag
+61	Can add role	17	add_role
+62	Can change role	17	change_role
+63	Can delete role	17	delete_role
+64	Can add site	18	add_site
+65	Can change site	18	change_site
+66	Can delete site	18	delete_site
+67	Can add site role	19	add_siterole
+68	Can change site role	19	change_siterole
+69	Can delete site role	19	delete_siterole
+70	Can add site privilege	20	add_siteprivilege
+71	Can change site privilege	20	change_siteprivilege
+72	Can delete site privilege	20	delete_siteprivilege
+73	Can add deployment	21	add_deployment
+74	Can change deployment	21	change_deployment
+75	Can delete deployment	21	delete_deployment
+76	Can add deployment role	22	add_deploymentrole
+77	Can change deployment role	22	change_deploymentrole
+78	Can delete deployment role	22	delete_deploymentrole
+79	Can add deployment privilege	23	add_deploymentprivilege
+80	Can change deployment privilege	23	change_deploymentprivilege
+81	Can delete deployment privilege	23	delete_deploymentprivilege
+82	Can add controller role	24	add_controllerrole
+83	Can change controller role	24	change_controllerrole
+84	Can delete controller role	24	delete_controllerrole
+85	Can add controller	25	add_controller
+86	Can change controller	25	change_controller
+87	Can delete controller	25	delete_controller
+88	Can add site deployment	26	add_sitedeployment
+89	Can change site deployment	26	change_sitedeployment
+90	Can delete site deployment	26	delete_sitedeployment
+91	Can add controller site	27	add_controllersite
+92	Can change controller site	27	change_controllersite
+93	Can delete controller site	27	delete_controllersite
+94	Can add diag	28	add_diag
+95	Can change diag	28	change_diag
+96	Can delete diag	28	delete_diag
+97	Can add dashboard view	29	add_dashboardview
+98	Can change dashboard view	29	change_dashboardview
+99	Can delete dashboard view	29	delete_dashboardview
+100	Can add controller dashboard view	30	add_controllerdashboardview
+101	Can change controller dashboard view	30	change_controllerdashboardview
+102	Can delete controller dashboard view	30	delete_controllerdashboardview
+103	Can add user	31	add_user
+104	Can change user	31	change_user
+105	Can delete user	31	delete_user
+106	Can add user dashboard view	32	add_userdashboardview
+107	Can change user dashboard view	32	change_userdashboardview
+108	Can delete user dashboard view	32	delete_userdashboardview
+109	Can add service class	33	add_serviceclass
+110	Can change service class	33	change_serviceclass
+111	Can delete service class	33	delete_serviceclass
+112	Can add flavor	34	add_flavor
+113	Can change flavor	34	change_flavor
+114	Can delete flavor	34	delete_flavor
+115	Can add image	35	add_image
+116	Can change image	35	change_image
+117	Can delete image	35	delete_image
+118	Can add image deployments	36	add_imagedeployments
+119	Can change image deployments	36	change_imagedeployments
+120	Can delete image deployments	36	delete_imagedeployments
+121	Can add controller images	37	add_controllerimages
+122	Can change controller images	37	change_controllerimages
+123	Can delete controller images	37	delete_controllerimages
+124	Can add slice	38	add_slice
+125	Can change slice	38	change_slice
+126	Can delete slice	38	delete_slice
+127	Can add slice role	39	add_slicerole
+128	Can change slice role	39	change_slicerole
+129	Can delete slice role	39	delete_slicerole
+130	Can add slice privilege	40	add_sliceprivilege
+131	Can change slice privilege	40	change_sliceprivilege
+132	Can delete slice privilege	40	delete_sliceprivilege
+133	Can add controller slice	41	add_controllerslice
+134	Can change controller slice	41	change_controllerslice
+135	Can delete controller slice	41	delete_controllerslice
+136	Can add controller user	42	add_controlleruser
+137	Can change controller user	42	change_controlleruser
+138	Can delete controller user	42	delete_controlleruser
+139	Can add controller site privilege	43	add_controllersiteprivilege
+140	Can change controller site privilege	43	change_controllersiteprivilege
+141	Can delete controller site privilege	43	delete_controllersiteprivilege
+142	Can add controller slice privilege	44	add_controllersliceprivilege
+143	Can change controller slice privilege	44	change_controllersliceprivilege
+144	Can delete controller slice privilege	44	delete_controllersliceprivilege
+145	Can add service resource	45	add_serviceresource
+146	Can change service resource	45	change_serviceresource
+147	Can delete service resource	45	delete_serviceresource
+148	Can add user credential	46	add_usercredential
+149	Can change user credential	46	change_usercredential
+150	Can delete user credential	46	delete_usercredential
+151	Can add site credential	47	add_sitecredential
+152	Can change site credential	47	change_sitecredential
+153	Can delete site credential	47	delete_sitecredential
+154	Can add slice credential	48	add_slicecredential
+155	Can change slice credential	48	change_slicecredential
+156	Can delete slice credential	48	delete_slicecredential
+157	Can add controller credential	49	add_controllercredential
+158	Can change controller credential	49	change_controllercredential
+159	Can delete controller credential	49	delete_controllercredential
+160	Can add node	50	add_node
+161	Can change node	50	change_node
+162	Can delete node	50	delete_node
+163	Can add node label	51	add_nodelabel
+164	Can change node label	51	change_nodelabel
+165	Can delete node label	51	delete_nodelabel
+166	Can add slice tag	52	add_slicetag
+167	Can change slice tag	52	change_slicetag
+168	Can delete slice tag	52	delete_slicetag
+169	Can add instance	53	add_instance
+170	Can change instance	53	change_instance
+171	Can delete instance	53	delete_instance
+172	Can add reservation	54	add_reservation
+173	Can change reservation	54	change_reservation
+174	Can delete reservation	54	delete_reservation
+175	Can add reserved resource	55	add_reservedresource
+176	Can change reserved resource	55	change_reservedresource
+177	Can delete reserved resource	55	delete_reservedresource
+178	Can add network template	56	add_networktemplate
+179	Can change network template	56	change_networktemplate
+180	Can delete network template	56	delete_networktemplate
+181	Can add network	57	add_network
+182	Can change network	57	change_network
+183	Can delete network	57	delete_network
+184	Can add controller network	58	add_controllernetwork
+185	Can change controller network	58	change_controllernetwork
+186	Can delete controller network	58	delete_controllernetwork
+187	Can add network slice	59	add_networkslice
+188	Can change network slice	59	change_networkslice
+189	Can delete network slice	59	delete_networkslice
+190	Can add port	60	add_port
+191	Can change port	60	change_port
+192	Can delete port	60	delete_port
+193	Can add router	61	add_router
+194	Can change router	61	change_router
+195	Can delete router	61	delete_router
+196	Can add network parameter type	62	add_networkparametertype
+197	Can change network parameter type	62	change_networkparametertype
+198	Can delete network parameter type	62	delete_networkparametertype
+199	Can add network parameter	63	add_networkparameter
+200	Can change network parameter	63	change_networkparameter
+201	Can delete network parameter	63	delete_networkparameter
+202	Can add address pool	64	add_addresspool
+203	Can change address pool	64	change_addresspool
+204	Can delete address pool	64	delete_addresspool
+205	Can add account	65	add_account
+206	Can change account	65	change_account
+207	Can delete account	65	delete_account
+208	Can add invoice	66	add_invoice
+209	Can change invoice	66	change_invoice
+210	Can delete invoice	66	delete_invoice
+211	Can add usable object	67	add_usableobject
+212	Can change usable object	67	change_usableobject
+213	Can delete usable object	67	delete_usableobject
+214	Can add payment	68	add_payment
+215	Can change payment	68	change_payment
+216	Can delete payment	68	delete_payment
+217	Can add charge	69	add_charge
+218	Can change charge	69	change_charge
+219	Can delete charge	69	delete_charge
+220	Can add program	70	add_program
+221	Can change program	70	change_program
+222	Can delete program	70	delete_program
+223	Can add HPC Service	75	add_hpcservice
+224	Can change HPC Service	75	change_hpcservice
+225	Can delete HPC Service	75	delete_hpcservice
+226	Can add service provider	76	add_serviceprovider
+227	Can change service provider	76	change_serviceprovider
+228	Can delete service provider	76	delete_serviceprovider
+229	Can add content provider	77	add_contentprovider
+230	Can change content provider	77	change_contentprovider
+231	Can delete content provider	77	delete_contentprovider
+232	Can add origin server	78	add_originserver
+233	Can change origin server	78	change_originserver
+234	Can delete origin server	78	delete_originserver
+235	Can add cdn prefix	79	add_cdnprefix
+236	Can change cdn prefix	79	change_cdnprefix
+237	Can delete cdn prefix	79	delete_cdnprefix
+238	Can add access map	80	add_accessmap
+239	Can change access map	80	change_accessmap
+240	Can delete access map	80	delete_accessmap
+241	Can add site map	81	add_sitemap
+242	Can change site map	81	change_sitemap
+243	Can delete site map	81	delete_sitemap
+244	Can add hpc health check	82	add_hpchealthcheck
+245	Can change hpc health check	82	change_hpchealthcheck
+246	Can delete hpc health check	82	delete_hpchealthcheck
+247	Can add cord subscriber root	11	add_cordsubscriberroot
+248	Can change cord subscriber root	11	change_cordsubscriberroot
+249	Can delete cord subscriber root	11	delete_cordsubscriberroot
+250	Can add vOLT Service	7	add_voltservice
+251	Can change vOLT Service	7	change_voltservice
+252	Can delete vOLT Service	7	delete_voltservice
+253	Can add volt tenant	12	add_volttenant
+254	Can change volt tenant	12	change_volttenant
+255	Can delete volt tenant	12	delete_volttenant
+256	Can add vSG Service	7	add_vsgservice
+257	Can change vSG Service	7	change_vsgservice
+258	Can delete vSG Service	7	delete_vsgservice
+259	Can add vsg tenant	12	add_vsgtenant
+260	Can change vsg tenant	12	change_vsgtenant
+261	Can delete vsg tenant	12	delete_vsgtenant
+262	Can add vBNG Service	7	add_vbngservice
+263	Can change vBNG Service	7	change_vbngservice
+264	Can delete vBNG Service	7	delete_vbngservice
+265	Can add vbng tenant	12	add_vbngtenant
+266	Can change vbng tenant	12	change_vbngtenant
+267	Can delete vbng tenant	12	delete_vbngtenant
+274	Can add ONOS Service	7	add_onosservice
+275	Can change ONOS Service	7	change_onosservice
+276	Can delete ONOS Service	7	delete_onosservice
+277	Can add onos app	12	add_onosapp
+278	Can change onos app	12	change_onosapp
+279	Can delete onos app	12	delete_onosapp
+280	Can add Ceilometer Service	7	add_ceilometerservice
+281	Can change Ceilometer Service	7	change_ceilometerservice
+282	Can delete Ceilometer Service	7	delete_ceilometerservice
+283	Can add monitoring channel	12	add_monitoringchannel
+284	Can change monitoring channel	12	change_monitoringchannel
+285	Can delete monitoring channel	12	delete_monitoringchannel
+286	Can add sFlow Collection Service	7	add_sflowservice
+287	Can change sFlow Collection Service	7	change_sflowservice
+288	Can delete sFlow Collection Service	7	delete_sflowservice
+289	Can add s flow tenant	12	add_sflowtenant
+290	Can change s flow tenant	12	change_sflowtenant
+291	Can delete s flow tenant	12	delete_sflowtenant
+292	Can add Request Router Service	98	add_requestrouterservice
+293	Can change Request Router Service	98	change_requestrouterservice
+294	Can delete Request Router Service	98	delete_requestrouterservice
+295	Can add service map	99	add_servicemap
+296	Can change service map	99	change_servicemap
+297	Can delete service map	99	delete_servicemap
+298	Can add Syndicate Service	100	add_syndicateservice
+299	Can change Syndicate Service	100	change_syndicateservice
+300	Can delete Syndicate Service	100	delete_syndicateservice
+301	Can add syndicate principal	101	add_syndicateprincipal
+302	Can change syndicate principal	101	change_syndicateprincipal
+303	Can delete syndicate principal	101	delete_syndicateprincipal
+304	Can add volume	102	add_volume
+305	Can change volume	102	change_volume
+306	Can delete volume	102	delete_volume
+307	Can add volume access right	103	add_volumeaccessright
+308	Can change volume access right	103	change_volumeaccessright
+309	Can delete volume access right	103	delete_volumeaccessright
+310	Can add slice secret	104	add_slicesecret
+311	Can change slice secret	104	change_slicesecret
+312	Can delete slice secret	104	delete_slicesecret
+313	Can add volume slice	105	add_volumeslice
+314	Can change volume slice	105	change_volumeslice
+315	Can delete volume slice	105	delete_volumeslice
+316	Can add vTR Service	7	add_vtrservice
+317	Can change vTR Service	7	change_vtrservice
+318	Can delete vTR Service	7	delete_vtrservice
+319	Can add vtr tenant	12	add_vtrtenant
+320	Can change vtr tenant	12	change_vtrtenant
+321	Can delete vtr tenant	12	delete_vtrtenant
+\.
+
+
+--
+-- Name: auth_permission_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('auth_permission_id_seq', 321, true);
+
+
+--
+-- Data for Name: core_account; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_account (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, site_id) FROM stdin;
+\.
+
+
+--
+-- Name: core_account_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_account_id_seq', 1, false);
+
+
+--
+-- Data for Name: core_addresspool; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_addresspool (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, name, addresses, inuse) FROM stdin;
+\.
+
+
+--
+-- Name: core_addresspool_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_addresspool_id_seq', 1, false);
+
+
+--
+-- Data for Name: core_charge; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_charge (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, kind, state, date, amount, "coreHours", account_id, invoice_id, object_id, slice_id) FROM stdin;
+\.
+
+
+--
+-- Name: core_charge_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_charge_id_seq', 1, false);
+
+
+--
+-- Data for Name: core_controller; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_controller (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, name, backend_type, version, auth_url, admin_user, admin_password, admin_tenant, domain, rabbit_host, rabbit_user, rabbit_password, deployment_id) FROM stdin;
+1	2016-04-05 17:41:57.870164+00	2016-04-05 17:41:57.870189+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	t	CloudLab	OpenStack	Juno	http://sample/v2	admin	adminpassword	admin	Default	\N	\N	\N	1
+\.
+
+
+--
+-- Name: core_controller_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_controller_id_seq', 1, true);
+
+
+--
+-- Data for Name: core_controllercredential; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_controllercredential (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, name, key_id, enc_value, controller_id) FROM stdin;
+\.
+
+
+--
+-- Name: core_controllercredential_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_controllercredential_id_seq', 1, false);
+
+
+--
+-- Data for Name: core_controllerdashboardview; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_controllerdashboardview (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, enabled, url, controller_id, "dashboardView_id") FROM stdin;
+\.
+
+
+--
+-- Name: core_controllerdashboardview_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_controllerdashboardview_id_seq', 1, false);
+
+
+--
+-- Data for Name: core_controllerimages; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_controllerimages (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, glance_image_id, controller_id, image_id) FROM stdin;
+\.
+
+
+--
+-- Name: core_controllerimages_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_controllerimages_id_seq', 1, false);
+
+
+--
+-- Data for Name: core_controllernetwork; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_controllernetwork (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, net_id, router_id, subnet_id, subnet, controller_id, network_id) FROM stdin;
+\.
+
+
+--
+-- Name: core_controllernetwork_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_controllernetwork_id_seq', 1, false);
+
+
+--
+-- Data for Name: core_controllerrole; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_controllerrole (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, role) FROM stdin;
+\.
+
+
+--
+-- Name: core_controllerrole_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_controllerrole_id_seq', 1, false);
+
+
+--
+-- Data for Name: core_controllersite; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_controllersite (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, tenant_id, controller_id, site_id) FROM stdin;
+\.
+
+
+--
+-- Name: core_controllersite_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_controllersite_id_seq', 1, false);
+
+
+--
+-- Data for Name: core_controllersiteprivilege; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_controllersiteprivilege (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, role_id, controller_id, site_privilege_id) FROM stdin;
+\.
+
+
+--
+-- Name: core_controllersiteprivilege_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_controllersiteprivilege_id_seq', 1, false);
+
+
+--
+-- Data for Name: core_controllerslice; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_controllerslice (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, tenant_id, controller_id, slice_id) FROM stdin;
+\.
+
+
+--
+-- Name: core_controllerslice_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_controllerslice_id_seq', 1, false);
+
+
+--
+-- Data for Name: core_controllersliceprivilege; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_controllersliceprivilege (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, role_id, controller_id, slice_privilege_id) FROM stdin;
+\.
+
+
+--
+-- Name: core_controllersliceprivilege_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_controllersliceprivilege_id_seq', 1, false);
+
+
+--
+-- Data for Name: core_controlleruser; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_controlleruser (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, kuser_id, controller_id, user_id) FROM stdin;
+\.
+
+
+--
+-- Name: core_controlleruser_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_controlleruser_id_seq', 1, false);
+
+
+--
+-- Data for Name: core_dashboardview; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_dashboardview (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, name, url, enabled) FROM stdin;
+1	2015-02-17 22:06:38.953+00	2015-02-17 22:06:38.953+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	xsh	template:xsh	t
+2	2015-02-17 22:06:39.011+00	2015-02-17 22:06:39.011+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	Customize	template:customize	t
+3	2015-02-17 22:06:39.069+00	2015-02-17 22:06:39.244+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	Tenant	template:xosTenant	t
+4	2015-02-17 22:06:39.302+00	2015-02-17 22:06:39.302+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	Developer	template:xosDeveloper_datatables	t
+5	2016-04-05 17:42:11.341605+00	2016-04-05 17:42:11.341634+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	Customer Care	template:xosDiagnostic	t
+6	2016-04-05 18:46:36.638199+00	2016-04-05 18:46:36.638233+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	truckroll	template:xosTruckroll	t
+\.
+
+
+--
+-- Data for Name: core_dashboardview_deployments; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_dashboardview_deployments (id, dashboardview_id, deployment_id) FROM stdin;
+1	3	1
+\.
+
+
+--
+-- Name: core_dashboardview_deployments_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_dashboardview_deployments_id_seq', 1, true);
+
+
+--
+-- Name: core_dashboardview_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_dashboardview_id_seq', 6, true);
+
+
+--
+-- Data for Name: core_deployment; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_deployment (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, name, "accessControl") FROM stdin;
+1	2015-02-17 22:06:37.789+00	2016-04-05 17:41:57.865591+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	t	MyDeployment	allow all
+\.
+
+
+--
+-- Name: core_deployment_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_deployment_id_seq', 1, true);
+
+
+--
+-- Data for Name: core_deploymentprivilege; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_deploymentprivilege (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, deployment_id, role_id, user_id) FROM stdin;
+\.
+
+
+--
+-- Name: core_deploymentprivilege_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_deploymentprivilege_id_seq', 1, false);
+
+
+--
+-- Data for Name: core_deploymentrole; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_deploymentrole (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, role) FROM stdin;
+1	2015-02-17 22:06:38.894+00	2015-02-17 22:06:38.894+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	admin
+\.
+
+
+--
+-- Name: core_deploymentrole_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_deploymentrole_id_seq', 1, true);
+
+
+--
+-- Data for Name: core_diag; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_diag (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, name) FROM stdin;
+\.
+
+
+--
+-- Name: core_diag_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_diag_id_seq', 1, false);
+
+
+--
+-- Data for Name: core_flavor; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_flavor (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, name, description, flavor, "order", "default") FROM stdin;
+1	2015-02-17 22:06:38.095+00	2015-02-17 22:06:38.236+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	t	m1.small	\N	m1.small	0	f
+2	2015-02-17 22:06:38.287+00	2015-02-17 22:06:38.394+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	t	m1.medium	\N	m1.medium	0	f
+3	2015-02-17 22:06:38.445+00	2015-02-17 22:06:38.561+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	t	m1.large	\N	m1.large	0	f
+\.
+
+
+--
+-- Data for Name: core_flavor_deployments; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_flavor_deployments (id, flavor_id, deployment_id) FROM stdin;
+1	1	1
+2	2	1
+3	3	1
+\.
+
+
+--
+-- Name: core_flavor_deployments_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_flavor_deployments_id_seq', 3, true);
+
+
+--
+-- Name: core_flavor_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_flavor_id_seq', 3, true);
+
+
+--
+-- Data for Name: core_image; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_image (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, name, kind, disk_format, container_format, path, tag) FROM stdin;
+1	2016-04-05 17:41:57.84418+00	2016-04-05 17:41:57.844213+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	trusty-server-multi-nic	vm	QCOW2	BARE	\N	\N
+2	2016-04-05 17:42:10.875232+00	2016-04-05 17:42:10.87526+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	docker-vcpe	container	na	na	andybavier/docker-vcpe	develop
+\.
+
+
+--
+-- Name: core_image_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_image_id_seq', 2, true);
+
+
+--
+-- Data for Name: core_imagedeployments; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_imagedeployments (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, deployment_id, image_id) FROM stdin;
+1	2016-04-05 17:41:57.855026+00	2016-04-05 17:41:57.855053+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	1	1
+\.
+
+
+--
+-- Name: core_imagedeployments_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_imagedeployments_id_seq', 1, true);
+
+
+--
+-- Data for Name: core_instance; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_instance (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, instance_id, instance_uuid, name, instance_name, ip, "numberCores", "userData", isolation, volumes, creator_id, deployment_id, flavor_id, image_id, node_id, parent_id, slice_id) FROM stdin;
+1	2016-04-05 17:42:11.041143+00	2016-04-05 17:42:11.041177+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	\N	\N	mysite_vcpe	\N	\N	0	\N	vm	/etc/dnsmasq.d,/etc/ufw	1	1	1	1	1	\N	1
+2	2016-04-05 17:42:11.143845+00	2016-04-05 17:42:11.505705+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	\N	\N	onos_app_1	\N	\N	0	\N	vm	\N	1	1	1	1	2	\N	5
+3	2016-04-05 17:42:11.180193+00	2016-04-05 17:42:11.508623+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	\N	\N	client1	\N	\N	0	\N	vm	\N	1	1	1	1	1	\N	4
+4	2016-04-05 17:42:11.24868+00	2016-04-05 17:42:11.512938+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	\N	\N	onos_app_2	\N	\N	0	\N	vm	\N	1	1	1	1	2	\N	6
+5	2016-04-05 17:42:11.32255+00	2016-04-05 17:42:11.516734+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	\N	\N	ovs_volt	\N	\N	0	\N	vm	\N	1	1	1	1	1	\N	3
+6	2016-04-05 17:42:11.336187+00	2016-04-05 17:42:11.519581+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	\N	\N	ovs_vbng	\N	\N	0	\N	vm	\N	1	1	1	1	2	\N	2
+\.
+
+
+--
+-- Name: core_instance_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_instance_id_seq', 6, true);
+
+
+--
+-- Data for Name: core_invoice; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_invoice (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, date, account_id) FROM stdin;
+\.
+
+
+--
+-- Name: core_invoice_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_invoice_id_seq', 1, false);
+
+
+--
+-- Data for Name: core_network; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_network (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, name, subnet, ports, labels, guaranteed_bandwidth, permit_all_slices, topology_parameters, controller_url, controller_parameters, network_id, router_id, subnet_id, autoconnect, owner_id, template_id) FROM stdin;
+1	2016-04-05 17:42:10.926943+00	2016-04-05 17:42:10.926967+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	wan_network		\N	\N	0	t	\N	\N	\N	\N	\N	\N	f	1	1
+2	2016-04-05 17:42:10.963196+00	2016-04-05 17:42:10.963223+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	lan_network		\N	\N	0	t	\N	\N	\N	\N	\N	\N	f	1	1
+3	2016-04-05 17:42:11.188082+00	2016-04-05 17:42:11.188111+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	public_network		\N	\N	0	t	\N	\N	\N	\N	\N	\N	f	2	5
+4	2016-04-05 17:42:11.370317+00	2016-04-05 17:42:11.370343+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	subscriber_network		\N	\N	0	t	\N	\N	\N	\N	\N	\N	f	3	1
+\.
+
+
+--
+-- Name: core_network_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_network_id_seq', 4, true);
+
+
+--
+-- Data for Name: core_network_permitted_slices; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_network_permitted_slices (id, network_id, slice_id) FROM stdin;
+\.
+
+
+--
+-- Name: core_network_permitted_slices_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_network_permitted_slices_id_seq', 1, false);
+
+
+--
+-- Data for Name: core_networkparameter; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_networkparameter (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, value, object_id, content_type_id, parameter_id) FROM stdin;
+1	2016-04-05 17:42:11.062812+00	2016-04-05 17:42:11.062838+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	432	1	60	5
+2	2016-04-05 17:42:11.068024+00	2016-04-05 17:42:11.068048+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	222	1	60	6
+3	2016-04-05 17:42:11.071633+00	2016-04-05 17:42:11.071645+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	stag-222	1	60	4
+\.
+
+
+--
+-- Name: core_networkparameter_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_networkparameter_id_seq', 3, true);
+
+
+--
+-- Data for Name: core_networkparametertype; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_networkparametertype (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, name, description) FROM stdin;
+1	2016-04-05 17:42:09.268578+00	2016-04-05 17:42:09.26861+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	bridge	
+2	2016-04-05 17:42:09.271808+00	2016-04-05 17:42:09.271835+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	next_hop	
+3	2016-04-05 17:42:09.274484+00	2016-04-05 17:42:09.27451+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	device	
+4	2016-04-05 17:42:09.276919+00	2016-04-05 17:42:09.276946+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	neutron_port_name	
+5	2016-04-05 17:42:09.279956+00	2016-04-05 17:42:09.279984+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	c_tag	
+6	2016-04-05 17:42:09.282047+00	2016-04-05 17:42:09.282073+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	s_tag	
+\.
+
+
+--
+-- Name: core_networkparametertype_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_networkparametertype_id_seq', 6, true);
+
+
+--
+-- Data for Name: core_networkslice; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_networkslice (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, network_id, slice_id) FROM stdin;
+1	2016-04-05 17:42:10.934539+00	2016-04-05 17:42:10.93457+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	1	1
+2	2016-04-05 17:42:10.948028+00	2016-04-05 17:42:10.948057+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	1	2
+3	2016-04-05 17:42:10.967241+00	2016-04-05 17:42:10.967274+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	2	1
+4	2016-04-05 17:42:10.971959+00	2016-04-05 17:42:10.971989+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	2	3
+5	2016-04-05 17:42:11.193081+00	2016-04-05 17:42:11.193111+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	3	2
+6	2016-04-05 17:42:11.37604+00	2016-04-05 17:42:11.376067+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	4	3
+7	2016-04-05 17:42:11.380003+00	2016-04-05 17:42:11.380064+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	4	4
+\.
+
+
+--
+-- Name: core_networkslice_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_networkslice_id_seq', 7, true);
+
+
+--
+-- Data for Name: core_networktemplate; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_networktemplate (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, name, description, guaranteed_bandwidth, visibility, translation, access, shared_network_name, shared_network_id, topology_kind, controller_kind) FROM stdin;
+3	2015-02-17 22:06:39.536+00	2015-02-17 22:06:39.536+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	Public dedicated IPv4	Connect a instance to the public network	0	public	none	\N	ext-net	\N	bigswitch	\N
+2	2015-02-17 22:06:39.477+00	2016-04-05 17:41:57.912367+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	Public shared IPv4	Connect a instance to the public network	0	private	NAT	\N	nat-net	\N	bigswitch	\N
+1	2015-02-17 22:06:39.419+00	2016-04-05 17:42:10.920852+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	Private	A private virtual network	0	private	none	\N	\N	\N	bigswitch	\N
+4	2016-04-05 17:42:10.950692+00	2016-04-05 17:42:10.950719+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	Private-Direct	\N	0	private	none	direct	\N	\N	bigswitch	\N
+5	2016-04-05 17:42:11.11517+00	2016-04-05 17:42:11.115197+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	Public network hack	\N	0	private	NAT	\N	tun0-net	\N	bigswitch	\N
+6	2016-04-05 17:42:11.309984+00	2016-04-05 17:42:11.310025+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	Private-Indirect	\N	0	private	none	indirect	\N	\N	bigswitch	\N
+\.
+
+
+--
+-- Name: core_networktemplate_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_networktemplate_id_seq', 6, true);
+
+
+--
+-- Data for Name: core_node; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_node (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, name, site_id, site_deployment_id) FROM stdin;
+1	2016-04-05 17:41:57.898724+00	2016-04-05 17:41:57.898751+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	t	node2.opencloud.us	1	1
+2	2016-04-05 17:41:57.908261+00	2016-04-05 17:41:57.908283+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	t	node1.opencloud.us	1	1
+\.
+
+
+--
+-- Name: core_node_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_node_id_seq', 2, true);
+
+
+--
+-- Data for Name: core_nodelabel; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_nodelabel (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, name) FROM stdin;
+\.
+
+
+--
+-- Name: core_nodelabel_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_nodelabel_id_seq', 1, false);
+
+
+--
+-- Data for Name: core_nodelabel_node; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_nodelabel_node (id, nodelabel_id, node_id) FROM stdin;
+\.
+
+
+--
+-- Name: core_nodelabel_node_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_nodelabel_node_id_seq', 1, false);
+
+
+--
+-- Data for Name: core_payment; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_payment (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, amount, date, account_id) FROM stdin;
+\.
+
+
+--
+-- Name: core_payment_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_payment_id_seq', 1, false);
+
+
+--
+-- Data for Name: core_port; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_port (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, ip, port_id, mac, xos_created, instance_id, network_id) FROM stdin;
+1	2016-04-05 17:42:11.049219+00	2016-04-05 17:42:11.073126+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	\N	\N	\N	f	1	2
+\.
+
+
+--
+-- Name: core_port_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_port_id_seq', 1, true);
+
+
+--
+-- Data for Name: core_program; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_program (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, name, description, kind, command, contents, output, messages, status, owner_id) FROM stdin;
+\.
+
+
+--
+-- Name: core_program_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_program_id_seq', 1, false);
+
+
+--
+-- Data for Name: core_project; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_project (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, name) FROM stdin;
+\.
+
+
+--
+-- Name: core_project_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_project_id_seq', 1, false);
+
+
+--
+-- Data for Name: core_reservation; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_reservation (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, "startTime", duration, slice_id) FROM stdin;
+\.
+
+
+--
+-- Name: core_reservation_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_reservation_id_seq', 1, false);
+
+
+--
+-- Data for Name: core_reservedresource; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_reservedresource (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, quantity, instance_id, "reservationSet_id", resource_id) FROM stdin;
+\.
+
+
+--
+-- Name: core_reservedresource_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_reservedresource_id_seq', 1, false);
+
+
+--
+-- Data for Name: core_role; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_role (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, role_type, role, description, content_type_id) FROM stdin;
+\.
+
+
+--
+-- Name: core_role_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_role_id_seq', 1, false);
+
+
+--
+-- Data for Name: core_router; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_router (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, name, owner_id) FROM stdin;
+\.
+
+
+--
+-- Name: core_router_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_router_id_seq', 1, false);
+
+
+--
+-- Data for Name: core_router_networks; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_router_networks (id, router_id, network_id) FROM stdin;
+\.
+
+
+--
+-- Name: core_router_networks_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_router_networks_id_seq', 1, false);
+
+
+--
+-- Data for Name: core_router_permittedNetworks; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY "core_router_permittedNetworks" (id, router_id, network_id) FROM stdin;
+\.
+
+
+--
+-- Name: core_router_permittedNetworks_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('"core_router_permittedNetworks_id_seq"', 1, false);
+
+
+--
+-- Data for Name: core_service; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_service (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, description, enabled, kind, name, "versionNumber", published, view_url, icon_url, public_key, private_key_fn, service_specific_id, service_specific_attribute) FROM stdin;
+1	2016-04-05 17:42:10.879967+00	2016-04-05 17:42:10.879992+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	\N	t	vBNG	service_vbng		t	/admin/cord/vbngservice/$id$/	\N	\N	\N	\N	\N
+2	2016-04-05 17:42:10.891972+00	2016-04-05 17:42:10.892005+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	\N	t	vCPE	service_vsg		t	/admin/cord/vsgservice/$id$/	\N	\N	\N	\N	{"backend_network_label": "hpc_client"}
+3	2016-04-05 17:42:10.974546+00	2016-04-05 17:42:10.97457+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	\N	t	vOLT	service_volt		t	/admin/cord/voltservice/$id$/	\N	\N	\N	\N	\N
+4	2016-04-05 17:42:11.119371+00	2016-04-05 17:42:11.119403+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	\N	t	onos	service_ONOS_vBNG		t	/admin/onos/onosservice/$id$/	\N	\N	\N	\N	{"no_container": false}
+5	2016-04-05 17:42:11.15434+00	2016-04-05 17:42:11.154366+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	\N	t	onos	service_ONOS_vOLT		t	/admin/onos/onosservice/$id$/	\N	\N	\N	\N	{"no_container": false}
+6	2016-04-05 17:42:11.183911+00	2016-04-05 17:42:11.183952+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	\N	t	vTR	service_vtr		t	/admin/vtr/vtrservice/$id$/	\N	\N	\N	\N	\N
+\.
+
+
+--
+-- Name: core_service_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_service_id_seq', 6, true);
+
+
+--
+-- Data for Name: core_serviceattribute; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_serviceattribute (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, name, value, service_id) FROM stdin;
+1	2016-04-05 17:42:11.158787+00	2016-04-05 17:42:11.158814+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	rest_onos/v1/network/configuration/	{\n  "devices" : {\n    "of:0000000000000001" : {\n      "accessDevice" : {\n        "uplink" : "2",\n        "vlan"   : "222",\n        "defaultVlan" : "1"\n      },\n      "basic" : {\n        "driver" : "pmc-olt"\n      }\n    }\n  }\n}\n	5
+\.
+
+
+--
+-- Name: core_serviceattribute_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_serviceattribute_id_seq', 1, true);
+
+
+--
+-- Data for Name: core_serviceclass; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_serviceclass (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, name, description, commitment, "membershipFee", "membershipFeeMonths", "upgradeRequiresApproval") FROM stdin;
+1	2015-02-17 22:06:39.361+00	2015-02-17 22:06:39.361+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	Best Effort	Best Effort	365	0	12	f
+\.
+
+
+--
+-- Name: core_serviceclass_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_serviceclass_id_seq', 1, true);
+
+
+--
+-- Data for Name: core_serviceclass_upgradeFrom; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY "core_serviceclass_upgradeFrom" (id, from_serviceclass_id, to_serviceclass_id) FROM stdin;
+\.
+
+
+--
+-- Name: core_serviceclass_upgradeFrom_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('"core_serviceclass_upgradeFrom_id_seq"', 1, false);
+
+
+--
+-- Data for Name: core_serviceprivilege; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_serviceprivilege (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, role_id, service_id, user_id) FROM stdin;
+\.
+
+
+--
+-- Name: core_serviceprivilege_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_serviceprivilege_id_seq', 1, false);
+
+
+--
+-- Data for Name: core_serviceresource; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_serviceresource (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, name, "maxUnitsDeployment", "maxUnitsNode", "maxDuration", "bucketInRate", "bucketMaxSize", cost, "calendarReservable", "serviceClass_id") FROM stdin;
+\.
+
+
+--
+-- Name: core_serviceresource_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_serviceresource_id_seq', 1, false);
+
+
+--
+-- Data for Name: core_servicerole; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_servicerole (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, role) FROM stdin;
+\.
+
+
+--
+-- Name: core_servicerole_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_servicerole_id_seq', 1, false);
+
+
+--
+-- Data for Name: core_site; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_site (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, name, site_url, enabled, hosts_nodes, hosts_users, location, longitude, latitude, login_base, is_public, abbreviated_name) FROM stdin;
+1	2015-02-17 22:06:37.837+00	2016-04-05 17:42:10.798018+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	mysite	http://opencloud.us/	t	t	t	0,0	\N	\N	mysite	t	mysite
+\.
+
+
+--
+-- Name: core_site_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_site_id_seq', 1, true);
+
+
+--
+-- Data for Name: core_sitecredential; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_sitecredential (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, name, key_id, enc_value, site_id) FROM stdin;
+\.
+
+
+--
+-- Name: core_sitecredential_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_sitecredential_id_seq', 1, false);
+
+
+--
+-- Data for Name: core_sitedeployment; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_sitedeployment (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, availability_zone, controller_id, deployment_id, site_id) FROM stdin;
+1	2015-02-17 22:06:37.893+00	2016-04-05 17:41:57.888081+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	\N	1	1	1
+\.
+
+
+--
+-- Name: core_sitedeployment_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_sitedeployment_id_seq', 1, true);
+
+
+--
+-- Data for Name: core_siteprivilege; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_siteprivilege (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, role_id, site_id, user_id) FROM stdin;
+\.
+
+
+--
+-- Name: core_siteprivilege_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_siteprivilege_id_seq', 1, false);
+
+
+--
+-- Data for Name: core_siterole; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_siterole (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, role) FROM stdin;
+1	2015-02-17 22:06:38.62+00	2015-02-17 22:06:38.62+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	admin
+2	2015-02-17 22:06:38.669+00	2015-02-17 22:06:38.67+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	pi
+3	2015-02-17 22:06:38.73+00	2015-02-17 22:06:38.731+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	tech
+\.
+
+
+--
+-- Name: core_siterole_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_siterole_id_seq', 3, true);
+
+
+--
+-- Data for Name: core_slice; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_slice (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, name, enabled, omf_friendly, description, slice_url, max_instances, network, exposed_ports, mount_data_sets, default_isolation, creator_id, default_flavor_id, default_image_id, service_id, "serviceClass_id", site_id) FROM stdin;
+1	2016-04-05 17:42:10.909075+00	2016-04-05 17:42:10.909102+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	mysite_vcpe	t	f			10	\N	\N	GenBank	vm	1	\N	\N	2	1	1
+2	2016-04-05 17:42:10.915949+00	2016-04-05 17:42:10.915976+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	mysite_vbng	t	f			10	\N	\N	GenBank	vm	1	\N	\N	\N	1	1
+3	2016-04-05 17:42:10.958832+00	2016-04-05 17:42:10.958858+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	mysite_volt	t	f			10	\N	\N	GenBank	vm	1	\N	\N	\N	1	1
+4	2016-04-05 17:42:11.112233+00	2016-04-05 17:42:11.112263+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	mysite_clients	t	f			10	\N	\N	GenBank	vm	1	\N	\N	\N	1	1
+5	2016-04-05 17:42:11.127649+00	2016-04-05 17:42:11.127678+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	mysite_onos_vbng	t	f			10	\N	\N	GenBank	vm	1	\N	\N	4	1	1
+6	2016-04-05 17:42:11.167287+00	2016-04-05 17:42:11.167313+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	mysite_onos_volt	t	f			10	\N	\N	GenBank	vm	1	\N	\N	5	1	1
+\.
+
+
+--
+-- Name: core_slice_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_slice_id_seq', 6, true);
+
+
+--
+-- Data for Name: core_slicecredential; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_slicecredential (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, name, key_id, enc_value, slice_id) FROM stdin;
+\.
+
+
+--
+-- Name: core_slicecredential_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_slicecredential_id_seq', 1, false);
+
+
+--
+-- Data for Name: core_sliceprivilege; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_sliceprivilege (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, role_id, slice_id, user_id) FROM stdin;
+\.
+
+
+--
+-- Name: core_sliceprivilege_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_sliceprivilege_id_seq', 1, false);
+
+
+--
+-- Data for Name: core_slicerole; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_slicerole (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, role) FROM stdin;
+1	2015-02-17 22:06:38.778+00	2015-02-17 22:06:38.778+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	admin
+2	2015-02-17 22:06:38.836+00	2015-02-17 22:06:38.836+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	access
+\.
+
+
+--
+-- Name: core_slicerole_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_slicerole_id_seq', 2, true);
+
+
+--
+-- Data for Name: core_slicetag; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_slicetag (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, name, value, slice_id) FROM stdin;
+\.
+
+
+--
+-- Name: core_slicetag_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_slicetag_id_seq', 1, false);
+
+
+--
+-- Data for Name: core_tag; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_tag (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, name, value, object_id, content_type_id, service_id) FROM stdin;
+1	2016-04-05 17:42:11.08141+00	2016-04-05 17:42:11.081432+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	s_tag	222	1	53	2
+\.
+
+
+--
+-- Name: core_tag_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_tag_id_seq', 1, true);
+
+
+--
+-- Data for Name: core_tenant; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_tenant (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, kind, service_specific_id, service_specific_attribute, connect_method, provider_service_id, subscriber_root_id, subscriber_service_id, subscriber_tenant_id, subscriber_user_id) FROM stdin;
+1	2016-04-05 17:42:10.897527+00	2016-04-05 17:42:10.897558+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	coarse	\N	\N	na	1	\N	2	\N	\N
+2	2016-04-05 17:42:10.978184+00	2016-04-05 17:42:10.978207+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	coarse	\N	\N	na	2	\N	3	\N	\N
+3	2016-04-05 17:42:10.995794+00	2016-04-05 17:42:10.995832+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	vOLT	123	{"creator_id": 1, "c_tag": "432", "s_tag": "222"}	na	3	1	\N	\N	\N
+5	2016-04-05 17:42:11.086763+00	2016-04-05 17:42:11.086785+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	vBNG	\N	\N	na	1	\N	\N	4	\N
+6	2016-04-05 17:42:11.224376+00	2016-04-05 17:42:11.22441+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	onos	\N	{"creator_id": 1, "dependencies": "org.onosproject.proxyarp, org.onosproject.virtualbng, org.onosproject.openflow, org.onosproject.fwd", "name": "vBNG_ONOS_app"}	na	4	\N	1	\N	\N
+7	2016-04-05 17:42:11.359136+00	2016-04-05 17:42:11.359169+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	onos	\N	{"creator_id": 1, "dependencies": "org.onosproject.openflow-base, org.onosproject.olt, org.ciena.onos.ext_notifier, org.ciena.onos.volt_event_publisher", "name": "vOLT_ONOS_app", "install_dependencies": "onos-ext-notifier-1.0-SNAPSHOT.oar, onos-ext-volt-event-publisher-1.0-SNAPSHOT.oar"}	na	5	\N	3	\N	\N
+4	2016-04-05 17:42:11.006459+00	2016-04-05 21:11:13.789553+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	vCPE	\N	{"instance_id": 1, "creator_id": 1}	na	2	\N	\N	3	\N
+\.
+
+
+--
+-- Name: core_tenant_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_tenant_id_seq', 7, true);
+
+
+--
+-- Data for Name: core_tenantattribute; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_tenantattribute (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, name, value, tenant_id) FROM stdin;
+1	2016-04-05 17:42:11.232458+00	2016-04-05 17:42:11.23249+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	config_network-cfg.json	{\n  "ports" : {\n    "of:0000000000000001/1" : {\n      "interfaces" : [\n        {\n          "ips"  : [ "10.0.1.253/24" ],\n          "mac"  : "00:00:00:00:00:99"\n        }\n      ]\n    },\n    "of:0000000000000001/2" : {\n      "interfaces" : [\n        {\n          "ips"  : [ "10.254.0.2/24" ],\n          "mac"  : "00:00:00:00:00:98"\n        }\n      ]\n    }\n  }\n}\n	6
+2	2016-04-05 17:42:11.366036+00	2016-04-05 17:42:11.366073+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	component_config	{\n   "org.ciena.onos.ext_notifier.KafkaNotificationBridge":{\n      "rabbit.user": "<rabbit_user>",\n      "rabbit.password": "<rabbit_password>",\n      "rabbit.host": "<rabbit_host>",\n      "publish.rabbit": "true",\n      "volt.events.rabbit.topic": "notifications.info",\n      "volt.events.rabbit.exchange": "voltlistener",\n      "volt.events.opaque.info": "{project_id: <keystone_tenant_id>, user_id: <keystone_user_id>}",\n      "publish.volt.events": "true"\n   }\n}\n	7
+\.
+
+
+--
+-- Name: core_tenantattribute_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_tenantattribute_id_seq', 2, true);
+
+
+--
+-- Data for Name: core_tenantroot; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_tenantroot (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, kind, name, service_specific_attribute, service_specific_id) FROM stdin;
+1	2016-04-05 17:42:10.85283+00	2016-04-05 21:11:13.773087+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	CordSubscriberRoot	My House	{"status": "enabled", "cdn_enable": false, "users": [{"mac": "01:02:03:04:05:06", "level": "PG_13", "id": 0, "name": "Mom's PC"}, {"mac": "34:36:3B:C9:B6:A6", "id": 1, "name": "Jill's Laptop", "level": "PG_13"}, {"mac": "68:5B:35:9D:91:D5", "level": "PG_13", "id": 2, "name": "Jack's Laptop"}, {"mac": "90:E2:BA:82:F9:75", "id": 3, "name": "Dad's PC", "level": "PG_13"}], "downlink_speed": 1000000000, "url_filter_level": "R", "uplink_speed": 1000000000, "enable_uverse": false, "firewall_enable": false, "url_filter_enable": false}	123
+\.
+
+
+--
+-- Name: core_tenantroot_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_tenantroot_id_seq', 1, true);
+
+
+--
+-- Data for Name: core_tenantrootprivilege; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_tenantrootprivilege (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, role_id, tenant_root_id, user_id) FROM stdin;
+1	2016-04-05 17:42:10.864854+00	2016-04-05 17:42:10.864879+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	1	1	2
+\.
+
+
+--
+-- Name: core_tenantrootprivilege_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_tenantrootprivilege_id_seq', 1, true);
+
+
+--
+-- Data for Name: core_tenantrootrole; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_tenantrootrole (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, role) FROM stdin;
+1	2016-04-05 17:42:10.859991+00	2016-04-05 17:42:10.860017+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	admin
+\.
+
+
+--
+-- Name: core_tenantrootrole_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_tenantrootrole_id_seq', 1, true);
+
+
+--
+-- Data for Name: core_usableobject; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_usableobject (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, name) FROM stdin;
+\.
+
+
+--
+-- Name: core_usableobject_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_usableobject_id_seq', 1, false);
+
+
+--
+-- Data for Name: core_user; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_user (id, password, last_login, email, username, firstname, lastname, phone, user_url, public_key, is_active, is_admin, is_staff, is_readonly, is_registering, is_appuser, login_page, created, updated, enacted, policed, backend_status, deleted, write_protect, timezone, site_id) FROM stdin;
+2	pbkdf2_sha256$12000$Oc7yu5OUSNRK$lV5m9OLtVPWAfog5aX0CHYfh4gyLYj1iSvRq+wk8kTk=	2016-04-05 17:42:10.803373+00	johndoe@myhouse.com	johndoe@myhouse.com	john	doe	\N	\N	\N	t	f	t	f	f	f	\N	2016-04-05 17:42:10.844525+00	2016-04-05 17:42:10.844548+00	\N	\N	Provisioning in progress	f	f	America/New_York	1
+1	pbkdf2_sha256$12000$Qufx9iqtaYma$xs0YurPOcj9qYQna/Qrb3K+im9Yr2XEVr0J4Kqek7AE=	2016-04-05 17:42:16.66369+00	padmin@vicci.org	padmin@vicci.org	XOS	admin	\N	\N	\N	t	t	t	f	f	f	\N	2015-02-17 22:06:38.059+00	2016-04-05 17:42:11.387962+00	\N	\N	Provisioning in progress	f	f	America/New_York	1
+\.
+
+
+--
+-- Name: core_user_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_user_id_seq', 2, true);
+
+
+--
+-- Data for Name: core_usercredential; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_usercredential (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, name, key_id, enc_value, user_id) FROM stdin;
+\.
+
+
+--
+-- Name: core_usercredential_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_usercredential_id_seq', 1, false);
+
+
+--
+-- Data for Name: core_userdashboardview; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY core_userdashboardview (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, "order", "dashboardView_id", user_id) FROM stdin;
+2	2016-04-05 18:46:44.099329+00	2016-04-05 18:46:44.099362+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	0	5	1
+3	2016-04-05 18:46:44.101231+00	2016-04-05 18:46:44.101257+00	\N	\N	{}	0 - Provisioning in progress	f	f	f	f	1	6	1
+\.
+
+
+--
+-- Name: core_userdashboardview_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('core_userdashboardview_id_seq', 3, true);
+
+
+--
+-- Data for Name: django_admin_log; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY django_admin_log (id, action_time, object_id, object_repr, action_flag, change_message, content_type_id, user_id) FROM stdin;
+1	2016-04-05 18:46:36.64407+00	6	truckroll	1		29	1
+\.
+
+
+--
+-- Name: django_admin_log_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('django_admin_log_id_seq', 1, true);
+
+
+--
+-- Data for Name: django_content_type; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY django_content_type (id, name, app_label, model) FROM stdin;
+1	permission	auth	permission
+2	group	auth	group
+3	content type	contenttypes	contenttype
+4	session	sessions	session
+5	log entry	admin	logentry
+6	project	core	project
+7	service	core	service
+8	service attribute	core	serviceattribute
+9	service role	core	servicerole
+10	service privilege	core	serviceprivilege
+11	tenant root	core	tenantroot
+12	tenant	core	tenant
+13	tenant attribute	core	tenantattribute
+14	tenant root role	core	tenantrootrole
+15	tenant root privilege	core	tenantrootprivilege
+16	tag	core	tag
+17	role	core	role
+18	site	core	site
+19	site role	core	siterole
+20	site privilege	core	siteprivilege
+21	deployment	core	deployment
+22	deployment role	core	deploymentrole
+23	deployment privilege	core	deploymentprivilege
+24	controller role	core	controllerrole
+25	controller	core	controller
+26	site deployment	core	sitedeployment
+27	controller site	core	controllersite
+28	diag	core	diag
+29	dashboard view	core	dashboardview
+30	controller dashboard view	core	controllerdashboardview
+31	user	core	user
+32	user dashboard view	core	userdashboardview
+33	service class	core	serviceclass
+34	flavor	core	flavor
+35	image	core	image
+36	image deployments	core	imagedeployments
+37	controller images	core	controllerimages
+38	slice	core	slice
+39	slice role	core	slicerole
+40	slice privilege	core	sliceprivilege
+41	controller slice	core	controllerslice
+42	controller user	core	controlleruser
+43	controller site privilege	core	controllersiteprivilege
+44	controller slice privilege	core	controllersliceprivilege
+45	service resource	core	serviceresource
+46	user credential	core	usercredential
+47	site credential	core	sitecredential
+48	slice credential	core	slicecredential
+49	controller credential	core	controllercredential
+50	node	core	node
+51	node label	core	nodelabel
+52	slice tag	core	slicetag
+53	instance	core	instance
+54	reservation	core	reservation
+55	reserved resource	core	reservedresource
+56	network template	core	networktemplate
+57	network	core	network
+58	controller network	core	controllernetwork
+59	network slice	core	networkslice
+60	port	core	port
+61	router	core	router
+62	network parameter type	core	networkparametertype
+63	network parameter	core	networkparameter
+64	address pool	core	addresspool
+65	account	core	account
+66	invoice	core	invoice
+67	usable object	core	usableobject
+68	payment	core	payment
+69	charge	core	charge
+70	program	core	program
+71	subscriber	core	subscriber
+72	provider	core	provider
+73	tenant with container	core	tenantwithcontainer
+74	coarse tenant	core	coarsetenant
+75	HPC Service	hpc	hpcservice
+76	service provider	hpc	serviceprovider
+77	content provider	hpc	contentprovider
+78	origin server	hpc	originserver
+79	cdn prefix	hpc	cdnprefix
+80	access map	hpc	accessmap
+81	site map	hpc	sitemap
+82	hpc health check	hpc	hpchealthcheck
+83	vBNG Service	cord	vbngservice
+84	vsg tenant	cord	vsgtenant
+85	volt tenant	cord	volttenant
+86	vbng tenant	cord	vbngtenant
+87	cord subscriber root	cord	cordsubscriberroot
+88	vOLT Service	cord	voltservice
+89	vSG Service	cord	vsgservice
+92	ONOS Service	onos	onosservice
+93	onos app	onos	onosapp
+94	s flow tenant	ceilometer	sflowtenant
+95	Ceilometer Service	ceilometer	ceilometerservice
+96	sFlow Collection Service	ceilometer	sflowservice
+97	monitoring channel	ceilometer	monitoringchannel
+98	Request Router Service	requestrouter	requestrouterservice
+99	service map	requestrouter	servicemap
+100	Syndicate Service	syndicate_storage	syndicateservice
+101	syndicate principal	syndicate_storage	syndicateprincipal
+102	volume	syndicate_storage	volume
+103	volume access right	syndicate_storage	volumeaccessright
+104	slice secret	syndicate_storage	slicesecret
+105	volume slice	syndicate_storage	volumeslice
+106	vtr tenant	vtr	vtrtenant
+107	vTR Service	vtr	vtrservice
+\.
+
+
+--
+-- Name: django_content_type_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('django_content_type_id_seq', 107, true);
+
+
+--
+-- Data for Name: django_migrations; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY django_migrations (id, app, name, applied) FROM stdin;
+1	contenttypes	0001_initial	2016-04-05 17:41:25.364327+00
+2	core	0001_initial	2016-04-05 17:41:45.947411+00
+3	admin	0001_initial	2016-04-05 17:41:46.336359+00
+4	auth	0001_initial	2016-04-05 17:41:46.384468+00
+5	ceilometer	0001_initial	2016-04-05 17:41:46.659809+00
+6	cord	0001_initial	2016-04-05 17:41:46.862406+00
+8	hpc	0001_initial	2016-04-05 17:41:50.450946+00
+9	onos	0001_initial	2016-04-05 17:41:50.637887+00
+10	requestrouter	0001_initial	2016-04-05 17:41:51.319325+00
+11	sessions	0001_initial	2016-04-05 17:41:51.331342+00
+12	syndicate_storage	0001_initial	2016-04-05 17:41:53.077489+00
+13	vtr	0001_initial	2016-04-05 17:41:53.270146+00
+\.
+
+
+--
+-- Name: django_migrations_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('django_migrations_id_seq', 13, true);
+
+
+--
+-- Data for Name: django_session; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY django_session (session_key, session_data, expire_date) FROM stdin;
+7ppjuoyfejs1zo7q3rn47a6sciqpqjxs	ZTMzOTkxNDYwNzJiZGI4NDdjMTM2YmU1ZDNjNmI2N2Y0NWM2MDdlMTp7Il9hdXRoX3VzZXJfaGFzaCI6IjVkMTdkNWYxYmQxYjNmOTJhMWJiYzc3YzE0NDNlMzNhNDRiNjQ0YzQiLCJhdXRoIjp7InVzZXJuYW1lIjoicGFkbWluQHZpY2NpLm9yZyIsInBhc3N3b3JkIjoibGV0bWVpbiJ9LCJfYXV0aF91c2VyX2JhY2tlbmQiOiJkamFuZ28uY29udHJpYi5hdXRoLmJhY2tlbmRzLk1vZGVsQmFja2VuZCIsIl9hdXRoX3VzZXJfaWQiOjF9	2016-04-19 17:42:16.666323+00
+\.
+
+
+--
+-- Data for Name: hpc_accessmap; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY hpc_accessmap (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, name, description, map, "contentProvider_id") FROM stdin;
+\.
+
+
+--
+-- Name: hpc_accessmap_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('hpc_accessmap_id_seq', 1, false);
+
+
+--
+-- Data for Name: hpc_cdnprefix; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY hpc_cdnprefix (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, cdn_prefix_id, prefix, description, enabled, "contentProvider_id", "defaultOriginServer_id") FROM stdin;
+\.
+
+
+--
+-- Name: hpc_cdnprefix_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('hpc_cdnprefix_id_seq', 1, false);
+
+
+--
+-- Data for Name: hpc_contentprovider; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY hpc_contentprovider (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, content_provider_id, name, enabled, description, "serviceProvider_id") FROM stdin;
+\.
+
+
+--
+-- Name: hpc_contentprovider_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('hpc_contentprovider_id_seq', 1, false);
+
+
+--
+-- Data for Name: hpc_contentprovider_users; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY hpc_contentprovider_users (id, contentprovider_id, user_id) FROM stdin;
+\.
+
+
+--
+-- Name: hpc_contentprovider_users_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('hpc_contentprovider_users_id_seq', 1, false);
+
+
+--
+-- Data for Name: hpc_hpchealthcheck; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY hpc_hpchealthcheck (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, kind, resource_name, result_contains, result_min_size, result_max_size, "hpcService_id") FROM stdin;
+\.
+
+
+--
+-- Name: hpc_hpchealthcheck_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('hpc_hpchealthcheck_id_seq', 1, false);
+
+
+--
+-- Data for Name: hpc_hpcservice; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY hpc_hpcservice (service_ptr_id, cmi_hostname, hpc_port80, watcher_hpc_network, watcher_dnsdemux_network, watcher_dnsredir_network) FROM stdin;
+\.
+
+
+--
+-- Data for Name: hpc_originserver; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY hpc_originserver (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, origin_server_id, url, authenticated, enabled, protocol, redirects, description, "contentProvider_id") FROM stdin;
+\.
+
+
+--
+-- Name: hpc_originserver_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('hpc_originserver_id_seq', 1, false);
+
+
+--
+-- Data for Name: hpc_serviceprovider; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY hpc_serviceprovider (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, service_provider_id, name, description, enabled, "hpcService_id") FROM stdin;
+\.
+
+
+--
+-- Name: hpc_serviceprovider_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('hpc_serviceprovider_id_seq', 1, false);
+
+
+--
+-- Data for Name: hpc_sitemap; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY hpc_sitemap (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, name, description, map, map_id, "cdnPrefix_id", "contentProvider_id", "hpcService_id", "serviceProvider_id") FROM stdin;
+\.
+
+
+--
+-- Name: hpc_sitemap_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('hpc_sitemap_id_seq', 1, false);
+
+
+--
+-- Data for Name: requestrouter_requestrouterservice; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY requestrouter_requestrouterservice (service_ptr_id, "behindNat", "defaultTTL", "defaultAction", "lastResortAction", "maxAnswers") FROM stdin;
+\.
+
+
+--
+-- Data for Name: requestrouter_servicemap; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY requestrouter_servicemap (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, name, prefix, "siteMap", "accessMap", owner_id, slice_id) FROM stdin;
+\.
+
+
+--
+-- Name: requestrouter_servicemap_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('requestrouter_servicemap_id_seq', 1, false);
+
+
+--
+-- Data for Name: syndicate_storage_slicesecret; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY syndicate_storage_slicesecret (id, secret, slice_id_id) FROM stdin;
+\.
+
+
+--
+-- Name: syndicate_storage_slicesecret_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('syndicate_storage_slicesecret_id_seq', 1, false);
+
+
+--
+-- Data for Name: syndicate_storage_syndicateprincipal; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY syndicate_storage_syndicateprincipal (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, principal_id, public_key_pem, sealed_private_key) FROM stdin;
+\.
+
+
+--
+-- Name: syndicate_storage_syndicateprincipal_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('syndicate_storage_syndicateprincipal_id_seq', 1, false);
+
+
+--
+-- Data for Name: syndicate_storage_syndicateservice; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY syndicate_storage_syndicateservice (service_ptr_id) FROM stdin;
+\.
+
+
+--
+-- Data for Name: syndicate_storage_volume; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY syndicate_storage_volume (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, name, description, blocksize, private, archive, cap_read_data, cap_write_data, cap_host_data, owner_id_id) FROM stdin;
+\.
+
+
+--
+-- Name: syndicate_storage_volume_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('syndicate_storage_volume_id_seq', 1, false);
+
+
+--
+-- Data for Name: syndicate_storage_volumeaccessright; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY syndicate_storage_volumeaccessright (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, cap_read_data, cap_write_data, cap_host_data, owner_id_id, volume_id) FROM stdin;
+\.
+
+
+--
+-- Name: syndicate_storage_volumeaccessright_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('syndicate_storage_volumeaccessright_id_seq', 1, false);
+
+
+--
+-- Data for Name: syndicate_storage_volumeslice; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY syndicate_storage_volumeslice (id, created, updated, enacted, policed, backend_register, backend_status, deleted, write_protect, lazy_blocked, no_sync, cap_read_data, cap_write_data, cap_host_data, "UG_portnum", "RG_portnum", credentials_blob, slice_id_id, volume_id_id) FROM stdin;
+\.
+
+
+--
+-- Name: syndicate_storage_volumeslice_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('syndicate_storage_volumeslice_id_seq', 1, false);
+
+
+--
+-- Name: auth_group_name_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY auth_group
+    ADD CONSTRAINT auth_group_name_key UNIQUE (name);
+
+
+--
+-- Name: auth_group_permissions_group_id_permission_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY auth_group_permissions
+    ADD CONSTRAINT auth_group_permissions_group_id_permission_id_key UNIQUE (group_id, permission_id);
+
+
+--
+-- Name: auth_group_permissions_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY auth_group_permissions
+    ADD CONSTRAINT auth_group_permissions_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: auth_group_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY auth_group
+    ADD CONSTRAINT auth_group_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: auth_permission_content_type_id_codename_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY auth_permission
+    ADD CONSTRAINT auth_permission_content_type_id_codename_key UNIQUE (content_type_id, codename);
+
+
+--
+-- Name: auth_permission_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY auth_permission
+    ADD CONSTRAINT auth_permission_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_account_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_account
+    ADD CONSTRAINT core_account_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_addresspool_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_addresspool
+    ADD CONSTRAINT core_addresspool_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_charge_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_charge
+    ADD CONSTRAINT core_charge_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_controller_name_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_controller
+    ADD CONSTRAINT core_controller_name_key UNIQUE (name);
+
+
+--
+-- Name: core_controller_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_controller
+    ADD CONSTRAINT core_controller_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_controllercredential_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_controllercredential
+    ADD CONSTRAINT core_controllercredential_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_controllerdashboardview_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_controllerdashboardview
+    ADD CONSTRAINT core_controllerdashboardview_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_controllerimages_image_id_77d3516dbca0a5d3_uniq; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_controllerimages
+    ADD CONSTRAINT core_controllerimages_image_id_77d3516dbca0a5d3_uniq UNIQUE (image_id, controller_id);
+
+
+--
+-- Name: core_controllerimages_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_controllerimages
+    ADD CONSTRAINT core_controllerimages_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_controllernetwork_network_id_30ce4dc681f2844f_uniq; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_controllernetwork
+    ADD CONSTRAINT core_controllernetwork_network_id_30ce4dc681f2844f_uniq UNIQUE (network_id, controller_id);
+
+
+--
+-- Name: core_controllernetwork_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_controllernetwork
+    ADD CONSTRAINT core_controllernetwork_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_controllerrole_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_controllerrole
+    ADD CONSTRAINT core_controllerrole_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_controllerrole_role_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_controllerrole
+    ADD CONSTRAINT core_controllerrole_role_key UNIQUE (role);
+
+
+--
+-- Name: core_controllersite_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_controllersite
+    ADD CONSTRAINT core_controllersite_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_controllersite_site_id_22f56d79564bc81b_uniq; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_controllersite
+    ADD CONSTRAINT core_controllersite_site_id_22f56d79564bc81b_uniq UNIQUE (site_id, controller_id);
+
+
+--
+-- Name: core_controllersiteprivileg_controller_id_5d0f19c7a7ceb9e5_uniq; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_controllersiteprivilege
+    ADD CONSTRAINT core_controllersiteprivileg_controller_id_5d0f19c7a7ceb9e5_uniq UNIQUE (controller_id, site_privilege_id, role_id);
+
+
+--
+-- Name: core_controllersiteprivilege_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_controllersiteprivilege
+    ADD CONSTRAINT core_controllersiteprivilege_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_controllerslice_controller_id_427703e66574ab83_uniq; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_controllerslice
+    ADD CONSTRAINT core_controllerslice_controller_id_427703e66574ab83_uniq UNIQUE (controller_id, slice_id);
+
+
+--
+-- Name: core_controllerslice_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_controllerslice
+    ADD CONSTRAINT core_controllerslice_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_controllersliceprivile_controller_id_4e8a6f6f999d67c3_uniq; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_controllersliceprivilege
+    ADD CONSTRAINT core_controllersliceprivile_controller_id_4e8a6f6f999d67c3_uniq UNIQUE (controller_id, slice_privilege_id);
+
+
+--
+-- Name: core_controllersliceprivilege_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_controllersliceprivilege
+    ADD CONSTRAINT core_controllersliceprivilege_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_controlleruser_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_controlleruser
+    ADD CONSTRAINT core_controlleruser_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_controlleruser_user_id_3beb039133bd099b_uniq; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_controlleruser
+    ADD CONSTRAINT core_controlleruser_user_id_3beb039133bd099b_uniq UNIQUE (user_id, controller_id);
+
+
+--
+-- Name: core_dashboardview_deployment_dashboardview_id_deployment_i_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_dashboardview_deployments
+    ADD CONSTRAINT core_dashboardview_deployment_dashboardview_id_deployment_i_key UNIQUE (dashboardview_id, deployment_id);
+
+
+--
+-- Name: core_dashboardview_deployments_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_dashboardview_deployments
+    ADD CONSTRAINT core_dashboardview_deployments_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_dashboardview_name_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_dashboardview
+    ADD CONSTRAINT core_dashboardview_name_key UNIQUE (name);
+
+
+--
+-- Name: core_dashboardview_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_dashboardview
+    ADD CONSTRAINT core_dashboardview_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_deployment_name_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_deployment
+    ADD CONSTRAINT core_deployment_name_key UNIQUE (name);
+
+
+--
+-- Name: core_deployment_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_deployment
+    ADD CONSTRAINT core_deployment_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_deploymentprivilege_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_deploymentprivilege
+    ADD CONSTRAINT core_deploymentprivilege_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_deploymentprivilege_user_id_8f49da97c7cff06_uniq; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_deploymentprivilege
+    ADD CONSTRAINT core_deploymentprivilege_user_id_8f49da97c7cff06_uniq UNIQUE (user_id, deployment_id, role_id);
+
+
+--
+-- Name: core_deploymentrole_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_deploymentrole
+    ADD CONSTRAINT core_deploymentrole_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_deploymentrole_role_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_deploymentrole
+    ADD CONSTRAINT core_deploymentrole_role_key UNIQUE (role);
+
+
+--
+-- Name: core_diag_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_diag
+    ADD CONSTRAINT core_diag_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_flavor_deployments_flavor_id_deployment_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_flavor_deployments
+    ADD CONSTRAINT core_flavor_deployments_flavor_id_deployment_id_key UNIQUE (flavor_id, deployment_id);
+
+
+--
+-- Name: core_flavor_deployments_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_flavor_deployments
+    ADD CONSTRAINT core_flavor_deployments_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_flavor_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_flavor
+    ADD CONSTRAINT core_flavor_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_image_name_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_image
+    ADD CONSTRAINT core_image_name_key UNIQUE (name);
+
+
+--
+-- Name: core_image_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_image
+    ADD CONSTRAINT core_image_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_imagedeployments_image_id_3bc8a23925d399ff_uniq; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_imagedeployments
+    ADD CONSTRAINT core_imagedeployments_image_id_3bc8a23925d399ff_uniq UNIQUE (image_id, deployment_id);
+
+
+--
+-- Name: core_imagedeployments_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_imagedeployments
+    ADD CONSTRAINT core_imagedeployments_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_instance_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_instance
+    ADD CONSTRAINT core_instance_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_invoice_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_invoice
+    ADD CONSTRAINT core_invoice_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_network_permitted_slices_network_id_slice_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_network_permitted_slices
+    ADD CONSTRAINT core_network_permitted_slices_network_id_slice_id_key UNIQUE (network_id, slice_id);
+
+
+--
+-- Name: core_network_permitted_slices_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_network_permitted_slices
+    ADD CONSTRAINT core_network_permitted_slices_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_network_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_network
+    ADD CONSTRAINT core_network_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_networkparameter_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_networkparameter
+    ADD CONSTRAINT core_networkparameter_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_networkparametertype_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_networkparametertype
+    ADD CONSTRAINT core_networkparametertype_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_networkslice_network_id_78984d02ac7c1fb3_uniq; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_networkslice
+    ADD CONSTRAINT core_networkslice_network_id_78984d02ac7c1fb3_uniq UNIQUE (network_id, slice_id);
+
+
+--
+-- Name: core_networkslice_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_networkslice
+    ADD CONSTRAINT core_networkslice_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_networktemplate_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_networktemplate
+    ADD CONSTRAINT core_networktemplate_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_node_name_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_node
+    ADD CONSTRAINT core_node_name_key UNIQUE (name);
+
+
+--
+-- Name: core_node_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_node
+    ADD CONSTRAINT core_node_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_nodelabel_name_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_nodelabel
+    ADD CONSTRAINT core_nodelabel_name_key UNIQUE (name);
+
+
+--
+-- Name: core_nodelabel_node_nodelabel_id_node_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_nodelabel_node
+    ADD CONSTRAINT core_nodelabel_node_nodelabel_id_node_id_key UNIQUE (nodelabel_id, node_id);
+
+
+--
+-- Name: core_nodelabel_node_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_nodelabel_node
+    ADD CONSTRAINT core_nodelabel_node_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_nodelabel_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_nodelabel
+    ADD CONSTRAINT core_nodelabel_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_payment_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_payment
+    ADD CONSTRAINT core_payment_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_port_network_id_693ab091ccd5a89a_uniq; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_port
+    ADD CONSTRAINT core_port_network_id_693ab091ccd5a89a_uniq UNIQUE (network_id, instance_id);
+
+
+--
+-- Name: core_port_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_port
+    ADD CONSTRAINT core_port_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_program_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_program
+    ADD CONSTRAINT core_program_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_project_name_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_project
+    ADD CONSTRAINT core_project_name_key UNIQUE (name);
+
+
+--
+-- Name: core_project_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_project
+    ADD CONSTRAINT core_project_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_reservation_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_reservation
+    ADD CONSTRAINT core_reservation_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_reservedresource_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_reservedresource
+    ADD CONSTRAINT core_reservedresource_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_role_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_role
+    ADD CONSTRAINT core_role_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_router_networks_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_router_networks
+    ADD CONSTRAINT core_router_networks_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_router_networks_router_id_network_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_router_networks
+    ADD CONSTRAINT core_router_networks_router_id_network_id_key UNIQUE (router_id, network_id);
+
+
+--
+-- Name: core_router_permittedNetworks_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY "core_router_permittedNetworks"
+    ADD CONSTRAINT "core_router_permittedNetworks_pkey" PRIMARY KEY (id);
+
+
+--
+-- Name: core_router_permittedNetworks_router_id_network_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY "core_router_permittedNetworks"
+    ADD CONSTRAINT "core_router_permittedNetworks_router_id_network_id_key" UNIQUE (router_id, network_id);
+
+
+--
+-- Name: core_router_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_router
+    ADD CONSTRAINT core_router_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_service_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_service
+    ADD CONSTRAINT core_service_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_serviceattribute_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_serviceattribute
+    ADD CONSTRAINT core_serviceattribute_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_serviceclass_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_serviceclass
+    ADD CONSTRAINT core_serviceclass_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_serviceclass_upgradeFrom_from_serviceclass_id_to_servi_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY "core_serviceclass_upgradeFrom"
+    ADD CONSTRAINT "core_serviceclass_upgradeFrom_from_serviceclass_id_to_servi_key" UNIQUE (from_serviceclass_id, to_serviceclass_id);
+
+
+--
+-- Name: core_serviceclass_upgradeFrom_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY "core_serviceclass_upgradeFrom"
+    ADD CONSTRAINT "core_serviceclass_upgradeFrom_pkey" PRIMARY KEY (id);
+
+
+--
+-- Name: core_serviceprivilege_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_serviceprivilege
+    ADD CONSTRAINT core_serviceprivilege_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_serviceprivilege_user_id_3e7ef04b1340e86c_uniq; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_serviceprivilege
+    ADD CONSTRAINT core_serviceprivilege_user_id_3e7ef04b1340e86c_uniq UNIQUE (user_id, service_id, role_id);
+
+
+--
+-- Name: core_serviceresource_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_serviceresource
+    ADD CONSTRAINT core_serviceresource_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_servicerole_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_servicerole
+    ADD CONSTRAINT core_servicerole_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_servicerole_role_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_servicerole
+    ADD CONSTRAINT core_servicerole_role_key UNIQUE (role);
+
+
+--
+-- Name: core_site_login_base_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_site
+    ADD CONSTRAINT core_site_login_base_key UNIQUE (login_base);
+
+
+--
+-- Name: core_site_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_site
+    ADD CONSTRAINT core_site_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_sitecredential_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_sitecredential
+    ADD CONSTRAINT core_sitecredential_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_sitedeployment_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_sitedeployment
+    ADD CONSTRAINT core_sitedeployment_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_sitedeployment_site_id_ed533b8a1954fbb_uniq; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_sitedeployment
+    ADD CONSTRAINT core_sitedeployment_site_id_ed533b8a1954fbb_uniq UNIQUE (site_id, deployment_id, controller_id);
+
+
+--
+-- Name: core_siteprivilege_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_siteprivilege
+    ADD CONSTRAINT core_siteprivilege_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_siterole_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_siterole
+    ADD CONSTRAINT core_siterole_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_siterole_role_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_siterole
+    ADD CONSTRAINT core_siterole_role_key UNIQUE (role);
+
+
+--
+-- Name: core_slice_name_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_slice
+    ADD CONSTRAINT core_slice_name_key UNIQUE (name);
+
+
+--
+-- Name: core_slice_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_slice
+    ADD CONSTRAINT core_slice_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_slicecredential_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_slicecredential
+    ADD CONSTRAINT core_slicecredential_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_sliceprivilege_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_sliceprivilege
+    ADD CONSTRAINT core_sliceprivilege_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_sliceprivilege_user_id_6bed734e37df8596_uniq; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_sliceprivilege
+    ADD CONSTRAINT core_sliceprivilege_user_id_6bed734e37df8596_uniq UNIQUE (user_id, slice_id, role_id);
+
+
+--
+-- Name: core_slicerole_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_slicerole
+    ADD CONSTRAINT core_slicerole_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_slicerole_role_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_slicerole
+    ADD CONSTRAINT core_slicerole_role_key UNIQUE (role);
+
+
+--
+-- Name: core_slicetag_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_slicetag
+    ADD CONSTRAINT core_slicetag_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_tag_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_tag
+    ADD CONSTRAINT core_tag_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_tenant_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_tenant
+    ADD CONSTRAINT core_tenant_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_tenantattribute_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_tenantattribute
+    ADD CONSTRAINT core_tenantattribute_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_tenantroot_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_tenantroot
+    ADD CONSTRAINT core_tenantroot_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_tenantrootprivilege_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_tenantrootprivilege
+    ADD CONSTRAINT core_tenantrootprivilege_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_tenantrootprivilege_user_id_2bfebdce70c89f50_uniq; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_tenantrootprivilege
+    ADD CONSTRAINT core_tenantrootprivilege_user_id_2bfebdce70c89f50_uniq UNIQUE (user_id, tenant_root_id, role_id);
+
+
+--
+-- Name: core_tenantrootrole_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_tenantrootrole
+    ADD CONSTRAINT core_tenantrootrole_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_tenantrootrole_role_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_tenantrootrole
+    ADD CONSTRAINT core_tenantrootrole_role_key UNIQUE (role);
+
+
+--
+-- Name: core_usableobject_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_usableobject
+    ADD CONSTRAINT core_usableobject_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_user_email_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_user
+    ADD CONSTRAINT core_user_email_key UNIQUE (email);
+
+
+--
+-- Name: core_user_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_user
+    ADD CONSTRAINT core_user_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_usercredential_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_usercredential
+    ADD CONSTRAINT core_usercredential_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_userdashboardview_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_userdashboardview
+    ADD CONSTRAINT core_userdashboardview_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: django_admin_log_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY django_admin_log
+    ADD CONSTRAINT django_admin_log_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: django_content_type_app_label_45f3b1d93ec8c61c_uniq; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY django_content_type
+    ADD CONSTRAINT django_content_type_app_label_45f3b1d93ec8c61c_uniq UNIQUE (app_label, model);
+
+
+--
+-- Name: django_content_type_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY django_content_type
+    ADD CONSTRAINT django_content_type_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: django_migrations_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY django_migrations
+    ADD CONSTRAINT django_migrations_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: django_session_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY django_session
+    ADD CONSTRAINT django_session_pkey PRIMARY KEY (session_key);
+
+
+--
+-- Name: hpc_accessmap_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY hpc_accessmap
+    ADD CONSTRAINT hpc_accessmap_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: hpc_cdnprefix_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY hpc_cdnprefix
+    ADD CONSTRAINT hpc_cdnprefix_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: hpc_contentprovider_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY hpc_contentprovider
+    ADD CONSTRAINT hpc_contentprovider_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: hpc_contentprovider_users_contentprovider_id_user_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY hpc_contentprovider_users
+    ADD CONSTRAINT hpc_contentprovider_users_contentprovider_id_user_id_key UNIQUE (contentprovider_id, user_id);
+
+
+--
+-- Name: hpc_contentprovider_users_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY hpc_contentprovider_users
+    ADD CONSTRAINT hpc_contentprovider_users_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: hpc_hpchealthcheck_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY hpc_hpchealthcheck
+    ADD CONSTRAINT hpc_hpchealthcheck_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: hpc_hpcservice_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY hpc_hpcservice
+    ADD CONSTRAINT hpc_hpcservice_pkey PRIMARY KEY (service_ptr_id);
+
+
+--
+-- Name: hpc_originserver_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY hpc_originserver
+    ADD CONSTRAINT hpc_originserver_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: hpc_serviceprovider_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY hpc_serviceprovider
+    ADD CONSTRAINT hpc_serviceprovider_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: hpc_sitemap_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY hpc_sitemap
+    ADD CONSTRAINT hpc_sitemap_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: requestrouter_requestrouterservice_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY requestrouter_requestrouterservice
+    ADD CONSTRAINT requestrouter_requestrouterservice_pkey PRIMARY KEY (service_ptr_id);
+
+
+--
+-- Name: requestrouter_servicemap_name_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY requestrouter_servicemap
+    ADD CONSTRAINT requestrouter_servicemap_name_key UNIQUE (name);
+
+
+--
+-- Name: requestrouter_servicemap_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY requestrouter_servicemap
+    ADD CONSTRAINT requestrouter_servicemap_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: syndicate_storage_slicesecret_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY syndicate_storage_slicesecret
+    ADD CONSTRAINT syndicate_storage_slicesecret_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: syndicate_storage_syndicateprincipal_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY syndicate_storage_syndicateprincipal
+    ADD CONSTRAINT syndicate_storage_syndicateprincipal_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: syndicate_storage_syndicateprincipal_principal_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY syndicate_storage_syndicateprincipal
+    ADD CONSTRAINT syndicate_storage_syndicateprincipal_principal_id_key UNIQUE (principal_id);
+
+
+--
+-- Name: syndicate_storage_syndicateservice_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY syndicate_storage_syndicateservice
+    ADD CONSTRAINT syndicate_storage_syndicateservice_pkey PRIMARY KEY (service_ptr_id);
+
+
+--
+-- Name: syndicate_storage_volume_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY syndicate_storage_volume
+    ADD CONSTRAINT syndicate_storage_volume_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: syndicate_storage_volumeaccessright_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY syndicate_storage_volumeaccessright
+    ADD CONSTRAINT syndicate_storage_volumeaccessright_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: syndicate_storage_volumeslice_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY syndicate_storage_volumeslice
+    ADD CONSTRAINT syndicate_storage_volumeslice_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: auth_group_permissions_0e939a4f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX auth_group_permissions_0e939a4f ON auth_group_permissions USING btree (group_id);
+
+
+--
+-- Name: auth_group_permissions_8373b171; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX auth_group_permissions_8373b171 ON auth_group_permissions USING btree (permission_id);
+
+
+--
+-- Name: auth_permission_417f1b1c; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX auth_permission_417f1b1c ON auth_permission USING btree (content_type_id);
+
+
+--
+-- Name: core_account_9365d6e7; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_account_9365d6e7 ON core_account USING btree (site_id);
+
+
+--
+-- Name: core_charge_8a089c2a; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_charge_8a089c2a ON core_charge USING btree (account_id);
+
+
+--
+-- Name: core_charge_af31437c; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_charge_af31437c ON core_charge USING btree (object_id);
+
+
+--
+-- Name: core_charge_be7f3a0f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_charge_be7f3a0f ON core_charge USING btree (slice_id);
+
+
+--
+-- Name: core_charge_f1f5d967; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_charge_f1f5d967 ON core_charge USING btree (invoice_id);
+
+
+--
+-- Name: core_controller_5921cd4f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controller_5921cd4f ON core_controller USING btree (deployment_id);
+
+
+--
+-- Name: core_controllercredential_a31c1112; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controllercredential_a31c1112 ON core_controllercredential USING btree (controller_id);
+
+
+--
+-- Name: core_controllercredential_b068931c; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controllercredential_b068931c ON core_controllercredential USING btree (name);
+
+
+--
+-- Name: core_controllerdashboardview_5da0369f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controllerdashboardview_5da0369f ON core_controllerdashboardview USING btree ("dashboardView_id");
+
+
+--
+-- Name: core_controllerdashboardview_a31c1112; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controllerdashboardview_a31c1112 ON core_controllerdashboardview USING btree (controller_id);
+
+
+--
+-- Name: core_controllerimages_a31c1112; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controllerimages_a31c1112 ON core_controllerimages USING btree (controller_id);
+
+
+--
+-- Name: core_controllerimages_f33175e6; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controllerimages_f33175e6 ON core_controllerimages USING btree (image_id);
+
+
+--
+-- Name: core_controllernetwork_4e19114d; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controllernetwork_4e19114d ON core_controllernetwork USING btree (network_id);
+
+
+--
+-- Name: core_controllernetwork_a31c1112; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controllernetwork_a31c1112 ON core_controllernetwork USING btree (controller_id);
+
+
+--
+-- Name: core_controllersite_38543614; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controllersite_38543614 ON core_controllersite USING btree (tenant_id);
+
+
+--
+-- Name: core_controllersite_9365d6e7; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controllersite_9365d6e7 ON core_controllersite USING btree (site_id);
+
+
+--
+-- Name: core_controllersite_a31c1112; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controllersite_a31c1112 ON core_controllersite USING btree (controller_id);
+
+
+--
+-- Name: core_controllersiteprivilege_28116b8e; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controllersiteprivilege_28116b8e ON core_controllersiteprivilege USING btree (site_privilege_id);
+
+
+--
+-- Name: core_controllersiteprivilege_84566833; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controllersiteprivilege_84566833 ON core_controllersiteprivilege USING btree (role_id);
+
+
+--
+-- Name: core_controllersiteprivilege_a31c1112; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controllersiteprivilege_a31c1112 ON core_controllersiteprivilege USING btree (controller_id);
+
+
+--
+-- Name: core_controllerslice_a31c1112; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controllerslice_a31c1112 ON core_controllerslice USING btree (controller_id);
+
+
+--
+-- Name: core_controllerslice_be7f3a0f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controllerslice_be7f3a0f ON core_controllerslice USING btree (slice_id);
+
+
+--
+-- Name: core_controllersliceprivilege_25740d9a; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controllersliceprivilege_25740d9a ON core_controllersliceprivilege USING btree (slice_privilege_id);
+
+
+--
+-- Name: core_controllersliceprivilege_84566833; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controllersliceprivilege_84566833 ON core_controllersliceprivilege USING btree (role_id);
+
+
+--
+-- Name: core_controllersliceprivilege_a31c1112; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controllersliceprivilege_a31c1112 ON core_controllersliceprivilege USING btree (controller_id);
+
+
+--
+-- Name: core_controlleruser_a31c1112; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controlleruser_a31c1112 ON core_controlleruser USING btree (controller_id);
+
+
+--
+-- Name: core_controlleruser_e8701ad4; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controlleruser_e8701ad4 ON core_controlleruser USING btree (user_id);
+
+
+--
+-- Name: core_dashboardview_deployments_5921cd4f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_dashboardview_deployments_5921cd4f ON core_dashboardview_deployments USING btree (deployment_id);
+
+
+--
+-- Name: core_dashboardview_deployments_79bd56c8; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_dashboardview_deployments_79bd56c8 ON core_dashboardview_deployments USING btree (dashboardview_id);
+
+
+--
+-- Name: core_deploymentprivilege_5921cd4f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_deploymentprivilege_5921cd4f ON core_deploymentprivilege USING btree (deployment_id);
+
+
+--
+-- Name: core_deploymentprivilege_84566833; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_deploymentprivilege_84566833 ON core_deploymentprivilege USING btree (role_id);
+
+
+--
+-- Name: core_deploymentprivilege_e8701ad4; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_deploymentprivilege_e8701ad4 ON core_deploymentprivilege USING btree (user_id);
+
+
+--
+-- Name: core_flavor_deployments_5921cd4f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_flavor_deployments_5921cd4f ON core_flavor_deployments USING btree (deployment_id);
+
+
+--
+-- Name: core_flavor_deployments_dd3f198d; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_flavor_deployments_dd3f198d ON core_flavor_deployments USING btree (flavor_id);
+
+
+--
+-- Name: core_imagedeployments_5921cd4f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_imagedeployments_5921cd4f ON core_imagedeployments USING btree (deployment_id);
+
+
+--
+-- Name: core_imagedeployments_f33175e6; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_imagedeployments_f33175e6 ON core_imagedeployments USING btree (image_id);
+
+
+--
+-- Name: core_instance_3700153c; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_instance_3700153c ON core_instance USING btree (creator_id);
+
+
+--
+-- Name: core_instance_5921cd4f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_instance_5921cd4f ON core_instance USING btree (deployment_id);
+
+
+--
+-- Name: core_instance_6be37982; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_instance_6be37982 ON core_instance USING btree (parent_id);
+
+
+--
+-- Name: core_instance_be7f3a0f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_instance_be7f3a0f ON core_instance USING btree (slice_id);
+
+
+--
+-- Name: core_instance_c693ebc8; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_instance_c693ebc8 ON core_instance USING btree (node_id);
+
+
+--
+-- Name: core_instance_dd3f198d; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_instance_dd3f198d ON core_instance USING btree (flavor_id);
+
+
+--
+-- Name: core_instance_f33175e6; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_instance_f33175e6 ON core_instance USING btree (image_id);
+
+
+--
+-- Name: core_invoice_8a089c2a; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_invoice_8a089c2a ON core_invoice USING btree (account_id);
+
+
+--
+-- Name: core_network_5e7b1936; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_network_5e7b1936 ON core_network USING btree (owner_id);
+
+
+--
+-- Name: core_network_74f53564; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_network_74f53564 ON core_network USING btree (template_id);
+
+
+--
+-- Name: core_network_permitted_slices_4e19114d; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_network_permitted_slices_4e19114d ON core_network_permitted_slices USING btree (network_id);
+
+
+--
+-- Name: core_network_permitted_slices_be7f3a0f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_network_permitted_slices_be7f3a0f ON core_network_permitted_slices USING btree (slice_id);
+
+
+--
+-- Name: core_networkparameter_417f1b1c; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_networkparameter_417f1b1c ON core_networkparameter USING btree (content_type_id);
+
+
+--
+-- Name: core_networkparameter_80740216; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_networkparameter_80740216 ON core_networkparameter USING btree (parameter_id);
+
+
+--
+-- Name: core_networkparametertype_b068931c; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_networkparametertype_b068931c ON core_networkparametertype USING btree (name);
+
+
+--
+-- Name: core_networkslice_4e19114d; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_networkslice_4e19114d ON core_networkslice USING btree (network_id);
+
+
+--
+-- Name: core_networkslice_be7f3a0f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_networkslice_be7f3a0f ON core_networkslice USING btree (slice_id);
+
+
+--
+-- Name: core_node_86aed61a; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_node_86aed61a ON core_node USING btree (site_deployment_id);
+
+
+--
+-- Name: core_node_9365d6e7; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_node_9365d6e7 ON core_node USING btree (site_id);
+
+
+--
+-- Name: core_nodelabel_node_c693ebc8; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_nodelabel_node_c693ebc8 ON core_nodelabel_node USING btree (node_id);
+
+
+--
+-- Name: core_nodelabel_node_dd685172; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_nodelabel_node_dd685172 ON core_nodelabel_node USING btree (nodelabel_id);
+
+
+--
+-- Name: core_payment_8a089c2a; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_payment_8a089c2a ON core_payment USING btree (account_id);
+
+
+--
+-- Name: core_port_4e19114d; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_port_4e19114d ON core_port USING btree (network_id);
+
+
+--
+-- Name: core_port_51afcc4f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_port_51afcc4f ON core_port USING btree (instance_id);
+
+
+--
+-- Name: core_program_5e7b1936; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_program_5e7b1936 ON core_program USING btree (owner_id);
+
+
+--
+-- Name: core_reservation_be7f3a0f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_reservation_be7f3a0f ON core_reservation USING btree (slice_id);
+
+
+--
+-- Name: core_reservedresource_51afcc4f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_reservedresource_51afcc4f ON core_reservedresource USING btree (instance_id);
+
+
+--
+-- Name: core_reservedresource_732beb09; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_reservedresource_732beb09 ON core_reservedresource USING btree ("reservationSet_id");
+
+
+--
+-- Name: core_reservedresource_e2f3ef5b; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_reservedresource_e2f3ef5b ON core_reservedresource USING btree (resource_id);
+
+
+--
+-- Name: core_role_417f1b1c; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_role_417f1b1c ON core_role USING btree (content_type_id);
+
+
+--
+-- Name: core_router_5e7b1936; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_router_5e7b1936 ON core_router USING btree (owner_id);
+
+
+--
+-- Name: core_router_networks_4e19114d; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_router_networks_4e19114d ON core_router_networks USING btree (network_id);
+
+
+--
+-- Name: core_router_networks_52d4f3af; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_router_networks_52d4f3af ON core_router_networks USING btree (router_id);
+
+
+--
+-- Name: core_router_permittednetworks_4e19114d; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_router_permittednetworks_4e19114d ON "core_router_permittedNetworks" USING btree (network_id);
+
+
+--
+-- Name: core_router_permittednetworks_52d4f3af; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_router_permittednetworks_52d4f3af ON "core_router_permittedNetworks" USING btree (router_id);
+
+
+--
+-- Name: core_serviceattribute_b0dc1e29; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_serviceattribute_b0dc1e29 ON core_serviceattribute USING btree (service_id);
+
+
+--
+-- Name: core_serviceclass_upgradefrom_a90aba97; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_serviceclass_upgradefrom_a90aba97 ON "core_serviceclass_upgradeFrom" USING btree (to_serviceclass_id);
+
+
+--
+-- Name: core_serviceclass_upgradefrom_e970e0f1; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_serviceclass_upgradefrom_e970e0f1 ON "core_serviceclass_upgradeFrom" USING btree (from_serviceclass_id);
+
+
+--
+-- Name: core_serviceprivilege_84566833; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_serviceprivilege_84566833 ON core_serviceprivilege USING btree (role_id);
+
+
+--
+-- Name: core_serviceprivilege_b0dc1e29; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_serviceprivilege_b0dc1e29 ON core_serviceprivilege USING btree (service_id);
+
+
+--
+-- Name: core_serviceprivilege_e8701ad4; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_serviceprivilege_e8701ad4 ON core_serviceprivilege USING btree (user_id);
+
+
+--
+-- Name: core_serviceresource_aa578034; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_serviceresource_aa578034 ON core_serviceresource USING btree ("serviceClass_id");
+
+
+--
+-- Name: core_sitecredential_9365d6e7; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_sitecredential_9365d6e7 ON core_sitecredential USING btree (site_id);
+
+
+--
+-- Name: core_sitecredential_b068931c; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_sitecredential_b068931c ON core_sitecredential USING btree (name);
+
+
+--
+-- Name: core_sitedeployment_5921cd4f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_sitedeployment_5921cd4f ON core_sitedeployment USING btree (deployment_id);
+
+
+--
+-- Name: core_sitedeployment_9365d6e7; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_sitedeployment_9365d6e7 ON core_sitedeployment USING btree (site_id);
+
+
+--
+-- Name: core_sitedeployment_a31c1112; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_sitedeployment_a31c1112 ON core_sitedeployment USING btree (controller_id);
+
+
+--
+-- Name: core_siteprivilege_84566833; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_siteprivilege_84566833 ON core_siteprivilege USING btree (role_id);
+
+
+--
+-- Name: core_siteprivilege_9365d6e7; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_siteprivilege_9365d6e7 ON core_siteprivilege USING btree (site_id);
+
+
+--
+-- Name: core_siteprivilege_e8701ad4; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_siteprivilege_e8701ad4 ON core_siteprivilege USING btree (user_id);
+
+
+--
+-- Name: core_slice_3700153c; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_slice_3700153c ON core_slice USING btree (creator_id);
+
+
+--
+-- Name: core_slice_531a000f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_slice_531a000f ON core_slice USING btree (default_flavor_id);
+
+
+--
+-- Name: core_slice_9365d6e7; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_slice_9365d6e7 ON core_slice USING btree (site_id);
+
+
+--
+-- Name: core_slice_a82f732f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_slice_a82f732f ON core_slice USING btree (default_image_id);
+
+
+--
+-- Name: core_slice_aa578034; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_slice_aa578034 ON core_slice USING btree ("serviceClass_id");
+
+
+--
+-- Name: core_slice_b0dc1e29; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_slice_b0dc1e29 ON core_slice USING btree (service_id);
+
+
+--
+-- Name: core_slicecredential_b068931c; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_slicecredential_b068931c ON core_slicecredential USING btree (name);
+
+
+--
+-- Name: core_slicecredential_be7f3a0f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_slicecredential_be7f3a0f ON core_slicecredential USING btree (slice_id);
+
+
+--
+-- Name: core_sliceprivilege_84566833; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_sliceprivilege_84566833 ON core_sliceprivilege USING btree (role_id);
+
+
+--
+-- Name: core_sliceprivilege_be7f3a0f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_sliceprivilege_be7f3a0f ON core_sliceprivilege USING btree (slice_id);
+
+
+--
+-- Name: core_sliceprivilege_e8701ad4; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_sliceprivilege_e8701ad4 ON core_sliceprivilege USING btree (user_id);
+
+
+--
+-- Name: core_slicetag_be7f3a0f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_slicetag_be7f3a0f ON core_slicetag USING btree (slice_id);
+
+
+--
+-- Name: core_tag_417f1b1c; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_tag_417f1b1c ON core_tag USING btree (content_type_id);
+
+
+--
+-- Name: core_tag_b068931c; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_tag_b068931c ON core_tag USING btree (name);
+
+
+--
+-- Name: core_tag_b0dc1e29; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_tag_b0dc1e29 ON core_tag USING btree (service_id);
+
+
+--
+-- Name: core_tenant_6d0512e4; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_tenant_6d0512e4 ON core_tenant USING btree (subscriber_tenant_id);
+
+
+--
+-- Name: core_tenant_a5c60fe7; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_tenant_a5c60fe7 ON core_tenant USING btree (subscriber_service_id);
+
+
+--
+-- Name: core_tenant_d1fbfb28; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_tenant_d1fbfb28 ON core_tenant USING btree (provider_service_id);
+
+
+--
+-- Name: core_tenant_ec8cbfdc; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_tenant_ec8cbfdc ON core_tenant USING btree (subscriber_user_id);
+
+
+--
+-- Name: core_tenant_f687e49c; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_tenant_f687e49c ON core_tenant USING btree (subscriber_root_id);
+
+
+--
+-- Name: core_tenantattribute_38543614; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_tenantattribute_38543614 ON core_tenantattribute USING btree (tenant_id);
+
+
+--
+-- Name: core_tenantrootprivilege_84566833; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_tenantrootprivilege_84566833 ON core_tenantrootprivilege USING btree (role_id);
+
+
+--
+-- Name: core_tenantrootprivilege_ad876f96; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_tenantrootprivilege_ad876f96 ON core_tenantrootprivilege USING btree (tenant_root_id);
+
+
+--
+-- Name: core_tenantrootprivilege_e8701ad4; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_tenantrootprivilege_e8701ad4 ON core_tenantrootprivilege USING btree (user_id);
+
+
+--
+-- Name: core_user_9365d6e7; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_user_9365d6e7 ON core_user USING btree (site_id);
+
+
+--
+-- Name: core_usercredential_b068931c; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_usercredential_b068931c ON core_usercredential USING btree (name);
+
+
+--
+-- Name: core_usercredential_e8701ad4; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_usercredential_e8701ad4 ON core_usercredential USING btree (user_id);
+
+
+--
+-- Name: core_userdashboardview_5da0369f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_userdashboardview_5da0369f ON core_userdashboardview USING btree ("dashboardView_id");
+
+
+--
+-- Name: core_userdashboardview_e8701ad4; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_userdashboardview_e8701ad4 ON core_userdashboardview USING btree (user_id);
+
+
+--
+-- Name: django_admin_log_417f1b1c; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX django_admin_log_417f1b1c ON django_admin_log USING btree (content_type_id);
+
+
+--
+-- Name: django_admin_log_e8701ad4; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX django_admin_log_e8701ad4 ON django_admin_log USING btree (user_id);
+
+
+--
+-- Name: django_session_de54fa62; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX django_session_de54fa62 ON django_session USING btree (expire_date);
+
+
+--
+-- Name: hpc_accessmap_bc4912a0; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX hpc_accessmap_bc4912a0 ON hpc_accessmap USING btree ("contentProvider_id");
+
+
+--
+-- Name: hpc_cdnprefix_8473b38b; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX hpc_cdnprefix_8473b38b ON hpc_cdnprefix USING btree ("defaultOriginServer_id");
+
+
+--
+-- Name: hpc_cdnprefix_bc4912a0; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX hpc_cdnprefix_bc4912a0 ON hpc_cdnprefix USING btree ("contentProvider_id");
+
+
+--
+-- Name: hpc_contentprovider_ebdbc659; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX hpc_contentprovider_ebdbc659 ON hpc_contentprovider USING btree ("serviceProvider_id");
+
+
+--
+-- Name: hpc_contentprovider_users_82c06917; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX hpc_contentprovider_users_82c06917 ON hpc_contentprovider_users USING btree (contentprovider_id);
+
+
+--
+-- Name: hpc_contentprovider_users_e8701ad4; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX hpc_contentprovider_users_e8701ad4 ON hpc_contentprovider_users USING btree (user_id);
+
+
+--
+-- Name: hpc_hpchealthcheck_591847bf; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX hpc_hpchealthcheck_591847bf ON hpc_hpchealthcheck USING btree ("hpcService_id");
+
+
+--
+-- Name: hpc_originserver_bc4912a0; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX hpc_originserver_bc4912a0 ON hpc_originserver USING btree ("contentProvider_id");
+
+
+--
+-- Name: hpc_serviceprovider_591847bf; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX hpc_serviceprovider_591847bf ON hpc_serviceprovider USING btree ("hpcService_id");
+
+
+--
+-- Name: hpc_sitemap_23b3ec8f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX hpc_sitemap_23b3ec8f ON hpc_sitemap USING btree ("cdnPrefix_id");
+
+
+--
+-- Name: hpc_sitemap_591847bf; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX hpc_sitemap_591847bf ON hpc_sitemap USING btree ("hpcService_id");
+
+
+--
+-- Name: hpc_sitemap_bc4912a0; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX hpc_sitemap_bc4912a0 ON hpc_sitemap USING btree ("contentProvider_id");
+
+
+--
+-- Name: hpc_sitemap_ebdbc659; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX hpc_sitemap_ebdbc659 ON hpc_sitemap USING btree ("serviceProvider_id");
+
+
+--
+-- Name: requestrouter_servicemap_5e7b1936; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX requestrouter_servicemap_5e7b1936 ON requestrouter_servicemap USING btree (owner_id);
+
+
+--
+-- Name: requestrouter_servicemap_be7f3a0f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX requestrouter_servicemap_be7f3a0f ON requestrouter_servicemap USING btree (slice_id);
+
+
+--
+-- Name: syndicate_storage_slicesecret_b717f5ab; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX syndicate_storage_slicesecret_b717f5ab ON syndicate_storage_slicesecret USING btree (slice_id_id);
+
+
+--
+-- Name: syndicate_storage_volume_279564bf; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX syndicate_storage_volume_279564bf ON syndicate_storage_volume USING btree (owner_id_id);
+
+
+--
+-- Name: syndicate_storage_volumeaccessright_279564bf; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX syndicate_storage_volumeaccessright_279564bf ON syndicate_storage_volumeaccessright USING btree (owner_id_id);
+
+
+--
+-- Name: syndicate_storage_volumeaccessright_654102bb; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX syndicate_storage_volumeaccessright_654102bb ON syndicate_storage_volumeaccessright USING btree (volume_id);
+
+
+--
+-- Name: syndicate_storage_volumeslice_5b591651; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX syndicate_storage_volumeslice_5b591651 ON syndicate_storage_volumeslice USING btree (volume_id_id);
+
+
+--
+-- Name: syndicate_storage_volumeslice_b717f5ab; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX syndicate_storage_volumeslice_b717f5ab ON syndicate_storage_volumeslice USING btree (slice_id_id);
+
+
+--
+-- Name: auth_content_type_id_508cf46651277a81_fk_django_content_type_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY auth_permission
+    ADD CONSTRAINT auth_content_type_id_508cf46651277a81_fk_django_content_type_id FOREIGN KEY (content_type_id) REFERENCES django_content_type(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: auth_group_permissio_group_id_689710a9a73b7457_fk_auth_group_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY auth_group_permissions
+    ADD CONSTRAINT auth_group_permissio_group_id_689710a9a73b7457_fk_auth_group_id FOREIGN KEY (group_id) REFERENCES auth_group(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: auth_group_permission_id_1f49ccbbdc69d2fc_fk_auth_permission_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY auth_group_permissions
+    ADD CONSTRAINT auth_group_permission_id_1f49ccbbdc69d2fc_fk_auth_permission_id FOREIGN KEY (permission_id) REFERENCES auth_permission(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: b8a90faf34a5dd47a7f1e2f88e99f8a2; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_hpchealthcheck
+    ADD CONSTRAINT b8a90faf34a5dd47a7f1e2f88e99f8a2 FOREIGN KEY ("hpcService_id") REFERENCES hpc_hpcservice(service_ptr_id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: c_from_serviceclass_id_188a83eaefe26390_fk_core_serviceclass_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY "core_serviceclass_upgradeFrom"
+    ADD CONSTRAINT c_from_serviceclass_id_188a83eaefe26390_fk_core_serviceclass_id FOREIGN KEY (from_serviceclass_id) REFERENCES core_serviceclass(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: c_parameter_id_2c17791ba32bd8c8_fk_core_networkparametertype_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_networkparameter
+    ADD CONSTRAINT c_parameter_id_2c17791ba32bd8c8_fk_core_networkparametertype_id FOREIGN KEY (parameter_id) REFERENCES core_networkparametertype(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: c_site_deployment_id_2dc763428bdc2781_fk_core_sitedeployment_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_node
+    ADD CONSTRAINT c_site_deployment_id_2dc763428bdc2781_fk_core_sitedeployment_id FOREIGN KEY (site_deployment_id) REFERENCES core_sitedeployment(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: co_slice_privilege_id_21402f4f2399079_fk_core_sliceprivilege_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllersliceprivilege
+    ADD CONSTRAINT co_slice_privilege_id_21402f4f2399079_fk_core_sliceprivilege_id FOREIGN KEY (slice_privilege_id) REFERENCES core_sliceprivilege(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: cor_site_privilege_id_41490e8c05c2e685_fk_core_siteprivilege_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllersiteprivilege
+    ADD CONSTRAINT cor_site_privilege_id_41490e8c05c2e685_fk_core_siteprivilege_id FOREIGN KEY (site_privilege_id) REFERENCES core_siteprivilege(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: cor_to_serviceclass_id_4e2748248647c43b_fk_core_serviceclass_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY "core_serviceclass_upgradeFrom"
+    ADD CONSTRAINT cor_to_serviceclass_id_4e2748248647c43b_fk_core_serviceclass_id FOREIGN KEY (to_serviceclass_id) REFERENCES core_serviceclass(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core__reservationset_id_395058233c59a671_fk_core_reservation_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_reservedresource
+    ADD CONSTRAINT core__reservationset_id_395058233c59a671_fk_core_reservation_id FOREIGN KEY ("reservationSet_id") REFERENCES core_reservation(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core__subscriber_root_id_26f21610cb2711f9_fk_core_tenantroot_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_tenant
+    ADD CONSTRAINT core__subscriber_root_id_26f21610cb2711f9_fk_core_tenantroot_id FOREIGN KEY (subscriber_root_id) REFERENCES core_tenantroot(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core__subscriber_service_id_5049d522dc2feae7_fk_core_service_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_tenant
+    ADD CONSTRAINT core__subscriber_service_id_5049d522dc2feae7_fk_core_service_id FOREIGN KEY (subscriber_service_id) REFERENCES core_service(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_account_site_id_7d8af010f408acb2_fk_core_site_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_account
+    ADD CONSTRAINT core_account_site_id_7d8af010f408acb2_fk_core_site_id FOREIGN KEY (site_id) REFERENCES core_site(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_charge_account_id_277c66c32427fb_fk_core_account_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_charge
+    ADD CONSTRAINT core_charge_account_id_277c66c32427fb_fk_core_account_id FOREIGN KEY (account_id) REFERENCES core_account(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_charge_invoice_id_7af39adf58aad977_fk_core_invoice_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_charge
+    ADD CONSTRAINT core_charge_invoice_id_7af39adf58aad977_fk_core_invoice_id FOREIGN KEY (invoice_id) REFERENCES core_invoice(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_charge_object_id_349f8834f1bf5ce6_fk_core_usableobject_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_charge
+    ADD CONSTRAINT core_charge_object_id_349f8834f1bf5ce6_fk_core_usableobject_id FOREIGN KEY (object_id) REFERENCES core_usableobject(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_charge_slice_id_5f33de3b320604f2_fk_core_slice_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_charge
+    ADD CONSTRAINT core_charge_slice_id_5f33de3b320604f2_fk_core_slice_id FOREIGN KEY (slice_id) REFERENCES core_slice(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_content_type_id_150a10ada282bcf9_fk_django_content_type_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_role
+    ADD CONSTRAINT core_content_type_id_150a10ada282bcf9_fk_django_content_type_id FOREIGN KEY (content_type_id) REFERENCES django_content_type(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_content_type_id_3cc30601489a3056_fk_django_content_type_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_networkparameter
+    ADD CONSTRAINT core_content_type_id_3cc30601489a3056_fk_django_content_type_id FOREIGN KEY (content_type_id) REFERENCES django_content_type(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_content_type_id_413c7b5400f8ad9c_fk_django_content_type_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_tag
+    ADD CONSTRAINT core_content_type_id_413c7b5400f8ad9c_fk_django_content_type_id FOREIGN KEY (content_type_id) REFERENCES django_content_type(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_contr_controller_id_11d29f7e2a4a5462_fk_core_controller_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllersiteprivilege
+    ADD CONSTRAINT core_contr_controller_id_11d29f7e2a4a5462_fk_core_controller_id FOREIGN KEY (controller_id) REFERENCES core_controller(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_contr_controller_id_1f82c3216437715f_fk_core_controller_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllerdashboardview
+    ADD CONSTRAINT core_contr_controller_id_1f82c3216437715f_fk_core_controller_id FOREIGN KEY (controller_id) REFERENCES core_controller(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_contr_controller_id_46178c1d21384e5e_fk_core_controller_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllersite
+    ADD CONSTRAINT core_contr_controller_id_46178c1d21384e5e_fk_core_controller_id FOREIGN KEY (controller_id) REFERENCES core_controller(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_contr_controller_id_4fb982de67c3b742_fk_core_controller_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllersliceprivilege
+    ADD CONSTRAINT core_contr_controller_id_4fb982de67c3b742_fk_core_controller_id FOREIGN KEY (controller_id) REFERENCES core_controller(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_contr_controller_id_5cd05d37bbdf1d96_fk_core_controller_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controlleruser
+    ADD CONSTRAINT core_contr_controller_id_5cd05d37bbdf1d96_fk_core_controller_id FOREIGN KEY (controller_id) REFERENCES core_controller(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_contr_controller_id_60b467e792b15198_fk_core_controller_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllernetwork
+    ADD CONSTRAINT core_contr_controller_id_60b467e792b15198_fk_core_controller_id FOREIGN KEY (controller_id) REFERENCES core_controller(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_contr_controller_id_7095bdbd27f73f56_fk_core_controller_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllerslice
+    ADD CONSTRAINT core_contr_controller_id_7095bdbd27f73f56_fk_core_controller_id FOREIGN KEY (controller_id) REFERENCES core_controller(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_contr_deployment_id_772a055c58b6e43a_fk_core_deployment_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controller
+    ADD CONSTRAINT core_contr_deployment_id_772a055c58b6e43a_fk_core_deployment_id FOREIGN KEY (deployment_id) REFERENCES core_deployment(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_contro_controller_id_5906172a2f34d3a_fk_core_controller_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllercredential
+    ADD CONSTRAINT core_contro_controller_id_5906172a2f34d3a_fk_core_controller_id FOREIGN KEY (controller_id) REFERENCES core_controller(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_contro_controller_id_6d1311b7cc69cd7_fk_core_controller_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllerimages
+    ADD CONSTRAINT core_contro_controller_id_6d1311b7cc69cd7_fk_core_controller_id FOREIGN KEY (controller_id) REFERENCES core_controller(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_controllerimage_image_id_5713221a6b077f6b_fk_core_image_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllerimages
+    ADD CONSTRAINT core_controllerimage_image_id_5713221a6b077f6b_fk_core_image_id FOREIGN KEY (image_id) REFERENCES core_image(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_controllern_network_id_3fe7748f6851d06f_fk_core_network_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllernetwork
+    ADD CONSTRAINT core_controllern_network_id_3fe7748f6851d06f_fk_core_network_id FOREIGN KEY (network_id) REFERENCES core_network(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_controllersite_site_id_4fa87f0734a60665_fk_core_site_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllersite
+    ADD CONSTRAINT core_controllersite_site_id_4fa87f0734a60665_fk_core_site_id FOREIGN KEY (site_id) REFERENCES core_site(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_controllerslice_slice_id_7005d287c601356b_fk_core_slice_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllerslice
+    ADD CONSTRAINT core_controllerslice_slice_id_7005d287c601356b_fk_core_slice_id FOREIGN KEY (slice_id) REFERENCES core_slice(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_controlleruser_user_id_60dc3a7220b1005b_fk_core_user_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controlleruser
+    ADD CONSTRAINT core_controlleruser_user_id_60dc3a7220b1005b_fk_core_user_id FOREIGN KEY (user_id) REFERENCES core_user(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_dashbo_deployment_id_8b902dfc7ab128b_fk_core_deployment_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_dashboardview_deployments
+    ADD CONSTRAINT core_dashbo_deployment_id_8b902dfc7ab128b_fk_core_deployment_id FOREIGN KEY (deployment_id) REFERENCES core_deployment(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_dashboardview_id_1241776e11825a15_fk_core_dashboardview_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllerdashboardview
+    ADD CONSTRAINT core_dashboardview_id_1241776e11825a15_fk_core_dashboardview_id FOREIGN KEY ("dashboardView_id") REFERENCES core_dashboardview(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_dashboardview_id_623d5d799346e0f8_fk_core_dashboardview_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_dashboardview_deployments
+    ADD CONSTRAINT core_dashboardview_id_623d5d799346e0f8_fk_core_dashboardview_id FOREIGN KEY (dashboardview_id) REFERENCES core_dashboardview(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_dashboardview_id_7d9723f531eefdde_fk_core_dashboardview_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_userdashboardview
+    ADD CONSTRAINT core_dashboardview_id_7d9723f531eefdde_fk_core_dashboardview_id FOREIGN KEY ("dashboardView_id") REFERENCES core_dashboardview(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_deplo_deployment_id_4606c90fff2e5ecf_fk_core_deployment_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_deploymentprivilege
+    ADD CONSTRAINT core_deplo_deployment_id_4606c90fff2e5ecf_fk_core_deployment_id FOREIGN KEY (deployment_id) REFERENCES core_deployment(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_deploym_role_id_221f61258b29e608_fk_core_deploymentrole_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_deploymentprivilege
+    ADD CONSTRAINT core_deploym_role_id_221f61258b29e608_fk_core_deploymentrole_id FOREIGN KEY (role_id) REFERENCES core_deploymentrole(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_deploymentprivile_user_id_2ac00d41376e2a8d_fk_core_user_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_deploymentprivilege
+    ADD CONSTRAINT core_deploymentprivile_user_id_2ac00d41376e2a8d_fk_core_user_id FOREIGN KEY (user_id) REFERENCES core_user(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_flavo_deployment_id_33af1c761c0497e3_fk_core_deployment_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_flavor_deployments
+    ADD CONSTRAINT core_flavo_deployment_id_33af1c761c0497e3_fk_core_deployment_id FOREIGN KEY (deployment_id) REFERENCES core_deployment(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_flavor_deploy_flavor_id_3e598722be0b3446_fk_core_flavor_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_flavor_deployments
+    ADD CONSTRAINT core_flavor_deploy_flavor_id_3e598722be0b3446_fk_core_flavor_id FOREIGN KEY (flavor_id) REFERENCES core_flavor(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_image_deployment_id_31772dfdcf4b80eb_fk_core_deployment_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_imagedeployments
+    ADD CONSTRAINT core_image_deployment_id_31772dfdcf4b80eb_fk_core_deployment_id FOREIGN KEY (deployment_id) REFERENCES core_deployment(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_imagedeployment_image_id_4a6df22c06603b40_fk_core_image_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_imagedeployments
+    ADD CONSTRAINT core_imagedeployment_image_id_4a6df22c06603b40_fk_core_image_id FOREIGN KEY (image_id) REFERENCES core_image(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_insta_deployment_id_111e2cdd025ec8ef_fk_core_deployment_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_instance
+    ADD CONSTRAINT core_insta_deployment_id_111e2cdd025ec8ef_fk_core_deployment_id FOREIGN KEY (deployment_id) REFERENCES core_deployment(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_instance_creator_id_66a7e8c819d15b29_fk_core_user_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_instance
+    ADD CONSTRAINT core_instance_creator_id_66a7e8c819d15b29_fk_core_user_id FOREIGN KEY (creator_id) REFERENCES core_user(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_instance_flavor_id_61bc3198a5673218_fk_core_flavor_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_instance
+    ADD CONSTRAINT core_instance_flavor_id_61bc3198a5673218_fk_core_flavor_id FOREIGN KEY (flavor_id) REFERENCES core_flavor(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_instance_image_id_5c8c96fe9a61802c_fk_core_image_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_instance
+    ADD CONSTRAINT core_instance_image_id_5c8c96fe9a61802c_fk_core_image_id FOREIGN KEY (image_id) REFERENCES core_image(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_instance_node_id_ae899cb7a62df9a_fk_core_node_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_instance
+    ADD CONSTRAINT core_instance_node_id_ae899cb7a62df9a_fk_core_node_id FOREIGN KEY (node_id) REFERENCES core_node(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_instance_parent_id_20ac3a3c727decb4_fk_core_instance_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_instance
+    ADD CONSTRAINT core_instance_parent_id_20ac3a3c727decb4_fk_core_instance_id FOREIGN KEY (parent_id) REFERENCES core_instance(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_instance_slice_id_2ddcfe06a9e4c985_fk_core_slice_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_instance
+    ADD CONSTRAINT core_instance_slice_id_2ddcfe06a9e4c985_fk_core_slice_id FOREIGN KEY (slice_id) REFERENCES core_slice(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_invoice_account_id_7802a49ab0cec433_fk_core_account_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_invoice
+    ADD CONSTRAINT core_invoice_account_id_7802a49ab0cec433_fk_core_account_id FOREIGN KEY (account_id) REFERENCES core_account(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_ne_template_id_7268a8d58aa4008e_fk_core_networktemplate_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_network
+    ADD CONSTRAINT core_ne_template_id_7268a8d58aa4008e_fk_core_networktemplate_id FOREIGN KEY (template_id) REFERENCES core_networktemplate(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_network_owner_id_1b5a720eac1f1d6c_fk_core_slice_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_network
+    ADD CONSTRAINT core_network_owner_id_1b5a720eac1f1d6c_fk_core_slice_id FOREIGN KEY (owner_id) REFERENCES core_slice(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_network_perm_network_id_79f8a18a0197dd1_fk_core_network_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_network_permitted_slices
+    ADD CONSTRAINT core_network_perm_network_id_79f8a18a0197dd1_fk_core_network_id FOREIGN KEY (network_id) REFERENCES core_network(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_network_permitt_slice_id_7d7e6e1a0b962f45_fk_core_slice_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_network_permitted_slices
+    ADD CONSTRAINT core_network_permitt_slice_id_7d7e6e1a0b962f45_fk_core_slice_id FOREIGN KEY (slice_id) REFERENCES core_slice(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_networkslic_network_id_2823f40a154bc2e6_fk_core_network_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_networkslice
+    ADD CONSTRAINT core_networkslic_network_id_2823f40a154bc2e6_fk_core_network_id FOREIGN KEY (network_id) REFERENCES core_network(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_networkslice_slice_id_801f34a8ab285a0_fk_core_slice_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_networkslice
+    ADD CONSTRAINT core_networkslice_slice_id_801f34a8ab285a0_fk_core_slice_id FOREIGN KEY (slice_id) REFERENCES core_slice(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_node_site_id_28bac05ef1a512ce_fk_core_site_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_node
+    ADD CONSTRAINT core_node_site_id_28bac05ef1a512ce_fk_core_site_id FOREIGN KEY (site_id) REFERENCES core_site(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_nodelab_nodelabel_id_6bbea668080a7ba5_fk_core_nodelabel_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_nodelabel_node
+    ADD CONSTRAINT core_nodelab_nodelabel_id_6bbea668080a7ba5_fk_core_nodelabel_id FOREIGN KEY (nodelabel_id) REFERENCES core_nodelabel(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_nodelabel_node_node_id_b98c651a6265ec0_fk_core_node_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_nodelabel_node
+    ADD CONSTRAINT core_nodelabel_node_node_id_b98c651a6265ec0_fk_core_node_id FOREIGN KEY (node_id) REFERENCES core_node(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_payment_account_id_3cc9ae7e7b925002_fk_core_account_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_payment
+    ADD CONSTRAINT core_payment_account_id_3cc9ae7e7b925002_fk_core_account_id FOREIGN KEY (account_id) REFERENCES core_account(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_port_instance_id_5bdb1ae59ca1dc73_fk_core_instance_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_port
+    ADD CONSTRAINT core_port_instance_id_5bdb1ae59ca1dc73_fk_core_instance_id FOREIGN KEY (instance_id) REFERENCES core_instance(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_port_network_id_655a9dc4ef32f845_fk_core_network_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_port
+    ADD CONSTRAINT core_port_network_id_655a9dc4ef32f845_fk_core_network_id FOREIGN KEY (network_id) REFERENCES core_network(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_program_owner_id_491cb2182952268e_fk_core_user_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_program
+    ADD CONSTRAINT core_program_owner_id_491cb2182952268e_fk_core_user_id FOREIGN KEY (owner_id) REFERENCES core_user(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_re_resource_id_1126f44e743a899d_fk_core_serviceresource_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_reservedresource
+    ADD CONSTRAINT core_re_resource_id_1126f44e743a899d_fk_core_serviceresource_id FOREIGN KEY (resource_id) REFERENCES core_serviceresource(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_reservation_slice_id_4df07726653daed_fk_core_slice_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_reservation
+    ADD CONSTRAINT core_reservation_slice_id_4df07726653daed_fk_core_slice_id FOREIGN KEY (slice_id) REFERENCES core_slice(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_reservedr_instance_id_626caea355f5195e_fk_core_instance_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_reservedresource
+    ADD CONSTRAINT core_reservedr_instance_id_626caea355f5195e_fk_core_instance_id FOREIGN KEY (instance_id) REFERENCES core_instance(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_router_netw_network_id_12bc59c5ca78fdc0_fk_core_network_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_router_networks
+    ADD CONSTRAINT core_router_netw_network_id_12bc59c5ca78fdc0_fk_core_network_id FOREIGN KEY (network_id) REFERENCES core_network(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_router_networ_router_id_3cf4f94bd7970e88_fk_core_router_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_router_networks
+    ADD CONSTRAINT core_router_networ_router_id_3cf4f94bd7970e88_fk_core_router_id FOREIGN KEY (router_id) REFERENCES core_router(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_router_owner_id_13c4ac38c56512c6_fk_core_slice_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_router
+    ADD CONSTRAINT core_router_owner_id_13c4ac38c56512c6_fk_core_slice_id FOREIGN KEY (owner_id) REFERENCES core_slice(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_router_permi_network_id_8ee54284c93cd43_fk_core_network_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY "core_router_permittedNetworks"
+    ADD CONSTRAINT core_router_permi_network_id_8ee54284c93cd43_fk_core_network_id FOREIGN KEY (network_id) REFERENCES core_network(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_router_permit_router_id_3506769cdaf40bb5_fk_core_router_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY "core_router_permittedNetworks"
+    ADD CONSTRAINT core_router_permit_router_id_3506769cdaf40bb5_fk_core_router_id FOREIGN KEY (router_id) REFERENCES core_router(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_s_serviceclass_id_7fa5b55190a88c84_fk_core_serviceclass_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_serviceresource
+    ADD CONSTRAINT core_s_serviceclass_id_7fa5b55190a88c84_fk_core_serviceclass_id FOREIGN KEY ("serviceClass_id") REFERENCES core_serviceclass(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_serviceattr_service_id_5dd88bdc4a289e9e_fk_core_service_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_serviceattribute
+    ADD CONSTRAINT core_serviceattr_service_id_5dd88bdc4a289e9e_fk_core_service_id FOREIGN KEY (service_id) REFERENCES core_service(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_servicepri_role_id_2516e31051d592b9_fk_core_servicerole_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_serviceprivilege
+    ADD CONSTRAINT core_servicepri_role_id_2516e31051d592b9_fk_core_servicerole_id FOREIGN KEY (role_id) REFERENCES core_servicerole(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_servicepriv_service_id_326f2584a82884fb_fk_core_service_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_serviceprivilege
+    ADD CONSTRAINT core_servicepriv_service_id_326f2584a82884fb_fk_core_service_id FOREIGN KEY (service_id) REFERENCES core_service(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_serviceprivilege_user_id_5e78485b5063e04_fk_core_user_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_serviceprivilege
+    ADD CONSTRAINT core_serviceprivilege_user_id_5e78485b5063e04_fk_core_user_id FOREIGN KEY (user_id) REFERENCES core_user(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_sitecredential_site_id_2ede808de256b5ca_fk_core_site_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_sitecredential
+    ADD CONSTRAINT core_sitecredential_site_id_2ede808de256b5ca_fk_core_site_id FOREIGN KEY (site_id) REFERENCES core_site(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_sited_controller_id_30291acda546cff3_fk_core_controller_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_sitedeployment
+    ADD CONSTRAINT core_sited_controller_id_30291acda546cff3_fk_core_controller_id FOREIGN KEY (controller_id) REFERENCES core_controller(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_sited_deployment_id_2073c8bc2ac33aee_fk_core_deployment_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_sitedeployment
+    ADD CONSTRAINT core_sited_deployment_id_2073c8bc2ac33aee_fk_core_deployment_id FOREIGN KEY (deployment_id) REFERENCES core_deployment(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_sitedeployment_site_id_10d760d1d81e2090_fk_core_site_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_sitedeployment
+    ADD CONSTRAINT core_sitedeployment_site_id_10d760d1d81e2090_fk_core_site_id FOREIGN KEY (site_id) REFERENCES core_site(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_siteprivilege_role_id_71e5069ae809cb06_fk_core_siterole_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_siteprivilege
+    ADD CONSTRAINT core_siteprivilege_role_id_71e5069ae809cb06_fk_core_siterole_id FOREIGN KEY (role_id) REFERENCES core_siterole(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_siteprivilege_site_id_33ec92307c1cb3bd_fk_core_site_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_siteprivilege
+    ADD CONSTRAINT core_siteprivilege_site_id_33ec92307c1cb3bd_fk_core_site_id FOREIGN KEY (site_id) REFERENCES core_site(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_siteprivilege_user_id_4a58c40e58eea8c5_fk_core_user_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_siteprivilege
+    ADD CONSTRAINT core_siteprivilege_user_id_4a58c40e58eea8c5_fk_core_user_id FOREIGN KEY (user_id) REFERENCES core_user(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_sl_serviceclass_id_77da7f94b58488b_fk_core_serviceclass_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_slice
+    ADD CONSTRAINT core_sl_serviceclass_id_77da7f94b58488b_fk_core_serviceclass_id FOREIGN KEY ("serviceClass_id") REFERENCES core_serviceclass(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_slice_creator_id_7c5fa82797e0d281_fk_core_user_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_slice
+    ADD CONSTRAINT core_slice_creator_id_7c5fa82797e0d281_fk_core_user_id FOREIGN KEY (creator_id) REFERENCES core_user(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_slice_default_flavor_id_7e9b60d7e92ce276_fk_core_flavor_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_slice
+    ADD CONSTRAINT core_slice_default_flavor_id_7e9b60d7e92ce276_fk_core_flavor_id FOREIGN KEY (default_flavor_id) REFERENCES core_flavor(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_slice_default_image_id_4cc5967fffec96da_fk_core_image_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_slice
+    ADD CONSTRAINT core_slice_default_image_id_4cc5967fffec96da_fk_core_image_id FOREIGN KEY (default_image_id) REFERENCES core_image(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_slice_service_id_56ec7a0b3401bf7c_fk_core_service_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_slice
+    ADD CONSTRAINT core_slice_service_id_56ec7a0b3401bf7c_fk_core_service_id FOREIGN KEY (service_id) REFERENCES core_service(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_slice_site_id_13fe089488dd45_fk_core_site_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_slice
+    ADD CONSTRAINT core_slice_site_id_13fe089488dd45_fk_core_site_id FOREIGN KEY (site_id) REFERENCES core_site(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_slicecredential_slice_id_1c79ffce7dd61f3c_fk_core_slice_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_slicecredential
+    ADD CONSTRAINT core_slicecredential_slice_id_1c79ffce7dd61f3c_fk_core_slice_id FOREIGN KEY (slice_id) REFERENCES core_slice(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_sliceprivile_role_id_1d55e0b0ac43107a_fk_core_slicerole_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_sliceprivilege
+    ADD CONSTRAINT core_sliceprivile_role_id_1d55e0b0ac43107a_fk_core_slicerole_id FOREIGN KEY (role_id) REFERENCES core_slicerole(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_sliceprivilege_slice_id_3fbaadbffeb24835_fk_core_slice_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_sliceprivilege
+    ADD CONSTRAINT core_sliceprivilege_slice_id_3fbaadbffeb24835_fk_core_slice_id FOREIGN KEY (slice_id) REFERENCES core_slice(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_sliceprivilege_user_id_253eeb2ddef0e745_fk_core_user_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_sliceprivilege
+    ADD CONSTRAINT core_sliceprivilege_user_id_253eeb2ddef0e745_fk_core_user_id FOREIGN KEY (user_id) REFERENCES core_user(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_slicetag_slice_id_75dfa2524457256_fk_core_slice_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_slicetag
+    ADD CONSTRAINT core_slicetag_slice_id_75dfa2524457256_fk_core_slice_id FOREIGN KEY (slice_id) REFERENCES core_slice(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_tag_service_id_5e53fc9f784e1c0_fk_core_service_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_tag
+    ADD CONSTRAINT core_tag_service_id_5e53fc9f784e1c0_fk_core_service_id FOREIGN KEY (service_id) REFERENCES core_service(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_te_provider_service_id_6f2ead723387396a_fk_core_service_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_tenant
+    ADD CONSTRAINT core_te_provider_service_id_6f2ead723387396a_fk_core_service_id FOREIGN KEY (provider_service_id) REFERENCES core_service(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_te_subscriber_tenant_id_5c45dc20d190aa0f_fk_core_tenant_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_tenant
+    ADD CONSTRAINT core_te_subscriber_tenant_id_5c45dc20d190aa0f_fk_core_tenant_id FOREIGN KEY (subscriber_tenant_id) REFERENCES core_tenant(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_tena_tenant_root_id_27d6362f903728d9_fk_core_tenantroot_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_tenantrootprivilege
+    ADD CONSTRAINT core_tena_tenant_root_id_27d6362f903728d9_fk_core_tenantroot_id FOREIGN KEY (tenant_root_id) REFERENCES core_tenantroot(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_tenant_subscriber_user_id_2fad15bb074ed3d6_fk_core_user_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_tenant
+    ADD CONSTRAINT core_tenant_subscriber_user_id_2fad15bb074ed3d6_fk_core_user_id FOREIGN KEY (subscriber_user_id) REFERENCES core_user(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_tenantattribut_tenant_id_aef1dc094229bec_fk_core_tenant_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_tenantattribute
+    ADD CONSTRAINT core_tenantattribut_tenant_id_aef1dc094229bec_fk_core_tenant_id FOREIGN KEY (tenant_id) REFERENCES core_tenant(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_tenantro_role_id_56bfa65de5fb299_fk_core_tenantrootrole_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_tenantrootprivilege
+    ADD CONSTRAINT core_tenantro_role_id_56bfa65de5fb299_fk_core_tenantrootrole_id FOREIGN KEY (role_id) REFERENCES core_tenantrootrole(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_tenantrootprivile_user_id_77f85e71ff279b56_fk_core_user_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_tenantrootprivilege
+    ADD CONSTRAINT core_tenantrootprivile_user_id_77f85e71ff279b56_fk_core_user_id FOREIGN KEY (user_id) REFERENCES core_user(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_user_site_id_3cc7d076f7b58a7_fk_core_site_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_user
+    ADD CONSTRAINT core_user_site_id_3cc7d076f7b58a7_fk_core_site_id FOREIGN KEY (site_id) REFERENCES core_site(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_usercredential_user_id_2db1046eae94c01a_fk_core_user_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_usercredential
+    ADD CONSTRAINT core_usercredential_user_id_2db1046eae94c01a_fk_core_user_id FOREIGN KEY (user_id) REFERENCES core_user(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_userdashboardview_user_id_66fac29b72c1b321_fk_core_user_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_userdashboardview
+    ADD CONSTRAINT core_userdashboardview_user_id_66fac29b72c1b321_fk_core_user_id FOREIGN KEY (user_id) REFERENCES core_user(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: d9aeae61481f9ccd18f57c7b51a38461; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_sitemap
+    ADD CONSTRAINT d9aeae61481f9ccd18f57c7b51a38461 FOREIGN KEY ("hpcService_id") REFERENCES hpc_hpcservice(service_ptr_id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: defaultoriginserver_id_3cb657d79e69f1e9_fk_hpc_originserver_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_cdnprefix
+    ADD CONSTRAINT defaultoriginserver_id_3cb657d79e69f1e9_fk_hpc_originserver_id FOREIGN KEY ("defaultOriginServer_id") REFERENCES hpc_originserver(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: djan_content_type_id_697914295151027a_fk_django_content_type_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY django_admin_log
+    ADD CONSTRAINT djan_content_type_id_697914295151027a_fk_django_content_type_id FOREIGN KEY (content_type_id) REFERENCES django_content_type(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: django_admin_log_user_id_52fdd58701c5f563_fk_core_user_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY django_admin_log
+    ADD CONSTRAINT django_admin_log_user_id_52fdd58701c5f563_fk_core_user_id FOREIGN KEY (user_id) REFERENCES core_user(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: ea3ce8ae9fc3a320680647cef82b1a56; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_serviceprovider
+    ADD CONSTRAINT ea3ce8ae9fc3a320680647cef82b1a56 FOREIGN KEY ("hpcService_id") REFERENCES hpc_hpcservice(service_ptr_id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: h_contentprovider_id_1420a46480bb1aff_fk_hpc_contentprovider_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_contentprovider_users
+    ADD CONSTRAINT h_contentprovider_id_1420a46480bb1aff_fk_hpc_contentprovider_id FOREIGN KEY (contentprovider_id) REFERENCES hpc_contentprovider(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: h_contentprovider_id_2f27d5fdbb2459c8_fk_hpc_contentprovider_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_originserver
+    ADD CONSTRAINT h_contentprovider_id_2f27d5fdbb2459c8_fk_hpc_contentprovider_id FOREIGN KEY ("contentProvider_id") REFERENCES hpc_contentprovider(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: h_contentprovider_id_63639a8e6ca8e2cd_fk_hpc_contentprovider_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_cdnprefix
+    ADD CONSTRAINT h_contentprovider_id_63639a8e6ca8e2cd_fk_hpc_contentprovider_id FOREIGN KEY ("contentProvider_id") REFERENCES hpc_contentprovider(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: h_contentprovider_id_7acf72f284b3b30e_fk_hpc_contentprovider_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_accessmap
+    ADD CONSTRAINT h_contentprovider_id_7acf72f284b3b30e_fk_hpc_contentprovider_id FOREIGN KEY ("contentProvider_id") REFERENCES hpc_contentprovider(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: h_serviceprovider_id_1b9fb41a73ac1b6a_fk_hpc_serviceprovider_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_contentprovider
+    ADD CONSTRAINT h_serviceprovider_id_1b9fb41a73ac1b6a_fk_hpc_serviceprovider_id FOREIGN KEY ("serviceProvider_id") REFERENCES hpc_serviceprovider(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: h_serviceprovider_id_788bfbe86c90f205_fk_hpc_serviceprovider_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_sitemap
+    ADD CONSTRAINT h_serviceprovider_id_788bfbe86c90f205_fk_hpc_serviceprovider_id FOREIGN KEY ("serviceProvider_id") REFERENCES hpc_serviceprovider(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: hp_contentprovider_id_2a37a8e8bee9c03_fk_hpc_contentprovider_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_sitemap
+    ADD CONSTRAINT hp_contentprovider_id_2a37a8e8bee9c03_fk_hpc_contentprovider_id FOREIGN KEY ("contentProvider_id") REFERENCES hpc_contentprovider(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: hpc_contentprovider_us_user_id_480a7cd783fecf37_fk_core_user_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_contentprovider_users
+    ADD CONSTRAINT hpc_contentprovider_us_user_id_480a7cd783fecf37_fk_core_user_id FOREIGN KEY (user_id) REFERENCES core_user(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: hpc_hpcservi_service_ptr_id_1b2f328c77b1554d_fk_core_service_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_hpcservice
+    ADD CONSTRAINT hpc_hpcservi_service_ptr_id_1b2f328c77b1554d_fk_core_service_id FOREIGN KEY (service_ptr_id) REFERENCES core_service(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: hpc_sitemap_cdnprefix_id_3c0b2f75c5a9a81e_fk_hpc_cdnprefix_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_sitemap
+    ADD CONSTRAINT hpc_sitemap_cdnprefix_id_3c0b2f75c5a9a81e_fk_hpc_cdnprefix_id FOREIGN KEY ("cdnPrefix_id") REFERENCES hpc_cdnprefix(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: requestroute_service_ptr_id_479451a78740d081_fk_core_service_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY requestrouter_requestrouterservice
+    ADD CONSTRAINT requestroute_service_ptr_id_479451a78740d081_fk_core_service_id FOREIGN KEY (service_ptr_id) REFERENCES core_service(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: requestrouter_serv_owner_id_5c71a9586041d2bc_fk_core_service_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY requestrouter_servicemap
+    ADD CONSTRAINT requestrouter_serv_owner_id_5c71a9586041d2bc_fk_core_service_id FOREIGN KEY (owner_id) REFERENCES core_service(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: requestrouter_servic_slice_id_50e57057a561f22f_fk_core_slice_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY requestrouter_servicemap
+    ADD CONSTRAINT requestrouter_servic_slice_id_50e57057a561f22f_fk_core_slice_id FOREIGN KEY (slice_id) REFERENCES core_slice(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: sy_volume_id_id_7dd16c76bfd7b129_fk_syndicate_storage_volume_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY syndicate_storage_volumeslice
+    ADD CONSTRAINT sy_volume_id_id_7dd16c76bfd7b129_fk_syndicate_storage_volume_id FOREIGN KEY (volume_id_id) REFERENCES syndicate_storage_volume(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: syndi_volume_id_3718f5b02d2245ce_fk_syndicate_storage_volume_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY syndicate_storage_volumeaccessright
+    ADD CONSTRAINT syndi_volume_id_3718f5b02d2245ce_fk_syndicate_storage_volume_id FOREIGN KEY (volume_id) REFERENCES syndicate_storage_volume(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: syndicate_st_service_ptr_id_26ca3aeabed50b6d_fk_core_service_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY syndicate_storage_syndicateservice
+    ADD CONSTRAINT syndicate_st_service_ptr_id_26ca3aeabed50b6d_fk_core_service_id FOREIGN KEY (service_ptr_id) REFERENCES core_service(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: syndicate_storage__owner_id_id_3d3e3d492d6cd6b5_fk_core_user_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY syndicate_storage_volumeaccessright
+    ADD CONSTRAINT syndicate_storage__owner_id_id_3d3e3d492d6cd6b5_fk_core_user_id FOREIGN KEY (owner_id_id) REFERENCES core_user(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: syndicate_storage__owner_id_id_7a99f36bf51f2c78_fk_core_user_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY syndicate_storage_volume
+    ADD CONSTRAINT syndicate_storage__owner_id_id_7a99f36bf51f2c78_fk_core_user_id FOREIGN KEY (owner_id_id) REFERENCES core_user(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: syndicate_storage_slice_id_id_1c80c36535559ad6_fk_core_slice_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY syndicate_storage_slicesecret
+    ADD CONSTRAINT syndicate_storage_slice_id_id_1c80c36535559ad6_fk_core_slice_id FOREIGN KEY (slice_id_id) REFERENCES core_slice(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: syndicate_storage_slice_id_id_36fa39a9ae458538_fk_core_slice_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY syndicate_storage_volumeslice
+    ADD CONSTRAINT syndicate_storage_slice_id_id_36fa39a9ae458538_fk_core_slice_id FOREIGN KEY (slice_id_id) REFERENCES core_slice(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: public; Type: ACL; Schema: -; Owner: postgres
+--
+
+REVOKE ALL ON SCHEMA public FROM PUBLIC;
+REVOKE ALL ON SCHEMA public FROM postgres;
+GRANT ALL ON SCHEMA public TO postgres;
+GRANT ALL ON SCHEMA public TO PUBLIC;
+
+
+--
+-- PostgreSQL database dump complete
+--
+
diff --git a/xos/configurations/frontend/xos.yaml b/xos/configurations/frontend/xos.yaml
new file mode 100644
index 0000000..3153e95
--- /dev/null
+++ b/xos/configurations/frontend/xos.yaml
@@ -0,0 +1,36 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Onboard the exampleservice
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    xos:
+      type: tosca.nodes.XOS
+      properties:
+        ui_port: 9999
+        bootstrap_ui_port: 9998
+        docker_project_name: frontend
+        frontend_only: true
+
+    /opt/xos/xos_configuration/xos_common_config:
+      type: tosca.nodes.XOSVolume
+      properties:
+          host_path: { path_join: [ SELF, CONFIG_DIR, ../common/xos_common_config, ENV_VAR ] }
+          read_only: false
+      requirements:
+          - xos:
+             node: xos
+             relationship: tosca.relationships.UsedByXOS
+
+    /opt/xos/xos_configuration/xos_vtn_config:
+      type: tosca.nodes.XOSVolume
+      properties:
+          host_path: { path_join: [ SELF, CONFIG_DIR, ../vtn/files/xos_vtn_config, ENV_VAR ] }
+          read_only: true
+      requirements:
+          - xos:
+              node: xos
+              relationship: tosca.relationships.UsedByXOS
diff --git a/xos/configurations/mcord/Makefile b/xos/configurations/mcord/Makefile
new file mode 100644
index 0000000..53fec7b
--- /dev/null
+++ b/xos/configurations/mcord/Makefile
@@ -0,0 +1,51 @@
+.PHONY: xos
+xos: nodes.yaml images.yaml
+	sudo docker-compose up -d
+	../common/wait_for_xos_port.sh 8000
+	sudo docker-compose run xos python /opt/xos/tosca/run.py none /opt/xos/configurations/common/fixtures.yaml
+	sudo docker-compose run xos python /opt/xos/tosca/run.py none /opt/xos/configurations/common/mydeployment.yaml
+	sudo docker-compose run xos python /opt/xos/tosca/run.py none /root/setup/setup.yaml
+	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/nodes.yaml
+	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/images.yaml
+	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/mgmt-net.yaml
+	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/mcord.yaml
+	sudo docker exec mcord_xos_1 cp /opt/xos/configurations/mcord/xos_mcord_config /opt/xos/xos_configuration/
+	sudo docker exec mcord_xos_1 touch /opt/xos/xos/settings.py
+
+nodes.yaml:
+	export SETUPDIR=.; bash ../common/make-nodes-yaml.sh
+
+images.yaml:
+	export SETUPDIR=.; bash ../common/make-images-yaml.sh
+
+.PHONY: local_containers
+local_containers:
+	cd ../../../containers/xos; make devel
+	cd ../../../containers/synchronizer; make
+enter-xos:
+	sudo docker exec -it mcord_xos_1 bash
+
+enter-os:
+	sudo docker exec -it mcord_xos_synchronizer_openstack_1 bash
+
+enter-vbbu:
+	sudo docker exec -it mcord_xos_synchronizer_vbbu_1 bash
+
+enter-vpgwc:
+	sudo docker exec -it mcord_xos_synchronizer_vpgwc_1 bash
+
+upgrade_pkgs:
+	sudo pip install httpie --upgrade
+
+rebuild_xos:
+	make -C ../../../containers/xos devel
+
+rebuild_synchronizer:
+	make -C ../../../containers/synchronizer
+
+stop:
+	docker-compose stop
+
+rm:
+	docker-compose stop; docker-compose rm
+
diff --git a/xos/configurations/mcord/docker-compose.yml b/xos/configurations/mcord/docker-compose.yml
new file mode 100644
index 0000000..367b168
--- /dev/null
+++ b/xos/configurations/mcord/docker-compose.yml
@@ -0,0 +1,78 @@
+xos_db:
+    image: xosproject/xos-postgres
+    expose:
+        - "5432"
+
+xos_synchronizer_openstack:
+    command: bash -c "sleep 120; python /opt/xos/synchronizers/openstack/xos-synchronizer.py"
+    image: xosproject/xos-synchronizer-openstack
+    labels:
+        org.xosproject.kind: synchronizer
+        org.xosproject.target: openstack
+    links:
+        - xos_db
+    volumes:
+        - .:/root/setup:ro
+        - ../setup/id_rsa:/opt/xos/configurations/mcord/mcord_private_key:ro  # private key
+    extra_hosts:
+        - "controller:10.102.81.3"
+        - "computeBBU1:10.102.81.6"
+        - "computeBBU2:10.102.81.7"
+        - "compute9:10.102.81.9"
+        - "compute10:10.102.81.10"
+
+xos_synchronizer_vbbu:
+    image: xosproject/xos-synchronizer-openstack
+    command: bash -c "sleep 120; python /opt/xos/synchronizers/vbbu/vbbu-synchronizer.py -C /opt/xos/synchronizers/vbbu/vbbu_config"
+    labels:
+        org.xosproject.kind: synchronizer
+        org.xosproject.target: vbbu 
+    links:
+        - xos_db
+    volumes:
+        - ../setup/id_rsa_mcord:/opt/xos/configurations/mcord/mcord_private_key:ro  # private key
+        - ../setup/id_rsa_mcord.pub:/opt/xos/configurations/mcord/mcord_public_key:ro  # public key
+        - ../setup:/root/setup:ro
+    extra_hosts:
+        - "controller:10.102.81.3"
+        - "computeBBU1:10.102.81.6"
+        - "computeBBU2:10.102.81.7"
+        - "compute9:10.102.81.9"
+        - "compute10:10.102.81.10"
+
+xos_synchronizer_vpgwc:
+    image: xosproject/xos-synchronizer-openstack
+    command: bash -c "sleep 120; python /opt/xos/synchronizers/vpgwc/vpgwc-synchronizer.py -C /opt/xos/synchronizers/vpgwc/vpgwc_config"
+    labels:
+        org.xosproject.kind: synchronizer
+        org.xosproject.target: vpgwc 
+    links:
+        - xos_db
+    volumes:
+        - ../setup/id_rsa_mcord:/opt/xos/configurations/mcord/mcord_private_key:ro  # private key
+        - ../setup/id_rsa_mcord.pub:/opt/xos/configurations/mcord/mcord_public_key:ro  # public key
+        - ../setup:/root/setup:ro
+    extra_hosts:
+        - "controller:10.102.81.3"
+        - "computeBBU1:10.102.81.6"
+        - "computeBBU2:10.102.81.7"
+        - "compute9:10.102.81.9"
+        - "compute10:10.102.81.10"
+
+# FUTURE
+#xos_swarm_synchronizer:
+#    image: xosproject/xos-swarm-synchronizer
+#    labels:
+#        org.xosproject.kind: synchronizer
+#        org.xosproject.target: swarm
+
+xos:
+    command: python /opt/xos/manage.py runserver 0.0.0.0:8000 --insecure --makemigrations
+    image: xosproject/xos
+    links:
+        - xos_db
+    ports:
+        - "8000:8000"
+    volumes:
+        - .:/root/setup:ro
+        - ../setup/id_rsa.pub:/opt/xos/configurations/mcord/mcord_public_key:ro  # private key
diff --git a/xos/configurations/mcord/images.yaml b/xos/configurations/mcord/images.yaml
new file mode 100644
index 0000000..2b62235
--- /dev/null
+++ b/xos/configurations/mcord/images.yaml
@@ -0,0 +1,18 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+imports:
+   - custom_types/xos.yaml
+
+description: autogenerated nodes file
+
+topology_template:
+  node_templates:
+    mysite:
+        type: tosca.nodes.Site
+
+    MyDeployment:
+      type: tosca.nodes.Deployment
+      properties:
+          flavors: m1.large, m1.medium, m1.small
+      requirements:
+
diff --git a/xos/configurations/mcord/mcord.yaml b/xos/configurations/mcord/mcord.yaml
new file mode 100644
index 0000000..450bd23
--- /dev/null
+++ b/xos/configurations/mcord/mcord.yaml
@@ -0,0 +1,332 @@
+tosca_definitions_version: tosca_simple_yaml_1_0

+

+description: Setup MCORD-related services.

+

+imports:

+   - custom_types/xos.yaml

+

+node_types:

+

+    tosca.nodes.MCORDService:

+        derived_from: tosca.nodes.Root

+        description: >

+            An XOS Service object. Services may be listed in the Service

+            directory and may be linked together via Tenancy Relationships.

+        capabilities:

+            scalable:

+                type: tosca.capabilities.Scalable

+            service:

+                type: tosca.capabilities.xos.Service

+        properties:

+            no-delete:

+                type: boolean

+                default: false

+                description: Do not allow Tosca to delete this object

+            no-create:

+                type: boolean

+                default: false

+                description: Do not allow Tosca to create this object

+            no-update:

+                type: boolean

+                default: false

+                description: Do not allow Tosca to update this object

+            kind:

+                type: string

+                default: RAN

+                description: Type of service.

+            view_url:

+                type: string

+                required: false

+                description: URL to follow when icon is clicked in the Service Directory.

+            icon_url:

+                type: string

+                required: false

+                description: ICON to display in the Service Directory.

+            enabled:

+                type: boolean

+                default: true

+            published:

+                type: boolean

+                default: true

+                description: If True then display this Service in the Service Directory.

+            public_key:

+                type: string

+                required: false

+                description: Public key to install into Instances to allows Services to SSH into them.

+            private_key_fn:

+                type: string

+                required: false

+                description: Location of private key file

+            versionNumber:

+                type: string

+                required: false

+                description: Version number of Service.

+

+    tosca.nodes.VBBUComponent:

+        derived_from: tosca.nodes.Root

+        description: >

+            CORD: vBBU Component of MCORD Service.

+        properties:

+            kind:

+                type: string

+                default: RAN 

+                description: Kind of component

+            s1u_tag:

+                type: string

+                required: false

+                default: 901

+                description: VTN stag port-name

+            s1mme_tag:

+                type: string

+                required: false

+                default: 900

+                description: VTN stag port-name

+            rru_tag:

+                type: string

+                required: false

+                default: 999 

+                description: VTN stag port-name

+            display_message:

+                type: string

+                required: false

+                default: New vBBU Component 

+                description: Just a message 

+                

+    tosca.nodes.VPGWCComponent:

+        derived_from: tosca.nodes.Root

+        description: >

+            CORD: vPGWC Component of MCORD Service.

+        properties:

+            kind:

+                type: string

+                default: VPGWC_KIND

+                description: Kind of component

+            s5s8_pgw_tag:

+                type: string

+                required: false

+                default: 300

+                description: VTN stag port-name

+            display_message:

+                type: string

+                required: false

+                default: New vPGWc Component 

+                description: Just a message 

+

+topology_template:

+  node_templates:

+    vBBU:

+      type: tosca.nodes.MCORDService

+      requirements:

+      properties:

+          kind: RAN

+          icon_url: /static/mCordServices/service_server.png

+          view_url: /admin/mcord/vbbucomponent

+          public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }

+          private_key_fn: /opt/xos/configurations/mcord/mcord_private_key

+      artifacts:

+          pubkey: /opt/xos/configurations/mcord/mcord_public_key

+

+    vPGWC:

+      type: tosca.nodes.MCORDService

+      requirements:

+      properties:

+          kind: vEPC

+          icon_url: /static/mCordServices/service_server.png

+          view_url: /admin/mcord/vpgwccomponent

+          public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }

+          private_key_fn: /opt/xos/configurations/mcord/mcord_private_key

+      artifacts:

+          pubkey: /opt/xos/configurations/mcord/mcord_public_key

+

+    m1.xlarge:

+      type: tosca.nodes.Flavor

+

+    Private:

+      type: tosca.nodes.NetworkTemplate

+

+    External:

+      type: tosca.nodes.NetworkTemplate

+

+    management_template:

+      type: tosca.nodes.NetworkTemplate

+      properties:

+          visibility: private

+          translation: none

+

+    management:

+      type: tosca.nodes.network.Network.XOS

+#      properties:

+#          no-create: true

+#          no-delete: true

+#          no-update: true

+

+    lan_3gpp_s1mme_network:

+      type: tosca.nodes.network.Network.XOS

+      properties:

+          ip_version: 4

+          labels: lan_3gpp_s1uc_net

+          cidr: 172.16.1.0/24

+          start_ip: 172.16.1.3

+          end_ip: 172.16.1.12

+          gateway_ip: 172.16.1.1

+      requirements:

+          - network_template:

+              node: External

+              relationship: tosca.relationships.UsesNetworkTemplate

+          - owner:

+              node: mysite_mobile_net

+              relationship: tosca.relationships.MemberOfSlice

+          - connection:

+              node: mysite_vbbu_slice1

+              relationship: tosca.relationships.ConnectsToSlice

+

+    lan_3gpp_s1u_network:

+      type: tosca.nodes.network.Network.XOS

+      properties:

+          ip_version: 4

+          labels: lan_3gpp_s1u_net

+          cidr: 172.16.2.0/24

+          start_ip: 172.16.2.3

+          end_ip: 172.16.2.12

+          gateway_ip: 172.16.16.1

+      requirements:

+          - network_template:

+              node: External

+              relationship: tosca.relationships.UsesNetworkTemplate

+          - owner:

+              node: mysite_mobile_net

+              relationship: tosca.relationships.MemberOfSlice

+          - connection:

+              node: mysite_vbbu_slice1

+              relationship: tosca.relationships.ConnectsToSlice

+

+    lan_rru_network:

+      type: tosca.nodes.network.Network.XOS

+      properties:

+          ip_version: 4

+          labels: lan_rru_net

+          cidr: 172.16.0.0/24

+          start_ip: 172.16.0.3

+          end_ip: 172.16.0.12

+          gateway_ip: 172.16.0.1

+      requirements:

+          - network_template:

+              node: External

+              relationship: tosca.relationships.UsesNetworkTemplate

+          - owner:

+              node: mysite_mobile_net

+              relationship: tosca.relationships.MemberOfSlice

+          - connection:

+              node: mysite_vbbu_slice1

+              relationship: tosca.relationships.ConnectsToSlice

+

+    lan_3gpp_s5s8_pgw_network:

+      type: tosca.nodes.network.Network.XOS

+      properties:

+          ip_version: 4

+          labels: lan_3gpp_s5s8_pgw_net

+          cidr: 172.17.1.0/24

+          start_ip: 172.17.1.2

+          end_ip: 172.17.1.8

+          gateway_ip: 172.17.1.1

+      requirements:

+          - network_template:

+              node: External

+              relationship: tosca.relationships.UsesNetworkTemplate

+          - owner:

+              node: mysite_mobile_net

+              relationship: tosca.relationships.MemberOfSlice

+          - connection:

+              node: mysite_vpgwc_slice1

+              relationship: tosca.relationships.ConnectsToSlice

+

+    mysite:

+      type: tosca.nodes.Site

+

+    mcord-bbu-multi-nic:

+      type: tosca.nodes.Image

+

+    mcord-vpgwc-onos-multi-nic:

+      type: tosca.nodes.Image

+

+    mysite_management:

+      description: This slice exists solely to own the management network

+      type: tosca.nodes.Slice

+      properties:

+          network: noauto

+      requirements:

+          - site:

+              node: mysite

+              relationship: tosca.relationships.MemberOfSite

+

+    mysite_mobile_net:

+      description: This slice exists solely to own the mobile network

+      type: tosca.nodes.Slice

+      properties:

+          network: noauto

+      requirements:

+          - site:

+              node: mysite

+              relationship: tosca.relationships.MemberOfSite

+

+    mysite_vbbu_slice1:

+      description: vBBU Service Slice 1

+      type: tosca.nodes.Slice

+      requirements:

+          - vBBU:

+              node: vBBU

+              relationship: tosca.relationships.MemberOfService

+          - site:

+              node: mysite

+              relationship: tosca.relationships.MemberOfSite

+          - default_image:

+                node: mcord-bbu-multi-nic 

+                relationship: tosca.relationships.DefaultImage

+          - default_flavor:

+                node: m1.xlarge

+                relationship: tosca.relationships.DefaultFlavor

+          - management:

+              node: management

+              relationship: tosca.relationships.ConnectsToNetwork

+      properties:

+          network: noauto

+#          default_flavor: m1.xlarge

+          default_node: computeBBU2 

+

+    mysite_vpgwc_slice1:

+      description: vPGWC Service Slice 1

+      type: tosca.nodes.Slice

+      requirements:

+          - vPGWC:

+              node: vPGWC

+              relationship: tosca.relationships.MemberOfService

+          - site:

+              node: mysite

+              relationship: tosca.relationships.MemberOfSite

+          - default_image:

+                node: mcord-vpgwc-onos-multi-nic 

+                relationship: tosca.relationships.DefaultImage

+          - default_flavor:

+                node: m1.xlarge

+                relationship: tosca.relationships.DefaultFlavor

+          - management:

+              node: management

+              relationship: tosca.relationships.ConnectsToNetwork

+      properties:

+          network: noauto

+          default_node: compute10

+

+    mysite_VPGWC_Component:

+      description: MCORD Service default Component

+      type: tosca.nodes.VPGWCComponent

+      requirements:

+          - provider_service:

+              node: vPGWC

+              relationship: tosca.relationships.MemberOfService

+          - vpgwc_slice:

+              node: mysite_vpgwc_slice1

+              relationship: tosca.relationships.MemberOfSlice

+      properties:

+          display_message: vPGWC looks good!

+          s5s8_pgw_tag: 300

+

diff --git a/xos/configurations/mcord/mgmt-net.yaml b/xos/configurations/mcord/mgmt-net.yaml
new file mode 100644
index 0000000..ac8ad7e
--- /dev/null
+++ b/xos/configurations/mcord/mgmt-net.yaml
@@ -0,0 +1,40 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Set up management network for CORD POD
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+
+    management_template:
+      type: tosca.nodes.NetworkTemplate
+      properties:
+          visibility: private
+          translation: none
+
+    management:
+      type: tosca.nodes.network.Network
+      properties:
+          ip_version: 4
+          cidr: 10.102.83.0/24
+      requirements:
+          - network_template:
+              node: management_template
+              relationship: tosca.relationships.UsesNetworkTemplate
+          - owner:
+              node: mysite_management
+              relationship: tosca.relationships.MemberOfSlice
+
+    mysite:
+      type: tosca.nodes.Site
+
+    mysite_management:
+      description: This slice exists solely to own the management network
+      type: tosca.nodes.Slice
+      properties:
+          network: noauto
+      requirements:
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
diff --git a/xos/configurations/mcord/migrations/0001_initial.py b/xos/configurations/mcord/migrations/0001_initial.py
new file mode 100644
index 0000000..a11fe30
--- /dev/null
+++ b/xos/configurations/mcord/migrations/0001_initial.py
@@ -0,0 +1,44 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('core', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='MCORDService',
+            fields=[
+            ],
+            options={
+                'verbose_name': 'MCORD Service',
+                'proxy': True,
+            },
+            bases=('core.service',),
+        ),
+        migrations.CreateModel(
+            name='VBBUComponent',
+            fields=[
+            ],
+            options={
+                'verbose_name': 'VBBU MCORD Service Component',
+                'proxy': True,
+            },
+            bases=('core.tenantwithcontainer',),
+        ),
+        migrations.CreateModel(
+            name='VPGWCComponent',
+            fields=[
+            ],
+            options={
+                'verbose_name': 'VPGWC MCORD Service Component',
+                'proxy': True,
+            },
+            bases=('core.tenantwithcontainer',),
+        ),
+    ]
diff --git a/xos/configurations/mcord/migrations/__init__.py b/xos/configurations/mcord/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xos/configurations/mcord/migrations/__init__.py
diff --git a/xos/configurations/mcord/nodes.yaml b/xos/configurations/mcord/nodes.yaml
new file mode 100644
index 0000000..48e7247
--- /dev/null
+++ b/xos/configurations/mcord/nodes.yaml
@@ -0,0 +1,44 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+imports:
+   - custom_types/xos.yaml
+
+description: autogenerated nodes file
+
+topology_template:
+  node_templates:
+    MyDeployment:
+        type: tosca.nodes.Deployment
+    mysite:
+        type: tosca.nodes.Site
+
+    computeBBU2:
+        type: tosca.nodes.Node
+        requirements:
+          - site:
+              node: mysite 
+              relationship: tosca.relationships.MemberOfSite
+          - deployment:
+              node: MyDeployment
+              relationship: tosca.relationships.MemberOfDeployment
+
+    nova-compute:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: mysite
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: MyDeployment
+            relationship: tosca.relationships.MemberOfDeployment
+
+    compute10:
+        type: tosca.nodes.Node
+        requirements:
+          - site:
+              node: mysite 
+              relationship: tosca.relationships.MemberOfSite
+          - deployment:
+              node: MyDeployment
+              relationship: tosca.relationships.MemberOfDeployment
+
diff --git a/xos/configurations/mcord/postgresql/Dockerfile b/xos/configurations/mcord/postgresql/Dockerfile
new file mode 100644
index 0000000..4d4ebfd
--- /dev/null
+++ b/xos/configurations/mcord/postgresql/Dockerfile
@@ -0,0 +1,35 @@
+FROM ubuntu
+
+RUN apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys B97B0AFCAA1A47F044F244A07FCC7D46ACCC4CF8
+
+RUN echo "deb http://apt.postgresql.org/pub/repos/apt/ precise-pgdg main" > /etc/apt/sources.list.d/pgdg.list
+
+RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y --force-yes\
+    python-software-properties \
+    software-properties-common \
+    postgresql-9.3 \
+    postgresql-client-9.3 \
+    postgresql-contrib-9.3
+
+# Workaround for AUFS issue
+# https://github.com/docker/docker/issues/783#issuecomment-56013588
+RUN mkdir /etc/ssl/private-copy; mv /etc/ssl/private/* /etc/ssl/private-copy/; rm -r /etc/ssl/private; mv /etc/ssl/private-copy /etc/ssl/private; chmod -R 0700 /etc/ssl/private; chown -R postgres /etc/ssl/private
+
+USER postgres
+
+RUN /etc/init.d/postgresql start && \
+    psql --command "ALTER USER postgres WITH SUPERUSER PASSWORD 'password' " && \
+    psql --command "CREATE DATABASE xos"
+
+# Allow remote connections. 
+RUN echo "host all  all    0.0.0.0/0  md5" >> /etc/postgresql/9.3/main/pg_hba.conf
+RUN echo "host all  all    0.0.0.0/0  password" >> /etc/postgresql/9.3/main/pg_hba.conf
+
+RUN echo "listen_addresses='*'" >> /etc/postgresql/9.3/main/postgresql.conf
+
+# Expose the PostgreSQL port
+EXPOSE 5432
+
+VOLUME  ["/etc/postgresql", "/var/log/postgresql", "/var/lib/postgresql"]
+
+CMD ["/usr/lib/postgresql/9.3/bin/postgres", "-D", "/var/lib/postgresql/9.3/main", "-c", "config_file=/etc/postgresql/9.3/main/postgresql.conf"]
diff --git a/xos/configurations/mcord/postgresql/Makefile b/xos/configurations/mcord/postgresql/Makefile
new file mode 100644
index 0000000..c50923e
--- /dev/null
+++ b/xos/configurations/mcord/postgresql/Makefile
@@ -0,0 +1,25 @@
+IMAGE_NAME:=xosproject/xos-postgres
+CONTAINER_NAME:=xos-db-postgres
+NO_DOCKER_CACHE?=false
+
+.PHONY: build
+build: ; docker build --no-cache=${NO_DOCKER_CACHE} --rm -t ${IMAGE_NAME} .
+
+.PHONY: run
+run: ; docker run -d -p 5432:5432 --name ${CONTAINER_NAME} ${IMAGE_NAME}
+
+.PHONY: stop
+stop: ; docker stop ${CONTAINER_NAME}
+
+.PHONY: rm
+rm: ; docker rm ${CONTAINER_NAME}
+
+.PHONE: rmi
+rmi: ; docker rmi ${IMAGE_NAME}
+
+.PHONY: backup
+backupvol: ; docker run --volumes-from ${CONTAINER_NAME} -v /backup:/backup postgres tar cvf /backup/backup-postgres.tar /var/lib/postgresql
+
+.PHONY: restore
+restorevol: ; docker run --volumes-from ${CONTAINER_NAME} -v /backup:/backup postgres cd /var/lib/postgresql && tar xvf /backup/backup-postgres.tar
+
diff --git a/xos/configurations/mcord/setup.yaml b/xos/configurations/mcord/setup.yaml
new file mode 100644
index 0000000..9db865e
--- /dev/null
+++ b/xos/configurations/mcord/setup.yaml
@@ -0,0 +1,248 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+    * Adds OpenCloud Sites, Deployments, and Controllers.
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+
+    MyDeployment:
+      type: tosca.nodes.Deployment
+      properties:
+          flavors: m1.xlarge, m1.large, m1.medium, m1.small
+
+    m1.xlarge:
+      type: tosca.nodes.Flavor
+
+
+    MyOpenStack:
+      type: tosca.nodes.Controller
+      requirements:
+          - deployment:
+              node: MyDeployment
+              relationship: tosca.relationships.ControllerDeployment
+      properties:
+          backend_type: OpenStack
+          version: Kilo
+          auth_url: { get_script_env: [ SELF, adminrc, OS_AUTH_URL, LOCAL_FILE] }
+          admin_user: { get_script_env: [ SELF, adminrc, OS_USERNAME, LOCAL_FILE] }
+          admin_password: { get_script_env: [ SELF, adminrc, OS_PASSWORD, LOCAL_FILE] }
+          admin_tenant: { get_script_env: [ SELF, adminrc, OS_TENANT_NAME, LOCAL_FILE] }
+          domain: Default
+      artifacts:
+          adminrc: /root/setup/admin-openrc.sh
+
+    mysite:
+      type: tosca.nodes.Site
+      properties:
+          display_name: MySite
+          site_url: http://xosproject.org/
+      requirements:
+          - deployment:
+               node: MyDeployment
+               relationship: tosca.relationships.SiteDeployment
+               requirements:
+                   - controller:
+                       node: MyOpenStack
+                       relationship: tosca.relationships.UsesController
+    Topology:
+      type: tosca.nodes.DashboardView
+      properties:
+          url: template:xosMcordTopology
+
+    # This user already exists in XOS with this password
+    # It's an example of how to create new users
+    padmin@vicci.org:
+      type: tosca.nodes.User
+      properties:
+          is_admin: true
+          is_active: true
+          firstname: XOS
+          lastname: admin
+          password: letmein
+      requirements:
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+          - mcord_dashboard:
+              node: Topology
+              relationship: tosca.relationships.UsesDashboard
+
+    johndoe@stanford.us:
+      type: tosca.nodes.User
+      properties:
+          is_active: true
+          password: letmein
+          firstname: john
+          lastname: doe
+      requirements:
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+    
+    # A subscriber
+    Stanford:
+       type: tosca.nodes.CORDSubscriber
+       properties:
+           service_specific_id: 123
+           firewall_enable: false
+           cdn_enable: false
+           url_filter_enable: false
+           url_filter_level: R
+       requirements:
+          - house_admin:
+              node: johndoe@stanford.us
+              relationship: tosca.relationships.AdminPrivilege
+
+    Barbera Lapinski:
+       type: tosca.nodes.CORDUser
+       properties:
+           mac: 01:02:03:04:05:06
+           level: PG_13
+       requirements:
+           - household:
+               node: Stanford
+               relationship: tosca.relationships.SubscriberDevice
+
+    Norbert Shumway:
+       type: tosca.nodes.CORDUser
+       properties:
+           mac: 90:E2:BA:82:F9:75
+           level: PG_13
+       requirements:
+           - household:
+               node: Stanford
+               relationship: tosca.relationships.SubscriberDevice
+
+    Fay Muldoon:
+       type: tosca.nodes.CORDUser
+       properties:
+           mac: 68:5B:35:9D:91:D5
+           level: PG_13
+       requirements:
+           - household:
+               node: Stanford
+               relationship: tosca.relationships.SubscriberDevice
+
+    Janene Earnest:
+       type: tosca.nodes.CORDUser
+       properties:
+           mac: 34:36:3B:C9:B6:A6
+           level: PG_13
+       requirements:
+           - household:
+               node: Stanford
+               relationship: tosca.relationships.SubscriberDevice
+
+    RRU:
+      type: tosca.nodes.Service
+      properties:
+          view_url: /mcord/?service=vBBU
+          icon_url: /static/mCordServices/service_rru.png
+          kind: RAN
+
+    eSON:
+      type: tosca.nodes.Service
+      properties:
+          icon_url: /static/mCordServices/service_server.png
+          view_url: http://www.google.com
+          kind: RAN
+
+    # EPC
+    vMME:
+      type: tosca.nodes.Service
+      properties:
+          icon_url: /static/mCordServices/service_server.png
+          view_url: /mcord/?service=vMME
+          kind: vEPC
+
+    vSGW:
+      type: tosca.nodes.Service
+      properties:
+          view_url: /mcord/?service=vSGW
+          icon_url: /static/mCordServices/service_server.png
+          kind: vEPC
+
+
+    # EDGE
+    Cache:
+      type: tosca.nodes.Service
+      properties:
+          view_url: /mcord/?service=Cache
+          icon_url: /static/mCordServices/service_cache.png
+          kind: EDGE
+
+    Firewall:
+      type: tosca.nodes.Service
+      properties:
+          view_url: /mcord/?service=Firewall
+          icon_url: /static/mCordServices/service_firewall.png
+          kind: EDGE
+
+    Video Optimization:
+      type: tosca.nodes.Service
+      properties:
+          view_url: /mcord/?service=Video%20Optimization
+          icon_url: /static/mCordServices/service_video.png
+          kind: EDGE
+
+    RRU:
+      type: tosca.nodes.Service
+      properties:
+          view_url: /mcord/?service=vBBU
+          icon_url: /static/mCordServices/service_rru.png
+          kind: RAN
+    eSON:
+      type: tosca.nodes.Service
+      properties:
+          icon_url: /static/mCordServices/service_server.png
+          view_url: http://www.google.com
+          kind: RAN
+
+    # EPC
+    vMME:
+      type: tosca.nodes.Service
+      properties:
+          icon_url: /static/mCordServices/service_server.png
+          view_url: /mcord/?service=vMME
+          kind: vEPC
+
+    vSGW:
+      type: tosca.nodes.Service
+      properties:
+          view_url: /mcord/?service=vSGW
+          icon_url: /static/mCordServices/service_server.png
+          kind: vEPC
+
+    vPGWC:
+      type: tosca.nodes.Service
+      properties:
+          view_url: /mcord/?service=vPGWC
+          icon_url: /static/mCordServices/service_server.png
+          kind: vEPC
+
+    # EDGE
+    Cache:
+      type: tosca.nodes.Service
+      properties:
+          view_url: /mcord/?service=Cache
+          icon_url: /static/mCordServices/service_cache.png
+          kind: EDGE
+
+    Firewall:
+      type: tosca.nodes.Service
+      properties:
+          view_url: /mcord/?service=Firewall
+          icon_url: /static/mCordServices/service_firewall.png
+          kind: EDGE
+
+    Video Optimization:
+      type: tosca.nodes.Service
+      properties:
+          view_url: /mcord/?service=Video%20Optimization
+          icon_url: /static/mCordServices/service_video.png
+          kind: EDGE
+
diff --git a/xos/configurations/mcord/synchronizer/Dockerfile b/xos/configurations/mcord/synchronizer/Dockerfile
new file mode 100644
index 0000000..011e8dd
--- /dev/null
+++ b/xos/configurations/mcord/synchronizer/Dockerfile
@@ -0,0 +1,48 @@
+FROM       xosproject/xos
+
+RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y \
+    openssh-client \
+    python-crypto \
+    python-jinja2 \
+    python-paramiko \
+    python-yaml \
+    python-httplib2 \
+    rsync \
+    supervisor
+
+RUN pip install -U \
+    jinja2
+
+# Install custom Ansible
+RUN \
+    git clone -b release1.8.2 git://github.com/ansible/ansible.git /opt/ansible && \
+    git clone -b release1.8.2 git://github.com/ansible/ansible-modules-extras.git /opt/ansible/lib/ansible/modules/extras && \
+    git clone -b release1.8.2 git://github.com/ansible/ansible-modules-extras.git /opt/ansible/v2/ansible/modules/extras && \
+    git clone git://github.com/sb98052/ansible-modules-core.git /opt/ansible/lib/ansible/modules/core && \
+    git clone git://github.com/sb98052/ansible-modules-core.git /opt/ansible/v2/ansible/modules/core && \
+    # git clone uses cached copy, doesn't pick up latest
+    git -C /opt/ansible pull && \
+    git -C /opt/ansible/lib/ansible/modules/core pull && \
+    git -C /opt/ansible/v2/ansible/modules/core pull
+
+
+# For Observer
+RUN mkdir -p /usr/local/share /bin /etc/ansible
+
+COPY conf/ansible-hosts /etc/ansible/hosts
+
+ADD http://phantomjs.googlecode.com/files/phantomjs-1.7.0-linux-x86_64.tar.bz2 /usr/local/share/
+
+RUN git clone git://git.planet-lab.org/fofum.git /tmp/fofum && \
+    cd /tmp/fofum; python setup.py install && \
+    rm -rf /tmp/fofum && \
+    tar jxvf /usr/local/share/phantomjs-1.7.0-linux-x86_64.tar.bz2 -C /usr/local/share/ && \
+    rm -f /usr/local/share/phantomjs-1.7.0-linux-x86_64.tar.bz2 && \
+    ln -s /usr/local/share/phantomjs-1.7.0-linux-x86_64 /usr/local/share/phantomjs && \
+    ln -s /usr/local/share/phantomjs/bin/phantomjs /bin/phantomjs
+
+
+# Supervisor
+COPY conf/synchronizer.conf /etc/supervisor/conf.d/
+
+CMD update-ca-certificates && /usr/bin/supervisord -c /etc/supervisor/conf.d/synchronizer.conf
diff --git a/xos/configurations/mcord/synchronizer/Makefile b/xos/configurations/mcord/synchronizer/Makefile
new file mode 100644
index 0000000..352616a
--- /dev/null
+++ b/xos/configurations/mcord/synchronizer/Makefile
@@ -0,0 +1,15 @@
+IMAGE_NAME:=xosproject/xos-synchronizer-openstack
+CONTAINER_NAME:=xos-synchronizer
+NO_DOCKER_CACHE?=false
+
+.PHONY: build
+build: ; sudo docker build --no-cache=${NO_DOCKER_CACHE} --rm -t ${IMAGE_NAME} .
+
+.PHONY: run
+run: ; sudo docker run -d --name ${CONTAINER_NAME} -v /usr/local/share/ca-certificates:/usr/local/share/ca-certificates:ro ${IMAGE_NAME}
+
+.PHONY: stop
+stop: ; sudo docker stop ${CONTAINER_NAME}
+
+.PHONY: rm
+rm: ; sudo docker rm ${CONTAINER_NAME}
diff --git a/xos/configurations/mcord/synchronizer/conf/ansible-hosts b/xos/configurations/mcord/synchronizer/conf/ansible-hosts
new file mode 100644
index 0000000..0dd74f1
--- /dev/null
+++ b/xos/configurations/mcord/synchronizer/conf/ansible-hosts
@@ -0,0 +1,2 @@
+[localhost]
+127.0.0.1
diff --git a/xos/configurations/mcord/synchronizer/conf/synchronizer.conf b/xos/configurations/mcord/synchronizer/conf/synchronizer.conf
new file mode 100644
index 0000000..2131a25
--- /dev/null
+++ b/xos/configurations/mcord/synchronizer/conf/synchronizer.conf
@@ -0,0 +1,9 @@
+[supervisord]
+logfile=/var/log/supervisord.log ; (main log file;default $CWD/supervisord.log)
+pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid)
+nodaemon=true
+
+[program:synchronizer]
+command=python /opt/xos/synchronizers/openstack/xos-synchronizer.py
+stderr_logfile=/var/log/supervisor/synchronizer.err.log
+stdout_logfile=/var/log/supervisor/synchronizer.out.log
diff --git a/xos/configurations/mcord/vbbu.yaml b/xos/configurations/mcord/vbbu.yaml
new file mode 100644
index 0000000..ee535e3
--- /dev/null
+++ b/xos/configurations/mcord/vbbu.yaml
@@ -0,0 +1,251 @@
+tosca_definitions_version: tosca_simple_yaml_1_0

+

+description: Setup MCORD-related services.

+

+imports:

+   - custom_types/xos.yaml

+

+node_types:

+

+    tosca.nodes.MCORDService:

+        derived_from: tosca.nodes.Root

+        description: >

+            An XOS Service object. Services may be listed in the Service

+            directory and may be linked together via Tenancy Relationships.

+        capabilities:

+            scalable:

+                type: tosca.capabilities.Scalable

+            service:

+                type: tosca.capabilities.xos.Service

+        properties:

+            no-delete:

+                type: boolean

+                default: false

+                description: Do not allow Tosca to delete this object

+            no-create:

+                type: boolean

+                default: false

+                description: Do not allow Tosca to create this object

+            no-update:

+                type: boolean

+                default: false

+                description: Do not allow Tosca to update this object

+            kind:

+                type: string

+                default: RAN

+                description: Type of service.

+            view_url:

+                type: string

+                required: false

+                description: URL to follow when icon is clicked in the Service Directory.

+            icon_url:

+                type: string

+                required: false

+                description: ICON to display in the Service Directory.

+            enabled:

+                type: boolean

+                default: true

+            published:

+                type: boolean

+                default: true

+                description: If True then display this Service in the Service Directory.

+            public_key:

+                type: string

+                required: false

+                description: Public key to install into Instances to allows Services to SSH into them.

+            private_key_fn:

+                type: string

+                required: false

+                description: Location of private key file

+            versionNumber:

+                type: string

+                required: false

+                description: Version number of Service.

+

+    tosca.nodes.VBBUComponent:

+        derived_from: tosca.nodes.Root

+        description: >

+            CORD: vBBU Component of MCORD Service.

+        properties:

+            kind:

+                type: string

+                default: RAN 

+                description: Kind of component

+            s1u_tag:

+                type: string

+                required: false

+                default: 201

+                description: VTN stag port-name

+            s1mme_tag:

+                type: string

+                required: false

+                default: 200

+                description: VTN stag port-name

+            rru_tag:

+                type: string

+                required: false

+                default: 199 

+                description: VTN stag port-name

+            display_message:

+                type: string

+                required: false

+                default: New vBBU Component 

+                description: Just a message 

+                

+

+topology_template:

+  node_templates:

+    vBBU:

+      type: tosca.nodes.MCORDService

+      requirements:

+      properties:

+          kind: RAN

+          icon_url: /static/mCordServices/service_server.png

+          view_url: /admin/mcord/vbbucomponent

+          public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }

+          private_key_fn: /opt/xos/configurations/mcord/mcord_private_key

+      artifacts:

+          pubkey: /opt/xos/configurations/mcord/mcord_public_key

+

+

+    Private:

+      type: tosca.nodes.NetworkTemplate

+

+    External:

+      type: tosca.nodes.NetworkTemplate

+

+    management_template:

+      type: tosca.nodes.NetworkTemplate

+      properties:

+          visibility: private

+          translation: none

+

+    management:

+      type: tosca.nodes.network.Network.XOS

+#      properties:

+#          no-create: true

+#          no-delete: true

+#          no-update: true

+

+    lan_3gpp_s1mme_network:

+      type: tosca.nodes.network.Network.XOS

+      properties:

+          ip_version: 4

+          labels: lan_3gpp_s1uc_net

+          cidr: 172.16.1.0/24

+          start_ip: 172.16.1.3

+          end_ip: 172.16.1.12

+          gateway_ip: 172.16.1.1

+      requirements:

+          - network_template:

+              node: External

+              relationship: tosca.relationships.UsesNetworkTemplate

+          - owner:

+              node: mysite_mobile_net

+              relationship: tosca.relationships.MemberOfSlice

+          - connection:

+              node: mysite_vbbu_slice1

+              relationship: tosca.relationships.ConnectsToSlice

+

+    lan_3gpp_s1u_network:

+      type: tosca.nodes.network.Network.XOS

+      properties:

+          ip_version: 4

+          labels: lan_3gpp_s1u_net

+          cidr: 172.16.2.0/24

+          start_ip: 172.16.2.3

+          end_ip: 172.16.2.12

+          gateway_ip: 172.16.16.1

+      requirements:

+          - network_template:

+              node: External

+              relationship: tosca.relationships.UsesNetworkTemplate

+          - owner:

+              node: mysite_mobile_net

+              relationship: tosca.relationships.MemberOfSlice

+          - connection:

+              node: mysite_vbbu_slice1

+              relationship: tosca.relationships.ConnectsToSlice

+

+    lan_rru_network:

+      type: tosca.nodes.network.Network.XOS

+      properties:

+          ip_version: 4

+          labels: lan_rru_net

+          cidr: 172.16.0.0/24

+          start_ip: 172.16.0.3

+          end_ip: 172.16.0.12

+          gateway_ip: 172.16.0.1

+      requirements:

+          - network_template:

+              node: External

+              relationship: tosca.relationships.UsesNetworkTemplate

+          - owner:

+              node: mysite_mobile_net

+              relationship: tosca.relationships.MemberOfSlice

+          - connection:

+              node: mysite_vbbu_slice1

+              relationship: tosca.relationships.ConnectsToSlice

+

+    mysite:

+      type: tosca.nodes.Site

+

+    mcord-bbu-multi-nic:

+      type: tosca.nodes.Image

+

+    mysite_management:

+      description: This slice exists solely to own the management network

+      type: tosca.nodes.Slice

+      properties:

+          network: noauto

+      requirements:

+          - site:

+              node: mysite

+              relationship: tosca.relationships.MemberOfSite

+

+    mysite_mobile_net:

+      description: This slice exists solely to own the mobile network

+      type: tosca.nodes.Slice

+      properties:

+          network: noauto

+      requirements:

+          - site:

+              node: mysite

+              relationship: tosca.relationships.MemberOfSite

+

+    mysite_vbbu_slice1:

+      description: vBBU Service Slice 1

+      type: tosca.nodes.Slice

+      requirements:

+          - vBBU:

+              node: vBBU

+              relationship: tosca.relationships.MemberOfService

+          - site:

+              node: mysite

+              relationship: tosca.relationships.MemberOfSite

+          - default_image:

+                node: mcord-bbu-multi-nic 

+                relationship: tosca.relationships.DefaultImage

+          - management:

+              node: management

+              relationship: tosca.relationships.ConnectsToNetwork

+      properties:

+          network: noauto

+          default_flavor: m1.xlarge

+          default_node: computeBBU2 

+    

+    mysite_VBBU_Component:

+      description: MCORD Service default Component

+      type: tosca.nodes.VBBUComponent

+      requirements:

+          - provider_service:

+              node: vBBU

+              relationship: tosca.relationships.MemberOfService

+          - vbbu_slice:

+              node: mysite_vbbu_slice1

+              relationship: tosca.relationships.MemberOfSlice

+      properties:

+          display_message: vBBU looks good!

+          s1u_tag: 201

+          s1mme_tag: 200

+          rru_tag: 199 

diff --git a/xos/configurations/mcord/vpgwc.yaml b/xos/configurations/mcord/vpgwc.yaml
new file mode 100644
index 0000000..d003bb2
--- /dev/null
+++ b/xos/configurations/mcord/vpgwc.yaml
@@ -0,0 +1,203 @@
+tosca_definitions_version: tosca_simple_yaml_1_0

+

+description: Setup MCORD-related services.

+

+imports:

+   - custom_types/xos.yaml

+

+node_types:

+

+    tosca.nodes.MCORDService:

+        derived_from: tosca.nodes.Root

+        description: >

+            An XOS Service object. Services may be listed in the Service

+            directory and may be linked together via Tenancy Relationships.

+        capabilities:

+            scalable:

+                type: tosca.capabilities.Scalable

+            service:

+                type: tosca.capabilities.xos.Service

+        properties:

+            no-delete:

+                type: boolean

+                default: false

+                description: Do not allow Tosca to delete this object

+            no-create:

+                type: boolean

+                default: false

+                description: Do not allow Tosca to create this object

+            no-update:

+                type: boolean

+                default: false

+                description: Do not allow Tosca to update this object

+            kind:

+                type: string

+                default: VPGWC_KIND

+                description: Type of service.

+            view_url:

+                type: string

+                required: false

+                description: URL to follow when icon is clicked in the Service Directory.

+            icon_url:

+                type: string

+                required: false

+                description: ICON to display in the Service Directory.

+            enabled:

+                type: boolean

+                default: true

+            published:

+                type: boolean

+                default: true

+                description: If True then display this Service in the Service Directory.

+            public_key:

+                type: string

+                required: false

+                description: Public key to install into Instances to allows Services to SSH into them.

+            private_key_fn:

+                type: string

+                required: false

+                description: Location of private key file

+            versionNumber:

+                type: string

+                required: false

+                description: Version number of Service.

+

+    tosca.nodes.VPGWCComponent:

+        derived_from: tosca.nodes.Root

+        description: >

+            CORD: vPGWC Component of MCORD Service.

+        properties:

+            kind:

+                type: string

+                default: VPGWC_KIND 

+                description: Kind of component

+            s5s8_pgw_tag:

+                type: string

+                required: false

+                default: 300

+                description: VTN stag port-name

+            display_message:

+                type: string

+                required: false

+                default: New vPGWC Component 

+                description: Just a message 

+                

+

+topology_template:

+  node_templates:

+    vPGWC:

+      type: tosca.nodes.MCORDService

+      requirements:

+      properties:

+          kind: VPGWC_KIND

+          icon_url: /static/mCordServices/service_server.png

+          view_url: /admin/mcord/vpgwccomponent

+          public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }

+          private_key_fn: /opt/xos/configurations/mcord/mcord_private_key

+      artifacts:

+          pubkey: /opt/xos/configurations/mcord/mcord_public_key

+

+    m1.xlarge:

+      type: tosca.nodes.Flavor

+

+    Private:

+      type: tosca.nodes.NetworkTemplate

+

+    External:

+      type: tosca.nodes.NetworkTemplate

+

+    management_template:

+      type: tosca.nodes.NetworkTemplate

+      properties:

+          visibility: private

+          translation: none

+

+    management:

+      type: tosca.nodes.network.Network.XOS

+#      properties:

+#          no-create: true

+#          no-delete: true

+#          no-update: true

+

+    lan_3gpp_s5s8_pgw_network:

+      type: tosca.nodes.network.Network.XOS

+      properties:

+          ip_version: 4

+          labels: lan_3gpp_s5s8_pgw_net

+          cidr: 172.17.1.0/24

+          start_ip: 172.17.1.2

+          end_ip: 172.17.1.8

+          gateway_ip: 172.17.1.1

+      requirements:

+          - network_template:

+              node: External

+              relationship: tosca.relationships.UsesNetworkTemplate

+          - owner:

+              node: mysite_mobile_net

+              relationship: tosca.relationships.MemberOfSlice

+          - connection:

+              node: mysite_vpgwc_slice1

+              relationship: tosca.relationships.ConnectsToSlice

+

+    mysite:

+      type: tosca.nodes.Site

+

+    mcord-vpgwc-onos-multi-nic:

+      type: tosca.nodes.Image

+

+    mysite_management:

+      description: This slice exists solely to own the management network

+      type: tosca.nodes.Slice

+      properties:

+          network: noauto

+      requirements:

+          - site:

+              node: mysite

+              relationship: tosca.relationships.MemberOfSite

+

+    mysite_mobile_net:

+      description: This slice exists solely to own the mobile network

+      type: tosca.nodes.Slice

+      properties:

+          network: noauto

+      requirements:

+          - site:

+              node: mysite

+              relationship: tosca.relationships.MemberOfSite

+

+    mysite_vpgwc_slice1:

+      description: vPGWC Service Slice 1

+      type: tosca.nodes.Slice

+      requirements:

+          - vPGWC:

+              node: vPGWC

+              relationship: tosca.relationships.MemberOfService

+          - site:

+              node: mysite

+              relationship: tosca.relationships.MemberOfSite

+          - default_image:

+                node: mcord-vpgwc-onos-multi-nic 

+                relationship: tosca.relationships.DefaultImage

+          - default_flavor:

+                node: m1.xlarge

+                relationship: tosca.relationships.DefaultFlavor

+          - management:

+              node: management

+              relationship: tosca.relationships.ConnectsToNetwork

+      properties:

+          network: noauto

+          default_node: compute10 

+    

+    mysite_VPGWC_Component:

+      description: MCORD Service default Component

+      type: tosca.nodes.VPGWCComponent

+      requirements:

+          - provider_service:

+              node: vPGWC

+              relationship: tosca.relationships.MemberOfService

+          - vpgwc_slice:

+              node: mysite_vpgwc_slice1

+              relationship: tosca.relationships.MemberOfSlice

+      properties:

+          display_message: vPGWC looks good!

+          s5s8_pgw_tag: 300

diff --git a/xos/configurations/mcord/xos/Dockerfile b/xos/configurations/mcord/xos/Dockerfile
new file mode 100644
index 0000000..f65eb37
--- /dev/null
+++ b/xos/configurations/mcord/xos/Dockerfile
@@ -0,0 +1,94 @@
+FROM       ubuntu:14.04.3
+
+# XXX Workaround for docker bug:
+# https://github.com/docker/docker/issues/6345
+# Kernel 3.15 breaks docker, uss the line below as a workaround
+# until there is a fix
+RUN ln -s -f /bin/true /usr/bin/chfn
+# XXX End workaround
+
+# Install.
+RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y \
+    curl \
+    gcc \
+    geoip-database \
+    git \
+    graphviz \
+    graphviz-dev \
+    libgeoip1 \
+    libxslt1.1 \
+    libxslt1-dev \
+    libyaml-dev \
+    m4 \
+    pkg-config \
+    python-dev \
+    python-httplib2 \
+    python-pip \
+    python-psycopg2 \
+    python-pycurl \
+    python-setuptools \
+    tar \
+    wget \
+##### observer dependencies
+    python-keystoneclient \
+    python-novaclient \
+    python-neutronclient \
+    python-glanceclient \
+    python-ceilometerclient
+
+RUN pip install \
+    django==1.7 \
+    django-bitfield \
+    django-crispy-forms \
+    django-encrypted-fields \
+    django-extensions \
+    django-filter==0.11.0 \
+    django-geoposition \
+    django-ipware \
+    django_rest_swagger \
+    django-suit==0.3a1 \
+    django-timezones \
+    djangorestframework==2.4.4 \
+    dnslib \
+    lxml \
+    markdown \
+    netaddr \
+    pyOpenSSL \
+    psycopg2 \
+    python-ceilometerclient \
+    python-dateutil \
+    python-keyczar \
+    pygraphviz \
+    pytz \
+    pyyaml \
+    requests
+
+RUN easy_install --upgrade httplib2
+
+RUN easy_install \
+    python_gflags \
+    google_api_python_client \
+    httplib2.ca_certs_locater
+
+ADD http://code.jquery.com/jquery-1.9.1.min.js /usr/local/lib/python2.7/dist-packages/suit/static/suit/js/
+
+# Install XOS
+RUN git clone git://github.com/open-cloud/xos.git /tmp/xos && \
+    mv /tmp/xos/xos /opt/ && \
+    chmod +x /opt/xos/tools/xos-manage && \
+    /opt/xos/tools/xos-manage genkeys
+
+# install Tosca engine
+RUN chmod +x /opt/xos/tosca/run.py
+RUN bash /opt/xos/tosca/install_tosca.sh
+
+EXPOSE 8000
+
+# Set environment variables.
+ENV HOME /root
+
+# Define working directory.
+WORKDIR /opt/xos
+
+# Define default command.
+CMD update-ca-certificates && python /opt/xos/manage.py runserver 0.0.0.0:8000 --insecure --makemigrations
diff --git a/xos/configurations/mcord/xos/Dockerfile.devel b/xos/configurations/mcord/xos/Dockerfile.devel
new file mode 100644
index 0000000..e0d0c6d
--- /dev/null
+++ b/xos/configurations/mcord/xos/Dockerfile.devel
@@ -0,0 +1,94 @@
+FROM       ubuntu:14.04.3
+
+# XXX Workaround for docker bug:
+# https://github.com/docker/docker/issues/6345
+# Kernel 3.15 breaks docker, uss the line below as a workaround
+# until there is a fix
+RUN ln -s -f /bin/true /usr/bin/chfn
+# XXX End workaround
+
+# Install.
+RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y \
+    curl \
+    gcc \
+    geoip-database \
+    git \
+    graphviz \
+    graphviz-dev \
+    libgeoip1 \
+    libxslt1.1 \
+    libxslt1-dev \
+    libyaml-dev \
+    m4 \
+    pkg-config \
+    python-dev \
+    python-httplib2 \
+    python-pip \
+    python-psycopg2 \
+    python-pycurl \
+    python-setuptools \
+    tar \
+    wget \
+##### observer dependencies
+    python-keystoneclient \
+    python-novaclient \
+    python-neutronclient \
+    python-glanceclient \
+    python-ceilometerclient
+
+RUN pip install \
+    django==1.7 \
+    django-bitfield \
+    django-crispy-forms \
+    django-encrypted-fields \
+    django-extensions \
+    django-filter==0.11.0 \
+    django-geoposition \
+    django-ipware \
+    django_rest_swagger \
+    django-suit==0.3a1 \
+    django-timezones \
+    djangorestframework==2.4.4 \
+    dnslib \
+    lxml \
+    markdown \
+    netaddr \
+    pyOpenSSL \
+    psycopg2 \
+    python-ceilometerclient \
+    python-dateutil \
+    python-keyczar \
+    pygraphviz \
+    pytz \
+    pyyaml \
+    requests
+
+RUN easy_install --upgrade httplib2
+
+RUN easy_install \
+    python_gflags \
+    google_api_python_client \
+    httplib2.ca_certs_locater
+
+ADD http://code.jquery.com/jquery-1.9.1.min.js /usr/local/lib/python2.7/dist-packages/suit/static/suit/js/
+
+# Install XOS
+ADD xos /opt/xos
+RUN chmod +x /opt/xos/tools/xos-manage
+RUN /opt/xos/tools/xos-manage genkeys
+
+# install Tosca engine
+RUN chmod +x /opt/xos/tosca/run.py
+RUN bash /opt/xos/tosca/install_tosca.sh
+
+EXPOSE 8000
+
+# Set environment variables.
+ENV HOME /root
+
+# Define working directory.
+WORKDIR /opt/xos
+
+# RUN python /opt/xos/manage.py makemigrations mcordservice 
+# Define default command.
+CMD update-ca-certificates && python /opt/xos/manage.py runserver 0.0.0.0:8000 --insecure --makemigrations
diff --git a/xos/configurations/mcord/xos/Dockerfile.templ b/xos/configurations/mcord/xos/Dockerfile.templ
new file mode 100644
index 0000000..25270a6
--- /dev/null
+++ b/xos/configurations/mcord/xos/Dockerfile.templ
@@ -0,0 +1,88 @@
+FROM       ubuntu:14.04.3
+
+# XXX Workaround for docker bug:
+# https://github.com/docker/docker/issues/6345
+# Kernel 3.15 breaks docker, uss the line below as a workaround
+# until there is a fix
+RUN ln -s -f /bin/true /usr/bin/chfn
+# XXX End workaround
+
+# Install.
+RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y \
+    curl \
+    gcc \
+    geoip-database \
+    git \
+    graphviz \
+    graphviz-dev \
+    libgeoip1 \
+    libxslt1.1 \
+    libxslt1-dev \
+    libyaml-dev \
+    m4 \
+    pkg-config \
+    python-dev \
+    python-httplib2 \
+    python-pip \
+    python-psycopg2 \
+    python-pycurl \
+    python-setuptools \
+    tar \
+    wget \
+##### observer dependencies
+    python-keystoneclient \
+    python-novaclient \
+    python-neutronclient \
+    python-glanceclient \
+    python-ceilometerclient
+
+RUN pip install -U \
+    django==1.7 \
+    django-bitfield \
+    django-crispy-forms \
+    django-encrypted-fields \
+    django_evolution \
+    django-extensions \
+    django-filter==0.11.0 \
+    django-geoposition \
+    django-ipware \
+    django_rest_swagger \
+    django-suit==0.3a1 \
+    django-timezones \
+    djangorestframework==2.4.4 \
+    dnslib \
+    google_api_python_client \
+    httplib2 \
+    httplib2.ca_certs_locater \
+    lxml \
+    markdown \
+    netaddr \
+    python-dateutil \
+    python_gflags \
+    python-keyczar \
+    pygraphviz \
+    pytz \
+    pyyaml \
+    requests
+
+ADD http://code.jquery.com/jquery-1.9.1.min.js /usr/local/lib/python2.7/dist-packages/suit/static/suit/js/
+
+# Install XOS
+RUN git clone XOS_GIT_REPO -b XOS_GIT_BRANCH /tmp/xos && \
+    mv /tmp/xos/xos /opt/ && \
+    chmod +x /opt/xos/tools/xos-manage && \
+    /opt/xos/tools/xos-manage genkeys
+
+# install Tosca engine
+RUN bash /opt/xos/tosca/install_tosca.sh
+
+EXPOSE 8000
+
+# Set environment variables.
+ENV HOME /root
+
+# Define working directory.
+WORKDIR /root
+
+# Define default command.
+CMD update-ca-certificates && python /opt/xos/manage.py runserver 0.0.0.0:8000 --insecure --makemigrations
diff --git a/xos/configurations/mcord/xos/Makefile b/xos/configurations/mcord/xos/Makefile
new file mode 100644
index 0000000..0ba043d
--- /dev/null
+++ b/xos/configurations/mcord/xos/Makefile
@@ -0,0 +1,27 @@
+CONTAINER_NAME:=xos-server
+IMAGE_NAME:=xosproject/xos
+TOSCA_CONFIG_PATH:=/opt/xos/configurations/opencloud/opencloud.yaml
+XOS_GIT_REPO?=git://github.com/open-cloud/xos.git
+XOS_GIT_BRANCH?=master
+NO_DOCKER_CACHE?=false
+
+.PHONY: build
+build: ; sudo docker build --no-cache=${NO_DOCKER_CACHE} --rm -t ${IMAGE_NAME} .
+
+.PHONY: custom
+custom: ; cat Dockerfile.templ | sed -e "s|XOS_GIT_REPO|${XOS_GIT_REPO}|g" -e "s|XOS_GIT_BRANCH|${XOS_GIT_BRANCH}|g" | docker build --no-cache=${NO_DOCKER_CACHE} --rm -t ${IMAGE_NAME} -
+
+.PHONY: devel
+devel: ; cd ../..; ls; sudo docker build -f containers/xos/Dockerfile.devel --no-cache=${NO_DOCKER_CACHE} --rm -t ${IMAGE_NAME} .
+
+.PHONY: run
+run: ; sudo docker run -d --name ${CONTAINER_NAME} -p 80:8000 -v /usr/local/share/ca-certificates:/usr/local/share/ca-certificates:ro ${IMAGE_NAME}
+
+.PHONY: runtosca
+runtosca: ; sudo docker exec -it ${CONTAINER_NAME} /usr/bin/python /opt/xos/tosca/run.py padmin@vicci.org ${TOSCA_CONFIG_PATH}
+
+.PHONY: stop
+stop: ; sudo docker stop ${CONTAINER_NAME}
+
+.PHONY: rm
+rm: ; sudo docker rm ${CONTAINER_NAME}
diff --git a/xos/configurations/mcord/xos/initdb b/xos/configurations/mcord/xos/initdb
new file mode 100755
index 0000000..1f5b770
--- /dev/null
+++ b/xos/configurations/mcord/xos/initdb
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+IMAGE_NAME=xosproject/xos
+CONTAINER_NAME=xos_build_helper_$$
+DB_HOST=$(wget http://ipinfo.io/ip -qO -)
+
+# configure db host
+docker run -it --name=$CONTAINER_NAME $IMAGE_NAME sed -i '0,/host/{s/host=localhost/host='$DB_HOST'/}' /opt/xos/xos_configuration/xos_common_config
+docker commit $CONTAINER_NAME $IMAGE_NAME
+docker rm $CONTAINER_NAME
+
+# init db schema
+docker run -it --name=$CONTAINER_NAME $IMAGE_NAME /opt/xos/tools/xos-manage makemigrations
+# run overrides the CMD specifed in the Dockerfile, so we re-set the CMD in the final commit"
+docker commit --change="CMD update-ca-certificates && python /opt/xos/manage.py runserver 0.0.0.0:8000 --insecure" $CONTAINER_NAME $IMAGE_NAME
+docker rm $CONTAINER_NAME
diff --git a/xos/configurations/mcord/xos_mcord_config b/xos/configurations/mcord/xos_mcord_config
new file mode 100644
index 0000000..8f4034d
--- /dev/null
+++ b/xos/configurations/mcord/xos_mcord_config
@@ -0,0 +1,6 @@
+[gui]
+branding_name=M-CORD
+branding_icon=/static/cord-logo.png
+branding_favicon=/static/cord-favicon.png
+branding_bg=/static/mcord-bg.jpg
+service_view_class=core.views.mCordServiceGrid.ServiceGridView
diff --git a/xos/configurations/opencloud/Makefile b/xos/configurations/opencloud/Makefile
new file mode 100644
index 0000000..03168ed
--- /dev/null
+++ b/xos/configurations/opencloud/Makefile
@@ -0,0 +1,36 @@
+xos:
+	sudo docker-compose up -d
+	bash ./wait_for_xos.sh
+	sudo docker-compose run xos python /opt/xos/tosca/run.py none /opt/xos/configurations/common/fixtures.yaml
+	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/opencloud/opencloud.yaml
+
+containers:
+	cd ../../../containers/xos; make devel
+	cd ../../../containers/synchronizer; make
+
+stop:
+	sudo docker-compose stop
+
+showlogs:
+	sudo docker-compose logs
+
+rm: stop
+	sudo docker-compose rm
+
+ps:
+	sudo docker-compose ps
+
+enter-xos:
+	sudo docker exec -it devel_xos_1 bash
+
+enter-synchronizer:
+	sudo docker exec -it devel_xos_synchronizer_openstack_1 bash
+
+upgrade_pkgs:
+	sudo pip install httpie --upgrade
+
+rebuild_xos:
+	make -C ../../../containers/xos devel
+
+rebuild_synchronizer:
+	make -C ../../../containers/synchronizer
diff --git a/xos/configurations/opencloud/README.md b/xos/configurations/opencloud/README.md
new file mode 100644
index 0000000..97449ed
--- /dev/null
+++ b/xos/configurations/opencloud/README.md
@@ -0,0 +1,24 @@
+# XOS OpenCloud Portal
+
+This configuration can be used to bring up XOS on the OpenCloud portal.  It launches
+XOS in three Docker containers (development GUI, Synchronizer, database) and configures XOS
+with the `opencloud.yaml` TOSCA file in this directory.  *docker-compose* is used to manage
+the containers.
+
+## Docker Helpers
+
+Stop the containers: `make stop`
+
+Restart the containers: `make stop; make`
+
+Delete the containers and relaunch them: `make rm; make`
+
+Build the containers from scratch using the local XOS source tree: `make containers`
+
+View logs: `make showlogs`
+
+See what containers are running: `make ps`
+
+Open a shell on the XOS container: `make enter-xos`
+
+Open a shell on the Synchronizer container: `make enter-synchronizer`
diff --git a/xos/configurations/opencloud/cdn-content.yaml b/xos/configurations/opencloud/cdn-content.yaml
new file mode 100644
index 0000000..ebf6b82
--- /dev/null
+++ b/xos/configurations/opencloud/cdn-content.yaml
@@ -0,0 +1,223 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Template for deploying a single server with predefined properties.
+
+imports:
+   - custom_types/xos.yaml
+   - custom_types/cdn.yaml
+
+topology_template:
+  node_templates:
+    HyperCache:
+      type: tosca.nodes.CDNService
+      properties:
+          # HyperCache service must already exist before running this recipe
+          no-create: true
+          no-delete: true
+          no-update: true
+
+    # Setup the CDN Service Provider
+
+    main_service_provider:
+        type: tosca.nodes.ServiceProvider
+        requirements:
+           - hpc_service:
+                 node: HyperCache
+                 relationship: tosca.relationships.MemberOfService
+
+    # Wall Street Journal Content Provider
+
+    wsj_content:
+        type: tosca.nodes.ContentProvider
+        requirements:
+            - service_provider:
+                  node: main_service_provider
+                  relationship: tosca.relationships.MemberOfServiceProvider
+
+    www.wsj.com:
+        type: tosca.nodes.CDNPrefix
+        requirements:
+             - content_provider:
+                   node: wsj_content
+                   relationship: tosca.relationships.MemberOfContentProvider
+             - default_origin_server:
+                   node: http_www.wsj.com
+                   relationship: tosca.relationships.DefaultOriginServer
+
+    si.wsj.net:
+        type: tosca.nodes.CDNPrefix
+        requirements:
+             - content_provider:
+                   node: wsj_content
+                   relationship: tosca.relationships.MemberOfContentProvider
+             - default_origin_server:
+                   node: http_si.wsj.net
+                   relationship: tosca.relationships.DefaultOriginServer
+
+    s.wsj.net:
+        type: tosca.nodes.CDNPrefix
+        requirements:
+             - content_provider:
+                   node: wsj_content
+                   relationship: tosca.relationships.MemberOfContentProvider
+             - default_origin_server:
+                   node: http_s.wsj.net
+                   relationship: tosca.relationships.DefaultOriginServer
+
+    ore.wsj.net:
+        type: tosca.nodes.CDNPrefix
+        requirements:
+             - content_provider:
+                   node: wsj_content
+                   relationship: tosca.relationships.MemberOfContentProvider
+             - default_origin_server:
+                   node: http_ore.wsj.net
+                   relationship: tosca.relationships.DefaultOriginServer
+
+    http_www.wsj.com:
+        type: tosca.nodes.OriginServer
+        requirements:
+             - content_provider:
+                   node: wsj_content
+                   relationship: tosca.relationships.MemberOfContentProvider
+
+    http_si.wsj.net:
+        type: tosca.nodes.OriginServer
+        requirements:
+             - content_provider:
+                   node: wsj_content
+                   relationship: tosca.relationships.MemberOfContentProvider
+
+    http_s.wsj.net:
+        type: tosca.nodes.OriginServer
+        requirements:
+             - content_provider:
+                   node: wsj_content
+                   relationship: tosca.relationships.MemberOfContentProvider
+
+    http_ore.wsj.net:
+        type: tosca.nodes.OriginServer
+        requirements:
+             - content_provider:
+                   node: wsj_content
+                   relationship: tosca.relationships.MemberOfContentProvider
+
+    # ON.Lab content provider
+
+    on_lab_content:
+        type: tosca.nodes.ContentProvider
+        requirements:
+            - service_provider:
+                  node: main_service_provider
+                  relationship: tosca.relationships.MemberOfServiceProvider
+
+    # Create CDN prefix onlab.vicci.org
+    onlab.vicci.org:

+        type: tosca.nodes.CDNPrefix

+        requirements:

+             - content_provider:

+                   node: on_lab_content

+                   relationship: tosca.relationships.MemberOfContentProvider
+
+    http_onos-videos.s3.amazonaws.com:
+        type: tosca.nodes.OriginServer

+        requirements:

+             - content_provider:

+                   node: on_lab_content

+                   relationship: tosca.relationships.MemberOfContentProvider
+
+    # Create origin server s3-us-west-1.amazonaws.com
+    http_s3-us-west-1.amazonaws.com:

+        type: tosca.nodes.OriginServer

+        requirements:

+             - content_provider:

+                   node: on_lab_content

+                   relationship: tosca.relationships.MemberOfContentProvider

+

+    # Create origin server s3.amazonaws.com

+    http_s3.amazonaws.com:

+        type: tosca.nodes.OriginServer

+        requirements:

+             - content_provider:

+                   node: on_lab_content

+                   relationship: tosca.relationships.MemberOfContentProvider
+
+    # Test Content Provider
+
+    testcp2:
+        type: tosca.nodes.ContentProvider

+        requirements:

+            - service_provider:

+                  node: main_service_provider

+                  relationship: tosca.relationships.MemberOfServiceProvider
+
+    http_www.cs.arizona.edu:
+        type: tosca.nodes.OriginServer

+        requirements:

+             - content_provider:

+                   node: testcp2

+                   relationship: tosca.relationships.MemberOfContentProvider
+
+    test-cdn.opencloud.us:
+        type: tosca.nodes.CDNPrefix

+        requirements:

+             - content_provider:

+                   node: testcp2

+                   relationship: tosca.relationships.MemberOfContentProvider

+

+             - default_origin_server:

+                   node: http_www.cs.arizona.edu

+                   relationship: tosca.relationships.DefaultOriginServer
+
+    # Health Checks
+
+    healthcheck_dns_onlab.vicci.org:
+        type: tosca.nodes.HpcHealthCheck
+        requirements:
+           - hpc_service:
+                 node: HyperCache
+                 relationship: tosca.relationships.MemberOfService
+        properties:
+           kind: dns
+           resource_name: onlab.vicci.org
+
+    healthcheck_dns_test-cdn.opencloud.us:
+        type: tosca.nodes.HpcHealthCheck
+        requirements:
+           - hpc_service:
+                 node: HyperCache
+                 relationship: tosca.relationships.MemberOfService
+        properties:
+           kind: dns
+           resource_name: test-cdn.opencloud.us
+
+    healthcheck_http_test-cdn-index:
+        type: tosca.nodes.HpcHealthCheck
+        requirements:
+           - hpc_service:
+                 node: HyperCache
+                 relationship: tosca.relationships.MemberOfService
+        properties:
+           kind: http
+           resource_name: test-cdn.opencloud.us:/
+           result_contains: Lowenthal
+
+    healthcheck_http_onlab_onos_image:
+        type: tosca.nodes.HpcHealthCheck
+        requirements:
+           - hpc_service:
+                 node: HyperCache
+                 relationship: tosca.relationships.MemberOfService
+        properties:
+           kind: http
+           resource_name: onlab.vicci.org:/onos/vm/onos-tutorial-1.1.0r220-ovf.zip
+
+    healthcheck_http_onlab_mininet_image:
+        type: tosca.nodes.HpcHealthCheck
+        requirements:
+           - hpc_service:
+                 node: HyperCache
+                 relationship: tosca.relationships.MemberOfService
+        properties:
+           kind: http
+           resource_name: onlab.vicci.org:/mininet-vm/mininet-2.1.0-130919-ubuntu-13.04-server-amd64-ovf.zip
diff --git a/xos/configurations/opencloud/cdn-opencloud.yaml b/xos/configurations/opencloud/cdn-opencloud.yaml
new file mode 100644
index 0000000..f66e0f2
--- /dev/null
+++ b/xos/configurations/opencloud/cdn-opencloud.yaml
@@ -0,0 +1,77 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Template for deploying a single server with predefined properties.
+
+imports:
+   - custom_types/xos.yaml
+   - custom_types/cdn.yaml
+
+topology_template:
+  node_templates:
+    HyperCache:
+      type: tosca.nodes.CDNService
+      description: Content Delivery Network
+      properties:
+          view_url: /admin/hpc/hpcservice/$id$/
+          icon_url: /static/primarycons_blue/network.png
+
+    onlab:
+      type: tosca.nodes.Site
+      properties:
+          # Assume the onlab site exists, and don't touch it
+          no-create: true
+          no-update: true
+          no-delete: true
+
+    onlab_cmi:
+      description: CMI Slice
+      type: tosca.nodes.Slice
+      properties:
+          exposed_ports: tcp 8003, tcp 8004, tcp 8140
+      requirements:
+          - cdn_service:
+              node: HyperCache
+              relationship: tosca.relationships.MemberOfService
+          - site:
+              node: onlab
+              relationship: tosca.relationships.MemberOfSite
+
+    onlab_hpc:
+      description: HyperCache Slice
+      type: tosca.nodes.Slice
+      properties:
+          exposed_ports: tcp 2120:2128, tcp 3200:3209, tcp 8006, tcp 8009, tcp 8015, tcp 80
+      requirements:
+          - cdn_service:
+              node: HyperCache
+              relationship: tosca.relationships.MemberOfService
+          - site:
+              node: onlab
+              relationship: tosca.relationships.MemberOfSite
+
+    onlab_dnsredir:
+      description: HyperCache Slice
+      type: tosca.nodes.Slice
+      properties:
+          exposed_ports: udp 53541, tcp 8016
+      requirements:
+          - cdn_service:
+              node: HyperCache
+              relationship: tosca.relationships.MemberOfService
+          - site:
+              node: onlab
+              relationship: tosca.relationships.MemberOfSite
+
+    onlab_dnsdemux:
+      description: HyperCache Slice
+      type: tosca.nodes.Slice
+      properties:
+          exposed_ports: udp 53, tcp 8017
+      requirements:
+          - cdn_service:
+              node: HyperCache
+              relationship: tosca.relationships.MemberOfService
+          - site:
+              node: onlab
+              relationship: tosca.relationships.MemberOfSite
+
diff --git a/xos/configurations/opencloud/cdn-syndicate-content.yaml b/xos/configurations/opencloud/cdn-syndicate-content.yaml
new file mode 100644
index 0000000..06dc623
--- /dev/null
+++ b/xos/configurations/opencloud/cdn-syndicate-content.yaml
@@ -0,0 +1,52 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Template for deploying a single server with predefined properties.
+
+imports:
+   - custom_types/xos.yaml
+   - custom_types/cdn.yaml
+
+topology_template:
+  node_templates:
+    HyperCache:
+      type: tosca.nodes.CDNService
+      properties:
+          # HyperCache service must already exist before running this recipe
+          no-create: true
+          no-delete: true
+          no-update: true
+
+    # Setup the Syndicate Devel Service Provider
+
+    main_service_provider:
+        type: tosca.nodes.ServiceProvider
+        requirements:
+           - hpc_service:
+                 node: HyperCache
+                 relationship: tosca.relationships.MemberOfService
+
+    syndicate_devel:
+        type: tosca.nodes.ContentProvider

+        requirements:

+            - service_provider:

+                  node: main_service_provider

+                  relationship: tosca.relationships.MemberOfServiceProvider
+
+#    http_node2.cs.arizona.edu:
+#        type: tosca.nodes.OriginServer

+#        requirements:

+#             - content_provider:

+#                   node: syndicate_devel

+#                   relationship: tosca.relationships.MemberOfContentProvider
+
+    syndicate-devel.opencloud.us:
+        type: tosca.nodes.CDNPrefix

+        requirements:

+             - content_provider:

+                   node: syndicate_devel

+                   relationship: tosca.relationships.MemberOfContentProvider

+

+#             - default_origin_server:

+#                   node: http_node2.cs.arizona.edu

+#                   relationship: tosca.relationships.DefaultOriginServer
+
diff --git a/xos/configurations/opencloud/docker-compose.yml b/xos/configurations/opencloud/docker-compose.yml
new file mode 100644
index 0000000..8e4445a
--- /dev/null
+++ b/xos/configurations/opencloud/docker-compose.yml
@@ -0,0 +1,73 @@
+xos_db:
+    image: xosproject/xos-postgres
+    expose:
+        - "5432"
+
+xos_synchronizer_openstack:
+    image: xosproject/xos-synchronizer-openstack
+    command: bash -c "update-ca-certificates; sleep 120; python /opt/xos/synchronizers/openstack/xos-synchronizer.py"
+    #command: sleep 86400
+    labels:
+        org.xosproject.kind: synchronizer
+        org.xosproject.target: openstack
+    links:
+        - xos_db
+    volumes:
+        - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
+        - /usr/local/share/ca-certificates:/usr/local/share/ca-certificates:ro
+        - ./files/xos_opencloud_config:/opt/xos/xos_configuration/xos_opencloud_config:ro
+        - ./images:/opt/xos/images:ro
+    log_driver: "json-file"
+    log_opt:
+            max-size: "100k"
+            max-file: "5"
+
+xos_synchronizer_hpc:
+    image: xosproject/xos-synchronizer-openstack
+    command: bash -c "sleep 120; python /opt/xos/synchronizers/hpc/hpc-synchronizer.py -C /opt/xos/synchronizers/hpc/hpc_synchronizer_config"
+    #command: sleep 86400
+    labels:
+        org.xosproject.kind: synchronizer
+        org.xosproject.target: hpc
+    links:
+        - xos_db
+    volumes:
+        - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
+        - /usr/local/share/ca-certificates:/usr/local/share/ca-certificates:ro
+        - ./files/xos_opencloud_config:/opt/xos/xos_configuration/xos_opencloud_config:ro
+    log_driver: "json-file"
+    log_opt:
+            max-size: "100k"
+            max-file: "5"
+
+xos_watcher_hpc:
+    image: xosproject/xos-synchronizer-openstack
+    command: bash -c "sleep 120; python /opt/xos/synchronizers/hpc/hpc_watcher.py"
+    #command: sleep 86400
+    labels:
+        org.xosproject.kind: watcher
+        org.xosproject.target: hpc
+    links:
+        - xos_db
+    volumes:
+        - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
+        - /usr/local/share/ca-certificates:/usr/local/share/ca-certificates:ro
+        - ./files/xos_opencloud_config:/opt/xos/xos_configuration/xos_opencloud_config:ro
+
+# FUTURE
+#xos_swarm_synchronizer:
+#    image: xosproject/xos-swarm-synchronizer
+#    labels:
+#        org.xosproject.kind: synchronizer
+#        org.xosproject.target: swarm
+
+xos:
+    image: xosproject/xos
+    command: python /opt/xos/manage.py runserver 0.0.0.0:8000 --insecure --makemigrations
+    ports:
+        - "80:8000"
+    links:
+        - xos_db
+    volumes:
+      - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
+      - ./files/xos_opencloud_config:/opt/xos/xos_configuration/xos_opencloud_config:ro
diff --git a/xos/configurations/opencloud/files/xos_opencloud_config b/xos/configurations/opencloud/files/xos_opencloud_config
new file mode 100644
index 0000000..62291b6
--- /dev/null
+++ b/xos/configurations/opencloud/files/xos_opencloud_config
@@ -0,0 +1,3 @@
+[server]
+restapi_hostname=portal.opencloud.us
+restapi_port=80
diff --git a/xos/configurations/opencloud/opencloud.yaml b/xos/configurations/opencloud/opencloud.yaml
new file mode 100644
index 0000000..c71369a
--- /dev/null
+++ b/xos/configurations/opencloud/opencloud.yaml
@@ -0,0 +1,1661 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Adds OpenCloud Sites, Deployments, and Controllers.
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+
+# Nodes
+    trusty-server-multi-nic:
+      type: tosca.nodes.Image
+      properties:
+         disk_format: QCOW2
+         container_format: BARE
+
+# network template
+    public-shared-ipv4:
+      type: tosca.nodes.NetworkTemplate
+      properties:
+          visibility: private
+          translation: NAT
+          shared_network_name: nat-net
+
+# deokoyments
+    backbone:
+      type: tosca.nodes.Deployment
+      properties:
+          flavors: m1.large, m1.medium, m1.small
+      requirements:
+          - image:
+              node: trusty-server-multi-nic
+              relationship: tosca.relationships.SupportsImage
+
+    campus:
+      type: tosca.nodes.Deployment
+      properties:
+          flavors: m1.large, m1.medium, m1.small
+      requirements:
+          - image:
+              node: trusty-server-multi-nic
+              relationship: tosca.relationships.SupportsImage
+
+    ec2:
+      type: tosca.nodes.Deployment
+      properties:
+          flavors: m1.large, m1.medium, m1.small
+      requirements:
+          - image:
+              node: trusty-server-multi-nic
+              relationship: tosca.relationships.SupportsImage
+
+# controllers
+    backbone-atl:
+      type: tosca.nodes.Controller
+      requirements:
+          - deployment:
+              node: backbone
+              relationship: tosca.relationships.ControllerDeployment
+      properties:
+          backend_type: OpenStack
+          version: Juno
+          auth_url: http://localhost:35357/v2.0/
+          admin_user: admin
+          admin_password: admin
+          admin_tenant: admin
+          domain: Default
+
+    backbone-chi:
+      type: tosca.nodes.Controller
+      requirements:
+          - deployment:
+              node: backbone
+              relationship: tosca.relationships.ControllerDeployment
+      properties:
+          backend_type: OpenStack
+          version: Juno
+          auth_url: http://localhost:35357/v2.0/
+          admin_user: admin
+          admin_password: admin
+          admin_tenant: admin
+          domain: Default
+
+    backbone-hou:
+      type: tosca.nodes.Controller
+      requirements:
+          - deployment:
+              node: backbone
+              relationship: tosca.relationships.ControllerDeployment
+      properties:
+          backend_type: OpenStack
+          version: Juno
+          auth_url: http://localhost:35357/v2.0/
+          admin_user: admin
+          admin_password: admin
+          admin_tenant: admin
+          domain: Default
+
+    backbone-kan:
+      type: tosca.nodes.Controller
+      requirements:
+          - deployment:
+              node: backbone
+              relationship: tosca.relationships.ControllerDeployment
+      properties:
+          backend_type: OpenStack
+          version: Juno
+          auth_url: http://localhost:35357/v2.0/
+          admin_user: admin
+          admin_password: admin
+          admin_tenant: admin
+          domain: Default
+
+    backbone-lax:
+      type: tosca.nodes.Controller
+      requirements:
+          - deployment:
+              node: backbone
+              relationship: tosca.relationships.ControllerDeployment
+      properties:
+          backend_type: OpenStack
+          version: Juno
+          auth_url: http://localhost:35357/v2.0/
+          admin_user: admin
+          admin_password: admin
+          admin_tenant: admin
+          domain: Default
+
+    backbone-nyc:
+      type: tosca.nodes.Controller
+      requirements:
+          - deployment:
+              node: backbone
+              relationship: tosca.relationships.ControllerDeployment
+      properties:
+          backend_type: OpenStack
+          version: Juno
+          auth_url: http://localhost:35357/v2.0/
+          admin_user: admin
+          admin_password: admin
+          admin_tenant: admin
+          domain: Default
+
+    backbone-slc:
+      type: tosca.nodes.Controller
+      requirements:
+          - deployment:
+              node: backbone
+              relationship: tosca.relationships.ControllerDeployment
+      properties:
+          backend_type: OpenStack
+          version: Juno
+          auth_url: http://localhost:35357/v2.0/
+          admin_user: admin
+          admin_password: admin
+          admin_tenant: admin
+          domain: Default
+
+    backbone-sea:
+      type: tosca.nodes.Controller
+      requirements:
+          - deployment:
+              node: backbone
+              relationship: tosca.relationships.ControllerDeployment
+      properties:
+          backend_type: OpenStack
+          version: Juno
+          auth_url: http://localhost:35357/v2.0/
+          admin_user: admin
+          admin_password: admin
+          admin_tenant: admin
+          domain: Default
+
+    backbone-sng:
+      type: tosca.nodes.Controller
+      requirements:
+          - deployment:
+              node: backbone
+              relationship: tosca.relationships.ControllerDeployment
+      properties:
+          backend_type: OpenStack
+          version: Juno
+          auth_url: http://localhost:35357/v2.0/
+          admin_user: admin
+          admin_password: admin
+          admin_tenant: admin
+          domain: Default
+
+    backbone-wdc:
+      type: tosca.nodes.Controller
+      requirements:
+          - deployment:
+              node: backbone
+              relationship: tosca.relationships.ControllerDeployment
+      properties:
+          backend_type: OpenStack
+          version: Juno
+          auth_url: http://localhost:35357/v2.0/
+          admin_user: admin
+          admin_password: admin
+          admin_tenant: admin
+          domain: Default
+
+    campus-arizona:
+      type: tosca.nodes.Controller
+      requirements:
+          - deployment:
+              node: campus
+              relationship: tosca.relationships.ControllerDeployment
+      properties:
+          backend_type: OpenStack
+          version: Juno
+          auth_url: http://localhost:35357/v2.0/
+          admin_user: admin
+          admin_password: admin
+          admin_tenant: admin
+          domain: Default
+
+    campus-princeton:
+      type: tosca.nodes.Controller
+      requirements:
+          - deployment:
+              node: campus
+              relationship: tosca.relationships.ControllerDeployment
+      properties:
+          backend_type: OpenStack
+          version: Juno
+          auth_url: http://localhost:35357/v2.0/
+          admin_user: admin
+          admin_password: admin
+          admin_tenant: admin
+          domain: Default
+
+    campus-stanford:
+      type: tosca.nodes.Controller
+      requirements:
+          - deployment:
+              node: campus
+              relationship: tosca.relationships.ControllerDeployment
+      properties:
+          backend_type: OpenStack
+          version: Juno
+          auth_url: http://localhost:35357/v2.0/
+          admin_user: admin
+          admin_password: admin
+          admin_tenant: admin
+          domain: Default
+
+    campus-washington:
+      type: tosca.nodes.Controller
+      requirements:
+          - deployment:
+              node: campus
+              relationship: tosca.relationships.ControllerDeployment
+      properties:
+          backend_type: OpenStack
+          version: Juno
+          auth_url: http://localhost:35357/v2.0/
+          admin_user: admin
+          admin_password: admin
+          admin_tenant: admin
+          domain: Default
+
+    campus-gatech:
+      type: tosca.nodes.Controller
+      requirements:
+          - deployment:
+              node: campus
+              relationship: tosca.relationships.ControllerDeployment
+      properties:
+          backend_type: OpenStack
+          version: Juno
+          auth_url: http://localhost:35357/v2.0/
+          admin_user: admin
+          admin_password: admin
+          admin_tenant: admin
+          domain: Default
+
+    campus-internet2:
+      type: tosca.nodes.Controller
+      requirements:
+          - deployment:
+              node: campus
+              relationship: tosca.relationships.ControllerDeployment
+      properties:
+          backend_type: OpenStack
+          version: Juno
+          auth_url: http://localhost:35357/v2.0/
+          admin_user: admin
+          admin_password: admin
+          admin_tenant: admin
+          domain: Default
+
+    campus-singapore:
+      type: tosca.nodes.Controller
+      requirements:
+          - deployment:
+              node: campus
+              relationship: tosca.relationships.ControllerDeployment
+      properties:
+          backend_type: OpenStack
+          version: Juno
+          auth_url: http://localhost:35357/v2.0/
+          admin_user: admin
+          admin_password: admin
+          admin_tenant: admin
+          domain: Default
+
+    campus-onlab:
+      type: tosca.nodes.Controller
+      requirements:
+          - deployment:
+              node: campus
+              relationship: tosca.relationships.ControllerDeployment
+      properties:
+          backend_type: OpenStack
+          version: Juno
+          auth_url: http://localhost:35357/v2.0/
+          admin_user: admin
+          admin_password: admin
+          admin_tenant: admin
+          domain: Default
+
+# Sites
+
+    i2-atl:
+      type: tosca.nodes.Site
+      properties:
+          display_name: I2-atl
+          site_url: http://opencloud.us/
+          hosts_nodes: false 
+      requirements:
+          - deployment:
+               node: backbone
+               relationship: tosca.relationships.SiteDeployment
+               requirements:
+                   - controller:
+                       node: backbone-atl
+                       relationship: tosca.relationships.UsesController
+
+    i2-chi:
+      type: tosca.nodes.Site
+      properties:
+          display_name: I2-chi
+          site_url: http://opencloud.us/
+          hosts_nodes: false 
+      requirements:
+          - deployment:
+               node: backbone
+               relationship: tosca.relationships.SiteDeployment
+               requirements:
+                   - controller:
+                       node: backbone-chi
+                       relationship: tosca.relationships.UsesController
+
+    i2-hou:
+      type: tosca.nodes.Site
+      properties:
+          display_name: I2-hou
+          site_url: http://opencloud.us/
+          hosts_nodes: false 
+      requirements:
+          - deployment:
+               node: backbone
+               relationship: tosca.relationships.SiteDeployment
+               requirements:
+                   - controller:
+                       node: backbone-hou
+                       relationship: tosca.relationships.UsesController
+   
+    i2-kas:
+      type: tosca.nodes.Site
+      properties:
+          display_name: I2-kas
+          site_url: http://opencloud.us/
+          hosts_nodes: false 
+      requirements:
+          - deployment:
+               node: backbone
+               relationship: tosca.relationships.SiteDeployment
+               requirements:
+                   - controller:
+                       node: backbone-kan
+                       relationship: tosca.relationships.UsesController
+
+    i2-lax:
+      type: tosca.nodes.Site
+      properties:
+          display_name: I2-lax
+          site_url: http://opencloud.us/
+          hosts_nodes: false 
+      requirements:
+          - deployment:
+               node: backbone
+               relationship: tosca.relationships.SiteDeployment
+               requirements:
+                   - controller:
+                       node: backbone-lax
+                       relationship: tosca.relationships.UsesController
+
+    i2-nyc:
+      type: tosca.nodes.Site
+      properties:
+          display_name: I2-nyc
+          site_url: http://opencloud.us/
+          hosts_nodes: false 
+      requirements:
+          - deployment:
+               node: backbone
+               relationship: tosca.relationships.SiteDeployment
+               requirements:
+                   - controller:
+                       node: backbone-nyc
+                       relationship: tosca.relationships.UsesController
+
+    i2-slc:
+      type: tosca.nodes.Site
+      properties:
+          display_name: I2-slc
+          site_url: http://opencloud.us/
+          hosts_nodes: false 
+      requirements:
+          - deployment:
+               node: backbone
+               relationship: tosca.relationships.SiteDeployment
+               requirements:
+                   - controller:
+                       node: backbone-slc
+                       relationship: tosca.relationships.UsesController
+
+    i2-sea:
+      type: tosca.nodes.Site
+      properties:
+          display_name: I2-seae
+          site_url: http://opencloud.us/
+          hosts_nodes: false 
+      requirements:
+          - deployment:
+               node: backbone
+               relationship: tosca.relationships.SiteDeployment
+               requirements:
+                   - controller:
+                       node: backbone-sea
+                       relationship: tosca.relationships.UsesController
+
+    i2-sng:
+      type: tosca.nodes.Site
+      properties:
+          display_name: I2-sng
+          site_url: http://opencloud.us/
+          hosts_nodes: false 
+      requirements:
+          - deployment:
+               node: backbone
+               relationship: tosca.relationships.SiteDeployment
+               requirements:
+                   - controller:
+                       node: backbone-sng
+                       relationship: tosca.relationships.UsesController
+
+    i2-wdc:
+      type: tosca.nodes.Site
+      properties:
+          display_name: I2-wdc
+          site_url: http://opencloud.us/
+          hosts_nodes: false 
+      requirements:
+          - deployment:
+               node: backbone
+               relationship: tosca.relationships.SiteDeployment
+               requirements:
+                   - controller:
+                       node: backbone-wdc
+                       relationship: tosca.relationships.UsesController
+
+    princeton:
+      type: tosca.nodes.Site
+      properties:
+          display_name: Princeton
+          site_url: http://opencloud.us/
+          hosts_nodes: true
+      requirements:
+          - deployment:
+               node: campus
+               relationship: tosca.relationships.SiteDeployment
+               requirements:
+                   - controller:
+                       node: campus-princeton
+                       relationship: tosca.relationships.UsesController
+
+    stanford:
+      type: tosca.nodes.Site
+      properties:
+          display_name: Stanford
+          site_url: http://opencloud.us/
+          hosts_nodes: true 
+      requirements:
+          - deployment:
+               node: campus
+               relationship: tosca.relationships.SiteDeployment
+               requirements:
+                   - controller:
+                       node: campus-stanford
+                       relationship: tosca.relationships.UsesController
+
+    washington:
+      type: tosca.nodes.Site
+      properties:
+          display_name: Washington
+          site_url: http://opencloud.us/
+          hosts_nodes: false 
+      requirements:
+          - deployment:
+               node: campus
+               relationship: tosca.relationships.SiteDeployment
+               requirements:
+                   - controller:
+                       node: campus-washington
+                       relationship: tosca.relationships.UsesController
+
+    gtech:
+      type: tosca.nodes.Site
+      properties:
+          display_name: GTech
+          site_url: http://opencloud.us/
+          hosts_nodes: false 
+      requirements:
+          - deployment:
+               node: campus
+               relationship: tosca.relationships.SiteDeployment
+               requirements:
+                   - controller:
+                       node: campus-gatech
+                       relationship: tosca.relationships.UsesController
+
+    arizona:
+      type: tosca.nodes.Site
+      properties:
+          display_name: Arizona
+          site_url: http://opencloud.us/
+          hosts_nodes: false 
+      requirements:
+          - deployment:
+               node: campus
+               relationship: tosca.relationships.SiteDeployment
+               requirements:
+                   - controller:
+                       node: campus-arizona
+                       relationship: tosca.relationships.UsesController
+
+    internet2:
+      type: tosca.nodes.Site
+      properties:
+          display_name: Internet2
+          site_url: http://opencloud.us/
+          hosts_nodes: false 
+      requirements:
+          - deployment:
+               node: campus
+               relationship: tosca.relationships.SiteDeployment
+               requirements:
+                   - controller:
+                       node: campus-internet2
+                       relationship: tosca.relationships.UsesController
+
+    singapore:
+      type: tosca.nodes.Site
+      properties:
+          display_name: Singapore
+          site_url: http://opencloud.us/
+          hosts_nodes: false 
+      requirements:
+          - deployment:
+               node: campus
+               relationship: tosca.relationships.SiteDeployment
+               requirements:
+                   - controller:
+                       node: campus-singapore
+                       relationship: tosca.relationships.UsesController
+
+    onlab:
+      type: tosca.nodes.Site
+      properties:
+          display_name: ON.Lab
+          site_url: http://opencloud.us/
+          hosts_nodes: false 
+      requirements:
+          - deployment:
+               node: campus
+               relationship: tosca.relationships.SiteDeployment
+               requirements:
+                   - controller:
+                       node: campus-onlab
+                       relationship: tosca.relationships.UsesController
+
+# Users
+    padmin@vicci.org:
+      type: tosca.nodes.User
+      requirements:
+          - site:
+              node: princeton
+              relationship: tosca.relationships.MemberOfSite
+      properties:
+          is_admin: true
+          is_active: true
+          firstname: XOS
+          lastname: admin
+          password: letmein
+
+    scott@onlab.us:
+      type: tosca.nodes.User
+      requirements:
+          - site:
+              node: onlab
+              relationship: tosca.relationships.MemberOfSite
+      properties:
+          is_admin: true
+          is_active: true
+          firstname: Scott
+          lastname: Baker
+          password: letmein
+
+    llp@onlab.us:
+      type: tosca.nodes.User
+      requirements:
+          - site:
+              node: onlab
+              relationship: tosca.relationships.MemberOfSite
+      properties:
+          is_admin: true
+          is_active: true
+          firstname: Larry
+          lastname: Peterson
+          password: letmein
+
+    luca@onlab.us:
+      type: tosca.nodes.User
+      requirements:
+          - site:
+              node: onlab
+              relationship: tosca.relationships.MemberOfSite
+      properties:
+          is_admin: true
+          is_active: true
+          firstname: Luca
+          lastname: Prete
+          password: letmein
+
+    sapanb@cs.princeton.edu:
+      type: tosca.nodes.User
+      requirements:
+          - site:
+              node: onlab
+              relationship: tosca.relationships.MemberOfSite
+      properties:
+          is_admin: true
+          is_active: true
+          firstname: Sapan
+          lastname: Bhatia
+          password: letmein
+
+    tmack@cs.princeton.edu:
+      type: tosca.nodes.User
+      requirements:
+          - site:
+              node: princeton
+              relationship: tosca.relationships.MemberOfSite
+      properties:
+          is_admin: true
+          is_active: true
+          firstname: Tony
+          lastname: Mack
+          password: letmein
+
+    acb@cs.princeton.edu:
+      type: tosca.nodes.User
+      requirements:
+          - site:
+              node: princeton
+              relationship: tosca.relationships.MemberOfSite
+      properties:
+          is_admin: true
+          is_active: true
+          firstname: Andy
+          lastname: Bavier
+          password: letmein
+
+    mhw@cs.princeton.edu:
+      type: tosca.nodes.User
+      requirements:
+          - site:
+              node: princeton
+              relationship: tosca.relationships.MemberOfSite
+      properties:
+          is_admin: true
+          is_active: true
+          firstname: Mike
+          lastname: Wawrzoniak
+          password: letmein
+
+    jcnelson@cs.princeton.edu:
+      type: tosca.nodes.User
+      requirements:
+          - site:
+              node: princeton
+              relationship: tosca.relationships.MemberOfSite
+      properties:
+          is_admin: true
+          is_active: true
+          firstname: Jude
+          lastname: Nelson
+          password: letmein
+
+    rnobrega@internet2.edu:
+      type: tosca.nodes.User
+      requirements:
+          - site:
+              node: internet2
+              relationship: tosca.relationships.MemberOfSite
+      properties:
+          is_admin: true
+          is_active: true
+          firstname: Ryan
+          lastname: Nobrega
+          password: letmein
+
+    matt@internet2.edu:
+      type: tosca.nodes.User
+      requirements:
+          - site:
+              node: internet2
+              relationship: tosca.relationships.MemberOfSite
+      properties:
+          is_admin: true
+          is_active: true
+          firstname: Matthew
+          lastname: Zekauskas
+          password: letmein
+
+    jhh@cs.arizona.edu:
+      type: tosca.nodes.User
+      requirements:
+          - site:
+              node: arizona
+              relationship: tosca.relationships.MemberOfSite
+      properties:
+          is_admin: true
+          is_active: true
+          firstname: John
+          lastname: Hartman
+          password: letmein
+
+
+# Slices
+    princeton_publicdata:
+      type: tosca.nodes.Slice
+      requirements:
+          - site:
+              node: princeton
+              relationship: tosca.relationships.MemberOfSite
+
+# Services
+    syndicate:
+      type: tosca.nodes.Service
+      capabilities:
+          scalable:
+              properties:
+                  max_instances: 25
+                  min_instances: 1
+                  default_instances: 1
+# Nodes
+    node37.princeton.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: princeton
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node39.princeton.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: princeton
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node41.princeton.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: princeton
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node43.princeton.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: princeton
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node45.princeton.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: princeton
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node49.princeton.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: princeton
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node51.princeton.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: princeton
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node52.princeton.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: princeton
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node54.princeton.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: princeton
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node55.princeton.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: princeton
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node57.princeton.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: princeton
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node59.princeton.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: princeton
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node65.princeton.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: princeton
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node66.princeton.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: princeton
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node67.princeton.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: princeton
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node68.princeton.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: princeton
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node69.princeton.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: princeton
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node2.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node3.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node5.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node6.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node7.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node8.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node9.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node10.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node11.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node12.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node13.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node14.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node15.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node16.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node17.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node18.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node19.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node20.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node21.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node22.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node23.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node24.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node25.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node26.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node27.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node28.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node29.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node30.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node31.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node32.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node33.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node34.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node35.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node37.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node38.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node39.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node40.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node41.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node42.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node43.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node44.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node45.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node46.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node47.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node48.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node49.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node50.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node51.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node52.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node54.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node55.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node56.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node57.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node58.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node59.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node60.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node61.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node62.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node63.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node64.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node67.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node68.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node69.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
+
+
+    node70.stanford.vicci.org:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: stanford
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: campus
+            relationship: tosca.relationships.MemberOfDeployment
diff --git a/xos/configurations/opencloud/wait_for_xos.sh b/xos/configurations/opencloud/wait_for_xos.sh
new file mode 100644
index 0000000..4f486af
--- /dev/null
+++ b/xos/configurations/opencloud/wait_for_xos.sh
@@ -0,0 +1,12 @@
+#! /bin/bash
+echo "Waiting for XOS to come up"
+until http 0.0.0.0:80 &> /dev/null
+do
+    sleep 1
+    RUNNING_CONTAINER=`sudo docker ps|grep "xos"|awk '{print $$NF}'`
+    if [[ $RUNNING_CONTAINER == "" ]]; then
+        echo Container may have failed. check with \"make showlogs\'
+        exit 1
+    fi
+done
+echo "XOS is ready"
diff --git a/xos/configurations/openvpn/Makefile b/xos/configurations/openvpn/Makefile
new file mode 100644
index 0000000..aa6f2d5
--- /dev/null
+++ b/xos/configurations/openvpn/Makefile
@@ -0,0 +1,59 @@
+MYIP:=$(shell hostname -i)
+
+cloudlab: common_cloudlab xos
+
+xos:
+	sudo MYIP=$(MYIP) docker-compose up -d
+	bash ../common/wait_for_xos.sh
+	sudo docker-compose run xos python /opt/xos/tosca/run.py none /opt/xos/configurations/common/fixtures.yaml
+	sudo docker-compose run xos python /opt/xos/tosca/run.py none /opt/xos/configurations/common/mydeployment.yaml
+	sudo MYIP=$(MYIP) docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/common/cloudlab-openstack.yaml
+	sudo MYIP=$(MYIP) docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/nodes.yaml
+
+frontend:
+	sudo make -f ../common/Makefile.prereqs
+	sudo docker-compose up -d
+	bash ../common/wait_for_xos.sh
+	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/frontend/sample.yaml
+
+containers:
+	cd ../../../containers/xos; make devel
+	cd ../../../containers/synchronizer; make
+	cd ../../../containers/openvpn; make
+
+common_cloudlab:
+	make -C ../common -f Makefile.cloudlab
+
+stop:
+	sudo MYIP=$(MYIP) docker-compose stop
+
+showlogs:
+	sudo MYIP=$(MYIP) docker-compose logs
+
+rm: stop
+	sudo MYIP=$(MYIP) docker-compose rm
+
+ps:
+	sudo MYIP=$(MYIP) docker-compose ps
+
+enter-xos:
+	sudo docker exec -it openvpn_xos_1 bash
+
+enter-synchronizer:
+	sudo docker exec -it openvpn_xos_synchronizer_openvpn_1 bash
+
+upgrade_pkgs:
+	sudo pip install httpie --upgrade
+
+rebuild_xos:
+	make -C ../../../containers/xos devel
+
+rebuild_synchronizer:
+	make -C ../../../containers/synchronizer
+
+cleanup_docker: rm
+	sudo docker rm -v $(docker ps -a -q -f status=exited) || true
+	docker rm -v $(docker ps -a -q -f status=exited) || true
+	sudo docker rmi $(docker images -qf "dangling=true") || true
+	socker rmi $(docker images -qf "dangling=true") || true
+	sudo docker run -v /var/run/docker.sock:/var/run/docker.sock -v /var/lib/docker:/var/lib/docker --rm martin/docker-cleanup-volumes || true
diff --git a/xos/configurations/openvpn/docker-compose.yml b/xos/configurations/openvpn/docker-compose.yml
new file mode 100644
index 0000000..e609838
--- /dev/null
+++ b/xos/configurations/openvpn/docker-compose.yml
@@ -0,0 +1,62 @@
+xos_db:
+    image: xosproject/xos-postgres
+    expose:
+        - "5432"
+
+xos_synchronizer_openstack:
+    image: xosproject/xos-synchronizer-openstack
+    command: bash -c "sleep 120; python /opt/xos/synchronizers/openstack/xos-synchronizer.py"
+    labels:
+        org.xosproject.kind: synchronizer
+        org.xosproject.target: openstack
+    links:
+        - xos_db
+    extra_hosts:
+        - ctl:${MYIP}
+    volumes:
+        - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
+        - ./images:/opt/xos/images:ro
+
+xos_synchronizer_openvpn:
+    image: xosproject/xos-openvpn
+    command: bash -c "sleep 120 ; python /opt/xos/synchronizers/openvpn/openvpn-synchronizer.py -C /opt/xos/synchronizers/openvpn/openvpn_config"
+    labels:
+        org.xosproject.kind: synchronizer
+        org.xosproject.target: openvpn
+    links:
+        - xos_db
+    extra_hosts:
+        - ctl:${MYIP}
+    volumes:
+        - ../setup/id_rsa:/opt/xos/synchronizers/openvpn/openvpn_private_key:ro  # private key
+    volumes_from:
+        - xos_openvpn_data:rw
+
+xos_openvpn_data:
+    image: xosproject/xos-openvpn
+    links:
+        - xos_db
+    extra_hosts:
+        - ctl:${MYIP}
+    volumes:
+        - /opt/openvpn
+
+# FUTURE
+#xos_swarm_synchronizer:
+#    image: xosproject/xos-swarm-synchronizer
+#    labels:
+#        org.xosproject.kind: synchronizer
+#        org.xosproject.target: swarm
+
+xos:
+    image: xosproject/xos-openvpn
+    command: python /opt/xos/manage.py runserver 0.0.0.0:8000 --insecure --makemigrations
+    ports:
+        - "9999:8000"
+    links:
+        - xos_db
+    volumes:
+      - ../setup:/root/setup:ro
+      - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
+    volumes_from:
+      - xos_openvpn_data:rw
diff --git a/xos/configurations/syndicate/MS.mk b/xos/configurations/syndicate/MS.mk
new file mode 100644
index 0000000..dc65237
--- /dev/null
+++ b/xos/configurations/syndicate/MS.mk
@@ -0,0 +1,47 @@
+# MS build parameters
+
+MS_APP_ADMIN_EMAIL        ?= sites@opencloud.us
+MS_APP_PUBLIC_HOST				?= localhost
+MS_APP_ADMIN_PUBLIC_KEY   ?= ms/admin.pub
+MS_APP_ADMIN_PRIVATE_KEY  ?= ms/admin.pem
+
+MS_APP_NAME               ?= syndicate-ms
+MS_APP_PUBLIC_KEY         ?= ms/syndicate.pub
+MS_APP_PRIVATE_KEY        ?= ms/syndicate.pem
+
+MS_DEVEL                  ?= true
+
+$(MS_APP_ADMIN_PRIVATE_KEY):
+	openssl genrsa 4096 > "$@"
+
+$(MS_APP_ADMIN_PUBLIC_KEY): $(MS_APP_ADMIN_PRIVATE_KEY)
+	openssl rsa -in "$<" -pubout > "$@"
+
+$(MS_APP_PRIVATE_KEY):
+	openssl genrsa 4096 > "$@"
+
+$(MS_APP_PUBLIC_KEY): $(MS_APP_PRIVATE_KEY)
+	openssl rsa -in "$<" -pubout > "$@"
+
+ms/admin_info.py: ms/admin_info.pyin $(MS_APP_ADMIN_PUBLIC_KEY) $(MS_APP_PUBLIC_KEY) $(MS_APP_PRIVATE_KEY)
+	mkdir -p "$(@D)"
+	cat "$<" | \
+		sed -e 's~@MS_APP_NAME@~$(MS_APP_NAME)~g;' | \
+		sed -e 's~@MS_APP_ADMIN_EMAIL@~$(MS_APP_ADMIN_EMAIL)~g;' | \
+		sed -e 's~@MS_DEVEL@~$(MS_DEVEL)~g;' | \
+		sed -e 's~@MS_APP_ADMIN_PUBLIC_KEY@~$(shell cat $(MS_APP_ADMIN_PUBLIC_KEY) | tr "\n" "@" | sed 's/@/\\n/g')~g;' | \
+		sed -e 's~@MS_APP_PRIVATE_KEY@~$(shell cat $(MS_APP_PRIVATE_KEY) | tr "\n" "@" | sed 's/@/\\n/g')~g;' | \
+		sed -e 's~@MS_APP_PUBLIC_KEY@~$(shell cat $(MS_APP_PUBLIC_KEY) | tr "\n" "@" | sed 's/@/\\n/g')~g;' > "$@"
+
+ms/app.yaml: ms/app.yamlin
+	mkdir -p "$(@D)"
+	cat "$<" | \
+		sed -e 's~@MS_APP_NAME@~$(MS_APP_NAME)~g;' | \
+		sed -e 's~@MS_APP_PUBLIC_HOST@~$(MS_APP_PUBLIC_HOST)~g;' > "$@"
+
+clean: 
+	rm -f ms/admin_info.py ms/app.yaml
+
+clean_certs:
+	rm -f $(MS_APP_ADMIN_PUBLIC_KEY) $(MS_APP_ADMIN_PRIVATE_KEY) $(MS_APP_PUBLIC_KEY) $(MS_APP_PRIVATE_KEY)
+
diff --git a/xos/configurations/syndicate/Makefile b/xos/configurations/syndicate/Makefile
new file mode 100644
index 0000000..3b29ee5
--- /dev/null
+++ b/xos/configurations/syndicate/Makefile
@@ -0,0 +1,62 @@
+MYIP:=$(shell hostname -i)
+
+cloudlab: common_cloudlab xos
+
+devstack: upgrade_pkgs common_devstack xos
+
+xos: syndicate_config
+	sudo MYIP=$(MYIP) docker-compose up -d
+	bash ../common/wait_for_xos.sh
+	sudo docker-compose run xos python /opt/xos/tosca/run.py none /opt/xos/configurations/common/fixtures.yaml
+	sudo docker-compose run xos python /opt/xos/tosca/run.py none /opt/xos/configurations/common/mydeployment.yaml
+	sudo MYIP=$(MYIP) docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/common/cloudlab-openstack.yaml
+	sudo MYIP=$(MYIP) docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/nodes.yaml
+
+containers:
+	cd ../../../containers/xos; make devel
+	cd ../../../containers/synchronizer; make
+	cd ../../../containers/syndicate-ms; make
+
+# see Makefiles on this project: https://github.com/syndicate-storage/syndicate-core
+include MS.mk
+syndicate_config: ms/admin_info.py ms/app.yaml
+
+common_cloudlab:
+	make -C ../common -f Makefile.cloudlab
+
+common_devstack:
+	make -C ../common -f Makefile.devstack
+
+stop:
+	sudo MYIP=$(MYIP) docker-compose stop
+
+showlogs:
+	sudo MYIP=$(MYIP) docker-compose logs
+
+rm: stop
+	sudo MYIP=$(MYIP) docker-compose rm --force
+
+ps:
+	sudo MYIP=$(MYIP) docker-compose ps
+
+enter-xos:
+	sudo docker exec -it syndicate_xos_1 bash
+
+enter-synchronizer:
+	sudo docker exec -it syndicate_xos_synchronizer_openstack_1 bash
+
+enter-ms:
+	sudo docker exec -it syndicate_xos_syndicate_ms_1 bash
+
+upgrade_pkgs:
+	sudo pip install httpie --upgrade
+
+rebuild_xos:
+	make -C ../../../containers/xos devel
+
+rebuild_synchronizer:
+	make -C ../../../containers/synchronizer
+
+rebuild_syndicate_ms:
+	make -C ../../../containers/syndicate-ms
+
diff --git a/xos/configurations/syndicate/README.md b/xos/configurations/syndicate/README.md
new file mode 100644
index 0000000..f78afd9
--- /dev/null
+++ b/xos/configurations/syndicate/README.md
@@ -0,0 +1,6 @@
+# XOS w/Syndicate environment
+
+This is a test environment derived from the [devel](../devel) environment.
+
+It implements the Metadata Service (MS) within an additional Docker container
+
diff --git a/xos/configurations/syndicate/docker-compose.yml b/xos/configurations/syndicate/docker-compose.yml
new file mode 100644
index 0000000..d2d3dbb
--- /dev/null
+++ b/xos/configurations/syndicate/docker-compose.yml
@@ -0,0 +1,51 @@
+xos_db:
+    image: xosproject/xos-postgres
+    expose:
+        - "5432"
+
+xos_syndicate_ms:
+    build:  ../../../containers/syndicate-ms/
+    expose:
+        - "8080"
+    volumes:
+      - ./ms/app.yaml:/usr/src/syndicate/ms/app.yaml
+      - ./ms/admin_info.py:/usr/src/syndicate/ms/common/admin_info.py
+
+xos_synchronizer_openstack:
+    image: xosproject/xos-synchronizer-openstack
+    command: bash -c "sleep 120; python /opt/xos/synchronizers/openstack/xos-synchronizer.py"
+    labels:
+        org.xosproject.kind: synchronizer
+        org.xosproject.target: openstack
+    links:
+        - xos_db
+    extra_hosts:
+        - ctl:${MYIP}
+    volumes:
+        - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
+        - ./images:/opt/xos/images:ro
+
+xos_synchronizer_exampleservice:
+    image: xosproject/xos-synchronizer-openstack
+    command: bash -c "sleep 120; python /opt/xos/synchronizers/exampleservice/exampleservice-synchronizer.py -C /opt/xos/synchronizers/exampleservice/exampleservice_config"
+    labels:
+        org.xosproject.kind: synchronizer
+        org.xosproject.target: exampleservice
+    links:
+        - xos_db
+    extra_hosts:
+        - ctl:${MYIP}
+    volumes:
+        - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
+        - ../setup/id_rsa:/opt/xos/synchronizers/exampleservice/exampleservice_private_key:ro
+
+xos:
+    image: xosproject/xos
+    command: python /opt/xos/manage.py runserver 0.0.0.0:8000 --insecure --makemigrations
+    ports:
+        - "9999:8000"
+    links:
+        - xos_db
+    volumes:
+      - ../setup:/root/setup:ro
+      - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
diff --git a/xos/configurations/syndicate/ms/admin_info.pyin b/xos/configurations/syndicate/ms/admin_info.pyin
new file mode 100644
index 0000000..9dee928
--- /dev/null
+++ b/xos/configurations/syndicate/ms/admin_info.pyin
@@ -0,0 +1,12 @@
+#!/usr/bin/python
+
+# AUTO-GENERATED FILE
+
+ADMIN_PUBLIC_KEY = """@MS_APP_ADMIN_PUBLIC_KEY@""".strip()
+ADMIN_EMAIL = "@MS_APP_ADMIN_EMAIL@".strip()
+ADMIN_ID = 0
+
+SYNDICATE_NAME = "@MS_APP_NAME@".strip()
+SYNDICATE_PUBKEY = """@MS_APP_PUBLIC_KEY@""".strip()
+SYNDICATE_PRIVKEY = """@MS_APP_PRIVATE_KEY@""".strip()
+
diff --git a/xos/configurations/syndicate/ms/app.yamlin b/xos/configurations/syndicate/ms/app.yamlin
new file mode 100644
index 0000000..ea8080b
--- /dev/null
+++ b/xos/configurations/syndicate/ms/app.yamlin
@@ -0,0 +1,47 @@
+application: @MS_APP_NAME@
+version: 1
+runtime: python27
+api_version: 1
+threadsafe: yes
+
+inbound_services:
+- warmup
+
+builtins:
+- appstats: on
+- admin_redirect: on
+- deferred: on
+
+handlers:
+- url: /cron.*
+  script: cron.app
+  login: admin
+
+- url: /CERT.*
+  script: msapp.app
+  secure: always
+
+- url: /USER.*
+  script: msapp.app
+  secure: always
+
+- url: /VOLUME.*
+  script: msapp.app
+  secure: always
+
+- url: .*
+  script: msapp.app
+  secure: never
+
+libraries:
+- name: webapp2
+  version: "2.5.2"
+- name: lxml
+  version: latest
+- name: pycrypto
+  version: latest
+- name: django
+  version: 1.4
+
+env_variables:
+  MS_APP_PUBLIC_HOST: '@MS_APP_PUBLIC_HOST@'
diff --git a/xos/configurations/test-standalone/Makefile b/xos/configurations/test-standalone/Makefile
new file mode 100644
index 0000000..3566d80
--- /dev/null
+++ b/xos/configurations/test-standalone/Makefile
@@ -0,0 +1,114 @@
+MYIP:=$(shell hostname -i)
+CONFIG_DIR:=$(shell pwd)
+DOCKER_COMPOSE_YML=./onboarding-docker-compose/docker-compose.yml
+BOOTSTRAP_YML=./docker-compose-bootstrap.yml
+DOCKER_PROJECT=teststandalone
+XOS_BOOTSTRAP_PORT=9998
+XOS_UI_PORT=9999
+
+define TRUNCATE_FN
+	CREATE OR REPLACE FUNCTION truncate_tables(username IN VARCHAR) RETURNS void AS $$$$
+	DECLARE
+			statements CURSOR FOR
+					SELECT tablename FROM pg_tables
+					WHERE tableowner = username AND schemaname = 'public';
+	BEGIN
+			FOR stmt IN statements LOOP
+					EXECUTE 'TRUNCATE TABLE ' || quote_ident(stmt.tablename) || ' CASCADE;';
+			END LOOP;
+	END;
+	$$$$ LANGUAGE plpgsql;
+endef
+export TRUNCATE_FN
+
+prepare: xos
+	sudo docker exec -i teststandalone_xos_ui_1 bash -c "cd /opt/xos/tests/api; npm install --production"
+	sudo docker exec teststandalone_xos_ui_1 pip install dredd_hooks
+
+xos: prereqs bootstrap onboarding
+
+prereqs:
+	sudo make -f ../common/Makefile.prereqs
+
+bootstrap:
+	echo "[BOOTSTRAP]"
+	sudo rm -f onboarding-docker-compose/docker-compose.yml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f docker-compose-bootstrap.yml up -d
+	bash ../common/wait_for_xos_port.sh 9998
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(BOOTSTRAP_YML) run -e CONFIG_DIR=$(CONFIG_DIR) xos_bootstrap_ui python /opt/xos/tosca/run.py none /opt/xos/configurations/test-standalone/xos.yaml
+
+onboarding:
+	echo "[ONBOARDING]"
+	bash ../common/wait_for_onboarding_ready.sh 9998 xos
+	sudo bash -c "echo somekey > key_import/vsg_rsa"
+	sudo bash -c "echo somekey > key_import/vsg_rsa.pub"
+	sudo bash -c "echo somekey > key_import/volt_rsa"
+	sudo bash -c "echo somekey > key_import/volt_rsa.pub"
+	sudo bash -c "echo somekey > key_import/onos_rsa"
+	sudo bash -c "echo somekey > key_import/onos_rsa.pub"
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(BOOTSTRAP_YML) run xos_bootstrap_ui python /opt/xos/tosca/run.py None /opt/xos/configurations/common/disable-onboarding.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(BOOTSTRAP_YML) run xos_bootstrap_ui python /opt/xos/tosca/run.py None /opt/xos/onboard/vrouter/vrouter-onboard.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(BOOTSTRAP_YML) run xos_bootstrap_ui python /opt/xos/tosca/run.py None /opt/xos/onboard/volt/volt-onboard.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(BOOTSTRAP_YML) run xos_bootstrap_ui python /opt/xos/tosca/run.py None /opt/xos/onboard/vsg/vsg-onboard.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(BOOTSTRAP_YML) run xos_bootstrap_ui python /opt/xos/tosca/run.py None /opt/xos/onboard/vtr/vtr-onboard.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(BOOTSTRAP_YML) run xos_bootstrap_ui python /opt/xos/tosca/run.py None /opt/xos/onboard/onos/onos-onboard.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(BOOTSTRAP_YML) run xos_bootstrap_ui python /opt/xos/tosca/run.py None /opt/xos/configurations/common/enable-onboarding.yaml
+	bash ../common/wait_for_onboarding_ready.sh 9998 services/vrouter
+	bash ../common/wait_for_onboarding_ready.sh 9998 services/volt
+	bash ../common/wait_for_onboarding_ready.sh 9998 services/vsg
+	bash ../common/wait_for_onboarding_ready.sh 9998 services/vtr
+	bash ../common/wait_for_onboarding_ready.sh 9998 services/onos
+	bash ../common/wait_for_onboarding_ready.sh 9998 xos
+	bash ../common/wait_for_xos_port.sh 9999
+
+restore-initial-db-status:
+	sudo docker exec teststandalone_xos_db_1 psql -U postgres -d xos -c "$$TRUNCATE_FN" >/dev/null 2>&1
+	sudo docker exec teststandalone_xos_db_1 psql -U postgres -d xos -c "SELECT truncate_tables('postgres');" >/dev/null 2>&1
+	sudo docker exec teststandalone_xos_db_1 psql -U postgres -d xos -c "SELECT setval('core_tenant_id_seq', 1)" >/dev/null 2>&1
+	sudo docker exec teststandalone_xos_db_1 psql -U postgres -d xos -c "SELECT setval('core_deployment_id_seq', 1)" >/dev/null 2>&1
+	sudo docker exec teststandalone_xos_db_1 psql -U postgres -d xos -c "SELECT setval('core_flavor_id_seq', 1)" >/dev/null 2>&1
+	sudo docker exec teststandalone_xos_db_1 psql -U postgres -d xos -c "SELECT setval('core_service_id_seq', 1)" >/dev/null 2>&1
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/manage.py --noobserver --nomodelpolicy loaddata /opt/xos/core/fixtures/core_initial_data.json
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py none /opt/xos/configurations/common/fixtures.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py none /opt/xos/configurations/common/mydeployment.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/frontend/sample.yaml
+
+
+test: restore-initial-db-status
+	# RUN TESTS
+	sudo docker cp ../../../apiary.apib teststandalone_xos_ui_1:/opt/xos/tests/api/apiary.apib
+	sudo docker exec -i teststandalone_xos_ui_1 bash -c "cd /opt/xos/tests/api; npm test"
+
+test-tosca: restore-initial-db-status
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui bash -c "cd /opt/xos/tosca/tests; python ./alltests.py"
+
+base-container: 
+	cd ../../../containers/xos; make base
+
+devel-container: base-container
+	cd ../../../containers/xos; make devel
+	cd ../../../containers/synchronizer; make
+	cd ../../../containers/onboarding_synchronizer; make
+
+containers: devel-container
+	cd ../../../containers/xos; make test
+
+stop:
+	test ! -s $(DOCKER_COMPOSE_YML) || sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) stop
+	sudo docker-compose -f $(BOOTSTRAP_YML) stop
+
+showlogs:
+	sudo docker-compose logs
+
+rm: stop
+	test ! -s $(DOCKER_COMPOSE_YML) || sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) rm -f
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(BOOTSTRAP_YML) rm -f
+
+docker-clean:
+	sudo docker rm -f $(shell sudo docker ps -aq)
+
+enter-xos:
+	sudo docker exec -ti teststandalone_xos_ui_1 bash
+
+enter-xos-db:
+	sudo docker exec -ti teststandalone_xos_db_1 bash
diff --git a/xos/configurations/test-standalone/README.md b/xos/configurations/test-standalone/README.md
new file mode 100644
index 0000000..32e7c95
--- /dev/null
+++ b/xos/configurations/test-standalone/README.md
@@ -0,0 +1,11 @@
+# API Test Configuration
+
+This configuration is intended to be used to test the API,
+to use it:
+
+- `make containers`
+- `make`
+
+Then anytime is needed `make test` (`xos/api` folder is shared with the container)
+
+Note that this test will be automatically executed by (Jenkins)[https://jenkins.opencord.org/]
\ No newline at end of file
diff --git a/xos/configurations/test-standalone/docker-compose-bootstrap.yml b/xos/configurations/test-standalone/docker-compose-bootstrap.yml
new file mode 100644
index 0000000..00a43f3
--- /dev/null
+++ b/xos/configurations/test-standalone/docker-compose-bootstrap.yml
@@ -0,0 +1,34 @@
+xos_db:
+    image: xosproject/xos-postgres
+    expose:
+        - "5432"
+
+xos_bootstrap_ui:
+    image: xosproject/xos
+    command: python /opt/xos/manage.py runserver 0.0.0.0:9998 --insecure --makemigrations
+    ports:
+        - "9998:9998"
+    links:
+        - xos_db
+    volumes:
+      - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config
+      - ../vtn/files/xos_vtn_config:/opt/xos/xos_configuration/xos_vtn_config:ro
+
+xos_synchronizer_onboarding:
+    image: xosproject/xos-synchronizer-onboarding
+    command: bash -c "cd /opt/xos/synchronizers/onboarding; ./run.sh"
+#    command: sleep 86400
+    labels:
+        org.xosproject.kind: synchronizer
+        org.xosproject.target: onboarding
+    links:
+        - xos_db
+    volumes:
+#        - .:/root/setup:ro
+        - /var/run/docker.sock:/var/run/docker.sock
+        - ./key_import:/opt/xos/key_import:ro
+        - ./onboarding-docker-compose:/opt/xos/synchronizers/onboarding/docker-compose
+    log_driver: "json-file"
+    log_opt:
+            max-size: "100k"
+            max-file: "5"
diff --git a/xos/configurations/test-standalone/xos.yaml b/xos/configurations/test-standalone/xos.yaml
new file mode 100644
index 0000000..62331d0
--- /dev/null
+++ b/xos/configurations/test-standalone/xos.yaml
@@ -0,0 +1,27 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Onboard the exampleservice
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    xos:
+      type: tosca.nodes.XOS
+      properties:
+        ui_port: 9999
+        bootstrap_ui_port: 9998
+        docker_project_name: teststandalone
+        frontend_only: true
+        source_ui_image: xosproject/xos-test
+
+    /opt/xos/xos_configuration/xos_common_config:
+      type: tosca.nodes.XOSVolume
+      properties:
+          host_path: { path_join: [ SELF, CONFIG_DIR, ../common/xos_common_config, ENV_VAR ] }
+          read_only: false
+      requirements:
+          - xos:
+             node: xos
+             relationship: tosca.relationships.UsedByXOS
diff --git a/xos/configurations/test/Makefile b/xos/configurations/test/Makefile
new file mode 100644
index 0000000..d4e54fd
--- /dev/null
+++ b/xos/configurations/test/Makefile
@@ -0,0 +1,44 @@
+MYIP:=$(shell hostname -i)
+
+cloudlab: common_cloudlab xos
+
+devstack: upgrade_pkgs common_devstack devstack_net_fix xos
+
+xos:
+	sudo MYIP=$(MYIP) docker-compose up -d
+	bash ../common/wait_for_xos.sh
+	sudo docker-compose run xos python /opt/xos/tosca/run.py none /opt/xos/configurations/common/fixtures.yaml
+	sudo docker-compose run xos python /opt/xos/tosca/run.py none /opt/xos/configurations/common/mydeployment.yaml
+	sudo MYIP=$(MYIP) docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/common/cloudlab-openstack.yaml
+	sudo MYIP=$(MYIP) docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/nodes.yaml
+	sudo MYIP=$(MYIP) docker-compose run xos bash -c "cd /opt/xos/tosca/tests; python ./alltests.py"
+	sudo MYIP=$(MYIP) docker-compose run xos bash -c "cd /opt/xos/tosca/tests; python ./allObserverTests.py"
+
+containers:
+	cd ../../../containers/xos; make devel
+	cd ../../../containers/synchronizer; make
+
+common_cloudlab:
+	make -C ../common -f Makefile.cloudlab
+
+common_devstack:
+	make -C ../common -f Makefile.devstack
+
+stop:
+	sudo MYIP=$(MYIP) docker-compose stop
+
+showlogs:
+	sudo MYIP=$(MYIP) docker-compose logs
+
+rm: stop
+	sudo MYIP=$(MYIP) docker-compose rm
+
+ps:
+	sudo MYIP=$(MYIP) docker-compose ps
+
+devstack_net_fix:
+	sudo ../common/devstack/net-fix.sh
+	sudo bash -c "source ../setup/admin-openrc.sh; neutron subnet-update private-subnet --dns-nameservers list=true 8.8.8.8 8.8.4.4"
+
+upgrade_pkgs:
+	sudo pip install httpie --upgrade
diff --git a/xos/configurations/test/README.md b/xos/configurations/test/README.md
new file mode 100644
index 0000000..37af594
--- /dev/null
+++ b/xos/configurations/test/README.md
@@ -0,0 +1,4 @@
+#CORD Test Configuration
+
+This configuration launches the XOS container on cloudlab and runs a test suite. The test results will be printed to
+the console, and then the docker container will exit. 
diff --git a/xos/configurations/test/docker-compose.yml b/xos/configurations/test/docker-compose.yml
new file mode 100644
index 0000000..91cd4e3
--- /dev/null
+++ b/xos/configurations/test/docker-compose.yml
@@ -0,0 +1,24 @@
+xos_db:
+    image: xosproject/xos-postgres
+    expose:
+        - "5432"
+
+# FUTURE
+#xos_swarm_synchronizer:
+#    image: xosproject/xos-swarm-synchronizer
+#    labels:
+#        org.xosproject.kind: synchronizer
+#        org.xosproject.target: swarm
+
+xos:
+    image: xosproject/xos-synchronizer-openstack  # Because we test the observer too
+    command: python /opt/xos/manage.py runserver 0.0.0.0:8000 --insecure --makemigrations
+    ports:
+        - "9999:8000"
+    links:
+        - xos_db
+    extra_hosts:
+        - ctl:${MYIP}
+    volumes:
+      - ../setup:/root/setup:ro
+      - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
diff --git a/xos/configurations/vtn/Makefile b/xos/configurations/vtn/Makefile
new file mode 100644
index 0000000..1315b39
--- /dev/null
+++ b/xos/configurations/vtn/Makefile
@@ -0,0 +1,54 @@
+SETUPDIR:=../setup
+MYIP:=$(shell hostname -i)
+
+cloudlab: common_cloudlab ansible_hosts xos
+
+devstack: upgrade_pkgs common_devstack ansible_hosts xos
+
+xos: vtn_network_cfg_json
+	sudo MYIP=$(MYIP) docker-compose up -d
+	bash ../common/wait_for_xos.sh
+	sudo MYIP=$(MYIP) docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/common/fixtures.yaml
+	sudo MYIP=$(MYIP) docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/common/base.yaml
+	sudo MYIP=$(MYIP) docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/nodes.yaml
+	sudo MYIP=$(MYIP) docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/vtn/vtn.yaml
+
+containers:
+	cd ../../../containers/xos; make devel
+	cd ../../../containers/synchronizer; make
+
+common_cloudlab:
+	make -C ../common -f Makefile.cloudlab
+
+common_devstack:
+	make -C ../common -f Makefile.devstack
+
+vtn_network_cfg_json:
+	export SETUPDIR=$(SETUPDIR); bash ../cord/make-vtn-networkconfig-json.sh
+
+ansible_hosts:
+	sudo bash -c "export SETUPDIR=$(SETUPDIR); scripts/gen-inventory.sh"
+
+stop:
+	sudo MYIP=$(MYIP) docker-compose stop
+
+showlogs:
+	sudo MYIP=$(MYIP) docker-compose logs
+
+rm: stop
+	sudo MYIP=$(MYIP) docker-compose rm
+
+ps:
+	sudo MYIP=$(MYIP) docker-compose ps
+
+enter-xos:
+	sudo docker exec -it vtn_xos_1 bash
+
+enter-synchronizer:
+	sudo docker exec -it vtn_xos_synchronizer_openstack_1 bash
+
+upgrade_pkgs:
+	sudo pip install httpie --upgrade
+
+destroy-networks:
+	sudo ../../tools/destroy-all-networks.sh
diff --git a/xos/configurations/vtn/README.md b/xos/configurations/vtn/README.md
new file mode 100644
index 0000000..f4c8248
--- /dev/null
+++ b/xos/configurations/vtn/README.md
@@ -0,0 +1,80 @@
+# XOS+VTN development environment
+
+This goal is to use this configuration to do basic end-to-end development of XOS and VTN.  
+It launches
+XOS in three Docker containers (development GUI, Synchronizer, database) and configures XOS
+to talk to an OpenStack backend.  *docker-compose* is used to manage the containers.
+
+See [the VTN README](../cord/README-VTN.md) for more information.
+
+## How to run it
+
+The configuration can be either run on [CloudLab](http://cloudlab.us) (controlling
+an OpenStack backend set up by a CloudLab profile) or used with a basic
+[DevStack](http://docs.openstack.org/developer/devstack/) configuration.
+
+### CloudLab
+
+To get started on CloudLab:
+* Create an experiment using the *OpenStack* profile.  Choose *Kilo* and
+disable security groups.
+* Wait until you get an email from CloudLab with title "OpenStack Instance Finished Setting Up".
+* Login to the *ctl* node of your experiment and run:
+```
+ctl:~$ git clone https://github.com/open-cloud/xos.git
+ctl:~$ cd xos/xos/configurations/vtn/
+ctl:~/xos/xos/configurations/vtn$ make cloudlab
+```
+
+The configuration provides an Ansible script that automates the configuration
+steps outlined in [the VTN README](../cord/README-VTN.md).  Run:
+```
+ctl:~/xos/xos/configurations/vtn$ make destroy-networks
+ctl:~/xos/xos/configurations/vtn$ sudo ansible-playbook setup.yml
+```
+
+
+### DevStack
+
+*NOTE: THIS CONFIGURATION IS NOT YET WORKING WITH DEVSTACK.*
+
+The following instructions can be used to install DevStack and XOS together
+on a single node.  This setup has been run successfully in a VirtualBox VM
+with 2 CPUs and 4096 GB RAM.
+
+First, if you happen to be installing DevStack on a CloudLab node, you can
+configure about 1TB of unallocated disk space for DevStack as follows:
+```
+~$ sudo mkdir -p /opt/stack
+~$ sudo /usr/testbed/bin/mkextrafs /opt/stack
+```
+
+To install DevStack and XOS:
+
+```
+~$ git clone https://github.com/open-cloud/xos.git
+~$ git clone https://git.openstack.org/openstack-dev/devstack
+~$ cd devstack
+~/devstack$ cp ../xos/xos/configurations/common/devstack/local.conf .
+~/devstack$ ./stack.sh
+~/devstack$ cd ../xos/xos/configurations/devel/
+~/xos/xos/configurations/devel$ make devstack
+```
+
+## Docker Helpers
+
+Stop the containers: `make stop`
+
+Restart the containers: `make stop; make [cloudlab|devstack]`
+
+Delete the containers and relaunch them: `make rm; make [cloudlab|devstack]`
+
+Build the containers from scratch using the local XOS source tree: `make containers`
+
+View logs: `make showlogs`
+
+See what containers are running: `make ps`
+
+Open a shell on the XOS container: `make enter-xos`
+
+Open a shell on the Synchronizer container: `make enter-synchronizer`
diff --git a/xos/configurations/vtn/cord-vtn-vsg.yaml b/xos/configurations/vtn/cord-vtn-vsg.yaml
new file mode 100644
index 0000000..c228a80
--- /dev/null
+++ b/xos/configurations/vtn/cord-vtn-vsg.yaml
@@ -0,0 +1,180 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Just enough Tosca to get the vSG slice running on VTN-Cloudlab
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    # CORD Services
+    service_volt:
+      type: tosca.nodes.Service
+      requirements:
+          - vsg_tenant:
+              node: service_vsg
+              relationship: tosca.relationships.TenantOfService
+      properties:
+          view_url: /admin/cord/voltservice/$id$/
+          kind: vOLT
+
+    public_addresses:
+      type: tosca.nodes.AddressPool
+      properties:
+          addresses: 10.123.0.128/25
+
+    service_vsg:
+      type: tosca.nodes.VSGService
+      requirements:
+          - vbng_tenant:
+              node: service_vbng
+              relationship: tosca.relationships.TenantOfService
+      properties:
+          view_url: /admin/cord/vsgservice/$id$/
+          backend_network_label: hpc_client
+          public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }
+          private_key_fn: /opt/xos/synchronizers/vcpe/vcpe_private_key
+          wan_container_gateway_ip: 10.123.0.1
+          wan_container_gateway_mac: 00:8c:fa:5b:09:d8
+          wan_container_netbits: 24
+          dns_servers: 8.8.8.8, 8.8.4.4
+#          node_label: label_vsg
+      artifacts:
+          pubkey: /opt/xos/synchronizers/vcpe/vcpe_public_key
+
+    service_vbng:
+      type: tosca.nodes.VBNGService
+      properties:
+          view_url: /admin/cord/vbngservice/$id$/
+# if unspecified, vbng observer will look for an ONOSApp Tenant and
+# generate a URL from its IP address
+#          vbng_url: http://10.11.10.24:8181/onos/virtualbng/
+
+    Private:
+      type: tosca.nodes.NetworkTemplate
+
+    management:
+      type: tosca.nodes.network.Network.XOS
+      properties:
+          no-create: true
+          no-delete: true
+          no-update: true
+
+    mysite:
+      type: tosca.nodes.Site
+
+    label_vsg:
+      type: tosca.nodes.NodeLabel
+
+    # Networks required by the CORD setup
+    mysite_vsg-access:
+      type: tosca.nodes.network.Network
+      properties:
+          ip_version: 4
+      requirements:
+          - network_template:
+              node: Private
+              relationship: tosca.relationships.UsesNetworkTemplate
+          - owner:
+              node: mysite_vsg
+              relationship: tosca.relationships.MemberOfSlice
+          - connection:
+              node: mysite_vsg
+              relationship: tosca.relationships.ConnectsToSlice
+
+    # CORD Slices
+    mysite_vsg:
+      description: vSG Controller Slice
+      type: tosca.nodes.Slice
+      properties:
+          network: noauto
+      requirements:
+          - vsg_service:
+              node: service_vsg
+              relationship: tosca.relationships.MemberOfService
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+          - management:
+              node: management
+              relationship: tosca.relationships.ConnectsToNetwork
+
+    # Let's add a user who can be administrator of the household
+    johndoe@myhouse.com:
+      type: tosca.nodes.User
+      properties:
+          password: letmein
+          firstname: john
+          lastname: doe
+      requirements:
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+
+    # A subscriber
+    My House:
+       type: tosca.nodes.CORDSubscriber
+       properties:
+           service_specific_id: 123
+           firewall_enable: false
+           cdn_enable: false
+           url_filter_enable: false
+           url_filter_level: R
+       requirements:
+          - house_admin:
+              node: johndoe@myhouse.com
+              relationship: tosca.relationships.AdminPrivilege
+
+    Mom's PC:
+       type: tosca.nodes.CORDUser
+       properties:
+           mac: 01:02:03:04:05:06
+           level: PG_13
+       requirements:
+           - household:
+               node: My House
+               relationship: tosca.relationships.SubscriberDevice
+
+    Dad's PC:
+       type: tosca.nodes.CORDUser
+       properties:
+           mac: 90:E2:BA:82:F9:75
+           level: PG_13
+       requirements:
+           - household:
+               node: My House
+               relationship: tosca.relationships.SubscriberDevice
+
+    Jack's Laptop:
+       type: tosca.nodes.CORDUser
+       properties:
+           mac: 68:5B:35:9D:91:D5
+           level: PG_13
+       requirements:
+           - household:
+               node: My House
+               relationship: tosca.relationships.SubscriberDevice
+
+    Jill's Laptop:
+       type: tosca.nodes.CORDUser
+       properties:
+           mac: 34:36:3B:C9:B6:A6
+           level: PG_13
+       requirements:
+           - household:
+               node: My House
+               relationship: tosca.relationships.SubscriberDevice
+
+    My Volt:
+        type: tosca.nodes.VOLTTenant
+        properties:
+            service_specific_id: 123
+            s_tag: 222
+            c_tag: 432
+        requirements:
+            - provider_service:
+                node: service_volt
+                relationship: tosca.relationships.MemberOfService
+            - subscriber:
+                node: My House
+                relationship: tosca.relationships.BelongsToSubscriber
diff --git a/xos/configurations/vtn/docker-compose.yml b/xos/configurations/vtn/docker-compose.yml
new file mode 100644
index 0000000..1839f78
--- /dev/null
+++ b/xos/configurations/vtn/docker-compose.yml
@@ -0,0 +1,54 @@
+xos_db:
+    image: xosproject/xos-postgres
+    expose:
+        - "5432"
+
+xos_synchronizer_openstack:
+    image: xosproject/xos-synchronizer-openstack
+    command: bash -c "python /opt/xos/synchronizers/openstack/xos-synchronizer.py"
+    labels:
+        org.xosproject.kind: synchronizer
+        org.xosproject.target: openstack
+    links:
+        - xos_db
+    extra_hosts:
+        - ctl:${MYIP}
+    volumes:
+        - ../setup:/root/setup:ro
+        - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
+        - ./files/xos_vtn_config:/opt/xos/xos_configuration/xos_vtn_config:ro
+        - ./images:/opt/xos/images:ro
+
+xos_synchronizer_onos:
+    image: xosproject/xos-synchronizer-openstack
+    command: bash -c "python /opt/xos/synchronizers/onos/onos-synchronizer.py -C /opt/xos/synchronizers/onos/onos_synchronizer_config"
+    labels:
+        org.xosproject.kind: synchronizer
+        org.xosproject.target: onos
+    links:
+        - xos_db
+    extra_hosts:
+        - ctl:${MYIP}
+    volumes:
+        - ../setup:/root/setup:ro
+        - ../setup/id_rsa:/opt/xos/synchronizers/onos/onos_key:ro  # private key
+
+# FUTURE
+#xos_swarm_synchronizer:
+#    image: xosproject/xos-swarm-synchronizer
+#    labels:
+#        org.xosproject.kind: synchronizer
+#        org.xosproject.target: swarm
+
+xos:
+    image: xosproject/xos
+    command: bash -c "python /opt/xos/manage.py runserver 0.0.0.0:8000 --insecure --makemigrations"
+    ports:
+        - "9999:8000"
+    links:
+        - xos_db
+    volumes:
+      - ../setup:/root/setup:ro
+      - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
+      - ./files/xos_vtn_config:/opt/xos/xos_configuration/xos_vtn_config:ro
+      - ../setup/id_rsa.pub:/opt/xos/synchronizers/onos/onos_key.pub:ro
diff --git a/xos/configurations/vtn/files/neutron-supervisor.conf b/xos/configurations/vtn/files/neutron-supervisor.conf
new file mode 100644
index 0000000..591df7d
--- /dev/null
+++ b/xos/configurations/vtn/files/neutron-supervisor.conf
@@ -0,0 +1,2 @@
+[program:neutron-server]
+command=/usr/bin/python /usr/bin/neutron-server --config-file=/etc/neutron/plugins/ml2/ml2_conf.ini --config-file=/etc/neutron/neutron.conf --config-file /usr/local/etc/neutron/plugins/ml2/conf_onos.ini --log-file=/var/log/neutron/neutron-server.log
diff --git a/xos/configurations/vtn/files/xos_vtn_config b/xos/configurations/vtn/files/xos_vtn_config
new file mode 100644
index 0000000..5dfd459
--- /dev/null
+++ b/xos/configurations/vtn/files/xos_vtn_config
@@ -0,0 +1,2 @@
+[networking]
+use_vtn=True
diff --git a/xos/configurations/vtn/scripts/gen-inventory.sh b/xos/configurations/vtn/scripts/gen-inventory.sh
new file mode 100755
index 0000000..f793a9a
--- /dev/null
+++ b/xos/configurations/vtn/scripts/gen-inventory.sh
@@ -0,0 +1,29 @@
+FN=/etc/ansible/hosts
+
+echo "Writing to $FN"
+
+rm -f $FN
+
+cat >> $FN <<EOF
+localhost
+
+[nodes]
+EOF
+
+NODES=$( sudo bash -c "source $SETUPDIR/admin-openrc.sh ; nova hypervisor-list" |grep enabled|awk '{print $4}' )
+
+# also configure ONOS to manage the nm node
+NM=`grep "^nm" /root/setup/fqdn.map | awk '{ print $2 }'`
+NODES="$NODES $NM"
+
+for NODE in $NODES; do
+    cat >> $FN <<EOF
+$NODE
+EOF
+done
+
+cat >> $FN <<EOF
+[nodes:vars]
+ansible_ssh_user=root
+ansible_ssh_key=/root/setup/id_rsa
+EOF
diff --git a/xos/configurations/vtn/setup.yml b/xos/configurations/vtn/setup.yml
new file mode 100644
index 0000000..ed7cd59
--- /dev/null
+++ b/xos/configurations/vtn/setup.yml
@@ -0,0 +1,51 @@
+---
+- hosts: localhost
+  connection: local
+  sudo: yes
+  vars:
+    vtn_host: cp-1.devel.xos-pg0.apt.emulab.net
+  tasks:
+  - apt: name={{ item }} state=installed
+    with_items:
+    - python-pip
+    - supervisor
+
+  - pip: name={{ item }} state=latest
+    with_items:
+    - setuptools
+    - pip
+    - testrepository
+  - git: repo=https://github.com/openstack/networking-onos.git
+      dest=/srv/networking-onos
+  - shell: cd /srv/networking-onos; python setup.py install
+
+  # Edit /etc/neutron/plugins/ml2/ml2_conf.ini
+  - ini_file: dest=/usr/local/etc/neutron/plugins/ml2/conf_onos.ini
+      section=onos option=url_path value=http://{{ vtn_host }}:8181/onos/openstackswitching
+  - ini_file: dest=/usr/local/etc/neutron/plugins/ml2/conf_onos.ini
+      section=onos option=username value=karaf
+  - ini_file: dest=/usr/local/etc/neutron/plugins/ml2/conf_onos.ini
+      section=onos option=password value=karaf
+
+  # Edit /etc/neutron/neutron.conf
+#  - ini_file: dest=/etc/neutron/neutron.conf
+#      section=DEFAULT option=core_plugin value=neutron.plugins.ml2.plugin.Ml2Plugin
+
+  # Edit /etc/neutron/plugins/ml2/ml2_conf.ini
+  - ini_file: dest=/etc/neutron/plugins/ml2/ml2_conf.ini
+      section=ml2 option=tenant_network_types value=vxlan
+  - ini_file: dest=/etc/neutron/plugins/ml2/ml2_conf.ini
+      section=ml2 option=type_drivers value=vxlan
+  - ini_file: dest=/etc/neutron/plugins/ml2/ml2_conf.ini
+      section=ml2 option=mechanism_drivers value=onos_ml2
+  - ini_file: dest=/etc/neutron/plugins/ml2/ml2_conf.ini
+      section=ml2_type_vxlan option=vni_ranges value=1001:2000
+
+  - service: name=neutron-server state=stopped enabled=no
+  # Run neutron-server with extra config file
+  - copy: src=files/neutron-supervisor.conf dest=/etc/supervisor/conf.d/
+  - shell: supervisorctl reload
+
+#  - shell: ../../scripts/destroy-all-networks.sh
+  - shell: cd ../cord/dataplane; bash ./generate-bm.sh > hosts-bm
+  - shell: cd ../cord/dataplane; ansible-playbook -i hosts-bm dataplane-vtn.yaml
diff --git a/xos/configurations/vtn/vtn.yaml b/xos/configurations/vtn/vtn.yaml
new file mode 100644
index 0000000..3928ba1
--- /dev/null
+++ b/xos/configurations/vtn/vtn.yaml
@@ -0,0 +1,120 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Some VTN related stuff
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    management_template:
+      type: tosca.nodes.NetworkTemplate
+      properties:
+          visibility: private
+          translation: none
+
+    management:
+      type: tosca.nodes.network.Network
+      properties:
+          ip_version: 4
+          cidr: 172.27.0.0/24
+      requirements:
+          - network_template:
+              node: management_template
+              relationship: tosca.relationships.UsesNetworkTemplate
+          - owner:
+              node: mysite_management
+              relationship: tosca.relationships.MemberOfSlice
+
+    mysite:
+      type: tosca.nodes.Site
+
+    mysite_management:
+      description: This slice exists solely to own the management network
+      type: tosca.nodes.Slice
+      properties:
+          network: noauto
+      requirements:
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+
+    service_ONOS_VTN:
+      type: tosca.nodes.ONOSService
+      requirements:
+      properties:
+          kind: onos
+          view_url: /admin/onos/onosservice/$id$/
+          public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }
+          node_key: { get_artifact: [ SELF, nodekey, LOCAL_FILE] }
+      artifacts:
+          pubkey: /opt/xos/synchronizers/onos/onos_key.pub
+          nodekey: /root/setup/node_key
+
+    VTN_ONOS_app:
+      type: tosca.nodes.ONOSVTNApp
+      requirements:
+          - onos_tenant:
+              node: service_ONOS_VTN
+              relationship: tosca.relationships.TenantOfService
+      properties:
+          dependencies: org.onosproject.drivers, org.onosproject.drivers.ovsdb, org.onosproject.lldpprovider, org.onosproject.openflow-base, org.onosproject.ovsdb-base, org.onosproject.dhcp, org.onosproject.cordvtn
+          rest_onos/v1/network/configuration/: { get_artifact: [ SELF, vtn_network_cfg_json, LOCAL_FILE ] }
+      artifacts:
+          vtn_network_cfg_json: /root/setup/vtn-network-cfg.json
+
+    # docker image for vcpe containers
+    docker-onos:
+      # TODO: need to attach this to mydeployment
+      type: tosca.nodes.Image
+      properties:
+        kind: container
+        container_format: na
+        disk_format: na
+        path: onosproject/onos
+
+    mysite:
+      type: tosca.nodes.Site
+
+    mysite_onos_vtn:
+      description: ONOS Controller Slice for VTN
+      type: tosca.nodes.Slice
+      requirements:
+          - ONOS:
+              node: service_ONOS_VTN
+              relationship: tosca.relationships.MemberOfService
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+          - onos_docker_image:
+              node: docker-onos
+              relationship: tosca.relationships.UsesImage
+      properties:
+          network: host
+          default_isolation: container
+
+    # Virtual machines
+    onos_app_vtn:
+      type: tosca.nodes.Compute.Container
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+        # Guest Operating System properties
+        os:
+          properties:
+            # host Operating System image properties
+            architecture: x86_64
+            type: linux
+            distribution: Ubuntu
+            version: 14.10
+      requirements:
+          - slice:
+                node: mysite_onos_vtn
+                relationship: tosca.relationships.MemberOfSlice
+          - image:
+                node: docker-onos
+                relationship: tosca.relationships.UsesImage
diff --git a/xos/core/__init__.py b/xos/core/__init__.py
new file mode 100644
index 0000000..e01f9cd
--- /dev/null
+++ b/xos/core/__init__.py
@@ -0,0 +1 @@
+# from tests import *
diff --git a/xos/core/acl.py b/xos/core/acl.py
new file mode 100644
index 0000000..518d199
--- /dev/null
+++ b/xos/core/acl.py
@@ -0,0 +1,136 @@
+from fnmatch import fnmatch
+
+"""
+    A General-purpose ACL mechanism.
+
+    [allow | deny] <type_of_object> <text_pattern>
+
+    "allow all" and "deny all" are shorthand for allowing or denying all objects.
+    Lines are executed from top to bottom until a match was found, typical
+    iptables style. An implicit 'deny all' exists at the bottom of the list.
+
+    For example,
+    allow site Max Planck Institute
+    deny site Arizona
+    allow region US
+    deny user scott@onlab.us
+    allow user *@onlab.us
+"""
+class ACLValidationError(Exception): pass
+
+class AccessControlList:
+    def __init__(self, aclText=None):
+        self.rules = []
+        if aclText:
+            self.import_text(aclText)
+
+    def import_text(self, aclText):
+        # allow either newline or ';' to separate rules
+        aclText = aclText.replace("\n", ";")
+        for line in aclText.split(";"):
+            line = line.strip()
+            if line.startswith("#"):
+                continue
+
+            if line=="":
+                continue
+
+            parts = line.split()
+
+            if len(parts)==2 and (parts[1]=="all"):
+                # "allow all" has no pattern
+                parts = (parts[0], parts[1], "")
+
+            if len(parts)!=3:
+                raise ACLValidationError(line)
+
+            (action, object, pattern) = parts
+
+            if action not in ["allow", "deny"]:
+                raise ACLValidationError(line)
+
+            if object not in ["site", "user", "all"]:
+                raise ACLValidationError(line)
+
+            self.rules.append( (action, object, pattern) )
+
+    def __str__(self):
+        lines = []
+        for rule in self.rules:
+            lines.append( " ".join(rule) )
+        return ";\n".join(lines)
+
+    def test(self, user, site=None):
+        for rule in self.rules:
+            if self.match_rule(rule, user):
+                return rule[0]
+        return "deny"
+
+    def match_rule(self, rule, user, site=None):
+        (action, object, pattern) = rule
+
+        if (site==None):
+            site = user.site
+
+        if (object == "site"):
+            if fnmatch(site.name, pattern):
+                return True
+        elif (object == "user"):
+            if fnmatch(user.email, pattern):
+                return True
+        elif (object == "all"):
+            return True
+
+        return False
+
+
+if __name__ == '__main__':
+    # self-test
+
+    class fakesite:
+        def __init__(self, siteName):
+            self.name = siteName
+
+    class fakeuser:
+        def __init__(self, email, siteName):
+            self.email = email
+            self.site = fakesite(siteName)
+
+    u_scott = fakeuser("scott@onlab.us", "ON.Lab")
+    u_bill = fakeuser("bill@onlab.us", "ON.Lab")
+    u_andy = fakeuser("acb@cs.princeton.edu", "Princeton")
+    u_john = fakeuser("jhh@cs.arizona.edu", "Arizona")
+    u_hacker = fakeuser("somehacker@foo.com", "Not A Real Site")
+
+    # check the "deny all" rule
+    acl = AccessControlList("deny all")
+    assert(acl.test(u_scott) == "deny")
+
+    # a blank ACL results in "deny all"
+    acl = AccessControlList("")
+    assert(acl.test(u_scott) == "deny")
+
+    # check the "allow all" rule
+    acl = AccessControlList("allow all")
+    assert(acl.test(u_scott) == "allow")
+
+    # allow only one site
+    acl = AccessControlList("allow site ON.Lab")
+    assert(acl.test(u_scott) == "allow")
+    assert(acl.test(u_andy) == "deny")
+
+    # some complicated ACL
+    acl = AccessControlList("""allow site Princeton
+                 allow user *@cs.arizona.edu
+                 deny site Arizona
+                 deny user scott@onlab.us
+                 allow site ON.Lab""")
+
+    assert(acl.test(u_scott) == "deny")
+    assert(acl.test(u_bill) == "allow")
+    assert(acl.test(u_andy) == "allow")
+    assert(acl.test(u_john) == "allow")
+    assert(acl.test(u_hacker) == "deny")
+
+    print acl
+
diff --git a/xos/core/admin.py b/xos/core/admin.py
new file mode 100644
index 0000000..4c46d81
--- /dev/null
+++ b/xos/core/admin.py
@@ -0,0 +1,2470 @@
+import threading
+from cgi import escape as html_escape
+
+from core.models import *
+from core.models import Site
+from django import forms
+from django.contrib import admin, messages
+from django.contrib.admin.widgets import (AdminTextareaWidget,
+                                          FilteredSelectMultiple)
+from django.contrib.auth.admin import UserAdmin
+from django.contrib.auth.forms import (AdminPasswordChangeForm,
+                                       ReadOnlyPasswordHashField)
+from django.contrib.auth.models import Group
+from django.contrib.auth.signals import user_logged_in
+from django.contrib.contenttypes import generic
+from django.core.exceptions import PermissionDenied, ValidationError
+from django.core.urlresolvers import NoReverseMatch, resolve, reverse
+from django.forms.utils import flatatt, to_current_timezone
+from django.utils import timezone
+from django.utils.encoding import force_text, python_2_unicode_compatible
+from django.utils.html import conditional_escape, format_html
+from django.utils.safestring import mark_safe
+from django.utils.text import capfirst
+from openstack.manager import OpenStackManager
+from suit.widgets import LinkedSelect
+
+# thread locals necessary to work around a django-suit issue
+_thread_locals = threading.local()
+
+ICON_URLS = {"success": "/static/admin/img/icon_success.gif",
+             "clock": "/static/admin/img/icon_clock.gif",
+             "error": "/static/admin/img/icon_error.gif"}
+
+
+def backend_icon(obj):
+    (icon, tooltip) = obj.get_backend_icon()
+
+    icon_url = ICON_URLS.get(icon, "unknown")
+
+    (exponent, last_success, last_failure, failures) = obj.get_backend_details()
+
+    # FIXME: Need to clean this up by separating Javascript from Python
+    if (obj.pk):
+        script = """
+        <script type="text/javascript">$(document).ready(function () {$("#show_details_%d").click(function () {$("#status%d").dialog({modal: true, height: 200, width: 200 });});});</script>
+        """ % (obj.pk, obj.pk)
+
+        div = """
+        <div style="display:none;" id="status%d" title="Details">
+                <p>Backoff Exponent: %r</p>
+                <p>Last Success: %r</p>
+                <p>Failures: %r</p>
+                <p>Last Failure: %r</p>
+                    </div>
+        """ % (obj.pk, exponent, last_success, failures, last_failure)
+        a = '<a id="show_details_%d" href="#">' % obj.pk
+        astop = '</a>'
+    else:
+        div = ''
+        script = ''
+        a = ''
+        astop = ''
+
+    if tooltip:
+        return '%s %s <span style="min-width:16px;" title="%s">%s<img src="%s">%s</span>' % (script, div, tooltip, a,  icon_url, astop)
+    else:
+        return '<span style="min-width:16px;"><img src="%s"></span>' % icon_url
+
+
+def backend_text(obj):
+    (icon, tooltip) = obj.get_backend_icon()
+    icon_url = ICON_URLS.get(icon, "unknown")
+
+    return '<img src="%s"> %s' % (icon_url, tooltip)
+
+
+class UploadTextareaWidget(AdminTextareaWidget):
+
+    def render(self, name, value, attrs=None):
+        if value is None:
+            value = ''
+        final_attrs = self.build_attrs(attrs, name=name)
+        return format_html('<input type="file" style="width: 0; height: 0" id="btn_upload_%s" onChange="uploadTextarea(event,\'%s\');">'
+                           '<button onClick="$(\'#btn_upload_%s\').click(); return false;">Upload</button>'
+                           '<br><textarea{0}>\r\n{1}</textarea>' % (
+                               attrs["id"], attrs["id"], attrs["id"]),
+                           flatatt(final_attrs),
+                           force_text(value))
+
+
+class SliderWidget(forms.HiddenInput):
+
+    def render(self, name, value,  attrs=None):
+        if value is None:
+            value = '0'
+        final_attrs = self.build_attrs(attrs, name=name)
+        attrs = attrs or attrs[:]
+        attrs["name"] = name
+        attrs["value"] = value
+        html = """<div style="width:640px"><span id="%(id)s_label">%(value)s</span><div id="%(id)s_slider" style="float:right;width:610px;margin-top:5px"></div></div>
+                              <script>
+                                  $(function() {
+                                      $("#%(id)s_slider").slider({
+                                         value: %(value)s,
+                                         slide: function(event, ui) { $("#%(id)s").val( ui.value ); $("#%(id)s_label").html(ui.value); },
+                                         });
+                                  });
+                              </script>
+                              <input type="hidden" id="%(id)s" name="%(name)s" value="%(value)s"></input>
+                           """ % attrs
+        html = html.replace("{", "{{").replace("}", "}}")
+        return format_html(html,
+                           flatatt(final_attrs),
+                           force_text(value))
+
+
+class PlainTextWidget(forms.HiddenInput):
+    input_type = 'hidden'
+
+    def render(self, name, value, attrs=None):
+        if value is None:
+            value = ''
+        return mark_safe(str(value) + super(PlainTextWidget, self).render(name, value, attrs))
+
+
+class XOSAdminMixin(object):
+    # call save_by_user and delete_by_user instead of save and delete
+
+    def has_add_permission(self, request, obj=None):
+        return (not self.__user_is_readonly(request))
+
+    def has_delete_permission(self, request, obj=None):
+        return (not self.__user_is_readonly(request))
+
+    def save_model(self, request, obj, form, change):
+        if self.__user_is_readonly(request):
+            # this 'if' might be redundant if save_by_user is implemented right
+            raise PermissionDenied
+
+        # reset exponential backoff
+        if hasattr(obj, "backend_register"):
+            obj.backend_register = "{}"
+
+        obj.caller = request.user
+        # update openstack connection to use this site/tenant
+        obj.save_by_user(request.user)
+
+    def delete_model(self, request, obj):
+        obj.delete_by_user(request.user)
+
+    def save_formset(self, request, form, formset, change):
+        instances = formset.save(commit=False)
+        for instance in instances:
+            instance.caller = request.user
+            instance.save_by_user(request.user)
+
+        # BUG in django 1.7? Objects are not deleted by formset.save if
+        # commit is False. So let's delete them ourselves.
+        #
+        # code from forms/models.py save_existing_objects()
+        try:
+            forms_to_delete = formset.deleted_forms
+        except AttributeError:
+            forms_to_delete = []
+        if formset.initial_forms:
+            for form in formset.initial_forms:
+                obj = form.instance
+                if form in forms_to_delete:
+                    if obj.pk is None:
+                        continue
+                    formset.deleted_objects.append(obj)
+                    obj.delete()
+
+        formset.save_m2m()
+
+    def get_actions(self, request):
+        actions = super(XOSAdminMixin, self).get_actions(request)
+
+        if self.__user_is_readonly(request):
+            if 'delete_selected' in actions:
+                del actions['delete_selected']
+
+        return actions
+
+    def url_for_model_changelist(self, request, model):
+        # used in add_extra_context
+        return reverse('admin:%s_%s_changelist' % (model._meta.app_label, model._meta.model_name), current_app=model._meta.app_label)
+
+    def add_extra_context(self, request, extra_context):
+        # allow custom application breadcrumb url and name
+        extra_context["custom_app_breadcrumb_url"] = getattr(
+            self, "custom_app_breadcrumb_url", None)
+        extra_context["custom_app_breadcrumb_name"] = getattr(
+            self, "custom_app_breadcrumb_name", None)
+        extra_context["custom_changelist_breadcrumb_url"] = getattr(
+            self, "custom_changelist_breadcrumb_url", None)
+
+        # for Service admins to render their Administration page
+        if getattr(self, "extracontext_registered_admins", False):
+            admins = []
+            for model, model_admin in admin.site._registry.items():
+                if model == self.model:
+                    continue
+                if model._meta.app_label == self.model._meta.app_label:
+                    info = {"app": model._meta.app_label,
+                            "model": model._meta.model_name,
+                            "name": capfirst(model._meta.verbose_name_plural),
+                            "url": self.url_for_model_changelist(request, model)}
+                    admins.append(info)
+            extra_context["registered_admins"] = admins
+
+    def change_view(self, request, object_id, extra_context=None):
+        extra_context = extra_context or {}
+
+        if self.__user_is_readonly(request):
+            if not hasattr(self, "readonly_save"):
+                # save the original readonly fields
+                self.readonly_save = self.readonly_fields
+                self.inlines_save = self.inlines
+            if hasattr(self, "user_readonly_fields"):
+                self.readonly_fields = self.user_readonly_fields
+            if hasattr(self, "user_readonly_inlines"):
+                self.inlines = self.user_readonly_inlines
+        else:
+            if hasattr(self, "readonly_save"):
+                # restore the original readonly fields
+                self.readonly_fields = self.readonly_save
+            if hasattr(self, "inlines_save"):
+                self.inlines = self.inlines_save
+
+        self.add_extra_context(request, extra_context)
+
+        try:
+            return super(XOSAdminMixin, self).change_view(request, object_id, extra_context=extra_context)
+        except PermissionDenied:
+            pass
+        except ValidationError as e:
+            if (e.params is None):
+                # Validation errors that don't reference a specific field will
+                # often throw a non-descriptive 500 page to the user. The code
+                # below will cause an error message to be printed and the
+                # page refreshed instead.
+                # As a side-effect it turns the request back into a 'GET' which
+                # may wipe anything the user had changed on the page. But, at
+                # least the user gets a real error message.
+                # TODO: revisit this and display some kind of error view
+                request.method = 'GET'
+                messages.error(request, e.message)
+                return super(XOSAdminMixin, self).change_view(request, object_id, extra_context=extra_context)
+            else:
+                raise
+        if request.method == 'POST':
+            raise PermissionDenied
+        request.readonly = True
+        return super(XOSAdminMixin, self).change_view(request, object_id, extra_context=extra_context)
+
+    def changelist_view(self, request, extra_context=None):
+        extra_context = extra_context or {}
+
+        self.add_extra_context(request, extra_context)
+
+        return super(XOSAdminMixin, self).changelist_view(request, extra_context=extra_context)
+
+    def add_view(self, request, form_url='', extra_context=None):
+        extra_context = extra_context or {}
+
+        self.add_extra_context(request, extra_context)
+
+        return super(XOSAdminMixin, self).add_view(request, form_url, extra_context=extra_context)
+
+    def __user_is_readonly(self, request):
+        return request.user.isReadOnlyUser()
+
+    def backend_status_text(self, obj):
+        return mark_safe(backend_text(obj))
+
+    def backend_status_icon(self, obj):
+        return mark_safe(backend_icon(obj))
+    backend_status_icon.short_description = ""
+
+    def get_form(self, request, obj=None, **kwargs):
+        # Save obj and request in thread-local storage, so suit_form_tabs can
+        # use it to determine whether we're in edit or add mode, and can
+        # determine whether the user is an admin.
+        _thread_locals.request = request
+        _thread_locals.obj = obj
+        return super(XOSAdminMixin, self).get_form(request, obj, **kwargs)
+
+    def get_inline_instances(self, request, obj=None):
+        inlines = super(XOSAdminMixin, self).get_inline_instances(request, obj)
+
+        # inlines that should only be shown to an admin user
+        if request.user.is_admin:
+            for inline_class in getattr(self, "admin_inlines", []):
+                inlines.append(inline_class(self.model, self.admin_site))
+
+        return inlines
+
+
+class ReadOnlyAwareAdmin(XOSAdminMixin, admin.ModelAdmin):
+    # Note: Make sure XOSAdminMixin is listed before
+    # admin.ModelAdmin in the class declaration.
+
+    pass
+
+
+class XOSBaseAdmin(ReadOnlyAwareAdmin):
+    save_on_top = False
+
+
+class SingletonAdmin (ReadOnlyAwareAdmin):
+
+    def has_add_permission(self, request):
+        if not super(SingletonAdmin, self).has_add_permission(request):
+            return False
+
+        num_objects = self.model.objects.count()
+        if num_objects >= 1:
+            return False
+        else:
+            return True
+
+
+class ServiceAppAdmin (SingletonAdmin):
+    extracontext_registered_admins = True
+
+
+class XOSTabularInline(admin.TabularInline):
+
+    def __init__(self, *args, **kwargs):
+        super(XOSTabularInline, self).__init__(*args, **kwargs)
+
+        # InlineModelAdmin as no get_fields() method, so in order to add
+        # the selflink field, we override __init__ to modify self.fields and
+        # self.readonly_fields.
+
+        self.setup_selflink()
+
+    @property
+    def selflink_model(self):
+        if hasattr(self, "selflink_fieldname"):
+            """ self.selflink_model can be defined to punch through a relation
+                to its target object. For example, in SliceNetworkInline, set
+                selflink_model = "network", and the URL will lead to the Network
+                object instead of trying to bring up a change view of the
+                SliceNetwork object.
+            """
+            return getattr(self.model, self.selflink_fieldname).field.rel.to
+        else:
+            return self.model
+
+    @property
+    def selflink_reverse_path(self):
+        return "admin:%s_change" % (self.selflink_model._meta.db_table)
+
+    def get_change_url(self, id):
+        """ Get the URL to a change form in the admin for this model """
+        reverse_path = self.selflink_reverse_path  # "admin:%s_change" % (self.selflink_model._meta.db_table)
+        try:
+            url = reverse(reverse_path, args=(id,))
+        except NoReverseMatch:
+            return None
+
+        return url
+
+    def setup_selflink(self):
+        url = self.get_change_url(0)
+
+        # We don't have an admin for this object, so don't create the
+        # selflink.
+        if (url == None):
+            return
+
+        # Since we need to add "selflink" to the field list, we need to create
+        # self.fields if it is None.
+        if (self.fields is None):
+            self.fields = []
+            for f in self.model._meta.fields:
+                if f.editable and f.name != "id":
+                    self.fields.append(f.name)
+
+        self.fields = tuple(self.fields) + ("selflink", )
+
+        if self.readonly_fields is None:
+            self.readonly_fields = ()
+
+        self.readonly_fields = tuple(self.readonly_fields) + ("selflink", )
+
+    def selflink(self, obj):
+        if hasattr(self, "selflink_fieldname"):
+            obj = getattr(obj, self.selflink_fieldname)
+
+        if obj.id:
+            url = self.get_change_url(obj.id)
+            return "<a href='%s'>Details</a>" % str(url)
+        else:
+            return "Not present"
+
+    selflink.allow_tags = True
+    selflink.short_description = "Details"
+
+    def has_add_permission(self, request):
+        return not request.user.isReadOnlyUser()
+
+    def get_readonly_fields(self, request, obj=None):
+        readonly_fields = list(self.readonly_fields)[:]
+        if request.user.isReadOnlyUser():
+            for field in self.fields:
+                if not field in readonly_fields:
+                    readonly_fields.append(field)
+        return readonly_fields
+
+    def backend_status_icon(self, obj):
+        return mark_safe(backend_icon(obj))
+    backend_status_icon.short_description = ""
+
+
+class PlStackGenericTabularInline(generic.GenericTabularInline):
+
+    def has_add_permission(self, request):
+        return not request.user.isReadOnlyUser()
+
+    def get_readonly_fields(self, request, obj=None):
+        readonly_fields = list(self.readonly_fields)[:]
+        if request.user.isReadOnlyUser():
+            for field in self.fields:
+                if not field in readonly_fields:
+                    readonly_fields.append(field)
+        return readonly_fields
+
+    def backend_status_icon(self, obj):
+        return mark_safe(backend_icon(obj))
+    backend_status_icon.short_description = ""
+
+
+class ReservationInline(XOSTabularInline):
+    model = Reservation
+    extra = 0
+    suit_classes = 'suit-tab suit-tab-reservations'
+
+    def queryset(self, request):
+        return Reservation.select_by_user(request.user)
+
+
+class TagInline(PlStackGenericTabularInline):
+    model = Tag
+    extra = 0
+    suit_classes = 'suit-tab suit-tab-tags'
+    fields = ['service', 'name', 'value']
+
+    def queryset(self, request):
+        return Tag.select_by_user(request.user)
+
+
+class InstanceInline(XOSTabularInline):
+    model = Instance
+    fields = ['backend_status_icon', 'all_ips_string', 'instance_id',
+              'instance_name', 'slice', 'deployment', 'flavor', 'image', 'node']
+    extra = 0
+    max_num = 0
+    readonly_fields = ['backend_status_icon', 'all_ips_string', 'instance_id',
+                       'instance_name', 'slice', 'deployment', 'flavor', 'image', 'node']
+    suit_classes = 'suit-tab suit-tab-instances'
+
+    def queryset(self, request):
+        return Instance.select_by_user(request.user)
+
+    def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
+        if db_field.name == 'deployment':
+            kwargs['queryset'] = Deployment.select_by_acl(request.user).filter(
+                sitedeployments__nodes__isnull=False).distinct()
+            kwargs['widget'] = forms.Select(
+                attrs={'onChange': "instance_deployment_changed(this);"})
+        if db_field.name == 'flavor':
+            kwargs['widget'] = forms.Select(
+                attrs={'onChange': "instance_flavor_changed(this);"})
+
+        field = super(InstanceInline, self).formfield_for_foreignkey(
+            db_field, request, **kwargs)
+
+        return field
+
+
+class CordInstanceInline(XOSTabularInline):
+    model = Instance
+    fields = ['backend_status_icon', 'all_ips_string', 'instance_id',
+              'instance_name', 'slice', 'flavor', 'image', 'node']
+    extra = 0
+    readonly_fields = ['backend_status_icon',
+                       'all_ips_string', 'instance_id', 'instance_name']
+    suit_classes = 'suit-tab suit-tab-instances'
+
+    def queryset(self, request):
+        return Instance.select_by_user(request.user)
+
+    def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
+        if db_field.name == 'deployment':
+
+            kwargs['queryset'] = Deployment.select_by_acl(request.user).filter(
+                sitedeployments__nodes__isnull=False).distinct()
+            kwargs['widget'] = forms.Select(
+                attrs={'onChange': "instance_deployment_changed(this);"})
+        if db_field.name == 'flavor':
+            kwargs['widget'] = forms.Select(
+                attrs={'onChange': "instance_flavor_changed(this);"})
+
+        field = super(CordInstanceInline, self).formfield_for_foreignkey(
+            db_field, request, **kwargs)
+
+        return field
+
+
+class SiteInline(XOSTabularInline):
+    model = Site
+    extra = 0
+    suit_classes = 'suit-tab suit-tab-sites'
+
+    def queryset(self, request):
+        return Site.select_by_user(request.user)
+
+
+class SiteHostsNodesInline(SiteInline):
+
+    def queryset(self, request):
+        return Site.select_by_user(request.user).filter(hosts_nodes=True)
+
+
+class SiteHostsUsersInline(SiteInline):
+
+    def queryset(self, request):
+        return Site.select_by_user(request.user).filter(hosts_users=True)
+
+
+class UserInline(XOSTabularInline):
+    model = User
+    fields = ['backend_status_icon', 'email', 'firstname', 'lastname']
+    readonly_fields = ('backend_status_icon', )
+    extra = 0
+    suit_classes = 'suit-tab suit-tab-users'
+
+    def queryset(self, request):
+        return User.select_by_user(request.user)
+
+
+class SliceInline(XOSTabularInline):
+    model = Slice
+    fields = ['backend_status_icon', 'name', 'site', 'serviceClass', 'service']
+    readonly_fields = ('backend_status_icon', )
+    extra = 0
+    suit_classes = 'suit-tab suit-tab-slices'
+
+    def queryset(self, request):
+        return Slice.select_by_user(request.user)
+
+
+class NodeInline(XOSTabularInline):
+    model = Node
+    extra = 0
+    suit_classes = 'suit-tab suit-tab-nodes'
+    fields = ['backend_status_icon', 'name', 'site_deployment']
+    readonly_fields = ('backend_status_icon', )
+
+
+class DeploymentPrivilegeInline(XOSTabularInline):
+    model = DeploymentPrivilege
+    extra = 0
+    suit_classes = 'suit-tab suit-tab-deploymentprivileges'
+    fields = ['backend_status_icon', 'user', 'role', 'deployment']
+    readonly_fields = ('backend_status_icon', )
+
+    def queryset(self, request):
+        return DeploymentPrivilege.select_by_user(request.user)
+
+
+class ControllerSiteInline(XOSTabularInline):
+    model = ControllerSite
+    extra = 0
+    suit_classes = 'suit-tab suit-tab-admin-only'
+    fields = ['controller', 'site', 'tenant_id']
+
+
+class SitePrivilegeInline(XOSTabularInline):
+    model = SitePrivilege
+    extra = 0
+    suit_classes = 'suit-tab suit-tab-siteprivileges'
+    fields = ['backend_status_icon', 'user', 'site', 'role']
+    readonly_fields = ('backend_status_icon', )
+
+    def formfield_for_foreignkey(self, db_field, request, **kwargs):
+        if db_field.name == 'site':
+            kwargs['queryset'] = Site.select_by_user(request.user)
+
+        if db_field.name == 'user':
+            kwargs['queryset'] = User.select_by_user(request.user)
+        return super(SitePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
+
+    def queryset(self, request):
+        return SitePrivilege.select_by_user(request.user)
+
+
+class ServicePrivilegeInline(XOSTabularInline):
+    model = ServicePrivilege
+    extra = 0
+    suit_classes = 'suit-tab suit-tab-serviceprivileges'
+    fields = ['backend_status_icon', 'user', 'service', 'role']
+    readonly_fields = ('backend_status_icon', )
+
+    def formfield_for_foreignkey(self, db_field, request, **kwargs):
+        if db_field.name == 'service':
+            kwargs['queryset'] = Service.select_by_user(request.user)
+        if db_field.name == 'user':
+            kwargs['queryset'] = User.select_by_user(request.user)
+        return super(ServicePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
+
+    def queryset(self, request):
+        return ServicePrivilege.select_by_user(request.user)
+
+
+class SiteDeploymentInline(XOSTabularInline):
+    model = SiteDeployment
+    extra = 0
+    suit_classes = 'suit-tab suit-tab-sitedeployments'
+    fields = ['backend_status_icon', 'deployment', 'site', 'controller']
+    readonly_fields = ('backend_status_icon', )
+
+    def formfield_for_foreignkey(self, db_field, request, **kwargs):
+        if db_field.name == 'site':
+            kwargs['queryset'] = Site.select_by_user(request.user)
+
+        if db_field.name == 'deployment':
+            kwargs['queryset'] = Deployment.select_by_user(request.user)
+
+        if db_field.name == 'controller':
+            if len(resolve(request.path).args) > 0:
+                kwargs['queryset'] = Controller.select_by_user(request.user).filter(
+                    deployment__id=int(resolve(request.path).args[0]))
+
+        return super(SiteDeploymentInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
+
+    def queryset(self, request):
+        return SiteDeployment.select_by_user(request.user)
+
+
+class SlicePrivilegeInline(XOSTabularInline):
+    model = SlicePrivilege
+    suit_classes = 'suit-tab suit-tab-sliceprivileges'
+    extra = 0
+    fields = ('backend_status_icon', 'user', 'slice', 'role')
+    readonly_fields = ('backend_status_icon', )
+
+    def formfield_for_foreignkey(self, db_field, request, **kwargs):
+        if db_field.name == 'slice':
+            kwargs['queryset'] = Slice.select_by_user(request.user)
+        if db_field.name == 'user':
+            # all users are available to be granted SlicePrivilege
+            kwargs['queryset'] = User.objects.all()
+
+        return super(SlicePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
+
+    def queryset(self, request):
+        return SlicePrivilege.select_by_user(request.user)
+
+
+class SliceNetworkInline(XOSTabularInline):
+    model = Network.slices.through
+    selflink_fieldname = "network"
+    extra = 0
+    verbose_name = "Network Connection"
+    verbose_name_plural = "Network Connections"
+    suit_classes = 'suit-tab suit-tab-slicenetworks'
+    fields = ['backend_status_icon', 'network']
+    readonly_fields = ('backend_status_icon', )
+
+
+class ImageDeploymentsInline(XOSTabularInline):
+    model = ImageDeployments
+    extra = 0
+    verbose_name = "Image Deployments"
+    verbose_name_plural = "Image Deployments"
+    suit_classes = 'suit-tab suit-tab-imagedeployments'
+    fields = ['backend_status_icon', 'image', 'deployment']
+    readonly_fields = ['backend_status_icon']
+
+
+class ControllerImagesInline(XOSTabularInline):
+    model = ControllerImages
+    extra = 0
+    verbose_name = "Controller Images"
+    verbose_name_plural = "Controller Images"
+    suit_classes = 'suit-tab suit-tab-admin-only'
+    fields = ['backend_status_icon', 'image', 'controller', 'glance_image_id']
+    readonly_fields = ['backend_status_icon', 'glance_image_id']
+
+
+class SliceRoleAdmin(XOSBaseAdmin):
+    model = SliceRole
+    pass
+
+
+class SiteRoleAdmin(XOSBaseAdmin):
+    model = SiteRole
+    pass
+
+
+class DeploymentAdminForm(forms.ModelForm):
+    images = forms.ModelMultipleChoiceField(
+        queryset=Image.objects.all(),
+        required=False,
+        help_text="Select which images should be deployed on this deployment",
+        widget=FilteredSelectMultiple(
+            verbose_name=('Images'), is_stacked=False
+        )
+    )
+    flavors = forms.ModelMultipleChoiceField(
+        queryset=Flavor.objects.all(),
+        required=False,
+        help_text="Select which flavors should be usable on this deployment",
+        widget=FilteredSelectMultiple(
+            verbose_name=('Flavors'), is_stacked=False
+        )
+    )
+
+    class Meta:
+        model = Deployment
+        many_to_many = ["flavors", ]
+
+    def __init__(self, *args, **kwargs):
+        request = kwargs.pop('request', None)
+        super(DeploymentAdminForm, self).__init__(*args, **kwargs)
+
+        self.fields['accessControl'].initial = "allow site " + \
+            request.user.site.name
+
+        if self.instance and self.instance.pk:
+            self.fields['images'].initial = [
+                x.image for x in self.instance.imagedeployments.all()]
+            self.fields['flavors'].initial = self.instance.flavors.all()
+
+    def manipulate_m2m_objs(self, this_obj, selected_objs, all_relations, relation_class, local_attrname, foreign_attrname):
+        """ helper function for handling m2m relations from the MultipleChoiceField
+
+            this_obj: the source object we want to link from
+
+            selected_objs: a list of destination objects we want to link to
+
+            all_relations: the full set of relations involving this_obj, including ones we don't want
+
+            relation_class: the class that implements the relation from source to dest
+
+            local_attrname: field name representing this_obj in relation_class
+
+            foreign_attrname: field name representing selected_objs in relation_class
+
+            This function will remove all newobjclass relations from this_obj
+            that are not contained in selected_objs, and add any relations that
+            are in selected_objs but don't exist in the data model yet.
+        """
+
+        existing_dest_objs = []
+        for relation in list(all_relations):
+            if getattr(relation, foreign_attrname) not in selected_objs:
+                # print "deleting site", sdp.site
+                relation.delete()
+            else:
+                existing_dest_objs.append(getattr(relation, foreign_attrname))
+
+        for dest_obj in selected_objs:
+            if dest_obj not in existing_dest_objs:
+                # print "adding site", site
+                kwargs = {foreign_attrname: dest_obj, local_attrname: this_obj}
+                relation = relation_class(**kwargs)
+                relation.save()
+
+    def save(self, commit=True):
+        deployment = super(DeploymentAdminForm, self).save(commit=False)
+
+        if commit:
+            deployment.save()
+            # this has to be done after save() if/when a deployment is first
+            # created
+            deployment.flavors = self.cleaned_data['flavors']
+
+        if deployment.pk:
+            # save_m2m() doesn't seem to work with 'through' relations. So we
+            #    create/destroy the through models ourselves. There has to be
+            #    a better way...
+
+            self.manipulate_m2m_objs(deployment, self.cleaned_data[
+                                     'images'], deployment.imagedeployments.all(), ImageDeployments, "deployment", "image")
+            # manipulate_m2m_objs doesn't work for Flavor/Deployment relationship
+            # so well handle that manually here
+            for flavor in deployment.flavors.all():
+                if getattr(flavor, 'name') not in self.cleaned_data['flavors']:
+                    deployment.flavors.remove(flavor)
+            for flavor in self.cleaned_data['flavors']:
+                if flavor not in deployment.flavors.all():
+                    flavor.deployments.add(deployment)
+
+        self.save_m2m()
+
+        return deployment
+
+
+class DeploymentAdminROForm(DeploymentAdminForm):
+
+    def save(self, commit=True):
+        raise PermissionDenied
+
+
+class SiteAssocInline(XOSTabularInline):
+    model = Site.deployments.through
+    extra = 0
+    suit_classes = 'suit-tab suit-tab-sites'
+
+
+class DeploymentAdmin(XOSBaseAdmin):
+    model = Deployment
+    fieldList = ['backend_status_text', 'name',
+                 'images', 'flavors', 'accessControl']
+    fieldsets = [
+        (None, {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
+    # node no longer directly connected to deployment
+    #inlines = [DeploymentPrivilegeInline,NodeInline,TagInline,ImageDeploymentsInline]
+    inlines = [DeploymentPrivilegeInline, TagInline,
+               ImageDeploymentsInline, SiteDeploymentInline]
+    list_display = ['backend_status_icon', 'name']
+    list_display_links = ('backend_status_icon', 'name', )
+    readonly_fields = ('backend_status_text', )
+
+    user_readonly_fields = ['name']
+
+    # nodes no longer direclty connected to deployments
+    suit_form_tabs = (('general', 'Deployment Details'),
+                      ('deploymentprivileges', 'Privileges'), ('sitedeployments', 'Sites'))
+
+    def get_form(self, request, obj=None, **kwargs):
+        if request.user.isReadOnlyUser() or not request.user.is_admin:
+            kwargs["form"] = DeploymentAdminROForm
+        else:
+            kwargs["form"] = DeploymentAdminForm
+        adminForm = super(DeploymentAdmin, self).get_form(
+            request, obj, **kwargs)
+
+        # from stackexchange: pass the request object into the form
+
+        class AdminFormMetaClass(adminForm):
+
+            def __new__(cls, *args, **kwargs):
+                kwargs['request'] = request
+                return adminForm(*args, **kwargs)
+
+        return AdminFormMetaClass
+
+
+class ControllerAdminForm(forms.ModelForm):
+    backend_disabled = forms.BooleanField(required=False)
+
+    class Meta:
+        model = Controller
+
+    def __init__(self, *args, **kwargs):
+        request = kwargs.pop('request', None)
+        super(ControllerAdminForm, self).__init__(*args, **kwargs)
+
+        if self.instance and self.instance.pk:
+            self.fields['backend_disabled'].initial = self.instance.get_backend_register(
+                'disabled', False)
+        else:
+            # defaults when adding new controller
+            self.fields['backend_disabled'].initial = False
+
+    def save(self, commit=True):
+        self.instance.set_backend_register(
+            "disabled", self.cleaned_data["backend_disabled"])
+        return super(ControllerAdminForm, self).save(commit=commit)
+
+
+class ControllerAdmin(XOSBaseAdmin):
+    model = Controller
+    fieldList = ['deployment', 'name', 'backend_type', 'backend_disabled', 'version', 'auth_url', 'admin_user',
+                 'admin_tenant', 'admin_password', 'domain', 'rabbit_host', 'rabbit_user', 'rabbit_password']
+    fieldsets = [
+        (None, {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
+    inlines = [ControllerSiteInline]  # ,ControllerImagesInline]
+    list_display = ['backend_status_icon', 'name', 'version', 'backend_type']
+    list_display_links = ('backend_status_icon', 'name', )
+    readonly_fields = ('backend_status_text',)
+    form = ControllerAdminForm
+
+    user_readonly_fields = []
+
+    def save_model(self, request, obj, form, change):
+            # update openstack connection to use this site/tenant
+        obj.save_by_user(request.user)
+
+    def delete_model(self, request, obj):
+        obj.delete_by_user(request.user)
+
+    def queryset(self, request):
+        return Controller.select_by_user(request.user)
+
+    @property
+    def suit_form_tabs(self):
+        tabs = [('general', 'Controller Details'),
+                ]
+
+        request = getattr(_thread_locals, "request", None)
+        if request and request.user.is_admin:
+            tabs.append(('admin-only', 'Admin-Only'))
+
+        return tabs
+
+
+class TenantAttributeAdmin(XOSBaseAdmin):
+    model = TenantAttribute
+    list_display = ('backend_status_icon', 'tenant', 'name', 'value')
+    list_display_links = ('backend_status_icon', 'name')
+    fieldList = ('backend_status_text', 'tenant', 'name', 'value', )
+    fieldsets = [
+        (None, {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
+    readonly_fields = ('backend_status_text', )
+
+    suit_form_tabs = (('general', 'Tenant Root Details'),
+                      )
+
+
+class TenantAttrAsTabInline(XOSTabularInline):
+    model = TenantAttribute
+    fields = ['name', 'value']
+    extra = 0
+    suit_classes = 'suit-tab suit-tab-tenantattrs'
+
+
+class TenantRootRoleAdmin(XOSBaseAdmin):
+    model = TenantRootRole
+    fields = ('role',)
+
+
+class TenantRootTenantInline(XOSTabularInline):
+    model = Tenant
+    fields = ['provider_service', 'subscriber_root']
+    extra = 0
+    suit_classes = 'suit-tab suit-tab-tenantroots'
+    fk_name = 'subscriber_root'
+    verbose_name = 'subscribed tenant'
+    verbose_name_plural = 'subscribed tenants'
+
+    # def queryset(self, request):
+    #    qs = super(TenantRootTenantInline, self).queryset(request)
+    #    return qs.filter(kind="coarse")
+
+
+class TenantRootPrivilegeInline(XOSTabularInline):
+    model = TenantRootPrivilege
+    extra = 0
+    suit_classes = 'suit-tab suit-tab-tenantrootprivileges'
+    fields = ['backend_status_icon', 'user', 'role', 'tenant_root']
+    readonly_fields = ('backend_status_icon', )
+
+    def queryset(self, request):
+        return TenantRootPrivilege.select_by_user(request.user)
+
+
+class TenantRootAdmin(XOSBaseAdmin):
+    model = TenantRoot
+    list_display = ('backend_status_icon', 'name', 'kind')
+    list_display_links = ('backend_status_icon', 'name')
+    fieldList = ('backend_status_text', 'name', 'kind', )
+    fieldsets = [
+        (None, {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
+    inlines = (TenantRootTenantInline, TenantRootPrivilegeInline)
+    readonly_fields = ('backend_status_text', )
+
+    suit_form_tabs = (('general', 'Tenant Root Details'),
+                      ('tenantroots', 'Tenancy'),
+                      ('tenantrootprivileges', 'Privileges')
+                      )
+
+
+class TenantRoleAdmin(XOSBaseAdmin):
+    """Admin for TenantRoles."""
+    model = TenantRole
+    fields = ('role',)
+
+
+class TenantPrivilegeInline(XOSTabularInline):
+    """Inline for adding a TenantPrivilege to a Tenant."""
+    model = TenantPrivilege
+    extra = 0
+    suit_classes = 'suit-tab suit-tab-tenantprivileges'
+    fields = ['backend_status_icon', 'user', 'role', 'tenant']
+    readonly_fields = ('backend_status_icon', )
+
+    def queryset(self, request):
+        return TenantPrivilege.select_by_user(request.user)
+
+
+class ProviderTenantInline(XOSTabularInline):
+    model = CoarseTenant
+    fields = ['provider_service', 'subscriber_service', 'connect_method']
+    extra = 0
+    suit_classes = 'suit-tab suit-tab-servicetenants'
+    fk_name = 'provider_service'
+    verbose_name = 'provided tenant'
+    verbose_name_plural = 'provided tenants'
+
+    def queryset(self, request):
+        qs = super(ProviderTenantInline, self).queryset(request)
+        return qs.filter(kind="coarse")
+
+
+class SubscriberTenantInline(XOSTabularInline):
+    model = CoarseTenant
+    fields = ['provider_service', 'subscriber_service', 'connect_method']
+    extra = 0
+    suit_classes = 'suit-tab suit-tab-servicetenants'
+    fk_name = 'subscriber_service'
+    verbose_name = 'subscribed tenant'
+    verbose_name_plural = 'subscribed tenants'
+
+    def queryset(self, request):
+        qs = super(SubscriberTenantInline, self).queryset(request)
+        return qs.filter(kind="coarse")
+
+
+class ServiceAttrAsTabInline(XOSTabularInline):
+    model = ServiceAttribute
+    fields = ['name', 'value']
+    extra = 0
+    suit_classes = 'suit-tab suit-tab-serviceattrs'
+
+
+class ServiceAdmin(XOSBaseAdmin):
+    list_display = ("backend_status_icon", "name", "kind",
+                    "versionNumber", "enabled", "published")
+    list_display_links = ('backend_status_icon', 'name', )
+    fieldList = ["backend_status_text", "name", "kind", "description", "controller", "versionNumber", "enabled", "published",
+                 "view_url", "icon_url", "public_key", "private_key_fn", "service_specific_attribute", "service_specific_id"]
+    fieldsets = [
+        (None, {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
+    inlines = [ServiceAttrAsTabInline, SliceInline, ProviderTenantInline,
+               SubscriberTenantInline, ServicePrivilegeInline]
+    readonly_fields = ('backend_status_text', )
+
+    user_readonly_fields = fieldList
+
+    suit_form_tabs = (('general', 'Service Details'),
+                      ('slices', 'Slices'),
+                      ('serviceattrs', 'Additional Attributes'),
+                      ('servicetenants', 'Tenancy'),
+                      ('serviceprivileges', 'Privileges')
+                      )
+
+class ServiceControllerResourceInline(XOSTabularInline):
+    model = ServiceControllerResource
+    fields = ['name', 'kind', 'format', 'url']
+    extra = 0
+    suit_classes = 'suit-tab suit-tab-resources'
+
+class ServiceControllerAdmin(XOSBaseAdmin):
+    list_display = ("backend_status_icon", "name",)
+    list_display_links = ('backend_status_icon', 'name',)
+    fieldList = ["backend_status_text", "name", "xos", "base_url", "synchronizer_run", "synchronizer_config"]
+    fieldsets = [
+        (None, {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
+    inlines = [ServiceControllerResourceInline]
+    readonly_fields = ('backend_status_text', )
+
+    user_readonly_fields = fieldList
+
+    suit_form_tabs = (('general', 'Service Details'),
+                      ('resources', 'Resources'),
+                      )
+
+
+class SiteNodeInline(XOSTabularInline):
+    model = Node
+    fields = ['name', 'site_deployment']
+    extra = 0
+    suit_classes = 'suit-tab suit-tab-nodes'
+
+    def formfield_for_foreignkey(self, db_field, request, **kwargs):
+        # only display site deployments associated with this site
+        if db_field.name == 'site_deployment':
+            kwargs['queryset'] = SiteDeployment.objects.filter(
+                site__id=int(request.path.split('/')[-2]))
+
+        return super(SiteNodeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
+
+
+class SiteAdmin(XOSBaseAdmin):
+    #fieldList = ['backend_status_text', 'name', 'site_url', 'enabled', 'is_public', 'login_base', 'accountLink','location']
+    fieldList = ['backend_status_text', 'name', 'site_url', 'enabled',
+                 'login_base', 'location', 'is_public', 'hosts_nodes', 'hosts_users']
+    fieldsets = [
+        (None, {'fields': fieldList, 'classes': [
+         'suit-tab suit-tab-general']}),
+        #('Deployment Networks', {'fields': ['deployments'], 'classes':['suit-tab suit-tab-deployments']}),
+    ]
+    #readonly_fields = ['backend_status_text', 'accountLink']
+    readonly_fields = ['backend_status_text']
+
+    #user_readonly_fields = ['name', 'deployments','site_url', 'enabled', 'is_public', 'login_base', 'accountLink']
+    user_readonly_fields = ['name', 'deployments', 'site_url',
+                            'enabled', 'is_public', 'login_base', 'hosts_nodes', 'hosts_users']
+
+    list_display = ('backend_status_icon', 'name',
+                    'login_base', 'site_url', 'enabled')
+    list_display_links = ('backend_status_icon', 'name', )
+    filter_horizontal = ('deployments',)
+    inlines = [SliceInline, UserInline, TagInline,
+               SitePrivilegeInline, SiteNodeInline]
+    admin_inlines = [ControllerSiteInline]
+    search_fields = ['name']
+
+    @property
+    def suit_form_tabs(self):
+        tabs = [('general', 'Site Details'),
+                ('users', 'Users'),
+                ('siteprivileges', 'Privileges'),
+                ('slices', 'Slices'),
+                ('nodes', 'Nodes'),
+                ]
+
+        request = getattr(_thread_locals, "request", None)
+        if request and request.user.is_admin:
+            tabs.append(('admin-only', 'Admin-Only'))
+
+        return tabs
+
+    def queryset(self, request):
+        return Site.select_by_user(request.user)
+
+    def get_formsets(self, request, obj=None):
+        for inline in self.get_inline_instances(request, obj):
+            # hide MyInline in the add view
+            if obj is None:
+                continue
+            if isinstance(inline, InstanceInline):
+                inline.model.caller = request.user
+            yield inline.get_formset(request, obj)
+
+    def accountLink(self, obj):
+        link_obj = obj.accounts.all()
+        if link_obj:
+            reverse_path = "admin:core_account_change"
+            url = reverse(reverse_path, args=(link_obj[0].id,))
+            return "<a href='%s'>%s</a>" % (url, "view billing details")
+        else:
+            return "no billing data for this site"
+    accountLink.allow_tags = True
+    accountLink.short_description = "Billing"
+
+    def save_model(self, request, obj, form, change):
+        # update openstack connection to use this site/tenant
+        obj.save_by_user(request.user)
+
+    def delete_model(self, request, obj):
+        obj.delete_by_user(request.user)
+
+
+class SitePrivilegeAdmin(XOSBaseAdmin):
+    fieldList = ['backend_status_text', 'user', 'site', 'role']
+    fieldsets = [
+        (None, {'fields': fieldList, 'classes': ['collapse']})
+    ]
+    readonly_fields = ('backend_status_text', )
+    list_display = ('backend_status_icon', 'user', 'site', 'role')
+    list_display_links = list_display
+    user_readonly_fields = fieldList
+    user_readonly_inlines = []
+
+    def formfield_for_foreignkey(self, db_field, request, **kwargs):
+        if db_field.name == 'site':
+            if not request.user.is_admin:
+                # only show sites where user is an admin or pi
+                sites = set()
+                for site_privilege in SitePrivilege.objects.filer(user=request.user):
+                    if site_privilege.role.role_type in ['admin', 'pi']:
+                        sites.add(site_privilege.site)
+                kwargs['queryset'] = Site.objects.filter(site__in=list(sites))
+
+        if db_field.name == 'user':
+            if not request.user.is_admin:
+                # only show users from sites where caller has admin or pi role
+                roles = Role.objects.filter(role_type__in=['admin', 'pi'])
+                site_privileges = SitePrivilege.objects.filter(
+                    user=request.user).filter(role__in=roles)
+                sites = [site_privilege.site for site_privilege in site_privileges]
+                site_privileges = SitePrivilege.objects.filter(site__in=sites)
+                emails = [
+                    site_privilege.user.email for site_privilege in site_privileges]
+                users = User.objects.filter(email__in=emails)
+                kwargs['queryset'] = users
+
+        return super(SitePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
+
+    def queryset(self, request):
+        # admins can see all privileges. Users can only see privileges at sites
+        # where they have the admin role or pi role.
+        qs = super(SitePrivilegeAdmin, self).queryset(request)
+        # if not request.user.is_admin:
+        #    roles = Role.objects.filter(role_type__in=['admin', 'pi'])
+        #    site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
+        #    login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
+        #    sites = Site.objects.filter(login_base__in=login_bases)
+        #    qs = qs.filter(site__in=sites)
+        return qs
+
+
+class SliceForm(forms.ModelForm):
+
+    class Meta:
+        model = Slice
+        widgets = {
+            'service': LinkedSelect
+        }
+
+    def clean(self):
+        cleaned_data = super(SliceForm, self).clean()
+        name = cleaned_data.get('name')
+        site = cleaned_data.get('site')
+        slice_id = self.instance.id
+        if not site and slice_id:
+            site = Slice.objects.get(id=slice_id).site
+        if (not isinstance(site, Site)):
+            # previous code indicates 'site' could be a site_id and not a site?
+            site = Slice.objects.get(id=site.id)
+        if not name.startswith(site.login_base):
+            raise forms.ValidationError(
+                'slice name must begin with %s' % site.login_base)
+        return cleaned_data
+
+
+class ControllerSliceInline(XOSTabularInline):
+    model = ControllerSlice
+    extra = 0
+    verbose_name = "Controller Slices"
+    verbose_name_plural = "Controller Slices"
+    suit_classes = 'suit-tab suit-tab-admin-only'
+    fields = ['backend_status_icon', 'controller', 'tenant_id']
+    readonly_fields = ('backend_status_icon', 'controller')
+
+
+class SliceAdmin(XOSBaseAdmin):
+    form = SliceForm
+    fieldList = ['backend_status_text', 'site', 'name', 'serviceClass', 'enabled',
+                 'description', 'service', 'slice_url', 'max_instances', "default_isolation", "default_image", "network"]
+    fieldsets = [('Slice Details', {'fields': fieldList, 'classes': [
+                  'suit-tab suit-tab-general']}), ]
+    readonly_fields = ('backend_status_text', )
+    list_display = ('backend_status_icon', 'name', 'site',
+                    'serviceClass', 'slice_url', 'max_instances')
+    list_display_links = ('backend_status_icon', 'name', )
+    normal_inlines = [SlicePrivilegeInline, InstanceInline,
+                      TagInline, ReservationInline, SliceNetworkInline]
+    inlines = normal_inlines
+    admin_inlines = [ControllerSliceInline]
+    suit_form_includes = (('slice_instance_tab.html', 'bottom', 'instances'),)
+
+    user_readonly_fields = fieldList
+
+    @property
+    def suit_form_tabs(self):
+        tabs = [('general', 'Slice Details'),
+                ('slicenetworks', 'Networks'),
+                ('sliceprivileges', 'Privileges'),
+                ('instances', 'Instances'),
+                #('reservations','Reservations'),
+                ('tags', 'Tags'),
+                ]
+
+        request = getattr(_thread_locals, "request", None)
+        if request and request.user.is_admin:
+            tabs.append(('admin-only', 'Admin-Only'))
+
+        return tabs
+
+    def add_view(self, request, form_url='', extra_context=None):
+        # Ugly hack for CORD
+        self.inlines = self.normal_inlines
+        # revert to default read-only fields
+        self.readonly_fields = ('backend_status_text',)
+        return super(SliceAdmin, self).add_view(request, form_url, extra_context=extra_context)
+
+    def change_view(self, request, object_id, form_url='', extra_context=None):
+        # cannot change the site of an existing slice so make the site field
+        # read only
+        if object_id:
+            self.readonly_fields = ('backend_status_text', 'site')
+
+        return super(SliceAdmin, self).change_view(request, object_id, form_url)
+
+    def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None):
+        deployment_nodes = []
+        for node in Node.objects.all():
+            deployment_nodes.append(
+                (node.site_deployment.deployment.id, node.id, node.name))
+
+        deployment_flavors = []
+        for flavor in Flavor.objects.all():
+            for deployment in flavor.deployments.all():
+                deployment_flavors.append(
+                    (deployment.id, flavor.id, flavor.name))
+
+        deployment_images = []
+        for image in Image.objects.all():
+            for deployment_image in image.imagedeployments.all():
+                deployment_images.append(
+                    (deployment_image.deployment.id, image.id, image.name))
+
+        site_login_bases = []
+        for site in Site.objects.all():
+            site_login_bases.append((site.id, site.login_base))
+
+        context["deployment_nodes"] = deployment_nodes
+        context["deployment_flavors"] = deployment_flavors
+        context["deployment_images"] = deployment_images
+        context["site_login_bases"] = site_login_bases
+        return super(SliceAdmin, self).render_change_form(request, context, add, change, form_url, obj)
+
+    def formfield_for_foreignkey(self, db_field, request, **kwargs):
+        if db_field.name == 'site':
+            kwargs['queryset'] = Site.select_by_user(
+                request.user).filter(hosts_users=True)
+            kwargs['widget'] = forms.Select(
+                attrs={'onChange': "update_slice_prefix(this, $($(this).closest('fieldset')[0]).find('.field-name input')[0].id)"})
+
+        return super(SliceAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
+
+    def queryset(self, request):
+        # admins can see all keys. Users can only see slices they belong to.
+        return Slice.select_by_user(request.user)
+
+    def get_formsets(self, request, obj=None):
+        for inline in self.get_inline_instances(request, obj):
+            # hide MyInline in the add view
+            if obj is None:
+                continue
+            if isinstance(inline, InstanceInline):
+                inline.model.caller = request.user
+            yield inline.get_formset(request, obj)
+
+    def add_extra_context(self, request, extra_context):
+        super(SliceAdmin, self).add_extra_context(request, extra_context)
+        # set context["slice_id"] to the PK passed in the URL to this view
+        if len(request.resolver_match.args) > 0:
+            extra_context["slice_id"] = request.resolver_match.args[0]
+
+    def UNUSED_get_inline_instances(self, request, obj=None):
+        # HACK for CORD to do something special on vcpe slice page
+        #    this was a good idea, but failed miserably, as something still
+        #    expects there to be a deployment field.
+        #    XXX this approach is better than clobbering self.inlines, so
+        #    try to make this work post-demo.
+        if (obj is not None) and (obj.name == "mysite_vcpe"):
+            cord_vcpe_inlines = [SlicePrivilegeInline, CordInstanceInline,
+                                 TagInline, ReservationInline, SliceNetworkInline]
+
+            inlines = []
+            for inline_class in cord_vcpe_inlines:
+                inlines.append(inline_class(self.model, self.admin_site))
+        else:
+            inlines = super(SliceAdmin, self).get_inline_instances(
+                request, obj)
+
+        return inlines
+
+
+class SlicePrivilegeAdmin(XOSBaseAdmin):
+    fieldsets = [
+        (None, {'fields': ['backend_status_text', 'user', 'slice', 'role']})
+    ]
+    readonly_fields = ('backend_status_text', )
+    list_display = ('backend_status_icon', 'user', 'slice', 'role')
+    list_display_links = list_display
+
+    user_readonly_fields = ['user', 'slice', 'role']
+    user_readonly_inlines = []
+
+    def formfield_for_foreignkey(self, db_field, request, **kwargs):
+        if db_field.name == 'slice':
+            kwargs['queryset'] = Slice.select_by_user(request.user)
+
+        if db_field.name == 'user':
+            kwargs['queryset'] = User.select_by_user(request.user)
+
+        return super(SlicePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
+
+    def queryset(self, request):
+        # admins can see all memberships. Users can only see memberships of
+        # slices where they have the admin role.
+        return SlicePrivilege.select_by_user(request.user)
+
+    def save_model(self, request, obj, form, change):
+        # update openstack connection to use this site/tenant
+        auth = request.session.get('auth', {})
+        auth['tenant'] = obj.slice.slicename
+        obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
+        obj.save()
+
+    def delete_model(self, request, obj):
+        # update openstack connection to use this site/tenant
+        auth = request.session.get('auth', {})
+        auth['tenant'] = obj.slice.slicename
+        obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
+        obj.delete()
+
+
+class ImageAdmin(XOSBaseAdmin):
+
+    fieldsets = [('Image Details',
+                  {'fields': ['backend_status_text', 'name', 'kind', 'disk_format', 'container_format', 'tag', 'path'],
+                   'classes': ['suit-tab suit-tab-general']})
+                 ]
+    readonly_fields = ('backend_status_text', )
+
+    suit_form_tabs = (('general', 'Image Details'), ('instances', 'Instances'),
+                      ('imagedeployments', 'Deployments'), ('admin-only', 'Admin-Only'))
+
+    inlines = [InstanceInline, ControllerImagesInline]
+
+    user_readonly_fields = ['name', 'disk_format',
+                            'container_format', 'tag', 'path']
+
+    list_display = ['backend_status_icon', 'name', 'kind']
+    list_display_links = ('backend_status_icon', 'name', )
+
+
+class NodeForm(forms.ModelForm):
+    nodelabels = forms.ModelMultipleChoiceField(
+        queryset=NodeLabel.objects.all(),
+        required=False,
+        help_text="Select which labels apply to this node",
+        widget=FilteredSelectMultiple(
+            verbose_name=('Labels'), is_stacked=False
+        )
+    )
+
+    class Meta:
+        model = Node
+        widgets = {
+            'site': LinkedSelect,
+            'deployment': LinkedSelect
+        }
+
+    def __init__(self, *args, **kwargs):
+        request = kwargs.pop('request', None)
+        super(NodeForm, self).__init__(*args, **kwargs)
+
+        if self.instance and self.instance.pk:
+            self.fields['nodelabels'].initial = self.instance.nodelabels.all()
+
+    def save(self, commit=True):
+        node = super(NodeForm, self).save(commit=False)
+
+        node.nodelabels = self.cleaned_data['nodelabels']
+
+        if commit:
+            node.save()
+
+        return node
+
+
+class NodeLabelAdmin(XOSBaseAdmin):
+    list_display = ('name',)
+    list_display_links = ('name', )
+
+    fields = ('name', )
+
+
+class NodeAdmin(XOSBaseAdmin):
+    form = NodeForm
+    list_display = ('backend_status_icon', 'name', 'site_deployment')
+    list_display_links = ('backend_status_icon', 'name', )
+    list_filter = ('site_deployment',)
+
+    inlines = [TagInline, InstanceInline]
+    fieldsets = [('Node Details', {'fields': ['backend_status_text', 'name', 'site_deployment'], 'classes':['suit-tab suit-tab-details']}),
+                 ('Labels', {'fields': ['nodelabels'], 'classes':['suit-tab suit-tab-labels']})]
+    readonly_fields = ('backend_status_text', )
+
+    user_readonly_fields = ['name', 'site_deployment']
+    user_readonly_inlines = [TagInline, InstanceInline]
+
+    suit_form_tabs = (('details', 'Node Details'), ('instances',
+                                                    'Instances'), ('labels', 'Labels'), ('tags', 'Tags'))
+
+    def formfield_for_foreignkey(self, db_field, request, **kwargs):
+        if db_field.name == 'site':
+            kwargs['queryset'] = Site.select_by_user(
+                request.user).filter(hosts_nodes=True)
+
+        field = super(NodeAdmin, self).formfield_for_foreignkey(
+            db_field, request, **kwargs)
+
+        return field
+
+
+class InstanceForm(forms.ModelForm):
+
+    class Meta:
+        model = Instance
+        ip = forms.CharField(widget=PlainTextWidget)
+        instance_name = forms.CharField(widget=PlainTextWidget)
+        widgets = {
+            'ip': PlainTextWidget(),
+            'instance_name': PlainTextWidget(),
+            'instance_id': PlainTextWidget(),
+            'slice': LinkedSelect,
+            'deployment': LinkedSelect,
+            'node': LinkedSelect,
+            'image': LinkedSelect
+        }
+
+
+class TagAdmin(XOSBaseAdmin):
+    list_display = ['backend_status_icon', 'service',
+                    'name', 'value', 'content_type', 'content_object', ]
+    list_display_links = list_display
+    user_readonly_fields = ['service', 'name',
+                            'value', 'content_type', 'content_object', ]
+    user_readonly_inlines = []
+
+
+class InstancePortInline(XOSTabularInline):
+    fields = ['backend_status_icon', 'network', 'instance', 'ip', 'mac']
+    readonly_fields = ("backend_status_icon", "ip", "mac")
+    model = Port
+    #selflink_fieldname = "network"
+    extra = 0
+    verbose_name_plural = "Ports"
+    verbose_name = "Port"
+    suit_classes = 'suit-tab suit-tab-ports'
+
+
+class InstanceAdmin(XOSBaseAdmin):
+    form = InstanceForm
+    fieldsets = [
+        ('Instance Details', {'fields': ['backend_status_text', 'slice', 'deployment', 'isolation', 'flavor', 'image', 'node',
+                                         'parent', 'all_ips_string', 'instance_id', 'instance_name', 'ssh_command', ], 'classes': ['suit-tab suit-tab-general'], }),
+        ('Container Settings', {'fields': ['volumes'], 'classes': [
+         'suit-tab suit-tab-container'], }),
+    ]
+    readonly_fields = ('backend_status_text', 'ssh_command', 'all_ips_string')
+    list_display = ['backend_status_icon', 'all_ips_string', 'instance_id',
+                    'instance_name', 'isolation', 'slice', 'flavor', 'image', 'node', 'deployment']
+    list_display_links = ('backend_status_icon',
+                          'all_ips_string', 'instance_id', )
+
+    suit_form_tabs = (('general', 'Instance Details'), ('ports', 'Ports'),
+                      ('container', 'Container Settings'), ('tags', 'Tags'))
+
+    inlines = [TagInline, InstancePortInline]
+
+    user_readonly_fields = ['slice', 'deployment',
+                            'node', 'ip', 'instance_name', 'flavor', 'image']
+
+    def ssh_command(self, obj):
+        ssh_command = obj.get_ssh_command()
+        if ssh_command:
+            return ssh_command
+        else:
+            return "(not available)"
+
+    def formfield_for_foreignkey(self, db_field, request, **kwargs):
+        if db_field.name == 'slice':
+            kwargs['queryset'] = Slice.select_by_user(request.user)
+
+        return super(InstanceAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
+
+    def queryset(self, request):
+        # admins can see all instances. Users can only see instances of
+        # the slices they belong to.
+        return Instance.select_by_user(request.user)
+
+    def add_view(self, request, form_url='', extra_context=None):
+        self.readonly_fields = ('backend_status_text',
+                                'ssh_command', 'all_ips_string')
+        return super(InstanceAdmin, self).add_view(request, form_url, extra_context)
+
+    def change_view(self, request, object_id, extra_context=None):
+        self.readonly_fields = ('backend_status_text', 'ssh_command',
+                                'all_ips_string', 'deployment', 'slice', 'flavor', 'image', 'node')
+        # for XOSAdminMixin.change_view's user_readonly_fields switching code
+        self.readonly_save = self.readonly_fields
+        return super(InstanceAdmin, self).change_view(request, object_id, extra_context)
+
+    def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None):
+        deployment_nodes = []
+#        for node in Node.objects.all():
+        for node in Node.objects.order_by("name"):
+            deployment_nodes.append(
+                (node.site_deployment.deployment.id, node.id, node.name))
+
+        deployment_flavors = []
+        for flavor in Flavor.objects.all():
+            for deployment in flavor.deployments.all():
+                deployment_flavors.append(
+                    (deployment.id, flavor.id, flavor.name))
+
+        deployment_images = []
+        for image in Image.objects.all():
+            for deployment_image in image.imagedeployments.all():
+                deployment_images.append(
+                    (deployment_image.deployment.id, image.id, image.name))
+
+        site_login_bases = []
+        for site in Site.objects.all():
+            site_login_bases.append((site.id, site.login_base))
+
+        context["deployment_nodes"] = deployment_nodes
+        context["deployment_flavors"] = deployment_flavors
+        context["deployment_images"] = deployment_images
+        context["site_login_bases"] = site_login_bases
+        return super(InstanceAdmin, self).render_change_form(request, context, add, change, form_url, obj)
+
+    def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
+        if db_field.name == 'deployment':
+            kwargs['queryset'] = Deployment.select_by_acl(request.user).filter(
+                sitedeployments__nodes__isnull=False).distinct()
+            kwargs['widget'] = forms.Select(
+                attrs={'onChange': "instance_deployment_changed(this);"})
+        if db_field.name == 'flavor':
+            kwargs['widget'] = forms.Select(
+                attrs={'onChange': "instance_flavor_changed(this);"})
+
+        field = super(InstanceAdmin, self).formfield_for_foreignkey(
+            db_field, request, **kwargs)
+
+        return field
+
+    # def save_model(self, request, obj, form, change):
+    #    # update openstack connection to use this site/tenant
+    #    auth = request.session.get('auth', {})
+    #    auth['tenant'] = obj.slice.name
+    #    obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
+    #    obj.creator = request.user
+    #    obj.save()
+
+    # def delete_model(self, request, obj):
+    #    # update openstack connection to use this site/tenant
+    #    auth = request.session.get('auth', {})
+    #    auth['tenant'] = obj.slice.name
+    #    obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
+    #    obj.delete()
+
+# class ContainerPortInline(XOSTabularInline):
+#    fields = ['backend_status_icon', 'network', 'container', 'ip', 'mac', 'segmentation_id']
+#    readonly_fields = ("backend_status_icon", "ip", "mac", "segmentation_id")
+#    model = Port
+#    selflink_fieldname = "network"
+#    extra = 0
+#    verbose_name_plural = "Ports"
+#    verbose_name = "Port"
+#    suit_classes = 'suit-tab suit-tab-ports'
+
+# class ContainerAdmin(XOSBaseAdmin):
+#    fieldsets = [
+#        ('Container Details', {'fields': ['backend_status_text', 'slice', 'node', 'docker_image', 'volumes', 'no_sync'], 'classes': ['suit-tab suit-tab-general'], })
+#    ]
+#    readonly_fields = ('backend_status_text', )
+#    list_display = ['backend_status_icon', 'id']
+#    list_display_links = ('backend_status_icon', 'id', )
+#
+#    suit_form_tabs =(('general', 'Container Details'), ('ports', 'Ports'))
+#
+#    inlines = [TagInline, ContainerPortInline]
+#
+#    def formfield_for_foreignkey(self, db_field, request, **kwargs):
+#        if db_field.name == 'slice':
+#            kwargs['queryset'] = Slice.select_by_user(request.user)
+#
+#        return super(ContainerAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
+#
+#    def queryset(self, request):
+#        # admins can see all instances. Users can only see instances of
+#        # the slices they belong to.
+#        return Container.select_by_user(request.user)
+
+
+class UserCreationForm(forms.ModelForm):
+    """A form for creating new users. Includes all the required
+    fields, plus a repeated password."""
+    password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
+    password2 = forms.CharField(
+        label='Password confirmation', widget=forms.PasswordInput)
+
+    class Meta:
+        model = User
+        fields = ('email', 'firstname', 'lastname', 'phone', 'public_key')
+
+    def clean_password2(self):
+        # Check that the two password entries match
+        password1 = self.cleaned_data.get("password1")
+        password2 = self.cleaned_data.get("password2")
+        if password1 and password2 and password1 != password2:
+            raise forms.ValidationError("Passwords don't match")
+        return password2
+
+    def save(self, commit=True):
+        # Save the provided password in hashed format
+        user = super(UserCreationForm, self).save(commit=False)
+        user.password = self.cleaned_data["password1"]
+        # user.set_password(self.cleaned_data["password1"])
+        if commit:
+            user.save()
+        return user
+
+
+class UserChangeForm(forms.ModelForm):
+    """A form for updating users. Includes all the fields on
+    the user, but replaces the password field with admin's
+    password hash display field.
+    """
+    password = ReadOnlyPasswordHashField(label='Password',
+                                         help_text='<a href=\"password/\">Change Password</a>.')
+
+    PROFILE_CHOICES = ((None, '------'), ('regular',
+                                          'Regular user'), ('cp', 'Content Provider'))
+    profile = forms.ChoiceField(
+        choices=PROFILE_CHOICES, required=False, label="Quick Profile")
+
+    class Meta:
+        model = User
+        widgets = {'public_key': UploadTextareaWidget, }
+
+    def clean_password(self):
+        # Regardless of what the user provides, return the initial value.
+        # This is done here, rather than on the field, because the
+        # field does not have access to the initial value
+        return self.initial["password"]
+
+    def save(self, *args, **kwargs):
+        if self.cleaned_data['profile']:
+            self.instance.apply_profile(self.cleaned_data['profile'])
+
+        return super(UserChangeForm, self).save(*args, **kwargs)
+
+
+class UserDashboardViewInline(XOSTabularInline):
+    model = UserDashboardView
+    extra = 0
+    suit_classes = 'suit-tab suit-tab-dashboards'
+    fields = ['user', 'dashboardView', 'order']
+
+
+class ControllerUserInline(XOSTabularInline):
+    model = ControllerUser
+    extra = 0
+    suit_classes = 'suit-tab suit-tab-admin-only'
+    fields = ['controller', 'user', 'kuser_id']
+
+
+class UserAdmin(XOSAdminMixin, UserAdmin):
+    # Note: Make sure XOSAdminMixin is listed before
+    # admin.ModelAdmin in the class declaration.
+
+    class Meta:
+        app_label = "core"
+
+    # The forms to add and change user instances
+    form = UserChangeForm
+    add_form = UserCreationForm
+
+    # The fields to be used in displaying the User model.
+    # These override the definitions on the base UserAdmin
+    # that reference specific fields on auth.User.
+    list_display = ('backend_status_icon', 'email',
+                    'firstname', 'lastname', 'site', 'last_login')
+    list_display_links = ("email",)
+    list_filter = ('site',)
+    inlines = [SlicePrivilegeInline, SitePrivilegeInline]
+    admin_inlines = [ControllerUserInline]
+    fieldListLoginDetails = ['backend_status_text', 'email', 'site', 'password', 'is_active',
+                             'is_readonly', 'is_admin', 'is_appuser', 'public_key', 'login_page', 'profile']
+    fieldListContactInfo = ['firstname', 'lastname', 'phone', 'timezone']
+
+    fieldsets = (
+        ('Login Details', {'fields': ['backend_status_text', 'email', 'site', 'password', 'is_active',
+                                      'is_readonly', 'is_admin', 'is_appuser', 'public_key'], 'classes': ['suit-tab suit-tab-general']}),
+        ('Contact Information', {'fields': (
+            'firstname', 'lastname', 'phone', 'timezone'), 'classes': ['suit-tab suit-tab-contact']}),
+        #('Important dates', {'fields': ('last_login',)}),
+    )
+    add_fieldsets = (
+        (None, {
+            'classes': ('wide',),
+            'fields': ('site', 'email', 'firstname', 'lastname', 'is_admin', 'is_readonly', 'is_appuser', 'phone', 'public_key', 'password1', 'password2')},
+         ),
+    )
+    readonly_fields = ('backend_status_text', )
+    search_fields = ('email',)
+    ordering = ('email',)
+    filter_horizontal = ()
+
+    user_readonly_fields = fieldListLoginDetails + fieldListContactInfo
+
+    @property
+    def suit_form_tabs(self):
+        if getattr(_thread_locals, "obj", None) is None:
+            return []
+        else:
+            tabs = [('general', 'Login Details'),
+                    ('contact', 'Contact Information'),
+                    ('sliceprivileges', 'Slice Privileges'),
+                    ('siteprivileges', 'Site Privileges')]
+
+            request = getattr(_thread_locals, "request", None)
+            if request and request.user.is_admin:
+                tabs.append(('admin-only', 'Admin-Only'))
+
+            return tabs
+
+    def formfield_for_foreignkey(self, db_field, request, **kwargs):
+        if db_field.name == 'site':
+            kwargs['queryset'] = Site.select_by_user(
+                request.user).filter(hosts_users=True)
+
+        return super(UserAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
+
+    def queryset(self, request):
+        return User.select_by_user(request.user)
+
+    def get_form(self, request, obj=None, **kwargs):
+        # copy login details list
+        login_details_fields = list(self.fieldListLoginDetails)
+        if not request.user.is_admin:
+            # only admins can see 'is_admin' and 'is_readonly' fields
+            if 'is_admin' in login_details_fields:
+                login_details_fields.remove('is_admin')
+            if 'is_readonly' in login_details_fields:
+                login_details_fields.remove('is_readonly')
+            if 'is_appuser' in login_details_fields:
+                login_details_fields.remove('is_admin')
+            if 'profile' in login_details_fields:
+                login_details_fields.remove('profile')
+            # if len(request.user.siteprivileges.filter(role__role = 'pi')) > 0:
+                # only admins and pis can change a user's site
+            #    self.readonly_fields = ('backend_status_text', 'site')
+        self.fieldsets = (
+            ('Login Details', {'fields': login_details_fields,
+                               'classes': ['suit-tab suit-tab-general']}),
+            ('Contact Information', {
+             'fields': self.fieldListContactInfo, 'classes': ['suit-tab suit-tab-contact']}),
+        )
+        return super(UserAdmin, self).get_form(request, obj, **kwargs)
+
+
+class ControllerDashboardViewInline(XOSTabularInline):
+    model = ControllerDashboardView
+    extra = 0
+    fields = ["controller", "url"]
+    suit_classes = 'suit-tab suit-tab-controllers'
+
+
+class DashboardViewAdmin(XOSBaseAdmin):
+    fieldsets = [('Dashboard View Details',
+                  {'fields': ['backend_status_text', 'name', 'url', 'enabled', 'deployments'],
+                   'classes': ['suit-tab suit-tab-general']})
+                 ]
+    list_display = ["name", "enabled", "url"]
+    readonly_fields = ('backend_status_text', )
+    inlines = [ControllerDashboardViewInline]
+
+    suit_form_tabs = (('general', 'Dashboard View Details'),
+                      ('controllers', 'Per-controller Dashboard Details'))
+
+
+class ServiceResourceInline(XOSTabularInline):
+    model = ServiceResource
+    extra = 0
+
+
+class ServiceClassAdmin(XOSBaseAdmin):
+    list_display = ('backend_status_icon', 'name',
+                    'commitment', 'membershipFee')
+    list_display_links = ('backend_status_icon', 'name', )
+    inlines = [ServiceResourceInline]
+
+    user_readonly_fields = ['name', 'commitment', 'membershipFee']
+    user_readonly_inlines = []
+
+
+class ReservedResourceInline(XOSTabularInline):
+    model = ReservedResource
+    extra = 0
+    suit_classes = 'suit-tab suit-tab-reservedresources'
+
+    def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
+        field = super(ReservedResourceInline, self).formfield_for_foreignkey(
+            db_field, request, **kwargs)
+
+        if db_field.name == 'resource':
+            # restrict resources to those that the slice's service class allows
+            if request._slice is not None:
+                field.queryset = field.queryset.filter(
+                    serviceClass=request._slice.serviceClass, calendarReservable=True)
+                if len(field.queryset) > 0:
+                    field.initial = field.queryset.all()[0]
+            else:
+                field.queryset = field.queryset.none()
+        elif db_field.name == 'instance':
+            # restrict instances to those that belong to the slice
+            if request._slice is not None:
+                field.queryset = field.queryset.filter(slice=request._slice)
+            else:
+                field.queryset = field.queryset.none()
+
+        return field
+
+    def queryset(self, request):
+        return ReservedResource.select_by_user(request.user)
+
+
+class ReservationChangeForm(forms.ModelForm):
+
+    class Meta:
+        model = Reservation
+        widgets = {
+            'slice': LinkedSelect
+        }
+
+
+class ReservationAddForm(forms.ModelForm):
+    slice = forms.ModelChoiceField(queryset=Slice.objects.all(), widget=forms.Select(
+        attrs={"onChange": "document.getElementById('id_refresh').value=1; submit()"}))
+    refresh = forms.CharField(widget=forms.HiddenInput())
+
+    class Media:
+        css = {'all': ('xos.css',)}   # .field-refresh { display: none; }
+
+    def clean_slice(self):
+        slice = self.cleaned_data.get("slice")
+        x = ServiceResource.objects.filter(
+            serviceClass=slice.serviceClass, calendarReservable=True)
+        if len(x) == 0:
+            raise forms.ValidationError(
+                "The slice you selected does not have a service class that allows reservations")
+        return slice
+
+    class Meta:
+        model = Reservation
+        widgets = {
+            'slice': LinkedSelect
+        }
+
+
+class ReservationAddRefreshForm(ReservationAddForm):
+    """ This form is displayed when the Reservation Form receives an update
+        from the Slice dropdown onChange handler. It doesn't validate the
+        data and doesn't save the data. This will cause the form to be
+        redrawn.
+    """
+
+    """ don't validate anything other than slice """
+    dont_validate_fields = ("startTime", "duration")
+
+    def full_clean(self):
+        result = super(ReservationAddForm, self).full_clean()
+
+        for fieldname in self.dont_validate_fields:
+            if fieldname in self._errors:
+                del self._errors[fieldname]
+
+        return result
+
+    """ don't save anything """
+
+    def is_valid(self):
+        return False
+
+
+class ReservationAdmin(XOSBaseAdmin):
+    fieldList = ['backend_status_text', 'slice', 'startTime', 'duration']
+    fieldsets = [('Reservation Details', {
+                  'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
+    readonly_fields = ('backend_status_text', )
+    list_display = ('startTime', 'duration')
+    form = ReservationAddForm
+
+    suit_form_tabs = (('general', 'Reservation Details'),
+                      ('reservedresources', 'Reserved Resources'))
+
+    inlines = [ReservedResourceInline]
+    user_readonly_fields = fieldList
+
+    def add_view(self, request, form_url='', extra_context=None):
+        timezone.activate(request.user.timezone)
+        request._refresh = False
+        request._slice = None
+        if request.method == 'POST':
+            # "refresh" will be set to "1" if the form was submitted due to
+            # a change in the Slice dropdown.
+            if request.POST.get("refresh", "1") == "1":
+                request._refresh = True
+                request.POST["refresh"] = "0"
+
+            # Keep track of the slice that was selected, so the
+            # reservedResource inline can filter items for the slice.
+            request._slice = request.POST.get("slice", None)
+            if (request._slice is not None):
+                request._slice = Slice.objects.get(id=request._slice)
+
+        result = super(ReservationAdmin, self).add_view(
+            request, form_url, extra_context)
+        return result
+
+    def changelist_view(self, request, extra_context=None):
+        timezone.activate(request.user.timezone)
+        return super(ReservationAdmin, self).changelist_view(request, extra_context)
+
+    def get_form(self, request, obj=None, **kwargs):
+        request._obj_ = obj
+        if obj is not None:
+            # For changes, set request._slice to the slice already set in the
+            # object.
+            request._slice = obj.slice
+            self.form = ReservationChangeForm
+        else:
+            if getattr(request, "_refresh", False):
+                self.form = ReservationAddRefreshForm
+            else:
+                self.form = ReservationAddForm
+        return super(ReservationAdmin, self).get_form(request, obj, **kwargs)
+
+    def get_readonly_fields(self, request, obj=None):
+        if (obj is not None):
+            # Prevent slice from being changed after the reservation has been
+            # created.
+            return ['slice']
+        else:
+            return []
+
+    def queryset(self, request):
+        return Reservation.select_by_user(request.user)
+
+
+class NetworkParameterTypeAdmin(XOSBaseAdmin):
+    list_display = ("backend_status_icon", "name", )
+    list_display_links = ('backend_status_icon', 'name', )
+    user_readonly_fields = ['name']
+    user_readonly_inlines = []
+
+
+class RouterAdmin(XOSBaseAdmin):
+    list_display = ("backend_status_icon", "name", )
+    list_display_links = ('backend_status_icon', 'name', )
+    user_readonly_fields = ['name']
+    user_readonly_inlines = []
+
+
+class RouterInline(XOSTabularInline):
+    model = Router.networks.through
+    extra = 0
+    verbose_name_plural = "Routers"
+    verbose_name = "Router"
+    suit_classes = 'suit-tab suit-tab-routers'
+
+
+class NetworkParameterInline(PlStackGenericTabularInline):
+    model = NetworkParameter
+    extra = 0
+    verbose_name_plural = "Parameters"
+    verbose_name = "Parameter"
+    suit_classes = 'suit-tab suit-tab-netparams'
+    fields = ['backend_status_icon', 'parameter', 'value']
+    readonly_fields = ('backend_status_icon', )
+
+
+class NetworkPortInline(XOSTabularInline):
+    fields = ['backend_status_icon', 'network', 'instance', 'ip', 'mac']
+    readonly_fields = ("backend_status_icon", "ip", "mac")
+    model = Port
+    #selflink_fieldname = "instance"
+    extra = 0
+    verbose_name_plural = "Ports"
+    verbose_name = "Port"
+    suit_classes = 'suit-tab suit-tab-ports'
+
+
+class NetworkSlicesInline(XOSTabularInline):
+    model = NetworkSlice
+    selflink_fieldname = "slice"
+    extra = 0
+    verbose_name_plural = "Slices"
+    verbose_name = "Slice"
+    suit_classes = 'suit-tab suit-tab-networkslices'
+    fields = ['backend_status_icon', 'network', 'slice']
+    readonly_fields = ('backend_status_icon', )
+
+
+class ControllerNetworkInline(XOSTabularInline):
+    model = ControllerNetwork
+    extra = 0
+    verbose_name_plural = "Controller Networks"
+    verbose_name = "Controller Network"
+    suit_classes = 'suit-tab suit-tab-admin-only'
+    fields = ['backend_status_icon', 'controller',
+              'net_id', 'subnet_id', 'subnet']
+    readonly_fields = ('backend_status_icon', )
+
+
+class NetworkForm(forms.ModelForm):
+
+    class Meta:
+        model = Network
+        widgets = {
+            'topologyParameters': UploadTextareaWidget,
+            'controllerParameters': UploadTextareaWidget,
+        }
+
+
+class NetworkAdmin(XOSBaseAdmin):
+    list_display = ("backend_status_icon", "name", "subnet", "ports", "labels")
+    list_display_links = ('backend_status_icon', 'name', )
+    readonly_fields = ("subnet", )
+    inlines = [NetworkParameterInline, NetworkPortInline,
+               NetworkSlicesInline, RouterInline]
+    admin_inlines = [ControllerNetworkInline]
+
+    form = NetworkForm
+
+    fieldsets = [
+        (None, {'fields': ['backend_status_text', 'name', 'template', 'ports', 'labels',
+                           'owner', 'guaranteed_bandwidth', 'permit_all_slices',
+                           'permitted_slices', 'network_id', 'router_id', 'subnet_id',
+                           'subnet', 'autoconnect'],
+                'classes':['suit-tab suit-tab-general']}),
+        (None, {'fields': ['topology_parameters', 'controller_url', 'controller_parameters'],
+                'classes':['suit-tab suit-tab-sdn']}),
+    ]
+
+    readonly_fields = ('backend_status_text', )
+    user_readonly_fields = ['name', 'template', 'ports', 'labels', 'owner', 'guaranteed_bandwidth',
+                            'permit_all_slices', 'permitted_slices', 'network_id', 'router_id',
+                            'subnet_id', 'subnet', 'autoconnect']
+
+    @property
+    def suit_form_tabs(self):
+        tabs = [('general', 'Network Details'),
+                ('sdn', 'SDN Configuration'),
+                ('netparams', 'Parameters'),
+                ('ports', 'Ports'),
+                ('networkslices', 'Slices'),
+                ('routers', 'Routers'),
+                ]
+
+        request = getattr(_thread_locals, "request", None)
+        if request and request.user.is_admin:
+            tabs.append(('admin-only', 'Admin-Only'))
+
+        return tabs
+
+
+class NetworkTemplateAdmin(XOSBaseAdmin):
+    list_display = ("backend_status_icon", "name",
+                    "guaranteed_bandwidth", "visibility")
+    list_display_links = ('backend_status_icon', 'name', )
+    user_readonly_fields = ["name", "guaranteed_bandwidth", "visibility"]
+    user_readonly_inlines = []
+    inlines = [NetworkParameterInline, ]
+    fieldsets = [
+        (None, {'fields': ['name', 'description', 'guaranteed_bandwidth', 'visibility', 'translation', 'access', 'shared_network_name', 'shared_network_id', 'topology_kind', 'controller_kind'],
+                'classes':['suit-tab suit-tab-general']}), ]
+    suit_form_tabs = (('general', 'Network Template Details'),
+                      ('netparams', 'Parameters'))
+
+
+class PortAdmin(XOSBaseAdmin):
+    list_display = ("backend_status_icon", "id", "ip")
+    list_display_links = ('backend_status_icon', 'id')
+    readonly_fields = ("subnet", )
+    inlines = [NetworkParameterInline]
+
+    fieldsets = [
+        (None, {'fields': ['backend_status_text', 'network', 'instance', 'ip', 'port_id', 'mac'],
+                'classes':['suit-tab suit-tab-general']}),
+    ]
+
+    readonly_fields = ('backend_status_text', )
+    suit_form_tabs = (('general', 'Port Details'), ('netparams', 'Parameters'))
+
+
+class FlavorAdmin(XOSBaseAdmin):
+    list_display = ("backend_status_icon", "name",
+                    "flavor", "order", "default")
+    list_display_links = ("backend_status_icon", "name")
+    user_readonly_fields = ("name", "flavor")
+    fields = ("name", "description", "flavor", "order", "default")
+
+# register a signal that caches the user's credentials when they log in
+
+
+def cache_credentials(sender, user, request, **kwds):
+    auth = {'username': request.POST['username'],
+            'password': request.POST['password']}
+    request.session['auth'] = auth
+user_logged_in.connect(cache_credentials)
+
+
+def dollar_field(fieldName, short_description):
+    def newFunc(self, obj):
+        try:
+            x = "$ %0.2f" % float(getattr(obj, fieldName, 0.0))
+        except:
+            x = getattr(obj, fieldName, 0.0)
+        return x
+    newFunc.short_description = short_description
+    return newFunc
+
+
+def right_dollar_field(fieldName, short_description):
+    def newFunc(self, obj):
+        try:
+            #x= '<div align=right style="width:6em">$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
+            x = '<div align=right>$ %0.2f</div>' % float(
+                getattr(obj, fieldName, 0.0))
+        except:
+            x = getattr(obj, fieldName, 0.0)
+        return x
+    newFunc.short_description = short_description
+    newFunc.allow_tags = True
+    return newFunc
+
+
+class InvoiceChargeInline(XOSTabularInline):
+    model = Charge
+    extra = 0
+    verbose_name_plural = "Charges"
+    verbose_name = "Charge"
+    exclude = ['account']
+    fields = ["date", "kind", "state", "object",
+              "coreHours", "dollar_amount", "slice"]
+    readonly_fields = ["date", "kind", "state",
+                       "object", "coreHours", "dollar_amount", "slice"]
+    can_delete = False
+    max_num = 0
+
+    dollar_amount = right_dollar_field("amount", "Amount")
+
+
+class InvoiceAdmin(admin.ModelAdmin):
+    list_display = ("date", "account")
+
+    inlines = [InvoiceChargeInline]
+
+    fields = ["date", "account", "dollar_amount"]
+    readonly_fields = ["date", "account", "dollar_amount"]
+
+    dollar_amount = dollar_field("amount", "Amount")
+
+
+class InvoiceInline(XOSTabularInline):
+    model = Invoice
+    extra = 0
+    verbose_name_plural = "Invoices"
+    verbose_name = "Invoice"
+    fields = ["date", "dollar_amount"]
+    readonly_fields = ["date", "dollar_amount"]
+    suit_classes = 'suit-tab suit-tab-accountinvoice'
+    can_delete = False
+    max_num = 0
+
+    dollar_amount = right_dollar_field("amount", "Amount")
+
+
+class PendingChargeInline(XOSTabularInline):
+    model = Charge
+    extra = 0
+    verbose_name_plural = "Charges"
+    verbose_name = "Charge"
+    exclude = ["invoice"]
+    fields = ["date", "kind", "state", "object",
+              "coreHours", "dollar_amount", "slice"]
+    readonly_fields = ["date", "kind", "state",
+                       "object", "coreHours", "dollar_amount", "slice"]
+    suit_classes = 'suit-tab suit-tab-accountpendingcharges'
+    can_delete = False
+    max_num = 0
+
+    def queryset(self, request):
+        qs = super(PendingChargeInline, self).queryset(request)
+        qs = qs.filter(state="pending")
+        return qs
+
+    dollar_amount = right_dollar_field("amount", "Amount")
+
+
+class PaymentInline(XOSTabularInline):
+    model = Payment
+    extra = 1
+    verbose_name_plural = "Payments"
+    verbose_name = "Payment"
+    fields = ["date", "dollar_amount"]
+    readonly_fields = ["date", "dollar_amount"]
+    suit_classes = 'suit-tab suit-tab-accountpayments'
+    can_delete = False
+    max_num = 0
+
+    dollar_amount = right_dollar_field("amount", "Amount")
+
+
+class AccountAdmin(admin.ModelAdmin):
+    list_display = ("site", "balance_due")
+
+    inlines = [InvoiceInline, PaymentInline, PendingChargeInline]
+
+    fieldsets = [
+        (None, {'fields': ['site', 'dollar_balance_due', 'dollar_total_invoices', 'dollar_total_payments'], 'classes':['suit-tab suit-tab-general']}), ]
+
+    readonly_fields = ['site', 'dollar_balance_due',
+                       'dollar_total_invoices', 'dollar_total_payments']
+
+    suit_form_tabs = (
+        ('general', 'Account Details'),
+        ('accountinvoice', 'Invoices'),
+        ('accountpayments', 'Payments'),
+        ('accountpendingcharges', 'Pending Charges'),
+    )
+
+    dollar_balance_due = dollar_field("balance_due", "Balance Due")
+    dollar_total_invoices = dollar_field("total_invoices", "Total Invoices")
+    dollar_total_payments = dollar_field("total_payments", "Total Payments")
+
+
+class ProgramForm(forms.ModelForm):
+
+    class Meta:
+        model = Program
+        widgets = {
+            'contents': UploadTextareaWidget(attrs={'rows': 20, 'cols': 80, 'class': "input-xxlarge"}),
+            'description': forms.Textarea(attrs={'rows': 3, 'cols': 80, 'class': 'input-xxlarge'}),
+            'messages': forms.Textarea(attrs={'rows': 20, 'cols': 80, 'class': 'input-xxlarge'}),
+            'output': forms.Textarea(attrs={'rows': 3, 'cols': 80, 'class': 'input-xxlarge'})
+        }
+
+
+class ProgramAdmin(XOSBaseAdmin):
+    list_display = ("name", "status")
+    list_display_links = ('name', "status")
+
+    form = ProgramForm
+
+    fieldsets = [
+        (None, {'fields': ['name', 'command', 'kind', 'description', 'output', 'status'],
+                'classes':['suit-tab suit-tab-general']}),
+        (None, {'fields': ['contents'],
+                'classes':['suit-tab suit-tab-contents']}),
+        (None, {'fields': ['messages'],
+                'classes':['suit-tab suit-tab-messages']}),
+    ]
+
+    readonly_fields = ("status",)
+
+    @property
+    def suit_form_tabs(self):
+        tabs = [('general', 'Program Details'),
+                ('contents', 'Program Source'),
+                ('messages', 'Messages'),
+                ]
+
+        request = getattr(_thread_locals, "request", None)
+        if request and request.user.is_admin:
+            tabs.append(('admin-only', 'Admin-Only'))
+
+        return tabs
+
+
+class AddressPoolForm(forms.ModelForm):
+
+    class Meta:
+        model = Program
+        widgets = {
+            'addresses': UploadTextareaWidget(attrs={'rows': 20, 'cols': 80, 'class': "input-xxlarge"}),
+        }
+
+
+class AddressPoolAdmin(XOSBaseAdmin):
+    list_display = ("name", "cidr")
+    list_display_links = ('name',)
+
+    form = AddressPoolForm
+
+    fieldsets = [
+        (None, {'fields': ['name', 'cidr', 'gateway_ip', 'gateway_mac', 'addresses', 'inuse', 'service'],
+                'classes':['suit-tab suit-tab-general']}),
+    ]
+
+    readonly_fields = ("status",)
+
+    @property
+    def suit_form_tabs(self):
+        tabs = [('general', 'Program Details'),
+                ('contents', 'Program Source'),
+                ('messages', 'Messages'),
+                ]
+
+#        request=getattr(_thread_locals, "request", None)
+#        if request and request.user.is_admin:
+#            tabs.append( ('admin-only', 'Admin-Only') )
+
+        return tabs
+
+class AddressPoolInline(XOSTabularInline):
+    model = AddressPool
+    extra = 0
+    suit_classes = 'suit-tab suit-tab-addresspools'
+    fields = ['cidr', 'gateway_ip', 'gateway_mac']
+    readonly_fields = ['cidr',]
+
+    # disable the add link
+    def has_add_permission(self, request):
+        return False
+
+class DiagAdmin(XOSBaseAdmin):
+    list_display = ("name", "backend_status", "backend_register")
+    list_display_links = ('name',)
+
+    fieldsets = [
+        (None, {'fields': ['name', 'backend_status', 'backend_register'],
+                'classes':['suit-tab suit-tab-general']}),
+    ]
+
+# Now register the new UserAdmin...
+admin.site.register(User, UserAdmin)
+# ... and, since we're not using Django's builtin permissions,
+# unregister the Group model from admin.
+# admin.site.unregister(Group)
+
+# When debugging it is often easier to see all the classes, but for regular use
+# only the top-levels should be displayed
+showAll = False
+
+admin.site.register(Deployment, DeploymentAdmin)
+admin.site.register(Controller, ControllerAdmin)
+admin.site.register(Site, SiteAdmin)
+admin.site.register(Slice, SliceAdmin)
+admin.site.register(Service, ServiceAdmin)
+admin.site.register(ServiceController, ServiceControllerAdmin)
+#admin.site.register(Reservation, ReservationAdmin)
+admin.site.register(Network, NetworkAdmin)
+admin.site.register(Port, PortAdmin)
+admin.site.register(Router, RouterAdmin)
+admin.site.register(NetworkTemplate, NetworkTemplateAdmin)
+admin.site.register(Program, ProgramAdmin)
+#admin.site.register(Account, AccountAdmin)
+#admin.site.register(Invoice, InvoiceAdmin)
+
+if True:
+    admin.site.register(NetworkParameterType, NetworkParameterTypeAdmin)
+    admin.site.register(ServiceClass, ServiceClassAdmin)
+    admin.site.register(Tag, TagAdmin)
+    admin.site.register(ControllerRole)
+    admin.site.register(SiteRole)
+    admin.site.register(SliceRole)
+    admin.site.register(Node, NodeAdmin)
+    admin.site.register(NodeLabel, NodeLabelAdmin)
+    #admin.site.register(SlicePrivilege, SlicePrivilegeAdmin)
+    #admin.site.register(SitePrivilege, SitePrivilegeAdmin)
+    admin.site.register(Instance, InstanceAdmin)
+    admin.site.register(Image, ImageAdmin)
+    admin.site.register(DashboardView, DashboardViewAdmin)
+    admin.site.register(Flavor, FlavorAdmin)
+    admin.site.register(TenantRoot, TenantRootAdmin)
+    admin.site.register(TenantRootRole, TenantRootRoleAdmin)
+    admin.site.register(TenantRole, TenantRoleAdmin)
+    admin.site.register(TenantAttribute, TenantAttributeAdmin)
+    admin.site.register(AddressPool, AddressPoolAdmin)
+    admin.site.register(Diag, DiagAdmin)
diff --git a/xos/core/context_processors.py b/xos/core/context_processors.py
new file mode 100644
index 0000000..bb5030b
--- /dev/null
+++ b/xos/core/context_processors.py
@@ -0,0 +1,19 @@
+from django.conf import settings
+from core.models import Site
+
+
+def xos(request):
+    allSites = []
+    for site in Site.objects.all():
+        allowNewUsers = True    # replace with logic for blessing sites for registration, if necessary
+        allSites.append( {"name": site.name,
+                           "id": site.id,
+                           "allowNewUsers": allowNewUsers} )
+
+    return {"DISABLE_MINIDASHBOARD": settings.DISABLE_MINIDASHBOARD,
+            "XOS_BRANDING_NAME": settings.XOS_BRANDING_NAME,
+            "XOS_BRANDING_CSS": settings.XOS_BRANDING_CSS,
+            "XOS_BRANDING_ICON": settings.XOS_BRANDING_ICON,
+            "XOS_BRANDING_FAVICON": settings.XOS_BRANDING_FAVICON,
+            "XOS_BRANDING_BG": settings.XOS_BRANDING_BG,
+            "sites": allSites}
diff --git a/xos/core/dashboard/__init__.py b/xos/core/dashboard/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/xos/core/dashboard/__init__.py
@@ -0,0 +1 @@
+
diff --git a/xos/core/dashboard/sites.py b/xos/core/dashboard/sites.py
new file mode 100644
index 0000000..c68ce78
--- /dev/null
+++ b/xos/core/dashboard/sites.py
@@ -0,0 +1,78 @@
+#sites.py
+
+from django.contrib.admin.sites import AdminSite
+
+
+class AdminMixin(object):
+    """Mixin for AdminSite to allow custom dashboard views."""
+
+    def __init__(self, *args, **kwargs):
+        return super(AdminMixin, self).__init__(*args, **kwargs)
+
+    def get_urls(self):
+        """Add our dashboard view to the admin urlconf. Deleted the default index."""
+        from django.conf.urls import patterns, url
+        from views import DashboardCustomize, DashboardDynamicView, SimulatorView, LoggedInView, \
+                          DashboardUserSiteView,  \
+                          TenantViewData, TenantCreateSlice, TenantAddUser,TenantAddOrRemoveInstanceView, TenantPickSitesView, TenantDeleteSliceView, \
+                          TenantUpdateSlice, DashboardSliceInteractions, RequestAccessView
+
+        from views import view_urls
+
+        urls = super(AdminMixin, self).get_urls()
+        del urls[0]
+
+        # these ones are for the views that were written before we implemented
+        # the ability to get the url from the View class.
+        dashboard_urls = [
+               url(r'^$', self.admin_view(DashboardDynamicView.as_view()),
+                    name="index"),
+               url(r'^loggedin/$', self.admin_view(LoggedInView.as_view()),
+                    name="loggedin"),
+               url(r'^test/', self.admin_view(DashboardUserSiteView.as_view()),
+                    name="test"),
+               url(r'^sliceinteractions/(?P<name>\w+)/$', self.admin_view(DashboardSliceInteractions.as_view()),
+                    name="interactions"),
+               url(r'^dashboard/(?P<name>[\w|\W]+)/$', self.admin_view(DashboardDynamicView.as_view()),
+                    name="dashboard"),
+               url(r'^dashboardWholePage/(?P<name>\w+)/$', self.admin_view(DashboardDynamicView.as_view()),
+                    {"wholePage": True},
+                    name="dashboardWholePage"),
+	       url(r'^customize/$', self.admin_view(DashboardCustomize.as_view()),
+                    name="customize"),
+               url(r'^hpcdashuserslices/', self.admin_view(DashboardUserSiteView.as_view()),
+                    name="hpcdashuserslices"),
+               url(r'^welcome/$', self.admin_view(DashboardDynamicView.as_view()),
+                    name="welcome"),
+               url(r'^simulator/', self.admin_view(SimulatorView.as_view()),
+                    name="simulator"),
+               url(r'^tenantaddorreminstance/$', self.admin_view(TenantAddOrRemoveInstanceView.as_view()),
+                    name="tenantaddorreminstance"),
+               url(r'^tenantview/$', self.admin_view(TenantViewData.as_view()),
+                    name="tenantview"),
+               url(r'^createnewslice/$', self.admin_view(TenantCreateSlice.as_view()),
+                    name="createnewslice"),
+               url(r'^adduser/$', self.admin_view(TenantAddUser.as_view()),
+                      name="adduser"),
+               url(r'^requestaccess/$', RequestAccessView.as_view(),
+                      name="requestacces"),
+	       url(r'^updateslice/$', self.admin_view(TenantUpdateSlice.as_view()),
+                    name="updateslice"),
+               url(r'^picksites/$', self.admin_view(TenantPickSitesView.as_view()),
+                    name="picksites"),
+	       url(r'^tenantdeleteslice/$', self.admin_view(TenantDeleteSliceView.as_view()),
+                    name="tenantdeleteslice")
+        ]
+
+        # these ones are for the views that have a "url" member in the class
+        for (view_url, view_classname, view_class) in view_urls:
+            dashboard_urls.append( url(view_url, self.admin_view(view_class.as_view()), name=view_classname.lower()))
+
+        return dashboard_urls + urls
+
+
+class SitePlus(AdminMixin, AdminSite):
+    """
+    A Django AdminSite with the AdminMixin to allow registering custom
+    dashboard view.
+    """
diff --git a/xos/core/dashboard/views/__init__.py b/xos/core/dashboard/views/__init__.py
new file mode 100644
index 0000000..8c693c8
--- /dev/null
+++ b/xos/core/dashboard/views/__init__.py
@@ -0,0 +1,44 @@
+#from home import DashboardWelcomeView, DashboardDynamicView
+#from tenant import TenantCreateSlice, TenantUpdateSlice, TenantDeleteSliceView, TenantAddOrRemoveInstanceView, TenantPickSitesView, TenantViewData
+#from simulator import SimulatorView
+#from cdn import DashboardSummaryAjaxView, DashboardAddOrRemoveInstanceView, DashboardAjaxView
+#from analytics import DashboardAnalyticsAjaxView
+#from customize import DashboardCustomize
+#from interactions import DashboardSliceInteractions
+#from test import DashboardUserSiteView
+
+from django.views.generic import View
+from django.conf.urls import patterns, url
+import os, sys
+import inspect
+import importlib
+
+# Find all modules in the current directory that have descendents of the View
+# object, and add them as globals to this module. Also, build up a list of urls
+# based on the "url" field of the view classes.
+
+sys_path_save = sys.path
+try:
+    # __import__() and importlib.import_module() both import modules from
+    # sys.path. So we make sure that the path where we can find the views is
+    # the first thing in sys.path.
+    view_dir = os.path.dirname(os.path.abspath(__file__))
+    sys.path = [view_dir] + sys.path
+    view_urls = []
+    for fn in os.listdir(view_dir):
+        pathname = os.path.join(view_dir,fn)
+        if os.path.isfile(pathname) and fn.endswith(".py") and (fn!="__init__.py"):
+            #module = imp.load_source(fn[:-3],pathname)
+            #module = importlib.import_module(fn[:-3])
+            module = __import__(fn[:-3])
+            for classname in dir(module):
+                c = getattr(module, classname, None)
+
+                if inspect.isclass(c) and issubclass(c, View) and (classname not in globals()):
+                    globals()[classname] = c
+
+                    view_url = getattr(c, "url", None)
+                    if view_url:
+                        view_urls.append( (view_url, classname, c) )
+finally:
+    sys.path = sys_path_save
diff --git a/xos/core/dashboard/views/analytics.unused b/xos/core/dashboard/views/analytics.unused
new file mode 100644
index 0000000..8661cf4
--- /dev/null
+++ b/xos/core/dashboard/views/analytics.unused
@@ -0,0 +1,13 @@
+from view_common import *
+import random
+from xos_analytics import DoXOSAnalytics
+
+class DashboardAnalyticsAjaxView(View):
+    url = r'^analytics/(?P<name>\w+)/$'
+
+    def get(self, request, name="hello_world", **kwargs):
+        if (name == "bigquery"):
+            (mimetype, data) = DoXOSAnalytics(request)
+            return HttpResponse(data, content_type=mimetype)
+        else:
+            return HttpResponse(json.dumps("Unknown"), content_type='application/javascript')
diff --git a/xos/core/dashboard/views/cdn.unused b/xos/core/dashboard/views/cdn.unused
new file mode 100644
index 0000000..0a71ffe
--- /dev/null
+++ b/xos/core/dashboard/views/cdn.unused
@@ -0,0 +1,139 @@
+from view_common import *
+from xos_analytics import XOSAnalytics, RED_LOAD, BLUE_LOAD
+
+def getCDNContentProviderData():
+    cps = []
+    for dm_cp in ContentProvider.objects.all():
+        cp = {"name": dm_cp.name,
+              "account": dm_cp.account}
+        cps.append(cp)
+
+    return cps
+
+def getCDNOperatorData(randomizeData = False, wait=True):
+    HPC_SLICE_NAME = "HyperCache"
+
+    bq = XOSAnalytics()
+
+    rows = bq.get_cached_query_results(bq.compose_cached_query(), wait)
+
+    # wait=False on the first time the Dashboard is opened. This means we might
+    # not have any rows yet. The dashboard code polls every 30 seconds, so it
+    # will eventually pick them up.
+
+    if rows:
+        rows = bq.postprocess_results(rows, filter={"event": "hpc_heartbeat"}, maxi=["cpu"], count=["hostname"], computed=["bytes_sent/elapsed"], groupBy=["Time","site"], maxDeltaTime=80)
+
+        # dictionaryize the statistics rows by site name
+        stats_rows = {}
+        for row in rows:
+            stats_rows[row["site"]] = row
+    else:
+        stats_rows = {}
+
+    slice = Slice.objects.filter(name=HPC_SLICE_NAME)
+    if slice:
+        slice_instances = list(slice[0].instances.all())
+    else:
+        slice_instances = []
+
+    new_rows = {}
+    for site in Site.objects.all():
+        # compute number of instances allocated in the data model
+        allocated_instances = 0
+        for instance in slice_instances:
+            if instance.node.site == site:
+                allocated_instances = allocated_instances + 1
+
+        stats_row = stats_rows.get(site.name,{})
+
+        max_cpu = stats_row.get("max_avg_cpu", stats_row.get("max_cpu",0))
+        cpu=float(max_cpu)/100.0
+        hotness = max(0.0, ((cpu*RED_LOAD) - BLUE_LOAD)/(RED_LOAD-BLUE_LOAD))
+
+        try:
+           lat=float(site.location.latitude)
+           long=float(site.location.longitude)
+        except:
+           lat=0
+           long=0
+
+        # format it to what that CDN Operations View is expecting
+        new_row = {"lat": lat,
+               "long": long,
+               "health": 0,
+               #"numNodes": int(site.nodes.count()),
+               "activeHPCInstances": int(stats_row.get("count_hostname", 0)),     # measured number of instances, from bigquery statistics
+               "numHPCInstances": allocated_instances,                              # allocated number of instances, from data model
+               "siteUrl": str(site.site_url),
+               "bandwidth": stats_row.get("sum_computed_bytes_sent_div_elapsed",0),
+               "load": max_cpu,
+               "hot": float(hotness)}
+        new_rows[str(site.name)] = new_row
+
+    # get rid of sites with 0 instances that overlap other sites with >0 instances
+    for (k,v) in new_rows.items():
+        bad=False
+        if v["numHPCInstances"]==0:
+            for v2 in new_rows.values():
+                if (v!=v2) and (v2["numHPCInstances"]>=0):
+                    d = haversine(v["lat"],v["long"],v2["lat"],v2["long"])
+                    if d<100:
+                         bad=True
+            if bad:
+                del new_rows[k]
+
+    return new_rows
+
+class DashboardSummaryAjaxView(View):
+    url=r'^hpcsummary/'
+
+    def get(self, request, **kwargs):
+        def avg(x):
+            if len(x)==0:
+                return 0
+            return float(sum(x))/len(x)
+
+        sites = getCDNOperatorData().values()
+
+        sites = [site for site in sites if site["numHPCInstances"]>0]
+
+        total_instances = sum( [site["numHPCInstances"] for site in sites] )
+        total_bandwidth = sum( [site["bandwidth"] for site in sites] )
+        average_cpu = int(avg( [site["load"] for site in sites] ))
+
+        result= {"total_instances": total_instances,
+                "total_bandwidth": total_bandwidth,
+                "average_cpu": average_cpu}
+
+        return HttpResponse(json.dumps(result), content_type='application/javascript')
+
+class DashboardAddOrRemoveInstanceView(View):
+    # TODO: deprecate this view in favor of using TenantAddOrRemoveInstanceView
+
+    url=r'^dashboardaddorreminstance/$'
+
+    def post(self, request, *args, **kwargs):
+        siteName = request.POST.get("site", None)
+        actionToDo = request.POST.get("actionToDo", "0")
+
+        siteList = [Site.objects.get(name=siteName)]
+        slice = Slice.objects.get(name="HyperCache")
+
+        if request.user.isReadOnlyUser():
+            return HttpResponseForbidden("User is in read-only mode")
+
+        if (actionToDo == "add"):
+            user_ip = request.GET.get("ip", get_ip(request))
+            slice_increase_instances(request.user, user_ip, siteList, slice, image.objects.all()[0], 1)
+        elif (actionToDo == "rem"):
+            slice_decrease_instances(request.user, siteList, slice, 1)
+
+        print '*' * 50
+        print 'Ask for site: ' + siteName + ' to ' + actionToDo + ' another HPC Instance'
+        return HttpResponse(json.dumps("Success"), content_type='application/javascript')
+
+class DashboardAjaxView(View):
+    url = r'^hpcdashboard/'
+    def get(self, request, **kwargs):
+        return HttpResponse(json.dumps(getCDNOperatorData(True)), content_type='application/javascript')
diff --git a/xos/core/dashboard/views/customize.py b/xos/core/dashboard/views/customize.py
new file mode 100644
index 0000000..6005562
--- /dev/null
+++ b/xos/core/dashboard/views/customize.py
@@ -0,0 +1,22 @@
+from view_common import *
+
+class DashboardCustomize(View):
+    def post(self, request, *args, **kwargs):
+        if request.user.isReadOnlyUser():
+            return HttpResponseForbidden("User is in read-only mode")
+
+        dashboards = request.POST.get("dashboards", None)
+        if not dashboards:
+            dashboards=[]
+        else:
+            dashboards = [x.strip() for x in dashboards.split(",")]
+            dashboards = [DashboardView.objects.get(name=x) for x in dashboards]
+
+        request.user.userdashboardviews.all().delete()
+
+        for i,dashboard in enumerate(dashboards):
+            udbv = UserDashboardView(user=request.user, dashboardView=dashboard, order=i)
+            udbv.save()
+
+        return HttpResponse(json.dumps("Success"), content_type='application/javascript')
+
diff --git a/xos/core/dashboard/views/download_ssh_commands.py b/xos/core/dashboard/views/download_ssh_commands.py
new file mode 100644
index 0000000..92bcac4
--- /dev/null
+++ b/xos/core/dashboard/views/download_ssh_commands.py
@@ -0,0 +1,18 @@
+from view_common import *
+from core.xoslib.objects.sliceplus import SlicePlus
+
+# This was intended to serve as a download feature for the tenant view. Found
+# a better way to do it. This is deprecated.
+
+class DownloadSSHCommandsView(View):
+    url = r'^sshcommands/(?P<sliceid>\d+)/$'
+
+    def get(self, request, sliceid=None, **kwargs):
+        #slice = Slices.objects.get(id=sliceid);
+        #for instance in slice.instances.all():
+        #    if (instance.instance_id && instance.instance_name):
+
+        slice = SlicePlus.objects.get(id=sliceid)
+
+        return HttpResponse(slice.getSliceInfo()["sshCommands"], content_type='text/text')
+
diff --git a/xos/core/dashboard/views/home.py b/xos/core/dashboard/views/home.py
new file mode 100644
index 0000000..f72be81
--- /dev/null
+++ b/xos/core/dashboard/views/home.py
@@ -0,0 +1,204 @@
+from view_common import *
+from django.http import HttpResponseRedirect
+import sys
+
+
+def isInt(s):
+    try:
+        int(s)
+        return True
+    except ValueError:
+        return False
+
+
+class LoggedInView(TemplateView):
+    def get(self, request, name="root", *args, **kwargs):
+        if request.user.login_page:
+            return HttpResponseRedirect(request.user.login_page)
+        else:
+            return HttpResponseRedirect("/admin/")
+
+
+class DashboardDynamicView(TemplateView):
+    head_template = r"""{% extends "admin/dashboard/dashboard_base.html" %}
+       {% load admin_static %}
+       {% block content %}
+    """
+
+    head_wholePage_template = r"""{% extends "admin/wholePage.html" %}
+       {% load admin_static %}
+       {% block content %}
+    """
+
+    tail_template = r"{% endblock %}"
+
+    def get(self, request, name="root", *args, **kwargs):
+        context = self.get_context_data(**kwargs)
+        context = getDashboardContext(request.user, context)
+
+        if name == "root":
+            # maybe it is a bit hacky, didn't want to mess up everything @teone
+            user_dashboards = request.user.get_dashboards()
+            first_dasboard_name = user_dashboards[0].id
+            return self.singleDashboardView(request, first_dasboard_name, context)
+            # return self.multiDashboardView(request, context)
+        elif kwargs.get("wholePage", None):
+            return self.singleFullView(request, name, context)
+        else:
+            return self.singleDashboardView(request, name, context)
+
+    def readTemplate(self, fn):
+        TEMPLATE_DIRS = [XOS_DIR + "/templates/admin/dashboard/",
+                         XOS_DIR + "/core/xoslib/dashboards/"]
+
+        for template_dir in TEMPLATE_DIRS:
+            pathname = os.path.join(template_dir, fn) + ".html"
+            if os.path.exists(pathname):
+                break
+        else:
+            return "failed to find %s in %s" % (fn, TEMPLATE_DIRS)
+
+        template = open(pathname, "r").read()
+        if (fn == "tenant"):
+            # fix for tenant view - it writes html to a div called tabs-5
+            template = '<div id="tabs-5"></div>' + template
+        return template
+
+    def embedDashboardUrl(self, url):
+        if url.startswith("template:"):
+            fn = url[9:]
+            return self.readTemplate(fn)
+        elif url.startswith("http"):
+            return '<iframe src="%s" width="100%%" height="100%%" style="min-height: 1024px;" frameBorder="0"></iframe>' % url
+        else:
+            return "don't know how to load dashboard %s" % url
+
+    def embedDashboardView(self, view, i=0):
+        body = ""
+        url = view.url
+        if (view.controllers.all().count() > 0):
+            body = body + 'Controller: <select id="dashselect-%d">' % i
+            body = body + '<option value="None">(select a controller)</option>'
+            for j, controllerdashboard in enumerate(view.controllerdashboardviews.all()):
+                body = body + '<option value="%d">%s</option>' % (j, controllerdashboard.controller.name)
+            body = body + '</select><hr>'
+
+            for j, controllerdashboard in enumerate(view.controllerdashboardviews.all()):
+                body = body + '<script type="text/template" id="dashtemplate-%d-%d">\n%s\n</script>\n' % (i,j, self.embedDashboardUrl(controllerdashboard.url));
+
+            body = body + '<div id="dashcontent-%d" class="dashcontent"></div>\n' % i
+
+            body = body + """<script>
+                             $("#dashselect-%d").change(function() {
+                                 v=$("#dashselect-%d").val();
+                                 if (v=="None") {
+                                     $("#dashcontent-%d").html("");
+                                     return;
+                                 }
+                                 $("#dashcontent-%d").html( $("#dashtemplate-%d-" + v).html() );
+                             });
+                             //$("#dashcontent-%d").html( $("#dashtemplate-%d-0").html() );
+                             </script>
+                          """ % (i, i, i, i, i, i, i)
+        else:
+            body = body + self.embedDashboardUrl(url)
+        return body
+
+    def multiDashboardView(self, request, context):
+        head_template = self.head_template
+        tail_template = self.tail_template
+
+        dashboards = request.user.get_dashboards()
+
+        if not request.user.is_appuser:
+            # customize is a special dashboard they always get
+            customize = DashboardView.objects.filter(name="Customize")
+            if customize:
+                dashboards.append(customize[0])
+
+        tabs = []
+        bodies = []
+
+        i = 0
+        for view in dashboards:
+            # don't display disabled dashboards
+            if (not view.enabled):
+                continue
+
+            tabs.append('<li><a href="#dashtab-%d">%s</a></li>\n' % (i, view.name))
+            body = '<div id="dashtab-%d">%s</div>\n' % (i, self.embedDashboardView(view, i))
+
+            bodies.append(body)
+            i = i + 1
+
+        # embed content provider dashboards
+        for cp in ContentProvider.objects.all():
+            if request.user in cp.users.all():
+                tabs.append('<li><a href="#dashtab-%d">%s</a></li>\n' % (i, cp.name))
+
+                body = ""
+                body = body + '<div id="dashtab-%d">\n' % i
+                body = body + self.embedDashboardUrl("http:/admin/hpc/contentprovider/%s/%s/embeddedfilteredchange" % (cp.serviceProvider.hpcService.id, cp.id))
+                body = body + '</div>\n'
+
+                bodies.append(body)
+                i = i + 1
+
+        if (len(tabs) == 1) and (len(bodies) == 1):
+            # there is only one dashboard, so optimize out the tabbing
+            contents = bodies[0]
+        else:
+            contents = """
+             <div id="hometabs" >
+             <ul id="suit_form_tabs" class="nav nav-tabs nav-tabs-suit" data-tab-prefix="suit-tab">
+             %s
+             </ul>
+             %s
+             </div>
+            """ % ("\n".join(tabs), "\n".join(bodies))
+
+        t = template.Template(head_template + contents + self.tail_template)
+
+        response_kwargs = {}
+        response_kwargs.setdefault('content_type', self.content_type)
+        return self.response_class(
+            request=request,
+            template=t,
+            context=context,
+            **response_kwargs)
+
+    def singleDashboardView(self, request, id, context):
+        head_template = self.head_template
+        tail_template = self.tail_template
+
+        # if id is a number, load by datamodel,
+        # else look directly for the template
+        if(isInt(id)):
+            view = DashboardView.objects.get(id=id)
+            t = template.Template(head_template + self.embedDashboardView(view) + self.tail_template)
+        else:
+            t = template.Template(head_template + self.readTemplate("xos" + id) + self.tail_template)
+
+        response_kwargs = {}
+        response_kwargs.setdefault('content_type', self.content_type)
+        return self.response_class(
+            request=request,
+            template=t,
+            context=context,
+            **response_kwargs)
+
+    def singleFullView(self, request, id, context):
+        head_template = self.head_wholePage_template
+        tail_template = self.tail_template
+
+        view = DashboardView.objects.get(id=id)
+
+        t = template.Template(head_template + self.embedDashboardView(view) + self.tail_template)
+
+        response_kwargs = {}
+        response_kwargs.setdefault('content_type', self.content_type)
+        return self.response_class(
+            request=request,
+            template=t,
+            context=context,
+            **response_kwargs)
diff --git a/xos/core/dashboard/views/interactions.py b/xos/core/dashboard/views/interactions.py
new file mode 100644
index 0000000..f74d01e
--- /dev/null
+++ b/xos/core/dashboard/views/interactions.py
@@ -0,0 +1,103 @@
+from view_common import *
+
+class DashboardSliceInteractions(View):
+    def get(self, request, name="users", **kwargs):
+        colors = ["#005586", "#6ebe49", "orange", "#707170", "#00c4b3", "#077767", "dodgerblue", "#a79b94", "#c4e76a", "red"]
+
+        groups = []
+        matrix = []
+        slices = list(Slice.objects.all())
+
+        ids_by_slice = self.build_id_list(slices, name)
+
+        slices = [x for x in slices if (len(ids_by_slice[x])>0)]
+
+        for i,slice in enumerate(slices):
+            groups.append({"name": slice.name, "color": colors[i%len(colors)]})
+            row=self.buildMatrix(slice, slices, name, ids_by_slice)
+            matrix.append(row)
+
+        result = {"groups": groups, "matrix": matrix}
+
+        if name=="users":
+            result["title"] = "Slice interactions by user privilege"
+            result["objectName"] = "users"
+        elif name=="networks":
+            result["title"] = "Slice interactions by network membership"
+            result["objectName"] = "networks"
+        elif name=="sites":
+            result["title"] = "Slice interactions by site ownership"
+            result["objectName"] = "sites"
+        elif name=="instance_sites":
+            result["title"] = "Slice interactions by instance sites"
+            result["objectName"] = "sites"
+        elif name=="instance_nodes":
+            result["title"] = "Slice interactions by instance nodes"
+            result["objectName"] = "nodes"
+
+        return HttpResponse(json.dumps(result), content_type='application/javascript')
+
+    def build_id_list(self, slices, name):
+        ids_by_slice = {}
+        for slice in slices:
+            # build up a list of object ids that are used by each slice
+            ids_by_slice[slice] = self.getIds(slice, name)
+
+        return ids_by_slice
+
+    def buildMatrix(self, slice, slices, name, ids_by_slice):
+        not_only_my_ids = []
+
+        # build up a list of object ids that are used by other slices
+        for otherSlice in ids_by_slice.keys():
+            if (slice != otherSlice):
+                for id in ids_by_slice[otherSlice]:
+                    if not id in not_only_my_ids:
+                        not_only_my_ids.append(id)
+
+        # build up a list of ids that are used only by the slice, and not
+        # shared with any other slice
+        only_my_ids = []
+        for id in ids_by_slice[slice]:
+             if id not in not_only_my_ids:
+                  only_my_ids.append(id)
+
+        row = []
+        for otherSlice in ids_by_slice.keys():
+            if (otherSlice == slice):
+                row.append(len(only_my_ids))
+            else:
+                row.append(self.inCommonIds(ids_by_slice[slice], ids_by_slice[otherSlice]))
+
+        return row
+
+    def getIds(self, slice, name):
+        ids=[]
+        if name=="users":
+            for sp in slice.slice_privileges.all():
+                    if sp.user.id not in ids:
+                        ids.append(sp.user.id)
+        elif name=="networks":
+            for sp in slice.networkslices.all():
+                    if sp.network.id not in ids:
+                        ids.append(sp.network.id)
+        elif name=="sites":
+            ids = [slice.site.id]
+        elif name=="instance_sites":
+            for sp in slice.instances.all():
+                 if sp.node.site.id not in ids:
+                     ids.append(sp.node.site.id)
+        elif name=="instance_nodes":
+            for sp in slice.instances.all():
+                 if sp.node.id not in ids:
+                     ids.append(sp.node.id)
+        return ids
+
+    def inCommonIds(self, ids1, ids2):
+        count = 0
+        for id in ids1:
+            if id in ids2:
+                count+=1
+        return count
+
+
diff --git a/xos/core/dashboard/views/shell.py b/xos/core/dashboard/views/shell.py
new file mode 100644
index 0000000..c49133b
--- /dev/null
+++ b/xos/core/dashboard/views/shell.py
@@ -0,0 +1,91 @@
+import datetime
+import os
+import sys
+import time
+import json
+from django.http import HttpResponse, HttpResponseServerError, HttpResponseForbidden
+from django.views.generic import TemplateView, View
+from core.models import *
+from django.forms.models import model_to_dict
+
+def ensure_serializable(d):
+    d2={}
+    for (k,v) in d.items():
+        # datetime is not json serializable
+        if isinstance(v, datetime.datetime):
+            d2[k] = time.mktime(v.timetuple())
+        elif v.__class__.__name__ == "Geoposition":
+            pass
+        else:
+            d2[k] = v
+    return d2
+
+def instance_to_dict(instance):
+    d = model_to_dict(instance)
+    d["slice_id"] = instance.slice.id
+    d["node_id"] = instance.node.id
+    return d
+
+def slice_to_dict(slice):
+    d = model_to_dict(slice)
+    d["instances"] = [instance_to_dict(x) for x in slice.instances]
+    return d
+
+def node_to_dict(node):
+    d = model_to_dict(node)
+    d["instances"] = []
+
+
+class OpenCloudData:
+    def __init__(self, user):
+        self.loadAll()
+
+    def loadAll(self):
+        self.allNodes = list(Node.objects.all())
+        self.allSlices = list(Slice.objects.all())
+        self.allInstances = list(Instance.objects.all())
+        self.allSites = list(Site.objects.all())
+
+        self.site_id = {}
+        for site in self.allSites:
+            d = model_to_dict(site)
+            d["node_ids"] = []
+            d["slice_ids"] = []
+            self.site_id[site.id] = ensure_serializable(d)
+
+        self.node_id = {}
+        for node in self.allNodes:
+            d = model_to_dict(node)
+            d["instance_ids"] = []
+            self.node_id[node.id] = ensure_serializable(d)
+            self.site_id[node.site_id]["node_ids"].append(node.id)
+
+        self.slice_id = {}
+        for slice in self.allSlices:
+            d = model_to_dict(slice)
+            d["instance_ids"] = []
+            self.slice_id[slice.id] = ensure_serializable(d)
+            self.site_id[slice.site_id]["slice_ids"].append(site.id)
+
+        print self.slice_id.keys()
+
+        self.instance_id = {}
+        for instance in self.allInstances:
+            self.instance_id[instance.id] = model_to_dict(instance)
+
+            self.slice_id[instance.slice_id]["instance_ids"].append(instance.id)
+            self.node_id[instance.node_id]["instance_ids"].append(instance.id)
+
+    def get_opencloud_data(self):
+        return {"slices": self.slice_id.values(),
+                "instances": self.instance_id.values(),
+                "nodes": self.node_id.values(),
+                "sites": self.site_id.values()}
+
+class ShellDataView(View):
+    url = r'^shelldata/'
+
+    def get(self, request, **kwargs):
+        result = OpenCloudData(request.user).get_opencloud_data()
+
+        return HttpResponse(json.dumps(result), mimetype='application/json')
diff --git a/xos/core/dashboard/views/simulator.py b/xos/core/dashboard/views/simulator.py
new file mode 100644
index 0000000..43332ab
--- /dev/null
+++ b/xos/core/dashboard/views/simulator.py
@@ -0,0 +1,18 @@
+from view_common import *
+
+class SimulatorView(View):
+    def get(self, request, **kwargs):
+        sim = json.loads(file("/tmp/simulator.json","r").read())
+        text = "<html><head></head><body>"
+        text += "Iteration: %d<br>" % sim["iteration"]
+        text += "Elapsed since report %d<br><br>" % sim["elapsed_since_report"]
+        text += "<table border=1>"
+        text += "<tr><th>site</th><th>trend</th><th>weight</th><th>bytes_sent</th><th>hot</th></tr>"
+        for site in sim["site_load"].values():
+            text += "<tr>"
+            text += "<td>%s</td><td>%0.2f</td><td>%0.2f</td><td>%d</td><td>%0.2f</td>" % \
+                        (site["name"], site["trend"], site["weight"], site["bytes_sent"], site["load_frac"])
+            text += "</tr>"
+        text += "</table>"
+        text += "</body></html>"
+        return HttpResponse(text)
diff --git a/xos/core/dashboard/views/tenant.py b/xos/core/dashboard/views/tenant.py
new file mode 100644
index 0000000..6fbc4d6
--- /dev/null
+++ b/xos/core/dashboard/views/tenant.py
@@ -0,0 +1,451 @@
+from view_common import *
+from core.models import *
+import functools
+from django.contrib.auth.models import BaseUserManager
+from django.core import serializers
+from django.core.mail import EmailMultiAlternatives
+import json
+
+BLESSED_DEPLOYMENTS = ["US-MaxPlanck", "US-GeorgiaTech", "US-Princeton", "US-Washington", "US-Stanford"]
+
+class RequestAccessView(View):
+    def post(self, request, *args, **kwargs):
+	email = request.POST.get("email", "0")
+	firstname = request.POST.get("firstname", "0")
+	lastname = request.POST.get("lastname", "0")
+	site = request.POST.get("site","0")
+        # see if it already exists
+        user=User.objects.filter(email=BaseUserManager.normalize_email(email))
+        if (user):
+             user = user[0]
+             if user.is_active:
+                 # force a new email to be sent
+                 user.is_registering=True
+                 user.save()
+                 return HttpResponse(json.dumps({"error": "already_approved"}), content_type='application/javascript')
+             else:
+                 return HttpResponse(json.dumps({"error": "already_pending"}), content_type='application/javascript')
+
+        user=User.deleted_objects.filter(email=BaseUserManager.normalize_email(email))
+        if (user):
+            return HttpResponse(json.dumps({"error": "is_deleted"}), content_type='application/javascript')
+
+	user = User(
+            email=BaseUserManager.normalize_email(email),
+            firstname=firstname,
+            lastname=lastname,
+	    is_active=False,
+            is_admin=False,
+            is_registering=True
+        )
+        user.save()
+	user.site=Site.objects.get(name=site)
+	user.save(update_fields=['site'])
+	sitePriv = SitePrivilege.objects.filter(site=user.site)
+	userId = user.id
+	userUrl = "http://"+request.get_host()+"/admin/core/user/"+str(userId)
+	for sp in sitePriv:
+		subject, from_email, to = 'Authorize OpenCloud User Account', 'support@opencloud.us', str(sp.user)
+		text_content = 'This is an important message.'
+		html_content = """<p>Please authorize the following user on site """+site+""": <br><br>User: """+firstname+""" """+lastname+"""<br>Email: """+email+"""<br><br>
+Check the checkbox next to Is Active property at <a href="""+userUrl+"""> this link</a> to authorize the user, and then click the Save button. If you do not recognize this individual, or otherwise do not want to approve this account, please ignore this email. If you do not approve this request in 48 hours, the account will automatically be deleted.</p>"""
+		msg = EmailMultiAlternatives(subject,text_content, from_email, [to])
+		msg.attach_alternative(html_content, "text/html")
+		msg.send()
+        return HttpResponse(serializers.serialize("json",[user,]), content_type='application/javascript')
+
+class TenantCreateSlice(View):
+    def post(self, request, *args, **kwargs):
+        if request.user.isReadOnlyUser():
+            return HttpResponseForbidden("User is in read-only mode")
+
+        sliceName = request.POST.get("sliceName", "0")
+        serviceClass = request.POST.get("serviceClass", "0")
+        imageName = request.POST.get("imageName", "0")
+        actionToDo = request.POST.get("actionToDo", "0")
+        networkPorts = request.POST.get("network","0")
+        mountDataSets = request.POST.get("mountDataSets","0")
+        privateVolume = request.POST.get("privateVolume","0")
+        userEmail = request.POST.get("userEmail","0")
+        if (actionToDo == "add"):
+           serviceClass = ServiceClass.objects.get(name=serviceClass)
+           site = request.user.site
+           image = Image.objects.get(name=imageName)
+           newSlice = Slice(name=sliceName,serviceClass=serviceClass,site=site,image_preference=image,mount_data_sets=mountDataSets)
+           newSlice.save()
+	   privateTemplate="Private"
+	   publicTemplate="Public shared IPv4"
+	   privateNetworkName = sliceName+"-"+privateTemplate
+	   publicNetworkName = sliceName+"-"+publicTemplate
+	   slice=Slice.objects.get(name=sliceName)
+	   addNetwork(privateNetworkName,privateTemplate,slice)
+	   addNetwork(publicNetworkName,publicTemplate,slice)
+	   addOrModifyPorts(networkPorts,sliceName)
+	   if privateVolume=="true":
+	   	privateVolForSlice(request.user,sliceName)
+	   slicePrivs=SlicePrivilege(user=User.objects.get(email=userEmail),slice=Slice.objects.get(name=sliceName),role=SliceRole.objects.get(role="admin"))
+           slicePrivs.save()
+        return HttpResponse(json.dumps("Slice created"), content_type='application/javascript')
+
+class TenantAddUser(View):
+    def post(self, request, *args, **kwargs):
+        if request.user.isReadOnlyUser():
+            return HttpResponseForbidden("User is in read-only mode")
+
+        sliceName = request.POST.get("sliceName", "0")
+        userEmail = request.POST.get("userEmail","0")
+        slicePrivs=SlicePrivilege(user=User.objects.get(email=userEmail),slice=Slice.objects.get(name=sliceName),role=SliceRole.objects.get(role="admin"))
+        slicePrivs.save()
+        return HttpResponse(json.dumps("Slice created"), content_type='application/javascript')
+
+def privateVolForSlice(user,sliceName):
+	if not hasPrivateVolume(sliceName):
+	   volumeName=createPrivateVolume(user,sliceName)
+	   readWrite="true"
+	   mountVolume(sliceName,volumeName,readWrite)
+
+class TenantUpdateSlice(View):
+    def post(self, request, *args, **kwargs):
+        if request.user.isReadOnlyUser():
+            return HttpResponseForbidden("User is in read-only mode")
+
+        sliceName = request.POST.get("sliceName", "0")
+        serviceClass = request.POST.get("serviceClass", "0")
+        imageName = request.POST.get("imageName", "0")
+        actionToDo = request.POST.get("actionToDo", "0")
+        networkPorts = request.POST.get("networkPorts","0")
+        dataSet = request.POST.get("dataSet","0")
+        privateVolume = request.POST.get("privateVolume","0")
+        slice = Slice.objects.all()
+        for entry in slice:
+                serviceClass = ServiceClass.objects.get(name=serviceClass)
+                if(entry.name==sliceName):
+                         if (actionToDo == "update"):
+                                setattr(entry,'serviceClass',serviceClass)
+                                setattr(entry,'image_preference',imageName)
+                                setattr(entry,'mount_data_sets',dataSet)
+                                entry.save()
+                                break
+	addOrModifyPorts(networkPorts,sliceName)
+	if privateVolume=="true":
+                privateVolForSlice(request.user,sliceName)
+        return HttpResponse(json.dumps("Slice updated"), content_type='application/javascript')
+
+def addNetwork(name,template,sliceName):
+	networkTemplate=NetworkTemplate.objects.get(name=template)
+	newNetwork = Network(name = name,
+                              template = networkTemplate,
+                              owner = sliceName)
+        newNetwork.save()
+	addNetworkSlice(newNetwork,sliceName)
+
+def addNetworkSlice(networkSlice,sliceName):
+	newNetworkSlice=NetworkSlice(network =networkSlice,
+				     slice=sliceName)
+	newNetworkSlice.save()
+
+def addOrModifyPorts(networkPorts,sliceName):
+	networkList = Network.objects.all()
+        networkInfo = []
+        if networkPorts:
+           for networkEntry in networkList:
+               networkSlices = networkEntry.slices.all()
+               for slice in networkSlices:
+                   if slice.name==sliceName:
+                          if networkEntry.template.name=="Public shared IPv4":
+                             setattr(networkEntry,'ports',networkPorts)
+                             networkEntry.save()
+
+def getTenantSliceInfo(user, tableFormat = False):
+    tenantSliceDetails = {}
+    tenantSliceData = getTenantInfo(user)
+    tenantServiceClassData = getServiceClassInfo(user)
+    if (tableFormat):
+       tenantSliceDetails['userSliceInfo'] = userSliceTableFormatter(tenantSliceData)
+       tenantSliceDetails['sliceServiceClass']=userSliceTableFormatter(tenantServiceClassData)
+    else:
+       tenantSliceDetails['userSliceInfo'] = tenantSliceData
+    tenantSliceDetails['sliceServiceClass']=userSliceTableFormatter(tenantServiceClassData)
+    tenantSliceDetails['image']=userSliceTableFormatter(getImageInfo(user))
+    tenantSliceDetails['deploymentSites']=userSliceTableFormatter(getDeploymentSites())
+    #tenantSliceDetails['sites'] = userSliceTableFormatter(getTenantSitesInfo())
+    tenantSliceDetails['mountDataSets'] = userSliceTableFormatter(getMountDataSets())
+    tenantSliceDetails['publicKey'] = getPublicKey(user)
+    tenantSliceDetails['availableSites']=userSliceTableFormatter(getAvailableSites())
+    tenantSliceDetails['role']=getUserRole(user)
+    tenantSliceDetails['siteUsers']=getSiteUsers(user)
+    return tenantSliceDetails
+
+def getSiteUsers(user):
+	users = User.objects.filter(site=user.site)
+	siteUsers=[]
+        for entry in users:
+		siteUsers.append(str(entry))
+	return siteUsers
+
+
+def getUserRole(user):
+	sp=SitePrivilege.objects.filter(user=user)
+	for entry in sp:
+		return str(entry.role)
+
+
+def getTenantInfo(user):
+    slices =Slice.objects.all()
+    userSliceInfo = []
+    for entry in slices:
+       if (entry.site == user.site):
+           sliceName = Slice.objects.get(id=entry.id).name
+           slice = Slice.objects.get(name=Slice.objects.get(id=entry.id).name)
+           sliceServiceClass = entry.serviceClass.name
+           preferredImage =  entry.image_preference
+           #sliceDataSet = entry.mount_data_sets
+           sliceNetwork = {}
+           numInstance = 0
+           sliceImage=""
+           sliceSite = {}
+           sliceNode = {}
+           sliceInstance= {}
+           #createPrivateVolume(user,sliceName)
+           available_sites = getAvailableSites()
+           for instance in slice.instances.all():
+                if instance.node.site.name in available_sites:
+                    sliceSite[instance.node.site.name] = sliceSite.get(instance.node.site.name,0) + 1
+                    sliceImage = instance.image.name
+                    sliceNode[str(instance)] = instance.node.name
+           numInstance = sum(sliceSite.values())
+           numSites = len(sliceSite)
+           userSliceInfo.append({'sliceName': sliceName,'sliceServiceClass': sliceServiceClass,'preferredImage':preferredImage,'numOfSites':numSites, 'sliceSite':sliceSite,'sliceImage':sliceImage,'numOfInstances':numInstance,'instanceNodePair':sliceNode})
+    return userSliceInfo
+
+def getTenantSitesInfo():
+        availableSites=getAvailableSites()
+	tenantSiteInfo=[]
+        for entry in Site.objects.all():
+            if entry.name in availableSites:
+		 tenantSiteInfo.append({'siteName':entry.name})
+	return tenantSiteInfo
+
+def getPublicKey(user):
+	users=User.objects.all()
+        for key in users:
+        	if (str(key.email)==str(user)):
+                    	sshKey = key.public_key
+        return sshKey
+
+def getServiceClassInfo(user):
+    serviceClassList = ServiceClass.objects.all()
+    sliceInfo = []
+    for entry in serviceClassList:
+          sliceInfo.append({'serviceClass':entry.name})
+    return sliceInfo
+
+def getImageInfo(user):
+    #imageList = Image.objects.all()
+    #imageInfo = []
+    #for imageEntry in imageList:
+          #imageInfo.append({'Image':imageEntry.name})
+    imageInfo = []
+    tempImageInfo = []
+    length = len(BLESSED_DEPLOYMENTS)
+    for deployment in Deployment.objects.all():
+        if deployment.name in BLESSED_DEPLOYMENTS:
+            for x in deployment.imagedeployments.all():
+                tempImageInfo.append(x.image.name)
+    temp = {}
+    for i in set(tempImageInfo):
+    	temp[i] = tempImageInfo.count(i)
+    for key in temp:
+	if temp[key]>1:
+		imageInfo.append(key)
+    return imageInfo
+
+def createPrivateVolume(user, sliceName):
+    caps = Volume.CAP_READ_DATA | Volume.CAP_WRITE_DATA | Volume.CAP_HOST_DATA
+    getattr(Volume.default_gateway_caps,"read data") | \
+           getattr(Volume.default_gateway_caps,"write data") | \
+           getattr(Volume.default_gateway_caps,"host files")
+    v = Volume(name="private_" + sliceName, owner_id=user, description="private volume for %s" % sliceName, blocksize=61440, private=True, archive=False, default_gateway_caps = caps)
+    v.save()
+    return v
+
+SYNDICATE_REPLICATE_PORTNUM = 1025
+
+def get_free_port():
+    inuse={}
+    inuse[SYNDICATE_REPLICATE_PORTNUM] = True
+    for vs in VolumeSlice.objects.all():
+        inuse[vs.peer_portnum]=True
+        inuse[vs.replicate_portnum]=True
+    for network in Network.objects.all():
+        if not network.ports:
+            continue
+        network_ports = [x.strip() for x in network.ports.split(",")]
+        for network_port in network_ports:
+            try:
+                inuse[int(network_port)] = True
+            except:
+                # in case someone has put a malformed port number in the list
+                pass
+    for i in range(1025, 65535):
+        if not inuse.get(i,False):
+            return i
+    return False
+
+def mountVolume(sliceName, volumeName, readWrite):
+    slice = Slice.objects.get(name=sliceName)
+    volume = Volume.objects.get(name=volumeName)
+    # choose some unused port numbers
+    flags = Volume.CAP_READ_DATA
+    if readWrite:
+        flags = flags | Volume.CAP_WRITE_DATA
+    vs = VolumeSlice(volume_id = volume, slice_id = slice, gateway_caps=flags, peer_portnum = get_free_port(), replicate_portnum = SYNDICATE_REPLICATE_PORTNUM)
+    vs.save()
+
+def hasPrivateVolume(sliceName):
+     slice = Slice.objects.get(name=sliceName)
+     for vs in VolumeSlice.objects.filter(slice_id=slice):
+         if vs.volume_id.private:
+             return True
+     return False
+
+def getMountDataSets():
+        dataSetInfo=[]
+        for volume in Volume.objects.all():
+            if not volume.private:
+                dataSetInfo.append({'DataSet': volume.name})
+
+        return dataSetInfo
+
+def getDeploymentSites():
+    deploymentList = Deployment.objects.all()
+    deploymentInfo = []
+    for entry in deploymentList:
+        deploymentInfo.append({'DeploymentSite':entry.name})
+    return deploymentInfo
+
+def getAvailableSites():
+    available_sites = []
+    for deployment in Deployment.objects.all():
+        if deployment.name in BLESSED_DEPLOYMENTS:
+            for x in deployment.sitedeployments.all():
+		if x.site.nodes.all():
+                	available_sites.append(x.site.name)
+    return list(set(available_sites))
+
+class TenantDeleteSliceView(View):
+        def post(self,request):
+                if request.user.isReadOnlyUser():
+                    return HttpResponseForbidden("User is in read-only mode")
+                sliceName = request.POST.get("sliceName",None)
+                slice = Slice.objects.get(name=sliceName)
+                #print slice, slice.id
+                sliceToDel=Slice(name=sliceName, id=slice.id)
+                sliceToDel.delete()
+                return HttpResponse(json.dumps("Slice deleted"), content_type='application/javascript')
+
+class TenantAddOrRemoveInstanceView(View):
+    """ Add or remove instances from a Slice
+
+        Arguments:
+            siteName - name of site. If not specified, XOS will pick the
+                       best site.,
+            actionToDo - [add | rem]
+            count - number of instances to add or remove
+            sliceName - name of slice
+            noAct - if set, no changes will be made to db, but result will still
+                    show which sites would have been modified.
+
+        Returns:
+            Dictionary of sites that were modified, and the count of nodes
+            that were added or removed at each site.
+    """
+    def post(self, request, *args, **kwargs):
+        siteName = request.POST.get("siteName", None)
+        actionToDo = request.POST.get("actionToDo", None)
+        count = int(request.POST.get("count","0"))
+	sliceName = request.POST.get("slice", None)
+	imageName = request.POST.get("image",None)
+        noAct = request.POST.get("noAct", False)
+
+        if not sliceName:
+            return HttpResponseServerError("No slice name given")
+
+        slice = Slice.objects.get(name=sliceName)
+	image = Image.objects.get(name=imageName)
+
+        if siteName:
+            siteList = [Site.objects.get(name=siteName)]
+        else:
+            siteList = None
+
+        if (actionToDo == "add"):
+            user_ip = request.GET.get("ip", get_ip(request))
+            if (siteList is None):
+                siteList = tenant_pick_sites(user, user_ip, slice, count)
+
+            sitesChanged = slice_increase_instances(request.user, user_ip, siteList, slice, image, count, noAct)
+        elif (actionToDo == "rem"):
+            sitesChanged = slice_decrease_instances(request.user, siteList, slice, count, noAct)
+        else:
+            return HttpResponseServerError("Unknown actionToDo %s" % actionToDo)
+
+        return HttpResponse(json.dumps(sitesChanged), content_type='application/javascript')
+
+    def get(self, request, *args, **kwargs):
+        request.POST = request.GET
+        return self.post(request, *args, **kwargs)  # for testing REST in browser
+        #return HttpResponseServerError("GET is not supported")
+
+class TenantPickSitesView(View):
+    """ primarily just for testing purposes """
+    def get(self, request, *args, **kwargs):
+        count = request.GET.get("count","0")
+	slice = request.GET.get("slice",None)
+        if slice:
+            slice = Slice.objects.get(name=slice)
+        ip = request.GET.get("ip", get_ip(request))
+        sites = tenant_pick_sites(request.user, user_ip=ip, count=0, slice=slice)
+        sites = [x.name for x in sites]
+        return HttpResponse(json.dumps(sites), content_type='application/javascript')
+
+def siteSortKey(site, slice=None, count=None, lat=None, lon=None):
+    # try to pick a site we're already using
+    has_instances_here=False
+    if slice:
+        for instance in slice.instances.all():
+            if instance.node.site.name == site.name:
+                has_instances_here=True
+
+    # Haversine method
+    d = haversine(site.location.latitude, site.location.longitude, lat, lon)
+
+    return (-has_instances_here, d)
+
+def tenant_pick_sites(user, user_ip=None, slice=None, count=None):
+    """ Returns list of sites, sorted from most favorable to least favorable """
+    lat=None
+    lon=None
+    try:
+        client_geo = GeoIP().city(user_ip)
+        if client_geo:
+            lat=float(client_geo["latitude"])
+            lon=float(client_geo["longitude"])
+    except:
+        print "exception in geo code"
+        traceback.print_exc()
+
+    available_sites = getAvailableSites()
+    sites = Site.objects.all()
+    sites = [x for x in sites if x.name in available_sites]
+    sites = sorted(sites, key=functools.partial(siteSortKey, slice=slice, count=count, lat=lat, lon=lon))
+
+    return sites
+
+class TenantViewData(View):
+    def get(self, request, **kwargs):
+        return HttpResponse(json.dumps(getTenantSliceInfo(request.user, True)), content_type='application/javascript')
+
+class RequestAccountView(View):
+    def get(self, request, **kwargs):
+        return HttpResponse()
diff --git a/xos/core/dashboard/views/test.py b/xos/core/dashboard/views/test.py
new file mode 100644
index 0000000..4eae215
--- /dev/null
+++ b/xos/core/dashboard/views/test.py
@@ -0,0 +1,5 @@
+from view_common import *
+
+class DashboardUserSiteView(View):
+    def get(self, request, **kwargs):
+        return HttpResponse(json.dumps(getDashboardContext(request.user, tableFormat=True)), content_type='application/javascript')
diff --git a/xos/core/dashboard/views/view_common.py b/xos/core/dashboard/views/view_common.py
new file mode 100644
index 0000000..ba78ffd
--- /dev/null
+++ b/xos/core/dashboard/views/view_common.py
@@ -0,0 +1,172 @@
+import os
+import sys
+from django.views.generic import TemplateView, View
+import datetime
+from pprint import pprint
+import json
+from services.syndicate_storage.models import *
+from core.models import *
+from services.hpc.models import ContentProvider
+from operator import attrgetter
+from django import template
+from django.views.decorators.csrf import csrf_exempt
+from django.http import HttpResponse, HttpResponseServerError, HttpResponseForbidden
+from django.core import urlresolvers
+from django.contrib.gis.geoip import GeoIP
+from django.db.models import Q
+from ipware.ip import get_ip
+from operator import itemgetter, attrgetter
+import traceback
+import math
+from xos.config import Config, XOS_DIR
+
+def getDashboardContext(user, context={}, tableFormat = False):
+        context = {}
+
+        userSliceData = getSliceInfo(user)
+        if (tableFormat):
+            context['userSliceInfo'] = userSliceTableFormatter(userSliceData)
+        else:
+            context['userSliceInfo'] = userSliceData
+#        context['cdnData'] = getCDNOperatorData(wait=False)
+#        context['cdnContentProviders'] = getCDNContentProviderData()
+
+        (dashboards, unusedDashboards)= getDashboards(user)
+        unusedDashboards=[x for x in unusedDashboards if x!="Customize"]
+        context['dashboards'] = dashboards
+        context['unusedDashboards'] = unusedDashboards
+
+        return context
+
+def getDashboards(user):
+    dashboards = user.get_dashboards()
+
+    dashboard_names = [d.name for d in dashboards]
+
+    unused_dashboard_names = []
+    for dashboardView in DashboardView.objects.all():
+        # do not show disabled dashboard views
+        if not dashboardView.enabled:
+            continue
+        if not dashboardView.name in dashboard_names:
+            unused_dashboard_names.append(dashboardView.name)
+
+    return (dashboard_names, unused_dashboard_names)
+
+def getSliceInfo(user):
+    sliceList = Slice.objects.all()
+    slicePrivs = SlicePrivilege.objects.filter(user=user)
+    userSliceInfo = []
+    for entry in slicePrivs:
+
+        slice = Slice.objects.filter(id=entry.slice.id)
+        if not slice:
+            # the privilege is to a slice that doesn't exist
+            print "data model consistency problem, slice %s doesn't exist" % entry.slice.id
+            continue
+        slice = slice[0]
+        slicename = slice.name
+        instanceList=Instance.objects.all()
+        sites_used = {}
+        for instance in slice.instances.all():
+             #sites_used['deploymentSites'] = instance.node.deployment.name
+             # sites_used[instance.image.name] = instance.image.name
+             sites_used[instance.node.site_deployment.site] = 1 #instance.numberCores
+        sliceid = Slice.objects.get(id=entry.slice.id).id
+        try:
+            instanceList = Instance.objects.filter(slice=entry.slice.id)
+            siteList = {}
+            for x in instanceList:
+               if x.node.site_deployment.site not in siteList:
+                  siteList[x.node.site_deployment.site] = 1
+            instancecount = len(instanceList)
+            sitecount = len(siteList)
+        except:
+            traceback.print_exc()
+            instancecount = 0
+            sitecount = 0
+
+        userSliceInfo.append({'slicename': slicename, 'sliceid':sliceid,
+                              'sitesUsed':sites_used,
+                              'role': SliceRole.objects.get(id=entry.role.id).role,
+                              'instancecount': instancecount,
+                              'sitecount':sitecount})
+
+    return userSliceInfo
+
+def slice_increase_instances(user, user_ip, siteList, slice, image, count, noAct=False):
+    sitesChanged = {}
+
+    # let's compute how many instances are in use in each node of each site
+    for site in siteList:
+        site.nodeList = list(site.nodes.all())
+        for node in site.nodeList:
+            node.instanceCount = 0
+            for instance in node.instances.all():
+                 if instance.slice.id == slice.id:
+                     node.instanceCount = node.instanceCount + 1
+
+    # Allocate instances to nodes
+    # for now, assume we want to allocate all instances from the same site
+    nodes = siteList[0].nodeList
+    while (count>0):
+        # Sort the node list by number of instances per node, then pick the
+        # node with the least number of instances.
+        nodes = sorted(nodes, key=attrgetter("instanceCount"))
+        node = nodes[0]
+
+        print "adding instance at node", node.name, "of site", node.site.name
+
+        if not noAct:
+            instance = Instance(name=node.name,
+                        slice=slice,
+                        node=node,
+                        image = image,
+                        creator = User.objects.get(email=user),
+                        deploymentNetwork=node.deployment)
+            instance.save()
+
+        node.instanceCount = node.instanceCount + 1
+
+        count = count - 1
+
+        sitesChanged[node.site.name] = sitesChanged.get(node.site.name,0) + 1
+
+    return sitesChanged
+
+def slice_decrease_instances(user, siteList, slice, count, noAct=False):
+    sitesChanged = {}
+    if siteList:
+        siteNames = [site.name for site in siteList]
+    else:
+        siteNames = None
+
+    for instance in list(slice.instances.all()):
+        if count>0:
+            if(not siteNames) or (instance.node.site.name in siteNames):
+                instance.delete()
+                print "deleting instance",instance.name,"at node",instance.node.name
+                count=count-1
+                sitesChanged[instance.node.site.name] = sitesChanged.get(instance.node.site.name,0) - 1
+
+    return sitesChanged
+
+def haversine(site_lat, site_lon, lat, lon):
+    d=0
+    if lat and lon and site_lat and site_lon:
+        site_lat = float(site_lat)
+        site_lon = float(site_lon)
+        lat = float(lat)
+        lon = float(lon)
+        R = 6378.1
+        a = math.sin( math.radians((lat - site_lat)/2.0) )**2 + math.cos( math.radians(lat) )*math.cos( math.radians(site_lat) )*(math.sin( math.radians((lon - site_lon)/2.0 ) )**2)
+        c = 2 * math.atan2( math.sqrt(a), math.sqrt(1 - a) )
+        d = R * c
+
+    return d
+
+def userSliceTableFormatter(data):
+    formattedData = {
+                     'rows' : data
+                    }
+    return formattedData
diff --git a/xos/core/fixtures/__init__.py b/xos/core/fixtures/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xos/core/fixtures/__init__.py
diff --git a/xos/core/fixtures/core_initial_data.json b/xos/core/fixtures/core_initial_data.json
new file mode 100644
index 0000000..01ff999
--- /dev/null
+++ b/xos/core/fixtures/core_initial_data.json
@@ -0,0 +1,22 @@
+[
+{
+    "fields": {
+        "updated": "2015-02-17T22:06:39.361Z",
+        "membershipFee": 0,
+        "policed": null,
+        "membershipFeeMonths": 12,
+        "created": "2015-02-17T22:06:39.361Z",
+        "deleted": false,
+        "description": "Best Effort",
+        "upgradeFrom": [],
+        "commitment": 365,
+        "name": "Best Effort",
+        "backend_register": "{}",
+        "backend_status": "0 - Provisioning in progress",
+        "upgradeRequiresApproval": false,
+        "enacted": null
+    },
+    "model": "core.serviceclass",
+    "pk": 1
+}
+]
diff --git a/xos/core/fixtures/demo_data.json b/xos/core/fixtures/demo_data.json
new file mode 100644
index 0000000..1045378
--- /dev/null
+++ b/xos/core/fixtures/demo_data.json
@@ -0,0 +1,57634 @@
+[
+{
+    "pk": 3, 
+    "model": "core.service", 
+    "fields": {
+        "updated": "2013-11-26T12:45:24.212Z", 
+        "description": "Used to help accelerate delivery of content through the CDN.", 
+        "created": "2013-11-26T12:45:24.212Z", 
+        "deleted": true, 
+        "enabled": true, 
+        "name": "HPC Service", 
+        "versionNumber": "1.0", 
+        "published": true, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 4, 
+    "model": "core.service", 
+    "fields": {
+        "updated": "2013-11-26T12:45:59.003Z", 
+        "description": "Service to help load balance and direct traffic flow to content within the CDN", 
+        "created": "2013-11-26T12:45:59.003Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "name": "Request Router Service", 
+        "versionNumber": "1.0", 
+        "published": true, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 5, 
+    "model": "core.service", 
+    "fields": {
+        "updated": "2013-12-04T22:51:07.137Z", 
+        "description": "Syndicate Shared Filesystem.", 
+        "created": "2013-12-04T22:51:07.137Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "name": "Syndicate", 
+        "versionNumber": "", 
+        "published": true, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 8, 
+    "model": "core.service", 
+    "fields": {
+        "updated": "2013-12-13T21:48:58.304Z", 
+        "description": "A provisioning service for long-term experiments.", 
+        "created": "2013-12-13T21:48:58.304Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "name": "Raven", 
+        "versionNumber": "1.0", 
+        "published": true, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 11, 
+    "model": "core.service", 
+    "fields": {
+        "updated": "2014-05-20T18:56:51.847Z", 
+        "description": "Cassandra distributed database management system", 
+        "created": "2014-05-20T18:56:51.847Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "name": "Cassandra", 
+        "versionNumber": "2.0.7", 
+        "published": true, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 12, 
+    "model": "core.service", 
+    "fields": {
+        "updated": "2014-05-20T18:57:33.778Z", 
+        "description": "KairosDB Time Series Database Service", 
+        "created": "2014-05-20T18:57:33.778Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "name": "KairosDB", 
+        "versionNumber": "0.9.3", 
+        "published": true, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 13, 
+    "model": "core.service", 
+    "fields": {
+        "updated": "2014-05-20T18:58:53.563Z", 
+        "description": "Nagios Monitoring Service", 
+        "created": "2014-05-20T18:58:53.563Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "name": "Nagios", 
+        "versionNumber": "4.0.6", 
+        "published": true, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 14, 
+    "model": "core.service", 
+    "fields": {
+        "updated": "2014-08-27T22:33:02.231Z", 
+        "description": "", 
+        "created": "2014-08-27T22:33:02.231Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "name": "HPC Service", 
+        "versionNumber": "2.9", 
+        "published": true, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 8, 
+    "model": "core.site", 
+    "fields": {
+        "updated": "2013-12-17T18:00:47.910Z", 
+        "name": "Stanford", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "longitude": null, 
+        "site_url": "http://www.stanford.edu/", 
+        "login_base": "stanford", 
+        "location": "37.4294,-122.17200000000003", 
+        "latitude": null, 
+        "is_public": true, 
+        "backend_status": "Provisioning in progress", 
+        "abbreviated_name": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 9, 
+    "model": "core.site", 
+    "fields": {
+        "updated": "2013-12-17T18:00:38.431Z", 
+        "name": "Washington", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "longitude": null, 
+        "site_url": "https://www.washington.edu/", 
+        "login_base": "wash", 
+        "location": "47.6531,-122.31299999999999", 
+        "latitude": null, 
+        "is_public": true, 
+        "backend_status": "Provisioning in progress", 
+        "abbreviated_name": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 10, 
+    "model": "core.site", 
+    "fields": {
+        "updated": "2013-12-17T18:00:28.495Z", 
+        "name": "Princeton", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "longitude": null, 
+        "site_url": "http://princeton.edu/", 
+        "login_base": "princeton", 
+        "location": "40.3502,-74.6524", 
+        "latitude": null, 
+        "is_public": true, 
+        "backend_status": "Provisioning in progress", 
+        "abbreviated_name": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 11, 
+    "model": "core.site", 
+    "fields": {
+        "updated": "2013-12-17T18:00:18.964Z", 
+        "name": "GeorgiaTech", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "longitude": null, 
+        "site_url": "http://www.gatech.edu/", 
+        "login_base": "gt", 
+        "location": "33.7772,-84.39760000000001", 
+        "latitude": null, 
+        "is_public": true, 
+        "backend_status": "Provisioning in progress", 
+        "abbreviated_name": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 12, 
+    "model": "core.site", 
+    "fields": {
+        "updated": "2013-12-17T18:00:07.704Z", 
+        "name": "MaxPlanck", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "longitude": null, 
+        "site_url": "http://www.mpi-sws.mpg.de/", 
+        "login_base": "mpisws", 
+        "location": "49.14,6.588999999999942", 
+        "latitude": null, 
+        "is_public": true, 
+        "backend_status": "Provisioning in progress", 
+        "abbreviated_name": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 13, 
+    "model": "core.site", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "I2 Atlanta", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "longitude": null, 
+        "site_url": "http://www.internet2.edu", 
+        "login_base": "i2atlanta", 
+        "location": "33.0075,-84.0038", 
+        "latitude": null, 
+        "is_public": true, 
+        "backend_status": "Provisioning in progress", 
+        "abbreviated_name": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 14, 
+    "model": "core.site", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "I2 Chicago", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "longitude": null, 
+        "site_url": "http://www.internet2.edu", 
+        "login_base": "i2chic", 
+        "location": "41.0085,-87.0065", 
+        "latitude": null, 
+        "is_public": true, 
+        "backend_status": "Provisioning in progress", 
+        "abbreviated_name": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 15, 
+    "model": "core.site", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "I2 Houston", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "longitude": null, 
+        "site_url": "http://www.internet2.edu", 
+        "login_base": "i2hous", 
+        "location": "29.0077,-95.0037", 
+        "latitude": null, 
+        "is_public": true, 
+        "backend_status": "Provisioning in progress", 
+        "abbreviated_name": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 16, 
+    "model": "core.site", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "I2 Kansas City", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "longitude": null, 
+        "site_url": "http://www.internet2.edu", 
+        "login_base": "i2kans", 
+        "location": "39.0012,-94.0063", 
+        "latitude": null, 
+        "is_public": true, 
+        "backend_status": "Provisioning in progress", 
+        "abbreviated_name": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 17, 
+    "model": "core.site", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "I2 Los Angeles", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "longitude": null, 
+        "site_url": "http://www.internet2.edu", 
+        "login_base": "i2losa", 
+        "location": "33.2505,-117.503", 
+        "latitude": null, 
+        "is_public": true, 
+        "backend_status": "Provisioning in progress", 
+        "abbreviated_name": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 18, 
+    "model": "core.site", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "I2 New York", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "longitude": null, 
+        "site_url": "http://www.internet2.edu", 
+        "login_base": "i2newy", 
+        "location": "40.72,-73.99", 
+        "latitude": null, 
+        "is_public": true, 
+        "backend_status": "Provisioning in progress", 
+        "abbreviated_name": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 19, 
+    "model": "core.site", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "I2 Salt Lake City", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "longitude": null, 
+        "site_url": "http://www.internet2.edu", 
+        "login_base": "i2salt", 
+        "location": "40.7659,-111.844", 
+        "latitude": null, 
+        "is_public": true, 
+        "backend_status": "Provisioning in progress", 
+        "abbreviated_name": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 20, 
+    "model": "core.site", 
+    "fields": {
+        "updated": "2014-03-22T06:27:07.824Z", 
+        "name": "I2 Seattle", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "longitude": null, 
+        "site_url": "http://www.internet2.edu/", 
+        "login_base": "i2seat", 
+        "location": "47.6531,-122.31299999999999", 
+        "latitude": null, 
+        "is_public": true, 
+        "backend_status": "Provisioning in progress", 
+        "abbreviated_name": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 21, 
+    "model": "core.site", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "I2 Washington DC", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "longitude": null, 
+        "site_url": "http://www.internet2.edu", 
+        "login_base": "i2wash", 
+        "location": "38.009,-77.0003", 
+        "latitude": null, 
+        "is_public": true, 
+        "backend_status": "Provisioning in progress", 
+        "abbreviated_name": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 22, 
+    "model": "core.site", 
+    "fields": {
+        "updated": "2013-12-17T17:30:14.491Z", 
+        "name": "ON.Lab", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "longitude": null, 
+        "site_url": "http://www.onlab.us/", 
+        "login_base": "onlab", 
+        "location": "37.452955,-122.18176599999998", 
+        "latitude": null, 
+        "is_public": true, 
+        "backend_status": "Provisioning in progress", 
+        "abbreviated_name": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 23, 
+    "model": "core.site", 
+    "fields": {
+        "updated": "2013-12-17T18:21:43.870Z", 
+        "name": "I2 Singapore", 
+        "created": "2013-12-17T17:08:49.669Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "longitude": null, 
+        "site_url": "http://www.internet2.edu/", 
+        "login_base": "i2singapore", 
+        "location": "1.33544,103.88999999999999", 
+        "latitude": null, 
+        "is_public": true, 
+        "backend_status": "Provisioning in progress", 
+        "abbreviated_name": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 24, 
+    "model": "core.site", 
+    "fields": {
+        "updated": "2013-12-17T18:08:01.373Z", 
+        "name": "Arizona", 
+        "created": "2013-12-17T18:07:14.190Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "longitude": null, 
+        "site_url": "http://www.cs.arizona.edu/", 
+        "login_base": "arizona", 
+        "location": "32.2333,-110.94799999999998", 
+        "latitude": null, 
+        "is_public": true, 
+        "backend_status": "Provisioning in progress", 
+        "abbreviated_name": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 1, 
+    "model": "core.siterole", 
+    "fields": {
+        "updated": "2013-12-17T18:08:54.842Z", 
+        "created": "2013-12-17T18:08:54.842Z", 
+        "deleted": false, 
+        "role": "pi", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 2, 
+    "model": "core.siterole", 
+    "fields": {
+        "updated": "2014-04-22T11:34:09.655Z", 
+        "created": "2014-04-22T11:34:09.655Z", 
+        "deleted": false, 
+        "role": "admin", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3, 
+    "model": "core.siterole", 
+    "fields": {
+        "updated": "2014-04-22T11:34:27.403Z", 
+        "created": "2014-04-22T11:34:27.403Z", 
+        "deleted": false, 
+        "role": "tech", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 4, 
+    "model": "core.siterole", 
+    "fields": {
+        "updated": "2014-04-22T11:34:39.770Z", 
+        "created": "2014-04-22T11:34:39.770Z", 
+        "deleted": false, 
+        "role": "billing", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 5, 
+    "model": "core.deployment", 
+    "fields": {
+        "accessControl": "allow all", 
+        "updated": "2013-04-03T22:57:23.015Z", 
+        "admin_user": null, 
+        "name": "US-Stanford", 
+        "created": "2013-04-03T22:57:23.015Z", 
+        "deleted": false, 
+        "auth_url": null, 
+        "admin_password": null, 
+        "backend_status": "Provisioning in progress", 
+        "admin_tenant": null, 
+        "enacted": null
+    }
+},
+{
+    "pk": 6, 
+    "model": "core.deployment", 
+    "fields": {
+        "accessControl": "allow all", 
+        "updated": "2013-04-03T22:57:23.015Z", 
+        "admin_user": null, 
+        "name": "US-Washington", 
+        "created": "2013-04-03T22:57:23.015Z", 
+        "deleted": false, 
+        "auth_url": null, 
+        "admin_password": null, 
+        "backend_status": "Provisioning in progress", 
+        "admin_tenant": null, 
+        "enacted": null
+    }
+},
+{
+    "pk": 7, 
+    "model": "core.deployment", 
+    "fields": {
+        "accessControl": "allow all", 
+        "updated": "2013-04-03T22:57:23.015Z", 
+        "admin_user": null, 
+        "name": "US-Princeton", 
+        "created": "2013-04-03T22:57:23.015Z", 
+        "deleted": false, 
+        "auth_url": null, 
+        "admin_password": null, 
+        "backend_status": "Provisioning in progress", 
+        "admin_tenant": null, 
+        "enacted": null
+    }
+},
+{
+    "pk": 8, 
+    "model": "core.deployment", 
+    "fields": {
+        "accessControl": "allow all", 
+        "updated": "2013-04-03T22:57:23.015Z", 
+        "admin_user": null, 
+        "name": "US-GeorgiaTech", 
+        "created": "2013-04-03T22:57:23.015Z", 
+        "deleted": false, 
+        "auth_url": null, 
+        "admin_password": null, 
+        "backend_status": "Provisioning in progress", 
+        "admin_tenant": null, 
+        "enacted": null
+    }
+},
+{
+    "pk": 9, 
+    "model": "core.deployment", 
+    "fields": {
+        "accessControl": "allow all", 
+        "updated": "2013-04-03T22:57:23.015Z", 
+        "admin_user": null, 
+        "name": "EU-MaxPlanck", 
+        "created": "2013-04-03T22:57:23.015Z", 
+        "deleted": false, 
+        "auth_url": null, 
+        "admin_password": null, 
+        "backend_status": "Provisioning in progress", 
+        "admin_tenant": null, 
+        "enacted": null
+    }
+},
+{
+    "pk": 10, 
+    "model": "core.deployment", 
+    "fields": {
+        "accessControl": "allow all", 
+        "updated": "2013-04-03T22:57:23.015Z", 
+        "admin_user": null, 
+        "name": "Internet2", 
+        "created": "2013-04-03T22:57:23.015Z", 
+        "deleted": false, 
+        "auth_url": null, 
+        "admin_password": null, 
+        "backend_status": "Provisioning in progress", 
+        "admin_tenant": null, 
+        "enacted": null
+    }
+},
+{
+    "pk": 11, 
+    "model": "core.deployment", 
+    "fields": {
+        "accessControl": "allow all", 
+        "updated": "2014-05-22T22:49:27.623Z", 
+        "admin_user": null, 
+        "name": "Amazon EC2", 
+        "created": "2014-05-22T22:49:27.623Z", 
+        "deleted": false, 
+        "auth_url": null, 
+        "admin_password": null, 
+        "backend_status": "Provisioning in progress", 
+        "admin_tenant": null, 
+        "enacted": null
+    }
+},
+{
+    "pk": 1, 
+    "model": "core.sitedeployment", 
+    "fields": {
+        "updated": "2014-05-07T23:52:01.453Z", 
+        "created": "2014-05-07T23:52:01.453Z", 
+        "deleted": false, 
+        "tenant_id": null, 
+        "site": 22, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 2, 
+    "model": "core.sitedeployment", 
+    "fields": {
+        "updated": "2014-05-07T23:52:01.455Z", 
+        "created": "2014-05-07T23:52:01.455Z", 
+        "deleted": false, 
+        "tenant_id": null, 
+        "site": 22, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3, 
+    "model": "core.sitedeployment", 
+    "fields": {
+        "updated": "2014-05-07T23:52:01.456Z", 
+        "created": "2014-05-07T23:52:01.456Z", 
+        "deleted": false, 
+        "tenant_id": null, 
+        "site": 22, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 4, 
+    "model": "core.sitedeployment", 
+    "fields": {
+        "updated": "2014-05-07T23:52:01.457Z", 
+        "created": "2014-05-07T23:52:01.456Z", 
+        "deleted": false, 
+        "tenant_id": null, 
+        "site": 22, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 5, 
+    "model": "core.sitedeployment", 
+    "fields": {
+        "updated": "2014-05-07T23:52:01.457Z", 
+        "created": "2014-05-07T23:52:01.457Z", 
+        "deleted": false, 
+        "tenant_id": null, 
+        "site": 22, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 6, 
+    "model": "core.sitedeployment", 
+    "fields": {
+        "updated": "2014-05-07T23:52:01.458Z", 
+        "created": "2014-05-07T23:52:01.458Z", 
+        "deleted": false, 
+        "tenant_id": null, 
+        "site": 22, 
+        "deployment": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 7, 
+    "model": "core.sitedeployment", 
+    "fields": {
+        "updated": "2014-05-08T00:00:37.305Z", 
+        "created": "2014-05-08T00:00:37.305Z", 
+        "deleted": false, 
+        "tenant_id": null, 
+        "site": 23, 
+        "deployment": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 8, 
+    "model": "core.sitedeployment", 
+    "fields": {
+        "updated": "2014-05-08T00:01:18.181Z", 
+        "created": "2014-05-08T00:01:18.181Z", 
+        "deleted": false, 
+        "tenant_id": null, 
+        "site": 21, 
+        "deployment": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 9, 
+    "model": "core.sitedeployment", 
+    "fields": {
+        "updated": "2014-05-08T00:01:29.768Z", 
+        "created": "2014-05-08T00:01:29.768Z", 
+        "deleted": false, 
+        "tenant_id": null, 
+        "site": 20, 
+        "deployment": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 10, 
+    "model": "core.sitedeployment", 
+    "fields": {
+        "updated": "2014-05-08T00:01:52.173Z", 
+        "created": "2014-05-08T00:01:52.173Z", 
+        "deleted": false, 
+        "tenant_id": null, 
+        "site": 19, 
+        "deployment": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 11, 
+    "model": "core.sitedeployment", 
+    "fields": {
+        "updated": "2014-05-08T00:02:03.435Z", 
+        "created": "2014-05-08T00:02:03.435Z", 
+        "deleted": false, 
+        "tenant_id": null, 
+        "site": 18, 
+        "deployment": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 12, 
+    "model": "core.sitedeployment", 
+    "fields": {
+        "updated": "2014-05-08T00:02:16.038Z", 
+        "created": "2014-05-08T00:02:16.038Z", 
+        "deleted": false, 
+        "tenant_id": null, 
+        "site": 17, 
+        "deployment": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 13, 
+    "model": "core.sitedeployment", 
+    "fields": {
+        "updated": "2014-05-08T00:02:33.626Z", 
+        "created": "2014-05-08T00:02:33.626Z", 
+        "deleted": false, 
+        "tenant_id": null, 
+        "site": 16, 
+        "deployment": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 14, 
+    "model": "core.sitedeployment", 
+    "fields": {
+        "updated": "2014-05-08T00:02:46.549Z", 
+        "created": "2014-05-08T00:02:46.549Z", 
+        "deleted": false, 
+        "tenant_id": null, 
+        "site": 15, 
+        "deployment": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 15, 
+    "model": "core.sitedeployment", 
+    "fields": {
+        "updated": "2014-05-08T00:03:01.445Z", 
+        "created": "2014-05-08T00:03:01.445Z", 
+        "deleted": false, 
+        "tenant_id": null, 
+        "site": 14, 
+        "deployment": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 16, 
+    "model": "core.sitedeployment", 
+    "fields": {
+        "updated": "2014-05-08T00:03:18.238Z", 
+        "created": "2014-05-08T00:03:18.238Z", 
+        "deleted": false, 
+        "tenant_id": null, 
+        "site": 13, 
+        "deployment": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 17, 
+    "model": "core.sitedeployment", 
+    "fields": {
+        "updated": "2014-05-08T00:03:32.156Z", 
+        "created": "2014-05-08T00:03:32.156Z", 
+        "deleted": false, 
+        "tenant_id": null, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 18, 
+    "model": "core.sitedeployment", 
+    "fields": {
+        "updated": "2014-05-08T00:03:45.449Z", 
+        "created": "2014-05-08T00:03:45.448Z", 
+        "deleted": false, 
+        "tenant_id": null, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 19, 
+    "model": "core.sitedeployment", 
+    "fields": {
+        "updated": "2014-05-08T00:03:59.510Z", 
+        "created": "2014-05-08T00:03:59.510Z", 
+        "deleted": false, 
+        "tenant_id": null, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 20, 
+    "model": "core.sitedeployment", 
+    "fields": {
+        "updated": "2014-05-08T00:04:12.516Z", 
+        "created": "2014-05-08T00:04:12.516Z", 
+        "deleted": false, 
+        "tenant_id": null, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 21, 
+    "model": "core.sitedeployment", 
+    "fields": {
+        "updated": "2014-05-08T00:04:25.576Z", 
+        "created": "2014-05-08T00:04:25.576Z", 
+        "deleted": false, 
+        "tenant_id": null, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 1, 
+    "model": "core.dashboardview", 
+    "fields": {
+        "updated": "2014-08-28T22:16:18.642Z", 
+        "name": "Developer", 
+        "created": "2014-05-19T22:11:11.408Z", 
+        "deleted": false, 
+        "url": "template:xosDeveloper_datatables", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 2, 
+    "model": "core.dashboardview", 
+    "fields": {
+        "updated": "2014-05-19T22:11:32.782Z", 
+        "name": "CDN Operations", 
+        "created": "2014-05-19T22:11:32.781Z", 
+        "deleted": false, 
+        "url": "template:cdnoperations", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3, 
+    "model": "core.dashboardview", 
+    "fields": {
+        "updated": "2014-05-19T22:11:46.731Z", 
+        "name": "Tenant", 
+        "created": "2014-05-19T22:11:46.731Z", 
+        "deleted": false, 
+        "url": "template:tenant", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 4, 
+    "model": "core.dashboardview", 
+    "fields": {
+        "updated": "2014-05-19T22:11:59.956Z", 
+        "name": "Historical", 
+        "created": "2014-05-19T22:11:59.956Z", 
+        "deleted": false, 
+        "url": "template:hpc_historical", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 5, 
+    "model": "core.dashboardview", 
+    "fields": {
+        "updated": "2014-05-20T00:32:44.462Z", 
+        "name": "Customize", 
+        "created": "2014-05-20T00:32:44.462Z", 
+        "deleted": false, 
+        "url": "template:customize", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 6, 
+    "model": "core.dashboardview", 
+    "fields": {
+        "updated": "2014-05-20T00:33:32.454Z", 
+        "name": "Slice Interactions", 
+        "created": "2014-05-20T00:33:32.454Z", 
+        "deleted": false, 
+        "url": "template:slice_interactions", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 7, 
+    "model": "core.dashboardview", 
+    "fields": {
+        "updated": "2014-05-26T23:12:15.410Z", 
+        "name": "CDN Nodes", 
+        "created": "2014-05-20T00:33:52.101Z", 
+        "deleted": false, 
+        "url": "template:cdn_nodes", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 8, 
+    "model": "core.dashboardview", 
+    "fields": {
+        "updated": "2014-06-18T00:00:43.149Z", 
+        "name": "nagios", 
+        "created": "2014-06-18T00:00:43.149Z", 
+        "deleted": false, 
+        "url": "http://nagiosadmin:letmein@node52.princeton.vicci.org:8088/nagios/cgi-bin/status.cgi?host=all", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 9, 
+    "model": "core.dashboardview", 
+    "fields": {
+        "updated": "2014-06-19T01:34:07.897Z", 
+        "name": "shell", 
+        "created": "2014-06-19T01:34:07.897Z", 
+        "deleted": false, 
+        "url": "template:shell", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 1, 
+    "model": "core.user", 
+    "fields": {
+        "username": "padmin@vicci.org", 
+        "public_key": null, 
+        "updated": "2013-11-26T12:36:49.829Z", 
+        "backend_status": "Provisioning in progress", 
+        "is_readonly": false, 
+        "firstname": "OpenCloud", 
+        "user_url": null, 
+        "deleted": false, 
+        "lastname": "Admin", 
+        "created": "2013-11-26T12:36:49.816Z", 
+        "is_active": true, 
+        "site": null, 
+        "phone": null, 
+        "is_staff": true, 
+        "last_login": "2014-06-17T11:07:08.691Z", 
+        "timezone": "America/New_York", 
+        "is_admin": true, 
+        "password": "pbkdf2_sha256$10000$v5qKhIyhSQ2N$V8vh2mkqYdjQib6d2jBkpwV57eMBfhd/9eiXqaDLUWg=", 
+        "email": "padmin@vicci.org", 
+        "enacted": null
+    }
+},
+{
+    "pk": 2, 
+    "model": "core.user", 
+    "fields": {
+        "username": "tmack@cs.princeton.edu", 
+        "public_key": "", 
+        "updated": "2014-03-23T23:10:57.378Z", 
+        "backend_status": "Provisioning in progress", 
+        "is_readonly": false, 
+        "firstname": "Tony", 
+        "user_url": null, 
+        "deleted": false, 
+        "lastname": "Mack", 
+        "created": "2013-09-22T21:47:30.959Z", 
+        "is_active": true, 
+        "site": 10, 
+        "phone": "", 
+        "is_staff": true, 
+        "last_login": "2013-12-14T03:21:24.872Z", 
+        "timezone": "America/New_York", 
+        "is_admin": true, 
+        "password": "pbkdf2_sha256$10000$dLKRXWJlkuvm$Ycamy79oT1lN0Q5R3B3nvlr70n2X50mL86yraDwzuWk=", 
+        "email": "tmack@cs.princeton.edu", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3, 
+    "model": "core.user", 
+    "fields": {
+        "username": "mhw@cs.princeton.edu", 
+        "public_key": "", 
+        "updated": "2014-03-23T23:10:01.387Z", 
+        "backend_status": "Provisioning in progress", 
+        "is_readonly": false, 
+        "firstname": "Mike", 
+        "user_url": null, 
+        "deleted": false, 
+        "lastname": "Wawrzoniak", 
+        "created": "2013-09-22T21:47:30.959Z", 
+        "is_active": true, 
+        "site": 10, 
+        "phone": "", 
+        "is_staff": true, 
+        "last_login": "2013-12-04T20:46:15.904Z", 
+        "timezone": "America/New_York", 
+        "is_admin": true, 
+        "password": "pbkdf2_sha256$10000$dLKRXWJlkuvm$Ycamy79oT1lN0Q5R3B3nvlr70n2X50mL86yraDwzuWk=", 
+        "email": "mhw@cs.princeton.edu", 
+        "enacted": null
+    }
+},
+{
+    "pk": 4, 
+    "model": "core.user", 
+    "fields": {
+        "username": "acb@cs.princeton.edu", 
+        "public_key": "", 
+        "updated": "2014-03-23T23:09:34.844Z", 
+        "backend_status": "Provisioning in progress", 
+        "is_readonly": false, 
+        "firstname": "Andy", 
+        "user_url": null, 
+        "deleted": false, 
+        "lastname": "Bavier", 
+        "created": "2013-09-22T21:47:30.959Z", 
+        "is_active": true, 
+        "site": 10, 
+        "phone": "", 
+        "is_staff": true, 
+        "last_login": "2014-05-28T14:02:29.996Z", 
+        "timezone": "America/New_York", 
+        "is_admin": true, 
+        "password": "pbkdf2_sha256$10000$dLKRXWJlkuvm$Ycamy79oT1lN0Q5R3B3nvlr70n2X50mL86yraDwzuWk=", 
+        "email": "acb@cs.princeton.edu", 
+        "enacted": null
+    }
+},
+{
+    "pk": 5, 
+    "model": "core.user", 
+    "fields": {
+        "username": "sapanb@cs.princeton.edu", 
+        "public_key": "", 
+        "updated": "2014-03-23T23:10:35.450Z", 
+        "backend_status": "Provisioning in progress", 
+        "is_readonly": false, 
+        "firstname": "Sapan", 
+        "user_url": null, 
+        "deleted": false, 
+        "lastname": "Bhatia", 
+        "created": "2013-09-22T21:47:30.959Z", 
+        "is_active": true, 
+        "site": 10, 
+        "phone": "", 
+        "is_staff": true, 
+        "last_login": "2014-05-28T01:03:05.136Z", 
+        "timezone": "America/New_York", 
+        "is_admin": true, 
+        "password": "pbkdf2_sha256$10000$dLKRXWJlkuvm$Ycamy79oT1lN0Q5R3B3nvlr70n2X50mL86yraDwzuWk=", 
+        "email": "sapanb@cs.princeton.edu", 
+        "enacted": null
+    }
+},
+{
+    "pk": 6, 
+    "model": "core.user", 
+    "fields": {
+        "username": "jcnelson@cs.princeton.edu", 
+        "public_key": "", 
+        "updated": "2013-12-16T15:44:27.429Z", 
+        "backend_status": "Provisioning in progress", 
+        "is_readonly": false, 
+        "firstname": "Jude", 
+        "user_url": null, 
+        "deleted": false, 
+        "lastname": "Nelson", 
+        "created": "2013-09-22T21:47:30.959Z", 
+        "is_active": true, 
+        "site": 10, 
+        "phone": "", 
+        "is_staff": true, 
+        "last_login": "2014-05-29T21:59:40.654Z", 
+        "timezone": "America/New_York", 
+        "is_admin": true, 
+        "password": "pbkdf2_sha256$10000$dLKRXWJlkuvm$Ycamy79oT1lN0Q5R3B3nvlr70n2X50mL86yraDwzuWk=", 
+        "email": "jcnelson@cs.princeton.edu", 
+        "enacted": null
+    }
+},
+{
+    "pk": 7, 
+    "model": "core.user", 
+    "fields": {
+        "username": "llp@onlab.us", 
+        "public_key": "xxx", 
+        "updated": "2014-05-27T01:55:57.760Z", 
+        "backend_status": "Provisioning in progress", 
+        "is_readonly": false, 
+        "firstname": "Larry", 
+        "user_url": null, 
+        "deleted": false, 
+        "lastname": "Peterson", 
+        "created": "2013-09-22T21:47:30.959Z", 
+        "is_active": true, 
+        "site": 22, 
+        "phone": "", 
+        "is_staff": true, 
+        "last_login": "2014-06-06T15:40:08.702Z", 
+        "timezone": "America/New_York", 
+        "is_admin": true, 
+        "password": "pbkdf2_sha256$10000$EOrqG6KzVO8z$4jSJMN/35PKPmJkDEHjAY1c/mDpBfoW1U8XAfk1eDLk=", 
+        "email": "llp@onlab.us", 
+        "enacted": null
+    }
+},
+{
+    "pk": 8, 
+    "model": "core.user", 
+    "fields": {
+        "username": "scott@onlab.us", 
+        "public_key": null, 
+        "updated": "2013-09-22T21:47:30.993Z", 
+        "backend_status": "Provisioning in progress", 
+        "is_readonly": false, 
+        "firstname": "Scott", 
+        "user_url": null, 
+        "deleted": false, 
+        "lastname": "Baker", 
+        "created": "2013-09-22T21:47:30.959Z", 
+        "is_active": true, 
+        "site": 22, 
+        "phone": null, 
+        "is_staff": true, 
+        "last_login": "2014-08-28T22:15:47.068Z", 
+        "timezone": "America/New_York", 
+        "is_admin": true, 
+        "password": "pbkdf2_sha256$12000$UBSotlGIN3iy$qqjsuWO+n//Fh/N5VIrnV6pnCNkxrTnRddCnSsAL3Dk=", 
+        "email": "scott@onlab.us", 
+        "enacted": null
+    }
+},
+{
+    "pk": 9, 
+    "model": "core.user", 
+    "fields": {
+        "username": "ali@onlab.us", 
+        "public_key": null, 
+        "updated": "2013-09-22T21:47:30.993Z", 
+        "backend_status": "Provisioning in progress", 
+        "is_readonly": false, 
+        "firstname": "Ali", 
+        "user_url": null, 
+        "deleted": false, 
+        "lastname": "Al-Shabibi", 
+        "created": "2013-09-22T21:47:30.959Z", 
+        "is_active": true, 
+        "site": 22, 
+        "phone": null, 
+        "is_staff": true, 
+        "last_login": "2013-09-22T21:48:01.047Z", 
+        "timezone": "America/New_York", 
+        "is_admin": true, 
+        "password": "pbkdf2_sha256$10000$dLKRXWJlkuvm$Ycamy79oT1lN0Q5R3B3nvlr70n2X50mL86yraDwzuWk=", 
+        "email": "ali@onlab.us", 
+        "enacted": null
+    }
+},
+{
+    "pk": 10, 
+    "model": "core.user", 
+    "fields": {
+        "username": "bill@onlab.us", 
+        "public_key": null, 
+        "updated": "2013-09-22T21:47:30.993Z", 
+        "backend_status": "Provisioning in progress", 
+        "is_readonly": false, 
+        "firstname": "Bill", 
+        "user_url": null, 
+        "deleted": false, 
+        "lastname": "Snow", 
+        "created": "2013-09-22T21:47:30.959Z", 
+        "is_active": true, 
+        "site": 22, 
+        "phone": null, 
+        "is_staff": true, 
+        "last_login": "2013-09-22T21:48:01.047Z", 
+        "timezone": "America/New_York", 
+        "is_admin": true, 
+        "password": "pbkdf2_sha256$10000$dLKRXWJlkuvm$Ycamy79oT1lN0Q5R3B3nvlr70n2X50mL86yraDwzuWk=", 
+        "email": "bill@onlab.us", 
+        "enacted": null
+    }
+},
+{
+    "pk": 11, 
+    "model": "core.user", 
+    "fields": {
+        "username": "guru@onlab.us", 
+        "public_key": null, 
+        "updated": "2013-09-22T21:47:30.993Z", 
+        "backend_status": "Provisioning in progress", 
+        "is_readonly": false, 
+        "firstname": "Guru", 
+        "user_url": null, 
+        "deleted": false, 
+        "lastname": "Parulkar", 
+        "created": "2013-09-22T21:47:30.959Z", 
+        "is_active": true, 
+        "site": 22, 
+        "phone": null, 
+        "is_staff": true, 
+        "last_login": "2013-09-22T21:48:01.047Z", 
+        "timezone": "America/New_York", 
+        "is_admin": true, 
+        "password": "pbkdf2_sha256$10000$dLKRXWJlkuvm$Ycamy79oT1lN0Q5R3B3nvlr70n2X50mL86yraDwzuWk=", 
+        "email": "guru@onlab.us", 
+        "enacted": null
+    }
+},
+{
+    "pk": 12, 
+    "model": "core.user", 
+    "fields": {
+        "username": "marc@onlab.us", 
+        "public_key": null, 
+        "updated": "2013-09-22T21:47:30.993Z", 
+        "backend_status": "Provisioning in progress", 
+        "is_readonly": false, 
+        "firstname": "Marc", 
+        "user_url": null, 
+        "deleted": false, 
+        "lastname": "Fiuczynski", 
+        "created": "2013-09-22T21:47:30.959Z", 
+        "is_active": true, 
+        "site": 22, 
+        "phone": null, 
+        "is_staff": true, 
+        "last_login": "2013-09-22T21:48:01.047Z", 
+        "timezone": "America/New_York", 
+        "is_admin": true, 
+        "password": "pbkdf2_sha256$10000$dLKRXWJlkuvm$Ycamy79oT1lN0Q5R3B3nvlr70n2X50mL86yraDwzuWk=", 
+        "email": "marc@onlab.us", 
+        "enacted": null
+    }
+},
+{
+    "pk": 13, 
+    "model": "core.user", 
+    "fields": {
+        "username": "siobhan@onlab.us", 
+        "public_key": null, 
+        "updated": "2013-09-22T21:47:30.993Z", 
+        "backend_status": "Provisioning in progress", 
+        "is_readonly": false, 
+        "firstname": "Siobhan", 
+        "user_url": null, 
+        "deleted": false, 
+        "lastname": "Tully", 
+        "created": "2013-09-22T21:47:30.959Z", 
+        "is_active": true, 
+        "site": 22, 
+        "phone": null, 
+        "is_staff": true, 
+        "last_login": "2013-09-22T21:48:01.047Z", 
+        "timezone": "America/New_York", 
+        "is_admin": true, 
+        "password": "pbkdf2_sha256$10000$dLKRXWJlkuvm$Ycamy79oT1lN0Q5R3B3nvlr70n2X50mL86yraDwzuWk=", 
+        "email": "siobhan@onlab.us", 
+        "enacted": null
+    }
+},
+{
+    "pk": 14, 
+    "model": "core.user", 
+    "fields": {
+        "username": "demo@onlab.us", 
+        "public_key": "", 
+        "updated": "2014-05-29T22:27:54.841Z", 
+        "backend_status": "Provisioning in progress", 
+        "is_readonly": true, 
+        "firstname": "Demo", 
+        "user_url": null, 
+        "deleted": false, 
+        "lastname": "OpenCloud", 
+        "created": "2013-12-06T11:25:41.211Z", 
+        "is_active": true, 
+        "site": 22, 
+        "phone": "", 
+        "is_staff": true, 
+        "last_login": "2014-06-18T08:35:13.300Z", 
+        "timezone": "America/New_York", 
+        "is_admin": true, 
+        "password": "pbkdf2_sha256$10000$jaLSTW2ksHEN$HDpjDKieFDjMvtV5wbF/ow3zfq8EqcFtNXLfuo+150s=", 
+        "email": "demo@onlab.us", 
+        "enacted": null
+    }
+},
+{
+    "pk": 15, 
+    "model": "core.user", 
+    "fields": {
+        "username": "jhh@cs.arizona.edu", 
+        "public_key": "", 
+        "updated": "2013-12-17T18:08:58.288Z", 
+        "backend_status": "Provisioning in progress", 
+        "is_readonly": false, 
+        "firstname": "John", 
+        "user_url": null, 
+        "deleted": false, 
+        "lastname": "Hartman", 
+        "created": "2013-12-17T18:08:01.381Z", 
+        "is_active": true, 
+        "site": 24, 
+        "phone": "", 
+        "is_staff": true, 
+        "last_login": "2013-12-17T18:08:01.356Z", 
+        "timezone": "America/New_York", 
+        "is_admin": true, 
+        "password": "!", 
+        "email": "jhh@cs.arizona.edu", 
+        "enacted": null
+    }
+},
+{
+    "pk": 16, 
+    "model": "core.user", 
+    "fields": {
+        "username": "parichar@akamai.com", 
+        "public_key": "", 
+        "updated": "2014-05-27T15:18:09.991Z", 
+        "backend_status": "Provisioning in progress", 
+        "is_readonly": false, 
+        "firstname": "Patrick", 
+        "user_url": null, 
+        "deleted": false, 
+        "lastname": "Richardson", 
+        "created": "2014-05-27T15:17:26.928Z", 
+        "is_active": true, 
+        "site": 22, 
+        "phone": "", 
+        "is_staff": true, 
+        "last_login": "2014-05-27T15:25:28.998Z", 
+        "timezone": "America/New_York", 
+        "is_admin": true, 
+        "password": "pbkdf2_sha256$10000$mEYJIb6cxVqC$cA/LHCpZdYPGvnSs9wCHrgyyenBrK8Y/diHBKhFOnO0=", 
+        "email": "parichar@akamai.com", 
+        "enacted": null
+    }
+},
+{
+    "pk": 1, 
+    "model": "core.userdashboardview", 
+    "fields": {
+        "updated": "2014-05-29T22:27:54.890Z", 
+        "created": "2014-05-23T22:03:14.097Z", 
+        "deleted": false, 
+        "dashboardView": 1, 
+        "user": 14, 
+        "backend_status": "Provisioning in progress", 
+        "order": 1, 
+        "enacted": null
+    }
+},
+{
+    "pk": 2, 
+    "model": "core.userdashboardview", 
+    "fields": {
+        "updated": "2014-05-29T22:27:54.910Z", 
+        "created": "2014-05-23T22:03:14.102Z", 
+        "deleted": false, 
+        "dashboardView": 2, 
+        "user": 14, 
+        "backend_status": "Provisioning in progress", 
+        "order": 2, 
+        "enacted": null
+    }
+},
+{
+    "pk": 3, 
+    "model": "core.userdashboardview", 
+    "fields": {
+        "updated": "2014-05-29T22:27:54.919Z", 
+        "created": "2014-05-23T22:03:14.106Z", 
+        "deleted": false, 
+        "dashboardView": 4, 
+        "user": 14, 
+        "backend_status": "Provisioning in progress", 
+        "order": 3, 
+        "enacted": null
+    }
+},
+{
+    "pk": 4, 
+    "model": "core.userdashboardview", 
+    "fields": {
+        "updated": "2014-05-29T22:27:54.927Z", 
+        "created": "2014-05-23T22:03:14.110Z", 
+        "deleted": false, 
+        "dashboardView": 6, 
+        "user": 14, 
+        "backend_status": "Provisioning in progress", 
+        "order": 4, 
+        "enacted": null
+    }
+},
+{
+    "pk": 5, 
+    "model": "core.userdashboardview", 
+    "fields": {
+        "updated": "2014-05-29T22:27:54.936Z", 
+        "created": "2014-05-23T22:03:14.115Z", 
+        "deleted": false, 
+        "dashboardView": 3, 
+        "user": 14, 
+        "backend_status": "Provisioning in progress", 
+        "order": 0, 
+        "enacted": null
+    }
+},
+{
+    "pk": 24, 
+    "model": "core.userdashboardview", 
+    "fields": {
+        "updated": "2014-05-27T15:31:48.271Z", 
+        "created": "2014-05-27T15:31:48.271Z", 
+        "deleted": false, 
+        "dashboardView": 3, 
+        "user": 16, 
+        "backend_status": "Provisioning in progress", 
+        "order": 0, 
+        "enacted": null
+    }
+},
+{
+    "pk": 25, 
+    "model": "core.userdashboardview", 
+    "fields": {
+        "updated": "2014-05-27T15:31:48.316Z", 
+        "created": "2014-05-27T15:31:48.316Z", 
+        "deleted": false, 
+        "dashboardView": 2, 
+        "user": 16, 
+        "backend_status": "Provisioning in progress", 
+        "order": 1, 
+        "enacted": null
+    }
+},
+{
+    "pk": 26, 
+    "model": "core.userdashboardview", 
+    "fields": {
+        "updated": "2014-05-27T15:31:48.366Z", 
+        "created": "2014-05-27T15:31:48.366Z", 
+        "deleted": false, 
+        "dashboardView": 7, 
+        "user": 16, 
+        "backend_status": "Provisioning in progress", 
+        "order": 2, 
+        "enacted": null
+    }
+},
+{
+    "pk": 36, 
+    "model": "core.userdashboardview", 
+    "fields": {
+        "updated": "2014-05-31T00:22:19.941Z", 
+        "created": "2014-05-31T00:22:19.941Z", 
+        "deleted": false, 
+        "dashboardView": 3, 
+        "user": 7, 
+        "backend_status": "Provisioning in progress", 
+        "order": 0, 
+        "enacted": null
+    }
+},
+{
+    "pk": 37, 
+    "model": "core.userdashboardview", 
+    "fields": {
+        "updated": "2014-05-31T00:22:19.987Z", 
+        "created": "2014-05-31T00:22:19.987Z", 
+        "deleted": false, 
+        "dashboardView": 1, 
+        "user": 7, 
+        "backend_status": "Provisioning in progress", 
+        "order": 1, 
+        "enacted": null
+    }
+},
+{
+    "pk": 38, 
+    "model": "core.userdashboardview", 
+    "fields": {
+        "updated": "2014-05-31T00:22:20.028Z", 
+        "created": "2014-05-31T00:22:20.028Z", 
+        "deleted": false, 
+        "dashboardView": 2, 
+        "user": 7, 
+        "backend_status": "Provisioning in progress", 
+        "order": 2, 
+        "enacted": null
+    }
+},
+{
+    "pk": 39, 
+    "model": "core.userdashboardview", 
+    "fields": {
+        "updated": "2014-05-31T00:22:20.069Z", 
+        "created": "2014-05-31T00:22:20.069Z", 
+        "deleted": false, 
+        "dashboardView": 7, 
+        "user": 7, 
+        "backend_status": "Provisioning in progress", 
+        "order": 3, 
+        "enacted": null
+    }
+},
+{
+    "pk": 40, 
+    "model": "core.userdashboardview", 
+    "fields": {
+        "updated": "2014-05-31T00:22:20.111Z", 
+        "created": "2014-05-31T00:22:20.111Z", 
+        "deleted": false, 
+        "dashboardView": 4, 
+        "user": 7, 
+        "backend_status": "Provisioning in progress", 
+        "order": 4, 
+        "enacted": null
+    }
+},
+{
+    "pk": 41, 
+    "model": "core.userdashboardview", 
+    "fields": {
+        "updated": "2014-06-17T11:07:32.639Z", 
+        "created": "2014-06-17T11:07:32.639Z", 
+        "deleted": false, 
+        "dashboardView": 3, 
+        "user": 1, 
+        "backend_status": "Provisioning in progress", 
+        "order": 0, 
+        "enacted": null
+    }
+},
+{
+    "pk": 42, 
+    "model": "core.userdashboardview", 
+    "fields": {
+        "updated": "2014-06-17T11:07:32.776Z", 
+        "created": "2014-06-17T11:07:32.776Z", 
+        "deleted": false, 
+        "dashboardView": 6, 
+        "user": 1, 
+        "backend_status": "Provisioning in progress", 
+        "order": 1, 
+        "enacted": null
+    }
+},
+{
+    "pk": 43, 
+    "model": "core.userdashboardview", 
+    "fields": {
+        "updated": "2014-06-19T23:54:01.961Z", 
+        "created": "2014-06-19T23:54:01.961Z", 
+        "deleted": false, 
+        "dashboardView": 3, 
+        "user": 8, 
+        "backend_status": "Provisioning in progress", 
+        "order": 0, 
+        "enacted": null
+    }
+},
+{
+    "pk": 44, 
+    "model": "core.userdashboardview", 
+    "fields": {
+        "updated": "2014-06-19T23:54:02.007Z", 
+        "created": "2014-06-19T23:54:02.006Z", 
+        "deleted": false, 
+        "dashboardView": 7, 
+        "user": 8, 
+        "backend_status": "Provisioning in progress", 
+        "order": 1, 
+        "enacted": null
+    }
+},
+{
+    "pk": 45, 
+    "model": "core.userdashboardview", 
+    "fields": {
+        "updated": "2014-06-19T23:54:02.056Z", 
+        "created": "2014-06-19T23:54:02.056Z", 
+        "deleted": false, 
+        "dashboardView": 6, 
+        "user": 8, 
+        "backend_status": "Provisioning in progress", 
+        "order": 2, 
+        "enacted": null
+    }
+},
+{
+    "pk": 46, 
+    "model": "core.userdashboardview", 
+    "fields": {
+        "updated": "2014-06-19T23:54:02.106Z", 
+        "created": "2014-06-19T23:54:02.106Z", 
+        "deleted": false, 
+        "dashboardView": 4, 
+        "user": 8, 
+        "backend_status": "Provisioning in progress", 
+        "order": 3, 
+        "enacted": null
+    }
+},
+{
+    "pk": 47, 
+    "model": "core.userdashboardview", 
+    "fields": {
+        "updated": "2014-06-19T23:54:02.156Z", 
+        "created": "2014-06-19T23:54:02.156Z", 
+        "deleted": false, 
+        "dashboardView": 1, 
+        "user": 8, 
+        "backend_status": "Provisioning in progress", 
+        "order": 4, 
+        "enacted": null
+    }
+},
+{
+    "pk": 48, 
+    "model": "core.userdashboardview", 
+    "fields": {
+        "updated": "2014-06-19T23:54:02.207Z", 
+        "created": "2014-06-19T23:54:02.207Z", 
+        "deleted": false, 
+        "dashboardView": 2, 
+        "user": 8, 
+        "backend_status": "Provisioning in progress", 
+        "order": 5, 
+        "enacted": null
+    }
+},
+{
+    "pk": 49, 
+    "model": "core.userdashboardview", 
+    "fields": {
+        "updated": "2014-06-19T23:54:02.248Z", 
+        "created": "2014-06-19T23:54:02.248Z", 
+        "deleted": false, 
+        "dashboardView": 8, 
+        "user": 8, 
+        "backend_status": "Provisioning in progress", 
+        "order": 6, 
+        "enacted": null
+    }
+},
+{
+    "pk": 50, 
+    "model": "core.userdashboardview", 
+    "fields": {
+        "updated": "2014-06-19T23:54:02.349Z", 
+        "created": "2014-06-19T23:54:02.349Z", 
+        "deleted": false, 
+        "dashboardView": 9, 
+        "user": 8, 
+        "backend_status": "Provisioning in progress", 
+        "order": 7, 
+        "enacted": null
+    }
+},
+{
+    "pk": 1, 
+    "model": "core.serviceclass", 
+    "fields": {
+        "updated": "2013-05-10T23:30:52.931Z", 
+        "membershipFee": 0, 
+        "name": "Best Effort", 
+        "membershipFeeMonths": 0, 
+        "created": "2013-05-10T23:30:52.931Z", 
+        "deleted": false, 
+        "description": "Best Effort", 
+        "upgradeFrom": [
+            2, 
+            3
+        ], 
+        "commitment": 0, 
+        "backend_status": "Provisioning in progress", 
+        "upgradeRequiresApproval": false, 
+        "enacted": null
+    }
+},
+{
+    "pk": 2, 
+    "model": "core.serviceclass", 
+    "fields": {
+        "updated": "2013-05-10T23:35:51.694Z", 
+        "membershipFee": 100, 
+        "name": "Silver", 
+        "membershipFeeMonths": 1, 
+        "created": "2013-05-10T23:33:24.930Z", 
+        "deleted": false, 
+        "description": "Silver", 
+        "upgradeFrom": [
+            1, 
+            3
+        ], 
+        "commitment": 365, 
+        "backend_status": "Provisioning in progress", 
+        "upgradeRequiresApproval": false, 
+        "enacted": null
+    }
+},
+{
+    "pk": 3, 
+    "model": "core.serviceclass", 
+    "fields": {
+        "updated": "2013-05-10T23:34:01.320Z", 
+        "membershipFee": 18000, 
+        "name": "Gold", 
+        "membershipFeeMonths": 12, 
+        "created": "2013-05-10T23:34:01.320Z", 
+        "deleted": false, 
+        "description": "Gold", 
+        "upgradeFrom": [
+            1, 
+            2
+        ], 
+        "commitment": 365, 
+        "backend_status": "Provisioning in progress", 
+        "upgradeRequiresApproval": false, 
+        "enacted": null
+    }
+},
+{
+    "pk": 4, 
+    "model": "core.slice", 
+    "fields": {
+        "updated": "2014-08-27T22:40:05.088Z", 
+        "image_preference": "Ubuntu 12.04 LTS", 
+        "name": "HyperCache", 
+        "service": 14, 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "slice_url": "", 
+        "description": "HyperCache slice for HyperCache service.", 
+        "serviceClass": 1, 
+        "enabled": true, 
+        "site": 22, 
+        "omf_friendly": false, 
+        "network": "Private Only", 
+        "max_instances": 10, 
+        "mount_data_sets": "GenBank", 
+        "backend_status": "Provisioning in progress", 
+        "creator": 1, 
+        "enacted": null
+    }
+},
+{
+    "pk": 6, 
+    "model": "core.slice", 
+    "fields": {
+        "updated": "2014-03-23T23:12:27.541Z", 
+        "image_preference": "Ubuntu 12.04 LTS", 
+        "name": "Syndicate", 
+        "service": 5, 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "slice_url": "", 
+        "description": "", 
+        "serviceClass": 1, 
+        "enabled": true, 
+        "site": 10, 
+        "omf_friendly": false, 
+        "network": "Private Only", 
+        "max_instances": 10, 
+        "mount_data_sets": "GenBank", 
+        "backend_status": "Provisioning in progress", 
+        "creator": 1, 
+        "enacted": null
+    }
+},
+{
+    "pk": 8, 
+    "model": "core.slice", 
+    "fields": {
+        "updated": "2014-03-23T23:17:33.686Z", 
+        "image_preference": "Ubuntu 12.04 LTS", 
+        "name": "DnsRedir", 
+        "service": 4, 
+        "created": "2013-12-04T22:48:35.584Z", 
+        "deleted": false, 
+        "slice_url": "", 
+        "description": "DNS Redirection slice for RequestRouter service.", 
+        "serviceClass": 2, 
+        "enabled": true, 
+        "site": 22, 
+        "omf_friendly": false, 
+        "network": "Private Only", 
+        "max_instances": 10, 
+        "mount_data_sets": "GenBank", 
+        "backend_status": "Provisioning in progress", 
+        "creator": 8, 
+        "enacted": null
+    }
+},
+{
+    "pk": 9, 
+    "model": "core.slice", 
+    "fields": {
+        "updated": "2014-03-23T23:18:00.528Z", 
+        "image_preference": "Ubuntu 12.04 LTS", 
+        "name": "DnsDemux", 
+        "service": 4, 
+        "created": "2013-12-04T22:49:23.051Z", 
+        "deleted": false, 
+        "slice_url": "", 
+        "description": "DNS Demultiplexing slice for RequestRouter service. ", 
+        "serviceClass": 2, 
+        "enabled": true, 
+        "site": 22, 
+        "omf_friendly": false, 
+        "network": "Private Only", 
+        "max_instances": 10, 
+        "mount_data_sets": "GenBank", 
+        "backend_status": "Provisioning in progress", 
+        "creator": 8, 
+        "enacted": null
+    }
+},
+{
+    "pk": 10, 
+    "model": "core.slice", 
+    "fields": {
+        "updated": "2014-03-23T23:19:56.253Z", 
+        "image_preference": "Ubuntu 12.04 LTS", 
+        "name": "Infrastructure", 
+        "service": null, 
+        "created": "2013-12-09T14:13:15.392Z", 
+        "deleted": false, 
+        "slice_url": "", 
+        "description": "", 
+        "serviceClass": 1, 
+        "enabled": true, 
+        "site": 22, 
+        "omf_friendly": false, 
+        "network": "Private Only", 
+        "max_instances": 10, 
+        "mount_data_sets": "GenBank", 
+        "backend_status": "Provisioning in progress", 
+        "creator": 1, 
+        "enacted": null
+    }
+},
+{
+    "pk": 11, 
+    "model": "core.slice", 
+    "fields": {
+        "updated": "2014-03-23T23:15:29.953Z", 
+        "image_preference": "Ubuntu 12.04 LTS", 
+        "name": "Stork", 
+        "service": 8, 
+        "created": "2013-12-13T21:49:59.476Z", 
+        "deleted": false, 
+        "slice_url": "", 
+        "description": "The Stork Package Management Service", 
+        "serviceClass": 1, 
+        "enabled": true, 
+        "site": 24, 
+        "omf_friendly": false, 
+        "network": "Private Only", 
+        "max_instances": 10, 
+        "mount_data_sets": "GenBank", 
+        "backend_status": "Provisioning in progress", 
+        "creator": 1, 
+        "enacted": null
+    }
+},
+{
+    "pk": 12, 
+    "model": "core.slice", 
+    "fields": {
+        "updated": "2014-03-23T23:16:01.742Z", 
+        "image_preference": "Ubuntu 12.04 LTS", 
+        "name": "Owl", 
+        "service": 8, 
+        "created": "2013-12-13T21:52:15.590Z", 
+        "deleted": false, 
+        "slice_url": "", 
+        "description": "The Owl Data Collection service", 
+        "serviceClass": 1, 
+        "enabled": true, 
+        "site": 24, 
+        "omf_friendly": false, 
+        "network": "Private Only", 
+        "max_instances": 10, 
+        "mount_data_sets": "GenBank", 
+        "backend_status": "Provisioning in progress", 
+        "creator": 1, 
+        "enacted": null
+    }
+},
+{
+    "pk": 13, 
+    "model": "core.slice", 
+    "fields": {
+        "updated": "2014-03-23T23:15:02.712Z", 
+        "image_preference": "Ubuntu 12.04 LTS", 
+        "name": "Hadoop", 
+        "service": null, 
+        "created": "2013-12-13T21:54:20.895Z", 
+        "deleted": false, 
+        "slice_url": "", 
+        "description": "Hadoop map-reduce service", 
+        "serviceClass": 2, 
+        "enabled": true, 
+        "site": 22, 
+        "omf_friendly": false, 
+        "network": "Private Only", 
+        "max_instances": 10, 
+        "mount_data_sets": "GenBank", 
+        "backend_status": "Provisioning in progress", 
+        "creator": 1, 
+        "enacted": null
+    }
+},
+{
+    "pk": 14, 
+    "model": "core.slice", 
+    "fields": {
+        "updated": "2014-03-23T23:14:27.648Z", 
+        "image_preference": "Ubuntu 12.04 LTS", 
+        "name": "test", 
+        "service": null, 
+        "created": "2013-12-13T21:56:57.299Z", 
+        "deleted": false, 
+        "slice_url": "", 
+        "description": "Test slice number one.", 
+        "serviceClass": 1, 
+        "enabled": true, 
+        "site": 10, 
+        "omf_friendly": false, 
+        "network": "Private Only", 
+        "max_instances": 10, 
+        "mount_data_sets": "GenBank", 
+        "backend_status": "Provisioning in progress", 
+        "creator": 1, 
+        "enacted": null
+    }
+},
+{
+    "pk": 15, 
+    "model": "core.slice", 
+    "fields": {
+        "updated": "2014-03-23T23:14:00.911Z", 
+        "image_preference": "Ubuntu 12.04 LTS", 
+        "name": "test2", 
+        "service": null, 
+        "created": "2013-12-13T22:00:03.049Z", 
+        "deleted": false, 
+        "slice_url": "", 
+        "description": "test slice number two.", 
+        "serviceClass": 1, 
+        "enabled": true, 
+        "site": 10, 
+        "omf_friendly": false, 
+        "network": "Private Only", 
+        "max_instances": 10, 
+        "mount_data_sets": "GenBank", 
+        "backend_status": "Provisioning in progress", 
+        "creator": 1, 
+        "enacted": null
+    }
+},
+{
+    "pk": 16, 
+    "model": "core.slice", 
+    "fields": {
+        "updated": "2014-05-27T14:05:40.950Z", 
+        "image_preference": "Hadoop 2.4.0", 
+        "name": "Analytics", 
+        "service": null, 
+        "created": "2014-05-20T17:54:07.100Z", 
+        "deleted": false, 
+        "slice_url": "", 
+        "description": "Analytics ", 
+        "serviceClass": 1, 
+        "enabled": true, 
+        "site": 22, 
+        "omf_friendly": false, 
+        "network": "Private Only", 
+        "max_instances": 10, 
+        "mount_data_sets": "GenBank-11-2013", 
+        "backend_status": "Provisioning in progress", 
+        "creator": 8, 
+        "enacted": null
+    }
+},
+{
+    "pk": 1, 
+    "model": "core.slicerole", 
+    "fields": {
+        "updated": "2013-12-18T21:09:27.717Z", 
+        "created": "2013-12-18T21:09:27.717Z", 
+        "deleted": false, 
+        "role": "admin", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 2, 
+    "model": "core.slicerole", 
+    "fields": {
+        "updated": "2013-12-18T21:09:35.074Z", 
+        "created": "2013-12-18T21:09:35.074Z", 
+        "deleted": false, 
+        "role": "default", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 1, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:37.713Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:21:37.713Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 2, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 2, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:37.729Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:21:37.729Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 3, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:37.739Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:21:37.739Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 4, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 4, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:37.752Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:21:37.752Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 5, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:37.771Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:21:37.771Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 6, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:37.790Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:21:37.789Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 7, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:37.808Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:21:37.808Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 8, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:37.835Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:21:37.835Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 9, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:37.862Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:21:37.862Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 11, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 10, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:37.890Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:21:37.890Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 12, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 11, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:37.925Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:21:37.925Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 13, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 12, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:37.960Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:21:37.960Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 14, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 13, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:37.996Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:21:37.996Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 15, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 14, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:38.038Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:21:38.038Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 1, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 15, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:38.092Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:21:38.091Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 16, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:38.103Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:21:38.103Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 2, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 17, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:38.111Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:21:38.111Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 3, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 18, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:38.122Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:21:38.122Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 4, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 19, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:38.141Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:21:38.141Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 20, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:38.160Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:21:38.160Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 21, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:38.179Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:21:38.179Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 22, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:38.206Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:21:38.206Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 23, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:38.233Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:21:38.233Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 24, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:38.260Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:21:38.260Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 11, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 25, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:38.287Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:21:38.287Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 12, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 26, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:38.322Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:21:38.322Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 13, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 27, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:38.358Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:21:38.358Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 14, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 28, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:38.393Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:21:38.393Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 15, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 29, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:38.428Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:21:38.428Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 1, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 30, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:38.472Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:21:38.472Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 31, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:38.484Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:21:38.484Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 2, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 32, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:38.492Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:21:38.492Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 3, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 33, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:38.503Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:21:38.503Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 4, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 34, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:38.522Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:21:38.522Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 35, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:38.540Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:21:38.540Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 36, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:38.559Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:21:38.559Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 37, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:38.578Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:21:38.578Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 38, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:38.605Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:21:38.605Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 39, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:38.632Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:21:38.632Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 11, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 40, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:38.660Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:21:38.660Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 12, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 41, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:38.695Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:21:38.695Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 13, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 42, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:38.731Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:21:38.731Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 14, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 43, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:38.766Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:21:38.766Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 15, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 44, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:38.801Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:21:38.801Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 1, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 45, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:38.845Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:21:38.845Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 46, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:38.857Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:21:38.857Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 2, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 47, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:38.865Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:21:38.864Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 3, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 48, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:38.875Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:21:38.875Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 4, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 49, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:38.894Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:21:38.894Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 50, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:38.913Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:21:38.913Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 51, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:38.932Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:21:38.932Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 52, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:38.951Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:21:38.951Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 53, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:38.978Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:21:38.978Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 54, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:39.005Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:21:39.005Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 11, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 55, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:39.032Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:21:39.032Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 12, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 56, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:39.068Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:21:39.067Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 13, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 57, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:39.103Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:21:39.103Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 14, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 58, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:39.139Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:21:39.139Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 15, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:39.175Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:21:39.175Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 1, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:39.219Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:21:39.219Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:39.229Z", 
+        "slice": 10, 
+        "created": "2013-12-18T21:21:39.229Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 2, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 62, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:39.238Z", 
+        "slice": 10, 
+        "created": "2013-12-18T21:21:39.238Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 3, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 63, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:39.248Z", 
+        "slice": 10, 
+        "created": "2013-12-18T21:21:39.248Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 4, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 64, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:39.267Z", 
+        "slice": 10, 
+        "created": "2013-12-18T21:21:39.267Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 65, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:39.286Z", 
+        "slice": 10, 
+        "created": "2013-12-18T21:21:39.286Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 66, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:39.304Z", 
+        "slice": 10, 
+        "created": "2013-12-18T21:21:39.304Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 67, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:39.324Z", 
+        "slice": 10, 
+        "created": "2013-12-18T21:21:39.324Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 68, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:39.351Z", 
+        "slice": 10, 
+        "created": "2013-12-18T21:21:39.351Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 69, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:39.378Z", 
+        "slice": 10, 
+        "created": "2013-12-18T21:21:39.378Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 11, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 70, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:39.405Z", 
+        "slice": 10, 
+        "created": "2013-12-18T21:21:39.405Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 12, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 71, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:39.440Z", 
+        "slice": 10, 
+        "created": "2013-12-18T21:21:39.440Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 13, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 72, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:39.476Z", 
+        "slice": 10, 
+        "created": "2013-12-18T21:21:39.476Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 14, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 73, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:39.511Z", 
+        "slice": 10, 
+        "created": "2013-12-18T21:21:39.511Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 15, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 74, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:39.547Z", 
+        "slice": 10, 
+        "created": "2013-12-18T21:21:39.547Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 1, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 75, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:39.590Z", 
+        "slice": 10, 
+        "created": "2013-12-18T21:21:39.590Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 76, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:39.602Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:21:39.602Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 2, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 77, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:39.610Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:21:39.610Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 3, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 78, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:39.621Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:21:39.621Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 4, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 79, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:39.640Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:21:39.640Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 80, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:39.659Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:21:39.659Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 81, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:39.678Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:21:39.678Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 82, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:39.705Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:21:39.705Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 83, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:39.732Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:21:39.732Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 84, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:39.759Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:21:39.759Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 11, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 85, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:39.786Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:21:39.786Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 12, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 86, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:39.821Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:21:39.821Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 13, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 87, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:39.857Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:21:39.857Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 14, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 88, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:39.891Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:21:39.891Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 15, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 89, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:39.927Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:21:39.927Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 1, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 90, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:39.971Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:21:39.971Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 91, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:39.983Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:21:39.983Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 2, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 92, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:39.991Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:21:39.991Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 3, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 93, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:40.002Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:21:40.002Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 4, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 94, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:40.020Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:21:40.020Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 95, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:40.039Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:21:40.039Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 96, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:40.058Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:21:40.058Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 97, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:40.077Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:21:40.077Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 98, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:40.104Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:21:40.104Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 99, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:40.131Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:21:40.131Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 11, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 100, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:40.159Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:21:40.159Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 12, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 101, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:40.194Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:21:40.194Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 13, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 102, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:40.230Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:21:40.230Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 14, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 103, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:40.265Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:21:40.265Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 15, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 104, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:40.300Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:21:40.300Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 1, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 105, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:40.344Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:21:40.344Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 106, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:40.356Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:21:40.355Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 2, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 107, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:40.364Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:21:40.364Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 3, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 108, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:40.374Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:21:40.374Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 4, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 109, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:40.393Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:21:40.393Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 110, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:40.412Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:21:40.412Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 111, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:40.431Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:21:40.431Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 112, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:40.450Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:21:40.450Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 113, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:40.477Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:21:40.477Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 114, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:40.504Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:21:40.504Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 11, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 115, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:40.531Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:21:40.531Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 12, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 116, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:40.566Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:21:40.566Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 13, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 117, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:40.602Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:21:40.602Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 14, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 118, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:40.637Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:21:40.637Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 15, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 119, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:40.673Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:21:40.673Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 1, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 120, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:40.717Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:21:40.717Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 121, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:40.728Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:21:40.728Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 2, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 122, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:40.736Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:21:40.736Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 3, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 123, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:40.747Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:21:40.747Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 4, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 124, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:40.766Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:21:40.766Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 125, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:40.784Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:21:40.784Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 126, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:40.803Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:21:40.803Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 127, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:40.822Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:21:40.822Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 128, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:40.849Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:21:40.849Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 129, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:40.877Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:21:40.877Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 11, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 130, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:40.903Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:21:40.903Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 12, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 131, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:40.939Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:21:40.939Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 13, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 132, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:40.975Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:21:40.975Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 14, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 133, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:41.010Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:21:41.010Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 15, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 134, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:41.045Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:21:41.045Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 1, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 135, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:41.089Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:21:41.089Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 136, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:41.101Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:21:41.101Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 2, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 137, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:41.109Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:21:41.109Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 3, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 138, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:41.119Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:21:41.119Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 4, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 139, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:41.138Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:21:41.138Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 140, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:41.157Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:21:41.157Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 141, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:41.176Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:21:41.176Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 142, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:41.204Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:21:41.203Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 143, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:41.231Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:21:41.231Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 144, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:41.258Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:21:41.258Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 11, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 145, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:41.285Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:21:41.285Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 12, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 146, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:41.320Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:21:41.320Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 13, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 147, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:41.356Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:21:41.356Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 14, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 148, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:41.391Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:21:41.391Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 15, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 149, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:41.426Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:21:41.426Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 1, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 150, 
+    "model": "core.sliceprivilege", 
+    "fields": {
+        "updated": "2013-12-18T21:21:41.470Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:21:41.470Z", 
+        "deleted": false, 
+        "role": 1, 
+        "user": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 1, 
+    "model": "core.image", 
+    "fields": {
+        "updated": "2013-12-09T14:26:56.787Z", 
+        "name": "Fedora 16 LXC rev 1.3", 
+        "created": "2013-12-09T14:26:56.787Z", 
+        "deleted": false, 
+        "container_format": "bare", 
+        "disk_format": "raw", 
+        "path": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 2, 
+    "model": "core.image", 
+    "fields": {
+        "updated": "2014-04-23T04:10:59.634Z", 
+        "name": "Ubuntu 12.04 LTS", 
+        "created": "2014-04-23T04:10:59.634Z", 
+        "deleted": false, 
+        "container_format": "bare", 
+        "disk_format": "raw", 
+        "path": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3, 
+    "model": "core.image", 
+    "fields": {
+        "updated": "2014-04-23T04:11:24.968Z", 
+        "name": "Hadoop 2.4.0", 
+        "created": "2014-04-23T04:11:24.968Z", 
+        "deleted": false, 
+        "container_format": "bare", 
+        "disk_format": "raw", 
+        "path": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 4, 
+    "model": "core.image", 
+    "fields": {
+        "updated": "2014-04-23T04:11:37.141Z", 
+        "name": "MPI 1.8", 
+        "created": "2014-04-23T04:11:37.141Z", 
+        "deleted": false, 
+        "container_format": "bare", 
+        "disk_format": "raw", 
+        "path": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 384, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node1.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 385, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node2.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 386, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node3.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 387, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node4.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 388, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node5.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 389, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node6.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 390, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node7.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 391, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node8.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 392, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node9.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 393, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node10.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 394, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node11.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 395, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node12.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 396, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node13.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 397, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node14.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 398, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node15.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 399, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node16.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 400, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node17.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 401, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node18.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 402, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node19.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 403, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node20.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 404, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node21.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 405, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node22.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 406, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node23.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 407, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node24.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 408, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node25.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 409, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node26.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 410, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node27.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 411, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node28.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 412, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node29.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 413, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node30.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 414, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node31.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 415, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node32.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 416, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node33.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 417, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node34.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 418, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node35.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 419, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node36.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 420, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node37.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 421, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node38.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 422, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node39.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 423, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node40.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 424, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node41.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 425, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node42.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 426, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node43.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 427, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node44.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 428, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node45.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 429, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node46.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 430, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node47.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 431, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node48.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 432, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node49.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 433, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node50.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 434, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node51.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 435, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node52.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 436, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node53.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 437, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node54.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 438, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node55.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 439, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node56.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 440, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node57.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 441, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node58.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 442, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node59.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 443, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node60.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 444, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node61.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 445, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node62.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 446, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node63.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 447, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node64.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 448, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node65.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 449, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node66.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 450, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node67.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 451, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node68.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 452, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node69.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 453, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node70.stanford.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 8, 
+        "deployment": 5, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 454, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node1.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 455, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node2.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 456, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node3.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 457, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node4.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 458, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node5.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 459, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node6.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 460, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node7.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 461, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node8.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 462, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node9.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 463, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node10.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 464, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node11.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 465, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node12.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 466, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node13.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 467, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node14.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 468, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node15.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 469, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node16.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 470, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node17.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 471, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node18.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 472, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node19.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 473, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node20.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 474, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node21.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 475, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node22.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 476, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node23.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 477, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node24.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 478, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node25.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 479, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node26.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 480, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node27.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 481, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node28.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 482, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node29.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 483, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node30.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 484, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node31.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 485, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node32.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 486, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node33.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 487, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node34.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 488, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node35.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 489, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node36.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 490, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node37.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 491, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node38.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 492, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node39.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 493, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node40.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 494, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node41.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 495, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node42.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 496, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node43.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 497, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node44.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 498, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node45.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 499, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node46.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 500, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node47.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 501, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node48.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 502, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node49.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 503, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node50.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 504, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node51.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 505, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node52.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 506, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node53.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 507, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node54.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 508, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node55.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 509, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node56.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 510, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node57.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 511, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node58.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 512, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node59.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 513, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node60.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 514, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node61.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 515, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node62.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 516, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node63.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 517, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node64.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 518, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node65.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 519, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node66.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 520, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node67.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 521, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node68.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 522, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node69.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 523, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node70.washington.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 9, 
+        "deployment": 6, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 524, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node1.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 525, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node2.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 526, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node3.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 527, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node4.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 528, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node5.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 529, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node6.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 530, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node7.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 531, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node8.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 532, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node9.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 533, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node10.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 534, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node11.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 535, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node12.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 536, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node13.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 537, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node14.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 538, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node15.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 539, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node16.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 540, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node17.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 541, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node18.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 542, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node19.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 543, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node20.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 544, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node21.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 545, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node22.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 546, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node23.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 547, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node24.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 548, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node25.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 549, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node26.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 550, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node27.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 551, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node28.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 552, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node29.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 553, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node30.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 554, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node31.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 555, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node32.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 556, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node33.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 557, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node34.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 558, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node35.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 559, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node36.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 560, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node37.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 561, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node38.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 562, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node39.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 563, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node40.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 564, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node41.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 565, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node42.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 566, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node43.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 567, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node44.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 568, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node45.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 569, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node46.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 570, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node47.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 571, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node48.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 572, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node49.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 573, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node50.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 574, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node51.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 575, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node52.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 576, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node53.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 577, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node54.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 578, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node55.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 579, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node56.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 580, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node57.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 581, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node58.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 582, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node59.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 583, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node60.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 584, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node61.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 585, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node62.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 586, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node63.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 587, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node64.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 588, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node65.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 589, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node66.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 590, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node67.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 591, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node68.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 592, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node69.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 593, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node70.princeton.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 10, 
+        "deployment": 7, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 594, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node1.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 595, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node2.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 596, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node3.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 597, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node4.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 598, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node5.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 599, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node6.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 600, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node7.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 601, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node8.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 602, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node9.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 603, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node10.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 604, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node11.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 605, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node12.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 606, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node13.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 607, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node14.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 608, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node15.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 609, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node16.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 610, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node17.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 611, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node18.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 612, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node19.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 613, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node20.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 614, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node21.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 615, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node22.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 616, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node23.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 617, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node24.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 618, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node25.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 619, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node26.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 620, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node27.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 621, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node28.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 622, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node29.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 623, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node30.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 624, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node31.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 625, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node32.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 626, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node33.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 627, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node34.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 628, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node35.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 629, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node36.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 630, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node37.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 631, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node38.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 632, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node39.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 633, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node40.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 634, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node41.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 635, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node42.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 636, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node43.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 637, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node44.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 638, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node45.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 639, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node46.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 640, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node47.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 641, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node48.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 642, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node49.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 643, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node50.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 644, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node51.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 645, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node52.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 646, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node53.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 647, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node54.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 648, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node55.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 649, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node56.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 650, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node57.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 651, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node58.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 652, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node59.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 653, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node60.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 654, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node61.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 655, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node62.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 656, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node63.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 657, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node64.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 658, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node65.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 659, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node66.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 660, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node67.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 661, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node68.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 662, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node69.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 663, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node70.gt.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 11, 
+        "deployment": 8, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 664, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node1.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 665, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node2.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 666, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node3.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 667, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node4.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 668, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node5.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 669, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node6.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 670, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node7.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 671, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node8.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 672, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node9.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 673, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node10.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 674, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node11.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 675, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node12.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 676, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node13.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 677, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node14.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 678, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node15.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 679, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node16.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 680, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node17.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 681, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node18.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 682, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node19.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 683, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node20.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 684, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node21.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 685, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node22.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 686, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node23.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 687, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node24.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 688, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node25.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 689, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node26.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 690, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node27.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 691, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node28.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 692, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node29.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 693, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node30.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 694, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node31.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 695, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node32.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 696, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node33.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 697, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node34.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 698, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node35.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 699, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node36.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 700, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node37.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 701, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node38.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 702, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node39.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 703, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node40.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 704, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node41.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 705, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node42.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 706, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node43.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 707, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node44.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 708, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node45.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 709, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node46.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 710, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node47.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 711, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node48.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 712, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node49.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 713, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node50.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 714, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node51.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 715, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node52.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 716, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node53.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 717, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node54.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 718, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node55.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 719, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node56.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 720, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node57.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 721, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node58.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 722, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node59.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 723, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node60.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 724, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node61.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 725, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node62.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 726, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node63.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 727, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node64.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 728, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node65.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 729, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node66.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 730, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node67.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 731, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node68.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 732, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node69.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 733, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node70.mpisws.vicci.org", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 12, 
+        "deployment": 9, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 734, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node1.atla.internet2.vini-veritas.net", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 13, 
+        "deployment": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 735, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node2.atla.internet2.vini-veritas.net", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 13, 
+        "deployment": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 736, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node1.chic.internet2.vini-veritas.net", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 14, 
+        "deployment": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 737, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node2.chic.internet2.vini-veritas.net", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 14, 
+        "deployment": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 738, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node1.hous.internet2.vini-veritas.net", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 15, 
+        "deployment": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 739, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node2.hous.internet2.vini-veritas.net", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 15, 
+        "deployment": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 740, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node1.kans.internet2.vini-veritas.net", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 16, 
+        "deployment": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 741, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node2.kans.internet2.vini-veritas.net", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 16, 
+        "deployment": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 742, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node1.losa.internet2.vini-veritas.net", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 17, 
+        "deployment": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 743, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node2.losa.internet2.vini-veritas.net", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 17, 
+        "deployment": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 744, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node1.newy.internet2.vini-veritas.net", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 18, 
+        "deployment": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 745, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node2.newy.internet2.vini-veritas.net", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 18, 
+        "deployment": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 746, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node1.salt.internet2.vini-veritas.net", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 19, 
+        "deployment": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 747, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node2.salt.internet2.vini-veritas.net", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 19, 
+        "deployment": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 748, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node1.seat.internet2.vini-veritas.net", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 20, 
+        "deployment": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 749, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node2.seat.internet2.vini-veritas.net", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 20, 
+        "deployment": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 750, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node1.wash.internet2.vini-veritas.net", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 21, 
+        "deployment": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 751, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-06-21T21:17:13.982Z", 
+        "name": "node2.wash.internet2.vini-veritas.net", 
+        "created": "2013-04-03T23:14:11.072Z", 
+        "deleted": false, 
+        "site": 21, 
+        "deployment": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 752, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-12-17T17:10:48.740Z", 
+        "name": "opencloud0.sing.internet2.edu", 
+        "created": "2013-12-17T17:10:48.740Z", 
+        "deleted": false, 
+        "site": 23, 
+        "deployment": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 753, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-12-17T17:10:48.742Z", 
+        "name": "opencloud1.sing.internet2.edu", 
+        "created": "2013-12-17T17:10:48.741Z", 
+        "deleted": false, 
+        "site": 23, 
+        "deployment": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 754, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-12-17T17:10:48.742Z", 
+        "name": "opencloud2.sing.internet2.edu", 
+        "created": "2013-12-17T17:10:48.742Z", 
+        "deleted": false, 
+        "site": 23, 
+        "deployment": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 755, 
+    "model": "core.node", 
+    "fields": {
+        "updated": "2013-12-17T17:10:48.743Z", 
+        "name": "opencloud3.sing.internet2.edu", 
+        "created": "2013-12-17T17:10:48.743Z", 
+        "deleted": false, 
+        "site": 23, 
+        "deployment": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 4, 
+    "model": "core.serviceresource", 
+    "fields": {
+        "updated": "2013-12-11T22:18:00.040Z", 
+        "bucketInRate": 0, 
+        "name": "Cycles", 
+        "bucketMaxSize": 0, 
+        "created": "2013-12-11T22:18:00.040Z", 
+        "deleted": false, 
+        "serviceClass": 1, 
+        "maxUnitsDeployment": 0, 
+        "calendarReservable": false, 
+        "maxDuration": 0, 
+        "cost": 7, 
+        "backend_status": "Provisioning in progress", 
+        "maxUnitsNode": 0, 
+        "enacted": null
+    }
+},
+{
+    "pk": 5, 
+    "model": "core.serviceresource", 
+    "fields": {
+        "updated": "2013-12-11T22:18:00.045Z", 
+        "bucketInRate": 0, 
+        "name": "Cycles", 
+        "bucketMaxSize": 0, 
+        "created": "2013-12-11T22:18:00.045Z", 
+        "deleted": false, 
+        "serviceClass": 2, 
+        "maxUnitsDeployment": 0, 
+        "calendarReservable": false, 
+        "maxDuration": 0, 
+        "cost": 7, 
+        "backend_status": "Provisioning in progress", 
+        "maxUnitsNode": 0, 
+        "enacted": null
+    }
+},
+{
+    "pk": 6, 
+    "model": "core.serviceresource", 
+    "fields": {
+        "updated": "2013-12-11T22:18:00.053Z", 
+        "bucketInRate": 0, 
+        "name": "Cycles", 
+        "bucketMaxSize": 0, 
+        "created": "2013-12-11T22:18:00.053Z", 
+        "deleted": false, 
+        "serviceClass": 3, 
+        "maxUnitsDeployment": 0, 
+        "calendarReservable": false, 
+        "maxDuration": 0, 
+        "cost": 7, 
+        "backend_status": "Provisioning in progress", 
+        "maxUnitsNode": 0, 
+        "enacted": null
+    }
+},
+{
+    "pk": 7, 
+    "model": "core.serviceresource", 
+    "fields": {
+        "updated": "2013-12-11T22:18:00.064Z", 
+        "bucketInRate": 0, 
+        "name": "numberCores", 
+        "bucketMaxSize": 0, 
+        "created": "2013-12-11T22:18:00.064Z", 
+        "deleted": false, 
+        "serviceClass": 3, 
+        "maxUnitsDeployment": 210, 
+        "calendarReservable": true, 
+        "maxDuration": 8760, 
+        "cost": 0, 
+        "backend_status": "Provisioning in progress", 
+        "maxUnitsNode": 6, 
+        "enacted": null
+    }
+},
+{
+    "pk": 8, 
+    "model": "core.serviceresource", 
+    "fields": {
+        "updated": "2013-12-11T22:18:00.072Z", 
+        "bucketInRate": 10, 
+        "name": "numberCores", 
+        "bucketMaxSize": 210, 
+        "created": "2013-12-11T22:18:00.072Z", 
+        "deleted": false, 
+        "serviceClass": 2, 
+        "maxUnitsDeployment": 210, 
+        "calendarReservable": true, 
+        "maxDuration": 168, 
+        "cost": 7, 
+        "backend_status": "Provisioning in progress", 
+        "maxUnitsNode": 6, 
+        "enacted": null
+    }
+},
+{
+    "pk": 1, 
+    "model": "core.flavor", 
+    "fields": {
+        "updated": "2014-09-02T20:38:23.122Z", 
+        "name": "m1.tiny", 
+        "created": "2014-09-02T20:38:23.122Z", 
+        "deleted": false, 
+        "description": "openstack tiny instance", 
+        "deployments": [
+            7, 
+            10, 
+            9, 
+            8, 
+            6, 
+            5
+        ], 
+        "default": false, 
+        "flavor": "m1.tiny", 
+        "backend_status": "Provisioning in progress", 
+        "order": 0, 
+        "enacted": null
+    }
+},
+{
+    "pk": 2, 
+    "model": "core.flavor", 
+    "fields": {
+        "updated": "2014-09-02T20:59:40.518Z", 
+        "name": "m1.small", 
+        "created": "2014-09-02T20:59:40.518Z", 
+        "deleted": false, 
+        "description": "small openstack instance", 
+        "deployments": [
+            7, 
+            10, 
+            9, 
+            8, 
+            6, 
+            5, 
+            11
+        ], 
+        "default": true, 
+        "flavor": "m1.small", 
+        "backend_status": "Provisioning in progress", 
+        "order": 1, 
+        "enacted": null
+    }
+},
+{
+    "pk": 3, 
+    "model": "core.flavor", 
+    "fields": {
+        "updated": "2014-09-02T21:00:28.795Z", 
+        "name": "m1.medium", 
+        "created": "2014-09-02T21:00:28.795Z", 
+        "deleted": false, 
+        "description": "medium openstack flavor", 
+        "deployments": [
+            7, 
+            10, 
+            9, 
+            8, 
+            6, 
+            5, 
+            11
+        ], 
+        "default": false, 
+        "flavor": "m1.medium", 
+        "backend_status": "Provisioning in progress", 
+        "order": 2, 
+        "enacted": null
+    }
+},
+{
+    "pk": 4, 
+    "model": "core.flavor", 
+    "fields": {
+        "updated": "2014-09-02T21:00:57.360Z", 
+        "name": "m1.large", 
+        "created": "2014-09-02T21:00:49.945Z", 
+        "deleted": false, 
+        "description": "large openstack flavor", 
+        "deployments": [
+            7, 
+            10, 
+            9, 
+            8, 
+            6, 
+            5, 
+            11
+        ], 
+        "default": false, 
+        "flavor": "m1.large", 
+        "backend_status": "Provisioning in progress", 
+        "order": 3, 
+        "enacted": null
+    }
+},
+{
+    "pk": 5, 
+    "model": "core.flavor", 
+    "fields": {
+        "updated": "2014-09-02T21:01:15.285Z", 
+        "name": "m1.xlarge", 
+        "created": "2014-09-02T21:01:15.285Z", 
+        "deleted": false, 
+        "description": "extra large openstack flavor", 
+        "deployments": [
+            7, 
+            10, 
+            9, 
+            8, 
+            6, 
+            5, 
+            11
+        ], 
+        "default": false, 
+        "flavor": "m1.xlarge", 
+        "backend_status": "Provisioning in progress", 
+        "order": 4, 
+        "enacted": null
+    }
+},
+{
+    "pk": 6, 
+    "model": "core.flavor", 
+    "fields": {
+        "updated": "2014-09-03T00:25:30.120Z", 
+        "name": "m3.medium", 
+        "created": "2014-09-03T00:25:30.120Z", 
+        "deleted": false, 
+        "description": "ec2 flavor m3.medium", 
+        "deployments": [
+            11
+        ], 
+        "default": false, 
+        "flavor": "m3.medium", 
+        "backend_status": "Provisioning in progress", 
+        "order": 33, 
+        "enacted": null
+    }
+},
+{
+    "pk": 7, 
+    "model": "core.flavor", 
+    "fields": {
+        "updated": "2014-09-03T00:25:50.419Z", 
+        "name": "m3.large", 
+        "created": "2014-09-03T00:25:50.419Z", 
+        "deleted": false, 
+        "description": "ec2 flavor m3.large", 
+        "deployments": [
+            11
+        ], 
+        "default": false, 
+        "flavor": "m3.large", 
+        "backend_status": "Provisioning in progress", 
+        "order": 34, 
+        "enacted": null
+    }
+},
+{
+    "pk": 8, 
+    "model": "core.flavor", 
+    "fields": {
+        "updated": "2014-09-03T00:26:11.770Z", 
+        "name": "m3.2xlarge", 
+        "created": "2014-09-03T00:26:11.770Z", 
+        "deleted": false, 
+        "description": "ec2 flavor m3.2xlarge", 
+        "deployments": [
+            11
+        ], 
+        "default": false, 
+        "flavor": "m3.2xlarge", 
+        "backend_status": "Provisioning in progress", 
+        "order": 35, 
+        "enacted": null
+    }
+},
+{
+    "pk": 40, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 613, 
+        "instance_name": "instance-000003e8", 
+        "updated": "2013-12-12T17:55:32.455Z", 
+        "slice": 4, 
+        "deploymentNetwork": 8, 
+        "name": "node20.gt.vicci.org", 
+        "created": "2013-12-12T17:55:32.455Z", 
+        "deleted": false, 
+        "ip": "130.207.98.29", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 41, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 615, 
+        "instance_name": "instance-000003e9", 
+        "updated": "2013-12-12T17:55:32.478Z", 
+        "slice": 4, 
+        "deploymentNetwork": 8, 
+        "name": "node22.gt.vicci.org", 
+        "created": "2013-12-12T17:55:32.478Z", 
+        "deleted": false, 
+        "ip": "130.207.98.31", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 42, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 617, 
+        "instance_name": "instance-000003ea", 
+        "updated": "2013-12-12T17:55:32.495Z", 
+        "slice": 4, 
+        "deploymentNetwork": 8, 
+        "name": "node24.gt.vicci.org", 
+        "created": "2013-12-12T17:55:32.495Z", 
+        "deleted": false, 
+        "ip": "130.207.98.33", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 43, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 622, 
+        "instance_name": "instance-000003eb", 
+        "updated": "2013-12-12T17:55:32.512Z", 
+        "slice": 4, 
+        "deploymentNetwork": 8, 
+        "name": "node29.gt.vicci.org", 
+        "created": "2013-12-12T17:55:32.511Z", 
+        "deleted": false, 
+        "ip": "130.207.98.38", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 44, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 623, 
+        "instance_name": "instance-000003ec", 
+        "updated": "2013-12-12T17:55:32.528Z", 
+        "slice": 4, 
+        "deploymentNetwork": 8, 
+        "name": "node30.gt.vicci.org", 
+        "created": "2013-12-12T17:55:32.528Z", 
+        "deleted": false, 
+        "ip": "130.207.98.39", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 46, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 625, 
+        "instance_name": "instance-000003ee", 
+        "updated": "2013-12-12T17:55:32.561Z", 
+        "slice": 4, 
+        "deploymentNetwork": 8, 
+        "name": "node32.gt.vicci.org", 
+        "created": "2013-12-12T17:55:32.561Z", 
+        "deleted": false, 
+        "ip": "130.207.98.41", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 47, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 630, 
+        "instance_name": "instance-000003ef", 
+        "updated": "2013-12-12T17:55:32.577Z", 
+        "slice": 4, 
+        "deploymentNetwork": 8, 
+        "name": "node37.gt.vicci.org", 
+        "created": "2013-12-12T17:55:32.577Z", 
+        "deleted": false, 
+        "ip": "130.207.98.46", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 48, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 666, 
+        "instance_name": "instance-000003f0", 
+        "updated": "2013-12-12T17:55:32.594Z", 
+        "slice": 4, 
+        "deploymentNetwork": 9, 
+        "name": "node3.mpisws.vicci.org", 
+        "created": "2013-12-12T17:55:32.594Z", 
+        "deleted": false, 
+        "ip": "141.39.220.13", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 49, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 683, 
+        "instance_name": "instance-000003f1", 
+        "updated": "2013-12-12T17:55:32.611Z", 
+        "slice": 4, 
+        "deploymentNetwork": 9, 
+        "name": "node20.mpisws.vicci.org", 
+        "created": "2013-12-12T17:55:32.610Z", 
+        "deleted": false, 
+        "ip": "141.39.220.30", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 50, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 684, 
+        "instance_name": "instance-000003f2", 
+        "updated": "2013-12-12T17:55:32.627Z", 
+        "slice": 4, 
+        "deploymentNetwork": 9, 
+        "name": "node21.mpisws.vicci.org", 
+        "created": "2013-12-12T17:55:32.627Z", 
+        "deleted": false, 
+        "ip": "141.39.220.31", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 51, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 686, 
+        "instance_name": "instance-000003f3", 
+        "updated": "2013-12-12T17:55:32.644Z", 
+        "slice": 4, 
+        "deploymentNetwork": 9, 
+        "name": "node23.mpisws.vicci.org", 
+        "created": "2013-12-12T17:55:32.644Z", 
+        "deleted": false, 
+        "ip": "141.39.220.33", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 52, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 687, 
+        "instance_name": "instance-000003f4", 
+        "updated": "2013-12-12T17:55:32.660Z", 
+        "slice": 4, 
+        "deploymentNetwork": 9, 
+        "name": "node24.mpisws.vicci.org", 
+        "created": "2013-12-12T17:55:32.660Z", 
+        "deleted": false, 
+        "ip": "141.39.220.34", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 53, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 691, 
+        "instance_name": "instance-000003f5", 
+        "updated": "2013-12-12T17:55:32.677Z", 
+        "slice": 4, 
+        "deploymentNetwork": 9, 
+        "name": "node28.mpisws.vicci.org", 
+        "created": "2013-12-12T17:55:32.677Z", 
+        "deleted": false, 
+        "ip": "141.39.220.38", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 54, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 693, 
+        "instance_name": "instance-000003f6", 
+        "updated": "2013-12-12T17:55:32.693Z", 
+        "slice": 4, 
+        "deploymentNetwork": 9, 
+        "name": "node30.mpisws.vicci.org", 
+        "created": "2013-12-12T17:55:32.693Z", 
+        "deleted": false, 
+        "ip": "141.39.220.40", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 55, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 694, 
+        "instance_name": "instance-000003f7", 
+        "updated": "2013-12-12T17:55:32.710Z", 
+        "slice": 4, 
+        "deploymentNetwork": 9, 
+        "name": "node31.mpisws.vicci.org", 
+        "created": "2013-12-12T17:55:32.710Z", 
+        "deleted": false, 
+        "ip": "141.39.220.41", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 58, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 561, 
+        "instance_name": "instance-000003fa", 
+        "updated": "2013-12-12T17:55:32.760Z", 
+        "slice": 4, 
+        "deploymentNetwork": 7, 
+        "name": "node38.princeton.vicci.org", 
+        "created": "2013-12-12T17:55:32.759Z", 
+        "deleted": false, 
+        "ip": "128.112.171.94", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 562, 
+        "instance_name": "instance-000003fb", 
+        "updated": "2013-12-12T17:55:32.776Z", 
+        "slice": 4, 
+        "deploymentNetwork": 7, 
+        "name": "node39.princeton.vicci.org", 
+        "created": "2013-12-12T17:55:32.776Z", 
+        "deleted": false, 
+        "ip": "128.112.171.96", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 563, 
+        "instance_name": "instance-000003fc", 
+        "updated": "2013-12-12T17:55:32.792Z", 
+        "slice": 4, 
+        "deploymentNetwork": 7, 
+        "name": "node40.princeton.vicci.org", 
+        "created": "2013-12-12T17:55:32.792Z", 
+        "deleted": false, 
+        "ip": "128.112.171.98", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 565, 
+        "instance_name": "instance-000003fd", 
+        "updated": "2013-12-12T17:55:32.809Z", 
+        "slice": 4, 
+        "deploymentNetwork": 7, 
+        "name": "node42.princeton.vicci.org", 
+        "created": "2013-12-12T17:55:32.809Z", 
+        "deleted": false, 
+        "ip": "128.112.171.102", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 62, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 566, 
+        "instance_name": "instance-000003fe", 
+        "updated": "2013-12-12T17:55:32.826Z", 
+        "slice": 4, 
+        "deploymentNetwork": 7, 
+        "name": "node43.princeton.vicci.org", 
+        "created": "2013-12-12T17:55:32.826Z", 
+        "deleted": false, 
+        "ip": "128.112.171.104", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 63, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 568, 
+        "instance_name": "instance-000003ff", 
+        "updated": "2013-12-12T17:55:32.842Z", 
+        "slice": 4, 
+        "deploymentNetwork": 7, 
+        "name": "node45.princeton.vicci.org", 
+        "created": "2013-12-12T17:55:32.842Z", 
+        "deleted": false, 
+        "ip": "128.112.171.108", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 64, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 404, 
+        "instance_name": "instance-00000400", 
+        "updated": "2013-12-12T17:55:32.859Z", 
+        "slice": 4, 
+        "deploymentNetwork": 5, 
+        "name": "node21.stanford.vicci.org", 
+        "created": "2013-12-12T17:55:32.859Z", 
+        "deleted": false, 
+        "ip": "171.67.92.159", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 65, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 405, 
+        "instance_name": "instance-00000401", 
+        "updated": "2013-12-12T17:55:32.875Z", 
+        "slice": 4, 
+        "deploymentNetwork": 5, 
+        "name": "node22.stanford.vicci.org", 
+        "created": "2013-12-12T17:55:32.875Z", 
+        "deleted": false, 
+        "ip": "171.67.92.160", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 66, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 406, 
+        "instance_name": "instance-00000402", 
+        "updated": "2013-12-12T17:55:32.892Z", 
+        "slice": 4, 
+        "deploymentNetwork": 5, 
+        "name": "node23.stanford.vicci.org", 
+        "created": "2013-12-12T17:55:32.892Z", 
+        "deleted": false, 
+        "ip": "171.67.92.161", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 67, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 407, 
+        "instance_name": "instance-00000403", 
+        "updated": "2013-12-12T17:55:32.909Z", 
+        "slice": 4, 
+        "deploymentNetwork": 5, 
+        "name": "node24.stanford.vicci.org", 
+        "created": "2013-12-12T17:55:32.909Z", 
+        "deleted": false, 
+        "ip": "171.67.92.162", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 68, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 408, 
+        "instance_name": "instance-00000404", 
+        "updated": "2013-12-12T17:55:32.925Z", 
+        "slice": 4, 
+        "deploymentNetwork": 5, 
+        "name": "node25.stanford.vicci.org", 
+        "created": "2013-12-12T17:55:32.925Z", 
+        "deleted": false, 
+        "ip": "171.67.92.163", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 69, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 409, 
+        "instance_name": "instance-00000405", 
+        "updated": "2013-12-12T17:55:32.942Z", 
+        "slice": 4, 
+        "deploymentNetwork": 5, 
+        "name": "node26.stanford.vicci.org", 
+        "created": "2013-12-12T17:55:32.942Z", 
+        "deleted": false, 
+        "ip": "171.67.92.164", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 70, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 412, 
+        "instance_name": "instance-00000406", 
+        "updated": "2013-12-12T17:55:32.958Z", 
+        "slice": 4, 
+        "deploymentNetwork": 5, 
+        "name": "node29.stanford.vicci.org", 
+        "created": "2013-12-12T17:55:32.958Z", 
+        "deleted": false, 
+        "ip": "171.67.92.167", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 71, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 413, 
+        "instance_name": "instance-00000407", 
+        "updated": "2013-12-12T17:55:32.975Z", 
+        "slice": 4, 
+        "deploymentNetwork": 5, 
+        "name": "node30.stanford.vicci.org", 
+        "created": "2013-12-12T17:55:32.975Z", 
+        "deleted": false, 
+        "ip": "171.67.92.168", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 72, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 460, 
+        "instance_name": "instance-00000408", 
+        "updated": "2013-12-12T17:55:32.992Z", 
+        "slice": 4, 
+        "deploymentNetwork": 6, 
+        "name": "node7.washington.vicci.org", 
+        "created": "2013-12-12T17:55:32.992Z", 
+        "deleted": false, 
+        "ip": "128.95.1.112", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 73, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 467, 
+        "instance_name": "instance-00000409", 
+        "updated": "2013-12-12T17:55:33.008Z", 
+        "slice": 4, 
+        "deploymentNetwork": 6, 
+        "name": "node14.washington.vicci.org", 
+        "created": "2013-12-12T17:55:33.008Z", 
+        "deleted": false, 
+        "ip": "128.95.1.119", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 76, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 470, 
+        "instance_name": "instance-0000040c", 
+        "updated": "2013-12-12T17:55:33.058Z", 
+        "slice": 4, 
+        "deploymentNetwork": 6, 
+        "name": "node17.washington.vicci.org", 
+        "created": "2013-12-12T17:55:33.058Z", 
+        "deleted": false, 
+        "ip": "128.95.1.122", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 77, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 553, 
+        "instance_name": "instance-0000040d", 
+        "updated": "2013-12-12T17:55:33.110Z", 
+        "slice": 8, 
+        "deploymentNetwork": 7, 
+        "name": "node30.princeton.vicci.org", 
+        "created": "2013-12-12T17:55:33.110Z", 
+        "deleted": false, 
+        "ip": "128.112.171.78", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 78, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 553, 
+        "instance_name": "instance-0000040e", 
+        "updated": "2013-12-12T17:55:33.142Z", 
+        "slice": 9, 
+        "deploymentNetwork": 7, 
+        "name": "node30.princeton.vicci.org", 
+        "created": "2013-12-12T17:55:33.142Z", 
+        "deleted": false, 
+        "ip": "128.112.171.78", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 79, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 469, 
+        "instance_name": null, 
+        "updated": "2013-12-13T21:51:36.927Z", 
+        "slice": 11, 
+        "deploymentNetwork": 6, 
+        "name": "Stork", 
+        "created": "2013-12-13T21:51:36.927Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 0, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 80, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 438, 
+        "instance_name": null, 
+        "updated": "2013-12-13T21:53:35.001Z", 
+        "slice": 12, 
+        "deploymentNetwork": 5, 
+        "name": "Owl", 
+        "created": "2013-12-13T21:53:35.001Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 0, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 81, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 588, 
+        "instance_name": null, 
+        "updated": "2013-12-18T22:21:36.513Z", 
+        "slice": 14, 
+        "deploymentNetwork": 7, 
+        "name": "test-slice-1", 
+        "created": "2013-12-13T21:58:13.897Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 0, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 82, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 589, 
+        "instance_name": null, 
+        "updated": "2013-12-18T22:21:36.522Z", 
+        "slice": 14, 
+        "deploymentNetwork": 7, 
+        "name": "test-slice-1", 
+        "created": "2013-12-13T21:58:44.349Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 0, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 83, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 590, 
+        "instance_name": null, 
+        "updated": "2013-12-18T22:21:36.530Z", 
+        "slice": 14, 
+        "deploymentNetwork": 7, 
+        "name": "test-slice-1", 
+        "created": "2013-12-13T21:58:44.350Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 0, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 84, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 384, 
+        "instance_name": null, 
+        "updated": "2013-12-13T21:59:36.723Z", 
+        "slice": 13, 
+        "deploymentNetwork": 5, 
+        "name": "Hadoop", 
+        "created": "2013-12-13T21:59:36.723Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 0, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 85, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 473, 
+        "instance_name": null, 
+        "updated": "2013-12-13T21:59:36.725Z", 
+        "slice": 13, 
+        "deploymentNetwork": 6, 
+        "name": "Hadoop", 
+        "created": "2013-12-13T21:59:36.725Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 0, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 86, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 535, 
+        "instance_name": null, 
+        "updated": "2013-12-13T21:59:36.726Z", 
+        "slice": 13, 
+        "deploymentNetwork": 7, 
+        "name": "Hadoop", 
+        "created": "2013-12-13T21:59:36.726Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 0, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 87, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 592, 
+        "instance_name": null, 
+        "updated": "2013-12-18T22:22:04.726Z", 
+        "slice": 15, 
+        "deploymentNetwork": 7, 
+        "name": "test-slice-2", 
+        "created": "2013-12-13T22:01:30.192Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 0, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 88, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 593, 
+        "instance_name": null, 
+        "updated": "2013-12-18T22:22:04.734Z", 
+        "slice": 15, 
+        "deploymentNetwork": 7, 
+        "name": "test-slice-2", 
+        "created": "2013-12-13T22:01:49.742Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 0, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 288, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 433, 
+        "instance_name": "instance-000005dc", 
+        "updated": "2013-12-18T21:41:49.275Z", 
+        "slice": 6, 
+        "deploymentNetwork": 5, 
+        "name": "node50.stanford.vicci.org", 
+        "created": "2013-12-18T21:41:49.275Z", 
+        "deleted": false, 
+        "ip": "171.67.92.188", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 289, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 643, 
+        "instance_name": "instance-000005dd", 
+        "updated": "2013-12-18T21:41:49.293Z", 
+        "slice": 6, 
+        "deploymentNetwork": 8, 
+        "name": "node50.gt.vicci.org", 
+        "created": "2013-12-18T21:41:49.293Z", 
+        "deleted": false, 
+        "ip": "130.207.98.59", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 290, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 713, 
+        "instance_name": "instance-000005de", 
+        "updated": "2013-12-18T21:41:49.310Z", 
+        "slice": 6, 
+        "deploymentNetwork": 9, 
+        "name": "node50.mpisws.vicci.org", 
+        "created": "2013-12-18T21:41:49.310Z", 
+        "deleted": false, 
+        "ip": "141.39.220.60", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 291, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 503, 
+        "instance_name": "instance-000005df", 
+        "updated": "2013-12-18T21:41:49.326Z", 
+        "slice": 6, 
+        "deploymentNetwork": 6, 
+        "name": "node50.washington.vicci.org", 
+        "created": "2013-12-18T21:41:49.326Z", 
+        "deleted": false, 
+        "ip": "128.95.1.155", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 292, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 513, 
+        "instance_name": "instance-000005e0", 
+        "updated": "2013-12-18T21:41:49.343Z", 
+        "slice": 6, 
+        "deploymentNetwork": 6, 
+        "name": "node60.washington.vicci.org", 
+        "created": "2013-12-18T21:41:49.343Z", 
+        "deleted": false, 
+        "ip": "128.95.1.165", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 293, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 723, 
+        "instance_name": "instance-000005e1", 
+        "updated": "2013-12-18T21:41:49.359Z", 
+        "slice": 6, 
+        "deploymentNetwork": 9, 
+        "name": "node60.mpisws.vicci.org", 
+        "created": "2013-12-18T21:41:49.359Z", 
+        "deleted": false, 
+        "ip": "141.39.220.70", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 294, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 603, 
+        "instance_name": "instance-000005e2", 
+        "updated": "2013-12-18T21:41:49.376Z", 
+        "slice": 6, 
+        "deploymentNetwork": 8, 
+        "name": "node10.gt.vicci.org", 
+        "created": "2013-12-18T21:41:49.376Z", 
+        "deleted": false, 
+        "ip": "130.207.98.19", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 295, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 559, 
+        "instance_name": "instance-000005e3", 
+        "updated": "2013-12-18T21:41:49.393Z", 
+        "slice": 6, 
+        "deploymentNetwork": 7, 
+        "name": "node36.princeton.vicci.org", 
+        "created": "2013-12-18T21:41:49.393Z", 
+        "deleted": false, 
+        "ip": "128.112.171.90", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 296, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 560, 
+        "instance_name": "instance-000005e4", 
+        "updated": "2013-12-18T21:41:49.409Z", 
+        "slice": 6, 
+        "deploymentNetwork": 7, 
+        "name": "node37.princeton.vicci.org", 
+        "created": "2013-12-18T21:41:49.409Z", 
+        "deleted": false, 
+        "ip": "128.112.171.92", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 297, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 561, 
+        "instance_name": "instance-000005e5", 
+        "updated": "2013-12-18T21:41:49.426Z", 
+        "slice": 6, 
+        "deploymentNetwork": 7, 
+        "name": "node38.princeton.vicci.org", 
+        "created": "2013-12-18T21:41:49.426Z", 
+        "deleted": false, 
+        "ip": "128.112.171.94", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 298, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 562, 
+        "instance_name": "instance-000005e6", 
+        "updated": "2013-12-18T21:41:49.442Z", 
+        "slice": 6, 
+        "deploymentNetwork": 7, 
+        "name": "node39.princeton.vicci.org", 
+        "created": "2013-12-18T21:41:49.442Z", 
+        "deleted": false, 
+        "ip": "128.112.171.96", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 299, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 563, 
+        "instance_name": "instance-000005e7", 
+        "updated": "2013-12-18T21:41:49.459Z", 
+        "slice": 6, 
+        "deploymentNetwork": 7, 
+        "name": "node40.princeton.vicci.org", 
+        "created": "2013-12-18T21:41:49.459Z", 
+        "deleted": false, 
+        "ip": "128.112.171.98", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 300, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 564, 
+        "instance_name": "instance-000005e8", 
+        "updated": "2013-12-18T21:41:49.476Z", 
+        "slice": 6, 
+        "deploymentNetwork": 7, 
+        "name": "node41.princeton.vicci.org", 
+        "created": "2013-12-18T21:41:49.475Z", 
+        "deleted": false, 
+        "ip": "128.112.171.100", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 301, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 565, 
+        "instance_name": "instance-000005e9", 
+        "updated": "2013-12-18T21:41:49.492Z", 
+        "slice": 6, 
+        "deploymentNetwork": 7, 
+        "name": "node42.princeton.vicci.org", 
+        "created": "2013-12-18T21:41:49.492Z", 
+        "deleted": false, 
+        "ip": "128.112.171.102", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 302, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 566, 
+        "instance_name": "instance-000005ea", 
+        "updated": "2013-12-18T21:41:49.508Z", 
+        "slice": 6, 
+        "deploymentNetwork": 7, 
+        "name": "node43.princeton.vicci.org", 
+        "created": "2013-12-18T21:41:49.508Z", 
+        "deleted": false, 
+        "ip": "128.112.171.104", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 303, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 567, 
+        "instance_name": "instance-000005eb", 
+        "updated": "2013-12-18T21:41:49.525Z", 
+        "slice": 6, 
+        "deploymentNetwork": 7, 
+        "name": "node44.princeton.vicci.org", 
+        "created": "2013-12-18T21:41:49.525Z", 
+        "deleted": false, 
+        "ip": "128.112.171.106", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 304, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 568, 
+        "instance_name": "instance-000005ec", 
+        "updated": "2013-12-18T21:41:49.542Z", 
+        "slice": 6, 
+        "deploymentNetwork": 7, 
+        "name": "node45.princeton.vicci.org", 
+        "created": "2013-12-18T21:41:49.542Z", 
+        "deleted": false, 
+        "ip": "128.112.171.108", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 305, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 569, 
+        "instance_name": "instance-000005ed", 
+        "updated": "2013-12-18T21:41:49.558Z", 
+        "slice": 6, 
+        "deploymentNetwork": 7, 
+        "name": "node46.princeton.vicci.org", 
+        "created": "2013-12-18T21:41:49.558Z", 
+        "deleted": false, 
+        "ip": "128.112.171.110", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 306, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 570, 
+        "instance_name": "instance-000005ee", 
+        "updated": "2013-12-18T21:41:49.575Z", 
+        "slice": 6, 
+        "deploymentNetwork": 7, 
+        "name": "node47.princeton.vicci.org", 
+        "created": "2013-12-18T21:41:49.575Z", 
+        "deleted": false, 
+        "ip": "128.112.171.112", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 307, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 571, 
+        "instance_name": "instance-000005ef", 
+        "updated": "2013-12-18T21:41:49.591Z", 
+        "slice": 6, 
+        "deploymentNetwork": 7, 
+        "name": "node48.princeton.vicci.org", 
+        "created": "2013-12-18T21:41:49.591Z", 
+        "deleted": false, 
+        "ip": "128.112.171.114", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 308, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 572, 
+        "instance_name": "instance-000005f0", 
+        "updated": "2013-12-18T21:41:49.608Z", 
+        "slice": 6, 
+        "deploymentNetwork": 7, 
+        "name": "node49.princeton.vicci.org", 
+        "created": "2013-12-18T21:41:49.608Z", 
+        "deleted": false, 
+        "ip": "128.112.171.116", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 309, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 573, 
+        "instance_name": "instance-000005f1", 
+        "updated": "2013-12-18T21:41:49.625Z", 
+        "slice": 6, 
+        "deploymentNetwork": 7, 
+        "name": "node50.princeton.vicci.org", 
+        "created": "2013-12-18T21:41:49.625Z", 
+        "deleted": false, 
+        "ip": "128.112.171.118", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 310, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 574, 
+        "instance_name": "instance-000005f2", 
+        "updated": "2013-12-18T21:41:49.641Z", 
+        "slice": 6, 
+        "deploymentNetwork": 7, 
+        "name": "node51.princeton.vicci.org", 
+        "created": "2013-12-18T21:41:49.641Z", 
+        "deleted": false, 
+        "ip": "128.112.171.120", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 311, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 575, 
+        "instance_name": "instance-000005f3", 
+        "updated": "2013-12-18T21:41:49.658Z", 
+        "slice": 6, 
+        "deploymentNetwork": 7, 
+        "name": "node52.princeton.vicci.org", 
+        "created": "2013-12-18T21:41:49.658Z", 
+        "deleted": false, 
+        "ip": "128.112.171.122", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 312, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 576, 
+        "instance_name": "instance-000005f4", 
+        "updated": "2013-12-18T21:41:49.674Z", 
+        "slice": 6, 
+        "deploymentNetwork": 7, 
+        "name": "node53.princeton.vicci.org", 
+        "created": "2013-12-18T21:41:49.674Z", 
+        "deleted": false, 
+        "ip": "128.112.171.124", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 313, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 577, 
+        "instance_name": "instance-000005f5", 
+        "updated": "2013-12-18T21:41:49.691Z", 
+        "slice": 6, 
+        "deploymentNetwork": 7, 
+        "name": "node54.princeton.vicci.org", 
+        "created": "2013-12-18T21:41:49.691Z", 
+        "deleted": false, 
+        "ip": "128.112.171.126", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 314, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 578, 
+        "instance_name": "instance-000005f6", 
+        "updated": "2013-12-18T21:41:49.707Z", 
+        "slice": 6, 
+        "deploymentNetwork": 7, 
+        "name": "node55.princeton.vicci.org", 
+        "created": "2013-12-18T21:41:49.707Z", 
+        "deleted": false, 
+        "ip": "128.112.171.128", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 315, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 579, 
+        "instance_name": "instance-000005f7", 
+        "updated": "2013-12-18T21:41:49.724Z", 
+        "slice": 6, 
+        "deploymentNetwork": 7, 
+        "name": "node56.princeton.vicci.org", 
+        "created": "2013-12-18T21:41:49.724Z", 
+        "deleted": false, 
+        "ip": "128.112.171.130", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 316, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 580, 
+        "instance_name": "instance-000005f8", 
+        "updated": "2013-12-18T21:41:49.741Z", 
+        "slice": 6, 
+        "deploymentNetwork": 7, 
+        "name": "node57.princeton.vicci.org", 
+        "created": "2013-12-18T21:41:49.740Z", 
+        "deleted": false, 
+        "ip": "128.112.171.132", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 317, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 581, 
+        "instance_name": "instance-000005f9", 
+        "updated": "2013-12-18T21:41:49.757Z", 
+        "slice": 6, 
+        "deploymentNetwork": 7, 
+        "name": "node58.princeton.vicci.org", 
+        "created": "2013-12-18T21:41:49.757Z", 
+        "deleted": false, 
+        "ip": "128.112.171.134", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 318, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 582, 
+        "instance_name": "instance-000005fa", 
+        "updated": "2013-12-18T21:41:49.774Z", 
+        "slice": 6, 
+        "deploymentNetwork": 7, 
+        "name": "node59.princeton.vicci.org", 
+        "created": "2013-12-18T21:41:49.774Z", 
+        "deleted": false, 
+        "ip": "128.112.171.136", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 319, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 583, 
+        "instance_name": "instance-000005fb", 
+        "updated": "2013-12-18T21:41:49.790Z", 
+        "slice": 6, 
+        "deploymentNetwork": 7, 
+        "name": "node60.princeton.vicci.org", 
+        "created": "2013-12-18T21:41:49.790Z", 
+        "deleted": false, 
+        "ip": "128.112.171.138", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 320, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 584, 
+        "instance_name": "instance-000005fc", 
+        "updated": "2013-12-18T21:41:49.807Z", 
+        "slice": 6, 
+        "deploymentNetwork": 7, 
+        "name": "node61.princeton.vicci.org", 
+        "created": "2013-12-18T21:41:49.807Z", 
+        "deleted": false, 
+        "ip": "128.112.171.140", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 321, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 585, 
+        "instance_name": "instance-000005fd", 
+        "updated": "2013-12-18T21:41:49.823Z", 
+        "slice": 6, 
+        "deploymentNetwork": 7, 
+        "name": "node62.princeton.vicci.org", 
+        "created": "2013-12-18T21:41:49.823Z", 
+        "deleted": false, 
+        "ip": "128.112.171.142", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 322, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 586, 
+        "instance_name": "instance-000005fe", 
+        "updated": "2013-12-18T21:41:49.840Z", 
+        "slice": 6, 
+        "deploymentNetwork": 7, 
+        "name": "node63.princeton.vicci.org", 
+        "created": "2013-12-18T21:41:49.840Z", 
+        "deleted": false, 
+        "ip": "128.112.171.144", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 323, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 587, 
+        "instance_name": "instance-000005ff", 
+        "updated": "2013-12-18T21:41:49.856Z", 
+        "slice": 6, 
+        "deploymentNetwork": 7, 
+        "name": "node64.princeton.vicci.org", 
+        "created": "2013-12-18T21:41:49.856Z", 
+        "deleted": false, 
+        "ip": "128.112.171.146", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 324, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 588, 
+        "instance_name": "instance-00000600", 
+        "updated": "2013-12-18T21:41:49.873Z", 
+        "slice": 6, 
+        "deploymentNetwork": 7, 
+        "name": "node65.princeton.vicci.org", 
+        "created": "2013-12-18T21:41:49.873Z", 
+        "deleted": false, 
+        "ip": "128.112.171.148", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 325, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 589, 
+        "instance_name": "instance-00000601", 
+        "updated": "2013-12-18T21:41:49.890Z", 
+        "slice": 6, 
+        "deploymentNetwork": 7, 
+        "name": "node66.princeton.vicci.org", 
+        "created": "2013-12-18T21:41:49.890Z", 
+        "deleted": false, 
+        "ip": "128.112.171.150", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 326, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 590, 
+        "instance_name": "instance-00000602", 
+        "updated": "2013-12-18T21:41:49.906Z", 
+        "slice": 6, 
+        "deploymentNetwork": 7, 
+        "name": "node67.princeton.vicci.org", 
+        "created": "2013-12-18T21:41:49.906Z", 
+        "deleted": false, 
+        "ip": "128.112.171.152", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 327, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 591, 
+        "instance_name": "instance-00000603", 
+        "updated": "2013-12-18T21:41:49.923Z", 
+        "slice": 6, 
+        "deploymentNetwork": 7, 
+        "name": "node68.princeton.vicci.org", 
+        "created": "2013-12-18T21:41:49.923Z", 
+        "deleted": false, 
+        "ip": "128.112.171.154", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 328, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 592, 
+        "instance_name": "instance-00000604", 
+        "updated": "2013-12-18T21:41:49.939Z", 
+        "slice": 6, 
+        "deploymentNetwork": 7, 
+        "name": "node69.princeton.vicci.org", 
+        "created": "2013-12-18T21:41:49.939Z", 
+        "deleted": false, 
+        "ip": "128.112.171.156", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 329, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 593, 
+        "instance_name": "instance-00000605", 
+        "updated": "2013-12-18T21:41:49.956Z", 
+        "slice": 6, 
+        "deploymentNetwork": 7, 
+        "name": "node70.princeton.vicci.org", 
+        "created": "2013-12-18T21:41:49.956Z", 
+        "deleted": false, 
+        "ip": "128.112.171.158", 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 330, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 453, 
+        "instance_name": null, 
+        "updated": "2014-05-20T16:19:07.852Z", 
+        "slice": 13, 
+        "deploymentNetwork": 5, 
+        "name": "node70.stanford.vicci.org", 
+        "created": "2014-05-20T16:19:07.852Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 1, 
+        "creator": 7, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 331, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 523, 
+        "instance_name": null, 
+        "updated": "2014-05-20T16:19:07.940Z", 
+        "slice": 13, 
+        "deploymentNetwork": 6, 
+        "name": "node70.washington.vicci.org", 
+        "created": "2014-05-20T16:19:07.940Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 1, 
+        "creator": 7, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 332, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 452, 
+        "instance_name": null, 
+        "updated": "2014-05-20T16:19:08.011Z", 
+        "slice": 13, 
+        "deploymentNetwork": 5, 
+        "name": "node69.stanford.vicci.org", 
+        "created": "2014-05-20T16:19:08.011Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 1, 
+        "creator": 7, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 333, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 522, 
+        "instance_name": null, 
+        "updated": "2014-05-20T16:19:08.076Z", 
+        "slice": 13, 
+        "deploymentNetwork": 6, 
+        "name": "node69.washington.vicci.org", 
+        "created": "2014-05-20T16:19:08.076Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 1, 
+        "creator": 7, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 334, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 451, 
+        "instance_name": null, 
+        "updated": "2014-05-20T16:19:08.160Z", 
+        "slice": 13, 
+        "deploymentNetwork": 5, 
+        "name": "node68.stanford.vicci.org", 
+        "created": "2014-05-20T16:19:08.159Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 1, 
+        "creator": 7, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 335, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 521, 
+        "instance_name": null, 
+        "updated": "2014-05-20T16:19:08.244Z", 
+        "slice": 13, 
+        "deploymentNetwork": 6, 
+        "name": "node68.washington.vicci.org", 
+        "created": "2014-05-20T16:19:08.244Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 1, 
+        "creator": 7, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 336, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 450, 
+        "instance_name": null, 
+        "updated": "2014-05-20T16:19:08.305Z", 
+        "slice": 13, 
+        "deploymentNetwork": 5, 
+        "name": "node67.stanford.vicci.org", 
+        "created": "2014-05-20T16:19:08.305Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 1, 
+        "creator": 7, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 337, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 593, 
+        "instance_name": null, 
+        "updated": "2014-05-20T16:19:08.403Z", 
+        "slice": 13, 
+        "deploymentNetwork": 7, 
+        "name": "node70.princeton.vicci.org", 
+        "created": "2014-05-20T16:19:08.397Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 1, 
+        "creator": 7, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 338, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 520, 
+        "instance_name": null, 
+        "updated": "2014-05-20T16:19:08.421Z", 
+        "slice": 13, 
+        "deploymentNetwork": 6, 
+        "name": "node67.washington.vicci.org", 
+        "created": "2014-05-20T16:19:08.421Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 1, 
+        "creator": 7, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 339, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 449, 
+        "instance_name": null, 
+        "updated": "2014-05-20T16:19:08.465Z", 
+        "slice": 13, 
+        "deploymentNetwork": 5, 
+        "name": "node66.stanford.vicci.org", 
+        "created": "2014-05-20T16:19:08.465Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 1, 
+        "creator": 7, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 340, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 592, 
+        "instance_name": null, 
+        "updated": "2014-05-20T16:19:08.555Z", 
+        "slice": 13, 
+        "deploymentNetwork": 7, 
+        "name": "node69.princeton.vicci.org", 
+        "created": "2014-05-20T16:19:08.555Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 1, 
+        "creator": 7, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 341, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 519, 
+        "instance_name": null, 
+        "updated": "2014-05-20T16:19:08.567Z", 
+        "slice": 13, 
+        "deploymentNetwork": 6, 
+        "name": "node66.washington.vicci.org", 
+        "created": "2014-05-20T16:19:08.567Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 1, 
+        "creator": 7, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 342, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 591, 
+        "instance_name": null, 
+        "updated": "2014-05-20T16:19:08.788Z", 
+        "slice": 13, 
+        "deploymentNetwork": 7, 
+        "name": "node68.princeton.vicci.org", 
+        "created": "2014-05-20T16:19:08.788Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 1, 
+        "creator": 7, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 343, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 590, 
+        "instance_name": null, 
+        "updated": "2014-05-20T16:19:08.903Z", 
+        "slice": 13, 
+        "deploymentNetwork": 7, 
+        "name": "node67.princeton.vicci.org", 
+        "created": "2014-05-20T16:19:08.903Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 1, 
+        "creator": 7, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 344, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 589, 
+        "instance_name": null, 
+        "updated": "2014-05-20T16:19:08.995Z", 
+        "slice": 13, 
+        "deploymentNetwork": 7, 
+        "name": "node66.princeton.vicci.org", 
+        "created": "2014-05-20T16:19:08.995Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 1, 
+        "creator": 7, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 345, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 535, 
+        "instance_name": null, 
+        "updated": "2014-05-20T17:55:00.654Z", 
+        "slice": 16, 
+        "deploymentNetwork": 7, 
+        "name": "Analytics", 
+        "created": "2014-05-20T17:55:00.654Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 0, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 346, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 384, 
+        "instance_name": null, 
+        "updated": "2014-05-20T23:45:35.304Z", 
+        "slice": 16, 
+        "deploymentNetwork": 5, 
+        "name": "node1.stanford.vicci.org", 
+        "created": "2014-05-20T23:45:35.304Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 2, 
+        "creator": 7, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 347, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 454, 
+        "instance_name": null, 
+        "updated": "2014-05-20T23:45:35.322Z", 
+        "slice": 16, 
+        "deploymentNetwork": 6, 
+        "name": "node1.washington.vicci.org", 
+        "created": "2014-05-20T23:45:35.322Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 2, 
+        "creator": 7, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 348, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 385, 
+        "instance_name": null, 
+        "updated": "2014-05-20T23:45:35.397Z", 
+        "slice": 16, 
+        "deploymentNetwork": 5, 
+        "name": "node2.stanford.vicci.org", 
+        "created": "2014-05-20T23:45:35.397Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 2, 
+        "creator": 7, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 349, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 455, 
+        "instance_name": null, 
+        "updated": "2014-05-20T23:45:35.436Z", 
+        "slice": 16, 
+        "deploymentNetwork": 6, 
+        "name": "node2.washington.vicci.org", 
+        "created": "2014-05-20T23:45:35.436Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 2, 
+        "creator": 7, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 350, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 524, 
+        "instance_name": null, 
+        "updated": "2014-05-20T23:45:35.461Z", 
+        "slice": 16, 
+        "deploymentNetwork": 7, 
+        "name": "node1.princeton.vicci.org", 
+        "created": "2014-05-20T23:45:35.461Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 2, 
+        "creator": 7, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 351, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 386, 
+        "instance_name": null, 
+        "updated": "2014-05-20T23:45:35.472Z", 
+        "slice": 16, 
+        "deploymentNetwork": 5, 
+        "name": "node3.stanford.vicci.org", 
+        "created": "2014-05-20T23:45:35.472Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 2, 
+        "creator": 7, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 352, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 456, 
+        "instance_name": null, 
+        "updated": "2014-05-20T23:45:35.508Z", 
+        "slice": 16, 
+        "deploymentNetwork": 6, 
+        "name": "node3.washington.vicci.org", 
+        "created": "2014-05-20T23:45:35.508Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 2, 
+        "creator": 7, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 353, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 525, 
+        "instance_name": null, 
+        "updated": "2014-05-20T23:45:35.565Z", 
+        "slice": 16, 
+        "deploymentNetwork": 7, 
+        "name": "node2.princeton.vicci.org", 
+        "created": "2014-05-20T23:45:35.565Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 2, 
+        "creator": 7, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 354, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 457, 
+        "instance_name": null, 
+        "updated": "2014-05-20T23:45:35.707Z", 
+        "slice": 16, 
+        "deploymentNetwork": 6, 
+        "name": "node4.washington.vicci.org", 
+        "created": "2014-05-20T23:45:35.706Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 2, 
+        "creator": 7, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 355, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 526, 
+        "instance_name": null, 
+        "updated": "2014-05-20T23:45:35.812Z", 
+        "slice": 16, 
+        "deploymentNetwork": 7, 
+        "name": "node3.princeton.vicci.org", 
+        "created": "2014-05-20T23:45:35.812Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 2, 
+        "creator": 7, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 356, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 458, 
+        "instance_name": null, 
+        "updated": "2014-05-20T23:45:35.860Z", 
+        "slice": 16, 
+        "deploymentNetwork": 6, 
+        "name": "node5.washington.vicci.org", 
+        "created": "2014-05-20T23:45:35.860Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 2, 
+        "creator": 7, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 357, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 527, 
+        "instance_name": null, 
+        "updated": "2014-05-20T23:45:35.887Z", 
+        "slice": 16, 
+        "deploymentNetwork": 7, 
+        "name": "node4.princeton.vicci.org", 
+        "created": "2014-05-20T23:45:35.887Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 2, 
+        "creator": 7, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 358, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 459, 
+        "instance_name": null, 
+        "updated": "2014-05-20T23:45:35.926Z", 
+        "slice": 16, 
+        "deploymentNetwork": 6, 
+        "name": "node6.washington.vicci.org", 
+        "created": "2014-05-20T23:45:35.926Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 2, 
+        "creator": 7, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 359, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 528, 
+        "instance_name": null, 
+        "updated": "2014-05-20T23:45:35.961Z", 
+        "slice": 16, 
+        "deploymentNetwork": 7, 
+        "name": "node5.princeton.vicci.org", 
+        "created": "2014-05-20T23:45:35.961Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 2, 
+        "creator": 7, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 360, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 387, 
+        "instance_name": null, 
+        "updated": "2014-05-20T23:46:01.919Z", 
+        "slice": 16, 
+        "deploymentNetwork": 5, 
+        "name": "node4.stanford.vicci.org", 
+        "created": "2014-05-20T23:46:01.919Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 2, 
+        "creator": 7, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 361, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 388, 
+        "instance_name": null, 
+        "updated": "2014-05-20T23:46:01.987Z", 
+        "slice": 16, 
+        "deploymentNetwork": 5, 
+        "name": "node5.stanford.vicci.org", 
+        "created": "2014-05-20T23:46:01.987Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 2, 
+        "creator": 7, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 362, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 389, 
+        "instance_name": null, 
+        "updated": "2014-05-20T23:46:02.054Z", 
+        "slice": 16, 
+        "deploymentNetwork": 5, 
+        "name": "node6.stanford.vicci.org", 
+        "created": "2014-05-20T23:46:02.054Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 2, 
+        "creator": 7, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 363, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 663, 
+        "instance_name": null, 
+        "updated": "2014-05-27T15:29:38.516Z", 
+        "slice": 4, 
+        "deploymentNetwork": 8, 
+        "name": "node70.gt.vicci.org", 
+        "created": "2014-05-27T15:29:38.516Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 1, 
+        "creator": 16, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 365, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 661, 
+        "instance_name": null, 
+        "updated": "2014-05-27T15:30:14.655Z", 
+        "slice": 4, 
+        "deploymentNetwork": 8, 
+        "name": "node68.gt.vicci.org", 
+        "created": "2014-05-27T15:30:14.655Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 1, 
+        "creator": 16, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 366, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 593, 
+        "instance_name": null, 
+        "updated": "2014-05-28T10:01:53.533Z", 
+        "slice": 4, 
+        "deploymentNetwork": 7, 
+        "name": "node70.princeton.vicci.org", 
+        "created": "2014-05-28T10:01:53.533Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 1, 
+        "creator": 16, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 368, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 453, 
+        "instance_name": null, 
+        "updated": "2014-05-28T12:15:02.758Z", 
+        "slice": 4, 
+        "deploymentNetwork": 5, 
+        "name": "node70.stanford.vicci.org", 
+        "created": "2014-05-28T12:15:02.758Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 1, 
+        "creator": 16, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 369, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 452, 
+        "instance_name": null, 
+        "updated": "2014-05-28T12:15:49.381Z", 
+        "slice": 4, 
+        "deploymentNetwork": 5, 
+        "name": "node69.stanford.vicci.org", 
+        "created": "2014-05-28T12:15:49.381Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 1, 
+        "creator": 16, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 370, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 660, 
+        "instance_name": null, 
+        "updated": "2014-05-28T12:44:22.130Z", 
+        "slice": 4, 
+        "deploymentNetwork": 8, 
+        "name": "node67.gt.vicci.org", 
+        "created": "2014-05-28T12:44:22.130Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 1, 
+        "creator": 16, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 371, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 523, 
+        "instance_name": null, 
+        "updated": "2014-05-28T12:51:19.616Z", 
+        "slice": 4, 
+        "deploymentNetwork": 6, 
+        "name": "node70.washington.vicci.org", 
+        "created": "2014-05-28T12:51:19.616Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 1, 
+        "creator": 16, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 372, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 522, 
+        "instance_name": null, 
+        "updated": "2014-05-29T17:07:47.912Z", 
+        "slice": 4, 
+        "deploymentNetwork": 6, 
+        "name": "node69.washington.vicci.org", 
+        "created": "2014-05-29T17:07:47.912Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 1, 
+        "creator": 8, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 373, 
+    "model": "core.instance", 
+    "fields": {
+        "node": 733, 
+        "instance_name": null, 
+        "updated": "2014-06-04T00:34:59.093Z", 
+        "slice": 4, 
+        "deploymentNetwork": 9, 
+        "name": "node70.mpisws.vicci.org", 
+        "created": "2014-06-04T00:34:59.093Z", 
+        "deleted": false, 
+        "ip": null, 
+        "image": 1, 
+        "creator": 7, 
+        "numberCores": 1, 
+        "instance_id": null, 
+        "userData": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 1, 
+    "model": "core.reservation", 
+    "fields": {
+        "updated": "2013-12-18T23:32:41.619Z", 
+        "slice": 9, 
+        "created": "2013-12-18T23:32:07.665Z", 
+        "deleted": false, 
+        "startTime": "2013-12-20T20:31:42Z", 
+        "duration": 48, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 2, 
+    "model": "core.reservation", 
+    "fields": {
+        "updated": "2013-12-18T23:34:02.148Z", 
+        "slice": 8, 
+        "created": "2013-12-18T23:33:27.591Z", 
+        "deleted": false, 
+        "startTime": "2013-12-20T20:33:23Z", 
+        "duration": 48, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3, 
+    "model": "core.reservation", 
+    "fields": {
+        "updated": "2013-12-18T23:35:45.483Z", 
+        "slice": 13, 
+        "created": "2013-12-18T23:34:55.406Z", 
+        "deleted": false, 
+        "startTime": "2013-12-20T20:34:32Z", 
+        "duration": 24, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 4, 
+    "model": "core.reservation", 
+    "fields": {
+        "updated": "2013-12-18T23:35:25.727Z", 
+        "slice": 13, 
+        "created": "2013-12-18T23:34:55.407Z", 
+        "deleted": false, 
+        "startTime": "2013-12-23T20:34:49Z", 
+        "duration": 24, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 1, 
+    "model": "core.reservedresource", 
+    "fields": {
+        "updated": "2013-12-18T23:32:41.622Z", 
+        "resource": 8, 
+        "created": "2013-12-18T23:32:41.622Z", 
+        "deleted": false, 
+        "instance": 78, 
+        "reservationSet": 1, 
+        "backend_status": "Provisioning in progress", 
+        "quantity": 5, 
+        "enacted": null
+    }
+},
+{
+    "pk": 2, 
+    "model": "core.reservedresource", 
+    "fields": {
+        "updated": "2013-12-18T23:34:02.152Z", 
+        "resource": 8, 
+        "created": "2013-12-18T23:34:02.152Z", 
+        "deleted": false, 
+        "instance": 77, 
+        "reservationSet": 2, 
+        "backend_status": "Provisioning in progress", 
+        "quantity": 5, 
+        "enacted": null
+    }
+},
+{
+    "pk": 3, 
+    "model": "core.reservedresource", 
+    "fields": {
+        "updated": "2013-12-18T23:35:25.731Z", 
+        "resource": 8, 
+        "created": "2013-12-18T23:35:25.731Z", 
+        "deleted": false, 
+        "instance": 84, 
+        "reservationSet": 4, 
+        "backend_status": "Provisioning in progress", 
+        "quantity": 1, 
+        "enacted": null
+    }
+},
+{
+    "pk": 4, 
+    "model": "core.reservedresource", 
+    "fields": {
+        "updated": "2013-12-18T23:35:25.732Z", 
+        "resource": 8, 
+        "created": "2013-12-18T23:35:25.732Z", 
+        "deleted": false, 
+        "instance": 85, 
+        "reservationSet": 4, 
+        "backend_status": "Provisioning in progress", 
+        "quantity": 1, 
+        "enacted": null
+    }
+},
+{
+    "pk": 5, 
+    "model": "core.reservedresource", 
+    "fields": {
+        "updated": "2013-12-18T23:35:25.733Z", 
+        "resource": 8, 
+        "created": "2013-12-18T23:35:25.733Z", 
+        "deleted": false, 
+        "instance": 86, 
+        "reservationSet": 4, 
+        "backend_status": "Provisioning in progress", 
+        "quantity": 1, 
+        "enacted": null
+    }
+},
+{
+    "pk": 6, 
+    "model": "core.reservedresource", 
+    "fields": {
+        "updated": "2013-12-18T23:35:45.486Z", 
+        "resource": 8, 
+        "created": "2013-12-18T23:35:45.486Z", 
+        "deleted": false, 
+        "instance": 84, 
+        "reservationSet": 3, 
+        "backend_status": "Provisioning in progress", 
+        "quantity": 1, 
+        "enacted": null
+    }
+},
+{
+    "pk": 7, 
+    "model": "core.reservedresource", 
+    "fields": {
+        "updated": "2013-12-18T23:35:45.488Z", 
+        "resource": 8, 
+        "created": "2013-12-18T23:35:45.487Z", 
+        "deleted": false, 
+        "instance": 85, 
+        "reservationSet": 3, 
+        "backend_status": "Provisioning in progress", 
+        "quantity": 1, 
+        "enacted": null
+    }
+},
+{
+    "pk": 8, 
+    "model": "core.reservedresource", 
+    "fields": {
+        "updated": "2013-12-18T23:35:45.488Z", 
+        "resource": 8, 
+        "created": "2013-12-18T23:35:45.488Z", 
+        "deleted": false, 
+        "instance": 86, 
+        "reservationSet": 3, 
+        "backend_status": "Provisioning in progress", 
+        "quantity": 1, 
+        "enacted": null
+    }
+},
+{
+    "pk": 1, 
+    "model": "core.networktemplate", 
+    "fields": {
+        "updated": "2014-05-12T19:23:35.239Z", 
+        "name": "Public dedicated IPv4", 
+        "created": "2013-12-09T14:15:16.899Z", 
+        "deleted": false, 
+        "description": "Connect a instance to the public network using dedicated public IPv4 address", 
+        "shared_network_name": "ext-net", 
+        "guaranteed_bandwidth": 0, 
+        "visibility": "public", 
+        "shared_network_id": "", 
+        "translation": "none", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": "2014-05-12T19:24:09Z"
+    }
+},
+{
+    "pk": 3, 
+    "model": "core.networktemplate", 
+    "fields": {
+        "updated": "2014-05-28T14:03:07.786Z", 
+        "name": "Public shared IPv4", 
+        "created": "2013-12-09T14:17:29.551Z", 
+        "deleted": false, 
+        "description": "Connect a instance to the public network via NAT, with port forwarding", 
+        "shared_network_name": "nat-net", 
+        "guaranteed_bandwidth": 0, 
+        "visibility": "private", 
+        "shared_network_id": "", 
+        "translation": "NAT", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": "2014-05-12T19:23:54Z"
+    }
+},
+{
+    "pk": 4, 
+    "model": "core.networktemplate", 
+    "fields": {
+        "updated": "2014-05-12T19:22:24.929Z", 
+        "name": "Private", 
+        "created": "2013-12-09T14:18:02.336Z", 
+        "deleted": false, 
+        "description": "A private virtual network", 
+        "shared_network_name": "", 
+        "guaranteed_bandwidth": 0, 
+        "visibility": "private", 
+        "shared_network_id": "", 
+        "translation": "none", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": "2014-05-12T19:23:30Z"
+    }
+},
+{
+    "pk": 1, 
+    "model": "core.network", 
+    "fields": {
+        "router_id": "", 
+        "subnet": "64.57.18.128/28", 
+        "updated": "2013-12-09T14:24:19.970Z", 
+        "subnet_id": "e1796711-5584-4bc1-b09b-45dff8f59f32", 
+        "name": "VINI-I2WashDC-public", 
+        "created": "2013-12-09T14:24:19.970Z", 
+        "deleted": false, 
+        "network_id": "7cb4291d-f8d3-4797-83b0-8deefd85bdf5", 
+        "permitted_slices": [], 
+        "labels": "public-net", 
+        "guaranteed_bandwidth": 0, 
+        "permit_all_slices": false, 
+        "template": 1, 
+        "owner": 10, 
+        "backend_status": "Provisioning in progress", 
+        "ports": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 2, 
+    "model": "core.network", 
+    "fields": {
+        "router_id": "", 
+        "subnet": "64.57.18.112/28", 
+        "updated": "2013-12-09T14:31:41.605Z", 
+        "subnet_id": "1afdc262-767b-4736-9403-584265293a81", 
+        "name": "VINI-I2Seattle-public", 
+        "created": "2013-12-09T14:31:41.605Z", 
+        "deleted": false, 
+        "network_id": "810b4cb8-9d8e-4eee-becc-676785a07725", 
+        "permitted_slices": [], 
+        "labels": "public-net", 
+        "guaranteed_bandwidth": 0, 
+        "permit_all_slices": false, 
+        "template": 1, 
+        "owner": 10, 
+        "backend_status": "Provisioning in progress", 
+        "ports": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3, 
+    "model": "core.network", 
+    "fields": {
+        "router_id": "", 
+        "subnet": "64.57.18.96/28", 
+        "updated": "2013-12-09T14:33:10.312Z", 
+        "subnet_id": "c3582780-76f1-4979-97b0-e27f39f18daa", 
+        "name": "VINI-I2SaltLakeCity-public", 
+        "created": "2013-12-09T14:33:10.312Z", 
+        "deleted": false, 
+        "network_id": "4b37f048-11de-4ddd-acaf-2fc5e8716f0e", 
+        "permitted_slices": [], 
+        "labels": "public-net", 
+        "guaranteed_bandwidth": 0, 
+        "permit_all_slices": false, 
+        "template": 1, 
+        "owner": 10, 
+        "backend_status": "Provisioning in progress", 
+        "ports": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 4, 
+    "model": "core.network", 
+    "fields": {
+        "router_id": "", 
+        "subnet": "64.57.18.80/28", 
+        "updated": "2013-12-09T14:34:55.754Z", 
+        "subnet_id": "c0d989f2-f42f-4b3e-a23f-a0063ac4f010", 
+        "name": "VINI-I2NewYork-public", 
+        "created": "2013-12-09T14:34:55.754Z", 
+        "deleted": false, 
+        "network_id": "684386d7-1286-4e58-acda-8ff45deac99e", 
+        "permitted_slices": [], 
+        "labels": "public-net", 
+        "guaranteed_bandwidth": 0, 
+        "permit_all_slices": false, 
+        "template": 1, 
+        "owner": 10, 
+        "backend_status": "Provisioning in progress", 
+        "ports": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 5, 
+    "model": "core.network", 
+    "fields": {
+        "router_id": "", 
+        "subnet": "64.57.18.64/28", 
+        "updated": "2013-12-09T14:36:09.261Z", 
+        "subnet_id": "d37bab1f-7e01-417c-86c4-ea0d69e2f25d", 
+        "name": "VINI-I2LosAngeles-public", 
+        "created": "2013-12-09T14:36:09.261Z", 
+        "deleted": false, 
+        "network_id": "fa090174-ec59-4b7a-812b-9206d911fb61", 
+        "permitted_slices": [], 
+        "labels": "public-net", 
+        "guaranteed_bandwidth": 0, 
+        "permit_all_slices": false, 
+        "template": 1, 
+        "owner": 10, 
+        "backend_status": "Provisioning in progress", 
+        "ports": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 6, 
+    "model": "core.network", 
+    "fields": {
+        "router_id": "", 
+        "subnet": "64.57.18.48/28", 
+        "updated": "2013-12-09T14:37:02.420Z", 
+        "subnet_id": "7caa4cfb-846a-4e4c-9984-8ead4091f816", 
+        "name": "VINI-I2KansasCity-public", 
+        "created": "2013-12-09T14:37:02.420Z", 
+        "deleted": false, 
+        "network_id": "017a3914-5eaf-4bcb-8609-6d17ebcdf075", 
+        "permitted_slices": [], 
+        "labels": "public-net", 
+        "guaranteed_bandwidth": 0, 
+        "permit_all_slices": false, 
+        "template": 1, 
+        "owner": 10, 
+        "backend_status": "Provisioning in progress", 
+        "ports": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 7, 
+    "model": "core.network", 
+    "fields": {
+        "router_id": "", 
+        "subnet": "64.57.18.32/28", 
+        "updated": "2013-12-09T14:38:11.552Z", 
+        "subnet_id": "4438dfbd-099a-4229-bd86-cf29478a009b", 
+        "name": "VINI-I2Houston-public", 
+        "created": "2013-12-09T14:38:11.552Z", 
+        "deleted": false, 
+        "network_id": "fdf0e3b1-439b-4673-b56e-d9dfe52b2bb7", 
+        "permitted_slices": [], 
+        "labels": "public-net", 
+        "guaranteed_bandwidth": 0, 
+        "permit_all_slices": false, 
+        "template": 1, 
+        "owner": 10, 
+        "backend_status": "Provisioning in progress", 
+        "ports": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 8, 
+    "model": "core.network", 
+    "fields": {
+        "router_id": "", 
+        "subnet": "64.57.18.32/28", 
+        "updated": "2013-12-09T14:39:51.262Z", 
+        "subnet_id": "4438dfbd-099a-4229-bd86-cf29478a009b", 
+        "name": "VINI-I2Houston-public", 
+        "created": "2013-12-09T14:39:51.262Z", 
+        "deleted": false, 
+        "network_id": "fdf0e3b1-439b-4673-b56e-d9dfe52b2bb7", 
+        "permitted_slices": [], 
+        "labels": "public-net", 
+        "guaranteed_bandwidth": 0, 
+        "permit_all_slices": false, 
+        "template": 1, 
+        "owner": 10, 
+        "backend_status": "Provisioning in progress", 
+        "ports": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 9, 
+    "model": "core.network", 
+    "fields": {
+        "router_id": "", 
+        "subnet": "64.57.18.32/28", 
+        "updated": "2013-12-09T14:41:00.237Z", 
+        "subnet_id": "4438dfbd-099a-4229-bd86-cf29478a009b", 
+        "name": "VINI-I2Houston-public", 
+        "created": "2013-12-09T14:41:00.237Z", 
+        "deleted": false, 
+        "network_id": "fdf0e3b1-439b-4673-b56e-d9dfe52b2bb7", 
+        "permitted_slices": [], 
+        "labels": "public-net", 
+        "guaranteed_bandwidth": 0, 
+        "permit_all_slices": false, 
+        "template": 1, 
+        "owner": 10, 
+        "backend_status": "Provisioning in progress", 
+        "ports": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 10, 
+    "model": "core.network", 
+    "fields": {
+        "router_id": "", 
+        "subnet": "64.57.18.16/28", 
+        "updated": "2013-12-09T14:42:03.158Z", 
+        "subnet_id": "332113b1-e6f4-492e-ad93-ce21512d3459", 
+        "name": "VINI-I2Chicago-public", 
+        "created": "2013-12-09T14:42:03.158Z", 
+        "deleted": false, 
+        "network_id": "ecdbaf66-b659-4d59-b0b7-1bf6d232ccba", 
+        "permitted_slices": [], 
+        "labels": "public-net", 
+        "guaranteed_bandwidth": 0, 
+        "permit_all_slices": false, 
+        "template": 1, 
+        "owner": 10, 
+        "backend_status": "Provisioning in progress", 
+        "ports": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 11, 
+    "model": "core.network", 
+    "fields": {
+        "router_id": "", 
+        "subnet": "64.57.18.0/28", 
+        "updated": "2013-12-09T14:42:49.781Z", 
+        "subnet_id": "dafefd4f-2622-4987-9f30-94e9a977cfc3", 
+        "name": "VINI-I2Atlanta-public", 
+        "created": "2013-12-09T14:42:49.781Z", 
+        "deleted": false, 
+        "network_id": "ae4d42e8-a97c-440d-9533-4bcbd62dfb00", 
+        "permitted_slices": [], 
+        "labels": "public-net", 
+        "guaranteed_bandwidth": 0, 
+        "permit_all_slices": false, 
+        "template": 1, 
+        "owner": 10, 
+        "backend_status": "Provisioning in progress", 
+        "ports": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 12, 
+    "model": "core.network", 
+    "fields": {
+        "router_id": "", 
+        "subnet": "", 
+        "updated": "2013-12-13T21:51:04.425Z", 
+        "subnet_id": "", 
+        "name": "Stork package distribution", 
+        "created": "2013-12-13T21:51:04.425Z", 
+        "deleted": false, 
+        "network_id": "", 
+        "permitted_slices": [], 
+        "labels": "", 
+        "guaranteed_bandwidth": 0, 
+        "permit_all_slices": true, 
+        "template": 4, 
+        "owner": 11, 
+        "backend_status": "Provisioning in progress", 
+        "ports": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 13, 
+    "model": "core.network", 
+    "fields": {
+        "router_id": "", 
+        "subnet": "", 
+        "updated": "2013-12-13T21:53:07.783Z", 
+        "subnet_id": "", 
+        "name": "Owl Data Collection", 
+        "created": "2013-12-13T21:53:07.783Z", 
+        "deleted": false, 
+        "network_id": "", 
+        "permitted_slices": [], 
+        "labels": "", 
+        "guaranteed_bandwidth": 0, 
+        "permit_all_slices": true, 
+        "template": 4, 
+        "owner": 12, 
+        "backend_status": "Provisioning in progress", 
+        "ports": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 14, 
+    "model": "core.network", 
+    "fields": {
+        "router_id": "", 
+        "subnet": "", 
+        "updated": "2013-12-13T21:55:51.703Z", 
+        "subnet_id": "", 
+        "name": "Hadoop Shared Filesystem Access", 
+        "created": "2013-12-13T21:55:51.703Z", 
+        "deleted": false, 
+        "network_id": "", 
+        "permitted_slices": [], 
+        "labels": "", 
+        "guaranteed_bandwidth": 0, 
+        "permit_all_slices": true, 
+        "template": 4, 
+        "owner": 13, 
+        "backend_status": "Provisioning in progress", 
+        "ports": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 15, 
+    "model": "core.network", 
+    "fields": {
+        "router_id": "", 
+        "subnet": "", 
+        "updated": "2013-12-13T21:57:38.995Z", 
+        "subnet_id": "", 
+        "name": "test-1-public", 
+        "created": "2013-12-13T21:57:38.995Z", 
+        "deleted": false, 
+        "network_id": "", 
+        "permitted_slices": [], 
+        "labels": "", 
+        "guaranteed_bandwidth": 0, 
+        "permit_all_slices": false, 
+        "template": 1, 
+        "owner": 14, 
+        "backend_status": "Provisioning in progress", 
+        "ports": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 16, 
+    "model": "core.network", 
+    "fields": {
+        "router_id": "", 
+        "subnet": "", 
+        "updated": "2013-12-13T22:00:40.549Z", 
+        "subnet_id": "", 
+        "name": "test-slice-2-nat", 
+        "created": "2013-12-13T22:00:40.549Z", 
+        "deleted": false, 
+        "network_id": "", 
+        "permitted_slices": [], 
+        "labels": "", 
+        "guaranteed_bandwidth": 0, 
+        "permit_all_slices": false, 
+        "template": 3, 
+        "owner": 15, 
+        "backend_status": "Provisioning in progress", 
+        "ports": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 17, 
+    "model": "core.network", 
+    "fields": {
+        "router_id": "", 
+        "subnet": "", 
+        "updated": "2013-12-18T22:05:09.944Z", 
+        "subnet_id": "", 
+        "name": "infrastructure-private", 
+        "created": "2013-12-18T22:05:09.944Z", 
+        "deleted": false, 
+        "network_id": "", 
+        "permitted_slices": [], 
+        "labels": "", 
+        "guaranteed_bandwidth": 0, 
+        "permit_all_slices": false, 
+        "template": 4, 
+        "owner": 10, 
+        "backend_status": "Provisioning in progress", 
+        "ports": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 18, 
+    "model": "core.network", 
+    "fields": {
+        "router_id": "", 
+        "subnet": "", 
+        "updated": "2013-12-18T22:05:50.112Z", 
+        "subnet_id": "", 
+        "name": "infrastructure-public", 
+        "created": "2013-12-18T22:05:50.112Z", 
+        "deleted": false, 
+        "network_id": "", 
+        "permitted_slices": [], 
+        "labels": "", 
+        "guaranteed_bandwidth": 0, 
+        "permit_all_slices": false, 
+        "template": 1, 
+        "owner": 10, 
+        "backend_status": "Provisioning in progress", 
+        "ports": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 19, 
+    "model": "core.network", 
+    "fields": {
+        "router_id": "", 
+        "subnet": "", 
+        "updated": "2013-12-18T22:13:17.310Z", 
+        "subnet_id": "", 
+        "name": "dnsdemux-private", 
+        "created": "2013-12-18T22:13:17.310Z", 
+        "deleted": false, 
+        "network_id": "", 
+        "permitted_slices": [], 
+        "labels": "", 
+        "guaranteed_bandwidth": 0, 
+        "permit_all_slices": false, 
+        "template": 4, 
+        "owner": 9, 
+        "backend_status": "Provisioning in progress", 
+        "ports": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 20, 
+    "model": "core.network", 
+    "fields": {
+        "router_id": "", 
+        "subnet": "", 
+        "updated": "2013-12-18T22:13:38.194Z", 
+        "subnet_id": "", 
+        "name": "dnsdemux-public", 
+        "created": "2013-12-18T22:13:38.194Z", 
+        "deleted": false, 
+        "network_id": "", 
+        "permitted_slices": [], 
+        "labels": "", 
+        "guaranteed_bandwidth": 0, 
+        "permit_all_slices": false, 
+        "template": 1, 
+        "owner": 9, 
+        "backend_status": "Provisioning in progress", 
+        "ports": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 21, 
+    "model": "core.network", 
+    "fields": {
+        "router_id": "", 
+        "subnet": "", 
+        "updated": "2013-12-18T22:16:19.797Z", 
+        "subnet_id": "", 
+        "name": "DnsRedir-private", 
+        "created": "2013-12-18T22:16:19.797Z", 
+        "deleted": false, 
+        "network_id": "", 
+        "permitted_slices": [], 
+        "labels": "", 
+        "guaranteed_bandwidth": 0, 
+        "permit_all_slices": false, 
+        "template": 4, 
+        "owner": 8, 
+        "backend_status": "Provisioning in progress", 
+        "ports": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 22, 
+    "model": "core.network", 
+    "fields": {
+        "router_id": "", 
+        "subnet": "", 
+        "updated": "2013-12-18T22:16:38.335Z", 
+        "subnet_id": "", 
+        "name": "DnsRedir-public", 
+        "created": "2013-12-18T22:16:38.335Z", 
+        "deleted": false, 
+        "network_id": "", 
+        "permitted_slices": [], 
+        "labels": "", 
+        "guaranteed_bandwidth": 0, 
+        "permit_all_slices": false, 
+        "template": 1, 
+        "owner": 8, 
+        "backend_status": "Provisioning in progress", 
+        "ports": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 23, 
+    "model": "core.network", 
+    "fields": {
+        "router_id": "", 
+        "subnet": "", 
+        "updated": "2013-12-19T00:13:55.598Z", 
+        "subnet_id": "", 
+        "name": "HyperCache-private", 
+        "created": "2013-12-18T22:24:19.109Z", 
+        "deleted": false, 
+        "network_id": "", 
+        "permitted_slices": [
+            6, 
+            8
+        ], 
+        "labels": "", 
+        "guaranteed_bandwidth": 0, 
+        "permit_all_slices": false, 
+        "template": 4, 
+        "owner": 4, 
+        "backend_status": "Provisioning in progress", 
+        "ports": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 24, 
+    "model": "core.network", 
+    "fields": {
+        "router_id": "", 
+        "subnet": "", 
+        "updated": "2013-12-18T22:24:38.066Z", 
+        "subnet_id": "", 
+        "name": "HyperCache-public", 
+        "created": "2013-12-18T22:24:38.066Z", 
+        "deleted": false, 
+        "network_id": "", 
+        "permitted_slices": [], 
+        "labels": "", 
+        "guaranteed_bandwidth": 0, 
+        "permit_all_slices": false, 
+        "template": 1, 
+        "owner": 4, 
+        "backend_status": "Provisioning in progress", 
+        "ports": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 25, 
+    "model": "core.network", 
+    "fields": {
+        "router_id": "", 
+        "subnet": "", 
+        "updated": "2013-12-18T22:26:46.435Z", 
+        "subnet_id": "", 
+        "name": "Syndicate-private", 
+        "created": "2013-12-18T22:26:46.435Z", 
+        "deleted": false, 
+        "network_id": "", 
+        "permitted_slices": [], 
+        "labels": "", 
+        "guaranteed_bandwidth": 0, 
+        "permit_all_slices": false, 
+        "template": 4, 
+        "owner": 6, 
+        "backend_status": "Provisioning in progress", 
+        "ports": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 26, 
+    "model": "core.network", 
+    "fields": {
+        "router_id": "", 
+        "subnet": "", 
+        "updated": "2013-12-18T22:27:12.647Z", 
+        "subnet_id": "", 
+        "name": "Syndicate-public", 
+        "created": "2013-12-18T22:27:12.647Z", 
+        "deleted": false, 
+        "network_id": "", 
+        "permitted_slices": [], 
+        "labels": "", 
+        "guaranteed_bandwidth": 0, 
+        "permit_all_slices": false, 
+        "template": 1, 
+        "owner": 6, 
+        "backend_status": "Provisioning in progress", 
+        "ports": "", 
+        "enacted": null
+    }
+},
+{
+    "pk": 1, 
+    "model": "core.networkslice", 
+    "fields": {
+        "updated": "2013-12-13T21:51:09.711Z", 
+        "slice": 11, 
+        "network": 12, 
+        "created": "2013-12-13T21:51:09.711Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 2, 
+    "model": "core.networkslice", 
+    "fields": {
+        "updated": "2013-12-13T21:53:15.909Z", 
+        "slice": 12, 
+        "network": 13, 
+        "created": "2013-12-13T21:53:15.909Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3, 
+    "model": "core.networkslice", 
+    "fields": {
+        "updated": "2013-12-13T21:53:15.914Z", 
+        "slice": 12, 
+        "network": 12, 
+        "created": "2013-12-13T21:53:15.914Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 4, 
+    "model": "core.networkslice", 
+    "fields": {
+        "updated": "2013-12-13T21:56:04.235Z", 
+        "slice": 13, 
+        "network": 14, 
+        "created": "2013-12-13T21:56:04.235Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 5, 
+    "model": "core.networkslice", 
+    "fields": {
+        "updated": "2013-12-13T21:56:04.241Z", 
+        "slice": 13, 
+        "network": 12, 
+        "created": "2013-12-13T21:56:04.241Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 6, 
+    "model": "core.networkslice", 
+    "fields": {
+        "updated": "2013-12-13T21:56:04.246Z", 
+        "slice": 13, 
+        "network": 13, 
+        "created": "2013-12-13T21:56:04.246Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 7, 
+    "model": "core.networkslice", 
+    "fields": {
+        "updated": "2013-12-13T21:57:56.826Z", 
+        "slice": 14, 
+        "network": 15, 
+        "created": "2013-12-13T21:57:56.826Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 8, 
+    "model": "core.networkslice", 
+    "fields": {
+        "updated": "2013-12-13T21:57:56.831Z", 
+        "slice": 14, 
+        "network": 13, 
+        "created": "2013-12-13T21:57:56.831Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 9, 
+    "model": "core.networkslice", 
+    "fields": {
+        "updated": "2013-12-13T21:57:56.836Z", 
+        "slice": 14, 
+        "network": 12, 
+        "created": "2013-12-13T21:57:56.836Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 10, 
+    "model": "core.networkslice", 
+    "fields": {
+        "updated": "2013-12-13T22:01:14.038Z", 
+        "slice": 15, 
+        "network": 16, 
+        "created": "2013-12-13T22:01:14.038Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 11, 
+    "model": "core.networkslice", 
+    "fields": {
+        "updated": "2013-12-13T22:01:14.043Z", 
+        "slice": 15, 
+        "network": 14, 
+        "created": "2013-12-13T22:01:14.043Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 12, 
+    "model": "core.networkslice", 
+    "fields": {
+        "updated": "2013-12-18T22:06:00.381Z", 
+        "slice": 10, 
+        "network": 17, 
+        "created": "2013-12-18T22:06:00.381Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 13, 
+    "model": "core.networkslice", 
+    "fields": {
+        "updated": "2013-12-18T22:06:00.386Z", 
+        "slice": 10, 
+        "network": 18, 
+        "created": "2013-12-18T22:06:00.386Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 14, 
+    "model": "core.networkslice", 
+    "fields": {
+        "updated": "2013-12-18T22:13:42.177Z", 
+        "slice": 9, 
+        "network": 19, 
+        "created": "2013-12-18T22:13:42.177Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 15, 
+    "model": "core.networkslice", 
+    "fields": {
+        "updated": "2013-12-18T22:13:42.183Z", 
+        "slice": 9, 
+        "network": 20, 
+        "created": "2013-12-18T22:13:42.183Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 16, 
+    "model": "core.networkslice", 
+    "fields": {
+        "updated": "2013-12-18T22:16:41.007Z", 
+        "slice": 8, 
+        "network": 21, 
+        "created": "2013-12-18T22:16:41.007Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 17, 
+    "model": "core.networkslice", 
+    "fields": {
+        "updated": "2013-12-18T22:16:41.013Z", 
+        "slice": 8, 
+        "network": 22, 
+        "created": "2013-12-18T22:16:41.013Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 18, 
+    "model": "core.networkslice", 
+    "fields": {
+        "updated": "2013-12-18T22:24:44.997Z", 
+        "slice": 4, 
+        "network": 23, 
+        "created": "2013-12-18T22:24:44.997Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 19, 
+    "model": "core.networkslice", 
+    "fields": {
+        "updated": "2013-12-18T22:24:45.003Z", 
+        "slice": 4, 
+        "network": 24, 
+        "created": "2013-12-18T22:24:45.003Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 20, 
+    "model": "core.networkslice", 
+    "fields": {
+        "updated": "2013-12-18T22:27:16.953Z", 
+        "slice": 6, 
+        "network": 25, 
+        "created": "2013-12-18T22:27:16.953Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 21, 
+    "model": "core.networkslice", 
+    "fields": {
+        "updated": "2013-12-18T22:27:16.959Z", 
+        "slice": 6, 
+        "network": 26, 
+        "created": "2013-12-18T22:27:16.959Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 22, 
+    "model": "core.networkslice", 
+    "fields": {
+        "updated": "2013-12-19T00:14:36.949Z", 
+        "slice": 6, 
+        "network": 23, 
+        "created": "2013-12-19T00:14:36.949Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 23, 
+    "model": "core.networkslice", 
+    "fields": {
+        "updated": "2013-12-19T00:15:11.362Z", 
+        "slice": 8, 
+        "network": 23, 
+        "created": "2013-12-19T00:15:11.362Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 1, 
+    "model": "core.networkparametertype", 
+    "fields": {
+        "updated": "2013-12-09T14:43:25.664Z", 
+        "name": "allocation-pool-end", 
+        "created": "2013-12-09T14:43:25.664Z", 
+        "deleted": false, 
+        "description": "End of IPv4 address allocation pool", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 2, 
+    "model": "core.networkparametertype", 
+    "fields": {
+        "updated": "2013-12-09T14:43:45.564Z", 
+        "name": "allocation-pool-start", 
+        "created": "2013-12-09T14:43:45.564Z", 
+        "deleted": false, 
+        "description": "Start of IPv4 address allocation pool", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3, 
+    "model": "core.networkparametertype", 
+    "fields": {
+        "updated": "2013-12-09T14:44:05.513Z", 
+        "name": "cidr", 
+        "created": "2013-12-09T14:44:05.513Z", 
+        "deleted": false, 
+        "description": "CIDR block for network", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 14, 
+    "model": "core.account", 
+    "fields": {
+        "updated": "2013-12-18T21:29:00.470Z", 
+        "created": "2013-12-18T21:29:00.470Z", 
+        "deleted": false, 
+        "site": 10, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 15, 
+    "model": "core.account", 
+    "fields": {
+        "updated": "2013-12-18T21:29:00.495Z", 
+        "created": "2013-12-18T21:29:00.495Z", 
+        "deleted": false, 
+        "site": 22, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 16, 
+    "model": "core.account", 
+    "fields": {
+        "updated": "2013-12-18T21:29:00.502Z", 
+        "created": "2013-12-18T21:29:00.502Z", 
+        "deleted": false, 
+        "site": 24, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 63, 
+    "model": "core.invoice", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.421Z", 
+        "created": "2013-12-18T21:29:16.421Z", 
+        "deleted": false, 
+        "account": 14, 
+        "date": "2013-11-18T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 64, 
+    "model": "core.invoice", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.434Z", 
+        "created": "2013-12-18T21:29:16.434Z", 
+        "deleted": false, 
+        "account": 14, 
+        "date": "2013-11-24T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 65, 
+    "model": "core.invoice", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.229Z", 
+        "created": "2013-12-18T21:29:17.229Z", 
+        "deleted": false, 
+        "account": 14, 
+        "date": "2013-12-01T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 66, 
+    "model": "core.invoice", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.213Z", 
+        "created": "2013-12-18T21:29:18.212Z", 
+        "deleted": false, 
+        "account": 14, 
+        "date": "2013-12-08T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 67, 
+    "model": "core.invoice", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.091Z", 
+        "created": "2013-12-18T21:29:19.091Z", 
+        "deleted": false, 
+        "account": 14, 
+        "date": "2013-12-15T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 68, 
+    "model": "core.invoice", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.175Z", 
+        "created": "2013-12-18T21:29:20.175Z", 
+        "deleted": false, 
+        "account": 15, 
+        "date": "2013-11-18T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 69, 
+    "model": "core.invoice", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.193Z", 
+        "created": "2013-12-18T21:29:20.193Z", 
+        "deleted": false, 
+        "account": 15, 
+        "date": "2013-11-24T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 70, 
+    "model": "core.invoice", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.239Z", 
+        "created": "2013-12-18T21:29:22.239Z", 
+        "deleted": false, 
+        "account": 15, 
+        "date": "2013-12-01T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 71, 
+    "model": "core.invoice", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.550Z", 
+        "created": "2013-12-18T21:29:24.550Z", 
+        "deleted": false, 
+        "account": 15, 
+        "date": "2013-12-08T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 72, 
+    "model": "core.invoice", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.820Z", 
+        "created": "2013-12-18T21:29:26.820Z", 
+        "deleted": false, 
+        "account": 15, 
+        "date": "2013-12-15T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 73, 
+    "model": "core.invoice", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.206Z", 
+        "created": "2013-12-18T21:29:29.206Z", 
+        "deleted": false, 
+        "account": 16, 
+        "date": "2013-11-18T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 74, 
+    "model": "core.invoice", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.222Z", 
+        "created": "2013-12-18T21:29:29.222Z", 
+        "deleted": false, 
+        "account": 16, 
+        "date": "2013-11-24T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 75, 
+    "model": "core.invoice", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.538Z", 
+        "created": "2013-12-18T21:29:29.538Z", 
+        "deleted": false, 
+        "account": 16, 
+        "date": "2013-12-01T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 76, 
+    "model": "core.invoice", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.894Z", 
+        "created": "2013-12-18T21:29:29.894Z", 
+        "deleted": false, 
+        "account": 16, 
+        "date": "2013-12-08T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 77, 
+    "model": "core.invoice", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.251Z", 
+        "created": "2013-12-18T21:29:30.251Z", 
+        "deleted": false, 
+        "account": 16, 
+        "date": "2013-12-15T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 104, 
+    "model": "core.usableobject", 
+    "fields": {
+        "updated": "2013-12-18T21:29:00.529Z", 
+        "name": "node17.washington.vicci.org", 
+        "created": "2013-12-18T21:29:00.529Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 105, 
+    "model": "core.usableobject", 
+    "fields": {
+        "updated": "2013-12-18T21:29:01.289Z", 
+        "name": "node16.washington.vicci.org", 
+        "created": "2013-12-18T21:29:01.289Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 106, 
+    "model": "core.usableobject", 
+    "fields": {
+        "updated": "2013-12-18T21:29:02.189Z", 
+        "name": "node15.washington.vicci.org", 
+        "created": "2013-12-18T21:29:02.189Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 107, 
+    "model": "core.usableobject", 
+    "fields": {
+        "updated": "2013-12-18T21:29:03.178Z", 
+        "name": "node14.washington.vicci.org", 
+        "created": "2013-12-18T21:29:03.178Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 108, 
+    "model": "core.usableobject", 
+    "fields": {
+        "updated": "2013-12-18T21:29:03.942Z", 
+        "name": "node70.princeton.vicci.org", 
+        "created": "2013-12-18T21:29:03.942Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 109, 
+    "model": "core.usableobject", 
+    "fields": {
+        "updated": "2013-12-18T21:29:04.702Z", 
+        "name": "node69.princeton.vicci.org", 
+        "created": "2013-12-18T21:29:04.702Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 110, 
+    "model": "core.usableobject", 
+    "fields": {
+        "updated": "2013-12-18T21:29:05.547Z", 
+        "name": "node68.princeton.vicci.org", 
+        "created": "2013-12-18T21:29:05.547Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 111, 
+    "model": "core.usableobject", 
+    "fields": {
+        "updated": "2013-12-18T21:29:06.336Z", 
+        "name": "node67.princeton.vicci.org", 
+        "created": "2013-12-18T21:29:06.336Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 112, 
+    "model": "core.usableobject", 
+    "fields": {
+        "updated": "2013-12-18T21:29:07.101Z", 
+        "name": "node30.princeton.vicci.org", 
+        "created": "2013-12-18T21:29:07.101Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 113, 
+    "model": "core.usableobject", 
+    "fields": {
+        "updated": "2013-12-18T21:29:09.453Z", 
+        "name": "node55.stanford.vicci.org", 
+        "created": "2013-12-18T21:29:09.453Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 114, 
+    "model": "core.usableobject", 
+    "fields": {
+        "updated": "2013-12-18T21:29:10.216Z", 
+        "name": "node12.princeton.vicci.org", 
+        "created": "2013-12-18T21:29:10.216Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 115, 
+    "model": "core.usableobject", 
+    "fields": {
+        "updated": "2013-12-18T21:29:10.975Z", 
+        "name": "node20.washington.vicci.org", 
+        "created": "2013-12-18T21:29:10.975Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 116, 
+    "model": "core.usableobject", 
+    "fields": {
+        "updated": "2013-12-18T21:29:11.729Z", 
+        "name": "node1.stanford.vicci.org", 
+        "created": "2013-12-18T21:29:11.729Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 117, 
+    "model": "core.usableobject", 
+    "fields": {
+        "updated": "2013-12-18T21:29:12.494Z", 
+        "name": "node33.princeton.vicci.org", 
+        "created": "2013-12-18T21:29:12.494Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 118, 
+    "model": "core.usableobject", 
+    "fields": {
+        "updated": "2013-12-18T21:29:13.329Z", 
+        "name": "node15.princeton.vicci.org", 
+        "created": "2013-12-18T21:29:13.329Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 119, 
+    "model": "core.usableobject", 
+    "fields": {
+        "updated": "2013-12-18T21:29:14.083Z", 
+        "name": "node23.princeton.vicci.org", 
+        "created": "2013-12-18T21:29:14.083Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 120, 
+    "model": "core.usableobject", 
+    "fields": {
+        "updated": "2013-12-18T21:29:14.847Z", 
+        "name": "node10.princeton.vicci.org", 
+        "created": "2013-12-18T21:29:14.847Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 121, 
+    "model": "core.usableobject", 
+    "fields": {
+        "updated": "2013-12-18T21:29:15.609Z", 
+        "name": "node13.princeton.vicci.org", 
+        "created": "2013-12-18T21:29:15.609Z", 
+        "deleted": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 37, 
+    "model": "core.payment", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.973Z", 
+        "created": "2013-12-18T21:29:19.973Z", 
+        "deleted": false, 
+        "account": 14, 
+        "amount": 0.2968, 
+        "date": "2013-12-03T02:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 38, 
+    "model": "core.payment", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.979Z", 
+        "created": "2013-12-18T21:29:19.979Z", 
+        "deleted": false, 
+        "account": 14, 
+        "amount": 21.14, 
+        "date": "2013-12-09T02:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 39, 
+    "model": "core.payment", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.987Z", 
+        "created": "2013-12-18T21:29:19.987Z", 
+        "deleted": false, 
+        "account": 14, 
+        "amount": 24.3768, 
+        "date": "2013-12-16T02:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 40, 
+    "model": "core.payment", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.154Z", 
+        "created": "2013-12-18T21:29:29.153Z", 
+        "deleted": false, 
+        "account": 15, 
+        "amount": 0.3024, 
+        "date": "2013-12-03T02:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 41, 
+    "model": "core.payment", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.166Z", 
+        "created": "2013-12-18T21:29:29.166Z", 
+        "deleted": false, 
+        "account": 15, 
+        "amount": 86.5536, 
+        "date": "2013-12-09T02:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 42, 
+    "model": "core.payment", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.174Z", 
+        "created": "2013-12-18T21:29:29.174Z", 
+        "deleted": false, 
+        "account": 15, 
+        "amount": 96.404, 
+        "date": "2013-12-16T02:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 43, 
+    "model": "core.payment", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.620Z", 
+        "created": "2013-12-18T21:29:30.620Z", 
+        "deleted": false, 
+        "account": 16, 
+        "amount": 0.1848, 
+        "date": "2013-12-03T02:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 44, 
+    "model": "core.payment", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.626Z", 
+        "created": "2013-12-18T21:29:30.626Z", 
+        "deleted": false, 
+        "account": 16, 
+        "amount": 8.5904, 
+        "date": "2013-12-09T02:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 45, 
+    "model": "core.payment", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.634Z", 
+        "created": "2013-12-18T21:29:30.634Z", 
+        "deleted": false, 
+        "account": 16, 
+        "amount": 10.0016, 
+        "date": "2013-12-16T02:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59761, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.186Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.540Z", 
+        "deleted": false, 
+        "amount": 0.3024, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.32, 
+        "invoice": 68, 
+        "date": "2013-11-18T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59762, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.302Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.550Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.68, 
+        "invoice": 69, 
+        "date": "2013-11-19T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59763, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.409Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.558Z", 
+        "deleted": false, 
+        "amount": 0.2016, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.88, 
+        "invoice": 69, 
+        "date": "2013-11-19T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59764, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.517Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.567Z", 
+        "deleted": false, 
+        "amount": 0.3024, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.32, 
+        "invoice": 69, 
+        "date": "2013-11-19T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59765, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.625Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.575Z", 
+        "deleted": false, 
+        "amount": 0.1848, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.64, 
+        "invoice": 69, 
+        "date": "2013-11-20T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59766, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.732Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.583Z", 
+        "deleted": false, 
+        "amount": 0.3192, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.56, 
+        "invoice": 69, 
+        "date": "2013-11-20T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59767, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.840Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.591Z", 
+        "deleted": false, 
+        "amount": 0.1512, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.16, 
+        "invoice": 69, 
+        "date": "2013-11-20T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59768, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.948Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.600Z", 
+        "deleted": false, 
+        "amount": 0.2744, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.92, 
+        "invoice": 69, 
+        "date": "2013-11-21T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59769, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.055Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.608Z", 
+        "deleted": false, 
+        "amount": 0.3248, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.64, 
+        "invoice": 69, 
+        "date": "2013-11-21T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59770, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.163Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.616Z", 
+        "deleted": false, 
+        "amount": 0.14, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.0, 
+        "invoice": 69, 
+        "date": "2013-11-21T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59771, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.271Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.625Z", 
+        "deleted": false, 
+        "amount": 0.1288, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.84, 
+        "invoice": 69, 
+        "date": "2013-11-22T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59772, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.378Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.633Z", 
+        "deleted": false, 
+        "amount": 0.336, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.8, 
+        "invoice": 69, 
+        "date": "2013-11-22T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59773, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.486Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.641Z", 
+        "deleted": false, 
+        "amount": 0.3192, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.56, 
+        "invoice": 69, 
+        "date": "2013-11-22T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59774, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.594Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.650Z", 
+        "deleted": false, 
+        "amount": 0.2184, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.12, 
+        "invoice": 69, 
+        "date": "2013-11-23T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59775, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.702Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.658Z", 
+        "deleted": false, 
+        "amount": 0.252, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.6, 
+        "invoice": 69, 
+        "date": "2013-11-23T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59776, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.809Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.666Z", 
+        "deleted": false, 
+        "amount": 0.1232, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.76, 
+        "invoice": 69, 
+        "date": "2013-11-23T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59777, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.917Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.674Z", 
+        "deleted": false, 
+        "amount": 0.1624, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.32, 
+        "invoice": 69, 
+        "date": "2013-11-24T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59778, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.025Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.683Z", 
+        "deleted": false, 
+        "amount": 0.1904, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.72, 
+        "invoice": 69, 
+        "date": "2013-11-24T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59779, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.132Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.691Z", 
+        "deleted": false, 
+        "amount": 0.1624, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.32, 
+        "invoice": 69, 
+        "date": "2013-11-24T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59780, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.248Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.699Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.16, 
+        "invoice": 70, 
+        "date": "2013-11-25T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59781, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.356Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.708Z", 
+        "deleted": false, 
+        "amount": 0.2072, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.96, 
+        "invoice": 70, 
+        "date": "2013-11-25T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59782, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.464Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.716Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.08, 
+        "invoice": 70, 
+        "date": "2013-11-25T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59783, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.613Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.724Z", 
+        "deleted": false, 
+        "amount": 0.2408, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.44, 
+        "invoice": 70, 
+        "date": "2013-11-26T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59784, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.721Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.732Z", 
+        "deleted": false, 
+        "amount": 0.3024, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.32, 
+        "invoice": 70, 
+        "date": "2013-11-26T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59785, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.828Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.741Z", 
+        "deleted": false, 
+        "amount": 0.1792, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.56, 
+        "invoice": 70, 
+        "date": "2013-11-26T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59786, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.936Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.749Z", 
+        "deleted": false, 
+        "amount": 0.1736, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.48, 
+        "invoice": 70, 
+        "date": "2013-11-27T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59787, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.043Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.757Z", 
+        "deleted": false, 
+        "amount": 0.1512, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.16, 
+        "invoice": 70, 
+        "date": "2013-11-27T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59788, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.151Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.766Z", 
+        "deleted": false, 
+        "amount": 0.1288, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.84, 
+        "invoice": 70, 
+        "date": "2013-11-27T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59789, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.259Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.774Z", 
+        "deleted": false, 
+        "amount": 0.2408, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.44, 
+        "invoice": 70, 
+        "date": "2013-11-28T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59790, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.367Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.782Z", 
+        "deleted": false, 
+        "amount": 0.1344, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.92, 
+        "invoice": 70, 
+        "date": "2013-11-28T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59791, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.474Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.790Z", 
+        "deleted": false, 
+        "amount": 0.2184, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.12, 
+        "invoice": 70, 
+        "date": "2013-11-28T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59792, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.582Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.799Z", 
+        "deleted": false, 
+        "amount": 0.308, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.4, 
+        "invoice": 70, 
+        "date": "2013-11-29T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59793, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.690Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.807Z", 
+        "deleted": false, 
+        "amount": 0.2968, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.24, 
+        "invoice": 70, 
+        "date": "2013-11-29T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59794, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.797Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.815Z", 
+        "deleted": false, 
+        "amount": 0.2352, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.36, 
+        "invoice": 70, 
+        "date": "2013-11-29T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59795, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.905Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.823Z", 
+        "deleted": false, 
+        "amount": 0.1904, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.72, 
+        "invoice": 70, 
+        "date": "2013-11-30T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59796, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.013Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.832Z", 
+        "deleted": false, 
+        "amount": 0.336, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.8, 
+        "invoice": 70, 
+        "date": "2013-11-30T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59797, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.120Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.840Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.68, 
+        "invoice": 70, 
+        "date": "2013-11-30T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59798, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.228Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.848Z", 
+        "deleted": false, 
+        "amount": 0.2968, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.24, 
+        "invoice": 70, 
+        "date": "2013-12-01T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59799, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.336Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.856Z", 
+        "deleted": false, 
+        "amount": 0.1288, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.84, 
+        "invoice": 70, 
+        "date": "2013-12-01T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59800, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.443Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.865Z", 
+        "deleted": false, 
+        "amount": 0.2016, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.88, 
+        "invoice": 70, 
+        "date": "2013-12-01T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59801, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.559Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.873Z", 
+        "deleted": false, 
+        "amount": 0.1288, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.84, 
+        "invoice": 71, 
+        "date": "2013-12-02T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59802, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.667Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.881Z", 
+        "deleted": false, 
+        "amount": 0.2744, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.92, 
+        "invoice": 71, 
+        "date": "2013-12-02T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59803, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.775Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.890Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.16, 
+        "invoice": 71, 
+        "date": "2013-12-02T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59804, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.883Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.898Z", 
+        "deleted": false, 
+        "amount": 0.168, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.4, 
+        "invoice": 71, 
+        "date": "2013-12-03T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59805, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.990Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.906Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 71, 
+        "date": "2013-12-03T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59806, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.098Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.915Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 71, 
+        "date": "2013-12-03T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59807, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.206Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.923Z", 
+        "deleted": false, 
+        "amount": 0.168, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.4, 
+        "invoice": 71, 
+        "date": "2013-12-04T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59808, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.313Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.931Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.68, 
+        "invoice": 71, 
+        "date": "2013-12-04T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59809, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.421Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.939Z", 
+        "deleted": false, 
+        "amount": 0.2576, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.68, 
+        "invoice": 71, 
+        "date": "2013-12-04T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59810, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.529Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.948Z", 
+        "deleted": false, 
+        "amount": 0.14, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.0, 
+        "invoice": 71, 
+        "date": "2013-12-05T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59811, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.637Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.956Z", 
+        "deleted": false, 
+        "amount": 0.2576, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.68, 
+        "invoice": 71, 
+        "date": "2013-12-05T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59812, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.744Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.964Z", 
+        "deleted": false, 
+        "amount": 0.2128, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.04, 
+        "invoice": 71, 
+        "date": "2013-12-05T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59813, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.852Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.973Z", 
+        "deleted": false, 
+        "amount": 0.2576, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.68, 
+        "invoice": 71, 
+        "date": "2013-12-06T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59814, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.959Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.981Z", 
+        "deleted": false, 
+        "amount": 0.2744, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.92, 
+        "invoice": 71, 
+        "date": "2013-12-06T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59815, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.067Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.989Z", 
+        "deleted": false, 
+        "amount": 0.2744, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.92, 
+        "invoice": 71, 
+        "date": "2013-12-06T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59816, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.175Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:00.997Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.16, 
+        "invoice": 71, 
+        "date": "2013-12-07T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59817, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.283Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.006Z", 
+        "deleted": false, 
+        "amount": 0.14, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.0, 
+        "invoice": 71, 
+        "date": "2013-12-07T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59818, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.390Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.014Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.68, 
+        "invoice": 71, 
+        "date": "2013-12-07T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59819, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.498Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.022Z", 
+        "deleted": false, 
+        "amount": 0.2744, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.92, 
+        "invoice": 71, 
+        "date": "2013-12-08T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59820, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.606Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.031Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 71, 
+        "date": "2013-12-08T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59821, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.713Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.039Z", 
+        "deleted": false, 
+        "amount": 0.336, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.8, 
+        "invoice": 71, 
+        "date": "2013-12-08T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59822, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.829Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.047Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.16, 
+        "invoice": 72, 
+        "date": "2013-12-09T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59823, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.937Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.055Z", 
+        "deleted": false, 
+        "amount": 0.2128, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.04, 
+        "invoice": 72, 
+        "date": "2013-12-09T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59824, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.045Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.064Z", 
+        "deleted": false, 
+        "amount": 0.1848, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.64, 
+        "invoice": 72, 
+        "date": "2013-12-09T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59825, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.152Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.072Z", 
+        "deleted": false, 
+        "amount": 0.2632, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.76, 
+        "invoice": 72, 
+        "date": "2013-12-10T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59826, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.260Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.080Z", 
+        "deleted": false, 
+        "amount": 0.1288, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.84, 
+        "invoice": 72, 
+        "date": "2013-12-10T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59827, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.368Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.088Z", 
+        "deleted": false, 
+        "amount": 0.2744, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.92, 
+        "invoice": 72, 
+        "date": "2013-12-10T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59828, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.475Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.097Z", 
+        "deleted": false, 
+        "amount": 0.1848, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.64, 
+        "invoice": 72, 
+        "date": "2013-12-11T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59829, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.641Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.105Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.08, 
+        "invoice": 72, 
+        "date": "2013-12-11T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59830, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.749Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.113Z", 
+        "deleted": false, 
+        "amount": 0.2296, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.28, 
+        "invoice": 72, 
+        "date": "2013-12-11T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59831, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.856Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.122Z", 
+        "deleted": false, 
+        "amount": 0.3024, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.32, 
+        "invoice": 72, 
+        "date": "2013-12-12T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59832, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.964Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.130Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.16, 
+        "invoice": 72, 
+        "date": "2013-12-12T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59833, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.072Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.138Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 72, 
+        "date": "2013-12-12T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59834, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.180Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.147Z", 
+        "deleted": false, 
+        "amount": 0.308, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.4, 
+        "invoice": 72, 
+        "date": "2013-12-13T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59835, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.287Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.155Z", 
+        "deleted": false, 
+        "amount": 0.1848, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.64, 
+        "invoice": 72, 
+        "date": "2013-12-13T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59836, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.395Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.163Z", 
+        "deleted": false, 
+        "amount": 0.2688, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.84, 
+        "invoice": 72, 
+        "date": "2013-12-13T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59837, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.503Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.171Z", 
+        "deleted": false, 
+        "amount": 0.1344, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.92, 
+        "invoice": 72, 
+        "date": "2013-12-14T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59838, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.610Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.180Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 72, 
+        "date": "2013-12-14T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59839, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.718Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.188Z", 
+        "deleted": false, 
+        "amount": 0.3024, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.32, 
+        "invoice": 72, 
+        "date": "2013-12-14T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59840, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.826Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.196Z", 
+        "deleted": false, 
+        "amount": 0.308, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.4, 
+        "invoice": 72, 
+        "date": "2013-12-15T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59841, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.933Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.205Z", 
+        "deleted": false, 
+        "amount": 0.308, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.4, 
+        "invoice": 72, 
+        "date": "2013-12-15T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59842, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.041Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.213Z", 
+        "deleted": false, 
+        "amount": 0.2576, 
+        "object": 104, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.68, 
+        "invoice": 72, 
+        "date": "2013-12-15T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59843, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:01.221Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.221Z", 
+        "deleted": false, 
+        "amount": 0.196, 
+        "object": 104, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 2.8, 
+        "invoice": null, 
+        "date": "2013-12-16T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59844, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:01.230Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.229Z", 
+        "deleted": false, 
+        "amount": 0.168, 
+        "object": 104, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 2.4, 
+        "invoice": null, 
+        "date": "2013-12-16T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59845, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:01.238Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.238Z", 
+        "deleted": false, 
+        "amount": 0.2576, 
+        "object": 104, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 3.68, 
+        "invoice": null, 
+        "date": "2013-12-16T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59846, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:01.246Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.246Z", 
+        "deleted": false, 
+        "amount": 0.168, 
+        "object": 104, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 2.4, 
+        "invoice": null, 
+        "date": "2013-12-17T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59847, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:01.254Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.254Z", 
+        "deleted": false, 
+        "amount": 0.3248, 
+        "object": 104, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 4.64, 
+        "invoice": null, 
+        "date": "2013-12-17T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59848, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:01.263Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.263Z", 
+        "deleted": false, 
+        "amount": 0.28, 
+        "object": 104, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 4.0, 
+        "invoice": null, 
+        "date": "2013-12-17T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59849, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:01.271Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.271Z", 
+        "deleted": false, 
+        "amount": 0.28, 
+        "object": 104, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 4.0, 
+        "invoice": null, 
+        "date": "2013-12-18T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59850, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:01.279Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.279Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 104, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 4.72, 
+        "invoice": null, 
+        "date": "2013-12-18T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59851, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.202Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.294Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.08, 
+        "invoice": 69, 
+        "date": "2013-11-18T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59852, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.310Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.304Z", 
+        "deleted": false, 
+        "amount": 0.2352, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.36, 
+        "invoice": 69, 
+        "date": "2013-11-19T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59853, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.417Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.312Z", 
+        "deleted": false, 
+        "amount": 0.3192, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.56, 
+        "invoice": 69, 
+        "date": "2013-11-19T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59854, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.525Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.320Z", 
+        "deleted": false, 
+        "amount": 0.2464, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.52, 
+        "invoice": 69, 
+        "date": "2013-11-19T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59855, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.633Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.329Z", 
+        "deleted": false, 
+        "amount": 0.2184, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.12, 
+        "invoice": 69, 
+        "date": "2013-11-20T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59856, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.741Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.337Z", 
+        "deleted": false, 
+        "amount": 0.168, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.4, 
+        "invoice": 69, 
+        "date": "2013-11-20T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59857, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.848Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.345Z", 
+        "deleted": false, 
+        "amount": 0.1792, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.56, 
+        "invoice": 69, 
+        "date": "2013-11-20T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59858, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.956Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.353Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.16, 
+        "invoice": 69, 
+        "date": "2013-11-21T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59859, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.064Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.362Z", 
+        "deleted": false, 
+        "amount": 0.2184, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.12, 
+        "invoice": 69, 
+        "date": "2013-11-21T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59860, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.171Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.370Z", 
+        "deleted": false, 
+        "amount": 0.14, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.0, 
+        "invoice": 69, 
+        "date": "2013-11-21T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59861, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.279Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.378Z", 
+        "deleted": false, 
+        "amount": 0.3248, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.64, 
+        "invoice": 69, 
+        "date": "2013-11-22T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59862, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.387Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.387Z", 
+        "deleted": false, 
+        "amount": 0.1904, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.72, 
+        "invoice": 69, 
+        "date": "2013-11-22T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59863, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.494Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.395Z", 
+        "deleted": false, 
+        "amount": 0.2632, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.76, 
+        "invoice": 69, 
+        "date": "2013-11-22T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59864, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.602Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.403Z", 
+        "deleted": false, 
+        "amount": 0.336, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.8, 
+        "invoice": 69, 
+        "date": "2013-11-23T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59865, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.710Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.412Z", 
+        "deleted": false, 
+        "amount": 0.2688, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.84, 
+        "invoice": 69, 
+        "date": "2013-11-23T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59866, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.818Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.420Z", 
+        "deleted": false, 
+        "amount": 0.2352, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.36, 
+        "invoice": 69, 
+        "date": "2013-11-23T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59867, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.925Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.428Z", 
+        "deleted": false, 
+        "amount": 0.2128, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.04, 
+        "invoice": 69, 
+        "date": "2013-11-24T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59868, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.033Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.436Z", 
+        "deleted": false, 
+        "amount": 0.196, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.8, 
+        "invoice": 69, 
+        "date": "2013-11-24T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59869, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.141Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.445Z", 
+        "deleted": false, 
+        "amount": 0.1792, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.56, 
+        "invoice": 69, 
+        "date": "2013-11-24T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59870, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.257Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.453Z", 
+        "deleted": false, 
+        "amount": 0.1288, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.84, 
+        "invoice": 70, 
+        "date": "2013-11-25T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59871, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.364Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.461Z", 
+        "deleted": false, 
+        "amount": 0.1736, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.48, 
+        "invoice": 70, 
+        "date": "2013-11-25T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59872, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.472Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.470Z", 
+        "deleted": false, 
+        "amount": 0.112, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.6, 
+        "invoice": 70, 
+        "date": "2013-11-25T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59873, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.621Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.478Z", 
+        "deleted": false, 
+        "amount": 0.2128, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.04, 
+        "invoice": 70, 
+        "date": "2013-11-26T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59874, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.729Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.486Z", 
+        "deleted": false, 
+        "amount": 0.308, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.4, 
+        "invoice": 70, 
+        "date": "2013-11-26T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59875, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.836Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.494Z", 
+        "deleted": false, 
+        "amount": 0.1512, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.16, 
+        "invoice": 70, 
+        "date": "2013-11-26T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59876, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.944Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.503Z", 
+        "deleted": false, 
+        "amount": 0.112, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.6, 
+        "invoice": 70, 
+        "date": "2013-11-27T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59877, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.052Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.511Z", 
+        "deleted": false, 
+        "amount": 0.308, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.4, 
+        "invoice": 70, 
+        "date": "2013-11-27T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59878, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.160Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.519Z", 
+        "deleted": false, 
+        "amount": 0.2072, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.96, 
+        "invoice": 70, 
+        "date": "2013-11-27T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59879, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.267Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.528Z", 
+        "deleted": false, 
+        "amount": 0.28, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.0, 
+        "invoice": 70, 
+        "date": "2013-11-28T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59880, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.375Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.536Z", 
+        "deleted": false, 
+        "amount": 0.1792, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.56, 
+        "invoice": 70, 
+        "date": "2013-11-28T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59881, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.483Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.544Z", 
+        "deleted": false, 
+        "amount": 0.224, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.2, 
+        "invoice": 70, 
+        "date": "2013-11-28T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59882, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.590Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.552Z", 
+        "deleted": false, 
+        "amount": 0.1568, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.24, 
+        "invoice": 70, 
+        "date": "2013-11-29T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59883, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.698Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.561Z", 
+        "deleted": false, 
+        "amount": 0.2968, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.24, 
+        "invoice": 70, 
+        "date": "2013-11-29T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59884, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.806Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.569Z", 
+        "deleted": false, 
+        "amount": 0.1232, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.76, 
+        "invoice": 70, 
+        "date": "2013-11-29T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59885, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.913Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.577Z", 
+        "deleted": false, 
+        "amount": 0.2352, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.36, 
+        "invoice": 70, 
+        "date": "2013-11-30T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59886, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.021Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.586Z", 
+        "deleted": false, 
+        "amount": 0.1736, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.48, 
+        "invoice": 70, 
+        "date": "2013-11-30T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59887, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.129Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.594Z", 
+        "deleted": false, 
+        "amount": 0.196, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.8, 
+        "invoice": 70, 
+        "date": "2013-11-30T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59888, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.236Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.602Z", 
+        "deleted": false, 
+        "amount": 0.1344, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.92, 
+        "invoice": 70, 
+        "date": "2013-12-01T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59889, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.344Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.610Z", 
+        "deleted": false, 
+        "amount": 0.1904, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.72, 
+        "invoice": 70, 
+        "date": "2013-12-01T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59890, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.452Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.619Z", 
+        "deleted": false, 
+        "amount": 0.2352, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.36, 
+        "invoice": 70, 
+        "date": "2013-12-01T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59891, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.568Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.627Z", 
+        "deleted": false, 
+        "amount": 0.2072, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.96, 
+        "invoice": 71, 
+        "date": "2013-12-02T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59892, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.676Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.635Z", 
+        "deleted": false, 
+        "amount": 0.2968, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.24, 
+        "invoice": 71, 
+        "date": "2013-12-02T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59893, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.783Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.644Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 71, 
+        "date": "2013-12-02T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59894, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.891Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.652Z", 
+        "deleted": false, 
+        "amount": 0.1288, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.84, 
+        "invoice": 71, 
+        "date": "2013-12-03T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59895, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.999Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.660Z", 
+        "deleted": false, 
+        "amount": 0.1568, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.24, 
+        "invoice": 71, 
+        "date": "2013-12-03T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59896, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.106Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.669Z", 
+        "deleted": false, 
+        "amount": 0.1792, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.56, 
+        "invoice": 71, 
+        "date": "2013-12-03T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59897, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.214Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.677Z", 
+        "deleted": false, 
+        "amount": 0.3024, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.32, 
+        "invoice": 71, 
+        "date": "2013-12-04T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59898, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.322Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.685Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 71, 
+        "date": "2013-12-04T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59899, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.429Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.693Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.16, 
+        "invoice": 71, 
+        "date": "2013-12-04T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59900, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.537Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.702Z", 
+        "deleted": false, 
+        "amount": 0.1288, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.84, 
+        "invoice": 71, 
+        "date": "2013-12-05T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59901, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.645Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.710Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 71, 
+        "date": "2013-12-05T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59902, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.752Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.718Z", 
+        "deleted": false, 
+        "amount": 0.3248, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.64, 
+        "invoice": 71, 
+        "date": "2013-12-05T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59903, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.860Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.727Z", 
+        "deleted": false, 
+        "amount": 0.3024, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.32, 
+        "invoice": 71, 
+        "date": "2013-12-06T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59904, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.968Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.735Z", 
+        "deleted": false, 
+        "amount": 0.14, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.0, 
+        "invoice": 71, 
+        "date": "2013-12-06T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59905, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.075Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.743Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 71, 
+        "date": "2013-12-06T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59906, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.183Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.751Z", 
+        "deleted": false, 
+        "amount": 0.2744, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.92, 
+        "invoice": 71, 
+        "date": "2013-12-07T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59907, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.291Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.760Z", 
+        "deleted": false, 
+        "amount": 0.2632, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.76, 
+        "invoice": 71, 
+        "date": "2013-12-07T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59908, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.399Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.768Z", 
+        "deleted": false, 
+        "amount": 0.2408, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.44, 
+        "invoice": 71, 
+        "date": "2013-12-07T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59909, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.506Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.776Z", 
+        "deleted": false, 
+        "amount": 0.1624, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.32, 
+        "invoice": 71, 
+        "date": "2013-12-08T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59910, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.614Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.784Z", 
+        "deleted": false, 
+        "amount": 0.2968, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.24, 
+        "invoice": 71, 
+        "date": "2013-12-08T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59911, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.722Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.793Z", 
+        "deleted": false, 
+        "amount": 0.2016, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.88, 
+        "invoice": 71, 
+        "date": "2013-12-08T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59912, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.838Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.801Z", 
+        "deleted": false, 
+        "amount": 0.2296, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.28, 
+        "invoice": 72, 
+        "date": "2013-12-09T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59913, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.945Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.809Z", 
+        "deleted": false, 
+        "amount": 0.2128, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.04, 
+        "invoice": 72, 
+        "date": "2013-12-09T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59914, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.053Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.818Z", 
+        "deleted": false, 
+        "amount": 0.112, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.6, 
+        "invoice": 72, 
+        "date": "2013-12-09T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59915, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.161Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.826Z", 
+        "deleted": false, 
+        "amount": 0.168, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.4, 
+        "invoice": 72, 
+        "date": "2013-12-10T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59916, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.268Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.834Z", 
+        "deleted": false, 
+        "amount": 0.168, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.4, 
+        "invoice": 72, 
+        "date": "2013-12-10T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59917, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.376Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.842Z", 
+        "deleted": false, 
+        "amount": 0.196, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.8, 
+        "invoice": 72, 
+        "date": "2013-12-10T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59918, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.484Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.851Z", 
+        "deleted": false, 
+        "amount": 0.2464, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.52, 
+        "invoice": 72, 
+        "date": "2013-12-11T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59919, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.649Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.859Z", 
+        "deleted": false, 
+        "amount": 0.112, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.6, 
+        "invoice": 72, 
+        "date": "2013-12-11T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59920, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.757Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.867Z", 
+        "deleted": false, 
+        "amount": 0.1792, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.56, 
+        "invoice": 72, 
+        "date": "2013-12-11T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59921, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.865Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.875Z", 
+        "deleted": false, 
+        "amount": 0.308, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.4, 
+        "invoice": 72, 
+        "date": "2013-12-12T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59922, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.972Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.884Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.68, 
+        "invoice": 72, 
+        "date": "2013-12-12T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59923, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.080Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.892Z", 
+        "deleted": false, 
+        "amount": 0.2016, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.88, 
+        "invoice": 72, 
+        "date": "2013-12-12T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59924, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.188Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.900Z", 
+        "deleted": false, 
+        "amount": 0.1512, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.16, 
+        "invoice": 72, 
+        "date": "2013-12-13T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59925, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.296Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.909Z", 
+        "deleted": false, 
+        "amount": 0.2352, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.36, 
+        "invoice": 72, 
+        "date": "2013-12-13T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59926, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.403Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.917Z", 
+        "deleted": false, 
+        "amount": 0.308, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.4, 
+        "invoice": 72, 
+        "date": "2013-12-13T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59927, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.511Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.925Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 72, 
+        "date": "2013-12-14T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59928, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.619Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.934Z", 
+        "deleted": false, 
+        "amount": 0.1792, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.56, 
+        "invoice": 72, 
+        "date": "2013-12-14T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59929, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.726Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.942Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 72, 
+        "date": "2013-12-14T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59930, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.834Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.950Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.08, 
+        "invoice": 72, 
+        "date": "2013-12-15T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59931, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.942Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:01.980Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 72, 
+        "date": "2013-12-15T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59932, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.049Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.021Z", 
+        "deleted": false, 
+        "amount": 0.1232, 
+        "object": 105, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.76, 
+        "invoice": 72, 
+        "date": "2013-12-15T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59933, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:02.066Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.066Z", 
+        "deleted": false, 
+        "amount": 0.2072, 
+        "object": 105, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 2.96, 
+        "invoice": null, 
+        "date": "2013-12-16T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59934, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:02.116Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.116Z", 
+        "deleted": false, 
+        "amount": 0.2408, 
+        "object": 105, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 3.44, 
+        "invoice": null, 
+        "date": "2013-12-16T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59935, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:02.124Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.124Z", 
+        "deleted": false, 
+        "amount": 0.2352, 
+        "object": 105, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 3.36, 
+        "invoice": null, 
+        "date": "2013-12-16T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59936, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:02.132Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.132Z", 
+        "deleted": false, 
+        "amount": 0.2576, 
+        "object": 105, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 3.68, 
+        "invoice": null, 
+        "date": "2013-12-17T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59937, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:02.141Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.141Z", 
+        "deleted": false, 
+        "amount": 0.2744, 
+        "object": 105, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 3.92, 
+        "invoice": null, 
+        "date": "2013-12-17T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59938, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:02.149Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.149Z", 
+        "deleted": false, 
+        "amount": 0.14, 
+        "object": 105, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 2.0, 
+        "invoice": null, 
+        "date": "2013-12-17T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59939, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:02.157Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.157Z", 
+        "deleted": false, 
+        "amount": 0.2688, 
+        "object": 105, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 3.84, 
+        "invoice": null, 
+        "date": "2013-12-18T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59940, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:02.165Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.165Z", 
+        "deleted": false, 
+        "amount": 0.3192, 
+        "object": 105, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 4.56, 
+        "invoice": null, 
+        "date": "2013-12-18T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59941, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.210Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.205Z", 
+        "deleted": false, 
+        "amount": 0.1624, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.32, 
+        "invoice": 69, 
+        "date": "2013-11-18T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59942, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.318Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.246Z", 
+        "deleted": false, 
+        "amount": 0.196, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.8, 
+        "invoice": 69, 
+        "date": "2013-11-19T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59943, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.426Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.273Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 69, 
+        "date": "2013-11-19T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59944, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.533Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.323Z", 
+        "deleted": false, 
+        "amount": 0.1288, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.84, 
+        "invoice": 69, 
+        "date": "2013-11-19T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59945, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.641Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.348Z", 
+        "deleted": false, 
+        "amount": 0.28, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.0, 
+        "invoice": 69, 
+        "date": "2013-11-20T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59946, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.749Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.379Z", 
+        "deleted": false, 
+        "amount": 0.2688, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.84, 
+        "invoice": 69, 
+        "date": "2013-11-20T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59947, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.857Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.430Z", 
+        "deleted": false, 
+        "amount": 0.1792, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.56, 
+        "invoice": 69, 
+        "date": "2013-11-20T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59948, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.964Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.471Z", 
+        "deleted": false, 
+        "amount": 0.1736, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.48, 
+        "invoice": 69, 
+        "date": "2013-11-21T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59949, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.072Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.497Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.68, 
+        "invoice": 69, 
+        "date": "2013-11-21T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59950, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.180Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.505Z", 
+        "deleted": false, 
+        "amount": 0.2576, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.68, 
+        "invoice": 69, 
+        "date": "2013-11-21T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59951, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.287Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.513Z", 
+        "deleted": false, 
+        "amount": 0.1904, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.72, 
+        "invoice": 69, 
+        "date": "2013-11-22T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59952, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.395Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.521Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 69, 
+        "date": "2013-11-22T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59953, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.503Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.530Z", 
+        "deleted": false, 
+        "amount": 0.3192, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.56, 
+        "invoice": 69, 
+        "date": "2013-11-22T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59954, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.610Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.538Z", 
+        "deleted": false, 
+        "amount": 0.3248, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.64, 
+        "invoice": 69, 
+        "date": "2013-11-23T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59955, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.718Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.546Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 69, 
+        "date": "2013-11-23T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59956, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.826Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.555Z", 
+        "deleted": false, 
+        "amount": 0.2744, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.92, 
+        "invoice": 69, 
+        "date": "2013-11-23T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59957, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.933Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.563Z", 
+        "deleted": false, 
+        "amount": 0.168, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.4, 
+        "invoice": 69, 
+        "date": "2013-11-24T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59958, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.041Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.571Z", 
+        "deleted": false, 
+        "amount": 0.28, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.0, 
+        "invoice": 69, 
+        "date": "2013-11-24T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59959, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.149Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.579Z", 
+        "deleted": false, 
+        "amount": 0.14, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.0, 
+        "invoice": 69, 
+        "date": "2013-11-24T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59960, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.265Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.588Z", 
+        "deleted": false, 
+        "amount": 0.3248, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.64, 
+        "invoice": 70, 
+        "date": "2013-11-25T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59961, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.372Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.596Z", 
+        "deleted": false, 
+        "amount": 0.2464, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.52, 
+        "invoice": 70, 
+        "date": "2013-11-25T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59962, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.480Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.604Z", 
+        "deleted": false, 
+        "amount": 0.1232, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.76, 
+        "invoice": 70, 
+        "date": "2013-11-25T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59963, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.629Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.613Z", 
+        "deleted": false, 
+        "amount": 0.1792, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.56, 
+        "invoice": 70, 
+        "date": "2013-11-26T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59964, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.737Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.621Z", 
+        "deleted": false, 
+        "amount": 0.336, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.8, 
+        "invoice": 70, 
+        "date": "2013-11-26T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59965, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.845Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.629Z", 
+        "deleted": false, 
+        "amount": 0.2632, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.76, 
+        "invoice": 70, 
+        "date": "2013-11-26T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59966, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.952Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.638Z", 
+        "deleted": false, 
+        "amount": 0.168, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.4, 
+        "invoice": 70, 
+        "date": "2013-11-27T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59967, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.060Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.646Z", 
+        "deleted": false, 
+        "amount": 0.3192, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.56, 
+        "invoice": 70, 
+        "date": "2013-11-27T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59968, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.168Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.654Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 70, 
+        "date": "2013-11-27T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59969, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.275Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.662Z", 
+        "deleted": false, 
+        "amount": 0.2744, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.92, 
+        "invoice": 70, 
+        "date": "2013-11-28T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59970, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.383Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.671Z", 
+        "deleted": false, 
+        "amount": 0.2016, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.88, 
+        "invoice": 70, 
+        "date": "2013-11-28T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59971, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.491Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.679Z", 
+        "deleted": false, 
+        "amount": 0.196, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.8, 
+        "invoice": 70, 
+        "date": "2013-11-28T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59972, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.598Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.687Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 70, 
+        "date": "2013-11-29T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59973, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.706Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.695Z", 
+        "deleted": false, 
+        "amount": 0.3192, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.56, 
+        "invoice": 70, 
+        "date": "2013-11-29T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59974, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.814Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.704Z", 
+        "deleted": false, 
+        "amount": 0.3192, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.56, 
+        "invoice": 70, 
+        "date": "2013-11-29T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59975, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.922Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.712Z", 
+        "deleted": false, 
+        "amount": 0.2464, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.52, 
+        "invoice": 70, 
+        "date": "2013-11-30T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59976, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.029Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.720Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.16, 
+        "invoice": 70, 
+        "date": "2013-11-30T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59977, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.137Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.729Z", 
+        "deleted": false, 
+        "amount": 0.2016, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.88, 
+        "invoice": 70, 
+        "date": "2013-11-30T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59978, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.245Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.737Z", 
+        "deleted": false, 
+        "amount": 0.2128, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.04, 
+        "invoice": 70, 
+        "date": "2013-12-01T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59979, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.352Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.745Z", 
+        "deleted": false, 
+        "amount": 0.1288, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.84, 
+        "invoice": 70, 
+        "date": "2013-12-01T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59980, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.460Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.753Z", 
+        "deleted": false, 
+        "amount": 0.2408, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.44, 
+        "invoice": 70, 
+        "date": "2013-12-01T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59981, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.576Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.762Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 71, 
+        "date": "2013-12-02T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59982, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.684Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.770Z", 
+        "deleted": false, 
+        "amount": 0.2688, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.84, 
+        "invoice": 71, 
+        "date": "2013-12-02T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59983, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.791Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.778Z", 
+        "deleted": false, 
+        "amount": 0.2072, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.96, 
+        "invoice": 71, 
+        "date": "2013-12-02T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59984, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.899Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.787Z", 
+        "deleted": false, 
+        "amount": 0.224, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.2, 
+        "invoice": 71, 
+        "date": "2013-12-03T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59985, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.007Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.795Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 71, 
+        "date": "2013-12-03T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59986, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.114Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.803Z", 
+        "deleted": false, 
+        "amount": 0.224, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.2, 
+        "invoice": 71, 
+        "date": "2013-12-03T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59987, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.222Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.811Z", 
+        "deleted": false, 
+        "amount": 0.2576, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.68, 
+        "invoice": 71, 
+        "date": "2013-12-04T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59988, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.330Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.820Z", 
+        "deleted": false, 
+        "amount": 0.2352, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.36, 
+        "invoice": 71, 
+        "date": "2013-12-04T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59989, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.438Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.828Z", 
+        "deleted": false, 
+        "amount": 0.308, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.4, 
+        "invoice": 71, 
+        "date": "2013-12-04T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59990, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.545Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.836Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 71, 
+        "date": "2013-12-05T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59991, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.653Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.845Z", 
+        "deleted": false, 
+        "amount": 0.224, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.2, 
+        "invoice": 71, 
+        "date": "2013-12-05T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59992, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.761Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.853Z", 
+        "deleted": false, 
+        "amount": 0.308, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.4, 
+        "invoice": 71, 
+        "date": "2013-12-05T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59993, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.868Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.861Z", 
+        "deleted": false, 
+        "amount": 0.2688, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.84, 
+        "invoice": 71, 
+        "date": "2013-12-06T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59994, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.976Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.869Z", 
+        "deleted": false, 
+        "amount": 0.2464, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.52, 
+        "invoice": 71, 
+        "date": "2013-12-06T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59995, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.084Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.878Z", 
+        "deleted": false, 
+        "amount": 0.3024, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.32, 
+        "invoice": 71, 
+        "date": "2013-12-06T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59996, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.192Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.886Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.08, 
+        "invoice": 71, 
+        "date": "2013-12-07T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59997, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.299Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.894Z", 
+        "deleted": false, 
+        "amount": 0.2968, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.24, 
+        "invoice": 71, 
+        "date": "2013-12-07T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59998, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.407Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.902Z", 
+        "deleted": false, 
+        "amount": 0.1344, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.92, 
+        "invoice": 71, 
+        "date": "2013-12-07T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 59999, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.514Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.911Z", 
+        "deleted": false, 
+        "amount": 0.3192, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.56, 
+        "invoice": 71, 
+        "date": "2013-12-08T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60000, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.622Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.919Z", 
+        "deleted": false, 
+        "amount": 0.1288, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.84, 
+        "invoice": 71, 
+        "date": "2013-12-08T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60001, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.730Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.927Z", 
+        "deleted": false, 
+        "amount": 0.2968, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.24, 
+        "invoice": 71, 
+        "date": "2013-12-08T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60002, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.846Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.936Z", 
+        "deleted": false, 
+        "amount": 0.1848, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.64, 
+        "invoice": 72, 
+        "date": "2013-12-09T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60003, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.953Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.944Z", 
+        "deleted": false, 
+        "amount": 0.1568, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.24, 
+        "invoice": 72, 
+        "date": "2013-12-09T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60004, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.061Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.952Z", 
+        "deleted": false, 
+        "amount": 0.1736, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.48, 
+        "invoice": 72, 
+        "date": "2013-12-09T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60005, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.169Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.960Z", 
+        "deleted": false, 
+        "amount": 0.3024, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.32, 
+        "invoice": 72, 
+        "date": "2013-12-10T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60006, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.277Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.969Z", 
+        "deleted": false, 
+        "amount": 0.2128, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.04, 
+        "invoice": 72, 
+        "date": "2013-12-10T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60007, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.384Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.977Z", 
+        "deleted": false, 
+        "amount": 0.168, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.4, 
+        "invoice": 72, 
+        "date": "2013-12-10T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60008, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.492Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.985Z", 
+        "deleted": false, 
+        "amount": 0.2968, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.24, 
+        "invoice": 72, 
+        "date": "2013-12-11T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60009, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.658Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:02.994Z", 
+        "deleted": false, 
+        "amount": 0.14, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.0, 
+        "invoice": 72, 
+        "date": "2013-12-11T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60010, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.765Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.002Z", 
+        "deleted": false, 
+        "amount": 0.252, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.6, 
+        "invoice": 72, 
+        "date": "2013-12-11T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60011, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.873Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.010Z", 
+        "deleted": false, 
+        "amount": 0.2744, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.92, 
+        "invoice": 72, 
+        "date": "2013-12-12T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60012, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.981Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.018Z", 
+        "deleted": false, 
+        "amount": 0.196, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.8, 
+        "invoice": 72, 
+        "date": "2013-12-12T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60013, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.088Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.027Z", 
+        "deleted": false, 
+        "amount": 0.168, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.4, 
+        "invoice": 72, 
+        "date": "2013-12-12T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60014, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.196Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.035Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.68, 
+        "invoice": 72, 
+        "date": "2013-12-13T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60015, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.304Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.043Z", 
+        "deleted": false, 
+        "amount": 0.3248, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.64, 
+        "invoice": 72, 
+        "date": "2013-12-13T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60016, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.411Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.052Z", 
+        "deleted": false, 
+        "amount": 0.1792, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.56, 
+        "invoice": 72, 
+        "date": "2013-12-13T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60017, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.519Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.060Z", 
+        "deleted": false, 
+        "amount": 0.1232, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.76, 
+        "invoice": 72, 
+        "date": "2013-12-14T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60018, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.627Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.068Z", 
+        "deleted": false, 
+        "amount": 0.1512, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.16, 
+        "invoice": 72, 
+        "date": "2013-12-14T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60019, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.735Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.076Z", 
+        "deleted": false, 
+        "amount": 0.3024, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.32, 
+        "invoice": 72, 
+        "date": "2013-12-14T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60020, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.842Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.085Z", 
+        "deleted": false, 
+        "amount": 0.1792, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.56, 
+        "invoice": 72, 
+        "date": "2013-12-15T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60021, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.950Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.093Z", 
+        "deleted": false, 
+        "amount": 0.1512, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.16, 
+        "invoice": 72, 
+        "date": "2013-12-15T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60022, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.058Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.101Z", 
+        "deleted": false, 
+        "amount": 0.2016, 
+        "object": 106, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.88, 
+        "invoice": 72, 
+        "date": "2013-12-15T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60023, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:03.110Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.110Z", 
+        "deleted": false, 
+        "amount": 0.2408, 
+        "object": 106, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 3.44, 
+        "invoice": null, 
+        "date": "2013-12-16T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60024, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:03.118Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.118Z", 
+        "deleted": false, 
+        "amount": 0.2184, 
+        "object": 106, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 3.12, 
+        "invoice": null, 
+        "date": "2013-12-16T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60025, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:03.126Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.126Z", 
+        "deleted": false, 
+        "amount": 0.1904, 
+        "object": 106, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 2.72, 
+        "invoice": null, 
+        "date": "2013-12-16T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60026, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:03.134Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.134Z", 
+        "deleted": false, 
+        "amount": 0.2464, 
+        "object": 106, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 3.52, 
+        "invoice": null, 
+        "date": "2013-12-17T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60027, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:03.143Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.143Z", 
+        "deleted": false, 
+        "amount": 0.2408, 
+        "object": 106, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 3.44, 
+        "invoice": null, 
+        "date": "2013-12-17T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60028, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:03.151Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.151Z", 
+        "deleted": false, 
+        "amount": 0.196, 
+        "object": 106, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 2.8, 
+        "invoice": null, 
+        "date": "2013-12-17T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60029, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:03.160Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.159Z", 
+        "deleted": false, 
+        "amount": 0.2632, 
+        "object": 106, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 3.76, 
+        "invoice": null, 
+        "date": "2013-12-18T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60030, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:03.168Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.168Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 106, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 1.68, 
+        "invoice": null, 
+        "date": "2013-12-18T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60031, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.219Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.183Z", 
+        "deleted": false, 
+        "amount": 0.112, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.6, 
+        "invoice": 69, 
+        "date": "2013-11-18T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60032, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.326Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.193Z", 
+        "deleted": false, 
+        "amount": 0.168, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.4, 
+        "invoice": 69, 
+        "date": "2013-11-19T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60033, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.434Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.201Z", 
+        "deleted": false, 
+        "amount": 0.3248, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.64, 
+        "invoice": 69, 
+        "date": "2013-11-19T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60034, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.542Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.209Z", 
+        "deleted": false, 
+        "amount": 0.2296, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.28, 
+        "invoice": 69, 
+        "date": "2013-11-19T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60035, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.650Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.217Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.16, 
+        "invoice": 69, 
+        "date": "2013-11-20T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60036, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.757Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.226Z", 
+        "deleted": false, 
+        "amount": 0.2016, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.88, 
+        "invoice": 69, 
+        "date": "2013-11-20T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60037, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.865Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.234Z", 
+        "deleted": false, 
+        "amount": 0.1736, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.48, 
+        "invoice": 69, 
+        "date": "2013-11-20T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60038, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.973Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.242Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.08, 
+        "invoice": 69, 
+        "date": "2013-11-21T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60039, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.080Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.251Z", 
+        "deleted": false, 
+        "amount": 0.1568, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.24, 
+        "invoice": 69, 
+        "date": "2013-11-21T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60040, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.188Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.259Z", 
+        "deleted": false, 
+        "amount": 0.224, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.2, 
+        "invoice": 69, 
+        "date": "2013-11-21T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60041, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.296Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.267Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.68, 
+        "invoice": 69, 
+        "date": "2013-11-22T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60042, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.403Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.275Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 69, 
+        "date": "2013-11-22T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60043, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.511Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.284Z", 
+        "deleted": false, 
+        "amount": 0.3192, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.56, 
+        "invoice": 69, 
+        "date": "2013-11-22T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60044, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.619Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.292Z", 
+        "deleted": false, 
+        "amount": 0.1736, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.48, 
+        "invoice": 69, 
+        "date": "2013-11-23T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60045, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.726Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.300Z", 
+        "deleted": false, 
+        "amount": 0.2352, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.36, 
+        "invoice": 69, 
+        "date": "2013-11-23T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60046, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.834Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.308Z", 
+        "deleted": false, 
+        "amount": 0.1736, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.48, 
+        "invoice": 69, 
+        "date": "2013-11-23T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60047, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.942Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.317Z", 
+        "deleted": false, 
+        "amount": 0.2128, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.04, 
+        "invoice": 69, 
+        "date": "2013-11-24T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60048, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.049Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.325Z", 
+        "deleted": false, 
+        "amount": 0.2968, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.24, 
+        "invoice": 69, 
+        "date": "2013-11-24T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60049, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.157Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.333Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.68, 
+        "invoice": 69, 
+        "date": "2013-11-24T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60050, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.273Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.342Z", 
+        "deleted": false, 
+        "amount": 0.1792, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.56, 
+        "invoice": 70, 
+        "date": "2013-11-25T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60051, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.381Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.350Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 70, 
+        "date": "2013-11-25T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60052, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.488Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.358Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.16, 
+        "invoice": 70, 
+        "date": "2013-11-25T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60053, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.638Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.366Z", 
+        "deleted": false, 
+        "amount": 0.252, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.6, 
+        "invoice": 70, 
+        "date": "2013-11-26T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60054, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.745Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.375Z", 
+        "deleted": false, 
+        "amount": 0.3024, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.32, 
+        "invoice": 70, 
+        "date": "2013-11-26T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60055, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.853Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.383Z", 
+        "deleted": false, 
+        "amount": 0.168, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.4, 
+        "invoice": 70, 
+        "date": "2013-11-26T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60056, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.961Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.391Z", 
+        "deleted": false, 
+        "amount": 0.308, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.4, 
+        "invoice": 70, 
+        "date": "2013-11-27T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60057, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.068Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.400Z", 
+        "deleted": false, 
+        "amount": 0.196, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.8, 
+        "invoice": 70, 
+        "date": "2013-11-27T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60058, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.176Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.408Z", 
+        "deleted": false, 
+        "amount": 0.1232, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.76, 
+        "invoice": 70, 
+        "date": "2013-11-27T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60059, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.284Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.416Z", 
+        "deleted": false, 
+        "amount": 0.3024, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.32, 
+        "invoice": 70, 
+        "date": "2013-11-28T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60060, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.391Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.424Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.16, 
+        "invoice": 70, 
+        "date": "2013-11-28T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60061, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.499Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.433Z", 
+        "deleted": false, 
+        "amount": 0.1904, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.72, 
+        "invoice": 70, 
+        "date": "2013-11-28T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60062, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.607Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.441Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.68, 
+        "invoice": 70, 
+        "date": "2013-11-29T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60063, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.715Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.449Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.08, 
+        "invoice": 70, 
+        "date": "2013-11-29T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60064, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.822Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.457Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 70, 
+        "date": "2013-11-29T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60065, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.930Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.466Z", 
+        "deleted": false, 
+        "amount": 0.308, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.4, 
+        "invoice": 70, 
+        "date": "2013-11-30T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60066, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.038Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.474Z", 
+        "deleted": false, 
+        "amount": 0.252, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.6, 
+        "invoice": 70, 
+        "date": "2013-11-30T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60067, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.145Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.482Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 70, 
+        "date": "2013-11-30T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60068, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.253Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.491Z", 
+        "deleted": false, 
+        "amount": 0.1624, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.32, 
+        "invoice": 70, 
+        "date": "2013-12-01T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60069, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.361Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.499Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 70, 
+        "date": "2013-12-01T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60070, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.468Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.507Z", 
+        "deleted": false, 
+        "amount": 0.168, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.4, 
+        "invoice": 70, 
+        "date": "2013-12-01T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60071, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.584Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.516Z", 
+        "deleted": false, 
+        "amount": 0.168, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.4, 
+        "invoice": 71, 
+        "date": "2013-12-02T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60072, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.692Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.524Z", 
+        "deleted": false, 
+        "amount": 0.28, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.0, 
+        "invoice": 71, 
+        "date": "2013-12-02T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60073, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.800Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.532Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 71, 
+        "date": "2013-12-02T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60074, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.907Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.541Z", 
+        "deleted": false, 
+        "amount": 0.3024, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.32, 
+        "invoice": 71, 
+        "date": "2013-12-03T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60075, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.015Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.549Z", 
+        "deleted": false, 
+        "amount": 0.2296, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.28, 
+        "invoice": 71, 
+        "date": "2013-12-03T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60076, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.123Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.557Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 71, 
+        "date": "2013-12-03T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60077, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.231Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.565Z", 
+        "deleted": false, 
+        "amount": 0.1792, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.56, 
+        "invoice": 71, 
+        "date": "2013-12-04T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60078, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.338Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.574Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.16, 
+        "invoice": 71, 
+        "date": "2013-12-04T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60079, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.446Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.582Z", 
+        "deleted": false, 
+        "amount": 0.2128, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.04, 
+        "invoice": 71, 
+        "date": "2013-12-04T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60080, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.554Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.590Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.08, 
+        "invoice": 71, 
+        "date": "2013-12-05T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60081, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.661Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.598Z", 
+        "deleted": false, 
+        "amount": 0.112, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.6, 
+        "invoice": 71, 
+        "date": "2013-12-05T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60082, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.769Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.607Z", 
+        "deleted": false, 
+        "amount": 0.28, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.0, 
+        "invoice": 71, 
+        "date": "2013-12-05T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60083, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.877Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.615Z", 
+        "deleted": false, 
+        "amount": 0.112, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.6, 
+        "invoice": 71, 
+        "date": "2013-12-06T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60084, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.984Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.623Z", 
+        "deleted": false, 
+        "amount": 0.224, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.2, 
+        "invoice": 71, 
+        "date": "2013-12-06T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60085, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.092Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.631Z", 
+        "deleted": false, 
+        "amount": 0.1344, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.92, 
+        "invoice": 71, 
+        "date": "2013-12-06T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60086, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.200Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.640Z", 
+        "deleted": false, 
+        "amount": 0.2968, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.24, 
+        "invoice": 71, 
+        "date": "2013-12-07T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60087, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.307Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.648Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 71, 
+        "date": "2013-12-07T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60088, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.415Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.657Z", 
+        "deleted": false, 
+        "amount": 0.3192, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.56, 
+        "invoice": 71, 
+        "date": "2013-12-07T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60089, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.523Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.665Z", 
+        "deleted": false, 
+        "amount": 0.336, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.8, 
+        "invoice": 71, 
+        "date": "2013-12-08T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60090, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.630Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.673Z", 
+        "deleted": false, 
+        "amount": 0.308, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.4, 
+        "invoice": 71, 
+        "date": "2013-12-08T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60091, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.738Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.681Z", 
+        "deleted": false, 
+        "amount": 0.1288, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.84, 
+        "invoice": 71, 
+        "date": "2013-12-08T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60092, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.854Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.690Z", 
+        "deleted": false, 
+        "amount": 0.2632, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.76, 
+        "invoice": 72, 
+        "date": "2013-12-09T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60093, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.962Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.698Z", 
+        "deleted": false, 
+        "amount": 0.2184, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.12, 
+        "invoice": 72, 
+        "date": "2013-12-09T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60094, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.069Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.706Z", 
+        "deleted": false, 
+        "amount": 0.1904, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.72, 
+        "invoice": 72, 
+        "date": "2013-12-09T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60095, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.177Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.714Z", 
+        "deleted": false, 
+        "amount": 0.168, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.4, 
+        "invoice": 72, 
+        "date": "2013-12-10T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60096, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.285Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.723Z", 
+        "deleted": false, 
+        "amount": 0.2464, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.52, 
+        "invoice": 72, 
+        "date": "2013-12-10T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60097, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.393Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.731Z", 
+        "deleted": false, 
+        "amount": 0.2184, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.12, 
+        "invoice": 72, 
+        "date": "2013-12-10T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60098, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.500Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.739Z", 
+        "deleted": false, 
+        "amount": 0.1736, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.48, 
+        "invoice": 72, 
+        "date": "2013-12-11T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60099, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.666Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.748Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.08, 
+        "invoice": 72, 
+        "date": "2013-12-11T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60100, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.774Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.756Z", 
+        "deleted": false, 
+        "amount": 0.1512, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.16, 
+        "invoice": 72, 
+        "date": "2013-12-11T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60101, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.881Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.764Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 72, 
+        "date": "2013-12-12T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60102, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.989Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.773Z", 
+        "deleted": false, 
+        "amount": 0.168, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.4, 
+        "invoice": 72, 
+        "date": "2013-12-12T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60103, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.097Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.781Z", 
+        "deleted": false, 
+        "amount": 0.3024, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.32, 
+        "invoice": 72, 
+        "date": "2013-12-12T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60104, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.204Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.789Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 72, 
+        "date": "2013-12-13T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60105, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.312Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.797Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 72, 
+        "date": "2013-12-13T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60106, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.420Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.806Z", 
+        "deleted": false, 
+        "amount": 0.1232, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.76, 
+        "invoice": 72, 
+        "date": "2013-12-13T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60107, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.527Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.814Z", 
+        "deleted": false, 
+        "amount": 0.2632, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.76, 
+        "invoice": 72, 
+        "date": "2013-12-14T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60108, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.635Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.822Z", 
+        "deleted": false, 
+        "amount": 0.196, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.8, 
+        "invoice": 72, 
+        "date": "2013-12-14T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60109, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.743Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.830Z", 
+        "deleted": false, 
+        "amount": 0.1344, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.92, 
+        "invoice": 72, 
+        "date": "2013-12-14T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60110, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.851Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.839Z", 
+        "deleted": false, 
+        "amount": 0.2352, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.36, 
+        "invoice": 72, 
+        "date": "2013-12-15T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60111, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.958Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.847Z", 
+        "deleted": false, 
+        "amount": 0.2632, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.76, 
+        "invoice": 72, 
+        "date": "2013-12-15T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60112, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.066Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.855Z", 
+        "deleted": false, 
+        "amount": 0.2128, 
+        "object": 107, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.04, 
+        "invoice": 72, 
+        "date": "2013-12-15T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60113, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:03.864Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.864Z", 
+        "deleted": false, 
+        "amount": 0.14, 
+        "object": 107, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 2.0, 
+        "invoice": null, 
+        "date": "2013-12-16T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60114, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:03.872Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.872Z", 
+        "deleted": false, 
+        "amount": 0.252, 
+        "object": 107, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 3.6, 
+        "invoice": null, 
+        "date": "2013-12-16T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60115, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:03.880Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.880Z", 
+        "deleted": false, 
+        "amount": 0.28, 
+        "object": 107, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 4.0, 
+        "invoice": null, 
+        "date": "2013-12-16T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60116, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:03.888Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.888Z", 
+        "deleted": false, 
+        "amount": 0.1624, 
+        "object": 107, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 2.32, 
+        "invoice": null, 
+        "date": "2013-12-17T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60117, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:03.897Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.897Z", 
+        "deleted": false, 
+        "amount": 0.2744, 
+        "object": 107, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 3.92, 
+        "invoice": null, 
+        "date": "2013-12-17T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60118, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:03.905Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.905Z", 
+        "deleted": false, 
+        "amount": 0.28, 
+        "object": 107, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 4.0, 
+        "invoice": null, 
+        "date": "2013-12-17T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60119, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:03.913Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.913Z", 
+        "deleted": false, 
+        "amount": 0.2408, 
+        "object": 107, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 3.44, 
+        "invoice": null, 
+        "date": "2013-12-18T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60120, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:03.921Z", 
+        "slice": 4, 
+        "created": "2013-12-18T21:29:03.921Z", 
+        "deleted": false, 
+        "amount": 0.308, 
+        "object": 107, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 4.4, 
+        "invoice": null, 
+        "date": "2013-12-18T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60121, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.227Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:03.953Z", 
+        "deleted": false, 
+        "amount": 0.2968, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.24, 
+        "invoice": 69, 
+        "date": "2013-11-18T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60122, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.335Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:03.963Z", 
+        "deleted": false, 
+        "amount": 0.196, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.8, 
+        "invoice": 69, 
+        "date": "2013-11-19T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60123, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.442Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:03.971Z", 
+        "deleted": false, 
+        "amount": 0.1232, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.76, 
+        "invoice": 69, 
+        "date": "2013-11-19T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60124, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.550Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:03.979Z", 
+        "deleted": false, 
+        "amount": 0.308, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.4, 
+        "invoice": 69, 
+        "date": "2013-11-19T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60125, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.658Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:03.988Z", 
+        "deleted": false, 
+        "amount": 0.2464, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.52, 
+        "invoice": 69, 
+        "date": "2013-11-20T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60126, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.765Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:03.996Z", 
+        "deleted": false, 
+        "amount": 0.196, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.8, 
+        "invoice": 69, 
+        "date": "2013-11-20T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60127, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.873Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.004Z", 
+        "deleted": false, 
+        "amount": 0.2464, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.52, 
+        "invoice": 69, 
+        "date": "2013-11-20T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60128, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.981Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.013Z", 
+        "deleted": false, 
+        "amount": 0.1736, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.48, 
+        "invoice": 69, 
+        "date": "2013-11-21T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60129, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.088Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.021Z", 
+        "deleted": false, 
+        "amount": 0.2968, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.24, 
+        "invoice": 69, 
+        "date": "2013-11-21T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60130, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.196Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.029Z", 
+        "deleted": false, 
+        "amount": 0.1568, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.24, 
+        "invoice": 69, 
+        "date": "2013-11-21T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60131, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.304Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.037Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 69, 
+        "date": "2013-11-22T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60132, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.412Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.046Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.08, 
+        "invoice": 69, 
+        "date": "2013-11-22T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60133, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.519Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.054Z", 
+        "deleted": false, 
+        "amount": 0.1288, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.84, 
+        "invoice": 69, 
+        "date": "2013-11-22T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60134, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.627Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.062Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.08, 
+        "invoice": 69, 
+        "date": "2013-11-23T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60135, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.735Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.071Z", 
+        "deleted": false, 
+        "amount": 0.2128, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.04, 
+        "invoice": 69, 
+        "date": "2013-11-23T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60136, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.842Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.079Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 69, 
+        "date": "2013-11-23T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60137, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.950Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.087Z", 
+        "deleted": false, 
+        "amount": 0.2464, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.52, 
+        "invoice": 69, 
+        "date": "2013-11-24T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60138, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.058Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.095Z", 
+        "deleted": false, 
+        "amount": 0.2744, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.92, 
+        "invoice": 69, 
+        "date": "2013-11-24T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60139, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.166Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.104Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.16, 
+        "invoice": 69, 
+        "date": "2013-11-24T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60140, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.281Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.112Z", 
+        "deleted": false, 
+        "amount": 0.2464, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.52, 
+        "invoice": 70, 
+        "date": "2013-11-25T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60141, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.389Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.120Z", 
+        "deleted": false, 
+        "amount": 0.2464, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.52, 
+        "invoice": 70, 
+        "date": "2013-11-25T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60142, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.497Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.129Z", 
+        "deleted": false, 
+        "amount": 0.1736, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.48, 
+        "invoice": 70, 
+        "date": "2013-11-25T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60143, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.646Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.137Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.08, 
+        "invoice": 70, 
+        "date": "2013-11-26T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60144, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.754Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.145Z", 
+        "deleted": false, 
+        "amount": 0.1568, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.24, 
+        "invoice": 70, 
+        "date": "2013-11-26T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60145, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.861Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.154Z", 
+        "deleted": false, 
+        "amount": 0.1736, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.48, 
+        "invoice": 70, 
+        "date": "2013-11-26T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60146, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.969Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.162Z", 
+        "deleted": false, 
+        "amount": 0.252, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.6, 
+        "invoice": 70, 
+        "date": "2013-11-27T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60147, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.077Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.170Z", 
+        "deleted": false, 
+        "amount": 0.2016, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.88, 
+        "invoice": 70, 
+        "date": "2013-11-27T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60148, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.184Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.178Z", 
+        "deleted": false, 
+        "amount": 0.3192, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.56, 
+        "invoice": 70, 
+        "date": "2013-11-27T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60149, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.292Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.187Z", 
+        "deleted": false, 
+        "amount": 0.2464, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.52, 
+        "invoice": 70, 
+        "date": "2013-11-28T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60150, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.400Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.195Z", 
+        "deleted": false, 
+        "amount": 0.112, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.6, 
+        "invoice": 70, 
+        "date": "2013-11-28T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60151, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.507Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.203Z", 
+        "deleted": false, 
+        "amount": 0.1568, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.24, 
+        "invoice": 70, 
+        "date": "2013-11-28T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60152, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.615Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.212Z", 
+        "deleted": false, 
+        "amount": 0.28, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.0, 
+        "invoice": 70, 
+        "date": "2013-11-29T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60153, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.723Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.220Z", 
+        "deleted": false, 
+        "amount": 0.2016, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.88, 
+        "invoice": 70, 
+        "date": "2013-11-29T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60154, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.831Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.228Z", 
+        "deleted": false, 
+        "amount": 0.2072, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.96, 
+        "invoice": 70, 
+        "date": "2013-11-29T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60155, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.938Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.236Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 70, 
+        "date": "2013-11-30T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60156, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.046Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.245Z", 
+        "deleted": false, 
+        "amount": 0.2464, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.52, 
+        "invoice": 70, 
+        "date": "2013-11-30T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60157, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.154Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.253Z", 
+        "deleted": false, 
+        "amount": 0.3192, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.56, 
+        "invoice": 70, 
+        "date": "2013-11-30T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60158, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.261Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.261Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.16, 
+        "invoice": 70, 
+        "date": "2013-12-01T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60159, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.369Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.269Z", 
+        "deleted": false, 
+        "amount": 0.2072, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.96, 
+        "invoice": 70, 
+        "date": "2013-12-01T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60160, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.477Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.278Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.16, 
+        "invoice": 70, 
+        "date": "2013-12-01T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60161, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.593Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.286Z", 
+        "deleted": false, 
+        "amount": 0.14, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.0, 
+        "invoice": 71, 
+        "date": "2013-12-02T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60162, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.700Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.294Z", 
+        "deleted": false, 
+        "amount": 0.1848, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.64, 
+        "invoice": 71, 
+        "date": "2013-12-02T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60163, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.808Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.303Z", 
+        "deleted": false, 
+        "amount": 0.2576, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.68, 
+        "invoice": 71, 
+        "date": "2013-12-02T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60164, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.916Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.311Z", 
+        "deleted": false, 
+        "amount": 0.2072, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.96, 
+        "invoice": 71, 
+        "date": "2013-12-03T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60165, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.023Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.319Z", 
+        "deleted": false, 
+        "amount": 0.1848, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.64, 
+        "invoice": 71, 
+        "date": "2013-12-03T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60166, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.131Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.327Z", 
+        "deleted": false, 
+        "amount": 0.1568, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.24, 
+        "invoice": 71, 
+        "date": "2013-12-03T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60167, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.239Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.336Z", 
+        "deleted": false, 
+        "amount": 0.2128, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.04, 
+        "invoice": 71, 
+        "date": "2013-12-04T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60168, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.346Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.344Z", 
+        "deleted": false, 
+        "amount": 0.168, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.4, 
+        "invoice": 71, 
+        "date": "2013-12-04T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60169, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.454Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.352Z", 
+        "deleted": false, 
+        "amount": 0.28, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.0, 
+        "invoice": 71, 
+        "date": "2013-12-04T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60170, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.562Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.361Z", 
+        "deleted": false, 
+        "amount": 0.2296, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.28, 
+        "invoice": 71, 
+        "date": "2013-12-05T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60171, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.670Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.369Z", 
+        "deleted": false, 
+        "amount": 0.1904, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.72, 
+        "invoice": 71, 
+        "date": "2013-12-05T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60172, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.777Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.377Z", 
+        "deleted": false, 
+        "amount": 0.1624, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.32, 
+        "invoice": 71, 
+        "date": "2013-12-05T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60173, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.885Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.385Z", 
+        "deleted": false, 
+        "amount": 0.252, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.6, 
+        "invoice": 71, 
+        "date": "2013-12-06T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60174, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.993Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.394Z", 
+        "deleted": false, 
+        "amount": 0.112, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.6, 
+        "invoice": 71, 
+        "date": "2013-12-06T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60175, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.100Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.402Z", 
+        "deleted": false, 
+        "amount": 0.2576, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.68, 
+        "invoice": 71, 
+        "date": "2013-12-06T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60176, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.208Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.410Z", 
+        "deleted": false, 
+        "amount": 0.3192, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.56, 
+        "invoice": 71, 
+        "date": "2013-12-07T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60177, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.316Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.419Z", 
+        "deleted": false, 
+        "amount": 0.2632, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.76, 
+        "invoice": 71, 
+        "date": "2013-12-07T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60178, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.423Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.427Z", 
+        "deleted": false, 
+        "amount": 0.1792, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.56, 
+        "invoice": 71, 
+        "date": "2013-12-07T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60179, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.531Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.435Z", 
+        "deleted": false, 
+        "amount": 0.196, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.8, 
+        "invoice": 71, 
+        "date": "2013-12-08T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60180, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.639Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.443Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.68, 
+        "invoice": 71, 
+        "date": "2013-12-08T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60181, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.746Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.452Z", 
+        "deleted": false, 
+        "amount": 0.2408, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.44, 
+        "invoice": 71, 
+        "date": "2013-12-08T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60182, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.862Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.460Z", 
+        "deleted": false, 
+        "amount": 0.2576, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.68, 
+        "invoice": 72, 
+        "date": "2013-12-09T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60183, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.970Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.468Z", 
+        "deleted": false, 
+        "amount": 0.2744, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.92, 
+        "invoice": 72, 
+        "date": "2013-12-09T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60184, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.078Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.476Z", 
+        "deleted": false, 
+        "amount": 0.3024, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.32, 
+        "invoice": 72, 
+        "date": "2013-12-09T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60185, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.186Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.485Z", 
+        "deleted": false, 
+        "amount": 0.3192, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.56, 
+        "invoice": 72, 
+        "date": "2013-12-10T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60186, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.293Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.493Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 72, 
+        "date": "2013-12-10T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60187, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.401Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.501Z", 
+        "deleted": false, 
+        "amount": 0.3192, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.56, 
+        "invoice": 72, 
+        "date": "2013-12-10T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60188, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.509Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.510Z", 
+        "deleted": false, 
+        "amount": 0.168, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.4, 
+        "invoice": 72, 
+        "date": "2013-12-11T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60189, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.674Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.518Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 72, 
+        "date": "2013-12-11T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60190, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.782Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.526Z", 
+        "deleted": false, 
+        "amount": 0.1792, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.56, 
+        "invoice": 72, 
+        "date": "2013-12-11T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60191, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.890Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.535Z", 
+        "deleted": false, 
+        "amount": 0.2576, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.68, 
+        "invoice": 72, 
+        "date": "2013-12-12T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60192, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.997Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.543Z", 
+        "deleted": false, 
+        "amount": 0.2464, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.52, 
+        "invoice": 72, 
+        "date": "2013-12-12T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60193, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.105Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.551Z", 
+        "deleted": false, 
+        "amount": 0.2968, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.24, 
+        "invoice": 72, 
+        "date": "2013-12-12T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60194, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.213Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.559Z", 
+        "deleted": false, 
+        "amount": 0.28, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.0, 
+        "invoice": 72, 
+        "date": "2013-12-13T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60195, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.320Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.568Z", 
+        "deleted": false, 
+        "amount": 0.1344, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.92, 
+        "invoice": 72, 
+        "date": "2013-12-13T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60196, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.428Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.576Z", 
+        "deleted": false, 
+        "amount": 0.2128, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.04, 
+        "invoice": 72, 
+        "date": "2013-12-13T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60197, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.536Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.584Z", 
+        "deleted": false, 
+        "amount": 0.196, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.8, 
+        "invoice": 72, 
+        "date": "2013-12-14T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60198, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.644Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.593Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.16, 
+        "invoice": 72, 
+        "date": "2013-12-14T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60199, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.751Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.601Z", 
+        "deleted": false, 
+        "amount": 0.2632, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.76, 
+        "invoice": 72, 
+        "date": "2013-12-14T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60200, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.859Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.609Z", 
+        "deleted": false, 
+        "amount": 0.3024, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.32, 
+        "invoice": 72, 
+        "date": "2013-12-15T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60201, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.967Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.617Z", 
+        "deleted": false, 
+        "amount": 0.1568, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.24, 
+        "invoice": 72, 
+        "date": "2013-12-15T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60202, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.074Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.626Z", 
+        "deleted": false, 
+        "amount": 0.2352, 
+        "object": 108, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.36, 
+        "invoice": 72, 
+        "date": "2013-12-15T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60203, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:04.634Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.634Z", 
+        "deleted": false, 
+        "amount": 0.2688, 
+        "object": 108, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 3.84, 
+        "invoice": null, 
+        "date": "2013-12-16T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60204, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:04.642Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.642Z", 
+        "deleted": false, 
+        "amount": 0.14, 
+        "object": 108, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 2.0, 
+        "invoice": null, 
+        "date": "2013-12-16T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60205, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:04.651Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.651Z", 
+        "deleted": false, 
+        "amount": 0.28, 
+        "object": 108, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 4.0, 
+        "invoice": null, 
+        "date": "2013-12-16T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60206, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:04.659Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.659Z", 
+        "deleted": false, 
+        "amount": 0.2352, 
+        "object": 108, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 3.36, 
+        "invoice": null, 
+        "date": "2013-12-17T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60207, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:04.667Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.667Z", 
+        "deleted": false, 
+        "amount": 0.1848, 
+        "object": 108, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 2.64, 
+        "invoice": null, 
+        "date": "2013-12-17T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60208, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:04.676Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.676Z", 
+        "deleted": false, 
+        "amount": 0.2688, 
+        "object": 108, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 3.84, 
+        "invoice": null, 
+        "date": "2013-12-17T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60209, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:04.684Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.684Z", 
+        "deleted": false, 
+        "amount": 0.2184, 
+        "object": 108, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 3.12, 
+        "invoice": null, 
+        "date": "2013-12-18T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60210, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:04.692Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.692Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 108, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 1.68, 
+        "invoice": null, 
+        "date": "2013-12-18T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60211, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.235Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.707Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 69, 
+        "date": "2013-11-18T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60212, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.343Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.717Z", 
+        "deleted": false, 
+        "amount": 0.196, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.8, 
+        "invoice": 69, 
+        "date": "2013-11-19T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60213, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.451Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.725Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.68, 
+        "invoice": 69, 
+        "date": "2013-11-19T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60214, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.558Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.733Z", 
+        "deleted": false, 
+        "amount": 0.28, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.0, 
+        "invoice": 69, 
+        "date": "2013-11-19T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60215, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.666Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.742Z", 
+        "deleted": false, 
+        "amount": 0.1792, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.56, 
+        "invoice": 69, 
+        "date": "2013-11-20T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60216, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.774Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.750Z", 
+        "deleted": false, 
+        "amount": 0.14, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.0, 
+        "invoice": 69, 
+        "date": "2013-11-20T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60217, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.881Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.758Z", 
+        "deleted": false, 
+        "amount": 0.2576, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.68, 
+        "invoice": 69, 
+        "date": "2013-11-20T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60218, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.989Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.767Z", 
+        "deleted": false, 
+        "amount": 0.1736, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.48, 
+        "invoice": 69, 
+        "date": "2013-11-21T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60219, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.097Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.775Z", 
+        "deleted": false, 
+        "amount": 0.336, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.8, 
+        "invoice": 69, 
+        "date": "2013-11-21T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60220, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.205Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.783Z", 
+        "deleted": false, 
+        "amount": 0.2072, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.96, 
+        "invoice": 69, 
+        "date": "2013-11-21T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60221, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.312Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.791Z", 
+        "deleted": false, 
+        "amount": 0.2184, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.12, 
+        "invoice": 69, 
+        "date": "2013-11-22T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60222, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.420Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.800Z", 
+        "deleted": false, 
+        "amount": 0.196, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.8, 
+        "invoice": 69, 
+        "date": "2013-11-22T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60223, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.528Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.808Z", 
+        "deleted": false, 
+        "amount": 0.3192, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.56, 
+        "invoice": 69, 
+        "date": "2013-11-22T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60224, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.636Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.816Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.08, 
+        "invoice": 69, 
+        "date": "2013-11-23T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60225, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.743Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.825Z", 
+        "deleted": false, 
+        "amount": 0.2296, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.28, 
+        "invoice": 69, 
+        "date": "2013-11-23T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60226, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.851Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.833Z", 
+        "deleted": false, 
+        "amount": 0.2016, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.88, 
+        "invoice": 69, 
+        "date": "2013-11-23T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60227, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.958Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.841Z", 
+        "deleted": false, 
+        "amount": 0.2352, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.36, 
+        "invoice": 69, 
+        "date": "2013-11-24T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60228, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.066Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.849Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.08, 
+        "invoice": 69, 
+        "date": "2013-11-24T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60229, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.174Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.858Z", 
+        "deleted": false, 
+        "amount": 0.252, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.6, 
+        "invoice": 69, 
+        "date": "2013-11-24T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60230, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.290Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.866Z", 
+        "deleted": false, 
+        "amount": 0.2296, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.28, 
+        "invoice": 70, 
+        "date": "2013-11-25T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60231, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.397Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.874Z", 
+        "deleted": false, 
+        "amount": 0.1792, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.56, 
+        "invoice": 70, 
+        "date": "2013-11-25T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60232, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.505Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.883Z", 
+        "deleted": false, 
+        "amount": 0.1848, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.64, 
+        "invoice": 70, 
+        "date": "2013-11-25T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60233, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.654Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.891Z", 
+        "deleted": false, 
+        "amount": 0.2128, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.04, 
+        "invoice": 70, 
+        "date": "2013-11-26T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60234, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.762Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.899Z", 
+        "deleted": false, 
+        "amount": 0.252, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.6, 
+        "invoice": 70, 
+        "date": "2013-11-26T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60235, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.870Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.907Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.16, 
+        "invoice": 70, 
+        "date": "2013-11-26T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60236, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.977Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.915Z", 
+        "deleted": false, 
+        "amount": 0.1568, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.24, 
+        "invoice": 70, 
+        "date": "2013-11-27T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60237, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.085Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.924Z", 
+        "deleted": false, 
+        "amount": 0.1288, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.84, 
+        "invoice": 70, 
+        "date": "2013-11-27T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60238, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.193Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.932Z", 
+        "deleted": false, 
+        "amount": 0.2016, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.88, 
+        "invoice": 70, 
+        "date": "2013-11-27T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60239, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.300Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.940Z", 
+        "deleted": false, 
+        "amount": 0.2184, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.12, 
+        "invoice": 70, 
+        "date": "2013-11-28T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60240, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.408Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.949Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.08, 
+        "invoice": 70, 
+        "date": "2013-11-28T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60241, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.516Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.957Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.08, 
+        "invoice": 70, 
+        "date": "2013-11-28T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60242, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.623Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.965Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 70, 
+        "date": "2013-11-29T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60243, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.731Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.974Z", 
+        "deleted": false, 
+        "amount": 0.2408, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.44, 
+        "invoice": 70, 
+        "date": "2013-11-29T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60244, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.839Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.982Z", 
+        "deleted": false, 
+        "amount": 0.2688, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.84, 
+        "invoice": 70, 
+        "date": "2013-11-29T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60245, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.947Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.990Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 70, 
+        "date": "2013-11-30T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60246, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.054Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:04.998Z", 
+        "deleted": false, 
+        "amount": 0.1624, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.32, 
+        "invoice": 70, 
+        "date": "2013-11-30T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60247, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.162Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.007Z", 
+        "deleted": false, 
+        "amount": 0.1624, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.32, 
+        "invoice": 70, 
+        "date": "2013-11-30T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60248, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.270Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.015Z", 
+        "deleted": false, 
+        "amount": 0.2184, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.12, 
+        "invoice": 70, 
+        "date": "2013-12-01T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60249, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.377Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.023Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.68, 
+        "invoice": 70, 
+        "date": "2013-12-01T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60250, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.485Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.032Z", 
+        "deleted": false, 
+        "amount": 0.2632, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.76, 
+        "invoice": 70, 
+        "date": "2013-12-01T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60251, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.601Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.040Z", 
+        "deleted": false, 
+        "amount": 0.1904, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.72, 
+        "invoice": 71, 
+        "date": "2013-12-02T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60252, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.709Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.048Z", 
+        "deleted": false, 
+        "amount": 0.3024, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.32, 
+        "invoice": 71, 
+        "date": "2013-12-02T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60253, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.816Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.056Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 71, 
+        "date": "2013-12-02T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60254, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.924Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.065Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 71, 
+        "date": "2013-12-03T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60255, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.032Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.073Z", 
+        "deleted": false, 
+        "amount": 0.3248, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.64, 
+        "invoice": 71, 
+        "date": "2013-12-03T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60256, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.139Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.081Z", 
+        "deleted": false, 
+        "amount": 0.2968, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.24, 
+        "invoice": 71, 
+        "date": "2013-12-03T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60257, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.247Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.090Z", 
+        "deleted": false, 
+        "amount": 0.308, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.4, 
+        "invoice": 71, 
+        "date": "2013-12-04T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60258, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.355Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.098Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 71, 
+        "date": "2013-12-04T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60259, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.462Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.106Z", 
+        "deleted": false, 
+        "amount": 0.252, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.6, 
+        "invoice": 71, 
+        "date": "2013-12-04T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60260, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.570Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.114Z", 
+        "deleted": false, 
+        "amount": 0.2744, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.92, 
+        "invoice": 71, 
+        "date": "2013-12-05T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60261, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.678Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.123Z", 
+        "deleted": false, 
+        "amount": 0.2632, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.76, 
+        "invoice": 71, 
+        "date": "2013-12-05T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60262, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.786Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.131Z", 
+        "deleted": false, 
+        "amount": 0.2016, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.88, 
+        "invoice": 71, 
+        "date": "2013-12-05T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60263, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.893Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.140Z", 
+        "deleted": false, 
+        "amount": 0.2688, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.84, 
+        "invoice": 71, 
+        "date": "2013-12-06T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60264, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.001Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.148Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 71, 
+        "date": "2013-12-06T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60265, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.109Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.156Z", 
+        "deleted": false, 
+        "amount": 0.1848, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.64, 
+        "invoice": 71, 
+        "date": "2013-12-06T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60266, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.216Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.164Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.68, 
+        "invoice": 71, 
+        "date": "2013-12-07T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60267, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.324Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.173Z", 
+        "deleted": false, 
+        "amount": 0.2016, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.88, 
+        "invoice": 71, 
+        "date": "2013-12-07T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60268, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.432Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.181Z", 
+        "deleted": false, 
+        "amount": 0.224, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.2, 
+        "invoice": 71, 
+        "date": "2013-12-07T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60269, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.539Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.189Z", 
+        "deleted": false, 
+        "amount": 0.168, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.4, 
+        "invoice": 71, 
+        "date": "2013-12-08T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60270, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.647Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.197Z", 
+        "deleted": false, 
+        "amount": 0.2968, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.24, 
+        "invoice": 71, 
+        "date": "2013-12-08T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60271, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.755Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.206Z", 
+        "deleted": false, 
+        "amount": 0.1568, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.24, 
+        "invoice": 71, 
+        "date": "2013-12-08T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60272, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.871Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.214Z", 
+        "deleted": false, 
+        "amount": 0.2744, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.92, 
+        "invoice": 72, 
+        "date": "2013-12-09T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60273, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.978Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.222Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 72, 
+        "date": "2013-12-09T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60274, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.086Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.231Z", 
+        "deleted": false, 
+        "amount": 0.1512, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.16, 
+        "invoice": 72, 
+        "date": "2013-12-09T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60275, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.194Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.253Z", 
+        "deleted": false, 
+        "amount": 0.1288, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.84, 
+        "invoice": 72, 
+        "date": "2013-12-10T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60276, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.301Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.331Z", 
+        "deleted": false, 
+        "amount": 0.252, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.6, 
+        "invoice": 72, 
+        "date": "2013-12-10T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60277, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.409Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.346Z", 
+        "deleted": false, 
+        "amount": 0.196, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.8, 
+        "invoice": 72, 
+        "date": "2013-12-10T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60278, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.517Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.355Z", 
+        "deleted": false, 
+        "amount": 0.1904, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.72, 
+        "invoice": 72, 
+        "date": "2013-12-11T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60279, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.683Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.363Z", 
+        "deleted": false, 
+        "amount": 0.2408, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.44, 
+        "invoice": 72, 
+        "date": "2013-12-11T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60280, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.790Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.371Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 72, 
+        "date": "2013-12-11T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60281, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.898Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.380Z", 
+        "deleted": false, 
+        "amount": 0.2408, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.44, 
+        "invoice": 72, 
+        "date": "2013-12-12T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60282, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.006Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.388Z", 
+        "deleted": false, 
+        "amount": 0.1512, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.16, 
+        "invoice": 72, 
+        "date": "2013-12-12T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60283, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.113Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.396Z", 
+        "deleted": false, 
+        "amount": 0.28, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.0, 
+        "invoice": 72, 
+        "date": "2013-12-12T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60284, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.221Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.404Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 72, 
+        "date": "2013-12-13T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60285, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.329Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.413Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.08, 
+        "invoice": 72, 
+        "date": "2013-12-13T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60286, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.436Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.421Z", 
+        "deleted": false, 
+        "amount": 0.3192, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.56, 
+        "invoice": 72, 
+        "date": "2013-12-13T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60287, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.544Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.429Z", 
+        "deleted": false, 
+        "amount": 0.3248, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.64, 
+        "invoice": 72, 
+        "date": "2013-12-14T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60288, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.652Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.438Z", 
+        "deleted": false, 
+        "amount": 0.2352, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.36, 
+        "invoice": 72, 
+        "date": "2013-12-14T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60289, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.759Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.446Z", 
+        "deleted": false, 
+        "amount": 0.1288, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.84, 
+        "invoice": 72, 
+        "date": "2013-12-14T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60290, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.867Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.454Z", 
+        "deleted": false, 
+        "amount": 0.28, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.0, 
+        "invoice": 72, 
+        "date": "2013-12-15T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60291, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.975Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.462Z", 
+        "deleted": false, 
+        "amount": 0.2464, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.52, 
+        "invoice": 72, 
+        "date": "2013-12-15T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60292, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.083Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.471Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 109, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 72, 
+        "date": "2013-12-15T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60293, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:05.479Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.479Z", 
+        "deleted": false, 
+        "amount": 0.2632, 
+        "object": 109, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 3.76, 
+        "invoice": null, 
+        "date": "2013-12-16T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60294, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:05.487Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.487Z", 
+        "deleted": false, 
+        "amount": 0.1736, 
+        "object": 109, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 2.48, 
+        "invoice": null, 
+        "date": "2013-12-16T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60295, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:05.496Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.495Z", 
+        "deleted": false, 
+        "amount": 0.3248, 
+        "object": 109, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 4.64, 
+        "invoice": null, 
+        "date": "2013-12-16T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60296, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:05.504Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.504Z", 
+        "deleted": false, 
+        "amount": 0.1344, 
+        "object": 109, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 1.92, 
+        "invoice": null, 
+        "date": "2013-12-17T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60297, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:05.512Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.512Z", 
+        "deleted": false, 
+        "amount": 0.1624, 
+        "object": 109, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 2.32, 
+        "invoice": null, 
+        "date": "2013-12-17T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60298, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:05.520Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.520Z", 
+        "deleted": false, 
+        "amount": 0.2968, 
+        "object": 109, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 4.24, 
+        "invoice": null, 
+        "date": "2013-12-17T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60299, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:05.529Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.529Z", 
+        "deleted": false, 
+        "amount": 0.1232, 
+        "object": 109, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 1.76, 
+        "invoice": null, 
+        "date": "2013-12-18T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60300, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:05.537Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.537Z", 
+        "deleted": false, 
+        "amount": 0.2296, 
+        "object": 109, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 3.28, 
+        "invoice": null, 
+        "date": "2013-12-18T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60301, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.244Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.552Z", 
+        "deleted": false, 
+        "amount": 0.2072, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.96, 
+        "invoice": 69, 
+        "date": "2013-11-18T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60302, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.351Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.562Z", 
+        "deleted": false, 
+        "amount": 0.1512, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.16, 
+        "invoice": 69, 
+        "date": "2013-11-19T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60303, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.459Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.570Z", 
+        "deleted": false, 
+        "amount": 0.1232, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.76, 
+        "invoice": 69, 
+        "date": "2013-11-19T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60304, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.567Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.578Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.68, 
+        "invoice": 69, 
+        "date": "2013-11-19T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60305, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.674Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.587Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.16, 
+        "invoice": 69, 
+        "date": "2013-11-20T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60306, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.782Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.595Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.08, 
+        "invoice": 69, 
+        "date": "2013-11-20T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60307, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.890Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.603Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 69, 
+        "date": "2013-11-20T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60308, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.997Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.611Z", 
+        "deleted": false, 
+        "amount": 0.252, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.6, 
+        "invoice": 69, 
+        "date": "2013-11-21T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60309, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.105Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.620Z", 
+        "deleted": false, 
+        "amount": 0.2968, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.24, 
+        "invoice": 69, 
+        "date": "2013-11-21T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60310, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.213Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.630Z", 
+        "deleted": false, 
+        "amount": 0.2184, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.12, 
+        "invoice": 69, 
+        "date": "2013-11-21T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60311, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.321Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.645Z", 
+        "deleted": false, 
+        "amount": 0.3248, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.64, 
+        "invoice": 69, 
+        "date": "2013-11-22T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60312, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.428Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.655Z", 
+        "deleted": false, 
+        "amount": 0.1736, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.48, 
+        "invoice": 69, 
+        "date": "2013-11-22T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60313, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.536Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.670Z", 
+        "deleted": false, 
+        "amount": 0.2968, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.24, 
+        "invoice": 69, 
+        "date": "2013-11-22T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60314, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.644Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.680Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.68, 
+        "invoice": 69, 
+        "date": "2013-11-23T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60315, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.751Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.694Z", 
+        "deleted": false, 
+        "amount": 0.224, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.2, 
+        "invoice": 69, 
+        "date": "2013-11-23T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60316, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.859Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.705Z", 
+        "deleted": false, 
+        "amount": 0.1624, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.32, 
+        "invoice": 69, 
+        "date": "2013-11-23T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60317, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.967Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.719Z", 
+        "deleted": false, 
+        "amount": 0.3192, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.56, 
+        "invoice": 69, 
+        "date": "2013-11-24T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60318, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.074Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.730Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 69, 
+        "date": "2013-11-24T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60319, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.182Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.738Z", 
+        "deleted": false, 
+        "amount": 0.1288, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.84, 
+        "invoice": 69, 
+        "date": "2013-11-24T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60320, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.298Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.747Z", 
+        "deleted": false, 
+        "amount": 0.1736, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.48, 
+        "invoice": 70, 
+        "date": "2013-11-25T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60321, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.406Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.755Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 70, 
+        "date": "2013-11-25T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60322, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.513Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.763Z", 
+        "deleted": false, 
+        "amount": 0.2296, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.28, 
+        "invoice": 70, 
+        "date": "2013-11-25T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60323, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.663Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.771Z", 
+        "deleted": false, 
+        "amount": 0.2072, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.96, 
+        "invoice": 70, 
+        "date": "2013-11-26T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60324, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.770Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.780Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.08, 
+        "invoice": 70, 
+        "date": "2013-11-26T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60325, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.878Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.788Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 70, 
+        "date": "2013-11-26T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60326, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.986Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.796Z", 
+        "deleted": false, 
+        "amount": 0.2352, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.36, 
+        "invoice": 70, 
+        "date": "2013-11-27T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60327, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.093Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.804Z", 
+        "deleted": false, 
+        "amount": 0.2408, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.44, 
+        "invoice": 70, 
+        "date": "2013-11-27T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60328, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.201Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.813Z", 
+        "deleted": false, 
+        "amount": 0.2128, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.04, 
+        "invoice": 70, 
+        "date": "2013-11-27T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60329, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.309Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.821Z", 
+        "deleted": false, 
+        "amount": 0.2408, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.44, 
+        "invoice": 70, 
+        "date": "2013-11-28T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60330, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.416Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.829Z", 
+        "deleted": false, 
+        "amount": 0.2296, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.28, 
+        "invoice": 70, 
+        "date": "2013-11-28T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60331, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.524Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.838Z", 
+        "deleted": false, 
+        "amount": 0.2576, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.68, 
+        "invoice": 70, 
+        "date": "2013-11-28T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60332, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.632Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.846Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 70, 
+        "date": "2013-11-29T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60333, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.739Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.854Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.68, 
+        "invoice": 70, 
+        "date": "2013-11-29T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60334, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.847Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.862Z", 
+        "deleted": false, 
+        "amount": 0.2072, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.96, 
+        "invoice": 70, 
+        "date": "2013-11-29T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60335, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.955Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.871Z", 
+        "deleted": false, 
+        "amount": 0.2632, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.76, 
+        "invoice": 70, 
+        "date": "2013-11-30T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60336, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.062Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.879Z", 
+        "deleted": false, 
+        "amount": 0.1736, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.48, 
+        "invoice": 70, 
+        "date": "2013-11-30T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60337, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.170Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.887Z", 
+        "deleted": false, 
+        "amount": 0.2632, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.76, 
+        "invoice": 70, 
+        "date": "2013-11-30T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60338, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.278Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.896Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 70, 
+        "date": "2013-12-01T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60339, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.385Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.904Z", 
+        "deleted": false, 
+        "amount": 0.2744, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.92, 
+        "invoice": 70, 
+        "date": "2013-12-01T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60340, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.493Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.912Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 70, 
+        "date": "2013-12-01T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60341, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.609Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.921Z", 
+        "deleted": false, 
+        "amount": 0.168, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.4, 
+        "invoice": 71, 
+        "date": "2013-12-02T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60342, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.717Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.929Z", 
+        "deleted": false, 
+        "amount": 0.14, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.0, 
+        "invoice": 71, 
+        "date": "2013-12-02T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60343, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.825Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.937Z", 
+        "deleted": false, 
+        "amount": 0.1288, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.84, 
+        "invoice": 71, 
+        "date": "2013-12-02T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60344, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.932Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.945Z", 
+        "deleted": false, 
+        "amount": 0.2632, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.76, 
+        "invoice": 71, 
+        "date": "2013-12-03T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60345, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.040Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.954Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.16, 
+        "invoice": 71, 
+        "date": "2013-12-03T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60346, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.148Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.962Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 71, 
+        "date": "2013-12-03T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60347, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.255Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.970Z", 
+        "deleted": false, 
+        "amount": 0.2688, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.84, 
+        "invoice": 71, 
+        "date": "2013-12-04T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60348, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.363Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.978Z", 
+        "deleted": false, 
+        "amount": 0.308, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.4, 
+        "invoice": 71, 
+        "date": "2013-12-04T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60349, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.471Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.987Z", 
+        "deleted": false, 
+        "amount": 0.1288, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.84, 
+        "invoice": 71, 
+        "date": "2013-12-04T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60350, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.578Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:05.995Z", 
+        "deleted": false, 
+        "amount": 0.3248, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.64, 
+        "invoice": 71, 
+        "date": "2013-12-05T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60351, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.686Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.003Z", 
+        "deleted": false, 
+        "amount": 0.2968, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.24, 
+        "invoice": 71, 
+        "date": "2013-12-05T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60352, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.794Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.012Z", 
+        "deleted": false, 
+        "amount": 0.3024, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.32, 
+        "invoice": 71, 
+        "date": "2013-12-05T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60353, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.902Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.020Z", 
+        "deleted": false, 
+        "amount": 0.224, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.2, 
+        "invoice": 71, 
+        "date": "2013-12-06T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60354, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.009Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.028Z", 
+        "deleted": false, 
+        "amount": 0.1848, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.64, 
+        "invoice": 71, 
+        "date": "2013-12-06T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60355, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.117Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.036Z", 
+        "deleted": false, 
+        "amount": 0.2576, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.68, 
+        "invoice": 71, 
+        "date": "2013-12-06T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60356, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.225Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.045Z", 
+        "deleted": false, 
+        "amount": 0.2968, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.24, 
+        "invoice": 71, 
+        "date": "2013-12-07T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60357, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.332Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.053Z", 
+        "deleted": false, 
+        "amount": 0.168, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.4, 
+        "invoice": 71, 
+        "date": "2013-12-07T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60358, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.440Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.061Z", 
+        "deleted": false, 
+        "amount": 0.1848, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.64, 
+        "invoice": 71, 
+        "date": "2013-12-07T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60359, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.548Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.070Z", 
+        "deleted": false, 
+        "amount": 0.2128, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.04, 
+        "invoice": 71, 
+        "date": "2013-12-08T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60360, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.655Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.078Z", 
+        "deleted": false, 
+        "amount": 0.1568, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.24, 
+        "invoice": 71, 
+        "date": "2013-12-08T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60361, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.763Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.086Z", 
+        "deleted": false, 
+        "amount": 0.2576, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.68, 
+        "invoice": 71, 
+        "date": "2013-12-08T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60362, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.879Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.094Z", 
+        "deleted": false, 
+        "amount": 0.1792, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.56, 
+        "invoice": 72, 
+        "date": "2013-12-09T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60363, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.987Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.103Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 72, 
+        "date": "2013-12-09T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60364, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.094Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.111Z", 
+        "deleted": false, 
+        "amount": 0.1848, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.64, 
+        "invoice": 72, 
+        "date": "2013-12-09T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60365, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.202Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.119Z", 
+        "deleted": false, 
+        "amount": 0.1344, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.92, 
+        "invoice": 72, 
+        "date": "2013-12-10T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60366, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.310Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.128Z", 
+        "deleted": false, 
+        "amount": 0.1792, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.56, 
+        "invoice": 72, 
+        "date": "2013-12-10T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60367, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.418Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.136Z", 
+        "deleted": false, 
+        "amount": 0.196, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.8, 
+        "invoice": 72, 
+        "date": "2013-12-10T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60368, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.525Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.144Z", 
+        "deleted": false, 
+        "amount": 0.1232, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.76, 
+        "invoice": 72, 
+        "date": "2013-12-11T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60369, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.691Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.153Z", 
+        "deleted": false, 
+        "amount": 0.3192, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.56, 
+        "invoice": 72, 
+        "date": "2013-12-11T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60370, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.798Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.161Z", 
+        "deleted": false, 
+        "amount": 0.2184, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.12, 
+        "invoice": 72, 
+        "date": "2013-12-11T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60371, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.906Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.169Z", 
+        "deleted": false, 
+        "amount": 0.3192, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.56, 
+        "invoice": 72, 
+        "date": "2013-12-12T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60372, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.014Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.177Z", 
+        "deleted": false, 
+        "amount": 0.3024, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.32, 
+        "invoice": 72, 
+        "date": "2013-12-12T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60373, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.122Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.186Z", 
+        "deleted": false, 
+        "amount": 0.1288, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.84, 
+        "invoice": 72, 
+        "date": "2013-12-12T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60374, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.229Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.194Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.08, 
+        "invoice": 72, 
+        "date": "2013-12-13T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60375, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.337Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.202Z", 
+        "deleted": false, 
+        "amount": 0.1288, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.84, 
+        "invoice": 72, 
+        "date": "2013-12-13T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60376, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.445Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.210Z", 
+        "deleted": false, 
+        "amount": 0.2632, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.76, 
+        "invoice": 72, 
+        "date": "2013-12-13T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60377, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.552Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.219Z", 
+        "deleted": false, 
+        "amount": 0.3192, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.56, 
+        "invoice": 72, 
+        "date": "2013-12-14T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60378, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.660Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.227Z", 
+        "deleted": false, 
+        "amount": 0.224, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.2, 
+        "invoice": 72, 
+        "date": "2013-12-14T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60379, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.768Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.235Z", 
+        "deleted": false, 
+        "amount": 0.2184, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.12, 
+        "invoice": 72, 
+        "date": "2013-12-14T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60380, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.875Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.244Z", 
+        "deleted": false, 
+        "amount": 0.196, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.8, 
+        "invoice": 72, 
+        "date": "2013-12-15T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60381, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.983Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.252Z", 
+        "deleted": false, 
+        "amount": 0.28, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.0, 
+        "invoice": 72, 
+        "date": "2013-12-15T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60382, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.091Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.260Z", 
+        "deleted": false, 
+        "amount": 0.224, 
+        "object": 110, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.2, 
+        "invoice": 72, 
+        "date": "2013-12-15T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60383, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:06.269Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.268Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 110, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 4.72, 
+        "invoice": null, 
+        "date": "2013-12-16T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60384, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:06.277Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.277Z", 
+        "deleted": false, 
+        "amount": 0.1848, 
+        "object": 110, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 2.64, 
+        "invoice": null, 
+        "date": "2013-12-16T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60385, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:06.285Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.285Z", 
+        "deleted": false, 
+        "amount": 0.28, 
+        "object": 110, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 4.0, 
+        "invoice": null, 
+        "date": "2013-12-16T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60386, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:06.293Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.293Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 110, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 1.68, 
+        "invoice": null, 
+        "date": "2013-12-17T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60387, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:06.302Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.302Z", 
+        "deleted": false, 
+        "amount": 0.2016, 
+        "object": 110, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 2.88, 
+        "invoice": null, 
+        "date": "2013-12-17T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60388, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:06.310Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.310Z", 
+        "deleted": false, 
+        "amount": 0.2576, 
+        "object": 110, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 3.68, 
+        "invoice": null, 
+        "date": "2013-12-17T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60389, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:06.318Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.318Z", 
+        "deleted": false, 
+        "amount": 0.336, 
+        "object": 110, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 4.8, 
+        "invoice": null, 
+        "date": "2013-12-18T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60390, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:06.326Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.326Z", 
+        "deleted": false, 
+        "amount": 0.3248, 
+        "object": 110, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 4.64, 
+        "invoice": null, 
+        "date": "2013-12-18T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60391, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.252Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.341Z", 
+        "deleted": false, 
+        "amount": 0.3248, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.64, 
+        "invoice": 69, 
+        "date": "2013-11-18T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60392, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.360Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.351Z", 
+        "deleted": false, 
+        "amount": 0.3248, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.64, 
+        "invoice": 69, 
+        "date": "2013-11-19T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60393, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.467Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.360Z", 
+        "deleted": false, 
+        "amount": 0.2576, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.68, 
+        "invoice": 69, 
+        "date": "2013-11-19T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60394, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.575Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.368Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 69, 
+        "date": "2013-11-19T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60395, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.683Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.376Z", 
+        "deleted": false, 
+        "amount": 0.112, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.6, 
+        "invoice": 69, 
+        "date": "2013-11-20T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60396, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.790Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.384Z", 
+        "deleted": false, 
+        "amount": 0.28, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.0, 
+        "invoice": 69, 
+        "date": "2013-11-20T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60397, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.898Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.393Z", 
+        "deleted": false, 
+        "amount": 0.1344, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.92, 
+        "invoice": 69, 
+        "date": "2013-11-20T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60398, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.006Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.401Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.68, 
+        "invoice": 69, 
+        "date": "2013-11-21T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60399, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.113Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.409Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.68, 
+        "invoice": 69, 
+        "date": "2013-11-21T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60400, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.221Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.417Z", 
+        "deleted": false, 
+        "amount": 0.3024, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.32, 
+        "invoice": 69, 
+        "date": "2013-11-21T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60401, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.329Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.426Z", 
+        "deleted": false, 
+        "amount": 0.1232, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.76, 
+        "invoice": 69, 
+        "date": "2013-11-22T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60402, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.436Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.434Z", 
+        "deleted": false, 
+        "amount": 0.252, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.6, 
+        "invoice": 69, 
+        "date": "2013-11-22T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60403, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.544Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.442Z", 
+        "deleted": false, 
+        "amount": 0.1624, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.32, 
+        "invoice": 69, 
+        "date": "2013-11-22T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60404, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.652Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.451Z", 
+        "deleted": false, 
+        "amount": 0.2632, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.76, 
+        "invoice": 69, 
+        "date": "2013-11-23T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60405, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.760Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.459Z", 
+        "deleted": false, 
+        "amount": 0.1848, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.64, 
+        "invoice": 69, 
+        "date": "2013-11-23T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60406, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.867Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.467Z", 
+        "deleted": false, 
+        "amount": 0.2184, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.12, 
+        "invoice": 69, 
+        "date": "2013-11-23T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60407, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.975Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.475Z", 
+        "deleted": false, 
+        "amount": 0.2408, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.44, 
+        "invoice": 69, 
+        "date": "2013-11-24T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60408, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.083Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.484Z", 
+        "deleted": false, 
+        "amount": 0.2184, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.12, 
+        "invoice": 69, 
+        "date": "2013-11-24T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60409, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.190Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.492Z", 
+        "deleted": false, 
+        "amount": 0.1288, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.84, 
+        "invoice": 69, 
+        "date": "2013-11-24T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60410, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.306Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.500Z", 
+        "deleted": false, 
+        "amount": 0.2688, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.84, 
+        "invoice": 70, 
+        "date": "2013-11-25T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60411, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.414Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.509Z", 
+        "deleted": false, 
+        "amount": 0.2072, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.96, 
+        "invoice": 70, 
+        "date": "2013-11-25T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60412, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.522Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.517Z", 
+        "deleted": false, 
+        "amount": 0.1232, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.76, 
+        "invoice": 70, 
+        "date": "2013-11-25T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60413, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.671Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.525Z", 
+        "deleted": false, 
+        "amount": 0.1792, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.56, 
+        "invoice": 70, 
+        "date": "2013-11-26T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60414, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.779Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.534Z", 
+        "deleted": false, 
+        "amount": 0.3024, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.32, 
+        "invoice": 70, 
+        "date": "2013-11-26T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60415, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.886Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.542Z", 
+        "deleted": false, 
+        "amount": 0.1568, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.24, 
+        "invoice": 70, 
+        "date": "2013-11-26T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60416, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.994Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.550Z", 
+        "deleted": false, 
+        "amount": 0.1232, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.76, 
+        "invoice": 70, 
+        "date": "2013-11-27T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60417, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.102Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.558Z", 
+        "deleted": false, 
+        "amount": 0.3248, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.64, 
+        "invoice": 70, 
+        "date": "2013-11-27T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60418, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.209Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.567Z", 
+        "deleted": false, 
+        "amount": 0.14, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.0, 
+        "invoice": 70, 
+        "date": "2013-11-27T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60419, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.317Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.575Z", 
+        "deleted": false, 
+        "amount": 0.2352, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.36, 
+        "invoice": 70, 
+        "date": "2013-11-28T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60420, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.425Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.583Z", 
+        "deleted": false, 
+        "amount": 0.1568, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.24, 
+        "invoice": 70, 
+        "date": "2013-11-28T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60421, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.532Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.591Z", 
+        "deleted": false, 
+        "amount": 0.1288, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.84, 
+        "invoice": 70, 
+        "date": "2013-11-28T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60422, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.640Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.600Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.16, 
+        "invoice": 70, 
+        "date": "2013-11-29T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60423, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.748Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.608Z", 
+        "deleted": false, 
+        "amount": 0.14, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.0, 
+        "invoice": 70, 
+        "date": "2013-11-29T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60424, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.855Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.616Z", 
+        "deleted": false, 
+        "amount": 0.1792, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.56, 
+        "invoice": 70, 
+        "date": "2013-11-29T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60425, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.963Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.625Z", 
+        "deleted": false, 
+        "amount": 0.252, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.6, 
+        "invoice": 70, 
+        "date": "2013-11-30T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60426, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.071Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.633Z", 
+        "deleted": false, 
+        "amount": 0.196, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.8, 
+        "invoice": 70, 
+        "date": "2013-11-30T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60427, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.178Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.641Z", 
+        "deleted": false, 
+        "amount": 0.2744, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.92, 
+        "invoice": 70, 
+        "date": "2013-11-30T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60428, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.286Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.650Z", 
+        "deleted": false, 
+        "amount": 0.168, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.4, 
+        "invoice": 70, 
+        "date": "2013-12-01T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60429, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.394Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.658Z", 
+        "deleted": false, 
+        "amount": 0.3024, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.32, 
+        "invoice": 70, 
+        "date": "2013-12-01T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60430, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.501Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.666Z", 
+        "deleted": false, 
+        "amount": 0.3192, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.56, 
+        "invoice": 70, 
+        "date": "2013-12-01T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60431, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.617Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.674Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 71, 
+        "date": "2013-12-02T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60432, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.725Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.683Z", 
+        "deleted": false, 
+        "amount": 0.3024, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.32, 
+        "invoice": 71, 
+        "date": "2013-12-02T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60433, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.833Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.691Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.68, 
+        "invoice": 71, 
+        "date": "2013-12-02T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60434, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.941Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.699Z", 
+        "deleted": false, 
+        "amount": 0.1232, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.76, 
+        "invoice": 71, 
+        "date": "2013-12-03T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60435, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.048Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.708Z", 
+        "deleted": false, 
+        "amount": 0.2632, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.76, 
+        "invoice": 71, 
+        "date": "2013-12-03T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60436, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.156Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.716Z", 
+        "deleted": false, 
+        "amount": 0.2128, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.04, 
+        "invoice": 71, 
+        "date": "2013-12-03T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60437, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.264Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.724Z", 
+        "deleted": false, 
+        "amount": 0.2968, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.24, 
+        "invoice": 71, 
+        "date": "2013-12-04T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60438, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.371Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.732Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.16, 
+        "invoice": 71, 
+        "date": "2013-12-04T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60439, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.479Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.741Z", 
+        "deleted": false, 
+        "amount": 0.1848, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.64, 
+        "invoice": 71, 
+        "date": "2013-12-04T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60440, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.587Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.749Z", 
+        "deleted": false, 
+        "amount": 0.1568, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.24, 
+        "invoice": 71, 
+        "date": "2013-12-05T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60441, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.694Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.757Z", 
+        "deleted": false, 
+        "amount": 0.2296, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.28, 
+        "invoice": 71, 
+        "date": "2013-12-05T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60442, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.802Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.766Z", 
+        "deleted": false, 
+        "amount": 0.1848, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.64, 
+        "invoice": 71, 
+        "date": "2013-12-05T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60443, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.910Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.774Z", 
+        "deleted": false, 
+        "amount": 0.112, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.6, 
+        "invoice": 71, 
+        "date": "2013-12-06T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60444, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.017Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.782Z", 
+        "deleted": false, 
+        "amount": 0.2296, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.28, 
+        "invoice": 71, 
+        "date": "2013-12-06T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60445, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.125Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.790Z", 
+        "deleted": false, 
+        "amount": 0.1232, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.76, 
+        "invoice": 71, 
+        "date": "2013-12-06T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60446, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.233Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.799Z", 
+        "deleted": false, 
+        "amount": 0.1288, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.84, 
+        "invoice": 71, 
+        "date": "2013-12-07T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60447, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.341Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.807Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.08, 
+        "invoice": 71, 
+        "date": "2013-12-07T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60448, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.448Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.815Z", 
+        "deleted": false, 
+        "amount": 0.252, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.6, 
+        "invoice": 71, 
+        "date": "2013-12-07T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60449, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.556Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.823Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 71, 
+        "date": "2013-12-08T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60450, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.664Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.832Z", 
+        "deleted": false, 
+        "amount": 0.2408, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.44, 
+        "invoice": 71, 
+        "date": "2013-12-08T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60451, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.771Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.840Z", 
+        "deleted": false, 
+        "amount": 0.2016, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.88, 
+        "invoice": 71, 
+        "date": "2013-12-08T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60452, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.887Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.848Z", 
+        "deleted": false, 
+        "amount": 0.2464, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.52, 
+        "invoice": 72, 
+        "date": "2013-12-09T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60453, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.995Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.857Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 72, 
+        "date": "2013-12-09T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60454, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.103Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.865Z", 
+        "deleted": false, 
+        "amount": 0.3192, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.56, 
+        "invoice": 72, 
+        "date": "2013-12-09T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60455, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.210Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.873Z", 
+        "deleted": false, 
+        "amount": 0.2576, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.68, 
+        "invoice": 72, 
+        "date": "2013-12-10T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60456, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.318Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.881Z", 
+        "deleted": false, 
+        "amount": 0.2072, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.96, 
+        "invoice": 72, 
+        "date": "2013-12-10T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60457, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.426Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.890Z", 
+        "deleted": false, 
+        "amount": 0.2184, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.12, 
+        "invoice": 72, 
+        "date": "2013-12-10T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60458, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.533Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.898Z", 
+        "deleted": false, 
+        "amount": 0.1344, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.92, 
+        "invoice": 72, 
+        "date": "2013-12-11T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60459, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.699Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.906Z", 
+        "deleted": false, 
+        "amount": 0.28, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 4.0, 
+        "invoice": 72, 
+        "date": "2013-12-11T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60460, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.807Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.915Z", 
+        "deleted": false, 
+        "amount": 0.1568, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.24, 
+        "invoice": 72, 
+        "date": "2013-12-11T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60461, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.914Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.923Z", 
+        "deleted": false, 
+        "amount": 0.2744, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.92, 
+        "invoice": 72, 
+        "date": "2013-12-12T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60462, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.022Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.931Z", 
+        "deleted": false, 
+        "amount": 0.1624, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.32, 
+        "invoice": 72, 
+        "date": "2013-12-12T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60463, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.130Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.939Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.08, 
+        "invoice": 72, 
+        "date": "2013-12-12T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60464, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.238Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.948Z", 
+        "deleted": false, 
+        "amount": 0.14, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.0, 
+        "invoice": 72, 
+        "date": "2013-12-13T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60465, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.345Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.956Z", 
+        "deleted": false, 
+        "amount": 0.224, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.2, 
+        "invoice": 72, 
+        "date": "2013-12-13T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60466, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.453Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.964Z", 
+        "deleted": false, 
+        "amount": 0.2688, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.84, 
+        "invoice": 72, 
+        "date": "2013-12-13T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60467, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.561Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.972Z", 
+        "deleted": false, 
+        "amount": 0.224, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.2, 
+        "invoice": 72, 
+        "date": "2013-12-14T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60468, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.668Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.981Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.68, 
+        "invoice": 72, 
+        "date": "2013-12-14T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60469, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.776Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.989Z", 
+        "deleted": false, 
+        "amount": 0.2296, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.28, 
+        "invoice": 72, 
+        "date": "2013-12-14T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60470, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.884Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:06.997Z", 
+        "deleted": false, 
+        "amount": 0.2072, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 2.96, 
+        "invoice": 72, 
+        "date": "2013-12-15T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60471, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.991Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:07.006Z", 
+        "deleted": false, 
+        "amount": 0.1344, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 1.92, 
+        "invoice": 72, 
+        "date": "2013-12-15T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60472, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.099Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:07.014Z", 
+        "deleted": false, 
+        "amount": 0.2352, 
+        "object": 111, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 3.36, 
+        "invoice": 72, 
+        "date": "2013-12-15T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60473, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:07.022Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:07.022Z", 
+        "deleted": false, 
+        "amount": 0.308, 
+        "object": 111, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 4.4, 
+        "invoice": null, 
+        "date": "2013-12-16T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60474, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:07.031Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:07.031Z", 
+        "deleted": false, 
+        "amount": 0.14, 
+        "object": 111, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 2.0, 
+        "invoice": null, 
+        "date": "2013-12-16T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60475, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:07.039Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:07.039Z", 
+        "deleted": false, 
+        "amount": 0.1344, 
+        "object": 111, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 1.92, 
+        "invoice": null, 
+        "date": "2013-12-16T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60476, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:07.047Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:07.047Z", 
+        "deleted": false, 
+        "amount": 0.196, 
+        "object": 111, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 2.8, 
+        "invoice": null, 
+        "date": "2013-12-17T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60477, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:07.055Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:07.055Z", 
+        "deleted": false, 
+        "amount": 0.336, 
+        "object": 111, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 4.8, 
+        "invoice": null, 
+        "date": "2013-12-17T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60478, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:07.064Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:07.064Z", 
+        "deleted": false, 
+        "amount": 0.3248, 
+        "object": 111, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 4.64, 
+        "invoice": null, 
+        "date": "2013-12-17T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60479, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:07.072Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:07.072Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 111, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 4.16, 
+        "invoice": null, 
+        "date": "2013-12-18T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60480, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:07.080Z", 
+        "slice": 6, 
+        "created": "2013-12-18T21:29:07.080Z", 
+        "deleted": false, 
+        "amount": 0.28, 
+        "object": 111, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 4.0, 
+        "invoice": null, 
+        "date": "2013-12-18T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60481, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.260Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.112Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-18T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60482, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.368Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.122Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-19T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60483, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.476Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.130Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-19T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60484, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.583Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.138Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-19T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60485, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.691Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.147Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-20T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60486, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.799Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.155Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-20T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60487, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.906Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.163Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-20T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60488, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.014Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.171Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-21T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60489, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.122Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.180Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-21T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60490, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.229Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.188Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-21T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60491, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.337Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.196Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-22T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60492, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.445Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.205Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-22T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60493, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.552Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.213Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-22T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60494, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.660Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.221Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-23T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60495, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.768Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.230Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-23T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60496, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.876Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.238Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-23T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60497, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.983Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.246Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-24T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60498, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.091Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.254Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-24T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60499, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.199Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.262Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-24T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60500, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.315Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.271Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-25T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60501, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.422Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.279Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-25T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60502, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.530Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.287Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-25T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60503, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.679Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.296Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-26T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60504, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.787Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.304Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-26T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60505, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.894Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.312Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-26T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60506, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.002Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.321Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-27T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60507, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.110Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.329Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-27T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60508, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.218Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.337Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-27T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60509, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.325Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.345Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-28T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60510, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.433Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.354Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-28T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60511, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.541Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.362Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-28T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60512, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.648Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.370Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-29T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60513, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.756Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.378Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-29T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60514, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.864Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.387Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-29T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60515, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.971Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.395Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-30T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60516, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.079Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.403Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-30T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60517, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.187Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.412Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-30T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60518, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.294Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.420Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-12-01T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60519, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.402Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.428Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-12-01T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60520, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.510Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.436Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-12-01T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60521, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.626Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.445Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-02T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60522, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.734Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.453Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-02T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60523, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.841Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.461Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-02T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60524, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.949Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.470Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-03T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60525, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.057Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.478Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-03T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60526, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.164Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.497Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-03T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60527, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.272Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.547Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-04T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60528, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.380Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.561Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-04T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60529, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.487Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.569Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-04T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60530, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.595Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.577Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-05T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60531, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.703Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.586Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-05T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60532, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.810Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.594Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-05T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60533, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.918Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.602Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-06T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60534, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.026Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.610Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-06T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60535, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.133Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.619Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-06T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60536, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.241Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.627Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-07T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60537, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.349Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.635Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-07T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60538, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.456Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.644Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-07T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60539, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.564Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.652Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-08T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60540, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.672Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.660Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-08T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60541, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.780Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.669Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-08T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60542, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.896Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.677Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-09T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60543, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.003Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.685Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-09T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60544, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.111Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.693Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-09T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60545, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.219Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.702Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-10T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60546, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.326Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.710Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-10T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60547, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.434Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.718Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-10T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60548, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.542Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.726Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-11T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60549, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.708Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.735Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-11T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60550, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.815Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.743Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-11T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60551, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.923Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.751Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-12T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60552, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.030Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.760Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-12T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60553, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.138Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.768Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-12T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60554, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.246Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.776Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-13T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60555, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.354Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.784Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-13T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60556, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.461Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.793Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-13T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60557, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.569Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.801Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-14T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60558, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.677Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.809Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-14T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60559, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.784Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.817Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-14T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60560, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.892Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.826Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-15T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60561, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.834Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-15T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60562, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.107Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.842Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-15T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60563, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:07.851Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.851Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 8.0, 
+        "invoice": null, 
+        "date": "2013-12-16T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60564, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:07.859Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.859Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 8.0, 
+        "invoice": null, 
+        "date": "2013-12-16T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60565, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:07.867Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.867Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 8.0, 
+        "invoice": null, 
+        "date": "2013-12-16T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60566, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:07.875Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.875Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 8.0, 
+        "invoice": null, 
+        "date": "2013-12-17T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60567, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:07.884Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.884Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 8.0, 
+        "invoice": null, 
+        "date": "2013-12-17T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60568, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:07.892Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.892Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 8.0, 
+        "invoice": null, 
+        "date": "2013-12-17T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60569, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:07.900Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.900Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 8.0, 
+        "invoice": null, 
+        "date": "2013-12-18T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60570, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:07.909Z", 
+        "slice": 8, 
+        "created": "2013-12-18T21:29:07.909Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 8.0, 
+        "invoice": null, 
+        "date": "2013-12-18T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60571, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.268Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:07.929Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-18T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60572, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.376Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:07.942Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-19T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60573, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.484Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:07.950Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-19T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60574, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.591Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:07.958Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-19T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60575, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.699Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:07.967Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-20T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60576, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.807Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:07.975Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-20T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60577, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.914Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:07.983Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-20T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60578, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.022Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:07.991Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-21T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60579, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.130Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-21T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60580, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.238Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.008Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-21T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60581, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.345Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.016Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-22T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60582, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.453Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.025Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-22T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60583, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.561Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.033Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-22T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60584, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.668Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.041Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-23T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60585, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.776Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.049Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-23T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60586, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.884Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.058Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-23T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60587, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.991Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.066Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-24T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60588, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.099Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.074Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-24T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60589, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.207Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.082Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-24T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60590, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.323Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.091Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-25T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60591, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.431Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.099Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-25T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60592, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.538Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.107Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-25T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60593, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.687Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.116Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-26T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60594, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.795Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.124Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-26T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60595, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.903Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.132Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-26T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60596, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.010Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.141Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-27T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60597, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.118Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.149Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-27T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60598, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.226Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.157Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-27T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60599, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.333Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.166Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-28T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60600, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.441Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.174Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-28T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60601, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.549Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.182Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-28T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60602, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.657Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.190Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-29T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60603, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.764Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.199Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-29T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60604, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.872Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.207Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-29T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60605, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.980Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.215Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-30T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60606, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.087Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.224Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-30T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60607, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.195Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.232Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-30T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60608, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.303Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.240Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-12-01T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60609, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.410Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.249Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-12-01T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60610, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.518Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.257Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-12-01T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60611, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.634Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.265Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-02T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60612, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.742Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.273Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-02T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60613, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.849Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.282Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-02T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60614, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.957Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.290Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-03T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60615, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.065Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.298Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-03T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60616, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.173Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.306Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-03T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60617, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.280Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.315Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-04T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60618, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.388Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.323Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-04T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60619, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.496Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.331Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-04T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60620, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.603Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.339Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-05T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60621, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.711Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.348Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-05T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60622, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.819Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.356Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-05T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60623, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.926Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.364Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-06T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60624, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.034Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.373Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-06T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60625, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.142Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.381Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-06T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60626, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.249Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.389Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-07T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60627, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.357Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.397Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-07T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60628, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.465Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.406Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-07T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60629, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.572Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.414Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-08T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60630, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.680Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.422Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-08T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60631, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.788Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.431Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-08T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60632, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.904Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.439Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-09T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60633, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.011Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.447Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-09T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60634, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.119Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.455Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-09T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60635, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.227Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.464Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-10T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60636, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.335Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.472Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-10T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60637, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.442Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.480Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-10T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60638, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.550Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.489Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-11T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60639, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.716Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.497Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-11T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60640, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.823Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.505Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-11T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60641, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.931Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.513Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-12T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60642, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.039Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.522Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-12T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60643, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.147Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.530Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-12T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60644, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.254Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.538Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-13T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60645, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.362Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.546Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-13T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60646, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.469Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.555Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-13T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60647, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.577Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.563Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-14T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60648, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.685Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.571Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-14T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60649, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.793Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.580Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-14T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60650, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.900Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.588Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-15T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60651, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.008Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.596Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-15T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60652, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.116Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.605Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-15T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60653, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:08.613Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.613Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 8.0, 
+        "invoice": null, 
+        "date": "2013-12-16T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60654, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:08.621Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.621Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 8.0, 
+        "invoice": null, 
+        "date": "2013-12-16T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60655, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:08.630Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.629Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 8.0, 
+        "invoice": null, 
+        "date": "2013-12-16T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60656, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:08.638Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.638Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 8.0, 
+        "invoice": null, 
+        "date": "2013-12-17T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60657, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:08.646Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.646Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 8.0, 
+        "invoice": null, 
+        "date": "2013-12-17T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60658, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:08.654Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.654Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 8.0, 
+        "invoice": null, 
+        "date": "2013-12-17T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60659, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:08.663Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.663Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 8.0, 
+        "invoice": null, 
+        "date": "2013-12-18T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60660, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:08.671Z", 
+        "slice": 9, 
+        "created": "2013-12-18T21:29:08.671Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 112, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 8.0, 
+        "invoice": null, 
+        "date": "2013-12-18T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60661, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.215Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:08.698Z", 
+        "deleted": false, 
+        "amount": 0.1848, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.64, 
+        "invoice": 73, 
+        "date": "2013-11-18T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60662, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.240Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:08.704Z", 
+        "deleted": false, 
+        "amount": 0.2072, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.96, 
+        "invoice": 74, 
+        "date": "2013-11-19T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60663, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.256Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:08.712Z", 
+        "deleted": false, 
+        "amount": 0.3248, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.64, 
+        "invoice": 74, 
+        "date": "2013-11-19T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60664, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.273Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:08.721Z", 
+        "deleted": false, 
+        "amount": 0.2352, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.36, 
+        "invoice": 74, 
+        "date": "2013-11-19T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60665, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.290Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:08.729Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 74, 
+        "date": "2013-11-20T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60666, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.306Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:08.737Z", 
+        "deleted": false, 
+        "amount": 0.308, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.4, 
+        "invoice": 74, 
+        "date": "2013-11-20T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60667, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.323Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:08.745Z", 
+        "deleted": false, 
+        "amount": 0.1232, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 1.76, 
+        "invoice": 74, 
+        "date": "2013-11-20T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60668, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.339Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:08.754Z", 
+        "deleted": false, 
+        "amount": 0.1568, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.24, 
+        "invoice": 74, 
+        "date": "2013-11-21T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60669, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.356Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:08.762Z", 
+        "deleted": false, 
+        "amount": 0.2744, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.92, 
+        "invoice": 74, 
+        "date": "2013-11-21T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60670, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.372Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:08.770Z", 
+        "deleted": false, 
+        "amount": 0.2184, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.12, 
+        "invoice": 74, 
+        "date": "2013-11-21T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60671, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.389Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:08.779Z", 
+        "deleted": false, 
+        "amount": 0.2184, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.12, 
+        "invoice": 74, 
+        "date": "2013-11-22T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60672, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.406Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:08.787Z", 
+        "deleted": false, 
+        "amount": 0.14, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.0, 
+        "invoice": 74, 
+        "date": "2013-11-22T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60673, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.424Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:08.795Z", 
+        "deleted": false, 
+        "amount": 0.2352, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.36, 
+        "invoice": 74, 
+        "date": "2013-11-22T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60674, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.440Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:08.803Z", 
+        "deleted": false, 
+        "amount": 0.1232, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 1.76, 
+        "invoice": 74, 
+        "date": "2013-11-23T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60675, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.457Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:08.812Z", 
+        "deleted": false, 
+        "amount": 0.2016, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.88, 
+        "invoice": 74, 
+        "date": "2013-11-23T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60676, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.473Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:08.820Z", 
+        "deleted": false, 
+        "amount": 0.28, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.0, 
+        "invoice": 74, 
+        "date": "2013-11-23T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60677, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.490Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:08.828Z", 
+        "deleted": false, 
+        "amount": 0.2408, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.44, 
+        "invoice": 74, 
+        "date": "2013-11-24T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60678, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.507Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:08.837Z", 
+        "deleted": false, 
+        "amount": 0.2072, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.96, 
+        "invoice": 74, 
+        "date": "2013-11-24T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60679, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.523Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:08.845Z", 
+        "deleted": false, 
+        "amount": 0.2296, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.28, 
+        "invoice": 74, 
+        "date": "2013-11-24T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60680, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.548Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:08.853Z", 
+        "deleted": false, 
+        "amount": 0.28, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.0, 
+        "invoice": 75, 
+        "date": "2013-11-25T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60681, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.565Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:08.861Z", 
+        "deleted": false, 
+        "amount": 0.3024, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.32, 
+        "invoice": 75, 
+        "date": "2013-11-25T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60682, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.581Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:08.870Z", 
+        "deleted": false, 
+        "amount": 0.1512, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.16, 
+        "invoice": 75, 
+        "date": "2013-11-25T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60683, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.598Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:08.878Z", 
+        "deleted": false, 
+        "amount": 0.196, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.8, 
+        "invoice": 75, 
+        "date": "2013-11-26T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60684, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.614Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:08.886Z", 
+        "deleted": false, 
+        "amount": 0.112, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 1.6, 
+        "invoice": 75, 
+        "date": "2013-11-26T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60685, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.631Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:08.894Z", 
+        "deleted": false, 
+        "amount": 0.2688, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.84, 
+        "invoice": 75, 
+        "date": "2013-11-26T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60686, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.648Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:08.903Z", 
+        "deleted": false, 
+        "amount": 0.336, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.8, 
+        "invoice": 75, 
+        "date": "2013-11-27T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60687, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.664Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:08.911Z", 
+        "deleted": false, 
+        "amount": 0.2296, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.28, 
+        "invoice": 75, 
+        "date": "2013-11-27T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60688, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.681Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:08.919Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.16, 
+        "invoice": 75, 
+        "date": "2013-11-27T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60689, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.697Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:08.928Z", 
+        "deleted": false, 
+        "amount": 0.308, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.4, 
+        "invoice": 75, 
+        "date": "2013-11-28T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60690, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.714Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:08.936Z", 
+        "deleted": false, 
+        "amount": 0.308, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.4, 
+        "invoice": 75, 
+        "date": "2013-11-28T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60691, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.730Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:08.944Z", 
+        "deleted": false, 
+        "amount": 0.336, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.8, 
+        "invoice": 75, 
+        "date": "2013-11-28T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60692, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.747Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:08.952Z", 
+        "deleted": false, 
+        "amount": 0.336, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.8, 
+        "invoice": 75, 
+        "date": "2013-11-29T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60693, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.763Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:08.961Z", 
+        "deleted": false, 
+        "amount": 0.336, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.8, 
+        "invoice": 75, 
+        "date": "2013-11-29T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60694, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.780Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:08.969Z", 
+        "deleted": false, 
+        "amount": 0.224, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.2, 
+        "invoice": 75, 
+        "date": "2013-11-29T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60695, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.797Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:08.977Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 75, 
+        "date": "2013-11-30T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60696, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.813Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:08.986Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 75, 
+        "date": "2013-11-30T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60697, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.830Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:08.994Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 75, 
+        "date": "2013-11-30T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60698, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.846Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.002Z", 
+        "deleted": false, 
+        "amount": 0.336, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.8, 
+        "invoice": 75, 
+        "date": "2013-12-01T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60699, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.863Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.010Z", 
+        "deleted": false, 
+        "amount": 0.2128, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.04, 
+        "invoice": 75, 
+        "date": "2013-12-01T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60700, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.879Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.019Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.08, 
+        "invoice": 75, 
+        "date": "2013-12-01T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60701, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.904Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.027Z", 
+        "deleted": false, 
+        "amount": 0.2128, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.04, 
+        "invoice": 76, 
+        "date": "2013-12-02T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60702, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.921Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.035Z", 
+        "deleted": false, 
+        "amount": 0.2576, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.68, 
+        "invoice": 76, 
+        "date": "2013-12-02T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60703, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.937Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.044Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 76, 
+        "date": "2013-12-02T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60704, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.954Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.054Z", 
+        "deleted": false, 
+        "amount": 0.2464, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.52, 
+        "invoice": 76, 
+        "date": "2013-12-03T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60705, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.971Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.060Z", 
+        "deleted": false, 
+        "amount": 0.1736, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.48, 
+        "invoice": 76, 
+        "date": "2013-12-03T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60706, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.987Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.068Z", 
+        "deleted": false, 
+        "amount": 0.2464, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.52, 
+        "invoice": 76, 
+        "date": "2013-12-03T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60707, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.004Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.077Z", 
+        "deleted": false, 
+        "amount": 0.2744, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.92, 
+        "invoice": 76, 
+        "date": "2013-12-04T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60708, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.020Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.085Z", 
+        "deleted": false, 
+        "amount": 0.2016, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.88, 
+        "invoice": 76, 
+        "date": "2013-12-04T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60709, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.037Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.093Z", 
+        "deleted": false, 
+        "amount": 0.308, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.4, 
+        "invoice": 76, 
+        "date": "2013-12-04T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60710, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.053Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.102Z", 
+        "deleted": false, 
+        "amount": 0.1288, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 1.84, 
+        "invoice": 76, 
+        "date": "2013-12-05T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60711, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.070Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.110Z", 
+        "deleted": false, 
+        "amount": 0.1232, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 1.76, 
+        "invoice": 76, 
+        "date": "2013-12-05T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60712, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.087Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.118Z", 
+        "deleted": false, 
+        "amount": 0.2184, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.12, 
+        "invoice": 76, 
+        "date": "2013-12-05T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60713, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.103Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.126Z", 
+        "deleted": false, 
+        "amount": 0.3192, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.56, 
+        "invoice": 76, 
+        "date": "2013-12-06T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60714, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.120Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.135Z", 
+        "deleted": false, 
+        "amount": 0.3192, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.56, 
+        "invoice": 76, 
+        "date": "2013-12-06T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60715, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.136Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.143Z", 
+        "deleted": false, 
+        "amount": 0.2744, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.92, 
+        "invoice": 76, 
+        "date": "2013-12-06T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60716, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.153Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.151Z", 
+        "deleted": false, 
+        "amount": 0.1232, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 1.76, 
+        "invoice": 76, 
+        "date": "2013-12-07T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60717, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.169Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.160Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.16, 
+        "invoice": 76, 
+        "date": "2013-12-07T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60718, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.186Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.168Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 76, 
+        "date": "2013-12-07T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60719, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.203Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.176Z", 
+        "deleted": false, 
+        "amount": 0.224, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.2, 
+        "invoice": 76, 
+        "date": "2013-12-08T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60720, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.219Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.185Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.08, 
+        "invoice": 76, 
+        "date": "2013-12-08T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60721, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.236Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.193Z", 
+        "deleted": false, 
+        "amount": 0.3192, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.56, 
+        "invoice": 76, 
+        "date": "2013-12-08T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60722, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.260Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.201Z", 
+        "deleted": false, 
+        "amount": 0.2576, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.68, 
+        "invoice": 77, 
+        "date": "2013-12-09T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60723, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.277Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.209Z", 
+        "deleted": false, 
+        "amount": 0.168, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.4, 
+        "invoice": 77, 
+        "date": "2013-12-09T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60724, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.294Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.218Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 77, 
+        "date": "2013-12-09T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60725, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.319Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.226Z", 
+        "deleted": false, 
+        "amount": 0.1232, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 1.76, 
+        "invoice": 77, 
+        "date": "2013-12-10T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60726, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.335Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.234Z", 
+        "deleted": false, 
+        "amount": 0.168, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.4, 
+        "invoice": 77, 
+        "date": "2013-12-10T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60727, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.352Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.243Z", 
+        "deleted": false, 
+        "amount": 0.1792, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.56, 
+        "invoice": 77, 
+        "date": "2013-12-10T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60728, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.369Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.251Z", 
+        "deleted": false, 
+        "amount": 0.3192, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.56, 
+        "invoice": 77, 
+        "date": "2013-12-11T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60729, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.385Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.259Z", 
+        "deleted": false, 
+        "amount": 0.1736, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.48, 
+        "invoice": 77, 
+        "date": "2013-12-11T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60730, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.402Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.267Z", 
+        "deleted": false, 
+        "amount": 0.196, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.8, 
+        "invoice": 77, 
+        "date": "2013-12-11T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60731, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.418Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.276Z", 
+        "deleted": false, 
+        "amount": 0.112, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 1.6, 
+        "invoice": 77, 
+        "date": "2013-12-12T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60732, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.435Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.284Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 77, 
+        "date": "2013-12-12T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60733, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.451Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.292Z", 
+        "deleted": false, 
+        "amount": 0.1568, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.24, 
+        "invoice": 77, 
+        "date": "2013-12-12T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60734, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.468Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.300Z", 
+        "deleted": false, 
+        "amount": 0.2408, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.44, 
+        "invoice": 77, 
+        "date": "2013-12-13T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60735, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.485Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.309Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.16, 
+        "invoice": 77, 
+        "date": "2013-12-13T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60736, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.501Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.317Z", 
+        "deleted": false, 
+        "amount": 0.1512, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.16, 
+        "invoice": 77, 
+        "date": "2013-12-13T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60737, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.518Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.325Z", 
+        "deleted": false, 
+        "amount": 0.2632, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.76, 
+        "invoice": 77, 
+        "date": "2013-12-14T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60738, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.534Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.334Z", 
+        "deleted": false, 
+        "amount": 0.2744, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.92, 
+        "invoice": 77, 
+        "date": "2013-12-14T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60739, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.551Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.342Z", 
+        "deleted": false, 
+        "amount": 0.1512, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.16, 
+        "invoice": 77, 
+        "date": "2013-12-14T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60740, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.567Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.350Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 77, 
+        "date": "2013-12-15T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60741, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.584Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.358Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 77, 
+        "date": "2013-12-15T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60742, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.601Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.367Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 105, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 77, 
+        "date": "2013-12-15T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60743, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:09.375Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.375Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 105, 
+        "account": 16, 
+        "state": "pending", 
+        "coreHours": 1.68, 
+        "invoice": null, 
+        "date": "2013-12-16T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60744, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:09.383Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.383Z", 
+        "deleted": false, 
+        "amount": 0.2128, 
+        "object": 105, 
+        "account": 16, 
+        "state": "pending", 
+        "coreHours": 3.04, 
+        "invoice": null, 
+        "date": "2013-12-16T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60745, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:09.392Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.392Z", 
+        "deleted": false, 
+        "amount": 0.28, 
+        "object": 105, 
+        "account": 16, 
+        "state": "pending", 
+        "coreHours": 4.0, 
+        "invoice": null, 
+        "date": "2013-12-16T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60746, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:09.400Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.400Z", 
+        "deleted": false, 
+        "amount": 0.224, 
+        "object": 105, 
+        "account": 16, 
+        "state": "pending", 
+        "coreHours": 3.2, 
+        "invoice": null, 
+        "date": "2013-12-17T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60747, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:09.408Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.408Z", 
+        "deleted": false, 
+        "amount": 0.2184, 
+        "object": 105, 
+        "account": 16, 
+        "state": "pending", 
+        "coreHours": 3.12, 
+        "invoice": null, 
+        "date": "2013-12-17T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60748, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:09.416Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.416Z", 
+        "deleted": false, 
+        "amount": 0.2464, 
+        "object": 105, 
+        "account": 16, 
+        "state": "pending", 
+        "coreHours": 3.52, 
+        "invoice": null, 
+        "date": "2013-12-17T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60749, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:09.425Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.425Z", 
+        "deleted": false, 
+        "amount": 0.308, 
+        "object": 105, 
+        "account": 16, 
+        "state": "pending", 
+        "coreHours": 4.4, 
+        "invoice": null, 
+        "date": "2013-12-18T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60750, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:09.433Z", 
+        "slice": 11, 
+        "created": "2013-12-18T21:29:09.433Z", 
+        "deleted": false, 
+        "amount": 0.3024, 
+        "object": 105, 
+        "account": 16, 
+        "state": "pending", 
+        "coreHours": 4.32, 
+        "invoice": null, 
+        "date": "2013-12-18T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60751, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.232Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.456Z", 
+        "deleted": false, 
+        "amount": 0.2352, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.36, 
+        "invoice": 74, 
+        "date": "2013-11-18T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60752, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.248Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.466Z", 
+        "deleted": false, 
+        "amount": 0.308, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.4, 
+        "invoice": 74, 
+        "date": "2013-11-19T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60753, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.265Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.474Z", 
+        "deleted": false, 
+        "amount": 0.2576, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.68, 
+        "invoice": 74, 
+        "date": "2013-11-19T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60754, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.281Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.483Z", 
+        "deleted": false, 
+        "amount": 0.3192, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.56, 
+        "invoice": 74, 
+        "date": "2013-11-19T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60755, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.298Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.491Z", 
+        "deleted": false, 
+        "amount": 0.1904, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.72, 
+        "invoice": 74, 
+        "date": "2013-11-20T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60756, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.314Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.499Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 74, 
+        "date": "2013-11-20T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60757, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.331Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.508Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 1.68, 
+        "invoice": 74, 
+        "date": "2013-11-20T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60758, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.347Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.516Z", 
+        "deleted": false, 
+        "amount": 0.28, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.0, 
+        "invoice": 74, 
+        "date": "2013-11-21T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60759, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.364Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.524Z", 
+        "deleted": false, 
+        "amount": 0.1232, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 1.76, 
+        "invoice": 74, 
+        "date": "2013-11-21T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60760, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.381Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.532Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 74, 
+        "date": "2013-11-21T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60761, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.397Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.541Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.08, 
+        "invoice": 74, 
+        "date": "2013-11-22T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60762, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.414Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.549Z", 
+        "deleted": false, 
+        "amount": 0.2576, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.68, 
+        "invoice": 74, 
+        "date": "2013-11-22T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60763, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.432Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.557Z", 
+        "deleted": false, 
+        "amount": 0.2016, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.88, 
+        "invoice": 74, 
+        "date": "2013-11-22T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60764, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.448Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.565Z", 
+        "deleted": false, 
+        "amount": 0.3024, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.32, 
+        "invoice": 74, 
+        "date": "2013-11-23T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60765, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.465Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.574Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 74, 
+        "date": "2013-11-23T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60766, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.482Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.582Z", 
+        "deleted": false, 
+        "amount": 0.2128, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.04, 
+        "invoice": 74, 
+        "date": "2013-11-23T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60767, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.498Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.590Z", 
+        "deleted": false, 
+        "amount": 0.1848, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.64, 
+        "invoice": 74, 
+        "date": "2013-11-24T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60768, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.515Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.599Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 74, 
+        "date": "2013-11-24T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60769, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.531Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.607Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.08, 
+        "invoice": 74, 
+        "date": "2013-11-24T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60770, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.556Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.615Z", 
+        "deleted": false, 
+        "amount": 0.2576, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.68, 
+        "invoice": 75, 
+        "date": "2013-11-25T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60771, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.573Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.623Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.16, 
+        "invoice": 75, 
+        "date": "2013-11-25T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60772, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.589Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.632Z", 
+        "deleted": false, 
+        "amount": 0.2744, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.92, 
+        "invoice": 75, 
+        "date": "2013-11-25T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60773, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.606Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.640Z", 
+        "deleted": false, 
+        "amount": 0.2296, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.28, 
+        "invoice": 75, 
+        "date": "2013-11-26T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60774, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.623Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.649Z", 
+        "deleted": false, 
+        "amount": 0.308, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.4, 
+        "invoice": 75, 
+        "date": "2013-11-26T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60775, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.639Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.657Z", 
+        "deleted": false, 
+        "amount": 0.1736, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.48, 
+        "invoice": 75, 
+        "date": "2013-11-26T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60776, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.656Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.665Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 1.68, 
+        "invoice": 75, 
+        "date": "2013-11-27T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60777, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.672Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.673Z", 
+        "deleted": false, 
+        "amount": 0.1736, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.48, 
+        "invoice": 75, 
+        "date": "2013-11-27T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60778, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.689Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.682Z", 
+        "deleted": false, 
+        "amount": 0.2968, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.24, 
+        "invoice": 75, 
+        "date": "2013-11-27T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60779, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.706Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.690Z", 
+        "deleted": false, 
+        "amount": 0.252, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.6, 
+        "invoice": 75, 
+        "date": "2013-11-28T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60780, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.722Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.698Z", 
+        "deleted": false, 
+        "amount": 0.2632, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.76, 
+        "invoice": 75, 
+        "date": "2013-11-28T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60781, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.739Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.706Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.08, 
+        "invoice": 75, 
+        "date": "2013-11-28T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60782, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.755Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.715Z", 
+        "deleted": false, 
+        "amount": 0.1512, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.16, 
+        "invoice": 75, 
+        "date": "2013-11-29T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60783, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.772Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.723Z", 
+        "deleted": false, 
+        "amount": 0.2072, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.96, 
+        "invoice": 75, 
+        "date": "2013-11-29T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60784, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.788Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.731Z", 
+        "deleted": false, 
+        "amount": 0.1624, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.32, 
+        "invoice": 75, 
+        "date": "2013-11-29T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60785, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.805Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.740Z", 
+        "deleted": false, 
+        "amount": 0.1848, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.64, 
+        "invoice": 75, 
+        "date": "2013-11-30T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60786, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.821Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.748Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 1.68, 
+        "invoice": 75, 
+        "date": "2013-11-30T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60787, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.838Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.756Z", 
+        "deleted": false, 
+        "amount": 0.196, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.8, 
+        "invoice": 75, 
+        "date": "2013-11-30T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60788, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.855Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.764Z", 
+        "deleted": false, 
+        "amount": 0.1792, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.56, 
+        "invoice": 75, 
+        "date": "2013-12-01T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60789, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.871Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.773Z", 
+        "deleted": false, 
+        "amount": 0.2408, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.44, 
+        "invoice": 75, 
+        "date": "2013-12-01T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60790, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.888Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.781Z", 
+        "deleted": false, 
+        "amount": 0.14, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.0, 
+        "invoice": 75, 
+        "date": "2013-12-01T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60791, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.913Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.789Z", 
+        "deleted": false, 
+        "amount": 0.112, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 1.6, 
+        "invoice": 76, 
+        "date": "2013-12-02T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60792, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.929Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.798Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 76, 
+        "date": "2013-12-02T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60793, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.946Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.806Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.08, 
+        "invoice": 76, 
+        "date": "2013-12-02T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60794, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.962Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.814Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.16, 
+        "invoice": 76, 
+        "date": "2013-12-03T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60795, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.979Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.822Z", 
+        "deleted": false, 
+        "amount": 0.2128, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.04, 
+        "invoice": 76, 
+        "date": "2013-12-03T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60796, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.995Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.831Z", 
+        "deleted": false, 
+        "amount": 0.1848, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.64, 
+        "invoice": 76, 
+        "date": "2013-12-03T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60797, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.012Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.839Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 76, 
+        "date": "2013-12-04T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60798, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.029Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.847Z", 
+        "deleted": false, 
+        "amount": 0.28, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.0, 
+        "invoice": 76, 
+        "date": "2013-12-04T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60799, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.045Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.855Z", 
+        "deleted": false, 
+        "amount": 0.308, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.4, 
+        "invoice": 76, 
+        "date": "2013-12-04T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60800, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.062Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.864Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 76, 
+        "date": "2013-12-05T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60801, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.078Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.872Z", 
+        "deleted": false, 
+        "amount": 0.2464, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.52, 
+        "invoice": 76, 
+        "date": "2013-12-05T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60802, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.095Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.880Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 76, 
+        "date": "2013-12-05T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60803, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.111Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.889Z", 
+        "deleted": false, 
+        "amount": 0.112, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 1.6, 
+        "invoice": 76, 
+        "date": "2013-12-06T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60804, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.128Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.897Z", 
+        "deleted": false, 
+        "amount": 0.2744, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.92, 
+        "invoice": 76, 
+        "date": "2013-12-06T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60805, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.145Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.905Z", 
+        "deleted": false, 
+        "amount": 0.1792, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.56, 
+        "invoice": 76, 
+        "date": "2013-12-06T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60806, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.161Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.913Z", 
+        "deleted": false, 
+        "amount": 0.1568, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.24, 
+        "invoice": 76, 
+        "date": "2013-12-07T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60807, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.178Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.922Z", 
+        "deleted": false, 
+        "amount": 0.2408, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.44, 
+        "invoice": 76, 
+        "date": "2013-12-07T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60808, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.194Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.930Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 1.68, 
+        "invoice": 76, 
+        "date": "2013-12-07T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60809, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.211Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.938Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 1.68, 
+        "invoice": 76, 
+        "date": "2013-12-08T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60810, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.227Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.947Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 76, 
+        "date": "2013-12-08T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60811, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.244Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.955Z", 
+        "deleted": false, 
+        "amount": 0.196, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.8, 
+        "invoice": 76, 
+        "date": "2013-12-08T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60812, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.269Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.963Z", 
+        "deleted": false, 
+        "amount": 0.2744, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.92, 
+        "invoice": 77, 
+        "date": "2013-12-09T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60813, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.285Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.971Z", 
+        "deleted": false, 
+        "amount": 0.1792, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.56, 
+        "invoice": 77, 
+        "date": "2013-12-09T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60814, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.302Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.980Z", 
+        "deleted": false, 
+        "amount": 0.112, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 1.6, 
+        "invoice": 77, 
+        "date": "2013-12-09T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60815, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.327Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.988Z", 
+        "deleted": false, 
+        "amount": 0.2296, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.28, 
+        "invoice": 77, 
+        "date": "2013-12-10T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60816, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.344Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:09.996Z", 
+        "deleted": false, 
+        "amount": 0.1232, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 1.76, 
+        "invoice": 77, 
+        "date": "2013-12-10T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60817, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.360Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:10.005Z", 
+        "deleted": false, 
+        "amount": 0.1848, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.64, 
+        "invoice": 77, 
+        "date": "2013-12-10T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60818, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.377Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:10.013Z", 
+        "deleted": false, 
+        "amount": 0.2296, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.28, 
+        "invoice": 77, 
+        "date": "2013-12-11T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60819, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.393Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:10.021Z", 
+        "deleted": false, 
+        "amount": 0.2968, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.24, 
+        "invoice": 77, 
+        "date": "2013-12-11T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60820, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.410Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:10.029Z", 
+        "deleted": false, 
+        "amount": 0.112, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 1.6, 
+        "invoice": 77, 
+        "date": "2013-12-11T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60821, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.427Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:10.038Z", 
+        "deleted": false, 
+        "amount": 0.2576, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.68, 
+        "invoice": 77, 
+        "date": "2013-12-12T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60822, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.443Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:10.046Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 77, 
+        "date": "2013-12-12T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60823, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.460Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:10.054Z", 
+        "deleted": false, 
+        "amount": 0.2576, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.68, 
+        "invoice": 77, 
+        "date": "2013-12-12T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60824, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.476Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:10.063Z", 
+        "deleted": false, 
+        "amount": 0.2688, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.84, 
+        "invoice": 77, 
+        "date": "2013-12-13T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60825, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.493Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:10.071Z", 
+        "deleted": false, 
+        "amount": 0.252, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.6, 
+        "invoice": 77, 
+        "date": "2013-12-13T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60826, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.509Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:10.079Z", 
+        "deleted": false, 
+        "amount": 0.14, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.0, 
+        "invoice": 77, 
+        "date": "2013-12-13T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60827, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.526Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:10.087Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 77, 
+        "date": "2013-12-14T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60828, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.543Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:10.096Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 77, 
+        "date": "2013-12-14T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60829, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.559Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:10.104Z", 
+        "deleted": false, 
+        "amount": 0.1848, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 2.64, 
+        "invoice": 77, 
+        "date": "2013-12-14T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60830, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.576Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:10.112Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 77, 
+        "date": "2013-12-15T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60831, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.592Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:10.120Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 4.16, 
+        "invoice": 77, 
+        "date": "2013-12-15T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60832, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:30.609Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:10.129Z", 
+        "deleted": false, 
+        "amount": 0.252, 
+        "object": 113, 
+        "account": 16, 
+        "state": "invoiced", 
+        "coreHours": 3.6, 
+        "invoice": 77, 
+        "date": "2013-12-15T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60833, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:10.137Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:10.137Z", 
+        "deleted": false, 
+        "amount": 0.14, 
+        "object": 113, 
+        "account": 16, 
+        "state": "pending", 
+        "coreHours": 2.0, 
+        "invoice": null, 
+        "date": "2013-12-16T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60834, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:10.146Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:10.146Z", 
+        "deleted": false, 
+        "amount": 0.14, 
+        "object": 113, 
+        "account": 16, 
+        "state": "pending", 
+        "coreHours": 2.0, 
+        "invoice": null, 
+        "date": "2013-12-16T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60835, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:10.154Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:10.154Z", 
+        "deleted": false, 
+        "amount": 0.2184, 
+        "object": 113, 
+        "account": 16, 
+        "state": "pending", 
+        "coreHours": 3.12, 
+        "invoice": null, 
+        "date": "2013-12-16T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60836, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:10.162Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:10.162Z", 
+        "deleted": false, 
+        "amount": 0.1904, 
+        "object": 113, 
+        "account": 16, 
+        "state": "pending", 
+        "coreHours": 2.72, 
+        "invoice": null, 
+        "date": "2013-12-17T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60837, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:10.170Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:10.170Z", 
+        "deleted": false, 
+        "amount": 0.1624, 
+        "object": 113, 
+        "account": 16, 
+        "state": "pending", 
+        "coreHours": 2.32, 
+        "invoice": null, 
+        "date": "2013-12-17T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60838, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:10.179Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:10.179Z", 
+        "deleted": false, 
+        "amount": 0.252, 
+        "object": 113, 
+        "account": 16, 
+        "state": "pending", 
+        "coreHours": 3.6, 
+        "invoice": null, 
+        "date": "2013-12-17T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60839, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:10.187Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:10.187Z", 
+        "deleted": false, 
+        "amount": 0.1904, 
+        "object": 113, 
+        "account": 16, 
+        "state": "pending", 
+        "coreHours": 2.72, 
+        "invoice": null, 
+        "date": "2013-12-18T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60840, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:10.195Z", 
+        "slice": 12, 
+        "created": "2013-12-18T21:29:10.195Z", 
+        "deleted": false, 
+        "amount": 0.224, 
+        "object": 113, 
+        "account": 16, 
+        "state": "pending", 
+        "coreHours": 3.2, 
+        "invoice": null, 
+        "date": "2013-12-18T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60841, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.277Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.227Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-18T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60842, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.384Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.237Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-19T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60843, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.492Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.245Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-19T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60844, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.600Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.253Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-19T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60845, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.707Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.262Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-20T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60846, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.815Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.270Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-20T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60847, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.923Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.278Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-20T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60848, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.031Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.286Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-21T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60849, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.138Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.295Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-21T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60850, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.246Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.303Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-21T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60851, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.354Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.311Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-22T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60852, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.461Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.319Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-22T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60853, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.569Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.328Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-22T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60854, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.677Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.336Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-23T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60855, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.784Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.344Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-23T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60856, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.892Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.352Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-23T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60857, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.361Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-24T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60858, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.107Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.369Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-24T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60859, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.215Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.377Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-24T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60860, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.331Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.386Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-25T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60861, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.439Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.394Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-25T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60862, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.559Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.402Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-25T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60863, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.696Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.410Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-26T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60864, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.803Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.419Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-26T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60865, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.911Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.427Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-26T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60866, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.019Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.435Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-27T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60867, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.126Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.444Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-27T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60868, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.234Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.452Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-27T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60869, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.342Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.460Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-28T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60870, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.449Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.468Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-28T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60871, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.557Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.477Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-28T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60872, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.665Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.485Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-29T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60873, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.773Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.493Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-29T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60874, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.880Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.502Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-29T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60875, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.988Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.510Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-30T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60876, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.096Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.518Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-30T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60877, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.203Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.526Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-30T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60878, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.311Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.535Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-12-01T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60879, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.419Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.543Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-12-01T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60880, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.526Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.551Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-12-01T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60881, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.642Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.560Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-02T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60882, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.750Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.568Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-02T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60883, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.858Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.576Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-02T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60884, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.965Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.584Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-03T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60885, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.073Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.593Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-03T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60886, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.181Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.601Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-03T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60887, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.289Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.609Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-04T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60888, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.396Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.618Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-04T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60889, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.504Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.626Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-04T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60890, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.612Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.634Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-05T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60891, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.719Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.643Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-05T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60892, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.827Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.651Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-05T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60893, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.935Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.659Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-06T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60894, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.042Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.668Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-06T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60895, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.150Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.676Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-06T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60896, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.258Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.684Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-07T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60897, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.365Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.692Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-07T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60898, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.473Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.701Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-07T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60899, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.581Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.709Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-08T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60900, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.689Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.717Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-08T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60901, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.796Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.725Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-08T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60902, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.912Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.734Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-09T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60903, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.020Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.742Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-09T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60904, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.127Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.750Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-09T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60905, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.235Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.759Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-10T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60906, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.343Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.767Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-10T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60907, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.451Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.775Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-10T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60908, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.558Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.783Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-11T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60909, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.724Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.792Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-11T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60910, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.832Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.800Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-11T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60911, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.939Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.808Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-12T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60912, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.047Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.816Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-12T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60913, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.155Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.825Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-12T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60914, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.262Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.833Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-13T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60915, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.370Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.841Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-13T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60916, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.478Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.850Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-13T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60917, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.585Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.858Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-14T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60918, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.693Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.866Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-14T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60919, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.801Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.874Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-14T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60920, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.909Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.883Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-15T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60921, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.016Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.891Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-15T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60922, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.124Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.899Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-15T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60923, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:10.908Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.908Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 8.0, 
+        "invoice": null, 
+        "date": "2013-12-16T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60924, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:10.916Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.916Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 8.0, 
+        "invoice": null, 
+        "date": "2013-12-16T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60925, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:10.924Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.924Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 8.0, 
+        "invoice": null, 
+        "date": "2013-12-16T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60926, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:10.932Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.932Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 8.0, 
+        "invoice": null, 
+        "date": "2013-12-17T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60927, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:10.941Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.941Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 8.0, 
+        "invoice": null, 
+        "date": "2013-12-17T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60928, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:10.949Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.949Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 8.0, 
+        "invoice": null, 
+        "date": "2013-12-17T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60929, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:10.957Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.957Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 8.0, 
+        "invoice": null, 
+        "date": "2013-12-18T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60930, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:10.966Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.966Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 114, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 8.0, 
+        "invoice": null, 
+        "date": "2013-12-18T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60931, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.285Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.981Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-18T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60932, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.393Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.990Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-19T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60933, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.500Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:10.999Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-19T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60934, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.608Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.007Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-19T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60935, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.716Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.015Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-20T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60936, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.823Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.024Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-20T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60937, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.931Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.032Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-20T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60938, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.039Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.040Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-21T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60939, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.147Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.048Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-21T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60940, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.254Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.057Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-21T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60941, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.362Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.065Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-22T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60942, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.470Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.073Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-22T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60943, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.577Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.081Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-22T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60944, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.685Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.090Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-23T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60945, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.793Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.098Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-23T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60946, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.900Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.106Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-23T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60947, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.008Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.115Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-24T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60948, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.116Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.123Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-24T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60949, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.223Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.131Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-24T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60950, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.339Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.140Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-25T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60951, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.447Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.148Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-25T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60952, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.596Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.156Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-25T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60953, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.704Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.164Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-26T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60954, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.812Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.173Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-26T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60955, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.919Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.181Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-26T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60956, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.027Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.189Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-27T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60957, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.135Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.197Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-27T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60958, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.242Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.206Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-27T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60959, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.350Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.214Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-28T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60960, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.458Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.222Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-28T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60961, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.565Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.231Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-28T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60962, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.673Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.239Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-29T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60963, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.781Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.247Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-29T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60964, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.889Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.255Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-29T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60965, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.996Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.264Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-30T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60966, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.104Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.272Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-30T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60967, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.212Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.280Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-30T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60968, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.319Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.289Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-12-01T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60969, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.427Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.297Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-12-01T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60970, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.535Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.305Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-12-01T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60971, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.651Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.313Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-02T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60972, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.758Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.322Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-02T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60973, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.866Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.330Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-02T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60974, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.974Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.338Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-03T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60975, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.081Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.346Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-03T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60976, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.189Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.355Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-03T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60977, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.297Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.363Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-04T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60978, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.404Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.371Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-04T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60979, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.512Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.380Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-04T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60980, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.620Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.388Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-05T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60981, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.728Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.396Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-05T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60982, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.835Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.404Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-05T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60983, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.943Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.413Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-06T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60984, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.051Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.421Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-06T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60985, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.158Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.429Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-06T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60986, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.266Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.438Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-07T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60987, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.374Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.446Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-07T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60988, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.481Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.454Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-07T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60989, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.589Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.463Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-08T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60990, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.697Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.471Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-08T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60991, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.804Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.479Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-08T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60992, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.920Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.487Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-09T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60993, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.028Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.496Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-09T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60994, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.136Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.504Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-09T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60995, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.244Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.512Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-10T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60996, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.351Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.521Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-10T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60997, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.459Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.529Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-10T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60998, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.584Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.537Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-11T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 60999, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.732Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.545Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-11T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61000, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.840Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.554Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-11T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61001, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.948Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.562Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-12T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61002, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.055Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.570Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-12T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61003, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.163Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.579Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-12T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61004, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.271Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.587Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-13T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61005, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.378Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.595Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-13T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61006, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.486Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.603Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-13T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61007, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.594Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.612Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-14T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61008, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.702Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.620Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-14T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61009, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.809Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.628Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-14T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61010, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.917Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.637Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-15T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61011, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.024Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.645Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-15T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61012, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.132Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.653Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-15T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61013, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:11.662Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.662Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 8.0, 
+        "invoice": null, 
+        "date": "2013-12-16T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61014, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:11.670Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.670Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 8.0, 
+        "invoice": null, 
+        "date": "2013-12-16T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61015, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:11.678Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.678Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 8.0, 
+        "invoice": null, 
+        "date": "2013-12-16T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61016, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:11.686Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.686Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 8.0, 
+        "invoice": null, 
+        "date": "2013-12-17T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61017, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:11.695Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.695Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 8.0, 
+        "invoice": null, 
+        "date": "2013-12-17T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61018, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:11.703Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.703Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 8.0, 
+        "invoice": null, 
+        "date": "2013-12-17T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61019, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:11.711Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.711Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 8.0, 
+        "invoice": null, 
+        "date": "2013-12-18T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61020, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:11.719Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.719Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 115, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 8.0, 
+        "invoice": null, 
+        "date": "2013-12-18T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61021, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.293Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.734Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-18T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61022, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.401Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.744Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-19T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61023, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.509Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.753Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-19T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61024, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.616Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.761Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-19T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61025, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.724Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.769Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-20T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61026, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.832Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.777Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-20T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61027, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:20.939Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.786Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-20T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61028, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.047Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.794Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-21T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61029, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.155Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.802Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-21T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61030, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.262Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.810Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-21T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61031, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.370Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.819Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-22T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61032, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.478Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.827Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-22T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61033, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.586Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.835Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-22T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61034, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.693Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.844Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-23T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61035, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.801Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.852Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-23T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61036, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:21.909Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.860Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-23T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61037, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.016Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.868Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-24T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61038, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.124Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.877Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-24T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61039, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.232Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.885Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 69, 
+        "date": "2013-11-24T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61040, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.348Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.893Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-25T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61041, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.455Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.902Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-25T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61042, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.604Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.910Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-25T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61043, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.712Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.918Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-26T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61044, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.820Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.927Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-26T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61045, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:22.928Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.935Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-26T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61046, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.035Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.943Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-27T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61047, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.143Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.951Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-27T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61048, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.251Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.960Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-27T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61049, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.358Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.968Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-28T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61050, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.466Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.976Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-28T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61051, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.574Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.984Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-28T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61052, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.681Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:11.993Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-29T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61053, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.789Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.001Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-29T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61054, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:23.897Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.009Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-29T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61055, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.004Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.018Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-30T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61056, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.112Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.026Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-30T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61057, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.220Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.034Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-11-30T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61058, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.328Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.042Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-12-01T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61059, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.435Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.051Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-12-01T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61060, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.543Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.059Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 70, 
+        "date": "2013-12-01T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61061, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.659Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.067Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-02T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61062, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.767Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.076Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-02T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61063, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.874Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.084Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-02T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61064, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:24.982Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.092Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-03T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61065, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.090Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.100Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-03T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61066, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.197Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.109Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-03T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61067, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.305Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.117Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-04T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61068, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.413Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.125Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-04T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61069, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.520Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.134Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-04T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61070, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.628Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.142Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-05T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61071, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.736Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.150Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-05T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61072, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.844Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.159Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-05T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61073, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:25.951Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.167Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-06T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61074, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.059Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.175Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-06T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61075, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.167Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.183Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-06T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61076, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.274Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.192Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-07T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61077, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.382Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.200Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-07T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61078, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.490Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.208Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-07T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61079, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.597Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.217Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-08T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61080, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.705Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.225Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-08T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61081, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.813Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.233Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 71, 
+        "date": "2013-12-08T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61082, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:26.929Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.242Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-09T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61083, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.036Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.250Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-09T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61084, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.144Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.258Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-09T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61085, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.252Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.266Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-10T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61086, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.359Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.275Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-10T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61087, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.467Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.283Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-10T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61088, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.628Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.291Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-11T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61089, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.741Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.299Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-11T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61090, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.848Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.308Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-11T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61091, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:27.956Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.316Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-12T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61092, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.064Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.324Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-12T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61093, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.171Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.333Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-12T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61094, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.279Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.341Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-13T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61095, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.387Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.349Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-13T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61096, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.494Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.357Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-13T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61097, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.602Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.366Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-14T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61098, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.710Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.374Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-14T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61099, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.817Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.382Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-14T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61100, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:28.925Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.391Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-15T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61101, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.033Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.399Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-15T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61102, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:29.141Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.407Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "invoiced", 
+        "coreHours": 8.0, 
+        "invoice": 72, 
+        "date": "2013-12-15T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61103, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:12.415Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.415Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 8.0, 
+        "invoice": null, 
+        "date": "2013-12-16T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61104, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:12.424Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.424Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 8.0, 
+        "invoice": null, 
+        "date": "2013-12-16T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61105, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:12.432Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.432Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 8.0, 
+        "invoice": null, 
+        "date": "2013-12-16T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61106, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:12.440Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.440Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 8.0, 
+        "invoice": null, 
+        "date": "2013-12-17T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61107, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:12.449Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.448Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 8.0, 
+        "invoice": null, 
+        "date": "2013-12-17T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61108, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:12.457Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.457Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 8.0, 
+        "invoice": null, 
+        "date": "2013-12-17T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61109, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:12.465Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.465Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 8.0, 
+        "invoice": null, 
+        "date": "2013-12-18T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61110, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:12.473Z", 
+        "slice": 13, 
+        "created": "2013-12-18T21:29:12.473Z", 
+        "deleted": false, 
+        "amount": 0.56, 
+        "object": 116, 
+        "account": 15, 
+        "state": "pending", 
+        "coreHours": 8.0, 
+        "invoice": null, 
+        "date": "2013-12-18T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "reservation", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61111, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.468Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.505Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 64, 
+        "date": "2013-11-18T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61112, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.510Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.565Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 64, 
+        "date": "2013-11-19T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61113, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.551Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.573Z", 
+        "deleted": false, 
+        "amount": 0.308, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.4, 
+        "invoice": 64, 
+        "date": "2013-11-19T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61114, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.593Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.581Z", 
+        "deleted": false, 
+        "amount": 0.2072, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.96, 
+        "invoice": 64, 
+        "date": "2013-11-19T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61115, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.634Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.589Z", 
+        "deleted": false, 
+        "amount": 0.2072, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.96, 
+        "invoice": 64, 
+        "date": "2013-11-20T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61116, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.675Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.598Z", 
+        "deleted": false, 
+        "amount": 0.252, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.6, 
+        "invoice": 64, 
+        "date": "2013-11-20T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61117, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.717Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.606Z", 
+        "deleted": false, 
+        "amount": 0.2688, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.84, 
+        "invoice": 64, 
+        "date": "2013-11-20T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61118, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.758Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.614Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 64, 
+        "date": "2013-11-21T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61119, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.800Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.622Z", 
+        "deleted": false, 
+        "amount": 0.3248, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.64, 
+        "invoice": 64, 
+        "date": "2013-11-21T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61120, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.841Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.631Z", 
+        "deleted": false, 
+        "amount": 0.2072, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.96, 
+        "invoice": 64, 
+        "date": "2013-11-21T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61121, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.883Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.639Z", 
+        "deleted": false, 
+        "amount": 0.2576, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.68, 
+        "invoice": 64, 
+        "date": "2013-11-22T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61122, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.924Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.647Z", 
+        "deleted": false, 
+        "amount": 0.14, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.0, 
+        "invoice": 64, 
+        "date": "2013-11-22T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61123, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.966Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.656Z", 
+        "deleted": false, 
+        "amount": 0.1512, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.16, 
+        "invoice": 64, 
+        "date": "2013-11-22T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61124, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.007Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.664Z", 
+        "deleted": false, 
+        "amount": 0.28, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.0, 
+        "invoice": 64, 
+        "date": "2013-11-23T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61125, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.048Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.672Z", 
+        "deleted": false, 
+        "amount": 0.2408, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.44, 
+        "invoice": 64, 
+        "date": "2013-11-23T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61126, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.090Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.680Z", 
+        "deleted": false, 
+        "amount": 0.308, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.4, 
+        "invoice": 64, 
+        "date": "2013-11-23T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61127, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.131Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.689Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 64, 
+        "date": "2013-11-24T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61128, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.173Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.697Z", 
+        "deleted": false, 
+        "amount": 0.1232, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.76, 
+        "invoice": 64, 
+        "date": "2013-11-24T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61129, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.220Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.705Z", 
+        "deleted": false, 
+        "amount": 0.1848, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.64, 
+        "invoice": 64, 
+        "date": "2013-11-24T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61130, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.289Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.714Z", 
+        "deleted": false, 
+        "amount": 0.2016, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.88, 
+        "invoice": 65, 
+        "date": "2013-11-25T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61131, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.344Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.722Z", 
+        "deleted": false, 
+        "amount": 0.2296, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.28, 
+        "invoice": 65, 
+        "date": "2013-11-25T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61132, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.385Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.730Z", 
+        "deleted": false, 
+        "amount": 0.2968, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.24, 
+        "invoice": 65, 
+        "date": "2013-11-25T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61133, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.427Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.739Z", 
+        "deleted": false, 
+        "amount": 0.1736, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.48, 
+        "invoice": 65, 
+        "date": "2013-11-26T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61134, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.468Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.747Z", 
+        "deleted": false, 
+        "amount": 0.336, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.8, 
+        "invoice": 65, 
+        "date": "2013-11-26T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61135, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.510Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.755Z", 
+        "deleted": false, 
+        "amount": 0.308, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.4, 
+        "invoice": 65, 
+        "date": "2013-11-26T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61136, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.626Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.763Z", 
+        "deleted": false, 
+        "amount": 0.2744, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.92, 
+        "invoice": 65, 
+        "date": "2013-11-27T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61137, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.667Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.772Z", 
+        "deleted": false, 
+        "amount": 0.2016, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.88, 
+        "invoice": 65, 
+        "date": "2013-11-27T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61138, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.709Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.780Z", 
+        "deleted": false, 
+        "amount": 0.1512, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.16, 
+        "invoice": 65, 
+        "date": "2013-11-27T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61139, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.750Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.788Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.16, 
+        "invoice": 65, 
+        "date": "2013-11-28T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61140, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.791Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.797Z", 
+        "deleted": false, 
+        "amount": 0.3248, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.64, 
+        "invoice": 65, 
+        "date": "2013-11-28T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61141, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.833Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.805Z", 
+        "deleted": false, 
+        "amount": 0.3192, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.56, 
+        "invoice": 65, 
+        "date": "2013-11-28T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61142, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.874Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.813Z", 
+        "deleted": false, 
+        "amount": 0.1736, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.48, 
+        "invoice": 65, 
+        "date": "2013-11-29T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61143, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.916Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.821Z", 
+        "deleted": false, 
+        "amount": 0.2632, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.76, 
+        "invoice": 65, 
+        "date": "2013-11-29T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61144, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.957Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.830Z", 
+        "deleted": false, 
+        "amount": 0.2464, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.52, 
+        "invoice": 65, 
+        "date": "2013-11-29T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61145, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.999Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.838Z", 
+        "deleted": false, 
+        "amount": 0.3192, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.56, 
+        "invoice": 65, 
+        "date": "2013-11-30T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61146, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.040Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.846Z", 
+        "deleted": false, 
+        "amount": 0.28, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.0, 
+        "invoice": 65, 
+        "date": "2013-11-30T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61147, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.081Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.854Z", 
+        "deleted": false, 
+        "amount": 0.1288, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.84, 
+        "invoice": 65, 
+        "date": "2013-11-30T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61148, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.123Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.863Z", 
+        "deleted": false, 
+        "amount": 0.1568, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.24, 
+        "invoice": 65, 
+        "date": "2013-12-01T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61149, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.164Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.871Z", 
+        "deleted": false, 
+        "amount": 0.1904, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.72, 
+        "invoice": 65, 
+        "date": "2013-12-01T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61150, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.206Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.879Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 65, 
+        "date": "2013-12-01T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61151, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.255Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.888Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.08, 
+        "invoice": 66, 
+        "date": "2013-12-02T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61152, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.297Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.896Z", 
+        "deleted": false, 
+        "amount": 0.2464, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.52, 
+        "invoice": 66, 
+        "date": "2013-12-02T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61153, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.338Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.904Z", 
+        "deleted": false, 
+        "amount": 0.2464, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.52, 
+        "invoice": 66, 
+        "date": "2013-12-02T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61154, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.379Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.913Z", 
+        "deleted": false, 
+        "amount": 0.2016, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.88, 
+        "invoice": 66, 
+        "date": "2013-12-03T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61155, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.421Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.921Z", 
+        "deleted": false, 
+        "amount": 0.1736, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.48, 
+        "invoice": 66, 
+        "date": "2013-12-03T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61156, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.462Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.929Z", 
+        "deleted": false, 
+        "amount": 0.2408, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.44, 
+        "invoice": 66, 
+        "date": "2013-12-03T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61157, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.504Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.937Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.16, 
+        "invoice": 66, 
+        "date": "2013-12-04T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61158, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.545Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.946Z", 
+        "deleted": false, 
+        "amount": 0.1288, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.84, 
+        "invoice": 66, 
+        "date": "2013-12-04T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61159, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.587Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.954Z", 
+        "deleted": false, 
+        "amount": 0.2632, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.76, 
+        "invoice": 66, 
+        "date": "2013-12-04T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61160, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.628Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.962Z", 
+        "deleted": false, 
+        "amount": 0.3024, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.32, 
+        "invoice": 66, 
+        "date": "2013-12-05T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61161, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.670Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.970Z", 
+        "deleted": false, 
+        "amount": 0.2296, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.28, 
+        "invoice": 66, 
+        "date": "2013-12-05T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61162, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.711Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.979Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 66, 
+        "date": "2013-12-05T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61163, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.752Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.987Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.68, 
+        "invoice": 66, 
+        "date": "2013-12-06T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61164, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.794Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:12.995Z", 
+        "deleted": false, 
+        "amount": 0.28, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.0, 
+        "invoice": 66, 
+        "date": "2013-12-06T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61165, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.835Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.004Z", 
+        "deleted": false, 
+        "amount": 0.224, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.2, 
+        "invoice": 66, 
+        "date": "2013-12-06T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61166, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.877Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.012Z", 
+        "deleted": false, 
+        "amount": 0.2688, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.84, 
+        "invoice": 66, 
+        "date": "2013-12-07T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61167, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.918Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.020Z", 
+        "deleted": false, 
+        "amount": 0.1568, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.24, 
+        "invoice": 66, 
+        "date": "2013-12-07T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61168, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.959Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.028Z", 
+        "deleted": false, 
+        "amount": 0.1624, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.32, 
+        "invoice": 66, 
+        "date": "2013-12-07T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61169, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.001Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.037Z", 
+        "deleted": false, 
+        "amount": 0.2688, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.84, 
+        "invoice": 66, 
+        "date": "2013-12-08T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61170, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.042Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.045Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.16, 
+        "invoice": 66, 
+        "date": "2013-12-08T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61171, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.084Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.053Z", 
+        "deleted": false, 
+        "amount": 0.1344, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.92, 
+        "invoice": 66, 
+        "date": "2013-12-08T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61172, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.133Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.062Z", 
+        "deleted": false, 
+        "amount": 0.196, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.8, 
+        "invoice": 67, 
+        "date": "2013-12-09T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61173, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.175Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.070Z", 
+        "deleted": false, 
+        "amount": 0.2184, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.12, 
+        "invoice": 67, 
+        "date": "2013-12-09T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61174, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.216Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.078Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 67, 
+        "date": "2013-12-09T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61175, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.258Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.086Z", 
+        "deleted": false, 
+        "amount": 0.2184, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.12, 
+        "invoice": 67, 
+        "date": "2013-12-10T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61176, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.299Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.095Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.68, 
+        "invoice": 67, 
+        "date": "2013-12-10T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61177, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.341Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.103Z", 
+        "deleted": false, 
+        "amount": 0.1624, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.32, 
+        "invoice": 67, 
+        "date": "2013-12-10T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61178, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.382Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.111Z", 
+        "deleted": false, 
+        "amount": 0.2968, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.24, 
+        "invoice": 67, 
+        "date": "2013-12-11T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61179, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.423Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.120Z", 
+        "deleted": false, 
+        "amount": 0.1344, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.92, 
+        "invoice": 67, 
+        "date": "2013-12-11T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61180, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.465Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.128Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 67, 
+        "date": "2013-12-11T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61181, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.506Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.136Z", 
+        "deleted": false, 
+        "amount": 0.1344, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.92, 
+        "invoice": 67, 
+        "date": "2013-12-12T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61182, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.548Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.153Z", 
+        "deleted": false, 
+        "amount": 0.112, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.6, 
+        "invoice": 67, 
+        "date": "2013-12-12T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61183, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.589Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.161Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.68, 
+        "invoice": 67, 
+        "date": "2013-12-12T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61184, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.630Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.170Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.08, 
+        "invoice": 67, 
+        "date": "2013-12-13T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61185, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.672Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.178Z", 
+        "deleted": false, 
+        "amount": 0.308, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.4, 
+        "invoice": 67, 
+        "date": "2013-12-13T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61186, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.713Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.186Z", 
+        "deleted": false, 
+        "amount": 0.28, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.0, 
+        "invoice": 67, 
+        "date": "2013-12-13T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61187, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.755Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.195Z", 
+        "deleted": false, 
+        "amount": 0.336, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.8, 
+        "invoice": 67, 
+        "date": "2013-12-14T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61188, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.796Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.203Z", 
+        "deleted": false, 
+        "amount": 0.1344, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.92, 
+        "invoice": 67, 
+        "date": "2013-12-14T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61189, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.804Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.220Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 67, 
+        "date": "2013-12-14T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61190, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.846Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.228Z", 
+        "deleted": false, 
+        "amount": 0.3024, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.32, 
+        "invoice": 67, 
+        "date": "2013-12-15T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61191, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.887Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.236Z", 
+        "deleted": false, 
+        "amount": 0.112, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.6, 
+        "invoice": 67, 
+        "date": "2013-12-15T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61192, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.929Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.245Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 117, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 67, 
+        "date": "2013-12-15T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61193, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:13.253Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.253Z", 
+        "deleted": false, 
+        "amount": 0.1288, 
+        "object": 117, 
+        "account": 14, 
+        "state": "pending", 
+        "coreHours": 1.84, 
+        "invoice": null, 
+        "date": "2013-12-16T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61194, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:13.261Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.261Z", 
+        "deleted": false, 
+        "amount": 0.336, 
+        "object": 117, 
+        "account": 14, 
+        "state": "pending", 
+        "coreHours": 4.8, 
+        "invoice": null, 
+        "date": "2013-12-16T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61195, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:13.278Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.278Z", 
+        "deleted": false, 
+        "amount": 0.1624, 
+        "object": 117, 
+        "account": 14, 
+        "state": "pending", 
+        "coreHours": 2.32, 
+        "invoice": null, 
+        "date": "2013-12-16T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61196, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:13.286Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.286Z", 
+        "deleted": false, 
+        "amount": 0.1904, 
+        "object": 117, 
+        "account": 14, 
+        "state": "pending", 
+        "coreHours": 2.72, 
+        "invoice": null, 
+        "date": "2013-12-17T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61197, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:13.294Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.294Z", 
+        "deleted": false, 
+        "amount": 0.3192, 
+        "object": 117, 
+        "account": 14, 
+        "state": "pending", 
+        "coreHours": 4.56, 
+        "invoice": null, 
+        "date": "2013-12-17T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61198, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:13.303Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.303Z", 
+        "deleted": false, 
+        "amount": 0.14, 
+        "object": 117, 
+        "account": 14, 
+        "state": "pending", 
+        "coreHours": 2.0, 
+        "invoice": null, 
+        "date": "2013-12-17T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61199, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:13.311Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.311Z", 
+        "deleted": false, 
+        "amount": 0.1288, 
+        "object": 117, 
+        "account": 14, 
+        "state": "pending", 
+        "coreHours": 1.84, 
+        "invoice": null, 
+        "date": "2013-12-18T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61200, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:13.319Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.319Z", 
+        "deleted": false, 
+        "amount": 0.2632, 
+        "object": 117, 
+        "account": 14, 
+        "state": "pending", 
+        "coreHours": 3.76, 
+        "invoice": null, 
+        "date": "2013-12-18T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61201, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.427Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.334Z", 
+        "deleted": false, 
+        "amount": 0.2968, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.24, 
+        "invoice": 63, 
+        "date": "2013-11-18T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61202, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.477Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.344Z", 
+        "deleted": false, 
+        "amount": 0.2072, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.96, 
+        "invoice": 64, 
+        "date": "2013-11-19T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61203, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.518Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.352Z", 
+        "deleted": false, 
+        "amount": 0.2968, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.24, 
+        "invoice": 64, 
+        "date": "2013-11-19T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61204, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.560Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.361Z", 
+        "deleted": false, 
+        "amount": 0.2296, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.28, 
+        "invoice": 64, 
+        "date": "2013-11-19T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61205, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.601Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.369Z", 
+        "deleted": false, 
+        "amount": 0.14, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.0, 
+        "invoice": 64, 
+        "date": "2013-11-20T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61206, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.642Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.377Z", 
+        "deleted": false, 
+        "amount": 0.2968, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.24, 
+        "invoice": 64, 
+        "date": "2013-11-20T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61207, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.684Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.385Z", 
+        "deleted": false, 
+        "amount": 0.1512, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.16, 
+        "invoice": 64, 
+        "date": "2013-11-20T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61208, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.725Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.394Z", 
+        "deleted": false, 
+        "amount": 0.336, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.8, 
+        "invoice": 64, 
+        "date": "2013-11-21T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61209, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.767Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.402Z", 
+        "deleted": false, 
+        "amount": 0.2688, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.84, 
+        "invoice": 64, 
+        "date": "2013-11-21T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61210, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.808Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.410Z", 
+        "deleted": false, 
+        "amount": 0.308, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.4, 
+        "invoice": 64, 
+        "date": "2013-11-21T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61211, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.850Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.418Z", 
+        "deleted": false, 
+        "amount": 0.1792, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.56, 
+        "invoice": 64, 
+        "date": "2013-11-22T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61212, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.891Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.427Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 64, 
+        "date": "2013-11-22T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61213, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.932Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.435Z", 
+        "deleted": false, 
+        "amount": 0.1288, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.84, 
+        "invoice": 64, 
+        "date": "2013-11-22T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61214, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.974Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.443Z", 
+        "deleted": false, 
+        "amount": 0.2352, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.36, 
+        "invoice": 64, 
+        "date": "2013-11-23T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61215, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.015Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.452Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 64, 
+        "date": "2013-11-23T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61216, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.057Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.460Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.16, 
+        "invoice": 64, 
+        "date": "2013-11-23T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61217, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.098Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.468Z", 
+        "deleted": false, 
+        "amount": 0.1512, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.16, 
+        "invoice": 64, 
+        "date": "2013-11-24T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61218, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.140Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.476Z", 
+        "deleted": false, 
+        "amount": 0.112, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.6, 
+        "invoice": 64, 
+        "date": "2013-11-24T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61219, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.181Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.485Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 64, 
+        "date": "2013-11-24T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61220, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.239Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.493Z", 
+        "deleted": false, 
+        "amount": 0.1512, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.16, 
+        "invoice": 65, 
+        "date": "2013-11-25T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61221, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.303Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.501Z", 
+        "deleted": false, 
+        "amount": 0.2016, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.88, 
+        "invoice": 65, 
+        "date": "2013-11-25T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61222, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.352Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.510Z", 
+        "deleted": false, 
+        "amount": 0.2968, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.24, 
+        "invoice": 65, 
+        "date": "2013-11-25T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61223, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.394Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.518Z", 
+        "deleted": false, 
+        "amount": 0.1736, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.48, 
+        "invoice": 65, 
+        "date": "2013-11-26T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61224, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.435Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.526Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 65, 
+        "date": "2013-11-26T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61225, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.477Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.534Z", 
+        "deleted": false, 
+        "amount": 0.3248, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.64, 
+        "invoice": 65, 
+        "date": "2013-11-26T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61226, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.531Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.543Z", 
+        "deleted": false, 
+        "amount": 0.1344, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.92, 
+        "invoice": 65, 
+        "date": "2013-11-27T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61227, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.634Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.551Z", 
+        "deleted": false, 
+        "amount": 0.1904, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.72, 
+        "invoice": 65, 
+        "date": "2013-11-27T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61228, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.676Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.559Z", 
+        "deleted": false, 
+        "amount": 0.2576, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.68, 
+        "invoice": 65, 
+        "date": "2013-11-27T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61229, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.717Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.567Z", 
+        "deleted": false, 
+        "amount": 0.3024, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.32, 
+        "invoice": 65, 
+        "date": "2013-11-28T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61230, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.758Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.576Z", 
+        "deleted": false, 
+        "amount": 0.336, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.8, 
+        "invoice": 65, 
+        "date": "2013-11-28T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61231, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.800Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.584Z", 
+        "deleted": false, 
+        "amount": 0.2016, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.88, 
+        "invoice": 65, 
+        "date": "2013-11-28T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61232, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.841Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.592Z", 
+        "deleted": false, 
+        "amount": 0.14, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.0, 
+        "invoice": 65, 
+        "date": "2013-11-29T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61233, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.882Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.601Z", 
+        "deleted": false, 
+        "amount": 0.14, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.0, 
+        "invoice": 65, 
+        "date": "2013-11-29T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61234, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.924Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.609Z", 
+        "deleted": false, 
+        "amount": 0.1232, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.76, 
+        "invoice": 65, 
+        "date": "2013-11-29T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61235, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.965Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.617Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 65, 
+        "date": "2013-11-30T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61236, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.007Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.626Z", 
+        "deleted": false, 
+        "amount": 0.3024, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.32, 
+        "invoice": 65, 
+        "date": "2013-11-30T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61237, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.048Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.634Z", 
+        "deleted": false, 
+        "amount": 0.2968, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.24, 
+        "invoice": 65, 
+        "date": "2013-11-30T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61238, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.090Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.642Z", 
+        "deleted": false, 
+        "amount": 0.3192, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.56, 
+        "invoice": 65, 
+        "date": "2013-12-01T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61239, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.131Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.651Z", 
+        "deleted": false, 
+        "amount": 0.196, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.8, 
+        "invoice": 65, 
+        "date": "2013-12-01T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61240, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.172Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.659Z", 
+        "deleted": false, 
+        "amount": 0.1344, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.92, 
+        "invoice": 65, 
+        "date": "2013-12-01T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61241, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.222Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.667Z", 
+        "deleted": false, 
+        "amount": 0.1512, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.16, 
+        "invoice": 66, 
+        "date": "2013-12-02T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61242, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.264Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.675Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 66, 
+        "date": "2013-12-02T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61243, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.305Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.684Z", 
+        "deleted": false, 
+        "amount": 0.1904, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.72, 
+        "invoice": 66, 
+        "date": "2013-12-02T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61244, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.346Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.692Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.16, 
+        "invoice": 66, 
+        "date": "2013-12-03T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61245, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.388Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.700Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 66, 
+        "date": "2013-12-03T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61246, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.429Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.709Z", 
+        "deleted": false, 
+        "amount": 0.28, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.0, 
+        "invoice": 66, 
+        "date": "2013-12-03T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61247, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.471Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.717Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 66, 
+        "date": "2013-12-04T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61248, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.512Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.725Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.68, 
+        "invoice": 66, 
+        "date": "2013-12-04T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61249, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.553Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.733Z", 
+        "deleted": false, 
+        "amount": 0.1736, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.48, 
+        "invoice": 66, 
+        "date": "2013-12-04T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61250, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.595Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.742Z", 
+        "deleted": false, 
+        "amount": 0.2184, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.12, 
+        "invoice": 66, 
+        "date": "2013-12-05T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61251, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.637Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.750Z", 
+        "deleted": false, 
+        "amount": 0.1624, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.32, 
+        "invoice": 66, 
+        "date": "2013-12-05T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61252, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.678Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.758Z", 
+        "deleted": false, 
+        "amount": 0.3192, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.56, 
+        "invoice": 66, 
+        "date": "2013-12-05T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61253, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.719Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.767Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 66, 
+        "date": "2013-12-06T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61254, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.761Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.775Z", 
+        "deleted": false, 
+        "amount": 0.112, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.6, 
+        "invoice": 66, 
+        "date": "2013-12-06T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61255, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.802Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.783Z", 
+        "deleted": false, 
+        "amount": 0.2688, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.84, 
+        "invoice": 66, 
+        "date": "2013-12-06T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61256, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.843Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.791Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.68, 
+        "invoice": 66, 
+        "date": "2013-12-07T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61257, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.885Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.800Z", 
+        "deleted": false, 
+        "amount": 0.2688, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.84, 
+        "invoice": 66, 
+        "date": "2013-12-07T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61258, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.926Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.808Z", 
+        "deleted": false, 
+        "amount": 0.2296, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.28, 
+        "invoice": 66, 
+        "date": "2013-12-07T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61259, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.968Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.816Z", 
+        "deleted": false, 
+        "amount": 0.224, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.2, 
+        "invoice": 66, 
+        "date": "2013-12-08T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61260, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.009Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.824Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 66, 
+        "date": "2013-12-08T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61261, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.051Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.833Z", 
+        "deleted": false, 
+        "amount": 0.224, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.2, 
+        "invoice": 66, 
+        "date": "2013-12-08T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61262, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.100Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.841Z", 
+        "deleted": false, 
+        "amount": 0.2576, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.68, 
+        "invoice": 67, 
+        "date": "2013-12-09T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61263, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.142Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.849Z", 
+        "deleted": false, 
+        "amount": 0.2296, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.28, 
+        "invoice": 67, 
+        "date": "2013-12-09T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61264, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.183Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.858Z", 
+        "deleted": false, 
+        "amount": 0.2632, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.76, 
+        "invoice": 67, 
+        "date": "2013-12-09T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61265, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.224Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.866Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 67, 
+        "date": "2013-12-10T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61266, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.266Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.874Z", 
+        "deleted": false, 
+        "amount": 0.336, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.8, 
+        "invoice": 67, 
+        "date": "2013-12-10T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61267, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.307Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.882Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 67, 
+        "date": "2013-12-10T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61268, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.349Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.891Z", 
+        "deleted": false, 
+        "amount": 0.2968, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.24, 
+        "invoice": 67, 
+        "date": "2013-12-11T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61269, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.390Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.899Z", 
+        "deleted": false, 
+        "amount": 0.1904, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.72, 
+        "invoice": 67, 
+        "date": "2013-12-11T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61270, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.432Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.907Z", 
+        "deleted": false, 
+        "amount": 0.2184, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.12, 
+        "invoice": 67, 
+        "date": "2013-12-11T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61271, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.473Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.916Z", 
+        "deleted": false, 
+        "amount": 0.2352, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.36, 
+        "invoice": 67, 
+        "date": "2013-12-12T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61272, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.514Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.924Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.68, 
+        "invoice": 67, 
+        "date": "2013-12-12T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61273, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.556Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.932Z", 
+        "deleted": false, 
+        "amount": 0.2464, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.52, 
+        "invoice": 67, 
+        "date": "2013-12-12T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61274, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.597Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.940Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 67, 
+        "date": "2013-12-13T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61275, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.639Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.949Z", 
+        "deleted": false, 
+        "amount": 0.196, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.8, 
+        "invoice": 67, 
+        "date": "2013-12-13T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61276, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.680Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.957Z", 
+        "deleted": false, 
+        "amount": 0.1624, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.32, 
+        "invoice": 67, 
+        "date": "2013-12-13T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61277, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.722Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.965Z", 
+        "deleted": false, 
+        "amount": 0.1232, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.76, 
+        "invoice": 67, 
+        "date": "2013-12-14T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61278, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.763Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.974Z", 
+        "deleted": false, 
+        "amount": 0.2296, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.28, 
+        "invoice": 67, 
+        "date": "2013-12-14T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61279, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.813Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.982Z", 
+        "deleted": false, 
+        "amount": 0.28, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.0, 
+        "invoice": 67, 
+        "date": "2013-12-14T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61280, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.854Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.990Z", 
+        "deleted": false, 
+        "amount": 0.2016, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.88, 
+        "invoice": 67, 
+        "date": "2013-12-15T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61281, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.895Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:13.998Z", 
+        "deleted": false, 
+        "amount": 0.1624, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.32, 
+        "invoice": 67, 
+        "date": "2013-12-15T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61282, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.937Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.007Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 118, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.16, 
+        "invoice": 67, 
+        "date": "2013-12-15T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61283, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:14.015Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.015Z", 
+        "deleted": false, 
+        "amount": 0.1344, 
+        "object": 118, 
+        "account": 14, 
+        "state": "pending", 
+        "coreHours": 1.92, 
+        "invoice": null, 
+        "date": "2013-12-16T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61284, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:14.023Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.023Z", 
+        "deleted": false, 
+        "amount": 0.1848, 
+        "object": 118, 
+        "account": 14, 
+        "state": "pending", 
+        "coreHours": 2.64, 
+        "invoice": null, 
+        "date": "2013-12-16T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61285, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:14.032Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.031Z", 
+        "deleted": false, 
+        "amount": 0.2128, 
+        "object": 118, 
+        "account": 14, 
+        "state": "pending", 
+        "coreHours": 3.04, 
+        "invoice": null, 
+        "date": "2013-12-16T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61286, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:14.040Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.040Z", 
+        "deleted": false, 
+        "amount": 0.2464, 
+        "object": 118, 
+        "account": 14, 
+        "state": "pending", 
+        "coreHours": 3.52, 
+        "invoice": null, 
+        "date": "2013-12-17T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61287, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:14.048Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.048Z", 
+        "deleted": false, 
+        "amount": 0.2352, 
+        "object": 118, 
+        "account": 14, 
+        "state": "pending", 
+        "coreHours": 3.36, 
+        "invoice": null, 
+        "date": "2013-12-17T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61288, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:14.056Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.056Z", 
+        "deleted": false, 
+        "amount": 0.2128, 
+        "object": 118, 
+        "account": 14, 
+        "state": "pending", 
+        "coreHours": 3.04, 
+        "invoice": null, 
+        "date": "2013-12-17T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61289, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:14.065Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.065Z", 
+        "deleted": false, 
+        "amount": 0.14, 
+        "object": 118, 
+        "account": 14, 
+        "state": "pending", 
+        "coreHours": 2.0, 
+        "invoice": null, 
+        "date": "2013-12-18T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61290, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:14.073Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.073Z", 
+        "deleted": false, 
+        "amount": 0.1792, 
+        "object": 118, 
+        "account": 14, 
+        "state": "pending", 
+        "coreHours": 2.56, 
+        "invoice": null, 
+        "date": "2013-12-18T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61291, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.444Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.088Z", 
+        "deleted": false, 
+        "amount": 0.1232, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.76, 
+        "invoice": 64, 
+        "date": "2013-11-18T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61292, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.485Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.098Z", 
+        "deleted": false, 
+        "amount": 0.1288, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.84, 
+        "invoice": 64, 
+        "date": "2013-11-19T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61293, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.527Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.106Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 64, 
+        "date": "2013-11-19T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61294, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.568Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.114Z", 
+        "deleted": false, 
+        "amount": 0.14, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.0, 
+        "invoice": 64, 
+        "date": "2013-11-19T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61295, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.609Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.123Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 64, 
+        "date": "2013-11-20T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61296, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.651Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.131Z", 
+        "deleted": false, 
+        "amount": 0.1792, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.56, 
+        "invoice": 64, 
+        "date": "2013-11-20T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61297, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.692Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.139Z", 
+        "deleted": false, 
+        "amount": 0.252, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.6, 
+        "invoice": 64, 
+        "date": "2013-11-20T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61298, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.734Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.148Z", 
+        "deleted": false, 
+        "amount": 0.2464, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.52, 
+        "invoice": 64, 
+        "date": "2013-11-21T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61299, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.775Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.156Z", 
+        "deleted": false, 
+        "amount": 0.2184, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.12, 
+        "invoice": 64, 
+        "date": "2013-11-21T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61300, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.816Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.164Z", 
+        "deleted": false, 
+        "amount": 0.252, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.6, 
+        "invoice": 64, 
+        "date": "2013-11-21T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61301, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.858Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.172Z", 
+        "deleted": false, 
+        "amount": 0.1624, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.32, 
+        "invoice": 64, 
+        "date": "2013-11-22T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61302, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.899Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.181Z", 
+        "deleted": false, 
+        "amount": 0.2072, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.96, 
+        "invoice": 64, 
+        "date": "2013-11-22T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61303, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.941Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.189Z", 
+        "deleted": false, 
+        "amount": 0.1904, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.72, 
+        "invoice": 64, 
+        "date": "2013-11-22T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61304, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.982Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.197Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 64, 
+        "date": "2013-11-23T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61305, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.024Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.206Z", 
+        "deleted": false, 
+        "amount": 0.2016, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.88, 
+        "invoice": 64, 
+        "date": "2013-11-23T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61306, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.065Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.214Z", 
+        "deleted": false, 
+        "amount": 0.2184, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.12, 
+        "invoice": 64, 
+        "date": "2013-11-23T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61307, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.106Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.222Z", 
+        "deleted": false, 
+        "amount": 0.14, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.0, 
+        "invoice": 64, 
+        "date": "2013-11-24T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61308, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.148Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.230Z", 
+        "deleted": false, 
+        "amount": 0.1288, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.84, 
+        "invoice": 64, 
+        "date": "2013-11-24T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61309, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.189Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.239Z", 
+        "deleted": false, 
+        "amount": 0.2632, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.76, 
+        "invoice": 64, 
+        "date": "2013-11-24T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61310, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.253Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.247Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 65, 
+        "date": "2013-11-25T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61311, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.314Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.255Z", 
+        "deleted": false, 
+        "amount": 0.1568, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.24, 
+        "invoice": 65, 
+        "date": "2013-11-25T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61312, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.361Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.264Z", 
+        "deleted": false, 
+        "amount": 0.2352, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.36, 
+        "invoice": 65, 
+        "date": "2013-11-25T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61313, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.402Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.272Z", 
+        "deleted": false, 
+        "amount": 0.2352, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.36, 
+        "invoice": 65, 
+        "date": "2013-11-26T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61314, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.443Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.280Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 65, 
+        "date": "2013-11-26T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61315, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.485Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.288Z", 
+        "deleted": false, 
+        "amount": 0.2408, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.44, 
+        "invoice": 65, 
+        "date": "2013-11-26T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61316, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.601Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.297Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.16, 
+        "invoice": 65, 
+        "date": "2013-11-27T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61317, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.642Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.305Z", 
+        "deleted": false, 
+        "amount": 0.2688, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.84, 
+        "invoice": 65, 
+        "date": "2013-11-27T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61318, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.684Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.313Z", 
+        "deleted": false, 
+        "amount": 0.168, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.4, 
+        "invoice": 65, 
+        "date": "2013-11-27T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61319, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.725Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.322Z", 
+        "deleted": false, 
+        "amount": 0.1792, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.56, 
+        "invoice": 65, 
+        "date": "2013-11-28T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61320, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.767Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.330Z", 
+        "deleted": false, 
+        "amount": 0.2184, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.12, 
+        "invoice": 65, 
+        "date": "2013-11-28T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61321, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.808Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.338Z", 
+        "deleted": false, 
+        "amount": 0.1848, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.64, 
+        "invoice": 65, 
+        "date": "2013-11-28T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61322, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.849Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.346Z", 
+        "deleted": false, 
+        "amount": 0.1792, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.56, 
+        "invoice": 65, 
+        "date": "2013-11-29T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61323, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.891Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.355Z", 
+        "deleted": false, 
+        "amount": 0.112, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.6, 
+        "invoice": 65, 
+        "date": "2013-11-29T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61324, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.932Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.363Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 65, 
+        "date": "2013-11-29T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61325, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.974Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.371Z", 
+        "deleted": false, 
+        "amount": 0.1568, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.24, 
+        "invoice": 65, 
+        "date": "2013-11-30T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61326, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.015Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.380Z", 
+        "deleted": false, 
+        "amount": 0.3024, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.32, 
+        "invoice": 65, 
+        "date": "2013-11-30T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61327, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.057Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.388Z", 
+        "deleted": false, 
+        "amount": 0.336, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.8, 
+        "invoice": 65, 
+        "date": "2013-11-30T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61328, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.098Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.396Z", 
+        "deleted": false, 
+        "amount": 0.28, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.0, 
+        "invoice": 65, 
+        "date": "2013-12-01T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61329, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.139Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.404Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 65, 
+        "date": "2013-12-01T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61330, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.181Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.413Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.68, 
+        "invoice": 65, 
+        "date": "2013-12-01T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61331, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.231Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.421Z", 
+        "deleted": false, 
+        "amount": 0.3248, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.64, 
+        "invoice": 66, 
+        "date": "2013-12-02T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61332, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.272Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.429Z", 
+        "deleted": false, 
+        "amount": 0.1288, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.84, 
+        "invoice": 66, 
+        "date": "2013-12-02T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61333, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.313Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.437Z", 
+        "deleted": false, 
+        "amount": 0.1848, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.64, 
+        "invoice": 66, 
+        "date": "2013-12-02T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61334, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.355Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.446Z", 
+        "deleted": false, 
+        "amount": 0.168, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.4, 
+        "invoice": 66, 
+        "date": "2013-12-03T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61335, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.396Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.454Z", 
+        "deleted": false, 
+        "amount": 0.1624, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.32, 
+        "invoice": 66, 
+        "date": "2013-12-03T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61336, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.438Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.462Z", 
+        "deleted": false, 
+        "amount": 0.112, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.6, 
+        "invoice": 66, 
+        "date": "2013-12-03T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61337, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.479Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.471Z", 
+        "deleted": false, 
+        "amount": 0.2184, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.12, 
+        "invoice": 66, 
+        "date": "2013-12-04T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61338, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.520Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.479Z", 
+        "deleted": false, 
+        "amount": 0.2576, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.68, 
+        "invoice": 66, 
+        "date": "2013-12-04T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61339, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.562Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.487Z", 
+        "deleted": false, 
+        "amount": 0.2072, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.96, 
+        "invoice": 66, 
+        "date": "2013-12-04T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61340, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.603Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.495Z", 
+        "deleted": false, 
+        "amount": 0.1232, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.76, 
+        "invoice": 66, 
+        "date": "2013-12-05T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61341, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.645Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.504Z", 
+        "deleted": false, 
+        "amount": 0.2632, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.76, 
+        "invoice": 66, 
+        "date": "2013-12-05T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61342, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.686Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.512Z", 
+        "deleted": false, 
+        "amount": 0.14, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.0, 
+        "invoice": 66, 
+        "date": "2013-12-05T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61343, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.728Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.520Z", 
+        "deleted": false, 
+        "amount": 0.196, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.8, 
+        "invoice": 66, 
+        "date": "2013-12-06T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61344, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.769Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.529Z", 
+        "deleted": false, 
+        "amount": 0.2576, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.68, 
+        "invoice": 66, 
+        "date": "2013-12-06T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61345, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.810Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.537Z", 
+        "deleted": false, 
+        "amount": 0.168, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.4, 
+        "invoice": 66, 
+        "date": "2013-12-06T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61346, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.852Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.545Z", 
+        "deleted": false, 
+        "amount": 0.2464, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.52, 
+        "invoice": 66, 
+        "date": "2013-12-07T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61347, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.893Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.553Z", 
+        "deleted": false, 
+        "amount": 0.336, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.8, 
+        "invoice": 66, 
+        "date": "2013-12-07T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61348, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.935Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.562Z", 
+        "deleted": false, 
+        "amount": 0.2464, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.52, 
+        "invoice": 66, 
+        "date": "2013-12-07T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61349, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.976Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.570Z", 
+        "deleted": false, 
+        "amount": 0.2576, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.68, 
+        "invoice": 66, 
+        "date": "2013-12-08T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61350, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.017Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.578Z", 
+        "deleted": false, 
+        "amount": 0.1736, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.48, 
+        "invoice": 66, 
+        "date": "2013-12-08T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61351, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.059Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.587Z", 
+        "deleted": false, 
+        "amount": 0.3024, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.32, 
+        "invoice": 66, 
+        "date": "2013-12-08T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61352, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.109Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.595Z", 
+        "deleted": false, 
+        "amount": 0.1848, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.64, 
+        "invoice": 67, 
+        "date": "2013-12-09T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61353, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.150Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.603Z", 
+        "deleted": false, 
+        "amount": 0.3024, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.32, 
+        "invoice": 67, 
+        "date": "2013-12-09T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61354, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.191Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.611Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 67, 
+        "date": "2013-12-09T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61355, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.233Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.620Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 67, 
+        "date": "2013-12-10T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61356, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.274Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.628Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.68, 
+        "invoice": 67, 
+        "date": "2013-12-10T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61357, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.316Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.636Z", 
+        "deleted": false, 
+        "amount": 0.2072, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.96, 
+        "invoice": 67, 
+        "date": "2013-12-10T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61358, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.357Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.645Z", 
+        "deleted": false, 
+        "amount": 0.2632, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.76, 
+        "invoice": 67, 
+        "date": "2013-12-11T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61359, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.398Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.653Z", 
+        "deleted": false, 
+        "amount": 0.2408, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.44, 
+        "invoice": 67, 
+        "date": "2013-12-11T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61360, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.440Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.661Z", 
+        "deleted": false, 
+        "amount": 0.2744, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.92, 
+        "invoice": 67, 
+        "date": "2013-12-11T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61361, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.481Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.669Z", 
+        "deleted": false, 
+        "amount": 0.3024, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.32, 
+        "invoice": 67, 
+        "date": "2013-12-12T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61362, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.523Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.678Z", 
+        "deleted": false, 
+        "amount": 0.1848, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.64, 
+        "invoice": 67, 
+        "date": "2013-12-12T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61363, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.564Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.686Z", 
+        "deleted": false, 
+        "amount": 0.168, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.4, 
+        "invoice": 67, 
+        "date": "2013-12-12T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61364, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.606Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.694Z", 
+        "deleted": false, 
+        "amount": 0.2576, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.68, 
+        "invoice": 67, 
+        "date": "2013-12-13T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61365, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.647Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.702Z", 
+        "deleted": false, 
+        "amount": 0.3024, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.32, 
+        "invoice": 67, 
+        "date": "2013-12-13T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61366, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.688Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.711Z", 
+        "deleted": false, 
+        "amount": 0.28, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.0, 
+        "invoice": 67, 
+        "date": "2013-12-13T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61367, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.730Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.719Z", 
+        "deleted": false, 
+        "amount": 0.224, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.2, 
+        "invoice": 67, 
+        "date": "2013-12-14T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61368, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.771Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.727Z", 
+        "deleted": false, 
+        "amount": 0.1736, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.48, 
+        "invoice": 67, 
+        "date": "2013-12-14T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61369, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.821Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.736Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 67, 
+        "date": "2013-12-14T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61370, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.862Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.744Z", 
+        "deleted": false, 
+        "amount": 0.2352, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.36, 
+        "invoice": 67, 
+        "date": "2013-12-15T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61371, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.904Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.752Z", 
+        "deleted": false, 
+        "amount": 0.28, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.0, 
+        "invoice": 67, 
+        "date": "2013-12-15T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61372, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.945Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.761Z", 
+        "deleted": false, 
+        "amount": 0.2184, 
+        "object": 119, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.12, 
+        "invoice": 67, 
+        "date": "2013-12-15T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61373, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:14.769Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.769Z", 
+        "deleted": false, 
+        "amount": 0.1288, 
+        "object": 119, 
+        "account": 14, 
+        "state": "pending", 
+        "coreHours": 1.84, 
+        "invoice": null, 
+        "date": "2013-12-16T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61374, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:14.777Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.777Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 119, 
+        "account": 14, 
+        "state": "pending", 
+        "coreHours": 4.48, 
+        "invoice": null, 
+        "date": "2013-12-16T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61375, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:14.785Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.785Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 119, 
+        "account": 14, 
+        "state": "pending", 
+        "coreHours": 2.08, 
+        "invoice": null, 
+        "date": "2013-12-16T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61376, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:14.794Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.794Z", 
+        "deleted": false, 
+        "amount": 0.3192, 
+        "object": 119, 
+        "account": 14, 
+        "state": "pending", 
+        "coreHours": 4.56, 
+        "invoice": null, 
+        "date": "2013-12-17T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61377, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:14.802Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.802Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 119, 
+        "account": 14, 
+        "state": "pending", 
+        "coreHours": 2.08, 
+        "invoice": null, 
+        "date": "2013-12-17T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61378, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:14.810Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.810Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 119, 
+        "account": 14, 
+        "state": "pending", 
+        "coreHours": 4.72, 
+        "invoice": null, 
+        "date": "2013-12-17T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61379, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:14.818Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.818Z", 
+        "deleted": false, 
+        "amount": 0.28, 
+        "object": 119, 
+        "account": 14, 
+        "state": "pending", 
+        "coreHours": 4.0, 
+        "invoice": null, 
+        "date": "2013-12-18T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61380, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:14.827Z", 
+        "slice": 14, 
+        "created": "2013-12-18T21:29:14.827Z", 
+        "deleted": false, 
+        "amount": 0.2352, 
+        "object": 119, 
+        "account": 14, 
+        "state": "pending", 
+        "coreHours": 3.36, 
+        "invoice": null, 
+        "date": "2013-12-18T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61381, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.452Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:14.858Z", 
+        "deleted": false, 
+        "amount": 0.252, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.6, 
+        "invoice": 64, 
+        "date": "2013-11-18T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61382, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.494Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:14.868Z", 
+        "deleted": false, 
+        "amount": 0.2688, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.84, 
+        "invoice": 64, 
+        "date": "2013-11-19T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61383, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.535Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:14.876Z", 
+        "deleted": false, 
+        "amount": 0.1736, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.48, 
+        "invoice": 64, 
+        "date": "2013-11-19T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61384, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.576Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:14.885Z", 
+        "deleted": false, 
+        "amount": 0.2464, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.52, 
+        "invoice": 64, 
+        "date": "2013-11-19T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61385, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.618Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:14.893Z", 
+        "deleted": false, 
+        "amount": 0.196, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.8, 
+        "invoice": 64, 
+        "date": "2013-11-20T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61386, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.659Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:14.901Z", 
+        "deleted": false, 
+        "amount": 0.1232, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.76, 
+        "invoice": 64, 
+        "date": "2013-11-20T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61387, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.700Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:14.910Z", 
+        "deleted": false, 
+        "amount": 0.14, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.0, 
+        "invoice": 64, 
+        "date": "2013-11-20T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61388, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.742Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:14.918Z", 
+        "deleted": false, 
+        "amount": 0.1624, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.32, 
+        "invoice": 64, 
+        "date": "2013-11-21T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61389, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.783Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:14.926Z", 
+        "deleted": false, 
+        "amount": 0.196, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.8, 
+        "invoice": 64, 
+        "date": "2013-11-21T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61390, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.825Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:14.934Z", 
+        "deleted": false, 
+        "amount": 0.196, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.8, 
+        "invoice": 64, 
+        "date": "2013-11-21T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61391, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.866Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:14.943Z", 
+        "deleted": false, 
+        "amount": 0.1792, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.56, 
+        "invoice": 64, 
+        "date": "2013-11-22T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61392, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.908Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:14.951Z", 
+        "deleted": false, 
+        "amount": 0.168, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.4, 
+        "invoice": 64, 
+        "date": "2013-11-22T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61393, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.949Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:14.959Z", 
+        "deleted": false, 
+        "amount": 0.1624, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.32, 
+        "invoice": 64, 
+        "date": "2013-11-22T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61394, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.990Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:14.968Z", 
+        "deleted": false, 
+        "amount": 0.2968, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.24, 
+        "invoice": 64, 
+        "date": "2013-11-23T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61395, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.032Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:14.976Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 64, 
+        "date": "2013-11-23T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61396, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.073Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:14.984Z", 
+        "deleted": false, 
+        "amount": 0.2576, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.68, 
+        "invoice": 64, 
+        "date": "2013-11-23T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61397, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.115Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:14.992Z", 
+        "deleted": false, 
+        "amount": 0.196, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.8, 
+        "invoice": 64, 
+        "date": "2013-11-24T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61398, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.156Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.001Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.16, 
+        "invoice": 64, 
+        "date": "2013-11-24T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61399, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.198Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.009Z", 
+        "deleted": false, 
+        "amount": 0.2352, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.36, 
+        "invoice": 64, 
+        "date": "2013-11-24T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61400, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.264Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.017Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.68, 
+        "invoice": 65, 
+        "date": "2013-11-25T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61401, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.328Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.025Z", 
+        "deleted": false, 
+        "amount": 0.3024, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.32, 
+        "invoice": 65, 
+        "date": "2013-11-25T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61402, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.369Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.034Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 65, 
+        "date": "2013-11-25T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61403, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.410Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.042Z", 
+        "deleted": false, 
+        "amount": 0.2744, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.92, 
+        "invoice": 65, 
+        "date": "2013-11-26T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61404, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.452Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.050Z", 
+        "deleted": false, 
+        "amount": 0.336, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.8, 
+        "invoice": 65, 
+        "date": "2013-11-26T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61405, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.493Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.059Z", 
+        "deleted": false, 
+        "amount": 0.2184, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.12, 
+        "invoice": 65, 
+        "date": "2013-11-26T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61406, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.609Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.067Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.68, 
+        "invoice": 65, 
+        "date": "2013-11-27T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61407, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.651Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.075Z", 
+        "deleted": false, 
+        "amount": 0.196, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.8, 
+        "invoice": 65, 
+        "date": "2013-11-27T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61408, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.692Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.084Z", 
+        "deleted": false, 
+        "amount": 0.1512, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.16, 
+        "invoice": 65, 
+        "date": "2013-11-27T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61409, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.733Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.092Z", 
+        "deleted": false, 
+        "amount": 0.196, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.8, 
+        "invoice": 65, 
+        "date": "2013-11-28T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61410, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.775Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.100Z", 
+        "deleted": false, 
+        "amount": 0.2128, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.04, 
+        "invoice": 65, 
+        "date": "2013-11-28T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61411, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.816Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.108Z", 
+        "deleted": false, 
+        "amount": 0.3192, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.56, 
+        "invoice": 65, 
+        "date": "2013-11-28T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61412, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.858Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.117Z", 
+        "deleted": false, 
+        "amount": 0.224, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.2, 
+        "invoice": 65, 
+        "date": "2013-11-29T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61413, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.899Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.125Z", 
+        "deleted": false, 
+        "amount": 0.1624, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.32, 
+        "invoice": 65, 
+        "date": "2013-11-29T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61414, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.940Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.133Z", 
+        "deleted": false, 
+        "amount": 0.336, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.8, 
+        "invoice": 65, 
+        "date": "2013-11-29T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61415, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.982Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.142Z", 
+        "deleted": false, 
+        "amount": 0.1288, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.84, 
+        "invoice": 65, 
+        "date": "2013-11-30T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61416, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.023Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.150Z", 
+        "deleted": false, 
+        "amount": 0.2016, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.88, 
+        "invoice": 65, 
+        "date": "2013-11-30T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61417, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.065Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.158Z", 
+        "deleted": false, 
+        "amount": 0.2296, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.28, 
+        "invoice": 65, 
+        "date": "2013-11-30T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61418, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.106Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.166Z", 
+        "deleted": false, 
+        "amount": 0.1568, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.24, 
+        "invoice": 65, 
+        "date": "2013-12-01T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61419, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.148Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.175Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.16, 
+        "invoice": 65, 
+        "date": "2013-12-01T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61420, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.189Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.183Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.68, 
+        "invoice": 65, 
+        "date": "2013-12-01T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61421, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.239Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.191Z", 
+        "deleted": false, 
+        "amount": 0.14, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.0, 
+        "invoice": 66, 
+        "date": "2013-12-02T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61422, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.280Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.200Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.08, 
+        "invoice": 66, 
+        "date": "2013-12-02T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61423, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.321Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.208Z", 
+        "deleted": false, 
+        "amount": 0.1848, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.64, 
+        "invoice": 66, 
+        "date": "2013-12-02T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61424, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.363Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.216Z", 
+        "deleted": false, 
+        "amount": 0.2688, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.84, 
+        "invoice": 66, 
+        "date": "2013-12-03T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61425, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.404Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.224Z", 
+        "deleted": false, 
+        "amount": 0.252, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.6, 
+        "invoice": 66, 
+        "date": "2013-12-03T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61426, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.446Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.233Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 66, 
+        "date": "2013-12-03T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61427, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.487Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.241Z", 
+        "deleted": false, 
+        "amount": 0.2968, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.24, 
+        "invoice": 66, 
+        "date": "2013-12-04T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61428, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.529Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.249Z", 
+        "deleted": false, 
+        "amount": 0.2072, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.96, 
+        "invoice": 66, 
+        "date": "2013-12-04T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61429, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.570Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.258Z", 
+        "deleted": false, 
+        "amount": 0.2408, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.44, 
+        "invoice": 66, 
+        "date": "2013-12-04T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61430, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.611Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.266Z", 
+        "deleted": false, 
+        "amount": 0.196, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.8, 
+        "invoice": 66, 
+        "date": "2013-12-05T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61431, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.653Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.274Z", 
+        "deleted": false, 
+        "amount": 0.1568, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.24, 
+        "invoice": 66, 
+        "date": "2013-12-05T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61432, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.694Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.282Z", 
+        "deleted": false, 
+        "amount": 0.1792, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.56, 
+        "invoice": 66, 
+        "date": "2013-12-05T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61433, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.736Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.291Z", 
+        "deleted": false, 
+        "amount": 0.14, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.0, 
+        "invoice": 66, 
+        "date": "2013-12-06T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61434, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.777Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.299Z", 
+        "deleted": false, 
+        "amount": 0.1904, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.72, 
+        "invoice": 66, 
+        "date": "2013-12-06T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61435, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.819Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.307Z", 
+        "deleted": false, 
+        "amount": 0.1568, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.24, 
+        "invoice": 66, 
+        "date": "2013-12-06T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61436, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.860Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.315Z", 
+        "deleted": false, 
+        "amount": 0.196, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.8, 
+        "invoice": 66, 
+        "date": "2013-12-07T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61437, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.901Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.324Z", 
+        "deleted": false, 
+        "amount": 0.1624, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.32, 
+        "invoice": 66, 
+        "date": "2013-12-07T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61438, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.943Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.332Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.16, 
+        "invoice": 66, 
+        "date": "2013-12-07T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61439, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.984Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.340Z", 
+        "deleted": false, 
+        "amount": 0.2352, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.36, 
+        "invoice": 66, 
+        "date": "2013-12-08T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61440, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.026Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.348Z", 
+        "deleted": false, 
+        "amount": 0.1736, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.48, 
+        "invoice": 66, 
+        "date": "2013-12-08T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61441, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.067Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.357Z", 
+        "deleted": false, 
+        "amount": 0.336, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.8, 
+        "invoice": 66, 
+        "date": "2013-12-08T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61442, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.117Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.365Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 67, 
+        "date": "2013-12-09T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61443, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.158Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.373Z", 
+        "deleted": false, 
+        "amount": 0.2744, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.92, 
+        "invoice": 67, 
+        "date": "2013-12-09T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61444, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.200Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.382Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.68, 
+        "invoice": 67, 
+        "date": "2013-12-09T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61445, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.241Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.390Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.08, 
+        "invoice": 67, 
+        "date": "2013-12-10T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61446, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.283Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.398Z", 
+        "deleted": false, 
+        "amount": 0.1344, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.92, 
+        "invoice": 67, 
+        "date": "2013-12-10T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61447, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.324Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.407Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.08, 
+        "invoice": 67, 
+        "date": "2013-12-10T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61448, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.365Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.415Z", 
+        "deleted": false, 
+        "amount": 0.112, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.6, 
+        "invoice": 67, 
+        "date": "2013-12-11T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61449, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.407Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.423Z", 
+        "deleted": false, 
+        "amount": 0.14, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.0, 
+        "invoice": 67, 
+        "date": "2013-12-11T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61450, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.448Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.431Z", 
+        "deleted": false, 
+        "amount": 0.2744, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.92, 
+        "invoice": 67, 
+        "date": "2013-12-11T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61451, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.490Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.440Z", 
+        "deleted": false, 
+        "amount": 0.2408, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.44, 
+        "invoice": 67, 
+        "date": "2013-12-12T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61452, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.531Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.448Z", 
+        "deleted": false, 
+        "amount": 0.1848, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.64, 
+        "invoice": 67, 
+        "date": "2013-12-12T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61453, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.572Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.456Z", 
+        "deleted": false, 
+        "amount": 0.308, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.4, 
+        "invoice": 67, 
+        "date": "2013-12-12T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61454, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.614Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.464Z", 
+        "deleted": false, 
+        "amount": 0.1568, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.24, 
+        "invoice": 67, 
+        "date": "2013-12-13T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61455, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.655Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.473Z", 
+        "deleted": false, 
+        "amount": 0.14, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.0, 
+        "invoice": 67, 
+        "date": "2013-12-13T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61456, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.697Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.481Z", 
+        "deleted": false, 
+        "amount": 0.1568, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.24, 
+        "invoice": 67, 
+        "date": "2013-12-13T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61457, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.738Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.489Z", 
+        "deleted": false, 
+        "amount": 0.336, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.8, 
+        "invoice": 67, 
+        "date": "2013-12-14T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61458, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.779Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.498Z", 
+        "deleted": false, 
+        "amount": 0.2072, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.96, 
+        "invoice": 67, 
+        "date": "2013-12-14T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61459, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.829Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.506Z", 
+        "deleted": false, 
+        "amount": 0.2688, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.84, 
+        "invoice": 67, 
+        "date": "2013-12-14T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61460, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.871Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.516Z", 
+        "deleted": false, 
+        "amount": 0.3248, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.64, 
+        "invoice": 67, 
+        "date": "2013-12-15T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61461, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.912Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.524Z", 
+        "deleted": false, 
+        "amount": 0.1624, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.32, 
+        "invoice": 67, 
+        "date": "2013-12-15T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61462, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.953Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.533Z", 
+        "deleted": false, 
+        "amount": 0.1176, 
+        "object": 120, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.68, 
+        "invoice": 67, 
+        "date": "2013-12-15T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61463, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:15.541Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.541Z", 
+        "deleted": false, 
+        "amount": 0.3192, 
+        "object": 120, 
+        "account": 14, 
+        "state": "pending", 
+        "coreHours": 4.56, 
+        "invoice": null, 
+        "date": "2013-12-16T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61464, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:15.549Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.549Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 120, 
+        "account": 14, 
+        "state": "pending", 
+        "coreHours": 4.48, 
+        "invoice": null, 
+        "date": "2013-12-16T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61465, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:15.557Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.557Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 120, 
+        "account": 14, 
+        "state": "pending", 
+        "coreHours": 2.08, 
+        "invoice": null, 
+        "date": "2013-12-16T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61466, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:15.566Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.566Z", 
+        "deleted": false, 
+        "amount": 0.28, 
+        "object": 120, 
+        "account": 14, 
+        "state": "pending", 
+        "coreHours": 4.0, 
+        "invoice": null, 
+        "date": "2013-12-17T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61467, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:15.574Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.574Z", 
+        "deleted": false, 
+        "amount": 0.2072, 
+        "object": 120, 
+        "account": 14, 
+        "state": "pending", 
+        "coreHours": 2.96, 
+        "invoice": null, 
+        "date": "2013-12-17T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61468, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:15.582Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.582Z", 
+        "deleted": false, 
+        "amount": 0.2352, 
+        "object": 120, 
+        "account": 14, 
+        "state": "pending", 
+        "coreHours": 3.36, 
+        "invoice": null, 
+        "date": "2013-12-17T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61469, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:15.591Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.590Z", 
+        "deleted": false, 
+        "amount": 0.336, 
+        "object": 120, 
+        "account": 14, 
+        "state": "pending", 
+        "coreHours": 4.8, 
+        "invoice": null, 
+        "date": "2013-12-18T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61470, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:15.599Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.599Z", 
+        "deleted": false, 
+        "amount": 0.1232, 
+        "object": 120, 
+        "account": 14, 
+        "state": "pending", 
+        "coreHours": 1.76, 
+        "invoice": null, 
+        "date": "2013-12-18T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61471, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.460Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.614Z", 
+        "deleted": false, 
+        "amount": 0.1848, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.64, 
+        "invoice": 64, 
+        "date": "2013-11-18T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61472, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.502Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.624Z", 
+        "deleted": false, 
+        "amount": 0.2464, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.52, 
+        "invoice": 64, 
+        "date": "2013-11-19T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61473, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.543Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.632Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.08, 
+        "invoice": 64, 
+        "date": "2013-11-19T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61474, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.585Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.640Z", 
+        "deleted": false, 
+        "amount": 0.2184, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.12, 
+        "invoice": 64, 
+        "date": "2013-11-19T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61475, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.626Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.649Z", 
+        "deleted": false, 
+        "amount": 0.252, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.6, 
+        "invoice": 64, 
+        "date": "2013-11-20T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61476, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.667Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.657Z", 
+        "deleted": false, 
+        "amount": 0.2352, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.36, 
+        "invoice": 64, 
+        "date": "2013-11-20T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61477, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.709Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.665Z", 
+        "deleted": false, 
+        "amount": 0.2408, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.44, 
+        "invoice": 64, 
+        "date": "2013-11-20T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61478, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.750Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.673Z", 
+        "deleted": false, 
+        "amount": 0.168, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.4, 
+        "invoice": 64, 
+        "date": "2013-11-21T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61479, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.792Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.682Z", 
+        "deleted": false, 
+        "amount": 0.1904, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.72, 
+        "invoice": 64, 
+        "date": "2013-11-21T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61480, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.833Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.690Z", 
+        "deleted": false, 
+        "amount": 0.14, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.0, 
+        "invoice": 64, 
+        "date": "2013-11-21T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61481, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.874Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.698Z", 
+        "deleted": false, 
+        "amount": 0.3248, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.64, 
+        "invoice": 64, 
+        "date": "2013-11-22T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61482, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.916Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.707Z", 
+        "deleted": false, 
+        "amount": 0.2072, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.96, 
+        "invoice": 64, 
+        "date": "2013-11-22T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61483, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.957Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.715Z", 
+        "deleted": false, 
+        "amount": 0.1736, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.48, 
+        "invoice": 64, 
+        "date": "2013-11-22T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61484, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.999Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.723Z", 
+        "deleted": false, 
+        "amount": 0.1904, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.72, 
+        "invoice": 64, 
+        "date": "2013-11-23T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61485, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.040Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.731Z", 
+        "deleted": false, 
+        "amount": 0.2744, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.92, 
+        "invoice": 64, 
+        "date": "2013-11-23T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61486, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.081Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.740Z", 
+        "deleted": false, 
+        "amount": 0.2184, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.12, 
+        "invoice": 64, 
+        "date": "2013-11-23T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61487, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.123Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.748Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.16, 
+        "invoice": 64, 
+        "date": "2013-11-24T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61488, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.164Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.756Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 64, 
+        "date": "2013-11-24T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61489, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.206Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.765Z", 
+        "deleted": false, 
+        "amount": 0.168, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.4, 
+        "invoice": 64, 
+        "date": "2013-11-24T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61490, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.278Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.773Z", 
+        "deleted": false, 
+        "amount": 0.224, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.2, 
+        "invoice": 65, 
+        "date": "2013-11-25T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61491, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.336Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.781Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 65, 
+        "date": "2013-11-25T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61492, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.377Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.789Z", 
+        "deleted": false, 
+        "amount": 0.336, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.8, 
+        "invoice": 65, 
+        "date": "2013-11-25T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61493, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.419Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.798Z", 
+        "deleted": false, 
+        "amount": 0.1736, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.48, 
+        "invoice": 65, 
+        "date": "2013-11-26T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61494, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.460Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.806Z", 
+        "deleted": false, 
+        "amount": 0.1792, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.56, 
+        "invoice": 65, 
+        "date": "2013-11-26T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61495, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.501Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.814Z", 
+        "deleted": false, 
+        "amount": 0.1288, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.84, 
+        "invoice": 65, 
+        "date": "2013-11-26T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61496, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.618Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.822Z", 
+        "deleted": false, 
+        "amount": 0.2744, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.92, 
+        "invoice": 65, 
+        "date": "2013-11-27T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61497, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.659Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.831Z", 
+        "deleted": false, 
+        "amount": 0.196, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.8, 
+        "invoice": 65, 
+        "date": "2013-11-27T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61498, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.700Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.839Z", 
+        "deleted": false, 
+        "amount": 0.2296, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.28, 
+        "invoice": 65, 
+        "date": "2013-11-27T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61499, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.742Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.847Z", 
+        "deleted": false, 
+        "amount": 0.1288, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.84, 
+        "invoice": 65, 
+        "date": "2013-11-28T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61500, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.783Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.856Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.16, 
+        "invoice": 65, 
+        "date": "2013-11-28T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61501, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.824Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.864Z", 
+        "deleted": false, 
+        "amount": 0.2464, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.52, 
+        "invoice": 65, 
+        "date": "2013-11-28T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61502, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.866Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.872Z", 
+        "deleted": false, 
+        "amount": 0.224, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.2, 
+        "invoice": 65, 
+        "date": "2013-11-29T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61503, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.907Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.880Z", 
+        "deleted": false, 
+        "amount": 0.2408, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.44, 
+        "invoice": 65, 
+        "date": "2013-11-29T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61504, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.949Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.889Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.08, 
+        "invoice": 65, 
+        "date": "2013-11-29T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61505, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:17.990Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.897Z", 
+        "deleted": false, 
+        "amount": 0.1848, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.64, 
+        "invoice": 65, 
+        "date": "2013-11-30T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61506, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.032Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.905Z", 
+        "deleted": false, 
+        "amount": 0.2576, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.68, 
+        "invoice": 65, 
+        "date": "2013-11-30T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61507, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.073Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.914Z", 
+        "deleted": false, 
+        "amount": 0.2128, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.04, 
+        "invoice": 65, 
+        "date": "2013-11-30T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61508, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.114Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.922Z", 
+        "deleted": false, 
+        "amount": 0.3248, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.64, 
+        "invoice": 65, 
+        "date": "2013-12-01T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61509, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.156Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.930Z", 
+        "deleted": false, 
+        "amount": 0.224, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.2, 
+        "invoice": 65, 
+        "date": "2013-12-01T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61510, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.197Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.938Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 65, 
+        "date": "2013-12-01T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61511, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.247Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.947Z", 
+        "deleted": false, 
+        "amount": 0.2912, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.16, 
+        "invoice": 66, 
+        "date": "2013-12-02T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61512, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.288Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.955Z", 
+        "deleted": false, 
+        "amount": 0.252, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.6, 
+        "invoice": 66, 
+        "date": "2013-12-02T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61513, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.330Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.963Z", 
+        "deleted": false, 
+        "amount": 0.2968, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.24, 
+        "invoice": 66, 
+        "date": "2013-12-02T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61514, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.371Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.972Z", 
+        "deleted": false, 
+        "amount": 0.1568, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.24, 
+        "invoice": 66, 
+        "date": "2013-12-03T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61515, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.413Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.980Z", 
+        "deleted": false, 
+        "amount": 0.3024, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.32, 
+        "invoice": 66, 
+        "date": "2013-12-03T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61516, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.454Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.988Z", 
+        "deleted": false, 
+        "amount": 0.196, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.8, 
+        "invoice": 66, 
+        "date": "2013-12-03T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61517, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.496Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:15.997Z", 
+        "deleted": false, 
+        "amount": 0.2968, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.24, 
+        "invoice": 66, 
+        "date": "2013-12-04T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61518, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.537Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.005Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 66, 
+        "date": "2013-12-04T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61519, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.578Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.013Z", 
+        "deleted": false, 
+        "amount": 0.1848, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.64, 
+        "invoice": 66, 
+        "date": "2013-12-04T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61520, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.620Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.021Z", 
+        "deleted": false, 
+        "amount": 0.2408, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.44, 
+        "invoice": 66, 
+        "date": "2013-12-05T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61521, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.661Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.030Z", 
+        "deleted": false, 
+        "amount": 0.2464, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.52, 
+        "invoice": 66, 
+        "date": "2013-12-05T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61522, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.703Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.038Z", 
+        "deleted": false, 
+        "amount": 0.28, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.0, 
+        "invoice": 66, 
+        "date": "2013-12-05T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61523, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.744Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.046Z", 
+        "deleted": false, 
+        "amount": 0.1848, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.64, 
+        "invoice": 66, 
+        "date": "2013-12-06T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61524, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.785Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.054Z", 
+        "deleted": false, 
+        "amount": 0.308, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.4, 
+        "invoice": 66, 
+        "date": "2013-12-06T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61525, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.827Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.063Z", 
+        "deleted": false, 
+        "amount": 0.3248, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.64, 
+        "invoice": 66, 
+        "date": "2013-12-06T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61526, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.868Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.071Z", 
+        "deleted": false, 
+        "amount": 0.112, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.6, 
+        "invoice": 66, 
+        "date": "2013-12-07T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61527, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.910Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.079Z", 
+        "deleted": false, 
+        "amount": 0.252, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.6, 
+        "invoice": 66, 
+        "date": "2013-12-07T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61528, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.951Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.088Z", 
+        "deleted": false, 
+        "amount": 0.308, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.4, 
+        "invoice": 66, 
+        "date": "2013-12-07T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61529, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:18.993Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.096Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 66, 
+        "date": "2013-12-08T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61530, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.034Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.104Z", 
+        "deleted": false, 
+        "amount": 0.2296, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.28, 
+        "invoice": 66, 
+        "date": "2013-12-08T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61531, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.075Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.112Z", 
+        "deleted": false, 
+        "amount": 0.3024, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.32, 
+        "invoice": 66, 
+        "date": "2013-12-08T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61532, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.125Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.121Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.08, 
+        "invoice": 67, 
+        "date": "2013-12-09T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61533, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.167Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.129Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.08, 
+        "invoice": 67, 
+        "date": "2013-12-09T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61534, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.208Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.137Z", 
+        "deleted": false, 
+        "amount": 0.2184, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.12, 
+        "invoice": 67, 
+        "date": "2013-12-09T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61535, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.249Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.146Z", 
+        "deleted": false, 
+        "amount": 0.2184, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.12, 
+        "invoice": 67, 
+        "date": "2013-12-10T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61536, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.291Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.154Z", 
+        "deleted": false, 
+        "amount": 0.1624, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.32, 
+        "invoice": 67, 
+        "date": "2013-12-10T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61537, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.332Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.162Z", 
+        "deleted": false, 
+        "amount": 0.308, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.4, 
+        "invoice": 67, 
+        "date": "2013-12-10T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61538, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.374Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.170Z", 
+        "deleted": false, 
+        "amount": 0.1568, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.24, 
+        "invoice": 67, 
+        "date": "2013-12-11T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61539, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.415Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.179Z", 
+        "deleted": false, 
+        "amount": 0.2856, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.08, 
+        "invoice": 67, 
+        "date": "2013-12-11T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61540, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.457Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.187Z", 
+        "deleted": false, 
+        "amount": 0.3136, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.48, 
+        "invoice": 67, 
+        "date": "2013-12-11T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61541, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.498Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.195Z", 
+        "deleted": false, 
+        "amount": 0.224, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.2, 
+        "invoice": 67, 
+        "date": "2013-12-12T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61542, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.539Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.204Z", 
+        "deleted": false, 
+        "amount": 0.2688, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.84, 
+        "invoice": 67, 
+        "date": "2013-12-12T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61543, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.581Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.212Z", 
+        "deleted": false, 
+        "amount": 0.224, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.2, 
+        "invoice": 67, 
+        "date": "2013-12-12T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61544, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.622Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.220Z", 
+        "deleted": false, 
+        "amount": 0.28, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.0, 
+        "invoice": 67, 
+        "date": "2013-12-13T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61545, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.664Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.228Z", 
+        "deleted": false, 
+        "amount": 0.1792, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.56, 
+        "invoice": 67, 
+        "date": "2013-12-13T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61546, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.705Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.237Z", 
+        "deleted": false, 
+        "amount": 0.1344, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 1.92, 
+        "invoice": 67, 
+        "date": "2013-12-13T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61547, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.746Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.245Z", 
+        "deleted": false, 
+        "amount": 0.2072, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.96, 
+        "invoice": 67, 
+        "date": "2013-12-14T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61548, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.788Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.253Z", 
+        "deleted": false, 
+        "amount": 0.252, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.6, 
+        "invoice": 67, 
+        "date": "2013-12-14T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61549, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.837Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.262Z", 
+        "deleted": false, 
+        "amount": 0.2296, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 3.28, 
+        "invoice": 67, 
+        "date": "2013-12-14T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61550, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.879Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.270Z", 
+        "deleted": false, 
+        "amount": 0.1456, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.08, 
+        "invoice": 67, 
+        "date": "2013-12-15T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61551, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.920Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.278Z", 
+        "deleted": false, 
+        "amount": 0.3304, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 4.72, 
+        "invoice": 67, 
+        "date": "2013-12-15T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61552, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:19.962Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.286Z", 
+        "deleted": false, 
+        "amount": 0.2016, 
+        "object": 121, 
+        "account": 14, 
+        "state": "invoiced", 
+        "coreHours": 2.88, 
+        "invoice": 67, 
+        "date": "2013-12-15T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61553, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.295Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.295Z", 
+        "deleted": false, 
+        "amount": 0.2128, 
+        "object": 121, 
+        "account": 14, 
+        "state": "pending", 
+        "coreHours": 3.04, 
+        "invoice": null, 
+        "date": "2013-12-16T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61554, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.303Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.303Z", 
+        "deleted": false, 
+        "amount": 0.3192, 
+        "object": 121, 
+        "account": 14, 
+        "state": "pending", 
+        "coreHours": 4.56, 
+        "invoice": null, 
+        "date": "2013-12-16T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61555, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.311Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.311Z", 
+        "deleted": false, 
+        "amount": 0.1232, 
+        "object": 121, 
+        "account": 14, 
+        "state": "pending", 
+        "coreHours": 1.76, 
+        "invoice": null, 
+        "date": "2013-12-16T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61556, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.320Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.320Z", 
+        "deleted": false, 
+        "amount": 0.1736, 
+        "object": 121, 
+        "account": 14, 
+        "state": "pending", 
+        "coreHours": 2.48, 
+        "invoice": null, 
+        "date": "2013-12-17T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61557, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.328Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.328Z", 
+        "deleted": false, 
+        "amount": 0.1792, 
+        "object": 121, 
+        "account": 14, 
+        "state": "pending", 
+        "coreHours": 2.56, 
+        "invoice": null, 
+        "date": "2013-12-17T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61558, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.336Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.336Z", 
+        "deleted": false, 
+        "amount": 0.112, 
+        "object": 121, 
+        "account": 14, 
+        "state": "pending", 
+        "coreHours": 1.6, 
+        "invoice": null, 
+        "date": "2013-12-17T21:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61559, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.344Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.344Z", 
+        "deleted": false, 
+        "amount": 0.196, 
+        "object": 121, 
+        "account": 14, 
+        "state": "pending", 
+        "coreHours": 2.8, 
+        "invoice": null, 
+        "date": "2013-12-18T05:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 61560, 
+    "model": "core.charge", 
+    "fields": {
+        "updated": "2013-12-18T21:29:16.353Z", 
+        "slice": 15, 
+        "created": "2013-12-18T21:29:16.353Z", 
+        "deleted": false, 
+        "amount": 0.252, 
+        "object": 121, 
+        "account": 14, 
+        "state": "pending", 
+        "coreHours": 3.6, 
+        "invoice": null, 
+        "date": "2013-12-18T13:00:00Z", 
+        "backend_status": "Provisioning in progress", 
+        "kind": "besteffort", 
+        "enacted": null
+    }
+},
+{
+    "pk": 14, 
+    "model": "hpc.hpcservice", 
+    "fields": {}
+},
+{
+    "pk": 1, 
+    "model": "hpc.serviceprovider", 
+    "fields": {
+        "updated": "2013-12-11T18:11:43.757Z", 
+        "name": "internet2", 
+        "created": "2013-12-11T18:11:43.757Z", 
+        "deleted": false, 
+        "description": "", 
+        "enabled": true, 
+        "service_provider_id": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 2, 
+    "model": "hpc.serviceprovider", 
+    "fields": {
+        "updated": "2013-12-11T18:13:38.024Z", 
+        "name": "Syndicate", 
+        "created": "2013-12-11T18:11:52.622Z", 
+        "deleted": false, 
+        "description": "", 
+        "enabled": true, 
+        "service_provider_id": null, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 29, 
+    "model": "hpc.contentprovider", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.472Z", 
+        "name": "Syndicate", 
+        "created": "2013-12-11T23:57:17.472Z", 
+        "deleted": false, 
+        "serviceProvider": 2, 
+        "description": "Peer-to-peer content sharing for Syndicate distributed filesystem", 
+        "enabled": true, 
+        "content_provider_id": null, 
+        "users": [], 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 30, 
+    "model": "hpc.contentprovider", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.586Z", 
+        "name": "Georgia Tech", 
+        "created": "2013-12-11T23:57:20.586Z", 
+        "deleted": false, 
+        "serviceProvider": 1, 
+        "description": "Content Provider for Georgia Tech", 
+        "enabled": true, 
+        "content_provider_id": null, 
+        "users": [], 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 31, 
+    "model": "hpc.contentprovider", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.611Z", 
+        "name": "Stanford University", 
+        "created": "2013-12-11T23:57:20.611Z", 
+        "deleted": false, 
+        "serviceProvider": 1, 
+        "description": "Content Provider for Stanford University", 
+        "enabled": true, 
+        "content_provider_id": null, 
+        "users": [], 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 32, 
+    "model": "hpc.contentprovider", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.636Z", 
+        "name": "University of Washington", 
+        "created": "2013-12-11T23:57:20.636Z", 
+        "deleted": false, 
+        "serviceProvider": 1, 
+        "description": "Content Provider for University of Washington", 
+        "enabled": true, 
+        "content_provider_id": null, 
+        "users": [], 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 33, 
+    "model": "hpc.contentprovider", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.660Z", 
+        "name": "Max Planck Institute", 
+        "created": "2013-12-11T23:57:20.660Z", 
+        "deleted": false, 
+        "serviceProvider": 1, 
+        "description": "Content Provider for Max Planck Institute", 
+        "enabled": true, 
+        "content_provider_id": null, 
+        "users": [], 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 34, 
+    "model": "hpc.contentprovider", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.685Z", 
+        "name": "Princeton University", 
+        "created": "2013-12-11T23:57:20.685Z", 
+        "deleted": false, 
+        "serviceProvider": 1, 
+        "description": "Content Provider for Princeton University", 
+        "enabled": true, 
+        "content_provider_id": null, 
+        "users": [], 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 35, 
+    "model": "hpc.contentprovider", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.710Z", 
+        "name": "ON.LAB", 
+        "created": "2013-12-11T23:57:20.710Z", 
+        "deleted": false, 
+        "serviceProvider": 1, 
+        "description": "Open Networking Lab", 
+        "enabled": true, 
+        "content_provider_id": null, 
+        "users": [], 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3527, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.496Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.496Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node70.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3528, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.503Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.503Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node69.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3529, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.512Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.512Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node68.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3530, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.520Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.520Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node67.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3531, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.528Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.528Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node66.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3532, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.537Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.537Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node65.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3533, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.545Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.545Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node64.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3534, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.553Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.553Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node63.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3535, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.561Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.561Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node62.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3536, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.570Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.570Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node61.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3537, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.578Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.578Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node60.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3538, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.586Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.586Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node59.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3539, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.595Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.595Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node58.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3540, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.603Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.603Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node57.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3541, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.611Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.611Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node56.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3542, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.619Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.619Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node55.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3543, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.628Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.628Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node54.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3544, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.636Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.636Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node53.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3545, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.644Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.644Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node52.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3546, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.653Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.653Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node51.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3547, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.661Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.661Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node50.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3548, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.669Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.669Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node49.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3549, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.677Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.677Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node48.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3550, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.686Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.686Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node47.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3551, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.694Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.694Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node46.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3552, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.702Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.702Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node45.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3553, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.711Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.711Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node44.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3554, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.719Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.719Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node43.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3555, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.727Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.727Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node42.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3556, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.735Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.735Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node41.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3557, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.744Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.744Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node40.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3558, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.752Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.752Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node39.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3559, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.760Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.760Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node38.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3560, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.768Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.768Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node37.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3561, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.777Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.777Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node36.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3562, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.785Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.785Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node35.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3563, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.793Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.793Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node34.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3564, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.802Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.802Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node33.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3565, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.810Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.810Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node32.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3566, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.818Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.818Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node31.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3567, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.826Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.826Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node30.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3568, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.835Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.835Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node29.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3569, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.843Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.843Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node28.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3570, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.851Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.851Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node27.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3571, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.860Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.860Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node26.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3572, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.868Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.868Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node25.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3573, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.876Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.876Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node24.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3574, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.884Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.884Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node23.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3575, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.893Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.893Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node22.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3576, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.901Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.901Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node21.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3577, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.909Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.909Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node20.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3578, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.918Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.918Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node19.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3579, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.926Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.926Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node18.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3580, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.934Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.934Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node17.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3581, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.942Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.942Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node16.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3582, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.951Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.951Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node15.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3583, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.959Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.959Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node14.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3584, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.967Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.967Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node13.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3585, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.975Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.975Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node12.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3586, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.984Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.984Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node11.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3587, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:17.992Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:17.992Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node10.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3588, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node9.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3589, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.009Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.009Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node8.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3590, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.017Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.017Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node7.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3591, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.025Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.025Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node6.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3592, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.034Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.034Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node5.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3593, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.042Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.042Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node4.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3594, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.050Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.050Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node3.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3595, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.058Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.058Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node2.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3596, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.067Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.067Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node1.stanford.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3597, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.084Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.084Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node70.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3598, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.092Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.092Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node69.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3599, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.100Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.100Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node68.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3600, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.108Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.108Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node67.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3601, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.116Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.116Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node66.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3602, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.125Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.125Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node65.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3603, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.133Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.133Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node64.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3604, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.141Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.141Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node63.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3605, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.149Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.149Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node62.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3606, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.158Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.158Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node61.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3607, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.166Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.166Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node60.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3608, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.174Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.174Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node59.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3609, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.183Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.183Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node58.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3610, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.191Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.191Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node57.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3611, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.199Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.199Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node56.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3612, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.208Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.207Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node55.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3613, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.216Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.216Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node54.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3614, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.224Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.224Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node53.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3615, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.238Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.238Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node52.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3616, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.286Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.286Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node51.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3617, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.299Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.298Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node50.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3618, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.307Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.307Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node49.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3619, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.315Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.315Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node48.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3620, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.323Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.323Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node47.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3621, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.332Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.332Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node46.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3622, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.340Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.340Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node45.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3623, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.348Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.348Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node44.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3624, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.357Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.356Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node43.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3625, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.365Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.365Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node42.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3626, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.373Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.373Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node41.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3627, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.381Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.381Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node40.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3628, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.390Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.390Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node39.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3629, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.398Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.398Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node38.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3630, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.406Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.406Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node37.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3631, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.414Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.414Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node36.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3632, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.423Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.423Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node35.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3633, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.431Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.431Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node34.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3634, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.439Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.439Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node33.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3635, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.448Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.448Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node32.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3636, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.456Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.456Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node31.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3637, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.464Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.464Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node30.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3638, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.472Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.472Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node29.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3639, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.481Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.481Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node28.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3640, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.489Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.489Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node27.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3641, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.497Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.497Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node26.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3642, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.506Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.505Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node25.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3643, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.514Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.514Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node24.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3644, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.522Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.522Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node23.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3645, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.530Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.530Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node22.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3646, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.539Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.539Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node21.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3647, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.547Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.547Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node20.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3648, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.555Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.555Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node19.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3649, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.564Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.563Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node18.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3650, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.572Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.572Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node17.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3651, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.580Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.580Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node16.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3652, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.588Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.588Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node15.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3653, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.597Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.597Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node14.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3654, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.605Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.605Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node13.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3655, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.613Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.613Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node12.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3656, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.622Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.622Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node11.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3657, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.630Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.630Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node10.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3658, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.638Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.638Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node9.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3659, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.646Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.646Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node8.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3660, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.655Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.655Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node7.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3661, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.663Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.663Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node6.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3662, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.671Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.671Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node5.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3663, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.680Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.680Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node4.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3664, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.688Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.688Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node3.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3665, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.696Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.696Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node2.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3666, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.704Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.704Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node1.washington.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3667, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.722Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.722Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node70.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3668, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.729Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.729Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node69.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3669, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.738Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.737Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node68.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3670, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.746Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.746Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node67.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3671, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.754Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.754Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node66.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3672, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.762Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.762Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node65.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3673, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.771Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.771Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node64.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3674, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.779Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.779Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node63.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3675, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.787Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.787Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node62.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3676, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.795Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.795Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node61.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3677, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.804Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.804Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node60.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3678, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.812Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.812Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node59.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3679, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.820Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.820Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node58.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3680, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.829Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.829Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node57.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3681, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.837Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.837Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node56.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3682, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.845Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.845Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node55.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3683, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.853Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.853Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node54.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3684, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.862Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.862Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node53.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3685, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.870Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.870Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node52.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3686, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.878Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.878Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node51.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3687, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.887Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.887Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node50.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3688, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.895Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.895Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node49.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3689, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.903Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.903Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node48.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3690, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.911Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.911Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node47.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3691, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.920Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.920Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node46.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3692, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.928Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.928Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node45.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3693, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.936Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.936Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node44.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3694, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.944Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.944Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node43.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3695, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.953Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.953Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node42.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3696, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.961Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.961Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node41.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3697, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.969Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.969Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node40.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3698, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.978Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.978Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node39.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3699, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.986Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.986Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node38.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3700, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:18.994Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:18.994Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node37.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3701, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.002Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.002Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node36.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3702, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.011Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.011Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node35.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3703, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.019Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.019Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node34.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3704, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.027Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.027Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node33.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3705, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.036Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.036Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node32.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3706, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.044Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.044Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node31.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3707, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.052Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.052Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node30.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3708, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.060Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.060Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node29.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3709, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.069Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.069Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node28.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3710, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.077Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.077Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node27.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3711, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.086Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.085Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node26.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3712, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.094Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.094Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node25.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3713, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.102Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.102Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node24.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3714, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.110Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.110Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node23.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3715, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.118Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.118Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node22.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3716, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.127Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.127Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node21.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3717, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.135Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.135Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node20.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3718, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.143Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.143Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node19.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3719, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.152Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.152Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node18.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3720, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.160Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.160Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node17.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3721, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.168Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.168Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node16.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3722, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.176Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.176Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node15.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3723, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.185Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.185Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node14.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3724, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.193Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.193Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node13.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3725, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.201Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.201Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node12.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3726, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.210Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.210Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node11.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3727, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.218Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.218Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node10.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3728, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.226Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.226Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node9.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3729, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.234Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.234Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node8.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3730, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.243Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.243Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node7.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3731, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.251Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.251Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node6.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3732, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.259Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.259Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node5.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3733, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.268Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.268Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node4.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3734, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.276Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.276Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node3.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3735, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.284Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.284Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node2.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3736, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.292Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.292Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node1.princeton.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3737, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.310Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.310Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node70.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3738, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.317Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.317Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node69.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3739, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.325Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.325Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node68.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3740, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.334Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.334Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node67.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3741, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.342Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.342Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node66.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3742, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.350Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.350Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node65.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3743, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.359Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.359Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node64.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3744, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.367Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.367Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node63.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3745, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.375Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.375Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node62.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3746, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.383Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.383Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node61.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3747, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.392Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.392Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node60.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3748, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.400Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.400Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node59.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3749, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.408Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.408Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node58.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3750, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.417Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.416Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node57.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3751, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.425Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.425Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node56.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3752, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.433Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.433Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node55.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3753, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.441Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.441Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node54.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3754, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.450Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.450Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node53.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3755, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.458Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.458Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node52.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3756, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.466Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.466Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node51.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3757, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.475Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.475Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node50.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3758, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.483Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.483Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node49.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3759, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.491Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.491Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node48.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3760, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.499Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.499Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node47.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3761, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.508Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.508Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node46.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3762, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.516Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.516Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node45.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3763, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.524Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.524Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node44.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3764, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.533Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.532Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node43.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3765, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.541Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.541Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node42.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3766, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.549Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.549Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node41.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3767, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.557Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.557Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node40.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3768, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.566Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.566Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node39.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3769, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.574Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.574Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node38.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3770, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.582Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.582Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node37.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3771, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.591Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.590Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node36.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3772, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.599Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.599Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node35.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3773, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.607Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.607Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node34.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3774, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.615Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.615Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node33.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3775, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.624Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.624Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node32.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3776, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.632Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.632Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node31.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3777, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.640Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.640Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node30.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3778, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.649Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.648Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node29.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3779, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.657Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.657Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node28.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3780, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.665Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.665Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node27.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3781, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.673Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.673Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node26.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3782, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.682Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.682Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node25.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3783, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.690Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.690Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node24.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3784, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.698Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.698Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node23.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3785, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.706Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.706Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node22.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3786, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.715Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.715Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node21.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3787, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.723Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.723Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node20.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3788, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.731Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.731Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node19.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3789, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.740Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.740Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node18.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3790, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.748Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.748Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node17.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3791, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.756Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.756Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node16.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3792, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.764Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.764Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node15.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3793, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.773Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.773Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node14.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3794, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.781Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.781Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node13.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3795, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.789Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.789Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node12.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3796, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.798Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.798Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node11.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3797, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.806Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.806Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node10.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3798, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.814Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.814Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node9.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3799, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.822Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.822Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node8.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3800, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.831Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.831Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node7.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3801, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.839Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.839Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node6.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3802, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.847Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.847Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node5.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3803, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.856Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.855Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node4.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3804, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.864Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.864Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node3.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3805, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.872Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.872Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node2.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3806, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.880Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.880Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node1.gt.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3807, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.898Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.898Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node70.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3808, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.905Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.905Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node69.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3809, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.913Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.913Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node68.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3810, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.922Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.922Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node67.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3811, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.930Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.930Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node66.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3812, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.938Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.938Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node65.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3813, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.947Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.947Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node64.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3814, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.955Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.955Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node63.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3815, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.963Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.963Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node62.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3816, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.971Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.971Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node61.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3817, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.980Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.980Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node60.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3818, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.988Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.988Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node59.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3819, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:19.996Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:19.996Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node58.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3820, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.005Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.005Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node57.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3821, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.013Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.013Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node56.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3822, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.021Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.021Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node55.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3823, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.029Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.029Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node54.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3824, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.038Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.038Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node53.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3825, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.046Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.046Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node52.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3826, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.054Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.054Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node51.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3827, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.063Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.062Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node50.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3828, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.071Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.071Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node49.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3829, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.079Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.079Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node48.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3830, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.087Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.087Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node47.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3831, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.096Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.096Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node46.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3832, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.104Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.104Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node45.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3833, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.112Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.112Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node44.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3834, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.121Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.121Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node43.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3835, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.129Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.129Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node42.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3836, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.137Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.137Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node41.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3837, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.146Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.145Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node40.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3838, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.154Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.154Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node39.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3839, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.162Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.162Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node38.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3840, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.170Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.170Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node37.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3841, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.179Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.179Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node36.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3842, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.187Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.187Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node35.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3843, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.195Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.195Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node34.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3844, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.203Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.203Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node33.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3845, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.212Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.212Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node32.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3846, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.220Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.220Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node31.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3847, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.228Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.228Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node30.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3848, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.237Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.236Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node29.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3849, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.245Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.245Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node28.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3850, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.253Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.253Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node27.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3851, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.261Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.261Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node26.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3852, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.270Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.270Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node25.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3853, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.278Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.278Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node24.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3854, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.286Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.286Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node23.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3855, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.294Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.294Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node22.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3856, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.303Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.303Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node21.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3857, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.311Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.311Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node20.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3858, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.319Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.319Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node19.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3859, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.328Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.328Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node18.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3860, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.336Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.336Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node17.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3861, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.344Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.344Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node16.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3862, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.352Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.352Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node15.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3863, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.361Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.361Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node14.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3864, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.369Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.369Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node13.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3865, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.377Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.377Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node12.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3866, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.386Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.386Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node11.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3867, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.394Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.394Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node10.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3868, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.402Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.402Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node9.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3869, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.410Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.410Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node8.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3870, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.419Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.419Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node7.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3871, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.427Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.427Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node6.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3872, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.435Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.435Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node5.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3873, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.443Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.443Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node4.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3874, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.452Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.452Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node3.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3875, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.460Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.460Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node2.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3876, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.468Z", 
+        "contentProvider": 29, 
+        "origin_server_id": null, 
+        "description": "syndicate origin server", 
+        "created": "2013-12-11T23:57:20.468Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "node1.mpisws.vicci.org:32780", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3877, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.594Z", 
+        "contentProvider": 30, 
+        "origin_server_id": null, 
+        "description": "Content from www.cs.gatech.edu", 
+        "created": "2013-12-11T23:57:20.594Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "www.cs.gatech.edu", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3878, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.619Z", 
+        "contentProvider": 31, 
+        "origin_server_id": null, 
+        "description": "Content from www.cs.stanford.edu", 
+        "created": "2013-12-11T23:57:20.619Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "www.cs.stanford.edu", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3879, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.644Z", 
+        "contentProvider": 32, 
+        "origin_server_id": null, 
+        "description": "Content from www.cs.washington.edu", 
+        "created": "2013-12-11T23:57:20.644Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "www.cs.washington.edu", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3880, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.669Z", 
+        "contentProvider": 33, 
+        "origin_server_id": null, 
+        "description": "Content from www.mpg.de", 
+        "created": "2013-12-11T23:57:20.669Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "www.mpg.de", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3881, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.694Z", 
+        "contentProvider": 34, 
+        "origin_server_id": null, 
+        "description": "Content from www.cs.princeton.edu", 
+        "created": "2013-12-11T23:57:20.694Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "www.cs.princeton.edu", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 3882, 
+    "model": "hpc.originserver", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.719Z", 
+        "contentProvider": 35, 
+        "origin_server_id": null, 
+        "description": "onlab virtual machine images", 
+        "created": "2013-12-11T23:57:20.719Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "redirects": true, 
+        "protocol": "http", 
+        "url": "images.onlab.org", 
+        "authenticated": false, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 36, 
+    "model": "hpc.cdnprefix", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.479Z", 
+        "contentProvider": 29, 
+        "description": "CDN Prefix for the Syndicate distributed filesystem", 
+        "created": "2013-12-11T23:57:20.479Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "cdn_prefix_id": null, 
+        "prefix": "cdn.syndicatedrive.com", 
+        "defaultOriginServer": 3876, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 37, 
+    "model": "hpc.cdnprefix", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.602Z", 
+        "contentProvider": 30, 
+        "description": "CDN Prefix for Georgia Tech", 
+        "created": "2013-12-11T23:57:20.602Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "cdn_prefix_id": null, 
+        "prefix": "gt.opencdn.internet2.edu", 
+        "defaultOriginServer": 3877, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 38, 
+    "model": "hpc.cdnprefix", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.627Z", 
+        "contentProvider": 31, 
+        "description": "CDN Prefix for Stanford University", 
+        "created": "2013-12-11T23:57:20.627Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "cdn_prefix_id": null, 
+        "prefix": "stanford.opencdn.internet2.edu", 
+        "defaultOriginServer": 3878, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 39, 
+    "model": "hpc.cdnprefix", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.652Z", 
+        "contentProvider": 32, 
+        "description": "CDN Prefix for University of Washington", 
+        "created": "2013-12-11T23:57:20.652Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "cdn_prefix_id": null, 
+        "prefix": "washington.opencdn.internet2.edu", 
+        "defaultOriginServer": 3879, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 40, 
+    "model": "hpc.cdnprefix", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.677Z", 
+        "contentProvider": 33, 
+        "description": "CDN Prefix for Max Planck Institute", 
+        "created": "2013-12-11T23:57:20.677Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "cdn_prefix_id": null, 
+        "prefix": "mp.opencdn.internet2.edu", 
+        "defaultOriginServer": 3880, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 41, 
+    "model": "hpc.cdnprefix", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.702Z", 
+        "contentProvider": 34, 
+        "description": "CDN Prefix for Princeton University", 
+        "created": "2013-12-11T23:57:20.702Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "cdn_prefix_id": null, 
+        "prefix": "princeton.opencdn.internet2.edu", 
+        "defaultOriginServer": 3881, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 42, 
+    "model": "hpc.cdnprefix", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.727Z", 
+        "contentProvider": 35, 
+        "description": "CDN Prefix for ON.LAB", 
+        "created": "2013-12-11T23:57:20.727Z", 
+        "deleted": false, 
+        "enabled": true, 
+        "cdn_prefix_id": null, 
+        "prefix": "onlab.vicci.org", 
+        "defaultOriginServer": 3882, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 5, 
+    "model": "syndicate_storage.syndicateservice", 
+    "fields": {}
+},
+{
+    "pk": 1, 
+    "model": "syndicate_storage.volume", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.727Z", 
+        "name": "GenBank-11-2013", 
+        "created": "2013-12-11T23:57:20.727Z", 
+        "deleted": false, 
+        "blocksize": 61440, 
+        "description": "GenBank dataset snapshot from Nov. 2013", 
+        "owner_id": 1, 
+        "private": false, 
+        "cap_write_data": false, 
+        "cap_read_data": true, 
+        "cap_host_data": false, 
+        "backend_status": "Provisioning in progress", 
+        "archive": true, 
+        "enacted": null
+    }
+},
+{
+    "pk": 2, 
+    "model": "syndicate_storage.volume", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.727Z", 
+        "name": "princeton_syndicate-Volume", 
+        "created": "2013-12-11T23:57:20.727Z", 
+        "deleted": false, 
+        "blocksize": 102400, 
+        "description": "Volume associated with princeton_syndicate", 
+        "owner_id": 1, 
+        "private": true, 
+        "cap_write_data": true, 
+        "cap_read_data": true, 
+        "cap_host_data": true, 
+        "backend_status": "Provisioning in progress", 
+        "archive": false, 
+        "enacted": null
+    }
+},
+{
+    "pk": 3, 
+    "model": "syndicate_storage.volume", 
+    "fields": {
+        "updated": "2014-05-23T18:52:00.782Z", 
+        "name": "LSST", 
+        "created": "2014-05-23T18:52:00.782Z", 
+        "deleted": false, 
+        "blocksize": 61440, 
+        "description": "LSST dataset", 
+        "owner_id": 1, 
+        "private": false, 
+        "cap_write_data": false, 
+        "cap_read_data": true, 
+        "cap_host_data": false, 
+        "backend_status": "Provisioning in progress", 
+        "archive": true, 
+        "enacted": null
+    }
+},
+{
+    "pk": 4, 
+    "model": "syndicate_storage.volume", 
+    "fields": {
+        "updated": "2014-05-23T18:52:53.617Z", 
+        "name": "LHC", 
+        "created": "2014-05-23T18:52:53.617Z", 
+        "deleted": false, 
+        "blocksize": 61440, 
+        "description": "LHC dataset", 
+        "owner_id": 1, 
+        "private": false, 
+        "cap_write_data": false, 
+        "cap_read_data": true, 
+        "cap_host_data": false, 
+        "backend_status": "Provisioning in progress", 
+        "archive": true, 
+        "enacted": null
+    }
+},
+{
+    "pk": 5, 
+    "model": "syndicate_storage.volume", 
+    "fields": {
+        "updated": "2014-05-23T18:53:20.349Z", 
+        "name": "NOAA", 
+        "created": "2014-05-23T18:53:20.349Z", 
+        "deleted": false, 
+        "blocksize": 61440, 
+        "description": "NOAA dataset", 
+        "owner_id": 1, 
+        "private": false, 
+        "cap_write_data": false, 
+        "cap_read_data": true, 
+        "cap_host_data": false, 
+        "backend_status": "Provisioning in progress", 
+        "archive": true, 
+        "enacted": null
+    }
+},
+{
+    "pk": 6, 
+    "model": "syndicate_storage.volume", 
+    "fields": {
+        "updated": "2014-05-23T18:53:56.495Z", 
+        "name": "Measurement Lab", 
+        "created": "2014-05-23T18:53:56.495Z", 
+        "deleted": false, 
+        "blocksize": 61440, 
+        "description": "Measurement Lab dataset", 
+        "owner_id": 1, 
+        "private": false, 
+        "cap_write_data": false, 
+        "cap_read_data": true, 
+        "cap_host_data": false, 
+        "backend_status": "Provisioning in progress", 
+        "archive": true, 
+        "enacted": null
+    }
+},
+{
+    "pk": 7, 
+    "model": "syndicate_storage.volume", 
+    "fields": {
+        "updated": "2014-05-23T18:54:35.691Z", 
+        "name": "Common Crawl", 
+        "created": "2014-05-23T18:54:35.691Z", 
+        "deleted": false, 
+        "blocksize": 61440, 
+        "description": "Common Crawl dataset", 
+        "owner_id": 1, 
+        "private": false, 
+        "cap_write_data": false, 
+        "cap_read_data": true, 
+        "cap_host_data": false, 
+        "backend_status": "Provisioning in progress", 
+        "archive": true, 
+        "enacted": null
+    }
+},
+{
+    "pk": 8, 
+    "model": "syndicate_storage.volume", 
+    "fields": {
+        "updated": "2014-05-27T14:05:41.026Z", 
+        "name": "private_Analytics", 
+        "created": "2014-05-27T14:05:41.025Z", 
+        "deleted": false, 
+        "blocksize": 61440, 
+        "description": "private volume for Analytics", 
+        "owner_id": 7, 
+        "private": true, 
+        "cap_write_data": true, 
+        "cap_read_data": true, 
+        "cap_host_data": true, 
+        "backend_status": "Provisioning in progress", 
+        "archive": false, 
+        "enacted": null
+    }
+},
+{
+    "pk": 9, 
+    "model": "syndicate_storage.volume", 
+    "fields": {
+        "updated": "2014-05-29T22:00:50.320Z", 
+        "name": "demo-bio5", 
+        "created": "2014-05-29T22:00:25.032Z", 
+        "deleted": false, 
+        "blocksize": 102400, 
+        "description": "This is the bio5 demo volume", 
+        "owner_id": 6, 
+        "private": true, 
+        "cap_write_data": true, 
+        "cap_read_data": true, 
+        "cap_host_data": true, 
+        "backend_status": "Provisioning in progress", 
+        "archive": false, 
+        "enacted": null
+    }
+},
+{
+    "pk": 1, 
+    "model": "syndicate_storage.volumeaccessright", 
+    "fields": {
+        "updated": "2013-12-11T23:57:20.727Z", 
+        "cap_host_data": false, 
+        "created": "2013-12-11T23:57:20.727Z", 
+        "deleted": false, 
+        "owner_id": 1, 
+        "cap_write_data": false, 
+        "volume": 1, 
+        "cap_read_data": true, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+},
+{
+    "pk": 1, 
+    "model": "syndicate_storage.volumeslice", 
+    "fields": {
+        "updated": "2014-05-27T14:05:41.084Z", 
+        "cap_host_data": false, 
+        "slice_id": 16, 
+        "created": "2014-05-27T14:05:41.084Z", 
+        "deleted": false, 
+        "cap_read_data": true, 
+        "cap_write_data": false, 
+        "UG_portnum": 1026, 
+        "RG_portnum": 1025, 
+        "volume_id": 8, 
+        "backend_status": "Provisioning in progress", 
+        "credentials_blob": null, 
+        "enacted": null
+    }
+},
+{
+    "pk": 2, 
+    "model": "syndicate_storage.volumeslice", 
+    "fields": {
+        "updated": "2014-05-29T22:00:50.340Z", 
+        "cap_host_data": false, 
+        "slice_id": 14, 
+        "created": "2014-05-29T22:00:50.340Z", 
+        "deleted": false, 
+        "cap_read_data": true, 
+        "cap_write_data": false, 
+        "UG_portnum": 4444, 
+        "RG_portnum": 5555, 
+        "volume_id": 9, 
+        "backend_status": "Provisioning in progress", 
+        "credentials_blob": null, 
+        "enacted": null
+    }
+},
+{
+    "pk": 1, 
+    "model": "core.siteprivilege", 
+    "fields": {
+        "updated": "2013-12-17T18:08:58.293Z", 
+        "created": "2013-12-17T18:08:58.293Z", 
+        "deleted": false, 
+        "site": 24, 
+        "role": 1, 
+        "user": 15, 
+        "backend_status": "Provisioning in progress", 
+        "enacted": null
+    }
+}
+]
diff --git a/xos/core/fixtures/serviceclass_intial_data.json b/xos/core/fixtures/serviceclass_intial_data.json
new file mode 100644
index 0000000..a8caf63
--- /dev/null
+++ b/xos/core/fixtures/serviceclass_intial_data.json
@@ -0,0 +1,132 @@
+[
+{
+    "pk": 1, 
+    "model": "core.serviceclass", 
+    "fields": {
+        "updated": "2013-05-10T23:30:52.931Z", 
+        "membershipFee": 0, 
+        "membershipFeeMonths": 0, 
+        "created": "2013-05-10T23:30:52.931Z", 
+        "upgradeFrom": [3, 2], 
+        "commitment": 0, 
+        "name": "Best Effort", 
+        "upgradeRequiresApproval": false, 
+        "description": "Best Effort"
+    }
+}, 
+{
+    "pk": 2, 
+    "model": "core.serviceclass", 
+    "fields": {
+        "updated": "2013-05-10T23:35:51.694Z", 
+        "membershipFee": 100, 
+        "membershipFeeMonths": 1, 
+        "created": "2013-05-10T23:33:24.930Z", 
+        "upgradeFrom": [1, 3], 
+        "commitment": 365, 
+        "name": "Silver", 
+        "upgradeRequiresApproval": false, 
+        "description": "Silver"
+    }
+}, 
+{
+    "pk": 3, 
+    "model": "core.serviceclass", 
+    "fields": {
+        "updated": "2013-05-10T23:34:01.320Z", 
+        "membershipFee": 18000, 
+        "membershipFeeMonths": 12, 
+        "created": "2013-05-10T23:34:01.320Z", 
+        "upgradeFrom": [1, 2], 
+        "commitment": 365, 
+        "name": "Gold", 
+        "upgradeRequiresApproval": false, 
+        "description": "Gold"
+    }
+}, 
+{
+    "pk": 1, 
+    "model": "core.serviceresource", 
+    "fields": {
+        "updated": "2013-05-10T23:44:50.862Z", 
+        "name": "Cycles", 
+        "bucketMaxSize": 0, 
+        "created": "2013-05-10T23:37:09.312Z", 
+        "serviceClass": 1, 
+        "maxUnitsDeployment": 0, 
+        "bucketInRate": 0, 
+        "cost": 7, 
+        "calendarReservable": false, 
+        "maxDuration": 0, 
+        "maxUnitsNode": 0
+    }
+}, 
+{
+    "pk": 2, 
+    "model": "core.serviceresource", 
+    "fields": {
+        "updated": "2013-05-10T23:44:39.936Z", 
+        "name": "Cycles", 
+        "bucketMaxSize": 0, 
+        "created": "2013-05-10T23:44:39.936Z", 
+        "serviceClass": 2, 
+        "maxUnitsDeployment": 0, 
+        "bucketInRate": 0, 
+        "cost": 7, 
+        "calendarReservable": false, 
+        "maxDuration": 0, 
+        "maxUnitsNode": 0
+    }
+}, 
+{
+    "pk": 3, 
+    "model": "core.serviceresource", 
+    "fields": {
+        "updated": "2013-05-10T23:45:16.137Z", 
+        "name": "Cycles", 
+        "bucketMaxSize": 0, 
+        "created": "2013-05-10T23:45:16.137Z", 
+        "serviceClass": 3, 
+        "maxUnitsDeployment": 0, 
+        "bucketInRate": 0, 
+        "cost": 7, 
+        "calendarReservable": false, 
+        "maxDuration": 0, 
+        "maxUnitsNode": 0
+    }
+}, 
+{
+    "pk": 4, 
+    "model": "core.serviceresource", 
+    "fields": {
+        "updated": "2013-05-10T23:47:39.033Z", 
+        "name": "numberCores", 
+        "bucketMaxSize": 210, 
+        "created": "2013-05-10T23:46:33.201Z", 
+        "serviceClass": 2, 
+        "maxUnitsDeployment": 210, 
+        "bucketInRate": 10, 
+        "cost": 7, 
+        "calendarReservable": true, 
+        "maxDuration": 168, 
+        "maxUnitsNode": 6
+    }
+}, 
+{
+    "pk": 5, 
+    "model": "core.serviceresource", 
+    "fields": {
+        "updated": "2013-05-10T23:47:31.771Z", 
+        "name": "numberCores", 
+        "bucketMaxSize": 0, 
+        "created": "2013-05-10T23:47:31.770Z", 
+        "serviceClass": 3, 
+        "maxUnitsDeployment": 210, 
+        "bucketInRate": 0, 
+        "cost": 0, 
+        "calendarReservable": true, 
+        "maxDuration": 8760, 
+        "maxUnitsNode": 6
+    }
+}
+]
diff --git a/xos/core/middleware.py b/xos/core/middleware.py
new file mode 100644
index 0000000..4cfd991
--- /dev/null
+++ b/xos/core/middleware.py
@@ -0,0 +1,13 @@
+from threading import local
+
+_active = local()
+
+def get_request():
+    if not hasattr(_active, "request"):
+        raise Exception("Please add 'core.middleware.GlobalRequestMiddleware' to <XOS_DIR>/xos.settings.py:MIDDLEWARE_CLASSES")
+    return _active.request
+
+class GlobalRequestMiddleware(object):
+    def process_view(self, request, view_func, view_args, view_kwargs):
+        _active.request = request
+        return None
diff --git a/xos/core/migrations/0001_initial.py b/xos/core/migrations/0001_initial.py
new file mode 100644
index 0000000..c55a8bf
--- /dev/null
+++ b/xos/core/migrations/0001_initial.py
@@ -0,0 +1,1953 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+import core.models.instance
+import core.models.network
+import core.models.serviceclass
+import django.utils.timezone
+import encrypted_fields.fields
+import geoposition.fields
+import timezones.fields
+from django.conf import settings
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('contenttypes', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='User',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('password', models.CharField(
+                    max_length=128, verbose_name='password')),
+                ('last_login', models.DateTimeField(
+                    default=django.utils.timezone.now, verbose_name='last login')),
+                ('email', models.EmailField(unique=True, max_length=255,
+                                            verbose_name=b'email address', db_index=True)),
+                ('username', models.CharField(default=b'Something', max_length=255)),
+                ('firstname', models.CharField(
+                    help_text=b"person's given name", max_length=200)),
+                ('lastname', models.CharField(
+                    help_text=b"person's surname", max_length=200)),
+                ('phone', models.CharField(help_text=b'phone number contact',
+                                           max_length=100, null=True, blank=True)),
+                ('user_url', models.URLField(null=True, blank=True)),
+                ('public_key', models.TextField(
+                    help_text=b'Public key string', max_length=1024, null=True, blank=True)),
+                ('is_active', models.BooleanField(default=True)),
+                ('is_admin', models.BooleanField(default=True)),
+                ('is_staff', models.BooleanField(default=True)),
+                ('is_readonly', models.BooleanField(default=False)),
+                ('created', models.DateTimeField(auto_now_add=True)),
+                ('updated', models.DateTimeField(auto_now=True)),
+                ('enacted', models.DateTimeField(default=None, null=True)),
+                ('policed', models.DateTimeField(default=None, null=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('timezone', timezones.fields.TimeZoneField(default=b'America/New_York', max_length=100, choices=[(b'Pacific/Midway', b'(GMT-1100) Pacific/Midway'), (b'Pacific/Niue', b'(GMT-1100) Pacific/Niue'), (b'Pacific/Pago_Pago', b'(GMT-1100) Pacific/Pago_Pago'), (b'America/Adak', b'(GMT-1000) America/Adak'), (b'Pacific/Honolulu', b'(GMT-1000) Pacific/Honolulu'), (b'Pacific/Johnston', b'(GMT-1000) Pacific/Johnston'), (b'Pacific/Rarotonga', b'(GMT-1000) Pacific/Rarotonga'), (b'Pacific/Tahiti', b'(GMT-1000) Pacific/Tahiti'), (b'US/Hawaii', b'(GMT-1000) US/Hawaii'), (b'Pacific/Marquesas', b'(GMT-0930) Pacific/Marquesas'), (b'America/Anchorage', b'(GMT-0900) America/Anchorage'), (b'America/Juneau', b'(GMT-0900) America/Juneau'), (b'America/Nome', b'(GMT-0900) America/Nome'), (b'America/Sitka', b'(GMT-0900) America/Sitka'), (b'America/Yakutat', b'(GMT-0900) America/Yakutat'), (b'Pacific/Gambier', b'(GMT-0900) Pacific/Gambier'), (b'US/Alaska', b'(GMT-0900) US/Alaska'), (b'America/Dawson', b'(GMT-0800) America/Dawson'), (b'America/Los_Angeles', b'(GMT-0800) America/Los_Angeles'), (b'America/Metlakatla', b'(GMT-0800) America/Metlakatla'), (b'America/Santa_Isabel', b'(GMT-0800) America/Santa_Isabel'), (b'America/Tijuana', b'(GMT-0800) America/Tijuana'), (b'America/Vancouver', b'(GMT-0800) America/Vancouver'), (b'America/Whitehorse', b'(GMT-0800) America/Whitehorse'), (b'Canada/Pacific', b'(GMT-0800) Canada/Pacific'), (b'Pacific/Pitcairn', b'(GMT-0800) Pacific/Pitcairn'), (b'US/Pacific', b'(GMT-0800) US/Pacific'), (b'America/Boise', b'(GMT-0700) America/Boise'), (b'America/Cambridge_Bay', b'(GMT-0700) America/Cambridge_Bay'), (b'America/Chihuahua', b'(GMT-0700) America/Chihuahua'), (b'America/Creston', b'(GMT-0700) America/Creston'), (b'America/Dawson_Creek', b'(GMT-0700) America/Dawson_Creek'), (b'America/Denver', b'(GMT-0700) America/Denver'), (b'America/Edmonton', b'(GMT-0700) America/Edmonton'), (b'America/Hermosillo', b'(GMT-0700) America/Hermosillo'), (b'America/Inuvik', b'(GMT-0700) America/Inuvik'), (b'America/Mazatlan', b'(GMT-0700) America/Mazatlan'), (b'America/Ojinaga', b'(GMT-0700) America/Ojinaga'), (b'America/Phoenix', b'(GMT-0700) America/Phoenix'), (b'America/Shiprock', b'(GMT-0700) America/Shiprock'), (b'America/Yellowknife', b'(GMT-0700) America/Yellowknife'), (b'Canada/Mountain', b'(GMT-0700) Canada/Mountain'), (b'US/Arizona', b'(GMT-0700) US/Arizona'), (b'US/Mountain', b'(GMT-0700) US/Mountain'), (b'America/Bahia_Banderas', b'(GMT-0600) America/Bahia_Banderas'), (b'America/Belize', b'(GMT-0600) America/Belize'), (b'America/Cancun', b'(GMT-0600) America/Cancun'), (b'America/Chicago', b'(GMT-0600) America/Chicago'), (b'America/Costa_Rica', b'(GMT-0600) America/Costa_Rica'), (b'America/El_Salvador', b'(GMT-0600) America/El_Salvador'), (b'America/Guatemala', b'(GMT-0600) America/Guatemala'), (b'America/Indiana/Knox', b'(GMT-0600) America/Indiana/Knox'), (b'America/Indiana/Tell_City', b'(GMT-0600) America/Indiana/Tell_City'), (b'America/Managua', b'(GMT-0600) America/Managua'), (b'America/Matamoros', b'(GMT-0600) America/Matamoros'), (b'America/Menominee', b'(GMT-0600) America/Menominee'), (b'America/Merida', b'(GMT-0600) America/Merida'), (b'America/Mexico_City', b'(GMT-0600) America/Mexico_City'), (b'America/Monterrey', b'(GMT-0600) America/Monterrey'), (b'America/North_Dakota/Beulah', b'(GMT-0600) America/North_Dakota/Beulah'), (b'America/North_Dakota/Center', b'(GMT-0600) America/North_Dakota/Center'), (b'America/North_Dakota/New_Salem', b'(GMT-0600) America/North_Dakota/New_Salem'), (b'America/Rainy_River', b'(GMT-0600) America/Rainy_River'), (b'America/Rankin_Inlet', b'(GMT-0600) America/Rankin_Inlet'), (b'America/Regina', b'(GMT-0600) America/Regina'), (b'America/Resolute', b'(GMT-0600) America/Resolute'), (b'America/Swift_Current', b'(GMT-0600) America/Swift_Current'), (b'America/Tegucigalpa', b'(GMT-0600) America/Tegucigalpa'), (b'America/Winnipeg', b'(GMT-0600) America/Winnipeg'), (b'Canada/Central', b'(GMT-0600) Canada/Central'), (b'Pacific/Galapagos', b'(GMT-0600) Pacific/Galapagos'), (b'US/Central', b'(GMT-0600) US/Central'), (b'America/Atikokan', b'(GMT-0500) America/Atikokan'), (b'America/Bogota', b'(GMT-0500) America/Bogota'), (b'America/Cayman', b'(GMT-0500) America/Cayman'), (b'America/Detroit', b'(GMT-0500) America/Detroit'), (b'America/Eirunepe', b'(GMT-0500) America/Eirunepe'), (b'America/Grand_Turk', b'(GMT-0500) America/Grand_Turk'), (b'America/Guayaquil', b'(GMT-0500) America/Guayaquil'), (b'America/Havana', b'(GMT-0500) America/Havana'), (b'America/Indiana/Indianapolis', b'(GMT-0500) America/Indiana/Indianapolis'), (b'America/Indiana/Marengo', b'(GMT-0500) America/Indiana/Marengo'), (b'America/Indiana/Petersburg', b'(GMT-0500) America/Indiana/Petersburg'), (b'America/Indiana/Vevay', b'(GMT-0500) America/Indiana/Vevay'), (b'America/Indiana/Vincennes', b'(GMT-0500) America/Indiana/Vincennes'), (b'America/Indiana/Winamac', b'(GMT-0500) America/Indiana/Winamac'), (b'America/Iqaluit', b'(GMT-0500) America/Iqaluit'), (b'America/Jamaica', b'(GMT-0500) America/Jamaica'), (b'America/Kentucky/Louisville', b'(GMT-0500) America/Kentucky/Louisville'), (b'America/Kentucky/Monticello', b'(GMT-0500) America/Kentucky/Monticello'), (b'America/Lima', b'(GMT-0500) America/Lima'), (b'America/Montreal', b'(GMT-0500) America/Montreal'), (b'America/Nassau', b'(GMT-0500) America/Nassau'), (b'America/New_York', b'(GMT-0500) America/New_York'), (b'America/Nipigon', b'(GMT-0500) America/Nipigon'), (b'America/Panama', b'(GMT-0500) America/Panama'), (b'America/Pangnirtung', b'(GMT-0500) America/Pangnirtung'), (b'America/Port-au-Prince', b'(GMT-0500) America/Port-au-Prince'), (b'America/Rio_Branco', b'(GMT-0500) America/Rio_Branco'), (b'America/Thunder_Bay', b'(GMT-0500) America/Thunder_Bay'), (b'America/Toronto', b'(GMT-0500) America/Toronto'), (b'Canada/Eastern', b'(GMT-0500) Canada/Eastern'), (b'Pacific/Easter', b'(GMT-0500) Pacific/Easter'), (b'US/Eastern', b'(GMT-0500) US/Eastern'), (b'America/Caracas', b'(GMT-0430) America/Caracas'), (b'America/Anguilla', b'(GMT-0400) America/Anguilla'), (b'America/Antigua', b'(GMT-0400) America/Antigua'), (b'America/Aruba', b'(GMT-0400) America/Aruba'), (b'America/Barbados', b'(GMT-0400) America/Barbados'), (b'America/Blanc-Sablon', b'(GMT-0400) America/Blanc-Sablon'), (b'America/Boa_Vista', b'(GMT-0400) America/Boa_Vista'), (b'America/Curacao', b'(GMT-0400) America/Curacao'), (b'America/Dominica', b'(GMT-0400) America/Dominica'), (b'America/Glace_Bay', b'(GMT-0400) America/Glace_Bay'), (b'America/Goose_Bay', b'(GMT-0400) America/Goose_Bay'), (b'America/Grenada', b'(GMT-0400) America/Grenada'), (b'America/Guadeloupe', b'(GMT-0400) America/Guadeloupe'), (b'America/Guyana', b'(GMT-0400) America/Guyana'), (b'America/Halifax', b'(GMT-0400) America/Halifax'), (b'America/Kralendijk', b'(GMT-0400) America/Kralendijk'), (b'America/La_Paz', b'(GMT-0400) America/La_Paz'), (b'America/Lower_Princes', b'(GMT-0400) America/Lower_Princes'), (b'America/Manaus', b'(GMT-0400) America/Manaus'), (b'America/Marigot', b'(GMT-0400) America/Marigot'), (b'America/Martinique', b'(GMT-0400) America/Martinique'), (b'America/Moncton', b'(GMT-0400) America/Moncton'), (b'America/Montserrat', b'(GMT-0400) America/Montserrat'), (b'America/Port_of_Spain', b'(GMT-0400) America/Port_of_Spain'), (b'America/Porto_Velho', b'(GMT-0400) America/Porto_Velho'), (b'America/Puerto_Rico', b'(GMT-0400) America/Puerto_Rico'), (b'America/Santo_Domingo', b'(GMT-0400) America/Santo_Domingo'), (b'America/St_Barthelemy', b'(GMT-0400) America/St_Barthelemy'), (b'America/St_Kitts', b'(GMT-0400) America/St_Kitts'), (b'America/St_Lucia', b'(GMT-0400) America/St_Lucia'), (b'America/St_Thomas', b'(GMT-0400) America/St_Thomas'), (b'America/St_Vincent', b'(GMT-0400) America/St_Vincent'), (b'America/Thule', b'(GMT-0400) America/Thule'), (b'America/Tortola', b'(GMT-0400) America/Tortola'), (b'Atlantic/Bermuda', b'(GMT-0400) Atlantic/Bermuda'), (b'Canada/Atlantic', b'(GMT-0400) Canada/Atlantic'), (b'America/St_Johns', b'(GMT-0330) America/St_Johns'), (b'Canada/Newfoundland', b'(GMT-0330) Canada/Newfoundland'), (b'America/Araguaina', b'(GMT-0300) America/Araguaina'), (b'America/Argentina/Buenos_Aires', b'(GMT-0300) America/Argentina/Buenos_Aires'), (b'America/Argentina/Catamarca', b'(GMT-0300) America/Argentina/Catamarca'), (b'America/Argentina/Cordoba', b'(GMT-0300) America/Argentina/Cordoba'), (b'America/Argentina/Jujuy', b'(GMT-0300) America/Argentina/Jujuy'), (b'America/Argentina/La_Rioja', b'(GMT-0300) America/Argentina/La_Rioja'), (b'America/Argentina/Mendoza', b'(GMT-0300) America/Argentina/Mendoza'), (b'America/Argentina/Rio_Gallegos', b'(GMT-0300) America/Argentina/Rio_Gallegos'), (b'America/Argentina/Salta', b'(GMT-0300) America/Argentina/Salta'), (b'America/Argentina/San_Juan', b'(GMT-0300) America/Argentina/San_Juan'), (b'America/Argentina/San_Luis', b'(GMT-0300) America/Argentina/San_Luis'), (b'America/Argentina/Tucuman', b'(GMT-0300) America/Argentina/Tucuman'), (b'America/Argentina/Ushuaia', b'(GMT-0300) America/Argentina/Ushuaia'), (b'America/Asuncion', b'(GMT-0300) America/Asuncion'), (b'America/Bahia', b'(GMT-0300) America/Bahia'), (b'America/Belem', b'(GMT-0300) America/Belem'), (b'America/Campo_Grande', b'(GMT-0300) America/Campo_Grande'), (b'America/Cayenne', b'(GMT-0300) America/Cayenne'), (b'America/Cuiaba', b'(GMT-0300) America/Cuiaba'), (b'America/Fortaleza', b'(GMT-0300) America/Fortaleza'), (b'America/Godthab', b'(GMT-0300) America/Godthab'), (b'America/Maceio', b'(GMT-0300) America/Maceio'), (b'America/Miquelon', b'(GMT-0300) America/Miquelon'), (b'America/Paramaribo', b'(GMT-0300) America/Paramaribo'), (b'America/Recife', b'(GMT-0300) America/Recife'), (b'America/Santarem', b'(GMT-0300) America/Santarem'), (b'America/Santiago', b'(GMT-0300) America/Santiago'), (b'Antarctica/Palmer', b'(GMT-0300) Antarctica/Palmer'), (b'Antarctica/Rothera', b'(GMT-0300) Antarctica/Rothera'), (b'Atlantic/Stanley', b'(GMT-0300) Atlantic/Stanley'), (b'America/Montevideo', b'(GMT-0200) America/Montevideo'), (b'America/Noronha', b'(GMT-0200) America/Noronha'), (b'America/Sao_Paulo', b'(GMT-0200) America/Sao_Paulo'), (b'Atlantic/South_Georgia', b'(GMT-0200) Atlantic/South_Georgia'), (b'America/Scoresbysund', b'(GMT-0100) America/Scoresbysund'), (b'Atlantic/Azores', b'(GMT-0100) Atlantic/Azores'), (b'Atlantic/Cape_Verde', b'(GMT-0100) Atlantic/Cape_Verde'), (b'Africa/Abidjan', b'(GMT+0000) Africa/Abidjan'), (b'Africa/Accra', b'(GMT+0000) Africa/Accra'), (b'Africa/Bamako', b'(GMT+0000) Africa/Bamako'), (b'Africa/Banjul', b'(GMT+0000) Africa/Banjul'), (b'Africa/Bissau', b'(GMT+0000) Africa/Bissau'), (b'Africa/Casablanca', b'(GMT+0000) Africa/Casablanca'), (b'Africa/Conakry', b'(GMT+0000) Africa/Conakry'), (b'Africa/Dakar', b'(GMT+0000) Africa/Dakar'), (b'Africa/El_Aaiun', b'(GMT+0000) Africa/El_Aaiun'), (b'Africa/Freetown', b'(GMT+0000) Africa/Freetown'), (b'Africa/Lome', b'(GMT+0000) Africa/Lome'), (b'Africa/Monrovia', b'(GMT+0000) Africa/Monrovia'), (b'Africa/Nouakchott', b'(GMT+0000) Africa/Nouakchott'), (b'Africa/Ouagadougou', b'(GMT+0000) Africa/Ouagadougou'), (b'Africa/Sao_Tome', b'(GMT+0000) Africa/Sao_Tome'), (b'America/Danmarkshavn', b'(GMT+0000) America/Danmarkshavn'), (b'Atlantic/Canary', b'(GMT+0000) Atlantic/Canary'), (b'Atlantic/Faroe', b'(GMT+0000) Atlantic/Faroe'), (b'Atlantic/Madeira', b'(GMT+0000) Atlantic/Madeira'), (b'Atlantic/Reykjavik', b'(GMT+0000) Atlantic/Reykjavik'), (b'Atlantic/St_Helena', b'(GMT+0000) Atlantic/St_Helena'), (b'Europe/Dublin', b'(GMT+0000) Europe/Dublin'), (b'Europe/Guernsey', b'(GMT+0000) Europe/Guernsey'), (
+                    b'Europe/Isle_of_Man', b'(GMT+0000) Europe/Isle_of_Man'), (b'Europe/Jersey', b'(GMT+0000) Europe/Jersey'), (b'Europe/Lisbon', b'(GMT+0000) Europe/Lisbon'), (b'Europe/London', b'(GMT+0000) Europe/London'), (b'GMT', b'(GMT+0000) GMT'), (b'UTC', b'(GMT+0000) UTC'), (b'Africa/Algiers', b'(GMT+0100) Africa/Algiers'), (b'Africa/Bangui', b'(GMT+0100) Africa/Bangui'), (b'Africa/Brazzaville', b'(GMT+0100) Africa/Brazzaville'), (b'Africa/Ceuta', b'(GMT+0100) Africa/Ceuta'), (b'Africa/Douala', b'(GMT+0100) Africa/Douala'), (b'Africa/Kinshasa', b'(GMT+0100) Africa/Kinshasa'), (b'Africa/Lagos', b'(GMT+0100) Africa/Lagos'), (b'Africa/Libreville', b'(GMT+0100) Africa/Libreville'), (b'Africa/Luanda', b'(GMT+0100) Africa/Luanda'), (b'Africa/Malabo', b'(GMT+0100) Africa/Malabo'), (b'Africa/Ndjamena', b'(GMT+0100) Africa/Ndjamena'), (b'Africa/Niamey', b'(GMT+0100) Africa/Niamey'), (b'Africa/Porto-Novo', b'(GMT+0100) Africa/Porto-Novo'), (b'Africa/Tunis', b'(GMT+0100) Africa/Tunis'), (b'Arctic/Longyearbyen', b'(GMT+0100) Arctic/Longyearbyen'), (b'Europe/Amsterdam', b'(GMT+0100) Europe/Amsterdam'), (b'Europe/Andorra', b'(GMT+0100) Europe/Andorra'), (b'Europe/Belgrade', b'(GMT+0100) Europe/Belgrade'), (b'Europe/Berlin', b'(GMT+0100) Europe/Berlin'), (b'Europe/Bratislava', b'(GMT+0100) Europe/Bratislava'), (b'Europe/Brussels', b'(GMT+0100) Europe/Brussels'), (b'Europe/Budapest', b'(GMT+0100) Europe/Budapest'), (b'Europe/Copenhagen', b'(GMT+0100) Europe/Copenhagen'), (b'Europe/Gibraltar', b'(GMT+0100) Europe/Gibraltar'), (b'Europe/Ljubljana', b'(GMT+0100) Europe/Ljubljana'), (b'Europe/Luxembourg', b'(GMT+0100) Europe/Luxembourg'), (b'Europe/Madrid', b'(GMT+0100) Europe/Madrid'), (b'Europe/Malta', b'(GMT+0100) Europe/Malta'), (b'Europe/Monaco', b'(GMT+0100) Europe/Monaco'), (b'Europe/Oslo', b'(GMT+0100) Europe/Oslo'), (b'Europe/Paris', b'(GMT+0100) Europe/Paris'), (b'Europe/Podgorica', b'(GMT+0100) Europe/Podgorica'), (b'Europe/Prague', b'(GMT+0100) Europe/Prague'), (b'Europe/Rome', b'(GMT+0100) Europe/Rome'), (b'Europe/San_Marino', b'(GMT+0100) Europe/San_Marino'), (b'Europe/Sarajevo', b'(GMT+0100) Europe/Sarajevo'), (b'Europe/Skopje', b'(GMT+0100) Europe/Skopje'), (b'Europe/Stockholm', b'(GMT+0100) Europe/Stockholm'), (b'Europe/Tirane', b'(GMT+0100) Europe/Tirane'), (b'Europe/Vaduz', b'(GMT+0100) Europe/Vaduz'), (b'Europe/Vatican', b'(GMT+0100) Europe/Vatican'), (b'Europe/Vienna', b'(GMT+0100) Europe/Vienna'), (b'Europe/Warsaw', b'(GMT+0100) Europe/Warsaw'), (b'Europe/Zagreb', b'(GMT+0100) Europe/Zagreb'), (b'Europe/Zurich', b'(GMT+0100) Europe/Zurich'), (b'Africa/Blantyre', b'(GMT+0200) Africa/Blantyre'), (b'Africa/Bujumbura', b'(GMT+0200) Africa/Bujumbura'), (b'Africa/Cairo', b'(GMT+0200) Africa/Cairo'), (b'Africa/Gaborone', b'(GMT+0200) Africa/Gaborone'), (b'Africa/Harare', b'(GMT+0200) Africa/Harare'), (b'Africa/Johannesburg', b'(GMT+0200) Africa/Johannesburg'), (b'Africa/Kigali', b'(GMT+0200) Africa/Kigali'), (b'Africa/Lubumbashi', b'(GMT+0200) Africa/Lubumbashi'), (b'Africa/Lusaka', b'(GMT+0200) Africa/Lusaka'), (b'Africa/Maputo', b'(GMT+0200) Africa/Maputo'), (b'Africa/Maseru', b'(GMT+0200) Africa/Maseru'), (b'Africa/Mbabane', b'(GMT+0200) Africa/Mbabane'), (b'Africa/Tripoli', b'(GMT+0200) Africa/Tripoli'), (b'Africa/Windhoek', b'(GMT+0200) Africa/Windhoek'), (b'Asia/Amman', b'(GMT+0200) Asia/Amman'), (b'Asia/Beirut', b'(GMT+0200) Asia/Beirut'), (b'Asia/Damascus', b'(GMT+0200) Asia/Damascus'), (b'Asia/Gaza', b'(GMT+0200) Asia/Gaza'), (b'Asia/Hebron', b'(GMT+0200) Asia/Hebron'), (b'Asia/Jerusalem', b'(GMT+0200) Asia/Jerusalem'), (b'Asia/Nicosia', b'(GMT+0200) Asia/Nicosia'), (b'Europe/Athens', b'(GMT+0200) Europe/Athens'), (b'Europe/Bucharest', b'(GMT+0200) Europe/Bucharest'), (b'Europe/Chisinau', b'(GMT+0200) Europe/Chisinau'), (b'Europe/Helsinki', b'(GMT+0200) Europe/Helsinki'), (b'Europe/Istanbul', b'(GMT+0200) Europe/Istanbul'), (b'Europe/Kiev', b'(GMT+0200) Europe/Kiev'), (b'Europe/Mariehamn', b'(GMT+0200) Europe/Mariehamn'), (b'Europe/Riga', b'(GMT+0200) Europe/Riga'), (b'Europe/Sofia', b'(GMT+0200) Europe/Sofia'), (b'Europe/Tallinn', b'(GMT+0200) Europe/Tallinn'), (b'Europe/Uzhgorod', b'(GMT+0200) Europe/Uzhgorod'), (b'Europe/Vilnius', b'(GMT+0200) Europe/Vilnius'), (b'Europe/Zaporozhye', b'(GMT+0200) Europe/Zaporozhye'), (b'Africa/Addis_Ababa', b'(GMT+0300) Africa/Addis_Ababa'), (b'Africa/Asmara', b'(GMT+0300) Africa/Asmara'), (b'Africa/Dar_es_Salaam', b'(GMT+0300) Africa/Dar_es_Salaam'), (b'Africa/Djibouti', b'(GMT+0300) Africa/Djibouti'), (b'Africa/Juba', b'(GMT+0300) Africa/Juba'), (b'Africa/Kampala', b'(GMT+0300) Africa/Kampala'), (b'Africa/Khartoum', b'(GMT+0300) Africa/Khartoum'), (b'Africa/Mogadishu', b'(GMT+0300) Africa/Mogadishu'), (b'Africa/Nairobi', b'(GMT+0300) Africa/Nairobi'), (b'Antarctica/Syowa', b'(GMT+0300) Antarctica/Syowa'), (b'Asia/Aden', b'(GMT+0300) Asia/Aden'), (b'Asia/Baghdad', b'(GMT+0300) Asia/Baghdad'), (b'Asia/Bahrain', b'(GMT+0300) Asia/Bahrain'), (b'Asia/Kuwait', b'(GMT+0300) Asia/Kuwait'), (b'Asia/Qatar', b'(GMT+0300) Asia/Qatar'), (b'Asia/Riyadh', b'(GMT+0300) Asia/Riyadh'), (b'Europe/Kaliningrad', b'(GMT+0300) Europe/Kaliningrad'), (b'Europe/Minsk', b'(GMT+0300) Europe/Minsk'), (b'Indian/Antananarivo', b'(GMT+0300) Indian/Antananarivo'), (b'Indian/Comoro', b'(GMT+0300) Indian/Comoro'), (b'Indian/Mayotte', b'(GMT+0300) Indian/Mayotte'), (b'Asia/Tehran', b'(GMT+0330) Asia/Tehran'), (b'Asia/Baku', b'(GMT+0400) Asia/Baku'), (b'Asia/Dubai', b'(GMT+0400) Asia/Dubai'), (b'Asia/Muscat', b'(GMT+0400) Asia/Muscat'), (b'Asia/Tbilisi', b'(GMT+0400) Asia/Tbilisi'), (b'Asia/Yerevan', b'(GMT+0400) Asia/Yerevan'), (b'Europe/Moscow', b'(GMT+0400) Europe/Moscow'), (b'Europe/Samara', b'(GMT+0400) Europe/Samara'), (b'Europe/Simferopol', b'(GMT+0400) Europe/Simferopol'), (b'Europe/Volgograd', b'(GMT+0400) Europe/Volgograd'), (b'Indian/Mahe', b'(GMT+0400) Indian/Mahe'), (b'Indian/Mauritius', b'(GMT+0400) Indian/Mauritius'), (b'Indian/Reunion', b'(GMT+0400) Indian/Reunion'), (b'Asia/Kabul', b'(GMT+0430) Asia/Kabul'), (b'Antarctica/Mawson', b'(GMT+0500) Antarctica/Mawson'), (b'Asia/Aqtau', b'(GMT+0500) Asia/Aqtau'), (b'Asia/Aqtobe', b'(GMT+0500) Asia/Aqtobe'), (b'Asia/Ashgabat', b'(GMT+0500) Asia/Ashgabat'), (b'Asia/Dushanbe', b'(GMT+0500) Asia/Dushanbe'), (b'Asia/Karachi', b'(GMT+0500) Asia/Karachi'), (b'Asia/Oral', b'(GMT+0500) Asia/Oral'), (b'Asia/Samarkand', b'(GMT+0500) Asia/Samarkand'), (b'Asia/Tashkent', b'(GMT+0500) Asia/Tashkent'), (b'Indian/Kerguelen', b'(GMT+0500) Indian/Kerguelen'), (b'Indian/Maldives', b'(GMT+0500) Indian/Maldives'), (b'Asia/Colombo', b'(GMT+0530) Asia/Colombo'), (b'Asia/Kolkata', b'(GMT+0530) Asia/Kolkata'), (b'Asia/Kathmandu', b'(GMT+0545) Asia/Kathmandu'), (b'Antarctica/Vostok', b'(GMT+0600) Antarctica/Vostok'), (b'Asia/Almaty', b'(GMT+0600) Asia/Almaty'), (b'Asia/Bishkek', b'(GMT+0600) Asia/Bishkek'), (b'Asia/Dhaka', b'(GMT+0600) Asia/Dhaka'), (b'Asia/Qyzylorda', b'(GMT+0600) Asia/Qyzylorda'), (b'Asia/Thimphu', b'(GMT+0600) Asia/Thimphu'), (b'Asia/Yekaterinburg', b'(GMT+0600) Asia/Yekaterinburg'), (b'Indian/Chagos', b'(GMT+0600) Indian/Chagos'), (b'Asia/Rangoon', b'(GMT+0630) Asia/Rangoon'), (b'Indian/Cocos', b'(GMT+0630) Indian/Cocos'), (b'Antarctica/Davis', b'(GMT+0700) Antarctica/Davis'), (b'Asia/Bangkok', b'(GMT+0700) Asia/Bangkok'), (b'Asia/Ho_Chi_Minh', b'(GMT+0700) Asia/Ho_Chi_Minh'), (b'Asia/Hovd', b'(GMT+0700) Asia/Hovd'), (b'Asia/Jakarta', b'(GMT+0700) Asia/Jakarta'), (b'Asia/Novokuznetsk', b'(GMT+0700) Asia/Novokuznetsk'), (b'Asia/Novosibirsk', b'(GMT+0700) Asia/Novosibirsk'), (b'Asia/Omsk', b'(GMT+0700) Asia/Omsk'), (b'Asia/Phnom_Penh', b'(GMT+0700) Asia/Phnom_Penh'), (b'Asia/Pontianak', b'(GMT+0700) Asia/Pontianak'), (b'Asia/Vientiane', b'(GMT+0700) Asia/Vientiane'), (b'Indian/Christmas', b'(GMT+0700) Indian/Christmas'), (b'Antarctica/Casey', b'(GMT+0800) Antarctica/Casey'), (b'Asia/Brunei', b'(GMT+0800) Asia/Brunei'), (b'Asia/Choibalsan', b'(GMT+0800) Asia/Choibalsan'), (b'Asia/Chongqing', b'(GMT+0800) Asia/Chongqing'), (b'Asia/Harbin', b'(GMT+0800) Asia/Harbin'), (b'Asia/Hong_Kong', b'(GMT+0800) Asia/Hong_Kong'), (b'Asia/Kashgar', b'(GMT+0800) Asia/Kashgar'), (b'Asia/Krasnoyarsk', b'(GMT+0800) Asia/Krasnoyarsk'), (b'Asia/Kuala_Lumpur', b'(GMT+0800) Asia/Kuala_Lumpur'), (b'Asia/Kuching', b'(GMT+0800) Asia/Kuching'), (b'Asia/Macau', b'(GMT+0800) Asia/Macau'), (b'Asia/Makassar', b'(GMT+0800) Asia/Makassar'), (b'Asia/Manila', b'(GMT+0800) Asia/Manila'), (b'Asia/Shanghai', b'(GMT+0800) Asia/Shanghai'), (b'Asia/Singapore', b'(GMT+0800) Asia/Singapore'), (b'Asia/Taipei', b'(GMT+0800) Asia/Taipei'), (b'Asia/Ulaanbaatar', b'(GMT+0800) Asia/Ulaanbaatar'), (b'Asia/Urumqi', b'(GMT+0800) Asia/Urumqi'), (b'Australia/Perth', b'(GMT+0800) Australia/Perth'), (b'Australia/Eucla', b'(GMT+0845) Australia/Eucla'), (b'Asia/Dili', b'(GMT+0900) Asia/Dili'), (b'Asia/Irkutsk', b'(GMT+0900) Asia/Irkutsk'), (b'Asia/Jayapura', b'(GMT+0900) Asia/Jayapura'), (b'Asia/Pyongyang', b'(GMT+0900) Asia/Pyongyang'), (b'Asia/Seoul', b'(GMT+0900) Asia/Seoul'), (b'Asia/Tokyo', b'(GMT+0900) Asia/Tokyo'), (b'Pacific/Palau', b'(GMT+0900) Pacific/Palau'), (b'Australia/Darwin', b'(GMT+0930) Australia/Darwin'), (b'Antarctica/DumontDUrville', b'(GMT+1000) Antarctica/DumontDUrville'), (b'Asia/Yakutsk', b'(GMT+1000) Asia/Yakutsk'), (b'Australia/Brisbane', b'(GMT+1000) Australia/Brisbane'), (b'Australia/Lindeman', b'(GMT+1000) Australia/Lindeman'), (b'Pacific/Chuuk', b'(GMT+1000) Pacific/Chuuk'), (b'Pacific/Guam', b'(GMT+1000) Pacific/Guam'), (b'Pacific/Port_Moresby', b'(GMT+1000) Pacific/Port_Moresby'), (b'Pacific/Saipan', b'(GMT+1000) Pacific/Saipan'), (b'Australia/Adelaide', b'(GMT+1030) Australia/Adelaide'), (b'Australia/Broken_Hill', b'(GMT+1030) Australia/Broken_Hill'), (b'Antarctica/Macquarie', b'(GMT+1100) Antarctica/Macquarie'), (b'Asia/Sakhalin', b'(GMT+1100) Asia/Sakhalin'), (b'Asia/Vladivostok', b'(GMT+1100) Asia/Vladivostok'), (b'Australia/Currie', b'(GMT+1100) Australia/Currie'), (b'Australia/Hobart', b'(GMT+1100) Australia/Hobart'), (b'Australia/Lord_Howe', b'(GMT+1100) Australia/Lord_Howe'), (b'Australia/Melbourne', b'(GMT+1100) Australia/Melbourne'), (b'Australia/Sydney', b'(GMT+1100) Australia/Sydney'), (b'Pacific/Efate', b'(GMT+1100) Pacific/Efate'), (b'Pacific/Guadalcanal', b'(GMT+1100) Pacific/Guadalcanal'), (b'Pacific/Kosrae', b'(GMT+1100) Pacific/Kosrae'), (b'Pacific/Noumea', b'(GMT+1100) Pacific/Noumea'), (b'Pacific/Pohnpei', b'(GMT+1100) Pacific/Pohnpei'), (b'Pacific/Norfolk', b'(GMT+1130) Pacific/Norfolk'), (b'Asia/Anadyr', b'(GMT+1200) Asia/Anadyr'), (b'Asia/Kamchatka', b'(GMT+1200) Asia/Kamchatka'), (b'Asia/Magadan', b'(GMT+1200) Asia/Magadan'), (b'Pacific/Fiji', b'(GMT+1200) Pacific/Fiji'), (b'Pacific/Funafuti', b'(GMT+1200) Pacific/Funafuti'), (b'Pacific/Kwajalein', b'(GMT+1200) Pacific/Kwajalein'), (b'Pacific/Majuro', b'(GMT+1200) Pacific/Majuro'), (b'Pacific/Nauru', b'(GMT+1200) Pacific/Nauru'), (b'Pacific/Tarawa', b'(GMT+1200) Pacific/Tarawa'), (b'Pacific/Wake', b'(GMT+1200) Pacific/Wake'), (b'Pacific/Wallis', b'(GMT+1200) Pacific/Wallis'), (b'Antarctica/McMurdo', b'(GMT+1300) Antarctica/McMurdo'), (b'Antarctica/South_Pole', b'(GMT+1300) Antarctica/South_Pole'), (b'Pacific/Auckland', b'(GMT+1300) Pacific/Auckland'), (b'Pacific/Enderbury', b'(GMT+1300) Pacific/Enderbury'), (b'Pacific/Fakaofo', b'(GMT+1300) Pacific/Fakaofo'), (b'Pacific/Tongatapu', b'(GMT+1300) Pacific/Tongatapu'), (b'Pacific/Chatham', b'(GMT+1345) Pacific/Chatham'), (b'Pacific/Apia', b'(GMT+1400) Pacific/Apia'), (b'Pacific/Kiritimati', b'(GMT+1400) Pacific/Kiritimati')])),
+            ],
+            options={
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Account',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Charge',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('kind', models.CharField(default=b'besteffort', max_length=30, choices=[
+                 (b'besteffort', b'besteffort'), (b'reservation', b'reservation'), (b'monthlyfee', b'monthlyfee')])),
+                ('state', models.CharField(default=b'pending', max_length=30, choices=[
+                 (b'pending', b'pending'), (b'invoiced', b'invoiced')])),
+                ('date', models.DateTimeField()),
+                ('amount', models.FloatField(default=0.0)),
+                ('coreHours', models.FloatField(default=0.0)),
+                ('account', models.ForeignKey(
+                    related_name=b'charges', to='core.Account')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Controller',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.CharField(
+                    help_text=b'Name of the Controller', unique=True, max_length=200)),
+                ('backend_type', models.CharField(
+                    help_text=b'Type of compute controller, e.g. EC2, OpenStack, or OpenStack version', max_length=200)),
+                ('version', models.CharField(
+                    help_text=b'Controller version', max_length=200)),
+                ('auth_url', models.CharField(
+                    help_text=b'Auth url for the compute controller', max_length=200, null=True, blank=True)),
+                ('admin_user', models.CharField(
+                    help_text=b'Username of an admin user at this controller', max_length=200, null=True, blank=True)),
+                ('admin_password', models.CharField(
+                    help_text=b'Password of theadmin user at this controller', max_length=200, null=True, blank=True)),
+                ('admin_tenant', models.CharField(
+                    help_text=b'Name of the tenant the admin user belongs to', max_length=200, null=True, blank=True)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='ControllerCredential',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.SlugField(
+                    help_text=b'The credential type, e.g. ec2', max_length=128)),
+                ('key_id', models.CharField(
+                    help_text=b'The backend id of this credential', max_length=1024)),
+                ('enc_value', encrypted_fields.fields.EncryptedCharField(
+                    help_text=b'The key value of this credential', max_length=1024)),
+                ('controller', models.ForeignKey(related_name=b'controllercredentials',
+                                                 to='core.Controller', help_text=b'The User this credential is associated with')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='ControllerDashboardView',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('enabled', models.BooleanField(default=True)),
+                ('url', models.CharField(help_text=b'URL of Dashboard', max_length=1024)),
+                ('controller', models.ForeignKey(
+                    related_name=b'controllerdashboardviews', to='core.Controller')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='ControllerImages',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('glance_image_id', models.CharField(
+                    help_text=b'Glance image id', max_length=200, null=True, blank=True)),
+                ('controller', models.ForeignKey(
+                    related_name=b'controllerimages', to='core.Controller')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='ControllerNetwork',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('net_id', models.CharField(help_text=b'Quantum network',
+                                            max_length=256, null=True, blank=True)),
+                ('router_id', models.CharField(help_text=b'Quantum router id',
+                                               max_length=256, null=True, blank=True)),
+                ('subnet_id', models.CharField(help_text=b'Quantum subnet id',
+                                               max_length=256, null=True, blank=True)),
+                ('subnet', models.CharField(max_length=32, blank=True)),
+                ('controller', models.ForeignKey(
+                    related_name=b'controllernetworks', to='core.Controller')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='ControllerRole',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('role', models.CharField(unique=True,
+                                          max_length=30, choices=[(b'admin', b'Admin')])),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='ControllerSite',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('tenant_id', models.CharField(help_text=b'Keystone tenant id',
+                                               max_length=200, null=True, db_index=True, blank=True)),
+                ('controller', models.ForeignKey(related_name=b'controllersite',
+                                                 blank=True, to='core.Controller', null=True)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='ControllerSitePrivilege',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('role_id', models.CharField(help_text=b'Keystone id',
+                                             max_length=200, null=True, db_index=True, blank=True)),
+                ('controller', models.ForeignKey(
+                    related_name=b'controllersiteprivileges', to='core.Controller')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='ControllerSlice',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('tenant_id', models.CharField(
+                    help_text=b'Keystone tenant id', max_length=200, null=True, blank=True)),
+                ('controller', models.ForeignKey(
+                    related_name=b'controllerslices', to='core.Controller')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='ControllerSlicePrivilege',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('role_id', models.CharField(help_text=b'Keystone id',
+                                             max_length=200, null=True, db_index=True, blank=True)),
+                ('controller', models.ForeignKey(
+                    related_name=b'controllersliceprivileges', to='core.Controller')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='ControllerUser',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('kuser_id', models.CharField(help_text=b'Keystone user id',
+                                              max_length=200, null=True, blank=True)),
+                ('controller', models.ForeignKey(
+                    related_name=b'controllersusers', to='core.Controller')),
+                ('user', models.ForeignKey(
+                    related_name=b'controllerusers', to=settings.AUTH_USER_MODEL)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='DashboardView',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.CharField(
+                    help_text=b'Name of the View', unique=True, max_length=200)),
+                ('url', models.CharField(help_text=b'URL of Dashboard', max_length=1024)),
+                ('enabled', models.BooleanField(default=True)),
+                ('controllers', models.ManyToManyField(related_name=b'dashboardviews',
+                                                       through='core.ControllerDashboardView', to='core.Controller', blank=True)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Deployment',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.CharField(
+                    help_text=b'Name of the Deployment', unique=True, max_length=200)),
+                ('accessControl', models.TextField(default=b'allow all',
+                                                   help_text=b'Access control list that specifies which sites/users may use nodes in this deployment', max_length=200)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='DeploymentPrivilege',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('deployment', models.ForeignKey(
+                    related_name=b'deploymentprivileges', to='core.Deployment')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='DeploymentRole',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('role', models.CharField(unique=True,
+                                          max_length=30, choices=[(b'admin', b'Admin')])),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Flavor',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.CharField(
+                    help_text=b'name of this flavor, as displayed to users', max_length=32)),
+                ('description', models.CharField(
+                    max_length=1024, null=True, blank=True)),
+                ('flavor', models.CharField(
+                    help_text=b'flavor string used to configure deployments', max_length=32)),
+                ('order', models.IntegerField(default=0,
+                                              help_text=b'used to order flavors when displayed in a list')),
+                ('default', models.BooleanField(default=False,
+                                                help_text=b'make this a default flavor to use when creating new instances')),
+                ('deployments', models.ManyToManyField(
+                    related_name=b'flavors', to='core.Deployment', blank=True)),
+            ],
+            options={
+                'ordering': ('order', 'name'),
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Image',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.CharField(unique=True, max_length=256)),
+                ('disk_format', models.CharField(max_length=256)),
+                ('container_format', models.CharField(max_length=256)),
+                ('path', models.CharField(help_text=b'Path to image on local disk',
+                                          max_length=256, null=True, blank=True)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='ImageDeployments',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('deployment', models.ForeignKey(
+                    related_name=b'imagedeployments', to='core.Deployment')),
+                ('image', models.ForeignKey(
+                    related_name=b'imagedeployments', to='core.Image')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Invoice',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('date', models.DateTimeField()),
+                ('account', models.ForeignKey(
+                    related_name=b'invoices', to='core.Account')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Network',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.CharField(max_length=32)),
+                ('subnet', models.CharField(max_length=32, blank=True)),
+                ('ports', models.CharField(blank=True, max_length=1024,
+                                           null=True, validators=[core.models.network.ValidateNatList])),
+                ('labels', models.CharField(max_length=1024, null=True, blank=True)),
+                ('guaranteed_bandwidth', models.IntegerField(default=0)),
+                ('permit_all_slices', models.BooleanField(default=False)),
+                ('topology_parameters', models.TextField(null=True, blank=True)),
+                ('controller_url', models.CharField(
+                    max_length=1024, null=True, blank=True)),
+                ('controller_parameters', models.TextField(null=True, blank=True)),
+                ('network_id', models.CharField(help_text=b'Quantum network',
+                                                max_length=256, null=True, blank=True)),
+                ('router_id', models.CharField(help_text=b'Quantum router id',
+                                               max_length=256, null=True, blank=True)),
+                ('subnet_id', models.CharField(help_text=b'Quantum subnet id',
+                                               max_length=256, null=True, blank=True)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='NetworkParameter',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('value', models.CharField(
+                    help_text=b'The value of this parameter', max_length=1024)),
+                ('object_id', models.PositiveIntegerField()),
+                ('content_type', models.ForeignKey(to='contenttypes.ContentType')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='NetworkParameterType',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.SlugField(
+                    help_text=b'The name of this parameter', max_length=128)),
+                ('description', models.CharField(max_length=1024)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='NetworkSlice',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('network', models.ForeignKey(
+                    related_name=b'networkslices', to='core.Network')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='NetworkInstance',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('ip', models.GenericIPAddressField(
+                    help_text=b'Instance ip address', null=True, blank=True)),
+                ('port_id', models.CharField(help_text=b'Quantum port id',
+                                             max_length=256, null=True, blank=True)),
+                ('network', models.ForeignKey(
+                    related_name=b'networkinstances', to='core.Network')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='NetworkTemplate',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.CharField(max_length=32)),
+                ('description', models.CharField(
+                    max_length=1024, null=True, blank=True)),
+                ('guaranteed_bandwidth', models.IntegerField(default=0)),
+                ('visibility', models.CharField(default=b'private', max_length=30,
+                                                choices=[(b'public', b'public'), (b'private', b'private')])),
+                ('translation', models.CharField(default=b'none', max_length=30,
+                                                 choices=[(b'none', b'none'), (b'NAT', b'NAT')])),
+                ('shared_network_name', models.CharField(
+                    max_length=30, null=True, blank=True)),
+                ('shared_network_id', models.CharField(
+                    help_text=b'Quantum network', max_length=256, null=True, blank=True)),
+                ('topology_kind', models.CharField(default=b'BigSwitch', max_length=30, choices=[
+                 (b'bigswitch', b'BigSwitch'), (b'physical', b'Physical'), (b'custom', b'Custom')])),
+                ('controller_kind', models.CharField(default=None, max_length=30, null=True,
+                                                     blank=True, choices=[(None, b'None'), (b'onos', b'ONOS'), (b'custom', b'Custom')])),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Node',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.CharField(
+                    help_text=b'Name of the Node', unique=True, max_length=200)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Payment',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('amount', models.FloatField(default=0.0)),
+                ('date', models.DateTimeField(default=django.utils.timezone.now)),
+                ('account', models.ForeignKey(
+                    related_name=b'payments', to='core.Account')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='PlanetStack',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('description', models.CharField(default=b'PlanetStack',
+                                                 help_text=b'Used for scoping of roles at the PlanetStack Application level', unique=True, max_length=200)),
+            ],
+            options={
+                'verbose_name_plural': 'PlanetStack',
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='PlanetStackPrivilege',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('planetstack', models.ForeignKey(
+                    related_name=b'planetstackprivileges', default=1, to='core.PlanetStack')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='PlanetStackRole',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('role', models.CharField(unique=True,
+                                          max_length=30, choices=[(b'admin', b'Admin')])),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Project',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.CharField(
+                    help_text=b'Name of Project', unique=True, max_length=200)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Reservation',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('startTime', models.DateTimeField()),
+                ('duration', models.IntegerField(default=1)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='ReservedResource',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('quantity', models.IntegerField(default=1)),
+                ('reservationSet', models.ForeignKey(
+                    related_name=b'reservedresources', to='core.Reservation')),
+            ],
+            options={
+                'abstract': False,
+                'verbose_name_plural': 'Reserved Resources',
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Role',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('role_type', models.CharField(max_length=80, verbose_name=b'Name')),
+                ('role', models.CharField(max_length=80, null=True,
+                                          verbose_name=b'Keystone role id', blank=True)),
+                ('description', models.CharField(
+                    max_length=120, verbose_name=b'Description')),
+                ('content_type', models.ForeignKey(
+                    verbose_name=b'Role Scope', to='contenttypes.ContentType')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Router',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.CharField(max_length=32)),
+                ('networks', models.ManyToManyField(
+                    related_name=b'routers', to='core.Network', blank=True)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Service',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('description', models.TextField(
+                    help_text=b'Description of Service', max_length=254, null=True, blank=True)),
+                ('enabled', models.BooleanField(default=True)),
+                ('name', models.CharField(help_text=b'Service Name', max_length=30)),
+                ('versionNumber', models.CharField(
+                    help_text=b'Version of Service Definition', max_length=30)),
+                ('published', models.BooleanField(default=True)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='ServiceAttribute',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.SlugField(help_text=b'Attribute Name', max_length=128)),
+                ('value', models.CharField(
+                    help_text=b'Attribute Value', max_length=1024)),
+                ('service', models.ForeignKey(related_name=b'serviceattributes',
+                                              to='core.Service', help_text=b'The Service this attribute is associated with')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='ServiceClass',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.CharField(max_length=32)),
+                ('description', models.CharField(max_length=255)),
+                ('commitment', models.IntegerField(default=365)),
+                ('membershipFee', models.IntegerField(default=0)),
+                ('membershipFeeMonths', models.IntegerField(default=12)),
+                ('upgradeRequiresApproval', models.BooleanField(default=False)),
+                ('upgradeFrom', models.ManyToManyField(
+                    related_name='upgradeFrom_rel_+', null=True, to='core.ServiceClass', blank=True)),
+            ],
+            options={
+                'abstract': False,
+                'verbose_name_plural': 'Service classes',
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='ServiceResource',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.CharField(max_length=32)),
+                ('maxUnitsDeployment', models.IntegerField(default=1)),
+                ('maxUnitsNode', models.IntegerField(default=1)),
+                ('maxDuration', models.IntegerField(default=1)),
+                ('bucketInRate', models.IntegerField(default=0)),
+                ('bucketMaxSize', models.IntegerField(default=0)),
+                ('cost', models.IntegerField(default=0)),
+                ('calendarReservable', models.BooleanField(default=True)),
+                ('serviceClass', models.ForeignKey(
+                    related_name=b'serviceresources', to='core.ServiceClass')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Site',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.CharField(
+                    help_text=b'Name for this Site', max_length=200)),
+                ('site_url', models.URLField(help_text=b"Site's Home URL Page",
+                                             max_length=512, null=True, blank=True)),
+                ('enabled', models.BooleanField(
+                    default=True, help_text=b'Status for this Site')),
+                ('location', geoposition.fields.GeopositionField(max_length=42)),
+                ('longitude', models.FloatField(null=True, blank=True)),
+                ('latitude', models.FloatField(null=True, blank=True)),
+                ('login_base', models.CharField(
+                    help_text=b'Prefix for Slices associated with this Site', unique=True, max_length=50)),
+                ('is_public', models.BooleanField(
+                    default=True, help_text=b'Indicates the visibility of this site to other members')),
+                ('abbreviated_name', models.CharField(max_length=80)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='SiteCredential',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.SlugField(
+                    help_text=b'The credential type, e.g. ec2', max_length=128)),
+                ('key_id', models.CharField(
+                    help_text=b'The backend id of this credential', max_length=1024)),
+                ('enc_value', encrypted_fields.fields.EncryptedCharField(
+                    help_text=b'The key value of this credential', max_length=1024)),
+                ('site', models.ForeignKey(related_name=b'sitecredentials', to='core.Site',
+                                           help_text=b'The User this credential is associated with')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='SiteDeployment',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('availability_zone', models.CharField(
+                    help_text=b'OpenStack availability zone', max_length=200, null=True, blank=True)),
+                ('controller', models.ForeignKey(
+                    related_name=b'sitedeployments', blank=True, to='core.Controller', null=True)),
+                ('deployment', models.ForeignKey(
+                    related_name=b'sitedeployments', to='core.Deployment')),
+                ('site', models.ForeignKey(
+                    related_name=b'sitedeployments', to='core.Site')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='SitePrivilege',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='SiteRole',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('role', models.CharField(unique=True, max_length=30, choices=[
+                 (b'admin', b'Admin'), (b'pi', b'PI'), (b'tech', b'Tech'), (b'billing', b'Billing')])),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Slice',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.CharField(
+                    help_text=b'The Name of the Slice', unique=True, max_length=80)),
+                ('enabled', models.BooleanField(
+                    default=True, help_text=b'Status for this Slice')),
+                ('omf_friendly', models.BooleanField(default=False)),
+                ('description', models.TextField(
+                    help_text=b'High level description of the slice and expected activities', max_length=1024, blank=True)),
+                ('slice_url', models.URLField(max_length=512, blank=True)),
+                ('max_instances', models.IntegerField(default=10)),
+                ('network', models.CharField(default=b'Private Only',
+                                             max_length=256, null=True, blank=True)),
+                ('mount_data_sets', models.CharField(
+                    default=b'GenBank', max_length=256, null=True, blank=True)),
+                ('creator', models.ForeignKey(related_name=b'slices',
+                                              blank=True, to=settings.AUTH_USER_MODEL, null=True)),
+                ('default_flavor', models.ForeignKey(
+                    related_name=b'slices', blank=True, to='core.Flavor', null=True)),
+                ('default_image', models.ForeignKey(
+                    related_name=b'slices', blank=True, to='core.Image', null=True)),
+                ('service', models.ForeignKey(related_name=b'service',
+                                              blank=True, to='core.Service', null=True)),
+                ('serviceClass', models.ForeignKey(related_name=b'slices',
+                                                   default=core.models.serviceclass.get_default_serviceclass, to='core.ServiceClass', null=True)),
+                ('site', models.ForeignKey(related_name=b'slices',
+                                           to='core.Site', help_text=b'The Site this Slice belongs to')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='SliceCredential',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.SlugField(
+                    help_text=b'The credential type, e.g. ec2', max_length=128)),
+                ('key_id', models.CharField(
+                    help_text=b'The backend id of this credential', max_length=1024)),
+                ('enc_value', encrypted_fields.fields.EncryptedCharField(
+                    help_text=b'The key value of this credential', max_length=1024)),
+                ('slice', models.ForeignKey(related_name=b'slicecredentials',
+                                            to='core.Slice', help_text=b'The User this credential is associated with')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='SlicePrivilege',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='SliceRole',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('role', models.CharField(unique=True, max_length=30,
+                                          choices=[(b'admin', b'Admin'), (b'default', b'Default')])),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='SliceTag',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.CharField(help_text=b'The name of this tag', max_length=30, choices=[
+                 (b'privatekey', b'Private Key'), (b'publickey', b'Public Key')])),
+                ('value', models.CharField(
+                    help_text=b'The value of this tag', max_length=1024)),
+                ('slice', models.ForeignKey(
+                    related_name=b'slicetags', to='core.Slice')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Instance',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('instance_id', models.CharField(
+                    help_text=b'Nova instance id', max_length=200, null=True, blank=True)),
+                ('instance_uuid', models.CharField(
+                    help_text=b'Nova instance uuid', max_length=200, null=True, blank=True)),
+                ('name', models.CharField(help_text=b'Instance name', max_length=200)),
+                ('instance_name', models.CharField(
+                    help_text=b'OpenStack generated name', max_length=200, null=True, blank=True)),
+                ('ip', models.GenericIPAddressField(
+                    help_text=b'Instance ip address', null=True, blank=True)),
+                ('numberCores', models.IntegerField(
+                    default=0, help_text=b'Number of cores for instance', verbose_name=b'Number of Cores')),
+                ('userData', models.TextField(
+                    help_text=b'user_data passed to instance during creation', null=True, blank=True)),
+                ('creator', models.ForeignKey(related_name=b'instances',
+                                              blank=True, to=settings.AUTH_USER_MODEL, null=True)),
+                ('deployment', models.ForeignKey(related_name=b'instance_deployment',
+                                                 verbose_name=b'deployment', to='core.Deployment')),
+                ('flavor', models.ForeignKey(default=core.models.instance.get_default_flavor,
+                                             to='core.Flavor', help_text=b'Flavor of this instance')),
+                ('image', models.ForeignKey(
+                    related_name=b'instances', to='core.Image')),
+                ('node', models.ForeignKey(related_name=b'instances', to='core.Node')),
+                ('slice', models.ForeignKey(
+                    related_name=b'instances', to='core.Slice')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='Tag',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.SlugField(
+                    help_text=b'The name of this tag', max_length=128)),
+                ('value', models.CharField(
+                    help_text=b'The value of this tag', max_length=1024)),
+                ('object_id', models.PositiveIntegerField()),
+                ('content_type', models.ForeignKey(to='contenttypes.ContentType')),
+                ('service', models.ForeignKey(related_name=b'tags', to='core.Service',
+                                              help_text=b'The Service this Tag is associated with')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='UsableObject',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.CharField(max_length=1024)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='UserCredential',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('name', models.SlugField(
+                    help_text=b'The credential type, e.g. ec2', max_length=128)),
+                ('key_id', models.CharField(
+                    help_text=b'The backend id of this credential', max_length=1024)),
+                ('enc_value', encrypted_fields.fields.EncryptedCharField(
+                    help_text=b'The key value of this credential', max_length=1024)),
+                ('user', models.ForeignKey(related_name=b'usercredentials', to=settings.AUTH_USER_MODEL,
+                                           help_text=b'The User this credential is associated with')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='UserDashboardView',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('order', models.IntegerField(default=0)),
+                ('dashboardView', models.ForeignKey(
+                    related_name=b'userdashboardviews', to='core.DashboardView')),
+                ('user', models.ForeignKey(
+                    related_name=b'userdashboardviews', to=settings.AUTH_USER_MODEL)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='TenantPrivilege',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='TenantRole',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID',
+                                        serialize=False, auto_created=True, primary_key=True)),
+                ('created', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now_add=True)),
+                ('updated', models.DateTimeField(
+                    default=django.utils.timezone.now, auto_now=True)),
+                ('enacted', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('policed', models.DateTimeField(
+                    default=None, null=True, blank=True)),
+                ('backend_status', models.CharField(
+                    default=b'Provisioning in progress', max_length=140)),
+                ('deleted', models.BooleanField(default=False)),
+                ('role', models.CharField(unique=True, max_length=30,
+                                          choices=[(b'admin', b'Admin'), (b'access', b'Access')])),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=(models.Model,),
+        ),
+        migrations.AddField(
+            model_name='sliceprivilege',
+            name='role',
+            field=models.ForeignKey(
+                related_name=b'sliceprivileges', to='core.SliceRole'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='sliceprivilege',
+            name='slice',
+            field=models.ForeignKey(
+                related_name=b'sliceprivileges', to='core.Slice'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='sliceprivilege',
+            name='user',
+            field=models.ForeignKey(
+                related_name=b'sliceprivileges', to=settings.AUTH_USER_MODEL),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='siteprivilege',
+            name='role',
+            field=models.ForeignKey(
+                related_name=b'siteprivileges', to='core.SiteRole'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='siteprivilege',
+            name='site',
+            field=models.ForeignKey(
+                related_name=b'siteprivileges', to='core.Site'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='siteprivilege',
+            name='user',
+            field=models.ForeignKey(
+                related_name=b'siteprivileges', to=settings.AUTH_USER_MODEL),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='site',
+            name='deployments',
+            field=models.ManyToManyField(help_text=b'Select which sites are allowed to host nodes in this deployment',
+                                         related_name=b'sites', through='core.SiteDeployment', to='core.Deployment', blank=True),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='router',
+            name='owner',
+            field=models.ForeignKey(related_name=b'routers', to='core.Slice'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='router',
+            name='permittedNetworks',
+            field=models.ManyToManyField(
+                related_name=b'availableRouters', to='core.Network', blank=True),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='reservedresource',
+            name='resource',
+            field=models.ForeignKey(
+                related_name=b'reservedresources', to='core.ServiceResource'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='reservedresource',
+            name='instance',
+            field=models.ForeignKey(
+                related_name=b'reservedresources', to='core.Instance'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='reservation',
+            name='slice',
+            field=models.ForeignKey(
+                related_name=b'reservations', to='core.Slice'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='planetstackprivilege',
+            name='role',
+            field=models.ForeignKey(to='core.PlanetStackRole'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='planetstackprivilege',
+            name='user',
+            field=models.ForeignKey(
+                related_name=b'planetstackprivileges', to=settings.AUTH_USER_MODEL),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='node',
+            name='site',
+            field=models.ForeignKey(
+                related_name=b'nodes', blank=True, to='core.Site', null=True),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='node',
+            name='site_deployment',
+            field=models.ForeignKey(
+                related_name=b'nodes', to='core.SiteDeployment'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='networkinstance',
+            name='instance',
+            field=models.ForeignKey(
+                related_name=b'networkinstances', to='core.Instance'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='networkslice',
+            name='slice',
+            field=models.ForeignKey(
+                related_name=b'networkslices', to='core.Slice'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='networkparameter',
+            name='parameter',
+            field=models.ForeignKey(related_name=b'networkparameters',
+                                    to='core.NetworkParameterType', help_text=b'The type of the parameter'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='network',
+            name='owner',
+            field=models.ForeignKey(related_name=b'ownedNetworks', to='core.Slice',
+                                    help_text=b'Slice that owns control of this Network'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='network',
+            name='permitted_slices',
+            field=models.ManyToManyField(
+                related_name=b'availableNetworks', to='core.Slice', blank=True),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='network',
+            name='slices',
+            field=models.ManyToManyField(
+                related_name=b'networks', through='core.NetworkSlice', to='core.Slice', blank=True),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='network',
+            name='instances',
+            field=models.ManyToManyField(
+                related_name=b'networks', through='core.NetworkInstance', to='core.Instance', blank=True),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='network',
+            name='template',
+            field=models.ForeignKey(to='core.NetworkTemplate'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='image',
+            name='deployments',
+            field=models.ManyToManyField(help_text=b'Select which images should be instantiated on this deployment',
+                                         related_name=b'images', through='core.ImageDeployments', to='core.Deployment', blank=True),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='deploymentprivilege',
+            name='role',
+            field=models.ForeignKey(
+                related_name=b'deploymentprivileges', to='core.DeploymentRole'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='deploymentprivilege',
+            name='user',
+            field=models.ForeignKey(
+                related_name=b'deploymentprivileges', to=settings.AUTH_USER_MODEL),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='controllersliceprivilege',
+            name='slice_privilege',
+            field=models.ForeignKey(
+                related_name=b'controllersliceprivileges', to='core.SlicePrivilege'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='controllerslice',
+            name='slice',
+            field=models.ForeignKey(
+                related_name=b'controllerslices', to='core.Slice'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='controllersiteprivilege',
+            name='site_privilege',
+            field=models.ForeignKey(
+                related_name=b'controllersiteprivileges', to='core.SitePrivilege'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='controllersite',
+            name='site',
+            field=models.ForeignKey(
+                related_name=b'controllersite', to='core.Site'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='controllernetwork',
+            name='network',
+            field=models.ForeignKey(
+                related_name=b'controllernetworks', to='core.Network'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='controllerimages',
+            name='image',
+            field=models.ForeignKey(
+                related_name=b'controllerimages', to='core.Image'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='controllerdashboardview',
+            name='dashboardView',
+            field=models.ForeignKey(
+                related_name=b'controllerdashboardviews', to='core.DashboardView'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='charge',
+            name='invoice',
+            field=models.ForeignKey(
+                related_name=b'charges', blank=True, to='core.Invoice', null=True),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='charge',
+            name='object',
+            field=models.ForeignKey(to='core.UsableObject'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='charge',
+            name='slice',
+            field=models.ForeignKey(
+                related_name=b'charges', blank=True, to='core.Slice', null=True),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='account',
+            name='site',
+            field=models.ForeignKey(
+                related_name=b'accounts', to='core.Site', help_text=b'Site for this account'),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='user',
+            name='dashboards',
+            field=models.ManyToManyField(
+                to='core.DashboardView', through='core.UserDashboardView', blank=True),
+            preserve_default=True,
+        ),
+        migrations.AddField(
+            model_name='user',
+            name='site',
+            field=models.ForeignKey(related_name=b'users', to='core.Site',
+                                    help_text=b'Site this user will be homed too', null=True),
+            preserve_default=True,
+        ),
+    ]
diff --git a/xos/core/migrations/0011_sliver_instance_uuid.py b/xos/core/migrations/0011_sliver_instance_uuid.py
new file mode 100644
index 0000000..3320158
--- /dev/null
+++ b/xos/core/migrations/0011_sliver_instance_uuid.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('core', '0010_auto_20150118_1926'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='instance',
+            name='instance_uuid',
+            field=models.CharField(help_text=b'Nova instance uuid', max_length=200, null=True, blank=True),
+            preserve_default=True,
+        ),
+    ]
diff --git a/xos/core/migrations/__init__.py b/xos/core/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xos/core/migrations/__init__.py
diff --git a/xos/core/models/__init__.py b/xos/core/models/__init__.py
new file mode 100644
index 0000000..41e6b3b
--- /dev/null
+++ b/xos/core/models/__init__.py
@@ -0,0 +1,34 @@
+from .plcorebase import PlCoreBase,PlCoreBaseManager,PlCoreBaseDeletionManager,PlModelMixIn
+from .project import Project
+from .singletonmodel import SingletonModel
+from .xosmodel import XOS, XOSVolume
+from .service import Service, Tenant, TenantWithContainer, CoarseTenant, ServicePrivilege, TenantRoot, TenantRootPrivilege, TenantRootRole, TenantPrivilege, TenantRole, Subscriber, Provider
+from .service import ServiceAttribute, TenantAttribute, ServiceRole
+from .service import ServiceController, ServiceControllerResource
+from .tag import Tag
+from .role import Role
+from .site import Site, Deployment, DeploymentRole, DeploymentPrivilege, Controller, ControllerRole, ControllerSite, SiteDeployment,Diag
+from .dashboard import DashboardView, ControllerDashboardView
+from .user import User, UserDashboardView
+from .serviceclass import ServiceClass
+from .site import ControllerManager, ControllerDeletionManager, ControllerLinkManager,ControllerLinkDeletionManager
+from .flavor import Flavor
+from .image import Image
+from .slice import Slice, ControllerSlice
+from .controlleruser import ControllerUser, ControllerSitePrivilege, ControllerSlicePrivilege
+from .image import ImageDeployments, ControllerImages
+from .serviceresource import ServiceResource
+from .slice import SliceRole
+from .slice import SlicePrivilege
+from .credential import UserCredential,SiteCredential,SliceCredential
+from .site import SiteRole
+from .site import SitePrivilege
+from .node import Node, NodeLabel
+from .slicetag import SliceTag
+from .instance import Instance
+from .reservation import ReservedResource
+from .reservation import Reservation
+from .network import Network, NetworkParameterType, NetworkParameter, Port, NetworkTemplate, Router, NetworkSlice, ControllerNetwork, AddressPool
+from .billing import Account, Invoice, Charge, UsableObject, Payment
+from .program import Program
+
diff --git a/xos/core/models/billing.py b/xos/core/models/billing.py
new file mode 100644
index 0000000..6e517b4
--- /dev/null
+++ b/xos/core/models/billing.py
@@ -0,0 +1,78 @@
+import datetime
+import os
+import socket
+from django.db import models
+from core.models import PlCoreBase, Site, Slice, Instance, Deployment
+from core.models.plcorebase import StrippedCharField
+from django.contrib.contenttypes.models import ContentType
+from django.contrib.contenttypes import generic
+from django.db.models import Sum
+from django.utils import timezone
+
+class Account(PlCoreBase):
+    site = models.ForeignKey(Site, related_name="accounts", help_text="Site for this account")
+
+    @property
+    def total_invoices(self):
+        # Since the amount of an invoice is the sum of it's charges, we can
+        # compute the sum of the invoices by summing all charges where
+        # charge.invoice != Null.
+        x=self.charges.filter(invoice__isnull=False).aggregate(Sum('amount'))["amount__sum"]
+        if (x==None):
+            return 0.0
+        return x
+
+    @property
+    def total_payments(self):
+        x=self.payments.all().aggregate(Sum('amount'))["amount__sum"]
+        if (x==None):
+            return 0.0
+        return x
+
+    @property
+    def balance_due(self):
+        return self.total_invoices - self.total_payments
+
+    def __unicode__(self):  return u'%s' % (self.site.name)
+
+class Invoice(PlCoreBase):
+    date = models.DateTimeField()
+    account = models.ForeignKey(Account, related_name="invoices")
+
+    @property
+    def amount(self):
+        return str(self.charges.all().aggregate(Sum('amount'))["amount__sum"])
+
+    def __unicode__(self):  return u'%s-%s' % (self.account.site.name, str(self.date))
+
+class UsableObject(PlCoreBase):
+    name = StrippedCharField(max_length=1024)
+
+    def __unicode__(self):  return u'%s' % (self.name)
+
+class Payment(PlCoreBase):
+    account = models.ForeignKey(Account, related_name="payments")
+    amount = models.FloatField(default=0.0)
+    date = models.DateTimeField(default=timezone.now)
+
+    def __unicode__(self): return u'%s-%0.2f-%s' % (self.account.site.name, self.amount, str(self.date))
+
+class Charge(PlCoreBase):
+    KIND_CHOICES = (('besteffort', 'besteffort'), ('reservation', 'reservation'), ('monthlyfee', 'monthlyfee'))
+    STATE_CHOICES = (('pending', 'pending'), ('invoiced', 'invoiced'))
+
+    account = models.ForeignKey(Account, related_name="charges")
+    slice = models.ForeignKey(Slice, related_name="charges", null=True, blank=True)
+    kind = StrippedCharField(max_length=30, choices=KIND_CHOICES, default="besteffort")
+    state = StrippedCharField(max_length=30, choices=STATE_CHOICES, default="pending")
+    date = models.DateTimeField()
+    object = models.ForeignKey(UsableObject)
+    amount = models.FloatField(default=0.0)
+    coreHours = models.FloatField(default=0.0)
+    invoice = models.ForeignKey(Invoice, blank=True, null=True, related_name="charges")
+
+    def __unicode__(self):  return u'%s-%0.2f-%s' % (self.account.site.name, self.amount, str(self.date))
+
+
+
+
diff --git a/xos/core/models/controlleruser.py b/xos/core/models/controlleruser.py
new file mode 100644
index 0000000..1031e12
--- /dev/null
+++ b/xos/core/models/controlleruser.py
@@ -0,0 +1,104 @@
+import os
+import datetime
+from collections import defaultdict
+from django.db import models
+from django.db.models import F, Q
+from core.models import PlCoreBase,User,Controller
+from core.models.plcorebase import StrippedCharField
+from core.models import Controller,ControllerLinkManager,ControllerLinkDeletionManager
+
+class ControllerUser(PlCoreBase):
+    objects = ControllerLinkManager()
+    deleted_objects = ControllerLinkDeletionManager()
+
+    user = models.ForeignKey(User,related_name='controllerusers')
+    controller = models.ForeignKey(Controller,related_name='controllersusers')
+    kuser_id = StrippedCharField(null=True, blank=True, max_length=200, help_text="Keystone user id")
+
+
+    class Meta:
+        unique_together = ('user', 'controller')
+
+    def __unicode__(self):  return u'%s %s' % (self.controller, self.user)
+
+    @staticmethod
+    def select_by_user(user):
+        if user.is_admin:
+            qs = ControllerUser.objects.all()
+        else:
+            users = User.select_by_user(user)
+            qs = ControllerUser.objects.filter(user__in=users)
+        return qs
+
+    def can_update(self, user):
+        return user.can_update_root()    
+
+
+class ControllerSitePrivilege(PlCoreBase):
+    objects = ControllerLinkManager()
+    deleted_objects = ControllerLinkDeletionManager()
+
+    controller = models.ForeignKey('Controller', related_name='controllersiteprivileges')
+    site_privilege = models.ForeignKey('SitePrivilege', related_name='controllersiteprivileges')
+    role_id = StrippedCharField(null=True, blank=True, max_length=200, db_index=True, help_text="Keystone id")
+
+    class Meta:
+        unique_together = ('controller', 'site_privilege', 'role_id')
+
+    def __unicode__(self):  return u'%s %s' % (self.controller, self.site_privilege)
+
+    def can_update(self, user):
+        if user.is_readonly:
+            return False
+        if user.is_admin:
+            return True
+        cprivs = ControllerSitePrivilege.objects.filter(site_privilege__user=user)
+        for cpriv in dprivs:
+            if cpriv.site_privilege.role.role == ['admin', 'Admin']:
+                return True
+        return False
+
+    @staticmethod
+    def select_by_user(user):
+        if user.is_admin:
+            qs = ControllerSitePrivilege.objects.all()
+        else:
+            cpriv_ids = [cp.id for cp in ControllerSitePrivilege.objects.filter(site_privilege__user=user)]
+            qs = ControllerSitePrivilege.objects.filter(id__in=cpriv_ids)
+        return qs
+
+
+class ControllerSlicePrivilege(PlCoreBase):
+    objects = ControllerLinkManager()
+    deleted_objects = ControllerLinkDeletionManager()
+
+    controller = models.ForeignKey('Controller', related_name='controllersliceprivileges')
+    slice_privilege = models.ForeignKey('SlicePrivilege', related_name='controllersliceprivileges')
+    role_id = StrippedCharField(null=True, blank=True, max_length=200, db_index=True, help_text="Keystone id")
+
+
+    class Meta:
+        unique_together = ('controller', 'slice_privilege')
+
+    def __unicode__(self):  return u'%s %s' % (self.controller, self.slice_privilege)
+
+    def can_update(self, user):
+        if user.is_readonly:
+            return False
+        if user.is_admin:
+            return True
+        cprivs = ControllerSlicePrivilege.objects.filter(slice_privilege__user=user)
+        for cpriv in dprivs:
+            if cpriv.role.role == ['admin', 'Admin']:
+                return True
+        return False
+
+    @staticmethod
+    def select_by_user(user):
+        if user.is_admin:
+            qs = ControllerSlicePrivilege.objects.all()
+        else:
+            cpriv_ids = [cp.id for cp in ControllerSlicePrivilege.objects.filter(slice_privilege__user=user)]
+            qs = ControllerSlicePrivilege.objects.filter(id__in=cpriv_ids)
+        return qs
+
diff --git a/xos/core/models/credential.py b/xos/core/models/credential.py
new file mode 100644
index 0000000..ba58360
--- /dev/null
+++ b/xos/core/models/credential.py
@@ -0,0 +1,53 @@
+import os
+from django.db import models
+from core.models import PlCoreBase
+from core.models import User,Site,Slice,Controller
+from core.models.plcorebase import StrippedCharField
+from encrypted_fields import EncryptedCharField
+from core.models import Controller,ControllerLinkManager,ControllerLinkDeletionManager
+
+class UserCredential(PlCoreBase):
+    user = models.ForeignKey(User, related_name='usercredentials', help_text="The User this credential is associated with")
+
+    name = models.SlugField(help_text="The credential type, e.g. ec2", max_length=128)
+    key_id = StrippedCharField(help_text="The backend id of this credential", max_length=1024)
+    enc_value = EncryptedCharField(help_text="The key value of this credential", max_length=1024)
+
+
+    def __unicode__(self):
+        return self.name
+
+class SiteCredential(PlCoreBase):
+    site = models.ForeignKey(Site, related_name='sitecredentials', help_text="The User this credential is associated with")
+
+    name = models.SlugField(help_text="The credential type, e.g. ec2", max_length=128)
+    key_id = StrippedCharField(help_text="The backend id of this credential", max_length=1024)
+    enc_value = EncryptedCharField(help_text="The key value of this credential", max_length=1024)
+
+
+    def __unicode__(self):
+        return self.name
+
+class SliceCredential(PlCoreBase):
+    slice = models.ForeignKey(Slice, related_name='slicecredentials', help_text="The User this credential is associated with")
+
+    name = models.SlugField(help_text="The credential type, e.g. ec2", max_length=128)
+    key_id = StrippedCharField(help_text="The backend id of this credential", max_length=1024)
+    enc_value = EncryptedCharField(help_text="The key value of this credential", max_length=1024)
+
+
+    def __unicode__(self):
+        return self.name
+
+class ControllerCredential(PlCoreBase):
+    objects = ControllerLinkManager()
+    deleted_objects = ControllerLinkDeletionManager()
+    controller = models.ForeignKey(Controller, related_name='controllercredentials', help_text="The User this credential is associated with")
+
+    name = models.SlugField(help_text="The credential type, e.g. ec2", max_length=128)
+    key_id = models.CharField(help_text="The backend id of this credential", max_length=1024)
+    enc_value = EncryptedCharField(help_text="The key value of this credential", max_length=1024)
+
+
+    def __unicode__(self):
+        return self.name
diff --git a/xos/core/models/dashboard.py b/xos/core/models/dashboard.py
new file mode 100644
index 0000000..5228381
--- /dev/null
+++ b/xos/core/models/dashboard.py
@@ -0,0 +1,27 @@
+import os
+from django.db import models
+from core.models import PlCoreBase, Controller, Deployment
+from core.models.plcorebase import StrippedCharField
+from core.models.site import ControllerLinkManager, ControllerLinkDeletionManager
+from django.contrib.contenttypes import generic
+
+class DashboardView(PlCoreBase):
+    name = StrippedCharField(max_length=200, unique=True, help_text="Name of the View")
+    url = StrippedCharField(max_length=1024, help_text="URL of Dashboard")
+    controllers = models.ManyToManyField(Controller, blank=True, related_name="dashboardviews", through='ControllerDashboardView')
+    enabled = models.BooleanField(default=True)
+    deployments = models.ManyToManyField(Deployment, blank=True, null=True, related_name="dashboardviews", help_text="Deployments that should be included in this view")
+
+    def __unicode__(self):  return u'%s' % (self.name)
+
+class ControllerDashboardView(PlCoreBase):
+    objects = ControllerLinkManager()
+    deleted_objects = ControllerLinkDeletionManager()
+    controller = models.ForeignKey(Controller, related_name='controllerdashboardviews')
+    dashboardView = models.ForeignKey(DashboardView, related_name='controllerdashboardviews')
+    enabled = models.BooleanField(default=True)
+
+    url = StrippedCharField(max_length=1024, help_text="URL of Dashboard")
+
+
+
diff --git a/xos/core/models/flavor.py b/xos/core/models/flavor.py
new file mode 100644
index 0000000..8251eb1
--- /dev/null
+++ b/xos/core/models/flavor.py
@@ -0,0 +1,46 @@
+import os
+import socket
+from django.db import models
+from core.models import PlCoreBase, Deployment
+from core.models.plcorebase import StrippedCharField
+from django.contrib.contenttypes.models import ContentType
+from django.contrib.contenttypes import generic
+
+class Flavor(PlCoreBase):
+    name = StrippedCharField(max_length=32, help_text="name of this flavor, as displayed to users")
+    description = StrippedCharField(max_length=1024, blank=True, null=True)
+    flavor = StrippedCharField(max_length=32, help_text="flavor string used to configure deployments")
+    deployments = models.ManyToManyField(Deployment, blank=True, related_name="flavors")
+    order = models.IntegerField(default=0, help_text="used to order flavors when displayed in a list")
+    default = models.BooleanField(default=False, help_text="make this a default flavor to use when creating new instances")
+
+    class Meta:
+        app_label = "core"
+        ordering = ('order', 'name')
+
+    def __init__(self, *args, **kwargs):
+        super(Flavor, self).__init__(*args, **kwargs)
+        self.no_sync=True
+
+    def __unicode__(self):  return u'%s' % (self.name)
+
+""" FlavorParameterType and FlavorParameter are below for completeness sake,
+    waiting for the day we might want to add parameters to flavors.
+
+class FlavorParameterType(PlCoreBase):
+    name = models.SlugField(help_text="The name of this parameter", max_length=128)
+    description = StrippedCharField(max_length=1024)
+
+    def __unicode__(self):  return u'%s' % (self.name)
+
+class FlavorParameter(PlCoreBase):
+    parameter = models.ForeignKey(FlavorParameterType, related_name="flavorparameters", help_text="The type of the parameter")
+    value = StrippedCharField(help_text="The value of this parameter", max_length=1024)
+
+    flavor = models.ForeignKey(Flavor,related_name='flavorparameter')
+
+    def __unicode__(self):
+        return self.parameter.name
+
+"""
+
diff --git a/xos/core/models/image.py b/xos/core/models/image.py
new file mode 100644
index 0000000..69d0f03
--- /dev/null
+++ b/xos/core/models/image.py
@@ -0,0 +1,45 @@
+import os
+from django.db import models
+from core.models import PlCoreBase
+from core.models.plcorebase import StrippedCharField
+from core.models import Deployment, DeploymentPrivilege, Controller,ControllerLinkManager,ControllerLinkDeletionManager
+
+# Create your models here.
+
+class Image(PlCoreBase):
+    KIND_CHOICES = (('vm', 'Virtual Machine'), ('container', 'Container'), )
+
+    name = StrippedCharField(max_length=256, unique=True)
+    kind = models.CharField(null=False, blank=False, max_length=30, choices=KIND_CHOICES, default="vm")
+    disk_format = StrippedCharField(max_length=256)
+    container_format = StrippedCharField(max_length=256)
+    path = StrippedCharField(max_length=256, null=True, blank=True, help_text="Path to image on local disk")
+    deployments = models.ManyToManyField('Deployment', through='ImageDeployments', blank=True, help_text="Select which images should be instantiated on this deployment", related_name='images')
+
+    tag = StrippedCharField(max_length=256, null=True, blank=True, help_text="For Docker Images, tag of image")
+
+    def __unicode__(self):  return u'%s' % (self.name)
+
+class ImageDeployments(PlCoreBase):
+    image = models.ForeignKey(Image,related_name='imagedeployments')
+    deployment = models.ForeignKey(Deployment,related_name='imagedeployments')
+
+    class Meta:
+        unique_together = ('image', 'deployment')
+
+    def __unicode__(self):  return u'%s %s' % (self.image, self.deployment)
+
+    def can_update(self, user):
+        return user.can_update_deployment(self.deployment)
+
+class ControllerImages(PlCoreBase):
+    objects = ControllerLinkManager()
+    deleted_objects = ControllerLinkDeletionManager()
+    image = models.ForeignKey(Image,related_name='controllerimages')
+    controller = models.ForeignKey(Controller,related_name='controllerimages')
+    glance_image_id = StrippedCharField(null=True, blank=True, max_length=200, help_text="Glance image id") 
+   
+    class Meta:
+        unique_together = ('image', 'controller')
+         
+    def __unicode__(self):  return u'%s %s' % (self.image, self.controller)
diff --git a/xos/core/models/instance.py b/xos/core/models/instance.py
new file mode 100644
index 0000000..8cd889a
--- /dev/null
+++ b/xos/core/models/instance.py
@@ -0,0 +1,251 @@
+import os
+from django.db import models
+from django.db.models import Q
+from django.core import exceptions
+from core.models import PlCoreBase,PlCoreBaseManager,PlCoreBaseDeletionManager
+from core.models.plcorebase import StrippedCharField
+from core.models import Image
+from core.models import Slice, SlicePrivilege
+from core.models import Node
+from core.models import Site
+from core.models import Deployment
+from core.models import Controller
+from core.models import User
+from core.models import Tag
+from core.models import Flavor
+from django.contrib.contenttypes import generic
+from xos.config import Config
+from django.core.exceptions import PermissionDenied, ValidationError
+
+config = Config()
+
+def get_default_flavor(controller = None):
+    # Find a default flavor that can be used for a instance. This is particularly
+    # useful in evolution. It's also intended this helper function can be used
+    # for admin.py when users
+
+    if controller:
+        flavors = controller.flavors.all()
+    else:
+        flavors = Flavor.objects.all()
+
+    if not flavors:
+        return None
+
+    for flavor in flavors:
+        if flavor.default:
+            return flavor
+
+    return flavors[0]
+
+class InstanceDeletionManager(PlCoreBaseDeletionManager):
+    def get_queryset(self):
+        parent=super(InstanceDeletionManager, self)
+        try:
+            backend_type = config.observer_backend_type
+        except AttributeError:
+            backend_type = None
+
+        parent_queryset = parent.get_queryset() if hasattr(parent, "get_queryset") else parent.get_query_set()
+        if (backend_type):
+            return parent_queryset.filter(Q(node__controller__backend_type=backend_type))
+        else:
+            return parent_queryset
+
+    # deprecated in django 1.7 in favor of get_queryset().
+    def get_query_set(self):
+        return self.get_queryset()
+
+
+class InstanceManager(PlCoreBaseManager):
+    def get_queryset(self):
+        parent=super(InstanceManager, self)
+
+        try:
+            backend_type = config.observer_backend_type
+        except AttributeError:
+            backend_type = None
+
+        parent_queryset = parent.get_queryset() if hasattr(parent, "get_queryset") else parent.get_query_set()
+
+        if backend_type:
+            return parent_queryset.filter(Q(node__controller__backend_type=backend_type))
+        else:
+            return parent_queryset
+
+    # deprecated in django 1.7 in favor of get_queryset().
+    def get_query_set(self):
+        return self.get_queryset()
+
+# Create your models here.
+class Instance(PlCoreBase):
+    ISOLATION_CHOICES = (('vm', 'Virtual Machine'), ('container', 'Container'), ('container_vm', 'Container In VM'))
+
+    objects = InstanceManager()
+    deleted_objects = InstanceDeletionManager()
+    instance_id = StrippedCharField(null=True, blank=True, max_length=200, help_text="Nova instance id")
+    instance_uuid = StrippedCharField(null=True, blank=True, max_length=200, help_text="Nova instance uuid")
+    name = StrippedCharField(max_length=200, help_text="Instance name")
+    instance_name = StrippedCharField(blank=True, null=True, max_length=200, help_text="OpenStack generated name")
+    ip = models.GenericIPAddressField(help_text="Instance ip address", blank=True, null=True)
+    image = models.ForeignKey(Image, related_name='instances')
+    creator = models.ForeignKey(User, related_name='instances', blank=True, null=True)
+    slice = models.ForeignKey(Slice, related_name='instances')
+    deployment = models.ForeignKey(Deployment, verbose_name='deployment', related_name='instance_deployment')
+    node = models.ForeignKey(Node, related_name='instances')
+    numberCores = models.IntegerField(verbose_name="Number of Cores", help_text="Number of cores for instance", default=0)
+    flavor = models.ForeignKey(Flavor, help_text="Flavor of this instance", default=get_default_flavor)
+    tags = generic.GenericRelation(Tag)
+    userData = models.TextField(blank=True, null=True, help_text="user_data passed to instance during creation")
+    isolation = models.CharField(null=False, blank=False, max_length=30, choices=ISOLATION_CHOICES, default="vm")
+    volumes = models.TextField(null=True, blank=True, help_text="Comma-separated list of directories to expose to parent context")
+    parent = models.ForeignKey("Instance", null=True, blank=True, help_text="Parent Instance for containers nested inside of VMs")
+
+    def get_controller (self):
+        return self.node.site_deployment.controller
+
+    def tologdict(self):
+        d=super(Instance,self).tologdict()
+        try:
+            d['slice_name']=self.slice.name
+            d['controller_name']=self.get_controller().name
+        except:
+            pass
+        return d
+
+    def __unicode__(self):
+        if self.name and Slice.objects.filter(id=self.slice_id) and (self.name != self.slice.name):
+            # NOTE: The weird check on self.slice_id was due to a problem when
+            #   deleting the slice before the instance.
+            return u'%s' % self.name
+        elif self.instance_name:
+            return u'%s' % (self.instance_name)
+        elif self.id:
+            return u'uninstantiated-%s' % str(self.id)
+        elif self.slice:
+            return u'unsaved-instance on %s' % self.slice.name
+        else:
+            return u'unsaved-instance'
+
+    def save(self, *args, **kwds):
+        if not self.name:
+            self.name = self.slice.name
+        if not self.creator and hasattr(self, 'caller'):
+            self.creator = self.caller
+        if not self.creator:
+            raise ValidationError('instance has no creator')
+
+        if (self.isolation == "container") or (self.isolation == "container_vm"):
+            if (self.image.kind != "container"):
+               raise ValidationError("Container instance must use container image")
+        elif (self.isolation == "vm"):
+            if (self.image.kind != "vm"):
+               raise ValidationError("VM instance must use VM image")
+
+        if (self.isolation == "container_vm") and (not self.parent):
+            raise ValidationError("Container-vm instance must have a parent")
+
+        if (self.parent) and (self.isolation != "container_vm"):
+            raise ValidationError("Parent field can only be set on Container-vm instances")
+
+        if (self.slice.creator != self.creator):
+            # Check to make sure there's a slice_privilege for the user. If there
+            # isn't, then keystone will throw an exception inside the observer.
+            slice_privs = SlicePrivilege.objects.filter(slice=self.slice, user=self.creator)
+            if not slice_privs:
+                raise ValidationError('instance creator has no privileges on slice')
+
+# XXX smbaker - disabled for now, was causing fault in tenant view create slice
+#        if not self.controllerNetwork.test_acl(slice=self.slice):
+#            raise exceptions.ValidationError("Deployment %s's ACL does not allow any of this slice %s's users" % (self.controllerNetwork.name, self.slice.name))
+
+        super(Instance, self).save(*args, **kwds)
+
+    def can_update(self, user):
+        return user.can_update_slice(self.slice)
+
+    def all_ips(self):
+        ips={}
+        for ns in self.ports.all():
+           if ns.ip:
+               ips[ns.network.name] = ns.ip
+        return ips
+
+    def all_ips_string(self):
+        result = []
+        ips = self.all_ips()
+        for key in sorted(ips.keys()):
+            #result.append("%s = %s" % (key, ips[key]))
+            result.append(ips[key])
+        return ", ".join(result)
+    all_ips_string.short_description = "addresses"
+
+    def get_public_ip(self):
+        for ns in self.ports.all():
+            if (ns.ip) and (ns.network.template.visibility=="public") and (ns.network.template.translation=="none"):
+                return ns.ip
+        return None
+
+    # return an address on nat-net
+    def get_network_ip(self, pattern):
+        for ns in self.ports.all():
+            if pattern in ns.network.name.lower():
+                return ns.ip
+        return None
+
+    # return an address that the synchronizer can use to SSH to the instance
+    def get_ssh_ip(self):
+        management=self.get_network_ip("management")
+        if management:
+            return management
+        return self.get_network_ip("nat")
+
+    @staticmethod
+    def select_by_user(user):
+        if user.is_admin:
+            qs = Instance.objects.all()
+        else:
+            slices = Slice.select_by_user(user)
+            qs = Instance.objects.filter(slice__in=slices)
+        return qs
+
+    def get_cpu_stats(self):
+        filter = 'instance_id=%s'%self.instance_id
+        return monitor.get_meter('cpu',filter,None)
+
+    def get_bw_stats(self):
+        filter = 'instance_id=%s'%self.instance_id
+        return monitor.get_meter('network.outgoing.bytes',filter,None)
+
+    def get_node_stats(self):
+        # Note sure what should go back here
+        return 1
+
+    def get_ssh_command(self):
+        if (not self.instance_id) or (not self.node) or (not self.instance_name):
+            return None
+        else:
+            return 'ssh -o "ProxyCommand ssh -q %s@%s" ubuntu@%s' % (self.instance_id, self.node.name, self.instance_name)
+
+    def get_public_keys(self):
+        slice_memberships = SlicePrivilege.objects.filter(slice=self.slice)
+        pubkeys = set([sm.user.public_key for sm in slice_memberships if sm.user.public_key])
+
+        if self.creator.public_key:
+            pubkeys.add(self.creator.public_key)
+
+        if self.slice.creator.public_key:
+            pubkeys.add(self.slice.creator.public_key)
+
+        if self.slice.service and self.slice.service.public_key:
+            pubkeys.add(self.slice.service.public_key)
+
+        return pubkeys
+
+def controller_setter(instance, **kwargs):
+    try:
+        instance.controller = instance.node.site_deployment.controller
+    except:
+        instance.controller = None
+
+models.signals.post_init.connect(controller_setter, Instance)
diff --git a/xos/core/models/network.py b/xos/core/models/network.py
new file mode 100644
index 0000000..37f4cfe
--- /dev/null
+++ b/xos/core/models/network.py
@@ -0,0 +1,415 @@
+import os
+import socket
+import sys
+from django.db import models, transaction
+from core.models import PlCoreBase, Site, Slice, Instance, Controller, Service
+from core.models import ControllerLinkManager,ControllerLinkDeletionManager
+from django.contrib.contenttypes.models import ContentType
+from django.contrib.contenttypes import generic
+from django.core.exceptions import ValidationError
+from django.db.models import Q
+
+# If true, then IP addresses will be allocated by the model. If false, then
+# we will assume the observer handles it.
+NO_OBSERVER=False
+
+def ParseNatList(ports):
+    """ Support a list of ports in the format "protocol:port, protocol:port, ..."
+        examples:
+            tcp 123
+            tcp 123:133
+            tcp 123, tcp 124, tcp 125, udp 201, udp 202
+
+        User can put either a "/" or a " " between protocol and ports
+        Port ranges can be specified with "-" or ":"
+    """
+    nats = []
+    if ports:
+        parts = ports.split(",")
+        for part in parts:
+            part = part.strip()
+            if "/" in part:
+                (protocol, ports) = part.split("/",1)
+            elif " " in part:
+                (protocol, ports) = part.split(None,1)
+            else:
+                raise TypeError('malformed port specifier %s, format example: "tcp 123, tcp 201:206, udp 333"' % part)
+
+            protocol = protocol.strip()
+            ports = ports.strip()
+
+            if not (protocol in ["udp", "tcp"]):
+                raise ValueError('unknown protocol %s' % protocol)
+
+            if "-" in ports:
+                (first, last) = ports.split("-")
+                first = int(first.strip())
+                last = int(last.strip())
+                portStr = "%d:%d" % (first, last)
+            elif ":" in ports:
+                (first, last) = ports.split(":")
+                first = int(first.strip())
+                last = int(last.strip())
+                portStr = "%d:%d" % (first, last)
+            else:
+                portStr = "%d" % int(ports)
+
+            nats.append( {"l4_protocol": protocol, "l4_port": portStr} )
+
+    return nats
+
+def ValidateNatList(ports):
+    try:
+        ParseNatList(ports)
+    except Exception,e:
+        raise ValidationError(str(e))
+
+class ParameterMixin(object):
+    # helper classes for dealing with NetworkParameter
+
+    def get_parameters(self):
+        parameter_dict = {}
+
+        instance_type = ContentType.objects.get_for_model(self)
+        for param in NetworkParameter.objects.filter(content_type__pk=instance_type.id, object_id=self.id):
+            parameter_dict[param.parameter.name] = param.value
+
+        return parameter_dict
+
+    def set_parameter(self, name, value):
+        instance_type = ContentType.objects.get_for_model(self)
+        existing_params = NetworkParameter.objects.filter(parameter__name=name, content_type__pk=instance_type.id, object_id=self.id)
+        if existing_params:
+            p=existing_params[0]
+            p.value = value
+            p.save()
+        else:
+            pt = NetworkParameterType.objects.get(name=name)
+            p = NetworkParameter(parameter=pt, content_type=instance_type, object_id=self.id, value=value)
+            p.save()
+
+    def unset_parameter(self, name):
+        instance_type = ContentType.objects.get_for_model(self)
+        existing_params = NetworkParameter.objects.filter(parameter__name=name, content_type__pk=instance_type.id, object_id=self.id)
+        for p in existing_params:
+            p.delete()
+
+
+class NetworkTemplate(PlCoreBase, ParameterMixin):
+    VISIBILITY_CHOICES = (('public', 'public'), ('private', 'private'))
+    TRANSLATION_CHOICES = (('none', 'none'), ('NAT', 'NAT'))
+    TOPOLOGY_CHOICES = (('bigswitch', 'BigSwitch'), ('physical', 'Physical'), ('custom', 'Custom'))
+    CONTROLLER_CHOICES = ((None, 'None'), ('onos', 'ONOS'), ('custom', 'Custom'))
+    ACCESS_CHOICES = ((None, 'None'), ('indirect', 'Indirect'), ('direct', 'Direct'))
+
+    name = models.CharField(max_length=32)
+    description = models.CharField(max_length=1024, blank=True, null=True)
+    guaranteed_bandwidth = models.IntegerField(default=0)
+    visibility = models.CharField(max_length=30, choices=VISIBILITY_CHOICES, default="private")
+    translation = models.CharField(max_length=30, choices=TRANSLATION_CHOICES, default="none")
+    access = models.CharField(max_length=30, null=True, blank=True, choices=ACCESS_CHOICES, help_text="Advertise this network as a means for other slices to contact this slice")
+    shared_network_name = models.CharField(max_length=30, blank=True, null=True)
+    shared_network_id = models.CharField(null=True, blank=True, max_length=256, help_text="Quantum network")
+    topology_kind = models.CharField(null=False, blank=False, max_length=30, choices=TOPOLOGY_CHOICES, default="bigswitch")
+    controller_kind = models.CharField(null=True, blank=True, max_length=30, choices=CONTROLLER_CHOICES, default=None)
+
+    def __init__(self, *args, **kwargs):
+        super(NetworkTemplate, self).__init__(*args, **kwargs)
+
+        # somehow these got set wrong inside of the live database. Remove this
+        # code after all is well...
+        if (self.topology_kind=="BigSwitch"):
+            print >> sys.stderr, "XXX warning: topology_kind invalid case"
+            self.topology_kind="bigswitch"
+        elif (self.topology_kind=="Physical"):
+            print >> sys.stderr, "XXX warning: topology_kind invalid case"
+            self.topology_kind="physical"
+        elif (self.topology_kind=="Custom"):
+            print >> sys.stderr, "XXX warning: topology_kind invalid case"
+            self.toplogy_kind="custom"
+
+    def save(self, *args, **kwargs):
+        self.enforce_choices(self.access, self.ACCESS_CHOICES)
+        super(NetworkTemplate, self).save(*args, **kwargs)
+
+    def __unicode__(self):  return u'%s' % (self.name)
+
+class Network(PlCoreBase, ParameterMixin):
+    name = models.CharField(max_length=32)
+    template = models.ForeignKey(NetworkTemplate)
+    subnet = models.CharField(max_length=32, blank=True)
+    start_ip = models.CharField(max_length=32, blank=True)
+    end_ip = models.CharField(max_length=32, blank=True)
+    ports = models.CharField(max_length=1024, blank=True, null=True, validators=[ValidateNatList])
+    labels = models.CharField(max_length=1024, blank=True, null=True)
+    owner = models.ForeignKey(Slice, related_name="ownedNetworks", help_text="Slice that owns control of this Network")
+
+    guaranteed_bandwidth = models.IntegerField(default=0)
+    permit_all_slices = models.BooleanField(default=False)
+    permitted_slices = models.ManyToManyField(Slice, blank=True, related_name="availableNetworks")
+    slices = models.ManyToManyField(Slice, blank=True, related_name="networks", through="NetworkSlice")
+    instances = models.ManyToManyField(Instance, blank=True, related_name="networks", through="Port")
+
+    topology_parameters = models.TextField(null=True, blank=True)
+    controller_url = models.CharField(null=True, blank=True, max_length=1024)
+    controller_parameters = models.TextField(null=True, blank=True)
+
+    # for observer/manager
+    network_id = models.CharField(null=True, blank=True, max_length=256, help_text="Quantum network")
+    router_id = models.CharField(null=True, blank=True, max_length=256, help_text="Quantum router id")
+    subnet_id = models.CharField(null=True, blank=True, max_length=256, help_text="Quantum subnet id")
+
+    autoconnect = models.BooleanField(default=True, help_text="This network can be autoconnected to the slice that owns it")
+
+    def __unicode__(self):  return u'%s' % (self.name)
+
+    def save(self, *args, **kwds):
+        if (not self.subnet) and (NO_OBSERVER):
+            from util.network_subnet_allocator import find_unused_subnet
+            self.subnet = find_unused_subnet(existing_subnets=[x.subnet for x in Network.objects.all()])
+            print "DEF_MOD_NET_IP", self.start_ip
+        super(Network, self).save(*args, **kwds)
+
+    def can_update(self, user):
+        return user.can_update_slice(self.owner)
+
+    @property
+    def nat_list(self):
+        return ParseNatList(self.ports)
+
+    @staticmethod
+    def select_by_user(user):
+        if user.is_admin:
+            qs = Network.objects.all()
+        else:
+            slices = Slice.select_by_user(user)
+            #slice_ids = [s.id for s in Slice.select_by_user(user)]
+            qs = Network.objects.filter(owner__in=slices)
+        return qs
+
+    def get_parameters(self):
+        # returns parameters from the template, updated by self.
+        p={}
+        if self.template:
+            p = self.template.get_parameters()
+        p.update(ParameterMixin.get_parameters(self))
+        return p
+
+class ControllerNetwork(PlCoreBase):
+    objects = ControllerLinkManager()
+    deleted_objects = ControllerLinkDeletionManager()
+
+    # Stores the openstack ids at various controllers
+    network = models.ForeignKey(Network, related_name='controllernetworks')
+    controller = models.ForeignKey(Controller, related_name='controllernetworks')
+    net_id = models.CharField(null=True, blank=True, max_length=256, help_text="Quantum network")
+    router_id = models.CharField(null=True, blank=True, max_length=256, help_text="Quantum router id")
+    subnet_id = models.CharField(null=True, blank=True, max_length=256, help_text="Quantum subnet id")
+    subnet = models.CharField(max_length=32, blank=True)
+    start_ip = models.CharField(max_length=32, blank=True)
+    stop_ip = models.CharField(max_length=32, blank=True)
+
+    class Meta:
+        unique_together = ('network', 'controller')
+
+    def tologdict(self):
+        d=super(ControllerNetwork,self).tologdict()
+        try:
+            d['network_name']=self.network.name
+            d['controller_name']=self.controller.name
+        except:
+            pass
+        return d
+ 
+    @staticmethod
+    def select_by_user(user):
+        if user.is_admin:
+            qs = ControllerNetwork.objects.all()
+        else:
+            slices = Slice.select_by_user(user)
+            networks = Network.objects.filter(owner__in=slices)
+            qs = ControllerNetwork.objects.filter(network__in=networks)
+        return qs
+
+class NetworkSlice(PlCoreBase):
+    # This object exists solely so we can implement the permission check when
+    # adding slices to networks. It adds no additional fields to the relation.
+
+    network = models.ForeignKey(Network,related_name='networkslices')
+    slice = models.ForeignKey(Slice,related_name='networkslices')
+
+    class Meta:
+        unique_together = ('network', 'slice')
+
+    def save(self, *args, **kwds):
+        slice = self.slice
+        if (slice not in self.network.permitted_slices.all()) and (slice != self.network.owner) and (not self.network.permit_all_slices):
+            # to add a instance to the network, then one of the following must be true:
+            #   1) instance's slice is in network's permittedSlices list,
+            #   2) instance's slice is network's owner, or
+            #   3) network's permitAllSlices is true
+            raise ValueError("Slice %s is not allowed to connect to network %s" % (str(slice), str(self.network)))
+
+        super(NetworkSlice, self).save(*args, **kwds)
+
+    def __unicode__(self):  return u'%s-%s' % (self.network.name, self.slice.name)
+
+    def can_update(self, user):
+        return user.can_update_slice(self.slice)
+
+    @staticmethod
+    def select_by_user(user):
+        if user.is_admin:
+            qs = NetworkSlice.objects.all()
+        else:
+            slice_ids = [s.id for s in Slice.select_by_user(user)]
+            network_ids = [network.id for network in Network.select_by_user(user)]
+            qs = NetworkSlice.objects.filter(Q(slice__in=slice_ids) | Q(network__in=network_ids))
+        return qs
+
+class Port(PlCoreBase, ParameterMixin):
+    network = models.ForeignKey(Network,related_name='links')
+    instance = models.ForeignKey(Instance, null=True, blank=True, related_name='ports')
+    ip = models.GenericIPAddressField(help_text="Instance ip address", blank=True, null=True)
+    port_id = models.CharField(null=True, blank=True, max_length=256, help_text="Neutron port id")
+    mac = models.CharField(null=True, blank=True, max_length=256, help_text="MAC address associated with this port")
+    xos_created = models.BooleanField(default=False) # True if XOS created this port in Neutron, False if port created by Neutron and observed by XOS
+
+    class Meta:
+        unique_together = ('network', 'instance')
+
+    def save(self, *args, **kwds):
+        if self.instance:
+            slice = self.instance.slice
+            if (slice not in self.network.permitted_slices.all()) and (slice != self.network.owner) and (not self.network.permit_all_slices):
+                # to add a instance to the network, then one of the following must be true:
+                #   1) instance's slice is in network's permittedSlices list,
+                #   2) instance's slice is network's owner, or
+                #   3) network's permitAllSlices is true
+                raise ValueError("Slice %s is not allowed to connect to network %s" % (str(slice), str(self.network)))
+
+        super(Port, self).save(*args, **kwds)
+
+    def __unicode__(self):
+        if self.instance:
+            return u'%s-%s' % (self.network.name, self.instance.instance_name)
+        else:
+            return u'%s-unboundport-%s' % (self.network.name, self.id)
+
+    def can_update(self, user):
+        if self.instance:
+            return user.can_update_slice(self.instance.slice)
+        if self.network:
+            return user.can_update_slice(self.network.owner)
+        return False
+
+    @staticmethod
+    def select_by_user(user):
+        if user.is_admin:
+            qs = Port.objects.all()
+        else:
+            instances = Instance.select_by_user(user)
+            instance_ids = [instance.id for instance in instances]
+            networks = Network.select_by_user(user)
+            network_ids = [network.id for network in networks]
+            qs = Port.objects.filter(Q(instance__in=instance_ids) | Q(network__in=network_ids))
+        return qs
+
+    def get_parameters(self):
+        # returns parameters from the network, updated by self.
+        p={}
+        if self.network:
+            p = self.network.get_parameters()
+        p.update(ParameterMixin.get_parameters(self))
+        return p
+
+class Router(PlCoreBase):
+    name = models.CharField(max_length=32)
+    owner = models.ForeignKey(Slice, related_name="routers")
+    permittedNetworks = models.ManyToManyField(Network, blank=True, related_name="availableRouters")
+    networks = models.ManyToManyField(Network, blank=True, related_name="routers")
+
+    def __unicode__(self):  return u'%s' % (self.name)
+
+    def can_update(self, user):
+        return user.can_update_slice(self.owner)
+
+class NetworkParameterType(PlCoreBase):
+    name = models.SlugField(help_text="The name of this parameter", max_length=128)
+    description = models.CharField(max_length=1024)
+
+    def __unicode__(self):  return u'%s' % (self.name)
+
+class NetworkParameter(PlCoreBase):
+    parameter = models.ForeignKey(NetworkParameterType, related_name="networkparameters", help_text="The type of the parameter")
+    value = models.CharField(help_text="The value of this parameter", max_length=1024)
+
+    # The required fields to do a ObjectType lookup, and object_id assignment
+    content_type = models.ForeignKey(ContentType)
+    object_id = models.PositiveIntegerField()
+    content_object = generic.GenericForeignKey('content_type', 'object_id')
+
+    def __unicode__(self):
+        return self.parameter.name
+
+class AddressPool(PlCoreBase):
+    name = models.CharField(max_length=32)
+    addresses = models.TextField(blank=True, null=True)
+    gateway_ip = models.CharField(max_length=32, null=True)
+    gateway_mac = models.CharField(max_length=32, null=True)
+    cidr = models.CharField(max_length=32, null=True)
+    inuse = models.TextField(blank=True, null=True)
+    service = models.ForeignKey(Service, related_name="addresspools", null=True, blank=True)
+
+    def __unicode__(self): return u'%s' % (self.name)
+
+    def get_address(self):
+        with transaction.atomic():
+            ap = AddressPool.objects.get(pk=self.pk)
+            if ap.addresses:
+                avail_ips = ap.addresses.split()
+            else:
+                avail_ips = []
+
+            if ap.inuse:
+                inuse_ips = ap.inuse.split()
+            else:
+                inuse_ips = []
+
+            while avail_ips:
+                addr = avail_ips.pop(0)
+
+                if addr in inuse_ips:
+                    # This may have happened if someone re-ran the tosca
+                    # recipe and 'refilled' the AddressPool while some addresses
+                    # were still in use.
+                    continue
+
+                inuse_ips.insert(0,addr)
+
+                ap.inuse = " ".join(inuse_ips)
+                ap.addresses = " ".join(avail_ips)
+                ap.save()
+                return addr
+
+            addr = None
+        return addr
+
+    def put_address(self, addr):
+        with transaction.atomic():
+            ap = AddressPool.objects.get(pk=self.pk)
+            addresses = ap.addresses or ""
+            parts = addresses.split()
+            if addr not in parts:
+                parts.insert(0,addr)
+                ap.addresses = " ".join(parts)
+
+            inuse = ap.inuse or ""
+            parts = inuse.split()
+            if addr in parts:
+                parts.remove(addr)
+                ap.inuse = " ".join(parts)
+
+            ap.save()
+
+
diff --git a/xos/core/models/node.py b/xos/core/models/node.py
new file mode 100644
index 0000000..f3ea303
--- /dev/null
+++ b/xos/core/models/node.py
@@ -0,0 +1,36 @@
+import os
+from django.db import models
+from core.models import PlCoreBase
+from core.models.plcorebase import StrippedCharField
+from core.models.site import Site, SiteDeployment, SitePrivilege
+from core.models import Tag
+from django.contrib.contenttypes import generic
+
+# Create your models here.
+
+class Node(PlCoreBase):
+    name = StrippedCharField(max_length=200, unique=True, help_text="Name of the Node")
+    site_deployment = models.ForeignKey(SiteDeployment, related_name='nodes')
+    site = models.ForeignKey(Site, null=True, blank=True, related_name='nodes')
+    tags = generic.GenericRelation(Tag)
+
+    def __unicode__(self):  return u'%s' % (self.name)
+
+    def __init__(self, *args, **kwargs):
+        super(Node, self).__init__(*args, **kwargs)
+        self.no_sync=True
+
+    def save(self, *args, **kwds):
+        if self.site is None and self.site_deployment is not None:
+            self.site = self.site_deployment.site
+
+        super(Node, self).save(*args, **kwds)
+
+    def can_update(self, user):
+        return user.can_update_site(self.site, allow=['tech'])
+
+class NodeLabel(PlCoreBase):
+    name = StrippedCharField(max_length=200, help_text="label name", unique=True)
+    node = models.ManyToManyField(Node, related_name="nodelabels", blank=True)
+
+    def __unicode__(self): return u'%s' % (self.name)
diff --git a/xos/core/models/plcorebase.py b/xos/core/models/plcorebase.py
new file mode 100644
index 0000000..b84b526
--- /dev/null
+++ b/xos/core/models/plcorebase.py
@@ -0,0 +1,315 @@
+import datetime
+import json
+import os
+import sys
+import threading
+from django import db
+from django.db import models
+from django.forms.models import model_to_dict
+from django.core.urlresolvers import reverse
+from django.forms.models import model_to_dict
+from django.utils import timezone
+from django.core.exceptions import PermissionDenied
+import synchronizers.model_policy
+from model_autodeletion import ephemeral_models
+from cgi import escape as html_escape
+
+try:
+    # This is a no-op if observer_disabled is set to 1 in the config file
+    from synchronizers.base import *
+except:
+    print >> sys.stderr, "import of observer failed! printing traceback and disabling observer:"
+    import traceback
+    traceback.print_exc()
+
+    # guard against something failing
+    def notify_observer(*args, **kwargs):
+        pass
+
+class StrippedCharField(models.CharField):
+    """ CharField that strips trailing and leading spaces."""
+    def clean(self, value, *args, **kwds):
+        if value is not None:
+            value = value.strip()
+        return super(StrippedCharField, self).clean(value, *args, **kwds)
+
+
+# This manager will be inherited by all subclasses because
+# the core model is abstract.
+class PlCoreBaseDeletionManager(models.Manager):
+    def get_queryset(self):
+        parent=super(PlCoreBaseDeletionManager, self)
+        if hasattr(parent, "get_queryset"):
+            return parent.get_queryset().filter(deleted=True)
+        else:
+            return parent.get_query_set().filter(deleted=True)
+
+    # deprecated in django 1.7 in favor of get_queryset().
+    def get_query_set(self):
+        return self.get_queryset()
+
+# This manager will be inherited by all subclasses because
+# the core model is abstract.
+class PlCoreBaseManager(models.Manager):
+    def get_queryset(self):
+        parent=super(PlCoreBaseManager, self)
+        if hasattr(parent, "get_queryset"):
+            return parent.get_queryset().filter(deleted=False)
+        else:
+            return parent.get_query_set().filter(deleted=False)
+
+    # deprecated in django 1.7 in favor of get_queryset().
+    def get_query_set(self):
+        return self.get_queryset()
+
+class PlModelMixIn(object):
+    # Provides useful methods for computing which objects in a model have
+    # changed. Make sure to do self._initial = self._dict in the __init__
+    # method.
+
+    # Also includes useful utility, like getValidators
+
+    # This is broken out of PlCoreBase into a Mixin so the User model can
+    # also make use of it.
+
+    @property
+    def _dict(self):
+        return model_to_dict(self, fields=[field.name for field in
+                             self._meta.fields])
+
+    def fields_differ(self,f1,f2):
+        if isinstance(f1,datetime.datetime) and isinstance(f2,datetime.datetime) and (timezone.is_aware(f1) != timezone.is_aware(f2)):
+            return True
+        else:
+            return (f1 != f2)
+
+    @property
+    def diff(self):
+        d1 = self._initial
+        d2 = self._dict
+        diffs = [(k, (v, d2[k])) for k, v in d1.items() if self.fields_differ(v,d2[k])]
+        return dict(diffs)
+
+    @property
+    def has_changed(self):
+        return bool(self.diff)
+
+    @property
+    def changed_fields(self):
+        return self.diff.keys()
+
+    def has_field_changed(self, field_name):
+        return field_name in self.diff.keys()
+
+    def get_field_diff(self, field_name):
+        return self.diff.get(field_name, None)
+
+    #classmethod
+    def getValidators(cls):
+        """ primarily for REST API, return a dictionary of field names mapped
+            to lists of the type of validations that need to be applied to
+            those fields.
+        """
+        validators = {}
+        for field in cls._meta.fields:
+            l = []
+            if field.blank==False:
+                l.append("notBlank")
+            if field.__class__.__name__=="URLField":
+                l.append("url")
+            validators[field.name] = l
+        return validators
+
+    def get_backend_register(self, k, default=None):
+        try:
+            return json.loads(self.backend_register).get(k, default)
+        except AttributeError:
+            return default
+
+    def set_backend_register(self, k, v):
+        br = {}
+        try:
+            br=json.loads(self.backend_register)
+        except AttributeError:
+            br={}
+
+        br[k] = v
+        self.backend_register = json.dumps(br)
+
+    def get_backend_details(self):
+        try:
+            scratchpad = json.loads(self.backend_register)
+        except AttributeError:
+            return (None, None, None, None)
+
+        try:
+            exponent = scratchpad['exponent']
+        except KeyError:
+            exponent = None
+
+        try:
+            last_success_time = scratchpad['last_success']
+            dt = datetime.datetime.fromtimestamp(last_success_time)
+            last_success = dt.strftime("%Y-%m-%d %H:%M")
+        except KeyError:
+            last_success = None
+
+        try:
+            failures = scratchpad['failures']
+        except KeyError:
+            failures=None
+
+        try:
+            last_failure_time = scratchpad['last_failure']
+            dt = datetime.datetime.fromtimestamp(last_failure_time)
+            last_failure = dt.strftime("%Y-%m-%d %H:%M")
+        except KeyError:
+            last_failure = None
+
+        return (exponent, last_success, last_failure, failures)
+
+    def get_backend_icon(self):
+        is_perfect = (self.backend_status is not None) and self.backend_status.startswith("1 -")
+        is_good = (self.backend_status is not None) and (self.backend_status.startswith("0 -") or self.backend_status.startswith("1 -"))
+        is_provisioning = self.backend_status is None or self.backend_status == "Provisioning in progress" or self.backend_status==""
+
+        # returns (icon_name, tooltip)
+        if (self.enacted is not None) and (self.enacted >= self.updated and is_good) or is_perfect:
+            return ("success", "successfully enacted")
+        else:
+            if is_good or is_provisioning:
+                return ("clock", "Pending sync, last_status = " + html_escape(self.backend_status, quote=True))
+            else:
+                return ("error", html_escape(self.backend_status, quote=True))
+
+    def enforce_choices(self, field, choices):
+        choices = [x[0] for x in choices]
+        for choice in choices:
+            if field==choice:
+                return
+            if (choice==None) and (field==""):
+                # allow "" and None to be equivalent
+                return
+        raise Exception("Field value %s is not in %s" % (field, str(choices)))
+
+class PlCoreBase(models.Model, PlModelMixIn):
+    objects = PlCoreBaseManager()
+    deleted_objects = PlCoreBaseDeletionManager()
+
+    # default values for created and updated are only there to keep evolution
+    # from failing.
+    created = models.DateTimeField(auto_now_add=True)
+    updated = models.DateTimeField(default=timezone.now)
+    enacted = models.DateTimeField(null=True, blank=True, default=None)
+    policed = models.DateTimeField(null=True, blank=True, default=None)
+
+    # This is a scratchpad used by the Observer
+    backend_register = models.CharField(max_length=1024,
+                                      default="{}", null=True)
+
+    backend_status = models.CharField(max_length=1024,
+                                      default="0 - Provisioning in progress")
+    deleted = models.BooleanField(default=False)
+    write_protect = models.BooleanField(default=False)
+    lazy_blocked = models.BooleanField(default=False)
+    no_sync = models.BooleanField(default=False)     # prevent object sync
+    no_policy = models.BooleanField(default=False)   # prevent model_policy run
+
+    class Meta:
+        # Changing abstract to False would require the managers of subclasses of
+        # PlCoreBase to be customized individually.
+        abstract = True
+        app_label = "core"
+
+    def __init__(self, *args, **kwargs):
+        super(PlCoreBase, self).__init__(*args, **kwargs)
+        self._initial = self._dict # for PlModelMixIn
+        self.silent = False
+
+    def get_controller(self):
+        return self.controller
+
+    def can_update(self, user):
+        return user.can_update_root()
+
+    def delete(self, *args, **kwds):
+        # so we have something to give the observer
+        purge = kwds.get('purge',False)
+        if purge:
+            del kwds['purge']
+        silent = kwds.get('silent',False)
+        if silent:
+            del kwds['silent']
+        try:
+            purge = purge or observer_disabled
+        except NameError:
+            pass
+
+        if (purge):
+            super(PlCoreBase, self).delete(*args, **kwds)
+        else:
+            if (not self.write_protect):
+                self.deleted = True
+                self.enacted=None
+                self.policed=None
+                self.save(update_fields=['enacted','deleted','policed'], silent=silent)
+
+
+    def save(self, *args, **kwargs):
+        # let the user specify silence as either a kwarg or an instance varible
+        silent = self.silent
+        if "silent" in kwargs:
+            silent=silent or kwargs.pop("silent")
+
+        # SMBAKER: if an object is trying to delete itself, or if the observer
+        # is updating an object's backend_* fields, then let it slip past the
+        # composite key check.
+        ignore_composite_key_check=False
+        if "update_fields" in kwargs:
+            ignore_composite_key_check=True
+            for field in kwargs["update_fields"]:
+                if not (field in ["backend_register", "backend_status", "deleted", "enacted", "updated"]):
+                    ignore_composite_key_check=False
+
+        if 'synchronizer' not in threading.current_thread().name:
+            self.updated = timezone.now()
+
+        super(PlCoreBase, self).save(*args, **kwargs)
+
+        # This is a no-op if observer_disabled is set
+        # if not silent:
+        #    notify_observer()
+
+        self._initial = self._dict
+
+    def save_by_user(self, user, *args, **kwds):
+        if not self.can_update(user):
+            if getattr(self, "_cant_update_fieldName", None) is not None:
+                raise PermissionDenied("You do not have permission to update field %s on object %s" % (self._cant_update_fieldName, self.__class__.__name__))
+            else:
+                raise PermissionDenied("You do not have permission to update %s objects" % self.__class__.__name__)
+
+        self.save(*args, **kwds)
+
+    def delete_by_user(self, user, *args, **kwds):
+        if not self.can_update(user):
+            raise PermissionDenied("You do not have permission to delete %s objects" % self.__class__.__name__)
+        self.delete(*args, **kwds)
+
+    @classmethod
+    def select_by_user(cls, user):
+        # This should be overridden by descendant classes that want to perform
+        # filtering of visible objects by user.
+        return cls.objects.all()
+
+    @classmethod
+    def is_ephemeral(cls):
+        return cls in ephemeral_models
+
+    def tologdict(self):
+        try:
+            d = {'model_name':self.__class__.__name__, 'pk': self.pk}
+        except:
+            d = {}
+
+        return d
diff --git a/xos/core/models/program.py b/xos/core/models/program.py
new file mode 100644
index 0000000..01e17fa
--- /dev/null
+++ b/xos/core/models/program.py
@@ -0,0 +1,42 @@
+from django.db import models
+from core.models import PlCoreBase,SingletonModel,PlCoreBaseManager,User
+from core.models.plcorebase import StrippedCharField
+from xos.exceptions import *
+from operator import attrgetter
+import json
+
+class Program(PlCoreBase):
+    KIND_CHOICES = (('tosca', 'Tosca'), )
+    COMMAND_CHOICES = (('run', 'Run'), ('destroy', 'Destroy'), )
+
+    name = StrippedCharField(max_length=30, help_text="Service Name")
+    description = models.TextField(max_length=254,null=True, blank=True,help_text="Description of Service")
+    kind = StrippedCharField(max_length=30, help_text="Kind of service", choices=KIND_CHOICES)
+    command = StrippedCharField(blank=True, null=True, max_length=30, help_text="Command to run", choices=COMMAND_CHOICES)
+
+    owner = models.ForeignKey(User, null=True, related_name="programs")
+
+    contents = models.TextField(blank=True, null=True, help_text="Contents of Program")
+    output = models.TextField(blank=True, null=True, help_text="Output of Program")
+    messages = models.TextField(blank=True, null=True, help_text="Debug messages")
+    status = models.TextField(blank=True, null=True, max_length=30, help_text="Status of program")
+
+    @classmethod
+    def select_by_user(cls, user):
+        return cls.objects.all()
+
+    def __unicode__(self): return u'%s' % (self.name)
+
+    def can_update(self, user):
+        return True
+
+    def save(self, *args, **kwargs):
+        # set creator on first save
+        if not self.owner and hasattr(self, 'caller'):
+            self.owner = self.caller
+
+        if (self.command in ["run", "destroy"]) and (self.status in ["complete", "exception"]):
+            self.status = "queued"
+
+        super(Program, self).save(*args, **kwargs)
+
diff --git a/xos/core/models/project.py b/xos/core/models/project.py
new file mode 100644
index 0000000..9cc2927
--- /dev/null
+++ b/xos/core/models/project.py
@@ -0,0 +1,12 @@
+import os
+from django.db import models
+from core.models import PlCoreBase
+from core.models.plcorebase import StrippedCharField
+
+# Create your models here.
+
+class Project(PlCoreBase):
+    name = StrippedCharField(max_length=200, unique=True, help_text="Name of Project")
+
+    def __unicode__(self):  return u'%s' % (self.name)
+
diff --git a/xos/core/models/reservation.py b/xos/core/models/reservation.py
new file mode 100644
index 0000000..ecf207c
--- /dev/null
+++ b/xos/core/models/reservation.py
@@ -0,0 +1,57 @@
+import os
+import datetime
+from django.db import models
+from core.models import PlCoreBase
+from core.models import Instance
+from core.models import Slice
+from core.models import ServiceResource
+
+# Create your models here.
+
+class Reservation(PlCoreBase):
+    startTime = models.DateTimeField()
+    slice = models.ForeignKey(Slice, related_name="reservations")
+    duration = models.IntegerField(default=1)
+
+    def __unicode__(self):  return u'%s to %s' % (self.startTime, self.endTime)
+
+    @property
+    def endTime(self):
+        return self.startTime + datetime.timedelta(hours=self.duration)
+
+    def can_update(self, user):
+        return user.can_update_slice(self.slice)
+
+    @staticmethod
+    def select_by_user(user):
+        if user.is_admin:
+            qs = Reservation.objects.all()
+        else:
+            slice_ids = [s.id for s in Slice.select_by_user(user)]
+            qs = Reservation.objects.filter(id__in=slice_ids)
+        return qs
+
+class ReservedResource(PlCoreBase):
+    instance = models.ForeignKey(Instance, related_name="reservedresources")
+    resource = models.ForeignKey(ServiceResource, related_name="reservedresources")
+    quantity = models.IntegerField(default=1)
+    reservationSet = models.ForeignKey(Reservation, related_name="reservedresources")
+
+    class Meta(PlCoreBase.Meta):
+       verbose_name_plural = "Reserved Resources"
+
+    def __unicode__(self):  return u'%d %s on %s' % (self.quantity, self.resource, self.instance)
+
+    def can_update(self, user):
+        return user.can_update(self.instance.slice)
+
+    @staticmethod
+    def select_by_user(user):
+        if user.is_admin:
+            qs = ReservedResource.objects.all()
+        else:
+            instance_ids = [s.id for s in Instance.select_by_user(user)]
+            qs = ReservedResource.objects.filter(id__in=instance_ids)
+        return qs
+
+
diff --git a/xos/core/models/role.py b/xos/core/models/role.py
new file mode 100644
index 0000000..353139e
--- /dev/null
+++ b/xos/core/models/role.py
@@ -0,0 +1,24 @@
+import os
+import datetime
+from django.db import models
+from django.contrib.contenttypes.models import ContentType
+from django.contrib.contenttypes import generic
+from core.models import PlCoreBase
+from core.models.plcorebase import StrippedCharField
+
+class Role(PlCoreBase):
+
+    role_type = StrippedCharField(max_length=80, verbose_name="Name")
+    role = StrippedCharField(max_length=80, verbose_name="Keystone role id", null=True, blank=True)
+    description = StrippedCharField(max_length=120, verbose_name="Description")
+    content_type = models.ForeignKey(ContentType, verbose_name="Role Scope")
+
+    def __unicode__(self):  return u'%s:%s' % (self.content_type,self.role_type)
+
+
+    def save(self, *args, **kwds):
+        super(Role, self).save(*args, **kwds)
+    
+    def delete(self, *args, **kwds):
+        super(Role, self).delete(*args, **kwds)
+            
diff --git a/xos/core/models/service.py b/xos/core/models/service.py
new file mode 100644
index 0000000..83b827c
--- /dev/null
+++ b/xos/core/models/service.py
@@ -0,0 +1,988 @@
+import json
+from operator import attrgetter
+
+from core.models import PlCoreBase, PlCoreBaseManager, SingletonModel, XOS
+from core.models.plcorebase import StrippedCharField
+from django.db import models
+from xos.exceptions import *
+import urlparse
+
+COARSE_KIND = "coarse"
+
+def get_xos():
+    xos = XOS.objects.all()
+
+    if xos:
+       return xos[0]
+    else:
+       return None
+

+
+class AttributeMixin(object):
+    # helper for extracting things from a json-encoded
+    # service_specific_attribute
+
+    def get_attribute(self, name, default=None):
+        if self.service_specific_attribute:
+            attributes = json.loads(self.service_specific_attribute)
+        else:
+            attributes = {}
+        return attributes.get(name, default)
+
+    def set_attribute(self, name, value):
+        if self.service_specific_attribute:
+            attributes = json.loads(self.service_specific_attribute)
+        else:
+            attributes = {}
+        attributes[name] = value
+        self.service_specific_attribute = json.dumps(attributes)
+
+    def get_initial_attribute(self, name, default=None):
+        if self._initial["service_specific_attribute"]:
+            attributes = json.loads(
+                self._initial["service_specific_attribute"])
+        else:
+            attributes = {}
+        return attributes.get(name, default)
+
+    @classmethod
+    def get_default_attribute(cls, name):
+        for (attrname, default) in cls.simple_attributes:
+            if attrname == name:
+                return default
+        if hasattr(cls, "default_attributes"):
+            if name in cls.default_attributes:
+                return cls.default_attributes[name]
+
+        return None
+
+    @classmethod
+    def setup_simple_attributes(cls):
+        for (attrname, default) in cls.simple_attributes:
+            setattr(cls, attrname, property(lambda self, attrname=attrname, default=default: self.get_attribute(attrname, default),
+                                            lambda self, value, attrname=attrname: self.set_attribute(
+                                                attrname, value),
+                                            None,
+                                            attrname))
+
+class ServiceController(PlCoreBase):
+    xos = models.ForeignKey(XOS, related_name='service_controllers', help_text="Pointer to XOS", default=get_xos)
+    name = StrippedCharField(max_length=30, help_text="Service Name")
+    base_url = StrippedCharField(max_length=1024, help_text="Base URL, allows use of relative URLs for resources", null=True, blank=True)
+
+    synchronizer_run = StrippedCharField(max_length=1024, help_text="synchronizer run command", null=True, blank=True)
+    synchronizer_config = StrippedCharField(max_length=1024, help_text="synchronizer config file", null=True, blank=True)
+
+    def __unicode__(self): return u'%s' % (self.name)
+
+    def save(self, *args, **kwargs):
+       super(ServiceController, self).save(*args, **kwargs)
+
+       if self.xos:
+           # force XOS to rebuild
+           # XXX somewhat hackish XXX
+           self.xos.save(update_fields=["updated"])
+
+class ServiceControllerResource(PlCoreBase):
+    KIND_CHOICES = (('models', 'Models'),
+                    ('admin', 'Admin'),
+                    ('admin_template', 'Admin Template'),
+                    ('django_library', 'Django Library'),
+                    ('synchronizer', 'Synchronizer'),
+                    ('rest_service', 'REST API (service)'),
+                    ('rest_tenant', 'REST API (tenant)'),
+                    ('tosca_custom_types', 'Tosca Custom Types'),
+                    ('tosca_resource', 'Tosca Resource'),
+                    ('private_key', 'Private Key'),
+                    ('public_key', 'Public Key'))
+
+    FORMAT_CHOICES = (('python', 'Python'),
+                      ('manifest', 'Manifest'),
+                      ('docker', 'Docker Container'),
+                      ('yaml', 'YAML'),
+                      ('raw', 'raw'))
+
+    service_controller = models.ForeignKey(ServiceController, related_name='service_controller_resources',
+                                help_text="The Service Controller this resource is associated with")
+
+    name = StrippedCharField(max_length=30, help_text="Object Name")
+    subdirectory = StrippedCharField(max_length=1024, help_text="optional subdirectory", null=True, blank=True)
+    kind = StrippedCharField(choices=KIND_CHOICES, max_length=30)
+    format = StrippedCharField(choices=FORMAT_CHOICES, max_length=30)
+    url = StrippedCharField(max_length=1024, help_text="URL of resource", null=True, blank=True)
+
+    def __unicode__(self): return u'%s' % (self.name)
+
+    @property
+    def full_url(self):
+        if self.service_controller and self.service_controller.base_url:
+            return urlparse.urljoin(self.service_controller.base_url, self.url)
+        else:
+            return self.url
+
+class Service(PlCoreBase, AttributeMixin):
+    # when subclassing a service, redefine KIND to describe the new service
+    KIND = "generic"
+
+    description = models.TextField(
+        max_length=254, null=True, blank=True, help_text="Description of Service")
+    enabled = models.BooleanField(default=True)
+    kind = StrippedCharField(
+        max_length=30, help_text="Kind of service", default=KIND)
+    name = StrippedCharField(max_length=30, help_text="Service Name")
+    versionNumber = StrippedCharField(blank=True, null=True,
+        max_length=30, help_text="Version of Service Definition")
+    published = models.BooleanField(default=True)
+    view_url = StrippedCharField(blank=True, null=True, max_length=1024)
+    icon_url = StrippedCharField(blank=True, null=True, max_length=1024)
+    public_key = models.TextField(
+        null=True, blank=True, max_length=1024, help_text="Public key string")
+    private_key_fn = StrippedCharField(blank=True, null=True, max_length=1024)
+
+    # Service_specific_attribute and service_specific_id are opaque to XOS
+    service_specific_id = StrippedCharField(
+        max_length=30, blank=True, null=True)
+    service_specific_attribute = models.TextField(blank=True, null=True)
+
+    controller = models.ForeignKey(ServiceController, related_name='services',
+                                help_text="The Service Controller this Service uses",
+                                null=True, blank=True)
+
+    def __init__(self, *args, **kwargs):
+        # for subclasses, set the default kind appropriately
+        self._meta.get_field("kind").default = self.KIND
+        super(Service, self).__init__(*args, **kwargs)
+
+    @classmethod
+    def get_service_objects(cls):
+        return cls.objects.filter(kind=cls.KIND)
+
+    @classmethod
+    def get_deleted_service_objects(cls):
+        return cls.deleted_objects.filter(kind=cls.KIND)
+
+    @classmethod
+    def get_service_objects_by_user(cls, user):
+        return cls.select_by_user(user).filter(kind=cls.KIND)
+
+    @classmethod
+    def select_by_user(cls, user):
+        if user.is_admin:
+            return cls.objects.all()
+        else:
+            service_ids = [
+                sp.slice.id for sp in ServicePrivilege.objects.filter(user=user)]
+            return cls.objects.filter(id__in=service_ids)
+
+    @property
+    def serviceattribute_dict(self):
+        attrs = {}
+        for attr in self.serviceattributes.all():
+            attrs[attr.name] = attr.value
+        return attrs
+
+    def __unicode__(self): return u'%s' % (self.name)
+
+    def can_update(self, user):
+        return user.can_update_service(self, allow=['admin'])
+
+    def get_scalable_nodes(self, slice, max_per_node=None, exclusive_slices=[]):
+        """
+             Get a list of nodes that can be used to scale up a slice.
+
+                slice - slice to scale up
+                max_per_node - maximum numbers of instances that 'slice' can have on a single node
+                exclusive_slices - list of slices that must have no nodes in common with 'slice'.
+        """
+
+        # late import to get around order-of-imports constraint in __init__.py
+        from core.models import Node, Instance
+
+        nodes = list(Node.objects.all())
+
+        conflicting_instances = Instance.objects.filter(
+            slice__in=exclusive_slices)
+        conflicting_nodes = Node.objects.filter(
+            instances__in=conflicting_instances)
+
+        nodes = [x for x in nodes if x not in conflicting_nodes]
+
+        # If max_per_node is set, then limit the number of instances this slice
+        # can have on a single node.
+        if max_per_node:
+            acceptable_nodes = []
+            for node in nodes:
+                existing_count = node.instances.filter(slice=slice).count()
+                if existing_count < max_per_node:
+                    acceptable_nodes.append(node)
+            nodes = acceptable_nodes
+
+        return nodes
+
+    def pick_node(self, slice, max_per_node=None, exclusive_slices=[]):
+        # Pick the best node to scale up a slice.
+
+        nodes = self.get_scalable_nodes(slice, max_per_node, exclusive_slices)
+        nodes = sorted(nodes, key=lambda node: node.instances.all().count())
+        if not nodes:
+            return None
+        return nodes[0]
+
+    def adjust_scale(self, slice_hint, scale, max_per_node=None, exclusive_slices=[]):
+        # late import to get around order-of-imports constraint in __init__.py
+        from core.models import Instance
+
+        slices = [x for x in self.slices.all() if slice_hint in x.name]
+        for slice in slices:
+            while slice.instances.all().count() > scale:
+                s = slice.instances.all()[0]
+                # print "drop instance", s
+                s.delete()
+
+            while slice.instances.all().count() < scale:
+                node = self.pick_node(slice, max_per_node, exclusive_slices)
+                if not node:
+                    # no more available nodes
+                    break
+
+                image = slice.default_image
+                if not image:
+                    raise XOSConfigurationError(
+                        "No default_image for slice %s" % slice.name)
+
+                flavor = slice.default_flavor
+                if not flavor:
+                    raise XOSConfigurationError(
+                        "No default_flavor for slice %s" % slice.name)
+
+                s = Instance(slice=slice,
+                             node=node,
+                             creator=slice.creator,
+                             image=image,
+                             flavor=flavor,
+                             deployment=node.site_deployment.deployment)
+                s.save()
+
+                # print "add instance", s
+
+    def get_vtn_src_nets(self):
+        nets = []
+        for slice in self.slices.all():
+            for ns in slice.networkslices.all():
+                if not ns.network:
+                    continue
+#                if ns.network.template.access in ["direct", "indirect"]:
+#                    # skip access networks; we want to use the private network
+#                    continue
+                if "management" in ns.network.name:
+                    # don't try to connect the management network to anything
+                    continue
+                if ns.network.name in ["wan_network", "lan_network"]:
+                    # we don't want to attach to the vCPE's lan or wan network
+                    # we only want to attach to its private network
+                    # TODO: fix hard-coding of network name
+                    continue
+                for cn in ns.network.controllernetworks.all():
+                    if cn.net_id:
+                        net = {"name": ns.network.name, "net_id": cn.net_id}
+                        nets.append(net)
+        return nets
+
+    def get_vtn_nets(self):
+        nets = []
+        for slice in self.slices.all():
+            for ns in slice.networkslices.all():
+                if not ns.network:
+                    continue
+                if ns.network.template.access not in ["direct", "indirect"]:
+                    # skip anything that's not an access network
+                    continue
+                for cn in ns.network.controllernetworks.all():
+                    if cn.net_id:
+                        net = {"name": ns.network.name, "net_id": cn.net_id}
+                        nets.append(net)
+        return nets
+
+    def get_vtn_dependencies_nets(self):
+        provider_nets = []
+        for tenant in self.subscribed_tenants.all():
+            if tenant.provider_service:
+                for net in tenant.provider_service.get_vtn_nets():
+                    if not net in provider_nets:
+                        provider_nets.append(net)
+        return provider_nets
+
+    def get_vtn_dependencies_ids(self):
+        return [x["net_id"] for x in self.get_vtn_dependencies_nets()]
+
+    def get_vtn_dependencies_names(self):
+        return [x["name"] + "_" + x["net_id"] for x in self.get_vtn_dependencies_nets()]
+
+    def get_vtn_src_ids(self):
+        return [x["net_id"] for x in self.get_vtn_src_nets()]
+
+    def get_vtn_src_names(self):
+        return [x["name"] + "_" + x["net_id"] for x in self.get_vtn_src_nets()]
+
+
+class ServiceAttribute(PlCoreBase):
+    name = models.CharField(help_text="Attribute Name", max_length=128)
+    value = StrippedCharField(help_text="Attribute Value", max_length=1024)
+    service = models.ForeignKey(Service, related_name='serviceattributes',
+                                help_text="The Service this attribute is associated with")
+
+
+class ServiceRole(PlCoreBase):
+    ROLE_CHOICES = (('admin', 'Admin'),)
+    role = StrippedCharField(choices=ROLE_CHOICES, unique=True, max_length=30)
+
+    def __unicode__(self): return u'%s' % (self.role)
+
+
+class ServicePrivilege(PlCoreBase):
+    user = models.ForeignKey('User', related_name='serviceprivileges')
+    service = models.ForeignKey('Service', related_name='serviceprivileges')
+    role = models.ForeignKey('ServiceRole', related_name='serviceprivileges')
+
+    class Meta:
+        unique_together = ('user', 'service', 'role')
+
+    def __unicode__(self): return u'%s %s %s' % (
+        self.service, self.user, self.role)
+
+    def can_update(self, user):
+        if not self.service.enabled:
+            raise PermissionDenied, "Cannot modify permission(s) of a disabled service"
+        return self.service.can_update(user)
+
+    def save(self, *args, **kwds):
+        if not self.service.enabled:
+            raise PermissionDenied, "Cannot modify permission(s) of a disabled service"
+        super(ServicePrivilege, self).save(*args, **kwds)
+
+    def delete(self, *args, **kwds):
+        if not self.service.enabled:
+            raise PermissionDenied, "Cannot modify permission(s) of a disabled service"
+        super(ServicePrivilege, self).delete(*args, **kwds)
+
+    @classmethod
+    def select_by_user(cls, user):
+        if user.is_admin:
+            qs = cls.objects.all()
+        else:
+            qs = cls.objects.filter(user=user)
+        return qs
+
+
+class TenantRoot(PlCoreBase, AttributeMixin):
+    """ A tenantRoot is one of the things that can sit at the root of a chain
+        of tenancy. This object represents a node.
+    """
+
+    KIND = "generic"
+    kind = StrippedCharField(max_length=30, default=KIND)
+    name = StrippedCharField(
+        max_length=255, help_text="name", blank=True, null=True)
+
+    service_specific_attribute = models.TextField(blank=True, null=True)
+    service_specific_id = StrippedCharField(
+        max_length=30, blank=True, null=True)
+
+    def __init__(self, *args, **kwargs):
+        # for subclasses, set the default kind appropriately
+        self._meta.get_field("kind").default = self.KIND
+        super(TenantRoot, self).__init__(*args, **kwargs)
+
+    def __unicode__(self):
+        if not self.name:
+            return u"%s-tenant_root-#%s" % (str(self.kind), str(self.id))
+        else:
+            return self.name
+
+    def can_update(self, user):
+        return user.can_update_tenant_root(self, allow=['admin'])
+
+    def get_subscribed_tenants(self, tenant_class):
+        ids = self.subscribed_tenants.filter(kind=tenant_class.KIND)
+        return tenant_class.objects.filter(id__in=ids)
+
+    def get_newest_subscribed_tenant(self, kind):
+        st = list(self.get_subscribed_tenants(kind))
+        if not st:
+            return None
+        return sorted(st, key=attrgetter('id'))[0]
+
+    @classmethod
+    def get_tenant_objects(cls):
+        return cls.objects.filter(kind=cls.KIND)
+
+    @classmethod
+    def get_tenant_objects_by_user(cls, user):
+        return cls.select_by_user(user).filter(kind=cls.KIND)
+
+    @classmethod
+    def select_by_user(cls, user):
+        if user.is_admin:
+            return cls.objects.all()
+        else:
+            tr_ids = [
+                trp.tenant_root.id for trp in TenantRootPrivilege.objects.filter(user=user)]
+            return cls.objects.filter(id__in=tr_ids)
+
+    # helper function to be used in subclasses that want to ensure
+    # service_specific_id is unique
+    def validate_unique_service_specific_id(self, none_okay=False):
+        if not none_okay and (self.service_specific_id is None):
+            raise XOSMissingField("subscriber_specific_id is None, and it's a required field", fields={
+                                  "service_specific_id": "cannot be none"})
+
+        if self.service_specific_id:
+            conflicts = self.get_tenant_objects().filter(
+                service_specific_id=self.service_specific_id)
+            if self.pk:
+                conflicts = conflicts.exclude(pk=self.pk)
+            if conflicts:
+                raise XOSDuplicateKey("service_specific_id %s already exists" % self.service_specific_id, fields={
+                                      "service_specific_id": "duplicate key"})
+
+
+class Tenant(PlCoreBase, AttributeMixin):
+    """ A tenant is a relationship between two entities, a subscriber and a
+        provider. This object represents an edge.
+
+        The subscriber can be a User, a Service, or a Tenant.
+
+        The provider is always a Service.
+
+        TODO: rename "Tenant" to "Tenancy"
+    """
+
+    CONNECTIVITY_CHOICES = (('public', 'Public'),
+                            ('private', 'Private'), ('na', 'Not Applicable'))
+
+    # when subclassing a service, redefine KIND to describe the new service
+    KIND = "generic"
+
+    kind = StrippedCharField(max_length=30, default=KIND)
+    provider_service = models.ForeignKey(
+        Service, related_name='provided_tenants')
+
+    # The next four things are the various type of objects that can be subscribers of this Tenancy
+    # relationship. One and only one can be used at a time.
+    # XXX these should really be changed to GenericForeignKey
+    subscriber_service = models.ForeignKey(
+        Service, related_name='subscribed_tenants', blank=True, null=True)
+    subscriber_tenant = models.ForeignKey(
+        "Tenant", related_name='subscribed_tenants', blank=True, null=True)
+    subscriber_user = models.ForeignKey(
+        "User", related_name='subscribed_tenants', blank=True, null=True)
+    subscriber_root = models.ForeignKey(
+        "TenantRoot", related_name="subscribed_tenants", blank=True, null=True)
+    subscriber_network = models.ForeignKey(
+        "Network", related_name="subscribed_tenants", blank=True, null=True)
+
+    # Service_specific_attribute and service_specific_id are opaque to XOS
+    service_specific_id = StrippedCharField(
+        max_length=30, blank=True, null=True)
+    service_specific_attribute = models.TextField(blank=True, null=True)
+
+    # Connect_method is only used by Coarse tenants
+    connect_method = models.CharField(
+        null=False, blank=False, max_length=30, choices=CONNECTIVITY_CHOICES, default="na")
+
+    def __init__(self, *args, **kwargs):
+        # for subclasses, set the default kind appropriately
+        self._meta.get_field("kind").default = self.KIND
+        super(Tenant, self).__init__(*args, **kwargs)
+
+    def __unicode__(self):
+        return u"%s-tenant-%s" % (str(self.kind), str(self.id))
+
+    @classmethod
+    def get_tenant_objects(cls):
+        return cls.objects.filter(kind=cls.KIND)
+
+    @classmethod
+    def get_tenant_objects_by_user(cls, user):
+        return cls.select_by_user(user).filter(kind=cls.KIND)
+
+    @classmethod
+    def get_deleted_tenant_objects(cls):
+        return cls.deleted_objects.filter(kind=cls.KIND)
+
+    @property
+    def tenantattribute_dict(self):
+        attrs = {}
+        for attr in self.tenantattributes.all():
+            attrs[attr.name] = attr.value
+        return attrs
+
+    # helper function to be used in subclasses that want to ensure
+    # service_specific_id is unique
+    def validate_unique_service_specific_id(self):
+        if self.pk is None:
+            if self.service_specific_id is None:
+                raise XOSMissingField("subscriber_specific_id is None, and it's a required field", fields={
+                                      "service_specific_id": "cannot be none"})
+
+            conflicts = self.get_tenant_objects().filter(
+                service_specific_id=self.service_specific_id)
+            if conflicts:
+                raise XOSDuplicateKey("service_specific_id %s already exists" % self.service_specific_id, fields={
+                                      "service_specific_id": "duplicate key"})
+
+    def save(self, *args, **kwargs):
+        subCount = sum([1 for e in [self.subscriber_service, self.subscriber_tenant,
+                                    self.subscriber_user, self.subscriber_root] if e is not None])
+        if (subCount > 1):
+            raise XOSConflictingField(
+                "Only one of subscriber_service, subscriber_tenant, subscriber_user, subscriber_root should be set")
+
+        super(Tenant, self).save(*args, **kwargs)
+
+    def get_subscribed_tenants(self, tenant_class):
+        ids = self.subscribed_tenants.filter(kind=tenant_class.KIND)
+        return tenant_class.objects.filter(id__in=ids)
+
+    def get_newest_subscribed_tenant(self, kind):
+        st = list(self.get_subscribed_tenants(kind))
+        if not st:
+            return None
+        return sorted(st, key=attrgetter('id'))[0]
+
+
+class Scheduler(object):
+    # XOS Scheduler Abstract Base Class
+    # Used to implement schedulers that pick which node to put instances on
+
+    def __init__(self, slice):
+        self.slice = slice
+
+    def pick(self):
+        # this method should return a tuple (node, parent)
+        #    node is the node to instantiate on
+        #    parent is for container_vm instances only, and is the VM that will
+        #      hold the container
+
+        raise Exception("Abstract Base")
+
+
+class LeastLoadedNodeScheduler(Scheduler):
+    # This scheduler always return the node with the fewest number of
+    # instances.
+
+    def __init__(self, slice, label=None):
+        super(LeastLoadedNodeScheduler, self).__init__(slice)
+        self.label = label
+
+    def pick(self):
+        from core.models import Node
+        if not self.slice.default_node:
+            nodes = list(Node.objects.all())
+            nodes = sorted(nodes, key=lambda node: node.instances.all().count())
+        else:
+            nodes = list(Node.objects.filter(name = self.slice.default_node))
+
+        if self.label:
+            nodes = nodes.filter(nodelabels__name=self.label)
+
+        nodes = list(nodes)
+
+        if not nodes:
+            raise Exception(
+                "LeastLoadedNodeScheduler: No suitable nodes to pick from")
+
+        # TODO: logic to filter nodes by which nodes are up, and which
+        #   nodes the slice can instantiate on.
+#        nodes = sorted(nodes, key=lambda node: node.instances.all().count())
+        return [nodes[0], None]
+
+
+class ContainerVmScheduler(Scheduler):
+    # This scheduler picks a VM in the slice with the fewest containers inside
+    # of it. If no VMs are suitable, then it creates a VM.
+
+    MAX_VM_PER_CONTAINER = 10
+
+    def __init__(self, slice):
+        super(ContainerVmScheduler, self).__init__(slice)
+
+    @property
+    def image(self):
+        from core.models import Image
+
+        # If slice has default_image set then use it
+        if self.slice.default_image:
+            return self.slice.default_image
+
+        raise XOSProgrammingError("Please set a default image for %s" % self.slice.name)
+
+    def make_new_instance(self):
+        from core.models import Instance, Flavor
+
+        flavors = Flavor.objects.filter(name="m1.small")
+        if not flavors:
+            raise XOSConfigurationError("No m1.small flavor")
+
+        (node, parent) = LeastLoadedNodeScheduler(self.slice).pick()
+
+        instance = Instance(slice=self.slice,
+                            node=node,
+                            image=self.image,
+                            creator=self.slice.creator,
+                            deployment=node.site_deployment.deployment,
+                            flavor=flavors[0],
+                            isolation="vm",
+                            parent=parent)
+        instance.save()
+        # We rely on a special naming convention to identify the VMs that will
+        # hole containers.
+        instance.name = "%s-outer-%s" % (instance.slice.name, instance.id)
+        instance.save()
+        return instance
+
+    def pick(self):
+        from core.models import Instance, Flavor
+
+        for vm in self.slice.instances.filter(isolation="vm"):
+            avail_vms = []
+            if (vm.name.startswith("%s-outer-" % self.slice.name)):
+                container_count = Instance.objects.filter(parent=vm).count()
+                if (container_count < self.MAX_VM_PER_CONTAINER):
+                    avail_vms.append((vm, container_count))
+            # sort by least containers-per-vm
+            avail_vms = sorted(avail_vms, key=lambda x: x[1])
+            print "XXX", avail_vms
+            if avail_vms:
+                instance = avail_vms[0][0]
+                return (instance.node, instance)
+
+        instance = self.make_new_instance()
+        return (instance.node, instance)
+
+
+class TenantWithContainer(Tenant):
+    """ A tenant that manages a container """
+
+    class Meta:
+        proxy = True
+
+    def __init__(self, *args, **kwargs):
+        super(TenantWithContainer, self).__init__(*args, **kwargs)
+        self.cached_instance = None
+        self.orig_instance_id = self.get_initial_attribute("instance_id")
+
+    @property
+    def instance(self):
+        from core.models import Instance
+        if getattr(self, "cached_instance", None):
+            return self.cached_instance
+        instance_id = self.get_attribute("instance_id")
+        if not instance_id:
+            return None
+        instances = Instance.objects.filter(id=instance_id)
+        if not instances:
+            return None
+        instance = instances[0]
+        instance.caller = self.creator
+        self.cached_instance = instance
+        return instance
+
+    @instance.setter
+    def instance(self, value):
+        if value:
+            value = value.id
+        if (value != self.get_attribute("instance_id", None)):
+            self.cached_instance = None
+        self.set_attribute("instance_id", value)
+
+    @property
+    def external_hostname(self):
+        return self.get_attribute("external_hostname", "")
+
+    @external_hostname.setter
+    def external_hostname(self, value):
+        self.set_attribute("external_hostname", value)
+
+    @property
+    def external_container(self):
+        return self.get_attribute("external_container", "")
+
+    @external_container.setter
+    def external_container(self, value):
+        self.set_attribute("external_container", value)
+
+    @property
+    def creator(self):
+        from core.models import User
+        if getattr(self, "cached_creator", None):
+            return self.cached_creator
+        creator_id = self.get_attribute("creator_id")
+        if not creator_id:
+            return None
+        users = User.objects.filter(id=creator_id)
+        if not users:
+            return None
+        user = users[0]
+        self.cached_creator = users[0]
+        return user
+
+    @creator.setter
+    def creator(self, value):
+        if value:
+            value = value.id
+        if (value != self.get_attribute("creator_id", None)):
+            self.cached_creator = None
+        self.set_attribute("creator_id", value)
+
+    @property
+    def image(self):
+        from core.models import Image
+        # Implement the logic here to pick the image that should be used when
+        # instantiating the VM that will hold the container.
+
+        slice = self.provider_service.slices.all()
+        if not slice:
+            raise XOSProgrammingError("provider service has no slice")
+        slice = slice[0]
+
+        # If slice has default_image set then use it
+        if slice.default_image:
+            return slice.default_image
+
+        raise XOSProgrammingError("Please set a default image for %s" % self.slice.name)
+
+    def save_instance(self, instance):
+        # Override this function to do custom pre-save or post-save processing,
+        # such as creating ports for containers.
+        instance.save()
+
+    def pick_least_loaded_instance_in_slice(self, slices):
+        for slice in slices:
+            if slice.instances.all().count() > 0:
+                for instance in slice.instances.all():
+                    # Pick the first instance that has lesser than 5 tenants
+                    if self.count_of_tenants_of_an_instance(instance) < 5:
+                        return instance
+        return None
+
+    # TODO: Ideally the tenant count for an instance should be maintained using a
+    # many-to-one relationship attribute, however this model being proxy, it does
+    # not permit any new attributes to be defined. Find if any better solutions
+    def count_of_tenants_of_an_instance(self, instance):
+        tenant_count = 0
+        for tenant in self.get_tenant_objects().all():
+            if tenant.get_attribute("instance_id", None) == instance.id:
+                tenant_count += 1
+        return tenant_count
+
+    def manage_container(self):
+        from core.models import Instance, Flavor
+
+        if self.deleted:
+            return
+
+        if (self.instance is not None) and (self.instance.image != self.image):
+            self.instance.delete()
+            self.instance = None
+
+        if self.instance is None:
+            if not self.provider_service.slices.count():
+                raise XOSConfigurationError("The service has no slices")
+
+            new_instance_created = False
+            instance = None
+            if self.get_attribute("use_same_instance_for_multiple_tenants", default=False):
+                # Find if any existing instances can be used for this tenant
+                slices = self.provider_service.slices.all()
+                instance = self.pick_least_loaded_instance_in_slice(slices)
+
+            if not instance:
+                slice = self.provider_service.slices.all()[0]
+
+                flavor = slice.default_flavor
+                if not flavor:
+                    flavors = Flavor.objects.filter(name="m1.small")
+                    if not flavors:
+                        raise XOSConfigurationError("No m1.small flavor")
+                    flavor = flavors[0]
+
+                if slice.default_isolation == "container_vm":
+                    (node, parent) = ContainerVmScheduler(slice).pick()
+                else:
+                    (node, parent) = LeastLoadedNodeScheduler(slice).pick()
+
+                instance = Instance(slice=slice,
+                                    node=node,
+                                    image=self.image,
+                                    creator=self.creator,
+                                    deployment=node.site_deployment.deployment,
+                                    flavor=flavor,
+                                    isolation=slice.default_isolation,
+                                    parent=parent)
+                self.save_instance(instance)
+                new_instance_created = True
+
+            try:
+                self.instance = instance
+                super(TenantWithContainer, self).save()
+            except:
+                if new_instance_created:
+                    instance.delete()
+                raise
+
+    def cleanup_container(self):
+        if self.instance:
+            if self.get_attribute("use_same_instance_for_multiple_tenants", default=False):
+                # Delete the instance only if this is last tenant in that
+                # instance
+                tenant_count = self.count_of_tenants_of_an_instance(
+                    self.instance)
+                if tenant_count == 0:
+                    self.instance.delete()
+            else:
+                self.instance.delete()
+            self.instance = None
+
+    def save(self, *args, **kwargs):
+        if (not self.creator) and (hasattr(self, "caller")) and (self.caller):
+            self.creator = self.caller
+        super(TenantWithContainer, self).save(*args, **kwargs)
+
+
+class CoarseTenant(Tenant):
+    """ TODO: rename "CoarseTenant" --> "StaticTenant" """
+    class Meta:
+        proxy = True
+
+    KIND = COARSE_KIND
+
+    def save(self, *args, **kwargs):
+        if (not self.subscriber_service):
+            raise XOSValidationError("subscriber_service cannot be null")
+        if (self.subscriber_tenant or self.subscriber_user):
+            raise XOSValidationError(
+                "subscriber_tenant and subscriber_user must be null")
+
+        super(CoarseTenant, self).save()
+
+
+class Subscriber(TenantRoot):
+    """ Intermediate class for TenantRoots that are to be Subscribers """
+
+    class Meta:
+        proxy = True
+
+    KIND = "Subscriber"
+
+
+class Provider(TenantRoot):
+    """ Intermediate class for TenantRoots that are to be Providers """
+
+    class Meta:
+        proxy = True
+
+    KIND = "Provider"
+
+
+class TenantAttribute(PlCoreBase):
+    name = models.CharField(help_text="Attribute Name", max_length=128)
+    value = models.TextField(help_text="Attribute Value")
+    tenant = models.ForeignKey(Tenant, related_name='tenantattributes',
+                               help_text="The Tenant this attribute is associated with")
+
+    def __unicode__(self): return u'%s-%s' % (self.name, self.id)
+
+
+class TenantRootRole(PlCoreBase):
+    ROLE_CHOICES = (('admin', 'Admin'), ('access', 'Access'))
+
+    role = StrippedCharField(choices=ROLE_CHOICES, unique=True, max_length=30)
+
+    def __unicode__(self): return u'%s' % (self.role)
+
+
+class TenantRootPrivilege(PlCoreBase):
+    user = models.ForeignKey('User', related_name="tenant_root_privileges")
+    tenant_root = models.ForeignKey(
+        'TenantRoot', related_name="tenant_root_privileges")
+    role = models.ForeignKey(
+        'TenantRootRole', related_name="tenant_root_privileges")
+
+    class Meta:
+        unique_together = ('user', 'tenant_root', 'role')
+
+    def __unicode__(self): return u'%s %s %s' % (
+        self.tenant_root, self.user, self.role)
+
+    def save(self, *args, **kwds):
+        if not self.user.is_active:
+            raise PermissionDenied, "Cannot modify role(s) of a disabled user"
+        super(TenantRootPrivilege, self).save(*args, **kwds)
+
+    def can_update(self, user):
+        return user.can_update_tenant_root_privilege(self)
+
+    @classmethod
+    def select_by_user(cls, user):
+        if user.is_admin:
+            return cls.objects.all()
+        else:
+            # User can see his own privilege
+            trp_ids = [trp.id for trp in cls.objects.filter(user=user)]
+
+            # A slice admin can see the SlicePrivileges for his Slice
+            for priv in cls.objects.filter(user=user, role__role="admin"):
+                trp_ids.extend(
+                    [trp.id for trp in cls.objects.filter(tenant_root=priv.tenant_root)])
+
+            return cls.objects.filter(id__in=trp_ids)
+
+
+class TenantRole(PlCoreBase):
+    """A TenantRole option."""
+    ROLE_CHOICES = (('admin', 'Admin'), ('access', 'Access'))
+    role = StrippedCharField(choices=ROLE_CHOICES, unique=True, max_length=30)
+
+    def __unicode__(self): return u'%s' % (self.role)
+
+
+class TenantPrivilege(PlCoreBase):
+    """"A TenantPrivilege which defines how users can access a particular Tenant.
+
+    Attributes:
+        id (models.AutoField): The ID of the privilege.
+        user (models.ForeignKey): A Foreign Key to the a User.
+        tenant (models.ForeignKey): A ForeignKey to the Tenant.
+        role (models.ForeignKey): A ForeignKey to the TenantRole.
+    """
+    id = models.AutoField(primary_key=True)
+    user = models.ForeignKey('User', related_name="tenantprivileges")
+    tenant = models.ForeignKey('Tenant', related_name="tenantprivileges")
+    role = models.ForeignKey('TenantRole', related_name="tenantprivileges")
+
+    def __unicode__(self): return u'%s %s %s' % (
+        self.tenant, self.user, self.role)
+
+    def save(self, *args, **kwds):
+        if not self.user.is_active:
+            raise PermissionDenied, "Cannot modify role(s) of a disabled user"
+        super(TenantPrivilege, self).save(*args, **kwds)
+
+    def can_update(self, user):
+        return user.can_update_tenant_privilege(self)
+
+    @classmethod
+    def select_by_user(cls, user):
+        if user.is_admin:
+            return cls.objects.all()
+        else:
+            # User can see his own privilege
+            trp_ids = [trp.id for trp in cls.objects.filter(user=user)]
+
+            # A tenant admin can see the TenantPrivileges for their Tenants
+            for priv in cls.objects.filter(user=user, role__role="admin"):
+                trp_ids.extend(
+                    [trp.id for trp in cls.objects.filter(tenant=priv.tenant)])
+
+            return cls.objects.filter(id__in=trp_ids)
diff --git a/xos/core/models/serviceclass.py b/xos/core/models/serviceclass.py
new file mode 100644
index 0000000..ccc3180
--- /dev/null
+++ b/xos/core/models/serviceclass.py
@@ -0,0 +1,28 @@
+import os
+from django.db import models
+from core.models import PlCoreBase
+from core.models.plcorebase import StrippedCharField
+
+def get_default_serviceclass():
+    try:
+        return ServiceClass.objects.get(name="Best Effort")
+    except ServiceClass.DoesNotExist:
+        return None
+
+class ServiceClass(PlCoreBase):
+    name = StrippedCharField(max_length=32)
+    description = StrippedCharField(max_length=255)
+    commitment = models.IntegerField(default=365)
+    membershipFee = models.IntegerField(default=0)
+    membershipFeeMonths = models.IntegerField(default=12)
+    upgradeRequiresApproval = models.BooleanField(default=False)
+    upgradeFrom = models.ManyToManyField('self', blank=True, null=True)
+
+    class Meta(PlCoreBase.Meta):
+       verbose_name_plural = "Service classes"
+
+    def __unicode__(self):  return u'%s' % (self.name)
+
+    def save_by_user(self, user, *args, **kwds):
+        if self.can_update(user):
+            super(ServiceClass, self).save(*args, **kwds)
diff --git a/xos/core/models/serviceresource.py b/xos/core/models/serviceresource.py
new file mode 100644
index 0000000..416627a
--- /dev/null
+++ b/xos/core/models/serviceresource.py
@@ -0,0 +1,20 @@
+import os
+from django.db import models
+from core.models import PlCoreBase
+from core.models import ServiceClass
+from core.models.plcorebase import StrippedCharField
+
+# Create your models here.
+
+class ServiceResource(PlCoreBase):
+    serviceClass = models.ForeignKey(ServiceClass, related_name = "serviceresources")
+    name = StrippedCharField(max_length=32)
+    maxUnitsDeployment = models.IntegerField(default=1)
+    maxUnitsNode = models.IntegerField(default=1)
+    maxDuration = models.IntegerField(default=1)
+    bucketInRate = models.IntegerField(default=0)
+    bucketMaxSize = models.IntegerField(default=0)
+    cost = models.IntegerField(default=0)
+    calendarReservable = models.BooleanField(default=True)
+
+    def __unicode__(self):  return u'%s' % (self.name)
diff --git a/xos/core/models/singletonmodel.py b/xos/core/models/singletonmodel.py
new file mode 100644
index 0000000..4ab6f6e
--- /dev/null
+++ b/xos/core/models/singletonmodel.py
@@ -0,0 +1,16 @@
+from django.db import models
+
+class SingletonModel(models.Model):
+    class Meta:
+        abstract = True
+ 
+    def save(self, *args, **kwargs):
+        self.__class__.objects.exclude(id=self.id).delete()
+        super(SingletonModel, self).save(*args, **kwargs)
+ 
+    @classmethod
+    def load(cls):
+        try:
+            return cls.objects.get()
+        except cls.DoesNotExist:
+            return cls()
diff --git a/xos/core/models/site.py b/xos/core/models/site.py
new file mode 100644
index 0000000..77b96ac
--- /dev/null
+++ b/xos/core/models/site.py
@@ -0,0 +1,330 @@
+import os
+from django.db import models
+from django.db.models import Q
+from django.contrib.contenttypes import generic
+from django.core.exceptions import PermissionDenied
+from geoposition.fields import GeopositionField
+from core.models import PlCoreBase,PlCoreBaseManager,PlCoreBaseDeletionManager
+from core.models import Tag
+from core.models.plcorebase import StrippedCharField
+from core.acl import AccessControlList
+from xos.config import Config
+
+config = Config()
+
+class ControllerLinkDeletionManager(PlCoreBaseDeletionManager):
+    def get_queryset(self):
+        parent=super(ControllerLinkDeletionManager, self)
+        try:
+            backend_type = config.observer_backend_type
+        except AttributeError:
+            backend_type = None
+
+        parent_queryset = parent.get_queryset() if hasattr(parent, "get_queryset") else parent.get_query_set()
+        if (backend_type):
+            return parent_queryset.filter(Q(controller__backend_type=backend_type))
+        else:
+            return parent_queryset
+
+    # deprecated in django 1.7 in favor of get_queryset().
+    def get_query_set(self):
+        return self.get_queryset()
+
+
+class ControllerDeletionManager(PlCoreBaseDeletionManager):
+    def get_queryset(self):
+        parent=super(ControllerDeletionManager, self)
+
+        try:
+            backend_type = config.observer_backend_type
+        except AttributeError:
+            backend_type = None
+
+        parent_queryset = parent.get_queryset() if hasattr(parent, "get_queryset") else parent.get_query_set()
+
+        if backend_type:
+            return parent_queryset.filter(Q(backend_type=backend_type))
+        else:
+            return parent_queryset
+
+    # deprecated in django 1.7 in favor of get_queryset().
+    def get_query_set(self):
+        return self.get_queryset()
+
+class ControllerLinkManager(PlCoreBaseManager):
+    def get_queryset(self):
+        parent=super(ControllerLinkManager, self)
+
+        try:
+            backend_type = config.observer_backend_type
+        except AttributeError:
+            backend_type = None
+
+        parent_queryset = parent.get_queryset() if hasattr(parent, "get_queryset") else parent.get_query_set()
+
+        if backend_type:
+            return parent_queryset.filter(Q(controller__backend_type=backend_type))
+        else:
+            return parent_queryset
+
+    # deprecated in django 1.7 in favor of get_queryset().
+    def get_query_set(self):
+        return self.get_queryset()
+
+
+class ControllerManager(PlCoreBaseManager):
+    def get_queryset(self):
+        parent=super(ControllerManager, self)
+
+        try:
+            backend_type = config.observer_backend_type
+        except AttributeError:
+            backend_type = None
+
+        parent_queryset = parent.get_queryset() if hasattr(parent, "get_queryset") else parent.get_query_set()
+
+        if backend_type:
+            return parent_queryset.filter(Q(backend_type=backend_type))
+        else:
+            return parent_queryset
+
+    # deprecated in django 1.7 in favor of get_queryset().
+    def get_query_set(self):
+        return self.get_queryset()
+
+class Site(PlCoreBase):
+    """
+        A logical grouping of Nodes that are co-located at the same geographic location, which also typically corresponds to the Nodes' location in the physical network.
+    """
+    name = StrippedCharField(max_length=200, help_text="Name for this Site")
+    site_url = models.URLField(null=True, blank=True, max_length=512, help_text="Site's Home URL Page")
+    enabled = models.BooleanField(default=True, help_text="Status for this Site")
+    hosts_nodes = models.BooleanField(default=True, help_text="Indicates whether or not the site host nodes")
+    hosts_users = models.BooleanField(default=True, help_text="Indicates whether or not the site manages user accounts")
+    location = GeopositionField()
+    longitude = models.FloatField(null=True, blank=True)
+    latitude = models.FloatField(null=True, blank=True)
+    login_base = StrippedCharField(max_length=50, unique=True, help_text="Prefix for Slices associated with this Site")
+    is_public = models.BooleanField(default=True, help_text="Indicates the visibility of this site to other members")
+    abbreviated_name = StrippedCharField(max_length=80)
+
+    #deployments = models.ManyToManyField('Deployment', blank=True, related_name='sites')
+    deployments = models.ManyToManyField('Deployment', through='SiteDeployment', blank=True, help_text="Select which sites are allowed to host nodes in this deployment", related_name='sites')
+    tags = generic.GenericRelation(Tag)
+
+    def __unicode__(self):  return u'%s' % (self.name)
+
+    def can_update(self, user):
+        return user.can_update_site(self, allow=['pi'])
+
+class SiteRole(PlCoreBase):
+
+    ROLE_CHOICES = (('admin','Admin'),('pi','PI'),('tech','Tech'),('billing','Billing'))
+    role = StrippedCharField(choices=ROLE_CHOICES, unique=True, max_length=30)
+
+    def __unicode__(self):  return u'%s' % (self.role)
+
+class SitePrivilege(PlCoreBase):
+
+    user = models.ForeignKey('User', related_name='siteprivileges')
+    site = models.ForeignKey('Site', related_name='siteprivileges')
+    role = models.ForeignKey('SiteRole',related_name='siteprivileges')
+
+    def __unicode__(self):  return u'%s %s %s' % (self.site, self.user, self.role)
+
+    def save(self, *args, **kwds):
+        if not self.user.is_active:
+            raise PermissionDenied, "Cannot modify role(s) of a disabled user"
+        super(SitePrivilege, self).save(*args, **kwds)
+
+    def delete(self, *args, **kwds):
+        super(SitePrivilege, self).delete(*args, **kwds)
+
+    def can_update(self, user):
+        return user.can_update_site(self, allow=['pi'])
+
+    @staticmethod
+    def select_by_user(user):
+        if user.is_admin:
+            qs = SitePrivilege.objects.all()
+        else:
+            sp_ids = [sp.id for sp in SitePrivilege.objects.filter(user=user)]
+            qs = SitePrivilege.objects.filter(id__in=sp_ids)
+        return qs
+
+class Deployment(PlCoreBase):
+    #objects = Controllermanager()
+    #deleted_objects = DeploymentDeletionManager()
+    name = StrippedCharField(max_length=200, unique=True, help_text="Name of the Deployment")
+    #admin_user = StrippedCharField(max_length=200, null=True, blank=True, help_text="Username of an admin user at this deployment")
+    #admin_password = StrippedCharField(max_length=200, null=True, blank=True, help_text="Password of theadmin user at this deployment")
+    #admin_tenant = StrippedCharField(max_length=200, null=True, blank=True, help_text="Name of the tenant the admin user belongs to")
+    #auth_url = StrippedCharField(max_length=200, null=True, blank=True, help_text="Auth url for the deployment")
+    #backend_type = StrippedCharField(max_length=200, null=True, blank=True, help_text="Type of deployment, e.g. EC2, OpenStack, or OpenStack version")
+    #availability_zone = StrippedCharField(max_length=200, null=True, blank=True, help_text="OpenStack availability zone")
+
+    # smbaker: the default of 'allow all' is intended for evolutions of existing
+    #    deployments. When new deployments are created via the GUI, they are
+    #    given a default of 'allow site <site_of_creator>'
+    accessControl = models.TextField(max_length=200, blank=False, null=False, default="allow all",
+                                     help_text="Access control list that specifies which sites/users may use nodes in this deployment")
+    def __init__(self, *args, **kwargs):
+        super(Deployment, self).__init__(*args, **kwargs)
+        self.no_sync=True
+
+    def get_acl(self):
+        return AccessControlList(self.accessControl)
+
+    def test_acl(self, slice=None, user=None):
+        potential_users=[]
+
+        if user:
+            potential_users.append(user)
+
+        if slice:
+            potential_users.append(slice.creator)
+            for priv in slice.sliceprivileges.all():
+                if priv.user not in potential_users:
+                    potential_users.append(priv.user)
+
+        acl = self.get_acl()
+        for user in potential_users:
+            if acl.test(user) == "allow":
+                return True
+
+        return False
+
+    @staticmethod
+    def select_by_acl(user):
+        ids = []
+        for deployment in Deployment.objects.all():
+            acl = deployment.get_acl()
+            if acl.test(user) == "allow":
+                ids.append(deployment.id)
+
+        return Deployment.objects.filter(id__in=ids)
+
+    def can_update(self, user):
+        return user.can_update_deployment(self)
+    
+    def __unicode__(self):  return u'%s' % (self.name)
+
+class DeploymentRole(PlCoreBase):
+    #objects = DeploymentLinkManager()
+    #deleted_objects = DeploymentLinkDeletionManager()
+    ROLE_CHOICES = (('admin','Admin'),)
+    role = StrippedCharField(choices=ROLE_CHOICES, unique=True, max_length=30)
+
+    def __unicode__(self):  return u'%s' % (self.role)
+
+class DeploymentPrivilege(PlCoreBase):
+    #objects = DeploymentLinkManager()
+    #deleted_objects = DeploymentLinkDeletionManager()
+
+    user = models.ForeignKey('User', related_name='deploymentprivileges')
+    deployment = models.ForeignKey('Deployment', related_name='deploymentprivileges')
+    role = models.ForeignKey('DeploymentRole',related_name='deploymentprivileges')
+    class Meta:
+        unique_together = ('user', 'deployment', 'role')
+
+    def __unicode__(self):  return u'%s %s %s' % (self.deployment, self.user, self.role)
+
+    def can_update(self, user):
+        return user.can_update_deployment(self)
+
+    @staticmethod
+    def select_by_user(user):
+        if user.is_admin:
+            qs = DeploymentPrivilege.objects.all()
+        else:
+            dpriv_ids = [dp.id for dp in DeploymentPrivilege.objects.filter(user=user)]
+            qs = DeploymentPrivilege.objects.filter(id__in=dpriv_ids)
+        return qs
+
+class ControllerRole(PlCoreBase):
+    #objects = ControllerLinkManager()
+    #deleted_objects = ControllerLinkDeletionManager()
+
+    ROLE_CHOICES = (('admin','Admin'),)
+    role = StrippedCharField(choices=ROLE_CHOICES, unique=True, max_length=30)
+
+    def __unicode__(self):  return u'%s' % (self.role)
+
+class Controller(PlCoreBase):
+
+    objects = ControllerManager()
+    deleted_objects = ControllerDeletionManager()
+
+    name = StrippedCharField(max_length=200, unique=True, help_text="Name of the Controller")
+    backend_type = StrippedCharField(max_length=200, help_text="Type of compute controller, e.g. EC2, OpenStack, or OpenStack version")
+    version = StrippedCharField(max_length=200, help_text="Controller version")
+    auth_url = StrippedCharField(max_length=200, null=True, blank=True, help_text="Auth url for the compute controller")
+    admin_user = StrippedCharField(max_length=200, null=True, blank=True, help_text="Username of an admin user at this controller")
+    admin_password = StrippedCharField(max_length=200, null=True, blank=True, help_text="Password of theadmin user at this controller")
+    admin_tenant = StrippedCharField(max_length=200, null=True, blank=True, help_text="Name of the tenant the admin user belongs to")
+    domain = StrippedCharField(max_length=200, null=True, blank=True, help_text="Name of the domain this controller belongs to")
+    rabbit_host = StrippedCharField(max_length=200, null=True, blank=True, help_text="IP address of rabbitmq server at this controller")
+    rabbit_user = StrippedCharField(max_length=200, null=True, blank=True, help_text="Username of rabbitmq server at this controller")
+    rabbit_password = StrippedCharField(max_length=200, null=True, blank=True, help_text="Password of rabbitmq server at this controller")
+    deployment = models.ForeignKey(Deployment,related_name='controllerdeployments')
+
+    def __init__(self, *args, **kwargs):
+        super(Controller, self).__init__(*args, **kwargs)
+        self.no_sync=True
+
+    def __unicode__(self):  return u'%s %s %s' % (self.name, self.backend_type, self.version)
+
+    @property
+    def auth_url_v3(self):
+        if self.auth_url and self.auth_url[-1] == '/':
+            return '{}/v3/'.format('/'.join(self.auth_url.split('/')[:-2]))
+        else:
+            return '{}/v3/'.format('/'.join(self.auth_url.split('/')[:-1]))
+
+    @staticmethod
+    def select_by_user(user):
+
+        if user.is_admin:
+            qs = Controller.objects.all()
+        else:
+            deployments = [dp.deployment for dp in DeploymentPrivilege.objects.filter(user=user, role__role__in=['Admin', 'admin'])]
+            qs = Controller.objects.filter(deployment__in=deployments)
+        return qs
+
+class SiteDeployment(PlCoreBase):
+    objects = ControllerLinkManager()
+    deleted_objects = ControllerLinkDeletionManager()
+
+    site = models.ForeignKey(Site,related_name='sitedeployments')
+    deployment = models.ForeignKey(Deployment,related_name='sitedeployments')
+    controller = models.ForeignKey(Controller, null=True, blank=True, related_name='sitedeployments')
+    availability_zone = StrippedCharField(max_length=200, null=True, blank=True, help_text="OpenStack availability zone")
+
+    class Meta:
+        unique_together = ('site', 'deployment', 'controller')
+
+    def __unicode__(self):  return u'%s %s' % (self.deployment, self.site)
+    
+class ControllerSite(PlCoreBase):
+     
+    site = models.ForeignKey(Site,related_name='controllersite')
+    controller = models.ForeignKey(Controller, null=True, blank=True, related_name='controllersite')
+    tenant_id = StrippedCharField(null=True, blank=True, max_length=200, db_index=True, help_text="Keystone tenant id")
+
+    def delete(self, *args, **kwds):
+        super(ControllerSite, self).delete(*args, **kwds)
+
+    
+    class Meta:
+        unique_together = ('site', 'controller') 
+
+class Diag(PlCoreBase):
+    name = StrippedCharField(max_length=200, help_text="Name of the synchronizer")
+    
+    @property
+    def enacted(self):
+        return None
+
+    @enacted.setter
+    def enacted(self, value):
+        pass # Ignore sets, Diag objects are always pending.
diff --git a/xos/core/models/slice.py b/xos/core/models/slice.py
new file mode 100644
index 0000000..73fa121
--- /dev/null
+++ b/xos/core/models/slice.py
@@ -0,0 +1,212 @@
+import os
+from django.db import models
+from core.models import PlCoreBase
+from core.models import Site
+from core.models.site import SitePrivilege
+from core.models import User
+from core.models import Role
+from core.models import Controller,ControllerLinkManager,ControllerLinkDeletionManager
+from core.models import ServiceClass
+#from core.models.serviceclass import get_default_serviceclass
+from core.models import Tag
+from django.contrib.contenttypes import generic
+from core.models import Service
+from core.models import Controller
+from core.models.node import Node
+from core.models import Flavor, Image
+from core.models.plcorebase import StrippedCharField
+from django.core.exceptions import PermissionDenied, ValidationError
+from xos.exceptions import *
+
+# Create your models here.
+
+class Slice(PlCoreBase):
+    ISOLATION_CHOICES = (('vm', 'Virtual Machine'), ('container', 'Container'), ('container_vm', 'Container In VM'))
+    NETWORK_CHOICES = ((None, 'Default'), ('host', 'Host'), ('bridged', 'Bridged'), ('noauto', 'No Automatic Networks'))
+
+    name = StrippedCharField(unique=True, help_text="The Name of the Slice", max_length=80)
+    enabled = models.BooleanField(default=True, help_text="Status for this Slice")
+    omf_friendly = models.BooleanField(default=False)
+    description=models.TextField(blank=True,help_text="High level description of the slice and expected activities", max_length=1024)
+    slice_url = models.URLField(blank=True, max_length=512)
+    site = models.ForeignKey(Site, related_name='slices', help_text="The Site this Slice belongs to")
+    max_instances = models.IntegerField(default=10)
+    service = models.ForeignKey(Service, related_name='slices', null=True, blank=True)
+    network = models.CharField(null=True, blank=True, max_length=256, choices=NETWORK_CHOICES)
+    exposed_ports = models.CharField(null=True, blank=True, max_length=256)
+    tags = generic.GenericRelation(Tag)
+    serviceClass = models.ForeignKey(ServiceClass, related_name = "slices", null=True, blank=True)  # DEPRECATED
+    creator = models.ForeignKey(User, related_name='slices', blank=True, null=True)
+
+    # for tenant view
+    default_flavor = models.ForeignKey(Flavor, related_name = "slices", null=True, blank=True)
+    default_image = models.ForeignKey(Image, related_name = "slices", null=True, blank=True);
+    default_node = models.ForeignKey(Node, related_name = "slices", null=True, blank=True)
+    mount_data_sets = StrippedCharField(default="GenBank",null=True, blank=True, max_length=256)
+
+    default_isolation = models.CharField(null=False, blank=False, max_length=30, choices=ISOLATION_CHOICES, default="vm")
+
+    def __unicode__(self):  return u'%s' % (self.name)
+
+    @property
+    def slicename(self):
+        return "%s_%s" % (self.site.login_base, self.name)
+
+    def save(self, *args, **kwds):
+        site = Site.objects.get(id=self.site.id)
+        # allow preexisting slices to keep their original name for now
+        if not self.id and not self.name.startswith(site.login_base):
+            raise XOSValidationError('slice name must begin with %s' % site.login_base)
+
+        if self.name == site.login_base+"_":
+            raise XOSValidationError('slice name is too short')
+
+        if " " in self.name:
+            raise XOSValidationError('slice name must not contain spaces')
+
+        # set creator on first save
+        if not self.creator and hasattr(self, 'caller'):
+            self.creator = self.caller
+
+        # only admins change a slice's creator
+        if 'creator' in self.changed_fields and \
+            (not hasattr(self, 'caller') or not self.caller.is_admin):
+
+            if (self._initial["creator"]==None) and (self.creator==getattr(self,"caller",None)):
+                # it's okay if the creator is being set by the caller to
+                # himeself on a new slice object.
+                pass
+            else:
+                raise PermissionDenied("Insufficient privileges to change slice creator")
+        
+        if not self.creator:
+            raise XOSValidationError('slice has no creator')
+
+        if self.network=="Private Only":
+            # "Private Only" was the default from the old Tenant View
+            self.network=None
+        self.enforce_choices(self.network, self.NETWORK_CHOICES)
+
+        super(Slice, self).save(*args, **kwds)
+
+    def can_update(self, user):
+        return user.can_update_slice(self)
+
+
+    @staticmethod
+    def select_by_user(user):
+        if user.is_admin:
+            qs = Slice.objects.all()
+        else:
+            # users can see slices they belong to 
+            slice_ids = [sp.slice.id for sp in SlicePrivilege.objects.filter(user=user)]
+            # pis and admins can see slices at their sites
+            sites = [sp.site for sp in SitePrivilege.objects.filter(user=user)\
+                        if (sp.role.role == 'pi') or (sp.role.role == 'admin')]
+            slice_ids.extend([s.id for s in Slice.objects.filter(site__in=sites)])
+            qs = Slice.objects.filter(id__in=slice_ids)
+        return qs
+
+    """
+    def delete(self, *args, **kwds):
+        # delete networks associated with this slice
+        from core.models.network import Network
+        nets = Network.objects.filter(slices=self)
+        nets.delete() 
+        # delete slice controllers
+        slice_controllers = ControllerSlice.objects.filter(slice=self)
+        slice_controllers.delete()
+        # delete slice privilege
+        slice_privileges = SlicePrivilege.objects.filter(slice=self)
+        slice_privileges.delete() 
+        # continue with normal delete
+        super(Slice, self).delete(*args, **kwds) 
+    """
+         
+
+class SliceRole(PlCoreBase):
+    ROLE_CHOICES = (('admin','Admin'),('default','Default'))
+
+    role = StrippedCharField(choices=ROLE_CHOICES, unique=True, max_length=30)
+
+    def __unicode__(self):  return u'%s' % (self.role)
+
+class SlicePrivilege(PlCoreBase):
+    user = models.ForeignKey('User', related_name='sliceprivileges')
+    slice = models.ForeignKey('Slice', related_name='sliceprivileges')
+    role = models.ForeignKey('SliceRole',related_name='sliceprivileges')
+
+    class Meta:
+        unique_together = ('user', 'slice', 'role')
+
+    def __unicode__(self):  return u'%s %s %s' % (self.slice, self.user, self.role)
+
+    def save(self, *args, **kwds):
+        if not self.user.is_active:
+            raise PermissionDenied, "Cannot modify role(s) of a disabled user"
+        super(SlicePrivilege, self).save(*args, **kwds)
+
+    def can_update(self, user):
+        return user.can_update_slice(self.slice)
+
+    @staticmethod
+    def select_by_user(user):
+        if user.is_admin:
+            qs = SlicePrivilege.objects.all()
+        else:
+            # You can see your own SlicePrivileges
+            sp_ids = [sp.id for sp in SlicePrivilege.objects.filter(user=user)]
+
+            # A site pi or site admin can see the SlicePrivileges for all slices in his Site
+            for priv in SitePrivilege.objects.filter(user=user):
+                if priv.role.role in ['pi', 'admin']:
+                    sp_ids.extend( [sp.id for sp in SlicePrivilege.objects.filter(slice__site = priv.site)] )
+
+            # A slice admin can see the SlicePrivileges for his Slice
+            for priv in SlicePrivilege.objects.filter(user=user, role__role="admin"):
+                sp_ids.extend( [sp.id for sp in SlicePrivilege.objects.filter(slice=priv.slice)] )
+
+            qs = SlicePrivilege.objects.filter(id__in=sp_ids)
+        return qs
+
+class ControllerSlice(PlCoreBase):
+    objects = ControllerLinkManager()
+    deleted_objects = ControllerLinkDeletionManager()
+
+    controller = models.ForeignKey(Controller, related_name='controllerslices')
+    slice = models.ForeignKey(Slice, related_name='controllerslices')
+    tenant_id = StrippedCharField(null=True, blank=True, max_length=200, help_text="Keystone tenant id")
+
+    class Meta:
+        unique_together = ('controller', 'slice')
+     
+    def tologdict(self):
+        d=super(ControllerSlice,self).tologdict()
+        try:
+            d['slice_name']=self.slice.name
+            d['controller_name']=self.controller.name
+        except:
+            pass
+        return d
+
+    def __unicode__(self):  return u'%s %s'  % (self.slice, self.controller)
+
+    @staticmethod
+    def select_by_user(user):
+        if user.is_admin:
+            qs = ControllerSlice.objects.all()
+        else:
+            slices = Slice.select_by_user(user)
+            qs = ControllerSlice.objects.filter(slice__in=slices)
+        return qs    
+
+    def get_cpu_stats(self):
+        filter = 'project_id=%s'%self.tenant_id
+        return monitor.get_meter('cpu',filter,None)
+
+    def get_bw_stats(self):
+        filter = 'project_id=%s'%self.tenant_id
+        return monitor.get_meter('network.outgoing.bytes',filter,None)
+
+    def get_node_stats(self):
+        return len(self.slice.instances)
diff --git a/xos/core/models/slicetag.py b/xos/core/models/slicetag.py
new file mode 100644
index 0000000..a335ce0
--- /dev/null
+++ b/xos/core/models/slicetag.py
@@ -0,0 +1,24 @@
+import os
+from django.db import models
+from core.models import PlCoreBase
+from core.models import Slice
+from core.models.plcorebase import StrippedCharField
+
+class SliceTag(PlCoreBase):
+    slice = models.ForeignKey(Slice, related_name='slicetags')
+
+    NAME_CHOICES = (('privatekey', 'Private Key'), ('publickey', 'Public Key'))
+    name = StrippedCharField(help_text="The name of this tag", max_length=30, choices=NAME_CHOICES)
+    value = StrippedCharField(help_text="The value of this tag", max_length=1024)
+
+    def can_update(self, user):
+        return user.can_update_slice(self.slice)
+
+    @staticmethod
+    def select_by_user(user):
+        if user.is_admin:
+            qs = SliceTag.objects.all()
+        else:
+            slices = Slice.select_by_user(user)
+            qs = SliceTag.objects.filter(slice__in=slices)
+        return qs
diff --git a/xos/core/models/tag.py b/xos/core/models/tag.py
new file mode 100644
index 0000000..76a4e2e
--- /dev/null
+++ b/xos/core/models/tag.py
@@ -0,0 +1,36 @@
+import os
+from django.db import models
+from core.models import PlCoreBase
+from core.models import Service
+from core.models.plcorebase import StrippedCharField
+from django.contrib.contenttypes.models import ContentType
+from django.contrib.contenttypes import generic
+
+# Create your models here.
+
+class Tag(PlCoreBase):
+
+    service = models.ForeignKey(Service, related_name='tags', help_text="The Service this Tag is associated with")
+
+    name = models.SlugField(help_text="The name of this tag", max_length=128)
+    value = StrippedCharField(help_text="The value of this tag", max_length=1024)
+
+    # The required fields to do a ObjectType lookup, and object_id assignment
+    content_type = models.ForeignKey(ContentType)
+    object_id = models.PositiveIntegerField()
+    content_object = generic.GenericForeignKey('content_type', 'object_id')
+
+    def __unicode__(self):
+        return self.name
+
+
+    def can_update(self, user):
+        return user.can_update_root()
+
+    @classmethod
+    def select_by_content_object(cls, obj):
+        return cls.objects.filter(content_type=ContentType.objects.get_for_model(obj), object_id=obj.id)
+
+    @staticmethod
+    def select_by_user(user):
+        return Tag.objects.all()
diff --git a/xos/core/models/user.py b/xos/core/models/user.py
new file mode 100644
index 0000000..715c670
--- /dev/null
+++ b/xos/core/models/user.py
@@ -0,0 +1,536 @@
+import datetime
+import hashlib
+import os
+import sys
+from collections import defaultdict
+from operator import attrgetter, itemgetter
+
+import synchronizers.model_policy
+from core.middleware import get_request
+from core.models import DashboardView, PlCoreBase, PlModelMixIn, Site
+from core.models.plcorebase import StrippedCharField
+from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
+from django.core.exceptions import PermissionDenied
+from django.core.mail import EmailMultiAlternatives
+from django.db import models
+from django.db.models import F, Q
+from django.forms.models import model_to_dict
+from django.utils import timezone
+from timezones.fields import TimeZoneField
+
+# ------ from plcorebase.py ------
+try:
+    # This is a no-op if observer_disabled is set to 1 in the config file
+    from synchronizers.base import *
+except:
+    print >> sys.stderr, "import of observer failed! printing traceback and disabling observer:"
+    import traceback
+    traceback.print_exc()
+
+    # guard against something failing
+    def notify_observer(*args, **kwargs):
+        pass
+# ------ ------
+
+# Create your models here.
+
+
+class UserManager(BaseUserManager):
+
+    def create_user(self, email, firstname, lastname, password=None):
+        """
+        Creates and saves a User with the given email, date of
+        birth and password.
+        """
+        if not email:
+            raise ValueError('Users must have an email address')
+
+        user = self.model(
+            email=UserManager.normalize_email(email),
+            firstname=firstname,
+            lastname=lastname,
+            password=password
+        )
+        # user.set_password(password)
+        user.is_admin = True
+        user.save(using=self._db)
+        return user
+
+    def create_superuser(self, email, firstname, lastname, password):
+        """
+        Creates and saves a superuser with the given email, date of
+        birth and password.
+        """
+        user = self.create_user(email,
+                                password=password,
+                                firstname=firstname,
+                                lastname=lastname
+                                )
+        user.is_admin = True
+        user.save(using=self._db)
+        return user
+
+    def get_queryset(self):
+        parent = super(UserManager, self)
+        if hasattr(parent, "get_queryset"):
+            return parent.get_queryset().filter(deleted=False)
+        else:
+            return parent.get_query_set().filter(deleted=False)
+
+    # deprecated in django 1.7 in favor of get_queryset().
+    def get_query_set(self):
+        return self.get_queryset()
+
+
+class DeletedUserManager(UserManager):
+
+    def get_queryset(self):
+        return super(UserManager, self).get_query_set().filter(deleted=True)
+
+    # deprecated in django 1.7 in favor of get_queryset()
+    def get_query_set(self):
+        return self.get_queryset()
+
+
+class User(AbstractBaseUser, PlModelMixIn):
+
+    @property
+    def remote_password(self):
+        return hashlib.md5(self.password).hexdigest()[:12]
+
+    class Meta:
+        app_label = "core"
+
+    email = models.EmailField(
+        verbose_name='email address',
+        max_length=255,
+        unique=True,
+        db_index=True,
+    )
+
+    username = StrippedCharField(max_length=255, default="Something")
+
+    firstname = StrippedCharField(
+        help_text="person's given name", max_length=200)
+    lastname = StrippedCharField(help_text="person's surname", max_length=200)
+
+    phone = StrippedCharField(null=True, blank=True,
+                              help_text="phone number contact", max_length=100)
+    user_url = models.URLField(null=True, blank=True)
+    site = models.ForeignKey(Site, related_name='users',
+                             help_text="Site this user will be homed too")
+    public_key = models.TextField(
+        null=True, blank=True, max_length=1024, help_text="Public key string")
+
+    is_active = models.BooleanField(default=True)
+    is_admin = models.BooleanField(default=False)
+    is_staff = models.BooleanField(default=True)
+    is_readonly = models.BooleanField(default=False)
+    is_registering = models.BooleanField(default=False)
+    is_appuser = models.BooleanField(default=False)
+
+    login_page = StrippedCharField(
+        help_text="send this user to a specific page on login", max_length=200, null=True, blank=True)
+
+    created = models.DateTimeField(auto_now_add=True)
+    updated = models.DateTimeField(auto_now=True)
+    enacted = models.DateTimeField(null=True, default=None)
+    policed = models.DateTimeField(null=True, default=None)
+    backend_status = StrippedCharField(max_length=1024,
+                                       default="Provisioning in progress")
+    deleted = models.BooleanField(default=False)
+    write_protect = models.BooleanField(default=False)
+    lazy_blocked = models.BooleanField(default=False)
+    no_sync = models.BooleanField(default=False)     # prevent object sync
+    no_policy = models.BooleanField(default=False)   # prevent model_policy run
+
+    timezone = TimeZoneField()
+
+    dashboards = models.ManyToManyField(
+        'DashboardView', through='UserDashboardView', blank=True)
+
+    objects = UserManager()
+    deleted_objects = DeletedUserManager()
+
+    USERNAME_FIELD = 'email'
+    REQUIRED_FIELDS = ['firstname', 'lastname']
+
+    PI_FORBIDDEN_FIELDS = ["is_admin", "site", "is_staff"]
+    USER_FORBIDDEN_FIELDS = ["is_admin", "is_active",
+                             "site", "is_staff", "is_readonly"]
+
+    def __init__(self, *args, **kwargs):
+        super(User, self).__init__(*args, **kwargs)
+        self._initial = self._dict  # for PlModelMixIn
+
+    def isReadOnlyUser(self):
+        return self.is_readonly
+
+    def get_full_name(self):
+        # The user is identified by their email address
+        return self.email
+
+    def get_short_name(self):
+        # The user is identified by their email address
+        return self.email
+
+    def delete(self, *args, **kwds):
+        # so we have something to give the observer
+        purge = kwds.get('purge', False)
+        if purge:
+            del kwds['purge']
+        try:
+            purge = purge or observer_disabled
+        except NameError:
+            pass
+
+        if (purge):
+            super(User, self).delete(*args, **kwds)
+        else:
+            if (not self.write_protect):
+                self.deleted = True
+                self.enacted = None
+                self.save(update_fields=['enacted', 'deleted'])
+
+    @property
+    def keyname(self):
+        return self.email[:self.email.find('@')]
+
+    def __unicode__(self):
+        return self.email
+
+    def has_perm(self, perm, obj=None):
+        "Does the user have a specific permission?"
+        # Simplest possible answer: Yes, always
+        return True
+
+    def has_module_perms(self, app_label):
+        "Does the user have permissions to view the app `app_label`?"
+        # Simplest possible answer: Yes, always
+        return True
+
+    def is_superuser(self):
+        return False
+
+    def get_dashboards(self):
+        DEFAULT_DASHBOARDS = ["Tenant"]
+
+        dashboards = sorted(
+            list(self.userdashboardviews.all()), key=attrgetter('order'))
+        dashboards = [x.dashboardView for x in dashboards]
+
+        if (not dashboards) and (not self.is_appuser):
+            for dashboardName in DEFAULT_DASHBOARDS:
+                dbv = DashboardView.objects.filter(name=dashboardName)
+                if dbv:
+                    dashboards.append(dbv[0])
+
+        return dashboards
+
+#    def get_roles(self):
+#        from core.models.site import SitePrivilege
+#        from core.models.slice import SliceMembership
+#
+#        site_privileges = SitePrivilege.objects.filter(user=self)
+#        slice_memberships = SliceMembership.objects.filter(user=self)
+#        roles = defaultdict(list)
+#        for site_privilege in site_privileges:
+#            roles[site_privilege.role.role_type].append(site_privilege.site.login_base)
+#        for slice_membership in slice_memberships:
+#            roles[slice_membership.role.role_type].append(slice_membership.slice.name)
+#        return roles
+
+    def save(self, *args, **kwds):
+        if not self.id:
+            self.set_password(self.password)
+        if self.is_active and self.is_registering:
+            self.send_temporary_password()
+            self.is_registering = False
+
+        self.username = self.email
+        super(User, self).save(*args, **kwds)
+
+        self._initial = self._dict
+
+    def send_temporary_password(self):
+        password = User.objects.make_random_password()
+        self.set_password(password)
+        subject, from_email, to = 'OpenCloud Account Credentials', 'support@opencloud.us', str(
+            self.email)
+        text_content = 'This is an important message.'
+        userUrl = "http://%s/" % get_request().get_host()
+        html_content = """<p>Your account has been created on OpenCloud. Please log in <a href=""" + userUrl + """>here</a> to activate your account<br><br>Username: """ + \
+            self.email + """<br>Temporary Password: """ + password + \
+            """<br>Please change your password once you successully login into the site.</p>"""
+        msg = EmailMultiAlternatives(subject, text_content, from_email, [to])
+        msg.attach_alternative(html_content, "text/html")
+        msg.send()
+
+    def can_update(self, user):
+        from core.models import SitePrivilege
+        _cant_update_fieldName = None
+        if user.can_update_root():
+            return True
+
+        # site pis can update
+        site_privs = SitePrivilege.objects.filter(user=user, site=self.site)
+        for site_priv in site_privs:
+            if site_priv.role.role == 'admin':
+                return True
+            if site_priv.role.role == 'pi':
+                for fieldName in self.diff.keys():
+                    if fieldName in self.PI_FORBIDDEN_FIELDS:
+                        _cant_update_fieldName = fieldName
+                        return False
+                return True
+        if (user.id == self.id):
+            for fieldName in self.diff.keys():
+                if fieldName in self.USER_FORBIDDEN_FIELDS:
+                    _cant_update_fieldName = fieldName
+                    return False
+            return True
+
+        return False
+
+    def can_update_root(self):
+        """
+        Return True if user has root (global) write access. 
+        """
+        if self.is_readonly:
+            return False
+        if self.is_admin:
+            return True
+
+        return False
+
+    def can_update_deployment(self, deployment):
+        from core.models.site import DeploymentPrivilege
+        if self.can_update_root():
+            return True
+
+        if DeploymentPrivilege.objects.filter(
+                deployment=deployment,
+                user=self,
+                role__role__in=['admin', 'Admin']):
+            return True
+        return False
+
+    def can_update_site(self, site, allow=[]):
+        from core.models.site import SitePrivilege
+        if self.can_update_root():
+            return True
+        if SitePrivilege.objects.filter(
+                site=site, user=self, role__role__in=['admin', 'Admin'] + allow):
+            return True
+        return False
+
+    def can_update_slice(self, slice):
+        from core.models.slice import SlicePrivilege
+        if self.can_update_root():
+            return True
+        if self == slice.creator:
+            return True
+        if self.can_update_site(slice.site, allow=['pi']):
+            return True
+
+        if SlicePrivilege.objects.filter(
+                slice=slice, user=self, role__role__in=['admin', 'Admin']):
+            return True
+        return False
+
+    def can_update_service(self, service, allow=[]):
+        from core.models.service import ServicePrivilege
+        if self.can_update_root():
+            return True
+        if ServicePrivilege.objects.filter(
+                service=service, user=self, role__role__in=['admin', 'Admin'] + allow):
+            return True
+        return False
+
+    def can_update_tenant_root(self, tenant_root, allow=[]):
+        from core.models.service import TenantRoot, TenantRootPrivilege
+        if self.can_update_root():
+            return True
+        if TenantRootPrivilege.objects.filter(
+                tenant_root=tenant_root, user=self, role__role__in=['admin', 'Admin'] + allow):
+            return True
+        return False
+
+    def can_update_tenant(self, tenant, allow=[]):
+        from core.models.service import Tenant, TenantPrivilege
+        if self.can_update_root():
+            return True
+        if TenantPrivilege.objects.filter(
+                tenant=tenant, user=self, role__role__in=['admin', 'Admin'] + allow):
+            return True
+        return False
+
+    def can_update_tenant_root_privilege(self, tenant_root_privilege, allow=[]):
+        return self.can_update_tenant_root(tenant_root_privilege.tenant_root, allow)
+
+    def can_update_tenant_privilege(self, tenant_privilege, allow=[]):
+        return self.can_update_tenant(tenant_privilege.tenant, allow)
+
+    def get_readable_objects(self, filter_by=None):
+        """ Returns a list of objects that the user is allowed to read. """
+        from core.models import Deployment, Flavor, Image, Network, NetworkTemplate, Node, PlModelMixIn, Site, Slice, SliceTag, Instance, Tag, User, DeploymentPrivilege, SitePrivilege, SlicePrivilege
+        models = []
+        if filter_by and isinstance(filter_by, list):
+            models = [m for m in filter_by if issubclass(m, PlModelMixIn)]
+        if not models:
+            models = [Deployment, Network, Site,
+                      Slice, SliceTag, Instance, Tag, User]
+        readable_objects = []
+        for model in models:
+            readable_objects.extend(model.select_by_user(self))
+        return readable_objects
+
+    def get_permissions(self, filter_by=None):
+        """ Return a list of objects for which the user has read or read/write 
+        access. The object will be an instance of a django model object. 
+        Permissions will be either 'r' or 'rw'.
+
+        e.g.
+        [{'object': django_object_instance, 'permissions': 'rw'}, ...]
+
+        Returns:
+          list of dicts  
+
+        """
+        from core.models import Deployment, Flavor, Image, Network, NetworkTemplate, Node, PlModelMixIn, Site, Slice, SliceTag, Instance, Tag, User, DeploymentPrivilege, SitePrivilege, SlicePrivilege
+        READ = 'r'
+        READWRITE = 'rw'
+        models = []
+        if filter_by and isinstance(filter_by, list):
+            models = [m for m in filter_by if issubclass(m, PlModelMixIn)]
+
+        deployment_priv_objs = [Image, NetworkTemplate, Flavor]
+        site_priv_objs = [Node, Slice, User]
+        slice_priv_objs = [Instance, Network]
+
+        # maps the set of objects a paticular role has write access
+        write_map = {
+            DeploymentPrivilege: {
+                'admin': deployment_priv_objects,
+            },
+            SitePrivilege: {
+                'admin': site_priv_objs,
+                'pi': [Slice, User],
+                'tech': [Node],
+            },
+            SlicePrivilege: {
+                'admin': slice_priv_objs,
+            },
+        }
+
+        privilege_map = {
+            DeploymentPrivilege: (Deployment, deployment_priv_objs),
+            SitePrivilege: (Site, site_priv_objs),
+            SlicePrivilege: (Slice, slice_priv_objs)
+        }
+        permissions = []
+        permission_dict = lambda x, y: {'object': x, 'permission': y}
+        for privilege_model, (model, affected_models) in privileg_map.items():
+            if models and model not in models:
+                continue
+
+            # get the objects affected by this privilege model
+            affected_objects = []
+            for affected_model in affected_models:
+                affected_objects.extend(affected_model.select_by_user(self))
+
+            if self.is_admin:
+                # assume admin users have read/write access to all objects
+                for affected_object in affected_objects:
+                    permissions.append(permission_dict(
+                        affected_object, READWRITE))
+            else:
+                # create a dict of the user's per object privileges
+                # ex:  {princeton_tmack : ['admin']
+                privileges = privilege_model.objects.filter(user=self)
+                for privilege in privileges:
+                    object_roles = defaultdict(list)
+                    obj = None
+                    roles = []
+                    for field in dir(privilege):
+                        if field == model.__name__.lower():
+                            obj = getattr(privilege, field)
+                    if obj:
+                        object_roles[obj].append(privilege.role.role)
+
+                # loop through all objects the user has access to and determine
+                # if they also have write access
+                for affected_object in affected_objects:
+                    if affected_object not in objects_roles:
+                        permissions.append(
+                            permission_dict(affected_object, READ))
+                    else:
+                        has_write_permission = False
+                        for write_role, models in write_dict.items():
+                            if affected_object._meta.model in models and \
+                                    write_role in object_roles[affected_object]:
+                                has_write_permission = True
+                                break
+                        if has_write_permission:
+                            permissions.append(
+                                permission_dict(affected_object, WRITE))
+                        else:
+                            permissions.append(
+                                permission_dict(affected_object, READ))
+
+        return permissions
+
+    def get_tenant_permissions(self):
+        from core.models import Site, Slice
+        return self.get_object_permissions(filter_by=[Site, Slice])
+
+    @staticmethod
+    def select_by_user(user):
+        if user.is_admin:
+            qs = User.objects.all()
+        else:
+            # can see all users at any site where this user has pi role
+            from core.models.site import SitePrivilege
+            site_privs = SitePrivilege.objects.filter(user=user)
+            sites = [sp.site for sp in site_privs if sp.role.role in [
+                'Admin', 'admin', 'pi']]
+            # get site privs of users at these sites
+            site_privs = SitePrivilege.objects.filter(site__in=sites)
+            user_ids = [sp.user.id for sp in site_privs] + [user.id]
+            qs = User.objects.filter(Q(site__in=sites) | Q(id__in=user_ids))
+        return qs
+
+    def save_by_user(self, user, *args, **kwds):
+        if not self.can_update(user):
+            if getattr(self, "_cant_update_fieldName", None) is not None:
+                raise PermissionDenied("You do not have permission to update field %s on object %s" % (
+                    self._cant_update_fieldName, self.__class__.__name__))
+            else:
+                raise PermissionDenied(
+                    "You do not have permission to update %s objects" % self.__class__.__name__)
+
+        self.save(*args, **kwds)
+
+    def delete_by_user(self, user, *args, **kwds):
+        if not self.can_update(user):
+            raise PermissionDenied(
+                "You do not have permission to delete %s objects" % self.__class__.__name__)
+        self.delete(*args, **kwds)
+
+    def apply_profile(self, profile):
+        if profile == "regular":
+            self.is_appuser = False
+            self.is_admin = False
+
+        elif profile == "cp":
+            self.is_appuser = True
+            self.is_admin = False
+            for db in self.userdashboardviews.all():
+                db.delete()
+
+
+class UserDashboardView(PlCoreBase):
+    user = models.ForeignKey(User, related_name='userdashboardviews')
+    dashboardView = models.ForeignKey(
+        DashboardView, related_name='userdashboardviews')
+    order = models.IntegerField(default=0)
diff --git a/xos/core/models/xosmodel.py b/xos/core/models/xosmodel.py
new file mode 100644
index 0000000..ea53bd1
--- /dev/null
+++ b/xos/core/models/xosmodel.py
@@ -0,0 +1,46 @@
+import os
+from django.db import models
+from core.models import PlCoreBase
+from core.models.plcorebase import StrippedCharField
+
+# XOS: Serves as the root of the build system
+
+
+
+class XOS(PlCoreBase):
+    name = StrippedCharField(max_length=200, unique=True, help_text="Name of XOS", default="XOS")
+    ui_port = models.IntegerField(help_text="Port for XOS UI", default=80)
+    bootstrap_ui_port = models.IntegerField(help_text="Port for XOS UI", default=81)
+    db_container_name = StrippedCharField(max_length=200, help_text="name of XOS db container", default="xos_db")
+    docker_project_name = StrippedCharField(max_length=200, help_text="docker project name")
+    enable_build = models.BooleanField(help_text="True if Onboarding Synchronizer should build XOS as necessary", default=True)
+    frontend_only = models.BooleanField(help_text="If True, XOS will not start synchronizer containers", default=False)
+    source_ui_image = StrippedCharField(max_length=200, default="xosproject/xos")
+
+    def __unicode__(self):  return u'%s' % (self.name)
+
+    def __init__(self, *args, **kwargs):
+        super(XOS, self).__init__(*args, **kwargs)
+
+    def save(self, *args, **kwds):
+        super(XOS, self).save(*args, **kwds)
+
+#    def can_update(self, user):
+#        return user.can_update_site(self.site, allow=['tech'])
+
+    def rebuild(self):
+        for service_controller in self.service_controllers.all():
+            for scr in service_controller.service_controller_resources.all():
+               scr.save()
+            service_controller.save()
+        self.save()
+
+class XOSVolume(PlCoreBase):
+    xos = models.ForeignKey(XOS, related_name='volumes', help_text="The XOS object for this Volume")
+    container_path=StrippedCharField(max_length=1024, unique=True, help_text="Path of Volume in Container")
+    host_path=StrippedCharField(max_length=1024, help_text="Path of Volume in Host")
+    read_only=models.BooleanField(default=False, help_text="True if mount read-only")
+
+    def __unicode__(self): return u'%s' % (self.container_path)
+
+
diff --git a/xos/core/serializers.py b/xos/core/serializers.py
new file mode 100644
index 0000000..d84f111
--- /dev/null
+++ b/xos/core/serializers.py
@@ -0,0 +1,269 @@
+from django.forms import widgets
+from rest_framework import serializers
+from core.models import *
+
+
+class DeploymentSerializer(serializers.HyperlinkedModelSerializer):
+
+    # HyperlinkedModelSerializer doesn't include the id by default
+    id = serializers.Field()
+    sites = serializers.HyperlinkedRelatedField(view_name='site-detail')
+    class Meta:
+        model = Deployment
+        fields = ('id',
+                  'url',
+                  'name',
+                  'sites'
+                 )
+
+class ImageSerializer(serializers.HyperlinkedModelSerializer):
+    # HyperlinkedModelSerializer doesn't include the id by default
+    id = serializers.Field()
+    class Meta:
+        model = Image
+        fields = ('id',
+                  'url',
+                  'image_id',
+                  'name',
+                  'disk_format',
+                  'container_format')
+
+class NodeSerializer(serializers.HyperlinkedModelSerializer):
+    # HyperlinkedModelSerializer doesn't include the id by default
+    id = serializers.Field()
+    class Meta:
+        model = Node
+        fields = ('id',
+                 'url',
+                 'name')
+
+class ProjectSerializer(serializers.HyperlinkedModelSerializer):
+    # HyperlinkedModelSerializer doesn't include the id by default
+    id = serializers.Field()
+    class Meta:
+        model = Project
+        fields = ('id',
+                 'url',
+                 'name')
+
+class ReservationSerializer(serializers.HyperlinkedModelSerializer):
+    # HyperlinkedModelSerializer doesn't include the id by default
+    id = serializers.Field()
+    class Meta:
+        model = Reservation
+        fields = ('id',
+                 'url',
+                 'startTime',
+                 'slice',
+                 'duration',
+                 'endTime',
+                 )
+
+class RoleSerializer(serializers.HyperlinkedModelSerializer):
+    # HyperlinkedModelSerializer doesn't include the id by default
+    id = serializers.Field()
+    class Meta:
+        model = Role
+        fields = ('id', 
+                 'url',
+                 'role',
+                 'role_type')
+
+
+class ServiceClassSerializer(serializers.HyperlinkedModelSerializer):
+    # HyperlinkedModelSerializer doesn't include the id by default
+    id = serializers.Field()
+    class Meta:
+        model = ServiceClass
+        fields = ('id',
+                 'url',
+                 'name',
+                 'description',
+                 'commitment',
+                 'membershipFee',
+                 'membershipFeeMonths',
+                 'upgradeRequiresApproval',
+                 'upgradeFrom',
+                 )
+
+class ServiceResourceSerializer(serializers.HyperlinkedModelSerializer):
+    # HyperlinkedModelSerializer doesn't include the id by default
+    id = serializers.Field()
+    serviceClass = serializers.HyperlinkedRelatedField(view_name='serviceclass-detail')
+    class Meta:
+        model = ServiceResource
+        fields = ('id',
+                 'url',
+                 'name',
+                 'serviceClass',
+                 'maxUnitsDeployment',
+                 'maxUnitsNode',
+                 'maxDuration',
+                 'bucketInRate',
+                 'bucketMaxSize',
+                 'cost',
+                 'calendarReservable',
+                 )
+
+class SliceSerializer(serializers.HyperlinkedModelSerializer):
+    # HyperlinkedModelSerializer doesn't include the id by default
+    id = serializers.Field()
+    site = serializers.HyperlinkedRelatedField(view_name='site-detail')
+    instances = serializers.HyperlinkedRelatedField(view_name='instance-detail')
+    class Meta:
+        model = Slice
+        fields = ('id',
+                  'url',
+                  'tenant_id',
+                  'enabled',
+                  'name',
+                  'url',
+                  'omf_friendly',
+                  'description',
+                  'slice_url',
+                  'network_id',
+                  'router_id',
+                  'subnet_id',
+                  'imagePreference',
+		  'network',
+		  'mountDataSets',
+                  'site',
+                  'instances',
+                  'updated',
+                  'created')
+
+class SlicePrivilegeSerializer(serializers.HyperlinkedModelSerializer):
+    id = serializers.Field()
+    slice = serializers.HyperlinkedRelatedField(view_name='slice-detail')
+    user = serializers.HyperlinkedRelatedField(view_name='user-detail')
+    role = serializers.HyperlinkedRelatedField(view_name='role-detail')
+    class Meta:
+        model = SlicePrivilege
+        fields = ('id',
+                  'url',
+                  'user',
+                  'slice',
+                  'role')
+
+class SiteSerializer(serializers.HyperlinkedModelSerializer):
+
+    #Experimenting with whether to use ids, hyperlinks, or nested includes
+    #slices = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
+    #slices = serializers.RelatedField(many=True, read_only=True)
+    #slices = SliceSerializer(many=True)
+    # HyperlinkedModelSerializer doesn't include the id by default
+    id = serializers.Field()
+    slices = serializers.HyperlinkedRelatedField(many=True, read_only=True,view_name='slice-detail')
+
+    class Meta:
+        model = Site
+        fields = ('id',
+                  'url',
+                  'name',
+                  'slices',
+                  'site_url',
+                  'enabled',
+                  'longitude',
+                  'latitude',
+                  'login_base',
+                  'tenant_id',
+                  'is_public',
+                  'abbreviated_name',
+                  'updated',
+                  'created')
+
+class SitePrivilegeSerializer(serializers.HyperlinkedModelSerializer):
+    id = serializers.Field()
+    site = serializers.HyperlinkedRelatedField(view_name='site-detail')
+    user = serializers.HyperlinkedRelatedField(view_name='user-detail')
+    role = serializers.HyperlinkedRelatedField(view_name='role-detail')
+    class Meta:
+        model = SitePrivilege
+        fields = ('id',
+                  'url',
+                  'user',
+                  'site',
+                  'role')
+
+class InstanceSerializer(serializers.HyperlinkedModelSerializer):
+    # HyperlinkedModelSerializer doesn't include the id by default
+    id = serializers.Field()
+    image = serializers.HyperlinkedRelatedField(view_name='image-detail')
+    slice = serializers.HyperlinkedRelatedField(view_name='slice-detail')
+    deploymentNetwork = serializers.HyperlinkedRelatedField(view_name='deployment-detail')
+    node = serializers.HyperlinkedRelatedField(view_name='node-detail')
+    
+    #slice = serializers.PrimaryKeyRelatedField(read_only=True)
+
+    class Meta:
+        model = Instance
+        fields = ('id',
+                  'url',
+                  'instance_id',
+                  'name',
+                  'instance_name',
+                  'ip',
+                  'image',
+                  'slice',
+                  'deploymentNetwork',
+                  'node')
+
+class UserSerializer(serializers.HyperlinkedModelSerializer):
+    # HyperlinkedModelSerializer doesn't include the id by default
+    id = serializers.Field()
+    site = serializers.HyperlinkedRelatedField(view_name='site-detail')
+    slice_privileges = serializers.HyperlinkedRelatedField(view_name='sliceprivilege-detail')
+    site_privileges = serializers.HyperlinkedRelatedField(view_name='siteprivilege-detail')
+    class Meta:
+        model = User
+        fields = ('id',
+                  'url',
+                  'kuser_id', 
+                  'firstname', 
+                  'lastname',
+                  'email', 
+                  'password',
+                  'phone',
+                  'public_key', 
+                  'user_url',
+                  'is_admin',
+                  'slice_privileges',
+                  'site_privileges')
+                    
+class TagSerializer(serializers.HyperlinkedModelSerializer):
+    # HyperlinkedModelSerializer doesn't include the id by default
+    id = serializers.Field()
+    project = serializers.HyperlinkedRelatedField(view_name='project-detail')
+    #content_type = serializers.PrimaryKeyRelatedField(read_only=True)
+    content_type = serializers.RelatedField(source = "content_type")
+    content_object = serializers.RelatedField(source='content_object')
+    class Meta:
+        model = Tag
+        fields = ('id', 
+                  'url',
+                  'project',
+                  'value',
+                  'content_type',
+                  'object_id',
+                  'content_object',
+                  'name')
+
+serializerLookUp = { 
+                 Deployment: DeploymentSerializer,
+                 Image: ImageSerializer,
+                 Node: NodeSerializer,
+                 Project: ProjectSerializer,
+                 Reservation: ReservationSerializer,
+                 Role: RoleSerializer,
+                 ServiceClass: ServiceClassSerializer,
+                 ServiceResource: ServiceResourceSerializer,
+                 Site: SiteSerializer,
+                 SitePrivilege: SitePrivilegeSerializer,
+                 Slice: SliceSerializer,
+                 SlicePrivilege: SlicePrivilegeSerializer,
+                 Instance: InstanceSerializer,
+                 Tag: TagSerializer,
+                 User: UserSerializer,
+                 None: None,
+                }
+
diff --git a/xos/core/static/.gitignore b/xos/core/static/.gitignore
new file mode 100644
index 0000000..c148592
--- /dev/null
+++ b/xos/core/static/.gitignore
@@ -0,0 +1,4 @@
+*.css
+!xos.css
+!cord.css
+!xosNgLib.css
\ No newline at end of file
diff --git a/xos/core/static/Deployments.png b/xos/core/static/Deployments.png
new file mode 100644
index 0000000..5d152ed
--- /dev/null
+++ b/xos/core/static/Deployments.png
Binary files differ
diff --git a/xos/core/static/Deployments_over.png b/xos/core/static/Deployments_over.png
new file mode 100644
index 0000000..8e2f008
--- /dev/null
+++ b/xos/core/static/Deployments_over.png
Binary files differ
diff --git a/xos/core/static/Home.png b/xos/core/static/Home.png
new file mode 100644
index 0000000..20eb6f0
--- /dev/null
+++ b/xos/core/static/Home.png
Binary files differ
diff --git a/xos/core/static/Home_over.png b/xos/core/static/Home_over.png
new file mode 100644
index 0000000..64b047d
--- /dev/null
+++ b/xos/core/static/Home_over.png
Binary files differ
diff --git a/xos/core/static/Reservations.png b/xos/core/static/Reservations.png
new file mode 100644
index 0000000..94a993d
--- /dev/null
+++ b/xos/core/static/Reservations.png
Binary files differ
diff --git a/xos/core/static/Reservations_over.png b/xos/core/static/Reservations_over.png
new file mode 100644
index 0000000..5a5835a
--- /dev/null
+++ b/xos/core/static/Reservations_over.png
Binary files differ
diff --git a/xos/core/static/Search.png b/xos/core/static/Search.png
new file mode 100644
index 0000000..34833a2
--- /dev/null
+++ b/xos/core/static/Search.png
Binary files differ
diff --git a/xos/core/static/Services.png b/xos/core/static/Services.png
new file mode 100644
index 0000000..f6d60c3
--- /dev/null
+++ b/xos/core/static/Services.png
Binary files differ
diff --git a/xos/core/static/Services_over.png b/xos/core/static/Services_over.png
new file mode 100644
index 0000000..828c790
--- /dev/null
+++ b/xos/core/static/Services_over.png
Binary files differ
diff --git a/xos/core/static/Sites.png b/xos/core/static/Sites.png
new file mode 100644
index 0000000..fac5fa4
--- /dev/null
+++ b/xos/core/static/Sites.png
Binary files differ
diff --git a/xos/core/static/Sites_over.png b/xos/core/static/Sites_over.png
new file mode 100644
index 0000000..9378984
--- /dev/null
+++ b/xos/core/static/Sites_over.png
Binary files differ
diff --git a/xos/core/static/Slices.png b/xos/core/static/Slices.png
new file mode 100644
index 0000000..fb06041
--- /dev/null
+++ b/xos/core/static/Slices.png
Binary files differ
diff --git a/xos/core/static/Slices_over.png b/xos/core/static/Slices_over.png
new file mode 100644
index 0000000..441d5ae
--- /dev/null
+++ b/xos/core/static/Slices_over.png
Binary files differ
diff --git a/xos/core/static/Users.png b/xos/core/static/Users.png
new file mode 100644
index 0000000..7e6d096
--- /dev/null
+++ b/xos/core/static/Users.png
Binary files differ
diff --git a/xos/core/static/Users_over.png b/xos/core/static/Users_over.png
new file mode 100644
index 0000000..9ffb418
--- /dev/null
+++ b/xos/core/static/Users_over.png
Binary files differ
diff --git a/xos/core/static/bg.jpg b/xos/core/static/bg.jpg
new file mode 100644
index 0000000..9ad9e54
--- /dev/null
+++ b/xos/core/static/bg.jpg
Binary files differ
diff --git a/xos/core/static/bg2.jpg b/xos/core/static/bg2.jpg
new file mode 100644
index 0000000..ba8dfe4
--- /dev/null
+++ b/xos/core/static/bg2.jpg
Binary files differ
diff --git a/xos/core/static/chartsBg.jpg b/xos/core/static/chartsBg.jpg
new file mode 100644
index 0000000..386614f
--- /dev/null
+++ b/xos/core/static/chartsBg.jpg
Binary files differ
diff --git a/xos/core/static/cord-bg-old.jpg b/xos/core/static/cord-bg-old.jpg
new file mode 100644
index 0000000..08df91d
--- /dev/null
+++ b/xos/core/static/cord-bg-old.jpg
Binary files differ
diff --git a/xos/core/static/cord-favicon.png b/xos/core/static/cord-favicon.png
new file mode 100644
index 0000000..758902e
--- /dev/null
+++ b/xos/core/static/cord-favicon.png
Binary files differ
diff --git a/xos/core/static/cord-logo.png b/xos/core/static/cord-logo.png
new file mode 100644
index 0000000..c2ff252
--- /dev/null
+++ b/xos/core/static/cord-logo.png
Binary files differ
diff --git a/xos/core/static/cord.css b/xos/core/static/cord.css
new file mode 100644
index 0000000..45f75eb
--- /dev/null
+++ b/xos/core/static/cord.css
@@ -0,0 +1,43 @@
+/* login page background image */
+.login {
+    background-image: url('cord_bg.jpg');
+    background-size: 100%;
+    background-repeat: no-repeat;
+}
+
+/* login page logo */
+.login #content-main h1 {
+    background: url("cord_logo_3.png") no-repeat scroll 40% center / 89% auto rgba(235, 240, 242, 0);
+    height: 55px;
+    background-repeat: no-repeat;
+    font-size: 0px;
+    padding-top: 70px;
+}
+
+/* content page logo */
+.logo {
+   display: block;

+   -moz-box-sizing: border-box;

+   box-sizing: border-box;

+   background: url('cord_logo_3_cropped_sized.png') no-repeat;

+   width: 250px;

+   height: 96px;

+   padding-left: 250px;

+}
+
+/* content page header, adjust the margin to match logo */
+.header{

+    margin-top: -100px !important;

+}

+

+/* hide the quick search box */

+.nav-quick-search {

+    display: None;

+}

+

+

+

+

+

+

+

diff --git a/xos/core/static/dashboardStatic.PNG b/xos/core/static/dashboardStatic.PNG
new file mode 100644
index 0000000..eb3ba80
--- /dev/null
+++ b/xos/core/static/dashboardStatic.PNG
Binary files differ
diff --git a/xos/core/static/down_arrow.png b/xos/core/static/down_arrow.png
new file mode 100644
index 0000000..e727172
--- /dev/null
+++ b/xos/core/static/down_arrow.png
Binary files differ
diff --git a/xos/core/static/favicon.png b/xos/core/static/favicon.png
new file mode 100644
index 0000000..d49afe0
--- /dev/null
+++ b/xos/core/static/favicon.png
Binary files differ
diff --git a/xos/core/static/hpc_historical.css b/xos/core/static/hpc_historical.css
new file mode 100644
index 0000000..7be52db
--- /dev/null
+++ b/xos/core/static/hpc_historical.css
@@ -0,0 +1,50 @@
+.row {
+  margin-right: -15px;
+  margin-left: -15px;
+}
+
+.row:before,
+.row:after {
+  display: table;
+  content: " ";
+}
+
+.row:after {
+  clear: both;
+}
+
+.row:before,
+.row:after {
+  display: table;
+  content: " ";
+}
+
+.row:after {
+  clear: both;
+}
+
+.graph_container {
+  width: 800px;
+}
+
+.col-md-halfgraph,
+.col-md-fullgraph {
+  position: relative;
+  min-height: 1px;
+  padding-right: 15px;
+  padding-left: 15px;
+}
+
+.col-md-halfgraph,
+.col-md-fullgraph {
+  float: left;
+}
+.col-md-halfgraph {
+  width: 350px;
+}
+.col-md-fullgraph {
+  width: 700px;
+}
+.col-md-12 {
+  width: 100%;
+}
diff --git a/xos/core/static/img/bg_left_white.gif b/xos/core/static/img/bg_left_white.gif
new file mode 100644
index 0000000..7407236
--- /dev/null
+++ b/xos/core/static/img/bg_left_white.gif
Binary files differ
diff --git a/xos/core/static/img/brokencircle.gif b/xos/core/static/img/brokencircle.gif
new file mode 100644
index 0000000..db4f155
--- /dev/null
+++ b/xos/core/static/img/brokencircle.gif
Binary files differ
diff --git a/xos/core/static/img/green-cloud.gif b/xos/core/static/img/green-cloud.gif
new file mode 100644
index 0000000..0a80d7d
--- /dev/null
+++ b/xos/core/static/img/green-cloud.gif
Binary files differ
diff --git a/xos/core/static/img/minus_circle.png b/xos/core/static/img/minus_circle.png
new file mode 100644
index 0000000..e0cd5a8
--- /dev/null
+++ b/xos/core/static/img/minus_circle.png
Binary files differ
diff --git a/xos/core/static/img/plus_circle.png b/xos/core/static/img/plus_circle.png
new file mode 100644
index 0000000..49746a1
--- /dev/null
+++ b/xos/core/static/img/plus_circle.png
Binary files differ
diff --git a/xos/core/static/img/red-cloud.gif b/xos/core/static/img/red-cloud.gif
new file mode 100644
index 0000000..3025720
--- /dev/null
+++ b/xos/core/static/img/red-cloud.gif
Binary files differ
diff --git a/xos/core/static/js/Leaflet.MakiMarkers.js b/xos/core/static/js/Leaflet.MakiMarkers.js
new file mode 100644
index 0000000..910bb31
--- /dev/null
+++ b/xos/core/static/js/Leaflet.MakiMarkers.js
@@ -0,0 +1,101 @@
+/*
+ * Leaflet plugin to create map icons using Maki Icons from MapBox.
+ *
+ * References:
+ *   Maki Icons: https://www.mapbox.com/maki/
+ *   MapBox Marker API: https://www.mapbox.com/developers/api/#Stand-alone.markers
+ *
+ * Usage:
+ *   var icon = L.MakiMarkers.icon({icon: "rocket", color: "#b0b", size: "m"});
+ *
+ * License:
+ *   MIT: http://jseppi.mit-license.org/
+ */
+(function () {
+  "use strict";
+  L.MakiMarkers = {
+    // Available Maki Icons
+    icons: ["circle-stroked", "circle", "square-stroked", "square",
+      "triangle-stroked", "triangle", "star-stroked", "star", "cross",
+      "marker-stroked", "marker", "religious-jewish", "religious-christian",
+      "religious-muslim", "cemetery", "rocket", "airport", "heliport", "rail",
+      "rail-metro", "rail-light", "bus", "fuel", "parking", "parking-garage",
+      "airfield", "roadblock", "ferry", "harbor", "bicycle", "park", "park2",
+      "museum", "lodging", "monument", "zoo", "garden", "campsite", "theatre",
+      "art-gallery", "pitch", "soccer", "america-football", "tennis", "basketball",
+      "baseball", "golf", "swimming", "cricket", "skiing", "school", "college",
+      "library", "post", "fire-station", "town-hall", "police", "prison",
+      "embassy", "beer", "restaurant", "cafe", "shop", "fast-food", "bar", "bank",
+      "grocery", "cinema", "pharmacy", "hospital", "danger", "industrial",
+      "warehouse", "commercial", "building", "place-of-worship", "alcohol-shop",
+      "logging", "oil-well", "slaughterhouse", "dam", "water", "wetland",
+      "disability", "telephone", "emergency-telephone", "toilets", "waste-basket",
+      "music", "land-use", "city", "town", "village", "farm", "bakery", "dog-park",
+      "lighthouse", "clothing-store", "polling-place", "playground", "entrance",
+      "heart", "london-underground", "minefield", "rail-underground", "rail-above",
+      "camera", "laundry", "car", "suitcase", "hairdresser", "chemist"],
+    defaultColor: "#0a0",
+    defaultIcon: "circle-stroked",
+    defaultSize: "m",
+    apiUrl: "https://api.tiles.mapbox.com/v3/marker/",
+    smallOptions: {
+      iconSize: [20, 50],
+      popupAnchor: [0,-20]
+    },
+    mediumOptions: {
+      iconSize: [30,70],
+      popupAnchor: [0,-30]
+    },
+    largeOptions: {
+      iconSize: [36,90],
+      popupAnchor: [0,-40]
+    }
+  };
+
+  L.MakiMarkers.Icon = L.Icon.extend({
+    options: {
+      //Maki icon: any from https://www.mapbox.com/maki/ (ref: L.MakiMarkers.icons)
+      icon: L.MakiMarkers.defaultIcon,
+      //Marker color: short or long form hex color code
+      color: L.MakiMarkers.defaultColor,
+      //Marker size: "s" (small), "m" (medium), or "l" (large)
+      size: L.MakiMarkers.defaultSize,
+      shadowAnchor: null,
+      shadowSize: null,
+      shadowUrl: null,
+      className: 'maki-marker'
+    },
+
+    initialize: function(options) {
+      var pin;
+
+      options = L.setOptions(this, options);
+
+      switch (options.size) {
+        case "s":
+          L.extend(options, L.MakiMarkers.smallOptions);
+          break;
+        case "l":
+          L.extend(options, L.MakiMarkers.largeOptions);
+          break;
+        default:
+          options.size = "m";
+          L.extend(options, L.MakiMarkers.mediumOptions);
+          break;
+      }
+
+      if (options.color.charAt(0) === '#') {
+        options.color = options.color.substr(1);
+      }
+
+      pin = "pin-" + options.size + "-" + options.icon + "+" +
+        options.color + ".png";
+
+      options.iconUrl = "" + L.MakiMarkers.apiUrl + pin;
+    }
+  });
+
+  L.MakiMarkers.icon = function(options) {
+    return new L.MakiMarkers.Icon(options);
+  };
+})();
diff --git a/xos/core/static/log4javascript-1.4.6/changelog.txt b/xos/core/static/log4javascript-1.4.6/changelog.txt
new file mode 100644
index 0000000..fe10b97
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/changelog.txt
@@ -0,0 +1,379 @@
+log4javascript change log

+-------------------------

+

+1.4.6 (19/3/2013)

+- Added fix to handle 1223 status code from XMLHttpRequest in IE

+

+1.4.5 (20/2/2013)

+- Changed AjaxAppender to send raw data rather than URL-encoded form data when

+  content-type is not "application/x-www-form-urlencoded"

+

+- Exposed sendAllRemaining() method of AjaxAppender

+

+1.4.4 (8/2/2013)

+- Fixed issue with repeated Content-Type headers in AjaxAppender

+

+- Improved uniqueness of PopUpAppender window name

+

+1.4.3 (18/9/2012)

+- Added addHeader() and getHeaders() methods to AjaxAppender

+

+- Modified sendAllOnUnload feature of AjaxAppender. It now works in WebKit but

+  at the expense of popping up a confirm dialog. That being the case, it is now

+  disabled by default.

+

+- Removed leaked global variable "initialized" 

+

+- Fixed bugs #3528265, #3560924, #3560922, #2805479, #3510639 on Sourceforge

+  Tracker

+

+

+1.4.2 (13/10/2011)

+- Fixed JsonLayout trailing comma issue. See

+  http://stackoverflow.com/questions/7735382/asmx-weirdness-deserializing-json-

+  blob-from-log4javascript-logging

+

+- Fixed bugs #3401332, #3185753, #2884623, #2817213 on Sourceforge Tracker

+

+

+1.4.1 (23/3/2009)

+- Fixed document.domain/query string bug (#2519903 on Sourceforge Tracker)

+

+- Added isVisible() method to PopUpAppender

+

+- Added check for whether the console has been closed in isVisible() method of

+  InPageAppender

+

+- Included unit tests in the distribution

+

+

+1.4 (30/10/2008)

+

+- Added time() and timeEnd() methods to Logger

+

+- Added group() and groupEnd() methods to Logger and support for displaying

+  expandable groups to InPageAppender and PopUpAppender

+

+- Added facility to layout custom fields. A custom field value may now

+  optionally be a function which is passed a reference to the layout and a

+  logging event and run at the time the layout's format method is called

+

+- Added option to XmlLayout and JsonLayout to allow multiple messages to be

+  formatted either as one combined message or multiple messages

+

+- Added code to set log4javascript as a property of the window object. This

+  ensures that if log4javascript is loaded via eval() (e.g. Dojo's module

+  loading system), the log4javascript object is guaranteed to be available even

+  though IE does not evaluate the script in the global scope

+

+- Added useDocumentWrite parameter to constructors and isUseDocumentWrite()

+  and setUseDocumentWrite() methods for InPageAppender and PopUpAppender and

+  added console.html to the build so that the appender may use either the

+  existing document.write method or the external HTML file to build the console.

+  This is to allow support for setting document.domain in the main document,

+  which is impossible with the document.write method

+

+- Added milliseconds property to logging events and changed JsonLayout,

+  XmlLayout and HttpPostDataLayout to include milliseconds by default

+

+- Added layout parameter to AjaxAppender and a toString() method on each layout

+

+- Setting configuration properties in appenders via constructor paramaters has

+  been phased out.

+

+- Added window.unload handler for AjaxAppender to send outstanding messages.

+  Doesn't work in Opera

+

+- Implemented log4j-style hierarchical loggers with additive appenders. For

+  example, a logger called "app.stuff" has as its parent the logger called

+  "app", all of whose appenders it inherits

+

+- Changed XmlLayout and JsonLayout to send data as a key/value pair

+

+- Bugfix for inaccessible error details

+

+- An appender can no longer be added more than once to the same logger

+

+- Multiple messages may now be specified in logger methods

+

+- New conversion character 'a' added to PatternLayout. This is the same as 'm'

+  except that if the first message specified is an array then it treats each

+  element of the array as though it had been passed in as a message parameter

+

+- Command line added to console windows with configurable object expansion

+  depth. Command line presence and object expansion depth are configurable in

+  the appender via setShowCommandLine() and setCommandLineObjectExpansionDepth()

+  methods respectively

+

+- Command line history, navigated by cursor keys and stored in a session cookie

+

+- Firebug-inspired command line functions added: $, dir, dirxml, cd, clear,

+  keys, values, expansionDepth

+

+- Fixes for several bugs in object expansion

+

+- Fix for bug in initialization of InPageAppender in IE 5

+

+- Fix to allow searchable HTML in log entries

+

+- Fix for bug which automatically displayed search next/previous buttons when

+  the search box is clicked regardless of whether there were any matches

+

+- Searches in PopUpAppender and InPageAppender now preserve formatting

+

+- More fixes to interaction of search and severity filters in console window

+  used by PopUpAppender and InPageAppender

+

+- Added SwitchableConsoleAppender that allows flipping from an in-page console

+  to a pop-up console window and back again while retaining state

+

+- Custom events added that are raised when PopUpAppender and InPageAppender

+  windows load and unload, and on the main log4javascript object when the main

+  page loads, when the main page is resized and when log4javascript errors occur

+

+- InPageAppender may now be initialized before the page loads by providing an

+  element id for its container, or omitting the container altogether (in which

+  case the appender is added as a fixed div at the bottom of the page)

+

+- Tweaked PopUpAppender and InPageAppender so that the formatted log message is

+  produced when append() is called rather than when the message is actually sent

+  to the console window, thus allowing reliable temporary switching of layouts

+

+- Much improved scrolling to current search match: scrolls only if part of the

+  search match is not visible and centres around it rather than putting flush to

+  the top left

+

+- Removed setReadable() method from JsonLayout - now specified only in the

+  constructor

+

+- Fixed problem in IE where copying selections of log entries would produce two

+  copies of each log entry

+

+

+1.3.1 (20/11/2006)

+

+- Fix to interaction of search and severity filters in console window used by

+  PopUpAppender and InPageAppender

+

+

+1.3 (19/10/2006)

+

+- Fully tested and supported in IE 7 Beta 3

+

+- Added support for FireBug logging levels in BrowserConsoleAppender

+

+- Added optional limit to the number of log messages stored by PopUpAppender and

+  InPageAppender. When this limit is reached, each new message causes the oldest

+  message to be discarded.

+

+- Exceptions passed into logging methods are now displayed in logging output.

+

+- Added facility to pass objects as well as strings to logging methods.

+  Enhanced conversion character 'm' to PatternLayout to expand object properties

+  in the formatted output

+

+- Added stack trace to error reports (alerts and log entries) in Firefox. This

+  is turned off by default but can be switched on via the new

+  log4javascript.setShowStackTraces function

+

+- Added log4javascript_stub.js to distribution - this has stub versions of all

+  objects and methods in log4javascript.js and can be used as a lightweight

+  replacement for log4javascript.js in production systems

+

+- Added log4javascript_compressed.js to distribution - comments and whitespace

+  are removed, resulting in a 30% smaller file

+

+- Added custom fields to layouts

+

+- Added setReopenWhenClosed and isReopenWhenClosed methods to PopUpAppender to

+  allow log4javascript to open a new pop-up console window automatically at the

+  time of the next log entry after the original window was closed

+

+- Layout.ignoresThrowable implemented to allow Layout/Appender combinations to

+  decide whether to display exceptions

+

+- Added NullLayout that performs no formatting on the logging event

+

+- Lowered BrowserConsoleAppender's default threshold to DEBUG and set its

+  default layout to NullLayout so that unformatted objects can be passed into

+  FireBug

+

+- Renamed InlineAppender to InPageAppender (though InlineAppender still works

+  for the sake of backwards compatibility)

+

+- Cosmetic changes to InPageAppender and PopUpAppender

+

+- Added equals() method to Level

+

+- Added removeAppender() and removeAllAppenders() methods to Logger

+

+- Added extensive test script

+

+- Fixed bug where Appender.setLayout and Appender.setThreshold threw an

+  unhandled error if not supplied with a genuine Layout or Level respectively

+

+- Fixed bug where InlinePopUpAppender and PopUpAppender continue to poll their

+  console windows indefinitely (thus generating warnings) if the console window

+  is closed before it has fully loaded

+

+- Fixed bug in w and W symbols in SimpleDateFormat

+

+- Fixed bug with quotes inside messages in JsonLayout

+

+- Fixed bugs in PatternLayout with built-in DATE format and truncation modifiers

+

+- Changed execution order of callbacks in AjaxAppender so that

+  requestSuccessCallback is guaranteed to be called before the next request is

+  sent

+

+- Changed AjaxAppender so that log messages are formatted immediately before

+  a request is sent rather than when append() is called, thus guaranteeing that

+  changes to the layout take effect immediately

+

+- PopUpAppender windows now have unique names per hostname to prevent clashes

+  from multiple instances of log4javascript running on different servers

+

+- Fixed error in XmlLayout's format method when passed an object

+

+- Fixed errors in JsonLayout's handling of strings containing line breaks and/or

+  double quotes

+

+

+1.2 (21/6/2006)

+

+- Tested in and added workaround for a bug in Opera 9 Beta 2 and Opera 9.0

+

+- Tested in Konqueror 3.4 and 3.5 and added workarounds and fixes for browser

+  bugs

+

+- Added addErrorListener and removeErrorListener methods to log4javascript

+  object to allow custom error handling

+

+- Added close() method to PopUpAppender and InlineAppender

+

+- Added test directory with an HTML page containing automated tests

+

+- Added enable/disable logging checkbox to InlinePopUpAppender and PopUpAppender

+  so that unnecessary messages (for instance, from a timer) can be ignored

+

+- An invalid value supplied to a configuration option setter now leaves config

+  property unchanged rather than reverting to the default

+

+- Fixed bug in PopUpAppender in IE on Windows XP Service Pack 2 when accessed

+  via the file system. The browser by default disables JavaScript in the pop-up

+  window until the user opts to enable it, at which point they would previously

+  see an uncaught error in log4javascript. Now, a proper error message is

+  displayed and the appender is disabled.

+

+- Slight alterations to toolbar in InlineAppender and PopUpAppender - text

+  capitalization and title attributes added to inputs

+

+- toString() method added to all appenders

+

+- Correction to errors in XmlLayout's output

+

+- Documentation corrections and additions

+

+

+1.1.1 (17/5/2006)

+

+- Fixed a minor bug with scrolling to the latest message and added "scroll to

+  latest" checkbox to console window in InlineAppender and PopUpAppender

+

+

+1.1 (16/5/2006)

+

+- Added configuration option setters on Appenders and refactored to prevent

+  config properties being altered directly. Several configuration options

+  may not be altered after the appender has been initialized

+

+- Added scrollToLatestMessage constructor parameter, isScrollToLatestMessage

+  and setScrollToLatestMessage methods to InlineAppender and PopUpAppender

+

+- Added isVisible method to InlineAppender

+

+- Changed setShowOneError to setAlertAllErrors in logLog, with obvious change

+  in logic

+

+- Added layout property key configuration options to layout constructors for

+  JsonLayout and HttpPostDataLayout

+

+- Changed the default timestamp property name to "timestamp" instead of

+  "timeStamp" in JsonLayout and HttpPostDataLayout

+

+- Expanded documentation to include a section in the manual about configuring

+  appenders

+

+- Removed browser sniffing code

+

+

+1.0.1 (30/4/2006)

+

+- Option to have new log messages appear at the top added to InlineAppender and

+  PopUpAppender. This option can be specified in the constructor and can also

+  be toggled via a checkbox in the console window

+

+- PopUpAppender changed to not focus the pop-up console window by default, and

+  the demo page altered to create its own logger with focussing turned on,

+  meaning the behaviour in the demo is essentially unchanged

+

+

+1.0 (26/4/2006)

+

+- Tweaks to default values in PopUpAppender and InlineAppender

+

+- Bugfixes and stylistic tweaks resulting from running JSLint on

+  log4javascript.js

+

+

+1.0 beta 2

+

+- Show/hide button removed from InlineAppender, replaced by show() and hide()

+  methods on the InlineAppender object

+

+- batchSeparator, batchHeader and batchFooter added to Layout and applied to

+  JsonLayout - a batch of JSON log messages is now created as an array literal

+

+

+1.0 beta

+

+- TRACE level added, since this was added to log4j in 1.2.12

+

+- PopUpAppender default settings bugfix

+

+- getLevel method added to Logger

+

+- Tweak to vertical alignment of checkboxes and padding of buttons in

+  InlineAppender and PopUpAppender

+

+- Fixed getDefaultLogger and getNullLogger to return loggers other than the

+  root logger

+

+0.96

+

+- Moved console.html to inline document.writes in log4javascript.js

+

+- Fixed getDefaultLogger to return the same object on successive calls

+

+- Fixed scrolling issue in Opera InlineAppender and PopUpAppender

+

+- Scrollbars are now automatic on InlineAppender and PopUpAppender, i.e. they

+  only appear when required

+

+- Fixed bug where regex searches were not applied to new log entries in

+  InlineAppender and PopUpAppender

+

+- Changed Safari font size in InlineAppender and PopUpAppender

+

+0.95

+

+- AjaxAppender enhancements:

+	- waitForResponse added

+	- timer added

+

+- layout parameter added to all appender constructors

+

+0.94

+- First publicly available version

+- IE 5 support added

+- Full support for wrapping in IE added for InlineAppender and PopUpAppender
\ No newline at end of file
diff --git a/xos/core/static/log4javascript-1.4.6/console.html b/xos/core/static/log4javascript-1.4.6/console.html
new file mode 100644
index 0000000..476d272
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/console.html
@@ -0,0 +1,263 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+<head>

+<title>log4javascript</title>

+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

+<!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->

+<meta http-equiv="X-UA-Compatible" content="IE=7" />

+<script type="text/javascript">var isIe = false, isIePre7 = false;</script>

+<!--[if IE]><script type="text/javascript">isIe = true</script><![endif]-->

+<!--[if lt IE 7]><script type="text/javascript">isIePre7 = true</script><![endif]-->

+<script type="text/javascript">

+//<![CDATA[

+var loggingEnabled=true;var logQueuedEventsTimer=null;var logEntries=[];var logEntriesAndSeparators=[];var logItems=[];var renderDelay=100;var unrenderedLogItemsExist=false;var rootGroup,currentGroup=null;var loaded=false;var currentLogItem=null;var logMainContainer;function copyProperties(obj,props){for(var i in props){obj[i]=props[i];}}

+function LogItem(){}

+LogItem.prototype={mainContainer:null,wrappedContainer:null,unwrappedContainer:null,group:null,appendToLog:function(){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].appendToLog();}

+this.group.update();},doRemove:function(doUpdate,removeFromGroup){if(this.rendered){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].remove();}

+this.unwrappedElementContainer=null;this.wrappedElementContainer=null;this.mainElementContainer=null;}

+if(this.group&&removeFromGroup){this.group.removeChild(this,doUpdate);}

+if(this===currentLogItem){currentLogItem=null;}},remove:function(doUpdate,removeFromGroup){this.doRemove(doUpdate,removeFromGroup);},render:function(){},accept:function(visitor){visitor.visit(this);},getUnwrappedDomContainer:function(){return this.group.unwrappedElementContainer.contentDiv;},getWrappedDomContainer:function(){return this.group.wrappedElementContainer.contentDiv;},getMainDomContainer:function(){return this.group.mainElementContainer.contentDiv;}};LogItem.serializedItemKeys={LOG_ENTRY:0,GROUP_START:1,GROUP_END:2};function LogItemContainerElement(){}

+LogItemContainerElement.prototype={appendToLog:function(){var insertBeforeFirst=(newestAtTop&&this.containerDomNode.hasChildNodes());if(insertBeforeFirst){this.containerDomNode.insertBefore(this.mainDiv,this.containerDomNode.firstChild);}else{this.containerDomNode.appendChild(this.mainDiv);}}};function SeparatorElementContainer(containerDomNode){this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.className="separator";this.mainDiv.innerHTML="&nbsp;";}

+SeparatorElementContainer.prototype=new LogItemContainerElement();SeparatorElementContainer.prototype.remove=function(){this.mainDiv.parentNode.removeChild(this.mainDiv);this.mainDiv=null;};function Separator(){this.rendered=false;}

+Separator.prototype=new LogItem();copyProperties(Separator.prototype,{render:function(){var containerDomNode=this.group.contentDiv;if(isIe){this.unwrappedElementContainer=new SeparatorElementContainer(this.getUnwrappedDomContainer());this.wrappedElementContainer=new SeparatorElementContainer(this.getWrappedDomContainer());this.elementContainers=[this.unwrappedElementContainer,this.wrappedElementContainer];}else{this.mainElementContainer=new SeparatorElementContainer(this.getMainDomContainer());this.elementContainers=[this.mainElementContainer];}

+this.content=this.formattedMessage;this.rendered=true;}});function GroupElementContainer(group,containerDomNode,isRoot,isWrapped){this.group=group;this.containerDomNode=containerDomNode;this.isRoot=isRoot;this.isWrapped=isWrapped;this.expandable=false;if(this.isRoot){if(isIe){this.contentDiv=logMainContainer.appendChild(document.createElement("div"));this.contentDiv.id=this.isWrapped?"log_wrapped":"log_unwrapped";}else{this.contentDiv=logMainContainer;}}else{var groupElementContainer=this;this.mainDiv=document.createElement("div");this.mainDiv.className="group";this.headingDiv=this.mainDiv.appendChild(document.createElement("div"));this.headingDiv.className="groupheading";this.expander=this.headingDiv.appendChild(document.createElement("span"));this.expander.className="expander unselectable greyedout";this.expander.unselectable=true;var expanderText=this.group.expanded?"-":"+";this.expanderTextNode=this.expander.appendChild(document.createTextNode(expanderText));this.headingDiv.appendChild(document.createTextNode(" "+this.group.name));this.contentDiv=this.mainDiv.appendChild(document.createElement("div"));var contentCssClass=this.group.expanded?"expanded":"collapsed";this.contentDiv.className="groupcontent "+contentCssClass;this.expander.onclick=function(){if(groupElementContainer.group.expandable){groupElementContainer.group.toggleExpanded();}};}}

+GroupElementContainer.prototype=new LogItemContainerElement();copyProperties(GroupElementContainer.prototype,{toggleExpanded:function(){if(!this.isRoot){var oldCssClass,newCssClass,expanderText;if(this.group.expanded){newCssClass="expanded";oldCssClass="collapsed";expanderText="-";}else{newCssClass="collapsed";oldCssClass="expanded";expanderText="+";}

+replaceClass(this.contentDiv,newCssClass,oldCssClass);this.expanderTextNode.nodeValue=expanderText;}},remove:function(){if(!this.isRoot){this.headingDiv=null;this.expander.onclick=null;this.expander=null;this.expanderTextNode=null;this.contentDiv=null;this.containerDomNode=null;this.mainDiv.parentNode.removeChild(this.mainDiv);this.mainDiv=null;}},reverseChildren:function(){var node=null;var childDomNodes=[];while((node=this.contentDiv.firstChild)){this.contentDiv.removeChild(node);childDomNodes.push(node);}

+while((node=childDomNodes.pop())){this.contentDiv.appendChild(node);}},update:function(){if(!this.isRoot){if(this.group.expandable){removeClass(this.expander,"greyedout");}else{addClass(this.expander,"greyedout");}}},clear:function(){if(this.isRoot){this.contentDiv.innerHTML="";}}});function Group(name,isRoot,initiallyExpanded){this.name=name;this.group=null;this.isRoot=isRoot;this.initiallyExpanded=initiallyExpanded;this.elementContainers=[];this.children=[];this.expanded=initiallyExpanded;this.rendered=false;this.expandable=false;}

+Group.prototype=new LogItem();copyProperties(Group.prototype,{addChild:function(logItem){this.children.push(logItem);logItem.group=this;},render:function(){if(isIe){var unwrappedDomContainer,wrappedDomContainer;if(this.isRoot){unwrappedDomContainer=logMainContainer;wrappedDomContainer=logMainContainer;}else{unwrappedDomContainer=this.getUnwrappedDomContainer();wrappedDomContainer=this.getWrappedDomContainer();}

+this.unwrappedElementContainer=new GroupElementContainer(this,unwrappedDomContainer,this.isRoot,false);this.wrappedElementContainer=new GroupElementContainer(this,wrappedDomContainer,this.isRoot,true);this.elementContainers=[this.unwrappedElementContainer,this.wrappedElementContainer];}else{var mainDomContainer=this.isRoot?logMainContainer:this.getMainDomContainer();this.mainElementContainer=new GroupElementContainer(this,mainDomContainer,this.isRoot,false);this.elementContainers=[this.mainElementContainer];}

+this.rendered=true;},toggleExpanded:function(){this.expanded=!this.expanded;for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].toggleExpanded();}},expand:function(){if(!this.expanded){this.toggleExpanded();}},accept:function(visitor){visitor.visitGroup(this);},reverseChildren:function(){if(this.rendered){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].reverseChildren();}}},update:function(){var previouslyExpandable=this.expandable;this.expandable=(this.children.length!==0);if(this.expandable!==previouslyExpandable){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].update();}}},flatten:function(){var visitor=new GroupFlattener();this.accept(visitor);return visitor.logEntriesAndSeparators;},removeChild:function(child,doUpdate){array_remove(this.children,child);child.group=null;if(doUpdate){this.update();}},remove:function(doUpdate,removeFromGroup){for(var i=0,len=this.children.length;i<len;i++){this.children[i].remove(false,false);}

+this.children=[];this.update();if(this===currentGroup){currentGroup=this.group;}

+this.doRemove(doUpdate,removeFromGroup);},serialize:function(items){items.push([LogItem.serializedItemKeys.GROUP_START,this.name]);for(var i=0,len=this.children.length;i<len;i++){this.children[i].serialize(items);}

+if(this!==currentGroup){items.push([LogItem.serializedItemKeys.GROUP_END]);}},clear:function(){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].clear();}}});function LogEntryElementContainer(){}

+LogEntryElementContainer.prototype=new LogItemContainerElement();copyProperties(LogEntryElementContainer.prototype,{remove:function(){this.doRemove();},doRemove:function(){this.mainDiv.parentNode.removeChild(this.mainDiv);this.mainDiv=null;this.contentElement=null;this.containerDomNode=null;},setContent:function(content,wrappedContent){if(content===this.formattedMessage){this.contentElement.innerHTML="";this.contentElement.appendChild(document.createTextNode(this.formattedMessage));}else{this.contentElement.innerHTML=content;}},setSearchMatch:function(isMatch){var oldCssClass=isMatch?"searchnonmatch":"searchmatch";var newCssClass=isMatch?"searchmatch":"searchnonmatch";replaceClass(this.mainDiv,newCssClass,oldCssClass);},clearSearch:function(){removeClass(this.mainDiv,"searchmatch");removeClass(this.mainDiv,"searchnonmatch");}});function LogEntryWrappedElementContainer(logEntry,containerDomNode){this.logEntry=logEntry;this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.appendChild(document.createTextNode(this.logEntry.formattedMessage));this.mainDiv.className="logentry wrapped "+this.logEntry.level;this.contentElement=this.mainDiv;}

+LogEntryWrappedElementContainer.prototype=new LogEntryElementContainer();LogEntryWrappedElementContainer.prototype.setContent=function(content,wrappedContent){if(content===this.formattedMessage){this.contentElement.innerHTML="";this.contentElement.appendChild(document.createTextNode(this.formattedMessage));}else{this.contentElement.innerHTML=wrappedContent;}};function LogEntryUnwrappedElementContainer(logEntry,containerDomNode){this.logEntry=logEntry;this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.className="logentry unwrapped "+this.logEntry.level;this.pre=this.mainDiv.appendChild(document.createElement("pre"));this.pre.appendChild(document.createTextNode(this.logEntry.formattedMessage));this.pre.className="unwrapped";this.contentElement=this.pre;}

+LogEntryUnwrappedElementContainer.prototype=new LogEntryElementContainer();LogEntryUnwrappedElementContainer.prototype.remove=function(){this.doRemove();this.pre=null;};function LogEntryMainElementContainer(logEntry,containerDomNode){this.logEntry=logEntry;this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.className="logentry nonielogentry "+this.logEntry.level;this.contentElement=this.mainDiv.appendChild(document.createElement("span"));this.contentElement.appendChild(document.createTextNode(this.logEntry.formattedMessage));}

+LogEntryMainElementContainer.prototype=new LogEntryElementContainer();function LogEntry(level,formattedMessage){this.level=level;this.formattedMessage=formattedMessage;this.rendered=false;}

+LogEntry.prototype=new LogItem();copyProperties(LogEntry.prototype,{render:function(){var logEntry=this;var containerDomNode=this.group.contentDiv;if(isIe){this.formattedMessage=this.formattedMessage.replace(/\r\n/g,"\r");this.unwrappedElementContainer=new LogEntryUnwrappedElementContainer(this,this.getUnwrappedDomContainer());this.wrappedElementContainer=new LogEntryWrappedElementContainer(this,this.getWrappedDomContainer());this.elementContainers=[this.unwrappedElementContainer,this.wrappedElementContainer];}else{this.mainElementContainer=new LogEntryMainElementContainer(this,this.getMainDomContainer());this.elementContainers=[this.mainElementContainer];}

+this.content=this.formattedMessage;this.rendered=true;},setContent:function(content,wrappedContent){if(content!=this.content){if(isIe&&(content!==this.formattedMessage)){content=content.replace(/\r\n/g,"\r");}

+for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].setContent(content,wrappedContent);}

+this.content=content;}},getSearchMatches:function(){var matches=[];var i,len;if(isIe){var unwrappedEls=getElementsByClass(this.unwrappedElementContainer.mainDiv,"searchterm","span");var wrappedEls=getElementsByClass(this.wrappedElementContainer.mainDiv,"searchterm","span");for(i=0,len=unwrappedEls.length;i<len;i++){matches[i]=new Match(this.level,null,unwrappedEls[i],wrappedEls[i]);}}else{var els=getElementsByClass(this.mainElementContainer.mainDiv,"searchterm","span");for(i=0,len=els.length;i<len;i++){matches[i]=new Match(this.level,els[i]);}}

+return matches;},setSearchMatch:function(isMatch){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].setSearchMatch(isMatch);}},clearSearch:function(){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].clearSearch();}},accept:function(visitor){visitor.visitLogEntry(this);},serialize:function(items){items.push([LogItem.serializedItemKeys.LOG_ENTRY,this.level,this.formattedMessage]);}});function LogItemVisitor(){}

+LogItemVisitor.prototype={visit:function(logItem){},visitParent:function(logItem){if(logItem.group){logItem.group.accept(this);}},visitChildren:function(logItem){for(var i=0,len=logItem.children.length;i<len;i++){logItem.children[i].accept(this);}},visitLogEntry:function(logEntry){this.visit(logEntry);},visitSeparator:function(separator){this.visit(separator);},visitGroup:function(group){this.visit(group);}};function GroupFlattener(){this.logEntriesAndSeparators=[];}

+GroupFlattener.prototype=new LogItemVisitor();GroupFlattener.prototype.visitGroup=function(group){this.visitChildren(group);};GroupFlattener.prototype.visitLogEntry=function(logEntry){this.logEntriesAndSeparators.push(logEntry);};GroupFlattener.prototype.visitSeparator=function(separator){this.logEntriesAndSeparators.push(separator);};window.onload=function(){if(location.search){var queryBits=unescape(location.search).substr(1).split("&"),nameValueBits;for(var i=0,len=queryBits.length;i<len;i++){nameValueBits=queryBits[i].split("=");if(nameValueBits[0]=="log4javascript_domain"){document.domain=nameValueBits[1];break;}}}

+logMainContainer=$("log");if(isIePre7){addClass(logMainContainer,"oldIe");}

+rootGroup=new Group("root",true);rootGroup.render();currentGroup=rootGroup;setCommandInputWidth();setLogContainerHeight();toggleLoggingEnabled();toggleSearchEnabled();toggleSearchFilter();toggleSearchHighlight();applyFilters();checkAllLevels();toggleWrap();toggleNewestAtTop();toggleScrollToLatest();renderQueuedLogItems();loaded=true;$("command").value="";$("command").autocomplete="off";$("command").onkeydown=function(evt){evt=getEvent(evt);if(evt.keyCode==10||evt.keyCode==13){evalCommandLine();stopPropagation(evt);}else if(evt.keyCode==27){this.value="";this.focus();}else if(evt.keyCode==38&&commandHistory.length>0){currentCommandIndex=Math.max(0,currentCommandIndex-1);this.value=commandHistory[currentCommandIndex];moveCaretToEnd(this);}else if(evt.keyCode==40&&commandHistory.length>0){currentCommandIndex=Math.min(commandHistory.length-1,currentCommandIndex+1);this.value=commandHistory[currentCommandIndex];moveCaretToEnd(this);}};$("command").onkeypress=function(evt){evt=getEvent(evt);if(evt.keyCode==38&&commandHistory.length>0&&evt.preventDefault){evt.preventDefault();}};$("command").onkeyup=function(evt){evt=getEvent(evt);if(evt.keyCode==27&&evt.preventDefault){evt.preventDefault();this.focus();}};document.onkeydown=function keyEventHandler(evt){evt=getEvent(evt);switch(evt.keyCode){case 69:if(evt.shiftKey&&(evt.ctrlKey||evt.metaKey)){evalLastCommand();cancelKeyEvent(evt);return false;}

+break;case 75:if(evt.shiftKey&&(evt.ctrlKey||evt.metaKey)){focusSearch();cancelKeyEvent(evt);return false;}

+break;case 40:case 76:if(evt.shiftKey&&(evt.ctrlKey||evt.metaKey)){focusCommandLine();cancelKeyEvent(evt);return false;}

+break;}};setTimeout(setLogContainerHeight,20);setShowCommandLine(showCommandLine);doSearch();};window.onunload=function(){if(mainWindowExists()){appender.unload();}

+appender=null;};function toggleLoggingEnabled(){setLoggingEnabled($("enableLogging").checked);}

+function setLoggingEnabled(enable){loggingEnabled=enable;}

+var appender=null;function setAppender(appenderParam){appender=appenderParam;}

+function setShowCloseButton(showCloseButton){$("closeButton").style.display=showCloseButton?"inline":"none";}

+function setShowHideButton(showHideButton){$("hideButton").style.display=showHideButton?"inline":"none";}

+var newestAtTop=false;function LogItemContentReverser(){}

+LogItemContentReverser.prototype=new LogItemVisitor();LogItemContentReverser.prototype.visitGroup=function(group){group.reverseChildren();this.visitChildren(group);};function setNewestAtTop(isNewestAtTop){var oldNewestAtTop=newestAtTop;var i,iLen,j,jLen;newestAtTop=Boolean(isNewestAtTop);if(oldNewestAtTop!=newestAtTop){var visitor=new LogItemContentReverser();rootGroup.accept(visitor);if(currentSearch){var currentMatch=currentSearch.matches[currentMatchIndex];var matchIndex=0;var matches=[];var actOnLogEntry=function(logEntry){var logEntryMatches=logEntry.getSearchMatches();for(j=0,jLen=logEntryMatches.length;j<jLen;j++){matches[matchIndex]=logEntryMatches[j];if(currentMatch&&logEntryMatches[j].equals(currentMatch)){currentMatchIndex=matchIndex;}

+matchIndex++;}};if(newestAtTop){for(i=logEntries.length-1;i>=0;i--){actOnLogEntry(logEntries[i]);}}else{for(i=0,iLen=logEntries.length;i<iLen;i++){actOnLogEntry(logEntries[i]);}}

+currentSearch.matches=matches;if(currentMatch){currentMatch.setCurrent();}}else if(scrollToLatest){doScrollToLatest();}}

+$("newestAtTop").checked=isNewestAtTop;}

+function toggleNewestAtTop(){var isNewestAtTop=$("newestAtTop").checked;setNewestAtTop(isNewestAtTop);}

+var scrollToLatest=true;function setScrollToLatest(isScrollToLatest){scrollToLatest=isScrollToLatest;if(scrollToLatest){doScrollToLatest();}

+$("scrollToLatest").checked=isScrollToLatest;}

+function toggleScrollToLatest(){var isScrollToLatest=$("scrollToLatest").checked;setScrollToLatest(isScrollToLatest);}

+function doScrollToLatest(){var l=logMainContainer;if(typeof l.scrollTop!="undefined"){if(newestAtTop){l.scrollTop=0;}else{var latestLogEntry=l.lastChild;if(latestLogEntry){l.scrollTop=l.scrollHeight;}}}}

+var closeIfOpenerCloses=true;function setCloseIfOpenerCloses(isCloseIfOpenerCloses){closeIfOpenerCloses=isCloseIfOpenerCloses;}

+var maxMessages=null;function setMaxMessages(max){maxMessages=max;pruneLogEntries();}

+var showCommandLine=false;function setShowCommandLine(isShowCommandLine){showCommandLine=isShowCommandLine;if(loaded){$("commandLine").style.display=showCommandLine?"block":"none";setCommandInputWidth();setLogContainerHeight();}}

+function focusCommandLine(){if(loaded){$("command").focus();}}

+function focusSearch(){if(loaded){$("searchBox").focus();}}

+function getLogItems(){var items=[];for(var i=0,len=logItems.length;i<len;i++){logItems[i].serialize(items);}

+return items;}

+function setLogItems(items){var loggingReallyEnabled=loggingEnabled;loggingEnabled=true;for(var i=0,len=items.length;i<len;i++){switch(items[i][0]){case LogItem.serializedItemKeys.LOG_ENTRY:log(items[i][1],items[i][2]);break;case LogItem.serializedItemKeys.GROUP_START:group(items[i][1]);break;case LogItem.serializedItemKeys.GROUP_END:groupEnd();break;}}

+loggingEnabled=loggingReallyEnabled;}

+function log(logLevel,formattedMessage){if(loggingEnabled){var logEntry=new LogEntry(logLevel,formattedMessage);logEntries.push(logEntry);logEntriesAndSeparators.push(logEntry);logItems.push(logEntry);currentGroup.addChild(logEntry);if(loaded){if(logQueuedEventsTimer!==null){clearTimeout(logQueuedEventsTimer);}

+logQueuedEventsTimer=setTimeout(renderQueuedLogItems,renderDelay);unrenderedLogItemsExist=true;}}}

+function renderQueuedLogItems(){logQueuedEventsTimer=null;var pruned=pruneLogEntries();var initiallyHasMatches=currentSearch?currentSearch.hasMatches():false;for(var i=0,len=logItems.length;i<len;i++){if(!logItems[i].rendered){logItems[i].render();logItems[i].appendToLog();if(currentSearch&&(logItems[i]instanceof LogEntry)){currentSearch.applyTo(logItems[i]);}}}

+if(currentSearch){if(pruned){if(currentSearch.hasVisibleMatches()){if(currentMatchIndex===null){setCurrentMatchIndex(0);}

+displayMatches();}else{displayNoMatches();}}else if(!initiallyHasMatches&&currentSearch.hasVisibleMatches()){setCurrentMatchIndex(0);displayMatches();}}

+if(scrollToLatest){doScrollToLatest();}

+unrenderedLogItemsExist=false;}

+function pruneLogEntries(){if((maxMessages!==null)&&(logEntriesAndSeparators.length>maxMessages)){var numberToDelete=logEntriesAndSeparators.length-maxMessages;var prunedLogEntries=logEntriesAndSeparators.slice(0,numberToDelete);if(currentSearch){currentSearch.removeMatches(prunedLogEntries);}

+var group;for(var i=0;i<numberToDelete;i++){group=logEntriesAndSeparators[i].group;array_remove(logItems,logEntriesAndSeparators[i]);array_remove(logEntries,logEntriesAndSeparators[i]);logEntriesAndSeparators[i].remove(true,true);if(group.children.length===0&&group!==currentGroup&&group!==rootGroup){array_remove(logItems,group);group.remove(true,true);}}

+logEntriesAndSeparators=array_removeFromStart(logEntriesAndSeparators,numberToDelete);return true;}

+return false;}

+function group(name,startExpanded){if(loggingEnabled){initiallyExpanded=(typeof startExpanded==="undefined")?true:Boolean(startExpanded);var newGroup=new Group(name,false,initiallyExpanded);currentGroup.addChild(newGroup);currentGroup=newGroup;logItems.push(newGroup);if(loaded){if(logQueuedEventsTimer!==null){clearTimeout(logQueuedEventsTimer);}

+logQueuedEventsTimer=setTimeout(renderQueuedLogItems,renderDelay);unrenderedLogItemsExist=true;}}}

+function groupEnd(){currentGroup=(currentGroup===rootGroup)?rootGroup:currentGroup.group;}

+function mainPageReloaded(){currentGroup=rootGroup;var separator=new Separator();logEntriesAndSeparators.push(separator);logItems.push(separator);currentGroup.addChild(separator);}

+function closeWindow(){if(appender&&mainWindowExists()){appender.close(true);}else{window.close();}}

+function hide(){if(appender&&mainWindowExists()){appender.hide();}}

+var mainWindow=window;var windowId="log4javascriptConsoleWindow_"+new Date().getTime()+"_"+(""+Math.random()).substr(2);function setMainWindow(win){mainWindow=win;mainWindow[windowId]=window;if(opener&&closeIfOpenerCloses){pollOpener();}}

+function pollOpener(){if(closeIfOpenerCloses){if(mainWindowExists()){setTimeout(pollOpener,500);}else{closeWindow();}}}

+function mainWindowExists(){try{return(mainWindow&&!mainWindow.closed&&mainWindow[windowId]==window);}catch(ex){}

+return false;}

+var logLevels=["TRACE","DEBUG","INFO","WARN","ERROR","FATAL"];function getCheckBox(logLevel){return $("switch_"+logLevel);}

+function getIeWrappedLogContainer(){return $("log_wrapped");}

+function getIeUnwrappedLogContainer(){return $("log_unwrapped");}

+function applyFilters(){for(var i=0;i<logLevels.length;i++){if(getCheckBox(logLevels[i]).checked){addClass(logMainContainer,logLevels[i]);}else{removeClass(logMainContainer,logLevels[i]);}}

+updateSearchFromFilters();}

+function toggleAllLevels(){var turnOn=$("switch_ALL").checked;for(var i=0;i<logLevels.length;i++){getCheckBox(logLevels[i]).checked=turnOn;if(turnOn){addClass(logMainContainer,logLevels[i]);}else{removeClass(logMainContainer,logLevels[i]);}}}

+function checkAllLevels(){for(var i=0;i<logLevels.length;i++){if(!getCheckBox(logLevels[i]).checked){getCheckBox("ALL").checked=false;return;}}

+getCheckBox("ALL").checked=true;}

+function clearLog(){rootGroup.clear();currentGroup=rootGroup;logEntries=[];logItems=[];logEntriesAndSeparators=[];doSearch();}

+function toggleWrap(){var enable=$("wrap").checked;if(enable){addClass(logMainContainer,"wrap");}else{removeClass(logMainContainer,"wrap");}

+refreshCurrentMatch();}

+var searchTimer=null;function scheduleSearch(){try{clearTimeout(searchTimer);}catch(ex){}

+searchTimer=setTimeout(doSearch,500);}

+function Search(searchTerm,isRegex,searchRegex,isCaseSensitive){this.searchTerm=searchTerm;this.isRegex=isRegex;this.searchRegex=searchRegex;this.isCaseSensitive=isCaseSensitive;this.matches=[];}

+Search.prototype={hasMatches:function(){return this.matches.length>0;},hasVisibleMatches:function(){if(this.hasMatches()){for(var i=0;i<this.matches.length;i++){if(this.matches[i].isVisible()){return true;}}}

+return false;},match:function(logEntry){var entryText=String(logEntry.formattedMessage);var matchesSearch=false;if(this.isRegex){matchesSearch=this.searchRegex.test(entryText);}else if(this.isCaseSensitive){matchesSearch=(entryText.indexOf(this.searchTerm)>-1);}else{matchesSearch=(entryText.toLowerCase().indexOf(this.searchTerm.toLowerCase())>-1);}

+return matchesSearch;},getNextVisibleMatchIndex:function(){for(var i=currentMatchIndex+1;i<this.matches.length;i++){if(this.matches[i].isVisible()){return i;}}

+for(i=0;i<=currentMatchIndex;i++){if(this.matches[i].isVisible()){return i;}}

+return-1;},getPreviousVisibleMatchIndex:function(){for(var i=currentMatchIndex-1;i>=0;i--){if(this.matches[i].isVisible()){return i;}}

+for(var i=this.matches.length-1;i>=currentMatchIndex;i--){if(this.matches[i].isVisible()){return i;}}

+return-1;},applyTo:function(logEntry){var doesMatch=this.match(logEntry);if(doesMatch){logEntry.group.expand();logEntry.setSearchMatch(true);var logEntryContent;var wrappedLogEntryContent;var searchTermReplacementStartTag="<span class=\"searchterm\">";var searchTermReplacementEndTag="<"+"/span>";var preTagName=isIe?"pre":"span";var preStartTag="<"+preTagName+" class=\"pre\">";var preEndTag="<"+"/"+preTagName+">";var startIndex=0;var searchIndex,matchedText,textBeforeMatch;if(this.isRegex){var flags=this.isCaseSensitive?"g":"gi";var capturingRegex=new RegExp("("+this.searchRegex.source+")",flags);var rnd=(""+Math.random()).substr(2);var startToken="%%s"+rnd+"%%";var endToken="%%e"+rnd+"%%";logEntryContent=logEntry.formattedMessage.replace(capturingRegex,startToken+"$1"+endToken);logEntryContent=escapeHtml(logEntryContent);var result;var searchString=logEntryContent;logEntryContent="";wrappedLogEntryContent="";while((searchIndex=searchString.indexOf(startToken,startIndex))>-1){var endTokenIndex=searchString.indexOf(endToken,searchIndex);matchedText=searchString.substring(searchIndex+startToken.length,endTokenIndex);textBeforeMatch=searchString.substring(startIndex,searchIndex);logEntryContent+=preStartTag+textBeforeMatch+preEndTag;logEntryContent+=searchTermReplacementStartTag+preStartTag+matchedText+

+preEndTag+searchTermReplacementEndTag;if(isIe){wrappedLogEntryContent+=textBeforeMatch+searchTermReplacementStartTag+

+matchedText+searchTermReplacementEndTag;}

+startIndex=endTokenIndex+endToken.length;}

+logEntryContent+=preStartTag+searchString.substr(startIndex)+preEndTag;if(isIe){wrappedLogEntryContent+=searchString.substr(startIndex);}}else{logEntryContent="";wrappedLogEntryContent="";var searchTermReplacementLength=searchTermReplacementStartTag.length+

+this.searchTerm.length+searchTermReplacementEndTag.length;var searchTermLength=this.searchTerm.length;var searchTermLowerCase=this.searchTerm.toLowerCase();var logTextLowerCase=logEntry.formattedMessage.toLowerCase();while((searchIndex=logTextLowerCase.indexOf(searchTermLowerCase,startIndex))>-1){matchedText=escapeHtml(logEntry.formattedMessage.substr(searchIndex,this.searchTerm.length));textBeforeMatch=escapeHtml(logEntry.formattedMessage.substring(startIndex,searchIndex));var searchTermReplacement=searchTermReplacementStartTag+

+preStartTag+matchedText+preEndTag+searchTermReplacementEndTag;logEntryContent+=preStartTag+textBeforeMatch+preEndTag+searchTermReplacement;if(isIe){wrappedLogEntryContent+=textBeforeMatch+searchTermReplacementStartTag+

+matchedText+searchTermReplacementEndTag;}

+startIndex=searchIndex+searchTermLength;}

+var textAfterLastMatch=escapeHtml(logEntry.formattedMessage.substr(startIndex));logEntryContent+=preStartTag+textAfterLastMatch+preEndTag;if(isIe){wrappedLogEntryContent+=textAfterLastMatch;}}

+logEntry.setContent(logEntryContent,wrappedLogEntryContent);var logEntryMatches=logEntry.getSearchMatches();this.matches=this.matches.concat(logEntryMatches);}else{logEntry.setSearchMatch(false);logEntry.setContent(logEntry.formattedMessage,logEntry.formattedMessage);}

+return doesMatch;},removeMatches:function(logEntries){var matchesToRemoveCount=0;var currentMatchRemoved=false;var matchesToRemove=[];var i,iLen,j,jLen;for(i=0,iLen=this.matches.length;i<iLen;i++){for(j=0,jLen=logEntries.length;j<jLen;j++){if(this.matches[i].belongsTo(logEntries[j])){matchesToRemove.push(this.matches[i]);if(i===currentMatchIndex){currentMatchRemoved=true;}}}}

+var newMatch=currentMatchRemoved?null:this.matches[currentMatchIndex];if(currentMatchRemoved){for(i=currentMatchIndex,iLen=this.matches.length;i<iLen;i++){if(this.matches[i].isVisible()&&!array_contains(matchesToRemove,this.matches[i])){newMatch=this.matches[i];break;}}}

+for(i=0,iLen=matchesToRemove.length;i<iLen;i++){array_remove(this.matches,matchesToRemove[i]);matchesToRemove[i].remove();}

+if(this.hasVisibleMatches()){if(newMatch===null){setCurrentMatchIndex(0);}else{var newMatchIndex=0;for(i=0,iLen=this.matches.length;i<iLen;i++){if(newMatch===this.matches[i]){newMatchIndex=i;break;}}

+setCurrentMatchIndex(newMatchIndex);}}else{currentMatchIndex=null;displayNoMatches();}}};function getPageOffsetTop(el,container){var currentEl=el;var y=0;while(currentEl&&currentEl!=container){y+=currentEl.offsetTop;currentEl=currentEl.offsetParent;}

+return y;}

+function scrollIntoView(el){var logContainer=logMainContainer;if(!$("wrap").checked){var logContainerLeft=logContainer.scrollLeft;var logContainerRight=logContainerLeft+logContainer.offsetWidth;var elLeft=el.offsetLeft;var elRight=elLeft+el.offsetWidth;if(elLeft<logContainerLeft||elRight>logContainerRight){logContainer.scrollLeft=elLeft-(logContainer.offsetWidth-el.offsetWidth)/2;}}

+var logContainerTop=logContainer.scrollTop;var logContainerBottom=logContainerTop+logContainer.offsetHeight;var elTop=getPageOffsetTop(el)-getToolBarsHeight();var elBottom=elTop+el.offsetHeight;if(elTop<logContainerTop||elBottom>logContainerBottom){logContainer.scrollTop=elTop-(logContainer.offsetHeight-el.offsetHeight)/2;}}

+function Match(logEntryLevel,spanInMainDiv,spanInUnwrappedPre,spanInWrappedDiv){this.logEntryLevel=logEntryLevel;this.spanInMainDiv=spanInMainDiv;if(isIe){this.spanInUnwrappedPre=spanInUnwrappedPre;this.spanInWrappedDiv=spanInWrappedDiv;}

+this.mainSpan=isIe?spanInUnwrappedPre:spanInMainDiv;}

+Match.prototype={equals:function(match){return this.mainSpan===match.mainSpan;},setCurrent:function(){if(isIe){addClass(this.spanInUnwrappedPre,"currentmatch");addClass(this.spanInWrappedDiv,"currentmatch");var elementToScroll=$("wrap").checked?this.spanInWrappedDiv:this.spanInUnwrappedPre;scrollIntoView(elementToScroll);}else{addClass(this.spanInMainDiv,"currentmatch");scrollIntoView(this.spanInMainDiv);}},belongsTo:function(logEntry){if(isIe){return isDescendant(this.spanInUnwrappedPre,logEntry.unwrappedPre);}else{return isDescendant(this.spanInMainDiv,logEntry.mainDiv);}},setNotCurrent:function(){if(isIe){removeClass(this.spanInUnwrappedPre,"currentmatch");removeClass(this.spanInWrappedDiv,"currentmatch");}else{removeClass(this.spanInMainDiv,"currentmatch");}},isOrphan:function(){return isOrphan(this.mainSpan);},isVisible:function(){return getCheckBox(this.logEntryLevel).checked;},remove:function(){if(isIe){this.spanInUnwrappedPre=null;this.spanInWrappedDiv=null;}else{this.spanInMainDiv=null;}}};var currentSearch=null;var currentMatchIndex=null;function doSearch(){var searchBox=$("searchBox");var searchTerm=searchBox.value;var isRegex=$("searchRegex").checked;var isCaseSensitive=$("searchCaseSensitive").checked;var i;if(searchTerm===""){$("searchReset").disabled=true;$("searchNav").style.display="none";removeClass(document.body,"searching");removeClass(searchBox,"hasmatches");removeClass(searchBox,"nomatches");for(i=0;i<logEntries.length;i++){logEntries[i].clearSearch();logEntries[i].setContent(logEntries[i].formattedMessage,logEntries[i].formattedMessage);}

+currentSearch=null;setLogContainerHeight();}else{$("searchReset").disabled=false;$("searchNav").style.display="block";var searchRegex;var regexValid;if(isRegex){try{searchRegex=isCaseSensitive?new RegExp(searchTerm,"g"):new RegExp(searchTerm,"gi");regexValid=true;replaceClass(searchBox,"validregex","invalidregex");searchBox.title="Valid regex";}catch(ex){regexValid=false;replaceClass(searchBox,"invalidregex","validregex");searchBox.title="Invalid regex: "+(ex.message?ex.message:(ex.description?ex.description:"unknown error"));return;}}else{searchBox.title="";removeClass(searchBox,"validregex");removeClass(searchBox,"invalidregex");}

+addClass(document.body,"searching");currentSearch=new Search(searchTerm,isRegex,searchRegex,isCaseSensitive);for(i=0;i<logEntries.length;i++){currentSearch.applyTo(logEntries[i]);}

+setLogContainerHeight();if(currentSearch.hasVisibleMatches()){setCurrentMatchIndex(0);displayMatches();}else{displayNoMatches();}}}

+function updateSearchFromFilters(){if(currentSearch){if(currentSearch.hasMatches()){if(currentMatchIndex===null){currentMatchIndex=0;}

+var currentMatch=currentSearch.matches[currentMatchIndex];if(currentMatch.isVisible()){displayMatches();setCurrentMatchIndex(currentMatchIndex);}else{currentMatch.setNotCurrent();var nextVisibleMatchIndex=currentSearch.getNextVisibleMatchIndex();if(nextVisibleMatchIndex>-1){setCurrentMatchIndex(nextVisibleMatchIndex);displayMatches();}else{displayNoMatches();}}}else{displayNoMatches();}}}

+function refreshCurrentMatch(){if(currentSearch&&currentSearch.hasVisibleMatches()){setCurrentMatchIndex(currentMatchIndex);}}

+function displayMatches(){replaceClass($("searchBox"),"hasmatches","nomatches");$("searchBox").title=""+currentSearch.matches.length+" matches found";$("searchNav").style.display="block";setLogContainerHeight();}

+function displayNoMatches(){replaceClass($("searchBox"),"nomatches","hasmatches");$("searchBox").title="No matches found";$("searchNav").style.display="none";setLogContainerHeight();}

+function toggleSearchEnabled(enable){enable=(typeof enable=="undefined")?!$("searchDisable").checked:enable;$("searchBox").disabled=!enable;$("searchReset").disabled=!enable;$("searchRegex").disabled=!enable;$("searchNext").disabled=!enable;$("searchPrevious").disabled=!enable;$("searchCaseSensitive").disabled=!enable;$("searchNav").style.display=(enable&&($("searchBox").value!=="")&&currentSearch&&currentSearch.hasVisibleMatches())?"block":"none";if(enable){removeClass($("search"),"greyedout");addClass(document.body,"searching");if($("searchHighlight").checked){addClass(logMainContainer,"searchhighlight");}else{removeClass(logMainContainer,"searchhighlight");}

+if($("searchFilter").checked){addClass(logMainContainer,"searchfilter");}else{removeClass(logMainContainer,"searchfilter");}

+$("searchDisable").checked=!enable;}else{addClass($("search"),"greyedout");removeClass(document.body,"searching");removeClass(logMainContainer,"searchhighlight");removeClass(logMainContainer,"searchfilter");}

+setLogContainerHeight();}

+function toggleSearchFilter(){var enable=$("searchFilter").checked;if(enable){addClass(logMainContainer,"searchfilter");}else{removeClass(logMainContainer,"searchfilter");}

+refreshCurrentMatch();}

+function toggleSearchHighlight(){var enable=$("searchHighlight").checked;if(enable){addClass(logMainContainer,"searchhighlight");}else{removeClass(logMainContainer,"searchhighlight");}}

+function clearSearch(){$("searchBox").value="";doSearch();}

+function searchNext(){if(currentSearch!==null&&currentMatchIndex!==null){currentSearch.matches[currentMatchIndex].setNotCurrent();var nextMatchIndex=currentSearch.getNextVisibleMatchIndex();if(nextMatchIndex>currentMatchIndex||confirm("Reached the end of the page. Start from the top?")){setCurrentMatchIndex(nextMatchIndex);}}}

+function searchPrevious(){if(currentSearch!==null&&currentMatchIndex!==null){currentSearch.matches[currentMatchIndex].setNotCurrent();var previousMatchIndex=currentSearch.getPreviousVisibleMatchIndex();if(previousMatchIndex<currentMatchIndex||confirm("Reached the start of the page. Continue from the bottom?")){setCurrentMatchIndex(previousMatchIndex);}}}

+function setCurrentMatchIndex(index){currentMatchIndex=index;currentSearch.matches[currentMatchIndex].setCurrent();}

+function addClass(el,cssClass){if(!hasClass(el,cssClass)){if(el.className){el.className+=" "+cssClass;}else{el.className=cssClass;}}}

+function hasClass(el,cssClass){if(el.className){var classNames=el.className.split(" ");return array_contains(classNames,cssClass);}

+return false;}

+function removeClass(el,cssClass){if(hasClass(el,cssClass)){var existingClasses=el.className.split(" ");var newClasses=[];for(var i=0,len=existingClasses.length;i<len;i++){if(existingClasses[i]!=cssClass){newClasses[newClasses.length]=existingClasses[i];}}

+el.className=newClasses.join(" ");}}

+function replaceClass(el,newCssClass,oldCssClass){removeClass(el,oldCssClass);addClass(el,newCssClass);}

+function getElementsByClass(el,cssClass,tagName){var elements=el.getElementsByTagName(tagName);var matches=[];for(var i=0,len=elements.length;i<len;i++){if(hasClass(elements[i],cssClass)){matches.push(elements[i]);}}

+return matches;}

+function $(id){return document.getElementById(id);}

+function isDescendant(node,ancestorNode){while(node!=null){if(node===ancestorNode){return true;}

+node=node.parentNode;}

+return false;}

+function isOrphan(node){var currentNode=node;while(currentNode){if(currentNode==document.body){return false;}

+currentNode=currentNode.parentNode;}

+return true;}

+function escapeHtml(str){return str.replace(/&/g,"&amp;").replace(/[<]/g,"&lt;").replace(/>/g,"&gt;");}

+function getWindowWidth(){if(window.innerWidth){return window.innerWidth;}else if(document.documentElement&&document.documentElement.clientWidth){return document.documentElement.clientWidth;}else if(document.body){return document.body.clientWidth;}

+return 0;}

+function getWindowHeight(){if(window.innerHeight){return window.innerHeight;}else if(document.documentElement&&document.documentElement.clientHeight){return document.documentElement.clientHeight;}else if(document.body){return document.body.clientHeight;}

+return 0;}

+function getToolBarsHeight(){return $("switches").offsetHeight;}

+function getChromeHeight(){var height=getToolBarsHeight();if(showCommandLine){height+=$("commandLine").offsetHeight;}

+return height;}

+function setLogContainerHeight(){if(logMainContainer){var windowHeight=getWindowHeight();$("body").style.height=getWindowHeight()+"px";logMainContainer.style.height=""+

+Math.max(0,windowHeight-getChromeHeight())+"px";}}

+function setCommandInputWidth(){if(showCommandLine){$("command").style.width=""+Math.max(0,$("commandLineContainer").offsetWidth-

+($("evaluateButton").offsetWidth+13))+"px";}}

+window.onresize=function(){setCommandInputWidth();setLogContainerHeight();};if(!Array.prototype.push){Array.prototype.push=function(){for(var i=0,len=arguments.length;i<len;i++){this[this.length]=arguments[i];}

+return this.length;};}

+if(!Array.prototype.pop){Array.prototype.pop=function(){if(this.length>0){var val=this[this.length-1];this.length=this.length-1;return val;}};}

+if(!Array.prototype.shift){Array.prototype.shift=function(){if(this.length>0){var firstItem=this[0];for(var i=0,len=this.length-1;i<len;i++){this[i]=this[i+1];}

+this.length=this.length-1;return firstItem;}};}

+if(!Array.prototype.splice){Array.prototype.splice=function(startIndex,deleteCount){var itemsAfterDeleted=this.slice(startIndex+deleteCount);var itemsDeleted=this.slice(startIndex,startIndex+deleteCount);this.length=startIndex;var argumentsArray=[];for(var i=0,len=arguments.length;i<len;i++){argumentsArray[i]=arguments[i];}

+var itemsToAppend=(argumentsArray.length>2)?itemsAfterDeleted=argumentsArray.slice(2).concat(itemsAfterDeleted):itemsAfterDeleted;for(i=0,len=itemsToAppend.length;i<len;i++){this.push(itemsToAppend[i]);}

+return itemsDeleted;};}

+function array_remove(arr,val){var index=-1;for(var i=0,len=arr.length;i<len;i++){if(arr[i]===val){index=i;break;}}

+if(index>=0){arr.splice(index,1);return index;}else{return false;}}

+function array_removeFromStart(array,numberToRemove){if(Array.prototype.splice){array.splice(0,numberToRemove);}else{for(var i=numberToRemove,len=array.length;i<len;i++){array[i-numberToRemove]=array[i];}

+array.length=array.length-numberToRemove;}

+return array;}

+function array_contains(arr,val){for(var i=0,len=arr.length;i<len;i++){if(arr[i]==val){return true;}}

+return false;}

+function getErrorMessage(ex){if(ex.message){return ex.message;}else if(ex.description){return ex.description;}

+return""+ex;}

+function moveCaretToEnd(input){if(input.setSelectionRange){input.focus();var length=input.value.length;input.setSelectionRange(length,length);}else if(input.createTextRange){var range=input.createTextRange();range.collapse(false);range.select();}

+input.focus();}

+function stopPropagation(evt){if(evt.stopPropagation){evt.stopPropagation();}else if(typeof evt.cancelBubble!="undefined"){evt.cancelBubble=true;}}

+function getEvent(evt){return evt?evt:event;}

+function getTarget(evt){return evt.target?evt.target:evt.srcElement;}

+function getRelatedTarget(evt){if(evt.relatedTarget){return evt.relatedTarget;}else if(evt.srcElement){switch(evt.type){case"mouseover":return evt.fromElement;case"mouseout":return evt.toElement;default:return evt.srcElement;}}}

+function cancelKeyEvent(evt){evt.returnValue=false;stopPropagation(evt);}

+function evalCommandLine(){var expr=$("command").value;evalCommand(expr);$("command").value="";}

+function evalLastCommand(){if(lastCommand!=null){evalCommand(lastCommand);}}

+var lastCommand=null;var commandHistory=[];var currentCommandIndex=0;function evalCommand(expr){if(appender){appender.evalCommandAndAppend(expr);}else{var prefix=">>> "+expr+"\r\n";try{log("INFO",prefix+eval(expr));}catch(ex){log("ERROR",prefix+"Error: "+getErrorMessage(ex));}}

+if(expr!=commandHistory[commandHistory.length-1]){commandHistory.push(expr);if(appender){appender.storeCommandHistory(commandHistory);}}

+currentCommandIndex=(expr==commandHistory[currentCommandIndex])?currentCommandIndex+1:commandHistory.length;lastCommand=expr;}

+//]]>

+</script>

+<style type="text/css">

+body{background-color:white;color:black;padding:0;margin:0;font-family:tahoma,verdana,arial,helvetica,sans-serif;overflow:hidden}div#switchesContainer input{margin-bottom:0}div.toolbar{border-top:solid #ffffff 1px;border-bottom:solid #aca899 1px;background-color:#f1efe7;padding:3px 5px;font-size:68.75%}div.toolbar,div#search input{font-family:tahoma,verdana,arial,helvetica,sans-serif}div.toolbar input.button{padding:0 5px;font-size:100%}div.toolbar input.hidden{display:none}div#switches input#clearButton{margin-left:20px}div#levels label{font-weight:bold}div#levels label,div#options label{margin-right:5px}div#levels label#wrapLabel{font-weight:normal}div#search label{margin-right:10px}div#search label.searchboxlabel{margin-right:0}div#search input{font-size:100%}div#search input.validregex{color:green}div#search input.invalidregex{color:red}div#search input.nomatches{color:white;background-color:#ff6666}div#search input.nomatches{color:white;background-color:#ff6666}div#searchNav{display:none}div#commandLine{display:none}div#commandLine input#command{font-size:100%;font-family:Courier New,Courier}div#commandLine input#evaluateButton{}*.greyedout{color:gray !important;border-color:gray !important}*.greyedout *.alwaysenabled{color:black}*.unselectable{-khtml-user-select:none;-moz-user-select:none;user-select:none}div#log{font-family:Courier New,Courier;font-size:75%;width:100%;overflow:auto;clear:both;position:relative}div.group{border-color:#cccccc;border-style:solid;border-width:1px 0 1px 1px;overflow:visible}div.oldIe div.group,div.oldIe div.group *,div.oldIe *.logentry{height:1%}div.group div.groupheading span.expander{border:solid black 1px;font-family:Courier New,Courier;font-size:0.833em;background-color:#eeeeee;position:relative;top:-1px;color:black;padding:0 2px;cursor:pointer;cursor:hand;height:1%}div.group div.groupcontent{margin-left:10px;padding-bottom:2px;overflow:visible}div.group div.expanded{display:block}div.group div.collapsed{display:none}*.logentry{overflow:visible;display:none;white-space:pre}span.pre{white-space:pre}pre.unwrapped{display:inline !important}pre.unwrapped pre.pre,div.wrapped pre.pre{display:inline}div.wrapped pre.pre{white-space:normal}div.wrapped{display:none}body.searching *.logentry span.currentmatch{color:white !important;background-color:green !important}body.searching div.searchhighlight *.logentry span.searchterm{color:black;background-color:yellow}div.wrap *.logentry{white-space:normal !important;border-width:0 0 1px 0;border-color:#dddddd;border-style:dotted}div.wrap #log_wrapped,#log_unwrapped{display:block}div.wrap #log_unwrapped,#log_wrapped{display:none}div.wrap *.logentry span.pre{overflow:visible;white-space:normal}div.wrap *.logentry pre.unwrapped{display:none}div.wrap *.logentry span.wrapped{display:inline}div.searchfilter *.searchnonmatch{display:none !important}div#log *.TRACE,label#label_TRACE{color:#666666}div#log *.DEBUG,label#label_DEBUG{color:green}div#log *.INFO,label#label_INFO{color:#000099}div#log *.WARN,label#label_WARN{color:#999900}div#log *.ERROR,label#label_ERROR{color:red}div#log *.FATAL,label#label_FATAL{color:#660066}div.TRACE#log *.TRACE,div.DEBUG#log *.DEBUG,div.INFO#log *.INFO,div.WARN#log *.WARN,div.ERROR#log *.ERROR,div.FATAL#log *.FATAL{display:block}div#log div.separator{background-color:#cccccc;margin:5px 0;line-height:1px}

+</style>

+</head>

+<body id="body">

+<div id="switchesContainer">

+<div id="switches">

+<div id="levels" class="toolbar">

+Filters:

+<input type="checkbox" id="switch_TRACE" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide trace messages" /><label for="switch_TRACE" id="label_TRACE">trace</label>

+<input type="checkbox" id="switch_DEBUG" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide debug messages" /><label for="switch_DEBUG" id="label_DEBUG">debug</label>

+<input type="checkbox" id="switch_INFO" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide info messages" /><label for="switch_INFO" id="label_INFO">info</label>

+<input type="checkbox" id="switch_WARN" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide warn messages" /><label for="switch_WARN" id="label_WARN">warn</label>

+<input type="checkbox" id="switch_ERROR" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide error messages" /><label for="switch_ERROR" id="label_ERROR">error</label>

+<input type="checkbox" id="switch_FATAL" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide fatal messages" /><label for="switch_FATAL" id="label_FATAL">fatal</label>

+<input type="checkbox" id="switch_ALL" onclick="toggleAllLevels(); applyFilters()" checked="checked" title="Show/hide all messages" /><label for="switch_ALL" id="label_ALL">all</label>

+</div>

+<div id="search" class="toolbar">

+<label for="searchBox" class="searchboxlabel">Search:</label> <input type="text" id="searchBox" onclick="toggleSearchEnabled(true)" onkeyup="scheduleSearch()" size="20" />

+<input type="button" id="searchReset" disabled="disabled" value="Reset" onclick="clearSearch()" class="button" title="Reset the search" />

+<input type="checkbox" id="searchRegex" onclick="doSearch()" title="If checked, search is treated as a regular expression" /><label for="searchRegex">Regex</label>

+<input type="checkbox" id="searchCaseSensitive" onclick="doSearch()" title="If checked, search is case sensitive" /><label for="searchCaseSensitive">Match case</label>

+<input type="checkbox" id="searchDisable" onclick="toggleSearchEnabled()" title="Enable/disable search" /><label for="searchDisable" class="alwaysenabled">Disable</label>

+<div id="searchNav">

+<input type="button" id="searchNext" disabled="disabled" value="Next" onclick="searchNext()" class="button" title="Go to the next matching log entry" />

+<input type="button" id="searchPrevious" disabled="disabled" value="Previous" onclick="searchPrevious()" class="button" title="Go to the previous matching log entry" />

+<input type="checkbox" id="searchFilter" onclick="toggleSearchFilter()" title="If checked, non-matching log entries are filtered out" /><label for="searchFilter">Filter</label>

+<input type="checkbox" id="searchHighlight" onclick="toggleSearchHighlight()" title="Highlight matched search terms" /><label for="searchHighlight" class="alwaysenabled">Highlight all</label>

+</div>

+</div>

+<div id="options" class="toolbar">

+Options:

+<input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Log</label>

+<input type="checkbox" id="wrap" onclick="toggleWrap()" title="Enable / disable word wrap" /><label for="wrap" id="wrapLabel">Wrap</label>

+<input type="checkbox" id="newestAtTop" onclick="toggleNewestAtTop()" title="If checked, causes newest messages to appear at the top" /><label for="newestAtTop" id="newestAtTopLabel">Newest at the top</label>

+<input type="checkbox" id="scrollToLatest" onclick="toggleScrollToLatest()" checked="checked" title="If checked, window automatically scrolls to a new message when it is added" /><label for="scrollToLatest" id="scrollToLatestLabel">Scroll to latest</label>

+<input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="button" title="Clear all log messages"  />

+<input type="button" id="hideButton" value="Hide" onclick="hide()" class="hidden button" title="Hide the console" />

+<input type="button" id="closeButton" value="Close" onclick="closeWindow()" class="hidden button" title="Close the window" />

+</div>

+</div>

+</div>

+<div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>

+<div id="commandLine" class="toolbar">

+<div id="commandLineContainer">

+<input type="text" id="command" title="Enter a JavaScript command here and hit return or press 'Evaluate'" />

+<input type="button" id="evaluateButton" value="Evaluate" class="button" title="Evaluate the command" onclick="evalCommandLine()" />

+</div>

+</div>

+</body>

+</html>

diff --git a/xos/core/static/log4javascript-1.4.6/console_uncompressed.html b/xos/core/static/log4javascript-1.4.6/console_uncompressed.html
new file mode 100644
index 0000000..55679f8
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/console_uncompressed.html
@@ -0,0 +1,2279 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript</title>

+		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

+		<!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->

+		<meta http-equiv="X-UA-Compatible" content="IE=7" />

+		<script type="text/javascript">var isIe = false, isIePre7 = false;</script>

+		<!--[if IE]><script type="text/javascript">isIe = true</script><![endif]-->

+		<!--[if lt IE 7]><script type="text/javascript">isIePre7 = true</script><![endif]-->

+		<script type="text/javascript">

+			//<![CDATA[

+			var loggingEnabled = true;

+			var logQueuedEventsTimer = null;

+			var logEntries = [];

+			var logEntriesAndSeparators = [];

+			var logItems = [];

+			var renderDelay = 100;

+			var unrenderedLogItemsExist = false;

+			var rootGroup, currentGroup = null;

+			var loaded = false;

+			var currentLogItem = null;

+			var logMainContainer;

+

+			function copyProperties(obj, props) {

+				for (var i in props) {

+					obj[i] = props[i];

+				}

+			}

+

+			/*----------------------------------------------------------------*/

+

+			function LogItem() {

+			}

+

+			LogItem.prototype = {

+				mainContainer: null,

+				wrappedContainer: null,

+				unwrappedContainer: null,

+				group: null,

+

+				appendToLog: function() {

+					for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+						this.elementContainers[i].appendToLog();

+					}

+					this.group.update();

+				},

+

+				doRemove: function(doUpdate, removeFromGroup) {

+					if (this.rendered) {

+						for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+							this.elementContainers[i].remove();

+						}

+						this.unwrappedElementContainer = null;

+						this.wrappedElementContainer = null;

+						this.mainElementContainer = null;

+					}

+					if (this.group && removeFromGroup) {

+						this.group.removeChild(this, doUpdate);

+					}

+					if (this === currentLogItem) {

+						currentLogItem = null;

+					}

+				},

+

+				remove: function(doUpdate, removeFromGroup) {

+					this.doRemove(doUpdate, removeFromGroup);

+				},

+

+				render: function() {},

+

+				accept: function(visitor) {

+					visitor.visit(this);

+				},

+

+				getUnwrappedDomContainer: function() {

+					return this.group.unwrappedElementContainer.contentDiv;

+				},

+

+				getWrappedDomContainer: function() {

+					return this.group.wrappedElementContainer.contentDiv;

+				},

+

+				getMainDomContainer: function() {

+					return this.group.mainElementContainer.contentDiv;

+				}

+			};

+

+			LogItem.serializedItemKeys = {LOG_ENTRY: 0, GROUP_START: 1, GROUP_END: 2};

+

+			/*----------------------------------------------------------------*/

+

+			function LogItemContainerElement() {

+			}

+

+			LogItemContainerElement.prototype = {

+				appendToLog: function() {

+					var insertBeforeFirst = (newestAtTop && this.containerDomNode.hasChildNodes());

+					if (insertBeforeFirst) {

+						this.containerDomNode.insertBefore(this.mainDiv, this.containerDomNode.firstChild);

+					} else {

+						this.containerDomNode.appendChild(this.mainDiv);

+					}

+				}

+			};

+

+			/*----------------------------------------------------------------*/

+

+			function SeparatorElementContainer(containerDomNode) {

+				this.containerDomNode = containerDomNode;

+				this.mainDiv = document.createElement("div");

+				this.mainDiv.className = "separator";

+				this.mainDiv.innerHTML = "&nbsp;";

+			}

+

+			SeparatorElementContainer.prototype = new LogItemContainerElement();

+

+			SeparatorElementContainer.prototype.remove = function() {

+				this.mainDiv.parentNode.removeChild(this.mainDiv);

+				this.mainDiv = null;

+			};

+

+			/*----------------------------------------------------------------*/

+

+			function Separator() {

+				this.rendered = false;

+			}

+

+			Separator.prototype = new LogItem();

+

+			copyProperties(Separator.prototype, {

+				render: function() {

+					var containerDomNode = this.group.contentDiv;

+					if (isIe) {

+						this.unwrappedElementContainer = new SeparatorElementContainer(this.getUnwrappedDomContainer());

+						this.wrappedElementContainer = new SeparatorElementContainer(this.getWrappedDomContainer());

+						this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];

+					} else {

+						this.mainElementContainer = new SeparatorElementContainer(this.getMainDomContainer());

+						this.elementContainers = [this.mainElementContainer];

+					}

+					this.content = this.formattedMessage;

+					this.rendered = true;

+				}

+			});

+

+			/*----------------------------------------------------------------*/

+

+			function GroupElementContainer(group, containerDomNode, isRoot, isWrapped) {

+				this.group = group;

+				this.containerDomNode = containerDomNode;

+				this.isRoot = isRoot;

+				this.isWrapped = isWrapped;

+				this.expandable = false;

+

+				if (this.isRoot) {

+					if (isIe) {

+						this.contentDiv = logMainContainer.appendChild(document.createElement("div"));

+						this.contentDiv.id = this.isWrapped ? "log_wrapped" : "log_unwrapped";

+					} else {

+						this.contentDiv = logMainContainer;

+					}

+				} else {

+					var groupElementContainer = this;

+					

+					this.mainDiv = document.createElement("div");

+					this.mainDiv.className = "group";

+

+					this.headingDiv = this.mainDiv.appendChild(document.createElement("div"));

+					this.headingDiv.className = "groupheading";

+

+					this.expander = this.headingDiv.appendChild(document.createElement("span"));

+					this.expander.className = "expander unselectable greyedout";

+					this.expander.unselectable = true;

+					var expanderText = this.group.expanded ? "-" : "+";

+					this.expanderTextNode = this.expander.appendChild(document.createTextNode(expanderText));

+					

+					this.headingDiv.appendChild(document.createTextNode(" " + this.group.name));

+

+					this.contentDiv = this.mainDiv.appendChild(document.createElement("div"));

+					var contentCssClass = this.group.expanded ? "expanded" : "collapsed";

+					this.contentDiv.className = "groupcontent " + contentCssClass;

+

+					this.expander.onclick = function() {

+						if (groupElementContainer.group.expandable) {

+							groupElementContainer.group.toggleExpanded();

+						}

+					};

+				}

+			}

+

+			GroupElementContainer.prototype = new LogItemContainerElement();

+

+			copyProperties(GroupElementContainer.prototype, {

+				toggleExpanded: function() {

+					if (!this.isRoot) {

+						var oldCssClass, newCssClass, expanderText;

+						if (this.group.expanded) {

+							newCssClass = "expanded";

+							oldCssClass = "collapsed";

+							expanderText = "-";

+						} else {

+							newCssClass = "collapsed";

+							oldCssClass = "expanded";

+							expanderText = "+";

+						}

+						replaceClass(this.contentDiv, newCssClass, oldCssClass);

+						this.expanderTextNode.nodeValue = expanderText;

+					}

+				},

+

+				remove: function() {

+					if (!this.isRoot) {

+						this.headingDiv = null;

+						this.expander.onclick = null;

+						this.expander = null;

+						this.expanderTextNode = null;

+						this.contentDiv = null;

+						this.containerDomNode = null;

+						this.mainDiv.parentNode.removeChild(this.mainDiv);

+						this.mainDiv = null;

+					}

+				},

+

+				reverseChildren: function() {

+					// Invert the order of the log entries

+					var node = null;

+

+					// Remove all the log container nodes

+					var childDomNodes = [];

+					while ((node = this.contentDiv.firstChild)) {

+						this.contentDiv.removeChild(node);

+						childDomNodes.push(node);

+					}

+

+					// Put them all back in reverse order

+					while ((node = childDomNodes.pop())) {

+						this.contentDiv.appendChild(node);

+					}

+				},

+

+				update: function() {

+					if (!this.isRoot) {

+						if (this.group.expandable) {

+							removeClass(this.expander, "greyedout");

+						} else {

+							addClass(this.expander, "greyedout");

+						}

+					}

+				},

+

+				clear: function() {

+					if (this.isRoot) {

+						this.contentDiv.innerHTML = "";

+					}

+				}

+			});

+

+			/*----------------------------------------------------------------*/

+

+			function Group(name, isRoot, initiallyExpanded) {

+				this.name = name;

+				this.group = null;

+				this.isRoot = isRoot;

+				this.initiallyExpanded = initiallyExpanded;

+				this.elementContainers = [];

+				this.children = [];

+				this.expanded = initiallyExpanded;

+				this.rendered = false;

+				this.expandable = false;

+			}

+

+			Group.prototype = new LogItem();

+

+			copyProperties(Group.prototype, {

+				addChild: function(logItem) {

+					this.children.push(logItem);

+					logItem.group = this;

+				},

+

+				render: function() {

+					if (isIe) {

+						var unwrappedDomContainer, wrappedDomContainer;

+						if (this.isRoot) {

+							unwrappedDomContainer = logMainContainer;

+							wrappedDomContainer = logMainContainer;

+						} else {

+							unwrappedDomContainer = this.getUnwrappedDomContainer();

+							wrappedDomContainer = this.getWrappedDomContainer();

+						}

+						this.unwrappedElementContainer = new GroupElementContainer(this, unwrappedDomContainer, this.isRoot, false);

+						this.wrappedElementContainer = new GroupElementContainer(this, wrappedDomContainer, this.isRoot, true);

+						this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];

+					} else {

+						var mainDomContainer = this.isRoot ? logMainContainer : this.getMainDomContainer();

+						this.mainElementContainer = new GroupElementContainer(this, mainDomContainer, this.isRoot, false);

+						this.elementContainers = [this.mainElementContainer];

+					}

+					this.rendered = true;

+				},

+

+				toggleExpanded: function() {

+					this.expanded = !this.expanded;

+					for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+						this.elementContainers[i].toggleExpanded();

+					}

+				},

+

+				expand: function() {

+					if (!this.expanded) {

+						this.toggleExpanded();

+					}

+				},

+

+				accept: function(visitor) {

+					visitor.visitGroup(this);

+				},

+

+				reverseChildren: function() {

+					if (this.rendered) {

+						for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+							this.elementContainers[i].reverseChildren();

+						}

+					}

+				},

+

+				update: function() {

+					var previouslyExpandable = this.expandable;

+					this.expandable = (this.children.length !== 0);

+					if (this.expandable !== previouslyExpandable) {

+						for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+							this.elementContainers[i].update();

+						}

+					}

+				},

+

+				flatten: function() {

+					var visitor = new GroupFlattener();

+					this.accept(visitor);

+					return visitor.logEntriesAndSeparators;

+				},

+

+				removeChild: function(child, doUpdate) {

+					array_remove(this.children, child);

+					child.group = null;

+					if (doUpdate) {

+						this.update();

+					}

+				},

+

+				remove: function(doUpdate, removeFromGroup) {

+					for (var i = 0, len = this.children.length; i < len; i++) {

+						this.children[i].remove(false, false);

+					}

+					this.children = [];

+					this.update();

+					if (this === currentGroup) {

+						currentGroup = this.group;

+					}

+					this.doRemove(doUpdate, removeFromGroup);

+				},

+

+				serialize: function(items) {

+					items.push([LogItem.serializedItemKeys.GROUP_START, this.name]);

+					for (var i = 0, len = this.children.length; i < len; i++) {

+						this.children[i].serialize(items);

+					}

+					if (this !== currentGroup) {

+						items.push([LogItem.serializedItemKeys.GROUP_END]);

+					}

+				},

+

+				clear: function() {

+					for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+						this.elementContainers[i].clear();

+					}

+				}

+			});

+

+			/*----------------------------------------------------------------*/

+

+			function LogEntryElementContainer() {

+			}

+

+			LogEntryElementContainer.prototype = new LogItemContainerElement();

+

+			copyProperties(LogEntryElementContainer.prototype, {

+				remove: function() {

+					this.doRemove();

+				},

+

+				doRemove: function() {

+					this.mainDiv.parentNode.removeChild(this.mainDiv);

+					this.mainDiv = null;

+					this.contentElement = null;

+					this.containerDomNode = null;

+				},

+

+				setContent: function(content, wrappedContent) {

+					if (content === this.formattedMessage) {

+						this.contentElement.innerHTML = "";

+						this.contentElement.appendChild(document.createTextNode(this.formattedMessage));

+					} else {

+						this.contentElement.innerHTML = content;

+					}

+				},

+

+				setSearchMatch: function(isMatch) {

+					var oldCssClass = isMatch ? "searchnonmatch" : "searchmatch";

+					var newCssClass = isMatch ? "searchmatch" : "searchnonmatch";

+					replaceClass(this.mainDiv, newCssClass, oldCssClass);

+				},

+

+				clearSearch: function() {

+					removeClass(this.mainDiv, "searchmatch");

+					removeClass(this.mainDiv, "searchnonmatch");

+				}

+			});

+

+			/*----------------------------------------------------------------*/

+

+			function LogEntryWrappedElementContainer(logEntry, containerDomNode) {

+				this.logEntry = logEntry;

+				this.containerDomNode = containerDomNode;

+				this.mainDiv = document.createElement("div");

+				this.mainDiv.appendChild(document.createTextNode(this.logEntry.formattedMessage));

+				this.mainDiv.className = "logentry wrapped " + this.logEntry.level;

+				this.contentElement = this.mainDiv;

+			}

+

+			LogEntryWrappedElementContainer.prototype = new LogEntryElementContainer();

+

+			LogEntryWrappedElementContainer.prototype.setContent = function(content, wrappedContent) {

+				if (content === this.formattedMessage) {

+					this.contentElement.innerHTML = "";

+					this.contentElement.appendChild(document.createTextNode(this.formattedMessage));

+				} else {

+					this.contentElement.innerHTML = wrappedContent;

+				}

+			};

+

+			/*----------------------------------------------------------------*/

+

+			function LogEntryUnwrappedElementContainer(logEntry, containerDomNode) {

+				this.logEntry = logEntry;

+				this.containerDomNode = containerDomNode;

+				this.mainDiv = document.createElement("div");

+				this.mainDiv.className = "logentry unwrapped " + this.logEntry.level;

+				this.pre = this.mainDiv.appendChild(document.createElement("pre"));

+				this.pre.appendChild(document.createTextNode(this.logEntry.formattedMessage));

+				this.pre.className = "unwrapped";

+				this.contentElement = this.pre;

+			}

+

+			LogEntryUnwrappedElementContainer.prototype = new LogEntryElementContainer();

+

+			LogEntryUnwrappedElementContainer.prototype.remove = function() {

+				this.doRemove();

+				this.pre = null;

+			};

+

+			/*----------------------------------------------------------------*/

+

+			function LogEntryMainElementContainer(logEntry, containerDomNode) {

+				this.logEntry = logEntry;

+				this.containerDomNode = containerDomNode;

+				this.mainDiv = document.createElement("div");

+				this.mainDiv.className = "logentry nonielogentry " + this.logEntry.level;

+				this.contentElement = this.mainDiv.appendChild(document.createElement("span"));

+				this.contentElement.appendChild(document.createTextNode(this.logEntry.formattedMessage));

+			}

+

+			LogEntryMainElementContainer.prototype = new LogEntryElementContainer();

+

+			/*----------------------------------------------------------------*/

+

+			function LogEntry(level, formattedMessage) {

+				this.level = level;

+				this.formattedMessage = formattedMessage;

+				this.rendered = false;

+			}

+

+			LogEntry.prototype = new LogItem();

+

+			copyProperties(LogEntry.prototype, {

+				render: function() {

+					var logEntry = this;

+					var containerDomNode = this.group.contentDiv;

+

+					// Support for the CSS attribute white-space in IE for Windows is

+					// non-existent pre version 6 and slightly odd in 6, so instead

+					// use two different HTML elements

+					if (isIe) {

+						this.formattedMessage = this.formattedMessage.replace(/\r\n/g, "\r"); // Workaround for IE's treatment of white space

+						this.unwrappedElementContainer = new LogEntryUnwrappedElementContainer(this, this.getUnwrappedDomContainer());

+						this.wrappedElementContainer = new LogEntryWrappedElementContainer(this, this.getWrappedDomContainer());

+						this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];

+					} else {

+						this.mainElementContainer = new LogEntryMainElementContainer(this, this.getMainDomContainer());

+						this.elementContainers = [this.mainElementContainer];

+					}

+					this.content = this.formattedMessage;

+					this.rendered = true;

+				},

+

+				setContent: function(content, wrappedContent) {

+					if (content != this.content) {

+						if (isIe && (content !== this.formattedMessage)) {

+							content = content.replace(/\r\n/g, "\r"); // Workaround for IE's treatment of white space

+						}

+						for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+							this.elementContainers[i].setContent(content, wrappedContent);

+						}

+						this.content = content;

+					}

+				},

+

+				getSearchMatches: function() {

+					var matches = [];

+					var i, len;

+					if (isIe) {

+						var unwrappedEls = getElementsByClass(this.unwrappedElementContainer.mainDiv, "searchterm", "span");

+						var wrappedEls = getElementsByClass(this.wrappedElementContainer.mainDiv, "searchterm", "span");

+						for (i = 0, len = unwrappedEls.length; i < len; i++) {

+							matches[i] = new Match(this.level, null, unwrappedEls[i], wrappedEls[i]);

+						}

+					} else {

+						var els = getElementsByClass(this.mainElementContainer.mainDiv, "searchterm", "span");

+						for (i = 0, len = els.length; i < len; i++) {

+							matches[i] = new Match(this.level, els[i]);

+						}

+					}

+					return matches;

+				},

+

+				setSearchMatch: function(isMatch) {

+					for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+						this.elementContainers[i].setSearchMatch(isMatch);

+					}

+				},

+

+				clearSearch: function() {

+					for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+						this.elementContainers[i].clearSearch();

+					}

+				},

+

+				accept: function(visitor) {

+					visitor.visitLogEntry(this);

+				},

+

+				serialize: function(items) {

+					items.push([LogItem.serializedItemKeys.LOG_ENTRY, this.level, this.formattedMessage]);

+				}

+			});

+

+			/*----------------------------------------------------------------*/

+

+			function LogItemVisitor() {

+			}

+

+			LogItemVisitor.prototype = {

+				visit: function(logItem) {

+				},

+

+				visitParent: function(logItem) {

+					if (logItem.group) {

+						logItem.group.accept(this);

+					}

+				},

+

+				visitChildren: function(logItem) {

+					for (var i = 0, len = logItem.children.length; i < len; i++) {

+						logItem.children[i].accept(this);

+					}

+				},

+

+				visitLogEntry: function(logEntry) {

+					this.visit(logEntry);

+				},

+

+				visitSeparator: function(separator) {

+					this.visit(separator);

+				},

+

+				visitGroup: function(group) {

+					this.visit(group);

+				}

+			};

+

+			/*----------------------------------------------------------------*/

+

+			function GroupFlattener() {

+				this.logEntriesAndSeparators = [];

+			}

+

+			GroupFlattener.prototype = new LogItemVisitor();

+

+			GroupFlattener.prototype.visitGroup = function(group) {

+				this.visitChildren(group);

+			};

+

+			GroupFlattener.prototype.visitLogEntry = function(logEntry) {

+				this.logEntriesAndSeparators.push(logEntry);

+			};

+

+			GroupFlattener.prototype.visitSeparator = function(separator) {

+				this.logEntriesAndSeparators.push(separator);

+			};

+

+			/*----------------------------------------------------------------*/

+

+			window.onload = function() {

+				// Sort out document.domain

+				if (location.search) {

+					var queryBits = unescape(location.search).substr(1).split("&"), nameValueBits;

+					for (var i = 0, len = queryBits.length; i < len; i++) {

+						nameValueBits = queryBits[i].split("=");

+						if (nameValueBits[0] == "log4javascript_domain") {

+							document.domain = nameValueBits[1];

+							break;

+						}

+					}

+				}

+

+				// Create DOM objects

+				logMainContainer = $("log");

+				if (isIePre7) {

+					addClass(logMainContainer, "oldIe");

+				}

+

+				rootGroup = new Group("root", true);

+				rootGroup.render();

+				currentGroup = rootGroup;

+				

+				setCommandInputWidth();

+				setLogContainerHeight();

+				toggleLoggingEnabled();

+				toggleSearchEnabled();

+				toggleSearchFilter();

+				toggleSearchHighlight();

+				applyFilters();

+				checkAllLevels();

+				toggleWrap();

+				toggleNewestAtTop();

+				toggleScrollToLatest();

+				renderQueuedLogItems();

+				loaded = true;

+				$("command").value = "";

+				$("command").autocomplete = "off";

+				$("command").onkeydown = function(evt) {

+					evt = getEvent(evt);

+					if (evt.keyCode == 10 || evt.keyCode == 13) { // Return/Enter

+						evalCommandLine();

+						stopPropagation(evt);

+					} else if (evt.keyCode == 27) { // Escape

+						this.value = "";

+						this.focus();

+					} else if (evt.keyCode == 38 && commandHistory.length > 0) { // Up

+						currentCommandIndex = Math.max(0, currentCommandIndex - 1);

+						this.value = commandHistory[currentCommandIndex];

+						moveCaretToEnd(this);

+					} else if (evt.keyCode == 40 && commandHistory.length > 0) { // Down

+						currentCommandIndex = Math.min(commandHistory.length - 1, currentCommandIndex + 1);

+						this.value = commandHistory[currentCommandIndex];

+						moveCaretToEnd(this);

+					}

+				};

+

+				// Prevent the keypress moving the caret in Firefox

+				$("command").onkeypress = function(evt) {

+					evt = getEvent(evt);

+					if (evt.keyCode == 38 && commandHistory.length > 0 && evt.preventDefault) { // Up

+						evt.preventDefault();

+					}

+				};

+

+				// Prevent the keyup event blurring the input in Opera

+				$("command").onkeyup = function(evt) {

+					evt = getEvent(evt);

+					if (evt.keyCode == 27 && evt.preventDefault) { // Up

+						evt.preventDefault();

+						this.focus();

+					}

+				};

+

+				// Add document keyboard shortcuts

+				document.onkeydown = function keyEventHandler(evt) {

+					evt = getEvent(evt);

+					switch (evt.keyCode) {

+						case 69: // Ctrl + shift + E: re-execute last command

+							if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {

+								evalLastCommand();

+								cancelKeyEvent(evt);

+								return false;

+							}

+							break;

+						case 75: // Ctrl + shift + K: focus search

+							if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {

+								focusSearch();

+								cancelKeyEvent(evt);

+								return false;

+							}

+							break;

+						case 40: // Ctrl + shift + down arrow: focus command line

+						case 76: // Ctrl + shift + L: focus command line

+							if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {

+								focusCommandLine();

+								cancelKeyEvent(evt);

+								return false;

+							}

+							break;

+					}

+				};

+

+				// Workaround to make sure log div starts at the correct size

+				setTimeout(setLogContainerHeight, 20);

+

+				setShowCommandLine(showCommandLine);

+				doSearch();

+			};

+

+			window.onunload = function() {

+				if (mainWindowExists()) {

+					appender.unload();

+				}

+				appender = null;

+			};

+

+			/*----------------------------------------------------------------*/

+

+			function toggleLoggingEnabled() {

+				setLoggingEnabled($("enableLogging").checked);

+			}

+

+			function setLoggingEnabled(enable) {

+				loggingEnabled = enable;

+			}

+

+			var appender = null;

+

+			function setAppender(appenderParam) {

+				appender = appenderParam;

+			}

+

+			function setShowCloseButton(showCloseButton) {

+				$("closeButton").style.display = showCloseButton ? "inline" : "none";

+			}

+

+			function setShowHideButton(showHideButton) {

+				$("hideButton").style.display = showHideButton ? "inline" : "none";

+			}

+

+			var newestAtTop = false;

+

+			/*----------------------------------------------------------------*/

+

+			function LogItemContentReverser() {

+			}

+			

+			LogItemContentReverser.prototype = new LogItemVisitor();

+			

+			LogItemContentReverser.prototype.visitGroup = function(group) {

+				group.reverseChildren();

+				this.visitChildren(group);

+			};

+

+			/*----------------------------------------------------------------*/

+

+			function setNewestAtTop(isNewestAtTop) {

+				var oldNewestAtTop = newestAtTop;

+				var i, iLen, j, jLen;

+				newestAtTop = Boolean(isNewestAtTop);

+				if (oldNewestAtTop != newestAtTop) {

+					var visitor = new LogItemContentReverser();

+					rootGroup.accept(visitor);

+

+					// Reassemble the matches array

+					if (currentSearch) {

+						var currentMatch = currentSearch.matches[currentMatchIndex];

+						var matchIndex = 0;

+						var matches = [];

+						var actOnLogEntry = function(logEntry) {

+							var logEntryMatches = logEntry.getSearchMatches();

+							for (j = 0, jLen = logEntryMatches.length; j < jLen; j++) {

+								matches[matchIndex] = logEntryMatches[j];

+								if (currentMatch && logEntryMatches[j].equals(currentMatch)) {

+									currentMatchIndex = matchIndex;

+								}

+								matchIndex++;

+							}

+						};

+						if (newestAtTop) {

+							for (i = logEntries.length - 1; i >= 0; i--) {

+								actOnLogEntry(logEntries[i]);

+							}

+						} else {

+							for (i = 0, iLen = logEntries.length; i < iLen; i++) {

+								actOnLogEntry(logEntries[i]);

+							}

+						}

+						currentSearch.matches = matches;

+						if (currentMatch) {

+							currentMatch.setCurrent();

+						}

+					} else if (scrollToLatest) {

+						doScrollToLatest();

+					}

+				}

+				$("newestAtTop").checked = isNewestAtTop;

+			}

+

+			function toggleNewestAtTop() {

+				var isNewestAtTop = $("newestAtTop").checked;

+				setNewestAtTop(isNewestAtTop);

+			}

+

+			var scrollToLatest = true;

+

+			function setScrollToLatest(isScrollToLatest) {

+				scrollToLatest = isScrollToLatest;

+				if (scrollToLatest) {

+					doScrollToLatest();

+				}

+				$("scrollToLatest").checked = isScrollToLatest;

+			}

+

+			function toggleScrollToLatest() {

+				var isScrollToLatest = $("scrollToLatest").checked;

+				setScrollToLatest(isScrollToLatest);

+			}

+

+			function doScrollToLatest() {

+				var l = logMainContainer;

+				if (typeof l.scrollTop != "undefined") {

+					if (newestAtTop) {

+						l.scrollTop = 0;

+					} else {

+						var latestLogEntry = l.lastChild;

+						if (latestLogEntry) {

+							l.scrollTop = l.scrollHeight;

+						}

+					}

+				}

+			}

+

+			var closeIfOpenerCloses = true;

+

+			function setCloseIfOpenerCloses(isCloseIfOpenerCloses) {

+				closeIfOpenerCloses = isCloseIfOpenerCloses;

+			}

+

+			var maxMessages = null;

+

+			function setMaxMessages(max) {

+				maxMessages = max;

+				pruneLogEntries();

+			}

+

+			var showCommandLine = false;

+

+			function setShowCommandLine(isShowCommandLine) {

+				showCommandLine = isShowCommandLine;

+				if (loaded) {

+					$("commandLine").style.display = showCommandLine ? "block" : "none";

+					setCommandInputWidth();

+					setLogContainerHeight();

+				}

+			}

+

+			function focusCommandLine() {

+				if (loaded) {

+					$("command").focus();

+				}

+			}

+

+			function focusSearch() {

+				if (loaded) {

+					$("searchBox").focus();

+				}

+			}

+

+			function getLogItems() {

+				var items = [];

+				for (var i = 0, len = logItems.length; i < len; i++) {

+					logItems[i].serialize(items);

+				}

+				return items;

+			}

+

+			function setLogItems(items) {

+				var loggingReallyEnabled = loggingEnabled;

+				// Temporarily turn logging on

+				loggingEnabled = true;

+				for (var i = 0, len = items.length; i < len; i++) {

+					switch (items[i][0]) {

+						case LogItem.serializedItemKeys.LOG_ENTRY:

+							log(items[i][1], items[i][2]);

+							break;

+						case LogItem.serializedItemKeys.GROUP_START:

+							group(items[i][1]);

+							break;

+						case LogItem.serializedItemKeys.GROUP_END:

+							groupEnd();

+							break;

+					}

+				}

+				loggingEnabled = loggingReallyEnabled;

+			}

+

+			function log(logLevel, formattedMessage) {

+				if (loggingEnabled) {

+					var logEntry = new LogEntry(logLevel, formattedMessage);

+					logEntries.push(logEntry);

+					logEntriesAndSeparators.push(logEntry);

+					logItems.push(logEntry);

+					currentGroup.addChild(logEntry);

+					if (loaded) {

+						if (logQueuedEventsTimer !== null) {

+							clearTimeout(logQueuedEventsTimer);

+						}

+						logQueuedEventsTimer = setTimeout(renderQueuedLogItems, renderDelay);

+						unrenderedLogItemsExist = true;

+					}

+				}

+			}

+

+			function renderQueuedLogItems() {

+				logQueuedEventsTimer = null;

+				var pruned = pruneLogEntries();

+

+				// Render any unrendered log entries and apply the current search to them

+				var initiallyHasMatches = currentSearch ? currentSearch.hasMatches() : false;

+				for (var i = 0, len = logItems.length; i < len; i++) {

+					if (!logItems[i].rendered) {

+						logItems[i].render();

+						logItems[i].appendToLog();

+						if (currentSearch && (logItems[i] instanceof LogEntry)) {

+							currentSearch.applyTo(logItems[i]);

+						}

+					}

+				}

+				if (currentSearch) {

+					if (pruned) {

+						if (currentSearch.hasVisibleMatches()) {

+							if (currentMatchIndex === null) {

+								setCurrentMatchIndex(0);

+							}

+							displayMatches();

+						} else {

+							displayNoMatches();

+						}

+					} else if (!initiallyHasMatches && currentSearch.hasVisibleMatches()) {

+						setCurrentMatchIndex(0);

+						displayMatches();

+					}

+				}

+				if (scrollToLatest) {

+					doScrollToLatest();

+				}

+				unrenderedLogItemsExist = false;

+			}

+

+			function pruneLogEntries() {

+				if ((maxMessages !== null) && (logEntriesAndSeparators.length > maxMessages)) {

+					var numberToDelete = logEntriesAndSeparators.length - maxMessages;

+					var prunedLogEntries = logEntriesAndSeparators.slice(0, numberToDelete);

+					if (currentSearch) {

+						currentSearch.removeMatches(prunedLogEntries);

+					}

+					var group;

+					for (var i = 0; i < numberToDelete; i++) {

+						group = logEntriesAndSeparators[i].group;

+						array_remove(logItems, logEntriesAndSeparators[i]);

+						array_remove(logEntries, logEntriesAndSeparators[i]);

+						logEntriesAndSeparators[i].remove(true, true);

+						if (group.children.length === 0 && group !== currentGroup && group !== rootGroup) {

+							array_remove(logItems, group);

+							group.remove(true, true);

+						}

+					}

+					logEntriesAndSeparators = array_removeFromStart(logEntriesAndSeparators, numberToDelete);

+					return true;

+				}

+				return false;

+			}

+

+			function group(name, startExpanded) {

+				if (loggingEnabled) {

+					initiallyExpanded = (typeof startExpanded === "undefined") ? true : Boolean(startExpanded);

+					var newGroup = new Group(name, false, initiallyExpanded);

+					currentGroup.addChild(newGroup);

+					currentGroup = newGroup;

+					logItems.push(newGroup);

+					if (loaded) {

+						if (logQueuedEventsTimer !== null) {

+							clearTimeout(logQueuedEventsTimer);

+						}

+						logQueuedEventsTimer = setTimeout(renderQueuedLogItems, renderDelay);

+						unrenderedLogItemsExist = true;

+					}

+				}

+			}

+

+			function groupEnd() {

+				currentGroup = (currentGroup === rootGroup) ? rootGroup : currentGroup.group;

+			}

+

+			function mainPageReloaded() {

+				currentGroup = rootGroup;

+				var separator = new Separator();

+				logEntriesAndSeparators.push(separator);

+				logItems.push(separator);

+				currentGroup.addChild(separator);

+			}

+

+			function closeWindow() {

+				if (appender && mainWindowExists()) {

+					appender.close(true);

+				} else {

+					window.close();

+				}

+			}

+

+			function hide() {

+				if (appender && mainWindowExists()) {

+					appender.hide();

+				}

+			}

+

+			var mainWindow = window;

+			var windowId = "log4javascriptConsoleWindow_" + new Date().getTime() + "_" + ("" + Math.random()).substr(2);

+

+			function setMainWindow(win) {

+				mainWindow = win;

+				mainWindow[windowId] = window;

+				// If this is a pop-up, poll the opener to see if it's closed

+				if (opener && closeIfOpenerCloses) {

+					pollOpener();

+				}

+			}

+

+			function pollOpener() {

+				if (closeIfOpenerCloses) {

+					if (mainWindowExists()) {

+						setTimeout(pollOpener, 500);

+					} else {

+						closeWindow();

+					}

+				}

+			}

+

+			function mainWindowExists() {

+				try {

+					return (mainWindow && !mainWindow.closed &&

+						mainWindow[windowId] == window);

+				} catch (ex) {}

+				return false;

+			}

+

+			var logLevels = ["TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"];

+

+			function getCheckBox(logLevel) {

+				return $("switch_" + logLevel);

+			}

+

+			function getIeWrappedLogContainer() {

+				return $("log_wrapped");

+			}

+

+			function getIeUnwrappedLogContainer() {

+				return $("log_unwrapped");

+			}

+

+			function applyFilters() {

+				for (var i = 0; i < logLevels.length; i++) {

+					if (getCheckBox(logLevels[i]).checked) {

+						addClass(logMainContainer, logLevels[i]);

+					} else {

+						removeClass(logMainContainer, logLevels[i]);

+					}

+				}

+				updateSearchFromFilters();

+			}

+

+			function toggleAllLevels() {

+				var turnOn = $("switch_ALL").checked;

+				for (var i = 0; i < logLevels.length; i++) {

+					getCheckBox(logLevels[i]).checked = turnOn;

+					if (turnOn) {

+						addClass(logMainContainer, logLevels[i]);

+					} else {

+						removeClass(logMainContainer, logLevels[i]);

+					}

+				}

+			}

+

+			function checkAllLevels() {

+				for (var i = 0; i < logLevels.length; i++) {

+					if (!getCheckBox(logLevels[i]).checked) {

+						getCheckBox("ALL").checked = false;

+						return;

+					}

+				}

+				getCheckBox("ALL").checked = true;

+			}

+

+			function clearLog() {

+				rootGroup.clear();

+				currentGroup = rootGroup;

+				logEntries = [];

+				logItems = [];

+				logEntriesAndSeparators = [];

+ 				doSearch();

+			}

+

+			function toggleWrap() {

+				var enable = $("wrap").checked;

+				if (enable) {

+					addClass(logMainContainer, "wrap");

+				} else {

+					removeClass(logMainContainer, "wrap");

+				}

+				refreshCurrentMatch();

+			}

+

+			/* ------------------------------------------------------------------- */

+

+			// Search

+

+			var searchTimer = null;

+

+			function scheduleSearch() {

+				try {

+					clearTimeout(searchTimer);

+				} catch (ex) {

+					// Do nothing

+				}

+				searchTimer = setTimeout(doSearch, 500);

+			}

+

+			function Search(searchTerm, isRegex, searchRegex, isCaseSensitive) {

+				this.searchTerm = searchTerm;

+				this.isRegex = isRegex;

+				this.searchRegex = searchRegex;

+				this.isCaseSensitive = isCaseSensitive;

+				this.matches = [];

+			}

+

+			Search.prototype = {

+				hasMatches: function() {

+					return this.matches.length > 0;

+				},

+

+				hasVisibleMatches: function() {

+					if (this.hasMatches()) {

+						for (var i = 0; i < this.matches.length; i++) {

+							if (this.matches[i].isVisible()) {

+								return true;

+							}

+						}

+					}

+					return false;

+				},

+

+				match: function(logEntry) {

+					var entryText = String(logEntry.formattedMessage);

+					var matchesSearch = false;

+					if (this.isRegex) {

+						matchesSearch = this.searchRegex.test(entryText);

+					} else if (this.isCaseSensitive) {

+						matchesSearch = (entryText.indexOf(this.searchTerm) > -1);

+					} else {

+						matchesSearch = (entryText.toLowerCase().indexOf(this.searchTerm.toLowerCase()) > -1);

+					}

+					return matchesSearch;

+				},

+

+				getNextVisibleMatchIndex: function() {

+					for (var i = currentMatchIndex + 1; i < this.matches.length; i++) {

+						if (this.matches[i].isVisible()) {

+							return i;

+						}

+					}

+					// Start again from the first match

+					for (i = 0; i <= currentMatchIndex; i++) {

+						if (this.matches[i].isVisible()) {

+							return i;

+						}

+					}

+					return -1;

+				},

+

+				getPreviousVisibleMatchIndex: function() {

+					for (var i = currentMatchIndex - 1; i >= 0; i--) {

+						if (this.matches[i].isVisible()) {

+							return i;

+						}

+					}

+					// Start again from the last match

+					for (var i = this.matches.length - 1; i >= currentMatchIndex; i--) {

+						if (this.matches[i].isVisible()) {

+							return i;

+						}

+					}

+					return -1;

+				},

+

+				applyTo: function(logEntry) {

+					var doesMatch = this.match(logEntry);

+					if (doesMatch) {

+						logEntry.group.expand();

+						logEntry.setSearchMatch(true);

+						var logEntryContent;

+						var wrappedLogEntryContent;

+						var searchTermReplacementStartTag = "<span class=\"searchterm\">";

+						var searchTermReplacementEndTag = "<" + "/span>";

+						var preTagName = isIe ? "pre" : "span";

+						var preStartTag = "<" + preTagName + " class=\"pre\">";

+						var preEndTag = "<" + "/" + preTagName + ">";

+						var startIndex = 0;

+						var searchIndex, matchedText, textBeforeMatch;

+						if (this.isRegex) {

+							var flags = this.isCaseSensitive ? "g" : "gi";

+							var capturingRegex = new RegExp("(" + this.searchRegex.source + ")", flags);

+

+							// Replace the search term with temporary tokens for the start and end tags

+							var rnd = ("" + Math.random()).substr(2);

+							var startToken = "%%s" + rnd + "%%";

+							var endToken = "%%e" + rnd + "%%";

+							logEntryContent = logEntry.formattedMessage.replace(capturingRegex, startToken + "$1" + endToken);

+

+							// Escape the HTML to get rid of angle brackets

+							logEntryContent = escapeHtml(logEntryContent);

+

+							// Substitute the proper HTML back in for the search match

+							var result;

+							var searchString = logEntryContent;

+							logEntryContent = "";

+							wrappedLogEntryContent = "";

+							while ((searchIndex = searchString.indexOf(startToken, startIndex)) > -1) {

+								var endTokenIndex = searchString.indexOf(endToken, searchIndex);

+								matchedText = searchString.substring(searchIndex + startToken.length, endTokenIndex);

+								textBeforeMatch = searchString.substring(startIndex, searchIndex);

+								logEntryContent += preStartTag + textBeforeMatch + preEndTag;

+								logEntryContent += searchTermReplacementStartTag + preStartTag + matchedText +

+									preEndTag + searchTermReplacementEndTag;

+								if (isIe) {

+									wrappedLogEntryContent += textBeforeMatch + searchTermReplacementStartTag +

+										matchedText + searchTermReplacementEndTag;

+								}

+								startIndex = endTokenIndex + endToken.length;

+							}

+							logEntryContent += preStartTag + searchString.substr(startIndex) + preEndTag;

+							if (isIe) {

+								wrappedLogEntryContent += searchString.substr(startIndex);

+							}

+						} else {

+							logEntryContent = "";

+							wrappedLogEntryContent = "";

+							var searchTermReplacementLength = searchTermReplacementStartTag.length +

+								this.searchTerm.length + searchTermReplacementEndTag.length;

+							var searchTermLength = this.searchTerm.length;

+							var searchTermLowerCase = this.searchTerm.toLowerCase();

+							var logTextLowerCase = logEntry.formattedMessage.toLowerCase();

+							while ((searchIndex = logTextLowerCase.indexOf(searchTermLowerCase, startIndex)) > -1) {

+								matchedText = escapeHtml(logEntry.formattedMessage.substr(searchIndex, this.searchTerm.length));

+								textBeforeMatch = escapeHtml(logEntry.formattedMessage.substring(startIndex, searchIndex));

+								var searchTermReplacement = searchTermReplacementStartTag +

+									preStartTag + matchedText + preEndTag + searchTermReplacementEndTag;

+								logEntryContent += preStartTag + textBeforeMatch + preEndTag + searchTermReplacement;

+								if (isIe) {

+									wrappedLogEntryContent += textBeforeMatch + searchTermReplacementStartTag +

+										matchedText + searchTermReplacementEndTag;

+								}

+								startIndex = searchIndex + searchTermLength;

+							}

+							var textAfterLastMatch = escapeHtml(logEntry.formattedMessage.substr(startIndex));

+							logEntryContent += preStartTag + textAfterLastMatch + preEndTag;

+							if (isIe) {

+								wrappedLogEntryContent += textAfterLastMatch;

+							}

+						}

+						logEntry.setContent(logEntryContent, wrappedLogEntryContent);

+						var logEntryMatches = logEntry.getSearchMatches();

+						this.matches = this.matches.concat(logEntryMatches);

+					} else {

+						logEntry.setSearchMatch(false);

+						logEntry.setContent(logEntry.formattedMessage, logEntry.formattedMessage);

+					}

+					return doesMatch;

+				},

+

+				removeMatches: function(logEntries) {

+					var matchesToRemoveCount = 0;

+					var currentMatchRemoved = false;

+					var matchesToRemove = [];

+					var i, iLen, j, jLen;

+

+					// Establish the list of matches to be removed

+					for (i = 0, iLen = this.matches.length; i < iLen; i++) {

+						for (j = 0, jLen = logEntries.length; j < jLen; j++) {

+							if (this.matches[i].belongsTo(logEntries[j])) {

+								matchesToRemove.push(this.matches[i]);

+								if (i === currentMatchIndex) {

+									currentMatchRemoved = true;

+								}

+							}

+						}

+					}

+

+					// Set the new current match index if the current match has been deleted

+					// This will be the first match that appears after the first log entry being

+					// deleted, if one exists; otherwise, it's the first match overall

+					var newMatch = currentMatchRemoved ? null : this.matches[currentMatchIndex];

+					if (currentMatchRemoved) {

+						for (i = currentMatchIndex, iLen = this.matches.length; i < iLen; i++) {

+							if (this.matches[i].isVisible() && !array_contains(matchesToRemove, this.matches[i])) {

+								newMatch = this.matches[i];

+								break;

+							}

+						}

+					}

+

+					// Remove the matches

+					for (i = 0, iLen = matchesToRemove.length; i < iLen; i++) {

+						array_remove(this.matches, matchesToRemove[i]);

+						matchesToRemove[i].remove();

+					}

+

+					// Set the new match, if one exists

+					if (this.hasVisibleMatches()) {

+						if (newMatch === null) {

+							setCurrentMatchIndex(0);

+						} else {

+							// Get the index of the new match

+							var newMatchIndex = 0;

+							for (i = 0, iLen = this.matches.length; i < iLen; i++) {

+								if (newMatch === this.matches[i]) {

+									newMatchIndex = i;

+									break;

+								}

+							}

+							setCurrentMatchIndex(newMatchIndex);

+						}

+					} else {

+						currentMatchIndex = null;

+						displayNoMatches();

+					}

+				}

+			};

+

+			function getPageOffsetTop(el, container) {

+				var currentEl = el;

+				var y = 0;

+				while (currentEl && currentEl != container) {

+					y += currentEl.offsetTop;

+					currentEl = currentEl.offsetParent;

+				}

+				return y;

+			}

+

+			function scrollIntoView(el) {

+				var logContainer = logMainContainer;

+				// Check if the whole width of the element is visible and centre if not

+				if (!$("wrap").checked) {

+					var logContainerLeft = logContainer.scrollLeft;

+					var logContainerRight = logContainerLeft  + logContainer.offsetWidth;

+					var elLeft = el.offsetLeft;

+					var elRight = elLeft + el.offsetWidth;

+					if (elLeft < logContainerLeft || elRight > logContainerRight) {

+						logContainer.scrollLeft = elLeft - (logContainer.offsetWidth - el.offsetWidth) / 2;

+					}

+				}

+				// Check if the whole height of the element is visible and centre if not

+				var logContainerTop = logContainer.scrollTop;

+				var logContainerBottom = logContainerTop  + logContainer.offsetHeight;

+				var elTop = getPageOffsetTop(el) - getToolBarsHeight();

+				var elBottom = elTop + el.offsetHeight;

+				if (elTop < logContainerTop || elBottom > logContainerBottom) {

+					logContainer.scrollTop = elTop - (logContainer.offsetHeight - el.offsetHeight) / 2;

+				}

+			}

+

+			function Match(logEntryLevel, spanInMainDiv, spanInUnwrappedPre, spanInWrappedDiv) {

+				this.logEntryLevel = logEntryLevel;

+				this.spanInMainDiv = spanInMainDiv;

+				if (isIe) {

+					this.spanInUnwrappedPre = spanInUnwrappedPre;

+					this.spanInWrappedDiv = spanInWrappedDiv;

+				}

+				this.mainSpan = isIe ? spanInUnwrappedPre : spanInMainDiv;

+			}

+

+			Match.prototype = {

+				equals: function(match) {

+					return this.mainSpan === match.mainSpan;

+				},

+

+				setCurrent: function() {

+					if (isIe) {

+						addClass(this.spanInUnwrappedPre, "currentmatch");

+						addClass(this.spanInWrappedDiv, "currentmatch");

+						// Scroll the visible one into view

+						var elementToScroll = $("wrap").checked ? this.spanInWrappedDiv : this.spanInUnwrappedPre;

+						scrollIntoView(elementToScroll);

+					} else {

+						addClass(this.spanInMainDiv, "currentmatch");

+						scrollIntoView(this.spanInMainDiv);

+					}

+				},

+

+				belongsTo: function(logEntry) {

+					if (isIe) {

+						return isDescendant(this.spanInUnwrappedPre, logEntry.unwrappedPre);

+					} else {

+						return isDescendant(this.spanInMainDiv, logEntry.mainDiv);

+					}

+				},

+

+				setNotCurrent: function() {

+					if (isIe) {

+						removeClass(this.spanInUnwrappedPre, "currentmatch");

+						removeClass(this.spanInWrappedDiv, "currentmatch");

+					} else {

+						removeClass(this.spanInMainDiv, "currentmatch");

+					}

+				},

+

+				isOrphan: function() {

+					return isOrphan(this.mainSpan);

+				},

+

+				isVisible: function() {

+					return getCheckBox(this.logEntryLevel).checked;

+				},

+

+				remove: function() {

+					if (isIe) {

+						this.spanInUnwrappedPre = null;

+						this.spanInWrappedDiv = null;

+					} else {

+						this.spanInMainDiv = null;

+					}

+				}

+			};

+

+			var currentSearch = null;

+			var currentMatchIndex = null;

+

+			function doSearch() {

+				var searchBox = $("searchBox");

+				var searchTerm = searchBox.value;

+				var isRegex = $("searchRegex").checked;

+				var isCaseSensitive = $("searchCaseSensitive").checked;

+				var i;

+

+				if (searchTerm === "") {

+					$("searchReset").disabled = true;

+					$("searchNav").style.display = "none";

+					removeClass(document.body, "searching");

+					removeClass(searchBox, "hasmatches");

+					removeClass(searchBox, "nomatches");

+					for (i = 0; i < logEntries.length; i++) {

+						logEntries[i].clearSearch();

+						logEntries[i].setContent(logEntries[i].formattedMessage, logEntries[i].formattedMessage);

+					}

+					currentSearch = null;

+					setLogContainerHeight();

+				} else {

+					$("searchReset").disabled = false;

+					$("searchNav").style.display = "block";

+					var searchRegex;

+					var regexValid;

+					if (isRegex) {

+						try {

+							searchRegex = isCaseSensitive ? new RegExp(searchTerm, "g") : new RegExp(searchTerm, "gi");

+							regexValid = true;

+							replaceClass(searchBox, "validregex", "invalidregex");

+							searchBox.title = "Valid regex";

+						} catch (ex) {

+							regexValid = false;

+							replaceClass(searchBox, "invalidregex", "validregex");

+							searchBox.title = "Invalid regex: " + (ex.message ? ex.message : (ex.description ? ex.description : "unknown error"));

+							return;

+						}

+					} else {

+						searchBox.title = "";

+						removeClass(searchBox, "validregex");

+						removeClass(searchBox, "invalidregex");

+					}

+					addClass(document.body, "searching");

+					currentSearch = new Search(searchTerm, isRegex, searchRegex, isCaseSensitive);

+					for (i = 0; i < logEntries.length; i++) {

+						currentSearch.applyTo(logEntries[i]);

+					}

+					setLogContainerHeight();

+

+					// Highlight the first search match

+					if (currentSearch.hasVisibleMatches()) {

+						setCurrentMatchIndex(0);

+						displayMatches();

+					} else {

+						displayNoMatches();

+					}

+				}

+			}

+

+			function updateSearchFromFilters() {

+				if (currentSearch) {

+					if (currentSearch.hasMatches()) {

+						if (currentMatchIndex === null) {

+							currentMatchIndex = 0;

+						}

+						var currentMatch = currentSearch.matches[currentMatchIndex];

+						if (currentMatch.isVisible()) {

+							displayMatches();

+							setCurrentMatchIndex(currentMatchIndex);

+						} else {

+							currentMatch.setNotCurrent();

+							// Find the next visible match, if one exists

+							var nextVisibleMatchIndex = currentSearch.getNextVisibleMatchIndex();

+							if (nextVisibleMatchIndex > -1) {

+								setCurrentMatchIndex(nextVisibleMatchIndex);

+								displayMatches();

+							} else {

+								displayNoMatches();

+							}

+						}

+					} else {

+						displayNoMatches();

+					}

+				}

+			}

+

+			function refreshCurrentMatch() {

+				if (currentSearch && currentSearch.hasVisibleMatches()) {

+					setCurrentMatchIndex(currentMatchIndex);

+				}

+			}

+

+			function displayMatches() {

+				replaceClass($("searchBox"), "hasmatches", "nomatches");

+				$("searchBox").title = "" + currentSearch.matches.length + " matches found";

+				$("searchNav").style.display = "block";

+				setLogContainerHeight();

+			}

+

+			function displayNoMatches() {

+				replaceClass($("searchBox"), "nomatches", "hasmatches");

+				$("searchBox").title = "No matches found";

+				$("searchNav").style.display = "none";

+				setLogContainerHeight();

+			}

+

+			function toggleSearchEnabled(enable) {

+				enable = (typeof enable == "undefined") ? !$("searchDisable").checked : enable;

+				$("searchBox").disabled = !enable;

+				$("searchReset").disabled = !enable;

+				$("searchRegex").disabled = !enable;

+				$("searchNext").disabled = !enable;

+				$("searchPrevious").disabled = !enable;

+				$("searchCaseSensitive").disabled = !enable;

+				$("searchNav").style.display = (enable && ($("searchBox").value !== "") &&

+						currentSearch && currentSearch.hasVisibleMatches()) ?

+					"block" : "none";

+				if (enable) {

+					removeClass($("search"), "greyedout");

+					addClass(document.body, "searching");

+					if ($("searchHighlight").checked) {

+						addClass(logMainContainer, "searchhighlight");

+					} else {

+						removeClass(logMainContainer, "searchhighlight");

+					}

+					if ($("searchFilter").checked) {

+						addClass(logMainContainer, "searchfilter");

+					} else {

+						removeClass(logMainContainer, "searchfilter");

+					}

+					$("searchDisable").checked = !enable;

+				} else {

+					addClass($("search"), "greyedout");

+					removeClass(document.body, "searching");

+					removeClass(logMainContainer, "searchhighlight");

+					removeClass(logMainContainer, "searchfilter");

+				}

+				setLogContainerHeight();

+			}

+

+			function toggleSearchFilter() {

+				var enable = $("searchFilter").checked;

+				if (enable) {

+					addClass(logMainContainer, "searchfilter");

+				} else {

+					removeClass(logMainContainer, "searchfilter");

+				}

+				refreshCurrentMatch();

+			}

+

+			function toggleSearchHighlight() {

+				var enable = $("searchHighlight").checked;

+				if (enable) {

+					addClass(logMainContainer, "searchhighlight");

+				} else {

+					removeClass(logMainContainer, "searchhighlight");

+				}

+			}

+

+			function clearSearch() {

+				$("searchBox").value = "";

+				doSearch();

+			}

+

+			function searchNext() {

+				if (currentSearch !== null && currentMatchIndex !== null) {

+					currentSearch.matches[currentMatchIndex].setNotCurrent();

+					var nextMatchIndex = currentSearch.getNextVisibleMatchIndex();

+					if (nextMatchIndex > currentMatchIndex || confirm("Reached the end of the page. Start from the top?")) {

+						setCurrentMatchIndex(nextMatchIndex);

+					}

+				}

+			}

+

+			function searchPrevious() {

+				if (currentSearch !== null && currentMatchIndex !== null) {

+					currentSearch.matches[currentMatchIndex].setNotCurrent();

+					var previousMatchIndex = currentSearch.getPreviousVisibleMatchIndex();

+					if (previousMatchIndex < currentMatchIndex || confirm("Reached the start of the page. Continue from the bottom?")) {

+						setCurrentMatchIndex(previousMatchIndex);

+					}

+				}

+			}

+

+			function setCurrentMatchIndex(index) {

+				currentMatchIndex = index;

+				currentSearch.matches[currentMatchIndex].setCurrent();

+			}

+

+			/* ------------------------------------------------------------------------- */

+

+			// CSS Utilities

+

+			function addClass(el, cssClass) {

+				if (!hasClass(el, cssClass)) {

+					if (el.className) {

+						el.className += " " + cssClass;

+					} else {

+						el.className = cssClass;

+					}

+				}

+			}

+

+			function hasClass(el, cssClass) {

+				if (el.className) {

+					var classNames = el.className.split(" ");

+					return array_contains(classNames, cssClass);

+				}

+				return false;

+			}

+

+			function removeClass(el, cssClass) {

+				if (hasClass(el, cssClass)) {

+					// Rebuild the className property

+					var existingClasses = el.className.split(" ");

+					var newClasses = [];

+					for (var i = 0, len = existingClasses.length; i < len; i++) {

+						if (existingClasses[i] != cssClass) {

+							newClasses[newClasses.length] = existingClasses[i];

+						}

+					}

+					el.className = newClasses.join(" ");

+				}

+			}

+

+			function replaceClass(el, newCssClass, oldCssClass) {

+				removeClass(el, oldCssClass);

+				addClass(el, newCssClass);

+			}

+

+			/* ------------------------------------------------------------------------- */

+

+			// Other utility functions

+

+			function getElementsByClass(el, cssClass, tagName) {

+				var elements = el.getElementsByTagName(tagName);

+				var matches = [];

+				for (var i = 0, len = elements.length; i < len; i++) {

+					if (hasClass(elements[i], cssClass)) {

+						matches.push(elements[i]);

+					}

+				}

+				return matches;

+			}

+

+			// Syntax borrowed from Prototype library

+			function $(id) {

+				return document.getElementById(id);

+			}

+

+			function isDescendant(node, ancestorNode) {

+				while (node != null) {

+					if (node === ancestorNode) {

+						return true;

+					}

+					node = node.parentNode;

+				}

+				return false;

+			}

+

+			function isOrphan(node) {

+				var currentNode = node;

+				while (currentNode) {

+					if (currentNode == document.body) {

+						return false;

+					}

+					currentNode = currentNode.parentNode;

+				}

+				return true;

+			}

+

+			function escapeHtml(str) {

+				return str.replace(/&/g, "&amp;").replace(/[<]/g, "&lt;").replace(/>/g, "&gt;");

+			}

+

+			function getWindowWidth() {

+				if (window.innerWidth) {

+					return window.innerWidth;

+				} else if (document.documentElement && document.documentElement.clientWidth) {

+					return document.documentElement.clientWidth;

+				} else if (document.body) {

+					return document.body.clientWidth;

+				}

+				return 0;

+			}

+

+			function getWindowHeight() {

+				if (window.innerHeight) {

+					return window.innerHeight;

+				} else if (document.documentElement && document.documentElement.clientHeight) {

+					return document.documentElement.clientHeight;

+				} else if (document.body) {

+					return document.body.clientHeight;

+				}

+				return 0;

+			}

+

+			function getToolBarsHeight() {

+				return $("switches").offsetHeight;

+			}

+

+			function getChromeHeight() {

+				var height = getToolBarsHeight();

+				if (showCommandLine) {

+					height += $("commandLine").offsetHeight;

+				}

+				return height;

+			}

+

+			function setLogContainerHeight() {

+				if (logMainContainer) {

+					var windowHeight = getWindowHeight();

+					$("body").style.height = getWindowHeight() + "px";

+					logMainContainer.style.height = "" +

+						Math.max(0, windowHeight - getChromeHeight()) + "px";

+				}

+			}

+

+			function setCommandInputWidth() {

+				if (showCommandLine) {

+					$("command").style.width = "" + Math.max(0, $("commandLineContainer").offsetWidth -

+						($("evaluateButton").offsetWidth + 13)) + "px";

+				}

+			}

+

+			window.onresize = function() {

+				setCommandInputWidth();

+				setLogContainerHeight();

+			};

+

+			if (!Array.prototype.push) {

+				Array.prototype.push = function() {

+			        for (var i = 0, len = arguments.length; i < len; i++){

+			            this[this.length] = arguments[i];

+			        }

+			        return this.length;

+				};

+			}

+

+			if (!Array.prototype.pop) {

+				Array.prototype.pop = function() {

+					if (this.length > 0) {

+						var val = this[this.length - 1];

+						this.length = this.length - 1;

+						return val;

+					}

+				};

+			}

+

+			if (!Array.prototype.shift) {

+				Array.prototype.shift = function() {

+					if (this.length > 0) {

+						var firstItem = this[0];

+						for (var i = 0, len = this.length - 1; i < len; i++) {

+							this[i] = this[i + 1];

+						}

+						this.length = this.length - 1;

+						return firstItem;

+					}

+				};

+			}

+

+			if (!Array.prototype.splice) {

+				Array.prototype.splice = function(startIndex, deleteCount) {

+					var itemsAfterDeleted = this.slice(startIndex + deleteCount);

+					var itemsDeleted = this.slice(startIndex, startIndex + deleteCount);

+					this.length = startIndex;

+					// Copy the arguments into a proper Array object

+					var argumentsArray = [];

+					for (var i = 0, len = arguments.length; i < len; i++) {

+						argumentsArray[i] = arguments[i];

+					}

+					var itemsToAppend = (argumentsArray.length > 2) ?

+						itemsAfterDeleted = argumentsArray.slice(2).concat(itemsAfterDeleted) : itemsAfterDeleted;

+					for (i = 0, len = itemsToAppend.length; i < len; i++) {

+						this.push(itemsToAppend[i]);

+					}

+					return itemsDeleted;

+				};

+			}

+

+			function array_remove(arr, val) {

+				var index = -1;

+				for (var i = 0, len = arr.length; i < len; i++) {

+					if (arr[i] === val) {

+						index = i;

+						break;

+					}

+				}

+				if (index >= 0) {

+					arr.splice(index, 1);

+					return index;

+				} else {

+					return false;

+				}

+			}

+

+			function array_removeFromStart(array, numberToRemove) {

+				if (Array.prototype.splice) {

+					array.splice(0, numberToRemove);

+				} else {

+					for (var i = numberToRemove, len = array.length; i < len; i++) {

+						array[i - numberToRemove] = array[i];

+					}

+					array.length = array.length - numberToRemove;

+				}

+				return array;

+			}

+

+			function array_contains(arr, val) {

+				for (var i = 0, len = arr.length; i < len; i++) {

+					if (arr[i] == val) {

+						return true;

+					}

+				}

+				return false;

+			}

+

+			function getErrorMessage(ex) {

+				if (ex.message) {

+					return ex.message;

+				} else if (ex.description) {

+					return ex.description;

+				}

+				return "" + ex;

+			}

+

+			function moveCaretToEnd(input) {

+				if (input.setSelectionRange) {

+					input.focus();

+					var length = input.value.length;

+					input.setSelectionRange(length, length);

+				} else if (input.createTextRange) {

+					var range = input.createTextRange();

+					range.collapse(false);

+					range.select();

+				}

+				input.focus();

+			}

+

+			function stopPropagation(evt) {

+				if (evt.stopPropagation) {

+					evt.stopPropagation();

+				} else if (typeof evt.cancelBubble != "undefined") {

+					evt.cancelBubble = true;

+				}

+			}

+

+			function getEvent(evt) {

+				return evt ? evt : event;

+			}

+

+			function getTarget(evt) {

+				return evt.target ? evt.target : evt.srcElement;

+			}

+

+			function getRelatedTarget(evt) {

+				if (evt.relatedTarget) {

+					return evt.relatedTarget;

+				} else if (evt.srcElement) {

+					switch(evt.type) {

+						case "mouseover":

+							return evt.fromElement;

+						case "mouseout":

+							return evt.toElement;

+						default:

+							return evt.srcElement;

+					}

+				}

+			}

+

+			function cancelKeyEvent(evt) {

+				evt.returnValue = false;

+				stopPropagation(evt);

+			}

+

+			function evalCommandLine() {

+				var expr = $("command").value;

+				evalCommand(expr);

+				$("command").value = "";

+			}

+

+			function evalLastCommand() {

+				if (lastCommand != null) {

+					evalCommand(lastCommand);

+				}

+			}

+

+			var lastCommand = null;

+			var commandHistory = [];

+			var currentCommandIndex = 0;

+

+			function evalCommand(expr) {

+				if (appender) {

+					appender.evalCommandAndAppend(expr);

+				} else {

+					var prefix = ">>> " + expr + "\r\n";

+					try {

+						log("INFO", prefix + eval(expr));

+					} catch (ex) {

+						log("ERROR", prefix + "Error: " + getErrorMessage(ex));

+					}

+				}

+				// Update command history

+				if (expr != commandHistory[commandHistory.length - 1]) {

+					commandHistory.push(expr);

+					// Update the appender

+					if (appender) {

+						appender.storeCommandHistory(commandHistory);

+					}

+				}

+				currentCommandIndex = (expr == commandHistory[currentCommandIndex]) ? currentCommandIndex + 1 : commandHistory.length;

+				lastCommand = expr;

+			}

+			//]]>

+		</script>

+		<style type="text/css">

+			body {

+				background-color: white;

+				color: black;

+				padding: 0;

+				margin: 0;

+				font-family: tahoma, verdana, arial, helvetica, sans-serif;

+				overflow: hidden;

+			}

+

+			div#switchesContainer input {

+				margin-bottom: 0;

+			}

+

+			div.toolbar {

+				border-top: solid #ffffff 1px;

+				border-bottom: solid #aca899 1px;

+				background-color: #f1efe7;

+				padding: 3px 5px;

+				font-size: 68.75%;

+			}

+

+			div.toolbar, div#search input {

+				font-family: tahoma, verdana, arial, helvetica, sans-serif;

+			}

+

+			div.toolbar input.button {

+				padding: 0 5px;

+				font-size: 100%;

+			}

+

+			div.toolbar input.hidden {

+				display: none;

+			}

+

+			div#switches input#clearButton {

+				margin-left: 20px;

+			}

+

+			div#levels label {

+				font-weight: bold;

+			}

+

+			div#levels label, div#options label {

+				margin-right: 5px;

+			}

+

+			div#levels label#wrapLabel {

+				font-weight: normal;

+			}

+

+			div#search label {

+				margin-right: 10px;

+			}

+

+			div#search label.searchboxlabel {

+				margin-right: 0;

+			}

+

+			div#search input {

+				font-size: 100%;

+			}

+

+			div#search input.validregex {

+				color: green;

+			}

+

+			div#search input.invalidregex {

+				color: red;

+			}

+

+			div#search input.nomatches {

+				color: white;

+				background-color: #ff6666;

+			}

+

+			div#search input.nomatches {

+				color: white;

+				background-color: #ff6666;

+			}

+

+			div#searchNav {

+				display: none;

+			}

+

+			div#commandLine {

+				display: none;

+			}

+

+			div#commandLine input#command {

+				font-size: 100%;

+				font-family: Courier New, Courier;

+			}

+

+			div#commandLine input#evaluateButton {

+			}

+

+			*.greyedout {

+				color: gray !important;

+				border-color: gray !important;

+			}

+

+			*.greyedout *.alwaysenabled { color: black; }

+

+			*.unselectable {

+				-khtml-user-select: none;

+				-moz-user-select: none;

+				user-select: none;

+			}

+

+			div#log {

+				font-family: Courier New, Courier;

+				font-size: 75%;

+				width: 100%;

+				overflow: auto;

+				clear: both;

+				position: relative;

+			}

+

+			div.group {

+				border-color: #cccccc;

+				border-style: solid;

+				border-width: 1px 0 1px 1px;

+				overflow: visible;

+			}

+

+			div.oldIe div.group, div.oldIe div.group *, div.oldIe *.logentry {

+				height: 1%;

+			}

+

+			div.group div.groupheading span.expander {

+				border: solid black 1px;

+				font-family: Courier New, Courier;

+				font-size: 0.833em;

+				background-color: #eeeeee;

+				position: relative;

+				top: -1px;

+				color: black;

+				padding: 0 2px;

+				cursor: pointer;

+				cursor: hand;

+				height: 1%;

+			}

+

+			div.group div.groupcontent {

+				margin-left: 10px;

+				padding-bottom: 2px;

+				overflow: visible;

+			}

+

+			div.group div.expanded {

+				display: block;

+			}

+

+			div.group div.collapsed {

+				display: none;

+			}

+

+			*.logentry {

+				overflow: visible;

+				display: none;

+				white-space: pre;

+			}

+

+			span.pre {

+				white-space: pre;

+			}

+			

+			pre.unwrapped {

+				display: inline !important;

+			}

+

+			pre.unwrapped pre.pre, div.wrapped pre.pre {

+				display: inline;

+			}

+

+			div.wrapped pre.pre {

+				white-space: normal;

+			}

+

+			div.wrapped {

+				display: none;

+			}

+

+			body.searching *.logentry span.currentmatch {

+				color: white !important;

+				background-color: green !important;

+			}

+

+			body.searching div.searchhighlight *.logentry span.searchterm {

+				color: black;

+				background-color: yellow;

+			}

+

+			div.wrap *.logentry {

+				white-space: normal !important;

+				border-width: 0 0 1px 0;

+				border-color: #dddddd;

+				border-style: dotted;

+			}

+

+			div.wrap #log_wrapped, #log_unwrapped {

+				display: block;

+			}

+

+			div.wrap #log_unwrapped, #log_wrapped {

+				display: none;

+			}

+

+			div.wrap *.logentry span.pre {

+				overflow: visible;

+				white-space: normal;

+			}

+

+			div.wrap *.logentry pre.unwrapped {

+				display: none;

+			}

+

+			div.wrap *.logentry span.wrapped {

+				display: inline;

+			}

+

+			div.searchfilter *.searchnonmatch {

+				display: none !important;

+			}

+

+			div#log *.TRACE, label#label_TRACE {

+				color: #666666;

+			}

+

+			div#log *.DEBUG, label#label_DEBUG {

+				color: green;

+			}

+

+			div#log *.INFO, label#label_INFO {

+				color: #000099;

+			}

+

+			div#log *.WARN, label#label_WARN {

+				color: #999900;

+			}

+

+			div#log *.ERROR, label#label_ERROR {

+				color: red;

+			}

+

+			div#log *.FATAL, label#label_FATAL {

+				color: #660066;

+			}

+

+			div.TRACE#log *.TRACE,

+			div.DEBUG#log *.DEBUG,

+			div.INFO#log *.INFO,

+			div.WARN#log *.WARN,

+			div.ERROR#log *.ERROR,

+			div.FATAL#log *.FATAL {

+				display: block;

+			}

+

+			div#log div.separator {

+				background-color: #cccccc;

+				margin: 5px 0;

+				line-height: 1px;

+			}

+		</style>

+	</head>

+

+	<body id="body">

+		<div id="switchesContainer">

+			<div id="switches">

+				<div id="levels" class="toolbar">

+					Filters:

+					<input type="checkbox" id="switch_TRACE" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide trace messages" /><label for="switch_TRACE" id="label_TRACE">trace</label>

+					<input type="checkbox" id="switch_DEBUG" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide debug messages" /><label for="switch_DEBUG" id="label_DEBUG">debug</label>

+					<input type="checkbox" id="switch_INFO" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide info messages" /><label for="switch_INFO" id="label_INFO">info</label>

+					<input type="checkbox" id="switch_WARN" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide warn messages" /><label for="switch_WARN" id="label_WARN">warn</label>

+					<input type="checkbox" id="switch_ERROR" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide error messages" /><label for="switch_ERROR" id="label_ERROR">error</label>

+					<input type="checkbox" id="switch_FATAL" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide fatal messages" /><label for="switch_FATAL" id="label_FATAL">fatal</label>

+					<input type="checkbox" id="switch_ALL" onclick="toggleAllLevels(); applyFilters()" checked="checked" title="Show/hide all messages" /><label for="switch_ALL" id="label_ALL">all</label>

+				</div>

+				<div id="search" class="toolbar">

+					<label for="searchBox" class="searchboxlabel">Search:</label> <input type="text" id="searchBox" onclick="toggleSearchEnabled(true)" onkeyup="scheduleSearch()" size="20" />

+					<input type="button" id="searchReset" disabled="disabled" value="Reset" onclick="clearSearch()" class="button" title="Reset the search" />

+					<input type="checkbox" id="searchRegex" onclick="doSearch()" title="If checked, search is treated as a regular expression" /><label for="searchRegex">Regex</label>

+					<input type="checkbox" id="searchCaseSensitive" onclick="doSearch()" title="If checked, search is case sensitive" /><label for="searchCaseSensitive">Match case</label>

+					<input type="checkbox" id="searchDisable" onclick="toggleSearchEnabled()" title="Enable/disable search" /><label for="searchDisable" class="alwaysenabled">Disable</label>

+					<div id="searchNav">

+						<input type="button" id="searchNext" disabled="disabled" value="Next" onclick="searchNext()" class="button" title="Go to the next matching log entry" />

+						<input type="button" id="searchPrevious" disabled="disabled" value="Previous" onclick="searchPrevious()" class="button" title="Go to the previous matching log entry" />

+						<input type="checkbox" id="searchFilter" onclick="toggleSearchFilter()" title="If checked, non-matching log entries are filtered out" /><label for="searchFilter">Filter</label>

+						<input type="checkbox" id="searchHighlight" onclick="toggleSearchHighlight()" title="Highlight matched search terms" /><label for="searchHighlight" class="alwaysenabled">Highlight all</label>

+					</div>

+				</div>

+				<div id="options" class="toolbar">

+					Options:

+					<input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Log</label>

+					<input type="checkbox" id="wrap" onclick="toggleWrap()" title="Enable / disable word wrap" /><label for="wrap" id="wrapLabel">Wrap</label>

+					<input type="checkbox" id="newestAtTop" onclick="toggleNewestAtTop()" title="If checked, causes newest messages to appear at the top" /><label for="newestAtTop" id="newestAtTopLabel">Newest at the top</label>

+					<input type="checkbox" id="scrollToLatest" onclick="toggleScrollToLatest()" checked="checked" title="If checked, window automatically scrolls to a new message when it is added" /><label for="scrollToLatest" id="scrollToLatestLabel">Scroll to latest</label>

+					<input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="button" title="Clear all log messages"  />

+					<input type="button" id="hideButton" value="Hide" onclick="hide()" class="hidden button" title="Hide the console" />

+					<input type="button" id="closeButton" value="Close" onclick="closeWindow()" class="hidden button" title="Close the window" />

+				</div>

+			</div>

+		</div>

+		<div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>

+		<div id="commandLine" class="toolbar">

+			<div id="commandLineContainer">

+				<input type="text" id="command" title="Enter a JavaScript command here and hit return or press 'Evaluate'" />

+				<input type="button" id="evaluateButton" value="Evaluate" class="button" title="Evaluate the command" onclick="evalCommandLine()" />

+			</div>

+		</div>

+	</body>

+</html>

diff --git a/xos/core/static/log4javascript-1.4.6/demos/basic.html b/xos/core/static/log4javascript-1.4.6/demos/basic.html
new file mode 100644
index 0000000..51d5857
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/demos/basic.html
@@ -0,0 +1,159 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript basic demo</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />

+		<script type="text/javascript" src="../js/log4javascript.js"></script>

+		<script type="text/javascript">

+			// <![CDATA[

+			var log = log4javascript.getLogger("main");

+			var appender = new log4javascript.PopUpAppender();

+			log.addAppender(appender);

+			log.debug("This is debugging message from the log4javascript basic demo page");

+

+			var words = ["Watford", "eased", "their", "relegation", "fears", "with", "a", "win",

+				"against", "a", "Charlton", "side", "who", "slipped", "further", "towards", "the",

+				"drop", "Don", "Cowie", "drilled", "in", "a", "shot", "to", "put", "the", "Hornets",

+				"ahead", "before", "Tresor", "Kandol", "ended", "a", "powerful", "run", "by",

+				"rounding", "keeper", "Scott", "Loach", "and", "slotting", "in", "to", "level"

+			];

+

+			var loaded = false;

+

+			function generateRandom() {

+				var numberOfEntries = parseInt(document.getElementById("numberOfLogEntries").value);

+				for (var i = 0; i < numberOfEntries; i++) {

+					var numberOfWords = 1 + Math.floor(10 * Math.random());

+					var entryWords = [];

+					for (var j = 0; j < numberOfWords; j++) {

+						entryWords.push(words[Math.floor(Math.random() * words.length)]);

+					}

+					var entryMessage = entryWords.join(" ");

+					var levelNum = Math.floor(Math.random() * 6);

+					switch (levelNum) {

+						case 0:

+							log.trace(entryMessage);

+							break;

+						case 1:

+							log.debug(entryMessage);

+							break;

+						case 2:

+							log.info(entryMessage);

+							break;

+						case 3:

+							log.warn(entryMessage);

+							break;

+						case 4:

+							log.error(entryMessage);

+							break;

+						case 5:

+							log.fatal(entryMessage);

+							break;

+					}

+				}

+			}

+

+			function generateObjectExpansion() {

+				var debugObj = {

+					a: {

+						b: "stuff",

+						c: 3,

+						d: {

+							e: ["a", "b", "c"]

+						}

+					},

+					f: "Things",

+					g: 5

+				};

+				log.debug(debugObj);

+			}

+

+			function generateError() {

+				try {

+					throw new Error("Made up error");

+				} catch (ex) {

+					log.error("Logging an error!", ex);

+				}

+			}

+			// ]]>

+		</script>

+	</head>

+	<body onload="loaded = true; document.getElementById('enabled').checked = true;">

+		<div id="container" class="nonav">

+			<div id="header">

+				<h1><a href="/docs/index.html">log4javascript</a></h1>

+			</div>

+			<div id="content">

+				<div id="nav">

+					<a class="navitem" href="../index.html">home</a>

+					| <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>

+					| <a class="navitem" href="../docs/index.html">docs</a>

+					| <a class="navitem" href="../docs/quickstart.html">quick start</a>

+					| <a class="navitem" href="index.html">demos</a>

+					| <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>

+					| <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>

+				</div>

+				<h1>log4javascript basic demo</h1>

+				<p>

+					<em><strong>NB.</strong> Since the demo below uses pop-up windows, you will

+					need to disable any pop-up blockers you may have for it to work.</em>

+				</p>

+				<p>

+					This demo demonstrates the default logger. For more options, please see the

+					<a href="index.html">demos area</a>.

+				</p>

+				<p>

+					Enter a log message below and click on one of the buttons to log

+					your message at your desired level. You can then filter by

+					log level, toggle word-wrapping and perform text and regular

+					expression searches on the log entries.

+				</p>

+				<div class="example">

+					<input type="text" id="logText" value="Put log message here" />

+					<input type="button" value="debug" onclick="log.debug(document.getElementById('logText').value)" />

+					<input type="button" value="info" onclick="log.info(document.getElementById('logText').value)" />

+					<input type="button" value="warn" onclick="log.warn(document.getElementById('logText').value)" />

+					<input type="button" value="error" onclick="log.error(document.getElementById('logText').value)" />

+					<input type="button" value="fatal" onclick="log.fatal(document.getElementById('logText').value)" />

+					<br />

+					<input type="button" value="assert 1 equals 1" onclick="log.assert(1 === 1)" />

+					<input type="button" value="assert 1 equals 2" onclick="log.assert(1 === 2)" />

+					<br />

+					Generate <input type="text" size="5" id="numberOfLogEntries" value="50" /> random log entries

+					<input type="button" value="go" onclick="generateRandom()" />

+					<br />

+					<input type="button" value="Log exception" onclick="generateError()" />

+					<input type="button" value="Log example object" onclick="generateObjectExpansion()" />

+					<br />

+					<input type="checkbox" id="enabled" onclick="log4javascript.setEnabled(this.checked)" checked="checked" /> <label for="enabled">logging enabled</label>

+					<br />

+					<input type="text" id="groupName" value="Group name" />

+					<input type="button" value="group" onclick="log.group(document.getElementById('groupName').value)" />

+					<input type="button" value="end group" onclick="log.groupEnd()" />

+					<br />

+					<input type="text" id="timerName" value="Example timer name" />

+					<input type="button" value="start timer" onclick="log.time(document.getElementById('timerName').value)" />

+					<input type="button" value="end timer" onclick="log.timeEnd(document.getElementById('timerName').value)" />

+				</div>

+			</div>

+			<br class="clear" />

+			<div id="footer">

+				<span class="externallinkinfo">

+					<strong>NB.</strong> All external links open in a new window.

+				</span>

+				Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>

+				<br />

+				log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"

+					title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,

+					Version 2.0</a>

+

+			</div>

+		</div>

+

+	</body>

+</html>

diff --git a/xos/core/static/log4javascript-1.4.6/demos/blank.html b/xos/core/static/log4javascript-1.4.6/demos/blank.html
new file mode 100644
index 0000000..7e8ac56
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/demos/blank.html
@@ -0,0 +1,4 @@
+<html>

+<head><title>Blank page</title></head>

+<body></body>

+</html>
\ No newline at end of file
diff --git a/xos/core/static/log4javascript-1.4.6/demos/index.html b/xos/core/static/log4javascript-1.4.6/demos/index.html
new file mode 100644
index 0000000..00e84ac
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/demos/index.html
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript demos</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />

+	</head>

+	<body>

+		<div id="container" class="nonav">

+			<div id="header">

+				<h1><a href="/docs/index.html">log4javascript</a></h1>

+			</div>

+			<div id="content">

+				<div id="nav">

+					<a class="navitem" href="../index.html">home</a>

+					| <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>

+					| <a class="navitem" href="../docs/index.html">docs</a>

+					| <a class="navitem" href="../docs/quickstart.html">quick start</a>

+					| <span class="navitem">demos</span>

+					| <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>

+					| <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>

+				</div>

+				<h1>log4javascript demos</h1>

+				<ul>

+					<li><a href="basic.html">Basic demo</a></li>

+					<li><a href="inpage.html">In-page console demo</a></li>

+					<li><a href="lite.html">log4javascript Lite demo</a></li>

+				</ul>

+			</div>

+			<br class="clear" />

+			<div id="footer">

+				<span class="externallinkinfo">

+					<strong>NB.</strong> All external links open in a new window.

+				</span>

+				Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>

+				<br />

+				log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"

+					title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,

+					Version 2.0</a>

+

+			</div>

+		</div>

+

+	</body>

+</html>

diff --git a/xos/core/static/log4javascript-1.4.6/demos/inpage.html b/xos/core/static/log4javascript-1.4.6/demos/inpage.html
new file mode 100644
index 0000000..8e47d72
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/demos/inpage.html
@@ -0,0 +1,174 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript in-page console demo</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />

+		<script type="text/javascript" src="../js/log4javascript_uncompressed.js"></script>

+		<script type="text/javascript">

+			// <![CDATA[

+			var log = log4javascript.getLogger("main");

+			var appender = new log4javascript.InPageAppender();

+			log.addAppender(appender);

+			log.debug("This is a debugging message from the log4javascript in-page page");

+

+			var words = ["Watford", "eased", "their", "relegation", "fears", "with", "a", "win",

+				"against", "a", "Charlton", "side", "who", "slipped", "further", "towards", "the",

+				"drop", "Don", "Cowie", "drilled", "in", "a", "shot", "to", "put", "the", "Hornets",

+				"ahead", "before", "Tresor", "Kandol", "ended", "a", "powerful", "run", "by",

+				"rounding", "keeper", "Scott", "Loach", "and", "slotting", "in", "to", "level"

+			];

+

+			var loaded = false;

+

+			function generateRandom() {

+				var numberOfEntries = parseInt(document.getElementById("numberOfLogEntries").value);

+				for (var i = 0; i < numberOfEntries; i++) {

+					var numberOfWords = 1 + Math.floor(10 * Math.random());

+					var entryWords = [];

+					for (var j = 0; j < numberOfWords; j++) {

+						entryWords.push(words[Math.floor(Math.random() * words.length)]);

+					}

+					var entryMessage = entryWords.join(" ");

+					var levelNum = Math.floor(Math.random() * 6);

+					switch (levelNum) {

+						case 0:

+							log.trace(entryMessage);

+							break;

+						case 1:

+							log.debug(entryMessage);

+							break;

+						case 2:

+							log.info(entryMessage);

+							break;

+						case 3:

+							log.warn(entryMessage);

+							break;

+						case 4:

+							log.error(entryMessage);

+							break;

+						case 5:

+							log.fatal(entryMessage);

+							break;

+					}

+				}

+			}

+			

+			var consoleVisible = true;

+			

+			function toggleConsole(button) {

+				if (consoleVisible) {

+					appender.hide();

+					button.value = "Show console";

+					consoleVisible = false;

+				} else {

+					appender.show();

+					button.value = "Hide console";

+					consoleVisible = true;

+				}

+			}

+

+			function generateObjectExpansion() {

+				var debugObj = {

+					a: {

+						b: "stuff",

+						c: 3,

+						d: {

+							e: ["a", "b", "c"]

+						}

+					},

+					f: "Things",

+					g: 5

+				};

+				log.debug(debugObj);

+			}

+

+			function generateError() {

+				try {

+					throw new Error("Made up error");

+				} catch (ex) {

+					log.error("Logging an error!", ex);

+				}

+			}

+			// ]]>

+		</script>

+	</head>

+	<body>

+		<div id="container" class="nonav">

+			<div id="header">

+				<h1><a href="/docs/index.html">log4javascript</a></h1>

+			</div>

+			<div id="content">

+				<div id="nav">

+					<a class="navitem" href="../index.html">home</a>

+					| <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>

+					| <a class="navitem" href="../docs/index.html">docs</a>

+					| <a class="navitem" href="../docs/quickstart.html">quick start</a>

+					| <a class="navitem" href="index.html">demos</a>

+					| <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>

+					| <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>

+				</div>

+				<h1>log4javascript in-page console demo</h1>

+				<p>

+					This demo demonstrates an in-page logger. The example uses the default behaviour, which

+					is to place the log console in a fixed area at the bottom of the page. However, the

+					console may be placed inside any element in the page. To do this, you may specify the ID

+					of the element (even if the page has not yet loaded) or a reference to the element itself.

+				</p>

+				<p>

+					Enter a log message below and click on one of the buttons to log

+					your message at your desired level. You can then filter by

+					log level, toggle word-wrapping and perform text and regular

+					expression searches on the log entries.

+				</p>

+				<div class="example">

+					<input type="button" value="Hide console" onclick="toggleConsole(this)" />

+					<br />

+					<input type="text" id="logText" value="Put log message here" />

+					<input type="button" value="debug" onclick="log.debug(document.getElementById('logText').value)" />

+					<input type="button" value="info" onclick="log.info(document.getElementById('logText').value)" />

+					<input type="button" value="warn" onclick="log.warn(document.getElementById('logText').value)" />

+					<input type="button" value="error" onclick="log.error(document.getElementById('logText').value)" />

+					<input type="button" value="fatal" onclick="log.fatal(document.getElementById('logText').value)" />

+					<br />

+					<input type="button" value="assert 1 equals 1" onclick="log.assert(1 === 1)" />

+					<input type="button" value="assert 1 equals 2" onclick="log.assert(1 === 2)" />

+					<br />

+					Generate <input type="text" size="5" id="numberOfLogEntries" value="50" /> random log entries

+					<input type="button" value="go" onclick="generateRandom()" />

+					<br />

+					<input type="button" value="Log exception" onclick="generateError()" />

+					<input type="button" value="Log example object" onclick="generateObjectExpansion()" />

+					<br />

+					<input type="checkbox" id="enabled" onclick="log4javascript.setEnabled(this.checked)" checked="checked" /> <label for="enabled">logging enabled</label>

+					<br />

+					<input type="text" id="groupName" value="Group name" />

+					<input type="button" value="group" onclick="log.group(document.getElementById('groupName').value)" />

+					<input type="button" value="end group" onclick="log.groupEnd()" />

+					<br />

+					<input type="text" id="timerName" value="Example timer name" />

+					<input type="button" value="start timer" onclick="log.time(document.getElementById('timerName').value)" />

+					<input type="button" value="end timer" onclick="log.timeEnd(document.getElementById('timerName').value)" />

+				</div>

+			</div>

+			<br class="clear" />

+			<div id="log"></div>

+			<div id="footer">

+				<span class="externallinkinfo">

+					<strong>NB.</strong> All external links open in a new window.

+				</span>

+				Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>

+				<br />

+				log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"

+					title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,

+					Version 2.0</a>

+

+			</div>

+		</div>

+

+	</body>

+</html>

diff --git a/xos/core/static/log4javascript-1.4.6/demos/lite.html b/xos/core/static/log4javascript-1.4.6/demos/lite.html
new file mode 100644
index 0000000..a1d2dd3
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/demos/lite.html
@@ -0,0 +1,148 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript lite demo</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />

+		<script type="text/javascript" src="../js/log4javascript_lite.js"></script>

+		<script type="text/javascript">

+			// <![CDATA[

+			var	log = log4javascript.getDefaultLogger();

+			log.debug("This is debugging message from the log4javascript lite demo page");

+

+			var words = ["Boothroyd", "who", "took", "over", "two", "years",

+					"ago", "and", "continues", "to", "maintain", "that", "the",

+					"club", "are", "building", "for", "the", "future", "made",

+					"six", "changes", "and", "gave", "a", "first", "Premiership",

+					"start", "to", "on-loan", "Brazilian", "midfielder",

+					"Douglas", "Rinaldi", "Darius", "Henderson", "and", "Steve",

+					"Kabba", "were", "two", "of", "the", "players", "restored",

+					"to", "the", "home", "side", "and", "were", "responsible",

+					"for", "giving", "Chelsea", "an", "uncomfortable", "start",

+					"which", "set", "the", "pattern", "for", "the", "match"

+					];

+

+			var loaded = false;

+

+			function generateRandom() {

+				var numberOfEntries = parseInt(document.getElementById("numberOfLogEntries").value);

+				for (var i = 0; i < numberOfEntries; i++) {

+					var numberOfWords = 1 + Math.floor(10 * Math.random());

+					var entryWords = [];

+					for (var j = 0; j < numberOfWords; j++) {

+						entryWords.push(words[Math.floor(Math.random() * words.length)]);

+					}

+					var entryMessage = entryWords.join(" ");

+					var levelNum = Math.floor(Math.random() * 6);

+					switch (levelNum) {

+						case 0:

+							log.trace(entryMessage);

+							break;

+						case 1:

+							log.debug(entryMessage);

+							break;

+						case 2:

+							log.info(entryMessage);

+							break;

+						case 3:

+							log.warn(entryMessage);

+							break;

+						case 4:

+							log.error(entryMessage);

+							break;

+						case 5:

+							log.fatal(entryMessage);

+							break;

+					}

+				}

+			}

+

+			function generateObjectExpansion() {

+				var debugObj = {

+					a: {

+						b: "stuff",

+						c: 3,

+						d: {

+							e: ["a", "b", "c"]

+						}

+					},

+					f: "Things",

+					g: 5

+				};

+				log.debug(debugObj);

+			}

+

+			function generateError() {

+				try {

+					throw new Error("Made up error");

+				} catch (ex) {

+					log.error("Logging an error!", ex);

+				}

+			}

+			// ]]>

+		</script>

+	</head>

+	<body onload="loaded = true; document.getElementById('enabled').checked = true;">

+		<div id="container" class="nonav">

+			<div id="header">

+				<h1><a href="/docs/index.html">log4javascript</a></h1>

+			</div>

+			<div id="content">

+				<div id="nav">

+					<a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>

+					| <a class="navitem" href="../docs/index.html">docs</a>

+					| <a class="navitem" href="../docs/quickstart.html">quick start</a>

+					| <a class="navitem" href="../docs/manual.html">manual</a>

+					| <a class="navitem" href="index.html">demos</a>

+					| <a class="navitem" href="http://www.timdown.co.uk/log4javascript" target="_blank">website</a>

+				</div>

+				<h1>log4javascript lite demo</h1>

+				<p>

+					<em><strong>NB.</strong> Since the demo below uses pop-up windows, you will

+					need to disable any pop-up blockers you may have for it to work.</em>

+				</p>

+				<p>

+					This demo demonstrates the lite edition of log4javascript.

+				</p>

+				<p>

+					Enter a log message below and click on one of the buttons to log

+					your message at your desired level.

+				</p>

+				<div class="example">

+					<input type="text" id="logText" value="Put log message here" />

+					<input type="button" value="trace" onclick="log.trace(document.getElementById('logText').value)" />

+					<input type="button" value="debug" onclick="log.debug(document.getElementById('logText').value)" />

+					<input type="button" value="info" onclick="log.info(document.getElementById('logText').value)" />

+					<input type="button" value="warn" onclick="log.warn(document.getElementById('logText').value)" />

+					<input type="button" value="error" onclick="log.error(document.getElementById('logText').value)" />

+					<input type="button" value="fatal" onclick="log.fatal(document.getElementById('logText').value)" />

+					<br />

+					Generate <input type="text" size="5" id="numberOfLogEntries" value="50" /> random log entries

+					<input type="button" value="go" onclick="generateRandom()" />

+					<br />

+					<input type="button" value="Log exception" onclick="generateError()" />

+					<input type="button" value="Log example object" onclick="generateObjectExpansion()" />

+					<br />

+					<input type="checkbox" id="enabled" onclick="log4javascript.setEnabled(this.checked)" checked="checked" /> <label for="enabled">logging enabled</label>

+					<br />

+				</div>

+			</div>

+			<br class="clear" />

+			<div id="footer">

+				<span class="externallinkinfo">

+					<strong>NB.</strong> All external links open in a new window.

+				</span>

+				Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>

+				<br />

+				log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"

+					title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,

+					Version 2.0</a>

+

+			</div>

+		</div>

+	</body>

+</html>

diff --git a/xos/core/static/log4javascript-1.4.6/docs/backwardsincompatibilities.html b/xos/core/static/log4javascript-1.4.6/docs/backwardsincompatibilities.html
new file mode 100644
index 0000000..f212fd4
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/docs/backwardsincompatibilities.html
@@ -0,0 +1,90 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript - backwards incompatibilities in version 1.4</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />

+	</head>

+	<body>

+		<div id="container" class="nonav">

+			<div id="header">

+				<h1><a href="/index.html">log4javascript</a></h1>

+			</div>

+			<div id="content">

+				<div id="nav">

+					<a class="navitem" href="../index.html">home</a>

+					| <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>

+					| <a class="navitem" href="index.html">docs</a>

+					| <a class="navitem" href="quickstart.html">quick start</a>

+					| <a class="navitem" href="../demos/index.html">demos</a>

+					| <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>

+					| <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>

+				</div>

+				<h1>Backwards incompatibilities in log4javascript 1.4</h1>

+				<ul>

+					<li>

+						Loggers are now hierarchical. This means logger names containing full stops have

+						special meaning. For example, from version 1.4 the logger named <code>myapp.ajax</code>

+						by default inherits all the appenders of the logger named <code>myapp</code>, while

+						prior to version 1.4 these loggers would be entirely independent;

+					</li>

+					<li>

+						The signature of the <code>log</code> method of <code>Logger</code> has changed.

+						However, you should not use this method directly; instead, use one of the level-specific

+						wrapper functions (<code>debug</code>, <code>info</code>, <code>error</code> etc.);

+					</li>

+					<li>

+						Appenders can no longer be configured via constructor parameters. Instead you must use

+						setter methods;

+					</li>

+					<li>

+						The format of requests sent via <code><a href="manual.html#ajaxappender">AjaxAppender</a></code>

+						has changed when using <code><a href="manual.html#jsonlayout">JsonLayout</a></code> or

+						<code><a href="manual.html#xmllayout">XmlLayout</a></code>: the formatted log messages are sent

+						as a name-value pair (with default name <code>data</code>) rather than a single unencoded string;

+					</li>

+					<li>

+						All timestamps returned by <code><a href="manual.html#xmllayout">XmlLayout</a></code>,

+						<code><a href="manual.html#jsonlayout">JsonLayout</a></code> and

+						<code><a href="manual.html#httppostdatlayout">HttpPostDataLayout</a></code> are

+						now measured in milliseconds since January 1st 1970 (previously they were returned

+						as seconds since January 1st 1970);

+					</li>

+					<li>

+						The constructors for <a href="manual.html#jsonlayout">JsonLayout</a> and

+						<a href="manual.html#httppostdatlayout">HttpPostDataLayout</a> have changed; the property names

+						used for the properties of the logging event are now set via <code>setKeys</code> rather than

+						in the constructor;

+					</li>

+					<li>

+						<code>setReadable</code> has been removed from <a href="manual.html#jsonlayout">JsonLayout</a>.

+						The <code>readable</code> property should now be set via the constructor;

+					</li>

+					<li>

+						<code>addErrorListener</code> and <code>removeErrorListener</code> removed from

+						the <code>log4javascript</code> object and replaced with the more generic

+						<code><a href="manual.html#log4javascriptaddeventlistener">addEventListener</a></code>

+						and <code>removeEventListener</code> methods. The listener functions are passed

+						different parameters.

+					</li>

+				</ul>

+			</div>

+			<div id="footer">

+				<span class="externallinkinfo">

+					<strong>NB.</strong> All external links open in a new window.

+				</span>

+				Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>

+				<br />

+				log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"

+					title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,

+					Version 2.0</a>

+

+			</div>

+		</div>

+

+	</body>

+</html>

diff --git a/xos/core/static/log4javascript-1.4.6/docs/distribution.html b/xos/core/static/log4javascript-1.4.6/docs/distribution.html
new file mode 100644
index 0000000..8f6cdfd
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/docs/distribution.html
@@ -0,0 +1,87 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en" >

+	<head>

+		<title>log4javascript 1.4 distribution</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />

+	</head>

+	<body>

+		<div id="container" class="nonav">

+			<div id="header">

+				<h1><a href="../index.html">log4javascript</a></h1>

+			</div>

+			<div id="content">

+				<div id="nav">

+					<a class="navitem" href="../index.html">home</a>

+					| <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>

+					| <a class="navitem" href="index.html">docs</a>

+					| <a class="navitem" href="quickstart.html">quick start</a>

+					| <a class="navitem" href="../demos/index.html">demos</a>

+					| <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>

+					| <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>

+				</div>

+				<h1>log4javascript 1.4 distribution</h1>

+				<p>

+					From version 1.4 the distribution includes three different editions of log4javascript:

+				</p>

+				<ul>

+					<li>

+						<div><strong>Standard Edition</strong></div>

+						<p>

+							Equivalent to log4javascript from earlier versions and suitable for general JavaScript

+							debugging and logging (including via Ajax).

+						</p>

+					</li>

+					<li>

+						<div><strong>Production Edition</strong></div>

+						<p>

+							Designed for use in production systems where the focus is solely on logging JavaScript

+							messages back to the server. Consequently this edition omits all appenders except

+							<a href="manual.html#ajaxappender">AjaxAppender</a>, resulting in a drastically reduced

+							file size compared to the standard edition.

+						</p>

+					</li>

+					<li>

+						<div><strong>Lite Edition</strong></div>

+						<p>

+							A lightweight version of log4javascript for quick page debugging. Included is a single logger

+							using a basic pop-up window appender with a fixed layout.

+						</p>

+					</li>

+				</ul>

+				<p>

+					Each edition comes in compressed and uncompressed versions. The compressed version is

+					functionally identical to the uncompressed version but has had whitespace and comments removed

+					and therefore downloads more quickly.

+				</p>

+				<p>

+					Each edition also comes with a stub version. This contains dummy implementations of all

+					log4javacript objects and methods in the public API, making it ideal for production environments

+					where logging is not required. Replacing the main log4javascript script file with this file

+					means that log calls may be left in production code. Compressed and uncompressed versions of

+					each stub are included.

+				</p>

+				<p>

+					Finally, each edition comes with a suite of unit tests, available as HTML pages in the

+					<code>test/</code> directory. Note that these tests crash old versions (pre-3.1) of Safari. Sorry.

+				</p>

+			</div>

+			<div id="footer">

+				<span class="externallinkinfo">

+					<strong>NB.</strong> All external links open in a new window.

+				</span>

+				Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>

+				<br />

+				log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"

+					title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,

+					Version 2.0</a>

+

+			</div>

+		</div>

+

+	</body>

+</html>

diff --git a/xos/core/static/log4javascript-1.4.6/docs/index.html b/xos/core/static/log4javascript-1.4.6/docs/index.html
new file mode 100644
index 0000000..d3b3ac2
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/docs/index.html
@@ -0,0 +1,190 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript documentation</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />

+	</head>

+	<body>

+		<div id="container" class="nonav">

+			<div id="header">

+				<h1><a href="../index.html">log4javascript</a></h1>

+				<div id="nav">

+					<a class="navitem" href="../index.html">home</a>

+					| <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>

+					| <span class="navitem">docs</span>

+					| <a class="navitem" href="quickstart.html">quick start</a>

+					| <a class="navitem" href="../demos/index.html">demos</a>

+					| <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>

+					| <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>

+				</div>

+			</div>

+			<div id="content">

+				<h1>log4javascript 1.4 documentation</h1>

+				<div id="links">

+					<h2>Links</h2>

+					<ul>

+						<li><a href="quickstart.html">Quick start</a></li>

+						<li><a href="distribution.html">Details of the log4javascript distribution</a></li>

+						<li><a href="backwardsincompatibilities.html">Backwards incompatibilities</a></li>

+						<li><a href="whatsnew.html">What's new in this release</a></li>

+						<li><a href="../changelog.txt">Change log</a></li>

+						<li><a href="manual.html">log4javascript manual</a></li>

+						<li><a href="lite.html">log4javascript Lite</a></li>

+						<li><a href="manual_lite.html">log4javascript Lite manual</a></li>

+						<li><a href="../demos/basic.html">Basic demo</a></li>

+						<li><a href="../demos/ajax.html">Ajax demo</a></li>

+					</ul>

+				</div>

+				<div id="contents">

+					<h2>Contents</h2>

+					<ul>

+						<li><a href="#whatitis">What it is</a></li>

+						<li><a href="#whofor">Who it's for</a></li>

+						<li><a href="#previousversions">Note on previous versions</a></li>

+						<li><a href="#features">Features</a></li>

+						<li><a href="#browsers">Browser support</a></li>

+						<li><a href="#licence">Licence</a></li>

+						<li><a href="#furtherreading">Further reading</a></li>

+					</ul>

+				</div>

+				<div id="whatitis">

+					<h2>What it is</h2>

+					<p>

+						log4javascript is a JavaScript logging framework based on the Java

+						logging framework <a href="http://logging.apache.org/log4j/docs/index.html"

+						title="log4j home page (opens in new window)" target="_blank">log4j</a>.

+					</p>

+					<p>

+						log4javascript implements a subset of log4j (primarily loggers, appenders

+						and layouts) and has a few convenience methods of its own for

+						quick JavaScript development. It can be used to debug JavaScript

+						applications of all sizes, including Ajax applications.

+					</p>

+					<p>

+						If you just want to start using it, try the <a href="quickstart.html">quickstart

+						tutorial</a>.

+					</p>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="whofor">

+					<h2>Who it's for</h2>

+					<p>

+						log4javascript is aimed at JavaScript developers.

+					</p>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="previousversions">

+					<h2>Note on previous versions</h2>

+					<p>

+						Documentation for previous versions of log4javascript are not available here.

+						However, documentation is bundled with every previous version, all of which

+						are <a href="http://sourceforge.net/projects/log4javascript"

+							target="_blank" title="Download (opens in new window)">available to download</a>.

+					</p>

+				</div>

+				<div id="features">

+					<h2>Features</h2>

+					<ul>

+						<li>can be initialized with one JavaScript include and one line of code;</li>

+						<li>

+							by default logs to a pop-up console window with powerful search (including

+							regular expression) and filtering features. This console window can also

+							be used inline as an iframe in the main page;

+						</li>

+						<li>

+							can send log messages to the server via HTTP (Ajax, if you like);

+						</li>

+						<li>

+							highly configurable using familiar methods from log4j, including the

+							powerful <code><a href="manual.html#patternlayout">PatternLayout</a></code>

+							which gives the developer complete control over the format of the log messages.

+						</li>

+					</ul>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="browsers">

+					<h2>Browser support</h2>

+					<h3>Fully supported browsers:</h3>

+					<ul>

+						<li>All versions Firefox back to 0.6</li>

+						<li>Other Mozilla-based browsers, as far back as Netscape 7</li>

+						<li>Internet Explorer 5 and higher for Windows</li>

+						<li>Safari 1.3 and higher (untested on earlier versions)</li>

+						<li>Opera 8.01 and higher (pre- version 9 browsers have a rendering

+							bug related to scrolling that affects searching in PopUpAppender and InPageAppender)</li>

+						<li>Konqueror 3.4.3 and higher (untested on earlier versions)</li>

+						<li>Google Chrome</li>

+					</ul>

+					<h3>Partially supported browsers:</h3>

+					<ul>

+						<li>Older Mozilla-based browsers, e.g. Netscape 6.2 (generally OK except for

+							display problems searching and filtering PopUpAppender and InPageAppender)</li>

+						<li>Opera 7.0 - 8.0 (InPageAppender not supported until version 7.5, plus some display

+							problems searching PopUpAppender and InPageAppender. AjaxAppender not supported at all)</li>

+					</ul>

+					<h3>Unsupported browsers:</h3>

+					<ul>

+						<li>

+							Internet Explorer for Mac. There are no plans to make log4javascript work

+							in this browser.

+						</li>

+					</ul>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="licence">

+					<h2>Licence</h2>

+					<p>

+						log4javascript is licenced under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"

+							title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,

+						Version 2.0</a>. The Apache website has <a href="http://www.apache.org/foundation/licence-FAQ.html#WhatDoesItMEAN"

+							title="View licence (opens in new window)" target="_blank">more details</a>.

+					</p>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="furtherreading">

+					<h2>Further reading</h2>

+					<p>

+						In order to gain an understanding of the ideas behind log4j and therefore log4javascript,

+						I highly recommend reading the <a href="http://logging.apache.org/log4j/docs/manual.html">short

+						introduction to log4j</a> from the log4j website. log4javascript borrows heavily from

+						log4j but does not carry over all its concepts - for example, Filters and Renderers are not

+						implemented.

+					</p>

+					<p>

+						<a href="manual.html">The full log4javascript manual</a>

+					</p>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+			</div>

+			<div id="footer">

+				<span class="externallinkinfo">

+					<strong>NB.</strong> All external links open in a new window.

+				</span>

+				Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>

+				<br />

+				log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"

+					title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,

+					Version 2.0</a>

+

+			</div>

+		</div>

+

+	</body>

+</html>
\ No newline at end of file
diff --git a/xos/core/static/log4javascript-1.4.6/docs/lite.html b/xos/core/static/log4javascript-1.4.6/docs/lite.html
new file mode 100644
index 0000000..11b4684
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/docs/lite.html
@@ -0,0 +1,182 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en" >

+	<head>

+		<title>log4javascript 1.4 Lite</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />

+		<style type="text/css">

+			.visibleifabletocopy {

+				display: none;

+			}

+			

+			body.abletocopy .visibleifabletocopy {

+				display: block;

+			}

+		</style>

+		<script type="text/javascript">

+			function copyCode() {

+				if (window.clipboardData && clipboardData.setData) {

+					clipboardData.setData("Text", code);

+					alert("Code copied to clipboard.")

+				}

+			}

+			

+			var code;

+			

+			window.onload = function() {

+				var textArea = document.getElementById("codetextarea");

+				code = textArea.value;

+				textArea.select(); 

+				if (window.clipboardData && clipboardData.setData) {

+					document.body.className = "abletocopy";

+				}

+			};

+		</script>

+		<link rel="stylesheet" type="text/css" media="screen,print" href="lite.css" title="Default" />

+	</head>

+	<body>

+		<div id="container" class="nonav">

+			<div id="header">

+				<h1><a href="../index.html">log4javascript</a></h1>

+			</div>

+			<div id="content">

+				<div id="nav">

+					<a class="navitem" href="../index.html">home</a>

+					| <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>

+					| <a class="navitem" href="index.html">docs</a>

+					| <a class="navitem" href="quickstart.html">quick start</a>

+					| <a class="navitem" href="../demos/index.html">demos</a>

+					| <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>

+					| <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>

+				</div>

+				<h1>log4javascript 1.4 Lite</h1>

+				<h2>Contents</h2>

+				<ul>

+					<li><a href="#intro">Introduction</a></li>

+					<li><a href="#code">Code</a></li>

+					<li><a href="#api">API</a></li>

+				</ul>

+				<div id="intro">

+					<h2>Introduction</h2>

+					<p>

+						log4javascript Lite is designed to be a basic, lightweight, cross-browser logging tool. It

+						provides functions to log messages of different severity to a pop-up window using the exactly

+						the same syntax as log4javascript.

+					</p>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="code">

+					<h2>Code</h2>

+					<p>

+						You can copy the code for log4javascript Lite below:

+					</p>

+					<textarea id="codetextarea" cols="80" rows="10">

+if(!Array.prototype.shift){Array.prototype.shift=function(){if(this.length>0){var firstItem=this[0];for(var i=0,len=this.length-1;i<len;i++){this[i]=this[i+1];}

+this.length--;return firstItem;}};}

+var log4javascript;(function(){var newLine="\r\n";function Log4JavaScript(){}

+log4javascript=new Log4JavaScript();log4javascript.version="1.4.6";log4javascript.edition="log4javascript_lite";function getExceptionMessage(ex){if(ex.message){return ex.message;}else if(ex.description){return ex.description;}else{return String(ex);}}

+function getUrlFileName(url){var lastSlashIndex=Math.max(url.lastIndexOf("/"),url.lastIndexOf("\\"));return url.substr(lastSlashIndex+1);}

+function getExceptionStringRep(ex){if(ex){var exStr="Exception: "+getExceptionMessage(ex);try{if(ex.lineNumber){exStr+=" on line number "+ex.lineNumber;}

+if(ex.fileName){exStr+=" in file "+getUrlFileName(ex.fileName);}}catch(localEx){}

+if(showStackTraces&&ex.stack){exStr+=newLine+"Stack trace:"+newLine+ex.stack;}

+return exStr;}

+return null;}

+function isError(err){return(err instanceof Error);}

+function bool(obj){return Boolean(obj);}

+var enabled=(typeof log4javascript_disabled!="undefined")&&log4javascript_disabled?false:true;log4javascript.setEnabled=function(enable){enabled=bool(enable);};log4javascript.isEnabled=function(){return enabled;};var showStackTraces=false;log4javascript.setShowStackTraces=function(show){showStackTraces=bool(show);};var Level=function(level,name){this.level=level;this.name=name;};Level.prototype={toString:function(){return this.name;},equals:function(level){return this.level==level.level;},isGreaterOrEqual:function(level){return this.level>=level.level;}};Level.ALL=new Level(Number.MIN_VALUE,"ALL");Level.TRACE=new Level(10000,"TRACE");Level.DEBUG=new Level(20000,"DEBUG");Level.INFO=new Level(30000,"INFO");Level.WARN=new Level(40000,"WARN");Level.ERROR=new Level(50000,"ERROR");Level.FATAL=new Level(60000,"FATAL");Level.OFF=new Level(Number.MAX_VALUE,"OFF");log4javascript.Level=Level;function Appender(){var getConsoleHtmlLines=function(){return['<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">','<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">','<head>','<title>log4javascript</title>','<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />','<!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->','<meta http-equiv="X-UA-Compatible" content="IE=7" />','<script type="text/javascript">','//<![CDATA[','var loggingEnabled=true;var messagesBeforeDocLoaded=[];function toggleLoggingEnabled(){setLoggingEnabled($("enableLogging").checked);}','function setLoggingEnabled(enable){loggingEnabled=enable;}','function scrollToLatestEntry(){var l=getLogContainer();if(typeof l.scrollTop!="undefined"){var latestLogEntry=l.lastChild;if(latestLogEntry){l.scrollTop=l.scrollHeight;}}}','function log(logLevel,formattedMessage){if(loggingEnabled){if(loaded){doLog(logLevel,formattedMessage);}else{messagesBeforeDocLoaded.push([logLevel,formattedMessage]);}}}','function doLog(logLevel,formattedMessage){var logEntry=document.createElement("div");logEntry.appendChild(document.createTextNode(formattedMessage));logEntry.className="logentry "+logLevel.name;getLogContainer().appendChild(logEntry);scrollToLatestEntry();}','function mainPageReloaded(){var separator=document.createElement("div");separator.className="separator";separator.innerHTML="&nbsp;";getLogContainer().appendChild(separator);}','var loaded=false;var logLevels=["DEBUG","INFO","WARN","ERROR","FATAL"];window.onload=function(){setLogContainerHeight();toggleLoggingEnabled();for(var i=0;i<messagesBeforeDocLoaded.length;i++){doLog(messagesBeforeDocLoaded[i][0],messagesBeforeDocLoaded[i][1]);}','messagesBeforeDocLoaded=[];loaded=true;setTimeout(setLogContainerHeight,20);};function getLogContainer(){return $("log");}','function clearLog(){getLogContainer().innerHTML="";}','function $(id){return document.getElementById(id);}','function getWindowHeight(){if(window.innerHeight){return window.innerHeight;}else if(document.documentElement&&document.documentElement.clientHeight){return document.documentElement.clientHeight;}else if(document.body){return document.body.clientHeight;}','return 0;}','function getChromeHeight(){return $("toolbar").offsetHeight;}','function setLogContainerHeight(){var windowHeight=getWindowHeight();$("body").style.height=getWindowHeight()+"px";getLogContainer().style.height=""+','Math.max(0,windowHeight-getChromeHeight())+"px";}','window.onresize=function(){setLogContainerHeight();};','//]]>','</scr' + 'ipt>','<style type="text/css">','body{background-color:white;color:black;padding:0;margin:0;font-family:tahoma,verdana,arial,helvetica,sans-serif;overflow:hidden}div#toolbar{border-top:solid #ffffff 1px;border-bottom:solid #aca899 1px;background-color:#f1efe7;padding:3px 5px;font-size:68.75%}div#toolbar input.button{padding:0 5px;font-size:100%}div#log{font-family:Courier New,Courier;font-size:75%;width:100%;overflow:auto;clear:both}*.logentry{overflow:visible;white-space:pre}*.TRACE{color:#666666}*.DEBUG{color:green}*.INFO{color:#000099}*.WARN{color:#999900}*.ERROR{color:red}*.FATAL{color:#660066}div#log div.separator{background-color:#cccccc;margin:5px 0;line-height:1px}','</style>','</head>','<body id="body">','<div id="toolbar">','Options:','<input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" class="stateful" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Enable logging</label>','<input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="stateful button" title="Clear all log messages"  />','<input type="button" id="closeButton" value="Close" onclick="window.close()" class="stateful button" title="Close the window" />','</div>','<div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>','</body>','</html>'];};var popUp=null;var popUpsBlocked=false;var popUpClosed=false;var popUpLoaded=false;var complainAboutPopUpBlocking=true;var initialized=false;var isSupported=true;var width=600;var height=400;var focusPopUp=false;var queuedLoggingEvents=new Array();function isLoaded(win){try{return bool(win.loaded);}catch(ex){return false;}}

+function finalInit(){popUpLoaded=true;appendQueuedLoggingEvents();}

+function writeHtml(doc){var lines=getConsoleHtmlLines();doc.open();for(var i=0,len=lines.length;i<len;i++){doc.writeln(lines[i]);}

+doc.close();}

+function pollConsoleWindow(){function pollConsoleWindowLoaded(){if(popUpLoaded){clearInterval(poll);}else if(bool(popUp)&&isLoaded(popUp)){clearInterval(poll);finalInit();}}

+var poll=setInterval(pollConsoleWindowLoaded,100);}

+function init(){var windowProperties="width="+width+",height="+height+",status,resizable";var windowName="log4javascriptLitePopUp"+location.host.replace(/[^a-z0-9]/gi,"_");popUp=window.open("",windowName,windowProperties);popUpClosed=false;if(popUp){if(isLoaded(popUp)){popUp.mainPageReloaded();finalInit();}else{writeHtml(popUp.document);if(isLoaded(popUp)){finalInit();}else{pollConsoleWindow();}}}else{isSupported=false;if(complainAboutPopUpBlocking){alert("log4javascript: pop-up windows appear to be blocked. Please unblock them to use pop-up logging.");}}

+initialized=true;}

+function safeToAppend(){if(!popUpsBlocked&&!popUpClosed){if(popUp.closed){popUpClosed=true;return false;}

+if(!popUpLoaded&&popUp.loaded){popUpLoaded=true;}}

+return!popUpsBlocked&&popUpLoaded&&!popUpClosed;}

+function padWithZeroes(num,len){var str=""+num;while(str.length<len){str="0"+str;}

+return str;}

+function padWithSpaces(str,len){while(str.length<len){str+=" ";}

+return str;}

+this.append=function(loggingEvent){if(!initialized){init();}

+queuedLoggingEvents.push(loggingEvent);if(safeToAppend()){appendQueuedLoggingEvents();}};function appendQueuedLoggingEvents(){if(safeToAppend()){while(queuedLoggingEvents.length>0){var currentLoggingEvent=queuedLoggingEvents.shift();var date=currentLoggingEvent.timeStamp;var formattedDate=padWithZeroes(date.getHours(),2)+":"+

+padWithZeroes(date.getMinutes(),2)+":"+padWithZeroes(date.getSeconds(),2);var formattedMessage=formattedDate+" "+padWithSpaces(currentLoggingEvent.level.name,5)+" - "+currentLoggingEvent.getCombinedMessages();var throwableStringRep=currentLoggingEvent.getThrowableStrRep();if(throwableStringRep){formattedMessage+=newLine+throwableStringRep;}

+popUp.log(currentLoggingEvent.level,formattedMessage);}

+if(focusPopUp){popUp.focus();}}}}

+log4javascript.Appender=Appender;function Logger(){var appender=new Appender();var loggerLevel=Level.ALL;this.log=function(level,params){if(enabled&&level.isGreaterOrEqual(this.getLevel())){var exception;var finalParamIndex=params.length-1;var lastParam=params[params.length-1];if(params.length>1&&isError(lastParam)){exception=lastParam;finalParamIndex--;}

+var messages=[];for(var i=0;i<=finalParamIndex;i++){messages[i]=params[i];}

+var loggingEvent=new LoggingEvent(this,new Date(),level,messages,exception);appender.append(loggingEvent);}};this.setLevel=function(level){loggerLevel=level;};this.getLevel=function(){return loggerLevel;};}

+Logger.prototype={trace:function(){this.log(Level.TRACE,arguments);},debug:function(){this.log(Level.DEBUG,arguments);},info:function(){this.log(Level.INFO,arguments);},warn:function(){this.log(Level.WARN,arguments);},error:function(){this.log(Level.ERROR,arguments);},fatal:function(){this.log(Level.FATAL,arguments);},isEnabledFor:function(level){return level.isGreaterOrEqual(this.getLevel());},isTraceEnabled:function(){return this.isEnabledFor(Level.TRACE);},isDebugEnabled:function(){return this.isEnabledFor(Level.DEBUG);},isInfoEnabled:function(){return this.isEnabledFor(Level.INFO);},isWarnEnabled:function(){return this.isEnabledFor(Level.WARN);},isErrorEnabled:function(){return this.isEnabledFor(Level.ERROR);},isFatalEnabled:function(){return this.isEnabledFor(Level.FATAL);}};var defaultLogger=null;log4javascript.getDefaultLogger=function(){if(!defaultLogger){defaultLogger=new Logger();}

+return defaultLogger;};log4javascript.getLogger=log4javascript.getDefaultLogger;var nullLogger=null;log4javascript.getNullLogger=function(){if(!nullLogger){nullLogger=new Logger();nullLogger.setLevel(Level.OFF);}

+return nullLogger;};var LoggingEvent=function(logger,timeStamp,level,messages,exception){this.logger=logger;this.timeStamp=timeStamp;this.level=level;this.messages=messages;this.exception=exception;};LoggingEvent.prototype={getThrowableStrRep:function(){return this.exception?getExceptionStringRep(this.exception):"";},getCombinedMessages:function(){return(this.messages.length===1)?this.messages[0]:this.messages.join(newLine);}};log4javascript.LoggingEvent=LoggingEvent;window.log4javascript=log4javascript;})();

+</textarea>

+					<p class="visibleifabletocopy">

+						Press this button to copy the code to the clipboard:

+						<input type="button" value="Copy" onclick="copyCode()" />

+					</p>

+					<p>

+						You can either paste the above code inside a script tag:

+					</p>

+					<pre class="code">

+&lt;script type="text/javascript"&gt;

+	... [Code here]...

+&lt;/script&gt;

+</pre>

+					<p>

+						 ... or include the <code>log4javascript_lite.js</code> included in the distribution:

+					</p>

+					<pre class="code">

+&lt;script type="text/javascript" src="log4javascript_lite.js"&gt;&lt;/script&gt;

+</pre>

+					<pre class="code">

+&lt;script type="text/javascript"&gt;

+	var log = log4javascript.getDefaultLogger();

+&lt;/script&gt;

+</pre>

+					<p>

+						Using log4javascript Lite is identical to using log4javascript with its default logger:

+					</p>

+					<pre class="code">

+&lt;script type="text/javascript"&gt;

+	var log = log4javascript.getDefaultLogger();

+	log.debug("What's going on here then?");

+&lt;/script&gt;

+</pre>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="api">

+					<h2>API</h2>

+					<p>

+						The functions available in log4javascript Lite make up a small subset of those provided

+						by log4javascript proper. Each function is <strong>named and called identically to the equivalent

+						function in log4javascript</strong>. Full details can be found in the

+						<a href="manual_lite.html">log4javascript Lite manual</a>.

+					</p>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+			</div>

+			<div id="footer">

+				<span class="externallinkinfo">

+					<strong>NB.</strong> All external links open in a new window.

+				</span>

+				Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>

+				<br />

+				log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"

+					title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,

+					Version 2.0</a>

+

+			</div>

+		</div>

+

+	</body>

+</html>

diff --git a/xos/core/static/log4javascript-1.4.6/docs/manual.html b/xos/core/static/log4javascript-1.4.6/docs/manual.html
new file mode 100644
index 0000000..defac9c
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/docs/manual.html
@@ -0,0 +1,3198 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript 1.4 manual</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />

+	</head>

+	<body>

+		<div id="container" class="nonav">

+			<div id="header">

+				<h1><a href="index.html">log4javascript</a></h1>

+			</div>

+			<div id="content">

+				<div id="nav">

+					<a class="navitem" href="../index.html">home</a>

+					| <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>

+					| <a class="navitem" href="index.html">docs</a>

+					| <a class="navitem" href="quickstart.html">quick start</a>

+					| <a class="navitem" href="../demos/index.html">demos</a>

+					| <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>

+					| <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>

+				</div>

+				<h1>log4javascript 1.4 manual</h1>

+				<h2>Contents</h2>

+				<ul>

+					<li><a href="#intro">Introduction</a></li>

+					<li><a href="#noteaboutlog4javascript">Note about the log4javascript object</a></li>

+					<li>

+						<a href="#loggersappenderslayoutslevels">Loggers, appenders, layouts and levels</a>

+						<ul>

+							<li><a href="#configuration">Configuring appenders</a></li>

+							<li><a href="#loggersappenderslayoutslevelsexample">Example</a></li>

+						</ul>

+					</li>

+					<li><a href="#log4javascript">log4javascript static properties/methods</a></li>

+					<li><a href="#levels">Levels</a></li>

+					<li><a href="#loggers">Loggers</a></li>

+					<li>

+						<a href="#appenders">Appenders</a>

+						<ul>

+							<li><a href="#appender">Appender</a></li>

+							<li><a href="#alertappender">AlertAppender</a></li>

+							<li><a href="#ajaxappender">AjaxAppender</a></li>

+							<li><a href="#popupappender">PopUpAppender</a></li>

+							<li><a href="#inpageappender">InPageAppender</a></li>

+							<li><a href="#browserconsoleappender">BrowserConsoleAppender</a></li>

+						</ul>

+					</li>

+					<li>

+						<a href="#layouts">Layouts</a>

+						<ul>

+							<li><a href="#layout">Layout</a></li>

+							<li><a href="#nulllayout">NullLayout</a></li>

+							<li><a href="#simplelayout">SimpleLayout</a></li>

+							<li><a href="#patternlayout">PatternLayout</a></li>

+							<li><a href="#xmllayout">XmlLayout</a></li>

+							<li><a href="#jsonlayout">JsonLayout</a></li>

+							<li><a href="#httppostdatalayout">HttpPostDataLayout</a></li>

+						</ul>

+					</li>

+					<li><a href="#enabling">Enabling / disabling log4javascript</a></li>

+					<li>

+						<a href="#errorhandling">log4javascript error handling</a>

+						<ul>

+							<li><a href="#loglog">LogLog</a></li>

+						</ul>

+					</li>

+					<li><a href="#differences">Differences between log4javascript and log4j</a></li>

+				</ul>

+				<div id="intro">

+					<h2>Introduction</h2>

+					<p>

+						Anyone who has done a reasonable amount of JavaScript development will be

+						familiar with <code>alert</code> as a means of debugging. For

+						a small script, it works fine. But for anything of greater complexity than,

+						say, a rollover script its shortcomings become apparent. The most obvious problem

+						is the endless clicking of 'OK'. Another problem is that for a page

+						heavily reliant on events generated from user actions, alerts

+						can actually alter the way the page behaves. One final problem is infinite loops:

+						without alerts, the browser will notice that the script has messed

+						up and will offer the user the chance to stop the script running. With an

+						alert inside an infinite loop, you're forced to kill the browser.

+					</p>

+					<p>

+						At the other end of the scale there is

+						<a href="http://www.mozilla.org/projects/venkman/" target="_blank">Venkman</a>,

+						a full-on JavaScript debugger for Mozilla-based browsers such as Firefox. Here

+						I have to confess that I simply have not put in the time to learn how to make

+						it work well for me and I suspect I am not alone.

+					</p>

+					<p>

+						Nowadays, easily the best option for day-to-day JavaScript development is the brilliant

+						<a href="http://www.getfirebug.com" title="Firebug home page (opens in new window)"

+						   target="_blank">Firebug</a>, a Firefox plugin with built-in debugger, console, logging,

+						and profiler. It's a seriously impressive tool but by its very nature as a Firefox

+						plugin can only be used in one of the typical target browsers for mainstream web

+						development.

+					</p>

+					<p>

+						log4javascript was originally written as a cross-browser tool to ease the pain of JavaScript

+						debugging without the time investment required to use a debugger effectively. It requires

+						only a JavaScript include and one line of code to initialize with default settings.

+						Having for several years used log4j and its .NET port log4net, it was natural for me to

+						base it on log4j.

+					</p>

+					<p>

+						log4javascript is by no means the only JavaScript logging framework out there.

+						It is not even the only JavaScript implementation of log4j. It turns out the name

+						log4javascript is used by another JavaScript logging framework, and that the name log4js is

+						used by at least two other pieces of software; this version of log4javascript is unrelated

+						to any of those.

+					</p>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="noteaboutlog4javascript">

+					<h2>Note about the log4javascript object</h2>

+					<p>

+						All of log4javascript's instantiable classes are accessible via the log4javascript object, which

+						acts as a namespace. Therefore references to all class names must be preceded with "log4javascript.".

+						For example:

+					</p>

+					<p>

+						<code>var popUpAppender = new log4javascript.PopUpAppender();</code>

+					</p>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="loggersappenderslayoutslevels">

+					<h2>Loggers, Appenders, Layouts and Levels</h2>

+					<p>

+						A <em>logger</em> in log4javascript is the object on which log calls are

+						made. A logger may be assigned zero or more <em>appenders</em>.

+						An appender is an object that actually does the logging: for example,

+						a <code><a href="#popupappender">PopUpAppender</a></code> logs messages to

+						a pop-up console window while an <code><a href="#ajaxappender">AjaxAppender</a></code>

+						uses HTTP to send log messages back to the server. Each appender is assigned

+						a <em>layout</em>, which is responsible for formatting log messages that

+						are passed to an appender.

+					</p>

+					<p>

+						Every log message has a <em>level</em>. This is the severity of the message.

+						Available levels are <code>TRACE</code>, <code>DEBUG</code>, <code>INFO</code>,

+						<code>WARN</code>, <code>ERROR</code> and <code>FATAL</code> - these correspond to

+						the logging methods <code>trace</code>, <code>debug</code>, <code>info</code>,

+						<code>warn</code>, <code>error</code> and <code>fatal</code> of <code>Logger</code>.

+						Levels are ordered as follows: <code>TRACE</code> &lt; <code>DEBUG</code> &lt;

+						<code>INFO</code> &lt; <code>WARN</code> &lt; <code>ERROR</code> &lt;

+						<code>FATAL</code>. This means the <code>FATAL</code> is the most severe and

+						<code>TRACE</code> the least. Also included are levels called <code>ALL</code>

+						and <code>OFF</code> intended to enable or disable all logging respectively.

+					</p>

+					<p>

+						Both loggers and appenders also have threshold levels (by default, <code>DEBUG</code>

+						for loggers and <code>ALL</code> for appenders).

+						Setting a level to either a logger or an appender disables log messages of severity

+						lower than that level. For instance, if a level of <code>INFO</code> is set on a

+						logger then only log messages of severity <code>INFO</code> or greater will be logged,

+						meaning <code>DEBUG</code> and <code>TRACE</code> messages will not be logged. If the

+						same logger had two appenders, one of level <code>DEBUG</code> and one of level

+						<code>WARN</code> then the first appender will still only log messages of

+						<code>INFO</code> or greater while the second appender will only log messages of level

+						<code>WARN</code> or greater.

+					</p>

+					<p>

+						This allows the developer fine control over which messages get logged where.

+					</p>

+					<div id="configuration">

+						<h3>Configuring appenders</h3>

+						<p>

+							From version 1.4, <strong>configuring appenders is only possible via configuration

+							methods</strong>. As the number of configuration options increases it becomes increasingly

+							undesirable to use constructor parameters, so support for it has been dropped.

+						</p>

+					</div>

+					<div id="loggersappenderslayoutslevelsexample">

+						<h3>Example</h3>

+						<p>

+							<strong>NB.</strong> The Ajax side of this example relies on having

+							server-side processing in place.

+						</p>

+						<p>

+							First, log4javascript is initialized, and a logger (actually the

+							anonymous logger) is assigned to a variable called <code>log</code>:

+						</p>

+						<pre class="code">

+&lt;script type="text/javascript" src="log4javascript.js"&gt;&lt;/script&gt;

+&lt;script type="text/javascript"&gt;

+	//&lt;![CDATA[

+	var log = log4javascript.getLogger();

+</pre>

+						<p>

+							<code>log</code> does not yet have any appenders, so a call to <code>log.debug()</code>

+							will do nothing as yet. For this example we will use a

+							<code><a href="#popupappender">PopUpAppender</a></code> for debugging purposes.

+							Since the lifespan of the messages displayed in the pop-up is only going to be the

+							same as that of the window, a <code><a href="#patternlayout">PatternLayout</a></code>

+							is used that displays the time of the message and not the date (note that this is

+							also true of PopUpAppender's default layout). The format of the string passed into

+							PatternLayout is explained <a href="#patternlayout">below</a>.

+						</p>

+						<pre class="code">

+	var popUpAppender = new log4javascript.PopUpAppender();

+	var popUpLayout = new log4javascript.PatternLayout("%d{HH:mm:ss} %-5p - %m%n");

+	popUpAppender.setLayout(popUpLayout);

+	log.addAppender(popUpAppender);

+</pre>

+						<p>

+							Suppose that we also want to send log messages to the server, but limited to

+							error messages only. To achieve this we use an

+							<code><a href="#ajaxappender">AjaxAppender</a></code>. Note that if no layout is

+							specified then for convenience a default layout is used; in the case of

+							AjaxAppender, that is <code><a href="#httppostdatalayout">HttpPostDataLayout</a></code>,

+							which formats log messages as a standard HTTP POST string from which a simple

+							server-side script (not provided with log4javascript) will be able to extract

+							posted parameters. This is fine for our purposes:

+						</p>

+						<pre class="code">

+	var ajaxAppender = new log4javascript.AjaxAppender("myloggingservlet.do");

+	ajaxAppender.setThreshold(log4javascript.Level.<code>ERROR</code>);

+	log.addAppender(ajaxAppender);

+</pre>

+						<p>

+							Finally, some test log messages and the closing script tag:

+						</p>

+						<pre class="code">

+	log.debug("Debugging message (appears in pop-up)");

+	log.error("Error message (appears in pop-up and in server log)");

+	//]]&gt;

+&lt;/script&gt;

+</pre>

+						<p>

+							The full script:

+						</p>

+						<pre class="code">

+&lt;script type="text/javascript" src="log4javascript.js"&gt;&lt;/script&gt;

+&lt;script type="text/javascript"&gt;

+	//&lt;![CDATA[

+	var log = log4javascript.getLogger();

+	var popUpAppender = new log4javascript.PopUpAppender();

+	var popUpLayout = new log4javascript.PatternLayout("%d{HH:mm:ss} %-5p - %m%n");

+	popUpAppender.setLayout(popUpLayout);

+	log.addAppender(popUpAppender);

+	var ajaxAppender = new log4javascript.AjaxAppender("myloggingservlet.do");

+	ajaxAppender.setThreshold(log4javascript.Level.ERROR);

+	log.addAppender(ajaxAppender);

+	log.debug("Debugging message (appears in pop-up)");

+	log.error("Error message (appears in pop-up and in server log)");

+	//]]&gt;

+&lt;/script&gt;

+</pre>

+						<p>

+							<a href="../examples/example_manual.html" title="View example (opens in new window)"

+								target="_blank">See this example in action</a> (opens in new window)

+						</p>

+					</div>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="log4javascript">

+					<h2>log4javascript static properties/methods</h2>

+					<h4>Properties</h4>

+					<ul class="propertieslist">

+						<li class="property">

+							<div class="name">version</div>

+							<div class="summary">

+								The version number of your copy of log4javascript.

+							</div>

+						</li>

+						<li class="property">

+							<div class="name">edition</div>

+							<div class="summary">

+								The edition of your copy of log4javascript.

+							</div>

+						</li>

+						<li class="property">

+							<div class="name">logLog</div>

+							<div class="summary">

+								log4javascript's internal logging object. <a href="#loglog">See below for more details</a>.

+							</div>

+						</li>

+					</ul>

+					<h4>Methods</h4>

+					<ul class="propertieslist">

+						<li class="method">

+							<div class="name">getLogger</div>

+							<div class="methodsignature"><code>Logger <strong>getLogger</strong>([String <em>loggerName</em>])</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">loggerName</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								<p>

+									Returns a logger with the specified name, creating it if a logger with that name does not

+									already exist. If no name is specified, a logger is returned with name <code>[anonymous]</code>, and

+									subsequent calls to <code>getLogger()</code> (with no logger name specified) will return

+									this same logger object.

+								</p>

+								<p>

+									Note that the names <code>[anonymous]</code>, <code>[default]</code>, <code>[null]</code>

+									and <code>root</code> are reserved for

+									the anonymous logger, default logger, null logger and root logger respectively.

+								</p>

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">getDefaultLogger</div>

+							<div class="methodsignature"><code>Logger <strong>getDefaultLogger</strong>()</code></div>

+							<div class="summary">

+								Convenience method that returns the default logger. The default logger

+								has a single appender: a <code><a href="#popupappender">PopUpAppender</a></code>

+								with the default layout, width and height, and with <code>focusPopUp</code> set to false

+								and <code>lazyInit</code>, <code>useOldPopUp</code> and

+								<code>complainAboutPopUpBlocking</code> all set to true.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">getNullLogger</div>

+							<div class="methodsignature"><code>Logger <strong>getNullLogger</strong>()</code></div>

+							<div class="summary">

+								Returns an empty logger with no appenders. Useful for disabling all logging.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">getRootLogger</div>

+							<div class="methodsignature"><code>Logger <strong>getRootLogger</strong>()</code></div>

+							<div class="summary">

+								Returns the root logger from which all other loggers derive.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">resetConfiguration</div>

+							<div class="methodsignature"><code>void <strong>resetConfiguration</strong>()</code></div>

+							<div class="summary">

+								Resets the all loggers to their default level.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">setEnabled</div>

+							<div class="methodsignature"><code>void <strong>setEnabled</strong>(Boolean <em>enabled</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">enabled</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Enables or disables all logging, depending on <code>enabled</code>.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns true or false depending on whether logging is enabled.

+							</div>

+						</li>

+						<li class="method" id="log4javascriptaddeventlistener">

+							<div class="name">addEventListener</div>

+							<div class="methodsignature"><code>void <strong>addEventListener</strong>(String <em>eventType</em>, Function <em>listener</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">eventType</code>

+								</li>

+								<li class="param">

+									<code class="paramname">listener</code>

+								</li>

+							</ul>

+							<div class="summary">

+								<p>

+									Adds a function to be called when an event of the type specified occurs in log4javascript.

+									Supported event types are <code>load</code> (occurs once the page has loaded) and

+									<code>error</code>.

+								</p>

+								<p>

+									Each listener is pased three paramaters:

+								</p>

+								<ul>

+									<li><code>sender</code>. The object that raised the event (i.e. the log4javascript object);</li>

+									<li><code>eventType</code>. The type of the event;</li>

+									<li>

+										<code>eventArgs</code>. An object containing of event-specific arguments. For the <code>error</code> event,

+										this is an object with properties <code>message</code> and <code>exception</code>. For the <code>load</code>

+										event this is an empty object.

+									</li>

+								</ul>

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">removeEventListener</div>

+							<div class="methodsignature"><code>void <strong>removeEventListener</strong>(String <em>eventType</em>, Function <em>listener</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">eventType</code>

+								</li>

+								<li class="param">

+									<code class="paramname">listener</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Removes the event listener function supplied for the event of the type specified.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">dispatchEvent</div>

+							<div class="methodsignature"><code>void <strong>dispatchEvent</strong>(String <em>eventType</em>, Object <em>eventArgs</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">eventType</code>

+								</li>

+								<li class="param">

+									<code class="paramname">eventArgs</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Raises an event of type <code>eventType</code> on the <code>log4javascript</code> object.

+								Each of the listeners for this type of event (registered via <code>addEventListener</code>)

+								is called and passed <code>eventArgs</code> as the third parameter.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">setEventTypes</div>

+							<div class="methodsignature"><code>void <strong>setEventTypes</strong>(Array <em>eventTypes</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">eventTypes</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Used internally to specify the types of events that the <code>log4javascript</code> object can raise.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">setShowStackTraces</div>

+							<div class="methodsignature"><code>void <strong>setShowStackTraces</strong>(Boolean <em>show</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">show</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Enables or disables displaying of error stack traces, depending on <code>show</code>.

+								By default, stack traces are not displayed. (Only works in Firefox)

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">evalInScope</div>

+							<div class="methodsignature"><code>Object <strong>evalInScope</strong>(String <em>expr</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">expr</code>

+								</li>

+							</ul>

+							<div class="summary">

+								This evaluates the given expression in the log4javascript scope, thus allowing

+								scripts to access internal log4javascript variables and functions. This was written

+								for the purposes of automated testing but could be used by custom extensions to

+								log4javascript.

+							</div>

+						</li>

+					</ul>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="levels">

+					<h2>Levels</h2>

+					<p>

+						Levels are available as static properties of the <code>log4javascript.Level</code>

+						object. In ascending order of severity:

+					</p>

+					<ol>

+						<li><code>log4javascript.Level.ALL</code></li>

+						<li><code>log4javascript.Level.TRACE</code></li>

+						<li><code>log4javascript.Level.DEBUG</code></li>

+						<li><code>log4javascript.Level.INFO</code></li>

+						<li><code>log4javascript.Level.WARN</code></li>

+						<li><code>log4javascript.Level.ERROR</code></li>

+						<li><code>log4javascript.Level.FATAL</code></li>

+						<li><code>log4javascript.Level.OFF</code></li>

+					</ol>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="loggers">

+					<h2>Loggers</h2>

+					<p>

+						It is possible to have multiple loggers in log4javascript. For example, you

+						may wish to have a logger for debugging purposes that logs messages to a

+						pop-up window and a separate logger that reports any client-side application

+						errors to the server via Ajax.

+					</p>

+					<div id="loggerhierarchy">

+						<h3>Logger hierarchy and appender additivity</h3>

+						<p>

+							From version 1.4, log4javascript has hierarchical loggers, implemented in the same way

+							as log4j. In summary, you specify a logger's parent logger by means of a dot between the

+							parent logger name and the child logger name. Therefore the logger <code>tim.app.security</code>

+							inherits from <code>tim.app</code>, which in turn inherits from <code>tim</code> which,

+							finally, inherits from the root logger.

+						</p>

+						<p>

+							What inheritance means for a logger is that in the absence of a threshold level set

+							specifically on the logger it inherits its level from its parent; also, a logger inherits

+							all its parent's appenders (this is known as <em>appender additivity</em> in log4j. This

+							behaviour can be enabled or disabled via <code>setAdditivity()</code>. See below). In the

+							above example, if the root logger has a level of <code>DEBUG</code> and one appender,

+							each of the loggers <code>tim.app.security</code>, <code>tim.app</code> and <code>tim</code> would

+							inherit the root level's appender. If, say, <code>tim.app</code>'s threshold level was set

+							to <code>WARN</code>, <code>tim</code>'s effective level would remain at <code>DEBUG</code>

+							(inherited from the root logger) while <code>tim.app.security</code>'s effective level would

+							be <code>WARN</code>, inherited from <code>tim.app</code>. The important thing to note is

+							that appenders accumulate down the logger hierarchy while levels are simply inherited from

+							the nearest ancestor with a threshold level set.

+						</p>

+						<p>

+							For a detailed explanation of the logger hierarchy, see the

+							<a href="http://logging.apache.org/log4j/docs/manual.html" target="_blank"

+							   title="Log4j manual (opens in new window)">log4j manual</a>.

+						</p>

+					</div>

+					<p><strong>Notes</strong></p>

+					<ul>

+						<li>

+							It is not possible to instantiate loggers directly. Instead you must use

+							one of the methods of the <code>log4javascript</code> object: <code>getLogger</code>,

+							<code>getRootLogger</code>, <code>getDefaultLogger</code> or <code>getNullLogger</code>.

+						</li>

+					</ul>

+					<h4>Logger methods</h4>

+					<ul class="propertieslist">

+						<li class="method">

+							<div class="name">addAppender</div>

+							<div class="methodsignature"><code>void <strong>addAppender</strong>(Appender <em>appender</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">appender</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Adds the given appender.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">removeAppender</div>

+							<div class="methodsignature"><code>void <strong>removeAppender</strong>(Appender <em>appender</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">appender</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Removes the given appender.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">removeAllAppenders</div>

+							<div class="methodsignature"><code>void <strong>removeAllAppenders</strong>()</code></div>

+							<div class="summary">

+								Clears all appenders for the current logger.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">setLevel</div>

+							<div class="methodsignature"><code>void <strong>setLevel</strong>(Level <em>level</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">level</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Sets the level. Log messages of a lower level than <code>level</code> will not be logged.

+								Default value is <code>DEBUG</code>.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">getLevel</div>

+							<div class="methodsignature"><code>Level <strong>getLevel</strong>()</code></div>

+							<div class="summary">

+								Returns the level explicitly set for this logger or <code>null</code> if none has been set.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">getEffectiveLevel</div>

+							<div class="methodsignature"><code>Level <strong>getEffectiveLevel</strong>()</code></div>

+							<div class="summary">

+								Returns the level at which the logger is operating. This is either the level explicitly

+								set on the logger or, if no level has been set, the effective level of the logger's parent.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">setAdditivity</div>

+							<div class="methodsignature"><code>void <strong>setAdditivity</strong>(Boolean <em>additivity</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">additivity</code>

+								</li>

+							</ul>

+							<div class="summary">

+								<p>

+									Sets whether appender additivity is enabled (the default) or disabled. If set to false, this

+									particular logger will not inherit any appenders form its ancestors. Any descendant of this

+									logger, however, will inherit from its ancestors as normal, unless its own additivity is

+									explicitly set to false.

+								</p>

+								<p>

+									Default value is <code>true</code>.

+								</p>

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">getAdditivity</div>

+							<div class="methodsignature"><code>Level <strong>getLevel</strong>()</code></div>

+							<div class="summary">

+								Returns whether additivity is enabled for this logger.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">log</div>

+							<div class="methodsignature"><code>void <strong>log</strong>(Level <em>level</em>, Object <em>params</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">level</code>

+								</li>

+								<li class="param">

+									<code class="paramname">params</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Generic logging method used by wrapper methods such as <code>debug</code>,

+								<code>error</code> etc.

+							</div>

+							<p><strong>Notes</strong></p>

+							<ul>

+								<li>

+									The signature of this method has changed in 1.4.

+								</li>

+							</ul>

+						</li>

+						<li class="method">

+							<div class="name">trace</div>

+							<div class="methodsignature"><code>void <strong>trace</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">message1[, message2...]</code>

+								</li>

+								<li class="param">

+									<code class="paramname">exception</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Logs one or more messages and optionally an error at level <code>TRACE</code>.

+							</div>

+							<p><strong>Notes</strong></p>

+							<ul>

+								<li>

+									Logging of multiple messages in one call is new in 1.4.

+								</li>

+							</ul>

+						</li>

+						<li class="method">

+							<div class="name">debug</div>

+							<div class="methodsignature"><code>void <strong>debug</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">message1[, message2...]</code>

+								</li>

+								<li class="param">

+									<code class="paramname">exception</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Logs one or more messages and optionally an error at level <code>DEBUG</code>.

+							</div>

+							<p><strong>Notes</strong></p>

+							<ul>

+								<li>

+									Logging of multiple messages in one call is new in 1.4.

+								</li>

+							</ul>

+						</li>

+						<li class="method">

+							<div class="name">info</div>

+							<div class="methodsignature"><code>void <strong>info</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">message1[, message2...]</code>

+								</li>

+								<li class="param">

+									<code class="paramname">exception</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Logs one or more messages and optionally an error at level <code>INFO</code>.

+							</div>

+							<p><strong>Notes</strong></p>

+							<ul>

+								<li>

+									Logging of multiple messages in one call is new in 1.4.

+								</li>

+							</ul>

+						</li>

+						<li class="method">

+							<div class="name">warn</div>

+							<div class="methodsignature"><code>void <strong>warn</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">message1[, message2...]</code>

+								</li>

+								<li class="param">

+									<code class="paramname">exception</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Logs one or more messages and optionally an error at level <code>WARN</code>.

+							</div>

+							<p><strong>Notes</strong></p>

+							<ul>

+								<li>

+									Logging of multiple messages in one call is new in 1.4.

+								</li>

+							</ul>

+						</li>

+						<li class="method">

+							<div class="name">error</div>

+							<div class="methodsignature"><code>void <strong>error</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">message1[, message2...]</code>

+								</li>

+								<li class="param">

+									<code class="paramname">exception</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Logs one or more messages and optionally an error at level <code>ERROR</code>.

+							</div>

+							<p><strong>Notes</strong></p>

+							<ul>

+								<li>

+									Logging of multiple messages in one call is new in 1.4.

+								</li>

+							</ul>

+						</li>

+						<li class="method">

+							<div class="name">fatal</div>

+							<div class="methodsignature"><code>void <strong>fatal</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">message1[, message2...]</code>

+								</li>

+								<li class="param">

+									<code class="paramname">exception</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Logs one or more messages and optionally an error at level <code>FATAL</code>.

+							</div>

+							<p><strong>Notes</strong></p>

+							<ul>

+								<li>

+									Logging of multiple messages in one call is new in 1.4.

+								</li>

+							</ul>

+						</li>

+						<li class="method">

+							<div class="name">isEnabledFor</div>

+							<div class="methodsignature"><code>Boolean <strong>isEnabledFor</strong>(Level <em>level</em>, Error <em>exception</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">level</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Returns whether the logger is enabled for the specified level. 

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isTraceEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isTraceEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns whether the logger is enabled for <code>TRACE</code> messages.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isDebugEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isDebugEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns whether the logger is enabled for <code>DEBUG</code> messages.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isInfoEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isInfoEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns whether the logger is enabled for <code>INFO</code> messages.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isWarnEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isWarnEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns whether the logger is enabled for <code>WARN</code> messages.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isErrorEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isErrorEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns whether the logger is enabled for <code>ERROR</code> messages.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isFatalEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isFatalEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns whether the logger is enabled for <code>FATAL</code> messages.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">group</div>

+							<div class="methodsignature"><code>void <strong>group</strong>(String <em>name</em>, Boolean <em>initiallyExpanded</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">name</code>

+								</li>

+								<li class="param">

+									<code class="paramname">initiallyExpanded</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Starts a new group of log messages. In appenders that support grouping (currently

+								<code><a href="#popupappender">PopUpAppender</a></code> and

+								<code><a href="#inpageappender">InPageAppender</a></code>), a group appears as an expandable

+								section in the console, labelled with the <code>name</code> specified.

+								Specifying <code>initiallyExpanded</code> determines whether the

+								group starts off expanded (the default is <code>true</code>). Groups may be nested.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">groupEnd</div>

+							<div class="methodsignature"><code>void <strong>groupEnd</strong>()</code></div>

+							<div class="summary">

+								Ends the current group. If there is no group then this function has no effect.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">time</div>

+							<div class="methodsignature"><code>void <strong>time</strong>(String <em>name</em>, Level <em>level</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">name</code>

+								</li>

+								<li class="param">

+									<code class="paramname">level</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Starts a timer with name <code>name</code>. When the timer is ended with a

+								call to <code>timeEnd</code> using the same name, the amount of time that

+								has elapsed in milliseconds since the timer was started is logged at level

+								<code>level</code>. If not level is supplied, the level defaults to <code>INFO</code>.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">timeEnd</div>

+							<div class="methodsignature"><code>void <strong>timeEnd</strong>(String <em>name</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">name</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Ends the timer with name <code>name</code> and logs the time elapsed.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">assert</div>

+							<div class="methodsignature"><code>void <strong>assert</strong>(Object <em>expr</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">expr</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Asserts the given expression is <code>true</code> or evaluates to <code>true</code>.

+								If so, nothing is logged. If not, an error is logged at the <code>ERROR</code> level.

+							</div>

+						</li>

+					</ul>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="appenders">

+					<h2>Appenders</h2>

+					<div id="appender">

+						<h3>Appender</h3>

+						<p>

+							There are methods common to all appenders, as listed below.

+						</p>

+						<h4>Methods</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">doAppend</div>

+								<div class="methodsignature"><code>void <strong>doAppend</strong>(LoggingEvent <em>loggingEvent</em>)</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">loggingEvent</code>

+									</li>

+								</ul>

+								<div class="summary">

+									<p>

+										Checks the logging event's level is at least as severe as the appender's

+										threshold and calls the appender's <code>append</code> method if so.

+									</p>

+									<p>

+										This method should not in general be used directly or overridden.

+									</p>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">append</div>

+								<div class="methodsignature"><code>void <strong>append</strong>(LoggingEvent <em>loggingEvent</em>)</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">loggingEvent</code>

+									</li>

+								</ul>

+								<div class="summary">

+									Appender-specific method to append a log message. Every appender object should implement

+									this method.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setLayout</div>

+								<div class="methodsignature"><code>void <strong>setLayout</strong>(Layout <em>layout</em>)</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">layout</code>

+									</li>

+								</ul>

+								<div class="summary">

+									Sets the appender's layout.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getLayout</div>

+								<div class="methodsignature"><code>Layout <strong>getLayout</strong>()</code></div>

+								<div class="summary">

+									Returns the appender's layout.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setThreshold</div>

+								<div class="methodsignature"><code>void <strong>setThreshold</strong>(Level <em>level</em>)</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">level</code>

+									</li>

+								</ul>

+								<div class="summary">

+									Sets the appender's threshold. Log messages of level less severe than this

+									threshold will not be logged.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getThreshold</div>

+								<div class="methodsignature"><code>Level <strong>getThreshold</strong>()</code></div>

+								<div class="summary">

+									Returns the appender's threshold.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">toString</div>

+								<div class="methodsignature"><code>string <strong>toString</strong>()</code></div>

+								<div class="summary">

+									Returns a string representation of the appender. Every appender object should implement

+									this method.

+								</div>

+							</li>

+						</ul>

+						<p class="linktotop">

+							<a href="#container">Top</a>

+						</p>

+					</div>

+					<div id="alertappender">

+						<h3>AlertAppender</h3>

+						<p class="editions">Editions: <strong>Standard</strong></p>

+						<p>

+							Displays a log message as a JavaScript alert.

+						</p>

+						<h4>Constructor</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">AlertAppender</div>

+								<div class="methodsignature"><code><strong>AlertAppender</strong>()</code></div>

+							</li>

+						</ul>

+						<p class="linktotop">

+							<a href="#container">Top</a>

+						</p>

+					</div>

+					<div id="ajaxappender">

+						<h3>AjaxAppender</h3>

+						<p class="editions">Editions: <strong>Standard, Production</strong></p>

+						<p>

+							A flexible appender that asynchronously  sends log messages to a server via HTTP

+							(Ajax, if you insist, though the 'x' of Ajax only comes into play in any form if you use an

+							<code><a href="#xmllayout">XmlLayout</a></code>).

+						</p>

+						<p>

+							The default configuration is to send each log message as a separate HTTP post

+							request to the server using an <code><a href="#httppostdatalayout">HttpPostDataLayout</a></code>,

+							without waiting for a response before sending any subsequent requests. However,

+							an <code>AjaxAppender</code> may be configured to do any one of or combinations of the following:

+						</p>

+						<ul>

+							<li>

+								send log messages in batches (if the selected layout supports it - particularly suited

+								to <code>AjaxAppender</code> are <code><a href="#jsonlayout">JsonLayout</a></code> and

+								<code><a href="#xmllayout">XmlLayout</a></code>, both of which allow batching);

+							</li>

+							<li>

+								wait for a response from a previous request before sending the next log message / batch

+								of messages;

+							</li>

+							<li>

+								send all queued log messages at timed intervals.

+							</li>

+						</ul>

+						<p><strong>Notes</strong></p>

+						<ul>

+							<li>

+								AjaxAppender relies on the <code>XMLHttpRequest</code> object. It also requires

+								the presence of correctly implemented <code>setRequestHeader</code> method on

+								this object, which rules out Opera prior to version 8.01. If your browser does not

+								support the necessary objects then one alert will display to explain why it

+								doesn't work, after which the appender will silently switch off.

+							</li>

+							<li>

+								In AjaxAppender only, <code>setLayout</code> may not be called after the first

+								message has been logged.

+							</li>

+							<li>

+								The default layout is <code><a href="#httppostdatalayout">HttpPostDataLayout</a></code>.

+							</li>

+							<li>

+								From version 1.4, log message data is always sent as one or more name/value pairs.

+								In the case of <code><a href="#httppostdatalayout">HttpPostDataLayout</a></code>, data

+								is sent the same as in previous versions. For other layouts such as

+								<code><a href="#jsonlayout">JsonLayout</a></code> and

+								<code><a href="#xmllayout">XmlLayout</a></code>, the formatted log message is posted as

+								the value of a parameter called <code>data</code>, though this may be changed via

+								<code>setPostVarName</code>.

+							</li>

+							<li>

+								From version 1.4, log message timestamps are sent as standard JavaScript times, i.e.

+								the number of milliseconds since 00:00:00 UTC on January 1, 1970.

+							</li>

+							<li>

+								<p>

+									Also from version 1.4, any outstanding log messages may optionally be sent when the

+									main page unloads (i.e. user follows a link, closes the window or refreshes the

+									page). This behaviour may be enabled using <code>setSendAllOnUnload</code>; see

+									below.

+								</p>

+								<p>

+									This behaviour is dependent on <code>window.onbeforeunload</code>; unfortunately,

+									Opera does not always raise this event, so this feature does not work reliably in

+									Opera.

+								</p>

+							</li>

+						</ul>

+						<h4>Constructor</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">AjaxAppender</div>

+								<div class="methodsignature">

+									<code><strong>AjaxAppender</strong>(String <em>url</em>)</code>

+								</div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">url</code>

+										<div>

+											The URL to which log messages should be sent. Note that this is subject

+											to the usual Ajax restrictions: the URL should be in the same domain as that

+											of the page making the request.

+										</div>

+									</li>

+								</ul>

+							</li>

+						</ul>

+						<h4>Methods</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">setSendAllOnUnload</div>

+								<div class="methodsignature"><code>void <strong>setSendAllOnUnload</strong>(Boolean <em>sendAllOnUnload</em>)</code></div>

+								<div class="summary">

+									<p>

+										[<em>not available after first message logged</em>]

+									</p>

+									<p>

+										Whether to send all remaining unsent log messages to the server when the page

+										unloads.

+									</p>

+									<p>

+										Since version 1.4.3, the default value is <code>false</code>. Previously the

+										default was <code>true</code>.

+									</p>

+									<p><strong>Notes</strong></p>

+									<ul>

+										<li>

+											This feature was found not to work prior to version 1.4.3 in WebKit

+											browsers (e.g. Google Chrome, Safari). As a result, a workaround was

+											implemented in 1.4.3 which has the unfortunate side effect of popping up a

+											confirmation dialog to the user if there are any log messages to send when

+											the page unloads. As a result, this feature is now obtrusive for the user

+											and is therefore disabled by default.

+										</li>

+										<li>

+											This feature does not work in any version of Opera.

+										</li>

+									</ul>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isSendAllOnUnload</div>

+								<div class="methodsignature"><code>Boolean <strong>isSendAllOnUnload</strong>()</code></div>

+								<div class="summary">

+									Returns whether all remaining unsent log messages are sent to the server when the page unloads.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setPostVarName</div>

+								<div class="methodsignature"><code>void <strong>setPostVarName</strong>(String <em>postVarName</em>)</code></div>

+								<div class="summary">

+									<p>

+										[<em>not available after first message logged</em>]

+									</p>

+									<p>

+										Sets the post variable name whose value will the formatted log message(s) for

+										each request.

+									</p>

+									<p>

+										Default value is <code>data</code>.

+									</p>

+									<p><strong>Notes</strong></p>

+									<ul>

+										<li>

+											This has no effect if the current layout is an

+											<code><a href="#httppostdatalayout">HttpPostDataLayout</a></code>.

+										</li>

+									</ul>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getPostVarName</div>

+								<div class="methodsignature"><code>String <strong>getPostVarName</strong>()</code></div>

+								<div class="summary">

+									Returns the post variable name whose value will the formatted log message(s) for

+									each request.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setTimed</div>

+								<div class="methodsignature"><code>void <strong>setTimed</strong>(Boolean <em>timed</em>)</code></div>

+								<div class="summary">

+									<p>

+										[<em>not available after first message logged</em>]

+									</p>

+									<p>

+										Whether to send log messages to the server at regular, timed intervals.

+									</p>

+									<p>

+										Default value is <code>false</code>.

+									</p>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isTimed</div>

+								<div class="methodsignature"><code>Boolean <strong>isTimed</strong>()</code></div>

+								<div class="summary">

+									Returns whether log messages are sent to the server at regular, timed intervals.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setWaitForResponse</div>

+								<div class="methodsignature"><code>void <strong>setWaitForResponse</strong>(Boolean <em>waitForResponse</em>)</code></div>

+								<div class="summary">

+									<p>

+										[<em>not available after first message logged</em>]

+									</p>

+									<p>

+										Sets whether to wait for a response from a previous HTTP request from this

+										appender before sending the next log message / batch of messages.

+									</p>

+									<p>

+										Default value is <code>false</code>.

+									</p>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isWaitForResponse</div>

+								<div class="methodsignature"><code>Boolean <strong>isWaitForResponse</strong>()</code></div>

+								<div class="summary">

+									Returns whether the appender waits for a response from a previous HTTP request from this

+									appender before sending the next log message / batch of messages.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setBatchSize</div>

+								<div class="methodsignature"><code>void <strong>setBatchSize</strong>(Number <em>batchSize</em>)</code></div>

+								<div class="summary">

+									<p>

+										[<em>not available after first message logged</em>]

+									</p>

+									<p>

+										Sets the number of log messages to send in each request. If not specified,

+										defaults to <code>1</code>.

+									</p>

+									<p><strong>Notes</strong></p>

+									<ul>

+										<li>

+											Setting this to a number greater than 1 means that the appender will wait

+											until it has forwarded that many valid log messages before sending any more.

+											This also means that if the page unloads for any reason and <code>sendAllOnUnload</code>

+											is not set to <code>true</code>, any log messages waiting in the queue will not be sent.

+										</li>

+										<li>

+											If batching is used in conjunction with timed sending of log messages,

+											messages will still be sent in batches of size <code>batchSize</code>,

+											regardless of how many log messages are queued by the time the timed

+											sending is invoked. Incomplete batches will not be sent except when the

+											page unloads, if <code>sendAllOnUnload</code> is set to <code>true</code>.

+										</li>

+									</ul>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getBatchSize</div>

+								<div class="methodsignature"><code>Number <strong>getBatchSize</strong>()</code></div>

+								<div class="summary">

+									Returns the number of log messages sent in each request. See above for more details.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setTimerInterval</div>

+								<div class="methodsignature"><code>void <strong>setTimerInterval</strong>(Number <em>timerInterval</em>)</code></div>

+								<div class="summary">

+									<p>

+										[<em>not available after first message logged</em>]

+									</p>

+									<p>

+										Sets the length of time in milliseconds between each sending of queued log

+										messages.

+									</p>

+									<p><strong>Notes</strong></p>

+									<ul>

+										<li>

+											<code>timerInterval</code> only has an effect in conjunction with

+											<code>timed</code> (set by <code>setTimed()</code>. If <code>timed</code>

+											is set to false then <code>timerInterval</code> has no effect.

+										</li>

+										<li>

+											Each time the queue of log messages or batches of messages is cleared,

+											the countdown to the next sending only starts once the final request

+											has been sent (and, if <code>waitForResponse</code> is set to <code>true</code>,

+											the final response received). This means that the actual interval at

+											which the queue of messages is cleared cannot be fixed.

+										</li>

+									</ul>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getTimerInterval</div>

+								<div class="methodsignature"><code>Number <strong>getTimerInterval</strong>()</code></div>

+								<div class="summary">

+									Returns the length of time in milliseconds between each sending of queued log

+									messages. See above for more details.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setRequestSuccessCallback</div>

+								<div class="methodsignature"><code>void <strong>setRequestSuccessCallback</strong>(Function <em>requestSuccessCallback</em>)</code></div>

+								<div class="summary">

+									<p>

+										Sets the function that is called whenever a successful request is made, called at the

+										point at which the response is received. This feature can be used to confirm

+										whether a request has been successful and act accordingly.

+									</p>

+									<p>

+										A single parameter, <code>xmlHttp</code>, is passed to the callback function.

+										This is the XMLHttpRequest object that performed the request.

+									</p>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setFailCallback</div>

+								<div class="methodsignature"><code>void <strong>setFailCallback</strong>(Function <em>failCallback</em>)</code></div>

+								<div class="summary">

+									<p>

+										Sets the function that is called whenever any kind of failure occurs in the appender,

+										including browser deficiencies or configuration errors (e.g. supplying a

+										non-existent URL to the appender). This feature can be used to handle

+										AjaxAppender-specific errors.

+									</p>

+									<p>

+										A single parameter, <code>message</code>, is passed to the callback function.

+										This is the error-specific message that caused the failure.

+									</p>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setSessionId</div>

+								<div class="methodsignature"><code>void <strong>setSessionId</strong>(String <em>sessionId</em>)</code></div>

+								<div class="summary">

+									Sets the session id sent to the server each time a request is made.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getSessionId</div>

+								<div class="methodsignature"><code>String <strong>getSessionId</strong>()</code></div>

+								<div class="summary">

+									Returns the session id sent to the server each time a request is made.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">addHeader</div>

+								<div class="methodsignature"><code>void <strong>addHeader</strong>(String <em>name</em>,

+									String <em>value</em>)</code></div>

+								<div class="summary">

+									<p>

+										Adds an HTTP header that is sent with each request.

+									</p>

+									<p>

+										<strong>Since: 1.4.3</strong>

+									</p>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getHeaders</div>

+								<div class="methodsignature"><code>Array <strong>getHeaders</strong>()</code></div>

+								<div class="summary">

+									Returns an array of the additional headers that are sent with each HTTP request.

+									Each array item is an object with properties <code>name</code> and

+									<code>value</code>.

+									<p>

+										<strong>Since: 1.4.3</strong>

+									</p>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">sendAll</div>

+								<div class="methodsignature"><code>void <strong>sendAll</strong>()</code></div>

+								<div class="summary">

+									Sends all log messages in the queue. If log messages are batched then only completed

+									batches are sent.

+								</div>

+							</li>

+						</ul>

+						<p class="linktotop">

+							<a href="#container">Top</a>

+						</p>

+					</div>

+					<div id="popupappender">

+						<h3>PopUpAppender</h3>

+						<p class="editions">Editions: <strong>Standard</strong></p>

+						<p>

+							Logs messages to a pop-up console window (note: you will need to disable pop-up

+							blockers to use it). The pop-up displays a list of all log messages, and has

+							the following features:

+						</p>

+						<ul>

+							<li>log messages are colour-coded by severity;</li>

+							<li>log messages are displayed in a monospace font to allow easy readability;</li>

+							<li>switchable wrap mode to allow wrapping of long lines</li>

+							<li>all whitespace in log messages is honoured (except in wrap mode);</li>

+							<li>filters to show and hide messages of a particular level;</li>

+							<li>

+								search facility that allows searching of log messages as you type, with the

+								following features:

+								<ul>

+									<li>supports regular expressions;</li>

+									<li>case sensitive or insensitive matching;</li>

+									<li>buttons to navigate through all the matches;</li>

+									<li>switch to highlight all matches;</li>

+									<li>switch to filter out all log messages that contain no matches;</li>

+									<li>switch to enable or disable the search;</li>

+									<li>search is dynamically applied to every log message as it is added to the console.</li>

+								</ul>

+							</li>

+							<li>switch to toggle between logging from the top down and from the bottom up;</li>

+							<li>switch to turn automatic scrolling when a new message is logged on and off;</li>

+							<li>switch to turn off all logging to the pop-up (useful if a timer is generating unwanted log messages);</li>

+							<li>optional configurable limit to the number of log message that are displayed. If

+								set and this limit is reached, each new log message will cause the oldest one to

+								be discarded;</li>

+							<li>grouped log messages. Groups may be nested and each has a button to show or hide the log messages in that group;</li>

+							<li>clear button to allow user to delete all current log messages.</li>

+							<li>

+								command prompt with up/down arrow history. Command line functions may be added

+								to the appender. Several command line functions are built in:

+								<ul class="propertieslist">

+									<li class="method">

+										<div class="methodsignature"><code><strong>$</strong>(String <em>id</em>)</code></div>

+										<div class="summary">

+											Prints a string representation of a single element with the id supplied.

+										</div>

+									</li>

+									<li class="method">

+										<div class="methodsignature"><code><strong>dir</strong>(Object <em>obj</em>)</code></div>

+										<div class="summary">

+											Prints a list of a properties of the object supplied.

+										</div>

+									</li>

+									<li class="method">

+										<div class="methodsignature"><code><strong>dirxml</strong>(HTMLElement <em>el</em>)</code></div>

+										<div class="summary">

+											Prints the XML source code of an HTML or XML element

+										</div>

+									</li>

+									<li class="method">

+										<div class="methodsignature"><code><strong>cd</strong>(Object <em>win</em>)</code></div>

+										<div class="summary">

+											Changes the scope of execution of commands to the named frame or window (either a

+											window/frame name or a reference to a window object may be supplied).

+										</div>

+									</li>

+									<li class="method">

+										<div class="methodsignature"><code><strong>clear</strong>()</code></div>

+										<div class="summary">

+											Clears the console.

+										</div>

+									</li>

+									<li class="method">

+										<div class="methodsignature"><code><strong>keys</strong>(Object <em>obj</em>)</code></div>

+										<div class="summary">

+											Prints a list of the names of all properties of the object supplied.

+										</div>

+									</li>

+									<li class="method">

+										<div class="methodsignature"><code><strong>values</strong>(Object <em>obj</em>)</code></div>

+										<div class="summary">

+											Prints a list of the values of all properties of the object supplied.

+										</div>

+									</li>

+									<li class="method">

+										<div class="methodsignature"><code><strong>expansionDepth</strong>(Number <em>depth</em>)</code></div>

+										<div class="summary">

+											Sets the number of levels of expansion of objects that are displayed by

+											the command line. The default value is 1.

+										</div>

+									</li>

+								</ul>

+							</li>

+						</ul>

+						<p><strong>Notes</strong></p>

+						<ul>

+							<li>

+								<p>

+									The default layout for this appender is <code><a href="#patternlayout">PatternLayout</a></code>

+									with pattern string

+								</p>

+								<p>

+									<code>%d{HH:mm:ss} %-5p - %m{1}%n</code>

+								</p>

+							</li>

+						</ul>

+						<h4>Constructor</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">PopUpAppender</div>

+								<div class="methodsignature">

+							   		<code><strong>PopUpAppender</strong>([Boolean <em>lazyInit</em>,

+									Boolean <em>initiallyMinimized</em>, Boolean <em>useDocumentWrite</em>,

+									Number <em>width</em>, Number <em>height</em>])</code>

+								</div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">lazyInit</code>

+										[<em>optional</em>]

+										<div>

+											Set this to <code>true</code> to open the pop-up only when the first log

+											message reaches the appender. Otherwise, the pop-up window opens as soon as the

+											appender is created. If not specified, defaults to <code>false</code>.

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">initiallyMinimized</code>

+										[<em>optional</em>]

+										<div>

+											<p>

+												Whether the console window should start off hidden / minimized.

+												If not specified, defaults to <code>false</code>.

+											</p>

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">useDocumentWrite</code>

+										[<em>optional</em>]

+										<div>

+											<p>

+												Specifies how the console window is created. By default, the console window is

+												created dynamically using <code>document</code>'s <code>write</code> method. This has the

+												advantage of keeping all the code in one single JavaScript file. However, if your

+												page sets <code>document.domain</code> then the browser prevents script access to

+												a window unless it too has the same value set for <code>document.domain</code>. To

+												get round this issue, you can set <code>useDocumentWrite</code> to <code>false</code>

+												and log4javascript will instead use the external HTML file <code>console.html</code>

+												(or <code>console_uncompressed.html</code> if you're using an uncompressed version of

+												log4javascript.js), which must be placed in the same directory as your log4javascript.js file.

+											</p>

+											<p>

+												Note that if <code>useDocumentWrite</code> is set to <code>true</code>, the old pop-up

+												window will always be closed and a new one created whenever the page is refreshed, even

+												if <code>setUseOldPopUp(true)</code> has been called.

+											</p>

+											<p>

+												In general it's simpler to use the <code>document.write</code> method, so unless your

+												page needs to set <code>document.domain</code>, <code>useDocumentWrite</code> should

+												be set to <code>true</code>.

+											</p>

+											<p>

+												If not specified, defaults to <code>true</code>.

+											</p>

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">width</code>

+										[<em>optional</em>]

+										<div>

+											The outer width in pixels of the pop-up window. If not specified,

+											defaults to <code>600</code>.

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">height</code>

+										[<em>optional</em>]

+										<div>

+											The outer height in pixels of the pop-up window. If not specified,

+											defaults to <code>400</code>.

+										</div>

+									</li>

+								</ul>

+							</li>

+						</ul>

+						<h4>Methods</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">isInitiallyMinimized</div>

+								<div class="methodsignature"><code>Boolean <strong>isInitiallyMinimized</strong>()</code></div>

+								<div class="summary">

+									Returns whether the console window starts off hidden / minimized.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setInitiallyMinimized</div>

+								<div class="methodsignature"><code>void <strong>setInitiallyMinimized</strong>(Boolean <em>initiallyMinimized</em>)</code></div>

+								<div class="summary">

+									[<em>not available after initialization</em>]

+									<br />

+									Sets whether the console window should start off hidden / minimized.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isFocusPopUp</div>

+								<div class="methodsignature"><code>Boolean <strong>isFocusPopUp</strong>()</code></div>

+								<div class="summary">

+									Returns whether the pop-up window is focussed (i.e. brought it to the front)

+									when a new log message is added. Default value is <code>false</code>.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setFocusPopUp</div>

+								<div class="methodsignature"><code>void <strong>setFocusPopUp</strong>(Boolean <em>focusPopUp</em>)</code></div>

+								<div class="summary">

+									Sets whether to focus the pop-up window (i.e. bring it to the front)

+									when a new log message is added.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isUseOldPopUp</div>

+								<div class="methodsignature"><code>Boolean <strong>isUseOldPopUp</strong>()</code></div>

+								<div class="summary">

+									<p>

+										Returns whether the same pop-up window is used if the main page is

+										reloaded. If set to <code>true</code>, when the page is reloaded

+										a line is drawn in the pop-up and subsequent log messages are added

+										to the same pop-up. Otherwise, a new pop-up window is created that

+										replaces the original pop-up. If not specified, defaults to

+										<code>true</code>.

+									</p>

+									<p><strong>Notes</strong></p>

+									<ul>

+										<li>

+											In Internet Explorer 5, the browser prevents this from working

+											properly, so a new pop-up window is always created when the main

+											page reloads. Also, the original pop-up does not get closed.

+										</li>

+									</ul>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setUseOldPopUp</div>

+								<div class="methodsignature"><code>void <strong>setUseOldPopUp</strong>(Boolean <em>useOldPopUp</em>)</code></div>

+								<div class="summary">

+									[<em>not available after initialization</em>]

+									<br />

+									Sets whether to use the same pop-up window if the main page is reloaded.

+									See <code>isUseOldPopUp</code> above for details.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isComplainAboutPopUpBlocking</div>

+								<div class="methodsignature"><code>Boolean <strong>isComplainAboutPopUpBlocking</strong>()</code></div>

+								<div class="summary">

+									Returns whether an alert is shown to the user when the pop-up window

+									cannot be created as a result of a pop-up blocker. Default value is <code>true</code>.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setComplainAboutPopUpBlocking</div>

+								<div class="methodsignature"><code>void <strong>setComplainAboutPopUpBlocking</strong>(Boolean <em>complainAboutPopUpBlocking</em>)</code></div>

+								<div class="summary">

+									[<em>not available after initialization</em>]

+									<br />

+									Sets whether to announce to show an alert to the user when the pop-up window

+									cannot be created as a result of a pop-up blocker.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isNewestMessageAtTop</div>

+								<div class="methodsignature"><code>Boolean <strong>isNewestMessageAtTop</strong>()</code></div>

+								<div class="summary">

+									Returns whether new log messages are displayed at the top of the pop-up window.

+									Default value is <code>false</code> (i.e. log messages are appended to the bottom of the window).

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setNewestMessageAtTop</div>

+								<div class="methodsignature"><code>void <strong>setNewestMessageAtTop</strong>(Boolean <em>newestMessageAtTop</em>)</code></div>

+								<div class="summary">

+									Sets whether to display new log messages at the top inside the pop-up window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isScrollToLatestMessage</div>

+								<div class="methodsignature"><code>Boolean <strong>isScrollToLatestMessage</strong>()</code></div>

+								<div class="summary">

+									Returns whether the pop-up window scrolls to display the latest log message when a new message

+									is logged. Default value is <code>true</code>.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setScrollToLatestMessage</div>

+								<div class="methodsignature"><code>void <strong>setScrollToLatestMessage</strong>(Boolean <em>scrollToLatestMessage</em>)</code></div>

+								<div class="summary">

+									Sets whether to scroll the pop-up window to display the latest log message when a new message

+									is logged.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isReopenWhenClosed</div>

+								<div class="methodsignature"><code>Boolean <strong>isReopenWhenClosed</strong>()</code></div>

+								<div class="summary">

+									Returns whether the pop-up window reopens automatically after being closed when a new log message is logged.

+									Default value is <code>false</code>.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setReopenWhenClosed</div>

+								<div class="methodsignature"><code>void <strong>setReopenWhenClosed</strong>(Boolean <em>reopenWhenClosed</em>)</code></div>

+								<div class="summary">

+									Sets whether to reopen the pop-up window automatically after being closed when a new log message is logged.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getWidth</div>

+								<div class="methodsignature"><code>Number <strong>getWidth</strong>()</code></div>

+								<div class="summary">

+									Returns the outer width in pixels of the pop-up window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setWidth</div>

+								<div class="methodsignature"><code>void <strong>setWidth</strong>(Number <em>width</em>)</code></div>

+								<div class="summary">

+									[<em>not available after initialization</em>]

+									<br />

+									Sets the outer width in pixels of the pop-up window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getHeight</div>

+								<div class="methodsignature"><code>Number <strong>getHeight</strong>()</code></div>

+								<div class="summary">

+									[<em>not available after initialization</em>]

+									<br />

+									Returns the outer height in pixels of the pop-up window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setHeight</div>

+								<div class="methodsignature"><code>void <strong>setHeight</strong>(Number <em>height</em>)</code></div>

+								<div class="summary">

+									Sets the outer height in pixels of the pop-up window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getMaxMessages</div>

+								<div class="methodsignature"><code>Number <strong>getMaxMessages</strong>()</code></div>

+								<div class="summary">

+									Returns the largest number of log messages that are displayed and stored

+									by the the console. Once reached, a new log message wil cause the

+									oldest message to be discarded.  Default value is <code>null</code>, which means no

+									limit is applied.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setMaxMessages</div>

+								<div class="methodsignature"><code>void <strong>setMaxMessages</strong>(Number <em>maxMessages</em>)</code></div>

+								<div class="summary">

+									[<em>not available after initialization</em>]

+									<br />

+									Sets the largest number of messages displayed and stored by the console window. Set

+									this to <code>null</code> to make this number unlimited.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isShowCommandLine</div>

+								<div class="methodsignature"><code>Boolean <strong>isShowCommandLine</strong>()</code></div>

+								<div class="summary">

+									Returns whether the console includes a command line.

+									Default value is <code>true</code>.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setShowCommandLine</div>

+								<div class="methodsignature"><code>void <strong>setShowCommandLine</strong>(Boolean <em>showCommandLine</em>)</code></div>

+								<div class="summary">

+									Sets whether the console includes a command line.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getCommandLineObjectExpansionDepth</div>

+								<div class="methodsignature"><code>Number <strong>getCommandLineObjectExpansionDepth</strong>()</code></div>

+								<div class="summary">

+									Returns the number of levels to expand when an object value is logged to the console.

+									Each property of an object above this threshold will be expanded if it is itself an object

+									or array, otherwise its string representation will be displayed. Default value is 1 (i.e.

+									the properties of the object logged will be displayed in their string representation but

+									not expanded).

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setCommandLineObjectExpansionDepth:</div>

+								<div class="methodsignature"><code>void <strong>setCommandLineObjectExpansionDepth</strong>(Number <em>expansionDepth</em>)</code></div>

+								<div class="summary">

+									Sets the number of levels to expand when an object value is logged to the console.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getCommandWindow</div>

+								<div class="methodsignature"><code>Window <strong>getCommandWindow</strong>()</code></div>

+								<div class="summary">

+									Returns a reference to the window in which commands typed into the command line

+									are currently being executed.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setCommandWindow</div>

+								<div class="methodsignature"><code>void <strong>setCommandWindow</strong>(Window <em>commandWindow</em>)</code></div>

+								<div class="summary">

+									Sets the window in which commands typed into the command line are executed.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getCommandLayout</div>

+								<div class="methodsignature"><code>Number <strong>getCommandLayout</strong>()</code></div>

+								<div class="summary">

+									Returns the layout used to format the output for commands typed into the command line.

+									The default value is a <code><a href="#patternlayout">PatternLayout</a></code> with

+									pattern string <code>%m</code>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setCommandLayout</div>

+								<div class="methodsignature"><code>void <strong>setCommandLayout</strong>(Layout <em>commandLayout</em>)</code></div>

+								<div class="summary">

+									Sets the layout used to format the output for commands typed into the command line.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">clear</div>

+								<div class="methodsignature"><code>void <strong>clear</strong>()</code></div>

+								<div class="summary">

+									Clears all messages from the console window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">close</div>

+								<div class="methodsignature"><code>void <strong>close</strong>()</code></div>

+								<div class="summary">

+									Closes the pop-up window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">show</div>

+								<div class="methodsignature"><code>void <strong>show</strong>()</code></div>

+								<div class="summary">

+									Opens the pop-up window, if not already open.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">hide</div>

+								<div class="methodsignature"><code>void <strong>hide</strong>()</code></div>

+								<div class="summary">

+									Closes the pop-up window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">focus</div>

+								<div class="methodsignature"><code>void <strong>focus</strong>()</code></div>

+								<div class="summary">

+									Brings the console window to the top and gives it the focus.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">focusCommandLine</div>

+								<div class="methodsignature"><code>void <strong>focusCommandLine</strong>()</code></div>

+								<div class="summary">

+									Brings the console window to the top and gives the focus to the command line.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">focusSearch</div>

+								<div class="methodsignature"><code>void <strong>focusSearch</strong>()</code></div>

+								<div class="summary">

+									Brings the console window to the top and gives the focus to the search box.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">evalCommandAndAppend</div>

+								<div class="methodsignature"><code>void <strong>evalCommandAndAppend</strong>(String <em>expr</em>)</code></div>

+								<div class="summary">

+									Evaluates the expression and appends the result to the console.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">addCommandLineFunction</div>

+								<div class="methodsignature"><code>void <strong>addCommandLineFunction</strong>(String <em>functionName</em>, Function <em>commandLineFunction</em>)</code></div>

+								<div class="summary">

+									<p>

+										Adds a function with the name specified to the list of functions available on the command line.

+										This feature may be used to add custom functions to the command line.

+									</p>

+									<p>

+										When you call the function on the command line, <code>commandLineFunction</code> is executed with the

+										following three parameters:

+									</p>

+									<ul>

+										<li><em>appender</em>. A reference to the appender in which the command was executed;</li>

+										<li><em>args</em>.

+											An array-like list of parameters passed into the function on the command line

+											(actually a reference to the <code>arguments</code> object representing the parameters passed

+											into the function by the user);</li>

+										<li><em>returnValue</em>. This is an object with two properties that allow the function to control

+											how the result is displayed:

+											<ul>

+												<li><em>appendResult</em>. A boolean value that determines whether the returned value from this

+													function is appended to the console. The default value is <code>true</code>;</li>

+												<li><em>isError</em>. A boolean value that specifies whether the output of this function

+													should be displayed as an error. The default value is <code>false</code>.</li>

+											</ul>

+										</li>

+									</ul>

+									<p>

+										The value returned by the function is formatted by the command layout and appended to the console.

+									</p>

+								</div>

+							</li>

+						</ul>

+						<p class="linktotop">

+							<a href="#container">Top</a>

+						</p>

+					</div>

+					<div id="inpageappender">

+						<h3>InPageAppender</h3>

+						<p class="editions">Editions: <strong>Standard</strong></p>

+						<p>

+							Logs messages to a console window in the page. The console is identical

+							to that used by the <code><a href="#popupappender">PopUpAppender</a></code>, except

+							for the absence of a 'Close' button.

+						</p>

+						<p><strong>Notes</strong></p>

+						<ul>

+							<li>

+								Prior to log4javascript 1.3, InPageAppender was known as InlineAppender.

+								For the sake of backwards compatibility, InlineAppender is still included in

+								1.3 and later as an alias for InPageAppender.

+							</li>

+							<li>

+								<p>

+									The default layout for this appender is <code><a href="#patternlayout">PatternLayout</a></code>

+									with pattern string

+								</p>

+								<p>

+									<code>%d{HH:mm:ss} %-5p - %m{1}%n</code>

+								</p>

+							</li>

+						</ul>

+						<h4>Constructor</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">InPageAppender</div>

+								<div class="methodsignature">

+									<code><strong>InPageAppender</strong>(HTMLElement <em>container</em>[,

+									Boolean <em>lazyInit</em>, Boolean <em>initiallyMinimized</em>,

+									Boolean <em>useDocumentWrite</em>, String <em>width</em>, String <em>height</em>])</code>

+								</div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">container</code>

+										<div>

+											The container element for the console window. This should be an HTML element.

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">lazyInit</code>

+										[<em>optional</em>]

+										<div>

+											Set this to <code>true</code> to create the console only when the first log

+											message reaches the appender. Otherwise, the console is initialized as soon as the

+											appender is created. If not specified, defaults to <code>true</code>.

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">initiallyMinimized</code>

+										[<em>optional</em>]

+										<div>

+											<p>

+												Whether the console window should start off hidden / minimized.

+												If not specified, defaults to <code>false</code>.

+											</p>

+											<p><strong>Notes</strong></p>

+											<ul>

+												<li>

+													In Safari (and possibly other browsers) hiding an <code>iframe</code>

+													resets its document, thus destroying the console window.

+												</li>

+											</ul>

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">useDocumentWrite</code>

+										[<em>optional</em>]

+										<div>

+											<p>

+												Specifies how the console window is created. By default, the console window is

+												created dynamically using <code>document</code>'s <code>write</code> method. This has the

+												advantage of keeping all the code in one single JavaScript file. However, if your

+												page sets <code>document.domain</code> then the browser prevents script access to

+												a window unless it too has the same value set for <code>document.domain</code>. To

+												get round this issue, you can set <code>useDocumentWrite</code> to <code>false</code>

+												and log4javascript will instead use the external HTML file <code>console.html</code>

+												(or <code>console_uncompressed.html</code> if you're using an uncompressed version of

+												log4javascript.js), which must be placed in the same directory as your log4javascript.js file.

+											</p>

+											<p>

+												In general it's simpler to use the <code>document.write</code> method, so unless your

+												page needs to set <code>document.domain</code>, <code>useDocumentWrite</code> should

+												be set to <code>true</code>.

+											</p>

+											<p>

+												If not specified, defaults to <code>true</code>.

+											</p>

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">width</code>

+										[<em>optional</em>]

+										<div>

+											The width of the console window. Any valid CSS length may be used. If not

+											specified, defaults to <code>100%</code>.

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">height</code>

+										[<em>optional</em>]

+										<div>

+											The height of the console window. Any valid CSS length may be used. If not

+											specified, defaults to <code>250px</code>.

+										</div>

+									</li>

+								</ul>

+							</li>

+						</ul>

+						<h4>Methods</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">addCssProperty</div>

+								<div class="methodsignature"><code>void <strong>addCssProperty</strong>(String <em>name</em>, String <em>value</em>)</code></div>

+								<div class="summary">

+									Sets a CSS style property on the HTML element containing the console iframe.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isVisible</div>

+								<div class="methodsignature"><code>Boolean <strong>isVisible</strong>()</code></div>

+								<div class="summary">

+									Returns whether the console window is currently visible.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isInitiallyMinimized</div>

+								<div class="methodsignature"><code>Boolean <strong>isInitiallyMinimized</strong>()</code></div>

+								<div class="summary">

+									Returns whether the console window starts off hidden / minimized.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setInitiallyMinimized</div>

+								<div class="methodsignature"><code>void <strong>setInitiallyMinimized</strong>(Boolean <em>initiallyMinimized</em>)</code></div>

+								<div class="summary">

+									[<em>not available after initialization</em>]

+									<br />

+									Sets whether the console window should start off hidden / minimized.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isNewestMessageAtTop</div>

+								<div class="methodsignature"><code>Boolean <strong>isNewestMessageAtTop</strong>()</code></div>

+								<div class="summary">

+									Returns whether new log messages are displayed at the top of the console window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setNewestMessageAtTop</div>

+								<div class="methodsignature"><code>void <strong>setNewestMessageAtTop</strong>(Boolean <em>newestMessageAtTop</em>)</code></div>

+								<div class="summary">

+									Sets whether to display new log messages at the top inside the console window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isScrollToLatestMessage</div>

+								<div class="methodsignature"><code>Boolean <strong>isScrollToLatestMessage</strong>()</code></div>

+								<div class="summary">

+									Returns whether the pop-up window scrolls to display the latest log message when a new message

+									is logged.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setScrollToLatestMessage</div>

+								<div class="methodsignature"><code>void <strong>setScrollToLatestMessage</strong>(Boolean <em>scrollToLatestMessage</em>)</code></div>

+								<div class="summary">

+									Sets whether to scroll the console window to display the latest log message when a new message

+									is logged.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getWidth</div>

+								<div class="methodsignature"><code>String <strong>getWidth</strong>()</code></div>

+								<div class="summary">

+									Returns the outer width of the console window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setWidth</div>

+								<div class="methodsignature"><code>void <strong>setWidth</strong>(String <em>width</em>)</code></div>

+								<div class="summary">

+									[<em>not available after initialization</em>]

+									<br />

+									Sets the outer width of the console window. Any valid CSS length may be used.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getHeight</div>

+								<div class="methodsignature"><code>String <strong>getHeight</strong>()</code></div>

+								<div class="summary">

+									Returns the outer height of the console window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setHeight</div>

+								<div class="methodsignature"><code>void <strong>setHeight</strong>(String <em>height</em>)</code></div>

+								<div class="summary">

+									[<em>not available after initialization</em>]

+									<br />

+									Sets the outer height of the console window. Any valid CSS length may be used.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getMaxMessages</div>

+								<div class="methodsignature"><code>Number <strong>getMaxMessages</strong>()</code></div>

+								<div class="summary">

+									Returns the largest number of messages displayed and stored by the console window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setMaxMessages</div>

+								<div class="methodsignature"><code>void <strong>setMaxMessages</strong>(Number <em>maxMessages</em>)</code></div>

+								<div class="summary">

+									[<em>not available after initialization</em>]

+									<br />

+									Sets the largest number of messages displayed and stored by the console window. Set

+									this to <code>null</code> to make this number unlimited.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isShowCommandLine</div>

+								<div class="methodsignature"><code>Boolean <strong>isShowCommandLine</strong>()</code></div>

+								<div class="summary">

+									Returns whether the console includes a command line.

+									Default value is <code>true</code>.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setShowCommandLine</div>

+								<div class="methodsignature"><code>void <strong>setShowCommandLine</strong>(Boolean <em>showCommandLine</em>)</code></div>

+								<div class="summary">

+									Sets whether the console includes a command line.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getCommandLineObjectExpansionDepth</div>

+								<div class="methodsignature"><code>Number <strong>getCommandLineObjectExpansionDepth</strong>()</code></div>

+								<div class="summary">

+									Returns the number of levels to expand when an object value is logged to the console.

+									Each property of an object above this threshold will be expanded if it is itself an object

+									or array, otherwise its string representation will be displayed. Default value is 1 (i.e.

+									the properties of the object logged will be displayed in their string representation but

+									not expanded).

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setCommandLineObjectExpansionDepth:</div>

+								<div class="methodsignature"><code>void <strong>setCommandLineObjectExpansionDepth</strong>(Number <em>expansionDepth</em>)</code></div>

+								<div class="summary">

+									Sets the number of levels to expand when an object value is logged to the console.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getCommandWindow</div>

+								<div class="methodsignature"><code>Window <strong>getCommandWindow</strong>()</code></div>

+								<div class="summary">

+									Returns a reference to the window in which commands typed into the command line

+									are currently being executed.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setCommandWindow</div>

+								<div class="methodsignature"><code>void <strong>setCommandWindow</strong>(Window <em>commandWindow</em>)</code></div>

+								<div class="summary">

+									Sets the window in which commands typed into the command line are executed.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getCommandLayout</div>

+								<div class="methodsignature"><code>Number <strong>getCommandLayout</strong>()</code></div>

+								<div class="summary">

+									Returns the layout used to format the output for commands typed into the command line.

+									The default value is a <code><a href="#patternlayout">PatternLayout</a></code> with

+									pattern string <code>%m</code>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setCommandLayout</div>

+								<div class="methodsignature"><code>void <strong>setCommandLayout</strong>(Layout <em>commandLayout</em>)</code></div>

+								<div class="summary">

+									Sets the layout used to format the output for commands typed into the command line.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">clear</div>

+								<div class="methodsignature"><code>void <strong>clear</strong>()</code></div>

+								<div class="summary">

+									Clears all messages from the console window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">show</div>

+								<div class="methodsignature"><code>void <strong>show</strong>()</code></div>

+								<div class="summary">

+									<p>

+										Shows / unhides the console window.

+									</p>

+									<p><strong>Notes</strong></p>

+									<ul>

+										<li>

+											In Safari (and possibly other browsers), hiding an <code>iframe</code>

+											resets its document, thus destroying the console window.

+										</li>

+									</ul>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">hide</div>

+								<div class="methodsignature"><code>void <strong>hide</strong>()</code></div>

+								<div class="summary">

+									<p>

+										Hides / minimizes the console window.

+									</p>

+									<p><strong>Notes</strong></p>

+									<ul>

+										<li>

+											In Safari (and possibly other browsers), hiding an <code>iframe</code>

+											resets its document, thus destroying the console window.

+										</li>

+									</ul>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">close</div>

+								<div class="methodsignature"><code>void <strong>close</strong>()</code></div>

+								<div class="summary">

+									Removes the console window iframe from the main document.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">focus</div>

+								<div class="methodsignature"><code>void <strong>focus</strong>()</code></div>

+								<div class="summary">

+									Brings the console window to the top and gives it the focus.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">focusCommandLine</div>

+								<div class="methodsignature"><code>void <strong>focusCommandLine</strong>()</code></div>

+								<div class="summary">

+									Brings the console window to the top and gives the focus to the command line.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">focusSearch</div>

+								<div class="methodsignature"><code>void <strong>focusSearch</strong>()</code></div>

+								<div class="summary">

+									Brings the console window to the top and gives the focus to the search box.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">evalCommandAndAppend</div>

+								<div class="methodsignature"><code>void <strong>evalCommandAndAppend</strong>(String <em>expr</em>)</code></div>

+								<div class="summary">

+									Evaluates the expression and appends the result to the console.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">addCommandLineFunction</div>

+								<div class="methodsignature"><code>void <strong>addCommandLineFunction</strong>(String <em>functionName</em>, Function <em>commandLineFunction</em>)</code></div>

+								<div class="summary">

+									<p>

+										Adds a function with the name specified to the list of functions available on the command line.

+										This feature may be used to add custom functions to the command line.

+									</p>

+									<p>

+										When you call the function on the command line, <code>commandLineFunction</code> is executed with the

+										following three parameters:

+									</p>

+									<ul>

+										<li><em>appender</em>. A reference to the appender in which the command was executed;</li>

+										<li><em>args</em>.

+											An array-like list of parameters passed into the function on the command line

+											(actually a reference to an <code>arguments</code> object);</li>

+										<li><em>returnValue</em>. This is an object with two properties that allow the function to control

+											how the result is displayed:

+											<ul>

+												<li><em>appendResult</em>. A boolean value that determines whether the returned value from this

+													function is appended to the console. The default value is <code>true</code>;</li>

+												<li><em>isError</em>. A boolean value that specifies whether the output of this function

+													should be displayed as an error. The default value is <code>false</code>.</li>

+											</ul>

+										</li>

+									</ul>

+									<p>

+										The value returned by the function is formatted by the command layout and appended to the console.

+									</p>

+								</div>

+							</li>

+						</ul>

+						<p class="linktotop">

+							<a href="#container">Top</a>

+						</p>

+					</div>

+					<div id="browserconsoleappender">

+						<h3>BrowserConsoleAppender</h3>

+						<p class="editions">Editions: <strong>Standardl</strong></p>

+						<p>

+							Writes log messages to the browser's built-in console, if present. This only works

+							currently in Safari, Opera and Firefox with the excellent

+							<a href="http://www.getfirebug.com" title="Firebug home page (opens in new window)"

+							target="_blank">Firebug</a> extension installed.

+						</p>

+						<p><strong>Notes</strong></p>

+						<ul>

+							<li>

+								As of log4javascript 1.3, the default threshold for this appender is <code>DEBUG</code>

+								as opposed to <code>WARN</code> as it was previously;

+							</li>

+							<li>

+								<p>

+									As of version 1.3, log4javascript has explicit support for Firebug's logging. This includes

+									the following mapping of log4javascript's log levels onto Firebug's:

+								</p>

+								<ul>

+									<li>log4javascript <code>TRACE</code>, <code>DEBUG</code> -&gt; Firebug <code>debug</code></li>

+									<li>log4javascript <code>INFO</code> -&gt; Firebug <code>info</code></li>

+									<li>log4javascript <code>WARN</code> -&gt; Firebug <code>warn</code></li>

+									<li>log4javascript <code>ERROR</code>, <code>FATAL</code> -&gt; Firebug <code>error</code></li>

+								</ul>

+								<p>

+									... and the ability to pass objects into Firebug and take advantage of its object inspection.

+									This is because the default layout is now <code><a href="#nulllayout">NullLayout</a></code>,

+									which performs no formatting on an object.

+								</p>

+							</li>

+						</ul>

+						<h4>Constructor</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">BrowserConsoleAppender</div>

+								<div class="methodsignature"><code><strong>BrowserConsoleAppender</strong>()</code></div>

+							</li>

+						</ul>

+						<p class="linktotop">

+							<a href="#container">Top</a>

+						</p>

+					</div>

+				</div>

+				<div id="layouts">

+					<h2>Layouts</h2>

+					<div id="layout">

+						<h3>Layout</h3>

+						<p>

+							There are a few methods common to all layouts:

+						</p>

+						<h4>Methods</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">format</div>

+								<div class="methodsignature"><code>String <strong>format</strong>(LoggingEvent <em>loggingEvent</em>)</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">loggingEvent</code>

+									</li>

+								</ul>

+								<div class="summary">

+									Formats the log message. You should override this method in your own layouts.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">ignoresThrowable</div>

+								<div class="methodsignature"><code>Boolean <strong>ignoresThrowable</strong>()</code></div>

+								<div class="summary">

+									Returns whether the layout ignores an error object in a logging event passed

+									to its <code>format</code> method.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getContentType</div>

+								<div class="methodsignature"><code>String <strong>getContentType</strong>()</code></div>

+								<div class="summary">

+									Returns the content type of the output of the layout.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">allowBatching</div>

+								<div class="methodsignature"><code>Boolean <strong>allowBatching</strong>()</code></div>

+								<div class="summary">

+									Returns whether the layout's output is suitable for batching.

+									<code><a href="#jsonlayout">JsonLayout</a></code> and <code><a href="#xmllayout">XmlLayout</a></code>

+									are the only built-in layouts that return true for this method.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getDataValues</div>

+								<div class="methodsignature"><code>Array <strong>getDataValues</strong>(LoggingEvent <em>loggingEvent</em>)</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">loggingEvent</code>

+									</li>

+								</ul>

+								<div class="summary">

+									Used internally by log4javascript in constructing formatted output for some layouts.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setKeys</div>

+								<div class="methodsignature"><code>void <strong>setKeys</strong>(String <em>loggerKey</em>,

+									String <em>timeStampKey</em>, String <em>levelKey</em>, String <em>messageKey</em>,

+									String <em>exceptionKey</em>, String <em>urlKey</em>)</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">loggerKey</code>

+										<div>

+											Parameter to use for the log message's logger name. Default is <code>logger</code>.

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">timeStampKey</code>

+										<div>

+											Parameter to use for the log message's timestamp.  Default is <code>timestamp</code>.

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">levelKey</code>

+										<div>

+											Parameter to use for the log message's level. Default is <code>level</code>.

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">messageKey</code>

+										<div>

+											Parameter to use for the message itself. Default is <code>message</code>.

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">exceptionKey</code>

+										<div>

+											Parameter to use for the log message's error (exception). Default is <code>exception</code>.

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">urlKey</code>

+										<div>

+											Parameter to use for the current page URL. Default is <code>url</code>.

+										</div>

+									</li>

+								</ul>

+								<div class="summary">

+									This method is used to change the default keys used to create formatted name-value pairs

+									for the properties of a log message, for layouts that do this. These layouts are

+									<code><a href="#jsonlayout">JsonLayout</a></code> and

+									<code><a href="#httppostdatalayout">HttpPostDataLayout</a></code>.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setCustomField</div>

+								<div class="methodsignature"><code>void <strong>setCustomField</strong>(String <em>name</em>,

+									String <em>value</em>)</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">name</code>

+										<div>

+											Name of the custom property you wish to be included in the formmtted output.

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">value</code>

+										<div>

+											Value of the custom property you wish to be included in the formatted output.

+										</div>

+									</li>

+								</ul>

+								<div class="summary">

+									Some layouts (<code><a href="#jsonlayout">JsonLayout</a></code>,

+									<code><a href="#httppostdatalayout">HttpPostDataLayout</a></code>,

+									<code><a href="#patternlayout">PatternLayout</a></code> and

+									<code><a href="#xmllayout">XmlLayout</a></code>) allow you to set

+									custom fields (e.g. a session id to send to the server) to the

+									formatted output. Use this method to set a custom field. If there

+									is already a custom field with the specified name, its value will

+									be updated with <code>value</code>.

+								</div>

+								<p><strong>Notes</strong></p>

+								<ul>

+									<li>

+										<p>

+											From version 1.4, the custom field value may be a function. In this

+											case, the function is run at the time the layout's format method is called,

+											with the following two parameters:

+										</p>

+										<ul>

+											<li><em>layout</em>. A reference to the layout being used;</li>

+											<li><em>loggingEvent</em>. A reference to the logging event being formatted.</li>

+										</ul>

+									</li>

+								</ul>

+							</li>

+							<li class="method">

+								<div class="name">hasCustomFields</div>

+								<div class="methodsignature"><code>Boolean <strong>hasCustomFields</strong>()</code></div>

+								<div class="summary">

+									Returns whether the layout has any custom fields.

+								</div>

+							</li>

+						</ul>

+						<p class="linktotop">

+							<a href="#container">Top</a>

+						</p>

+					</div>

+					<div id="nulllayout">

+						<h3>NullLayout</h3>

+						<p class="editions">Editions: <strong>All</strong></p>

+						<p>

+							The most basic layout. NullLayout's <code>format()</code> methods performs no

+							formatting at all and simply returns the message logged.

+						</p>

+						<h4>Constructor</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">NullLayout</div>

+								<div class="methodsignature"><code><strong>NullLayout</strong>()</code></div>

+							</li>

+						</ul>

+						<p class="linktotop">

+							<a href="#container">Top</a>

+						</p>

+					</div>

+					<div id="simplelayout">

+						<h3>SimpleLayout</h3>

+						<p class="editions">Editions: <strong>Standard, Production</strong></p>

+						<p>

+							Provides basic formatting. SimpleLayout consists of the level of the log statement,

+							followed by " - " and then the log message itself. For example,

+						</p>

+						<p><code>DEBUG - Hello world</code></p>

+						<h4>Constructor</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">SimpleLayout</div>

+								<div class="methodsignature"><code><strong>SimpleLayout</strong>()</code></div>

+							</li>

+						</ul>

+						<p class="linktotop">

+							<a href="#container">Top</a>

+						</p>

+					</div>

+					<div id="patternlayout">

+						<h3>PatternLayout</h3>

+						<p class="editions">Editions: <strong>All</strong></p>

+						<p>

+							Provides a flexible way of formatting a log message by means of a conversion pattern

+							string. The behaviour of this layout is a full implementation of <code>PatternLayout</code>

+							in log4j, with the exception of the set of conversion characters - log4javascript's is

+							necessarily a subset of that of log4j with a few additions of its own, since many of

+							the conversion characters in log4j only make sense in the context of Java.

+						</p>

+						<p>

+							The conversion pattern consists of literal text interspersed with special strings starting with

+							a % symbol called <em>conversion specifiers</em>. A conversion specifier consists of the

+							% symbol, a conversion character (possible characters are listed below) and

+							<em>format modifiers</em>. For full documentation of the conversion pattern, see

+							<a href="http://logging.apache.org/log4j/docs/api/org/apache/log4j/PatternLayout.html" target="_blank">log4j's

+							documentation</a>. Below is a list of all conversion characters available in log4javascript.

+						</p>

+						<h4>Conversion characters</h4>

+						<table border="1" cellspacing="0">

+							<thead>

+								<tr>

+									<th>Conversion Character</th>

+									<th>Effect</th>

+								</tr>

+							</thead>

+							<tbody>

+								<tr>

+									<td>a</td>

+									<td>

+										<p>

+											Outputs log messages specified as an array.

+										</p>

+										<p>

+											Behaves exactly like <code>%m</code>, except that multiple log messages are

+											assumed to have been specified in the logging call as an array rather than

+											as multiple parameters.

+										</p>

+										<p>

+											<strong>Since: 1.4</strong>

+										</p>

+									</td>

+								</tr>

+								<tr>

+									<td>c</td>

+									<td>

+										<p>

+											Outputs the logger name.

+										</p>

+									</td>

+								</tr>

+								<tr>

+									<td>d</td>

+									<td>

+										<p>

+											Outputs the date of the logging event. The date conversion specifier

+											may be followed by a date format specifier enclosed between braces. For

+											example, <code>%d{HH:mm:ss,SSS}</code> or

+											<code>%d{dd MMM yyyy HH:mm:ss,SSS}</code>. If no date

+											format specifier is given then ISO8601 format is assumed.

+										</p>

+										<p>

+											The date format specifier is the same as that used by Java's

+											<code><a href="http://java.sun.com/j2se/1.5.0/docs/api/java/text/SimpleDateFormat.html"

+												target="_blank">SimpleDateFormat</a></code>. log4javascript

+											includes a full implementation of SimpleDateFormat's

+											<code>format</code> method, with the exception of the pattern letter

+											'z', (string representation of the timezone) for which the information

+											is not available in JavaScript.

+										</p>

+									</td>

+								</tr>

+								<tr>

+									<td>f</td>

+									<td>

+										<p>

+											Outputs the value of a custom field set on the layout. If present, the specifier gives

+											the index in the array of custom fields to use; otherwise, the first custom field in the

+											array is used.

+										</p>

+										<p>

+											<strong>Since: 1.3</strong>

+										</p>

+									</td>

+								</tr>

+								<tr>

+									<td>m</td>

+									<td>

+										<p>

+											Outputs the log messages of the logging event (i.e. the log

+											messages supplied by the client code).

+										</p>

+										<p>

+											As of version 1.4, multiple log messages may be supplied to logging calls.

+											<code>%m</code> displays each log message (using the rules below) one after

+											another, separated by spaces. 

+										</p>

+										<p>

+											As of version 1.3, an object may be specified as the log message and will

+											be expanded to show its properties in the output, provided that a specifier

+											containing the number of levels to expand is provided. If no specifier is

+											provided then the message will be treated as a string regardless of its type.

+											For example, <code>%m{1}</code> will display an expansion of the object one

+											level deep, i.e. each property of the object will be displayed but if the

+											property value is itself an object it will not be expanded and will appear

+											as <code>[object Object]</code>.

+										</p>

+									</td>

+								</tr>

+								<tr>

+									<td>n</td>

+									<td>

+										<p>

+											Outputs a line separator.

+										</p>

+									</td>

+								</tr>

+								<tr>

+									<td>p</td>

+									<td>

+										<p>

+											Outputs the level of the logging event.

+										</p>

+									</td>

+								</tr>

+								<tr>

+									<td>r</td>

+									<td>

+										<p>

+											Outputs the number of milliseconds since log4javascript was initialized.

+										</p>

+									</td>

+								</tr>

+								<tr>

+									<td>%</td>

+									<td>

+										<p>

+											The sequence %% outputs a single percent sign.

+										</p>

+									</td>

+								</tr>

+							</tbody>

+						</table>

+						<h4>Static properties</h4>

+						<ul class="propertieslist">

+							<li class="property">

+								<div class="name">TTCC_CONVERSION_PATTERN</div>

+								<div class="summary">

+									Built-in conversion pattern, equivalent to <code>%r %p %c - %m%n</code>.

+								</div>

+							</li>

+							<li class="property">

+								<div class="name">DEFAULT_CONVERSION_PATTERN</div>

+								<div class="summary">

+									Built-in conversion pattern, equivalent to <code>%m%n</code>.

+								</div>

+							</li>

+							<li class="property">

+								<div class="name">ISO8601_DATEFORMAT</div>

+								<div class="summary">

+									Built-in date format (and also the default), equivalent to

+									<code>yyyy-MM-dd HH:mm:ss,SSS</code>.

+								</div>

+							</li>

+							<li class="property">

+								<div class="name">DATETIME_DATEFORMAT</div>

+								<div class="summary">

+									Built-in date format, equivalent to <code>dd MMM YYYY HH:mm:ss,SSS</code>.

+								</div>

+							</li>

+							<li class="property">

+								<div class="name">ABSOLUTETIME_DATEFORMAT</div>

+								<div class="summary">

+									Built-in date format, equivalent to <code>HH:mm:ss,SSS</code>.

+								</div>

+							</li>

+						</ul>

+						<h4>Constructor</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">PatternLayout</div>

+								<div class="methodsignature"><code><strong>PatternLayout</strong>(String <em>pattern</em>)</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">pattern</code>

+										<div>

+											The conversion pattern string to use.

+										</div>

+									</li>

+								</ul>

+							</li>

+						</ul>

+						<p class="linktotop">

+							<a href="#container">Top</a>

+						</p>

+					</div>

+					<div id="xmllayout">

+						<h3>XmlLayout</h3>

+						<p class="editions">Editions: <strong>Standard, Production</strong></p>

+						<p>

+							Based on log4j's <code>XmlLayout</code>, this layout formats a log message as a

+							fragment of XML. An example of the format of the fragment is as follows:

+						</p>

+						<pre>

+&lt;log4javascript:event logger="[default]" timestamp="1201048234203" level="ERROR"&gt;

+&lt;log4javascript:message&gt;&lt;![CDATA[Big problem!]]&gt;&lt;/log4javascript:message&gt;

+&lt;log4javascript:exception&gt;&lt;![CDATA[Nasty error on line number 1

+	in file http://log4javascript.org/test.html]]&gt;&lt;/log4javascript:exception&gt;

+&lt;/log4javascript:event&gt;

+</pre>

+						<p><strong>Notes</strong></p>

+						<ul>

+							<li>

+								This layout supports batching of log messages when used in an

+								<code><a href="#ajaxappender">AjaxAppender</a></code>. A batch of

+								messages is simply concatenated to form a string of several XML

+								frgaments similar to that above.

+							</li>

+							<li>

+								The <code>&lt;log4javascript:exception&gt;</code> element is only present if an

+								exception was passed into the original log call.

+							</li>

+							<li>

+								As of version 1.4, timestamps are returned as milliseconds since midnight of

+								January 1, 1970 rather than seconds as in previous versions. This allows finer

+								measurement of the time a logging event occurred and is also the JavaScript

+								<code>Date</code> object's standard measurement.

+							</li>

+							<li>

+								Also as of version 1.4, multiple messages may be specified as separate parameters

+								in a single logging call. In <code>XmlLayout</code>, multiple messages may be

+								formatted as a single combined message or may be formated as several

+								<code>&lt;log4javascript:message&gt;</code> elements inside one

+								<code>&lt;log4javascript:messages&gt;</code> element as shown below:

+								<br />

+								<pre>

+&lt;log4javascript:event logger="[default]" timestamp="1201048234203" level="ERROR"&gt;

+&lt;log4javascript:messages&gt;

+	&lt;log4javascript:message&gt;&lt;![CDATA[Big problem!]]&gt;&lt;/log4javascript:message&gt;

+	&lt;log4javascript:message&gt;&lt;![CDATA[Value of x when this error

+		occurred: 3]]&gt;&lt;/log4javascript:message&gt;

+&lt;/log4javascript:messages&gt;

+&lt;log4javascript:exception&gt;&lt;![CDATA[Nasty error on line number 1

+	in file http://log4javascript.org/test.html]]&gt;&lt;/log4javascript:exception&gt;

+&lt;/log4javascript:event&gt;

+</pre>

+							</li>

+							<li>

+								As of version 1.3, custom fields may be added to the output. Each field will

+								add a tag of the following form inside the <code>&lt;log4javascript:event&gt;</code>

+								tag:

+								<br />

+								<pre>

+&lt;log4javascript:customfield name="sessionid"&gt;&lt;![CDATA[1234]]&gt;&lt;/log4javascript:customfield&gt;

+</pre>

+							</li>

+						</ul>

+						<h4>Constructor</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">XmlLayout</div>

+								<div class="methodsignature"><code><strong>XmlLayout</strong>([Boolean <em>combineMessages</em>])</code></div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">combineMessages</code>

+										<div>

+											Whether or not to format multiple log messages as a combined single

+											<code>&lt;log4javascript:message&gt;</code> element

+											composed of each individual message separated by line breaks or to include

+											a <code>&lt;log4javascript:message&gt;</code> element for each message inside

+											one <code>&lt;log4javascript:messages&gt;</code> element.

+											If not specified, defaults to <code>true</code>.

+										</div>

+									</li>

+								</ul>

+							</li>

+						</ul>

+						<p class="linktotop">

+							<a href="#container">Top</a>

+						</p>

+					</div>

+					<div id="jsonlayout">

+						<h3>JsonLayout</h3>

+						<p class="editions">Editions: <strong>Standard, Production</strong></p>

+						<p>

+							Formats a logging event into JavaScript Object Notation (JSON).

+							JSON is a subset of JavaScript's object literal syntax, meaning that log

+							messages formatted with this layout can be interpreted directly by JavaScript

+							and converted into objects. See

+							<a href="http://json.org/" target="_blank" title="json.org (opens in new window)">json.org</a> for more details

+							about JSON.

+						</p>

+						<p>Example:</p>

+						<pre>

+{

+	"logger": "[default]",

+	"timeStamp": 1201048234203,

+	"level": "ERROR",

+	"url": "http://log4javascript.org/test.html",

+	"message": "Big problem!",

+	"exception": "Nasty error on line number 1 in file

+		http://log4javascript.org/test.html"

+}

+</pre>

+						<p>

+							The <code>exception</code> property is only present if an exception was passed

+							into the original log call.

+						</p>

+						<p><strong>Notes</strong></p>

+						<ul>

+							<li>

+								This layout supports batching of log messages when used in an

+								<code><a href="#ajaxappender">AjaxAppender</a></code>. When sent singly

+								the layout formats the log message as a single JavaScript object literal;

+								when sent as a batch, the messages are formatted as an array literal whose

+								elements are log message objects.

+							</li>

+							<li>

+								<p>

+									As of version 1.3, custom fields may be added to the output. Each field will

+									add a property of the following form to the main object literal:

+								</p>

+								<pre>

+	"sessionid": 1234

+</pre>

+							</li>

+							<li>

+								From version 1.4, the variable names used for log event properties such as

+								the message, timestamp and exception are specified using the <code>setKeys()</code>

+								method of <code><a href="#layout">Layout</a></code>.

+							</li>

+							<li>

+								<p>

+									Also as of version 1.4, multiple messages may be specified as separate parameters

+									in a single logging call. In <code>JsonLayout</code>, multiple messages may be

+									formatted as a single combined message or may be formated as an array of messages

+									as shown below:

+								</p>

+								<pre>

+{

+	"logger": "[default]",

+	"timeStamp": 1201048234203,

+	"level": "ERROR",

+	"url": "http://log4javascript.org/test.html",

+	"message": [

+		"Big problem!",

+		"Value of x when this error occurred: 3"

+	],

+	"exception": "Nasty error on line number 1 in file

+		http://log4javascript.org/test.html"

+}

+</pre>

+							</li>

+						</ul>

+						<h4>Constructor</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">JsonLayout</div>

+								<div class="methodsignature"><code><strong>JsonLayout</strong>([Boolean <em>readable</em>, Boolean <em>combineMessages</em>])</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">readable</code>

+										<div>

+											Whether or not to format each log message with line breaks and tabs.

+											If not specified, defaults to <code>false</code>.

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">combineMessages</code>

+										<div>

+											Whether or not to format multiple log messages as a combined single

+											<code>message</code> property composed of each individual message separated by line

+											breaks or to format multiple messages as an array.

+											If not specified, defaults to <code>true</code>.

+										</div>

+									</li>

+								</ul>

+							</li>

+						</ul>

+						<h4>Methods</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">isReadable</div>

+								<div class="methodsignature"><code>Boolean <strong>isReadable</strong>()</code></div>

+								<div class="summary">

+									Returns whether or not to each log message is formatted with line breaks and tabs.

+								</div>

+								<p><strong>Notes</strong></p>

+								<ul>

+									<li>

+										<p>

+											<code>setReadable</code> has been removed in version 1.4. This property can

+											be set via the constructor.

+										</p>

+									</li>

+								</ul>

+							</li>

+						</ul>

+					</div>

+					<div id="httppostdatalayout">

+						<h3>HttpPostDataLayout</h3>

+						<p class="editions">Editions: <strong>Standard, Production</strong></p>

+						<p>

+							Formats the log message as a simple URL-encoded string from which a simple

+							server-side script may extract parameters such as the log message, severity

+							and timestamp. This is the default layout for

+							<code><a href="#ajaxappender">AjaxAppender</a></code>.

+						</p>

+						<h4>Constructor</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">HttpPostDataLayout</div>

+								<div class="methodsignature"><code><strong>HttpPostDataLayout</strong>()</code></div>

+							</li>

+						</ul>

+						<p><strong>Notes</strong></p>

+						<ul>

+							<li>

+								As of version 1.3, custom fields may be added to the output. Each field will

+								be added as a parameter to the post data.

+							</li>

+							<li>

+								From version 1.4, the variable names used for log event properties such as

+								the message, timestamp and exception are specified using the <code>setKeys()</code>

+								method of <code><a href="#layout">Layout</a></code>.

+							</li>

+						</ul>

+						<p class="linktotop">

+							<a href="#container">Top</a>

+						</p>

+					</div>

+				</div>

+				<div id="enabling">

+					<h2>Enabling / disabling log4javascript</h2>

+					<p>

+						All logging can be enabled or disabled in log4javascript in a number of ways:

+					</p>

+					<ul>

+						<li>

+							At any time, you can call

+							<code>log4javascript.setEnabled(<em>enabled</em>)</code>. This will

+							enable or disable all logging, depending on whether <code>enabled</code>

+							is set to <code>true</code> or <code>false</code>.

+						</li>

+						<li>

+							<p>

+								Assign a value to the global variable <code>log4javascript_disabled</code>.

+								The idea of this is so that you can enable or disable logging for a whole site by

+								including a JavaScript file in all your pages, and allowing this file to be

+								included <strong>before</strong> log4javascript.js to guarantee that no logging

+								can take place without having to alter log4javascript.js itself. Your included

+								.js file would include a single line such as the following:

+							</p>

+							<p>

+								<code>var log4javascript_disabled = true;</code>

+							</p>

+						</li>

+						<li>

+							Assign your logger object a value of <code>log4javascript.getNullLogger()</code>.

+						</li>

+						<li>

+							Replace your copy of log4javascript_x.js with stubs/log4javascript_x.js, provided in the

+							distribution. This file has a stub version of each of the functions and methods

+							in the log4javascript API and can simply be dropped in in place of the main file.

+							The compressed version of the stub is typically 15 times smaller than the

+							compressed version of the main file.

+						</li>

+					</ul>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="errorhandling">

+					<h2>log4javascript error handling</h2>

+					<p>

+						log4javascript has a single rudimentary logger-like object of its own to handle

+						messages generated by log4javascript itself. This logger is called <code>LogLog</code>

+						and is accessed via <code>log4javascript.logLog</code>.

+					</p>

+					<div id="loglog">

+						<h4>Methods</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">setQuietMode</div>

+								<div class="methodsignature"><code>void <strong>setQuietMode</strong>(Boolean <em>quietMode</em>)</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">quietMode</code>

+										<div>

+											Whether to turn quiet mode on or off.

+										</div>

+									</li>

+								</ul>

+								<div class="summary">

+									Sets whether <code>LogLog</code> is in quiet mode or not. In quiet mode, no

+									messages sent to <code>LogLog</code> have any visible effect. By default,

+									quiet mode is switched off.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setAlertAllErrors</div>

+								<div class="methodsignature"><code>void <strong>setAlertAllErrors</strong>(Boolean <em>alertAllErrors</em>)</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">showAllErrors</code>

+										<div>

+											Whether to show all errors or just the first.

+										</div>

+									</li>

+								</ul>

+								<div class="summary">

+									Sets how many errors <code>LogLog</code> will display alerts for. By default,

+									only the first error encountered generates an alert to the user. If you turn

+									all errors on by supplying <code>true</code> to this method then all errors

+									will generate alerts.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">debug</div>

+								<div class="methodsignature"><code>void <strong>debug</strong>(String <em>message</em>[, Error <em>exception</em>])</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">message</code>

+									</li>

+									<li class="param">

+										<code class="paramname">exception</code>

+										[<em>optional</em>]

+									</li>

+								</ul>

+								<div class="summary">

+									Logs a debugging message to an in-memory list. This implementation is new in version 1.4.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">displayDebug</div>

+								<div class="methodsignature"><code>void <strong>displayDebug</strong>()</code></div>

+								<div class="summary">

+									Displays an alert of all debugging messages. This method is new in version 1.4.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">warn</div>

+								<div class="methodsignature"><code>void <strong>warn</strong>(String <em>message</em>[, Error <em>exception</em>])</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">message</code>

+									</li>

+									<li class="param">

+										<code class="paramname">exception</code>

+										[<em>optional</em>]

+									</li>

+								</ul>

+								<div class="summary">

+									Currently has no effect.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">error</div>

+								<div class="methodsignature"><code>void <strong>error</strong>(String <em>message</em>[, Error <em>exception</em>])</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">message</code>

+									</li>

+									<li class="param">

+										<code class="paramname">exception</code>

+										[<em>optional</em>]

+									</li>

+								</ul>

+								<div class="summary">

+									Generates an alert to the user if and only if the error is the first one

+									encountered and <code>setAlertAllErrors(true)</code> has not been called.

+								</div>

+							</li>

+						</ul>

+						<p class="linktotop">

+							<a href="#container">Top</a>

+						</p>

+					</div>

+				</div>

+				<div id="differences">

+					<h2>Differences between log4javascript and log4j</h2>

+					<p>

+						For the sake of keeping log4javascript as light and useful as possible, many

+						of the features of log4j that seem over-complex or inappropriate for

+						JavaScript have not been implemented. These include:

+					</p>

+					<ul>

+						<li>Filters</li>

+						<li>Configurators</li>

+						<li>Renderers</li>

+					</ul>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+  				</div>

+			</div>

+			<div id="footer">

+				<span class="externallinkinfo">

+					<strong>NB.</strong> All external links open in a new window.

+				</span>

+				Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>

+				<br />

+				log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"

+					title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,

+					Version 2.0</a>

+

+			</div>

+		</div>

+

+	</body>

+</html>

diff --git a/xos/core/static/log4javascript-1.4.6/docs/manual_lite.html b/xos/core/static/log4javascript-1.4.6/docs/manual_lite.html
new file mode 100644
index 0000000..74e5a7d
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/docs/manual_lite.html
@@ -0,0 +1,383 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript 1.4 Lite manual</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />

+	</head>

+	<body>

+		<div id="container" class="nonav">

+			<div id="header">

+				<h1><a href="index.html">log4javascript</a></h1>

+			</div>

+			<div id="content">

+				<div id="nav">

+					<a class="navitem" href="../index.html">home</a>

+					| <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>

+					| <a class="navitem" href="index.html">docs</a>

+					| <a class="navitem" href="quickstart.html">quick start</a>

+					| <a class="navitem" href="../demos/index.html">demos</a>

+					| <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>

+					| <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>

+				</div>

+				<h1>log4javascript 1.4 Lite manual</h1>

+				<h2>Contents</h2>

+				<ul>

+					<li><a href="#intro">Introduction</a></li>

+					<li><a href="#log4javascript">log4javascript static properties/methods</a></li>

+					<li><a href="#levels">Levels</a></li>

+					<li><a href="#loggers">Loggers</a></li>

+					<li><a href="#enabling">Enabling / disabling log4javascript Lite</a></li>

+				</ul>

+				<div id="intro">

+					<h2>Introduction</h2>

+					<p>

+						log4javascript Lite is designed to be a basic, lightweight, cross-browser logging tool. It

+						provides functions to log messages of different severity to a pop-up window using the exactly

+						the same syntax as log4javascript. It is designed for situations when the key requirement is just

+						to display logging messages without needing all the features of the standard version of

+						log4javascript. 

+					</p>

+					<p>

+						Below is the complete list of functions and properties available in log4javascript Lite.

+						They make up a small subset of those provided by the standard version of

+						log4javascript. Each function is <strong>named and called identically to the equivalent

+						function in log4javascript</strong>. Please refer to the

+						<a href="manual.html">log4javascript manual</a> for a detailed explanation

+						of all the concepts alluded to in this document.

+					</p>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="log4javascript">

+					<h2>log4javascript static properties/methods</h2>

+					<h4>Properties</h4>

+					<ul class="propertieslist">

+						<li class="property">

+							<div class="name">version</div>

+							<div class="summary">

+								The version number of your copy of log4javascript.

+							</div>

+						</li>

+						<li class="property">

+							<div class="name">edition</div>

+							<div class="summary">

+								The edition of your copy of log4javascript ("log4javascript_lite" in this case").

+							</div>

+						</li>

+					</ul>

+					<h4>Methods</h4>

+					<ul class="propertieslist">

+						<li class="method">

+							<div class="name">getDefaultLogger</div>

+							<div class="methodsignature"><code>Logger <strong>getDefaultLogger</strong>()</code></div>

+							<div class="summary">

+								Returns the default and only logger (apart from the null logger). The default logger

+								logs to a simple pop-up window.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">getNullLogger</div>

+							<div class="methodsignature"><code>Logger <strong>getNullLogger</strong>()</code></div>

+							<div class="summary">

+								Returns an empty logger. Useful for disabling all logging.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">setEnabled</div>

+							<div class="methodsignature"><code>void <strong>setEnabled</strong>(Boolean <em>enabled</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">enabled</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Enables or disables all logging, depending on <code>enabled</code>.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns true or false depending on whether logging is enabled.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">setShowStackTraces</div>

+							<div class="methodsignature"><code>void <strong>setShowStackTraces</strong>(Boolean <em>show</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">show</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Enables or disables displaying of error stack traces, depending on <code>show</code>.

+								By default, stack traces are not displayed. (Only works in Firefox)

+							</div>

+						</li>

+					</ul>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="levels">

+					<h2>Levels</h2>

+					<p>

+						Levels are available as static properties of the <code>log4javascript.Level</code>

+						object. In ascending order of severity:

+					</p>

+					<ol>

+						<li><code>log4javascript.Level.ALL</code></li>

+						<li><code>log4javascript.Level.TRACE</code></li>

+						<li><code>log4javascript.Level.DEBUG</code></li>

+						<li><code>log4javascript.Level.INFO</code></li>

+						<li><code>log4javascript.Level.WARN</code></li>

+						<li><code>log4javascript.Level.ERROR</code></li>

+						<li><code>log4javascript.Level.FATAL</code></li>

+						<li><code>log4javascript.Level.NONE</code></li>

+					</ol>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="loggers">

+					<h2>Loggers</h2>

+					<p>

+						There are only two loggers in log4javascript Lite: the default logger obtained

+						by calling <code>log4javascript.getDefaultLogger()</code> and the empty logger

+						returned by <code>log4javascript.getNullLogger()</code>.

+					</p>

+					<h4>Logger methods</h4>

+					<ul class="propertieslist">

+						<li class="method">

+							<div class="name">setLevel</div>

+							<div class="methodsignature"><code>void <strong>setLevel</strong>(Level <em>level</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">level</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Sets the level. Log messages of a lower level than <code>level</code> will not be logged.

+								Default value is <code>ALL</code> (unlike in log4javascript, where the default level is

+								<code>DEBUG</code>).

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">getLevel</div>

+							<div class="methodsignature"><code>Level <strong>getLevel</strong>()</code></div>

+							<div class="summary">

+								Returns the level for this logger.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">trace</div>

+							<div class="methodsignature"><code>void <strong>trace</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">message1[, message2...]</code>

+								</li>

+								<li class="param">

+									<code class="paramname">exception</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Logs one or more messages and optionally an error at level <code>TRACE</code>.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">debug</div>

+							<div class="methodsignature"><code>void <strong>debug</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">message1[, message2...]</code>

+								</li>

+								<li class="param">

+									<code class="paramname">exception</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Logs one or more messages and optionally an error at level <code>DEBUG</code>.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">info</div>

+							<div class="methodsignature"><code>void <strong>info</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">message1[, message2...]</code>

+								</li>

+								<li class="param">

+									<code class="paramname">exception</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Logs one or more messages and optionally an error at level <code>INFO</code>.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">warn</div>

+							<div class="methodsignature"><code>void <strong>warn</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">message1[, message2...]</code>

+								</li>

+								<li class="param">

+									<code class="paramname">exception</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Logs one or more messages and optionally an error at level <code>WARN</code>.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">error</div>

+							<div class="methodsignature"><code>void <strong>error</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">message1[, message2...]</code>

+								</li>

+								<li class="param">

+									<code class="paramname">exception</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Logs one or more messages and optionally an error at level <code>ERROR</code>.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">fatal</div>

+							<div class="methodsignature"><code>void <strong>fatal</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">message1[, message2...]</code>

+								</li>

+								<li class="param">

+									<code class="paramname">exception</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Logs one or more messages and optionally an error at level <code>FATAL</code>.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isEnabledFor</div>

+							<div class="methodsignature"><code>Boolean <strong>isEnabledFor</strong>(Level <em>level</em>, Error <em>exception</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">level</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Returns whether the logger is enabled for the specified level. 

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isTraceEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isTraceEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns whether the logger is enabled for <code>TRACE</code> messages.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isDebugEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isDebugEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns whether the logger is enabled for <code>DEBUG</code> messages.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isInfoEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isInfoEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns whether the logger is enabled for <code>INFO</code> messages.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isWarnEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isWarnEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns whether the logger is enabled for <code>WARN</code> messages.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isErrorEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isErrorEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns whether the logger is enabled for <code>ERROR</code> messages.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isFatalEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isFatalEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns whether the logger is enabled for <code>FATAL</code> messages.

+							</div>

+						</li>

+					</ul>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="enabling">

+					<h2>Enabling / disabling log4javascript Lite</h2>

+					<p>

+						All logging can be enabled or disabled in log4javascript Lite in a number of ways:

+					</p>

+					<ul>

+						<li>

+							At any time, you can call

+							<code>log4javascript.setEnabled(<em>enabled</em>)</code>. This will

+							enable or disable all logging, depending on whether <code>enabled</code>

+							is set to <code>true</code> or <code>false</code>.

+						</li>

+						<li>

+							Assign your logger object a value of <code>log4javascript.getNullLogger()</code>.

+						</li>

+						<li>

+							Replace your copy of log4javascript_lite.js with stubs/log4javascript_lite.js, provided in the

+							distribution. This file has a stub version of each of the functions and methods

+							in the log4javascript Lite API and can simply be dropped in in place of the main file.

+						</li>

+					</ul>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+			</div>

+			<div id="footer">

+				<span class="externallinkinfo">

+					<strong>NB.</strong> All external links open in a new window.

+				</span>

+				Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>

+				<br />

+				log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"

+					title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,

+					Version 2.0</a>

+

+			</div>

+		</div>

+

+	</body>

+</html>

diff --git a/xos/core/static/log4javascript-1.4.6/docs/quickstart.html b/xos/core/static/log4javascript-1.4.6/docs/quickstart.html
new file mode 100644
index 0000000..3bffff5
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/docs/quickstart.html
@@ -0,0 +1,230 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript quick start tutorial</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />

+	</head>

+	<body>

+		<div id="container" class="nonav">

+			<div id="header">

+				<h1><a href="index.html">log4javascript</a></h1>

+			</div>

+			<div id="content">

+				<div id="nav">

+					<a class="navitem" href="../index.html">home</a>

+					| <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>

+					| <a class="navitem" href="index.html">docs</a>

+					| <span class="navitem">quick start</span>

+					| <a class="navitem" href="../demos/index.html">demos</a>

+					| <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>

+					| <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>

+				</div>

+				<h1>log4javascript quick start tutorial</h1>

+				<h2>Three step guide</h2>

+				<ol>

+					<li>

+						<h3>Download the code</h3>

+						<p>

+							Unzip the distribution and copy log4javascript.js into the desired

+							location. No other files are necessary.

+						</p>

+					</li>

+					<li>

+						<h3>Initialize log4javascript in your web page</h3>

+						<p>

+							Include log4javascript.js in your page using the code below. This

+							code assumes log4javascript is stored in the same directory as

+							your web page.

+						</p>

+						<pre class="code">

+&lt;script type="text/javascript" src="log4javascript.js"&gt;&lt;/script&gt;

+&lt;script type="text/javascript"&gt;

+	var log = log4javascript.getDefaultLogger();

+&lt;/script&gt;

+</pre>

+						<p>

+							The default logger uses a <code><a href="manual.html#popupappender">PopUpAppender</a></code>

+							which opens a pop-up window. By default, this window will open when the first

+							log message is written. For this to work, you will need to disable any pop-up blockers

+							you may have.

+						</p>

+					</li>

+					<li>

+						<h3>Include logging statements in your code</h3>

+						<p>

+							You have six logging methods at your disposal, depending on the severity

+							of the message you wish to log. By default, all messages are logged

+							in the pop-up window. The logging methods are:

+						</p>

+						<ul>

+							<li><code>log.trace(<em>message</em>[, <em>message2</em>, ... ][, <em>exception</em>])</code></li>

+							<li><code>log.debug(<em>message</em>[, <em>message2</em>, ... ][, <em>exception</em>])</code></li>

+							<li><code>log.info(<em>message</em>[, <em>message2</em>, ... ][, <em>exception</em>])</code></li>

+							<li><code>log.warn(<em>message</em>[, <em>message2</em>, ... ][, <em>exception</em>])</code></li>

+							<li><code>log.error(<em>message</em>[, <em>message2</em>, ... ][, <em>exception</em>])</code></li>

+							<li><code>log.fatal(<em>message</em>[, <em>message2</em>, ... ][, <em>exception</em>])</code></li>

+						</ul>

+						<p>

+							And that's it, log away. Below are some examples of common types of logging.

+						</p>

+					</li>

+				</ol>

+				<h2>Logging examples</h2>

+				<ol>

+					<li>

+						<h3>A simple logging message string</h3>

+						<pre class="code">

+	log.info("Hello world");

+</pre>

+displays

+						<pre class="console info">

+19:52:03 INFO  - Hello world

+</pre>

+					</li>

+					<li>

+						<h3>Logging an error with a message</h3>

+						<pre class="code">

+	try {

+		throw new Error("Faking something going wrong!");

+	} catch (e) {

+		log.error("An error occurred", e);

+	}

+</pre>

+displays

+						<pre class="console error">

+19:52:32 ERROR - An error occurred

+Exception: Faking something going wrong! on line number 80 in file basic.html

+</pre>

+					</li>

+					<li>

+						<h3>Logging multiple messages with one logging call</h3>

+						<pre class="code">

+	var a = "Hello";

+	var b = 3;

+	log.debug(a, b);

+</pre>

+displays

+						<pre class="console debug">

+19:53:05 DEBUG  - Hello 3

+</pre>

+					</li>

+					<li>

+						<h3>Logging an object</h3>

+						<p>Logging an object:</p>

+						<pre class="code">

+	var obj = new Object();

+	obj.name = "Octopus";

+	obj.tentacles = 8;

+	log.info(obj);

+</pre>

+displays

+						<pre class="console info">

+19:53:17 INFO  - {

+	name: Octopus,

+	tentacles: 8

+}

+</pre>

+					</li>

+				</ol>

+				<h2>Tweaking the default logger</h2>

+				<p>

+					The default logger is fine as a starting point, but what if you want the default logger

+					with a few different options (say, bringing the pop-up to the front whenever a log message is

+					logged, or having new log messages appear at the top of the pop-up rather than the bottom)?

+				</p>

+				<p>

+					In this case, you will need to create a new logger, then create a

+					<code><a href="manual.html#popupappender">PopUpAppender</a></code>, set options

+					on it, and add it to the logger:

+				</p>

+				<pre class="code">

+&lt;script type="text/javascript" src="log4javascript.js"&gt;&lt;/script&gt;

+&lt;script type="text/javascript"&gt;

+	// Create the logger

+	var log = log4javascript.getLogger();

+

+	// Create a PopUpAppender with default options

+	var popUpAppender = new log4javascript.PopUpAppender();

+

+	// Change the desired configuration options

+	popUpAppender.setFocusPopUp(true);

+	popUpAppender.setNewestMessageAtTop(true);

+

+	// Add the appender to the logger

+	log.addAppender(popUpAppender);

+

+	// Test the logger

+	log.debug("Hello world!");

+&lt;/script&gt;

+</pre>

+				<p>

+					<a href="../examples/example_quickstart_1.html" title="View example (opens in new window)"

+						target="_blank">See this example in action</a> (opens in new window)

+				</p>

+				<p>

+					Refer to the manual for more information about

+					<a href="manual.html#configuration">configuring appenders</a> and more

+					details about <code><a href="manual.html#popupappender">PopUpAppender</a></code>.

+				</p>

+				<h2>Sending log messages to the server</h2>

+				<p>

+					For this you will need to use an <code><a href="manual.html#ajaxappender">AjaxAppender</a></code>

+					as follows:

+				</p>

+				<pre class="code">

+	var ajaxAppender = new log4javascript.AjaxAppender(<em>URL</em>);

+	log.addAppender(ajaxAppender);

+</pre>

+				<p>

+					Now your log messages will appear in the pop-up window and be sent

+					asynchronously to the URL you specify in the form of HTTP post parameters.

+					No server-side code to process these requests is provided with log4javascript.

+				</p>

+				<p>

+					See <code><a href="manual.html#ajaxappender">AjaxAppender</a></code> for more details

+					on formatting log messages.

+				</p>

+				<h2>Changing the format of log messages</h2>

+				<p>

+					Using a <code><a href="manual.html#layouts">Layout</a></code>, you can

+					format log messages however you like. For example:

+				</p>

+				<pre class="code">

+	var log = log4javascript.getLogger("mylogger");

+	var popUpAppender = new log4javascript.PopUpAppender();

+	var layout = new log4javascript.PatternLayout("[%-5p] %m");

+	popUpAppender.setLayout(layout);

+</pre>

+				<p>A call to</p>

+				<pre class="code">

+	log.debug("Hello world");

+</pre>

+				<p>will now result in output in the pop-up window of </p>

+				<pre class="console debug">

+[DEBUG] Hello world

+</pre>

+				<p>

+					See <code><a href="manual.html#patternlayout">PatternLayout</a></code> for more details

+					on formatting log messages.

+				</p>

+			</div>

+			<div id="footer">

+				<span class="externallinkinfo">

+					<strong>NB.</strong> All external links open in a new window.

+				</span>

+				Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>

+				<br />

+				log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"

+					title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,

+					Version 2.0</a>

+

+			</div>

+		</div>

+

+	</body>

+</html>

diff --git a/xos/core/static/log4javascript-1.4.6/docs/whatsnew.html b/xos/core/static/log4javascript-1.4.6/docs/whatsnew.html
new file mode 100644
index 0000000..6e4e06f
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/docs/whatsnew.html
@@ -0,0 +1,86 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript - what's new in version 1.4</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />

+	</head>

+	<body>

+		<div id="container" class="nonav">

+			<div id="header">

+				<h1><a href="index.html">log4javascript</a></h1>

+			</div>

+			<div id="content">

+				<div id="nav">

+					<a class="navitem" href="../index.html">home</a>

+					| <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>

+					| <a class="navitem" href="index.html">docs</a>

+					| <a class="navitem" href="quickstart.html">quick start</a>

+					| <a class="navitem" href="../demos/index.html">demos</a>

+					| <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>

+					| <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>

+				</div>

+				<h1>log4javascript - what's new in version 1.4</h1>

+				<ul>

+					<li>

+						log4javascript now comes in three different editions: Standard, Production

+						and Lite. <a href="distribution.html">Full details here</a>.

+					</li>

+					<li>

+						Loggers are now hierarchical and work exactly the same as log4j loggers.

+						This means that a logger with no level set on it inherits its level from its parent,

+						and inherits all of its parents appenders.

+					</li>

+					<li>

+						The logging console used by <code><a href="manual.html#popupappender">PopUpAppender</a></code> and

+						<code><a href="manual.html#inpageappender">InPageAppender</a></code>now has a command line, featuring

+						a command history navigated with the up and down arrow keys and a number of built-in command line

+						functions.

+					</li>

+					<li>

+						It is now possible to specify multiple messages in a single log call.

+					</li>

+					<li>

+						Log messages may be grouped in the logging console.

+					</li>

+					<li>

+						Built-in timers.

+					</li>

+					<li>

+						Improved <code><a href="manual.html#ajaxappender">AjaxAppender</a></code>, with the ability

+						to send all pending log calls to the server when navigating away from a page. Timestamps now

+						include milliseconds. All log messages or batches of log messages are now posted as

+						name-value pairs.

+					</li>

+					<li>

+						Support for IE8 beta 2.

+					</li>

+					<li>

+						Many minor enhancements and bug fixes. See the <a href="../changelog.txt">change log</a> for full

+						details.

+					</li>

+				</ul>

+				<p>

+					Please note that there are a few minor <a href="backwardsincompatibilities.html">incompatibilities

+					with earlier versions of log4javascript</a>.

+				</p>

+			</div>

+			<div id="footer">

+				<span class="externallinkinfo">

+					<strong>NB.</strong> All external links open in a new window.

+				</span>

+				Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>

+				<br />

+				log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"

+					title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,

+					Version 2.0</a>

+

+			</div>

+		</div>

+

+	</body>

+</html>

diff --git a/xos/core/static/log4javascript-1.4.6/examples/demo.html b/xos/core/static/log4javascript-1.4.6/examples/demo.html
new file mode 100644
index 0000000..118b879
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/examples/demo.html
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript demo redirect</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="noindex" />

+		<meta http-equiv="refresh" content="0; url=../demos/basic.html" />

+	</head>

+	<body>

+		This page has been replaced by <a href="/demos/basic.html">the basic demo page</a>.

+		Please use this link if you are not redirected automatically.

+	</body>

+</html>

diff --git a/xos/core/static/log4javascript-1.4.6/examples/example_manual.html b/xos/core/static/log4javascript-1.4.6/examples/example_manual.html
new file mode 100644
index 0000000..68189e3
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/examples/example_manual.html
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript example from  manual</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<script type="text/javascript" src="../js/log4javascript.js"></script>

+		<script type="text/javascript">

+			//<![CDATA[

+			var log = log4javascript.getLogger();

+			var popUpAppender = new log4javascript.PopUpAppender();

+			var popUpLayout = new log4javascript.PatternLayout("%d{HH:mm:ss} %-5p - %m%n");

+			popUpAppender.setLayout(popUpLayout);

+			log.addAppender(popUpAppender);

+			var ajaxAppender = new log4javascript.AjaxAppender("myloggingservlet.do");

+			ajaxAppender.setThreshold(log4javascript.Level.ERROR);

+			log.addAppender(ajaxAppender);

+			log.debug("Debugging message (appears in pop-up)");

+			log.error("Error message (appears in pop-up and in server log)");

+			//]]>

+		</script>

+	</head>

+	<body>

+		<h1>log4javascript example from  manual</h1>

+

+

+	</body>

+</html>

diff --git a/xos/core/static/log4javascript-1.4.6/examples/example_quickstart_1.html b/xos/core/static/log4javascript-1.4.6/examples/example_quickstart_1.html
new file mode 100644
index 0000000..3ae4a9f
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/examples/example_quickstart_1.html
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript quick start example 1</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<script type="text/javascript" src="../js/log4javascript.js"></script>

+		<script type="text/javascript">

+			//<![CDATA[

+			// Create the logger

+			var log = log4javascript.getLogger(); 

+		

+			// Create a PopUpAppender with default options

+			var popUpAppender = new log4javascript.PopUpAppender();

+			

+			// Change the desired configuration options

+			popUpAppender.setFocusPopUp(true);

+			popUpAppender.setNewestMessageAtTop(true);

+			

+			// Add the appender to the logger

+			log.addAppender(popUpAppender);

+			

+			// Test the logger

+			log.debug("Hello world!");

+			//]]>

+		</script>

+	</head>

+	<body>

+		<h1>log4javascript quick start example 1</h1>

+	

+	

+	</body>

+</html>

diff --git a/xos/core/static/log4javascript-1.4.6/examples/myloggingservlet.do b/xos/core/static/log4javascript-1.4.6/examples/myloggingservlet.do
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/examples/myloggingservlet.do
diff --git a/xos/core/static/log4javascript-1.4.6/js/console.html b/xos/core/static/log4javascript-1.4.6/js/console.html
new file mode 100644
index 0000000..476d272
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/js/console.html
@@ -0,0 +1,263 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+<head>

+<title>log4javascript</title>

+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

+<!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->

+<meta http-equiv="X-UA-Compatible" content="IE=7" />

+<script type="text/javascript">var isIe = false, isIePre7 = false;</script>

+<!--[if IE]><script type="text/javascript">isIe = true</script><![endif]-->

+<!--[if lt IE 7]><script type="text/javascript">isIePre7 = true</script><![endif]-->

+<script type="text/javascript">

+//<![CDATA[

+var loggingEnabled=true;var logQueuedEventsTimer=null;var logEntries=[];var logEntriesAndSeparators=[];var logItems=[];var renderDelay=100;var unrenderedLogItemsExist=false;var rootGroup,currentGroup=null;var loaded=false;var currentLogItem=null;var logMainContainer;function copyProperties(obj,props){for(var i in props){obj[i]=props[i];}}

+function LogItem(){}

+LogItem.prototype={mainContainer:null,wrappedContainer:null,unwrappedContainer:null,group:null,appendToLog:function(){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].appendToLog();}

+this.group.update();},doRemove:function(doUpdate,removeFromGroup){if(this.rendered){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].remove();}

+this.unwrappedElementContainer=null;this.wrappedElementContainer=null;this.mainElementContainer=null;}

+if(this.group&&removeFromGroup){this.group.removeChild(this,doUpdate);}

+if(this===currentLogItem){currentLogItem=null;}},remove:function(doUpdate,removeFromGroup){this.doRemove(doUpdate,removeFromGroup);},render:function(){},accept:function(visitor){visitor.visit(this);},getUnwrappedDomContainer:function(){return this.group.unwrappedElementContainer.contentDiv;},getWrappedDomContainer:function(){return this.group.wrappedElementContainer.contentDiv;},getMainDomContainer:function(){return this.group.mainElementContainer.contentDiv;}};LogItem.serializedItemKeys={LOG_ENTRY:0,GROUP_START:1,GROUP_END:2};function LogItemContainerElement(){}

+LogItemContainerElement.prototype={appendToLog:function(){var insertBeforeFirst=(newestAtTop&&this.containerDomNode.hasChildNodes());if(insertBeforeFirst){this.containerDomNode.insertBefore(this.mainDiv,this.containerDomNode.firstChild);}else{this.containerDomNode.appendChild(this.mainDiv);}}};function SeparatorElementContainer(containerDomNode){this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.className="separator";this.mainDiv.innerHTML="&nbsp;";}

+SeparatorElementContainer.prototype=new LogItemContainerElement();SeparatorElementContainer.prototype.remove=function(){this.mainDiv.parentNode.removeChild(this.mainDiv);this.mainDiv=null;};function Separator(){this.rendered=false;}

+Separator.prototype=new LogItem();copyProperties(Separator.prototype,{render:function(){var containerDomNode=this.group.contentDiv;if(isIe){this.unwrappedElementContainer=new SeparatorElementContainer(this.getUnwrappedDomContainer());this.wrappedElementContainer=new SeparatorElementContainer(this.getWrappedDomContainer());this.elementContainers=[this.unwrappedElementContainer,this.wrappedElementContainer];}else{this.mainElementContainer=new SeparatorElementContainer(this.getMainDomContainer());this.elementContainers=[this.mainElementContainer];}

+this.content=this.formattedMessage;this.rendered=true;}});function GroupElementContainer(group,containerDomNode,isRoot,isWrapped){this.group=group;this.containerDomNode=containerDomNode;this.isRoot=isRoot;this.isWrapped=isWrapped;this.expandable=false;if(this.isRoot){if(isIe){this.contentDiv=logMainContainer.appendChild(document.createElement("div"));this.contentDiv.id=this.isWrapped?"log_wrapped":"log_unwrapped";}else{this.contentDiv=logMainContainer;}}else{var groupElementContainer=this;this.mainDiv=document.createElement("div");this.mainDiv.className="group";this.headingDiv=this.mainDiv.appendChild(document.createElement("div"));this.headingDiv.className="groupheading";this.expander=this.headingDiv.appendChild(document.createElement("span"));this.expander.className="expander unselectable greyedout";this.expander.unselectable=true;var expanderText=this.group.expanded?"-":"+";this.expanderTextNode=this.expander.appendChild(document.createTextNode(expanderText));this.headingDiv.appendChild(document.createTextNode(" "+this.group.name));this.contentDiv=this.mainDiv.appendChild(document.createElement("div"));var contentCssClass=this.group.expanded?"expanded":"collapsed";this.contentDiv.className="groupcontent "+contentCssClass;this.expander.onclick=function(){if(groupElementContainer.group.expandable){groupElementContainer.group.toggleExpanded();}};}}

+GroupElementContainer.prototype=new LogItemContainerElement();copyProperties(GroupElementContainer.prototype,{toggleExpanded:function(){if(!this.isRoot){var oldCssClass,newCssClass,expanderText;if(this.group.expanded){newCssClass="expanded";oldCssClass="collapsed";expanderText="-";}else{newCssClass="collapsed";oldCssClass="expanded";expanderText="+";}

+replaceClass(this.contentDiv,newCssClass,oldCssClass);this.expanderTextNode.nodeValue=expanderText;}},remove:function(){if(!this.isRoot){this.headingDiv=null;this.expander.onclick=null;this.expander=null;this.expanderTextNode=null;this.contentDiv=null;this.containerDomNode=null;this.mainDiv.parentNode.removeChild(this.mainDiv);this.mainDiv=null;}},reverseChildren:function(){var node=null;var childDomNodes=[];while((node=this.contentDiv.firstChild)){this.contentDiv.removeChild(node);childDomNodes.push(node);}

+while((node=childDomNodes.pop())){this.contentDiv.appendChild(node);}},update:function(){if(!this.isRoot){if(this.group.expandable){removeClass(this.expander,"greyedout");}else{addClass(this.expander,"greyedout");}}},clear:function(){if(this.isRoot){this.contentDiv.innerHTML="";}}});function Group(name,isRoot,initiallyExpanded){this.name=name;this.group=null;this.isRoot=isRoot;this.initiallyExpanded=initiallyExpanded;this.elementContainers=[];this.children=[];this.expanded=initiallyExpanded;this.rendered=false;this.expandable=false;}

+Group.prototype=new LogItem();copyProperties(Group.prototype,{addChild:function(logItem){this.children.push(logItem);logItem.group=this;},render:function(){if(isIe){var unwrappedDomContainer,wrappedDomContainer;if(this.isRoot){unwrappedDomContainer=logMainContainer;wrappedDomContainer=logMainContainer;}else{unwrappedDomContainer=this.getUnwrappedDomContainer();wrappedDomContainer=this.getWrappedDomContainer();}

+this.unwrappedElementContainer=new GroupElementContainer(this,unwrappedDomContainer,this.isRoot,false);this.wrappedElementContainer=new GroupElementContainer(this,wrappedDomContainer,this.isRoot,true);this.elementContainers=[this.unwrappedElementContainer,this.wrappedElementContainer];}else{var mainDomContainer=this.isRoot?logMainContainer:this.getMainDomContainer();this.mainElementContainer=new GroupElementContainer(this,mainDomContainer,this.isRoot,false);this.elementContainers=[this.mainElementContainer];}

+this.rendered=true;},toggleExpanded:function(){this.expanded=!this.expanded;for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].toggleExpanded();}},expand:function(){if(!this.expanded){this.toggleExpanded();}},accept:function(visitor){visitor.visitGroup(this);},reverseChildren:function(){if(this.rendered){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].reverseChildren();}}},update:function(){var previouslyExpandable=this.expandable;this.expandable=(this.children.length!==0);if(this.expandable!==previouslyExpandable){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].update();}}},flatten:function(){var visitor=new GroupFlattener();this.accept(visitor);return visitor.logEntriesAndSeparators;},removeChild:function(child,doUpdate){array_remove(this.children,child);child.group=null;if(doUpdate){this.update();}},remove:function(doUpdate,removeFromGroup){for(var i=0,len=this.children.length;i<len;i++){this.children[i].remove(false,false);}

+this.children=[];this.update();if(this===currentGroup){currentGroup=this.group;}

+this.doRemove(doUpdate,removeFromGroup);},serialize:function(items){items.push([LogItem.serializedItemKeys.GROUP_START,this.name]);for(var i=0,len=this.children.length;i<len;i++){this.children[i].serialize(items);}

+if(this!==currentGroup){items.push([LogItem.serializedItemKeys.GROUP_END]);}},clear:function(){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].clear();}}});function LogEntryElementContainer(){}

+LogEntryElementContainer.prototype=new LogItemContainerElement();copyProperties(LogEntryElementContainer.prototype,{remove:function(){this.doRemove();},doRemove:function(){this.mainDiv.parentNode.removeChild(this.mainDiv);this.mainDiv=null;this.contentElement=null;this.containerDomNode=null;},setContent:function(content,wrappedContent){if(content===this.formattedMessage){this.contentElement.innerHTML="";this.contentElement.appendChild(document.createTextNode(this.formattedMessage));}else{this.contentElement.innerHTML=content;}},setSearchMatch:function(isMatch){var oldCssClass=isMatch?"searchnonmatch":"searchmatch";var newCssClass=isMatch?"searchmatch":"searchnonmatch";replaceClass(this.mainDiv,newCssClass,oldCssClass);},clearSearch:function(){removeClass(this.mainDiv,"searchmatch");removeClass(this.mainDiv,"searchnonmatch");}});function LogEntryWrappedElementContainer(logEntry,containerDomNode){this.logEntry=logEntry;this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.appendChild(document.createTextNode(this.logEntry.formattedMessage));this.mainDiv.className="logentry wrapped "+this.logEntry.level;this.contentElement=this.mainDiv;}

+LogEntryWrappedElementContainer.prototype=new LogEntryElementContainer();LogEntryWrappedElementContainer.prototype.setContent=function(content,wrappedContent){if(content===this.formattedMessage){this.contentElement.innerHTML="";this.contentElement.appendChild(document.createTextNode(this.formattedMessage));}else{this.contentElement.innerHTML=wrappedContent;}};function LogEntryUnwrappedElementContainer(logEntry,containerDomNode){this.logEntry=logEntry;this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.className="logentry unwrapped "+this.logEntry.level;this.pre=this.mainDiv.appendChild(document.createElement("pre"));this.pre.appendChild(document.createTextNode(this.logEntry.formattedMessage));this.pre.className="unwrapped";this.contentElement=this.pre;}

+LogEntryUnwrappedElementContainer.prototype=new LogEntryElementContainer();LogEntryUnwrappedElementContainer.prototype.remove=function(){this.doRemove();this.pre=null;};function LogEntryMainElementContainer(logEntry,containerDomNode){this.logEntry=logEntry;this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.className="logentry nonielogentry "+this.logEntry.level;this.contentElement=this.mainDiv.appendChild(document.createElement("span"));this.contentElement.appendChild(document.createTextNode(this.logEntry.formattedMessage));}

+LogEntryMainElementContainer.prototype=new LogEntryElementContainer();function LogEntry(level,formattedMessage){this.level=level;this.formattedMessage=formattedMessage;this.rendered=false;}

+LogEntry.prototype=new LogItem();copyProperties(LogEntry.prototype,{render:function(){var logEntry=this;var containerDomNode=this.group.contentDiv;if(isIe){this.formattedMessage=this.formattedMessage.replace(/\r\n/g,"\r");this.unwrappedElementContainer=new LogEntryUnwrappedElementContainer(this,this.getUnwrappedDomContainer());this.wrappedElementContainer=new LogEntryWrappedElementContainer(this,this.getWrappedDomContainer());this.elementContainers=[this.unwrappedElementContainer,this.wrappedElementContainer];}else{this.mainElementContainer=new LogEntryMainElementContainer(this,this.getMainDomContainer());this.elementContainers=[this.mainElementContainer];}

+this.content=this.formattedMessage;this.rendered=true;},setContent:function(content,wrappedContent){if(content!=this.content){if(isIe&&(content!==this.formattedMessage)){content=content.replace(/\r\n/g,"\r");}

+for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].setContent(content,wrappedContent);}

+this.content=content;}},getSearchMatches:function(){var matches=[];var i,len;if(isIe){var unwrappedEls=getElementsByClass(this.unwrappedElementContainer.mainDiv,"searchterm","span");var wrappedEls=getElementsByClass(this.wrappedElementContainer.mainDiv,"searchterm","span");for(i=0,len=unwrappedEls.length;i<len;i++){matches[i]=new Match(this.level,null,unwrappedEls[i],wrappedEls[i]);}}else{var els=getElementsByClass(this.mainElementContainer.mainDiv,"searchterm","span");for(i=0,len=els.length;i<len;i++){matches[i]=new Match(this.level,els[i]);}}

+return matches;},setSearchMatch:function(isMatch){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].setSearchMatch(isMatch);}},clearSearch:function(){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].clearSearch();}},accept:function(visitor){visitor.visitLogEntry(this);},serialize:function(items){items.push([LogItem.serializedItemKeys.LOG_ENTRY,this.level,this.formattedMessage]);}});function LogItemVisitor(){}

+LogItemVisitor.prototype={visit:function(logItem){},visitParent:function(logItem){if(logItem.group){logItem.group.accept(this);}},visitChildren:function(logItem){for(var i=0,len=logItem.children.length;i<len;i++){logItem.children[i].accept(this);}},visitLogEntry:function(logEntry){this.visit(logEntry);},visitSeparator:function(separator){this.visit(separator);},visitGroup:function(group){this.visit(group);}};function GroupFlattener(){this.logEntriesAndSeparators=[];}

+GroupFlattener.prototype=new LogItemVisitor();GroupFlattener.prototype.visitGroup=function(group){this.visitChildren(group);};GroupFlattener.prototype.visitLogEntry=function(logEntry){this.logEntriesAndSeparators.push(logEntry);};GroupFlattener.prototype.visitSeparator=function(separator){this.logEntriesAndSeparators.push(separator);};window.onload=function(){if(location.search){var queryBits=unescape(location.search).substr(1).split("&"),nameValueBits;for(var i=0,len=queryBits.length;i<len;i++){nameValueBits=queryBits[i].split("=");if(nameValueBits[0]=="log4javascript_domain"){document.domain=nameValueBits[1];break;}}}

+logMainContainer=$("log");if(isIePre7){addClass(logMainContainer,"oldIe");}

+rootGroup=new Group("root",true);rootGroup.render();currentGroup=rootGroup;setCommandInputWidth();setLogContainerHeight();toggleLoggingEnabled();toggleSearchEnabled();toggleSearchFilter();toggleSearchHighlight();applyFilters();checkAllLevels();toggleWrap();toggleNewestAtTop();toggleScrollToLatest();renderQueuedLogItems();loaded=true;$("command").value="";$("command").autocomplete="off";$("command").onkeydown=function(evt){evt=getEvent(evt);if(evt.keyCode==10||evt.keyCode==13){evalCommandLine();stopPropagation(evt);}else if(evt.keyCode==27){this.value="";this.focus();}else if(evt.keyCode==38&&commandHistory.length>0){currentCommandIndex=Math.max(0,currentCommandIndex-1);this.value=commandHistory[currentCommandIndex];moveCaretToEnd(this);}else if(evt.keyCode==40&&commandHistory.length>0){currentCommandIndex=Math.min(commandHistory.length-1,currentCommandIndex+1);this.value=commandHistory[currentCommandIndex];moveCaretToEnd(this);}};$("command").onkeypress=function(evt){evt=getEvent(evt);if(evt.keyCode==38&&commandHistory.length>0&&evt.preventDefault){evt.preventDefault();}};$("command").onkeyup=function(evt){evt=getEvent(evt);if(evt.keyCode==27&&evt.preventDefault){evt.preventDefault();this.focus();}};document.onkeydown=function keyEventHandler(evt){evt=getEvent(evt);switch(evt.keyCode){case 69:if(evt.shiftKey&&(evt.ctrlKey||evt.metaKey)){evalLastCommand();cancelKeyEvent(evt);return false;}

+break;case 75:if(evt.shiftKey&&(evt.ctrlKey||evt.metaKey)){focusSearch();cancelKeyEvent(evt);return false;}

+break;case 40:case 76:if(evt.shiftKey&&(evt.ctrlKey||evt.metaKey)){focusCommandLine();cancelKeyEvent(evt);return false;}

+break;}};setTimeout(setLogContainerHeight,20);setShowCommandLine(showCommandLine);doSearch();};window.onunload=function(){if(mainWindowExists()){appender.unload();}

+appender=null;};function toggleLoggingEnabled(){setLoggingEnabled($("enableLogging").checked);}

+function setLoggingEnabled(enable){loggingEnabled=enable;}

+var appender=null;function setAppender(appenderParam){appender=appenderParam;}

+function setShowCloseButton(showCloseButton){$("closeButton").style.display=showCloseButton?"inline":"none";}

+function setShowHideButton(showHideButton){$("hideButton").style.display=showHideButton?"inline":"none";}

+var newestAtTop=false;function LogItemContentReverser(){}

+LogItemContentReverser.prototype=new LogItemVisitor();LogItemContentReverser.prototype.visitGroup=function(group){group.reverseChildren();this.visitChildren(group);};function setNewestAtTop(isNewestAtTop){var oldNewestAtTop=newestAtTop;var i,iLen,j,jLen;newestAtTop=Boolean(isNewestAtTop);if(oldNewestAtTop!=newestAtTop){var visitor=new LogItemContentReverser();rootGroup.accept(visitor);if(currentSearch){var currentMatch=currentSearch.matches[currentMatchIndex];var matchIndex=0;var matches=[];var actOnLogEntry=function(logEntry){var logEntryMatches=logEntry.getSearchMatches();for(j=0,jLen=logEntryMatches.length;j<jLen;j++){matches[matchIndex]=logEntryMatches[j];if(currentMatch&&logEntryMatches[j].equals(currentMatch)){currentMatchIndex=matchIndex;}

+matchIndex++;}};if(newestAtTop){for(i=logEntries.length-1;i>=0;i--){actOnLogEntry(logEntries[i]);}}else{for(i=0,iLen=logEntries.length;i<iLen;i++){actOnLogEntry(logEntries[i]);}}

+currentSearch.matches=matches;if(currentMatch){currentMatch.setCurrent();}}else if(scrollToLatest){doScrollToLatest();}}

+$("newestAtTop").checked=isNewestAtTop;}

+function toggleNewestAtTop(){var isNewestAtTop=$("newestAtTop").checked;setNewestAtTop(isNewestAtTop);}

+var scrollToLatest=true;function setScrollToLatest(isScrollToLatest){scrollToLatest=isScrollToLatest;if(scrollToLatest){doScrollToLatest();}

+$("scrollToLatest").checked=isScrollToLatest;}

+function toggleScrollToLatest(){var isScrollToLatest=$("scrollToLatest").checked;setScrollToLatest(isScrollToLatest);}

+function doScrollToLatest(){var l=logMainContainer;if(typeof l.scrollTop!="undefined"){if(newestAtTop){l.scrollTop=0;}else{var latestLogEntry=l.lastChild;if(latestLogEntry){l.scrollTop=l.scrollHeight;}}}}

+var closeIfOpenerCloses=true;function setCloseIfOpenerCloses(isCloseIfOpenerCloses){closeIfOpenerCloses=isCloseIfOpenerCloses;}

+var maxMessages=null;function setMaxMessages(max){maxMessages=max;pruneLogEntries();}

+var showCommandLine=false;function setShowCommandLine(isShowCommandLine){showCommandLine=isShowCommandLine;if(loaded){$("commandLine").style.display=showCommandLine?"block":"none";setCommandInputWidth();setLogContainerHeight();}}

+function focusCommandLine(){if(loaded){$("command").focus();}}

+function focusSearch(){if(loaded){$("searchBox").focus();}}

+function getLogItems(){var items=[];for(var i=0,len=logItems.length;i<len;i++){logItems[i].serialize(items);}

+return items;}

+function setLogItems(items){var loggingReallyEnabled=loggingEnabled;loggingEnabled=true;for(var i=0,len=items.length;i<len;i++){switch(items[i][0]){case LogItem.serializedItemKeys.LOG_ENTRY:log(items[i][1],items[i][2]);break;case LogItem.serializedItemKeys.GROUP_START:group(items[i][1]);break;case LogItem.serializedItemKeys.GROUP_END:groupEnd();break;}}

+loggingEnabled=loggingReallyEnabled;}

+function log(logLevel,formattedMessage){if(loggingEnabled){var logEntry=new LogEntry(logLevel,formattedMessage);logEntries.push(logEntry);logEntriesAndSeparators.push(logEntry);logItems.push(logEntry);currentGroup.addChild(logEntry);if(loaded){if(logQueuedEventsTimer!==null){clearTimeout(logQueuedEventsTimer);}

+logQueuedEventsTimer=setTimeout(renderQueuedLogItems,renderDelay);unrenderedLogItemsExist=true;}}}

+function renderQueuedLogItems(){logQueuedEventsTimer=null;var pruned=pruneLogEntries();var initiallyHasMatches=currentSearch?currentSearch.hasMatches():false;for(var i=0,len=logItems.length;i<len;i++){if(!logItems[i].rendered){logItems[i].render();logItems[i].appendToLog();if(currentSearch&&(logItems[i]instanceof LogEntry)){currentSearch.applyTo(logItems[i]);}}}

+if(currentSearch){if(pruned){if(currentSearch.hasVisibleMatches()){if(currentMatchIndex===null){setCurrentMatchIndex(0);}

+displayMatches();}else{displayNoMatches();}}else if(!initiallyHasMatches&&currentSearch.hasVisibleMatches()){setCurrentMatchIndex(0);displayMatches();}}

+if(scrollToLatest){doScrollToLatest();}

+unrenderedLogItemsExist=false;}

+function pruneLogEntries(){if((maxMessages!==null)&&(logEntriesAndSeparators.length>maxMessages)){var numberToDelete=logEntriesAndSeparators.length-maxMessages;var prunedLogEntries=logEntriesAndSeparators.slice(0,numberToDelete);if(currentSearch){currentSearch.removeMatches(prunedLogEntries);}

+var group;for(var i=0;i<numberToDelete;i++){group=logEntriesAndSeparators[i].group;array_remove(logItems,logEntriesAndSeparators[i]);array_remove(logEntries,logEntriesAndSeparators[i]);logEntriesAndSeparators[i].remove(true,true);if(group.children.length===0&&group!==currentGroup&&group!==rootGroup){array_remove(logItems,group);group.remove(true,true);}}

+logEntriesAndSeparators=array_removeFromStart(logEntriesAndSeparators,numberToDelete);return true;}

+return false;}

+function group(name,startExpanded){if(loggingEnabled){initiallyExpanded=(typeof startExpanded==="undefined")?true:Boolean(startExpanded);var newGroup=new Group(name,false,initiallyExpanded);currentGroup.addChild(newGroup);currentGroup=newGroup;logItems.push(newGroup);if(loaded){if(logQueuedEventsTimer!==null){clearTimeout(logQueuedEventsTimer);}

+logQueuedEventsTimer=setTimeout(renderQueuedLogItems,renderDelay);unrenderedLogItemsExist=true;}}}

+function groupEnd(){currentGroup=(currentGroup===rootGroup)?rootGroup:currentGroup.group;}

+function mainPageReloaded(){currentGroup=rootGroup;var separator=new Separator();logEntriesAndSeparators.push(separator);logItems.push(separator);currentGroup.addChild(separator);}

+function closeWindow(){if(appender&&mainWindowExists()){appender.close(true);}else{window.close();}}

+function hide(){if(appender&&mainWindowExists()){appender.hide();}}

+var mainWindow=window;var windowId="log4javascriptConsoleWindow_"+new Date().getTime()+"_"+(""+Math.random()).substr(2);function setMainWindow(win){mainWindow=win;mainWindow[windowId]=window;if(opener&&closeIfOpenerCloses){pollOpener();}}

+function pollOpener(){if(closeIfOpenerCloses){if(mainWindowExists()){setTimeout(pollOpener,500);}else{closeWindow();}}}

+function mainWindowExists(){try{return(mainWindow&&!mainWindow.closed&&mainWindow[windowId]==window);}catch(ex){}

+return false;}

+var logLevels=["TRACE","DEBUG","INFO","WARN","ERROR","FATAL"];function getCheckBox(logLevel){return $("switch_"+logLevel);}

+function getIeWrappedLogContainer(){return $("log_wrapped");}

+function getIeUnwrappedLogContainer(){return $("log_unwrapped");}

+function applyFilters(){for(var i=0;i<logLevels.length;i++){if(getCheckBox(logLevels[i]).checked){addClass(logMainContainer,logLevels[i]);}else{removeClass(logMainContainer,logLevels[i]);}}

+updateSearchFromFilters();}

+function toggleAllLevels(){var turnOn=$("switch_ALL").checked;for(var i=0;i<logLevels.length;i++){getCheckBox(logLevels[i]).checked=turnOn;if(turnOn){addClass(logMainContainer,logLevels[i]);}else{removeClass(logMainContainer,logLevels[i]);}}}

+function checkAllLevels(){for(var i=0;i<logLevels.length;i++){if(!getCheckBox(logLevels[i]).checked){getCheckBox("ALL").checked=false;return;}}

+getCheckBox("ALL").checked=true;}

+function clearLog(){rootGroup.clear();currentGroup=rootGroup;logEntries=[];logItems=[];logEntriesAndSeparators=[];doSearch();}

+function toggleWrap(){var enable=$("wrap").checked;if(enable){addClass(logMainContainer,"wrap");}else{removeClass(logMainContainer,"wrap");}

+refreshCurrentMatch();}

+var searchTimer=null;function scheduleSearch(){try{clearTimeout(searchTimer);}catch(ex){}

+searchTimer=setTimeout(doSearch,500);}

+function Search(searchTerm,isRegex,searchRegex,isCaseSensitive){this.searchTerm=searchTerm;this.isRegex=isRegex;this.searchRegex=searchRegex;this.isCaseSensitive=isCaseSensitive;this.matches=[];}

+Search.prototype={hasMatches:function(){return this.matches.length>0;},hasVisibleMatches:function(){if(this.hasMatches()){for(var i=0;i<this.matches.length;i++){if(this.matches[i].isVisible()){return true;}}}

+return false;},match:function(logEntry){var entryText=String(logEntry.formattedMessage);var matchesSearch=false;if(this.isRegex){matchesSearch=this.searchRegex.test(entryText);}else if(this.isCaseSensitive){matchesSearch=(entryText.indexOf(this.searchTerm)>-1);}else{matchesSearch=(entryText.toLowerCase().indexOf(this.searchTerm.toLowerCase())>-1);}

+return matchesSearch;},getNextVisibleMatchIndex:function(){for(var i=currentMatchIndex+1;i<this.matches.length;i++){if(this.matches[i].isVisible()){return i;}}

+for(i=0;i<=currentMatchIndex;i++){if(this.matches[i].isVisible()){return i;}}

+return-1;},getPreviousVisibleMatchIndex:function(){for(var i=currentMatchIndex-1;i>=0;i--){if(this.matches[i].isVisible()){return i;}}

+for(var i=this.matches.length-1;i>=currentMatchIndex;i--){if(this.matches[i].isVisible()){return i;}}

+return-1;},applyTo:function(logEntry){var doesMatch=this.match(logEntry);if(doesMatch){logEntry.group.expand();logEntry.setSearchMatch(true);var logEntryContent;var wrappedLogEntryContent;var searchTermReplacementStartTag="<span class=\"searchterm\">";var searchTermReplacementEndTag="<"+"/span>";var preTagName=isIe?"pre":"span";var preStartTag="<"+preTagName+" class=\"pre\">";var preEndTag="<"+"/"+preTagName+">";var startIndex=0;var searchIndex,matchedText,textBeforeMatch;if(this.isRegex){var flags=this.isCaseSensitive?"g":"gi";var capturingRegex=new RegExp("("+this.searchRegex.source+")",flags);var rnd=(""+Math.random()).substr(2);var startToken="%%s"+rnd+"%%";var endToken="%%e"+rnd+"%%";logEntryContent=logEntry.formattedMessage.replace(capturingRegex,startToken+"$1"+endToken);logEntryContent=escapeHtml(logEntryContent);var result;var searchString=logEntryContent;logEntryContent="";wrappedLogEntryContent="";while((searchIndex=searchString.indexOf(startToken,startIndex))>-1){var endTokenIndex=searchString.indexOf(endToken,searchIndex);matchedText=searchString.substring(searchIndex+startToken.length,endTokenIndex);textBeforeMatch=searchString.substring(startIndex,searchIndex);logEntryContent+=preStartTag+textBeforeMatch+preEndTag;logEntryContent+=searchTermReplacementStartTag+preStartTag+matchedText+

+preEndTag+searchTermReplacementEndTag;if(isIe){wrappedLogEntryContent+=textBeforeMatch+searchTermReplacementStartTag+

+matchedText+searchTermReplacementEndTag;}

+startIndex=endTokenIndex+endToken.length;}

+logEntryContent+=preStartTag+searchString.substr(startIndex)+preEndTag;if(isIe){wrappedLogEntryContent+=searchString.substr(startIndex);}}else{logEntryContent="";wrappedLogEntryContent="";var searchTermReplacementLength=searchTermReplacementStartTag.length+

+this.searchTerm.length+searchTermReplacementEndTag.length;var searchTermLength=this.searchTerm.length;var searchTermLowerCase=this.searchTerm.toLowerCase();var logTextLowerCase=logEntry.formattedMessage.toLowerCase();while((searchIndex=logTextLowerCase.indexOf(searchTermLowerCase,startIndex))>-1){matchedText=escapeHtml(logEntry.formattedMessage.substr(searchIndex,this.searchTerm.length));textBeforeMatch=escapeHtml(logEntry.formattedMessage.substring(startIndex,searchIndex));var searchTermReplacement=searchTermReplacementStartTag+

+preStartTag+matchedText+preEndTag+searchTermReplacementEndTag;logEntryContent+=preStartTag+textBeforeMatch+preEndTag+searchTermReplacement;if(isIe){wrappedLogEntryContent+=textBeforeMatch+searchTermReplacementStartTag+

+matchedText+searchTermReplacementEndTag;}

+startIndex=searchIndex+searchTermLength;}

+var textAfterLastMatch=escapeHtml(logEntry.formattedMessage.substr(startIndex));logEntryContent+=preStartTag+textAfterLastMatch+preEndTag;if(isIe){wrappedLogEntryContent+=textAfterLastMatch;}}

+logEntry.setContent(logEntryContent,wrappedLogEntryContent);var logEntryMatches=logEntry.getSearchMatches();this.matches=this.matches.concat(logEntryMatches);}else{logEntry.setSearchMatch(false);logEntry.setContent(logEntry.formattedMessage,logEntry.formattedMessage);}

+return doesMatch;},removeMatches:function(logEntries){var matchesToRemoveCount=0;var currentMatchRemoved=false;var matchesToRemove=[];var i,iLen,j,jLen;for(i=0,iLen=this.matches.length;i<iLen;i++){for(j=0,jLen=logEntries.length;j<jLen;j++){if(this.matches[i].belongsTo(logEntries[j])){matchesToRemove.push(this.matches[i]);if(i===currentMatchIndex){currentMatchRemoved=true;}}}}

+var newMatch=currentMatchRemoved?null:this.matches[currentMatchIndex];if(currentMatchRemoved){for(i=currentMatchIndex,iLen=this.matches.length;i<iLen;i++){if(this.matches[i].isVisible()&&!array_contains(matchesToRemove,this.matches[i])){newMatch=this.matches[i];break;}}}

+for(i=0,iLen=matchesToRemove.length;i<iLen;i++){array_remove(this.matches,matchesToRemove[i]);matchesToRemove[i].remove();}

+if(this.hasVisibleMatches()){if(newMatch===null){setCurrentMatchIndex(0);}else{var newMatchIndex=0;for(i=0,iLen=this.matches.length;i<iLen;i++){if(newMatch===this.matches[i]){newMatchIndex=i;break;}}

+setCurrentMatchIndex(newMatchIndex);}}else{currentMatchIndex=null;displayNoMatches();}}};function getPageOffsetTop(el,container){var currentEl=el;var y=0;while(currentEl&&currentEl!=container){y+=currentEl.offsetTop;currentEl=currentEl.offsetParent;}

+return y;}

+function scrollIntoView(el){var logContainer=logMainContainer;if(!$("wrap").checked){var logContainerLeft=logContainer.scrollLeft;var logContainerRight=logContainerLeft+logContainer.offsetWidth;var elLeft=el.offsetLeft;var elRight=elLeft+el.offsetWidth;if(elLeft<logContainerLeft||elRight>logContainerRight){logContainer.scrollLeft=elLeft-(logContainer.offsetWidth-el.offsetWidth)/2;}}

+var logContainerTop=logContainer.scrollTop;var logContainerBottom=logContainerTop+logContainer.offsetHeight;var elTop=getPageOffsetTop(el)-getToolBarsHeight();var elBottom=elTop+el.offsetHeight;if(elTop<logContainerTop||elBottom>logContainerBottom){logContainer.scrollTop=elTop-(logContainer.offsetHeight-el.offsetHeight)/2;}}

+function Match(logEntryLevel,spanInMainDiv,spanInUnwrappedPre,spanInWrappedDiv){this.logEntryLevel=logEntryLevel;this.spanInMainDiv=spanInMainDiv;if(isIe){this.spanInUnwrappedPre=spanInUnwrappedPre;this.spanInWrappedDiv=spanInWrappedDiv;}

+this.mainSpan=isIe?spanInUnwrappedPre:spanInMainDiv;}

+Match.prototype={equals:function(match){return this.mainSpan===match.mainSpan;},setCurrent:function(){if(isIe){addClass(this.spanInUnwrappedPre,"currentmatch");addClass(this.spanInWrappedDiv,"currentmatch");var elementToScroll=$("wrap").checked?this.spanInWrappedDiv:this.spanInUnwrappedPre;scrollIntoView(elementToScroll);}else{addClass(this.spanInMainDiv,"currentmatch");scrollIntoView(this.spanInMainDiv);}},belongsTo:function(logEntry){if(isIe){return isDescendant(this.spanInUnwrappedPre,logEntry.unwrappedPre);}else{return isDescendant(this.spanInMainDiv,logEntry.mainDiv);}},setNotCurrent:function(){if(isIe){removeClass(this.spanInUnwrappedPre,"currentmatch");removeClass(this.spanInWrappedDiv,"currentmatch");}else{removeClass(this.spanInMainDiv,"currentmatch");}},isOrphan:function(){return isOrphan(this.mainSpan);},isVisible:function(){return getCheckBox(this.logEntryLevel).checked;},remove:function(){if(isIe){this.spanInUnwrappedPre=null;this.spanInWrappedDiv=null;}else{this.spanInMainDiv=null;}}};var currentSearch=null;var currentMatchIndex=null;function doSearch(){var searchBox=$("searchBox");var searchTerm=searchBox.value;var isRegex=$("searchRegex").checked;var isCaseSensitive=$("searchCaseSensitive").checked;var i;if(searchTerm===""){$("searchReset").disabled=true;$("searchNav").style.display="none";removeClass(document.body,"searching");removeClass(searchBox,"hasmatches");removeClass(searchBox,"nomatches");for(i=0;i<logEntries.length;i++){logEntries[i].clearSearch();logEntries[i].setContent(logEntries[i].formattedMessage,logEntries[i].formattedMessage);}

+currentSearch=null;setLogContainerHeight();}else{$("searchReset").disabled=false;$("searchNav").style.display="block";var searchRegex;var regexValid;if(isRegex){try{searchRegex=isCaseSensitive?new RegExp(searchTerm,"g"):new RegExp(searchTerm,"gi");regexValid=true;replaceClass(searchBox,"validregex","invalidregex");searchBox.title="Valid regex";}catch(ex){regexValid=false;replaceClass(searchBox,"invalidregex","validregex");searchBox.title="Invalid regex: "+(ex.message?ex.message:(ex.description?ex.description:"unknown error"));return;}}else{searchBox.title="";removeClass(searchBox,"validregex");removeClass(searchBox,"invalidregex");}

+addClass(document.body,"searching");currentSearch=new Search(searchTerm,isRegex,searchRegex,isCaseSensitive);for(i=0;i<logEntries.length;i++){currentSearch.applyTo(logEntries[i]);}

+setLogContainerHeight();if(currentSearch.hasVisibleMatches()){setCurrentMatchIndex(0);displayMatches();}else{displayNoMatches();}}}

+function updateSearchFromFilters(){if(currentSearch){if(currentSearch.hasMatches()){if(currentMatchIndex===null){currentMatchIndex=0;}

+var currentMatch=currentSearch.matches[currentMatchIndex];if(currentMatch.isVisible()){displayMatches();setCurrentMatchIndex(currentMatchIndex);}else{currentMatch.setNotCurrent();var nextVisibleMatchIndex=currentSearch.getNextVisibleMatchIndex();if(nextVisibleMatchIndex>-1){setCurrentMatchIndex(nextVisibleMatchIndex);displayMatches();}else{displayNoMatches();}}}else{displayNoMatches();}}}

+function refreshCurrentMatch(){if(currentSearch&&currentSearch.hasVisibleMatches()){setCurrentMatchIndex(currentMatchIndex);}}

+function displayMatches(){replaceClass($("searchBox"),"hasmatches","nomatches");$("searchBox").title=""+currentSearch.matches.length+" matches found";$("searchNav").style.display="block";setLogContainerHeight();}

+function displayNoMatches(){replaceClass($("searchBox"),"nomatches","hasmatches");$("searchBox").title="No matches found";$("searchNav").style.display="none";setLogContainerHeight();}

+function toggleSearchEnabled(enable){enable=(typeof enable=="undefined")?!$("searchDisable").checked:enable;$("searchBox").disabled=!enable;$("searchReset").disabled=!enable;$("searchRegex").disabled=!enable;$("searchNext").disabled=!enable;$("searchPrevious").disabled=!enable;$("searchCaseSensitive").disabled=!enable;$("searchNav").style.display=(enable&&($("searchBox").value!=="")&&currentSearch&&currentSearch.hasVisibleMatches())?"block":"none";if(enable){removeClass($("search"),"greyedout");addClass(document.body,"searching");if($("searchHighlight").checked){addClass(logMainContainer,"searchhighlight");}else{removeClass(logMainContainer,"searchhighlight");}

+if($("searchFilter").checked){addClass(logMainContainer,"searchfilter");}else{removeClass(logMainContainer,"searchfilter");}

+$("searchDisable").checked=!enable;}else{addClass($("search"),"greyedout");removeClass(document.body,"searching");removeClass(logMainContainer,"searchhighlight");removeClass(logMainContainer,"searchfilter");}

+setLogContainerHeight();}

+function toggleSearchFilter(){var enable=$("searchFilter").checked;if(enable){addClass(logMainContainer,"searchfilter");}else{removeClass(logMainContainer,"searchfilter");}

+refreshCurrentMatch();}

+function toggleSearchHighlight(){var enable=$("searchHighlight").checked;if(enable){addClass(logMainContainer,"searchhighlight");}else{removeClass(logMainContainer,"searchhighlight");}}

+function clearSearch(){$("searchBox").value="";doSearch();}

+function searchNext(){if(currentSearch!==null&&currentMatchIndex!==null){currentSearch.matches[currentMatchIndex].setNotCurrent();var nextMatchIndex=currentSearch.getNextVisibleMatchIndex();if(nextMatchIndex>currentMatchIndex||confirm("Reached the end of the page. Start from the top?")){setCurrentMatchIndex(nextMatchIndex);}}}

+function searchPrevious(){if(currentSearch!==null&&currentMatchIndex!==null){currentSearch.matches[currentMatchIndex].setNotCurrent();var previousMatchIndex=currentSearch.getPreviousVisibleMatchIndex();if(previousMatchIndex<currentMatchIndex||confirm("Reached the start of the page. Continue from the bottom?")){setCurrentMatchIndex(previousMatchIndex);}}}

+function setCurrentMatchIndex(index){currentMatchIndex=index;currentSearch.matches[currentMatchIndex].setCurrent();}

+function addClass(el,cssClass){if(!hasClass(el,cssClass)){if(el.className){el.className+=" "+cssClass;}else{el.className=cssClass;}}}

+function hasClass(el,cssClass){if(el.className){var classNames=el.className.split(" ");return array_contains(classNames,cssClass);}

+return false;}

+function removeClass(el,cssClass){if(hasClass(el,cssClass)){var existingClasses=el.className.split(" ");var newClasses=[];for(var i=0,len=existingClasses.length;i<len;i++){if(existingClasses[i]!=cssClass){newClasses[newClasses.length]=existingClasses[i];}}

+el.className=newClasses.join(" ");}}

+function replaceClass(el,newCssClass,oldCssClass){removeClass(el,oldCssClass);addClass(el,newCssClass);}

+function getElementsByClass(el,cssClass,tagName){var elements=el.getElementsByTagName(tagName);var matches=[];for(var i=0,len=elements.length;i<len;i++){if(hasClass(elements[i],cssClass)){matches.push(elements[i]);}}

+return matches;}

+function $(id){return document.getElementById(id);}

+function isDescendant(node,ancestorNode){while(node!=null){if(node===ancestorNode){return true;}

+node=node.parentNode;}

+return false;}

+function isOrphan(node){var currentNode=node;while(currentNode){if(currentNode==document.body){return false;}

+currentNode=currentNode.parentNode;}

+return true;}

+function escapeHtml(str){return str.replace(/&/g,"&amp;").replace(/[<]/g,"&lt;").replace(/>/g,"&gt;");}

+function getWindowWidth(){if(window.innerWidth){return window.innerWidth;}else if(document.documentElement&&document.documentElement.clientWidth){return document.documentElement.clientWidth;}else if(document.body){return document.body.clientWidth;}

+return 0;}

+function getWindowHeight(){if(window.innerHeight){return window.innerHeight;}else if(document.documentElement&&document.documentElement.clientHeight){return document.documentElement.clientHeight;}else if(document.body){return document.body.clientHeight;}

+return 0;}

+function getToolBarsHeight(){return $("switches").offsetHeight;}

+function getChromeHeight(){var height=getToolBarsHeight();if(showCommandLine){height+=$("commandLine").offsetHeight;}

+return height;}

+function setLogContainerHeight(){if(logMainContainer){var windowHeight=getWindowHeight();$("body").style.height=getWindowHeight()+"px";logMainContainer.style.height=""+

+Math.max(0,windowHeight-getChromeHeight())+"px";}}

+function setCommandInputWidth(){if(showCommandLine){$("command").style.width=""+Math.max(0,$("commandLineContainer").offsetWidth-

+($("evaluateButton").offsetWidth+13))+"px";}}

+window.onresize=function(){setCommandInputWidth();setLogContainerHeight();};if(!Array.prototype.push){Array.prototype.push=function(){for(var i=0,len=arguments.length;i<len;i++){this[this.length]=arguments[i];}

+return this.length;};}

+if(!Array.prototype.pop){Array.prototype.pop=function(){if(this.length>0){var val=this[this.length-1];this.length=this.length-1;return val;}};}

+if(!Array.prototype.shift){Array.prototype.shift=function(){if(this.length>0){var firstItem=this[0];for(var i=0,len=this.length-1;i<len;i++){this[i]=this[i+1];}

+this.length=this.length-1;return firstItem;}};}

+if(!Array.prototype.splice){Array.prototype.splice=function(startIndex,deleteCount){var itemsAfterDeleted=this.slice(startIndex+deleteCount);var itemsDeleted=this.slice(startIndex,startIndex+deleteCount);this.length=startIndex;var argumentsArray=[];for(var i=0,len=arguments.length;i<len;i++){argumentsArray[i]=arguments[i];}

+var itemsToAppend=(argumentsArray.length>2)?itemsAfterDeleted=argumentsArray.slice(2).concat(itemsAfterDeleted):itemsAfterDeleted;for(i=0,len=itemsToAppend.length;i<len;i++){this.push(itemsToAppend[i]);}

+return itemsDeleted;};}

+function array_remove(arr,val){var index=-1;for(var i=0,len=arr.length;i<len;i++){if(arr[i]===val){index=i;break;}}

+if(index>=0){arr.splice(index,1);return index;}else{return false;}}

+function array_removeFromStart(array,numberToRemove){if(Array.prototype.splice){array.splice(0,numberToRemove);}else{for(var i=numberToRemove,len=array.length;i<len;i++){array[i-numberToRemove]=array[i];}

+array.length=array.length-numberToRemove;}

+return array;}

+function array_contains(arr,val){for(var i=0,len=arr.length;i<len;i++){if(arr[i]==val){return true;}}

+return false;}

+function getErrorMessage(ex){if(ex.message){return ex.message;}else if(ex.description){return ex.description;}

+return""+ex;}

+function moveCaretToEnd(input){if(input.setSelectionRange){input.focus();var length=input.value.length;input.setSelectionRange(length,length);}else if(input.createTextRange){var range=input.createTextRange();range.collapse(false);range.select();}

+input.focus();}

+function stopPropagation(evt){if(evt.stopPropagation){evt.stopPropagation();}else if(typeof evt.cancelBubble!="undefined"){evt.cancelBubble=true;}}

+function getEvent(evt){return evt?evt:event;}

+function getTarget(evt){return evt.target?evt.target:evt.srcElement;}

+function getRelatedTarget(evt){if(evt.relatedTarget){return evt.relatedTarget;}else if(evt.srcElement){switch(evt.type){case"mouseover":return evt.fromElement;case"mouseout":return evt.toElement;default:return evt.srcElement;}}}

+function cancelKeyEvent(evt){evt.returnValue=false;stopPropagation(evt);}

+function evalCommandLine(){var expr=$("command").value;evalCommand(expr);$("command").value="";}

+function evalLastCommand(){if(lastCommand!=null){evalCommand(lastCommand);}}

+var lastCommand=null;var commandHistory=[];var currentCommandIndex=0;function evalCommand(expr){if(appender){appender.evalCommandAndAppend(expr);}else{var prefix=">>> "+expr+"\r\n";try{log("INFO",prefix+eval(expr));}catch(ex){log("ERROR",prefix+"Error: "+getErrorMessage(ex));}}

+if(expr!=commandHistory[commandHistory.length-1]){commandHistory.push(expr);if(appender){appender.storeCommandHistory(commandHistory);}}

+currentCommandIndex=(expr==commandHistory[currentCommandIndex])?currentCommandIndex+1:commandHistory.length;lastCommand=expr;}

+//]]>

+</script>

+<style type="text/css">

+body{background-color:white;color:black;padding:0;margin:0;font-family:tahoma,verdana,arial,helvetica,sans-serif;overflow:hidden}div#switchesContainer input{margin-bottom:0}div.toolbar{border-top:solid #ffffff 1px;border-bottom:solid #aca899 1px;background-color:#f1efe7;padding:3px 5px;font-size:68.75%}div.toolbar,div#search input{font-family:tahoma,verdana,arial,helvetica,sans-serif}div.toolbar input.button{padding:0 5px;font-size:100%}div.toolbar input.hidden{display:none}div#switches input#clearButton{margin-left:20px}div#levels label{font-weight:bold}div#levels label,div#options label{margin-right:5px}div#levels label#wrapLabel{font-weight:normal}div#search label{margin-right:10px}div#search label.searchboxlabel{margin-right:0}div#search input{font-size:100%}div#search input.validregex{color:green}div#search input.invalidregex{color:red}div#search input.nomatches{color:white;background-color:#ff6666}div#search input.nomatches{color:white;background-color:#ff6666}div#searchNav{display:none}div#commandLine{display:none}div#commandLine input#command{font-size:100%;font-family:Courier New,Courier}div#commandLine input#evaluateButton{}*.greyedout{color:gray !important;border-color:gray !important}*.greyedout *.alwaysenabled{color:black}*.unselectable{-khtml-user-select:none;-moz-user-select:none;user-select:none}div#log{font-family:Courier New,Courier;font-size:75%;width:100%;overflow:auto;clear:both;position:relative}div.group{border-color:#cccccc;border-style:solid;border-width:1px 0 1px 1px;overflow:visible}div.oldIe div.group,div.oldIe div.group *,div.oldIe *.logentry{height:1%}div.group div.groupheading span.expander{border:solid black 1px;font-family:Courier New,Courier;font-size:0.833em;background-color:#eeeeee;position:relative;top:-1px;color:black;padding:0 2px;cursor:pointer;cursor:hand;height:1%}div.group div.groupcontent{margin-left:10px;padding-bottom:2px;overflow:visible}div.group div.expanded{display:block}div.group div.collapsed{display:none}*.logentry{overflow:visible;display:none;white-space:pre}span.pre{white-space:pre}pre.unwrapped{display:inline !important}pre.unwrapped pre.pre,div.wrapped pre.pre{display:inline}div.wrapped pre.pre{white-space:normal}div.wrapped{display:none}body.searching *.logentry span.currentmatch{color:white !important;background-color:green !important}body.searching div.searchhighlight *.logentry span.searchterm{color:black;background-color:yellow}div.wrap *.logentry{white-space:normal !important;border-width:0 0 1px 0;border-color:#dddddd;border-style:dotted}div.wrap #log_wrapped,#log_unwrapped{display:block}div.wrap #log_unwrapped,#log_wrapped{display:none}div.wrap *.logentry span.pre{overflow:visible;white-space:normal}div.wrap *.logentry pre.unwrapped{display:none}div.wrap *.logentry span.wrapped{display:inline}div.searchfilter *.searchnonmatch{display:none !important}div#log *.TRACE,label#label_TRACE{color:#666666}div#log *.DEBUG,label#label_DEBUG{color:green}div#log *.INFO,label#label_INFO{color:#000099}div#log *.WARN,label#label_WARN{color:#999900}div#log *.ERROR,label#label_ERROR{color:red}div#log *.FATAL,label#label_FATAL{color:#660066}div.TRACE#log *.TRACE,div.DEBUG#log *.DEBUG,div.INFO#log *.INFO,div.WARN#log *.WARN,div.ERROR#log *.ERROR,div.FATAL#log *.FATAL{display:block}div#log div.separator{background-color:#cccccc;margin:5px 0;line-height:1px}

+</style>

+</head>

+<body id="body">

+<div id="switchesContainer">

+<div id="switches">

+<div id="levels" class="toolbar">

+Filters:

+<input type="checkbox" id="switch_TRACE" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide trace messages" /><label for="switch_TRACE" id="label_TRACE">trace</label>

+<input type="checkbox" id="switch_DEBUG" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide debug messages" /><label for="switch_DEBUG" id="label_DEBUG">debug</label>

+<input type="checkbox" id="switch_INFO" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide info messages" /><label for="switch_INFO" id="label_INFO">info</label>

+<input type="checkbox" id="switch_WARN" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide warn messages" /><label for="switch_WARN" id="label_WARN">warn</label>

+<input type="checkbox" id="switch_ERROR" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide error messages" /><label for="switch_ERROR" id="label_ERROR">error</label>

+<input type="checkbox" id="switch_FATAL" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide fatal messages" /><label for="switch_FATAL" id="label_FATAL">fatal</label>

+<input type="checkbox" id="switch_ALL" onclick="toggleAllLevels(); applyFilters()" checked="checked" title="Show/hide all messages" /><label for="switch_ALL" id="label_ALL">all</label>

+</div>

+<div id="search" class="toolbar">

+<label for="searchBox" class="searchboxlabel">Search:</label> <input type="text" id="searchBox" onclick="toggleSearchEnabled(true)" onkeyup="scheduleSearch()" size="20" />

+<input type="button" id="searchReset" disabled="disabled" value="Reset" onclick="clearSearch()" class="button" title="Reset the search" />

+<input type="checkbox" id="searchRegex" onclick="doSearch()" title="If checked, search is treated as a regular expression" /><label for="searchRegex">Regex</label>

+<input type="checkbox" id="searchCaseSensitive" onclick="doSearch()" title="If checked, search is case sensitive" /><label for="searchCaseSensitive">Match case</label>

+<input type="checkbox" id="searchDisable" onclick="toggleSearchEnabled()" title="Enable/disable search" /><label for="searchDisable" class="alwaysenabled">Disable</label>

+<div id="searchNav">

+<input type="button" id="searchNext" disabled="disabled" value="Next" onclick="searchNext()" class="button" title="Go to the next matching log entry" />

+<input type="button" id="searchPrevious" disabled="disabled" value="Previous" onclick="searchPrevious()" class="button" title="Go to the previous matching log entry" />

+<input type="checkbox" id="searchFilter" onclick="toggleSearchFilter()" title="If checked, non-matching log entries are filtered out" /><label for="searchFilter">Filter</label>

+<input type="checkbox" id="searchHighlight" onclick="toggleSearchHighlight()" title="Highlight matched search terms" /><label for="searchHighlight" class="alwaysenabled">Highlight all</label>

+</div>

+</div>

+<div id="options" class="toolbar">

+Options:

+<input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Log</label>

+<input type="checkbox" id="wrap" onclick="toggleWrap()" title="Enable / disable word wrap" /><label for="wrap" id="wrapLabel">Wrap</label>

+<input type="checkbox" id="newestAtTop" onclick="toggleNewestAtTop()" title="If checked, causes newest messages to appear at the top" /><label for="newestAtTop" id="newestAtTopLabel">Newest at the top</label>

+<input type="checkbox" id="scrollToLatest" onclick="toggleScrollToLatest()" checked="checked" title="If checked, window automatically scrolls to a new message when it is added" /><label for="scrollToLatest" id="scrollToLatestLabel">Scroll to latest</label>

+<input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="button" title="Clear all log messages"  />

+<input type="button" id="hideButton" value="Hide" onclick="hide()" class="hidden button" title="Hide the console" />

+<input type="button" id="closeButton" value="Close" onclick="closeWindow()" class="hidden button" title="Close the window" />

+</div>

+</div>

+</div>

+<div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>

+<div id="commandLine" class="toolbar">

+<div id="commandLineContainer">

+<input type="text" id="command" title="Enter a JavaScript command here and hit return or press 'Evaluate'" />

+<input type="button" id="evaluateButton" value="Evaluate" class="button" title="Evaluate the command" onclick="evalCommandLine()" />

+</div>

+</div>

+</body>

+</html>

diff --git a/xos/core/static/log4javascript-1.4.6/js/console_uncompressed.html b/xos/core/static/log4javascript-1.4.6/js/console_uncompressed.html
new file mode 100644
index 0000000..55679f8
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/js/console_uncompressed.html
@@ -0,0 +1,2279 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript</title>

+		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

+		<!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->

+		<meta http-equiv="X-UA-Compatible" content="IE=7" />

+		<script type="text/javascript">var isIe = false, isIePre7 = false;</script>

+		<!--[if IE]><script type="text/javascript">isIe = true</script><![endif]-->

+		<!--[if lt IE 7]><script type="text/javascript">isIePre7 = true</script><![endif]-->

+		<script type="text/javascript">

+			//<![CDATA[

+			var loggingEnabled = true;

+			var logQueuedEventsTimer = null;

+			var logEntries = [];

+			var logEntriesAndSeparators = [];

+			var logItems = [];

+			var renderDelay = 100;

+			var unrenderedLogItemsExist = false;

+			var rootGroup, currentGroup = null;

+			var loaded = false;

+			var currentLogItem = null;

+			var logMainContainer;

+

+			function copyProperties(obj, props) {

+				for (var i in props) {

+					obj[i] = props[i];

+				}

+			}

+

+			/*----------------------------------------------------------------*/

+

+			function LogItem() {

+			}

+

+			LogItem.prototype = {

+				mainContainer: null,

+				wrappedContainer: null,

+				unwrappedContainer: null,

+				group: null,

+

+				appendToLog: function() {

+					for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+						this.elementContainers[i].appendToLog();

+					}

+					this.group.update();

+				},

+

+				doRemove: function(doUpdate, removeFromGroup) {

+					if (this.rendered) {

+						for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+							this.elementContainers[i].remove();

+						}

+						this.unwrappedElementContainer = null;

+						this.wrappedElementContainer = null;

+						this.mainElementContainer = null;

+					}

+					if (this.group && removeFromGroup) {

+						this.group.removeChild(this, doUpdate);

+					}

+					if (this === currentLogItem) {

+						currentLogItem = null;

+					}

+				},

+

+				remove: function(doUpdate, removeFromGroup) {

+					this.doRemove(doUpdate, removeFromGroup);

+				},

+

+				render: function() {},

+

+				accept: function(visitor) {

+					visitor.visit(this);

+				},

+

+				getUnwrappedDomContainer: function() {

+					return this.group.unwrappedElementContainer.contentDiv;

+				},

+

+				getWrappedDomContainer: function() {

+					return this.group.wrappedElementContainer.contentDiv;

+				},

+

+				getMainDomContainer: function() {

+					return this.group.mainElementContainer.contentDiv;

+				}

+			};

+

+			LogItem.serializedItemKeys = {LOG_ENTRY: 0, GROUP_START: 1, GROUP_END: 2};

+

+			/*----------------------------------------------------------------*/

+

+			function LogItemContainerElement() {

+			}

+

+			LogItemContainerElement.prototype = {

+				appendToLog: function() {

+					var insertBeforeFirst = (newestAtTop && this.containerDomNode.hasChildNodes());

+					if (insertBeforeFirst) {

+						this.containerDomNode.insertBefore(this.mainDiv, this.containerDomNode.firstChild);

+					} else {

+						this.containerDomNode.appendChild(this.mainDiv);

+					}

+				}

+			};

+

+			/*----------------------------------------------------------------*/

+

+			function SeparatorElementContainer(containerDomNode) {

+				this.containerDomNode = containerDomNode;

+				this.mainDiv = document.createElement("div");

+				this.mainDiv.className = "separator";

+				this.mainDiv.innerHTML = "&nbsp;";

+			}

+

+			SeparatorElementContainer.prototype = new LogItemContainerElement();

+

+			SeparatorElementContainer.prototype.remove = function() {

+				this.mainDiv.parentNode.removeChild(this.mainDiv);

+				this.mainDiv = null;

+			};

+

+			/*----------------------------------------------------------------*/

+

+			function Separator() {

+				this.rendered = false;

+			}

+

+			Separator.prototype = new LogItem();

+

+			copyProperties(Separator.prototype, {

+				render: function() {

+					var containerDomNode = this.group.contentDiv;

+					if (isIe) {

+						this.unwrappedElementContainer = new SeparatorElementContainer(this.getUnwrappedDomContainer());

+						this.wrappedElementContainer = new SeparatorElementContainer(this.getWrappedDomContainer());

+						this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];

+					} else {

+						this.mainElementContainer = new SeparatorElementContainer(this.getMainDomContainer());

+						this.elementContainers = [this.mainElementContainer];

+					}

+					this.content = this.formattedMessage;

+					this.rendered = true;

+				}

+			});

+

+			/*----------------------------------------------------------------*/

+

+			function GroupElementContainer(group, containerDomNode, isRoot, isWrapped) {

+				this.group = group;

+				this.containerDomNode = containerDomNode;

+				this.isRoot = isRoot;

+				this.isWrapped = isWrapped;

+				this.expandable = false;

+

+				if (this.isRoot) {

+					if (isIe) {

+						this.contentDiv = logMainContainer.appendChild(document.createElement("div"));

+						this.contentDiv.id = this.isWrapped ? "log_wrapped" : "log_unwrapped";

+					} else {

+						this.contentDiv = logMainContainer;

+					}

+				} else {

+					var groupElementContainer = this;

+					

+					this.mainDiv = document.createElement("div");

+					this.mainDiv.className = "group";

+

+					this.headingDiv = this.mainDiv.appendChild(document.createElement("div"));

+					this.headingDiv.className = "groupheading";

+

+					this.expander = this.headingDiv.appendChild(document.createElement("span"));

+					this.expander.className = "expander unselectable greyedout";

+					this.expander.unselectable = true;

+					var expanderText = this.group.expanded ? "-" : "+";

+					this.expanderTextNode = this.expander.appendChild(document.createTextNode(expanderText));

+					

+					this.headingDiv.appendChild(document.createTextNode(" " + this.group.name));

+

+					this.contentDiv = this.mainDiv.appendChild(document.createElement("div"));

+					var contentCssClass = this.group.expanded ? "expanded" : "collapsed";

+					this.contentDiv.className = "groupcontent " + contentCssClass;

+

+					this.expander.onclick = function() {

+						if (groupElementContainer.group.expandable) {

+							groupElementContainer.group.toggleExpanded();

+						}

+					};

+				}

+			}

+

+			GroupElementContainer.prototype = new LogItemContainerElement();

+

+			copyProperties(GroupElementContainer.prototype, {

+				toggleExpanded: function() {

+					if (!this.isRoot) {

+						var oldCssClass, newCssClass, expanderText;

+						if (this.group.expanded) {

+							newCssClass = "expanded";

+							oldCssClass = "collapsed";

+							expanderText = "-";

+						} else {

+							newCssClass = "collapsed";

+							oldCssClass = "expanded";

+							expanderText = "+";

+						}

+						replaceClass(this.contentDiv, newCssClass, oldCssClass);

+						this.expanderTextNode.nodeValue = expanderText;

+					}

+				},

+

+				remove: function() {

+					if (!this.isRoot) {

+						this.headingDiv = null;

+						this.expander.onclick = null;

+						this.expander = null;

+						this.expanderTextNode = null;

+						this.contentDiv = null;

+						this.containerDomNode = null;

+						this.mainDiv.parentNode.removeChild(this.mainDiv);

+						this.mainDiv = null;

+					}

+				},

+

+				reverseChildren: function() {

+					// Invert the order of the log entries

+					var node = null;

+

+					// Remove all the log container nodes

+					var childDomNodes = [];

+					while ((node = this.contentDiv.firstChild)) {

+						this.contentDiv.removeChild(node);

+						childDomNodes.push(node);

+					}

+

+					// Put them all back in reverse order

+					while ((node = childDomNodes.pop())) {

+						this.contentDiv.appendChild(node);

+					}

+				},

+

+				update: function() {

+					if (!this.isRoot) {

+						if (this.group.expandable) {

+							removeClass(this.expander, "greyedout");

+						} else {

+							addClass(this.expander, "greyedout");

+						}

+					}

+				},

+

+				clear: function() {

+					if (this.isRoot) {

+						this.contentDiv.innerHTML = "";

+					}

+				}

+			});

+

+			/*----------------------------------------------------------------*/

+

+			function Group(name, isRoot, initiallyExpanded) {

+				this.name = name;

+				this.group = null;

+				this.isRoot = isRoot;

+				this.initiallyExpanded = initiallyExpanded;

+				this.elementContainers = [];

+				this.children = [];

+				this.expanded = initiallyExpanded;

+				this.rendered = false;

+				this.expandable = false;

+			}

+

+			Group.prototype = new LogItem();

+

+			copyProperties(Group.prototype, {

+				addChild: function(logItem) {

+					this.children.push(logItem);

+					logItem.group = this;

+				},

+

+				render: function() {

+					if (isIe) {

+						var unwrappedDomContainer, wrappedDomContainer;

+						if (this.isRoot) {

+							unwrappedDomContainer = logMainContainer;

+							wrappedDomContainer = logMainContainer;

+						} else {

+							unwrappedDomContainer = this.getUnwrappedDomContainer();

+							wrappedDomContainer = this.getWrappedDomContainer();

+						}

+						this.unwrappedElementContainer = new GroupElementContainer(this, unwrappedDomContainer, this.isRoot, false);

+						this.wrappedElementContainer = new GroupElementContainer(this, wrappedDomContainer, this.isRoot, true);

+						this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];

+					} else {

+						var mainDomContainer = this.isRoot ? logMainContainer : this.getMainDomContainer();

+						this.mainElementContainer = new GroupElementContainer(this, mainDomContainer, this.isRoot, false);

+						this.elementContainers = [this.mainElementContainer];

+					}

+					this.rendered = true;

+				},

+

+				toggleExpanded: function() {

+					this.expanded = !this.expanded;

+					for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+						this.elementContainers[i].toggleExpanded();

+					}

+				},

+

+				expand: function() {

+					if (!this.expanded) {

+						this.toggleExpanded();

+					}

+				},

+

+				accept: function(visitor) {

+					visitor.visitGroup(this);

+				},

+

+				reverseChildren: function() {

+					if (this.rendered) {

+						for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+							this.elementContainers[i].reverseChildren();

+						}

+					}

+				},

+

+				update: function() {

+					var previouslyExpandable = this.expandable;

+					this.expandable = (this.children.length !== 0);

+					if (this.expandable !== previouslyExpandable) {

+						for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+							this.elementContainers[i].update();

+						}

+					}

+				},

+

+				flatten: function() {

+					var visitor = new GroupFlattener();

+					this.accept(visitor);

+					return visitor.logEntriesAndSeparators;

+				},

+

+				removeChild: function(child, doUpdate) {

+					array_remove(this.children, child);

+					child.group = null;

+					if (doUpdate) {

+						this.update();

+					}

+				},

+

+				remove: function(doUpdate, removeFromGroup) {

+					for (var i = 0, len = this.children.length; i < len; i++) {

+						this.children[i].remove(false, false);

+					}

+					this.children = [];

+					this.update();

+					if (this === currentGroup) {

+						currentGroup = this.group;

+					}

+					this.doRemove(doUpdate, removeFromGroup);

+				},

+

+				serialize: function(items) {

+					items.push([LogItem.serializedItemKeys.GROUP_START, this.name]);

+					for (var i = 0, len = this.children.length; i < len; i++) {

+						this.children[i].serialize(items);

+					}

+					if (this !== currentGroup) {

+						items.push([LogItem.serializedItemKeys.GROUP_END]);

+					}

+				},

+

+				clear: function() {

+					for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+						this.elementContainers[i].clear();

+					}

+				}

+			});

+

+			/*----------------------------------------------------------------*/

+

+			function LogEntryElementContainer() {

+			}

+

+			LogEntryElementContainer.prototype = new LogItemContainerElement();

+

+			copyProperties(LogEntryElementContainer.prototype, {

+				remove: function() {

+					this.doRemove();

+				},

+

+				doRemove: function() {

+					this.mainDiv.parentNode.removeChild(this.mainDiv);

+					this.mainDiv = null;

+					this.contentElement = null;

+					this.containerDomNode = null;

+				},

+

+				setContent: function(content, wrappedContent) {

+					if (content === this.formattedMessage) {

+						this.contentElement.innerHTML = "";

+						this.contentElement.appendChild(document.createTextNode(this.formattedMessage));

+					} else {

+						this.contentElement.innerHTML = content;

+					}

+				},

+

+				setSearchMatch: function(isMatch) {

+					var oldCssClass = isMatch ? "searchnonmatch" : "searchmatch";

+					var newCssClass = isMatch ? "searchmatch" : "searchnonmatch";

+					replaceClass(this.mainDiv, newCssClass, oldCssClass);

+				},

+

+				clearSearch: function() {

+					removeClass(this.mainDiv, "searchmatch");

+					removeClass(this.mainDiv, "searchnonmatch");

+				}

+			});

+

+			/*----------------------------------------------------------------*/

+

+			function LogEntryWrappedElementContainer(logEntry, containerDomNode) {

+				this.logEntry = logEntry;

+				this.containerDomNode = containerDomNode;

+				this.mainDiv = document.createElement("div");

+				this.mainDiv.appendChild(document.createTextNode(this.logEntry.formattedMessage));

+				this.mainDiv.className = "logentry wrapped " + this.logEntry.level;

+				this.contentElement = this.mainDiv;

+			}

+

+			LogEntryWrappedElementContainer.prototype = new LogEntryElementContainer();

+

+			LogEntryWrappedElementContainer.prototype.setContent = function(content, wrappedContent) {

+				if (content === this.formattedMessage) {

+					this.contentElement.innerHTML = "";

+					this.contentElement.appendChild(document.createTextNode(this.formattedMessage));

+				} else {

+					this.contentElement.innerHTML = wrappedContent;

+				}

+			};

+

+			/*----------------------------------------------------------------*/

+

+			function LogEntryUnwrappedElementContainer(logEntry, containerDomNode) {

+				this.logEntry = logEntry;

+				this.containerDomNode = containerDomNode;

+				this.mainDiv = document.createElement("div");

+				this.mainDiv.className = "logentry unwrapped " + this.logEntry.level;

+				this.pre = this.mainDiv.appendChild(document.createElement("pre"));

+				this.pre.appendChild(document.createTextNode(this.logEntry.formattedMessage));

+				this.pre.className = "unwrapped";

+				this.contentElement = this.pre;

+			}

+

+			LogEntryUnwrappedElementContainer.prototype = new LogEntryElementContainer();

+

+			LogEntryUnwrappedElementContainer.prototype.remove = function() {

+				this.doRemove();

+				this.pre = null;

+			};

+

+			/*----------------------------------------------------------------*/

+

+			function LogEntryMainElementContainer(logEntry, containerDomNode) {

+				this.logEntry = logEntry;

+				this.containerDomNode = containerDomNode;

+				this.mainDiv = document.createElement("div");

+				this.mainDiv.className = "logentry nonielogentry " + this.logEntry.level;

+				this.contentElement = this.mainDiv.appendChild(document.createElement("span"));

+				this.contentElement.appendChild(document.createTextNode(this.logEntry.formattedMessage));

+			}

+

+			LogEntryMainElementContainer.prototype = new LogEntryElementContainer();

+

+			/*----------------------------------------------------------------*/

+

+			function LogEntry(level, formattedMessage) {

+				this.level = level;

+				this.formattedMessage = formattedMessage;

+				this.rendered = false;

+			}

+

+			LogEntry.prototype = new LogItem();

+

+			copyProperties(LogEntry.prototype, {

+				render: function() {

+					var logEntry = this;

+					var containerDomNode = this.group.contentDiv;

+

+					// Support for the CSS attribute white-space in IE for Windows is

+					// non-existent pre version 6 and slightly odd in 6, so instead

+					// use two different HTML elements

+					if (isIe) {

+						this.formattedMessage = this.formattedMessage.replace(/\r\n/g, "\r"); // Workaround for IE's treatment of white space

+						this.unwrappedElementContainer = new LogEntryUnwrappedElementContainer(this, this.getUnwrappedDomContainer());

+						this.wrappedElementContainer = new LogEntryWrappedElementContainer(this, this.getWrappedDomContainer());

+						this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];

+					} else {

+						this.mainElementContainer = new LogEntryMainElementContainer(this, this.getMainDomContainer());

+						this.elementContainers = [this.mainElementContainer];

+					}

+					this.content = this.formattedMessage;

+					this.rendered = true;

+				},

+

+				setContent: function(content, wrappedContent) {

+					if (content != this.content) {

+						if (isIe && (content !== this.formattedMessage)) {

+							content = content.replace(/\r\n/g, "\r"); // Workaround for IE's treatment of white space

+						}

+						for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+							this.elementContainers[i].setContent(content, wrappedContent);

+						}

+						this.content = content;

+					}

+				},

+

+				getSearchMatches: function() {

+					var matches = [];

+					var i, len;

+					if (isIe) {

+						var unwrappedEls = getElementsByClass(this.unwrappedElementContainer.mainDiv, "searchterm", "span");

+						var wrappedEls = getElementsByClass(this.wrappedElementContainer.mainDiv, "searchterm", "span");

+						for (i = 0, len = unwrappedEls.length; i < len; i++) {

+							matches[i] = new Match(this.level, null, unwrappedEls[i], wrappedEls[i]);

+						}

+					} else {

+						var els = getElementsByClass(this.mainElementContainer.mainDiv, "searchterm", "span");

+						for (i = 0, len = els.length; i < len; i++) {

+							matches[i] = new Match(this.level, els[i]);

+						}

+					}

+					return matches;

+				},

+

+				setSearchMatch: function(isMatch) {

+					for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+						this.elementContainers[i].setSearchMatch(isMatch);

+					}

+				},

+

+				clearSearch: function() {

+					for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+						this.elementContainers[i].clearSearch();

+					}

+				},

+

+				accept: function(visitor) {

+					visitor.visitLogEntry(this);

+				},

+

+				serialize: function(items) {

+					items.push([LogItem.serializedItemKeys.LOG_ENTRY, this.level, this.formattedMessage]);

+				}

+			});

+

+			/*----------------------------------------------------------------*/

+

+			function LogItemVisitor() {

+			}

+

+			LogItemVisitor.prototype = {

+				visit: function(logItem) {

+				},

+

+				visitParent: function(logItem) {

+					if (logItem.group) {

+						logItem.group.accept(this);

+					}

+				},

+

+				visitChildren: function(logItem) {

+					for (var i = 0, len = logItem.children.length; i < len; i++) {

+						logItem.children[i].accept(this);

+					}

+				},

+

+				visitLogEntry: function(logEntry) {

+					this.visit(logEntry);

+				},

+

+				visitSeparator: function(separator) {

+					this.visit(separator);

+				},

+

+				visitGroup: function(group) {

+					this.visit(group);

+				}

+			};

+

+			/*----------------------------------------------------------------*/

+

+			function GroupFlattener() {

+				this.logEntriesAndSeparators = [];

+			}

+

+			GroupFlattener.prototype = new LogItemVisitor();

+

+			GroupFlattener.prototype.visitGroup = function(group) {

+				this.visitChildren(group);

+			};

+

+			GroupFlattener.prototype.visitLogEntry = function(logEntry) {

+				this.logEntriesAndSeparators.push(logEntry);

+			};

+

+			GroupFlattener.prototype.visitSeparator = function(separator) {

+				this.logEntriesAndSeparators.push(separator);

+			};

+

+			/*----------------------------------------------------------------*/

+

+			window.onload = function() {

+				// Sort out document.domain

+				if (location.search) {

+					var queryBits = unescape(location.search).substr(1).split("&"), nameValueBits;

+					for (var i = 0, len = queryBits.length; i < len; i++) {

+						nameValueBits = queryBits[i].split("=");

+						if (nameValueBits[0] == "log4javascript_domain") {

+							document.domain = nameValueBits[1];

+							break;

+						}

+					}

+				}

+

+				// Create DOM objects

+				logMainContainer = $("log");

+				if (isIePre7) {

+					addClass(logMainContainer, "oldIe");

+				}

+

+				rootGroup = new Group("root", true);

+				rootGroup.render();

+				currentGroup = rootGroup;

+				

+				setCommandInputWidth();

+				setLogContainerHeight();

+				toggleLoggingEnabled();

+				toggleSearchEnabled();

+				toggleSearchFilter();

+				toggleSearchHighlight();

+				applyFilters();

+				checkAllLevels();

+				toggleWrap();

+				toggleNewestAtTop();

+				toggleScrollToLatest();

+				renderQueuedLogItems();

+				loaded = true;

+				$("command").value = "";

+				$("command").autocomplete = "off";

+				$("command").onkeydown = function(evt) {

+					evt = getEvent(evt);

+					if (evt.keyCode == 10 || evt.keyCode == 13) { // Return/Enter

+						evalCommandLine();

+						stopPropagation(evt);

+					} else if (evt.keyCode == 27) { // Escape

+						this.value = "";

+						this.focus();

+					} else if (evt.keyCode == 38 && commandHistory.length > 0) { // Up

+						currentCommandIndex = Math.max(0, currentCommandIndex - 1);

+						this.value = commandHistory[currentCommandIndex];

+						moveCaretToEnd(this);

+					} else if (evt.keyCode == 40 && commandHistory.length > 0) { // Down

+						currentCommandIndex = Math.min(commandHistory.length - 1, currentCommandIndex + 1);

+						this.value = commandHistory[currentCommandIndex];

+						moveCaretToEnd(this);

+					}

+				};

+

+				// Prevent the keypress moving the caret in Firefox

+				$("command").onkeypress = function(evt) {

+					evt = getEvent(evt);

+					if (evt.keyCode == 38 && commandHistory.length > 0 && evt.preventDefault) { // Up

+						evt.preventDefault();

+					}

+				};

+

+				// Prevent the keyup event blurring the input in Opera

+				$("command").onkeyup = function(evt) {

+					evt = getEvent(evt);

+					if (evt.keyCode == 27 && evt.preventDefault) { // Up

+						evt.preventDefault();

+						this.focus();

+					}

+				};

+

+				// Add document keyboard shortcuts

+				document.onkeydown = function keyEventHandler(evt) {

+					evt = getEvent(evt);

+					switch (evt.keyCode) {

+						case 69: // Ctrl + shift + E: re-execute last command

+							if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {

+								evalLastCommand();

+								cancelKeyEvent(evt);

+								return false;

+							}

+							break;

+						case 75: // Ctrl + shift + K: focus search

+							if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {

+								focusSearch();

+								cancelKeyEvent(evt);

+								return false;

+							}

+							break;

+						case 40: // Ctrl + shift + down arrow: focus command line

+						case 76: // Ctrl + shift + L: focus command line

+							if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {

+								focusCommandLine();

+								cancelKeyEvent(evt);

+								return false;

+							}

+							break;

+					}

+				};

+

+				// Workaround to make sure log div starts at the correct size

+				setTimeout(setLogContainerHeight, 20);

+

+				setShowCommandLine(showCommandLine);

+				doSearch();

+			};

+

+			window.onunload = function() {

+				if (mainWindowExists()) {

+					appender.unload();

+				}

+				appender = null;

+			};

+

+			/*----------------------------------------------------------------*/

+

+			function toggleLoggingEnabled() {

+				setLoggingEnabled($("enableLogging").checked);

+			}

+

+			function setLoggingEnabled(enable) {

+				loggingEnabled = enable;

+			}

+

+			var appender = null;

+

+			function setAppender(appenderParam) {

+				appender = appenderParam;

+			}

+

+			function setShowCloseButton(showCloseButton) {

+				$("closeButton").style.display = showCloseButton ? "inline" : "none";

+			}

+

+			function setShowHideButton(showHideButton) {

+				$("hideButton").style.display = showHideButton ? "inline" : "none";

+			}

+

+			var newestAtTop = false;

+

+			/*----------------------------------------------------------------*/

+

+			function LogItemContentReverser() {

+			}

+			

+			LogItemContentReverser.prototype = new LogItemVisitor();

+			

+			LogItemContentReverser.prototype.visitGroup = function(group) {

+				group.reverseChildren();

+				this.visitChildren(group);

+			};

+

+			/*----------------------------------------------------------------*/

+

+			function setNewestAtTop(isNewestAtTop) {

+				var oldNewestAtTop = newestAtTop;

+				var i, iLen, j, jLen;

+				newestAtTop = Boolean(isNewestAtTop);

+				if (oldNewestAtTop != newestAtTop) {

+					var visitor = new LogItemContentReverser();

+					rootGroup.accept(visitor);

+

+					// Reassemble the matches array

+					if (currentSearch) {

+						var currentMatch = currentSearch.matches[currentMatchIndex];

+						var matchIndex = 0;

+						var matches = [];

+						var actOnLogEntry = function(logEntry) {

+							var logEntryMatches = logEntry.getSearchMatches();

+							for (j = 0, jLen = logEntryMatches.length; j < jLen; j++) {

+								matches[matchIndex] = logEntryMatches[j];

+								if (currentMatch && logEntryMatches[j].equals(currentMatch)) {

+									currentMatchIndex = matchIndex;

+								}

+								matchIndex++;

+							}

+						};

+						if (newestAtTop) {

+							for (i = logEntries.length - 1; i >= 0; i--) {

+								actOnLogEntry(logEntries[i]);

+							}

+						} else {

+							for (i = 0, iLen = logEntries.length; i < iLen; i++) {

+								actOnLogEntry(logEntries[i]);

+							}

+						}

+						currentSearch.matches = matches;

+						if (currentMatch) {

+							currentMatch.setCurrent();

+						}

+					} else if (scrollToLatest) {

+						doScrollToLatest();

+					}

+				}

+				$("newestAtTop").checked = isNewestAtTop;

+			}

+

+			function toggleNewestAtTop() {

+				var isNewestAtTop = $("newestAtTop").checked;

+				setNewestAtTop(isNewestAtTop);

+			}

+

+			var scrollToLatest = true;

+

+			function setScrollToLatest(isScrollToLatest) {

+				scrollToLatest = isScrollToLatest;

+				if (scrollToLatest) {

+					doScrollToLatest();

+				}

+				$("scrollToLatest").checked = isScrollToLatest;

+			}

+

+			function toggleScrollToLatest() {

+				var isScrollToLatest = $("scrollToLatest").checked;

+				setScrollToLatest(isScrollToLatest);

+			}

+

+			function doScrollToLatest() {

+				var l = logMainContainer;

+				if (typeof l.scrollTop != "undefined") {

+					if (newestAtTop) {

+						l.scrollTop = 0;

+					} else {

+						var latestLogEntry = l.lastChild;

+						if (latestLogEntry) {

+							l.scrollTop = l.scrollHeight;

+						}

+					}

+				}

+			}

+

+			var closeIfOpenerCloses = true;

+

+			function setCloseIfOpenerCloses(isCloseIfOpenerCloses) {

+				closeIfOpenerCloses = isCloseIfOpenerCloses;

+			}

+

+			var maxMessages = null;

+

+			function setMaxMessages(max) {

+				maxMessages = max;

+				pruneLogEntries();

+			}

+

+			var showCommandLine = false;

+

+			function setShowCommandLine(isShowCommandLine) {

+				showCommandLine = isShowCommandLine;

+				if (loaded) {

+					$("commandLine").style.display = showCommandLine ? "block" : "none";

+					setCommandInputWidth();

+					setLogContainerHeight();

+				}

+			}

+

+			function focusCommandLine() {

+				if (loaded) {

+					$("command").focus();

+				}

+			}

+

+			function focusSearch() {

+				if (loaded) {

+					$("searchBox").focus();

+				}

+			}

+

+			function getLogItems() {

+				var items = [];

+				for (var i = 0, len = logItems.length; i < len; i++) {

+					logItems[i].serialize(items);

+				}

+				return items;

+			}

+

+			function setLogItems(items) {

+				var loggingReallyEnabled = loggingEnabled;

+				// Temporarily turn logging on

+				loggingEnabled = true;

+				for (var i = 0, len = items.length; i < len; i++) {

+					switch (items[i][0]) {

+						case LogItem.serializedItemKeys.LOG_ENTRY:

+							log(items[i][1], items[i][2]);

+							break;

+						case LogItem.serializedItemKeys.GROUP_START:

+							group(items[i][1]);

+							break;

+						case LogItem.serializedItemKeys.GROUP_END:

+							groupEnd();

+							break;

+					}

+				}

+				loggingEnabled = loggingReallyEnabled;

+			}

+

+			function log(logLevel, formattedMessage) {

+				if (loggingEnabled) {

+					var logEntry = new LogEntry(logLevel, formattedMessage);

+					logEntries.push(logEntry);

+					logEntriesAndSeparators.push(logEntry);

+					logItems.push(logEntry);

+					currentGroup.addChild(logEntry);

+					if (loaded) {

+						if (logQueuedEventsTimer !== null) {

+							clearTimeout(logQueuedEventsTimer);

+						}

+						logQueuedEventsTimer = setTimeout(renderQueuedLogItems, renderDelay);

+						unrenderedLogItemsExist = true;

+					}

+				}

+			}

+

+			function renderQueuedLogItems() {

+				logQueuedEventsTimer = null;

+				var pruned = pruneLogEntries();

+

+				// Render any unrendered log entries and apply the current search to them

+				var initiallyHasMatches = currentSearch ? currentSearch.hasMatches() : false;

+				for (var i = 0, len = logItems.length; i < len; i++) {

+					if (!logItems[i].rendered) {

+						logItems[i].render();

+						logItems[i].appendToLog();

+						if (currentSearch && (logItems[i] instanceof LogEntry)) {

+							currentSearch.applyTo(logItems[i]);

+						}

+					}

+				}

+				if (currentSearch) {

+					if (pruned) {

+						if (currentSearch.hasVisibleMatches()) {

+							if (currentMatchIndex === null) {

+								setCurrentMatchIndex(0);

+							}

+							displayMatches();

+						} else {

+							displayNoMatches();

+						}

+					} else if (!initiallyHasMatches && currentSearch.hasVisibleMatches()) {

+						setCurrentMatchIndex(0);

+						displayMatches();

+					}

+				}

+				if (scrollToLatest) {

+					doScrollToLatest();

+				}

+				unrenderedLogItemsExist = false;

+			}

+

+			function pruneLogEntries() {

+				if ((maxMessages !== null) && (logEntriesAndSeparators.length > maxMessages)) {

+					var numberToDelete = logEntriesAndSeparators.length - maxMessages;

+					var prunedLogEntries = logEntriesAndSeparators.slice(0, numberToDelete);

+					if (currentSearch) {

+						currentSearch.removeMatches(prunedLogEntries);

+					}

+					var group;

+					for (var i = 0; i < numberToDelete; i++) {

+						group = logEntriesAndSeparators[i].group;

+						array_remove(logItems, logEntriesAndSeparators[i]);

+						array_remove(logEntries, logEntriesAndSeparators[i]);

+						logEntriesAndSeparators[i].remove(true, true);

+						if (group.children.length === 0 && group !== currentGroup && group !== rootGroup) {

+							array_remove(logItems, group);

+							group.remove(true, true);

+						}

+					}

+					logEntriesAndSeparators = array_removeFromStart(logEntriesAndSeparators, numberToDelete);

+					return true;

+				}

+				return false;

+			}

+

+			function group(name, startExpanded) {

+				if (loggingEnabled) {

+					initiallyExpanded = (typeof startExpanded === "undefined") ? true : Boolean(startExpanded);

+					var newGroup = new Group(name, false, initiallyExpanded);

+					currentGroup.addChild(newGroup);

+					currentGroup = newGroup;

+					logItems.push(newGroup);

+					if (loaded) {

+						if (logQueuedEventsTimer !== null) {

+							clearTimeout(logQueuedEventsTimer);

+						}

+						logQueuedEventsTimer = setTimeout(renderQueuedLogItems, renderDelay);

+						unrenderedLogItemsExist = true;

+					}

+				}

+			}

+

+			function groupEnd() {

+				currentGroup = (currentGroup === rootGroup) ? rootGroup : currentGroup.group;

+			}

+

+			function mainPageReloaded() {

+				currentGroup = rootGroup;

+				var separator = new Separator();

+				logEntriesAndSeparators.push(separator);

+				logItems.push(separator);

+				currentGroup.addChild(separator);

+			}

+

+			function closeWindow() {

+				if (appender && mainWindowExists()) {

+					appender.close(true);

+				} else {

+					window.close();

+				}

+			}

+

+			function hide() {

+				if (appender && mainWindowExists()) {

+					appender.hide();

+				}

+			}

+

+			var mainWindow = window;

+			var windowId = "log4javascriptConsoleWindow_" + new Date().getTime() + "_" + ("" + Math.random()).substr(2);

+

+			function setMainWindow(win) {

+				mainWindow = win;

+				mainWindow[windowId] = window;

+				// If this is a pop-up, poll the opener to see if it's closed

+				if (opener && closeIfOpenerCloses) {

+					pollOpener();

+				}

+			}

+

+			function pollOpener() {

+				if (closeIfOpenerCloses) {

+					if (mainWindowExists()) {

+						setTimeout(pollOpener, 500);

+					} else {

+						closeWindow();

+					}

+				}

+			}

+

+			function mainWindowExists() {

+				try {

+					return (mainWindow && !mainWindow.closed &&

+						mainWindow[windowId] == window);

+				} catch (ex) {}

+				return false;

+			}

+

+			var logLevels = ["TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"];

+

+			function getCheckBox(logLevel) {

+				return $("switch_" + logLevel);

+			}

+

+			function getIeWrappedLogContainer() {

+				return $("log_wrapped");

+			}

+

+			function getIeUnwrappedLogContainer() {

+				return $("log_unwrapped");

+			}

+

+			function applyFilters() {

+				for (var i = 0; i < logLevels.length; i++) {

+					if (getCheckBox(logLevels[i]).checked) {

+						addClass(logMainContainer, logLevels[i]);

+					} else {

+						removeClass(logMainContainer, logLevels[i]);

+					}

+				}

+				updateSearchFromFilters();

+			}

+

+			function toggleAllLevels() {

+				var turnOn = $("switch_ALL").checked;

+				for (var i = 0; i < logLevels.length; i++) {

+					getCheckBox(logLevels[i]).checked = turnOn;

+					if (turnOn) {

+						addClass(logMainContainer, logLevels[i]);

+					} else {

+						removeClass(logMainContainer, logLevels[i]);

+					}

+				}

+			}

+

+			function checkAllLevels() {

+				for (var i = 0; i < logLevels.length; i++) {

+					if (!getCheckBox(logLevels[i]).checked) {

+						getCheckBox("ALL").checked = false;

+						return;

+					}

+				}

+				getCheckBox("ALL").checked = true;

+			}

+

+			function clearLog() {

+				rootGroup.clear();

+				currentGroup = rootGroup;

+				logEntries = [];

+				logItems = [];

+				logEntriesAndSeparators = [];

+ 				doSearch();

+			}

+

+			function toggleWrap() {

+				var enable = $("wrap").checked;

+				if (enable) {

+					addClass(logMainContainer, "wrap");

+				} else {

+					removeClass(logMainContainer, "wrap");

+				}

+				refreshCurrentMatch();

+			}

+

+			/* ------------------------------------------------------------------- */

+

+			// Search

+

+			var searchTimer = null;

+

+			function scheduleSearch() {

+				try {

+					clearTimeout(searchTimer);

+				} catch (ex) {

+					// Do nothing

+				}

+				searchTimer = setTimeout(doSearch, 500);

+			}

+

+			function Search(searchTerm, isRegex, searchRegex, isCaseSensitive) {

+				this.searchTerm = searchTerm;

+				this.isRegex = isRegex;

+				this.searchRegex = searchRegex;

+				this.isCaseSensitive = isCaseSensitive;

+				this.matches = [];

+			}

+

+			Search.prototype = {

+				hasMatches: function() {

+					return this.matches.length > 0;

+				},

+

+				hasVisibleMatches: function() {

+					if (this.hasMatches()) {

+						for (var i = 0; i < this.matches.length; i++) {

+							if (this.matches[i].isVisible()) {

+								return true;

+							}

+						}

+					}

+					return false;

+				},

+

+				match: function(logEntry) {

+					var entryText = String(logEntry.formattedMessage);

+					var matchesSearch = false;

+					if (this.isRegex) {

+						matchesSearch = this.searchRegex.test(entryText);

+					} else if (this.isCaseSensitive) {

+						matchesSearch = (entryText.indexOf(this.searchTerm) > -1);

+					} else {

+						matchesSearch = (entryText.toLowerCase().indexOf(this.searchTerm.toLowerCase()) > -1);

+					}

+					return matchesSearch;

+				},

+

+				getNextVisibleMatchIndex: function() {

+					for (var i = currentMatchIndex + 1; i < this.matches.length; i++) {

+						if (this.matches[i].isVisible()) {

+							return i;

+						}

+					}

+					// Start again from the first match

+					for (i = 0; i <= currentMatchIndex; i++) {

+						if (this.matches[i].isVisible()) {

+							return i;

+						}

+					}

+					return -1;

+				},

+

+				getPreviousVisibleMatchIndex: function() {

+					for (var i = currentMatchIndex - 1; i >= 0; i--) {

+						if (this.matches[i].isVisible()) {

+							return i;

+						}

+					}

+					// Start again from the last match

+					for (var i = this.matches.length - 1; i >= currentMatchIndex; i--) {

+						if (this.matches[i].isVisible()) {

+							return i;

+						}

+					}

+					return -1;

+				},

+

+				applyTo: function(logEntry) {

+					var doesMatch = this.match(logEntry);

+					if (doesMatch) {

+						logEntry.group.expand();

+						logEntry.setSearchMatch(true);

+						var logEntryContent;

+						var wrappedLogEntryContent;

+						var searchTermReplacementStartTag = "<span class=\"searchterm\">";

+						var searchTermReplacementEndTag = "<" + "/span>";

+						var preTagName = isIe ? "pre" : "span";

+						var preStartTag = "<" + preTagName + " class=\"pre\">";

+						var preEndTag = "<" + "/" + preTagName + ">";

+						var startIndex = 0;

+						var searchIndex, matchedText, textBeforeMatch;

+						if (this.isRegex) {

+							var flags = this.isCaseSensitive ? "g" : "gi";

+							var capturingRegex = new RegExp("(" + this.searchRegex.source + ")", flags);

+

+							// Replace the search term with temporary tokens for the start and end tags

+							var rnd = ("" + Math.random()).substr(2);

+							var startToken = "%%s" + rnd + "%%";

+							var endToken = "%%e" + rnd + "%%";

+							logEntryContent = logEntry.formattedMessage.replace(capturingRegex, startToken + "$1" + endToken);

+

+							// Escape the HTML to get rid of angle brackets

+							logEntryContent = escapeHtml(logEntryContent);

+

+							// Substitute the proper HTML back in for the search match

+							var result;

+							var searchString = logEntryContent;

+							logEntryContent = "";

+							wrappedLogEntryContent = "";

+							while ((searchIndex = searchString.indexOf(startToken, startIndex)) > -1) {

+								var endTokenIndex = searchString.indexOf(endToken, searchIndex);

+								matchedText = searchString.substring(searchIndex + startToken.length, endTokenIndex);

+								textBeforeMatch = searchString.substring(startIndex, searchIndex);

+								logEntryContent += preStartTag + textBeforeMatch + preEndTag;

+								logEntryContent += searchTermReplacementStartTag + preStartTag + matchedText +

+									preEndTag + searchTermReplacementEndTag;

+								if (isIe) {

+									wrappedLogEntryContent += textBeforeMatch + searchTermReplacementStartTag +

+										matchedText + searchTermReplacementEndTag;

+								}

+								startIndex = endTokenIndex + endToken.length;

+							}

+							logEntryContent += preStartTag + searchString.substr(startIndex) + preEndTag;

+							if (isIe) {

+								wrappedLogEntryContent += searchString.substr(startIndex);

+							}

+						} else {

+							logEntryContent = "";

+							wrappedLogEntryContent = "";

+							var searchTermReplacementLength = searchTermReplacementStartTag.length +

+								this.searchTerm.length + searchTermReplacementEndTag.length;

+							var searchTermLength = this.searchTerm.length;

+							var searchTermLowerCase = this.searchTerm.toLowerCase();

+							var logTextLowerCase = logEntry.formattedMessage.toLowerCase();

+							while ((searchIndex = logTextLowerCase.indexOf(searchTermLowerCase, startIndex)) > -1) {

+								matchedText = escapeHtml(logEntry.formattedMessage.substr(searchIndex, this.searchTerm.length));

+								textBeforeMatch = escapeHtml(logEntry.formattedMessage.substring(startIndex, searchIndex));

+								var searchTermReplacement = searchTermReplacementStartTag +

+									preStartTag + matchedText + preEndTag + searchTermReplacementEndTag;

+								logEntryContent += preStartTag + textBeforeMatch + preEndTag + searchTermReplacement;

+								if (isIe) {

+									wrappedLogEntryContent += textBeforeMatch + searchTermReplacementStartTag +

+										matchedText + searchTermReplacementEndTag;

+								}

+								startIndex = searchIndex + searchTermLength;

+							}

+							var textAfterLastMatch = escapeHtml(logEntry.formattedMessage.substr(startIndex));

+							logEntryContent += preStartTag + textAfterLastMatch + preEndTag;

+							if (isIe) {

+								wrappedLogEntryContent += textAfterLastMatch;

+							}

+						}

+						logEntry.setContent(logEntryContent, wrappedLogEntryContent);

+						var logEntryMatches = logEntry.getSearchMatches();

+						this.matches = this.matches.concat(logEntryMatches);

+					} else {

+						logEntry.setSearchMatch(false);

+						logEntry.setContent(logEntry.formattedMessage, logEntry.formattedMessage);

+					}

+					return doesMatch;

+				},

+

+				removeMatches: function(logEntries) {

+					var matchesToRemoveCount = 0;

+					var currentMatchRemoved = false;

+					var matchesToRemove = [];

+					var i, iLen, j, jLen;

+

+					// Establish the list of matches to be removed

+					for (i = 0, iLen = this.matches.length; i < iLen; i++) {

+						for (j = 0, jLen = logEntries.length; j < jLen; j++) {

+							if (this.matches[i].belongsTo(logEntries[j])) {

+								matchesToRemove.push(this.matches[i]);

+								if (i === currentMatchIndex) {

+									currentMatchRemoved = true;

+								}

+							}

+						}

+					}

+

+					// Set the new current match index if the current match has been deleted

+					// This will be the first match that appears after the first log entry being

+					// deleted, if one exists; otherwise, it's the first match overall

+					var newMatch = currentMatchRemoved ? null : this.matches[currentMatchIndex];

+					if (currentMatchRemoved) {

+						for (i = currentMatchIndex, iLen = this.matches.length; i < iLen; i++) {

+							if (this.matches[i].isVisible() && !array_contains(matchesToRemove, this.matches[i])) {

+								newMatch = this.matches[i];

+								break;

+							}

+						}

+					}

+

+					// Remove the matches

+					for (i = 0, iLen = matchesToRemove.length; i < iLen; i++) {

+						array_remove(this.matches, matchesToRemove[i]);

+						matchesToRemove[i].remove();

+					}

+

+					// Set the new match, if one exists

+					if (this.hasVisibleMatches()) {

+						if (newMatch === null) {

+							setCurrentMatchIndex(0);

+						} else {

+							// Get the index of the new match

+							var newMatchIndex = 0;

+							for (i = 0, iLen = this.matches.length; i < iLen; i++) {

+								if (newMatch === this.matches[i]) {

+									newMatchIndex = i;

+									break;

+								}

+							}

+							setCurrentMatchIndex(newMatchIndex);

+						}

+					} else {

+						currentMatchIndex = null;

+						displayNoMatches();

+					}

+				}

+			};

+

+			function getPageOffsetTop(el, container) {

+				var currentEl = el;

+				var y = 0;

+				while (currentEl && currentEl != container) {

+					y += currentEl.offsetTop;

+					currentEl = currentEl.offsetParent;

+				}

+				return y;

+			}

+

+			function scrollIntoView(el) {

+				var logContainer = logMainContainer;

+				// Check if the whole width of the element is visible and centre if not

+				if (!$("wrap").checked) {

+					var logContainerLeft = logContainer.scrollLeft;

+					var logContainerRight = logContainerLeft  + logContainer.offsetWidth;

+					var elLeft = el.offsetLeft;

+					var elRight = elLeft + el.offsetWidth;

+					if (elLeft < logContainerLeft || elRight > logContainerRight) {

+						logContainer.scrollLeft = elLeft - (logContainer.offsetWidth - el.offsetWidth) / 2;

+					}

+				}

+				// Check if the whole height of the element is visible and centre if not

+				var logContainerTop = logContainer.scrollTop;

+				var logContainerBottom = logContainerTop  + logContainer.offsetHeight;

+				var elTop = getPageOffsetTop(el) - getToolBarsHeight();

+				var elBottom = elTop + el.offsetHeight;

+				if (elTop < logContainerTop || elBottom > logContainerBottom) {

+					logContainer.scrollTop = elTop - (logContainer.offsetHeight - el.offsetHeight) / 2;

+				}

+			}

+

+			function Match(logEntryLevel, spanInMainDiv, spanInUnwrappedPre, spanInWrappedDiv) {

+				this.logEntryLevel = logEntryLevel;

+				this.spanInMainDiv = spanInMainDiv;

+				if (isIe) {

+					this.spanInUnwrappedPre = spanInUnwrappedPre;

+					this.spanInWrappedDiv = spanInWrappedDiv;

+				}

+				this.mainSpan = isIe ? spanInUnwrappedPre : spanInMainDiv;

+			}

+

+			Match.prototype = {

+				equals: function(match) {

+					return this.mainSpan === match.mainSpan;

+				},

+

+				setCurrent: function() {

+					if (isIe) {

+						addClass(this.spanInUnwrappedPre, "currentmatch");

+						addClass(this.spanInWrappedDiv, "currentmatch");

+						// Scroll the visible one into view

+						var elementToScroll = $("wrap").checked ? this.spanInWrappedDiv : this.spanInUnwrappedPre;

+						scrollIntoView(elementToScroll);

+					} else {

+						addClass(this.spanInMainDiv, "currentmatch");

+						scrollIntoView(this.spanInMainDiv);

+					}

+				},

+

+				belongsTo: function(logEntry) {

+					if (isIe) {

+						return isDescendant(this.spanInUnwrappedPre, logEntry.unwrappedPre);

+					} else {

+						return isDescendant(this.spanInMainDiv, logEntry.mainDiv);

+					}

+				},

+

+				setNotCurrent: function() {

+					if (isIe) {

+						removeClass(this.spanInUnwrappedPre, "currentmatch");

+						removeClass(this.spanInWrappedDiv, "currentmatch");

+					} else {

+						removeClass(this.spanInMainDiv, "currentmatch");

+					}

+				},

+

+				isOrphan: function() {

+					return isOrphan(this.mainSpan);

+				},

+

+				isVisible: function() {

+					return getCheckBox(this.logEntryLevel).checked;

+				},

+

+				remove: function() {

+					if (isIe) {

+						this.spanInUnwrappedPre = null;

+						this.spanInWrappedDiv = null;

+					} else {

+						this.spanInMainDiv = null;

+					}

+				}

+			};

+

+			var currentSearch = null;

+			var currentMatchIndex = null;

+

+			function doSearch() {

+				var searchBox = $("searchBox");

+				var searchTerm = searchBox.value;

+				var isRegex = $("searchRegex").checked;

+				var isCaseSensitive = $("searchCaseSensitive").checked;

+				var i;

+

+				if (searchTerm === "") {

+					$("searchReset").disabled = true;

+					$("searchNav").style.display = "none";

+					removeClass(document.body, "searching");

+					removeClass(searchBox, "hasmatches");

+					removeClass(searchBox, "nomatches");

+					for (i = 0; i < logEntries.length; i++) {

+						logEntries[i].clearSearch();

+						logEntries[i].setContent(logEntries[i].formattedMessage, logEntries[i].formattedMessage);

+					}

+					currentSearch = null;

+					setLogContainerHeight();

+				} else {

+					$("searchReset").disabled = false;

+					$("searchNav").style.display = "block";

+					var searchRegex;

+					var regexValid;

+					if (isRegex) {

+						try {

+							searchRegex = isCaseSensitive ? new RegExp(searchTerm, "g") : new RegExp(searchTerm, "gi");

+							regexValid = true;

+							replaceClass(searchBox, "validregex", "invalidregex");

+							searchBox.title = "Valid regex";

+						} catch (ex) {

+							regexValid = false;

+							replaceClass(searchBox, "invalidregex", "validregex");

+							searchBox.title = "Invalid regex: " + (ex.message ? ex.message : (ex.description ? ex.description : "unknown error"));

+							return;

+						}

+					} else {

+						searchBox.title = "";

+						removeClass(searchBox, "validregex");

+						removeClass(searchBox, "invalidregex");

+					}

+					addClass(document.body, "searching");

+					currentSearch = new Search(searchTerm, isRegex, searchRegex, isCaseSensitive);

+					for (i = 0; i < logEntries.length; i++) {

+						currentSearch.applyTo(logEntries[i]);

+					}

+					setLogContainerHeight();

+

+					// Highlight the first search match

+					if (currentSearch.hasVisibleMatches()) {

+						setCurrentMatchIndex(0);

+						displayMatches();

+					} else {

+						displayNoMatches();

+					}

+				}

+			}

+

+			function updateSearchFromFilters() {

+				if (currentSearch) {

+					if (currentSearch.hasMatches()) {

+						if (currentMatchIndex === null) {

+							currentMatchIndex = 0;

+						}

+						var currentMatch = currentSearch.matches[currentMatchIndex];

+						if (currentMatch.isVisible()) {

+							displayMatches();

+							setCurrentMatchIndex(currentMatchIndex);

+						} else {

+							currentMatch.setNotCurrent();

+							// Find the next visible match, if one exists

+							var nextVisibleMatchIndex = currentSearch.getNextVisibleMatchIndex();

+							if (nextVisibleMatchIndex > -1) {

+								setCurrentMatchIndex(nextVisibleMatchIndex);

+								displayMatches();

+							} else {

+								displayNoMatches();

+							}

+						}

+					} else {

+						displayNoMatches();

+					}

+				}

+			}

+

+			function refreshCurrentMatch() {

+				if (currentSearch && currentSearch.hasVisibleMatches()) {

+					setCurrentMatchIndex(currentMatchIndex);

+				}

+			}

+

+			function displayMatches() {

+				replaceClass($("searchBox"), "hasmatches", "nomatches");

+				$("searchBox").title = "" + currentSearch.matches.length + " matches found";

+				$("searchNav").style.display = "block";

+				setLogContainerHeight();

+			}

+

+			function displayNoMatches() {

+				replaceClass($("searchBox"), "nomatches", "hasmatches");

+				$("searchBox").title = "No matches found";

+				$("searchNav").style.display = "none";

+				setLogContainerHeight();

+			}

+

+			function toggleSearchEnabled(enable) {

+				enable = (typeof enable == "undefined") ? !$("searchDisable").checked : enable;

+				$("searchBox").disabled = !enable;

+				$("searchReset").disabled = !enable;

+				$("searchRegex").disabled = !enable;

+				$("searchNext").disabled = !enable;

+				$("searchPrevious").disabled = !enable;

+				$("searchCaseSensitive").disabled = !enable;

+				$("searchNav").style.display = (enable && ($("searchBox").value !== "") &&

+						currentSearch && currentSearch.hasVisibleMatches()) ?

+					"block" : "none";

+				if (enable) {

+					removeClass($("search"), "greyedout");

+					addClass(document.body, "searching");

+					if ($("searchHighlight").checked) {

+						addClass(logMainContainer, "searchhighlight");

+					} else {

+						removeClass(logMainContainer, "searchhighlight");

+					}

+					if ($("searchFilter").checked) {

+						addClass(logMainContainer, "searchfilter");

+					} else {

+						removeClass(logMainContainer, "searchfilter");

+					}

+					$("searchDisable").checked = !enable;

+				} else {

+					addClass($("search"), "greyedout");

+					removeClass(document.body, "searching");

+					removeClass(logMainContainer, "searchhighlight");

+					removeClass(logMainContainer, "searchfilter");

+				}

+				setLogContainerHeight();

+			}

+

+			function toggleSearchFilter() {

+				var enable = $("searchFilter").checked;

+				if (enable) {

+					addClass(logMainContainer, "searchfilter");

+				} else {

+					removeClass(logMainContainer, "searchfilter");

+				}

+				refreshCurrentMatch();

+			}

+

+			function toggleSearchHighlight() {

+				var enable = $("searchHighlight").checked;

+				if (enable) {

+					addClass(logMainContainer, "searchhighlight");

+				} else {

+					removeClass(logMainContainer, "searchhighlight");

+				}

+			}

+

+			function clearSearch() {

+				$("searchBox").value = "";

+				doSearch();

+			}

+

+			function searchNext() {

+				if (currentSearch !== null && currentMatchIndex !== null) {

+					currentSearch.matches[currentMatchIndex].setNotCurrent();

+					var nextMatchIndex = currentSearch.getNextVisibleMatchIndex();

+					if (nextMatchIndex > currentMatchIndex || confirm("Reached the end of the page. Start from the top?")) {

+						setCurrentMatchIndex(nextMatchIndex);

+					}

+				}

+			}

+

+			function searchPrevious() {

+				if (currentSearch !== null && currentMatchIndex !== null) {

+					currentSearch.matches[currentMatchIndex].setNotCurrent();

+					var previousMatchIndex = currentSearch.getPreviousVisibleMatchIndex();

+					if (previousMatchIndex < currentMatchIndex || confirm("Reached the start of the page. Continue from the bottom?")) {

+						setCurrentMatchIndex(previousMatchIndex);

+					}

+				}

+			}

+

+			function setCurrentMatchIndex(index) {

+				currentMatchIndex = index;

+				currentSearch.matches[currentMatchIndex].setCurrent();

+			}

+

+			/* ------------------------------------------------------------------------- */

+

+			// CSS Utilities

+

+			function addClass(el, cssClass) {

+				if (!hasClass(el, cssClass)) {

+					if (el.className) {

+						el.className += " " + cssClass;

+					} else {

+						el.className = cssClass;

+					}

+				}

+			}

+

+			function hasClass(el, cssClass) {

+				if (el.className) {

+					var classNames = el.className.split(" ");

+					return array_contains(classNames, cssClass);

+				}

+				return false;

+			}

+

+			function removeClass(el, cssClass) {

+				if (hasClass(el, cssClass)) {

+					// Rebuild the className property

+					var existingClasses = el.className.split(" ");

+					var newClasses = [];

+					for (var i = 0, len = existingClasses.length; i < len; i++) {

+						if (existingClasses[i] != cssClass) {

+							newClasses[newClasses.length] = existingClasses[i];

+						}

+					}

+					el.className = newClasses.join(" ");

+				}

+			}

+

+			function replaceClass(el, newCssClass, oldCssClass) {

+				removeClass(el, oldCssClass);

+				addClass(el, newCssClass);

+			}

+

+			/* ------------------------------------------------------------------------- */

+

+			// Other utility functions

+

+			function getElementsByClass(el, cssClass, tagName) {

+				var elements = el.getElementsByTagName(tagName);

+				var matches = [];

+				for (var i = 0, len = elements.length; i < len; i++) {

+					if (hasClass(elements[i], cssClass)) {

+						matches.push(elements[i]);

+					}

+				}

+				return matches;

+			}

+

+			// Syntax borrowed from Prototype library

+			function $(id) {

+				return document.getElementById(id);

+			}

+

+			function isDescendant(node, ancestorNode) {

+				while (node != null) {

+					if (node === ancestorNode) {

+						return true;

+					}

+					node = node.parentNode;

+				}

+				return false;

+			}

+

+			function isOrphan(node) {

+				var currentNode = node;

+				while (currentNode) {

+					if (currentNode == document.body) {

+						return false;

+					}

+					currentNode = currentNode.parentNode;

+				}

+				return true;

+			}

+

+			function escapeHtml(str) {

+				return str.replace(/&/g, "&amp;").replace(/[<]/g, "&lt;").replace(/>/g, "&gt;");

+			}

+

+			function getWindowWidth() {

+				if (window.innerWidth) {

+					return window.innerWidth;

+				} else if (document.documentElement && document.documentElement.clientWidth) {

+					return document.documentElement.clientWidth;

+				} else if (document.body) {

+					return document.body.clientWidth;

+				}

+				return 0;

+			}

+

+			function getWindowHeight() {

+				if (window.innerHeight) {

+					return window.innerHeight;

+				} else if (document.documentElement && document.documentElement.clientHeight) {

+					return document.documentElement.clientHeight;

+				} else if (document.body) {

+					return document.body.clientHeight;

+				}

+				return 0;

+			}

+

+			function getToolBarsHeight() {

+				return $("switches").offsetHeight;

+			}

+

+			function getChromeHeight() {

+				var height = getToolBarsHeight();

+				if (showCommandLine) {

+					height += $("commandLine").offsetHeight;

+				}

+				return height;

+			}

+

+			function setLogContainerHeight() {

+				if (logMainContainer) {

+					var windowHeight = getWindowHeight();

+					$("body").style.height = getWindowHeight() + "px";

+					logMainContainer.style.height = "" +

+						Math.max(0, windowHeight - getChromeHeight()) + "px";

+				}

+			}

+

+			function setCommandInputWidth() {

+				if (showCommandLine) {

+					$("command").style.width = "" + Math.max(0, $("commandLineContainer").offsetWidth -

+						($("evaluateButton").offsetWidth + 13)) + "px";

+				}

+			}

+

+			window.onresize = function() {

+				setCommandInputWidth();

+				setLogContainerHeight();

+			};

+

+			if (!Array.prototype.push) {

+				Array.prototype.push = function() {

+			        for (var i = 0, len = arguments.length; i < len; i++){

+			            this[this.length] = arguments[i];

+			        }

+			        return this.length;

+				};

+			}

+

+			if (!Array.prototype.pop) {

+				Array.prototype.pop = function() {

+					if (this.length > 0) {

+						var val = this[this.length - 1];

+						this.length = this.length - 1;

+						return val;

+					}

+				};

+			}

+

+			if (!Array.prototype.shift) {

+				Array.prototype.shift = function() {

+					if (this.length > 0) {

+						var firstItem = this[0];

+						for (var i = 0, len = this.length - 1; i < len; i++) {

+							this[i] = this[i + 1];

+						}

+						this.length = this.length - 1;

+						return firstItem;

+					}

+				};

+			}

+

+			if (!Array.prototype.splice) {

+				Array.prototype.splice = function(startIndex, deleteCount) {

+					var itemsAfterDeleted = this.slice(startIndex + deleteCount);

+					var itemsDeleted = this.slice(startIndex, startIndex + deleteCount);

+					this.length = startIndex;

+					// Copy the arguments into a proper Array object

+					var argumentsArray = [];

+					for (var i = 0, len = arguments.length; i < len; i++) {

+						argumentsArray[i] = arguments[i];

+					}

+					var itemsToAppend = (argumentsArray.length > 2) ?

+						itemsAfterDeleted = argumentsArray.slice(2).concat(itemsAfterDeleted) : itemsAfterDeleted;

+					for (i = 0, len = itemsToAppend.length; i < len; i++) {

+						this.push(itemsToAppend[i]);

+					}

+					return itemsDeleted;

+				};

+			}

+

+			function array_remove(arr, val) {

+				var index = -1;

+				for (var i = 0, len = arr.length; i < len; i++) {

+					if (arr[i] === val) {

+						index = i;

+						break;

+					}

+				}

+				if (index >= 0) {

+					arr.splice(index, 1);

+					return index;

+				} else {

+					return false;

+				}

+			}

+

+			function array_removeFromStart(array, numberToRemove) {

+				if (Array.prototype.splice) {

+					array.splice(0, numberToRemove);

+				} else {

+					for (var i = numberToRemove, len = array.length; i < len; i++) {

+						array[i - numberToRemove] = array[i];

+					}

+					array.length = array.length - numberToRemove;

+				}

+				return array;

+			}

+

+			function array_contains(arr, val) {

+				for (var i = 0, len = arr.length; i < len; i++) {

+					if (arr[i] == val) {

+						return true;

+					}

+				}

+				return false;

+			}

+

+			function getErrorMessage(ex) {

+				if (ex.message) {

+					return ex.message;

+				} else if (ex.description) {

+					return ex.description;

+				}

+				return "" + ex;

+			}

+

+			function moveCaretToEnd(input) {

+				if (input.setSelectionRange) {

+					input.focus();

+					var length = input.value.length;

+					input.setSelectionRange(length, length);

+				} else if (input.createTextRange) {

+					var range = input.createTextRange();

+					range.collapse(false);

+					range.select();

+				}

+				input.focus();

+			}

+

+			function stopPropagation(evt) {

+				if (evt.stopPropagation) {

+					evt.stopPropagation();

+				} else if (typeof evt.cancelBubble != "undefined") {

+					evt.cancelBubble = true;

+				}

+			}

+

+			function getEvent(evt) {

+				return evt ? evt : event;

+			}

+

+			function getTarget(evt) {

+				return evt.target ? evt.target : evt.srcElement;

+			}

+

+			function getRelatedTarget(evt) {

+				if (evt.relatedTarget) {

+					return evt.relatedTarget;

+				} else if (evt.srcElement) {

+					switch(evt.type) {

+						case "mouseover":

+							return evt.fromElement;

+						case "mouseout":

+							return evt.toElement;

+						default:

+							return evt.srcElement;

+					}

+				}

+			}

+

+			function cancelKeyEvent(evt) {

+				evt.returnValue = false;

+				stopPropagation(evt);

+			}

+

+			function evalCommandLine() {

+				var expr = $("command").value;

+				evalCommand(expr);

+				$("command").value = "";

+			}

+

+			function evalLastCommand() {

+				if (lastCommand != null) {

+					evalCommand(lastCommand);

+				}

+			}

+

+			var lastCommand = null;

+			var commandHistory = [];

+			var currentCommandIndex = 0;

+

+			function evalCommand(expr) {

+				if (appender) {

+					appender.evalCommandAndAppend(expr);

+				} else {

+					var prefix = ">>> " + expr + "\r\n";

+					try {

+						log("INFO", prefix + eval(expr));

+					} catch (ex) {

+						log("ERROR", prefix + "Error: " + getErrorMessage(ex));

+					}

+				}

+				// Update command history

+				if (expr != commandHistory[commandHistory.length - 1]) {

+					commandHistory.push(expr);

+					// Update the appender

+					if (appender) {

+						appender.storeCommandHistory(commandHistory);

+					}

+				}

+				currentCommandIndex = (expr == commandHistory[currentCommandIndex]) ? currentCommandIndex + 1 : commandHistory.length;

+				lastCommand = expr;

+			}

+			//]]>

+		</script>

+		<style type="text/css">

+			body {

+				background-color: white;

+				color: black;

+				padding: 0;

+				margin: 0;

+				font-family: tahoma, verdana, arial, helvetica, sans-serif;

+				overflow: hidden;

+			}

+

+			div#switchesContainer input {

+				margin-bottom: 0;

+			}

+

+			div.toolbar {

+				border-top: solid #ffffff 1px;

+				border-bottom: solid #aca899 1px;

+				background-color: #f1efe7;

+				padding: 3px 5px;

+				font-size: 68.75%;

+			}

+

+			div.toolbar, div#search input {

+				font-family: tahoma, verdana, arial, helvetica, sans-serif;

+			}

+

+			div.toolbar input.button {

+				padding: 0 5px;

+				font-size: 100%;

+			}

+

+			div.toolbar input.hidden {

+				display: none;

+			}

+

+			div#switches input#clearButton {

+				margin-left: 20px;

+			}

+

+			div#levels label {

+				font-weight: bold;

+			}

+

+			div#levels label, div#options label {

+				margin-right: 5px;

+			}

+

+			div#levels label#wrapLabel {

+				font-weight: normal;

+			}

+

+			div#search label {

+				margin-right: 10px;

+			}

+

+			div#search label.searchboxlabel {

+				margin-right: 0;

+			}

+

+			div#search input {

+				font-size: 100%;

+			}

+

+			div#search input.validregex {

+				color: green;

+			}

+

+			div#search input.invalidregex {

+				color: red;

+			}

+

+			div#search input.nomatches {

+				color: white;

+				background-color: #ff6666;

+			}

+

+			div#search input.nomatches {

+				color: white;

+				background-color: #ff6666;

+			}

+

+			div#searchNav {

+				display: none;

+			}

+

+			div#commandLine {

+				display: none;

+			}

+

+			div#commandLine input#command {

+				font-size: 100%;

+				font-family: Courier New, Courier;

+			}

+

+			div#commandLine input#evaluateButton {

+			}

+

+			*.greyedout {

+				color: gray !important;

+				border-color: gray !important;

+			}

+

+			*.greyedout *.alwaysenabled { color: black; }

+

+			*.unselectable {

+				-khtml-user-select: none;

+				-moz-user-select: none;

+				user-select: none;

+			}

+

+			div#log {

+				font-family: Courier New, Courier;

+				font-size: 75%;

+				width: 100%;

+				overflow: auto;

+				clear: both;

+				position: relative;

+			}

+

+			div.group {

+				border-color: #cccccc;

+				border-style: solid;

+				border-width: 1px 0 1px 1px;

+				overflow: visible;

+			}

+

+			div.oldIe div.group, div.oldIe div.group *, div.oldIe *.logentry {

+				height: 1%;

+			}

+

+			div.group div.groupheading span.expander {

+				border: solid black 1px;

+				font-family: Courier New, Courier;

+				font-size: 0.833em;

+				background-color: #eeeeee;

+				position: relative;

+				top: -1px;

+				color: black;

+				padding: 0 2px;

+				cursor: pointer;

+				cursor: hand;

+				height: 1%;

+			}

+

+			div.group div.groupcontent {

+				margin-left: 10px;

+				padding-bottom: 2px;

+				overflow: visible;

+			}

+

+			div.group div.expanded {

+				display: block;

+			}

+

+			div.group div.collapsed {

+				display: none;

+			}

+

+			*.logentry {

+				overflow: visible;

+				display: none;

+				white-space: pre;

+			}

+

+			span.pre {

+				white-space: pre;

+			}

+			

+			pre.unwrapped {

+				display: inline !important;

+			}

+

+			pre.unwrapped pre.pre, div.wrapped pre.pre {

+				display: inline;

+			}

+

+			div.wrapped pre.pre {

+				white-space: normal;

+			}

+

+			div.wrapped {

+				display: none;

+			}

+

+			body.searching *.logentry span.currentmatch {

+				color: white !important;

+				background-color: green !important;

+			}

+

+			body.searching div.searchhighlight *.logentry span.searchterm {

+				color: black;

+				background-color: yellow;

+			}

+

+			div.wrap *.logentry {

+				white-space: normal !important;

+				border-width: 0 0 1px 0;

+				border-color: #dddddd;

+				border-style: dotted;

+			}

+

+			div.wrap #log_wrapped, #log_unwrapped {

+				display: block;

+			}

+

+			div.wrap #log_unwrapped, #log_wrapped {

+				display: none;

+			}

+

+			div.wrap *.logentry span.pre {

+				overflow: visible;

+				white-space: normal;

+			}

+

+			div.wrap *.logentry pre.unwrapped {

+				display: none;

+			}

+

+			div.wrap *.logentry span.wrapped {

+				display: inline;

+			}

+

+			div.searchfilter *.searchnonmatch {

+				display: none !important;

+			}

+

+			div#log *.TRACE, label#label_TRACE {

+				color: #666666;

+			}

+

+			div#log *.DEBUG, label#label_DEBUG {

+				color: green;

+			}

+

+			div#log *.INFO, label#label_INFO {

+				color: #000099;

+			}

+

+			div#log *.WARN, label#label_WARN {

+				color: #999900;

+			}

+

+			div#log *.ERROR, label#label_ERROR {

+				color: red;

+			}

+

+			div#log *.FATAL, label#label_FATAL {

+				color: #660066;

+			}

+

+			div.TRACE#log *.TRACE,

+			div.DEBUG#log *.DEBUG,

+			div.INFO#log *.INFO,

+			div.WARN#log *.WARN,

+			div.ERROR#log *.ERROR,

+			div.FATAL#log *.FATAL {

+				display: block;

+			}

+

+			div#log div.separator {

+				background-color: #cccccc;

+				margin: 5px 0;

+				line-height: 1px;

+			}

+		</style>

+	</head>

+

+	<body id="body">

+		<div id="switchesContainer">

+			<div id="switches">

+				<div id="levels" class="toolbar">

+					Filters:

+					<input type="checkbox" id="switch_TRACE" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide trace messages" /><label for="switch_TRACE" id="label_TRACE">trace</label>

+					<input type="checkbox" id="switch_DEBUG" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide debug messages" /><label for="switch_DEBUG" id="label_DEBUG">debug</label>

+					<input type="checkbox" id="switch_INFO" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide info messages" /><label for="switch_INFO" id="label_INFO">info</label>

+					<input type="checkbox" id="switch_WARN" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide warn messages" /><label for="switch_WARN" id="label_WARN">warn</label>

+					<input type="checkbox" id="switch_ERROR" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide error messages" /><label for="switch_ERROR" id="label_ERROR">error</label>

+					<input type="checkbox" id="switch_FATAL" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide fatal messages" /><label for="switch_FATAL" id="label_FATAL">fatal</label>

+					<input type="checkbox" id="switch_ALL" onclick="toggleAllLevels(); applyFilters()" checked="checked" title="Show/hide all messages" /><label for="switch_ALL" id="label_ALL">all</label>

+				</div>

+				<div id="search" class="toolbar">

+					<label for="searchBox" class="searchboxlabel">Search:</label> <input type="text" id="searchBox" onclick="toggleSearchEnabled(true)" onkeyup="scheduleSearch()" size="20" />

+					<input type="button" id="searchReset" disabled="disabled" value="Reset" onclick="clearSearch()" class="button" title="Reset the search" />

+					<input type="checkbox" id="searchRegex" onclick="doSearch()" title="If checked, search is treated as a regular expression" /><label for="searchRegex">Regex</label>

+					<input type="checkbox" id="searchCaseSensitive" onclick="doSearch()" title="If checked, search is case sensitive" /><label for="searchCaseSensitive">Match case</label>

+					<input type="checkbox" id="searchDisable" onclick="toggleSearchEnabled()" title="Enable/disable search" /><label for="searchDisable" class="alwaysenabled">Disable</label>

+					<div id="searchNav">

+						<input type="button" id="searchNext" disabled="disabled" value="Next" onclick="searchNext()" class="button" title="Go to the next matching log entry" />

+						<input type="button" id="searchPrevious" disabled="disabled" value="Previous" onclick="searchPrevious()" class="button" title="Go to the previous matching log entry" />

+						<input type="checkbox" id="searchFilter" onclick="toggleSearchFilter()" title="If checked, non-matching log entries are filtered out" /><label for="searchFilter">Filter</label>

+						<input type="checkbox" id="searchHighlight" onclick="toggleSearchHighlight()" title="Highlight matched search terms" /><label for="searchHighlight" class="alwaysenabled">Highlight all</label>

+					</div>

+				</div>

+				<div id="options" class="toolbar">

+					Options:

+					<input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Log</label>

+					<input type="checkbox" id="wrap" onclick="toggleWrap()" title="Enable / disable word wrap" /><label for="wrap" id="wrapLabel">Wrap</label>

+					<input type="checkbox" id="newestAtTop" onclick="toggleNewestAtTop()" title="If checked, causes newest messages to appear at the top" /><label for="newestAtTop" id="newestAtTopLabel">Newest at the top</label>

+					<input type="checkbox" id="scrollToLatest" onclick="toggleScrollToLatest()" checked="checked" title="If checked, window automatically scrolls to a new message when it is added" /><label for="scrollToLatest" id="scrollToLatestLabel">Scroll to latest</label>

+					<input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="button" title="Clear all log messages"  />

+					<input type="button" id="hideButton" value="Hide" onclick="hide()" class="hidden button" title="Hide the console" />

+					<input type="button" id="closeButton" value="Close" onclick="closeWindow()" class="hidden button" title="Close the window" />

+				</div>

+			</div>

+		</div>

+		<div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>

+		<div id="commandLine" class="toolbar">

+			<div id="commandLineContainer">

+				<input type="text" id="command" title="Enter a JavaScript command here and hit return or press 'Evaluate'" />

+				<input type="button" id="evaluateButton" value="Evaluate" class="button" title="Evaluate the command" onclick="evalCommandLine()" />

+			</div>

+		</div>

+	</body>

+</html>

diff --git a/xos/core/static/log4javascript-1.4.6/js/liteconsole.html b/xos/core/static/log4javascript-1.4.6/js/liteconsole.html
new file mode 100644
index 0000000..840a59b
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/js/liteconsole.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+<head>

+<title>log4javascript</title>

+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

+<!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->

+<meta http-equiv="X-UA-Compatible" content="IE=7" />

+<script type="text/javascript">

+//<![CDATA[

+var loggingEnabled=true;var messagesBeforeDocLoaded=[];function toggleLoggingEnabled(){setLoggingEnabled($("enableLogging").checked);}

+function setLoggingEnabled(enable){loggingEnabled=enable;}

+function scrollToLatestEntry(){var l=getLogContainer();if(typeof l.scrollTop!="undefined"){var latestLogEntry=l.lastChild;if(latestLogEntry){l.scrollTop=l.scrollHeight;}}}

+function log(logLevel,formattedMessage){if(loggingEnabled){if(loaded){doLog(logLevel,formattedMessage);}else{messagesBeforeDocLoaded.push([logLevel,formattedMessage]);}}}

+function doLog(logLevel,formattedMessage){var logEntry=document.createElement("div");logEntry.appendChild(document.createTextNode(formattedMessage));logEntry.className="logentry "+logLevel.name;getLogContainer().appendChild(logEntry);scrollToLatestEntry();}

+function mainPageReloaded(){var separator=document.createElement("div");separator.className="separator";separator.innerHTML="&nbsp;";getLogContainer().appendChild(separator);}

+var loaded=false;var logLevels=["DEBUG","INFO","WARN","ERROR","FATAL"];window.onload=function(){setLogContainerHeight();toggleLoggingEnabled();for(var i=0;i<messagesBeforeDocLoaded.length;i++){doLog(messagesBeforeDocLoaded[i][0],messagesBeforeDocLoaded[i][1]);}

+messagesBeforeDocLoaded=[];loaded=true;setTimeout(setLogContainerHeight,20);};function getLogContainer(){return $("log");}

+function clearLog(){getLogContainer().innerHTML="";}

+function $(id){return document.getElementById(id);}

+function getWindowHeight(){if(window.innerHeight){return window.innerHeight;}else if(document.documentElement&&document.documentElement.clientHeight){return document.documentElement.clientHeight;}else if(document.body){return document.body.clientHeight;}

+return 0;}

+function getChromeHeight(){return $("toolbar").offsetHeight;}

+function setLogContainerHeight(){var windowHeight=getWindowHeight();$("body").style.height=getWindowHeight()+"px";getLogContainer().style.height=""+

+Math.max(0,windowHeight-getChromeHeight())+"px";}

+window.onresize=function(){setLogContainerHeight();};

+//]]>

+</script>

+<style type="text/css">

+body{background-color:white;color:black;padding:0;margin:0;font-family:tahoma,verdana,arial,helvetica,sans-serif;overflow:hidden}div#toolbar{border-top:solid #ffffff 1px;border-bottom:solid #aca899 1px;background-color:#f1efe7;padding:3px 5px;font-size:68.75%}div#toolbar input.button{padding:0 5px;font-size:100%}div#log{font-family:Courier New,Courier;font-size:75%;width:100%;overflow:auto;clear:both}*.logentry{overflow:visible;white-space:pre}*.TRACE{color:#666666}*.DEBUG{color:green}*.INFO{color:#000099}*.WARN{color:#999900}*.ERROR{color:red}*.FATAL{color:#660066}div#log div.separator{background-color:#cccccc;margin:5px 0;line-height:1px}

+</style>

+</head>

+<body id="body">

+<div id="toolbar">

+Options:

+<input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" class="stateful" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Enable logging</label>

+<input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="stateful button" title="Clear all log messages"  />

+<input type="button" id="closeButton" value="Close" onclick="window.close()" class="stateful button" title="Close the window" />

+</div>

+<div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>

+</body>

+</html>
\ No newline at end of file
diff --git a/xos/core/static/log4javascript-1.4.6/js/liteconsole_uncompressed.html b/xos/core/static/log4javascript-1.4.6/js/liteconsole_uncompressed.html
new file mode 100644
index 0000000..df5275f
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/js/liteconsole_uncompressed.html
@@ -0,0 +1,194 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript</title>

+		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

+		<!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->

+		<meta http-equiv="X-UA-Compatible" content="IE=7" />

+		<script type="text/javascript">

+			//<![CDATA[

+			var loggingEnabled = true;

+			var messagesBeforeDocLoaded = [];

+

+			function toggleLoggingEnabled() {

+				setLoggingEnabled($("enableLogging").checked);

+			}

+

+			function setLoggingEnabled(enable) {

+				loggingEnabled = enable;

+			}

+

+			function scrollToLatestEntry() {

+				var l = getLogContainer();

+				if (typeof l.scrollTop != "undefined") {

+					var latestLogEntry = l.lastChild;

+					if (latestLogEntry) {

+						l.scrollTop = l.scrollHeight;

+					}

+				}

+			}

+

+			function log(logLevel, formattedMessage) {

+				if (loggingEnabled) {

+					if (loaded) {

+						doLog(logLevel, formattedMessage);

+					} else {

+						messagesBeforeDocLoaded.push([logLevel, formattedMessage]);

+					}

+				}

+			}

+

+			function doLog(logLevel, formattedMessage) {

+				var logEntry = document.createElement("div");

+				logEntry.appendChild(document.createTextNode(formattedMessage));

+				logEntry.className = "logentry " + logLevel.name;

+				getLogContainer().appendChild(logEntry);

+				scrollToLatestEntry();

+			}

+

+			function mainPageReloaded() {

+				var separator = document.createElement("div");

+				separator.className = "separator";

+				separator.innerHTML = "&nbsp;";

+				getLogContainer().appendChild(separator);

+			}

+

+			var loaded = false;

+			var logLevels = ["DEBUG", "INFO", "WARN", "ERROR", "FATAL"];

+

+			window.onload = function() {

+				setLogContainerHeight();

+				toggleLoggingEnabled();

+				for (var i = 0; i < messagesBeforeDocLoaded.length; i++) {

+					doLog(messagesBeforeDocLoaded[i][0], messagesBeforeDocLoaded[i][1]);

+				}

+				messagesBeforeDocLoaded = [];

+				loaded = true;

+

+				// Workaround to make sure log div starts at the correct size

+				setTimeout(setLogContainerHeight, 20);

+			};

+

+			function getLogContainer() {

+				return $("log");

+			}

+

+			function clearLog() {

+				getLogContainer().innerHTML = "";

+			}

+

+			/* ------------------------------------------------------------------------- */

+

+			// Other utility functions

+

+			// Syntax borrowed from Prototype library

+			function $(id) {

+				return document.getElementById(id);

+			}

+

+			function getWindowHeight() {

+				if (window.innerHeight) {

+					return window.innerHeight;

+				} else if (document.documentElement && document.documentElement.clientHeight) {

+					return document.documentElement.clientHeight;

+				} else if (document.body) {

+					return document.body.clientHeight;

+				}

+				return 0;

+			}

+

+			function getChromeHeight() {

+				return $("toolbar").offsetHeight;

+			}

+

+			function setLogContainerHeight() {

+				var windowHeight = getWindowHeight();

+				$("body").style.height = getWindowHeight() + "px";

+				getLogContainer().style.height = "" +

+					Math.max(0, windowHeight - getChromeHeight()) + "px";

+			}

+

+			window.onresize = function() {

+				setLogContainerHeight();

+			};

+

+			//]]>

+		</script>

+		<style type="text/css">

+			body {

+				background-color: white;

+				color: black;

+				padding: 0;

+				margin: 0;

+				font-family: tahoma, verdana, arial, helvetica, sans-serif;

+				overflow: hidden;

+			}

+			

+			div#toolbar {

+				border-top: solid #ffffff 1px;

+				border-bottom: solid #aca899 1px;

+				background-color: #f1efe7;

+				padding: 3px 5px;

+				font-size: 68.75%;

+			}

+

+			div#toolbar input.button {

+				padding: 0 5px;

+				font-size: 100%;

+			}

+

+			div#log {

+				font-family: Courier New, Courier;

+				font-size: 75%;

+				width: 100%;

+				overflow: auto;

+				clear: both;

+			}

+

+			*.logentry {

+				overflow: visible;

+				white-space: pre;

+			}

+

+			*.TRACE {

+				color: #666666;

+			}

+

+			*.DEBUG {

+				color: green;

+			}

+

+			*.INFO {

+				color: #000099;

+			}

+

+			*.WARN {

+				color: #999900;

+			}

+

+			*.ERROR {

+				color: red;

+			}

+

+			*.FATAL {

+				color: #660066;

+			}

+

+			div#log div.separator {

+				background-color: #cccccc;

+				margin: 5px 0;

+				line-height: 1px;

+			}

+		</style>

+	</head>

+

+	<body id="body">

+		<div id="toolbar">

+			Options:

+			<input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" class="stateful" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Enable logging</label>

+			<input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="stateful button" title="Clear all log messages"  />

+			<input type="button" id="closeButton" value="Close" onclick="window.close()" class="stateful button" title="Close the window" />

+		</div>

+		<div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>

+	</body>

+</html>
\ No newline at end of file
diff --git a/xos/core/static/log4javascript-1.4.6/js/log4javascript.js b/xos/core/static/log4javascript-1.4.6/js/log4javascript.js
new file mode 100644
index 0000000..042daa9
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/js/log4javascript.js
@@ -0,0 +1,274 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+

+if(!Array.prototype.push){Array.prototype.push=function(){for(var i=0,len=arguments.length;i<len;i++){this[this.length]=arguments[i];}

+return this.length;};}

+if(!Array.prototype.shift){Array.prototype.shift=function(){if(this.length>0){var firstItem=this[0];for(var i=0,len=this.length-1;i<len;i++){this[i]=this[i+1];}

+this.length=this.length-1;return firstItem;}};}

+if(!Array.prototype.splice){Array.prototype.splice=function(startIndex,deleteCount){var itemsAfterDeleted=this.slice(startIndex+deleteCount);var itemsDeleted=this.slice(startIndex,startIndex+deleteCount);this.length=startIndex;var argumentsArray=[];for(var i=0,len=arguments.length;i<len;i++){argumentsArray[i]=arguments[i];}

+var itemsToAppend=(argumentsArray.length>2)?itemsAfterDeleted=argumentsArray.slice(2).concat(itemsAfterDeleted):itemsAfterDeleted;for(i=0,len=itemsToAppend.length;i<len;i++){this.push(itemsToAppend[i]);}

+return itemsDeleted;};}

+var log4javascript=(function(){function isUndefined(obj){return typeof obj=="undefined";}

+function EventSupport(){}

+EventSupport.prototype={eventTypes:[],eventListeners:{},setEventTypes:function(eventTypesParam){if(eventTypesParam instanceof Array){this.eventTypes=eventTypesParam;this.eventListeners={};for(var i=0,len=this.eventTypes.length;i<len;i++){this.eventListeners[this.eventTypes[i]]=[];}}else{handleError("log4javascript.EventSupport ["+this+"]: setEventTypes: eventTypes parameter must be an Array");}},addEventListener:function(eventType,listener){if(typeof listener=="function"){if(!array_contains(this.eventTypes,eventType)){handleError("log4javascript.EventSupport ["+this+"]: addEventListener: no event called '"+eventType+"'");}

+this.eventListeners[eventType].push(listener);}else{handleError("log4javascript.EventSupport ["+this+"]: addEventListener: listener must be a function");}},removeEventListener:function(eventType,listener){if(typeof listener=="function"){if(!array_contains(this.eventTypes,eventType)){handleError("log4javascript.EventSupport ["+this+"]: removeEventListener: no event called '"+eventType+"'");}

+array_remove(this.eventListeners[eventType],listener);}else{handleError("log4javascript.EventSupport ["+this+"]: removeEventListener: listener must be a function");}},dispatchEvent:function(eventType,eventArgs){if(array_contains(this.eventTypes,eventType)){var listeners=this.eventListeners[eventType];for(var i=0,len=listeners.length;i<len;i++){listeners[i](this,eventType,eventArgs);}}else{handleError("log4javascript.EventSupport ["+this+"]: dispatchEvent: no event called '"+eventType+"'");}}};var applicationStartDate=new Date();var uniqueId="log4javascript_"+applicationStartDate.getTime()+"_"+

+Math.floor(Math.random()*100000000);var emptyFunction=function(){};var newLine="\r\n";var pageLoaded=false;function Log4JavaScript(){}

+Log4JavaScript.prototype=new EventSupport();log4javascript=new Log4JavaScript();log4javascript.version="1.4.6";log4javascript.edition="log4javascript";function toStr(obj){if(obj&&obj.toString){return obj.toString();}else{return String(obj);}}

+function getExceptionMessage(ex){if(ex.message){return ex.message;}else if(ex.description){return ex.description;}else{return toStr(ex);}}

+function getUrlFileName(url){var lastSlashIndex=Math.max(url.lastIndexOf("/"),url.lastIndexOf("\\"));return url.substr(lastSlashIndex+1);}

+function getExceptionStringRep(ex){if(ex){var exStr="Exception: "+getExceptionMessage(ex);try{if(ex.lineNumber){exStr+=" on line number "+ex.lineNumber;}

+if(ex.fileName){exStr+=" in file "+getUrlFileName(ex.fileName);}}catch(localEx){logLog.warn("Unable to obtain file and line information for error");}

+if(showStackTraces&&ex.stack){exStr+=newLine+"Stack trace:"+newLine+ex.stack;}

+return exStr;}

+return null;}

+function bool(obj){return Boolean(obj);}

+function trim(str){return str.replace(/^\s+/,"").replace(/\s+$/,"");}

+function splitIntoLines(text){var text2=text.replace(/\r\n/g,"\n").replace(/\r/g,"\n");return text2.split("\n");}

+var urlEncode=(typeof window.encodeURIComponent!="undefined")?function(str){return encodeURIComponent(str);}:function(str){return escape(str).replace(/\+/g,"%2B").replace(/"/g,"%22").replace(/'/g,"%27").replace(/\//g,"%2F").replace(/=/g,"%3D");};var urlDecode=(typeof window.decodeURIComponent!="undefined")?function(str){return decodeURIComponent(str);}:function(str){return unescape(str).replace(/%2B/g,"+").replace(/%22/g,"\"").replace(/%27/g,"'").replace(/%2F/g,"/").replace(/%3D/g,"=");};function array_remove(arr,val){var index=-1;for(var i=0,len=arr.length;i<len;i++){if(arr[i]===val){index=i;break;}}

+if(index>=0){arr.splice(index,1);return true;}else{return false;}}

+function array_contains(arr,val){for(var i=0,len=arr.length;i<len;i++){if(arr[i]==val){return true;}}

+return false;}

+function extractBooleanFromParam(param,defaultValue){if(isUndefined(param)){return defaultValue;}else{return bool(param);}}

+function extractStringFromParam(param,defaultValue){if(isUndefined(param)){return defaultValue;}else{return String(param);}}

+function extractIntFromParam(param,defaultValue){if(isUndefined(param)){return defaultValue;}else{try{var value=parseInt(param,10);return isNaN(value)?defaultValue:value;}catch(ex){logLog.warn("Invalid int param "+param,ex);return defaultValue;}}}

+function extractFunctionFromParam(param,defaultValue){if(typeof param=="function"){return param;}else{return defaultValue;}}

+function isError(err){return(err instanceof Error);}

+if(!Function.prototype.apply){Function.prototype.apply=function(obj,args){var methodName="__apply__";if(typeof obj[methodName]!="undefined"){methodName+=String(Math.random()).substr(2);}

+obj[methodName]=this;var argsStrings=[];for(var i=0,len=args.length;i<len;i++){argsStrings[i]="args["+i+"]";}

+var script="obj."+methodName+"("+argsStrings.join(",")+")";var returnValue=eval(script);delete obj[methodName];return returnValue;};}

+if(!Function.prototype.call){Function.prototype.call=function(obj){var args=[];for(var i=1,len=arguments.length;i<len;i++){args[i-1]=arguments[i];}

+return this.apply(obj,args);};}

+function getListenersPropertyName(eventName){return"__log4javascript_listeners__"+eventName;}

+function addEvent(node,eventName,listener,useCapture,win){win=win?win:window;if(node.addEventListener){node.addEventListener(eventName,listener,useCapture);}else if(node.attachEvent){node.attachEvent("on"+eventName,listener);}else{var propertyName=getListenersPropertyName(eventName);if(!node[propertyName]){node[propertyName]=[];node["on"+eventName]=function(evt){evt=getEvent(evt,win);var listenersPropertyName=getListenersPropertyName(eventName);var listeners=this[listenersPropertyName].concat([]);var currentListener;while((currentListener=listeners.shift())){currentListener.call(this,evt);}};}

+node[propertyName].push(listener);}}

+function removeEvent(node,eventName,listener,useCapture){if(node.removeEventListener){node.removeEventListener(eventName,listener,useCapture);}else if(node.detachEvent){node.detachEvent("on"+eventName,listener);}else{var propertyName=getListenersPropertyName(eventName);if(node[propertyName]){array_remove(node[propertyName],listener);}}}

+function getEvent(evt,win){win=win?win:window;return evt?evt:win.event;}

+function stopEventPropagation(evt){if(evt.stopPropagation){evt.stopPropagation();}else if(typeof evt.cancelBubble!="undefined"){evt.cancelBubble=true;}

+evt.returnValue=false;}

+var logLog={quietMode:false,debugMessages:[],setQuietMode:function(quietMode){this.quietMode=bool(quietMode);},numberOfErrors:0,alertAllErrors:false,setAlertAllErrors:function(alertAllErrors){this.alertAllErrors=alertAllErrors;},debug:function(message){this.debugMessages.push(message);},displayDebug:function(){alert(this.debugMessages.join(newLine));},warn:function(message,exception){},error:function(message,exception){if(++this.numberOfErrors==1||this.alertAllErrors){if(!this.quietMode){var alertMessage="log4javascript error: "+message;if(exception){alertMessage+=newLine+newLine+"Original error: "+getExceptionStringRep(exception);}

+alert(alertMessage);}}}};log4javascript.logLog=logLog;log4javascript.setEventTypes(["load","error"]);function handleError(message,exception){logLog.error(message,exception);log4javascript.dispatchEvent("error",{"message":message,"exception":exception});}

+log4javascript.handleError=handleError;var enabled=!((typeof log4javascript_disabled!="undefined")&&log4javascript_disabled);log4javascript.setEnabled=function(enable){enabled=bool(enable);};log4javascript.isEnabled=function(){return enabled;};var useTimeStampsInMilliseconds=true;log4javascript.setTimeStampsInMilliseconds=function(timeStampsInMilliseconds){useTimeStampsInMilliseconds=bool(timeStampsInMilliseconds);};log4javascript.isTimeStampsInMilliseconds=function(){return useTimeStampsInMilliseconds;};log4javascript.evalInScope=function(expr){return eval(expr);};var showStackTraces=false;log4javascript.setShowStackTraces=function(show){showStackTraces=bool(show);};var Level=function(level,name){this.level=level;this.name=name;};Level.prototype={toString:function(){return this.name;},equals:function(level){return this.level==level.level;},isGreaterOrEqual:function(level){return this.level>=level.level;}};Level.ALL=new Level(Number.MIN_VALUE,"ALL");Level.TRACE=new Level(10000,"TRACE");Level.DEBUG=new Level(20000,"DEBUG");Level.INFO=new Level(30000,"INFO");Level.WARN=new Level(40000,"WARN");Level.ERROR=new Level(50000,"ERROR");Level.FATAL=new Level(60000,"FATAL");Level.OFF=new Level(Number.MAX_VALUE,"OFF");log4javascript.Level=Level;function Timer(name,level){this.name=name;this.level=isUndefined(level)?Level.INFO:level;this.start=new Date();}

+Timer.prototype.getElapsedTime=function(){return new Date().getTime()-this.start.getTime();};var anonymousLoggerName="[anonymous]";var defaultLoggerName="[default]";var nullLoggerName="[null]";var rootLoggerName="root";function Logger(name){this.name=name;this.parent=null;this.children=[];var appenders=[];var loggerLevel=null;var isRoot=(this.name===rootLoggerName);var isNull=(this.name===nullLoggerName);var appenderCache=null;var appenderCacheInvalidated=false;this.addChild=function(childLogger){this.children.push(childLogger);childLogger.parent=this;childLogger.invalidateAppenderCache();};var additive=true;this.getAdditivity=function(){return additive;};this.setAdditivity=function(additivity){var valueChanged=(additive!=additivity);additive=additivity;if(valueChanged){this.invalidateAppenderCache();}};this.addAppender=function(appender){if(isNull){handleError("Logger.addAppender: you may not add an appender to the null logger");}else{if(appender instanceof log4javascript.Appender){if(!array_contains(appenders,appender)){appenders.push(appender);appender.setAddedToLogger(this);this.invalidateAppenderCache();}}else{handleError("Logger.addAppender: appender supplied ('"+

+toStr(appender)+"') is not a subclass of Appender");}}};this.removeAppender=function(appender){array_remove(appenders,appender);appender.setRemovedFromLogger(this);this.invalidateAppenderCache();};this.removeAllAppenders=function(){var appenderCount=appenders.length;if(appenderCount>0){for(var i=0;i<appenderCount;i++){appenders[i].setRemovedFromLogger(this);}

+appenders.length=0;this.invalidateAppenderCache();}};this.getEffectiveAppenders=function(){if(appenderCache===null||appenderCacheInvalidated){var parentEffectiveAppenders=(isRoot||!this.getAdditivity())?[]:this.parent.getEffectiveAppenders();appenderCache=parentEffectiveAppenders.concat(appenders);appenderCacheInvalidated=false;}

+return appenderCache;};this.invalidateAppenderCache=function(){appenderCacheInvalidated=true;for(var i=0,len=this.children.length;i<len;i++){this.children[i].invalidateAppenderCache();}};this.log=function(level,params){if(enabled&&level.isGreaterOrEqual(this.getEffectiveLevel())){var exception;var finalParamIndex=params.length-1;var lastParam=params[finalParamIndex];if(params.length>1&&isError(lastParam)){exception=lastParam;finalParamIndex--;}

+var messages=[];for(var i=0;i<=finalParamIndex;i++){messages[i]=params[i];}

+var loggingEvent=new LoggingEvent(this,new Date(),level,messages,exception);this.callAppenders(loggingEvent);}};this.callAppenders=function(loggingEvent){var effectiveAppenders=this.getEffectiveAppenders();for(var i=0,len=effectiveAppenders.length;i<len;i++){effectiveAppenders[i].doAppend(loggingEvent);}};this.setLevel=function(level){if(isRoot&&level===null){handleError("Logger.setLevel: you cannot set the level of the root logger to null");}else if(level instanceof Level){loggerLevel=level;}else{handleError("Logger.setLevel: level supplied to logger "+

+this.name+" is not an instance of log4javascript.Level");}};this.getLevel=function(){return loggerLevel;};this.getEffectiveLevel=function(){for(var logger=this;logger!==null;logger=logger.parent){var level=logger.getLevel();if(level!==null){return level;}}};this.group=function(name,initiallyExpanded){if(enabled){var effectiveAppenders=this.getEffectiveAppenders();for(var i=0,len=effectiveAppenders.length;i<len;i++){effectiveAppenders[i].group(name,initiallyExpanded);}}};this.groupEnd=function(){if(enabled){var effectiveAppenders=this.getEffectiveAppenders();for(var i=0,len=effectiveAppenders.length;i<len;i++){effectiveAppenders[i].groupEnd();}}};var timers={};this.time=function(name,level){if(enabled){if(isUndefined(name)){handleError("Logger.time: a name for the timer must be supplied");}else if(level&&!(level instanceof Level)){handleError("Logger.time: level supplied to timer "+

+name+" is not an instance of log4javascript.Level");}else{timers[name]=new Timer(name,level);}}};this.timeEnd=function(name){if(enabled){if(isUndefined(name)){handleError("Logger.timeEnd: a name for the timer must be supplied");}else if(timers[name]){var timer=timers[name];var milliseconds=timer.getElapsedTime();this.log(timer.level,["Timer "+toStr(name)+" completed in "+milliseconds+"ms"]);delete timers[name];}else{logLog.warn("Logger.timeEnd: no timer found with name "+name);}}};this.assert=function(expr){if(enabled&&!expr){var args=[];for(var i=1,len=arguments.length;i<len;i++){args.push(arguments[i]);}

+args=(args.length>0)?args:["Assertion Failure"];args.push(newLine);args.push(expr);this.log(Level.ERROR,args);}};this.toString=function(){return"Logger["+this.name+"]";};}

+Logger.prototype={trace:function(){this.log(Level.TRACE,arguments);},debug:function(){this.log(Level.DEBUG,arguments);},info:function(){this.log(Level.INFO,arguments);},warn:function(){this.log(Level.WARN,arguments);},error:function(){this.log(Level.ERROR,arguments);},fatal:function(){this.log(Level.FATAL,arguments);},isEnabledFor:function(level){return level.isGreaterOrEqual(this.getEffectiveLevel());},isTraceEnabled:function(){return this.isEnabledFor(Level.TRACE);},isDebugEnabled:function(){return this.isEnabledFor(Level.DEBUG);},isInfoEnabled:function(){return this.isEnabledFor(Level.INFO);},isWarnEnabled:function(){return this.isEnabledFor(Level.WARN);},isErrorEnabled:function(){return this.isEnabledFor(Level.ERROR);},isFatalEnabled:function(){return this.isEnabledFor(Level.FATAL);}};Logger.prototype.trace.isEntryPoint=true;Logger.prototype.debug.isEntryPoint=true;Logger.prototype.info.isEntryPoint=true;Logger.prototype.warn.isEntryPoint=true;Logger.prototype.error.isEntryPoint=true;Logger.prototype.fatal.isEntryPoint=true;var loggers={};var loggerNames=[];var ROOT_LOGGER_DEFAULT_LEVEL=Level.DEBUG;var rootLogger=new Logger(rootLoggerName);rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);log4javascript.getRootLogger=function(){return rootLogger;};log4javascript.getLogger=function(loggerName){if(!(typeof loggerName=="string")){loggerName=anonymousLoggerName;logLog.warn("log4javascript.getLogger: non-string logger name "+

+toStr(loggerName)+" supplied, returning anonymous logger");}

+if(loggerName==rootLoggerName){handleError("log4javascript.getLogger: root logger may not be obtained by name");}

+if(!loggers[loggerName]){var logger=new Logger(loggerName);loggers[loggerName]=logger;loggerNames.push(loggerName);var lastDotIndex=loggerName.lastIndexOf(".");var parentLogger;if(lastDotIndex>-1){var parentLoggerName=loggerName.substring(0,lastDotIndex);parentLogger=log4javascript.getLogger(parentLoggerName);}else{parentLogger=rootLogger;}

+parentLogger.addChild(logger);}

+return loggers[loggerName];};var defaultLogger=null;log4javascript.getDefaultLogger=function(){if(!defaultLogger){defaultLogger=log4javascript.getLogger(defaultLoggerName);var a=new log4javascript.PopUpAppender();defaultLogger.addAppender(a);}

+return defaultLogger;};var nullLogger=null;log4javascript.getNullLogger=function(){if(!nullLogger){nullLogger=new Logger(nullLoggerName);nullLogger.setLevel(Level.OFF);}

+return nullLogger;};log4javascript.resetConfiguration=function(){rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);loggers={};};var LoggingEvent=function(logger,timeStamp,level,messages,exception){this.logger=logger;this.timeStamp=timeStamp;this.timeStampInMilliseconds=timeStamp.getTime();this.timeStampInSeconds=Math.floor(this.timeStampInMilliseconds/1000);this.milliseconds=this.timeStamp.getMilliseconds();this.level=level;this.messages=messages;this.exception=exception;};LoggingEvent.prototype={getThrowableStrRep:function(){return this.exception?getExceptionStringRep(this.exception):"";},getCombinedMessages:function(){return(this.messages.length==1)?this.messages[0]:this.messages.join(newLine);},toString:function(){return"LoggingEvent["+this.level+"]";}};log4javascript.LoggingEvent=LoggingEvent;var Layout=function(){};Layout.prototype={defaults:{loggerKey:"logger",timeStampKey:"timestamp",millisecondsKey:"milliseconds",levelKey:"level",messageKey:"message",exceptionKey:"exception",urlKey:"url"},loggerKey:"logger",timeStampKey:"timestamp",millisecondsKey:"milliseconds",levelKey:"level",messageKey:"message",exceptionKey:"exception",urlKey:"url",batchHeader:"",batchFooter:"",batchSeparator:"",returnsPostData:false,overrideTimeStampsSetting:false,useTimeStampsInMilliseconds:null,format:function(){handleError("Layout.format: layout supplied has no format() method");},ignoresThrowable:function(){handleError("Layout.ignoresThrowable: layout supplied has no ignoresThrowable() method");},getContentType:function(){return"text/plain";},allowBatching:function(){return true;},setTimeStampsInMilliseconds:function(timeStampsInMilliseconds){this.overrideTimeStampsSetting=true;this.useTimeStampsInMilliseconds=bool(timeStampsInMilliseconds);},isTimeStampsInMilliseconds:function(){return this.overrideTimeStampsSetting?this.useTimeStampsInMilliseconds:useTimeStampsInMilliseconds;},getTimeStampValue:function(loggingEvent){return this.isTimeStampsInMilliseconds()?loggingEvent.timeStampInMilliseconds:loggingEvent.timeStampInSeconds;},getDataValues:function(loggingEvent,combineMessages){var dataValues=[[this.loggerKey,loggingEvent.logger.name],[this.timeStampKey,this.getTimeStampValue(loggingEvent)],[this.levelKey,loggingEvent.level.name],[this.urlKey,window.location.href],[this.messageKey,combineMessages?loggingEvent.getCombinedMessages():loggingEvent.messages]];if(!this.isTimeStampsInMilliseconds()){dataValues.push([this.millisecondsKey,loggingEvent.milliseconds]);}

+if(loggingEvent.exception){dataValues.push([this.exceptionKey,getExceptionStringRep(loggingEvent.exception)]);}

+if(this.hasCustomFields()){for(var i=0,len=this.customFields.length;i<len;i++){var val=this.customFields[i].value;if(typeof val==="function"){val=val(this,loggingEvent);}

+dataValues.push([this.customFields[i].name,val]);}}

+return dataValues;},setKeys:function(loggerKey,timeStampKey,levelKey,messageKey,exceptionKey,urlKey,millisecondsKey){this.loggerKey=extractStringFromParam(loggerKey,this.defaults.loggerKey);this.timeStampKey=extractStringFromParam(timeStampKey,this.defaults.timeStampKey);this.levelKey=extractStringFromParam(levelKey,this.defaults.levelKey);this.messageKey=extractStringFromParam(messageKey,this.defaults.messageKey);this.exceptionKey=extractStringFromParam(exceptionKey,this.defaults.exceptionKey);this.urlKey=extractStringFromParam(urlKey,this.defaults.urlKey);this.millisecondsKey=extractStringFromParam(millisecondsKey,this.defaults.millisecondsKey);},setCustomField:function(name,value){var fieldUpdated=false;for(var i=0,len=this.customFields.length;i<len;i++){if(this.customFields[i].name===name){this.customFields[i].value=value;fieldUpdated=true;}}

+if(!fieldUpdated){this.customFields.push({"name":name,"value":value});}},hasCustomFields:function(){return(this.customFields.length>0);},toString:function(){handleError("Layout.toString: all layouts must override this method");}};log4javascript.Layout=Layout;var Appender=function(){};Appender.prototype=new EventSupport();Appender.prototype.layout=new PatternLayout();Appender.prototype.threshold=Level.ALL;Appender.prototype.loggers=[];Appender.prototype.doAppend=function(loggingEvent){if(enabled&&loggingEvent.level.level>=this.threshold.level){this.append(loggingEvent);}};Appender.prototype.append=function(loggingEvent){};Appender.prototype.setLayout=function(layout){if(layout instanceof Layout){this.layout=layout;}else{handleError("Appender.setLayout: layout supplied to "+

+this.toString()+" is not a subclass of Layout");}};Appender.prototype.getLayout=function(){return this.layout;};Appender.prototype.setThreshold=function(threshold){if(threshold instanceof Level){this.threshold=threshold;}else{handleError("Appender.setThreshold: threshold supplied to "+

+this.toString()+" is not a subclass of Level");}};Appender.prototype.getThreshold=function(){return this.threshold;};Appender.prototype.setAddedToLogger=function(logger){this.loggers.push(logger);};Appender.prototype.setRemovedFromLogger=function(logger){array_remove(this.loggers,logger);};Appender.prototype.group=emptyFunction;Appender.prototype.groupEnd=emptyFunction;Appender.prototype.toString=function(){handleError("Appender.toString: all appenders must override this method");};log4javascript.Appender=Appender;function SimpleLayout(){this.customFields=[];}

+SimpleLayout.prototype=new Layout();SimpleLayout.prototype.format=function(loggingEvent){return loggingEvent.level.name+" - "+loggingEvent.getCombinedMessages();};SimpleLayout.prototype.ignoresThrowable=function(){return true;};SimpleLayout.prototype.toString=function(){return"SimpleLayout";};log4javascript.SimpleLayout=SimpleLayout;function NullLayout(){this.customFields=[];}

+NullLayout.prototype=new Layout();NullLayout.prototype.format=function(loggingEvent){return loggingEvent.messages;};NullLayout.prototype.ignoresThrowable=function(){return true;};NullLayout.prototype.toString=function(){return"NullLayout";};log4javascript.NullLayout=NullLayout;function XmlLayout(combineMessages){this.combineMessages=extractBooleanFromParam(combineMessages,true);this.customFields=[];}

+XmlLayout.prototype=new Layout();XmlLayout.prototype.isCombinedMessages=function(){return this.combineMessages;};XmlLayout.prototype.getContentType=function(){return"text/xml";};XmlLayout.prototype.escapeCdata=function(str){return str.replace(/\]\]>/,"]]>]]&gt;<![CDATA[");};XmlLayout.prototype.format=function(loggingEvent){var layout=this;var i,len;function formatMessage(message){message=(typeof message==="string")?message:toStr(message);return"<log4javascript:message><![CDATA["+

+layout.escapeCdata(message)+"]]></log4javascript:message>";}

+var str="<log4javascript:event logger=\""+loggingEvent.logger.name+"\" timestamp=\""+this.getTimeStampValue(loggingEvent)+"\"";if(!this.isTimeStampsInMilliseconds()){str+=" milliseconds=\""+loggingEvent.milliseconds+"\"";}

+str+=" level=\""+loggingEvent.level.name+"\">"+newLine;if(this.combineMessages){str+=formatMessage(loggingEvent.getCombinedMessages());}else{str+="<log4javascript:messages>"+newLine;for(i=0,len=loggingEvent.messages.length;i<len;i++){str+=formatMessage(loggingEvent.messages[i])+newLine;}

+str+="</log4javascript:messages>"+newLine;}

+if(this.hasCustomFields()){for(i=0,len=this.customFields.length;i<len;i++){str+="<log4javascript:customfield name=\""+

+this.customFields[i].name+"\"><![CDATA["+

+this.customFields[i].value.toString()+"]]></log4javascript:customfield>"+newLine;}}

+if(loggingEvent.exception){str+="<log4javascript:exception><![CDATA["+

+getExceptionStringRep(loggingEvent.exception)+"]]></log4javascript:exception>"+newLine;}

+str+="</log4javascript:event>"+newLine+newLine;return str;};XmlLayout.prototype.ignoresThrowable=function(){return false;};XmlLayout.prototype.toString=function(){return"XmlLayout";};log4javascript.XmlLayout=XmlLayout;function escapeNewLines(str){return str.replace(/\r\n|\r|\n/g,"\\r\\n");}

+function JsonLayout(readable,combineMessages){this.readable=extractBooleanFromParam(readable,false);this.combineMessages=extractBooleanFromParam(combineMessages,true);this.batchHeader=this.readable?"["+newLine:"[";this.batchFooter=this.readable?"]"+newLine:"]";this.batchSeparator=this.readable?","+newLine:",";this.setKeys();this.colon=this.readable?": ":":";this.tab=this.readable?"\t":"";this.lineBreak=this.readable?newLine:"";this.customFields=[];}

+JsonLayout.prototype=new Layout();JsonLayout.prototype.isReadable=function(){return this.readable;};JsonLayout.prototype.isCombinedMessages=function(){return this.combineMessages;};JsonLayout.prototype.format=function(loggingEvent){var layout=this;var dataValues=this.getDataValues(loggingEvent,this.combineMessages);var str="{"+this.lineBreak;var i,len;function formatValue(val,prefix,expand){var formattedValue;var valType=typeof val;if(val instanceof Date){formattedValue=String(val.getTime());}else if(expand&&(val instanceof Array)){formattedValue="["+layout.lineBreak;for(var i=0,len=val.length;i<len;i++){var childPrefix=prefix+layout.tab;formattedValue+=childPrefix+formatValue(val[i],childPrefix,false);if(i<val.length-1){formattedValue+=",";}

+formattedValue+=layout.lineBreak;}

+formattedValue+=prefix+"]";}else if(valType!=="number"&&valType!=="boolean"){formattedValue="\""+escapeNewLines(toStr(val).replace(/\"/g,"\\\""))+"\"";}else{formattedValue=val;}

+return formattedValue;}

+for(i=0,len=dataValues.length-1;i<=len;i++){str+=this.tab+"\""+dataValues[i][0]+"\""+this.colon+formatValue(dataValues[i][1],this.tab,true);if(i<len){str+=",";}

+str+=this.lineBreak;}

+str+="}"+this.lineBreak;return str;};JsonLayout.prototype.ignoresThrowable=function(){return false;};JsonLayout.prototype.toString=function(){return"JsonLayout";};JsonLayout.prototype.getContentType=function(){return"application/json";};log4javascript.JsonLayout=JsonLayout;function HttpPostDataLayout(){this.setKeys();this.customFields=[];this.returnsPostData=true;}

+HttpPostDataLayout.prototype=new Layout();HttpPostDataLayout.prototype.allowBatching=function(){return false;};HttpPostDataLayout.prototype.format=function(loggingEvent){var dataValues=this.getDataValues(loggingEvent);var queryBits=[];for(var i=0,len=dataValues.length;i<len;i++){var val=(dataValues[i][1]instanceof Date)?String(dataValues[i][1].getTime()):dataValues[i][1];queryBits.push(urlEncode(dataValues[i][0])+"="+urlEncode(val));}

+return queryBits.join("&");};HttpPostDataLayout.prototype.ignoresThrowable=function(loggingEvent){return false;};HttpPostDataLayout.prototype.toString=function(){return"HttpPostDataLayout";};log4javascript.HttpPostDataLayout=HttpPostDataLayout;function formatObjectExpansion(obj,depth,indentation){var objectsExpanded=[];function doFormat(obj,depth,indentation){var i,j,len,childDepth,childIndentation,childLines,expansion,childExpansion;if(!indentation){indentation="";}

+function formatString(text){var lines=splitIntoLines(text);for(var j=1,jLen=lines.length;j<jLen;j++){lines[j]=indentation+lines[j];}

+return lines.join(newLine);}

+if(obj===null){return"null";}else if(typeof obj=="undefined"){return"undefined";}else if(typeof obj=="string"){return formatString(obj);}else if(typeof obj=="object"&&array_contains(objectsExpanded,obj)){try{expansion=toStr(obj);}catch(ex){expansion="Error formatting property. Details: "+getExceptionStringRep(ex);}

+return expansion+" [already expanded]";}else if((obj instanceof Array)&&depth>0){objectsExpanded.push(obj);expansion="["+newLine;childDepth=depth-1;childIndentation=indentation+"  ";childLines=[];for(i=0,len=obj.length;i<len;i++){try{childExpansion=doFormat(obj[i],childDepth,childIndentation);childLines.push(childIndentation+childExpansion);}catch(ex){childLines.push(childIndentation+"Error formatting array member. Details: "+

+getExceptionStringRep(ex)+"");}}

+expansion+=childLines.join(","+newLine)+newLine+indentation+"]";return expansion;}else if(Object.prototype.toString.call(obj)=="[object Date]"){return obj.toString();}else if(typeof obj=="object"&&depth>0){objectsExpanded.push(obj);expansion="{"+newLine;childDepth=depth-1;childIndentation=indentation+"  ";childLines=[];for(i in obj){try{childExpansion=doFormat(obj[i],childDepth,childIndentation);childLines.push(childIndentation+i+": "+childExpansion);}catch(ex){childLines.push(childIndentation+i+": Error formatting property. Details: "+

+getExceptionStringRep(ex));}}

+expansion+=childLines.join(","+newLine)+newLine+indentation+"}";return expansion;}else{return formatString(toStr(obj));}}

+return doFormat(obj,depth,indentation);}

+var SimpleDateFormat;(function(){var regex=/('[^']*')|(G+|y+|M+|w+|W+|D+|d+|F+|E+|a+|H+|k+|K+|h+|m+|s+|S+|Z+)|([a-zA-Z]+)|([^a-zA-Z']+)/;var monthNames=["January","February","March","April","May","June","July","August","September","October","November","December"];var dayNames=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];var TEXT2=0,TEXT3=1,NUMBER=2,YEAR=3,MONTH=4,TIMEZONE=5;var types={G:TEXT2,y:YEAR,M:MONTH,w:NUMBER,W:NUMBER,D:NUMBER,d:NUMBER,F:NUMBER,E:TEXT3,a:TEXT2,H:NUMBER,k:NUMBER,K:NUMBER,h:NUMBER,m:NUMBER,s:NUMBER,S:NUMBER,Z:TIMEZONE};var ONE_DAY=24*60*60*1000;var ONE_WEEK=7*ONE_DAY;var DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK=1;var newDateAtMidnight=function(year,month,day){var d=new Date(year,month,day,0,0,0);d.setMilliseconds(0);return d;};Date.prototype.getDifference=function(date){return this.getTime()-date.getTime();};Date.prototype.isBefore=function(d){return this.getTime()<d.getTime();};Date.prototype.getUTCTime=function(){return Date.UTC(this.getFullYear(),this.getMonth(),this.getDate(),this.getHours(),this.getMinutes(),this.getSeconds(),this.getMilliseconds());};Date.prototype.getTimeSince=function(d){return this.getUTCTime()-d.getUTCTime();};Date.prototype.getPreviousSunday=function(){var midday=new Date(this.getFullYear(),this.getMonth(),this.getDate(),12,0,0);var previousSunday=new Date(midday.getTime()-this.getDay()*ONE_DAY);return newDateAtMidnight(previousSunday.getFullYear(),previousSunday.getMonth(),previousSunday.getDate());};Date.prototype.getWeekInYear=function(minimalDaysInFirstWeek){if(isUndefined(this.minimalDaysInFirstWeek)){minimalDaysInFirstWeek=DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;}

+var previousSunday=this.getPreviousSunday();var startOfYear=newDateAtMidnight(this.getFullYear(),0,1);var numberOfSundays=previousSunday.isBefore(startOfYear)?0:1+Math.floor(previousSunday.getTimeSince(startOfYear)/ONE_WEEK);var numberOfDaysInFirstWeek=7-startOfYear.getDay();var weekInYear=numberOfSundays;if(numberOfDaysInFirstWeek<minimalDaysInFirstWeek){weekInYear--;}

+return weekInYear;};Date.prototype.getWeekInMonth=function(minimalDaysInFirstWeek){if(isUndefined(this.minimalDaysInFirstWeek)){minimalDaysInFirstWeek=DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;}

+var previousSunday=this.getPreviousSunday();var startOfMonth=newDateAtMidnight(this.getFullYear(),this.getMonth(),1);var numberOfSundays=previousSunday.isBefore(startOfMonth)?0:1+Math.floor(previousSunday.getTimeSince(startOfMonth)/ONE_WEEK);var numberOfDaysInFirstWeek=7-startOfMonth.getDay();var weekInMonth=numberOfSundays;if(numberOfDaysInFirstWeek>=minimalDaysInFirstWeek){weekInMonth++;}

+return weekInMonth;};Date.prototype.getDayInYear=function(){var startOfYear=newDateAtMidnight(this.getFullYear(),0,1);return 1+Math.floor(this.getTimeSince(startOfYear)/ONE_DAY);};SimpleDateFormat=function(formatString){this.formatString=formatString;};SimpleDateFormat.prototype.setMinimalDaysInFirstWeek=function(days){this.minimalDaysInFirstWeek=days;};SimpleDateFormat.prototype.getMinimalDaysInFirstWeek=function(){return isUndefined(this.minimalDaysInFirstWeek)?DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK:this.minimalDaysInFirstWeek;};var padWithZeroes=function(str,len){while(str.length<len){str="0"+str;}

+return str;};var formatText=function(data,numberOfLetters,minLength){return(numberOfLetters>=4)?data:data.substr(0,Math.max(minLength,numberOfLetters));};var formatNumber=function(data,numberOfLetters){var dataString=""+data;return padWithZeroes(dataString,numberOfLetters);};SimpleDateFormat.prototype.format=function(date){var formattedString="";var result;var searchString=this.formatString;while((result=regex.exec(searchString))){var quotedString=result[1];var patternLetters=result[2];var otherLetters=result[3];var otherCharacters=result[4];if(quotedString){if(quotedString=="''"){formattedString+="'";}else{formattedString+=quotedString.substring(1,quotedString.length-1);}}else if(otherLetters){}else if(otherCharacters){formattedString+=otherCharacters;}else if(patternLetters){var patternLetter=patternLetters.charAt(0);var numberOfLetters=patternLetters.length;var rawData="";switch(patternLetter){case"G":rawData="AD";break;case"y":rawData=date.getFullYear();break;case"M":rawData=date.getMonth();break;case"w":rawData=date.getWeekInYear(this.getMinimalDaysInFirstWeek());break;case"W":rawData=date.getWeekInMonth(this.getMinimalDaysInFirstWeek());break;case"D":rawData=date.getDayInYear();break;case"d":rawData=date.getDate();break;case"F":rawData=1+Math.floor((date.getDate()-1)/7);break;case"E":rawData=dayNames[date.getDay()];break;case"a":rawData=(date.getHours()>=12)?"PM":"AM";break;case"H":rawData=date.getHours();break;case"k":rawData=date.getHours()||24;break;case"K":rawData=date.getHours()%12;break;case"h":rawData=(date.getHours()%12)||12;break;case"m":rawData=date.getMinutes();break;case"s":rawData=date.getSeconds();break;case"S":rawData=date.getMilliseconds();break;case"Z":rawData=date.getTimezoneOffset();break;}

+switch(types[patternLetter]){case TEXT2:formattedString+=formatText(rawData,numberOfLetters,2);break;case TEXT3:formattedString+=formatText(rawData,numberOfLetters,3);break;case NUMBER:formattedString+=formatNumber(rawData,numberOfLetters);break;case YEAR:if(numberOfLetters<=3){var dataString=""+rawData;formattedString+=dataString.substr(2,2);}else{formattedString+=formatNumber(rawData,numberOfLetters);}

+break;case MONTH:if(numberOfLetters>=3){formattedString+=formatText(monthNames[rawData],numberOfLetters,numberOfLetters);}else{formattedString+=formatNumber(rawData+1,numberOfLetters);}

+break;case TIMEZONE:var isPositive=(rawData>0);var prefix=isPositive?"-":"+";var absData=Math.abs(rawData);var hours=""+Math.floor(absData/60);hours=padWithZeroes(hours,2);var minutes=""+(absData%60);minutes=padWithZeroes(minutes,2);formattedString+=prefix+hours+minutes;break;}}

+searchString=searchString.substr(result.index+result[0].length);}

+return formattedString;};})();log4javascript.SimpleDateFormat=SimpleDateFormat;function PatternLayout(pattern){if(pattern){this.pattern=pattern;}else{this.pattern=PatternLayout.DEFAULT_CONVERSION_PATTERN;}

+this.customFields=[];}

+PatternLayout.TTCC_CONVERSION_PATTERN="%r %p %c - %m%n";PatternLayout.DEFAULT_CONVERSION_PATTERN="%m%n";PatternLayout.ISO8601_DATEFORMAT="yyyy-MM-dd HH:mm:ss,SSS";PatternLayout.DATETIME_DATEFORMAT="dd MMM yyyy HH:mm:ss,SSS";PatternLayout.ABSOLUTETIME_DATEFORMAT="HH:mm:ss,SSS";PatternLayout.prototype=new Layout();PatternLayout.prototype.format=function(loggingEvent){var regex=/%(-?[0-9]+)?(\.?[0-9]+)?([acdfmMnpr%])(\{([^\}]+)\})?|([^%]+)/;var formattedString="";var result;var searchString=this.pattern;while((result=regex.exec(searchString))){var matchedString=result[0];var padding=result[1];var truncation=result[2];var conversionCharacter=result[3];var specifier=result[5];var text=result[6];if(text){formattedString+=""+text;}else{var replacement="";switch(conversionCharacter){case"a":case"m":var depth=0;if(specifier){depth=parseInt(specifier,10);if(isNaN(depth)){handleError("PatternLayout.format: invalid specifier '"+

+specifier+"' for conversion character '"+conversionCharacter+"' - should be a number");depth=0;}}

+var messages=(conversionCharacter==="a")?loggingEvent.messages[0]:loggingEvent.messages;for(var i=0,len=messages.length;i<len;i++){if(i>0&&(replacement.charAt(replacement.length-1)!==" ")){replacement+=" ";}

+if(depth===0){replacement+=messages[i];}else{replacement+=formatObjectExpansion(messages[i],depth);}}

+break;case"c":var loggerName=loggingEvent.logger.name;if(specifier){var precision=parseInt(specifier,10);var loggerNameBits=loggingEvent.logger.name.split(".");if(precision>=loggerNameBits.length){replacement=loggerName;}else{replacement=loggerNameBits.slice(loggerNameBits.length-precision).join(".");}}else{replacement=loggerName;}

+break;case"d":var dateFormat=PatternLayout.ISO8601_DATEFORMAT;if(specifier){dateFormat=specifier;if(dateFormat=="ISO8601"){dateFormat=PatternLayout.ISO8601_DATEFORMAT;}else if(dateFormat=="ABSOLUTE"){dateFormat=PatternLayout.ABSOLUTETIME_DATEFORMAT;}else if(dateFormat=="DATE"){dateFormat=PatternLayout.DATETIME_DATEFORMAT;}}

+replacement=(new SimpleDateFormat(dateFormat)).format(loggingEvent.timeStamp);break;case"f":if(this.hasCustomFields()){var fieldIndex=0;if(specifier){fieldIndex=parseInt(specifier,10);if(isNaN(fieldIndex)){handleError("PatternLayout.format: invalid specifier '"+

+specifier+"' for conversion character 'f' - should be a number");}else if(fieldIndex===0){handleError("PatternLayout.format: invalid specifier '"+

+specifier+"' for conversion character 'f' - must be greater than zero");}else if(fieldIndex>this.customFields.length){handleError("PatternLayout.format: invalid specifier '"+

+specifier+"' for conversion character 'f' - there aren't that many custom fields");}else{fieldIndex=fieldIndex-1;}}

+var val=this.customFields[fieldIndex].value;if(typeof val=="function"){val=val(this,loggingEvent);}

+replacement=val;}

+break;case"n":replacement=newLine;break;case"p":replacement=loggingEvent.level.name;break;case"r":replacement=""+loggingEvent.timeStamp.getDifference(applicationStartDate);break;case"%":replacement="%";break;default:replacement=matchedString;break;}

+var l;if(truncation){l=parseInt(truncation.substr(1),10);var strLen=replacement.length;if(l<strLen){replacement=replacement.substring(strLen-l,strLen);}}

+if(padding){if(padding.charAt(0)=="-"){l=parseInt(padding.substr(1),10);while(replacement.length<l){replacement+=" ";}}else{l=parseInt(padding,10);while(replacement.length<l){replacement=" "+replacement;}}}

+formattedString+=replacement;}

+searchString=searchString.substr(result.index+result[0].length);}

+return formattedString;};PatternLayout.prototype.ignoresThrowable=function(){return true;};PatternLayout.prototype.toString=function(){return"PatternLayout";};log4javascript.PatternLayout=PatternLayout;function AlertAppender(){}

+AlertAppender.prototype=new Appender();AlertAppender.prototype.layout=new SimpleLayout();AlertAppender.prototype.append=function(loggingEvent){var formattedMessage=this.getLayout().format(loggingEvent);if(this.getLayout().ignoresThrowable()){formattedMessage+=loggingEvent.getThrowableStrRep();}

+alert(formattedMessage);};AlertAppender.prototype.toString=function(){return"AlertAppender";};log4javascript.AlertAppender=AlertAppender;function BrowserConsoleAppender(){}

+BrowserConsoleAppender.prototype=new log4javascript.Appender();BrowserConsoleAppender.prototype.layout=new NullLayout();BrowserConsoleAppender.prototype.threshold=Level.DEBUG;BrowserConsoleAppender.prototype.append=function(loggingEvent){var appender=this;var getFormattedMessage=function(){var layout=appender.getLayout();var formattedMessage=layout.format(loggingEvent);if(layout.ignoresThrowable()&&loggingEvent.exception){formattedMessage+=loggingEvent.getThrowableStrRep();}

+return formattedMessage;};if((typeof opera!="undefined")&&opera.postError){opera.postError(getFormattedMessage());}else if(window.console&&window.console.log){var formattedMesage=getFormattedMessage();if(window.console.debug&&Level.DEBUG.isGreaterOrEqual(loggingEvent.level)){window.console.debug(formattedMesage);}else if(window.console.info&&Level.INFO.equals(loggingEvent.level)){window.console.info(formattedMesage);}else if(window.console.warn&&Level.WARN.equals(loggingEvent.level)){window.console.warn(formattedMesage);}else if(window.console.error&&loggingEvent.level.isGreaterOrEqual(Level.ERROR)){window.console.error(formattedMesage);}else{window.console.log(formattedMesage);}}};BrowserConsoleAppender.prototype.group=function(name){if(window.console&&window.console.group){window.console.group(name);}};BrowserConsoleAppender.prototype.groupEnd=function(){if(window.console&&window.console.groupEnd){window.console.groupEnd();}};BrowserConsoleAppender.prototype.toString=function(){return"BrowserConsoleAppender";};log4javascript.BrowserConsoleAppender=BrowserConsoleAppender;var xmlHttpFactories=[function(){return new XMLHttpRequest();},function(){return new ActiveXObject("Msxml2.XMLHTTP");},function(){return new ActiveXObject("Microsoft.XMLHTTP");}];var getXmlHttp=function(errorHandler){var xmlHttp=null,factory;for(var i=0,len=xmlHttpFactories.length;i<len;i++){factory=xmlHttpFactories[i];try{xmlHttp=factory();getXmlHttp=factory;return xmlHttp;}catch(e){}}

+if(errorHandler){errorHandler();}else{handleError("getXmlHttp: unable to obtain XMLHttpRequest object");}};function isHttpRequestSuccessful(xmlHttp){return isUndefined(xmlHttp.status)||xmlHttp.status===0||(xmlHttp.status>=200&&xmlHttp.status<300)||xmlHttp.status==1223;}

+function AjaxAppender(url){var appender=this;var isSupported=true;if(!url){handleError("AjaxAppender: URL must be specified in constructor");isSupported=false;}

+var timed=this.defaults.timed;var waitForResponse=this.defaults.waitForResponse;var batchSize=this.defaults.batchSize;var timerInterval=this.defaults.timerInterval;var requestSuccessCallback=this.defaults.requestSuccessCallback;var failCallback=this.defaults.failCallback;var postVarName=this.defaults.postVarName;var sendAllOnUnload=this.defaults.sendAllOnUnload;var contentType=this.defaults.contentType;var sessionId=null;var queuedLoggingEvents=[];var queuedRequests=[];var headers=[];var sending=false;var initialized=false;function checkCanConfigure(configOptionName){if(initialized){handleError("AjaxAppender: configuration option '"+

+configOptionName+"' may not be set after the appender has been initialized");return false;}

+return true;}

+this.getSessionId=function(){return sessionId;};this.setSessionId=function(sessionIdParam){sessionId=extractStringFromParam(sessionIdParam,null);this.layout.setCustomField("sessionid",sessionId);};this.setLayout=function(layoutParam){if(checkCanConfigure("layout")){this.layout=layoutParam;if(sessionId!==null){this.setSessionId(sessionId);}}};this.isTimed=function(){return timed;};this.setTimed=function(timedParam){if(checkCanConfigure("timed")){timed=bool(timedParam);}};this.getTimerInterval=function(){return timerInterval;};this.setTimerInterval=function(timerIntervalParam){if(checkCanConfigure("timerInterval")){timerInterval=extractIntFromParam(timerIntervalParam,timerInterval);}};this.isWaitForResponse=function(){return waitForResponse;};this.setWaitForResponse=function(waitForResponseParam){if(checkCanConfigure("waitForResponse")){waitForResponse=bool(waitForResponseParam);}};this.getBatchSize=function(){return batchSize;};this.setBatchSize=function(batchSizeParam){if(checkCanConfigure("batchSize")){batchSize=extractIntFromParam(batchSizeParam,batchSize);}};this.isSendAllOnUnload=function(){return sendAllOnUnload;};this.setSendAllOnUnload=function(sendAllOnUnloadParam){if(checkCanConfigure("sendAllOnUnload")){sendAllOnUnload=extractBooleanFromParam(sendAllOnUnloadParam,sendAllOnUnload);}};this.setRequestSuccessCallback=function(requestSuccessCallbackParam){requestSuccessCallback=extractFunctionFromParam(requestSuccessCallbackParam,requestSuccessCallback);};this.setFailCallback=function(failCallbackParam){failCallback=extractFunctionFromParam(failCallbackParam,failCallback);};this.getPostVarName=function(){return postVarName;};this.setPostVarName=function(postVarNameParam){if(checkCanConfigure("postVarName")){postVarName=extractStringFromParam(postVarNameParam,postVarName);}};this.getHeaders=function(){return headers;};this.addHeader=function(name,value){if(name.toLowerCase()=="content-type"){contentType=value;}else{headers.push({name:name,value:value});}};function sendAll(){if(isSupported&&enabled){sending=true;var currentRequestBatch;if(waitForResponse){if(queuedRequests.length>0){currentRequestBatch=queuedRequests.shift();sendRequest(preparePostData(currentRequestBatch),sendAll);}else{sending=false;if(timed){scheduleSending();}}}else{while((currentRequestBatch=queuedRequests.shift())){sendRequest(preparePostData(currentRequestBatch));}

+sending=false;if(timed){scheduleSending();}}}}

+this.sendAll=sendAll;function sendAllRemaining(){var sendingAnything=false;if(isSupported&&enabled){var actualBatchSize=appender.getLayout().allowBatching()?batchSize:1;var currentLoggingEvent;var batchedLoggingEvents=[];while((currentLoggingEvent=queuedLoggingEvents.shift())){batchedLoggingEvents.push(currentLoggingEvent);if(queuedLoggingEvents.length>=actualBatchSize){queuedRequests.push(batchedLoggingEvents);batchedLoggingEvents=[];}}

+if(batchedLoggingEvents.length>0){queuedRequests.push(batchedLoggingEvents);}

+sendingAnything=(queuedRequests.length>0);waitForResponse=false;timed=false;sendAll();}

+return sendingAnything;}

+this.sendAllRemaining=sendAllRemaining;function preparePostData(batchedLoggingEvents){var formattedMessages=[];var currentLoggingEvent;var postData="";while((currentLoggingEvent=batchedLoggingEvents.shift())){var currentFormattedMessage=appender.getLayout().format(currentLoggingEvent);if(appender.getLayout().ignoresThrowable()){currentFormattedMessage+=currentLoggingEvent.getThrowableStrRep();}

+formattedMessages.push(currentFormattedMessage);}

+if(batchedLoggingEvents.length==1){postData=formattedMessages.join("");}else{postData=appender.getLayout().batchHeader+

+formattedMessages.join(appender.getLayout().batchSeparator)+

+appender.getLayout().batchFooter;}

+if(contentType==appender.defaults.contentType){postData=appender.getLayout().returnsPostData?postData:urlEncode(postVarName)+"="+urlEncode(postData);if(postData.length>0){postData+="&";}

+postData+="layout="+urlEncode(appender.getLayout().toString());}

+return postData;}

+function scheduleSending(){window.setTimeout(sendAll,timerInterval);}

+function xmlHttpErrorHandler(){var msg="AjaxAppender: could not create XMLHttpRequest object. AjaxAppender disabled";handleError(msg);isSupported=false;if(failCallback){failCallback(msg);}}

+function sendRequest(postData,successCallback){try{var xmlHttp=getXmlHttp(xmlHttpErrorHandler);if(isSupported){if(xmlHttp.overrideMimeType){xmlHttp.overrideMimeType(appender.getLayout().getContentType());}

+xmlHttp.onreadystatechange=function(){if(xmlHttp.readyState==4){if(isHttpRequestSuccessful(xmlHttp)){if(requestSuccessCallback){requestSuccessCallback(xmlHttp);}

+if(successCallback){successCallback(xmlHttp);}}else{var msg="AjaxAppender.append: XMLHttpRequest request to URL "+

+url+" returned status code "+xmlHttp.status;handleError(msg);if(failCallback){failCallback(msg);}}

+xmlHttp.onreadystatechange=emptyFunction;xmlHttp=null;}};xmlHttp.open("POST",url,true);try{for(var i=0,header;header=headers[i++];){xmlHttp.setRequestHeader(header.name,header.value);}

+xmlHttp.setRequestHeader("Content-Type",contentType);}catch(headerEx){var msg="AjaxAppender.append: your browser's XMLHttpRequest implementation"+" does not support setRequestHeader, therefore cannot post data. AjaxAppender disabled";handleError(msg);isSupported=false;if(failCallback){failCallback(msg);}

+return;}

+xmlHttp.send(postData);}}catch(ex){var errMsg="AjaxAppender.append: error sending log message to "+url;handleError(errMsg,ex);isSupported=false;if(failCallback){failCallback(errMsg+". Details: "+getExceptionStringRep(ex));}}}

+this.append=function(loggingEvent){if(isSupported){if(!initialized){init();}

+queuedLoggingEvents.push(loggingEvent);var actualBatchSize=this.getLayout().allowBatching()?batchSize:1;if(queuedLoggingEvents.length>=actualBatchSize){var currentLoggingEvent;var batchedLoggingEvents=[];while((currentLoggingEvent=queuedLoggingEvents.shift())){batchedLoggingEvents.push(currentLoggingEvent);}

+queuedRequests.push(batchedLoggingEvents);if(!timed&&(!waitForResponse||(waitForResponse&&!sending))){sendAll();}}}};function init(){initialized=true;if(sendAllOnUnload){var oldBeforeUnload=window.onbeforeunload;window.onbeforeunload=function(){if(oldBeforeUnload){oldBeforeUnload();}

+if(sendAllRemaining()){return"Sending log messages";}};}

+if(timed){scheduleSending();}}}

+AjaxAppender.prototype=new Appender();AjaxAppender.prototype.defaults={waitForResponse:false,timed:false,timerInterval:1000,batchSize:1,sendAllOnUnload:false,requestSuccessCallback:null,failCallback:null,postVarName:"data",contentType:"application/x-www-form-urlencoded"};AjaxAppender.prototype.layout=new HttpPostDataLayout();AjaxAppender.prototype.toString=function(){return"AjaxAppender";};log4javascript.AjaxAppender=AjaxAppender;function setCookie(name,value,days,path){var expires;path=path?"; path="+path:"";if(days){var date=new Date();date.setTime(date.getTime()+(days*24*60*60*1000));expires="; expires="+date.toGMTString();}else{expires="";}

+document.cookie=escape(name)+"="+escape(value)+expires+path;}

+function getCookie(name){var nameEquals=escape(name)+"=";var ca=document.cookie.split(";");for(var i=0,len=ca.length;i<len;i++){var c=ca[i];while(c.charAt(0)===" "){c=c.substring(1,c.length);}

+if(c.indexOf(nameEquals)===0){return unescape(c.substring(nameEquals.length,c.length));}}

+return null;}

+function getBaseUrl(){var scripts=document.getElementsByTagName("script");for(var i=0,len=scripts.length;i<len;++i){if(scripts[i].src.indexOf("log4javascript")!=-1){var lastSlash=scripts[i].src.lastIndexOf("/");return(lastSlash==-1)?"":scripts[i].src.substr(0,lastSlash+1);}}

+return null;}

+function isLoaded(win){try{return bool(win.loaded);}catch(ex){return false;}}

+var ConsoleAppender;(function(){var getConsoleHtmlLines=function(){return['<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">','<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">','<head>','<title>log4javascript</title>','<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />','<!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->','<meta http-equiv="X-UA-Compatible" content="IE=7" />','<script type="text/javascript">var isIe = false, isIePre7 = false;</script>','<!--[if IE]><script type="text/javascript">isIe = true</script><![endif]-->','<!--[if lt IE 7]><script type="text/javascript">isIePre7 = true</script><![endif]-->','<script type="text/javascript">','//<![CDATA[','var loggingEnabled=true;var logQueuedEventsTimer=null;var logEntries=[];var logEntriesAndSeparators=[];var logItems=[];var renderDelay=100;var unrenderedLogItemsExist=false;var rootGroup,currentGroup=null;var loaded=false;var currentLogItem=null;var logMainContainer;function copyProperties(obj,props){for(var i in props){obj[i]=props[i];}}','function LogItem(){}','LogItem.prototype={mainContainer:null,wrappedContainer:null,unwrappedContainer:null,group:null,appendToLog:function(){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].appendToLog();}','this.group.update();},doRemove:function(doUpdate,removeFromGroup){if(this.rendered){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].remove();}','this.unwrappedElementContainer=null;this.wrappedElementContainer=null;this.mainElementContainer=null;}','if(this.group&&removeFromGroup){this.group.removeChild(this,doUpdate);}','if(this===currentLogItem){currentLogItem=null;}},remove:function(doUpdate,removeFromGroup){this.doRemove(doUpdate,removeFromGroup);},render:function(){},accept:function(visitor){visitor.visit(this);},getUnwrappedDomContainer:function(){return this.group.unwrappedElementContainer.contentDiv;},getWrappedDomContainer:function(){return this.group.wrappedElementContainer.contentDiv;},getMainDomContainer:function(){return this.group.mainElementContainer.contentDiv;}};LogItem.serializedItemKeys={LOG_ENTRY:0,GROUP_START:1,GROUP_END:2};function LogItemContainerElement(){}','LogItemContainerElement.prototype={appendToLog:function(){var insertBeforeFirst=(newestAtTop&&this.containerDomNode.hasChildNodes());if(insertBeforeFirst){this.containerDomNode.insertBefore(this.mainDiv,this.containerDomNode.firstChild);}else{this.containerDomNode.appendChild(this.mainDiv);}}};function SeparatorElementContainer(containerDomNode){this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.className="separator";this.mainDiv.innerHTML="&nbsp;";}','SeparatorElementContainer.prototype=new LogItemContainerElement();SeparatorElementContainer.prototype.remove=function(){this.mainDiv.parentNode.removeChild(this.mainDiv);this.mainDiv=null;};function Separator(){this.rendered=false;}','Separator.prototype=new LogItem();copyProperties(Separator.prototype,{render:function(){var containerDomNode=this.group.contentDiv;if(isIe){this.unwrappedElementContainer=new SeparatorElementContainer(this.getUnwrappedDomContainer());this.wrappedElementContainer=new SeparatorElementContainer(this.getWrappedDomContainer());this.elementContainers=[this.unwrappedElementContainer,this.wrappedElementContainer];}else{this.mainElementContainer=new SeparatorElementContainer(this.getMainDomContainer());this.elementContainers=[this.mainElementContainer];}','this.content=this.formattedMessage;this.rendered=true;}});function GroupElementContainer(group,containerDomNode,isRoot,isWrapped){this.group=group;this.containerDomNode=containerDomNode;this.isRoot=isRoot;this.isWrapped=isWrapped;this.expandable=false;if(this.isRoot){if(isIe){this.contentDiv=logMainContainer.appendChild(document.createElement("div"));this.contentDiv.id=this.isWrapped?"log_wrapped":"log_unwrapped";}else{this.contentDiv=logMainContainer;}}else{var groupElementContainer=this;this.mainDiv=document.createElement("div");this.mainDiv.className="group";this.headingDiv=this.mainDiv.appendChild(document.createElement("div"));this.headingDiv.className="groupheading";this.expander=this.headingDiv.appendChild(document.createElement("span"));this.expander.className="expander unselectable greyedout";this.expander.unselectable=true;var expanderText=this.group.expanded?"-":"+";this.expanderTextNode=this.expander.appendChild(document.createTextNode(expanderText));this.headingDiv.appendChild(document.createTextNode(" "+this.group.name));this.contentDiv=this.mainDiv.appendChild(document.createElement("div"));var contentCssClass=this.group.expanded?"expanded":"collapsed";this.contentDiv.className="groupcontent "+contentCssClass;this.expander.onclick=function(){if(groupElementContainer.group.expandable){groupElementContainer.group.toggleExpanded();}};}}','GroupElementContainer.prototype=new LogItemContainerElement();copyProperties(GroupElementContainer.prototype,{toggleExpanded:function(){if(!this.isRoot){var oldCssClass,newCssClass,expanderText;if(this.group.expanded){newCssClass="expanded";oldCssClass="collapsed";expanderText="-";}else{newCssClass="collapsed";oldCssClass="expanded";expanderText="+";}','replaceClass(this.contentDiv,newCssClass,oldCssClass);this.expanderTextNode.nodeValue=expanderText;}},remove:function(){if(!this.isRoot){this.headingDiv=null;this.expander.onclick=null;this.expander=null;this.expanderTextNode=null;this.contentDiv=null;this.containerDomNode=null;this.mainDiv.parentNode.removeChild(this.mainDiv);this.mainDiv=null;}},reverseChildren:function(){var node=null;var childDomNodes=[];while((node=this.contentDiv.firstChild)){this.contentDiv.removeChild(node);childDomNodes.push(node);}','while((node=childDomNodes.pop())){this.contentDiv.appendChild(node);}},update:function(){if(!this.isRoot){if(this.group.expandable){removeClass(this.expander,"greyedout");}else{addClass(this.expander,"greyedout");}}},clear:function(){if(this.isRoot){this.contentDiv.innerHTML="";}}});function Group(name,isRoot,initiallyExpanded){this.name=name;this.group=null;this.isRoot=isRoot;this.initiallyExpanded=initiallyExpanded;this.elementContainers=[];this.children=[];this.expanded=initiallyExpanded;this.rendered=false;this.expandable=false;}','Group.prototype=new LogItem();copyProperties(Group.prototype,{addChild:function(logItem){this.children.push(logItem);logItem.group=this;},render:function(){if(isIe){var unwrappedDomContainer,wrappedDomContainer;if(this.isRoot){unwrappedDomContainer=logMainContainer;wrappedDomContainer=logMainContainer;}else{unwrappedDomContainer=this.getUnwrappedDomContainer();wrappedDomContainer=this.getWrappedDomContainer();}','this.unwrappedElementContainer=new GroupElementContainer(this,unwrappedDomContainer,this.isRoot,false);this.wrappedElementContainer=new GroupElementContainer(this,wrappedDomContainer,this.isRoot,true);this.elementContainers=[this.unwrappedElementContainer,this.wrappedElementContainer];}else{var mainDomContainer=this.isRoot?logMainContainer:this.getMainDomContainer();this.mainElementContainer=new GroupElementContainer(this,mainDomContainer,this.isRoot,false);this.elementContainers=[this.mainElementContainer];}','this.rendered=true;},toggleExpanded:function(){this.expanded=!this.expanded;for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].toggleExpanded();}},expand:function(){if(!this.expanded){this.toggleExpanded();}},accept:function(visitor){visitor.visitGroup(this);},reverseChildren:function(){if(this.rendered){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].reverseChildren();}}},update:function(){var previouslyExpandable=this.expandable;this.expandable=(this.children.length!==0);if(this.expandable!==previouslyExpandable){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].update();}}},flatten:function(){var visitor=new GroupFlattener();this.accept(visitor);return visitor.logEntriesAndSeparators;},removeChild:function(child,doUpdate){array_remove(this.children,child);child.group=null;if(doUpdate){this.update();}},remove:function(doUpdate,removeFromGroup){for(var i=0,len=this.children.length;i<len;i++){this.children[i].remove(false,false);}','this.children=[];this.update();if(this===currentGroup){currentGroup=this.group;}','this.doRemove(doUpdate,removeFromGroup);},serialize:function(items){items.push([LogItem.serializedItemKeys.GROUP_START,this.name]);for(var i=0,len=this.children.length;i<len;i++){this.children[i].serialize(items);}','if(this!==currentGroup){items.push([LogItem.serializedItemKeys.GROUP_END]);}},clear:function(){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].clear();}}});function LogEntryElementContainer(){}','LogEntryElementContainer.prototype=new LogItemContainerElement();copyProperties(LogEntryElementContainer.prototype,{remove:function(){this.doRemove();},doRemove:function(){this.mainDiv.parentNode.removeChild(this.mainDiv);this.mainDiv=null;this.contentElement=null;this.containerDomNode=null;},setContent:function(content,wrappedContent){if(content===this.formattedMessage){this.contentElement.innerHTML="";this.contentElement.appendChild(document.createTextNode(this.formattedMessage));}else{this.contentElement.innerHTML=content;}},setSearchMatch:function(isMatch){var oldCssClass=isMatch?"searchnonmatch":"searchmatch";var newCssClass=isMatch?"searchmatch":"searchnonmatch";replaceClass(this.mainDiv,newCssClass,oldCssClass);},clearSearch:function(){removeClass(this.mainDiv,"searchmatch");removeClass(this.mainDiv,"searchnonmatch");}});function LogEntryWrappedElementContainer(logEntry,containerDomNode){this.logEntry=logEntry;this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.appendChild(document.createTextNode(this.logEntry.formattedMessage));this.mainDiv.className="logentry wrapped "+this.logEntry.level;this.contentElement=this.mainDiv;}','LogEntryWrappedElementContainer.prototype=new LogEntryElementContainer();LogEntryWrappedElementContainer.prototype.setContent=function(content,wrappedContent){if(content===this.formattedMessage){this.contentElement.innerHTML="";this.contentElement.appendChild(document.createTextNode(this.formattedMessage));}else{this.contentElement.innerHTML=wrappedContent;}};function LogEntryUnwrappedElementContainer(logEntry,containerDomNode){this.logEntry=logEntry;this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.className="logentry unwrapped "+this.logEntry.level;this.pre=this.mainDiv.appendChild(document.createElement("pre"));this.pre.appendChild(document.createTextNode(this.logEntry.formattedMessage));this.pre.className="unwrapped";this.contentElement=this.pre;}','LogEntryUnwrappedElementContainer.prototype=new LogEntryElementContainer();LogEntryUnwrappedElementContainer.prototype.remove=function(){this.doRemove();this.pre=null;};function LogEntryMainElementContainer(logEntry,containerDomNode){this.logEntry=logEntry;this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.className="logentry nonielogentry "+this.logEntry.level;this.contentElement=this.mainDiv.appendChild(document.createElement("span"));this.contentElement.appendChild(document.createTextNode(this.logEntry.formattedMessage));}','LogEntryMainElementContainer.prototype=new LogEntryElementContainer();function LogEntry(level,formattedMessage){this.level=level;this.formattedMessage=formattedMessage;this.rendered=false;}','LogEntry.prototype=new LogItem();copyProperties(LogEntry.prototype,{render:function(){var logEntry=this;var containerDomNode=this.group.contentDiv;if(isIe){this.formattedMessage=this.formattedMessage.replace(/\\r\\n/g,"\\r");this.unwrappedElementContainer=new LogEntryUnwrappedElementContainer(this,this.getUnwrappedDomContainer());this.wrappedElementContainer=new LogEntryWrappedElementContainer(this,this.getWrappedDomContainer());this.elementContainers=[this.unwrappedElementContainer,this.wrappedElementContainer];}else{this.mainElementContainer=new LogEntryMainElementContainer(this,this.getMainDomContainer());this.elementContainers=[this.mainElementContainer];}','this.content=this.formattedMessage;this.rendered=true;},setContent:function(content,wrappedContent){if(content!=this.content){if(isIe&&(content!==this.formattedMessage)){content=content.replace(/\\r\\n/g,"\\r");}','for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].setContent(content,wrappedContent);}','this.content=content;}},getSearchMatches:function(){var matches=[];var i,len;if(isIe){var unwrappedEls=getElementsByClass(this.unwrappedElementContainer.mainDiv,"searchterm","span");var wrappedEls=getElementsByClass(this.wrappedElementContainer.mainDiv,"searchterm","span");for(i=0,len=unwrappedEls.length;i<len;i++){matches[i]=new Match(this.level,null,unwrappedEls[i],wrappedEls[i]);}}else{var els=getElementsByClass(this.mainElementContainer.mainDiv,"searchterm","span");for(i=0,len=els.length;i<len;i++){matches[i]=new Match(this.level,els[i]);}}','return matches;},setSearchMatch:function(isMatch){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].setSearchMatch(isMatch);}},clearSearch:function(){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].clearSearch();}},accept:function(visitor){visitor.visitLogEntry(this);},serialize:function(items){items.push([LogItem.serializedItemKeys.LOG_ENTRY,this.level,this.formattedMessage]);}});function LogItemVisitor(){}','LogItemVisitor.prototype={visit:function(logItem){},visitParent:function(logItem){if(logItem.group){logItem.group.accept(this);}},visitChildren:function(logItem){for(var i=0,len=logItem.children.length;i<len;i++){logItem.children[i].accept(this);}},visitLogEntry:function(logEntry){this.visit(logEntry);},visitSeparator:function(separator){this.visit(separator);},visitGroup:function(group){this.visit(group);}};function GroupFlattener(){this.logEntriesAndSeparators=[];}','GroupFlattener.prototype=new LogItemVisitor();GroupFlattener.prototype.visitGroup=function(group){this.visitChildren(group);};GroupFlattener.prototype.visitLogEntry=function(logEntry){this.logEntriesAndSeparators.push(logEntry);};GroupFlattener.prototype.visitSeparator=function(separator){this.logEntriesAndSeparators.push(separator);};window.onload=function(){if(location.search){var queryBits=unescape(location.search).substr(1).split("&"),nameValueBits;for(var i=0,len=queryBits.length;i<len;i++){nameValueBits=queryBits[i].split("=");if(nameValueBits[0]=="log4javascript_domain"){document.domain=nameValueBits[1];break;}}}','logMainContainer=$("log");if(isIePre7){addClass(logMainContainer,"oldIe");}','rootGroup=new Group("root",true);rootGroup.render();currentGroup=rootGroup;setCommandInputWidth();setLogContainerHeight();toggleLoggingEnabled();toggleSearchEnabled();toggleSearchFilter();toggleSearchHighlight();applyFilters();checkAllLevels();toggleWrap();toggleNewestAtTop();toggleScrollToLatest();renderQueuedLogItems();loaded=true;$("command").value="";$("command").autocomplete="off";$("command").onkeydown=function(evt){evt=getEvent(evt);if(evt.keyCode==10||evt.keyCode==13){evalCommandLine();stopPropagation(evt);}else if(evt.keyCode==27){this.value="";this.focus();}else if(evt.keyCode==38&&commandHistory.length>0){currentCommandIndex=Math.max(0,currentCommandIndex-1);this.value=commandHistory[currentCommandIndex];moveCaretToEnd(this);}else if(evt.keyCode==40&&commandHistory.length>0){currentCommandIndex=Math.min(commandHistory.length-1,currentCommandIndex+1);this.value=commandHistory[currentCommandIndex];moveCaretToEnd(this);}};$("command").onkeypress=function(evt){evt=getEvent(evt);if(evt.keyCode==38&&commandHistory.length>0&&evt.preventDefault){evt.preventDefault();}};$("command").onkeyup=function(evt){evt=getEvent(evt);if(evt.keyCode==27&&evt.preventDefault){evt.preventDefault();this.focus();}};document.onkeydown=function keyEventHandler(evt){evt=getEvent(evt);switch(evt.keyCode){case 69:if(evt.shiftKey&&(evt.ctrlKey||evt.metaKey)){evalLastCommand();cancelKeyEvent(evt);return false;}','break;case 75:if(evt.shiftKey&&(evt.ctrlKey||evt.metaKey)){focusSearch();cancelKeyEvent(evt);return false;}','break;case 40:case 76:if(evt.shiftKey&&(evt.ctrlKey||evt.metaKey)){focusCommandLine();cancelKeyEvent(evt);return false;}','break;}};setTimeout(setLogContainerHeight,20);setShowCommandLine(showCommandLine);doSearch();};window.onunload=function(){if(mainWindowExists()){appender.unload();}','appender=null;};function toggleLoggingEnabled(){setLoggingEnabled($("enableLogging").checked);}','function setLoggingEnabled(enable){loggingEnabled=enable;}','var appender=null;function setAppender(appenderParam){appender=appenderParam;}','function setShowCloseButton(showCloseButton){$("closeButton").style.display=showCloseButton?"inline":"none";}','function setShowHideButton(showHideButton){$("hideButton").style.display=showHideButton?"inline":"none";}','var newestAtTop=false;function LogItemContentReverser(){}','LogItemContentReverser.prototype=new LogItemVisitor();LogItemContentReverser.prototype.visitGroup=function(group){group.reverseChildren();this.visitChildren(group);};function setNewestAtTop(isNewestAtTop){var oldNewestAtTop=newestAtTop;var i,iLen,j,jLen;newestAtTop=Boolean(isNewestAtTop);if(oldNewestAtTop!=newestAtTop){var visitor=new LogItemContentReverser();rootGroup.accept(visitor);if(currentSearch){var currentMatch=currentSearch.matches[currentMatchIndex];var matchIndex=0;var matches=[];var actOnLogEntry=function(logEntry){var logEntryMatches=logEntry.getSearchMatches();for(j=0,jLen=logEntryMatches.length;j<jLen;j++){matches[matchIndex]=logEntryMatches[j];if(currentMatch&&logEntryMatches[j].equals(currentMatch)){currentMatchIndex=matchIndex;}','matchIndex++;}};if(newestAtTop){for(i=logEntries.length-1;i>=0;i--){actOnLogEntry(logEntries[i]);}}else{for(i=0,iLen=logEntries.length;i<iLen;i++){actOnLogEntry(logEntries[i]);}}','currentSearch.matches=matches;if(currentMatch){currentMatch.setCurrent();}}else if(scrollToLatest){doScrollToLatest();}}','$("newestAtTop").checked=isNewestAtTop;}','function toggleNewestAtTop(){var isNewestAtTop=$("newestAtTop").checked;setNewestAtTop(isNewestAtTop);}','var scrollToLatest=true;function setScrollToLatest(isScrollToLatest){scrollToLatest=isScrollToLatest;if(scrollToLatest){doScrollToLatest();}','$("scrollToLatest").checked=isScrollToLatest;}','function toggleScrollToLatest(){var isScrollToLatest=$("scrollToLatest").checked;setScrollToLatest(isScrollToLatest);}','function doScrollToLatest(){var l=logMainContainer;if(typeof l.scrollTop!="undefined"){if(newestAtTop){l.scrollTop=0;}else{var latestLogEntry=l.lastChild;if(latestLogEntry){l.scrollTop=l.scrollHeight;}}}}','var closeIfOpenerCloses=true;function setCloseIfOpenerCloses(isCloseIfOpenerCloses){closeIfOpenerCloses=isCloseIfOpenerCloses;}','var maxMessages=null;function setMaxMessages(max){maxMessages=max;pruneLogEntries();}','var showCommandLine=false;function setShowCommandLine(isShowCommandLine){showCommandLine=isShowCommandLine;if(loaded){$("commandLine").style.display=showCommandLine?"block":"none";setCommandInputWidth();setLogContainerHeight();}}','function focusCommandLine(){if(loaded){$("command").focus();}}','function focusSearch(){if(loaded){$("searchBox").focus();}}','function getLogItems(){var items=[];for(var i=0,len=logItems.length;i<len;i++){logItems[i].serialize(items);}','return items;}','function setLogItems(items){var loggingReallyEnabled=loggingEnabled;loggingEnabled=true;for(var i=0,len=items.length;i<len;i++){switch(items[i][0]){case LogItem.serializedItemKeys.LOG_ENTRY:log(items[i][1],items[i][2]);break;case LogItem.serializedItemKeys.GROUP_START:group(items[i][1]);break;case LogItem.serializedItemKeys.GROUP_END:groupEnd();break;}}','loggingEnabled=loggingReallyEnabled;}','function log(logLevel,formattedMessage){if(loggingEnabled){var logEntry=new LogEntry(logLevel,formattedMessage);logEntries.push(logEntry);logEntriesAndSeparators.push(logEntry);logItems.push(logEntry);currentGroup.addChild(logEntry);if(loaded){if(logQueuedEventsTimer!==null){clearTimeout(logQueuedEventsTimer);}','logQueuedEventsTimer=setTimeout(renderQueuedLogItems,renderDelay);unrenderedLogItemsExist=true;}}}','function renderQueuedLogItems(){logQueuedEventsTimer=null;var pruned=pruneLogEntries();var initiallyHasMatches=currentSearch?currentSearch.hasMatches():false;for(var i=0,len=logItems.length;i<len;i++){if(!logItems[i].rendered){logItems[i].render();logItems[i].appendToLog();if(currentSearch&&(logItems[i]instanceof LogEntry)){currentSearch.applyTo(logItems[i]);}}}','if(currentSearch){if(pruned){if(currentSearch.hasVisibleMatches()){if(currentMatchIndex===null){setCurrentMatchIndex(0);}','displayMatches();}else{displayNoMatches();}}else if(!initiallyHasMatches&&currentSearch.hasVisibleMatches()){setCurrentMatchIndex(0);displayMatches();}}','if(scrollToLatest){doScrollToLatest();}','unrenderedLogItemsExist=false;}','function pruneLogEntries(){if((maxMessages!==null)&&(logEntriesAndSeparators.length>maxMessages)){var numberToDelete=logEntriesAndSeparators.length-maxMessages;var prunedLogEntries=logEntriesAndSeparators.slice(0,numberToDelete);if(currentSearch){currentSearch.removeMatches(prunedLogEntries);}','var group;for(var i=0;i<numberToDelete;i++){group=logEntriesAndSeparators[i].group;array_remove(logItems,logEntriesAndSeparators[i]);array_remove(logEntries,logEntriesAndSeparators[i]);logEntriesAndSeparators[i].remove(true,true);if(group.children.length===0&&group!==currentGroup&&group!==rootGroup){array_remove(logItems,group);group.remove(true,true);}}','logEntriesAndSeparators=array_removeFromStart(logEntriesAndSeparators,numberToDelete);return true;}','return false;}','function group(name,startExpanded){if(loggingEnabled){initiallyExpanded=(typeof startExpanded==="undefined")?true:Boolean(startExpanded);var newGroup=new Group(name,false,initiallyExpanded);currentGroup.addChild(newGroup);currentGroup=newGroup;logItems.push(newGroup);if(loaded){if(logQueuedEventsTimer!==null){clearTimeout(logQueuedEventsTimer);}','logQueuedEventsTimer=setTimeout(renderQueuedLogItems,renderDelay);unrenderedLogItemsExist=true;}}}','function groupEnd(){currentGroup=(currentGroup===rootGroup)?rootGroup:currentGroup.group;}','function mainPageReloaded(){currentGroup=rootGroup;var separator=new Separator();logEntriesAndSeparators.push(separator);logItems.push(separator);currentGroup.addChild(separator);}','function closeWindow(){if(appender&&mainWindowExists()){appender.close(true);}else{window.close();}}','function hide(){if(appender&&mainWindowExists()){appender.hide();}}','var mainWindow=window;var windowId="log4javascriptConsoleWindow_"+new Date().getTime()+"_"+(""+Math.random()).substr(2);function setMainWindow(win){mainWindow=win;mainWindow[windowId]=window;if(opener&&closeIfOpenerCloses){pollOpener();}}','function pollOpener(){if(closeIfOpenerCloses){if(mainWindowExists()){setTimeout(pollOpener,500);}else{closeWindow();}}}','function mainWindowExists(){try{return(mainWindow&&!mainWindow.closed&&mainWindow[windowId]==window);}catch(ex){}','return false;}','var logLevels=["TRACE","DEBUG","INFO","WARN","ERROR","FATAL"];function getCheckBox(logLevel){return $("switch_"+logLevel);}','function getIeWrappedLogContainer(){return $("log_wrapped");}','function getIeUnwrappedLogContainer(){return $("log_unwrapped");}','function applyFilters(){for(var i=0;i<logLevels.length;i++){if(getCheckBox(logLevels[i]).checked){addClass(logMainContainer,logLevels[i]);}else{removeClass(logMainContainer,logLevels[i]);}}','updateSearchFromFilters();}','function toggleAllLevels(){var turnOn=$("switch_ALL").checked;for(var i=0;i<logLevels.length;i++){getCheckBox(logLevels[i]).checked=turnOn;if(turnOn){addClass(logMainContainer,logLevels[i]);}else{removeClass(logMainContainer,logLevels[i]);}}}','function checkAllLevels(){for(var i=0;i<logLevels.length;i++){if(!getCheckBox(logLevels[i]).checked){getCheckBox("ALL").checked=false;return;}}','getCheckBox("ALL").checked=true;}','function clearLog(){rootGroup.clear();currentGroup=rootGroup;logEntries=[];logItems=[];logEntriesAndSeparators=[];doSearch();}','function toggleWrap(){var enable=$("wrap").checked;if(enable){addClass(logMainContainer,"wrap");}else{removeClass(logMainContainer,"wrap");}','refreshCurrentMatch();}','var searchTimer=null;function scheduleSearch(){try{clearTimeout(searchTimer);}catch(ex){}','searchTimer=setTimeout(doSearch,500);}','function Search(searchTerm,isRegex,searchRegex,isCaseSensitive){this.searchTerm=searchTerm;this.isRegex=isRegex;this.searchRegex=searchRegex;this.isCaseSensitive=isCaseSensitive;this.matches=[];}','Search.prototype={hasMatches:function(){return this.matches.length>0;},hasVisibleMatches:function(){if(this.hasMatches()){for(var i=0;i<this.matches.length;i++){if(this.matches[i].isVisible()){return true;}}}','return false;},match:function(logEntry){var entryText=String(logEntry.formattedMessage);var matchesSearch=false;if(this.isRegex){matchesSearch=this.searchRegex.test(entryText);}else if(this.isCaseSensitive){matchesSearch=(entryText.indexOf(this.searchTerm)>-1);}else{matchesSearch=(entryText.toLowerCase().indexOf(this.searchTerm.toLowerCase())>-1);}','return matchesSearch;},getNextVisibleMatchIndex:function(){for(var i=currentMatchIndex+1;i<this.matches.length;i++){if(this.matches[i].isVisible()){return i;}}','for(i=0;i<=currentMatchIndex;i++){if(this.matches[i].isVisible()){return i;}}','return-1;},getPreviousVisibleMatchIndex:function(){for(var i=currentMatchIndex-1;i>=0;i--){if(this.matches[i].isVisible()){return i;}}','for(var i=this.matches.length-1;i>=currentMatchIndex;i--){if(this.matches[i].isVisible()){return i;}}','return-1;},applyTo:function(logEntry){var doesMatch=this.match(logEntry);if(doesMatch){logEntry.group.expand();logEntry.setSearchMatch(true);var logEntryContent;var wrappedLogEntryContent;var searchTermReplacementStartTag="<span class=\\\"searchterm\\\">";var searchTermReplacementEndTag="<"+"/span>";var preTagName=isIe?"pre":"span";var preStartTag="<"+preTagName+" class=\\\"pre\\\">";var preEndTag="<"+"/"+preTagName+">";var startIndex=0;var searchIndex,matchedText,textBeforeMatch;if(this.isRegex){var flags=this.isCaseSensitive?"g":"gi";var capturingRegex=new RegExp("("+this.searchRegex.source+")",flags);var rnd=(""+Math.random()).substr(2);var startToken="%%s"+rnd+"%%";var endToken="%%e"+rnd+"%%";logEntryContent=logEntry.formattedMessage.replace(capturingRegex,startToken+"$1"+endToken);logEntryContent=escapeHtml(logEntryContent);var result;var searchString=logEntryContent;logEntryContent="";wrappedLogEntryContent="";while((searchIndex=searchString.indexOf(startToken,startIndex))>-1){var endTokenIndex=searchString.indexOf(endToken,searchIndex);matchedText=searchString.substring(searchIndex+startToken.length,endTokenIndex);textBeforeMatch=searchString.substring(startIndex,searchIndex);logEntryContent+=preStartTag+textBeforeMatch+preEndTag;logEntryContent+=searchTermReplacementStartTag+preStartTag+matchedText+','preEndTag+searchTermReplacementEndTag;if(isIe){wrappedLogEntryContent+=textBeforeMatch+searchTermReplacementStartTag+','matchedText+searchTermReplacementEndTag;}','startIndex=endTokenIndex+endToken.length;}','logEntryContent+=preStartTag+searchString.substr(startIndex)+preEndTag;if(isIe){wrappedLogEntryContent+=searchString.substr(startIndex);}}else{logEntryContent="";wrappedLogEntryContent="";var searchTermReplacementLength=searchTermReplacementStartTag.length+','this.searchTerm.length+searchTermReplacementEndTag.length;var searchTermLength=this.searchTerm.length;var searchTermLowerCase=this.searchTerm.toLowerCase();var logTextLowerCase=logEntry.formattedMessage.toLowerCase();while((searchIndex=logTextLowerCase.indexOf(searchTermLowerCase,startIndex))>-1){matchedText=escapeHtml(logEntry.formattedMessage.substr(searchIndex,this.searchTerm.length));textBeforeMatch=escapeHtml(logEntry.formattedMessage.substring(startIndex,searchIndex));var searchTermReplacement=searchTermReplacementStartTag+','preStartTag+matchedText+preEndTag+searchTermReplacementEndTag;logEntryContent+=preStartTag+textBeforeMatch+preEndTag+searchTermReplacement;if(isIe){wrappedLogEntryContent+=textBeforeMatch+searchTermReplacementStartTag+','matchedText+searchTermReplacementEndTag;}','startIndex=searchIndex+searchTermLength;}','var textAfterLastMatch=escapeHtml(logEntry.formattedMessage.substr(startIndex));logEntryContent+=preStartTag+textAfterLastMatch+preEndTag;if(isIe){wrappedLogEntryContent+=textAfterLastMatch;}}','logEntry.setContent(logEntryContent,wrappedLogEntryContent);var logEntryMatches=logEntry.getSearchMatches();this.matches=this.matches.concat(logEntryMatches);}else{logEntry.setSearchMatch(false);logEntry.setContent(logEntry.formattedMessage,logEntry.formattedMessage);}','return doesMatch;},removeMatches:function(logEntries){var matchesToRemoveCount=0;var currentMatchRemoved=false;var matchesToRemove=[];var i,iLen,j,jLen;for(i=0,iLen=this.matches.length;i<iLen;i++){for(j=0,jLen=logEntries.length;j<jLen;j++){if(this.matches[i].belongsTo(logEntries[j])){matchesToRemove.push(this.matches[i]);if(i===currentMatchIndex){currentMatchRemoved=true;}}}}','var newMatch=currentMatchRemoved?null:this.matches[currentMatchIndex];if(currentMatchRemoved){for(i=currentMatchIndex,iLen=this.matches.length;i<iLen;i++){if(this.matches[i].isVisible()&&!array_contains(matchesToRemove,this.matches[i])){newMatch=this.matches[i];break;}}}','for(i=0,iLen=matchesToRemove.length;i<iLen;i++){array_remove(this.matches,matchesToRemove[i]);matchesToRemove[i].remove();}','if(this.hasVisibleMatches()){if(newMatch===null){setCurrentMatchIndex(0);}else{var newMatchIndex=0;for(i=0,iLen=this.matches.length;i<iLen;i++){if(newMatch===this.matches[i]){newMatchIndex=i;break;}}','setCurrentMatchIndex(newMatchIndex);}}else{currentMatchIndex=null;displayNoMatches();}}};function getPageOffsetTop(el,container){var currentEl=el;var y=0;while(currentEl&&currentEl!=container){y+=currentEl.offsetTop;currentEl=currentEl.offsetParent;}','return y;}','function scrollIntoView(el){var logContainer=logMainContainer;if(!$("wrap").checked){var logContainerLeft=logContainer.scrollLeft;var logContainerRight=logContainerLeft+logContainer.offsetWidth;var elLeft=el.offsetLeft;var elRight=elLeft+el.offsetWidth;if(elLeft<logContainerLeft||elRight>logContainerRight){logContainer.scrollLeft=elLeft-(logContainer.offsetWidth-el.offsetWidth)/2;}}','var logContainerTop=logContainer.scrollTop;var logContainerBottom=logContainerTop+logContainer.offsetHeight;var elTop=getPageOffsetTop(el)-getToolBarsHeight();var elBottom=elTop+el.offsetHeight;if(elTop<logContainerTop||elBottom>logContainerBottom){logContainer.scrollTop=elTop-(logContainer.offsetHeight-el.offsetHeight)/2;}}','function Match(logEntryLevel,spanInMainDiv,spanInUnwrappedPre,spanInWrappedDiv){this.logEntryLevel=logEntryLevel;this.spanInMainDiv=spanInMainDiv;if(isIe){this.spanInUnwrappedPre=spanInUnwrappedPre;this.spanInWrappedDiv=spanInWrappedDiv;}','this.mainSpan=isIe?spanInUnwrappedPre:spanInMainDiv;}','Match.prototype={equals:function(match){return this.mainSpan===match.mainSpan;},setCurrent:function(){if(isIe){addClass(this.spanInUnwrappedPre,"currentmatch");addClass(this.spanInWrappedDiv,"currentmatch");var elementToScroll=$("wrap").checked?this.spanInWrappedDiv:this.spanInUnwrappedPre;scrollIntoView(elementToScroll);}else{addClass(this.spanInMainDiv,"currentmatch");scrollIntoView(this.spanInMainDiv);}},belongsTo:function(logEntry){if(isIe){return isDescendant(this.spanInUnwrappedPre,logEntry.unwrappedPre);}else{return isDescendant(this.spanInMainDiv,logEntry.mainDiv);}},setNotCurrent:function(){if(isIe){removeClass(this.spanInUnwrappedPre,"currentmatch");removeClass(this.spanInWrappedDiv,"currentmatch");}else{removeClass(this.spanInMainDiv,"currentmatch");}},isOrphan:function(){return isOrphan(this.mainSpan);},isVisible:function(){return getCheckBox(this.logEntryLevel).checked;},remove:function(){if(isIe){this.spanInUnwrappedPre=null;this.spanInWrappedDiv=null;}else{this.spanInMainDiv=null;}}};var currentSearch=null;var currentMatchIndex=null;function doSearch(){var searchBox=$("searchBox");var searchTerm=searchBox.value;var isRegex=$("searchRegex").checked;var isCaseSensitive=$("searchCaseSensitive").checked;var i;if(searchTerm===""){$("searchReset").disabled=true;$("searchNav").style.display="none";removeClass(document.body,"searching");removeClass(searchBox,"hasmatches");removeClass(searchBox,"nomatches");for(i=0;i<logEntries.length;i++){logEntries[i].clearSearch();logEntries[i].setContent(logEntries[i].formattedMessage,logEntries[i].formattedMessage);}','currentSearch=null;setLogContainerHeight();}else{$("searchReset").disabled=false;$("searchNav").style.display="block";var searchRegex;var regexValid;if(isRegex){try{searchRegex=isCaseSensitive?new RegExp(searchTerm,"g"):new RegExp(searchTerm,"gi");regexValid=true;replaceClass(searchBox,"validregex","invalidregex");searchBox.title="Valid regex";}catch(ex){regexValid=false;replaceClass(searchBox,"invalidregex","validregex");searchBox.title="Invalid regex: "+(ex.message?ex.message:(ex.description?ex.description:"unknown error"));return;}}else{searchBox.title="";removeClass(searchBox,"validregex");removeClass(searchBox,"invalidregex");}','addClass(document.body,"searching");currentSearch=new Search(searchTerm,isRegex,searchRegex,isCaseSensitive);for(i=0;i<logEntries.length;i++){currentSearch.applyTo(logEntries[i]);}','setLogContainerHeight();if(currentSearch.hasVisibleMatches()){setCurrentMatchIndex(0);displayMatches();}else{displayNoMatches();}}}','function updateSearchFromFilters(){if(currentSearch){if(currentSearch.hasMatches()){if(currentMatchIndex===null){currentMatchIndex=0;}','var currentMatch=currentSearch.matches[currentMatchIndex];if(currentMatch.isVisible()){displayMatches();setCurrentMatchIndex(currentMatchIndex);}else{currentMatch.setNotCurrent();var nextVisibleMatchIndex=currentSearch.getNextVisibleMatchIndex();if(nextVisibleMatchIndex>-1){setCurrentMatchIndex(nextVisibleMatchIndex);displayMatches();}else{displayNoMatches();}}}else{displayNoMatches();}}}','function refreshCurrentMatch(){if(currentSearch&&currentSearch.hasVisibleMatches()){setCurrentMatchIndex(currentMatchIndex);}}','function displayMatches(){replaceClass($("searchBox"),"hasmatches","nomatches");$("searchBox").title=""+currentSearch.matches.length+" matches found";$("searchNav").style.display="block";setLogContainerHeight();}','function displayNoMatches(){replaceClass($("searchBox"),"nomatches","hasmatches");$("searchBox").title="No matches found";$("searchNav").style.display="none";setLogContainerHeight();}','function toggleSearchEnabled(enable){enable=(typeof enable=="undefined")?!$("searchDisable").checked:enable;$("searchBox").disabled=!enable;$("searchReset").disabled=!enable;$("searchRegex").disabled=!enable;$("searchNext").disabled=!enable;$("searchPrevious").disabled=!enable;$("searchCaseSensitive").disabled=!enable;$("searchNav").style.display=(enable&&($("searchBox").value!=="")&&currentSearch&&currentSearch.hasVisibleMatches())?"block":"none";if(enable){removeClass($("search"),"greyedout");addClass(document.body,"searching");if($("searchHighlight").checked){addClass(logMainContainer,"searchhighlight");}else{removeClass(logMainContainer,"searchhighlight");}','if($("searchFilter").checked){addClass(logMainContainer,"searchfilter");}else{removeClass(logMainContainer,"searchfilter");}','$("searchDisable").checked=!enable;}else{addClass($("search"),"greyedout");removeClass(document.body,"searching");removeClass(logMainContainer,"searchhighlight");removeClass(logMainContainer,"searchfilter");}','setLogContainerHeight();}','function toggleSearchFilter(){var enable=$("searchFilter").checked;if(enable){addClass(logMainContainer,"searchfilter");}else{removeClass(logMainContainer,"searchfilter");}','refreshCurrentMatch();}','function toggleSearchHighlight(){var enable=$("searchHighlight").checked;if(enable){addClass(logMainContainer,"searchhighlight");}else{removeClass(logMainContainer,"searchhighlight");}}','function clearSearch(){$("searchBox").value="";doSearch();}','function searchNext(){if(currentSearch!==null&&currentMatchIndex!==null){currentSearch.matches[currentMatchIndex].setNotCurrent();var nextMatchIndex=currentSearch.getNextVisibleMatchIndex();if(nextMatchIndex>currentMatchIndex||confirm("Reached the end of the page. Start from the top?")){setCurrentMatchIndex(nextMatchIndex);}}}','function searchPrevious(){if(currentSearch!==null&&currentMatchIndex!==null){currentSearch.matches[currentMatchIndex].setNotCurrent();var previousMatchIndex=currentSearch.getPreviousVisibleMatchIndex();if(previousMatchIndex<currentMatchIndex||confirm("Reached the start of the page. Continue from the bottom?")){setCurrentMatchIndex(previousMatchIndex);}}}','function setCurrentMatchIndex(index){currentMatchIndex=index;currentSearch.matches[currentMatchIndex].setCurrent();}','function addClass(el,cssClass){if(!hasClass(el,cssClass)){if(el.className){el.className+=" "+cssClass;}else{el.className=cssClass;}}}','function hasClass(el,cssClass){if(el.className){var classNames=el.className.split(" ");return array_contains(classNames,cssClass);}','return false;}','function removeClass(el,cssClass){if(hasClass(el,cssClass)){var existingClasses=el.className.split(" ");var newClasses=[];for(var i=0,len=existingClasses.length;i<len;i++){if(existingClasses[i]!=cssClass){newClasses[newClasses.length]=existingClasses[i];}}','el.className=newClasses.join(" ");}}','function replaceClass(el,newCssClass,oldCssClass){removeClass(el,oldCssClass);addClass(el,newCssClass);}','function getElementsByClass(el,cssClass,tagName){var elements=el.getElementsByTagName(tagName);var matches=[];for(var i=0,len=elements.length;i<len;i++){if(hasClass(elements[i],cssClass)){matches.push(elements[i]);}}','return matches;}','function $(id){return document.getElementById(id);}','function isDescendant(node,ancestorNode){while(node!=null){if(node===ancestorNode){return true;}','node=node.parentNode;}','return false;}','function isOrphan(node){var currentNode=node;while(currentNode){if(currentNode==document.body){return false;}','currentNode=currentNode.parentNode;}','return true;}','function escapeHtml(str){return str.replace(/&/g,"&amp;").replace(/[<]/g,"&lt;").replace(/>/g,"&gt;");}','function getWindowWidth(){if(window.innerWidth){return window.innerWidth;}else if(document.documentElement&&document.documentElement.clientWidth){return document.documentElement.clientWidth;}else if(document.body){return document.body.clientWidth;}','return 0;}','function getWindowHeight(){if(window.innerHeight){return window.innerHeight;}else if(document.documentElement&&document.documentElement.clientHeight){return document.documentElement.clientHeight;}else if(document.body){return document.body.clientHeight;}','return 0;}','function getToolBarsHeight(){return $("switches").offsetHeight;}','function getChromeHeight(){var height=getToolBarsHeight();if(showCommandLine){height+=$("commandLine").offsetHeight;}','return height;}','function setLogContainerHeight(){if(logMainContainer){var windowHeight=getWindowHeight();$("body").style.height=getWindowHeight()+"px";logMainContainer.style.height=""+','Math.max(0,windowHeight-getChromeHeight())+"px";}}','function setCommandInputWidth(){if(showCommandLine){$("command").style.width=""+Math.max(0,$("commandLineContainer").offsetWidth-','($("evaluateButton").offsetWidth+13))+"px";}}','window.onresize=function(){setCommandInputWidth();setLogContainerHeight();};if(!Array.prototype.push){Array.prototype.push=function(){for(var i=0,len=arguments.length;i<len;i++){this[this.length]=arguments[i];}','return this.length;};}','if(!Array.prototype.pop){Array.prototype.pop=function(){if(this.length>0){var val=this[this.length-1];this.length=this.length-1;return val;}};}','if(!Array.prototype.shift){Array.prototype.shift=function(){if(this.length>0){var firstItem=this[0];for(var i=0,len=this.length-1;i<len;i++){this[i]=this[i+1];}','this.length=this.length-1;return firstItem;}};}','if(!Array.prototype.splice){Array.prototype.splice=function(startIndex,deleteCount){var itemsAfterDeleted=this.slice(startIndex+deleteCount);var itemsDeleted=this.slice(startIndex,startIndex+deleteCount);this.length=startIndex;var argumentsArray=[];for(var i=0,len=arguments.length;i<len;i++){argumentsArray[i]=arguments[i];}','var itemsToAppend=(argumentsArray.length>2)?itemsAfterDeleted=argumentsArray.slice(2).concat(itemsAfterDeleted):itemsAfterDeleted;for(i=0,len=itemsToAppend.length;i<len;i++){this.push(itemsToAppend[i]);}','return itemsDeleted;};}','function array_remove(arr,val){var index=-1;for(var i=0,len=arr.length;i<len;i++){if(arr[i]===val){index=i;break;}}','if(index>=0){arr.splice(index,1);return index;}else{return false;}}','function array_removeFromStart(array,numberToRemove){if(Array.prototype.splice){array.splice(0,numberToRemove);}else{for(var i=numberToRemove,len=array.length;i<len;i++){array[i-numberToRemove]=array[i];}','array.length=array.length-numberToRemove;}','return array;}','function array_contains(arr,val){for(var i=0,len=arr.length;i<len;i++){if(arr[i]==val){return true;}}','return false;}','function getErrorMessage(ex){if(ex.message){return ex.message;}else if(ex.description){return ex.description;}','return""+ex;}','function moveCaretToEnd(input){if(input.setSelectionRange){input.focus();var length=input.value.length;input.setSelectionRange(length,length);}else if(input.createTextRange){var range=input.createTextRange();range.collapse(false);range.select();}','input.focus();}','function stopPropagation(evt){if(evt.stopPropagation){evt.stopPropagation();}else if(typeof evt.cancelBubble!="undefined"){evt.cancelBubble=true;}}','function getEvent(evt){return evt?evt:event;}','function getTarget(evt){return evt.target?evt.target:evt.srcElement;}','function getRelatedTarget(evt){if(evt.relatedTarget){return evt.relatedTarget;}else if(evt.srcElement){switch(evt.type){case"mouseover":return evt.fromElement;case"mouseout":return evt.toElement;default:return evt.srcElement;}}}','function cancelKeyEvent(evt){evt.returnValue=false;stopPropagation(evt);}','function evalCommandLine(){var expr=$("command").value;evalCommand(expr);$("command").value="";}','function evalLastCommand(){if(lastCommand!=null){evalCommand(lastCommand);}}','var lastCommand=null;var commandHistory=[];var currentCommandIndex=0;function evalCommand(expr){if(appender){appender.evalCommandAndAppend(expr);}else{var prefix=">>> "+expr+"\\r\\n";try{log("INFO",prefix+eval(expr));}catch(ex){log("ERROR",prefix+"Error: "+getErrorMessage(ex));}}','if(expr!=commandHistory[commandHistory.length-1]){commandHistory.push(expr);if(appender){appender.storeCommandHistory(commandHistory);}}','currentCommandIndex=(expr==commandHistory[currentCommandIndex])?currentCommandIndex+1:commandHistory.length;lastCommand=expr;}','//]]>','</script>','<style type="text/css">','body{background-color:white;color:black;padding:0;margin:0;font-family:tahoma,verdana,arial,helvetica,sans-serif;overflow:hidden}div#switchesContainer input{margin-bottom:0}div.toolbar{border-top:solid #ffffff 1px;border-bottom:solid #aca899 1px;background-color:#f1efe7;padding:3px 5px;font-size:68.75%}div.toolbar,div#search input{font-family:tahoma,verdana,arial,helvetica,sans-serif}div.toolbar input.button{padding:0 5px;font-size:100%}div.toolbar input.hidden{display:none}div#switches input#clearButton{margin-left:20px}div#levels label{font-weight:bold}div#levels label,div#options label{margin-right:5px}div#levels label#wrapLabel{font-weight:normal}div#search label{margin-right:10px}div#search label.searchboxlabel{margin-right:0}div#search input{font-size:100%}div#search input.validregex{color:green}div#search input.invalidregex{color:red}div#search input.nomatches{color:white;background-color:#ff6666}div#search input.nomatches{color:white;background-color:#ff6666}div#searchNav{display:none}div#commandLine{display:none}div#commandLine input#command{font-size:100%;font-family:Courier New,Courier}div#commandLine input#evaluateButton{}*.greyedout{color:gray !important;border-color:gray !important}*.greyedout *.alwaysenabled{color:black}*.unselectable{-khtml-user-select:none;-moz-user-select:none;user-select:none}div#log{font-family:Courier New,Courier;font-size:75%;width:100%;overflow:auto;clear:both;position:relative}div.group{border-color:#cccccc;border-style:solid;border-width:1px 0 1px 1px;overflow:visible}div.oldIe div.group,div.oldIe div.group *,div.oldIe *.logentry{height:1%}div.group div.groupheading span.expander{border:solid black 1px;font-family:Courier New,Courier;font-size:0.833em;background-color:#eeeeee;position:relative;top:-1px;color:black;padding:0 2px;cursor:pointer;cursor:hand;height:1%}div.group div.groupcontent{margin-left:10px;padding-bottom:2px;overflow:visible}div.group div.expanded{display:block}div.group div.collapsed{display:none}*.logentry{overflow:visible;display:none;white-space:pre}span.pre{white-space:pre}pre.unwrapped{display:inline !important}pre.unwrapped pre.pre,div.wrapped pre.pre{display:inline}div.wrapped pre.pre{white-space:normal}div.wrapped{display:none}body.searching *.logentry span.currentmatch{color:white !important;background-color:green !important}body.searching div.searchhighlight *.logentry span.searchterm{color:black;background-color:yellow}div.wrap *.logentry{white-space:normal !important;border-width:0 0 1px 0;border-color:#dddddd;border-style:dotted}div.wrap #log_wrapped,#log_unwrapped{display:block}div.wrap #log_unwrapped,#log_wrapped{display:none}div.wrap *.logentry span.pre{overflow:visible;white-space:normal}div.wrap *.logentry pre.unwrapped{display:none}div.wrap *.logentry span.wrapped{display:inline}div.searchfilter *.searchnonmatch{display:none !important}div#log *.TRACE,label#label_TRACE{color:#666666}div#log *.DEBUG,label#label_DEBUG{color:green}div#log *.INFO,label#label_INFO{color:#000099}div#log *.WARN,label#label_WARN{color:#999900}div#log *.ERROR,label#label_ERROR{color:red}div#log *.FATAL,label#label_FATAL{color:#660066}div.TRACE#log *.TRACE,div.DEBUG#log *.DEBUG,div.INFO#log *.INFO,div.WARN#log *.WARN,div.ERROR#log *.ERROR,div.FATAL#log *.FATAL{display:block}div#log div.separator{background-color:#cccccc;margin:5px 0;line-height:1px}','</style>','</head>','<body id="body">','<div id="switchesContainer">','<div id="switches">','<div id="levels" class="toolbar">','Filters:','<input type="checkbox" id="switch_TRACE" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide trace messages" /><label for="switch_TRACE" id="label_TRACE">trace</label>','<input type="checkbox" id="switch_DEBUG" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide debug messages" /><label for="switch_DEBUG" id="label_DEBUG">debug</label>','<input type="checkbox" id="switch_INFO" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide info messages" /><label for="switch_INFO" id="label_INFO">info</label>','<input type="checkbox" id="switch_WARN" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide warn messages" /><label for="switch_WARN" id="label_WARN">warn</label>','<input type="checkbox" id="switch_ERROR" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide error messages" /><label for="switch_ERROR" id="label_ERROR">error</label>','<input type="checkbox" id="switch_FATAL" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide fatal messages" /><label for="switch_FATAL" id="label_FATAL">fatal</label>','<input type="checkbox" id="switch_ALL" onclick="toggleAllLevels(); applyFilters()" checked="checked" title="Show/hide all messages" /><label for="switch_ALL" id="label_ALL">all</label>','</div>','<div id="search" class="toolbar">','<label for="searchBox" class="searchboxlabel">Search:</label> <input type="text" id="searchBox" onclick="toggleSearchEnabled(true)" onkeyup="scheduleSearch()" size="20" />','<input type="button" id="searchReset" disabled="disabled" value="Reset" onclick="clearSearch()" class="button" title="Reset the search" />','<input type="checkbox" id="searchRegex" onclick="doSearch()" title="If checked, search is treated as a regular expression" /><label for="searchRegex">Regex</label>','<input type="checkbox" id="searchCaseSensitive" onclick="doSearch()" title="If checked, search is case sensitive" /><label for="searchCaseSensitive">Match case</label>','<input type="checkbox" id="searchDisable" onclick="toggleSearchEnabled()" title="Enable/disable search" /><label for="searchDisable" class="alwaysenabled">Disable</label>','<div id="searchNav">','<input type="button" id="searchNext" disabled="disabled" value="Next" onclick="searchNext()" class="button" title="Go to the next matching log entry" />','<input type="button" id="searchPrevious" disabled="disabled" value="Previous" onclick="searchPrevious()" class="button" title="Go to the previous matching log entry" />','<input type="checkbox" id="searchFilter" onclick="toggleSearchFilter()" title="If checked, non-matching log entries are filtered out" /><label for="searchFilter">Filter</label>','<input type="checkbox" id="searchHighlight" onclick="toggleSearchHighlight()" title="Highlight matched search terms" /><label for="searchHighlight" class="alwaysenabled">Highlight all</label>','</div>','</div>','<div id="options" class="toolbar">','Options:','<input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Log</label>','<input type="checkbox" id="wrap" onclick="toggleWrap()" title="Enable / disable word wrap" /><label for="wrap" id="wrapLabel">Wrap</label>','<input type="checkbox" id="newestAtTop" onclick="toggleNewestAtTop()" title="If checked, causes newest messages to appear at the top" /><label for="newestAtTop" id="newestAtTopLabel">Newest at the top</label>','<input type="checkbox" id="scrollToLatest" onclick="toggleScrollToLatest()" checked="checked" title="If checked, window automatically scrolls to a new message when it is added" /><label for="scrollToLatest" id="scrollToLatestLabel">Scroll to latest</label>','<input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="button" title="Clear all log messages"  />','<input type="button" id="hideButton" value="Hide" onclick="hide()" class="hidden button" title="Hide the console" />','<input type="button" id="closeButton" value="Close" onclick="closeWindow()" class="hidden button" title="Close the window" />','</div>','</div>','</div>','<div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>','<div id="commandLine" class="toolbar">','<div id="commandLineContainer">','<input type="text" id="command" title="Enter a JavaScript command here and hit return or press \'Evaluate\'" />','<input type="button" id="evaluateButton" value="Evaluate" class="button" title="Evaluate the command" onclick="evalCommandLine()" />','</div>','</div>','</body>','</html>',''];};var defaultCommandLineFunctions=[];ConsoleAppender=function(){};var consoleAppenderIdCounter=1;ConsoleAppender.prototype=new Appender();ConsoleAppender.prototype.create=function(inPage,container,lazyInit,initiallyMinimized,useDocumentWrite,width,height,focusConsoleWindow){var appender=this;var initialized=false;var consoleWindowCreated=false;var consoleWindowLoaded=false;var consoleClosed=false;var queuedLoggingEvents=[];var isSupported=true;var consoleAppenderId=consoleAppenderIdCounter++;initiallyMinimized=extractBooleanFromParam(initiallyMinimized,this.defaults.initiallyMinimized);lazyInit=extractBooleanFromParam(lazyInit,this.defaults.lazyInit);useDocumentWrite=extractBooleanFromParam(useDocumentWrite,this.defaults.useDocumentWrite);var newestMessageAtTop=this.defaults.newestMessageAtTop;var scrollToLatestMessage=this.defaults.scrollToLatestMessage;width=width?width:this.defaults.width;height=height?height:this.defaults.height;var maxMessages=this.defaults.maxMessages;var showCommandLine=this.defaults.showCommandLine;var commandLineObjectExpansionDepth=this.defaults.commandLineObjectExpansionDepth;var showHideButton=this.defaults.showHideButton;var showCloseButton=this.defaults.showCloseButton;var showLogEntryDeleteButtons=this.defaults.showLogEntryDeleteButtons;this.setLayout(this.defaults.layout);var init,createWindow,safeToAppend,getConsoleWindow,open;var appenderName=inPage?"InPageAppender":"PopUpAppender";var checkCanConfigure=function(configOptionName){if(consoleWindowCreated){handleError(appenderName+": configuration option '"+configOptionName+"' may not be set after the appender has been initialized");return false;}

+return true;};var consoleWindowExists=function(){return(consoleWindowLoaded&&isSupported&&!consoleClosed);};this.isNewestMessageAtTop=function(){return newestMessageAtTop;};this.setNewestMessageAtTop=function(newestMessageAtTopParam){newestMessageAtTop=bool(newestMessageAtTopParam);if(consoleWindowExists()){getConsoleWindow().setNewestAtTop(newestMessageAtTop);}};this.isScrollToLatestMessage=function(){return scrollToLatestMessage;};this.setScrollToLatestMessage=function(scrollToLatestMessageParam){scrollToLatestMessage=bool(scrollToLatestMessageParam);if(consoleWindowExists()){getConsoleWindow().setScrollToLatest(scrollToLatestMessage);}};this.getWidth=function(){return width;};this.setWidth=function(widthParam){if(checkCanConfigure("width")){width=extractStringFromParam(widthParam,width);}};this.getHeight=function(){return height;};this.setHeight=function(heightParam){if(checkCanConfigure("height")){height=extractStringFromParam(heightParam,height);}};this.getMaxMessages=function(){return maxMessages;};this.setMaxMessages=function(maxMessagesParam){maxMessages=extractIntFromParam(maxMessagesParam,maxMessages);if(consoleWindowExists()){getConsoleWindow().setMaxMessages(maxMessages);}};this.isShowCommandLine=function(){return showCommandLine;};this.setShowCommandLine=function(showCommandLineParam){showCommandLine=bool(showCommandLineParam);if(consoleWindowExists()){getConsoleWindow().setShowCommandLine(showCommandLine);}};this.isShowHideButton=function(){return showHideButton;};this.setShowHideButton=function(showHideButtonParam){showHideButton=bool(showHideButtonParam);if(consoleWindowExists()){getConsoleWindow().setShowHideButton(showHideButton);}};this.isShowCloseButton=function(){return showCloseButton;};this.setShowCloseButton=function(showCloseButtonParam){showCloseButton=bool(showCloseButtonParam);if(consoleWindowExists()){getConsoleWindow().setShowCloseButton(showCloseButton);}};this.getCommandLineObjectExpansionDepth=function(){return commandLineObjectExpansionDepth;};this.setCommandLineObjectExpansionDepth=function(commandLineObjectExpansionDepthParam){commandLineObjectExpansionDepth=extractIntFromParam(commandLineObjectExpansionDepthParam,commandLineObjectExpansionDepth);};var minimized=initiallyMinimized;this.isInitiallyMinimized=function(){return initiallyMinimized;};this.setInitiallyMinimized=function(initiallyMinimizedParam){if(checkCanConfigure("initiallyMinimized")){initiallyMinimized=bool(initiallyMinimizedParam);minimized=initiallyMinimized;}};this.isUseDocumentWrite=function(){return useDocumentWrite;};this.setUseDocumentWrite=function(useDocumentWriteParam){if(checkCanConfigure("useDocumentWrite")){useDocumentWrite=bool(useDocumentWriteParam);}};function QueuedLoggingEvent(loggingEvent,formattedMessage){this.loggingEvent=loggingEvent;this.levelName=loggingEvent.level.name;this.formattedMessage=formattedMessage;}

+QueuedLoggingEvent.prototype.append=function(){getConsoleWindow().log(this.levelName,this.formattedMessage);};function QueuedGroup(name,initiallyExpanded){this.name=name;this.initiallyExpanded=initiallyExpanded;}

+QueuedGroup.prototype.append=function(){getConsoleWindow().group(this.name,this.initiallyExpanded);};function QueuedGroupEnd(){}

+QueuedGroupEnd.prototype.append=function(){getConsoleWindow().groupEnd();};var checkAndAppend=function(){safeToAppend();if(!initialized){init();}else if(consoleClosed&&reopenWhenClosed){createWindow();}

+if(safeToAppend()){appendQueuedLoggingEvents();}};this.append=function(loggingEvent){if(isSupported){var formattedMessage=appender.getLayout().format(loggingEvent);if(this.getLayout().ignoresThrowable()){formattedMessage+=loggingEvent.getThrowableStrRep();}

+queuedLoggingEvents.push(new QueuedLoggingEvent(loggingEvent,formattedMessage));checkAndAppend();}};this.group=function(name,initiallyExpanded){if(isSupported){queuedLoggingEvents.push(new QueuedGroup(name,initiallyExpanded));checkAndAppend();}};this.groupEnd=function(){if(isSupported){queuedLoggingEvents.push(new QueuedGroupEnd());checkAndAppend();}};var appendQueuedLoggingEvents=function(){var currentLoggingEvent;while(queuedLoggingEvents.length>0){queuedLoggingEvents.shift().append();}

+if(focusConsoleWindow){getConsoleWindow().focus();}};this.setAddedToLogger=function(logger){this.loggers.push(logger);if(enabled&&!lazyInit){init();}};this.clear=function(){if(consoleWindowExists()){getConsoleWindow().clearLog();}

+queuedLoggingEvents.length=0;};this.focus=function(){if(consoleWindowExists()){getConsoleWindow().focus();}};this.focusCommandLine=function(){if(consoleWindowExists()){getConsoleWindow().focusCommandLine();}};this.focusSearch=function(){if(consoleWindowExists()){getConsoleWindow().focusSearch();}};var commandWindow=window;this.getCommandWindow=function(){return commandWindow;};this.setCommandWindow=function(commandWindowParam){commandWindow=commandWindowParam;};this.executeLastCommand=function(){if(consoleWindowExists()){getConsoleWindow().evalLastCommand();}};var commandLayout=new PatternLayout("%m");this.getCommandLayout=function(){return commandLayout;};this.setCommandLayout=function(commandLayoutParam){commandLayout=commandLayoutParam;};this.evalCommandAndAppend=function(expr){var commandReturnValue={appendResult:true,isError:false};var commandOutput="";try{var result,i;if(!commandWindow.eval&&commandWindow.execScript){commandWindow.execScript("null");}

+var commandLineFunctionsHash={};for(i=0,len=commandLineFunctions.length;i<len;i++){commandLineFunctionsHash[commandLineFunctions[i][0]]=commandLineFunctions[i][1];}

+var objectsToRestore=[];var addObjectToRestore=function(name){objectsToRestore.push([name,commandWindow[name]]);};addObjectToRestore("appender");commandWindow.appender=appender;addObjectToRestore("commandReturnValue");commandWindow.commandReturnValue=commandReturnValue;addObjectToRestore("commandLineFunctionsHash");commandWindow.commandLineFunctionsHash=commandLineFunctionsHash;var addFunctionToWindow=function(name){addObjectToRestore(name);commandWindow[name]=function(){return this.commandLineFunctionsHash[name](appender,arguments,commandReturnValue);};};for(i=0,len=commandLineFunctions.length;i<len;i++){addFunctionToWindow(commandLineFunctions[i][0]);}

+if(commandWindow===window&&commandWindow.execScript){addObjectToRestore("evalExpr");addObjectToRestore("result");window.evalExpr=expr;commandWindow.execScript("window.result=eval(window.evalExpr);");result=window.result;}else{result=commandWindow.eval(expr);}

+commandOutput=isUndefined(result)?result:formatObjectExpansion(result,commandLineObjectExpansionDepth);for(i=0,len=objectsToRestore.length;i<len;i++){commandWindow[objectsToRestore[i][0]]=objectsToRestore[i][1];}}catch(ex){commandOutput="Error evaluating command: "+getExceptionStringRep(ex);commandReturnValue.isError=true;}

+if(commandReturnValue.appendResult){var message=">>> "+expr;if(!isUndefined(commandOutput)){message+=newLine+commandOutput;}

+var level=commandReturnValue.isError?Level.ERROR:Level.INFO;var loggingEvent=new LoggingEvent(null,new Date(),level,[message],null);var mainLayout=this.getLayout();this.setLayout(commandLayout);this.append(loggingEvent);this.setLayout(mainLayout);}};var commandLineFunctions=defaultCommandLineFunctions.concat([]);this.addCommandLineFunction=function(functionName,commandLineFunction){commandLineFunctions.push([functionName,commandLineFunction]);};var commandHistoryCookieName="log4javascriptCommandHistory";this.storeCommandHistory=function(commandHistory){setCookie(commandHistoryCookieName,commandHistory.join(","));};var writeHtml=function(doc){var lines=getConsoleHtmlLines();doc.open();for(var i=0,len=lines.length;i<len;i++){doc.writeln(lines[i]);}

+doc.close();};this.setEventTypes(["load","unload"]);var consoleWindowLoadHandler=function(){var win=getConsoleWindow();win.setAppender(appender);win.setNewestAtTop(newestMessageAtTop);win.setScrollToLatest(scrollToLatestMessage);win.setMaxMessages(maxMessages);win.setShowCommandLine(showCommandLine);win.setShowHideButton(showHideButton);win.setShowCloseButton(showCloseButton);win.setMainWindow(window);var storedValue=getCookie(commandHistoryCookieName);if(storedValue){win.commandHistory=storedValue.split(",");win.currentCommandIndex=win.commandHistory.length;}

+appender.dispatchEvent("load",{"win":win});};this.unload=function(){logLog.debug("unload "+this+", caller: "+this.unload.caller);if(!consoleClosed){logLog.debug("really doing unload "+this);consoleClosed=true;consoleWindowLoaded=false;consoleWindowCreated=false;appender.dispatchEvent("unload",{});}};var pollConsoleWindow=function(windowTest,interval,successCallback,errorMessage){function doPoll(){try{if(consoleClosed){clearInterval(poll);}

+if(windowTest(getConsoleWindow())){clearInterval(poll);successCallback();}}catch(ex){clearInterval(poll);isSupported=false;handleError(errorMessage,ex);}}

+var poll=setInterval(doPoll,interval);};var getConsoleUrl=function(){var documentDomainSet=(document.domain!=location.hostname);return useDocumentWrite?"":getBaseUrl()+"console.html"+

+(documentDomainSet?"?log4javascript_domain="+escape(document.domain):"");};if(inPage){var containerElement=null;var cssProperties=[];this.addCssProperty=function(name,value){if(checkCanConfigure("cssProperties")){cssProperties.push([name,value]);}};var windowCreationStarted=false;var iframeContainerDiv;var iframeId=uniqueId+"_InPageAppender_"+consoleAppenderId;this.hide=function(){if(initialized&&consoleWindowCreated){if(consoleWindowExists()){getConsoleWindow().$("command").blur();}

+iframeContainerDiv.style.display="none";minimized=true;}};this.show=function(){if(initialized){if(consoleWindowCreated){iframeContainerDiv.style.display="block";this.setShowCommandLine(showCommandLine);minimized=false;}else if(!windowCreationStarted){createWindow(true);}}};this.isVisible=function(){return!minimized&&!consoleClosed;};this.close=function(fromButton){if(!consoleClosed&&(!fromButton||confirm("This will permanently remove the console from the page. No more messages will be logged. Do you wish to continue?"))){iframeContainerDiv.parentNode.removeChild(iframeContainerDiv);this.unload();}};open=function(){var initErrorMessage="InPageAppender.open: unable to create console iframe";function finalInit(){try{if(!initiallyMinimized){appender.show();}

+consoleWindowLoadHandler();consoleWindowLoaded=true;appendQueuedLoggingEvents();}catch(ex){isSupported=false;handleError(initErrorMessage,ex);}}

+function writeToDocument(){try{var windowTest=function(win){return isLoaded(win);};if(useDocumentWrite){writeHtml(getConsoleWindow().document);}

+if(windowTest(getConsoleWindow())){finalInit();}else{pollConsoleWindow(windowTest,100,finalInit,initErrorMessage);}}catch(ex){isSupported=false;handleError(initErrorMessage,ex);}}

+minimized=false;iframeContainerDiv=containerElement.appendChild(document.createElement("div"));iframeContainerDiv.style.width=width;iframeContainerDiv.style.height=height;iframeContainerDiv.style.border="solid gray 1px";for(var i=0,len=cssProperties.length;i<len;i++){iframeContainerDiv.style[cssProperties[i][0]]=cssProperties[i][1];}

+var iframeSrc=useDocumentWrite?"":" src='"+getConsoleUrl()+"'";iframeContainerDiv.innerHTML="<iframe id='"+iframeId+"' name='"+iframeId+"' width='100%' height='100%' frameborder='0'"+iframeSrc+" scrolling='no'></iframe>";consoleClosed=false;var iframeDocumentExistsTest=function(win){try{return bool(win)&&bool(win.document);}catch(ex){return false;}};if(iframeDocumentExistsTest(getConsoleWindow())){writeToDocument();}else{pollConsoleWindow(iframeDocumentExistsTest,100,writeToDocument,initErrorMessage);}

+consoleWindowCreated=true;};createWindow=function(show){if(show||!initiallyMinimized){var pageLoadHandler=function(){if(!container){containerElement=document.createElement("div");containerElement.style.position="fixed";containerElement.style.left="0";containerElement.style.right="0";containerElement.style.bottom="0";document.body.appendChild(containerElement);appender.addCssProperty("borderWidth","1px 0 0 0");appender.addCssProperty("zIndex",1000000);open();}else{try{var el=document.getElementById(container);if(el.nodeType==1){containerElement=el;}

+open();}catch(ex){handleError("InPageAppender.init: invalid container element '"+container+"' supplied",ex);}}};if(pageLoaded&&container&&container.appendChild){containerElement=container;open();}else if(pageLoaded){pageLoadHandler();}else{log4javascript.addEventListener("load",pageLoadHandler);}

+windowCreationStarted=true;}};init=function(){createWindow();initialized=true;};getConsoleWindow=function(){var iframe=window.frames[iframeId];if(iframe){return iframe;}};safeToAppend=function(){if(isSupported&&!consoleClosed){if(consoleWindowCreated&&!consoleWindowLoaded&&getConsoleWindow()&&isLoaded(getConsoleWindow())){consoleWindowLoaded=true;}

+return consoleWindowLoaded;}

+return false;};}else{var useOldPopUp=appender.defaults.useOldPopUp;var complainAboutPopUpBlocking=appender.defaults.complainAboutPopUpBlocking;var reopenWhenClosed=this.defaults.reopenWhenClosed;this.isUseOldPopUp=function(){return useOldPopUp;};this.setUseOldPopUp=function(useOldPopUpParam){if(checkCanConfigure("useOldPopUp")){useOldPopUp=bool(useOldPopUpParam);}};this.isComplainAboutPopUpBlocking=function(){return complainAboutPopUpBlocking;};this.setComplainAboutPopUpBlocking=function(complainAboutPopUpBlockingParam){if(checkCanConfigure("complainAboutPopUpBlocking")){complainAboutPopUpBlocking=bool(complainAboutPopUpBlockingParam);}};this.isFocusPopUp=function(){return focusConsoleWindow;};this.setFocusPopUp=function(focusPopUpParam){focusConsoleWindow=bool(focusPopUpParam);};this.isReopenWhenClosed=function(){return reopenWhenClosed;};this.setReopenWhenClosed=function(reopenWhenClosedParam){reopenWhenClosed=bool(reopenWhenClosedParam);};this.close=function(){logLog.debug("close "+this);try{popUp.close();this.unload();}catch(ex){}};this.hide=function(){logLog.debug("hide "+this);if(consoleWindowExists()){this.close();}};this.show=function(){logLog.debug("show "+this);if(!consoleWindowCreated){open();}};this.isVisible=function(){return safeToAppend();};var popUp;open=function(){var windowProperties="width="+width+",height="+height+",status,resizable";var frameInfo="";try{var frameEl=window.frameElement;if(frameEl){frameInfo="_"+frameEl.tagName+"_"+(frameEl.name||frameEl.id||"");}}catch(e){frameInfo="_inaccessibleParentFrame";}

+var windowName="PopUp_"+location.host.replace(/[^a-z0-9]/gi,"_")+"_"+consoleAppenderId+frameInfo;if(!useOldPopUp||!useDocumentWrite){windowName=windowName+"_"+uniqueId;}

+var checkPopUpClosed=function(win){if(consoleClosed){return true;}else{try{return bool(win)&&win.closed;}catch(ex){}}

+return false;};var popUpClosedCallback=function(){if(!consoleClosed){appender.unload();}};function finalInit(){getConsoleWindow().setCloseIfOpenerCloses(!useOldPopUp||!useDocumentWrite);consoleWindowLoadHandler();consoleWindowLoaded=true;appendQueuedLoggingEvents();pollConsoleWindow(checkPopUpClosed,500,popUpClosedCallback,"PopUpAppender.checkPopUpClosed: error checking pop-up window");}

+try{popUp=window.open(getConsoleUrl(),windowName,windowProperties);consoleClosed=false;consoleWindowCreated=true;if(popUp&&popUp.document){if(useDocumentWrite&&useOldPopUp&&isLoaded(popUp)){popUp.mainPageReloaded();finalInit();}else{if(useDocumentWrite){writeHtml(popUp.document);}

+var popUpLoadedTest=function(win){return bool(win)&&isLoaded(win);};if(isLoaded(popUp)){finalInit();}else{pollConsoleWindow(popUpLoadedTest,100,finalInit,"PopUpAppender.init: unable to create console window");}}}else{isSupported=false;logLog.warn("PopUpAppender.init: pop-ups blocked, please unblock to use PopUpAppender");if(complainAboutPopUpBlocking){handleError("log4javascript: pop-up windows appear to be blocked. Please unblock them to use pop-up logging.");}}}catch(ex){handleError("PopUpAppender.init: error creating pop-up",ex);}};createWindow=function(){if(!initiallyMinimized){open();}};init=function(){createWindow();initialized=true;};getConsoleWindow=function(){return popUp;};safeToAppend=function(){if(isSupported&&!isUndefined(popUp)&&!consoleClosed){if(popUp.closed||(consoleWindowLoaded&&isUndefined(popUp.closed))){appender.unload();logLog.debug("PopUpAppender: pop-up closed");return false;}

+if(!consoleWindowLoaded&&isLoaded(popUp)){consoleWindowLoaded=true;}}

+return isSupported&&consoleWindowLoaded&&!consoleClosed;};}

+this.getConsoleWindow=getConsoleWindow;};ConsoleAppender.addGlobalCommandLineFunction=function(functionName,commandLineFunction){defaultCommandLineFunctions.push([functionName,commandLineFunction]);};function PopUpAppender(lazyInit,initiallyMinimized,useDocumentWrite,width,height){this.create(false,null,lazyInit,initiallyMinimized,useDocumentWrite,width,height,this.defaults.focusPopUp);}

+PopUpAppender.prototype=new ConsoleAppender();PopUpAppender.prototype.defaults={layout:new PatternLayout("%d{HH:mm:ss} %-5p - %m{1}%n"),initiallyMinimized:false,focusPopUp:false,lazyInit:true,useOldPopUp:true,complainAboutPopUpBlocking:true,newestMessageAtTop:false,scrollToLatestMessage:true,width:"600",height:"400",reopenWhenClosed:false,maxMessages:null,showCommandLine:true,commandLineObjectExpansionDepth:1,showHideButton:false,showCloseButton:true,showLogEntryDeleteButtons:true,useDocumentWrite:true};PopUpAppender.prototype.toString=function(){return"PopUpAppender";};log4javascript.PopUpAppender=PopUpAppender;function InPageAppender(container,lazyInit,initiallyMinimized,useDocumentWrite,width,height){this.create(true,container,lazyInit,initiallyMinimized,useDocumentWrite,width,height,false);}

+InPageAppender.prototype=new ConsoleAppender();InPageAppender.prototype.defaults={layout:new PatternLayout("%d{HH:mm:ss} %-5p - %m{1}%n"),initiallyMinimized:false,lazyInit:true,newestMessageAtTop:false,scrollToLatestMessage:true,width:"100%",height:"220px",maxMessages:null,showCommandLine:true,commandLineObjectExpansionDepth:1,showHideButton:false,showCloseButton:false,showLogEntryDeleteButtons:true,useDocumentWrite:true};InPageAppender.prototype.toString=function(){return"InPageAppender";};log4javascript.InPageAppender=InPageAppender;log4javascript.InlineAppender=InPageAppender;})();function padWithSpaces(str,len){if(str.length<len){var spaces=[];var numberOfSpaces=Math.max(0,len-str.length);for(var i=0;i<numberOfSpaces;i++){spaces[i]=" ";}

+str+=spaces.join("");}

+return str;}

+(function(){function dir(obj){var maxLen=0;for(var p in obj){maxLen=Math.max(toStr(p).length,maxLen);}

+var propList=[];for(p in obj){var propNameStr="  "+padWithSpaces(toStr(p),maxLen+2);var propVal;try{propVal=splitIntoLines(toStr(obj[p])).join(padWithSpaces(newLine,maxLen+6));}catch(ex){propVal="[Error obtaining property. Details: "+getExceptionMessage(ex)+"]";}

+propList.push(propNameStr+propVal);}

+return propList.join(newLine);}

+var nodeTypes={ELEMENT_NODE:1,ATTRIBUTE_NODE:2,TEXT_NODE:3,CDATA_SECTION_NODE:4,ENTITY_REFERENCE_NODE:5,ENTITY_NODE:6,PROCESSING_INSTRUCTION_NODE:7,COMMENT_NODE:8,DOCUMENT_NODE:9,DOCUMENT_TYPE_NODE:10,DOCUMENT_FRAGMENT_NODE:11,NOTATION_NODE:12};var preFormattedElements=["script","pre"];var emptyElements=["br","img","hr","param","link","area","input","col","base","meta"];var indentationUnit="  ";function getXhtml(rootNode,includeRootNode,indentation,startNewLine,preformatted){includeRootNode=(typeof includeRootNode=="undefined")?true:!!includeRootNode;if(typeof indentation!="string"){indentation="";}

+startNewLine=!!startNewLine;preformatted=!!preformatted;var xhtml;function isWhitespace(node){return((node.nodeType==nodeTypes.TEXT_NODE)&&/^[ \t\r\n]*$/.test(node.nodeValue));}

+function fixAttributeValue(attrValue){return attrValue.toString().replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/"/g,"&quot;");}

+function getStyleAttributeValue(el){var stylePairs=el.style.cssText.split(";");var styleValue="";var isFirst=true;for(var j=0,len=stylePairs.length;j<len;j++){var nameValueBits=stylePairs[j].split(":");var props=[];if(!/^\s*$/.test(nameValueBits[0])){props.push(trim(nameValueBits[0]).toLowerCase()+":"+trim(nameValueBits[1]));}

+styleValue=props.join(";");}

+return styleValue;}

+function getNamespace(el){if(el.prefix){return el.prefix;}else if(el.outerHTML){var regex=new RegExp("<([^:]+):"+el.tagName+"[^>]*>","i");if(regex.test(el.outerHTML)){return RegExp.$1.toLowerCase();}}

+return"";}

+var lt="<";var gt=">";if(includeRootNode&&rootNode.nodeType!=nodeTypes.DOCUMENT_FRAGMENT_NODE){switch(rootNode.nodeType){case nodeTypes.ELEMENT_NODE:var tagName=rootNode.tagName.toLowerCase();xhtml=startNewLine?newLine+indentation:"";xhtml+=lt;var prefix=getNamespace(rootNode);var hasPrefix=!!prefix;if(hasPrefix){xhtml+=prefix+":";}

+xhtml+=tagName;for(i=0,len=rootNode.attributes.length;i<len;i++){var currentAttr=rootNode.attributes[i];if(!currentAttr.specified||currentAttr.nodeValue===null||currentAttr.nodeName.toLowerCase()==="style"||typeof currentAttr.nodeValue!=="string"||currentAttr.nodeName.indexOf("_moz")===0){continue;}

+xhtml+=" "+currentAttr.nodeName.toLowerCase()+"=\"";xhtml+=fixAttributeValue(currentAttr.nodeValue);xhtml+="\"";}

+if(rootNode.style.cssText){var styleValue=getStyleAttributeValue(rootNode);if(styleValue!==""){xhtml+=" style=\""+getStyleAttributeValue(rootNode)+"\"";}}

+if(array_contains(emptyElements,tagName)||(hasPrefix&&!rootNode.hasChildNodes())){xhtml+="/"+gt;}else{xhtml+=gt;var childStartNewLine=!(rootNode.childNodes.length===1&&rootNode.childNodes[0].nodeType===nodeTypes.TEXT_NODE);var childPreformatted=array_contains(preFormattedElements,tagName);for(var i=0,len=rootNode.childNodes.length;i<len;i++){xhtml+=getXhtml(rootNode.childNodes[i],true,indentation+indentationUnit,childStartNewLine,childPreformatted);}

+var endTag=lt+"/"+tagName+gt;xhtml+=childStartNewLine?newLine+indentation+endTag:endTag;}

+return xhtml;case nodeTypes.TEXT_NODE:if(isWhitespace(rootNode)){xhtml="";}else{if(preformatted){xhtml=rootNode.nodeValue;}else{var lines=splitIntoLines(trim(rootNode.nodeValue));var trimmedLines=[];for(var i=0,len=lines.length;i<len;i++){trimmedLines[i]=trim(lines[i]);}

+xhtml=trimmedLines.join(newLine+indentation);}

+if(startNewLine){xhtml=newLine+indentation+xhtml;}}

+return xhtml;case nodeTypes.CDATA_SECTION_NODE:return"<![CDA"+"TA["+rootNode.nodeValue+"]"+"]>"+newLine;case nodeTypes.DOCUMENT_NODE:xhtml="";for(var i=0,len=rootNode.childNodes.length;i<len;i++){xhtml+=getXhtml(rootNode.childNodes[i],true,indentation);}

+return xhtml;default:return"";}}else{xhtml="";for(var i=0,len=rootNode.childNodes.length;i<len;i++){xhtml+=getXhtml(rootNode.childNodes[i],true,indentation+indentationUnit);}

+return xhtml;}}

+function createCommandLineFunctions(){ConsoleAppender.addGlobalCommandLineFunction("$",function(appender,args,returnValue){return document.getElementById(args[0]);});ConsoleAppender.addGlobalCommandLineFunction("dir",function(appender,args,returnValue){var lines=[];for(var i=0,len=args.length;i<len;i++){lines[i]=dir(args[i]);}

+return lines.join(newLine+newLine);});ConsoleAppender.addGlobalCommandLineFunction("dirxml",function(appender,args,returnValue){var lines=[];for(var i=0,len=args.length;i<len;i++){var win=appender.getCommandWindow();lines[i]=getXhtml(args[i]);}

+return lines.join(newLine+newLine);});ConsoleAppender.addGlobalCommandLineFunction("cd",function(appender,args,returnValue){var win,message;if(args.length===0||args[0]===""){win=window;message="Command line set to run in main window";}else{if(args[0].window==args[0]){win=args[0];message="Command line set to run in frame '"+args[0].name+"'";}else{win=window.frames[args[0]];if(win){message="Command line set to run in frame '"+args[0]+"'";}else{returnValue.isError=true;message="Frame '"+args[0]+"' does not exist";win=appender.getCommandWindow();}}}

+appender.setCommandWindow(win);return message;});ConsoleAppender.addGlobalCommandLineFunction("clear",function(appender,args,returnValue){returnValue.appendResult=false;appender.clear();});ConsoleAppender.addGlobalCommandLineFunction("keys",function(appender,args,returnValue){var keys=[];for(var k in args[0]){keys.push(k);}

+return keys;});ConsoleAppender.addGlobalCommandLineFunction("values",function(appender,args,returnValue){var values=[];for(var k in args[0]){try{values.push(args[0][k]);}catch(ex){logLog.warn("values(): Unable to obtain value for key "+k+". Details: "+getExceptionMessage(ex));}}

+return values;});ConsoleAppender.addGlobalCommandLineFunction("expansionDepth",function(appender,args,returnValue){var expansionDepth=parseInt(args[0],10);if(isNaN(expansionDepth)||expansionDepth<0){returnValue.isError=true;return""+args[0]+" is not a valid expansion depth";}else{appender.setCommandLineObjectExpansionDepth(expansionDepth);return"Object expansion depth set to "+expansionDepth;}});}

+function init(){createCommandLineFunctions();}

+init();})();log4javascript.setDocumentReady=function(){pageLoaded=true;log4javascript.dispatchEvent("load",{});};if(window.addEventListener){window.addEventListener("load",log4javascript.setDocumentReady,false);}else if(window.attachEvent){window.attachEvent("onload",log4javascript.setDocumentReady);}else{var oldOnload=window.onload;if(typeof window.onload!="function"){window.onload=log4javascript.setDocumentReady;}else{window.onload=function(evt){if(oldOnload){oldOnload(evt);}

+log4javascript.setDocumentReady();};}}

+window.log4javascript=log4javascript;return log4javascript;})();

diff --git a/xos/core/static/log4javascript-1.4.6/js/log4javascript_lite.js b/xos/core/static/log4javascript-1.4.6/js/log4javascript_lite.js
new file mode 100644
index 0000000..b04ce8e
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/js/log4javascript_lite.js
@@ -0,0 +1,55 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+

+if(!Array.prototype.shift){Array.prototype.shift=function(){if(this.length>0){var firstItem=this[0];for(var i=0,len=this.length-1;i<len;i++){this[i]=this[i+1];}

+this.length--;return firstItem;}};}

+var log4javascript;(function(){var newLine="\r\n";function Log4JavaScript(){}

+log4javascript=new Log4JavaScript();log4javascript.version="1.4.6";log4javascript.edition="log4javascript_lite";function getExceptionMessage(ex){if(ex.message){return ex.message;}else if(ex.description){return ex.description;}else{return String(ex);}}

+function getUrlFileName(url){var lastSlashIndex=Math.max(url.lastIndexOf("/"),url.lastIndexOf("\\"));return url.substr(lastSlashIndex+1);}

+function getExceptionStringRep(ex){if(ex){var exStr="Exception: "+getExceptionMessage(ex);try{if(ex.lineNumber){exStr+=" on line number "+ex.lineNumber;}

+if(ex.fileName){exStr+=" in file "+getUrlFileName(ex.fileName);}}catch(localEx){}

+if(showStackTraces&&ex.stack){exStr+=newLine+"Stack trace:"+newLine+ex.stack;}

+return exStr;}

+return null;}

+function isError(err){return(err instanceof Error);}

+function bool(obj){return Boolean(obj);}

+var enabled=(typeof log4javascript_disabled!="undefined")&&log4javascript_disabled?false:true;log4javascript.setEnabled=function(enable){enabled=bool(enable);};log4javascript.isEnabled=function(){return enabled;};var showStackTraces=false;log4javascript.setShowStackTraces=function(show){showStackTraces=bool(show);};var Level=function(level,name){this.level=level;this.name=name;};Level.prototype={toString:function(){return this.name;},equals:function(level){return this.level==level.level;},isGreaterOrEqual:function(level){return this.level>=level.level;}};Level.ALL=new Level(Number.MIN_VALUE,"ALL");Level.TRACE=new Level(10000,"TRACE");Level.DEBUG=new Level(20000,"DEBUG");Level.INFO=new Level(30000,"INFO");Level.WARN=new Level(40000,"WARN");Level.ERROR=new Level(50000,"ERROR");Level.FATAL=new Level(60000,"FATAL");Level.OFF=new Level(Number.MAX_VALUE,"OFF");log4javascript.Level=Level;function Appender(){var getConsoleHtmlLines=function(){return['<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">','<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">','<head>','<title>log4javascript</title>','<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />','<!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->','<meta http-equiv="X-UA-Compatible" content="IE=7" />','<script type="text/javascript">','//<![CDATA[','var loggingEnabled=true;var messagesBeforeDocLoaded=[];function toggleLoggingEnabled(){setLoggingEnabled($("enableLogging").checked);}','function setLoggingEnabled(enable){loggingEnabled=enable;}','function scrollToLatestEntry(){var l=getLogContainer();if(typeof l.scrollTop!="undefined"){var latestLogEntry=l.lastChild;if(latestLogEntry){l.scrollTop=l.scrollHeight;}}}','function log(logLevel,formattedMessage){if(loggingEnabled){if(loaded){doLog(logLevel,formattedMessage);}else{messagesBeforeDocLoaded.push([logLevel,formattedMessage]);}}}','function doLog(logLevel,formattedMessage){var logEntry=document.createElement("div");logEntry.appendChild(document.createTextNode(formattedMessage));logEntry.className="logentry "+logLevel.name;getLogContainer().appendChild(logEntry);scrollToLatestEntry();}','function mainPageReloaded(){var separator=document.createElement("div");separator.className="separator";separator.innerHTML="&nbsp;";getLogContainer().appendChild(separator);}','var loaded=false;var logLevels=["DEBUG","INFO","WARN","ERROR","FATAL"];window.onload=function(){setLogContainerHeight();toggleLoggingEnabled();for(var i=0;i<messagesBeforeDocLoaded.length;i++){doLog(messagesBeforeDocLoaded[i][0],messagesBeforeDocLoaded[i][1]);}','messagesBeforeDocLoaded=[];loaded=true;setTimeout(setLogContainerHeight,20);};function getLogContainer(){return $("log");}','function clearLog(){getLogContainer().innerHTML="";}','function $(id){return document.getElementById(id);}','function getWindowHeight(){if(window.innerHeight){return window.innerHeight;}else if(document.documentElement&&document.documentElement.clientHeight){return document.documentElement.clientHeight;}else if(document.body){return document.body.clientHeight;}','return 0;}','function getChromeHeight(){return $("toolbar").offsetHeight;}','function setLogContainerHeight(){var windowHeight=getWindowHeight();$("body").style.height=getWindowHeight()+"px";getLogContainer().style.height=""+','Math.max(0,windowHeight-getChromeHeight())+"px";}','window.onresize=function(){setLogContainerHeight();};','//]]>','</script>','<style type="text/css">','body{background-color:white;color:black;padding:0;margin:0;font-family:tahoma,verdana,arial,helvetica,sans-serif;overflow:hidden}div#toolbar{border-top:solid #ffffff 1px;border-bottom:solid #aca899 1px;background-color:#f1efe7;padding:3px 5px;font-size:68.75%}div#toolbar input.button{padding:0 5px;font-size:100%}div#log{font-family:Courier New,Courier;font-size:75%;width:100%;overflow:auto;clear:both}*.logentry{overflow:visible;white-space:pre}*.TRACE{color:#666666}*.DEBUG{color:green}*.INFO{color:#000099}*.WARN{color:#999900}*.ERROR{color:red}*.FATAL{color:#660066}div#log div.separator{background-color:#cccccc;margin:5px 0;line-height:1px}','</style>','</head>','<body id="body">','<div id="toolbar">','Options:','<input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" class="stateful" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Enable logging</label>','<input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="stateful button" title="Clear all log messages"  />','<input type="button" id="closeButton" value="Close" onclick="window.close()" class="stateful button" title="Close the window" />','</div>','<div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>','</body>','</html>'];};var popUp=null;var popUpsBlocked=false;var popUpClosed=false;var popUpLoaded=false;var complainAboutPopUpBlocking=true;var initialized=false;var isSupported=true;var width=600;var height=400;var focusPopUp=false;var queuedLoggingEvents=new Array();function isLoaded(win){try{return bool(win.loaded);}catch(ex){return false;}}

+function finalInit(){popUpLoaded=true;appendQueuedLoggingEvents();}

+function writeHtml(doc){var lines=getConsoleHtmlLines();doc.open();for(var i=0,len=lines.length;i<len;i++){doc.writeln(lines[i]);}

+doc.close();}

+function pollConsoleWindow(){function pollConsoleWindowLoaded(){if(popUpLoaded){clearInterval(poll);}else if(bool(popUp)&&isLoaded(popUp)){clearInterval(poll);finalInit();}}

+var poll=setInterval(pollConsoleWindowLoaded,100);}

+function init(){var windowProperties="width="+width+",height="+height+",status,resizable";var windowName="log4javascriptLitePopUp"+location.host.replace(/[^a-z0-9]/gi,"_");popUp=window.open("",windowName,windowProperties);popUpClosed=false;if(popUp){if(isLoaded(popUp)){popUp.mainPageReloaded();finalInit();}else{writeHtml(popUp.document);if(isLoaded(popUp)){finalInit();}else{pollConsoleWindow();}}}else{isSupported=false;if(complainAboutPopUpBlocking){alert("log4javascript: pop-up windows appear to be blocked. Please unblock them to use pop-up logging.");}}

+initialized=true;}

+function safeToAppend(){if(!popUpsBlocked&&!popUpClosed){if(popUp.closed){popUpClosed=true;return false;}

+if(!popUpLoaded&&popUp.loaded){popUpLoaded=true;}}

+return!popUpsBlocked&&popUpLoaded&&!popUpClosed;}

+function padWithZeroes(num,len){var str=""+num;while(str.length<len){str="0"+str;}

+return str;}

+function padWithSpaces(str,len){while(str.length<len){str+=" ";}

+return str;}

+this.append=function(loggingEvent){if(!initialized){init();}

+queuedLoggingEvents.push(loggingEvent);if(safeToAppend()){appendQueuedLoggingEvents();}};function appendQueuedLoggingEvents(){if(safeToAppend()){while(queuedLoggingEvents.length>0){var currentLoggingEvent=queuedLoggingEvents.shift();var date=currentLoggingEvent.timeStamp;var formattedDate=padWithZeroes(date.getHours(),2)+":"+

+padWithZeroes(date.getMinutes(),2)+":"+padWithZeroes(date.getSeconds(),2);var formattedMessage=formattedDate+" "+padWithSpaces(currentLoggingEvent.level.name,5)+" - "+currentLoggingEvent.getCombinedMessages();var throwableStringRep=currentLoggingEvent.getThrowableStrRep();if(throwableStringRep){formattedMessage+=newLine+throwableStringRep;}

+popUp.log(currentLoggingEvent.level,formattedMessage);}

+if(focusPopUp){popUp.focus();}}}}

+log4javascript.Appender=Appender;function Logger(){var appender=new Appender();var loggerLevel=Level.ALL;this.log=function(level,params){if(enabled&&level.isGreaterOrEqual(this.getLevel())){var exception;var finalParamIndex=params.length-1;var lastParam=params[params.length-1];if(params.length>1&&isError(lastParam)){exception=lastParam;finalParamIndex--;}

+var messages=[];for(var i=0;i<=finalParamIndex;i++){messages[i]=params[i];}

+var loggingEvent=new LoggingEvent(this,new Date(),level,messages,exception);appender.append(loggingEvent);}};this.setLevel=function(level){loggerLevel=level;};this.getLevel=function(){return loggerLevel;};}

+Logger.prototype={trace:function(){this.log(Level.TRACE,arguments);},debug:function(){this.log(Level.DEBUG,arguments);},info:function(){this.log(Level.INFO,arguments);},warn:function(){this.log(Level.WARN,arguments);},error:function(){this.log(Level.ERROR,arguments);},fatal:function(){this.log(Level.FATAL,arguments);},isEnabledFor:function(level){return level.isGreaterOrEqual(this.getLevel());},isTraceEnabled:function(){return this.isEnabledFor(Level.TRACE);},isDebugEnabled:function(){return this.isEnabledFor(Level.DEBUG);},isInfoEnabled:function(){return this.isEnabledFor(Level.INFO);},isWarnEnabled:function(){return this.isEnabledFor(Level.WARN);},isErrorEnabled:function(){return this.isEnabledFor(Level.ERROR);},isFatalEnabled:function(){return this.isEnabledFor(Level.FATAL);}};var defaultLogger=null;log4javascript.getDefaultLogger=function(){if(!defaultLogger){defaultLogger=new Logger();}

+return defaultLogger;};log4javascript.getLogger=log4javascript.getDefaultLogger;var nullLogger=null;log4javascript.getNullLogger=function(){if(!nullLogger){nullLogger=new Logger();nullLogger.setLevel(Level.OFF);}

+return nullLogger;};var LoggingEvent=function(logger,timeStamp,level,messages,exception){this.logger=logger;this.timeStamp=timeStamp;this.level=level;this.messages=messages;this.exception=exception;};LoggingEvent.prototype={getThrowableStrRep:function(){return this.exception?getExceptionStringRep(this.exception):"";},getCombinedMessages:function(){return(this.messages.length===1)?this.messages[0]:this.messages.join(newLine);}};log4javascript.LoggingEvent=LoggingEvent;window.log4javascript=log4javascript;})();

diff --git a/xos/core/static/log4javascript-1.4.6/js/log4javascript_lite_uncompressed.js b/xos/core/static/log4javascript-1.4.6/js/log4javascript_lite_uncompressed.js
new file mode 100644
index 0000000..12e97d8
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/js/log4javascript_lite_uncompressed.js
@@ -0,0 +1,620 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+if (!Array.prototype.shift) {

+	Array.prototype.shift = function() {

+		if (this.length > 0) {

+			var firstItem = this[0];

+			for (var i = 0, len = this.length - 1; i < len; i++) {

+				this[i] = this[i + 1];

+			}

+			this.length--;

+			return firstItem;

+		}

+	};

+}

+

+var log4javascript;

+

+(function() {

+	var newLine = "\r\n";

+	function Log4JavaScript() {}

+	log4javascript = new Log4JavaScript();

+	log4javascript.version = "1.4.6";

+	log4javascript.edition = "log4javascript_lite";

+

+	function getExceptionMessage(ex) {

+		if (ex.message) {

+			return ex.message;

+		} else if (ex.description) {

+			return ex.description;

+		} else {

+			return String(ex);

+		}

+	}

+

+	// Gets the portion of the URL after the last slash

+	function getUrlFileName(url) {

+		var lastSlashIndex = Math.max(url.lastIndexOf("/"), url.lastIndexOf("\\"));

+		return url.substr(lastSlashIndex + 1);

+	}

+

+	// Returns a nicely formatted representation of an error

+	function getExceptionStringRep(ex) {

+		if (ex) {

+			var exStr = "Exception: " + getExceptionMessage(ex);

+			try {

+				if (ex.lineNumber) {

+					exStr += " on line number " + ex.lineNumber;

+				}

+				if (ex.fileName) {

+					exStr += " in file " + getUrlFileName(ex.fileName);

+				}

+			} catch (localEx) {

+			}

+			if (showStackTraces && ex.stack) {

+				exStr += newLine + "Stack trace:" + newLine + ex.stack;

+			}

+			return exStr;

+		}

+		return null;

+	}

+

+	function isError(err) {

+		return (err instanceof Error);

+	}

+

+	function bool(obj) {

+		return Boolean(obj);

+	}

+

+	var enabled = (typeof log4javascript_disabled != "undefined") &&

+		log4javascript_disabled ? false : true;

+

+	log4javascript.setEnabled = function(enable) {

+		enabled = bool(enable);

+	};

+

+	log4javascript.isEnabled = function() {

+		return enabled;

+	};

+

+	var showStackTraces = false;

+

+	log4javascript.setShowStackTraces = function(show) {

+		showStackTraces = bool(show);

+	};

+

+	/* ---------------------------------------------------------------------- */

+	// Levels

+

+	var Level = function(level, name) {

+		this.level = level;

+		this.name = name;

+	};

+

+	Level.prototype = {

+		toString: function() {

+			return this.name;

+		},

+		equals: function(level) {

+			return this.level == level.level;

+		},

+		isGreaterOrEqual: function(level) {

+			return this.level >= level.level;

+		}

+	};

+

+	Level.ALL = new Level(Number.MIN_VALUE, "ALL");

+	Level.TRACE = new Level(10000, "TRACE");

+	Level.DEBUG = new Level(20000, "DEBUG");

+	Level.INFO = new Level(30000, "INFO");

+	Level.WARN = new Level(40000, "WARN");

+	Level.ERROR = new Level(50000, "ERROR");

+	Level.FATAL = new Level(60000, "FATAL");

+	Level.OFF = new Level(Number.MAX_VALUE, "OFF");

+

+	log4javascript.Level = Level;

+

+	/* ---------------------------------------------------------------------- */

+	// Appenders

+

+	function Appender() {

+		var getConsoleHtmlLines = function() {

+			return [

+'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',

+'<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">',

+'	<head>',

+'		<title>log4javascript</title>',

+'		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />',

+'		<!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->',

+'		<meta http-equiv="X-UA-Compatible" content="IE=7" />',

+'		<script type="text/javascript">',

+'			//<![CDATA[',

+'			var loggingEnabled = true;',

+'			var messagesBeforeDocLoaded = [];',

+'',

+'			function toggleLoggingEnabled() {',

+'				setLoggingEnabled($("enableLogging").checked);',

+'			}',

+'',

+'			function setLoggingEnabled(enable) {',

+'				loggingEnabled = enable;',

+'			}',

+'',

+'			function scrollToLatestEntry() {',

+'				var l = getLogContainer();',

+'				if (typeof l.scrollTop != "undefined") {',

+'					var latestLogEntry = l.lastChild;',

+'					if (latestLogEntry) {',

+'						l.scrollTop = l.scrollHeight;',

+'					}',

+'				}',

+'			}',

+'',

+'			function log(logLevel, formattedMessage) {',

+'				if (loggingEnabled) {',

+'					if (loaded) {',

+'						doLog(logLevel, formattedMessage);',

+'					} else {',

+'						messagesBeforeDocLoaded.push([logLevel, formattedMessage]);',

+'					}',

+'				}',

+'			}',

+'',

+'			function doLog(logLevel, formattedMessage) {',

+'				var logEntry = document.createElement("div");',

+'				logEntry.appendChild(document.createTextNode(formattedMessage));',

+'				logEntry.className = "logentry " + logLevel.name;',

+'				getLogContainer().appendChild(logEntry);',

+'				scrollToLatestEntry();',

+'			}',

+'',

+'			function mainPageReloaded() {',

+'				var separator = document.createElement("div");',

+'				separator.className = "separator";',

+'				separator.innerHTML = "&nbsp;";',

+'				getLogContainer().appendChild(separator);',

+'			}',

+'',

+'			var loaded = false;',

+'			var logLevels = ["DEBUG", "INFO", "WARN", "ERROR", "FATAL"];',

+'',

+'			window.onload = function() {',

+'				setLogContainerHeight();',

+'				toggleLoggingEnabled();',

+'				for (var i = 0; i < messagesBeforeDocLoaded.length; i++) {',

+'					doLog(messagesBeforeDocLoaded[i][0], messagesBeforeDocLoaded[i][1]);',

+'				}',

+'				messagesBeforeDocLoaded = [];',

+'				loaded = true;',

+'',

+'				// Workaround to make sure log div starts at the correct size',

+'				setTimeout(setLogContainerHeight, 20);',

+'			};',

+'',

+'			function getLogContainer() {',

+'				return $("log");',

+'			}',

+'',

+'			function clearLog() {',

+'				getLogContainer().innerHTML = "";',

+'			}',

+'',

+'			/* ------------------------------------------------------------------------- */',

+'',

+'			// Other utility functions',

+'',

+'			// Syntax borrowed from Prototype library',

+'			function $(id) {',

+'				return document.getElementById(id);',

+'			}',

+'',

+'			function getWindowHeight() {',

+'				if (window.innerHeight) {',

+'					return window.innerHeight;',

+'				} else if (document.documentElement && document.documentElement.clientHeight) {',

+'					return document.documentElement.clientHeight;',

+'				} else if (document.body) {',

+'					return document.body.clientHeight;',

+'				}',

+'				return 0;',

+'			}',

+'',

+'			function getChromeHeight() {',

+'				return $("toolbar").offsetHeight;',

+'			}',

+'',

+'			function setLogContainerHeight() {',

+'				var windowHeight = getWindowHeight();',

+'				$("body").style.height = getWindowHeight() + "px";',

+'				getLogContainer().style.height = "" +',

+'					Math.max(0, windowHeight - getChromeHeight()) + "px";',

+'			}',

+'',

+'			window.onresize = function() {',

+'				setLogContainerHeight();',

+'			};',

+'',

+'			//]]>',

+'		</script>',

+'		<style type="text/css">',

+'			body {',

+'				background-color: white;',

+'				color: black;',

+'				padding: 0;',

+'				margin: 0;',

+'				font-family: tahoma, verdana, arial, helvetica, sans-serif;',

+'				overflow: hidden;',

+'			}',

+'			',

+'			div#toolbar {',

+'				border-top: solid #ffffff 1px;',

+'				border-bottom: solid #aca899 1px;',

+'				background-color: #f1efe7;',

+'				padding: 3px 5px;',

+'				font-size: 68.75%;',

+'			}',

+'',

+'			div#toolbar input.button {',

+'				padding: 0 5px;',

+'				font-size: 100%;',

+'			}',

+'',

+'			div#log {',

+'				font-family: Courier New, Courier;',

+'				font-size: 75%;',

+'				width: 100%;',

+'				overflow: auto;',

+'				clear: both;',

+'			}',

+'',

+'			*.logentry {',

+'				overflow: visible;',

+'				white-space: pre;',

+'			}',

+'',

+'			*.TRACE {',

+'				color: #666666;',

+'			}',

+'',

+'			*.DEBUG {',

+'				color: green;',

+'			}',

+'',

+'			*.INFO {',

+'				color: #000099;',

+'			}',

+'',

+'			*.WARN {',

+'				color: #999900;',

+'			}',

+'',

+'			*.ERROR {',

+'				color: red;',

+'			}',

+'',

+'			*.FATAL {',

+'				color: #660066;',

+'			}',

+'',

+'			div#log div.separator {',

+'				background-color: #cccccc;',

+'				margin: 5px 0;',

+'				line-height: 1px;',

+'			}',

+'		</style>',

+'	</head>',

+'',

+'	<body id="body">',

+'		<div id="toolbar">',

+'			Options:',

+'			<input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" class="stateful" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Enable logging</label>',

+'			<input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="stateful button" title="Clear all log messages"  />',

+'			<input type="button" id="closeButton" value="Close" onclick="window.close()" class="stateful button" title="Close the window" />',

+'		</div>',

+'		<div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>',

+'	</body>',

+'</html>'

+];

+		};

+

+		var popUp = null;

+		var popUpsBlocked = false;

+		var popUpClosed = false;

+		var popUpLoaded = false;

+		var complainAboutPopUpBlocking = true;

+		var initialized = false;

+		var isSupported = true;

+		var width = 600;

+		var height = 400;

+		var focusPopUp = false;

+		var queuedLoggingEvents = new Array();

+

+		function isLoaded(win) {

+			try {

+				return bool(win.loaded);

+			} catch (ex) {

+				return false;

+			}

+		}

+

+		function finalInit() {

+			popUpLoaded = true;

+			appendQueuedLoggingEvents();

+		}

+

+		function writeHtml(doc) {

+			var lines = getConsoleHtmlLines();

+			doc.open();

+			for (var i = 0, len = lines.length; i < len; i++) {

+				doc.writeln(lines[i]);

+			}

+			doc.close();

+		}

+

+		function pollConsoleWindow() {

+			function pollConsoleWindowLoaded() {

+				if (popUpLoaded) {

+					clearInterval(poll);

+				} else if (bool(popUp) && isLoaded(popUp)) {

+					clearInterval(poll);

+					finalInit();

+				}

+			}

+

+			// Poll the pop-up since the onload event is not reliable

+			var poll = setInterval(pollConsoleWindowLoaded, 100);

+		}

+

+		function init() {

+			var windowProperties = "width=" + width + ",height=" + height + ",status,resizable";

+			var windowName = "log4javascriptLitePopUp" + location.host.replace(/[^a-z0-9]/gi, "_");

+

+			popUp = window.open("", windowName, windowProperties);

+			popUpClosed = false;

+			if (popUp) {

+				if (isLoaded(popUp)) {

+					popUp.mainPageReloaded();

+					finalInit();

+				} else {

+					writeHtml(popUp.document);

+

+					// Check if the pop-up window object is available

+					if (isLoaded(popUp)) {

+						finalInit();

+					} else {

+						pollConsoleWindow();

+					}

+				}

+			} else {

+				isSupported = false;

+				if (complainAboutPopUpBlocking) {

+					alert("log4javascript: pop-up windows appear to be blocked. Please unblock them to use pop-up logging.");

+				}

+			}

+			initialized = true;

+		}

+

+		function safeToAppend() {

+			if (!popUpsBlocked && !popUpClosed) {

+				if (popUp.closed) {

+					popUpClosed = true;

+					return false;

+				}

+				if (!popUpLoaded && popUp.loaded) {

+					popUpLoaded = true;

+				}

+			}

+			return !popUpsBlocked && popUpLoaded && !popUpClosed;

+		}

+

+		function padWithZeroes(num, len) {

+			var str = "" + num;

+			while (str.length < len) {

+				str = "0" + str;

+			}

+			return str;

+		}

+

+		function padWithSpaces(str, len) {

+			while (str.length < len) {

+				str += " ";

+			}

+			return str;

+		}

+

+		this.append = function(loggingEvent) {

+			if (!initialized) {

+				init();

+			}

+			queuedLoggingEvents.push(loggingEvent);

+			if (safeToAppend()) {

+				appendQueuedLoggingEvents();

+			}

+		};

+

+		function appendQueuedLoggingEvents() {

+			if (safeToAppend()) {

+				while (queuedLoggingEvents.length > 0) {

+					var currentLoggingEvent = queuedLoggingEvents.shift();

+					var date = currentLoggingEvent.timeStamp;

+					var formattedDate = padWithZeroes(date.getHours(), 2) + ":" +

+						padWithZeroes(date.getMinutes(), 2) + ":" + padWithZeroes(date.getSeconds(), 2);

+					var formattedMessage = formattedDate + " " + padWithSpaces(currentLoggingEvent.level.name, 5) +

+						" - " + currentLoggingEvent.getCombinedMessages();

+					var throwableStringRep = currentLoggingEvent.getThrowableStrRep();

+					if (throwableStringRep) {

+						formattedMessage += newLine + throwableStringRep;

+					}

+					popUp.log(currentLoggingEvent.level, formattedMessage);

+				}

+				if (focusPopUp) {

+					popUp.focus();

+				}

+			}

+		}

+	}

+

+	log4javascript.Appender = Appender;

+

+	/* ---------------------------------------------------------------------- */

+	// Loggers

+

+	function Logger() {

+		var appender = new Appender();

+		var loggerLevel = Level.ALL;

+

+		this.log = function(level, params) {

+			if (enabled && level.isGreaterOrEqual(this.getLevel())) {

+				// Check whether last param is an exception

+				var exception;

+				var finalParamIndex = params.length - 1;

+				var lastParam = params[params.length - 1];

+				if (params.length > 1 && isError(lastParam)) {

+					exception = lastParam;

+					finalParamIndex--;

+				}

+

+				// Construct genuine array for the params

+				var messages = [];

+				for (var i = 0; i <= finalParamIndex; i++) {

+					messages[i] = params[i];

+				}

+

+				var loggingEvent = new LoggingEvent(

+					this, new Date(), level, messages, exception);

+

+				appender.append(loggingEvent);

+			}

+		};

+

+		this.setLevel = function(level) {

+			loggerLevel = level;

+		};

+

+		this.getLevel = function() {

+			return loggerLevel;

+		};

+	}

+

+	Logger.prototype = {

+		trace: function() {

+			this.log(Level.TRACE, arguments);

+		},

+

+		debug: function() {

+			this.log(Level.DEBUG, arguments);

+		},

+

+		info: function() {

+			this.log(Level.INFO, arguments);

+		},

+

+		warn: function() {

+			this.log(Level.WARN, arguments);

+		},

+

+		error: function() {

+			this.log(Level.ERROR, arguments);

+		},

+

+		fatal: function() {

+			this.log(Level.FATAL, arguments);

+		},

+

+		isEnabledFor: function(level) {

+			return level.isGreaterOrEqual(this.getLevel());

+		},

+

+		isTraceEnabled: function() {

+			return this.isEnabledFor(Level.TRACE);

+		},

+

+		isDebugEnabled: function() {

+			return this.isEnabledFor(Level.DEBUG);

+		},

+

+		isInfoEnabled: function() {

+			return this.isEnabledFor(Level.INFO);

+		},

+

+		isWarnEnabled: function() {

+			return this.isEnabledFor(Level.WARN);

+		},

+

+		isErrorEnabled: function() {

+			return this.isEnabledFor(Level.ERROR);

+		},

+

+		isFatalEnabled: function() {

+			return this.isEnabledFor(Level.FATAL);

+		}

+	};

+

+	/* ---------------------------------------------------------------------- */

+	// Logger access methods

+

+	var defaultLogger = null;

+	log4javascript.getDefaultLogger = function() {

+		if (!defaultLogger) {

+			defaultLogger = new Logger();

+		}

+		return defaultLogger;

+	};

+

+	log4javascript.getLogger = log4javascript.getDefaultLogger;

+

+	var nullLogger = null;

+	log4javascript.getNullLogger = function() {

+		if (!nullLogger) {

+			nullLogger = new Logger();

+			nullLogger.setLevel(Level.OFF);

+		}

+		return nullLogger;

+	};

+

+	/* ---------------------------------------------------------------------- */

+	// Logging events

+

+	var LoggingEvent = function(logger, timeStamp, level, messages,

+			exception) {

+		this.logger = logger;

+		this.timeStamp = timeStamp;

+		this.level = level;

+		this.messages = messages;

+		this.exception = exception;

+	};

+

+	LoggingEvent.prototype = {

+		getThrowableStrRep: function() {

+			return this.exception ?

+				getExceptionStringRep(this.exception) : "";

+		},

+

+		getCombinedMessages: function() {

+			return (this.messages.length === 1) ? this.messages[0] :

+				   this.messages.join(newLine);

+		}

+	};

+

+	log4javascript.LoggingEvent = LoggingEvent;

+

+	// Ensure that the log4javascript object is available in the window. This

+	// is necessary for log4javascript to be available in IE if loaded using

+	// Dojo's module system

+	window.log4javascript = log4javascript;

+})();
\ No newline at end of file
diff --git a/xos/core/static/log4javascript-1.4.6/js/log4javascript_production.js b/xos/core/static/log4javascript-1.4.6/js/log4javascript_production.js
new file mode 100644
index 0000000..1a31299
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/js/log4javascript_production.js
@@ -0,0 +1,188 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+

+if(!Array.prototype.push){Array.prototype.push=function(){for(var i=0,len=arguments.length;i<len;i++){this[this.length]=arguments[i];}

+return this.length;};}

+if(!Array.prototype.shift){Array.prototype.shift=function(){if(this.length>0){var firstItem=this[0];for(var i=0,len=this.length-1;i<len;i++){this[i]=this[i+1];}

+this.length=this.length-1;return firstItem;}};}

+if(!Array.prototype.splice){Array.prototype.splice=function(startIndex,deleteCount){var itemsAfterDeleted=this.slice(startIndex+deleteCount);var itemsDeleted=this.slice(startIndex,startIndex+deleteCount);this.length=startIndex;var argumentsArray=[];for(var i=0,len=arguments.length;i<len;i++){argumentsArray[i]=arguments[i];}

+var itemsToAppend=(argumentsArray.length>2)?itemsAfterDeleted=argumentsArray.slice(2).concat(itemsAfterDeleted):itemsAfterDeleted;for(i=0,len=itemsToAppend.length;i<len;i++){this.push(itemsToAppend[i]);}

+return itemsDeleted;};}

+var log4javascript=(function(){function isUndefined(obj){return typeof obj=="undefined";}

+function EventSupport(){}

+EventSupport.prototype={eventTypes:[],eventListeners:{},setEventTypes:function(eventTypesParam){if(eventTypesParam instanceof Array){this.eventTypes=eventTypesParam;this.eventListeners={};for(var i=0,len=this.eventTypes.length;i<len;i++){this.eventListeners[this.eventTypes[i]]=[];}}else{handleError("log4javascript.EventSupport ["+this+"]: setEventTypes: eventTypes parameter must be an Array");}},addEventListener:function(eventType,listener){if(typeof listener=="function"){if(!array_contains(this.eventTypes,eventType)){handleError("log4javascript.EventSupport ["+this+"]: addEventListener: no event called '"+eventType+"'");}

+this.eventListeners[eventType].push(listener);}else{handleError("log4javascript.EventSupport ["+this+"]: addEventListener: listener must be a function");}},removeEventListener:function(eventType,listener){if(typeof listener=="function"){if(!array_contains(this.eventTypes,eventType)){handleError("log4javascript.EventSupport ["+this+"]: removeEventListener: no event called '"+eventType+"'");}

+array_remove(this.eventListeners[eventType],listener);}else{handleError("log4javascript.EventSupport ["+this+"]: removeEventListener: listener must be a function");}},dispatchEvent:function(eventType,eventArgs){if(array_contains(this.eventTypes,eventType)){var listeners=this.eventListeners[eventType];for(var i=0,len=listeners.length;i<len;i++){listeners[i](this,eventType,eventArgs);}}else{handleError("log4javascript.EventSupport ["+this+"]: dispatchEvent: no event called '"+eventType+"'");}}};var applicationStartDate=new Date();var uniqueId="log4javascript_"+applicationStartDate.getTime()+"_"+

+Math.floor(Math.random()*100000000);var emptyFunction=function(){};var newLine="\r\n";var pageLoaded=false;function Log4JavaScript(){}

+Log4JavaScript.prototype=new EventSupport();log4javascript=new Log4JavaScript();log4javascript.version="1.4.6";log4javascript.edition="log4javascript_production";function toStr(obj){if(obj&&obj.toString){return obj.toString();}else{return String(obj);}}

+function getExceptionMessage(ex){if(ex.message){return ex.message;}else if(ex.description){return ex.description;}else{return toStr(ex);}}

+function getUrlFileName(url){var lastSlashIndex=Math.max(url.lastIndexOf("/"),url.lastIndexOf("\\"));return url.substr(lastSlashIndex+1);}

+function getExceptionStringRep(ex){if(ex){var exStr="Exception: "+getExceptionMessage(ex);try{if(ex.lineNumber){exStr+=" on line number "+ex.lineNumber;}

+if(ex.fileName){exStr+=" in file "+getUrlFileName(ex.fileName);}}catch(localEx){logLog.warn("Unable to obtain file and line information for error");}

+if(showStackTraces&&ex.stack){exStr+=newLine+"Stack trace:"+newLine+ex.stack;}

+return exStr;}

+return null;}

+function bool(obj){return Boolean(obj);}

+function trim(str){return str.replace(/^\s+/,"").replace(/\s+$/,"");}

+function splitIntoLines(text){var text2=text.replace(/\r\n/g,"\n").replace(/\r/g,"\n");return text2.split("\n");}

+var urlEncode=(typeof window.encodeURIComponent!="undefined")?function(str){return encodeURIComponent(str);}:function(str){return escape(str).replace(/\+/g,"%2B").replace(/"/g,"%22").replace(/'/g,"%27").replace(/\//g,"%2F").replace(/=/g,"%3D");};var urlDecode=(typeof window.decodeURIComponent!="undefined")?function(str){return decodeURIComponent(str);}:function(str){return unescape(str).replace(/%2B/g,"+").replace(/%22/g,"\"").replace(/%27/g,"'").replace(/%2F/g,"/").replace(/%3D/g,"=");};function array_remove(arr,val){var index=-1;for(var i=0,len=arr.length;i<len;i++){if(arr[i]===val){index=i;break;}}

+if(index>=0){arr.splice(index,1);return true;}else{return false;}}

+function array_contains(arr,val){for(var i=0,len=arr.length;i<len;i++){if(arr[i]==val){return true;}}

+return false;}

+function extractBooleanFromParam(param,defaultValue){if(isUndefined(param)){return defaultValue;}else{return bool(param);}}

+function extractStringFromParam(param,defaultValue){if(isUndefined(param)){return defaultValue;}else{return String(param);}}

+function extractIntFromParam(param,defaultValue){if(isUndefined(param)){return defaultValue;}else{try{var value=parseInt(param,10);return isNaN(value)?defaultValue:value;}catch(ex){logLog.warn("Invalid int param "+param,ex);return defaultValue;}}}

+function extractFunctionFromParam(param,defaultValue){if(typeof param=="function"){return param;}else{return defaultValue;}}

+function isError(err){return(err instanceof Error);}

+if(!Function.prototype.apply){Function.prototype.apply=function(obj,args){var methodName="__apply__";if(typeof obj[methodName]!="undefined"){methodName+=String(Math.random()).substr(2);}

+obj[methodName]=this;var argsStrings=[];for(var i=0,len=args.length;i<len;i++){argsStrings[i]="args["+i+"]";}

+var script="obj."+methodName+"("+argsStrings.join(",")+")";var returnValue=eval(script);delete obj[methodName];return returnValue;};}

+if(!Function.prototype.call){Function.prototype.call=function(obj){var args=[];for(var i=1,len=arguments.length;i<len;i++){args[i-1]=arguments[i];}

+return this.apply(obj,args);};}

+function getListenersPropertyName(eventName){return"__log4javascript_listeners__"+eventName;}

+function addEvent(node,eventName,listener,useCapture,win){win=win?win:window;if(node.addEventListener){node.addEventListener(eventName,listener,useCapture);}else if(node.attachEvent){node.attachEvent("on"+eventName,listener);}else{var propertyName=getListenersPropertyName(eventName);if(!node[propertyName]){node[propertyName]=[];node["on"+eventName]=function(evt){evt=getEvent(evt,win);var listenersPropertyName=getListenersPropertyName(eventName);var listeners=this[listenersPropertyName].concat([]);var currentListener;while((currentListener=listeners.shift())){currentListener.call(this,evt);}};}

+node[propertyName].push(listener);}}

+function removeEvent(node,eventName,listener,useCapture){if(node.removeEventListener){node.removeEventListener(eventName,listener,useCapture);}else if(node.detachEvent){node.detachEvent("on"+eventName,listener);}else{var propertyName=getListenersPropertyName(eventName);if(node[propertyName]){array_remove(node[propertyName],listener);}}}

+function getEvent(evt,win){win=win?win:window;return evt?evt:win.event;}

+function stopEventPropagation(evt){if(evt.stopPropagation){evt.stopPropagation();}else if(typeof evt.cancelBubble!="undefined"){evt.cancelBubble=true;}

+evt.returnValue=false;}

+var logLog={quietMode:false,debugMessages:[],setQuietMode:function(quietMode){this.quietMode=bool(quietMode);},numberOfErrors:0,alertAllErrors:false,setAlertAllErrors:function(alertAllErrors){this.alertAllErrors=alertAllErrors;},debug:function(message){this.debugMessages.push(message);},displayDebug:function(){alert(this.debugMessages.join(newLine));},warn:function(message,exception){},error:function(message,exception){if(++this.numberOfErrors==1||this.alertAllErrors){if(!this.quietMode){var alertMessage="log4javascript error: "+message;if(exception){alertMessage+=newLine+newLine+"Original error: "+getExceptionStringRep(exception);}

+alert(alertMessage);}}}};log4javascript.logLog=logLog;log4javascript.setEventTypes(["load","error"]);function handleError(message,exception){logLog.error(message,exception);log4javascript.dispatchEvent("error",{"message":message,"exception":exception});}

+log4javascript.handleError=handleError;var enabled=!((typeof log4javascript_disabled!="undefined")&&log4javascript_disabled);log4javascript.setEnabled=function(enable){enabled=bool(enable);};log4javascript.isEnabled=function(){return enabled;};var useTimeStampsInMilliseconds=true;log4javascript.setTimeStampsInMilliseconds=function(timeStampsInMilliseconds){useTimeStampsInMilliseconds=bool(timeStampsInMilliseconds);};log4javascript.isTimeStampsInMilliseconds=function(){return useTimeStampsInMilliseconds;};log4javascript.evalInScope=function(expr){return eval(expr);};var showStackTraces=false;log4javascript.setShowStackTraces=function(show){showStackTraces=bool(show);};var Level=function(level,name){this.level=level;this.name=name;};Level.prototype={toString:function(){return this.name;},equals:function(level){return this.level==level.level;},isGreaterOrEqual:function(level){return this.level>=level.level;}};Level.ALL=new Level(Number.MIN_VALUE,"ALL");Level.TRACE=new Level(10000,"TRACE");Level.DEBUG=new Level(20000,"DEBUG");Level.INFO=new Level(30000,"INFO");Level.WARN=new Level(40000,"WARN");Level.ERROR=new Level(50000,"ERROR");Level.FATAL=new Level(60000,"FATAL");Level.OFF=new Level(Number.MAX_VALUE,"OFF");log4javascript.Level=Level;function Timer(name,level){this.name=name;this.level=isUndefined(level)?Level.INFO:level;this.start=new Date();}

+Timer.prototype.getElapsedTime=function(){return new Date().getTime()-this.start.getTime();};var anonymousLoggerName="[anonymous]";var defaultLoggerName="[default]";var nullLoggerName="[null]";var rootLoggerName="root";function Logger(name){this.name=name;this.parent=null;this.children=[];var appenders=[];var loggerLevel=null;var isRoot=(this.name===rootLoggerName);var isNull=(this.name===nullLoggerName);var appenderCache=null;var appenderCacheInvalidated=false;this.addChild=function(childLogger){this.children.push(childLogger);childLogger.parent=this;childLogger.invalidateAppenderCache();};var additive=true;this.getAdditivity=function(){return additive;};this.setAdditivity=function(additivity){var valueChanged=(additive!=additivity);additive=additivity;if(valueChanged){this.invalidateAppenderCache();}};this.addAppender=function(appender){if(isNull){handleError("Logger.addAppender: you may not add an appender to the null logger");}else{if(appender instanceof log4javascript.Appender){if(!array_contains(appenders,appender)){appenders.push(appender);appender.setAddedToLogger(this);this.invalidateAppenderCache();}}else{handleError("Logger.addAppender: appender supplied ('"+

+toStr(appender)+"') is not a subclass of Appender");}}};this.removeAppender=function(appender){array_remove(appenders,appender);appender.setRemovedFromLogger(this);this.invalidateAppenderCache();};this.removeAllAppenders=function(){var appenderCount=appenders.length;if(appenderCount>0){for(var i=0;i<appenderCount;i++){appenders[i].setRemovedFromLogger(this);}

+appenders.length=0;this.invalidateAppenderCache();}};this.getEffectiveAppenders=function(){if(appenderCache===null||appenderCacheInvalidated){var parentEffectiveAppenders=(isRoot||!this.getAdditivity())?[]:this.parent.getEffectiveAppenders();appenderCache=parentEffectiveAppenders.concat(appenders);appenderCacheInvalidated=false;}

+return appenderCache;};this.invalidateAppenderCache=function(){appenderCacheInvalidated=true;for(var i=0,len=this.children.length;i<len;i++){this.children[i].invalidateAppenderCache();}};this.log=function(level,params){if(enabled&&level.isGreaterOrEqual(this.getEffectiveLevel())){var exception;var finalParamIndex=params.length-1;var lastParam=params[finalParamIndex];if(params.length>1&&isError(lastParam)){exception=lastParam;finalParamIndex--;}

+var messages=[];for(var i=0;i<=finalParamIndex;i++){messages[i]=params[i];}

+var loggingEvent=new LoggingEvent(this,new Date(),level,messages,exception);this.callAppenders(loggingEvent);}};this.callAppenders=function(loggingEvent){var effectiveAppenders=this.getEffectiveAppenders();for(var i=0,len=effectiveAppenders.length;i<len;i++){effectiveAppenders[i].doAppend(loggingEvent);}};this.setLevel=function(level){if(isRoot&&level===null){handleError("Logger.setLevel: you cannot set the level of the root logger to null");}else if(level instanceof Level){loggerLevel=level;}else{handleError("Logger.setLevel: level supplied to logger "+

+this.name+" is not an instance of log4javascript.Level");}};this.getLevel=function(){return loggerLevel;};this.getEffectiveLevel=function(){for(var logger=this;logger!==null;logger=logger.parent){var level=logger.getLevel();if(level!==null){return level;}}};this.group=function(name,initiallyExpanded){if(enabled){var effectiveAppenders=this.getEffectiveAppenders();for(var i=0,len=effectiveAppenders.length;i<len;i++){effectiveAppenders[i].group(name,initiallyExpanded);}}};this.groupEnd=function(){if(enabled){var effectiveAppenders=this.getEffectiveAppenders();for(var i=0,len=effectiveAppenders.length;i<len;i++){effectiveAppenders[i].groupEnd();}}};var timers={};this.time=function(name,level){if(enabled){if(isUndefined(name)){handleError("Logger.time: a name for the timer must be supplied");}else if(level&&!(level instanceof Level)){handleError("Logger.time: level supplied to timer "+

+name+" is not an instance of log4javascript.Level");}else{timers[name]=new Timer(name,level);}}};this.timeEnd=function(name){if(enabled){if(isUndefined(name)){handleError("Logger.timeEnd: a name for the timer must be supplied");}else if(timers[name]){var timer=timers[name];var milliseconds=timer.getElapsedTime();this.log(timer.level,["Timer "+toStr(name)+" completed in "+milliseconds+"ms"]);delete timers[name];}else{logLog.warn("Logger.timeEnd: no timer found with name "+name);}}};this.assert=function(expr){if(enabled&&!expr){var args=[];for(var i=1,len=arguments.length;i<len;i++){args.push(arguments[i]);}

+args=(args.length>0)?args:["Assertion Failure"];args.push(newLine);args.push(expr);this.log(Level.ERROR,args);}};this.toString=function(){return"Logger["+this.name+"]";};}

+Logger.prototype={trace:function(){this.log(Level.TRACE,arguments);},debug:function(){this.log(Level.DEBUG,arguments);},info:function(){this.log(Level.INFO,arguments);},warn:function(){this.log(Level.WARN,arguments);},error:function(){this.log(Level.ERROR,arguments);},fatal:function(){this.log(Level.FATAL,arguments);},isEnabledFor:function(level){return level.isGreaterOrEqual(this.getEffectiveLevel());},isTraceEnabled:function(){return this.isEnabledFor(Level.TRACE);},isDebugEnabled:function(){return this.isEnabledFor(Level.DEBUG);},isInfoEnabled:function(){return this.isEnabledFor(Level.INFO);},isWarnEnabled:function(){return this.isEnabledFor(Level.WARN);},isErrorEnabled:function(){return this.isEnabledFor(Level.ERROR);},isFatalEnabled:function(){return this.isEnabledFor(Level.FATAL);}};Logger.prototype.trace.isEntryPoint=true;Logger.prototype.debug.isEntryPoint=true;Logger.prototype.info.isEntryPoint=true;Logger.prototype.warn.isEntryPoint=true;Logger.prototype.error.isEntryPoint=true;Logger.prototype.fatal.isEntryPoint=true;var loggers={};var loggerNames=[];var ROOT_LOGGER_DEFAULT_LEVEL=Level.DEBUG;var rootLogger=new Logger(rootLoggerName);rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);log4javascript.getRootLogger=function(){return rootLogger;};log4javascript.getLogger=function(loggerName){if(!(typeof loggerName=="string")){loggerName=anonymousLoggerName;logLog.warn("log4javascript.getLogger: non-string logger name "+

+toStr(loggerName)+" supplied, returning anonymous logger");}

+if(loggerName==rootLoggerName){handleError("log4javascript.getLogger: root logger may not be obtained by name");}

+if(!loggers[loggerName]){var logger=new Logger(loggerName);loggers[loggerName]=logger;loggerNames.push(loggerName);var lastDotIndex=loggerName.lastIndexOf(".");var parentLogger;if(lastDotIndex>-1){var parentLoggerName=loggerName.substring(0,lastDotIndex);parentLogger=log4javascript.getLogger(parentLoggerName);}else{parentLogger=rootLogger;}

+parentLogger.addChild(logger);}

+return loggers[loggerName];};var defaultLogger=null;log4javascript.getDefaultLogger=function(){if(!defaultLogger){defaultLogger=log4javascript.getLogger(defaultLoggerName);var a=new log4javascript.PopUpAppender();defaultLogger.addAppender(a);}

+return defaultLogger;};var nullLogger=null;log4javascript.getNullLogger=function(){if(!nullLogger){nullLogger=new Logger(nullLoggerName);nullLogger.setLevel(Level.OFF);}

+return nullLogger;};log4javascript.resetConfiguration=function(){rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);loggers={};};var LoggingEvent=function(logger,timeStamp,level,messages,exception){this.logger=logger;this.timeStamp=timeStamp;this.timeStampInMilliseconds=timeStamp.getTime();this.timeStampInSeconds=Math.floor(this.timeStampInMilliseconds/1000);this.milliseconds=this.timeStamp.getMilliseconds();this.level=level;this.messages=messages;this.exception=exception;};LoggingEvent.prototype={getThrowableStrRep:function(){return this.exception?getExceptionStringRep(this.exception):"";},getCombinedMessages:function(){return(this.messages.length==1)?this.messages[0]:this.messages.join(newLine);},toString:function(){return"LoggingEvent["+this.level+"]";}};log4javascript.LoggingEvent=LoggingEvent;var Layout=function(){};Layout.prototype={defaults:{loggerKey:"logger",timeStampKey:"timestamp",millisecondsKey:"milliseconds",levelKey:"level",messageKey:"message",exceptionKey:"exception",urlKey:"url"},loggerKey:"logger",timeStampKey:"timestamp",millisecondsKey:"milliseconds",levelKey:"level",messageKey:"message",exceptionKey:"exception",urlKey:"url",batchHeader:"",batchFooter:"",batchSeparator:"",returnsPostData:false,overrideTimeStampsSetting:false,useTimeStampsInMilliseconds:null,format:function(){handleError("Layout.format: layout supplied has no format() method");},ignoresThrowable:function(){handleError("Layout.ignoresThrowable: layout supplied has no ignoresThrowable() method");},getContentType:function(){return"text/plain";},allowBatching:function(){return true;},setTimeStampsInMilliseconds:function(timeStampsInMilliseconds){this.overrideTimeStampsSetting=true;this.useTimeStampsInMilliseconds=bool(timeStampsInMilliseconds);},isTimeStampsInMilliseconds:function(){return this.overrideTimeStampsSetting?this.useTimeStampsInMilliseconds:useTimeStampsInMilliseconds;},getTimeStampValue:function(loggingEvent){return this.isTimeStampsInMilliseconds()?loggingEvent.timeStampInMilliseconds:loggingEvent.timeStampInSeconds;},getDataValues:function(loggingEvent,combineMessages){var dataValues=[[this.loggerKey,loggingEvent.logger.name],[this.timeStampKey,this.getTimeStampValue(loggingEvent)],[this.levelKey,loggingEvent.level.name],[this.urlKey,window.location.href],[this.messageKey,combineMessages?loggingEvent.getCombinedMessages():loggingEvent.messages]];if(!this.isTimeStampsInMilliseconds()){dataValues.push([this.millisecondsKey,loggingEvent.milliseconds]);}

+if(loggingEvent.exception){dataValues.push([this.exceptionKey,getExceptionStringRep(loggingEvent.exception)]);}

+if(this.hasCustomFields()){for(var i=0,len=this.customFields.length;i<len;i++){var val=this.customFields[i].value;if(typeof val==="function"){val=val(this,loggingEvent);}

+dataValues.push([this.customFields[i].name,val]);}}

+return dataValues;},setKeys:function(loggerKey,timeStampKey,levelKey,messageKey,exceptionKey,urlKey,millisecondsKey){this.loggerKey=extractStringFromParam(loggerKey,this.defaults.loggerKey);this.timeStampKey=extractStringFromParam(timeStampKey,this.defaults.timeStampKey);this.levelKey=extractStringFromParam(levelKey,this.defaults.levelKey);this.messageKey=extractStringFromParam(messageKey,this.defaults.messageKey);this.exceptionKey=extractStringFromParam(exceptionKey,this.defaults.exceptionKey);this.urlKey=extractStringFromParam(urlKey,this.defaults.urlKey);this.millisecondsKey=extractStringFromParam(millisecondsKey,this.defaults.millisecondsKey);},setCustomField:function(name,value){var fieldUpdated=false;for(var i=0,len=this.customFields.length;i<len;i++){if(this.customFields[i].name===name){this.customFields[i].value=value;fieldUpdated=true;}}

+if(!fieldUpdated){this.customFields.push({"name":name,"value":value});}},hasCustomFields:function(){return(this.customFields.length>0);},toString:function(){handleError("Layout.toString: all layouts must override this method");}};log4javascript.Layout=Layout;var Appender=function(){};Appender.prototype=new EventSupport();Appender.prototype.layout=new PatternLayout();Appender.prototype.threshold=Level.ALL;Appender.prototype.loggers=[];Appender.prototype.doAppend=function(loggingEvent){if(enabled&&loggingEvent.level.level>=this.threshold.level){this.append(loggingEvent);}};Appender.prototype.append=function(loggingEvent){};Appender.prototype.setLayout=function(layout){if(layout instanceof Layout){this.layout=layout;}else{handleError("Appender.setLayout: layout supplied to "+

+this.toString()+" is not a subclass of Layout");}};Appender.prototype.getLayout=function(){return this.layout;};Appender.prototype.setThreshold=function(threshold){if(threshold instanceof Level){this.threshold=threshold;}else{handleError("Appender.setThreshold: threshold supplied to "+

+this.toString()+" is not a subclass of Level");}};Appender.prototype.getThreshold=function(){return this.threshold;};Appender.prototype.setAddedToLogger=function(logger){this.loggers.push(logger);};Appender.prototype.setRemovedFromLogger=function(logger){array_remove(this.loggers,logger);};Appender.prototype.group=emptyFunction;Appender.prototype.groupEnd=emptyFunction;Appender.prototype.toString=function(){handleError("Appender.toString: all appenders must override this method");};log4javascript.Appender=Appender;function SimpleLayout(){this.customFields=[];}

+SimpleLayout.prototype=new Layout();SimpleLayout.prototype.format=function(loggingEvent){return loggingEvent.level.name+" - "+loggingEvent.getCombinedMessages();};SimpleLayout.prototype.ignoresThrowable=function(){return true;};SimpleLayout.prototype.toString=function(){return"SimpleLayout";};log4javascript.SimpleLayout=SimpleLayout;function NullLayout(){this.customFields=[];}

+NullLayout.prototype=new Layout();NullLayout.prototype.format=function(loggingEvent){return loggingEvent.messages;};NullLayout.prototype.ignoresThrowable=function(){return true;};NullLayout.prototype.toString=function(){return"NullLayout";};log4javascript.NullLayout=NullLayout;function XmlLayout(combineMessages){this.combineMessages=extractBooleanFromParam(combineMessages,true);this.customFields=[];}

+XmlLayout.prototype=new Layout();XmlLayout.prototype.isCombinedMessages=function(){return this.combineMessages;};XmlLayout.prototype.getContentType=function(){return"text/xml";};XmlLayout.prototype.escapeCdata=function(str){return str.replace(/\]\]>/,"]]>]]&gt;<![CDATA[");};XmlLayout.prototype.format=function(loggingEvent){var layout=this;var i,len;function formatMessage(message){message=(typeof message==="string")?message:toStr(message);return"<log4javascript:message><![CDATA["+

+layout.escapeCdata(message)+"]]></log4javascript:message>";}

+var str="<log4javascript:event logger=\""+loggingEvent.logger.name+"\" timestamp=\""+this.getTimeStampValue(loggingEvent)+"\"";if(!this.isTimeStampsInMilliseconds()){str+=" milliseconds=\""+loggingEvent.milliseconds+"\"";}

+str+=" level=\""+loggingEvent.level.name+"\">"+newLine;if(this.combineMessages){str+=formatMessage(loggingEvent.getCombinedMessages());}else{str+="<log4javascript:messages>"+newLine;for(i=0,len=loggingEvent.messages.length;i<len;i++){str+=formatMessage(loggingEvent.messages[i])+newLine;}

+str+="</log4javascript:messages>"+newLine;}

+if(this.hasCustomFields()){for(i=0,len=this.customFields.length;i<len;i++){str+="<log4javascript:customfield name=\""+

+this.customFields[i].name+"\"><![CDATA["+

+this.customFields[i].value.toString()+"]]></log4javascript:customfield>"+newLine;}}

+if(loggingEvent.exception){str+="<log4javascript:exception><![CDATA["+

+getExceptionStringRep(loggingEvent.exception)+"]]></log4javascript:exception>"+newLine;}

+str+="</log4javascript:event>"+newLine+newLine;return str;};XmlLayout.prototype.ignoresThrowable=function(){return false;};XmlLayout.prototype.toString=function(){return"XmlLayout";};log4javascript.XmlLayout=XmlLayout;function escapeNewLines(str){return str.replace(/\r\n|\r|\n/g,"\\r\\n");}

+function JsonLayout(readable,combineMessages){this.readable=extractBooleanFromParam(readable,false);this.combineMessages=extractBooleanFromParam(combineMessages,true);this.batchHeader=this.readable?"["+newLine:"[";this.batchFooter=this.readable?"]"+newLine:"]";this.batchSeparator=this.readable?","+newLine:",";this.setKeys();this.colon=this.readable?": ":":";this.tab=this.readable?"\t":"";this.lineBreak=this.readable?newLine:"";this.customFields=[];}

+JsonLayout.prototype=new Layout();JsonLayout.prototype.isReadable=function(){return this.readable;};JsonLayout.prototype.isCombinedMessages=function(){return this.combineMessages;};JsonLayout.prototype.format=function(loggingEvent){var layout=this;var dataValues=this.getDataValues(loggingEvent,this.combineMessages);var str="{"+this.lineBreak;var i,len;function formatValue(val,prefix,expand){var formattedValue;var valType=typeof val;if(val instanceof Date){formattedValue=String(val.getTime());}else if(expand&&(val instanceof Array)){formattedValue="["+layout.lineBreak;for(var i=0,len=val.length;i<len;i++){var childPrefix=prefix+layout.tab;formattedValue+=childPrefix+formatValue(val[i],childPrefix,false);if(i<val.length-1){formattedValue+=",";}

+formattedValue+=layout.lineBreak;}

+formattedValue+=prefix+"]";}else if(valType!=="number"&&valType!=="boolean"){formattedValue="\""+escapeNewLines(toStr(val).replace(/\"/g,"\\\""))+"\"";}else{formattedValue=val;}

+return formattedValue;}

+for(i=0,len=dataValues.length-1;i<=len;i++){str+=this.tab+"\""+dataValues[i][0]+"\""+this.colon+formatValue(dataValues[i][1],this.tab,true);if(i<len){str+=",";}

+str+=this.lineBreak;}

+str+="}"+this.lineBreak;return str;};JsonLayout.prototype.ignoresThrowable=function(){return false;};JsonLayout.prototype.toString=function(){return"JsonLayout";};JsonLayout.prototype.getContentType=function(){return"application/json";};log4javascript.JsonLayout=JsonLayout;function HttpPostDataLayout(){this.setKeys();this.customFields=[];this.returnsPostData=true;}

+HttpPostDataLayout.prototype=new Layout();HttpPostDataLayout.prototype.allowBatching=function(){return false;};HttpPostDataLayout.prototype.format=function(loggingEvent){var dataValues=this.getDataValues(loggingEvent);var queryBits=[];for(var i=0,len=dataValues.length;i<len;i++){var val=(dataValues[i][1]instanceof Date)?String(dataValues[i][1].getTime()):dataValues[i][1];queryBits.push(urlEncode(dataValues[i][0])+"="+urlEncode(val));}

+return queryBits.join("&");};HttpPostDataLayout.prototype.ignoresThrowable=function(loggingEvent){return false;};HttpPostDataLayout.prototype.toString=function(){return"HttpPostDataLayout";};log4javascript.HttpPostDataLayout=HttpPostDataLayout;function formatObjectExpansion(obj,depth,indentation){var objectsExpanded=[];function doFormat(obj,depth,indentation){var i,j,len,childDepth,childIndentation,childLines,expansion,childExpansion;if(!indentation){indentation="";}

+function formatString(text){var lines=splitIntoLines(text);for(var j=1,jLen=lines.length;j<jLen;j++){lines[j]=indentation+lines[j];}

+return lines.join(newLine);}

+if(obj===null){return"null";}else if(typeof obj=="undefined"){return"undefined";}else if(typeof obj=="string"){return formatString(obj);}else if(typeof obj=="object"&&array_contains(objectsExpanded,obj)){try{expansion=toStr(obj);}catch(ex){expansion="Error formatting property. Details: "+getExceptionStringRep(ex);}

+return expansion+" [already expanded]";}else if((obj instanceof Array)&&depth>0){objectsExpanded.push(obj);expansion="["+newLine;childDepth=depth-1;childIndentation=indentation+"  ";childLines=[];for(i=0,len=obj.length;i<len;i++){try{childExpansion=doFormat(obj[i],childDepth,childIndentation);childLines.push(childIndentation+childExpansion);}catch(ex){childLines.push(childIndentation+"Error formatting array member. Details: "+

+getExceptionStringRep(ex)+"");}}

+expansion+=childLines.join(","+newLine)+newLine+indentation+"]";return expansion;}else if(Object.prototype.toString.call(obj)=="[object Date]"){return obj.toString();}else if(typeof obj=="object"&&depth>0){objectsExpanded.push(obj);expansion="{"+newLine;childDepth=depth-1;childIndentation=indentation+"  ";childLines=[];for(i in obj){try{childExpansion=doFormat(obj[i],childDepth,childIndentation);childLines.push(childIndentation+i+": "+childExpansion);}catch(ex){childLines.push(childIndentation+i+": Error formatting property. Details: "+

+getExceptionStringRep(ex));}}

+expansion+=childLines.join(","+newLine)+newLine+indentation+"}";return expansion;}else{return formatString(toStr(obj));}}

+return doFormat(obj,depth,indentation);}

+var SimpleDateFormat;(function(){var regex=/('[^']*')|(G+|y+|M+|w+|W+|D+|d+|F+|E+|a+|H+|k+|K+|h+|m+|s+|S+|Z+)|([a-zA-Z]+)|([^a-zA-Z']+)/;var monthNames=["January","February","March","April","May","June","July","August","September","October","November","December"];var dayNames=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];var TEXT2=0,TEXT3=1,NUMBER=2,YEAR=3,MONTH=4,TIMEZONE=5;var types={G:TEXT2,y:YEAR,M:MONTH,w:NUMBER,W:NUMBER,D:NUMBER,d:NUMBER,F:NUMBER,E:TEXT3,a:TEXT2,H:NUMBER,k:NUMBER,K:NUMBER,h:NUMBER,m:NUMBER,s:NUMBER,S:NUMBER,Z:TIMEZONE};var ONE_DAY=24*60*60*1000;var ONE_WEEK=7*ONE_DAY;var DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK=1;var newDateAtMidnight=function(year,month,day){var d=new Date(year,month,day,0,0,0);d.setMilliseconds(0);return d;};Date.prototype.getDifference=function(date){return this.getTime()-date.getTime();};Date.prototype.isBefore=function(d){return this.getTime()<d.getTime();};Date.prototype.getUTCTime=function(){return Date.UTC(this.getFullYear(),this.getMonth(),this.getDate(),this.getHours(),this.getMinutes(),this.getSeconds(),this.getMilliseconds());};Date.prototype.getTimeSince=function(d){return this.getUTCTime()-d.getUTCTime();};Date.prototype.getPreviousSunday=function(){var midday=new Date(this.getFullYear(),this.getMonth(),this.getDate(),12,0,0);var previousSunday=new Date(midday.getTime()-this.getDay()*ONE_DAY);return newDateAtMidnight(previousSunday.getFullYear(),previousSunday.getMonth(),previousSunday.getDate());};Date.prototype.getWeekInYear=function(minimalDaysInFirstWeek){if(isUndefined(this.minimalDaysInFirstWeek)){minimalDaysInFirstWeek=DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;}

+var previousSunday=this.getPreviousSunday();var startOfYear=newDateAtMidnight(this.getFullYear(),0,1);var numberOfSundays=previousSunday.isBefore(startOfYear)?0:1+Math.floor(previousSunday.getTimeSince(startOfYear)/ONE_WEEK);var numberOfDaysInFirstWeek=7-startOfYear.getDay();var weekInYear=numberOfSundays;if(numberOfDaysInFirstWeek<minimalDaysInFirstWeek){weekInYear--;}

+return weekInYear;};Date.prototype.getWeekInMonth=function(minimalDaysInFirstWeek){if(isUndefined(this.minimalDaysInFirstWeek)){minimalDaysInFirstWeek=DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;}

+var previousSunday=this.getPreviousSunday();var startOfMonth=newDateAtMidnight(this.getFullYear(),this.getMonth(),1);var numberOfSundays=previousSunday.isBefore(startOfMonth)?0:1+Math.floor(previousSunday.getTimeSince(startOfMonth)/ONE_WEEK);var numberOfDaysInFirstWeek=7-startOfMonth.getDay();var weekInMonth=numberOfSundays;if(numberOfDaysInFirstWeek>=minimalDaysInFirstWeek){weekInMonth++;}

+return weekInMonth;};Date.prototype.getDayInYear=function(){var startOfYear=newDateAtMidnight(this.getFullYear(),0,1);return 1+Math.floor(this.getTimeSince(startOfYear)/ONE_DAY);};SimpleDateFormat=function(formatString){this.formatString=formatString;};SimpleDateFormat.prototype.setMinimalDaysInFirstWeek=function(days){this.minimalDaysInFirstWeek=days;};SimpleDateFormat.prototype.getMinimalDaysInFirstWeek=function(){return isUndefined(this.minimalDaysInFirstWeek)?DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK:this.minimalDaysInFirstWeek;};var padWithZeroes=function(str,len){while(str.length<len){str="0"+str;}

+return str;};var formatText=function(data,numberOfLetters,minLength){return(numberOfLetters>=4)?data:data.substr(0,Math.max(minLength,numberOfLetters));};var formatNumber=function(data,numberOfLetters){var dataString=""+data;return padWithZeroes(dataString,numberOfLetters);};SimpleDateFormat.prototype.format=function(date){var formattedString="";var result;var searchString=this.formatString;while((result=regex.exec(searchString))){var quotedString=result[1];var patternLetters=result[2];var otherLetters=result[3];var otherCharacters=result[4];if(quotedString){if(quotedString=="''"){formattedString+="'";}else{formattedString+=quotedString.substring(1,quotedString.length-1);}}else if(otherLetters){}else if(otherCharacters){formattedString+=otherCharacters;}else if(patternLetters){var patternLetter=patternLetters.charAt(0);var numberOfLetters=patternLetters.length;var rawData="";switch(patternLetter){case"G":rawData="AD";break;case"y":rawData=date.getFullYear();break;case"M":rawData=date.getMonth();break;case"w":rawData=date.getWeekInYear(this.getMinimalDaysInFirstWeek());break;case"W":rawData=date.getWeekInMonth(this.getMinimalDaysInFirstWeek());break;case"D":rawData=date.getDayInYear();break;case"d":rawData=date.getDate();break;case"F":rawData=1+Math.floor((date.getDate()-1)/7);break;case"E":rawData=dayNames[date.getDay()];break;case"a":rawData=(date.getHours()>=12)?"PM":"AM";break;case"H":rawData=date.getHours();break;case"k":rawData=date.getHours()||24;break;case"K":rawData=date.getHours()%12;break;case"h":rawData=(date.getHours()%12)||12;break;case"m":rawData=date.getMinutes();break;case"s":rawData=date.getSeconds();break;case"S":rawData=date.getMilliseconds();break;case"Z":rawData=date.getTimezoneOffset();break;}

+switch(types[patternLetter]){case TEXT2:formattedString+=formatText(rawData,numberOfLetters,2);break;case TEXT3:formattedString+=formatText(rawData,numberOfLetters,3);break;case NUMBER:formattedString+=formatNumber(rawData,numberOfLetters);break;case YEAR:if(numberOfLetters<=3){var dataString=""+rawData;formattedString+=dataString.substr(2,2);}else{formattedString+=formatNumber(rawData,numberOfLetters);}

+break;case MONTH:if(numberOfLetters>=3){formattedString+=formatText(monthNames[rawData],numberOfLetters,numberOfLetters);}else{formattedString+=formatNumber(rawData+1,numberOfLetters);}

+break;case TIMEZONE:var isPositive=(rawData>0);var prefix=isPositive?"-":"+";var absData=Math.abs(rawData);var hours=""+Math.floor(absData/60);hours=padWithZeroes(hours,2);var minutes=""+(absData%60);minutes=padWithZeroes(minutes,2);formattedString+=prefix+hours+minutes;break;}}

+searchString=searchString.substr(result.index+result[0].length);}

+return formattedString;};})();log4javascript.SimpleDateFormat=SimpleDateFormat;function PatternLayout(pattern){if(pattern){this.pattern=pattern;}else{this.pattern=PatternLayout.DEFAULT_CONVERSION_PATTERN;}

+this.customFields=[];}

+PatternLayout.TTCC_CONVERSION_PATTERN="%r %p %c - %m%n";PatternLayout.DEFAULT_CONVERSION_PATTERN="%m%n";PatternLayout.ISO8601_DATEFORMAT="yyyy-MM-dd HH:mm:ss,SSS";PatternLayout.DATETIME_DATEFORMAT="dd MMM yyyy HH:mm:ss,SSS";PatternLayout.ABSOLUTETIME_DATEFORMAT="HH:mm:ss,SSS";PatternLayout.prototype=new Layout();PatternLayout.prototype.format=function(loggingEvent){var regex=/%(-?[0-9]+)?(\.?[0-9]+)?([acdfmMnpr%])(\{([^\}]+)\})?|([^%]+)/;var formattedString="";var result;var searchString=this.pattern;while((result=regex.exec(searchString))){var matchedString=result[0];var padding=result[1];var truncation=result[2];var conversionCharacter=result[3];var specifier=result[5];var text=result[6];if(text){formattedString+=""+text;}else{var replacement="";switch(conversionCharacter){case"a":case"m":var depth=0;if(specifier){depth=parseInt(specifier,10);if(isNaN(depth)){handleError("PatternLayout.format: invalid specifier '"+

+specifier+"' for conversion character '"+conversionCharacter+"' - should be a number");depth=0;}}

+var messages=(conversionCharacter==="a")?loggingEvent.messages[0]:loggingEvent.messages;for(var i=0,len=messages.length;i<len;i++){if(i>0&&(replacement.charAt(replacement.length-1)!==" ")){replacement+=" ";}

+if(depth===0){replacement+=messages[i];}else{replacement+=formatObjectExpansion(messages[i],depth);}}

+break;case"c":var loggerName=loggingEvent.logger.name;if(specifier){var precision=parseInt(specifier,10);var loggerNameBits=loggingEvent.logger.name.split(".");if(precision>=loggerNameBits.length){replacement=loggerName;}else{replacement=loggerNameBits.slice(loggerNameBits.length-precision).join(".");}}else{replacement=loggerName;}

+break;case"d":var dateFormat=PatternLayout.ISO8601_DATEFORMAT;if(specifier){dateFormat=specifier;if(dateFormat=="ISO8601"){dateFormat=PatternLayout.ISO8601_DATEFORMAT;}else if(dateFormat=="ABSOLUTE"){dateFormat=PatternLayout.ABSOLUTETIME_DATEFORMAT;}else if(dateFormat=="DATE"){dateFormat=PatternLayout.DATETIME_DATEFORMAT;}}

+replacement=(new SimpleDateFormat(dateFormat)).format(loggingEvent.timeStamp);break;case"f":if(this.hasCustomFields()){var fieldIndex=0;if(specifier){fieldIndex=parseInt(specifier,10);if(isNaN(fieldIndex)){handleError("PatternLayout.format: invalid specifier '"+

+specifier+"' for conversion character 'f' - should be a number");}else if(fieldIndex===0){handleError("PatternLayout.format: invalid specifier '"+

+specifier+"' for conversion character 'f' - must be greater than zero");}else if(fieldIndex>this.customFields.length){handleError("PatternLayout.format: invalid specifier '"+

+specifier+"' for conversion character 'f' - there aren't that many custom fields");}else{fieldIndex=fieldIndex-1;}}

+var val=this.customFields[fieldIndex].value;if(typeof val=="function"){val=val(this,loggingEvent);}

+replacement=val;}

+break;case"n":replacement=newLine;break;case"p":replacement=loggingEvent.level.name;break;case"r":replacement=""+loggingEvent.timeStamp.getDifference(applicationStartDate);break;case"%":replacement="%";break;default:replacement=matchedString;break;}

+var l;if(truncation){l=parseInt(truncation.substr(1),10);var strLen=replacement.length;if(l<strLen){replacement=replacement.substring(strLen-l,strLen);}}

+if(padding){if(padding.charAt(0)=="-"){l=parseInt(padding.substr(1),10);while(replacement.length<l){replacement+=" ";}}else{l=parseInt(padding,10);while(replacement.length<l){replacement=" "+replacement;}}}

+formattedString+=replacement;}

+searchString=searchString.substr(result.index+result[0].length);}

+return formattedString;};PatternLayout.prototype.ignoresThrowable=function(){return true;};PatternLayout.prototype.toString=function(){return"PatternLayout";};log4javascript.PatternLayout=PatternLayout;var xmlHttpFactories=[function(){return new XMLHttpRequest();},function(){return new ActiveXObject("Msxml2.XMLHTTP");},function(){return new ActiveXObject("Microsoft.XMLHTTP");}];var getXmlHttp=function(errorHandler){var xmlHttp=null,factory;for(var i=0,len=xmlHttpFactories.length;i<len;i++){factory=xmlHttpFactories[i];try{xmlHttp=factory();getXmlHttp=factory;return xmlHttp;}catch(e){}}

+if(errorHandler){errorHandler();}else{handleError("getXmlHttp: unable to obtain XMLHttpRequest object");}};function isHttpRequestSuccessful(xmlHttp){return isUndefined(xmlHttp.status)||xmlHttp.status===0||(xmlHttp.status>=200&&xmlHttp.status<300)||xmlHttp.status==1223;}

+function AjaxAppender(url){var appender=this;var isSupported=true;if(!url){handleError("AjaxAppender: URL must be specified in constructor");isSupported=false;}

+var timed=this.defaults.timed;var waitForResponse=this.defaults.waitForResponse;var batchSize=this.defaults.batchSize;var timerInterval=this.defaults.timerInterval;var requestSuccessCallback=this.defaults.requestSuccessCallback;var failCallback=this.defaults.failCallback;var postVarName=this.defaults.postVarName;var sendAllOnUnload=this.defaults.sendAllOnUnload;var contentType=this.defaults.contentType;var sessionId=null;var queuedLoggingEvents=[];var queuedRequests=[];var headers=[];var sending=false;var initialized=false;function checkCanConfigure(configOptionName){if(initialized){handleError("AjaxAppender: configuration option '"+

+configOptionName+"' may not be set after the appender has been initialized");return false;}

+return true;}

+this.getSessionId=function(){return sessionId;};this.setSessionId=function(sessionIdParam){sessionId=extractStringFromParam(sessionIdParam,null);this.layout.setCustomField("sessionid",sessionId);};this.setLayout=function(layoutParam){if(checkCanConfigure("layout")){this.layout=layoutParam;if(sessionId!==null){this.setSessionId(sessionId);}}};this.isTimed=function(){return timed;};this.setTimed=function(timedParam){if(checkCanConfigure("timed")){timed=bool(timedParam);}};this.getTimerInterval=function(){return timerInterval;};this.setTimerInterval=function(timerIntervalParam){if(checkCanConfigure("timerInterval")){timerInterval=extractIntFromParam(timerIntervalParam,timerInterval);}};this.isWaitForResponse=function(){return waitForResponse;};this.setWaitForResponse=function(waitForResponseParam){if(checkCanConfigure("waitForResponse")){waitForResponse=bool(waitForResponseParam);}};this.getBatchSize=function(){return batchSize;};this.setBatchSize=function(batchSizeParam){if(checkCanConfigure("batchSize")){batchSize=extractIntFromParam(batchSizeParam,batchSize);}};this.isSendAllOnUnload=function(){return sendAllOnUnload;};this.setSendAllOnUnload=function(sendAllOnUnloadParam){if(checkCanConfigure("sendAllOnUnload")){sendAllOnUnload=extractBooleanFromParam(sendAllOnUnloadParam,sendAllOnUnload);}};this.setRequestSuccessCallback=function(requestSuccessCallbackParam){requestSuccessCallback=extractFunctionFromParam(requestSuccessCallbackParam,requestSuccessCallback);};this.setFailCallback=function(failCallbackParam){failCallback=extractFunctionFromParam(failCallbackParam,failCallback);};this.getPostVarName=function(){return postVarName;};this.setPostVarName=function(postVarNameParam){if(checkCanConfigure("postVarName")){postVarName=extractStringFromParam(postVarNameParam,postVarName);}};this.getHeaders=function(){return headers;};this.addHeader=function(name,value){if(name.toLowerCase()=="content-type"){contentType=value;}else{headers.push({name:name,value:value});}};function sendAll(){if(isSupported&&enabled){sending=true;var currentRequestBatch;if(waitForResponse){if(queuedRequests.length>0){currentRequestBatch=queuedRequests.shift();sendRequest(preparePostData(currentRequestBatch),sendAll);}else{sending=false;if(timed){scheduleSending();}}}else{while((currentRequestBatch=queuedRequests.shift())){sendRequest(preparePostData(currentRequestBatch));}

+sending=false;if(timed){scheduleSending();}}}}

+this.sendAll=sendAll;function sendAllRemaining(){var sendingAnything=false;if(isSupported&&enabled){var actualBatchSize=appender.getLayout().allowBatching()?batchSize:1;var currentLoggingEvent;var batchedLoggingEvents=[];while((currentLoggingEvent=queuedLoggingEvents.shift())){batchedLoggingEvents.push(currentLoggingEvent);if(queuedLoggingEvents.length>=actualBatchSize){queuedRequests.push(batchedLoggingEvents);batchedLoggingEvents=[];}}

+if(batchedLoggingEvents.length>0){queuedRequests.push(batchedLoggingEvents);}

+sendingAnything=(queuedRequests.length>0);waitForResponse=false;timed=false;sendAll();}

+return sendingAnything;}

+this.sendAllRemaining=sendAllRemaining;function preparePostData(batchedLoggingEvents){var formattedMessages=[];var currentLoggingEvent;var postData="";while((currentLoggingEvent=batchedLoggingEvents.shift())){var currentFormattedMessage=appender.getLayout().format(currentLoggingEvent);if(appender.getLayout().ignoresThrowable()){currentFormattedMessage+=currentLoggingEvent.getThrowableStrRep();}

+formattedMessages.push(currentFormattedMessage);}

+if(batchedLoggingEvents.length==1){postData=formattedMessages.join("");}else{postData=appender.getLayout().batchHeader+

+formattedMessages.join(appender.getLayout().batchSeparator)+

+appender.getLayout().batchFooter;}

+if(contentType==appender.defaults.contentType){postData=appender.getLayout().returnsPostData?postData:urlEncode(postVarName)+"="+urlEncode(postData);if(postData.length>0){postData+="&";}

+postData+="layout="+urlEncode(appender.getLayout().toString());}

+return postData;}

+function scheduleSending(){window.setTimeout(sendAll,timerInterval);}

+function xmlHttpErrorHandler(){var msg="AjaxAppender: could not create XMLHttpRequest object. AjaxAppender disabled";handleError(msg);isSupported=false;if(failCallback){failCallback(msg);}}

+function sendRequest(postData,successCallback){try{var xmlHttp=getXmlHttp(xmlHttpErrorHandler);if(isSupported){if(xmlHttp.overrideMimeType){xmlHttp.overrideMimeType(appender.getLayout().getContentType());}

+xmlHttp.onreadystatechange=function(){if(xmlHttp.readyState==4){if(isHttpRequestSuccessful(xmlHttp)){if(requestSuccessCallback){requestSuccessCallback(xmlHttp);}

+if(successCallback){successCallback(xmlHttp);}}else{var msg="AjaxAppender.append: XMLHttpRequest request to URL "+

+url+" returned status code "+xmlHttp.status;handleError(msg);if(failCallback){failCallback(msg);}}

+xmlHttp.onreadystatechange=emptyFunction;xmlHttp=null;}};xmlHttp.open("POST",url,true);try{for(var i=0,header;header=headers[i++];){xmlHttp.setRequestHeader(header.name,header.value);}

+xmlHttp.setRequestHeader("Content-Type",contentType);}catch(headerEx){var msg="AjaxAppender.append: your browser's XMLHttpRequest implementation"+" does not support setRequestHeader, therefore cannot post data. AjaxAppender disabled";handleError(msg);isSupported=false;if(failCallback){failCallback(msg);}

+return;}

+xmlHttp.send(postData);}}catch(ex){var errMsg="AjaxAppender.append: error sending log message to "+url;handleError(errMsg,ex);isSupported=false;if(failCallback){failCallback(errMsg+". Details: "+getExceptionStringRep(ex));}}}

+this.append=function(loggingEvent){if(isSupported){if(!initialized){init();}

+queuedLoggingEvents.push(loggingEvent);var actualBatchSize=this.getLayout().allowBatching()?batchSize:1;if(queuedLoggingEvents.length>=actualBatchSize){var currentLoggingEvent;var batchedLoggingEvents=[];while((currentLoggingEvent=queuedLoggingEvents.shift())){batchedLoggingEvents.push(currentLoggingEvent);}

+queuedRequests.push(batchedLoggingEvents);if(!timed&&(!waitForResponse||(waitForResponse&&!sending))){sendAll();}}}};function init(){initialized=true;if(sendAllOnUnload){var oldBeforeUnload=window.onbeforeunload;window.onbeforeunload=function(){if(oldBeforeUnload){oldBeforeUnload();}

+if(sendAllRemaining()){return"Sending log messages";}};}

+if(timed){scheduleSending();}}}

+AjaxAppender.prototype=new Appender();AjaxAppender.prototype.defaults={waitForResponse:false,timed:false,timerInterval:1000,batchSize:1,sendAllOnUnload:false,requestSuccessCallback:null,failCallback:null,postVarName:"data",contentType:"application/x-www-form-urlencoded"};AjaxAppender.prototype.layout=new HttpPostDataLayout();AjaxAppender.prototype.toString=function(){return"AjaxAppender";};log4javascript.AjaxAppender=AjaxAppender;log4javascript.setDocumentReady=function(){pageLoaded=true;log4javascript.dispatchEvent("load",{});};if(window.addEventListener){window.addEventListener("load",log4javascript.setDocumentReady,false);}else if(window.attachEvent){window.attachEvent("onload",log4javascript.setDocumentReady);}else{var oldOnload=window.onload;if(typeof window.onload!="function"){window.onload=log4javascript.setDocumentReady;}else{window.onload=function(evt){if(oldOnload){oldOnload(evt);}

+log4javascript.setDocumentReady();};}}

+window.log4javascript=log4javascript;return log4javascript;})();

diff --git a/xos/core/static/log4javascript-1.4.6/js/log4javascript_production_uncompressed.js b/xos/core/static/log4javascript-1.4.6/js/log4javascript_production_uncompressed.js
new file mode 100644
index 0000000..1a29621
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/js/log4javascript_production_uncompressed.js
@@ -0,0 +1,2290 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+/**

+ * log4javascript

+ *

+ * log4javascript is a logging framework for JavaScript based on log4j

+ * for Java. This file contains all core log4javascript code and is the only

+ * file required to use log4javascript, unless you require support for

+ * document.domain, in which case you will also need console.html, which must be

+ * stored in the same directory as the main log4javascript.js file.

+ *

+ * Author: Tim Down <tim@log4javascript.org>

+ * Version: 1.4.6

+ * Edition: log4javascript_production

+ * Build date: 19 March 2013

+ * Website: http://log4javascript.org

+ */

+

+/* -------------------------------------------------------------------------- */

+// Array-related stuff

+

+// Next three methods are solely for IE5, which is missing them

+if (!Array.prototype.push) {

+	Array.prototype.push = function() {

+		for (var i = 0, len = arguments.length; i < len; i++){

+			this[this.length] = arguments[i];

+		}

+		return this.length;

+	};

+}

+

+if (!Array.prototype.shift) {

+	Array.prototype.shift = function() {

+		if (this.length > 0) {

+			var firstItem = this[0];

+			for (var i = 0, len = this.length - 1; i < len; i++) {

+				this[i] = this[i + 1];

+			}

+			this.length = this.length - 1;

+			return firstItem;

+		}

+	};

+}

+

+if (!Array.prototype.splice) {

+	Array.prototype.splice = function(startIndex, deleteCount) {

+		var itemsAfterDeleted = this.slice(startIndex + deleteCount);

+		var itemsDeleted = this.slice(startIndex, startIndex + deleteCount);

+		this.length = startIndex;

+		// Copy the arguments into a proper Array object

+		var argumentsArray = [];

+		for (var i = 0, len = arguments.length; i < len; i++) {

+			argumentsArray[i] = arguments[i];

+		}

+		var itemsToAppend = (argumentsArray.length > 2) ?

+			itemsAfterDeleted = argumentsArray.slice(2).concat(itemsAfterDeleted) : itemsAfterDeleted;

+		for (i = 0, len = itemsToAppend.length; i < len; i++) {

+			this.push(itemsToAppend[i]);

+		}

+		return itemsDeleted;

+	};

+}

+

+/* -------------------------------------------------------------------------- */

+

+var log4javascript = (function() {

+

+	function isUndefined(obj) {

+		return typeof obj == "undefined";

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// Custom event support

+

+	function EventSupport() {}

+

+	EventSupport.prototype = {

+		eventTypes: [],

+		eventListeners: {},

+		setEventTypes: function(eventTypesParam) {

+			if (eventTypesParam instanceof Array) {

+				this.eventTypes = eventTypesParam;

+				this.eventListeners = {};

+				for (var i = 0, len = this.eventTypes.length; i < len; i++) {

+					this.eventListeners[this.eventTypes[i]] = [];

+				}

+			} else {

+				handleError("log4javascript.EventSupport [" + this + "]: setEventTypes: eventTypes parameter must be an Array");

+			}

+		},

+

+		addEventListener: function(eventType, listener) {

+			if (typeof listener == "function") {

+				if (!array_contains(this.eventTypes, eventType)) {

+					handleError("log4javascript.EventSupport [" + this + "]: addEventListener: no event called '" + eventType + "'");

+				}

+				this.eventListeners[eventType].push(listener);

+			} else {

+				handleError("log4javascript.EventSupport [" + this + "]: addEventListener: listener must be a function");

+			}

+		},

+

+		removeEventListener: function(eventType, listener) {

+			if (typeof listener == "function") {

+				if (!array_contains(this.eventTypes, eventType)) {

+					handleError("log4javascript.EventSupport [" + this + "]: removeEventListener: no event called '" + eventType + "'");

+				}

+				array_remove(this.eventListeners[eventType], listener);

+			} else {

+				handleError("log4javascript.EventSupport [" + this + "]: removeEventListener: listener must be a function");

+			}

+		},

+

+		dispatchEvent: function(eventType, eventArgs) {

+			if (array_contains(this.eventTypes, eventType)) {

+				var listeners = this.eventListeners[eventType];

+				for (var i = 0, len = listeners.length; i < len; i++) {

+					listeners[i](this, eventType, eventArgs);

+				}

+			} else {

+				handleError("log4javascript.EventSupport [" + this + "]: dispatchEvent: no event called '" + eventType + "'");

+			}

+		}

+	};

+

+	/* -------------------------------------------------------------------------- */

+

+	var applicationStartDate = new Date();

+	var uniqueId = "log4javascript_" + applicationStartDate.getTime() + "_" +

+		Math.floor(Math.random() * 100000000);

+	var emptyFunction = function() {};

+	var newLine = "\r\n";

+	var pageLoaded = false;

+

+	// Create main log4javascript object; this will be assigned public properties

+	function Log4JavaScript() {}

+	Log4JavaScript.prototype = new EventSupport();

+

+	log4javascript = new Log4JavaScript();

+	log4javascript.version = "1.4.6";

+	log4javascript.edition = "log4javascript_production";

+

+	/* -------------------------------------------------------------------------- */

+	// Utility functions

+

+	function toStr(obj) {

+		if (obj && obj.toString) {

+			return obj.toString();

+		} else {

+			return String(obj);

+		}

+	}

+

+	function getExceptionMessage(ex) {

+		if (ex.message) {

+			return ex.message;

+		} else if (ex.description) {

+			return ex.description;

+		} else {

+			return toStr(ex);

+		}

+	}

+

+	// Gets the portion of the URL after the last slash

+	function getUrlFileName(url) {

+		var lastSlashIndex = Math.max(url.lastIndexOf("/"), url.lastIndexOf("\\"));

+		return url.substr(lastSlashIndex + 1);

+	}

+

+	// Returns a nicely formatted representation of an error

+	function getExceptionStringRep(ex) {

+		if (ex) {

+			var exStr = "Exception: " + getExceptionMessage(ex);

+			try {

+				if (ex.lineNumber) {

+					exStr += " on line number " + ex.lineNumber;

+				}

+				if (ex.fileName) {

+					exStr += " in file " + getUrlFileName(ex.fileName);

+				}

+			} catch (localEx) {

+				logLog.warn("Unable to obtain file and line information for error");

+			}

+			if (showStackTraces && ex.stack) {

+				exStr += newLine + "Stack trace:" + newLine + ex.stack;

+			}

+			return exStr;

+		}

+		return null;

+	}

+

+	function bool(obj) {

+		return Boolean(obj);

+	}

+

+	function trim(str) {

+		return str.replace(/^\s+/, "").replace(/\s+$/, "");

+	}

+

+	function splitIntoLines(text) {

+		// Ensure all line breaks are \n only

+		var text2 = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");

+		return text2.split("\n");

+	}

+

+	var urlEncode = (typeof window.encodeURIComponent != "undefined") ?

+		function(str) {

+			return encodeURIComponent(str);

+		}: 

+		function(str) {

+			return escape(str).replace(/\+/g, "%2B").replace(/"/g, "%22").replace(/'/g, "%27").replace(/\//g, "%2F").replace(/=/g, "%3D");

+		};

+

+	var urlDecode = (typeof window.decodeURIComponent != "undefined") ?

+		function(str) {

+			return decodeURIComponent(str);

+		}: 

+		function(str) {

+			return unescape(str).replace(/%2B/g, "+").replace(/%22/g, "\"").replace(/%27/g, "'").replace(/%2F/g, "/").replace(/%3D/g, "=");

+		};

+

+	function array_remove(arr, val) {

+		var index = -1;

+		for (var i = 0, len = arr.length; i < len; i++) {

+			if (arr[i] === val) {

+				index = i;

+				break;

+			}

+		}

+		if (index >= 0) {

+			arr.splice(index, 1);

+			return true;

+		} else {

+			return false;

+		}

+	}

+

+	function array_contains(arr, val) {

+		for(var i = 0, len = arr.length; i < len; i++) {

+			if (arr[i] == val) {

+				return true;

+			}

+		}

+		return false;

+	}

+

+	function extractBooleanFromParam(param, defaultValue) {

+		if (isUndefined(param)) {

+			return defaultValue;

+		} else {

+			return bool(param);

+		}

+	}

+

+	function extractStringFromParam(param, defaultValue) {

+		if (isUndefined(param)) {

+			return defaultValue;

+		} else {

+			return String(param);

+		}

+	}

+

+	function extractIntFromParam(param, defaultValue) {

+		if (isUndefined(param)) {

+			return defaultValue;

+		} else {

+			try {

+				var value = parseInt(param, 10);

+				return isNaN(value) ? defaultValue : value;

+			} catch (ex) {

+				logLog.warn("Invalid int param " + param, ex);

+				return defaultValue;

+			}

+		}

+	}

+

+	function extractFunctionFromParam(param, defaultValue) {

+		if (typeof param == "function") {

+			return param;

+		} else {

+			return defaultValue;

+		}

+	}

+

+	function isError(err) {

+		return (err instanceof Error);

+	}

+

+	if (!Function.prototype.apply){

+		Function.prototype.apply = function(obj, args) {

+			var methodName = "__apply__";

+			if (typeof obj[methodName] != "undefined") {

+				methodName += String(Math.random()).substr(2);

+			}

+			obj[methodName] = this;

+

+			var argsStrings = [];

+			for (var i = 0, len = args.length; i < len; i++) {

+				argsStrings[i] = "args[" + i + "]";

+			}

+			var script = "obj." + methodName + "(" + argsStrings.join(",") + ")";

+			var returnValue = eval(script);

+			delete obj[methodName];

+			return returnValue;

+		};

+	}

+

+	if (!Function.prototype.call){

+		Function.prototype.call = function(obj) {

+			var args = [];

+			for (var i = 1, len = arguments.length; i < len; i++) {

+				args[i - 1] = arguments[i];

+			}

+			return this.apply(obj, args);

+		};

+	}

+

+	function getListenersPropertyName(eventName) {

+		return "__log4javascript_listeners__" + eventName;

+	}

+

+	function addEvent(node, eventName, listener, useCapture, win) {

+		win = win ? win : window;

+		if (node.addEventListener) {

+			node.addEventListener(eventName, listener, useCapture);

+		} else if (node.attachEvent) {

+			node.attachEvent("on" + eventName, listener);

+		} else {

+			var propertyName = getListenersPropertyName(eventName);

+			if (!node[propertyName]) {

+				node[propertyName] = [];

+				// Set event handler

+				node["on" + eventName] = function(evt) {

+					evt = getEvent(evt, win);

+					var listenersPropertyName = getListenersPropertyName(eventName);

+

+					// Clone the array of listeners to leave the original untouched

+					var listeners = this[listenersPropertyName].concat([]);

+					var currentListener;

+

+					// Call each listener in turn

+					while ((currentListener = listeners.shift())) {

+						currentListener.call(this, evt);

+					}

+				};

+			}

+			node[propertyName].push(listener);

+		}

+	}

+

+	function removeEvent(node, eventName, listener, useCapture) {

+		if (node.removeEventListener) {

+			node.removeEventListener(eventName, listener, useCapture);

+		} else if (node.detachEvent) {

+			node.detachEvent("on" + eventName, listener);

+		} else {

+			var propertyName = getListenersPropertyName(eventName);

+			if (node[propertyName]) {

+				array_remove(node[propertyName], listener);

+			}

+		}

+	}

+

+	function getEvent(evt, win) {

+		win = win ? win : window;

+		return evt ? evt : win.event;

+	}

+

+	function stopEventPropagation(evt) {

+		if (evt.stopPropagation) {

+			evt.stopPropagation();

+		} else if (typeof evt.cancelBubble != "undefined") {

+			evt.cancelBubble = true;

+		}

+		evt.returnValue = false;

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// Simple logging for log4javascript itself

+

+	var logLog = {

+		quietMode: false,

+

+		debugMessages: [],

+

+		setQuietMode: function(quietMode) {

+			this.quietMode = bool(quietMode);

+		},

+

+		numberOfErrors: 0,

+

+		alertAllErrors: false,

+

+		setAlertAllErrors: function(alertAllErrors) {

+			this.alertAllErrors = alertAllErrors;

+		},

+

+		debug: function(message) {

+			this.debugMessages.push(message);

+		},

+

+		displayDebug: function() {

+			alert(this.debugMessages.join(newLine));

+		},

+

+		warn: function(message, exception) {

+		},

+

+		error: function(message, exception) {

+			if (++this.numberOfErrors == 1 || this.alertAllErrors) {

+				if (!this.quietMode) {

+					var alertMessage = "log4javascript error: " + message;

+					if (exception) {

+						alertMessage += newLine + newLine + "Original error: " + getExceptionStringRep(exception);

+					}

+					alert(alertMessage);

+				}

+			}

+		}

+	};

+	log4javascript.logLog = logLog;

+

+	log4javascript.setEventTypes(["load", "error"]);

+

+	function handleError(message, exception) {

+		logLog.error(message, exception);

+		log4javascript.dispatchEvent("error", { "message": message, "exception": exception });

+	}

+

+	log4javascript.handleError = handleError;

+

+	/* ---------------------------------------------------------------------- */

+

+	var enabled = !((typeof log4javascript_disabled != "undefined") &&

+					log4javascript_disabled);

+

+	log4javascript.setEnabled = function(enable) {

+		enabled = bool(enable);

+	};

+

+	log4javascript.isEnabled = function() {

+		return enabled;

+	};

+

+	var useTimeStampsInMilliseconds = true;

+

+	log4javascript.setTimeStampsInMilliseconds = function(timeStampsInMilliseconds) {

+		useTimeStampsInMilliseconds = bool(timeStampsInMilliseconds);

+	};

+

+	log4javascript.isTimeStampsInMilliseconds = function() {

+		return useTimeStampsInMilliseconds;

+	};

+	

+

+	// This evaluates the given expression in the current scope, thus allowing

+	// scripts to access private variables. Particularly useful for testing

+	log4javascript.evalInScope = function(expr) {

+		return eval(expr);

+	};

+

+	var showStackTraces = false;

+

+	log4javascript.setShowStackTraces = function(show) {

+		showStackTraces = bool(show);

+	};

+

+	/* ---------------------------------------------------------------------- */

+	// Levels

+

+	var Level = function(level, name) {

+		this.level = level;

+		this.name = name;

+	};

+

+	Level.prototype = {

+		toString: function() {

+			return this.name;

+		},

+		equals: function(level) {

+			return this.level == level.level;

+		},

+		isGreaterOrEqual: function(level) {

+			return this.level >= level.level;

+		}

+	};

+

+	Level.ALL = new Level(Number.MIN_VALUE, "ALL");

+	Level.TRACE = new Level(10000, "TRACE");

+	Level.DEBUG = new Level(20000, "DEBUG");

+	Level.INFO = new Level(30000, "INFO");

+	Level.WARN = new Level(40000, "WARN");

+	Level.ERROR = new Level(50000, "ERROR");

+	Level.FATAL = new Level(60000, "FATAL");

+	Level.OFF = new Level(Number.MAX_VALUE, "OFF");

+

+	log4javascript.Level = Level;

+

+	/* ---------------------------------------------------------------------- */

+	// Timers

+

+	function Timer(name, level) {

+		this.name = name;

+		this.level = isUndefined(level) ? Level.INFO : level;

+		this.start = new Date();

+	}

+

+	Timer.prototype.getElapsedTime = function() {

+		return new Date().getTime() - this.start.getTime();

+	};

+

+	/* ---------------------------------------------------------------------- */

+	// Loggers

+

+	var anonymousLoggerName = "[anonymous]";

+	var defaultLoggerName = "[default]";

+	var nullLoggerName = "[null]";

+	var rootLoggerName = "root";

+

+	function Logger(name) {

+		this.name = name;

+		this.parent = null;

+		this.children = [];

+

+		var appenders = [];

+		var loggerLevel = null;

+		var isRoot = (this.name === rootLoggerName);

+		var isNull = (this.name === nullLoggerName);

+

+		var appenderCache = null;

+		var appenderCacheInvalidated = false;

+		

+		this.addChild = function(childLogger) {

+			this.children.push(childLogger);

+			childLogger.parent = this;

+			childLogger.invalidateAppenderCache();

+		};

+

+		// Additivity

+		var additive = true;

+		this.getAdditivity = function() {

+			return additive;

+		};

+

+		this.setAdditivity = function(additivity) {

+			var valueChanged = (additive != additivity);

+			additive = additivity;

+			if (valueChanged) {

+				this.invalidateAppenderCache();

+			}

+		};

+

+		// Create methods that use the appenders variable in this scope

+		this.addAppender = function(appender) {

+			if (isNull) {

+				handleError("Logger.addAppender: you may not add an appender to the null logger");

+			} else {

+				if (appender instanceof log4javascript.Appender) {

+					if (!array_contains(appenders, appender)) {

+						appenders.push(appender);

+						appender.setAddedToLogger(this);

+						this.invalidateAppenderCache();

+					}

+				} else {

+					handleError("Logger.addAppender: appender supplied ('" +

+						toStr(appender) + "') is not a subclass of Appender");

+				}

+			}

+		};

+

+		this.removeAppender = function(appender) {

+			array_remove(appenders, appender);

+			appender.setRemovedFromLogger(this);

+			this.invalidateAppenderCache();

+		};

+

+		this.removeAllAppenders = function() {

+			var appenderCount = appenders.length;

+			if (appenderCount > 0) {

+				for (var i = 0; i < appenderCount; i++) {

+					appenders[i].setRemovedFromLogger(this);

+				}

+				appenders.length = 0;

+				this.invalidateAppenderCache();

+			}

+		};

+

+		this.getEffectiveAppenders = function() {

+			if (appenderCache === null || appenderCacheInvalidated) {

+				// Build appender cache

+				var parentEffectiveAppenders = (isRoot || !this.getAdditivity()) ?

+					[] : this.parent.getEffectiveAppenders();

+				appenderCache = parentEffectiveAppenders.concat(appenders);

+				appenderCacheInvalidated = false;

+			}

+			return appenderCache;

+		};

+		

+		this.invalidateAppenderCache = function() {

+			appenderCacheInvalidated = true;

+			for (var i = 0, len = this.children.length; i < len; i++) {

+				this.children[i].invalidateAppenderCache();

+			}

+		};

+

+		this.log = function(level, params) {

+			if (enabled && level.isGreaterOrEqual(this.getEffectiveLevel())) {

+				// Check whether last param is an exception

+				var exception;

+				var finalParamIndex = params.length - 1;

+				var lastParam = params[finalParamIndex];

+				if (params.length > 1 && isError(lastParam)) {

+					exception = lastParam;

+					finalParamIndex--;

+				}

+

+				// Construct genuine array for the params

+				var messages = [];

+				for (var i = 0; i <= finalParamIndex; i++) {

+					messages[i] = params[i];

+				}

+

+				var loggingEvent = new LoggingEvent(

+					this, new Date(), level, messages, exception);

+

+				this.callAppenders(loggingEvent);

+			}

+		};

+

+		this.callAppenders = function(loggingEvent) {

+			var effectiveAppenders = this.getEffectiveAppenders();

+			for (var i = 0, len = effectiveAppenders.length; i < len; i++) {

+				effectiveAppenders[i].doAppend(loggingEvent);

+			}

+		};

+

+		this.setLevel = function(level) {

+			// Having a level of null on the root logger would be very bad.

+			if (isRoot && level === null) {

+				handleError("Logger.setLevel: you cannot set the level of the root logger to null");

+			} else if (level instanceof Level) {

+				loggerLevel = level;

+			} else {

+				handleError("Logger.setLevel: level supplied to logger " +

+					this.name + " is not an instance of log4javascript.Level");

+			}

+		};

+

+		this.getLevel = function() {

+			return loggerLevel;

+		};

+

+		this.getEffectiveLevel = function() {

+			for (var logger = this; logger !== null; logger = logger.parent) {

+				var level = logger.getLevel();

+				if (level !== null) {

+					return level;

+				}

+			}

+		};

+

+		this.group = function(name, initiallyExpanded) {

+			if (enabled) {

+				var effectiveAppenders = this.getEffectiveAppenders();

+				for (var i = 0, len = effectiveAppenders.length; i < len; i++) {

+					effectiveAppenders[i].group(name, initiallyExpanded);

+				}

+			}

+		};

+

+		this.groupEnd = function() {

+			if (enabled) {

+				var effectiveAppenders = this.getEffectiveAppenders();

+				for (var i = 0, len = effectiveAppenders.length; i < len; i++) {

+					effectiveAppenders[i].groupEnd();

+				}

+			}

+		};

+

+		var timers = {};

+

+		this.time = function(name, level) {

+			if (enabled) {

+				if (isUndefined(name)) {

+					handleError("Logger.time: a name for the timer must be supplied");

+				} else if (level && !(level instanceof Level)) {

+					handleError("Logger.time: level supplied to timer " +

+						name + " is not an instance of log4javascript.Level");

+				} else {

+					timers[name] = new Timer(name, level);

+				}

+			}

+		};

+

+		this.timeEnd = function(name) {

+			if (enabled) {

+				if (isUndefined(name)) {

+					handleError("Logger.timeEnd: a name for the timer must be supplied");

+				} else if (timers[name]) {

+					var timer = timers[name];

+					var milliseconds = timer.getElapsedTime();

+					this.log(timer.level, ["Timer " + toStr(name) + " completed in " + milliseconds + "ms"]);

+					delete timers[name];

+				} else {

+					logLog.warn("Logger.timeEnd: no timer found with name " + name);

+				}

+			}

+		};

+

+		this.assert = function(expr) {

+			if (enabled && !expr) {

+				var args = [];

+				for (var i = 1, len = arguments.length; i < len; i++) {

+					args.push(arguments[i]);

+				}

+				args = (args.length > 0) ? args : ["Assertion Failure"];

+				args.push(newLine);

+				args.push(expr);

+				this.log(Level.ERROR, args);

+			}

+		};

+

+		this.toString = function() {

+			return "Logger[" + this.name + "]";

+		};

+	}

+

+	Logger.prototype = {

+		trace: function() {

+			this.log(Level.TRACE, arguments);

+		},

+

+		debug: function() {

+			this.log(Level.DEBUG, arguments);

+		},

+

+		info: function() {

+			this.log(Level.INFO, arguments);

+		},

+

+		warn: function() {

+			this.log(Level.WARN, arguments);

+		},

+

+		error: function() {

+			this.log(Level.ERROR, arguments);

+		},

+

+		fatal: function() {

+			this.log(Level.FATAL, arguments);

+		},

+

+		isEnabledFor: function(level) {

+			return level.isGreaterOrEqual(this.getEffectiveLevel());

+		},

+

+		isTraceEnabled: function() {

+			return this.isEnabledFor(Level.TRACE);

+		},

+

+		isDebugEnabled: function() {

+			return this.isEnabledFor(Level.DEBUG);

+		},

+

+		isInfoEnabled: function() {

+			return this.isEnabledFor(Level.INFO);

+		},

+

+		isWarnEnabled: function() {

+			return this.isEnabledFor(Level.WARN);

+		},

+

+		isErrorEnabled: function() {

+			return this.isEnabledFor(Level.ERROR);

+		},

+

+		isFatalEnabled: function() {

+			return this.isEnabledFor(Level.FATAL);

+		}

+	};

+

+	Logger.prototype.trace.isEntryPoint = true;

+	Logger.prototype.debug.isEntryPoint = true;

+	Logger.prototype.info.isEntryPoint = true;

+	Logger.prototype.warn.isEntryPoint = true;

+	Logger.prototype.error.isEntryPoint = true;

+	Logger.prototype.fatal.isEntryPoint = true;

+

+	/* ---------------------------------------------------------------------- */

+	// Logger access methods

+

+	// Hashtable of loggers keyed by logger name

+	var loggers = {};

+	var loggerNames = [];

+

+	var ROOT_LOGGER_DEFAULT_LEVEL = Level.DEBUG;

+	var rootLogger = new Logger(rootLoggerName);

+	rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);

+

+	log4javascript.getRootLogger = function() {

+		return rootLogger;

+	};

+

+	log4javascript.getLogger = function(loggerName) {

+		// Use default logger if loggerName is not specified or invalid

+		if (!(typeof loggerName == "string")) {

+			loggerName = anonymousLoggerName;

+			logLog.warn("log4javascript.getLogger: non-string logger name "	+

+				toStr(loggerName) + " supplied, returning anonymous logger");

+		}

+

+		// Do not allow retrieval of the root logger by name

+		if (loggerName == rootLoggerName) {

+			handleError("log4javascript.getLogger: root logger may not be obtained by name");

+		}

+

+		// Create the logger for this name if it doesn't already exist

+		if (!loggers[loggerName]) {

+			var logger = new Logger(loggerName);

+			loggers[loggerName] = logger;

+			loggerNames.push(loggerName);

+

+			// Set up parent logger, if it doesn't exist

+			var lastDotIndex = loggerName.lastIndexOf(".");

+			var parentLogger;

+			if (lastDotIndex > -1) {

+				var parentLoggerName = loggerName.substring(0, lastDotIndex);

+				parentLogger = log4javascript.getLogger(parentLoggerName); // Recursively sets up grandparents etc.

+			} else {

+				parentLogger = rootLogger;

+			}

+			parentLogger.addChild(logger);

+		}

+		return loggers[loggerName];

+	};

+

+	var defaultLogger = null;

+	log4javascript.getDefaultLogger = function() {

+		if (!defaultLogger) {

+			defaultLogger = log4javascript.getLogger(defaultLoggerName);

+			var a = new log4javascript.PopUpAppender();

+			defaultLogger.addAppender(a);

+		}

+		return defaultLogger;

+	};

+

+	var nullLogger = null;

+	log4javascript.getNullLogger = function() {

+		if (!nullLogger) {

+			nullLogger = new Logger(nullLoggerName);

+			nullLogger.setLevel(Level.OFF);

+		}

+		return nullLogger;

+	};

+

+	// Destroys all loggers

+	log4javascript.resetConfiguration = function() {

+		rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);

+		loggers = {};

+	};

+

+	/* ---------------------------------------------------------------------- */

+	// Logging events

+

+	var LoggingEvent = function(logger, timeStamp, level, messages,

+			exception) {

+		this.logger = logger;

+		this.timeStamp = timeStamp;

+		this.timeStampInMilliseconds = timeStamp.getTime();

+		this.timeStampInSeconds = Math.floor(this.timeStampInMilliseconds / 1000);

+		this.milliseconds = this.timeStamp.getMilliseconds();

+		this.level = level;

+		this.messages = messages;

+		this.exception = exception;

+	};

+

+	LoggingEvent.prototype = {

+		getThrowableStrRep: function() {

+			return this.exception ?

+				getExceptionStringRep(this.exception) : "";

+		},

+		getCombinedMessages: function() {

+			return (this.messages.length == 1) ? this.messages[0] :

+				   this.messages.join(newLine);

+		},

+		toString: function() {

+			return "LoggingEvent[" + this.level + "]";

+		}

+	};

+

+	log4javascript.LoggingEvent = LoggingEvent;

+

+	/* ---------------------------------------------------------------------- */

+	// Layout prototype

+

+	var Layout = function() {

+	};

+

+	Layout.prototype = {

+		defaults: {

+			loggerKey: "logger",

+			timeStampKey: "timestamp",

+			millisecondsKey: "milliseconds",

+			levelKey: "level",

+			messageKey: "message",

+			exceptionKey: "exception",

+			urlKey: "url"

+		},

+		loggerKey: "logger",

+		timeStampKey: "timestamp",

+		millisecondsKey: "milliseconds",

+		levelKey: "level",

+		messageKey: "message",

+		exceptionKey: "exception",

+		urlKey: "url",

+		batchHeader: "",

+		batchFooter: "",

+		batchSeparator: "",

+		returnsPostData: false,

+		overrideTimeStampsSetting: false,

+		useTimeStampsInMilliseconds: null,

+

+		format: function() {

+			handleError("Layout.format: layout supplied has no format() method");

+		},

+

+		ignoresThrowable: function() {

+			handleError("Layout.ignoresThrowable: layout supplied has no ignoresThrowable() method");

+		},

+

+		getContentType: function() {

+			return "text/plain";

+		},

+

+		allowBatching: function() {

+			return true;

+		},

+

+		setTimeStampsInMilliseconds: function(timeStampsInMilliseconds) {

+			this.overrideTimeStampsSetting = true;

+			this.useTimeStampsInMilliseconds = bool(timeStampsInMilliseconds);

+		},

+

+		isTimeStampsInMilliseconds: function() {

+			return this.overrideTimeStampsSetting ?

+				this.useTimeStampsInMilliseconds : useTimeStampsInMilliseconds;

+		},

+

+		getTimeStampValue: function(loggingEvent) {

+			return this.isTimeStampsInMilliseconds() ?

+				loggingEvent.timeStampInMilliseconds : loggingEvent.timeStampInSeconds;

+		},

+

+		getDataValues: function(loggingEvent, combineMessages) {

+			var dataValues = [

+				[this.loggerKey, loggingEvent.logger.name],

+				[this.timeStampKey, this.getTimeStampValue(loggingEvent)],

+				[this.levelKey, loggingEvent.level.name],

+				[this.urlKey, window.location.href],

+				[this.messageKey, combineMessages ? loggingEvent.getCombinedMessages() : loggingEvent.messages]

+			];

+			if (!this.isTimeStampsInMilliseconds()) {

+				dataValues.push([this.millisecondsKey, loggingEvent.milliseconds]);

+			}

+			if (loggingEvent.exception) {

+				dataValues.push([this.exceptionKey, getExceptionStringRep(loggingEvent.exception)]);

+			}

+			if (this.hasCustomFields()) {

+				for (var i = 0, len = this.customFields.length; i < len; i++) {

+					var val = this.customFields[i].value;

+

+					// Check if the value is a function. If so, execute it, passing it the

+					// current layout and the logging event

+					if (typeof val === "function") {

+						val = val(this, loggingEvent);

+					}

+					dataValues.push([this.customFields[i].name, val]);

+				}

+			}

+			return dataValues;

+		},

+

+		setKeys: function(loggerKey, timeStampKey, levelKey, messageKey,

+				exceptionKey, urlKey, millisecondsKey) {

+			this.loggerKey = extractStringFromParam(loggerKey, this.defaults.loggerKey);

+			this.timeStampKey = extractStringFromParam(timeStampKey, this.defaults.timeStampKey);

+			this.levelKey = extractStringFromParam(levelKey, this.defaults.levelKey);

+			this.messageKey = extractStringFromParam(messageKey, this.defaults.messageKey);

+			this.exceptionKey = extractStringFromParam(exceptionKey, this.defaults.exceptionKey);

+			this.urlKey = extractStringFromParam(urlKey, this.defaults.urlKey);

+			this.millisecondsKey = extractStringFromParam(millisecondsKey, this.defaults.millisecondsKey);

+		},

+

+		setCustomField: function(name, value) {

+			var fieldUpdated = false;

+			for (var i = 0, len = this.customFields.length; i < len; i++) {

+				if (this.customFields[i].name === name) {

+					this.customFields[i].value = value;

+					fieldUpdated = true;

+				}

+			}

+			if (!fieldUpdated) {

+				this.customFields.push({"name": name, "value": value});

+			}

+		},

+

+		hasCustomFields: function() {

+			return (this.customFields.length > 0);

+		},

+

+		toString: function() {

+			handleError("Layout.toString: all layouts must override this method");

+		}

+	};

+

+	log4javascript.Layout = Layout;

+

+	/* ---------------------------------------------------------------------- */

+	// Appender prototype

+

+	var Appender = function() {};

+

+	Appender.prototype = new EventSupport();

+

+	Appender.prototype.layout = new PatternLayout();

+	Appender.prototype.threshold = Level.ALL;

+	Appender.prototype.loggers = [];

+

+	// Performs threshold checks before delegating actual logging to the

+	// subclass's specific append method.

+	Appender.prototype.doAppend = function(loggingEvent) {

+		if (enabled && loggingEvent.level.level >= this.threshold.level) {

+			this.append(loggingEvent);

+		}

+	};

+

+	Appender.prototype.append = function(loggingEvent) {};

+

+	Appender.prototype.setLayout = function(layout) {

+		if (layout instanceof Layout) {

+			this.layout = layout;

+		} else {

+			handleError("Appender.setLayout: layout supplied to " +

+				this.toString() + " is not a subclass of Layout");

+		}

+	};

+

+	Appender.prototype.getLayout = function() {

+		return this.layout;

+	};

+

+	Appender.prototype.setThreshold = function(threshold) {

+		if (threshold instanceof Level) {

+			this.threshold = threshold;

+		} else {

+			handleError("Appender.setThreshold: threshold supplied to " +

+				this.toString() + " is not a subclass of Level");

+		}

+	};

+

+	Appender.prototype.getThreshold = function() {

+		return this.threshold;

+	};

+

+	Appender.prototype.setAddedToLogger = function(logger) {

+		this.loggers.push(logger);

+	};

+

+	Appender.prototype.setRemovedFromLogger = function(logger) {

+		array_remove(this.loggers, logger);

+	};

+

+	Appender.prototype.group = emptyFunction;

+	Appender.prototype.groupEnd = emptyFunction;

+

+	Appender.prototype.toString = function() {

+		handleError("Appender.toString: all appenders must override this method");

+	};

+

+	log4javascript.Appender = Appender;

+

+	/* ---------------------------------------------------------------------- */

+	// SimpleLayout 

+

+	function SimpleLayout() {

+		this.customFields = [];

+	}

+

+	SimpleLayout.prototype = new Layout();

+

+	SimpleLayout.prototype.format = function(loggingEvent) {

+		return loggingEvent.level.name + " - " + loggingEvent.getCombinedMessages();

+	};

+

+	SimpleLayout.prototype.ignoresThrowable = function() {

+	    return true;

+	};

+

+	SimpleLayout.prototype.toString = function() {

+	    return "SimpleLayout";

+	};

+

+	log4javascript.SimpleLayout = SimpleLayout;

+	/* ----------------------------------------------------------------------- */

+	// NullLayout 

+

+	function NullLayout() {

+		this.customFields = [];

+	}

+

+	NullLayout.prototype = new Layout();

+

+	NullLayout.prototype.format = function(loggingEvent) {

+		return loggingEvent.messages;

+	};

+

+	NullLayout.prototype.ignoresThrowable = function() {

+	    return true;

+	};

+

+	NullLayout.prototype.toString = function() {

+	    return "NullLayout";

+	};

+

+	log4javascript.NullLayout = NullLayout;

+/* ---------------------------------------------------------------------- */

+	// XmlLayout

+

+	function XmlLayout(combineMessages) {

+		this.combineMessages = extractBooleanFromParam(combineMessages, true);

+		this.customFields = [];

+	}

+

+	XmlLayout.prototype = new Layout();

+

+	XmlLayout.prototype.isCombinedMessages = function() {

+		return this.combineMessages;

+	};

+

+	XmlLayout.prototype.getContentType = function() {

+		return "text/xml";

+	};

+

+	XmlLayout.prototype.escapeCdata = function(str) {

+		return str.replace(/\]\]>/, "]]>]]&gt;<![CDATA[");

+	};

+

+	XmlLayout.prototype.format = function(loggingEvent) {

+		var layout = this;

+		var i, len;

+		function formatMessage(message) {

+			message = (typeof message === "string") ? message : toStr(message);

+			return "<log4javascript:message><![CDATA[" +

+				layout.escapeCdata(message) + "]]></log4javascript:message>";

+		}

+

+		var str = "<log4javascript:event logger=\"" + loggingEvent.logger.name +

+			"\" timestamp=\"" + this.getTimeStampValue(loggingEvent) + "\"";

+		if (!this.isTimeStampsInMilliseconds()) {

+			str += " milliseconds=\"" + loggingEvent.milliseconds + "\"";

+		}

+		str += " level=\"" + loggingEvent.level.name + "\">" + newLine;

+		if (this.combineMessages) {

+			str += formatMessage(loggingEvent.getCombinedMessages());

+		} else {

+			str += "<log4javascript:messages>" + newLine;

+			for (i = 0, len = loggingEvent.messages.length; i < len; i++) {

+				str += formatMessage(loggingEvent.messages[i]) + newLine;

+			}

+			str += "</log4javascript:messages>" + newLine;

+		}

+		if (this.hasCustomFields()) {

+			for (i = 0, len = this.customFields.length; i < len; i++) {

+				str += "<log4javascript:customfield name=\"" +

+					this.customFields[i].name + "\"><![CDATA[" +

+					this.customFields[i].value.toString() +

+					"]]></log4javascript:customfield>" + newLine;

+			}

+		}

+		if (loggingEvent.exception) {

+			str += "<log4javascript:exception><![CDATA[" +

+				getExceptionStringRep(loggingEvent.exception) +

+				"]]></log4javascript:exception>" + newLine;

+		}

+		str += "</log4javascript:event>" + newLine + newLine;

+		return str;

+	};

+

+	XmlLayout.prototype.ignoresThrowable = function() {

+	    return false;

+	};

+

+	XmlLayout.prototype.toString = function() {

+	    return "XmlLayout";

+	};

+

+	log4javascript.XmlLayout = XmlLayout;

+	/* ---------------------------------------------------------------------- */

+	// JsonLayout related

+

+	function escapeNewLines(str) {

+		return str.replace(/\r\n|\r|\n/g, "\\r\\n");

+	}

+

+	function JsonLayout(readable, combineMessages) {

+		this.readable = extractBooleanFromParam(readable, false);

+		this.combineMessages = extractBooleanFromParam(combineMessages, true);

+		this.batchHeader = this.readable ? "[" + newLine : "[";

+		this.batchFooter = this.readable ? "]" + newLine : "]";

+		this.batchSeparator = this.readable ? "," + newLine : ",";

+		this.setKeys();

+		this.colon = this.readable ? ": " : ":";

+		this.tab = this.readable ? "\t" : "";

+		this.lineBreak = this.readable ? newLine : "";

+		this.customFields = [];

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// JsonLayout

+

+	JsonLayout.prototype = new Layout();

+

+	JsonLayout.prototype.isReadable = function() {

+		return this.readable;

+	};

+

+	JsonLayout.prototype.isCombinedMessages = function() {

+		return this.combineMessages;

+	};

+

+    JsonLayout.prototype.format = function(loggingEvent) {

+        var layout = this;

+        var dataValues = this.getDataValues(loggingEvent, this.combineMessages);

+        var str = "{" + this.lineBreak;

+        var i, len;

+

+        function formatValue(val, prefix, expand) {

+            // Check the type of the data value to decide whether quotation marks

+            // or expansion are required

+            var formattedValue;

+            var valType = typeof val;

+            if (val instanceof Date) {

+                formattedValue = String(val.getTime());

+            } else if (expand && (val instanceof Array)) {

+                formattedValue = "[" + layout.lineBreak;

+                for (var i = 0, len = val.length; i < len; i++) {

+                    var childPrefix = prefix + layout.tab;

+                    formattedValue += childPrefix + formatValue(val[i], childPrefix, false);

+                    if (i < val.length - 1) {

+                        formattedValue += ",";

+                    }

+                    formattedValue += layout.lineBreak;

+                }

+                formattedValue += prefix + "]";

+            } else if (valType !== "number" && valType !== "boolean") {

+                formattedValue = "\"" + escapeNewLines(toStr(val).replace(/\"/g, "\\\"")) + "\"";

+            } else {

+                formattedValue = val;

+            }

+            return formattedValue;

+        }

+

+        for (i = 0, len = dataValues.length - 1; i <= len; i++) {

+            str += this.tab + "\"" + dataValues[i][0] + "\"" + this.colon + formatValue(dataValues[i][1], this.tab, true);

+            if (i < len) {

+                str += ",";

+            }

+            str += this.lineBreak;

+        }

+

+        str += "}" + this.lineBreak;

+        return str;

+    };

+

+	JsonLayout.prototype.ignoresThrowable = function() {

+	    return false;

+	};

+

+	JsonLayout.prototype.toString = function() {

+	    return "JsonLayout";

+	};

+

+	JsonLayout.prototype.getContentType = function() {

+		return "application/json";

+	};

+

+	log4javascript.JsonLayout = JsonLayout;

+	/* ---------------------------------------------------------------------- */

+	// HttpPostDataLayout

+

+	function HttpPostDataLayout() {

+		this.setKeys();

+		this.customFields = [];

+		this.returnsPostData = true;

+	}

+

+	HttpPostDataLayout.prototype = new Layout();

+

+	// Disable batching

+	HttpPostDataLayout.prototype.allowBatching = function() {

+		return false;

+	};

+

+	HttpPostDataLayout.prototype.format = function(loggingEvent) {

+		var dataValues = this.getDataValues(loggingEvent);

+		var queryBits = [];

+		for (var i = 0, len = dataValues.length; i < len; i++) {

+			var val = (dataValues[i][1] instanceof Date) ?

+				String(dataValues[i][1].getTime()) : dataValues[i][1];

+			queryBits.push(urlEncode(dataValues[i][0]) + "=" + urlEncode(val));

+		}

+		return queryBits.join("&");

+	};

+

+	HttpPostDataLayout.prototype.ignoresThrowable = function(loggingEvent) {

+	    return false;

+	};

+

+	HttpPostDataLayout.prototype.toString = function() {

+	    return "HttpPostDataLayout";

+	};

+

+	log4javascript.HttpPostDataLayout = HttpPostDataLayout;

+	/* ---------------------------------------------------------------------- */

+	// formatObjectExpansion

+

+	function formatObjectExpansion(obj, depth, indentation) {

+		var objectsExpanded = [];

+

+		function doFormat(obj, depth, indentation) {

+			var i, j, len, childDepth, childIndentation, childLines, expansion,

+				childExpansion;

+

+			if (!indentation) {

+				indentation = "";

+			}

+

+			function formatString(text) {

+				var lines = splitIntoLines(text);

+				for (var j = 1, jLen = lines.length; j < jLen; j++) {

+					lines[j] = indentation + lines[j];

+				}

+				return lines.join(newLine);

+			}

+

+			if (obj === null) {

+				return "null";

+			} else if (typeof obj == "undefined") {

+				return "undefined";

+			} else if (typeof obj == "string") {

+				return formatString(obj);

+			} else if (typeof obj == "object" && array_contains(objectsExpanded, obj)) {

+				try {

+					expansion = toStr(obj);

+				} catch (ex) {

+					expansion = "Error formatting property. Details: " + getExceptionStringRep(ex);

+				}

+				return expansion + " [already expanded]";

+			} else if ((obj instanceof Array) && depth > 0) {

+				objectsExpanded.push(obj);

+				expansion = "[" + newLine;

+				childDepth = depth - 1;

+				childIndentation = indentation + "  ";

+				childLines = [];

+				for (i = 0, len = obj.length; i < len; i++) {

+					try {

+						childExpansion = doFormat(obj[i], childDepth, childIndentation);

+						childLines.push(childIndentation + childExpansion);

+					} catch (ex) {

+						childLines.push(childIndentation + "Error formatting array member. Details: " +

+							getExceptionStringRep(ex) + "");

+					}

+				}

+				expansion += childLines.join("," + newLine) + newLine + indentation + "]";

+				return expansion;

+            } else if (Object.prototype.toString.call(obj) == "[object Date]") {

+                return obj.toString();

+			} else if (typeof obj == "object" && depth > 0) {

+				objectsExpanded.push(obj);

+				expansion = "{" + newLine;

+				childDepth = depth - 1;

+				childIndentation = indentation + "  ";

+				childLines = [];

+				for (i in obj) {

+					try {

+						childExpansion = doFormat(obj[i], childDepth, childIndentation);

+						childLines.push(childIndentation + i + ": " + childExpansion);

+					} catch (ex) {

+						childLines.push(childIndentation + i + ": Error formatting property. Details: " +

+							getExceptionStringRep(ex));

+					}

+				}

+				expansion += childLines.join("," + newLine) + newLine + indentation + "}";

+				return expansion;

+			} else {

+				return formatString(toStr(obj));

+			}

+		}

+		return doFormat(obj, depth, indentation);

+	}

+	/* ---------------------------------------------------------------------- */

+	// Date-related stuff

+

+	var SimpleDateFormat;

+

+	(function() {

+		var regex = /('[^']*')|(G+|y+|M+|w+|W+|D+|d+|F+|E+|a+|H+|k+|K+|h+|m+|s+|S+|Z+)|([a-zA-Z]+)|([^a-zA-Z']+)/;

+		var monthNames = ["January", "February", "March", "April", "May", "June",

+			"July", "August", "September", "October", "November", "December"];

+		var dayNames = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];

+		var TEXT2 = 0, TEXT3 = 1, NUMBER = 2, YEAR = 3, MONTH = 4, TIMEZONE = 5;

+		var types = {

+			G : TEXT2,

+			y : YEAR,

+			M : MONTH,

+			w : NUMBER,

+			W : NUMBER,

+			D : NUMBER,

+			d : NUMBER,

+			F : NUMBER,

+			E : TEXT3,

+			a : TEXT2,

+			H : NUMBER,

+			k : NUMBER,

+			K : NUMBER,

+			h : NUMBER,

+			m : NUMBER,

+			s : NUMBER,

+			S : NUMBER,

+			Z : TIMEZONE

+		};

+		var ONE_DAY = 24 * 60 * 60 * 1000;

+		var ONE_WEEK = 7 * ONE_DAY;

+		var DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK = 1;

+

+		var newDateAtMidnight = function(year, month, day) {

+			var d = new Date(year, month, day, 0, 0, 0);

+			d.setMilliseconds(0);

+			return d;

+		};

+

+		Date.prototype.getDifference = function(date) {

+			return this.getTime() - date.getTime();

+		};

+

+		Date.prototype.isBefore = function(d) {

+			return this.getTime() < d.getTime();

+		};

+

+		Date.prototype.getUTCTime = function() {

+			return Date.UTC(this.getFullYear(), this.getMonth(), this.getDate(), this.getHours(), this.getMinutes(),

+					this.getSeconds(), this.getMilliseconds());

+		};

+

+		Date.prototype.getTimeSince = function(d) {

+			return this.getUTCTime() - d.getUTCTime();

+		};

+

+		Date.prototype.getPreviousSunday = function() {

+			// Using midday avoids any possibility of DST messing things up

+			var midday = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 12, 0, 0);

+			var previousSunday = new Date(midday.getTime() - this.getDay() * ONE_DAY);

+			return newDateAtMidnight(previousSunday.getFullYear(), previousSunday.getMonth(),

+					previousSunday.getDate());

+		};

+

+		Date.prototype.getWeekInYear = function(minimalDaysInFirstWeek) {

+			if (isUndefined(this.minimalDaysInFirstWeek)) {

+				minimalDaysInFirstWeek = DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;

+			}

+			var previousSunday = this.getPreviousSunday();

+			var startOfYear = newDateAtMidnight(this.getFullYear(), 0, 1);

+			var numberOfSundays = previousSunday.isBefore(startOfYear) ?

+				0 : 1 + Math.floor(previousSunday.getTimeSince(startOfYear) / ONE_WEEK);

+			var numberOfDaysInFirstWeek =  7 - startOfYear.getDay();

+			var weekInYear = numberOfSundays;

+			if (numberOfDaysInFirstWeek < minimalDaysInFirstWeek) {

+				weekInYear--;

+			}

+			return weekInYear;

+		};

+

+		Date.prototype.getWeekInMonth = function(minimalDaysInFirstWeek) {

+			if (isUndefined(this.minimalDaysInFirstWeek)) {

+				minimalDaysInFirstWeek = DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;

+			}

+			var previousSunday = this.getPreviousSunday();

+			var startOfMonth = newDateAtMidnight(this.getFullYear(), this.getMonth(), 1);

+			var numberOfSundays = previousSunday.isBefore(startOfMonth) ?

+				0 : 1 + Math.floor(previousSunday.getTimeSince(startOfMonth) / ONE_WEEK);

+			var numberOfDaysInFirstWeek =  7 - startOfMonth.getDay();

+			var weekInMonth = numberOfSundays;

+			if (numberOfDaysInFirstWeek >= minimalDaysInFirstWeek) {

+				weekInMonth++;

+			}

+			return weekInMonth;

+		};

+

+		Date.prototype.getDayInYear = function() {

+			var startOfYear = newDateAtMidnight(this.getFullYear(), 0, 1);

+			return 1 + Math.floor(this.getTimeSince(startOfYear) / ONE_DAY);

+		};

+

+		/* ------------------------------------------------------------------ */

+

+		SimpleDateFormat = function(formatString) {

+			this.formatString = formatString;

+		};

+

+		/**

+		 * Sets the minimum number of days in a week in order for that week to

+		 * be considered as belonging to a particular month or year

+		 */

+		SimpleDateFormat.prototype.setMinimalDaysInFirstWeek = function(days) {

+			this.minimalDaysInFirstWeek = days;

+		};

+

+		SimpleDateFormat.prototype.getMinimalDaysInFirstWeek = function() {

+			return isUndefined(this.minimalDaysInFirstWeek)	?

+				DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK : this.minimalDaysInFirstWeek;

+		};

+

+		var padWithZeroes = function(str, len) {

+			while (str.length < len) {

+				str = "0" + str;

+			}

+			return str;

+		};

+

+		var formatText = function(data, numberOfLetters, minLength) {

+			return (numberOfLetters >= 4) ? data : data.substr(0, Math.max(minLength, numberOfLetters));

+		};

+

+		var formatNumber = function(data, numberOfLetters) {

+			var dataString = "" + data;

+			// Pad with 0s as necessary

+			return padWithZeroes(dataString, numberOfLetters);

+		};

+

+		SimpleDateFormat.prototype.format = function(date) {

+			var formattedString = "";

+			var result;

+			var searchString = this.formatString;

+			while ((result = regex.exec(searchString))) {

+				var quotedString = result[1];

+				var patternLetters = result[2];

+				var otherLetters = result[3];

+				var otherCharacters = result[4];

+

+				// If the pattern matched is quoted string, output the text between the quotes

+				if (quotedString) {

+					if (quotedString == "''") {

+						formattedString += "'";

+					} else {

+						formattedString += quotedString.substring(1, quotedString.length - 1);

+					}

+				} else if (otherLetters) {

+					// Swallow non-pattern letters by doing nothing here

+				} else if (otherCharacters) {

+					// Simply output other characters

+					formattedString += otherCharacters;

+				} else if (patternLetters) {

+					// Replace pattern letters

+					var patternLetter = patternLetters.charAt(0);

+					var numberOfLetters = patternLetters.length;

+					var rawData = "";

+					switch(patternLetter) {

+						case "G":

+							rawData = "AD";

+							break;

+						case "y":

+							rawData = date.getFullYear();

+							break;

+						case "M":

+							rawData = date.getMonth();

+							break;

+						case "w":

+							rawData = date.getWeekInYear(this.getMinimalDaysInFirstWeek());

+							break;

+						case "W":

+							rawData = date.getWeekInMonth(this.getMinimalDaysInFirstWeek());

+							break;

+						case "D":

+							rawData = date.getDayInYear();

+							break;

+						case "d":

+							rawData = date.getDate();

+							break;

+						case "F":

+							rawData = 1 + Math.floor((date.getDate() - 1) / 7);

+							break;

+						case "E":

+							rawData = dayNames[date.getDay()];

+							break;

+						case "a":

+							rawData = (date.getHours() >= 12) ? "PM" : "AM";

+							break;

+						case "H":

+							rawData = date.getHours();

+							break;

+						case "k":

+							rawData = date.getHours() || 24;

+							break;

+						case "K":

+							rawData = date.getHours() % 12;

+							break;

+						case "h":

+							rawData = (date.getHours() % 12) || 12;

+							break;

+						case "m":

+							rawData = date.getMinutes();

+							break;

+						case "s":

+							rawData = date.getSeconds();

+							break;

+						case "S":

+							rawData = date.getMilliseconds();

+							break;

+						case "Z":

+							rawData = date.getTimezoneOffset(); // This returns the number of minutes since GMT was this time.

+							break;

+					}

+					// Format the raw data depending on the type

+					switch(types[patternLetter]) {

+						case TEXT2:

+							formattedString += formatText(rawData, numberOfLetters, 2);

+							break;

+						case TEXT3:

+							formattedString += formatText(rawData, numberOfLetters, 3);

+							break;

+						case NUMBER:

+							formattedString += formatNumber(rawData, numberOfLetters);

+							break;

+						case YEAR:

+							if (numberOfLetters <= 3) {

+								// Output a 2-digit year

+								var dataString = "" + rawData;

+								formattedString += dataString.substr(2, 2);

+							} else {

+								formattedString += formatNumber(rawData, numberOfLetters);

+							}

+							break;

+						case MONTH:

+							if (numberOfLetters >= 3) {

+								formattedString += formatText(monthNames[rawData], numberOfLetters, numberOfLetters);

+							} else {

+								// NB. Months returned by getMonth are zero-based

+								formattedString += formatNumber(rawData + 1, numberOfLetters);

+							}

+							break;

+						case TIMEZONE:

+							var isPositive = (rawData > 0);

+							// The following line looks like a mistake but isn't

+							// because of the way getTimezoneOffset measures.

+							var prefix = isPositive ? "-" : "+";

+							var absData = Math.abs(rawData);

+

+							// Hours

+							var hours = "" + Math.floor(absData / 60);

+							hours = padWithZeroes(hours, 2);

+							// Minutes

+							var minutes = "" + (absData % 60);

+							minutes = padWithZeroes(minutes, 2);

+

+							formattedString += prefix + hours + minutes;

+							break;

+					}

+				}

+				searchString = searchString.substr(result.index + result[0].length);

+			}

+			return formattedString;

+		};

+	})();

+

+	log4javascript.SimpleDateFormat = SimpleDateFormat;

+

+	/* ---------------------------------------------------------------------- */

+	// PatternLayout

+

+	function PatternLayout(pattern) {

+		if (pattern) {

+			this.pattern = pattern;

+		} else {

+			this.pattern = PatternLayout.DEFAULT_CONVERSION_PATTERN;

+		}

+		this.customFields = [];

+	}

+

+	PatternLayout.TTCC_CONVERSION_PATTERN = "%r %p %c - %m%n";

+	PatternLayout.DEFAULT_CONVERSION_PATTERN = "%m%n";

+	PatternLayout.ISO8601_DATEFORMAT = "yyyy-MM-dd HH:mm:ss,SSS";

+	PatternLayout.DATETIME_DATEFORMAT = "dd MMM yyyy HH:mm:ss,SSS";

+	PatternLayout.ABSOLUTETIME_DATEFORMAT = "HH:mm:ss,SSS";

+

+	PatternLayout.prototype = new Layout();

+

+	PatternLayout.prototype.format = function(loggingEvent) {

+		var regex = /%(-?[0-9]+)?(\.?[0-9]+)?([acdfmMnpr%])(\{([^\}]+)\})?|([^%]+)/;

+		var formattedString = "";

+		var result;

+		var searchString = this.pattern;

+

+		// Cannot use regex global flag since it doesn't work with exec in IE5

+		while ((result = regex.exec(searchString))) {

+			var matchedString = result[0];

+			var padding = result[1];

+			var truncation = result[2];

+			var conversionCharacter = result[3];

+			var specifier = result[5];

+			var text = result[6];

+

+			// Check if the pattern matched was just normal text

+			if (text) {

+				formattedString += "" + text;

+			} else {

+				// Create a raw replacement string based on the conversion

+				// character and specifier

+				var replacement = "";

+				switch(conversionCharacter) {

+					case "a": // Array of messages

+					case "m": // Message

+						var depth = 0;

+						if (specifier) {

+							depth = parseInt(specifier, 10);

+							if (isNaN(depth)) {

+								handleError("PatternLayout.format: invalid specifier '" +

+									specifier + "' for conversion character '" + conversionCharacter +

+									"' - should be a number");

+								depth = 0;

+							}

+						}

+						var messages = (conversionCharacter === "a") ? loggingEvent.messages[0] : loggingEvent.messages;

+						for (var i = 0, len = messages.length; i < len; i++) {

+							if (i > 0 && (replacement.charAt(replacement.length - 1) !== " ")) {

+								replacement += " ";

+							}

+							if (depth === 0) {

+								replacement += messages[i];

+							} else {

+								replacement += formatObjectExpansion(messages[i], depth);

+							}

+						}

+						break;

+					case "c": // Logger name

+						var loggerName = loggingEvent.logger.name;

+						if (specifier) {

+							var precision = parseInt(specifier, 10);

+							var loggerNameBits = loggingEvent.logger.name.split(".");

+							if (precision >= loggerNameBits.length) {

+								replacement = loggerName;

+							} else {

+								replacement = loggerNameBits.slice(loggerNameBits.length - precision).join(".");

+							}

+						} else {

+							replacement = loggerName;

+						}

+						break;

+					case "d": // Date

+						var dateFormat = PatternLayout.ISO8601_DATEFORMAT;

+						if (specifier) {

+							dateFormat = specifier;

+							// Pick up special cases

+							if (dateFormat == "ISO8601") {

+								dateFormat = PatternLayout.ISO8601_DATEFORMAT;

+							} else if (dateFormat == "ABSOLUTE") {

+								dateFormat = PatternLayout.ABSOLUTETIME_DATEFORMAT;

+							} else if (dateFormat == "DATE") {

+								dateFormat = PatternLayout.DATETIME_DATEFORMAT;

+							}

+						}

+						// Format the date

+						replacement = (new SimpleDateFormat(dateFormat)).format(loggingEvent.timeStamp);

+						break;

+					case "f": // Custom field

+						if (this.hasCustomFields()) {

+							var fieldIndex = 0;

+							if (specifier) {

+								fieldIndex = parseInt(specifier, 10);

+								if (isNaN(fieldIndex)) {

+									handleError("PatternLayout.format: invalid specifier '" +

+										specifier + "' for conversion character 'f' - should be a number");

+								} else if (fieldIndex === 0) {

+									handleError("PatternLayout.format: invalid specifier '" +

+										specifier + "' for conversion character 'f' - must be greater than zero");

+								} else if (fieldIndex > this.customFields.length) {

+									handleError("PatternLayout.format: invalid specifier '" +

+										specifier + "' for conversion character 'f' - there aren't that many custom fields");

+								} else {

+									fieldIndex = fieldIndex - 1;

+								}

+							}

+                            var val = this.customFields[fieldIndex].value;

+                            if (typeof val == "function") {

+                                val = val(this, loggingEvent);

+                            }

+                            replacement = val;

+						}

+						break;

+					case "n": // New line

+						replacement = newLine;

+						break;

+					case "p": // Level

+						replacement = loggingEvent.level.name;

+						break;

+					case "r": // Milliseconds since log4javascript startup

+						replacement = "" + loggingEvent.timeStamp.getDifference(applicationStartDate);

+						break;

+					case "%": // Literal % sign

+						replacement = "%";

+						break;

+					default:

+						replacement = matchedString;

+						break;

+				}

+				// Format the replacement according to any padding or

+				// truncation specified

+				var l;

+

+				// First, truncation

+				if (truncation) {

+					l = parseInt(truncation.substr(1), 10);

+					var strLen = replacement.length;

+					if (l < strLen) {

+						replacement = replacement.substring(strLen - l, strLen);

+					}

+				}

+				// Next, padding

+				if (padding) {

+					if (padding.charAt(0) == "-") {

+						l = parseInt(padding.substr(1), 10);

+						// Right pad with spaces

+						while (replacement.length < l) {

+							replacement += " ";

+						}

+					} else {

+						l = parseInt(padding, 10);

+						// Left pad with spaces

+						while (replacement.length < l) {

+							replacement = " " + replacement;

+						}

+					}

+				}

+				formattedString += replacement;

+			}

+			searchString = searchString.substr(result.index + result[0].length);

+		}

+		return formattedString;

+	};

+

+	PatternLayout.prototype.ignoresThrowable = function() {

+	    return true;

+	};

+

+	PatternLayout.prototype.toString = function() {

+	    return "PatternLayout";

+	};

+

+	log4javascript.PatternLayout = PatternLayout;

+	/* ---------------------------------------------------------------------- */

+	// AjaxAppender related

+

+	var xmlHttpFactories = [

+		function() { return new XMLHttpRequest(); },

+		function() { return new ActiveXObject("Msxml2.XMLHTTP"); },

+		function() { return new ActiveXObject("Microsoft.XMLHTTP"); }

+	];

+

+	var getXmlHttp = function(errorHandler) {

+		// This is only run the first time; the value of getXmlHttp gets

+		// replaced with the factory that succeeds on the first run

+		var xmlHttp = null, factory;

+		for (var i = 0, len = xmlHttpFactories.length; i < len; i++) {

+			factory = xmlHttpFactories[i];

+			try {

+				xmlHttp = factory();

+				getXmlHttp = factory;

+				return xmlHttp;

+			} catch (e) {

+			}

+		}

+		// If we're here, all factories have failed, so throw an error

+		if (errorHandler) {

+			errorHandler();

+		} else {

+			handleError("getXmlHttp: unable to obtain XMLHttpRequest object");

+		}

+	};

+

+	function isHttpRequestSuccessful(xmlHttp) {

+		return isUndefined(xmlHttp.status) || xmlHttp.status === 0 ||

+			(xmlHttp.status >= 200 && xmlHttp.status < 300) ||

+			xmlHttp.status == 1223 /* Fix for IE */;

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// AjaxAppender

+

+	function AjaxAppender(url) {

+		var appender = this;

+		var isSupported = true;

+		if (!url) {

+			handleError("AjaxAppender: URL must be specified in constructor");

+			isSupported = false;

+		}

+

+		var timed = this.defaults.timed;

+		var waitForResponse = this.defaults.waitForResponse;

+		var batchSize = this.defaults.batchSize;

+		var timerInterval = this.defaults.timerInterval;

+		var requestSuccessCallback = this.defaults.requestSuccessCallback;

+		var failCallback = this.defaults.failCallback;

+		var postVarName = this.defaults.postVarName;

+		var sendAllOnUnload = this.defaults.sendAllOnUnload;

+		var contentType = this.defaults.contentType;

+		var sessionId = null;

+

+		var queuedLoggingEvents = [];

+		var queuedRequests = [];

+		var headers = [];

+		var sending = false;

+		var initialized = false;

+

+		// Configuration methods. The function scope is used to prevent

+		// direct alteration to the appender configuration properties.

+		function checkCanConfigure(configOptionName) {

+			if (initialized) {

+				handleError("AjaxAppender: configuration option '" +

+					configOptionName +

+					"' may not be set after the appender has been initialized");

+				return false;

+			}

+			return true;

+		}

+

+		this.getSessionId = function() { return sessionId; };

+		this.setSessionId = function(sessionIdParam) {

+			sessionId = extractStringFromParam(sessionIdParam, null);

+			this.layout.setCustomField("sessionid", sessionId);

+		};

+

+		this.setLayout = function(layoutParam) {

+			if (checkCanConfigure("layout")) {

+				this.layout = layoutParam;

+				// Set the session id as a custom field on the layout, if not already present

+				if (sessionId !== null) {

+					this.setSessionId(sessionId);

+				}

+			}

+		};

+

+		this.isTimed = function() { return timed; };

+		this.setTimed = function(timedParam) {

+			if (checkCanConfigure("timed")) {

+				timed = bool(timedParam);

+			}

+		};

+

+		this.getTimerInterval = function() { return timerInterval; };

+		this.setTimerInterval = function(timerIntervalParam) {

+			if (checkCanConfigure("timerInterval")) {

+				timerInterval = extractIntFromParam(timerIntervalParam, timerInterval);

+			}

+		};

+

+		this.isWaitForResponse = function() { return waitForResponse; };

+		this.setWaitForResponse = function(waitForResponseParam) {

+			if (checkCanConfigure("waitForResponse")) {

+				waitForResponse = bool(waitForResponseParam);

+			}

+		};

+

+		this.getBatchSize = function() { return batchSize; };

+		this.setBatchSize = function(batchSizeParam) {

+			if (checkCanConfigure("batchSize")) {

+				batchSize = extractIntFromParam(batchSizeParam, batchSize);

+			}

+		};

+

+		this.isSendAllOnUnload = function() { return sendAllOnUnload; };

+		this.setSendAllOnUnload = function(sendAllOnUnloadParam) {

+			if (checkCanConfigure("sendAllOnUnload")) {

+				sendAllOnUnload = extractBooleanFromParam(sendAllOnUnloadParam, sendAllOnUnload);

+			}

+		};

+

+		this.setRequestSuccessCallback = function(requestSuccessCallbackParam) {

+			requestSuccessCallback = extractFunctionFromParam(requestSuccessCallbackParam, requestSuccessCallback);

+		};

+

+		this.setFailCallback = function(failCallbackParam) {

+			failCallback = extractFunctionFromParam(failCallbackParam, failCallback);

+		};

+

+		this.getPostVarName = function() { return postVarName; };

+		this.setPostVarName = function(postVarNameParam) {

+			if (checkCanConfigure("postVarName")) {

+				postVarName = extractStringFromParam(postVarNameParam, postVarName);

+			}

+		};

+

+		this.getHeaders = function() { return headers; };

+		this.addHeader = function(name, value) {

+			if (name.toLowerCase() == "content-type") {

+				contentType = value;

+			} else {

+				headers.push( { name: name, value: value } );

+			}

+		};

+

+		// Internal functions

+		function sendAll() {

+			if (isSupported && enabled) {

+				sending = true;

+				var currentRequestBatch;

+				if (waitForResponse) {

+					// Send the first request then use this function as the callback once

+					// the response comes back

+					if (queuedRequests.length > 0) {

+						currentRequestBatch = queuedRequests.shift();

+						sendRequest(preparePostData(currentRequestBatch), sendAll);

+					} else {

+						sending = false;

+						if (timed) {

+							scheduleSending();

+						}

+					}

+				} else {

+					// Rattle off all the requests without waiting to see the response

+					while ((currentRequestBatch = queuedRequests.shift())) {

+						sendRequest(preparePostData(currentRequestBatch));

+					}

+					sending = false;

+					if (timed) {

+						scheduleSending();

+					}

+				}

+			}

+		}

+

+		this.sendAll = sendAll;

+

+		// Called when the window unloads. At this point we're past caring about

+		// waiting for responses or timers or incomplete batches - everything

+		// must go, now

+		function sendAllRemaining() {

+			var sendingAnything = false;

+			if (isSupported && enabled) {

+				// Create requests for everything left over, batched as normal

+				var actualBatchSize = appender.getLayout().allowBatching() ? batchSize : 1;

+				var currentLoggingEvent;

+				var batchedLoggingEvents = [];

+				while ((currentLoggingEvent = queuedLoggingEvents.shift())) {

+					batchedLoggingEvents.push(currentLoggingEvent);

+					if (queuedLoggingEvents.length >= actualBatchSize) {

+						// Queue this batch of log entries

+						queuedRequests.push(batchedLoggingEvents);

+						batchedLoggingEvents = [];

+					}

+				}

+				// If there's a partially completed batch, add it

+				if (batchedLoggingEvents.length > 0) {

+					queuedRequests.push(batchedLoggingEvents);

+				}

+				sendingAnything = (queuedRequests.length > 0);

+				waitForResponse = false;

+				timed = false;

+				sendAll();

+			}

+			return sendingAnything;

+		}

+

+		this.sendAllRemaining = sendAllRemaining;

+

+		function preparePostData(batchedLoggingEvents) {

+			// Format the logging events

+			var formattedMessages = [];

+			var currentLoggingEvent;

+			var postData = "";

+			while ((currentLoggingEvent = batchedLoggingEvents.shift())) {

+				var currentFormattedMessage = appender.getLayout().format(currentLoggingEvent);

+				if (appender.getLayout().ignoresThrowable()) {

+					currentFormattedMessage += currentLoggingEvent.getThrowableStrRep();

+				}

+				formattedMessages.push(currentFormattedMessage);

+			}

+			// Create the post data string

+			if (batchedLoggingEvents.length == 1) {

+				postData = formattedMessages.join("");

+			} else {

+				postData = appender.getLayout().batchHeader +

+					formattedMessages.join(appender.getLayout().batchSeparator) +

+					appender.getLayout().batchFooter;

+			}

+			if (contentType == appender.defaults.contentType) {

+				postData = appender.getLayout().returnsPostData ? postData :

+					urlEncode(postVarName) + "=" + urlEncode(postData);

+				// Add the layout name to the post data

+				if (postData.length > 0) {

+					postData += "&";

+				}

+				postData += "layout=" + urlEncode(appender.getLayout().toString());

+			}

+			return postData;

+		}

+

+		function scheduleSending() {

+			window.setTimeout(sendAll, timerInterval);

+		}

+

+		function xmlHttpErrorHandler() {

+			var msg = "AjaxAppender: could not create XMLHttpRequest object. AjaxAppender disabled";

+			handleError(msg);

+			isSupported = false;

+			if (failCallback) {

+				failCallback(msg);

+			}

+		}

+

+		function sendRequest(postData, successCallback) {

+			try {

+				var xmlHttp = getXmlHttp(xmlHttpErrorHandler);

+				if (isSupported) {

+					if (xmlHttp.overrideMimeType) {

+						xmlHttp.overrideMimeType(appender.getLayout().getContentType());

+					}

+					xmlHttp.onreadystatechange = function() {

+						if (xmlHttp.readyState == 4) {

+							if (isHttpRequestSuccessful(xmlHttp)) {

+								if (requestSuccessCallback) {

+									requestSuccessCallback(xmlHttp);

+								}

+								if (successCallback) {

+									successCallback(xmlHttp);

+								}

+							} else {

+								var msg = "AjaxAppender.append: XMLHttpRequest request to URL " +

+									url + " returned status code " + xmlHttp.status;

+								handleError(msg);

+								if (failCallback) {

+									failCallback(msg);

+								}

+							}

+							xmlHttp.onreadystatechange = emptyFunction;

+							xmlHttp = null;

+						}

+					};

+					xmlHttp.open("POST", url, true);

+					try {

+						for (var i = 0, header; header = headers[i++]; ) {

+							xmlHttp.setRequestHeader(header.name, header.value);

+						}

+						xmlHttp.setRequestHeader("Content-Type", contentType);

+					} catch (headerEx) {

+						var msg = "AjaxAppender.append: your browser's XMLHttpRequest implementation" +

+							" does not support setRequestHeader, therefore cannot post data. AjaxAppender disabled";

+						handleError(msg);

+						isSupported = false;

+						if (failCallback) {

+							failCallback(msg);

+						}

+						return;

+					}

+					xmlHttp.send(postData);

+				}

+			} catch (ex) {

+				var errMsg = "AjaxAppender.append: error sending log message to " + url;

+				handleError(errMsg, ex);

+				isSupported = false;

+				if (failCallback) {

+					failCallback(errMsg + ". Details: " + getExceptionStringRep(ex));

+				}

+			}

+		}

+

+		this.append = function(loggingEvent) {

+			if (isSupported) {

+				if (!initialized) {

+					init();

+				}

+				queuedLoggingEvents.push(loggingEvent);

+				var actualBatchSize = this.getLayout().allowBatching() ? batchSize : 1;

+

+				if (queuedLoggingEvents.length >= actualBatchSize) {

+					var currentLoggingEvent;

+					var batchedLoggingEvents = [];

+					while ((currentLoggingEvent = queuedLoggingEvents.shift())) {

+						batchedLoggingEvents.push(currentLoggingEvent);

+					}

+					// Queue this batch of log entries

+					queuedRequests.push(batchedLoggingEvents);

+

+					// If using a timer, the queue of requests will be processed by the

+					// timer function, so nothing needs to be done here.

+					if (!timed && (!waitForResponse || (waitForResponse && !sending))) {

+						sendAll();

+					}

+				}

+			}

+		};

+

+		function init() {

+			initialized = true;

+			// Add unload event to send outstanding messages

+			if (sendAllOnUnload) {

+				var oldBeforeUnload = window.onbeforeunload;

+				window.onbeforeunload = function() {

+					if (oldBeforeUnload) {

+						oldBeforeUnload();

+					}

+					if (sendAllRemaining()) {

+						return "Sending log messages";

+					}

+				};

+			}

+			// Start timer

+			if (timed) {

+				scheduleSending();

+			}

+		}

+	}

+

+	AjaxAppender.prototype = new Appender();

+

+	AjaxAppender.prototype.defaults = {

+		waitForResponse: false,

+		timed: false,

+		timerInterval: 1000,

+		batchSize: 1,

+		sendAllOnUnload: false,

+		requestSuccessCallback: null,

+		failCallback: null,

+		postVarName: "data",

+		contentType: "application/x-www-form-urlencoded"

+	};

+

+	AjaxAppender.prototype.layout = new HttpPostDataLayout();

+

+	AjaxAppender.prototype.toString = function() {

+		return "AjaxAppender";

+	};

+

+	log4javascript.AjaxAppender = AjaxAppender;

+

+	/* ---------------------------------------------------------------------- */

+	// Main load

+

+   log4javascript.setDocumentReady = function() {

+       pageLoaded = true;

+       log4javascript.dispatchEvent("load", {});

+   };

+

+    if (window.addEventListener) {

+        window.addEventListener("load", log4javascript.setDocumentReady, false);

+    } else if (window.attachEvent) {

+        window.attachEvent("onload", log4javascript.setDocumentReady);

+    } else {

+        var oldOnload = window.onload;

+        if (typeof window.onload != "function") {

+            window.onload = log4javascript.setDocumentReady;

+        } else {

+            window.onload = function(evt) {

+                if (oldOnload) {

+                    oldOnload(evt);

+                }

+                log4javascript.setDocumentReady();

+            };

+        }

+    }

+

+    // Ensure that the log4javascript object is available in the window. This

+    // is necessary for log4javascript to be available in IE if loaded using

+    // Dojo's module system

+    window.log4javascript = log4javascript;

+

+    return log4javascript;

+})();
\ No newline at end of file
diff --git a/xos/core/static/log4javascript-1.4.6/js/log4javascript_uncompressed.js b/xos/core/static/log4javascript-1.4.6/js/log4javascript_uncompressed.js
new file mode 100644
index 0000000..a644e3b
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/js/log4javascript_uncompressed.js
@@ -0,0 +1,5879 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+/**

+ * log4javascript

+ *

+ * log4javascript is a logging framework for JavaScript based on log4j

+ * for Java. This file contains all core log4javascript code and is the only

+ * file required to use log4javascript, unless you require support for

+ * document.domain, in which case you will also need console.html, which must be

+ * stored in the same directory as the main log4javascript.js file.

+ *

+ * Author: Tim Down <tim@log4javascript.org>

+ * Version: 1.4.6

+ * Edition: log4javascript

+ * Build date: 19 March 2013

+ * Website: http://log4javascript.org

+ */

+

+/* -------------------------------------------------------------------------- */

+// Array-related stuff

+

+// Next three methods are solely for IE5, which is missing them

+if (!Array.prototype.push) {

+	Array.prototype.push = function() {

+		for (var i = 0, len = arguments.length; i < len; i++){

+			this[this.length] = arguments[i];

+		}

+		return this.length;

+	};

+}

+

+if (!Array.prototype.shift) {

+	Array.prototype.shift = function() {

+		if (this.length > 0) {

+			var firstItem = this[0];

+			for (var i = 0, len = this.length - 1; i < len; i++) {

+				this[i] = this[i + 1];

+			}

+			this.length = this.length - 1;

+			return firstItem;

+		}

+	};

+}

+

+if (!Array.prototype.splice) {

+	Array.prototype.splice = function(startIndex, deleteCount) {

+		var itemsAfterDeleted = this.slice(startIndex + deleteCount);

+		var itemsDeleted = this.slice(startIndex, startIndex + deleteCount);

+		this.length = startIndex;

+		// Copy the arguments into a proper Array object

+		var argumentsArray = [];

+		for (var i = 0, len = arguments.length; i < len; i++) {

+			argumentsArray[i] = arguments[i];

+		}

+		var itemsToAppend = (argumentsArray.length > 2) ?

+			itemsAfterDeleted = argumentsArray.slice(2).concat(itemsAfterDeleted) : itemsAfterDeleted;

+		for (i = 0, len = itemsToAppend.length; i < len; i++) {

+			this.push(itemsToAppend[i]);

+		}

+		return itemsDeleted;

+	};

+}

+

+/* -------------------------------------------------------------------------- */

+

+var log4javascript = (function() {

+

+	function isUndefined(obj) {

+		return typeof obj == "undefined";

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// Custom event support

+

+	function EventSupport() {}

+

+	EventSupport.prototype = {

+		eventTypes: [],

+		eventListeners: {},

+		setEventTypes: function(eventTypesParam) {

+			if (eventTypesParam instanceof Array) {

+				this.eventTypes = eventTypesParam;

+				this.eventListeners = {};

+				for (var i = 0, len = this.eventTypes.length; i < len; i++) {

+					this.eventListeners[this.eventTypes[i]] = [];

+				}

+			} else {

+				handleError("log4javascript.EventSupport [" + this + "]: setEventTypes: eventTypes parameter must be an Array");

+			}

+		},

+

+		addEventListener: function(eventType, listener) {

+			if (typeof listener == "function") {

+				if (!array_contains(this.eventTypes, eventType)) {

+					handleError("log4javascript.EventSupport [" + this + "]: addEventListener: no event called '" + eventType + "'");

+				}

+				this.eventListeners[eventType].push(listener);

+			} else {

+				handleError("log4javascript.EventSupport [" + this + "]: addEventListener: listener must be a function");

+			}

+		},

+

+		removeEventListener: function(eventType, listener) {

+			if (typeof listener == "function") {

+				if (!array_contains(this.eventTypes, eventType)) {

+					handleError("log4javascript.EventSupport [" + this + "]: removeEventListener: no event called '" + eventType + "'");

+				}

+				array_remove(this.eventListeners[eventType], listener);

+			} else {

+				handleError("log4javascript.EventSupport [" + this + "]: removeEventListener: listener must be a function");

+			}

+		},

+

+		dispatchEvent: function(eventType, eventArgs) {

+			if (array_contains(this.eventTypes, eventType)) {

+				var listeners = this.eventListeners[eventType];

+				for (var i = 0, len = listeners.length; i < len; i++) {

+					listeners[i](this, eventType, eventArgs);

+				}

+			} else {

+				handleError("log4javascript.EventSupport [" + this + "]: dispatchEvent: no event called '" + eventType + "'");

+			}

+		}

+	};

+

+	/* -------------------------------------------------------------------------- */

+

+	var applicationStartDate = new Date();

+	var uniqueId = "log4javascript_" + applicationStartDate.getTime() + "_" +

+		Math.floor(Math.random() * 100000000);

+	var emptyFunction = function() {};

+	var newLine = "\r\n";

+	var pageLoaded = false;

+

+	// Create main log4javascript object; this will be assigned public properties

+	function Log4JavaScript() {}

+	Log4JavaScript.prototype = new EventSupport();

+

+	log4javascript = new Log4JavaScript();

+	log4javascript.version = "1.4.6";

+	log4javascript.edition = "log4javascript";

+

+	/* -------------------------------------------------------------------------- */

+	// Utility functions

+

+	function toStr(obj) {

+		if (obj && obj.toString) {

+			return obj.toString();

+		} else {

+			return String(obj);

+		}

+	}

+

+	function getExceptionMessage(ex) {

+		if (ex.message) {

+			return ex.message;

+		} else if (ex.description) {

+			return ex.description;

+		} else {

+			return toStr(ex);

+		}

+	}

+

+	// Gets the portion of the URL after the last slash

+	function getUrlFileName(url) {

+		var lastSlashIndex = Math.max(url.lastIndexOf("/"), url.lastIndexOf("\\"));

+		return url.substr(lastSlashIndex + 1);

+	}

+

+	// Returns a nicely formatted representation of an error

+	function getExceptionStringRep(ex) {

+		if (ex) {

+			var exStr = "Exception: " + getExceptionMessage(ex);

+			try {

+				if (ex.lineNumber) {

+					exStr += " on line number " + ex.lineNumber;

+				}

+				if (ex.fileName) {

+					exStr += " in file " + getUrlFileName(ex.fileName);

+				}

+			} catch (localEx) {

+				logLog.warn("Unable to obtain file and line information for error");

+			}

+			if (showStackTraces && ex.stack) {

+				exStr += newLine + "Stack trace:" + newLine + ex.stack;

+			}

+			return exStr;

+		}

+		return null;

+	}

+

+	function bool(obj) {

+		return Boolean(obj);

+	}

+

+	function trim(str) {

+		return str.replace(/^\s+/, "").replace(/\s+$/, "");

+	}

+

+	function splitIntoLines(text) {

+		// Ensure all line breaks are \n only

+		var text2 = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");

+		return text2.split("\n");

+	}

+

+	var urlEncode = (typeof window.encodeURIComponent != "undefined") ?

+		function(str) {

+			return encodeURIComponent(str);

+		}: 

+		function(str) {

+			return escape(str).replace(/\+/g, "%2B").replace(/"/g, "%22").replace(/'/g, "%27").replace(/\//g, "%2F").replace(/=/g, "%3D");

+		};

+

+	var urlDecode = (typeof window.decodeURIComponent != "undefined") ?

+		function(str) {

+			return decodeURIComponent(str);

+		}: 

+		function(str) {

+			return unescape(str).replace(/%2B/g, "+").replace(/%22/g, "\"").replace(/%27/g, "'").replace(/%2F/g, "/").replace(/%3D/g, "=");

+		};

+

+	function array_remove(arr, val) {

+		var index = -1;

+		for (var i = 0, len = arr.length; i < len; i++) {

+			if (arr[i] === val) {

+				index = i;

+				break;

+			}

+		}

+		if (index >= 0) {

+			arr.splice(index, 1);

+			return true;

+		} else {

+			return false;

+		}

+	}

+

+	function array_contains(arr, val) {

+		for(var i = 0, len = arr.length; i < len; i++) {

+			if (arr[i] == val) {

+				return true;

+			}

+		}

+		return false;

+	}

+

+	function extractBooleanFromParam(param, defaultValue) {

+		if (isUndefined(param)) {

+			return defaultValue;

+		} else {

+			return bool(param);

+		}

+	}

+

+	function extractStringFromParam(param, defaultValue) {

+		if (isUndefined(param)) {

+			return defaultValue;

+		} else {

+			return String(param);

+		}

+	}

+

+	function extractIntFromParam(param, defaultValue) {

+		if (isUndefined(param)) {

+			return defaultValue;

+		} else {

+			try {

+				var value = parseInt(param, 10);

+				return isNaN(value) ? defaultValue : value;

+			} catch (ex) {

+				logLog.warn("Invalid int param " + param, ex);

+				return defaultValue;

+			}

+		}

+	}

+

+	function extractFunctionFromParam(param, defaultValue) {

+		if (typeof param == "function") {

+			return param;

+		} else {

+			return defaultValue;

+		}

+	}

+

+	function isError(err) {

+		return (err instanceof Error);

+	}

+

+	if (!Function.prototype.apply){

+		Function.prototype.apply = function(obj, args) {

+			var methodName = "__apply__";

+			if (typeof obj[methodName] != "undefined") {

+				methodName += String(Math.random()).substr(2);

+			}

+			obj[methodName] = this;

+

+			var argsStrings = [];

+			for (var i = 0, len = args.length; i < len; i++) {

+				argsStrings[i] = "args[" + i + "]";

+			}

+			var script = "obj." + methodName + "(" + argsStrings.join(",") + ")";

+			var returnValue = eval(script);

+			delete obj[methodName];

+			return returnValue;

+		};

+	}

+

+	if (!Function.prototype.call){

+		Function.prototype.call = function(obj) {

+			var args = [];

+			for (var i = 1, len = arguments.length; i < len; i++) {

+				args[i - 1] = arguments[i];

+			}

+			return this.apply(obj, args);

+		};

+	}

+

+	function getListenersPropertyName(eventName) {

+		return "__log4javascript_listeners__" + eventName;

+	}

+

+	function addEvent(node, eventName, listener, useCapture, win) {

+		win = win ? win : window;

+		if (node.addEventListener) {

+			node.addEventListener(eventName, listener, useCapture);

+		} else if (node.attachEvent) {

+			node.attachEvent("on" + eventName, listener);

+		} else {

+			var propertyName = getListenersPropertyName(eventName);

+			if (!node[propertyName]) {

+				node[propertyName] = [];

+				// Set event handler

+				node["on" + eventName] = function(evt) {

+					evt = getEvent(evt, win);

+					var listenersPropertyName = getListenersPropertyName(eventName);

+

+					// Clone the array of listeners to leave the original untouched

+					var listeners = this[listenersPropertyName].concat([]);

+					var currentListener;

+

+					// Call each listener in turn

+					while ((currentListener = listeners.shift())) {

+						currentListener.call(this, evt);

+					}

+				};

+			}

+			node[propertyName].push(listener);

+		}

+	}

+

+	function removeEvent(node, eventName, listener, useCapture) {

+		if (node.removeEventListener) {

+			node.removeEventListener(eventName, listener, useCapture);

+		} else if (node.detachEvent) {

+			node.detachEvent("on" + eventName, listener);

+		} else {

+			var propertyName = getListenersPropertyName(eventName);

+			if (node[propertyName]) {

+				array_remove(node[propertyName], listener);

+			}

+		}

+	}

+

+	function getEvent(evt, win) {

+		win = win ? win : window;

+		return evt ? evt : win.event;

+	}

+

+	function stopEventPropagation(evt) {

+		if (evt.stopPropagation) {

+			evt.stopPropagation();

+		} else if (typeof evt.cancelBubble != "undefined") {

+			evt.cancelBubble = true;

+		}

+		evt.returnValue = false;

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// Simple logging for log4javascript itself

+

+	var logLog = {

+		quietMode: false,

+

+		debugMessages: [],

+

+		setQuietMode: function(quietMode) {

+			this.quietMode = bool(quietMode);

+		},

+

+		numberOfErrors: 0,

+

+		alertAllErrors: false,

+

+		setAlertAllErrors: function(alertAllErrors) {

+			this.alertAllErrors = alertAllErrors;

+		},

+

+		debug: function(message) {

+			this.debugMessages.push(message);

+		},

+

+		displayDebug: function() {

+			alert(this.debugMessages.join(newLine));

+		},

+

+		warn: function(message, exception) {

+		},

+

+		error: function(message, exception) {

+			if (++this.numberOfErrors == 1 || this.alertAllErrors) {

+				if (!this.quietMode) {

+					var alertMessage = "log4javascript error: " + message;

+					if (exception) {

+						alertMessage += newLine + newLine + "Original error: " + getExceptionStringRep(exception);

+					}

+					alert(alertMessage);

+				}

+			}

+		}

+	};

+	log4javascript.logLog = logLog;

+

+	log4javascript.setEventTypes(["load", "error"]);

+

+	function handleError(message, exception) {

+		logLog.error(message, exception);

+		log4javascript.dispatchEvent("error", { "message": message, "exception": exception });

+	}

+

+	log4javascript.handleError = handleError;

+

+	/* ---------------------------------------------------------------------- */

+

+	var enabled = !((typeof log4javascript_disabled != "undefined") &&

+					log4javascript_disabled);

+

+	log4javascript.setEnabled = function(enable) {

+		enabled = bool(enable);

+	};

+

+	log4javascript.isEnabled = function() {

+		return enabled;

+	};

+

+	var useTimeStampsInMilliseconds = true;

+

+	log4javascript.setTimeStampsInMilliseconds = function(timeStampsInMilliseconds) {

+		useTimeStampsInMilliseconds = bool(timeStampsInMilliseconds);

+	};

+

+	log4javascript.isTimeStampsInMilliseconds = function() {

+		return useTimeStampsInMilliseconds;

+	};

+	

+

+	// This evaluates the given expression in the current scope, thus allowing

+	// scripts to access private variables. Particularly useful for testing

+	log4javascript.evalInScope = function(expr) {

+		return eval(expr);

+	};

+

+	var showStackTraces = false;

+

+	log4javascript.setShowStackTraces = function(show) {

+		showStackTraces = bool(show);

+	};

+

+	/* ---------------------------------------------------------------------- */

+	// Levels

+

+	var Level = function(level, name) {

+		this.level = level;

+		this.name = name;

+	};

+

+	Level.prototype = {

+		toString: function() {

+			return this.name;

+		},

+		equals: function(level) {

+			return this.level == level.level;

+		},

+		isGreaterOrEqual: function(level) {

+			return this.level >= level.level;

+		}

+	};

+

+	Level.ALL = new Level(Number.MIN_VALUE, "ALL");

+	Level.TRACE = new Level(10000, "TRACE");

+	Level.DEBUG = new Level(20000, "DEBUG");

+	Level.INFO = new Level(30000, "INFO");

+	Level.WARN = new Level(40000, "WARN");

+	Level.ERROR = new Level(50000, "ERROR");

+	Level.FATAL = new Level(60000, "FATAL");

+	Level.OFF = new Level(Number.MAX_VALUE, "OFF");

+

+	log4javascript.Level = Level;

+

+	/* ---------------------------------------------------------------------- */

+	// Timers

+

+	function Timer(name, level) {

+		this.name = name;

+		this.level = isUndefined(level) ? Level.INFO : level;

+		this.start = new Date();

+	}

+

+	Timer.prototype.getElapsedTime = function() {

+		return new Date().getTime() - this.start.getTime();

+	};

+

+	/* ---------------------------------------------------------------------- */

+	// Loggers

+

+	var anonymousLoggerName = "[anonymous]";

+	var defaultLoggerName = "[default]";

+	var nullLoggerName = "[null]";

+	var rootLoggerName = "root";

+

+	function Logger(name) {

+		this.name = name;

+		this.parent = null;

+		this.children = [];

+

+		var appenders = [];

+		var loggerLevel = null;

+		var isRoot = (this.name === rootLoggerName);

+		var isNull = (this.name === nullLoggerName);

+

+		var appenderCache = null;

+		var appenderCacheInvalidated = false;

+		

+		this.addChild = function(childLogger) {

+			this.children.push(childLogger);

+			childLogger.parent = this;

+			childLogger.invalidateAppenderCache();

+		};

+

+		// Additivity

+		var additive = true;

+		this.getAdditivity = function() {

+			return additive;

+		};

+

+		this.setAdditivity = function(additivity) {

+			var valueChanged = (additive != additivity);

+			additive = additivity;

+			if (valueChanged) {

+				this.invalidateAppenderCache();

+			}

+		};

+

+		// Create methods that use the appenders variable in this scope

+		this.addAppender = function(appender) {

+			if (isNull) {

+				handleError("Logger.addAppender: you may not add an appender to the null logger");

+			} else {

+				if (appender instanceof log4javascript.Appender) {

+					if (!array_contains(appenders, appender)) {

+						appenders.push(appender);

+						appender.setAddedToLogger(this);

+						this.invalidateAppenderCache();

+					}

+				} else {

+					handleError("Logger.addAppender: appender supplied ('" +

+						toStr(appender) + "') is not a subclass of Appender");

+				}

+			}

+		};

+

+		this.removeAppender = function(appender) {

+			array_remove(appenders, appender);

+			appender.setRemovedFromLogger(this);

+			this.invalidateAppenderCache();

+		};

+

+		this.removeAllAppenders = function() {

+			var appenderCount = appenders.length;

+			if (appenderCount > 0) {

+				for (var i = 0; i < appenderCount; i++) {

+					appenders[i].setRemovedFromLogger(this);

+				}

+				appenders.length = 0;

+				this.invalidateAppenderCache();

+			}

+		};

+

+		this.getEffectiveAppenders = function() {

+			if (appenderCache === null || appenderCacheInvalidated) {

+				// Build appender cache

+				var parentEffectiveAppenders = (isRoot || !this.getAdditivity()) ?

+					[] : this.parent.getEffectiveAppenders();

+				appenderCache = parentEffectiveAppenders.concat(appenders);

+				appenderCacheInvalidated = false;

+			}

+			return appenderCache;

+		};

+		

+		this.invalidateAppenderCache = function() {

+			appenderCacheInvalidated = true;

+			for (var i = 0, len = this.children.length; i < len; i++) {

+				this.children[i].invalidateAppenderCache();

+			}

+		};

+

+		this.log = function(level, params) {

+			if (enabled && level.isGreaterOrEqual(this.getEffectiveLevel())) {

+				// Check whether last param is an exception

+				var exception;

+				var finalParamIndex = params.length - 1;

+				var lastParam = params[finalParamIndex];

+				if (params.length > 1 && isError(lastParam)) {

+					exception = lastParam;

+					finalParamIndex--;

+				}

+

+				// Construct genuine array for the params

+				var messages = [];

+				for (var i = 0; i <= finalParamIndex; i++) {

+					messages[i] = params[i];

+				}

+

+				var loggingEvent = new LoggingEvent(

+					this, new Date(), level, messages, exception);

+

+				this.callAppenders(loggingEvent);

+			}

+		};

+

+		this.callAppenders = function(loggingEvent) {

+			var effectiveAppenders = this.getEffectiveAppenders();

+			for (var i = 0, len = effectiveAppenders.length; i < len; i++) {

+				effectiveAppenders[i].doAppend(loggingEvent);

+			}

+		};

+

+		this.setLevel = function(level) {

+			// Having a level of null on the root logger would be very bad.

+			if (isRoot && level === null) {

+				handleError("Logger.setLevel: you cannot set the level of the root logger to null");

+			} else if (level instanceof Level) {

+				loggerLevel = level;

+			} else {

+				handleError("Logger.setLevel: level supplied to logger " +

+					this.name + " is not an instance of log4javascript.Level");

+			}

+		};

+

+		this.getLevel = function() {

+			return loggerLevel;

+		};

+

+		this.getEffectiveLevel = function() {

+			for (var logger = this; logger !== null; logger = logger.parent) {

+				var level = logger.getLevel();

+				if (level !== null) {

+					return level;

+				}

+			}

+		};

+

+		this.group = function(name, initiallyExpanded) {

+			if (enabled) {

+				var effectiveAppenders = this.getEffectiveAppenders();

+				for (var i = 0, len = effectiveAppenders.length; i < len; i++) {

+					effectiveAppenders[i].group(name, initiallyExpanded);

+				}

+			}

+		};

+

+		this.groupEnd = function() {

+			if (enabled) {

+				var effectiveAppenders = this.getEffectiveAppenders();

+				for (var i = 0, len = effectiveAppenders.length; i < len; i++) {

+					effectiveAppenders[i].groupEnd();

+				}

+			}

+		};

+

+		var timers = {};

+

+		this.time = function(name, level) {

+			if (enabled) {

+				if (isUndefined(name)) {

+					handleError("Logger.time: a name for the timer must be supplied");

+				} else if (level && !(level instanceof Level)) {

+					handleError("Logger.time: level supplied to timer " +

+						name + " is not an instance of log4javascript.Level");

+				} else {

+					timers[name] = new Timer(name, level);

+				}

+			}

+		};

+

+		this.timeEnd = function(name) {

+			if (enabled) {

+				if (isUndefined(name)) {

+					handleError("Logger.timeEnd: a name for the timer must be supplied");

+				} else if (timers[name]) {

+					var timer = timers[name];

+					var milliseconds = timer.getElapsedTime();

+					this.log(timer.level, ["Timer " + toStr(name) + " completed in " + milliseconds + "ms"]);

+					delete timers[name];

+				} else {

+					logLog.warn("Logger.timeEnd: no timer found with name " + name);

+				}

+			}

+		};

+

+		this.assert = function(expr) {

+			if (enabled && !expr) {

+				var args = [];

+				for (var i = 1, len = arguments.length; i < len; i++) {

+					args.push(arguments[i]);

+				}

+				args = (args.length > 0) ? args : ["Assertion Failure"];

+				args.push(newLine);

+				args.push(expr);

+				this.log(Level.ERROR, args);

+			}

+		};

+

+		this.toString = function() {

+			return "Logger[" + this.name + "]";

+		};

+	}

+

+	Logger.prototype = {

+		trace: function() {

+			this.log(Level.TRACE, arguments);

+		},

+

+		debug: function() {

+			this.log(Level.DEBUG, arguments);

+		},

+

+		info: function() {

+			this.log(Level.INFO, arguments);

+		},

+

+		warn: function() {

+			this.log(Level.WARN, arguments);

+		},

+

+		error: function() {

+			this.log(Level.ERROR, arguments);

+		},

+

+		fatal: function() {

+			this.log(Level.FATAL, arguments);

+		},

+

+		isEnabledFor: function(level) {

+			return level.isGreaterOrEqual(this.getEffectiveLevel());

+		},

+

+		isTraceEnabled: function() {

+			return this.isEnabledFor(Level.TRACE);

+		},

+

+		isDebugEnabled: function() {

+			return this.isEnabledFor(Level.DEBUG);

+		},

+

+		isInfoEnabled: function() {

+			return this.isEnabledFor(Level.INFO);

+		},

+

+		isWarnEnabled: function() {

+			return this.isEnabledFor(Level.WARN);

+		},

+

+		isErrorEnabled: function() {

+			return this.isEnabledFor(Level.ERROR);

+		},

+

+		isFatalEnabled: function() {

+			return this.isEnabledFor(Level.FATAL);

+		}

+	};

+

+	Logger.prototype.trace.isEntryPoint = true;

+	Logger.prototype.debug.isEntryPoint = true;

+	Logger.prototype.info.isEntryPoint = true;

+	Logger.prototype.warn.isEntryPoint = true;

+	Logger.prototype.error.isEntryPoint = true;

+	Logger.prototype.fatal.isEntryPoint = true;

+

+	/* ---------------------------------------------------------------------- */

+	// Logger access methods

+

+	// Hashtable of loggers keyed by logger name

+	var loggers = {};

+	var loggerNames = [];

+

+	var ROOT_LOGGER_DEFAULT_LEVEL = Level.DEBUG;

+	var rootLogger = new Logger(rootLoggerName);

+	rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);

+

+	log4javascript.getRootLogger = function() {

+		return rootLogger;

+	};

+

+	log4javascript.getLogger = function(loggerName) {

+		// Use default logger if loggerName is not specified or invalid

+		if (!(typeof loggerName == "string")) {

+			loggerName = anonymousLoggerName;

+			logLog.warn("log4javascript.getLogger: non-string logger name "	+

+				toStr(loggerName) + " supplied, returning anonymous logger");

+		}

+

+		// Do not allow retrieval of the root logger by name

+		if (loggerName == rootLoggerName) {

+			handleError("log4javascript.getLogger: root logger may not be obtained by name");

+		}

+

+		// Create the logger for this name if it doesn't already exist

+		if (!loggers[loggerName]) {

+			var logger = new Logger(loggerName);

+			loggers[loggerName] = logger;

+			loggerNames.push(loggerName);

+

+			// Set up parent logger, if it doesn't exist

+			var lastDotIndex = loggerName.lastIndexOf(".");

+			var parentLogger;

+			if (lastDotIndex > -1) {

+				var parentLoggerName = loggerName.substring(0, lastDotIndex);

+				parentLogger = log4javascript.getLogger(parentLoggerName); // Recursively sets up grandparents etc.

+			} else {

+				parentLogger = rootLogger;

+			}

+			parentLogger.addChild(logger);

+		}

+		return loggers[loggerName];

+	};

+

+	var defaultLogger = null;

+	log4javascript.getDefaultLogger = function() {

+		if (!defaultLogger) {

+			defaultLogger = log4javascript.getLogger(defaultLoggerName);

+			var a = new log4javascript.PopUpAppender();

+			defaultLogger.addAppender(a);

+		}

+		return defaultLogger;

+	};

+

+	var nullLogger = null;

+	log4javascript.getNullLogger = function() {

+		if (!nullLogger) {

+			nullLogger = new Logger(nullLoggerName);

+			nullLogger.setLevel(Level.OFF);

+		}

+		return nullLogger;

+	};

+

+	// Destroys all loggers

+	log4javascript.resetConfiguration = function() {

+		rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);

+		loggers = {};

+	};

+

+	/* ---------------------------------------------------------------------- */

+	// Logging events

+

+	var LoggingEvent = function(logger, timeStamp, level, messages,

+			exception) {

+		this.logger = logger;

+		this.timeStamp = timeStamp;

+		this.timeStampInMilliseconds = timeStamp.getTime();

+		this.timeStampInSeconds = Math.floor(this.timeStampInMilliseconds / 1000);

+		this.milliseconds = this.timeStamp.getMilliseconds();

+		this.level = level;

+		this.messages = messages;

+		this.exception = exception;

+	};

+

+	LoggingEvent.prototype = {

+		getThrowableStrRep: function() {

+			return this.exception ?

+				getExceptionStringRep(this.exception) : "";

+		},

+		getCombinedMessages: function() {

+			return (this.messages.length == 1) ? this.messages[0] :

+				   this.messages.join(newLine);

+		},

+		toString: function() {

+			return "LoggingEvent[" + this.level + "]";

+		}

+	};

+

+	log4javascript.LoggingEvent = LoggingEvent;

+

+	/* ---------------------------------------------------------------------- */

+	// Layout prototype

+

+	var Layout = function() {

+	};

+

+	Layout.prototype = {

+		defaults: {

+			loggerKey: "logger",

+			timeStampKey: "timestamp",

+			millisecondsKey: "milliseconds",

+			levelKey: "level",

+			messageKey: "message",

+			exceptionKey: "exception",

+			urlKey: "url"

+		},

+		loggerKey: "logger",

+		timeStampKey: "timestamp",

+		millisecondsKey: "milliseconds",

+		levelKey: "level",

+		messageKey: "message",

+		exceptionKey: "exception",

+		urlKey: "url",

+		batchHeader: "",

+		batchFooter: "",

+		batchSeparator: "",

+		returnsPostData: false,

+		overrideTimeStampsSetting: false,

+		useTimeStampsInMilliseconds: null,

+

+		format: function() {

+			handleError("Layout.format: layout supplied has no format() method");

+		},

+

+		ignoresThrowable: function() {

+			handleError("Layout.ignoresThrowable: layout supplied has no ignoresThrowable() method");

+		},

+

+		getContentType: function() {

+			return "text/plain";

+		},

+

+		allowBatching: function() {

+			return true;

+		},

+

+		setTimeStampsInMilliseconds: function(timeStampsInMilliseconds) {

+			this.overrideTimeStampsSetting = true;

+			this.useTimeStampsInMilliseconds = bool(timeStampsInMilliseconds);

+		},

+

+		isTimeStampsInMilliseconds: function() {

+			return this.overrideTimeStampsSetting ?

+				this.useTimeStampsInMilliseconds : useTimeStampsInMilliseconds;

+		},

+

+		getTimeStampValue: function(loggingEvent) {

+			return this.isTimeStampsInMilliseconds() ?

+				loggingEvent.timeStampInMilliseconds : loggingEvent.timeStampInSeconds;

+		},

+

+		getDataValues: function(loggingEvent, combineMessages) {

+			var dataValues = [

+				[this.loggerKey, loggingEvent.logger.name],

+				[this.timeStampKey, this.getTimeStampValue(loggingEvent)],

+				[this.levelKey, loggingEvent.level.name],

+				[this.urlKey, window.location.href],

+				[this.messageKey, combineMessages ? loggingEvent.getCombinedMessages() : loggingEvent.messages]

+			];

+			if (!this.isTimeStampsInMilliseconds()) {

+				dataValues.push([this.millisecondsKey, loggingEvent.milliseconds]);

+			}

+			if (loggingEvent.exception) {

+				dataValues.push([this.exceptionKey, getExceptionStringRep(loggingEvent.exception)]);

+			}

+			if (this.hasCustomFields()) {

+				for (var i = 0, len = this.customFields.length; i < len; i++) {

+					var val = this.customFields[i].value;

+

+					// Check if the value is a function. If so, execute it, passing it the

+					// current layout and the logging event

+					if (typeof val === "function") {

+						val = val(this, loggingEvent);

+					}

+					dataValues.push([this.customFields[i].name, val]);

+				}

+			}

+			return dataValues;

+		},

+

+		setKeys: function(loggerKey, timeStampKey, levelKey, messageKey,

+				exceptionKey, urlKey, millisecondsKey) {

+			this.loggerKey = extractStringFromParam(loggerKey, this.defaults.loggerKey);

+			this.timeStampKey = extractStringFromParam(timeStampKey, this.defaults.timeStampKey);

+			this.levelKey = extractStringFromParam(levelKey, this.defaults.levelKey);

+			this.messageKey = extractStringFromParam(messageKey, this.defaults.messageKey);

+			this.exceptionKey = extractStringFromParam(exceptionKey, this.defaults.exceptionKey);

+			this.urlKey = extractStringFromParam(urlKey, this.defaults.urlKey);

+			this.millisecondsKey = extractStringFromParam(millisecondsKey, this.defaults.millisecondsKey);

+		},

+

+		setCustomField: function(name, value) {

+			var fieldUpdated = false;

+			for (var i = 0, len = this.customFields.length; i < len; i++) {

+				if (this.customFields[i].name === name) {

+					this.customFields[i].value = value;

+					fieldUpdated = true;

+				}

+			}

+			if (!fieldUpdated) {

+				this.customFields.push({"name": name, "value": value});

+			}

+		},

+

+		hasCustomFields: function() {

+			return (this.customFields.length > 0);

+		},

+

+		toString: function() {

+			handleError("Layout.toString: all layouts must override this method");

+		}

+	};

+

+	log4javascript.Layout = Layout;

+

+	/* ---------------------------------------------------------------------- */

+	// Appender prototype

+

+	var Appender = function() {};

+

+	Appender.prototype = new EventSupport();

+

+	Appender.prototype.layout = new PatternLayout();

+	Appender.prototype.threshold = Level.ALL;

+	Appender.prototype.loggers = [];

+

+	// Performs threshold checks before delegating actual logging to the

+	// subclass's specific append method.

+	Appender.prototype.doAppend = function(loggingEvent) {

+		if (enabled && loggingEvent.level.level >= this.threshold.level) {

+			this.append(loggingEvent);

+		}

+	};

+

+	Appender.prototype.append = function(loggingEvent) {};

+

+	Appender.prototype.setLayout = function(layout) {

+		if (layout instanceof Layout) {

+			this.layout = layout;

+		} else {

+			handleError("Appender.setLayout: layout supplied to " +

+				this.toString() + " is not a subclass of Layout");

+		}

+	};

+

+	Appender.prototype.getLayout = function() {

+		return this.layout;

+	};

+

+	Appender.prototype.setThreshold = function(threshold) {

+		if (threshold instanceof Level) {

+			this.threshold = threshold;

+		} else {

+			handleError("Appender.setThreshold: threshold supplied to " +

+				this.toString() + " is not a subclass of Level");

+		}

+	};

+

+	Appender.prototype.getThreshold = function() {

+		return this.threshold;

+	};

+

+	Appender.prototype.setAddedToLogger = function(logger) {

+		this.loggers.push(logger);

+	};

+

+	Appender.prototype.setRemovedFromLogger = function(logger) {

+		array_remove(this.loggers, logger);

+	};

+

+	Appender.prototype.group = emptyFunction;

+	Appender.prototype.groupEnd = emptyFunction;

+

+	Appender.prototype.toString = function() {

+		handleError("Appender.toString: all appenders must override this method");

+	};

+

+	log4javascript.Appender = Appender;

+

+	/* ---------------------------------------------------------------------- */

+	// SimpleLayout 

+

+	function SimpleLayout() {

+		this.customFields = [];

+	}

+

+	SimpleLayout.prototype = new Layout();

+

+	SimpleLayout.prototype.format = function(loggingEvent) {

+		return loggingEvent.level.name + " - " + loggingEvent.getCombinedMessages();

+	};

+

+	SimpleLayout.prototype.ignoresThrowable = function() {

+	    return true;

+	};

+

+	SimpleLayout.prototype.toString = function() {

+	    return "SimpleLayout";

+	};

+

+	log4javascript.SimpleLayout = SimpleLayout;

+	/* ----------------------------------------------------------------------- */

+	// NullLayout 

+

+	function NullLayout() {

+		this.customFields = [];

+	}

+

+	NullLayout.prototype = new Layout();

+

+	NullLayout.prototype.format = function(loggingEvent) {

+		return loggingEvent.messages;

+	};

+

+	NullLayout.prototype.ignoresThrowable = function() {

+	    return true;

+	};

+

+	NullLayout.prototype.toString = function() {

+	    return "NullLayout";

+	};

+

+	log4javascript.NullLayout = NullLayout;

+/* ---------------------------------------------------------------------- */

+	// XmlLayout

+

+	function XmlLayout(combineMessages) {

+		this.combineMessages = extractBooleanFromParam(combineMessages, true);

+		this.customFields = [];

+	}

+

+	XmlLayout.prototype = new Layout();

+

+	XmlLayout.prototype.isCombinedMessages = function() {

+		return this.combineMessages;

+	};

+

+	XmlLayout.prototype.getContentType = function() {

+		return "text/xml";

+	};

+

+	XmlLayout.prototype.escapeCdata = function(str) {

+		return str.replace(/\]\]>/, "]]>]]&gt;<![CDATA[");

+	};

+

+	XmlLayout.prototype.format = function(loggingEvent) {

+		var layout = this;

+		var i, len;

+		function formatMessage(message) {

+			message = (typeof message === "string") ? message : toStr(message);

+			return "<log4javascript:message><![CDATA[" +

+				layout.escapeCdata(message) + "]]></log4javascript:message>";

+		}

+

+		var str = "<log4javascript:event logger=\"" + loggingEvent.logger.name +

+			"\" timestamp=\"" + this.getTimeStampValue(loggingEvent) + "\"";

+		if (!this.isTimeStampsInMilliseconds()) {

+			str += " milliseconds=\"" + loggingEvent.milliseconds + "\"";

+		}

+		str += " level=\"" + loggingEvent.level.name + "\">" + newLine;

+		if (this.combineMessages) {

+			str += formatMessage(loggingEvent.getCombinedMessages());

+		} else {

+			str += "<log4javascript:messages>" + newLine;

+			for (i = 0, len = loggingEvent.messages.length; i < len; i++) {

+				str += formatMessage(loggingEvent.messages[i]) + newLine;

+			}

+			str += "</log4javascript:messages>" + newLine;

+		}

+		if (this.hasCustomFields()) {

+			for (i = 0, len = this.customFields.length; i < len; i++) {

+				str += "<log4javascript:customfield name=\"" +

+					this.customFields[i].name + "\"><![CDATA[" +

+					this.customFields[i].value.toString() +

+					"]]></log4javascript:customfield>" + newLine;

+			}

+		}

+		if (loggingEvent.exception) {

+			str += "<log4javascript:exception><![CDATA[" +

+				getExceptionStringRep(loggingEvent.exception) +

+				"]]></log4javascript:exception>" + newLine;

+		}

+		str += "</log4javascript:event>" + newLine + newLine;

+		return str;

+	};

+

+	XmlLayout.prototype.ignoresThrowable = function() {

+	    return false;

+	};

+

+	XmlLayout.prototype.toString = function() {

+	    return "XmlLayout";

+	};

+

+	log4javascript.XmlLayout = XmlLayout;

+	/* ---------------------------------------------------------------------- */

+	// JsonLayout related

+

+	function escapeNewLines(str) {

+		return str.replace(/\r\n|\r|\n/g, "\\r\\n");

+	}

+

+	function JsonLayout(readable, combineMessages) {

+		this.readable = extractBooleanFromParam(readable, false);

+		this.combineMessages = extractBooleanFromParam(combineMessages, true);

+		this.batchHeader = this.readable ? "[" + newLine : "[";

+		this.batchFooter = this.readable ? "]" + newLine : "]";

+		this.batchSeparator = this.readable ? "," + newLine : ",";

+		this.setKeys();

+		this.colon = this.readable ? ": " : ":";

+		this.tab = this.readable ? "\t" : "";

+		this.lineBreak = this.readable ? newLine : "";

+		this.customFields = [];

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// JsonLayout

+

+	JsonLayout.prototype = new Layout();

+

+	JsonLayout.prototype.isReadable = function() {

+		return this.readable;

+	};

+

+	JsonLayout.prototype.isCombinedMessages = function() {

+		return this.combineMessages;

+	};

+

+    JsonLayout.prototype.format = function(loggingEvent) {

+        var layout = this;

+        var dataValues = this.getDataValues(loggingEvent, this.combineMessages);

+        var str = "{" + this.lineBreak;

+        var i, len;

+

+        function formatValue(val, prefix, expand) {

+            // Check the type of the data value to decide whether quotation marks

+            // or expansion are required

+            var formattedValue;

+            var valType = typeof val;

+            if (val instanceof Date) {

+                formattedValue = String(val.getTime());

+            } else if (expand && (val instanceof Array)) {

+                formattedValue = "[" + layout.lineBreak;

+                for (var i = 0, len = val.length; i < len; i++) {

+                    var childPrefix = prefix + layout.tab;

+                    formattedValue += childPrefix + formatValue(val[i], childPrefix, false);

+                    if (i < val.length - 1) {

+                        formattedValue += ",";

+                    }

+                    formattedValue += layout.lineBreak;

+                }

+                formattedValue += prefix + "]";

+            } else if (valType !== "number" && valType !== "boolean") {

+                formattedValue = "\"" + escapeNewLines(toStr(val).replace(/\"/g, "\\\"")) + "\"";

+            } else {

+                formattedValue = val;

+            }

+            return formattedValue;

+        }

+

+        for (i = 0, len = dataValues.length - 1; i <= len; i++) {

+            str += this.tab + "\"" + dataValues[i][0] + "\"" + this.colon + formatValue(dataValues[i][1], this.tab, true);

+            if (i < len) {

+                str += ",";

+            }

+            str += this.lineBreak;

+        }

+

+        str += "}" + this.lineBreak;

+        return str;

+    };

+

+	JsonLayout.prototype.ignoresThrowable = function() {

+	    return false;

+	};

+

+	JsonLayout.prototype.toString = function() {

+	    return "JsonLayout";

+	};

+

+	JsonLayout.prototype.getContentType = function() {

+		return "application/json";

+	};

+

+	log4javascript.JsonLayout = JsonLayout;

+	/* ---------------------------------------------------------------------- */

+	// HttpPostDataLayout

+

+	function HttpPostDataLayout() {

+		this.setKeys();

+		this.customFields = [];

+		this.returnsPostData = true;

+	}

+

+	HttpPostDataLayout.prototype = new Layout();

+

+	// Disable batching

+	HttpPostDataLayout.prototype.allowBatching = function() {

+		return false;

+	};

+

+	HttpPostDataLayout.prototype.format = function(loggingEvent) {

+		var dataValues = this.getDataValues(loggingEvent);

+		var queryBits = [];

+		for (var i = 0, len = dataValues.length; i < len; i++) {

+			var val = (dataValues[i][1] instanceof Date) ?

+				String(dataValues[i][1].getTime()) : dataValues[i][1];

+			queryBits.push(urlEncode(dataValues[i][0]) + "=" + urlEncode(val));

+		}

+		return queryBits.join("&");

+	};

+

+	HttpPostDataLayout.prototype.ignoresThrowable = function(loggingEvent) {

+	    return false;

+	};

+

+	HttpPostDataLayout.prototype.toString = function() {

+	    return "HttpPostDataLayout";

+	};

+

+	log4javascript.HttpPostDataLayout = HttpPostDataLayout;

+	/* ---------------------------------------------------------------------- */

+	// formatObjectExpansion

+

+	function formatObjectExpansion(obj, depth, indentation) {

+		var objectsExpanded = [];

+

+		function doFormat(obj, depth, indentation) {

+			var i, j, len, childDepth, childIndentation, childLines, expansion,

+				childExpansion;

+

+			if (!indentation) {

+				indentation = "";

+			}

+

+			function formatString(text) {

+				var lines = splitIntoLines(text);

+				for (var j = 1, jLen = lines.length; j < jLen; j++) {

+					lines[j] = indentation + lines[j];

+				}

+				return lines.join(newLine);

+			}

+

+			if (obj === null) {

+				return "null";

+			} else if (typeof obj == "undefined") {

+				return "undefined";

+			} else if (typeof obj == "string") {

+				return formatString(obj);

+			} else if (typeof obj == "object" && array_contains(objectsExpanded, obj)) {

+				try {

+					expansion = toStr(obj);

+				} catch (ex) {

+					expansion = "Error formatting property. Details: " + getExceptionStringRep(ex);

+				}

+				return expansion + " [already expanded]";

+			} else if ((obj instanceof Array) && depth > 0) {

+				objectsExpanded.push(obj);

+				expansion = "[" + newLine;

+				childDepth = depth - 1;

+				childIndentation = indentation + "  ";

+				childLines = [];

+				for (i = 0, len = obj.length; i < len; i++) {

+					try {

+						childExpansion = doFormat(obj[i], childDepth, childIndentation);

+						childLines.push(childIndentation + childExpansion);

+					} catch (ex) {

+						childLines.push(childIndentation + "Error formatting array member. Details: " +

+							getExceptionStringRep(ex) + "");

+					}

+				}

+				expansion += childLines.join("," + newLine) + newLine + indentation + "]";

+				return expansion;

+            } else if (Object.prototype.toString.call(obj) == "[object Date]") {

+                return obj.toString();

+			} else if (typeof obj == "object" && depth > 0) {

+				objectsExpanded.push(obj);

+				expansion = "{" + newLine;

+				childDepth = depth - 1;

+				childIndentation = indentation + "  ";

+				childLines = [];

+				for (i in obj) {

+					try {

+						childExpansion = doFormat(obj[i], childDepth, childIndentation);

+						childLines.push(childIndentation + i + ": " + childExpansion);

+					} catch (ex) {

+						childLines.push(childIndentation + i + ": Error formatting property. Details: " +

+							getExceptionStringRep(ex));

+					}

+				}

+				expansion += childLines.join("," + newLine) + newLine + indentation + "}";

+				return expansion;

+			} else {

+				return formatString(toStr(obj));

+			}

+		}

+		return doFormat(obj, depth, indentation);

+	}

+	/* ---------------------------------------------------------------------- */

+	// Date-related stuff

+

+	var SimpleDateFormat;

+

+	(function() {

+		var regex = /('[^']*')|(G+|y+|M+|w+|W+|D+|d+|F+|E+|a+|H+|k+|K+|h+|m+|s+|S+|Z+)|([a-zA-Z]+)|([^a-zA-Z']+)/;

+		var monthNames = ["January", "February", "March", "April", "May", "June",

+			"July", "August", "September", "October", "November", "December"];

+		var dayNames = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];

+		var TEXT2 = 0, TEXT3 = 1, NUMBER = 2, YEAR = 3, MONTH = 4, TIMEZONE = 5;

+		var types = {

+			G : TEXT2,

+			y : YEAR,

+			M : MONTH,

+			w : NUMBER,

+			W : NUMBER,

+			D : NUMBER,

+			d : NUMBER,

+			F : NUMBER,

+			E : TEXT3,

+			a : TEXT2,

+			H : NUMBER,

+			k : NUMBER,

+			K : NUMBER,

+			h : NUMBER,

+			m : NUMBER,

+			s : NUMBER,

+			S : NUMBER,

+			Z : TIMEZONE

+		};

+		var ONE_DAY = 24 * 60 * 60 * 1000;

+		var ONE_WEEK = 7 * ONE_DAY;

+		var DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK = 1;

+

+		var newDateAtMidnight = function(year, month, day) {

+			var d = new Date(year, month, day, 0, 0, 0);

+			d.setMilliseconds(0);

+			return d;

+		};

+

+		Date.prototype.getDifference = function(date) {

+			return this.getTime() - date.getTime();

+		};

+

+		Date.prototype.isBefore = function(d) {

+			return this.getTime() < d.getTime();

+		};

+

+		Date.prototype.getUTCTime = function() {

+			return Date.UTC(this.getFullYear(), this.getMonth(), this.getDate(), this.getHours(), this.getMinutes(),

+					this.getSeconds(), this.getMilliseconds());

+		};

+

+		Date.prototype.getTimeSince = function(d) {

+			return this.getUTCTime() - d.getUTCTime();

+		};

+

+		Date.prototype.getPreviousSunday = function() {

+			// Using midday avoids any possibility of DST messing things up

+			var midday = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 12, 0, 0);

+			var previousSunday = new Date(midday.getTime() - this.getDay() * ONE_DAY);

+			return newDateAtMidnight(previousSunday.getFullYear(), previousSunday.getMonth(),

+					previousSunday.getDate());

+		};

+

+		Date.prototype.getWeekInYear = function(minimalDaysInFirstWeek) {

+			if (isUndefined(this.minimalDaysInFirstWeek)) {

+				minimalDaysInFirstWeek = DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;

+			}

+			var previousSunday = this.getPreviousSunday();

+			var startOfYear = newDateAtMidnight(this.getFullYear(), 0, 1);

+			var numberOfSundays = previousSunday.isBefore(startOfYear) ?

+				0 : 1 + Math.floor(previousSunday.getTimeSince(startOfYear) / ONE_WEEK);

+			var numberOfDaysInFirstWeek =  7 - startOfYear.getDay();

+			var weekInYear = numberOfSundays;

+			if (numberOfDaysInFirstWeek < minimalDaysInFirstWeek) {

+				weekInYear--;

+			}

+			return weekInYear;

+		};

+

+		Date.prototype.getWeekInMonth = function(minimalDaysInFirstWeek) {

+			if (isUndefined(this.minimalDaysInFirstWeek)) {

+				minimalDaysInFirstWeek = DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;

+			}

+			var previousSunday = this.getPreviousSunday();

+			var startOfMonth = newDateAtMidnight(this.getFullYear(), this.getMonth(), 1);

+			var numberOfSundays = previousSunday.isBefore(startOfMonth) ?

+				0 : 1 + Math.floor(previousSunday.getTimeSince(startOfMonth) / ONE_WEEK);

+			var numberOfDaysInFirstWeek =  7 - startOfMonth.getDay();

+			var weekInMonth = numberOfSundays;

+			if (numberOfDaysInFirstWeek >= minimalDaysInFirstWeek) {

+				weekInMonth++;

+			}

+			return weekInMonth;

+		};

+

+		Date.prototype.getDayInYear = function() {

+			var startOfYear = newDateAtMidnight(this.getFullYear(), 0, 1);

+			return 1 + Math.floor(this.getTimeSince(startOfYear) / ONE_DAY);

+		};

+

+		/* ------------------------------------------------------------------ */

+

+		SimpleDateFormat = function(formatString) {

+			this.formatString = formatString;

+		};

+

+		/**

+		 * Sets the minimum number of days in a week in order for that week to

+		 * be considered as belonging to a particular month or year

+		 */

+		SimpleDateFormat.prototype.setMinimalDaysInFirstWeek = function(days) {

+			this.minimalDaysInFirstWeek = days;

+		};

+

+		SimpleDateFormat.prototype.getMinimalDaysInFirstWeek = function() {

+			return isUndefined(this.minimalDaysInFirstWeek)	?

+				DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK : this.minimalDaysInFirstWeek;

+		};

+

+		var padWithZeroes = function(str, len) {

+			while (str.length < len) {

+				str = "0" + str;

+			}

+			return str;

+		};

+

+		var formatText = function(data, numberOfLetters, minLength) {

+			return (numberOfLetters >= 4) ? data : data.substr(0, Math.max(minLength, numberOfLetters));

+		};

+

+		var formatNumber = function(data, numberOfLetters) {

+			var dataString = "" + data;

+			// Pad with 0s as necessary

+			return padWithZeroes(dataString, numberOfLetters);

+		};

+

+		SimpleDateFormat.prototype.format = function(date) {

+			var formattedString = "";

+			var result;

+			var searchString = this.formatString;

+			while ((result = regex.exec(searchString))) {

+				var quotedString = result[1];

+				var patternLetters = result[2];

+				var otherLetters = result[3];

+				var otherCharacters = result[4];

+

+				// If the pattern matched is quoted string, output the text between the quotes

+				if (quotedString) {

+					if (quotedString == "''") {

+						formattedString += "'";

+					} else {

+						formattedString += quotedString.substring(1, quotedString.length - 1);

+					}

+				} else if (otherLetters) {

+					// Swallow non-pattern letters by doing nothing here

+				} else if (otherCharacters) {

+					// Simply output other characters

+					formattedString += otherCharacters;

+				} else if (patternLetters) {

+					// Replace pattern letters

+					var patternLetter = patternLetters.charAt(0);

+					var numberOfLetters = patternLetters.length;

+					var rawData = "";

+					switch(patternLetter) {

+						case "G":

+							rawData = "AD";

+							break;

+						case "y":

+							rawData = date.getFullYear();

+							break;

+						case "M":

+							rawData = date.getMonth();

+							break;

+						case "w":

+							rawData = date.getWeekInYear(this.getMinimalDaysInFirstWeek());

+							break;

+						case "W":

+							rawData = date.getWeekInMonth(this.getMinimalDaysInFirstWeek());

+							break;

+						case "D":

+							rawData = date.getDayInYear();

+							break;

+						case "d":

+							rawData = date.getDate();

+							break;

+						case "F":

+							rawData = 1 + Math.floor((date.getDate() - 1) / 7);

+							break;

+						case "E":

+							rawData = dayNames[date.getDay()];

+							break;

+						case "a":

+							rawData = (date.getHours() >= 12) ? "PM" : "AM";

+							break;

+						case "H":

+							rawData = date.getHours();

+							break;

+						case "k":

+							rawData = date.getHours() || 24;

+							break;

+						case "K":

+							rawData = date.getHours() % 12;

+							break;

+						case "h":

+							rawData = (date.getHours() % 12) || 12;

+							break;

+						case "m":

+							rawData = date.getMinutes();

+							break;

+						case "s":

+							rawData = date.getSeconds();

+							break;

+						case "S":

+							rawData = date.getMilliseconds();

+							break;

+						case "Z":

+							rawData = date.getTimezoneOffset(); // This returns the number of minutes since GMT was this time.

+							break;

+					}

+					// Format the raw data depending on the type

+					switch(types[patternLetter]) {

+						case TEXT2:

+							formattedString += formatText(rawData, numberOfLetters, 2);

+							break;

+						case TEXT3:

+							formattedString += formatText(rawData, numberOfLetters, 3);

+							break;

+						case NUMBER:

+							formattedString += formatNumber(rawData, numberOfLetters);

+							break;

+						case YEAR:

+							if (numberOfLetters <= 3) {

+								// Output a 2-digit year

+								var dataString = "" + rawData;

+								formattedString += dataString.substr(2, 2);

+							} else {

+								formattedString += formatNumber(rawData, numberOfLetters);

+							}

+							break;

+						case MONTH:

+							if (numberOfLetters >= 3) {

+								formattedString += formatText(monthNames[rawData], numberOfLetters, numberOfLetters);

+							} else {

+								// NB. Months returned by getMonth are zero-based

+								formattedString += formatNumber(rawData + 1, numberOfLetters);

+							}

+							break;

+						case TIMEZONE:

+							var isPositive = (rawData > 0);

+							// The following line looks like a mistake but isn't

+							// because of the way getTimezoneOffset measures.

+							var prefix = isPositive ? "-" : "+";

+							var absData = Math.abs(rawData);

+

+							// Hours

+							var hours = "" + Math.floor(absData / 60);

+							hours = padWithZeroes(hours, 2);

+							// Minutes

+							var minutes = "" + (absData % 60);

+							minutes = padWithZeroes(minutes, 2);

+

+							formattedString += prefix + hours + minutes;

+							break;

+					}

+				}

+				searchString = searchString.substr(result.index + result[0].length);

+			}

+			return formattedString;

+		};

+	})();

+

+	log4javascript.SimpleDateFormat = SimpleDateFormat;

+

+	/* ---------------------------------------------------------------------- */

+	// PatternLayout

+

+	function PatternLayout(pattern) {

+		if (pattern) {

+			this.pattern = pattern;

+		} else {

+			this.pattern = PatternLayout.DEFAULT_CONVERSION_PATTERN;

+		}

+		this.customFields = [];

+	}

+

+	PatternLayout.TTCC_CONVERSION_PATTERN = "%r %p %c - %m%n";

+	PatternLayout.DEFAULT_CONVERSION_PATTERN = "%m%n";

+	PatternLayout.ISO8601_DATEFORMAT = "yyyy-MM-dd HH:mm:ss,SSS";

+	PatternLayout.DATETIME_DATEFORMAT = "dd MMM yyyy HH:mm:ss,SSS";

+	PatternLayout.ABSOLUTETIME_DATEFORMAT = "HH:mm:ss,SSS";

+

+	PatternLayout.prototype = new Layout();

+

+	PatternLayout.prototype.format = function(loggingEvent) {

+		var regex = /%(-?[0-9]+)?(\.?[0-9]+)?([acdfmMnpr%])(\{([^\}]+)\})?|([^%]+)/;

+		var formattedString = "";

+		var result;

+		var searchString = this.pattern;

+

+		// Cannot use regex global flag since it doesn't work with exec in IE5

+		while ((result = regex.exec(searchString))) {

+			var matchedString = result[0];

+			var padding = result[1];

+			var truncation = result[2];

+			var conversionCharacter = result[3];

+			var specifier = result[5];

+			var text = result[6];

+

+			// Check if the pattern matched was just normal text

+			if (text) {

+				formattedString += "" + text;

+			} else {

+				// Create a raw replacement string based on the conversion

+				// character and specifier

+				var replacement = "";

+				switch(conversionCharacter) {

+					case "a": // Array of messages

+					case "m": // Message

+						var depth = 0;

+						if (specifier) {

+							depth = parseInt(specifier, 10);

+							if (isNaN(depth)) {

+								handleError("PatternLayout.format: invalid specifier '" +

+									specifier + "' for conversion character '" + conversionCharacter +

+									"' - should be a number");

+								depth = 0;

+							}

+						}

+						var messages = (conversionCharacter === "a") ? loggingEvent.messages[0] : loggingEvent.messages;

+						for (var i = 0, len = messages.length; i < len; i++) {

+							if (i > 0 && (replacement.charAt(replacement.length - 1) !== " ")) {

+								replacement += " ";

+							}

+							if (depth === 0) {

+								replacement += messages[i];

+							} else {

+								replacement += formatObjectExpansion(messages[i], depth);

+							}

+						}

+						break;

+					case "c": // Logger name

+						var loggerName = loggingEvent.logger.name;

+						if (specifier) {

+							var precision = parseInt(specifier, 10);

+							var loggerNameBits = loggingEvent.logger.name.split(".");

+							if (precision >= loggerNameBits.length) {

+								replacement = loggerName;

+							} else {

+								replacement = loggerNameBits.slice(loggerNameBits.length - precision).join(".");

+							}

+						} else {

+							replacement = loggerName;

+						}

+						break;

+					case "d": // Date

+						var dateFormat = PatternLayout.ISO8601_DATEFORMAT;

+						if (specifier) {

+							dateFormat = specifier;

+							// Pick up special cases

+							if (dateFormat == "ISO8601") {

+								dateFormat = PatternLayout.ISO8601_DATEFORMAT;

+							} else if (dateFormat == "ABSOLUTE") {

+								dateFormat = PatternLayout.ABSOLUTETIME_DATEFORMAT;

+							} else if (dateFormat == "DATE") {

+								dateFormat = PatternLayout.DATETIME_DATEFORMAT;

+							}

+						}

+						// Format the date

+						replacement = (new SimpleDateFormat(dateFormat)).format(loggingEvent.timeStamp);

+						break;

+					case "f": // Custom field

+						if (this.hasCustomFields()) {

+							var fieldIndex = 0;

+							if (specifier) {

+								fieldIndex = parseInt(specifier, 10);

+								if (isNaN(fieldIndex)) {

+									handleError("PatternLayout.format: invalid specifier '" +

+										specifier + "' for conversion character 'f' - should be a number");

+								} else if (fieldIndex === 0) {

+									handleError("PatternLayout.format: invalid specifier '" +

+										specifier + "' for conversion character 'f' - must be greater than zero");

+								} else if (fieldIndex > this.customFields.length) {

+									handleError("PatternLayout.format: invalid specifier '" +

+										specifier + "' for conversion character 'f' - there aren't that many custom fields");

+								} else {

+									fieldIndex = fieldIndex - 1;

+								}

+							}

+                            var val = this.customFields[fieldIndex].value;

+                            if (typeof val == "function") {

+                                val = val(this, loggingEvent);

+                            }

+                            replacement = val;

+						}

+						break;

+					case "n": // New line

+						replacement = newLine;

+						break;

+					case "p": // Level

+						replacement = loggingEvent.level.name;

+						break;

+					case "r": // Milliseconds since log4javascript startup

+						replacement = "" + loggingEvent.timeStamp.getDifference(applicationStartDate);

+						break;

+					case "%": // Literal % sign

+						replacement = "%";

+						break;

+					default:

+						replacement = matchedString;

+						break;

+				}

+				// Format the replacement according to any padding or

+				// truncation specified

+				var l;

+

+				// First, truncation

+				if (truncation) {

+					l = parseInt(truncation.substr(1), 10);

+					var strLen = replacement.length;

+					if (l < strLen) {

+						replacement = replacement.substring(strLen - l, strLen);

+					}

+				}

+				// Next, padding

+				if (padding) {

+					if (padding.charAt(0) == "-") {

+						l = parseInt(padding.substr(1), 10);

+						// Right pad with spaces

+						while (replacement.length < l) {

+							replacement += " ";

+						}

+					} else {

+						l = parseInt(padding, 10);

+						// Left pad with spaces

+						while (replacement.length < l) {

+							replacement = " " + replacement;

+						}

+					}

+				}

+				formattedString += replacement;

+			}

+			searchString = searchString.substr(result.index + result[0].length);

+		}

+		return formattedString;

+	};

+

+	PatternLayout.prototype.ignoresThrowable = function() {

+	    return true;

+	};

+

+	PatternLayout.prototype.toString = function() {

+	    return "PatternLayout";

+	};

+

+	log4javascript.PatternLayout = PatternLayout;

+	/* ---------------------------------------------------------------------- */

+	// AlertAppender

+

+	function AlertAppender() {}

+

+	AlertAppender.prototype = new Appender();

+

+	AlertAppender.prototype.layout = new SimpleLayout();

+

+	AlertAppender.prototype.append = function(loggingEvent) {

+		var formattedMessage = this.getLayout().format(loggingEvent);

+		if (this.getLayout().ignoresThrowable()) {

+			formattedMessage += loggingEvent.getThrowableStrRep();

+		}

+		alert(formattedMessage);

+	};

+

+	AlertAppender.prototype.toString = function() {

+		return "AlertAppender";

+	};

+

+	log4javascript.AlertAppender = AlertAppender;

+	/* ---------------------------------------------------------------------- */

+	// BrowserConsoleAppender (only works in Opera and Safari and Firefox with

+	// Firebug extension)

+

+	function BrowserConsoleAppender() {}

+

+	BrowserConsoleAppender.prototype = new log4javascript.Appender();

+	BrowserConsoleAppender.prototype.layout = new NullLayout();

+	BrowserConsoleAppender.prototype.threshold = Level.DEBUG;

+

+	BrowserConsoleAppender.prototype.append = function(loggingEvent) {

+		var appender = this;

+

+		var getFormattedMessage = function() {

+			var layout = appender.getLayout();

+			var formattedMessage = layout.format(loggingEvent);

+			if (layout.ignoresThrowable() && loggingEvent.exception) {

+				formattedMessage += loggingEvent.getThrowableStrRep();

+			}

+			return formattedMessage;

+		};

+

+		if ((typeof opera != "undefined") && opera.postError) { // Opera

+			opera.postError(getFormattedMessage());

+		} else if (window.console && window.console.log) { // Safari and Firebug

+			var formattedMesage = getFormattedMessage();

+			// Log to Firebug using its logging methods or revert to the console.log

+			// method in Safari

+			if (window.console.debug && Level.DEBUG.isGreaterOrEqual(loggingEvent.level)) {

+				window.console.debug(formattedMesage);

+			} else if (window.console.info && Level.INFO.equals(loggingEvent.level)) {

+				window.console.info(formattedMesage);

+			} else if (window.console.warn && Level.WARN.equals(loggingEvent.level)) {

+				window.console.warn(formattedMesage);

+			} else if (window.console.error && loggingEvent.level.isGreaterOrEqual(Level.ERROR)) {

+				window.console.error(formattedMesage);

+			} else {

+				window.console.log(formattedMesage);

+			}

+		}

+	};

+

+	BrowserConsoleAppender.prototype.group = function(name) {

+		if (window.console && window.console.group) {

+			window.console.group(name);

+		}

+	};

+

+	BrowserConsoleAppender.prototype.groupEnd = function() {

+		if (window.console && window.console.groupEnd) {

+			window.console.groupEnd();

+		}

+	};

+

+	BrowserConsoleAppender.prototype.toString = function() {

+		return "BrowserConsoleAppender";

+	};

+

+	log4javascript.BrowserConsoleAppender = BrowserConsoleAppender;

+	/* ---------------------------------------------------------------------- */

+	// AjaxAppender related

+

+	var xmlHttpFactories = [

+		function() { return new XMLHttpRequest(); },

+		function() { return new ActiveXObject("Msxml2.XMLHTTP"); },

+		function() { return new ActiveXObject("Microsoft.XMLHTTP"); }

+	];

+

+	var getXmlHttp = function(errorHandler) {

+		// This is only run the first time; the value of getXmlHttp gets

+		// replaced with the factory that succeeds on the first run

+		var xmlHttp = null, factory;

+		for (var i = 0, len = xmlHttpFactories.length; i < len; i++) {

+			factory = xmlHttpFactories[i];

+			try {

+				xmlHttp = factory();

+				getXmlHttp = factory;

+				return xmlHttp;

+			} catch (e) {

+			}

+		}

+		// If we're here, all factories have failed, so throw an error

+		if (errorHandler) {

+			errorHandler();

+		} else {

+			handleError("getXmlHttp: unable to obtain XMLHttpRequest object");

+		}

+	};

+

+	function isHttpRequestSuccessful(xmlHttp) {

+		return isUndefined(xmlHttp.status) || xmlHttp.status === 0 ||

+			(xmlHttp.status >= 200 && xmlHttp.status < 300) ||

+			xmlHttp.status == 1223 /* Fix for IE */;

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// AjaxAppender

+

+	function AjaxAppender(url) {

+		var appender = this;

+		var isSupported = true;

+		if (!url) {

+			handleError("AjaxAppender: URL must be specified in constructor");

+			isSupported = false;

+		}

+

+		var timed = this.defaults.timed;

+		var waitForResponse = this.defaults.waitForResponse;

+		var batchSize = this.defaults.batchSize;

+		var timerInterval = this.defaults.timerInterval;

+		var requestSuccessCallback = this.defaults.requestSuccessCallback;

+		var failCallback = this.defaults.failCallback;

+		var postVarName = this.defaults.postVarName;

+		var sendAllOnUnload = this.defaults.sendAllOnUnload;

+		var contentType = this.defaults.contentType;

+		var sessionId = null;

+

+		var queuedLoggingEvents = [];

+		var queuedRequests = [];

+		var headers = [];

+		var sending = false;

+		var initialized = false;

+

+		// Configuration methods. The function scope is used to prevent

+		// direct alteration to the appender configuration properties.

+		function checkCanConfigure(configOptionName) {

+			if (initialized) {

+				handleError("AjaxAppender: configuration option '" +

+					configOptionName +

+					"' may not be set after the appender has been initialized");

+				return false;

+			}

+			return true;

+		}

+

+		this.getSessionId = function() { return sessionId; };

+		this.setSessionId = function(sessionIdParam) {

+			sessionId = extractStringFromParam(sessionIdParam, null);

+			this.layout.setCustomField("sessionid", sessionId);

+		};

+

+		this.setLayout = function(layoutParam) {

+			if (checkCanConfigure("layout")) {

+				this.layout = layoutParam;

+				// Set the session id as a custom field on the layout, if not already present

+				if (sessionId !== null) {

+					this.setSessionId(sessionId);

+				}

+			}

+		};

+

+		this.isTimed = function() { return timed; };

+		this.setTimed = function(timedParam) {

+			if (checkCanConfigure("timed")) {

+				timed = bool(timedParam);

+			}

+		};

+

+		this.getTimerInterval = function() { return timerInterval; };

+		this.setTimerInterval = function(timerIntervalParam) {

+			if (checkCanConfigure("timerInterval")) {

+				timerInterval = extractIntFromParam(timerIntervalParam, timerInterval);

+			}

+		};

+

+		this.isWaitForResponse = function() { return waitForResponse; };

+		this.setWaitForResponse = function(waitForResponseParam) {

+			if (checkCanConfigure("waitForResponse")) {

+				waitForResponse = bool(waitForResponseParam);

+			}

+		};

+

+		this.getBatchSize = function() { return batchSize; };

+		this.setBatchSize = function(batchSizeParam) {

+			if (checkCanConfigure("batchSize")) {

+				batchSize = extractIntFromParam(batchSizeParam, batchSize);

+			}

+		};

+

+		this.isSendAllOnUnload = function() { return sendAllOnUnload; };

+		this.setSendAllOnUnload = function(sendAllOnUnloadParam) {

+			if (checkCanConfigure("sendAllOnUnload")) {

+				sendAllOnUnload = extractBooleanFromParam(sendAllOnUnloadParam, sendAllOnUnload);

+			}

+		};

+

+		this.setRequestSuccessCallback = function(requestSuccessCallbackParam) {

+			requestSuccessCallback = extractFunctionFromParam(requestSuccessCallbackParam, requestSuccessCallback);

+		};

+

+		this.setFailCallback = function(failCallbackParam) {

+			failCallback = extractFunctionFromParam(failCallbackParam, failCallback);

+		};

+

+		this.getPostVarName = function() { return postVarName; };

+		this.setPostVarName = function(postVarNameParam) {

+			if (checkCanConfigure("postVarName")) {

+				postVarName = extractStringFromParam(postVarNameParam, postVarName);

+			}

+		};

+

+		this.getHeaders = function() { return headers; };

+		this.addHeader = function(name, value) {

+			if (name.toLowerCase() == "content-type") {

+				contentType = value;

+			} else {

+				headers.push( { name: name, value: value } );

+			}

+		};

+

+		// Internal functions

+		function sendAll() {

+			if (isSupported && enabled) {

+				sending = true;

+				var currentRequestBatch;

+				if (waitForResponse) {

+					// Send the first request then use this function as the callback once

+					// the response comes back

+					if (queuedRequests.length > 0) {

+						currentRequestBatch = queuedRequests.shift();

+						sendRequest(preparePostData(currentRequestBatch), sendAll);

+					} else {

+						sending = false;

+						if (timed) {

+							scheduleSending();

+						}

+					}

+				} else {

+					// Rattle off all the requests without waiting to see the response

+					while ((currentRequestBatch = queuedRequests.shift())) {

+						sendRequest(preparePostData(currentRequestBatch));

+					}

+					sending = false;

+					if (timed) {

+						scheduleSending();

+					}

+				}

+			}

+		}

+

+		this.sendAll = sendAll;

+

+		// Called when the window unloads. At this point we're past caring about

+		// waiting for responses or timers or incomplete batches - everything

+		// must go, now

+		function sendAllRemaining() {

+			var sendingAnything = false;

+			if (isSupported && enabled) {

+				// Create requests for everything left over, batched as normal

+				var actualBatchSize = appender.getLayout().allowBatching() ? batchSize : 1;

+				var currentLoggingEvent;

+				var batchedLoggingEvents = [];

+				while ((currentLoggingEvent = queuedLoggingEvents.shift())) {

+					batchedLoggingEvents.push(currentLoggingEvent);

+					if (queuedLoggingEvents.length >= actualBatchSize) {

+						// Queue this batch of log entries

+						queuedRequests.push(batchedLoggingEvents);

+						batchedLoggingEvents = [];

+					}

+				}

+				// If there's a partially completed batch, add it

+				if (batchedLoggingEvents.length > 0) {

+					queuedRequests.push(batchedLoggingEvents);

+				}

+				sendingAnything = (queuedRequests.length > 0);

+				waitForResponse = false;

+				timed = false;

+				sendAll();

+			}

+			return sendingAnything;

+		}

+

+		this.sendAllRemaining = sendAllRemaining;

+

+		function preparePostData(batchedLoggingEvents) {

+			// Format the logging events

+			var formattedMessages = [];

+			var currentLoggingEvent;

+			var postData = "";

+			while ((currentLoggingEvent = batchedLoggingEvents.shift())) {

+				var currentFormattedMessage = appender.getLayout().format(currentLoggingEvent);

+				if (appender.getLayout().ignoresThrowable()) {

+					currentFormattedMessage += currentLoggingEvent.getThrowableStrRep();

+				}

+				formattedMessages.push(currentFormattedMessage);

+			}

+			// Create the post data string

+			if (batchedLoggingEvents.length == 1) {

+				postData = formattedMessages.join("");

+			} else {

+				postData = appender.getLayout().batchHeader +

+					formattedMessages.join(appender.getLayout().batchSeparator) +

+					appender.getLayout().batchFooter;

+			}

+			if (contentType == appender.defaults.contentType) {

+				postData = appender.getLayout().returnsPostData ? postData :

+					urlEncode(postVarName) + "=" + urlEncode(postData);

+				// Add the layout name to the post data

+				if (postData.length > 0) {

+					postData += "&";

+				}

+				postData += "layout=" + urlEncode(appender.getLayout().toString());

+			}

+			return postData;

+		}

+

+		function scheduleSending() {

+			window.setTimeout(sendAll, timerInterval);

+		}

+

+		function xmlHttpErrorHandler() {

+			var msg = "AjaxAppender: could not create XMLHttpRequest object. AjaxAppender disabled";

+			handleError(msg);

+			isSupported = false;

+			if (failCallback) {

+				failCallback(msg);

+			}

+		}

+

+		function sendRequest(postData, successCallback) {

+			try {

+				var xmlHttp = getXmlHttp(xmlHttpErrorHandler);

+				if (isSupported) {

+					if (xmlHttp.overrideMimeType) {

+						xmlHttp.overrideMimeType(appender.getLayout().getContentType());

+					}

+					xmlHttp.onreadystatechange = function() {

+						if (xmlHttp.readyState == 4) {

+							if (isHttpRequestSuccessful(xmlHttp)) {

+								if (requestSuccessCallback) {

+									requestSuccessCallback(xmlHttp);

+								}

+								if (successCallback) {

+									successCallback(xmlHttp);

+								}

+							} else {

+								var msg = "AjaxAppender.append: XMLHttpRequest request to URL " +

+									url + " returned status code " + xmlHttp.status;

+								handleError(msg);

+								if (failCallback) {

+									failCallback(msg);

+								}

+							}

+							xmlHttp.onreadystatechange = emptyFunction;

+							xmlHttp = null;

+						}

+					};

+					xmlHttp.open("POST", url, true);

+					try {

+						for (var i = 0, header; header = headers[i++]; ) {

+							xmlHttp.setRequestHeader(header.name, header.value);

+						}

+						xmlHttp.setRequestHeader("Content-Type", contentType);

+					} catch (headerEx) {

+						var msg = "AjaxAppender.append: your browser's XMLHttpRequest implementation" +

+							" does not support setRequestHeader, therefore cannot post data. AjaxAppender disabled";

+						handleError(msg);

+						isSupported = false;

+						if (failCallback) {

+							failCallback(msg);

+						}

+						return;

+					}

+					xmlHttp.send(postData);

+				}

+			} catch (ex) {

+				var errMsg = "AjaxAppender.append: error sending log message to " + url;

+				handleError(errMsg, ex);

+				isSupported = false;

+				if (failCallback) {

+					failCallback(errMsg + ". Details: " + getExceptionStringRep(ex));

+				}

+			}

+		}

+

+		this.append = function(loggingEvent) {

+			if (isSupported) {

+				if (!initialized) {

+					init();

+				}

+				queuedLoggingEvents.push(loggingEvent);

+				var actualBatchSize = this.getLayout().allowBatching() ? batchSize : 1;

+

+				if (queuedLoggingEvents.length >= actualBatchSize) {

+					var currentLoggingEvent;

+					var batchedLoggingEvents = [];

+					while ((currentLoggingEvent = queuedLoggingEvents.shift())) {

+						batchedLoggingEvents.push(currentLoggingEvent);

+					}

+					// Queue this batch of log entries

+					queuedRequests.push(batchedLoggingEvents);

+

+					// If using a timer, the queue of requests will be processed by the

+					// timer function, so nothing needs to be done here.

+					if (!timed && (!waitForResponse || (waitForResponse && !sending))) {

+						sendAll();

+					}

+				}

+			}

+		};

+

+		function init() {

+			initialized = true;

+			// Add unload event to send outstanding messages

+			if (sendAllOnUnload) {

+				var oldBeforeUnload = window.onbeforeunload;

+				window.onbeforeunload = function() {

+					if (oldBeforeUnload) {

+						oldBeforeUnload();

+					}

+					if (sendAllRemaining()) {

+						return "Sending log messages";

+					}

+				};

+			}

+			// Start timer

+			if (timed) {

+				scheduleSending();

+			}

+		}

+	}

+

+	AjaxAppender.prototype = new Appender();

+

+	AjaxAppender.prototype.defaults = {

+		waitForResponse: false,

+		timed: false,

+		timerInterval: 1000,

+		batchSize: 1,

+		sendAllOnUnload: false,

+		requestSuccessCallback: null,

+		failCallback: null,

+		postVarName: "data",

+		contentType: "application/x-www-form-urlencoded"

+	};

+

+	AjaxAppender.prototype.layout = new HttpPostDataLayout();

+

+	AjaxAppender.prototype.toString = function() {

+		return "AjaxAppender";

+	};

+

+	log4javascript.AjaxAppender = AjaxAppender;

+	/* ---------------------------------------------------------------------- */

+	// PopUpAppender and InPageAppender related

+

+	function setCookie(name, value, days, path) {

+	    var expires;

+	    path = path ? "; path=" + path : "";

+		if (days) {

+			var date = new Date();

+			date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));

+			expires = "; expires=" + date.toGMTString();

+		} else {

+		    expires = "";

+	    }

+		document.cookie = escape(name) + "=" + escape(value) + expires + path;

+	}

+

+	function getCookie(name) {

+		var nameEquals = escape(name) + "=";

+		var ca = document.cookie.split(";");

+		for (var i = 0, len = ca.length; i < len; i++) {

+			var c = ca[i];

+			while (c.charAt(0) === " ") {

+			    c = c.substring(1, c.length);

+			}

+			if (c.indexOf(nameEquals) === 0) {

+			    return unescape(c.substring(nameEquals.length, c.length));

+	        }

+		}

+		return null;

+	}

+

+	// Gets the base URL of the location of the log4javascript script.

+	// This is far from infallible.

+	function getBaseUrl() {

+		var scripts = document.getElementsByTagName("script");

+		for (var i = 0, len = scripts.length; i < len; ++i) {

+			if (scripts[i].src.indexOf("log4javascript") != -1) {

+				var lastSlash = scripts[i].src.lastIndexOf("/");

+				return (lastSlash == -1) ? "" : scripts[i].src.substr(0, lastSlash + 1);

+			}

+		}

+        return null;

+    }

+

+	function isLoaded(win) {

+		try {

+			return bool(win.loaded);

+		} catch (ex) {

+			return false;

+		}

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// ConsoleAppender (prototype for PopUpAppender and InPageAppender)

+

+	var ConsoleAppender;

+

+	// Create an anonymous function to protect base console methods

+	(function() {

+		var getConsoleHtmlLines = function() {

+			return [

+'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',

+'<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">',

+'	<head>',

+'		<title>log4javascript</title>',

+'		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />',

+'		<!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->',

+'		<meta http-equiv="X-UA-Compatible" content="IE=7" />',

+'		<script type="text/javascript">var isIe = false, isIePre7 = false;</script>',

+'		<!--[if IE]><script type="text/javascript">isIe = true</script><![endif]-->',

+'		<!--[if lt IE 7]><script type="text/javascript">isIePre7 = true</script><![endif]-->',

+'		<script type="text/javascript">',

+'			//<![CDATA[',

+'			var loggingEnabled = true;',

+'			var logQueuedEventsTimer = null;',

+'			var logEntries = [];',

+'			var logEntriesAndSeparators = [];',

+'			var logItems = [];',

+'			var renderDelay = 100;',

+'			var unrenderedLogItemsExist = false;',

+'			var rootGroup, currentGroup = null;',

+'			var loaded = false;',

+'			var currentLogItem = null;',

+'			var logMainContainer;',

+'',

+'			function copyProperties(obj, props) {',

+'				for (var i in props) {',

+'					obj[i] = props[i];',

+'				}',

+'			}',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogItem() {',

+'			}',

+'',

+'			LogItem.prototype = {',

+'				mainContainer: null,',

+'				wrappedContainer: null,',

+'				unwrappedContainer: null,',

+'				group: null,',

+'',

+'				appendToLog: function() {',

+'					for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'						this.elementContainers[i].appendToLog();',

+'					}',

+'					this.group.update();',

+'				},',

+'',

+'				doRemove: function(doUpdate, removeFromGroup) {',

+'					if (this.rendered) {',

+'						for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'							this.elementContainers[i].remove();',

+'						}',

+'						this.unwrappedElementContainer = null;',

+'						this.wrappedElementContainer = null;',

+'						this.mainElementContainer = null;',

+'					}',

+'					if (this.group && removeFromGroup) {',

+'						this.group.removeChild(this, doUpdate);',

+'					}',

+'					if (this === currentLogItem) {',

+'						currentLogItem = null;',

+'					}',

+'				},',

+'',

+'				remove: function(doUpdate, removeFromGroup) {',

+'					this.doRemove(doUpdate, removeFromGroup);',

+'				},',

+'',

+'				render: function() {},',

+'',

+'				accept: function(visitor) {',

+'					visitor.visit(this);',

+'				},',

+'',

+'				getUnwrappedDomContainer: function() {',

+'					return this.group.unwrappedElementContainer.contentDiv;',

+'				},',

+'',

+'				getWrappedDomContainer: function() {',

+'					return this.group.wrappedElementContainer.contentDiv;',

+'				},',

+'',

+'				getMainDomContainer: function() {',

+'					return this.group.mainElementContainer.contentDiv;',

+'				}',

+'			};',

+'',

+'			LogItem.serializedItemKeys = {LOG_ENTRY: 0, GROUP_START: 1, GROUP_END: 2};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogItemContainerElement() {',

+'			}',

+'',

+'			LogItemContainerElement.prototype = {',

+'				appendToLog: function() {',

+'					var insertBeforeFirst = (newestAtTop && this.containerDomNode.hasChildNodes());',

+'					if (insertBeforeFirst) {',

+'						this.containerDomNode.insertBefore(this.mainDiv, this.containerDomNode.firstChild);',

+'					} else {',

+'						this.containerDomNode.appendChild(this.mainDiv);',

+'					}',

+'				}',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function SeparatorElementContainer(containerDomNode) {',

+'				this.containerDomNode = containerDomNode;',

+'				this.mainDiv = document.createElement("div");',

+'				this.mainDiv.className = "separator";',

+'				this.mainDiv.innerHTML = "&nbsp;";',

+'			}',

+'',

+'			SeparatorElementContainer.prototype = new LogItemContainerElement();',

+'',

+'			SeparatorElementContainer.prototype.remove = function() {',

+'				this.mainDiv.parentNode.removeChild(this.mainDiv);',

+'				this.mainDiv = null;',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function Separator() {',

+'				this.rendered = false;',

+'			}',

+'',

+'			Separator.prototype = new LogItem();',

+'',

+'			copyProperties(Separator.prototype, {',

+'				render: function() {',

+'					var containerDomNode = this.group.contentDiv;',

+'					if (isIe) {',

+'						this.unwrappedElementContainer = new SeparatorElementContainer(this.getUnwrappedDomContainer());',

+'						this.wrappedElementContainer = new SeparatorElementContainer(this.getWrappedDomContainer());',

+'						this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];',

+'					} else {',

+'						this.mainElementContainer = new SeparatorElementContainer(this.getMainDomContainer());',

+'						this.elementContainers = [this.mainElementContainer];',

+'					}',

+'					this.content = this.formattedMessage;',

+'					this.rendered = true;',

+'				}',

+'			});',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function GroupElementContainer(group, containerDomNode, isRoot, isWrapped) {',

+'				this.group = group;',

+'				this.containerDomNode = containerDomNode;',

+'				this.isRoot = isRoot;',

+'				this.isWrapped = isWrapped;',

+'				this.expandable = false;',

+'',

+'				if (this.isRoot) {',

+'					if (isIe) {',

+'						this.contentDiv = logMainContainer.appendChild(document.createElement("div"));',

+'						this.contentDiv.id = this.isWrapped ? "log_wrapped" : "log_unwrapped";',

+'					} else {',

+'						this.contentDiv = logMainContainer;',

+'					}',

+'				} else {',

+'					var groupElementContainer = this;',

+'					',

+'					this.mainDiv = document.createElement("div");',

+'					this.mainDiv.className = "group";',

+'',

+'					this.headingDiv = this.mainDiv.appendChild(document.createElement("div"));',

+'					this.headingDiv.className = "groupheading";',

+'',

+'					this.expander = this.headingDiv.appendChild(document.createElement("span"));',

+'					this.expander.className = "expander unselectable greyedout";',

+'					this.expander.unselectable = true;',

+'					var expanderText = this.group.expanded ? "-" : "+";',

+'					this.expanderTextNode = this.expander.appendChild(document.createTextNode(expanderText));',

+'					',

+'					this.headingDiv.appendChild(document.createTextNode(" " + this.group.name));',

+'',

+'					this.contentDiv = this.mainDiv.appendChild(document.createElement("div"));',

+'					var contentCssClass = this.group.expanded ? "expanded" : "collapsed";',

+'					this.contentDiv.className = "groupcontent " + contentCssClass;',

+'',

+'					this.expander.onclick = function() {',

+'						if (groupElementContainer.group.expandable) {',

+'							groupElementContainer.group.toggleExpanded();',

+'						}',

+'					};',

+'				}',

+'			}',

+'',

+'			GroupElementContainer.prototype = new LogItemContainerElement();',

+'',

+'			copyProperties(GroupElementContainer.prototype, {',

+'				toggleExpanded: function() {',

+'					if (!this.isRoot) {',

+'						var oldCssClass, newCssClass, expanderText;',

+'						if (this.group.expanded) {',

+'							newCssClass = "expanded";',

+'							oldCssClass = "collapsed";',

+'							expanderText = "-";',

+'						} else {',

+'							newCssClass = "collapsed";',

+'							oldCssClass = "expanded";',

+'							expanderText = "+";',

+'						}',

+'						replaceClass(this.contentDiv, newCssClass, oldCssClass);',

+'						this.expanderTextNode.nodeValue = expanderText;',

+'					}',

+'				},',

+'',

+'				remove: function() {',

+'					if (!this.isRoot) {',

+'						this.headingDiv = null;',

+'						this.expander.onclick = null;',

+'						this.expander = null;',

+'						this.expanderTextNode = null;',

+'						this.contentDiv = null;',

+'						this.containerDomNode = null;',

+'						this.mainDiv.parentNode.removeChild(this.mainDiv);',

+'						this.mainDiv = null;',

+'					}',

+'				},',

+'',

+'				reverseChildren: function() {',

+'					// Invert the order of the log entries',

+'					var node = null;',

+'',

+'					// Remove all the log container nodes',

+'					var childDomNodes = [];',

+'					while ((node = this.contentDiv.firstChild)) {',

+'						this.contentDiv.removeChild(node);',

+'						childDomNodes.push(node);',

+'					}',

+'',

+'					// Put them all back in reverse order',

+'					while ((node = childDomNodes.pop())) {',

+'						this.contentDiv.appendChild(node);',

+'					}',

+'				},',

+'',

+'				update: function() {',

+'					if (!this.isRoot) {',

+'						if (this.group.expandable) {',

+'							removeClass(this.expander, "greyedout");',

+'						} else {',

+'							addClass(this.expander, "greyedout");',

+'						}',

+'					}',

+'				},',

+'',

+'				clear: function() {',

+'					if (this.isRoot) {',

+'						this.contentDiv.innerHTML = "";',

+'					}',

+'				}',

+'			});',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function Group(name, isRoot, initiallyExpanded) {',

+'				this.name = name;',

+'				this.group = null;',

+'				this.isRoot = isRoot;',

+'				this.initiallyExpanded = initiallyExpanded;',

+'				this.elementContainers = [];',

+'				this.children = [];',

+'				this.expanded = initiallyExpanded;',

+'				this.rendered = false;',

+'				this.expandable = false;',

+'			}',

+'',

+'			Group.prototype = new LogItem();',

+'',

+'			copyProperties(Group.prototype, {',

+'				addChild: function(logItem) {',

+'					this.children.push(logItem);',

+'					logItem.group = this;',

+'				},',

+'',

+'				render: function() {',

+'					if (isIe) {',

+'						var unwrappedDomContainer, wrappedDomContainer;',

+'						if (this.isRoot) {',

+'							unwrappedDomContainer = logMainContainer;',

+'							wrappedDomContainer = logMainContainer;',

+'						} else {',

+'							unwrappedDomContainer = this.getUnwrappedDomContainer();',

+'							wrappedDomContainer = this.getWrappedDomContainer();',

+'						}',

+'						this.unwrappedElementContainer = new GroupElementContainer(this, unwrappedDomContainer, this.isRoot, false);',

+'						this.wrappedElementContainer = new GroupElementContainer(this, wrappedDomContainer, this.isRoot, true);',

+'						this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];',

+'					} else {',

+'						var mainDomContainer = this.isRoot ? logMainContainer : this.getMainDomContainer();',

+'						this.mainElementContainer = new GroupElementContainer(this, mainDomContainer, this.isRoot, false);',

+'						this.elementContainers = [this.mainElementContainer];',

+'					}',

+'					this.rendered = true;',

+'				},',

+'',

+'				toggleExpanded: function() {',

+'					this.expanded = !this.expanded;',

+'					for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'						this.elementContainers[i].toggleExpanded();',

+'					}',

+'				},',

+'',

+'				expand: function() {',

+'					if (!this.expanded) {',

+'						this.toggleExpanded();',

+'					}',

+'				},',

+'',

+'				accept: function(visitor) {',

+'					visitor.visitGroup(this);',

+'				},',

+'',

+'				reverseChildren: function() {',

+'					if (this.rendered) {',

+'						for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'							this.elementContainers[i].reverseChildren();',

+'						}',

+'					}',

+'				},',

+'',

+'				update: function() {',

+'					var previouslyExpandable = this.expandable;',

+'					this.expandable = (this.children.length !== 0);',

+'					if (this.expandable !== previouslyExpandable) {',

+'						for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'							this.elementContainers[i].update();',

+'						}',

+'					}',

+'				},',

+'',

+'				flatten: function() {',

+'					var visitor = new GroupFlattener();',

+'					this.accept(visitor);',

+'					return visitor.logEntriesAndSeparators;',

+'				},',

+'',

+'				removeChild: function(child, doUpdate) {',

+'					array_remove(this.children, child);',

+'					child.group = null;',

+'					if (doUpdate) {',

+'						this.update();',

+'					}',

+'				},',

+'',

+'				remove: function(doUpdate, removeFromGroup) {',

+'					for (var i = 0, len = this.children.length; i < len; i++) {',

+'						this.children[i].remove(false, false);',

+'					}',

+'					this.children = [];',

+'					this.update();',

+'					if (this === currentGroup) {',

+'						currentGroup = this.group;',

+'					}',

+'					this.doRemove(doUpdate, removeFromGroup);',

+'				},',

+'',

+'				serialize: function(items) {',

+'					items.push([LogItem.serializedItemKeys.GROUP_START, this.name]);',

+'					for (var i = 0, len = this.children.length; i < len; i++) {',

+'						this.children[i].serialize(items);',

+'					}',

+'					if (this !== currentGroup) {',

+'						items.push([LogItem.serializedItemKeys.GROUP_END]);',

+'					}',

+'				},',

+'',

+'				clear: function() {',

+'					for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'						this.elementContainers[i].clear();',

+'					}',

+'				}',

+'			});',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogEntryElementContainer() {',

+'			}',

+'',

+'			LogEntryElementContainer.prototype = new LogItemContainerElement();',

+'',

+'			copyProperties(LogEntryElementContainer.prototype, {',

+'				remove: function() {',

+'					this.doRemove();',

+'				},',

+'',

+'				doRemove: function() {',

+'					this.mainDiv.parentNode.removeChild(this.mainDiv);',

+'					this.mainDiv = null;',

+'					this.contentElement = null;',

+'					this.containerDomNode = null;',

+'				},',

+'',

+'				setContent: function(content, wrappedContent) {',

+'					if (content === this.formattedMessage) {',

+'						this.contentElement.innerHTML = "";',

+'						this.contentElement.appendChild(document.createTextNode(this.formattedMessage));',

+'					} else {',

+'						this.contentElement.innerHTML = content;',

+'					}',

+'				},',

+'',

+'				setSearchMatch: function(isMatch) {',

+'					var oldCssClass = isMatch ? "searchnonmatch" : "searchmatch";',

+'					var newCssClass = isMatch ? "searchmatch" : "searchnonmatch";',

+'					replaceClass(this.mainDiv, newCssClass, oldCssClass);',

+'				},',

+'',

+'				clearSearch: function() {',

+'					removeClass(this.mainDiv, "searchmatch");',

+'					removeClass(this.mainDiv, "searchnonmatch");',

+'				}',

+'			});',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogEntryWrappedElementContainer(logEntry, containerDomNode) {',

+'				this.logEntry = logEntry;',

+'				this.containerDomNode = containerDomNode;',

+'				this.mainDiv = document.createElement("div");',

+'				this.mainDiv.appendChild(document.createTextNode(this.logEntry.formattedMessage));',

+'				this.mainDiv.className = "logentry wrapped " + this.logEntry.level;',

+'				this.contentElement = this.mainDiv;',

+'			}',

+'',

+'			LogEntryWrappedElementContainer.prototype = new LogEntryElementContainer();',

+'',

+'			LogEntryWrappedElementContainer.prototype.setContent = function(content, wrappedContent) {',

+'				if (content === this.formattedMessage) {',

+'					this.contentElement.innerHTML = "";',

+'					this.contentElement.appendChild(document.createTextNode(this.formattedMessage));',

+'				} else {',

+'					this.contentElement.innerHTML = wrappedContent;',

+'				}',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogEntryUnwrappedElementContainer(logEntry, containerDomNode) {',

+'				this.logEntry = logEntry;',

+'				this.containerDomNode = containerDomNode;',

+'				this.mainDiv = document.createElement("div");',

+'				this.mainDiv.className = "logentry unwrapped " + this.logEntry.level;',

+'				this.pre = this.mainDiv.appendChild(document.createElement("pre"));',

+'				this.pre.appendChild(document.createTextNode(this.logEntry.formattedMessage));',

+'				this.pre.className = "unwrapped";',

+'				this.contentElement = this.pre;',

+'			}',

+'',

+'			LogEntryUnwrappedElementContainer.prototype = new LogEntryElementContainer();',

+'',

+'			LogEntryUnwrappedElementContainer.prototype.remove = function() {',

+'				this.doRemove();',

+'				this.pre = null;',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogEntryMainElementContainer(logEntry, containerDomNode) {',

+'				this.logEntry = logEntry;',

+'				this.containerDomNode = containerDomNode;',

+'				this.mainDiv = document.createElement("div");',

+'				this.mainDiv.className = "logentry nonielogentry " + this.logEntry.level;',

+'				this.contentElement = this.mainDiv.appendChild(document.createElement("span"));',

+'				this.contentElement.appendChild(document.createTextNode(this.logEntry.formattedMessage));',

+'			}',

+'',

+'			LogEntryMainElementContainer.prototype = new LogEntryElementContainer();',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogEntry(level, formattedMessage) {',

+'				this.level = level;',

+'				this.formattedMessage = formattedMessage;',

+'				this.rendered = false;',

+'			}',

+'',

+'			LogEntry.prototype = new LogItem();',

+'',

+'			copyProperties(LogEntry.prototype, {',

+'				render: function() {',

+'					var logEntry = this;',

+'					var containerDomNode = this.group.contentDiv;',

+'',

+'					// Support for the CSS attribute white-space in IE for Windows is',

+'					// non-existent pre version 6 and slightly odd in 6, so instead',

+'					// use two different HTML elements',

+'					if (isIe) {',

+'						this.formattedMessage = this.formattedMessage.replace(/\\r\\n/g, "\\r"); // Workaround for IE\'s treatment of white space',

+'						this.unwrappedElementContainer = new LogEntryUnwrappedElementContainer(this, this.getUnwrappedDomContainer());',

+'						this.wrappedElementContainer = new LogEntryWrappedElementContainer(this, this.getWrappedDomContainer());',

+'						this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];',

+'					} else {',

+'						this.mainElementContainer = new LogEntryMainElementContainer(this, this.getMainDomContainer());',

+'						this.elementContainers = [this.mainElementContainer];',

+'					}',

+'					this.content = this.formattedMessage;',

+'					this.rendered = true;',

+'				},',

+'',

+'				setContent: function(content, wrappedContent) {',

+'					if (content != this.content) {',

+'						if (isIe && (content !== this.formattedMessage)) {',

+'							content = content.replace(/\\r\\n/g, "\\r"); // Workaround for IE\'s treatment of white space',

+'						}',

+'						for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'							this.elementContainers[i].setContent(content, wrappedContent);',

+'						}',

+'						this.content = content;',

+'					}',

+'				},',

+'',

+'				getSearchMatches: function() {',

+'					var matches = [];',

+'					var i, len;',

+'					if (isIe) {',

+'						var unwrappedEls = getElementsByClass(this.unwrappedElementContainer.mainDiv, "searchterm", "span");',

+'						var wrappedEls = getElementsByClass(this.wrappedElementContainer.mainDiv, "searchterm", "span");',

+'						for (i = 0, len = unwrappedEls.length; i < len; i++) {',

+'							matches[i] = new Match(this.level, null, unwrappedEls[i], wrappedEls[i]);',

+'						}',

+'					} else {',

+'						var els = getElementsByClass(this.mainElementContainer.mainDiv, "searchterm", "span");',

+'						for (i = 0, len = els.length; i < len; i++) {',

+'							matches[i] = new Match(this.level, els[i]);',

+'						}',

+'					}',

+'					return matches;',

+'				},',

+'',

+'				setSearchMatch: function(isMatch) {',

+'					for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'						this.elementContainers[i].setSearchMatch(isMatch);',

+'					}',

+'				},',

+'',

+'				clearSearch: function() {',

+'					for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'						this.elementContainers[i].clearSearch();',

+'					}',

+'				},',

+'',

+'				accept: function(visitor) {',

+'					visitor.visitLogEntry(this);',

+'				},',

+'',

+'				serialize: function(items) {',

+'					items.push([LogItem.serializedItemKeys.LOG_ENTRY, this.level, this.formattedMessage]);',

+'				}',

+'			});',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogItemVisitor() {',

+'			}',

+'',

+'			LogItemVisitor.prototype = {',

+'				visit: function(logItem) {',

+'				},',

+'',

+'				visitParent: function(logItem) {',

+'					if (logItem.group) {',

+'						logItem.group.accept(this);',

+'					}',

+'				},',

+'',

+'				visitChildren: function(logItem) {',

+'					for (var i = 0, len = logItem.children.length; i < len; i++) {',

+'						logItem.children[i].accept(this);',

+'					}',

+'				},',

+'',

+'				visitLogEntry: function(logEntry) {',

+'					this.visit(logEntry);',

+'				},',

+'',

+'				visitSeparator: function(separator) {',

+'					this.visit(separator);',

+'				},',

+'',

+'				visitGroup: function(group) {',

+'					this.visit(group);',

+'				}',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function GroupFlattener() {',

+'				this.logEntriesAndSeparators = [];',

+'			}',

+'',

+'			GroupFlattener.prototype = new LogItemVisitor();',

+'',

+'			GroupFlattener.prototype.visitGroup = function(group) {',

+'				this.visitChildren(group);',

+'			};',

+'',

+'			GroupFlattener.prototype.visitLogEntry = function(logEntry) {',

+'				this.logEntriesAndSeparators.push(logEntry);',

+'			};',

+'',

+'			GroupFlattener.prototype.visitSeparator = function(separator) {',

+'				this.logEntriesAndSeparators.push(separator);',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			window.onload = function() {',

+'				// Sort out document.domain',

+'				if (location.search) {',

+'					var queryBits = unescape(location.search).substr(1).split("&"), nameValueBits;',

+'					for (var i = 0, len = queryBits.length; i < len; i++) {',

+'						nameValueBits = queryBits[i].split("=");',

+'						if (nameValueBits[0] == "log4javascript_domain") {',

+'							document.domain = nameValueBits[1];',

+'							break;',

+'						}',

+'					}',

+'				}',

+'',

+'				// Create DOM objects',

+'				logMainContainer = $("log");',

+'				if (isIePre7) {',

+'					addClass(logMainContainer, "oldIe");',

+'				}',

+'',

+'				rootGroup = new Group("root", true);',

+'				rootGroup.render();',

+'				currentGroup = rootGroup;',

+'				',

+'				setCommandInputWidth();',

+'				setLogContainerHeight();',

+'				toggleLoggingEnabled();',

+'				toggleSearchEnabled();',

+'				toggleSearchFilter();',

+'				toggleSearchHighlight();',

+'				applyFilters();',

+'				checkAllLevels();',

+'				toggleWrap();',

+'				toggleNewestAtTop();',

+'				toggleScrollToLatest();',

+'				renderQueuedLogItems();',

+'				loaded = true;',

+'				$("command").value = "";',

+'				$("command").autocomplete = "off";',

+'				$("command").onkeydown = function(evt) {',

+'					evt = getEvent(evt);',

+'					if (evt.keyCode == 10 || evt.keyCode == 13) { // Return/Enter',

+'						evalCommandLine();',

+'						stopPropagation(evt);',

+'					} else if (evt.keyCode == 27) { // Escape',

+'						this.value = "";',

+'						this.focus();',

+'					} else if (evt.keyCode == 38 && commandHistory.length > 0) { // Up',

+'						currentCommandIndex = Math.max(0, currentCommandIndex - 1);',

+'						this.value = commandHistory[currentCommandIndex];',

+'						moveCaretToEnd(this);',

+'					} else if (evt.keyCode == 40 && commandHistory.length > 0) { // Down',

+'						currentCommandIndex = Math.min(commandHistory.length - 1, currentCommandIndex + 1);',

+'						this.value = commandHistory[currentCommandIndex];',

+'						moveCaretToEnd(this);',

+'					}',

+'				};',

+'',

+'				// Prevent the keypress moving the caret in Firefox',

+'				$("command").onkeypress = function(evt) {',

+'					evt = getEvent(evt);',

+'					if (evt.keyCode == 38 && commandHistory.length > 0 && evt.preventDefault) { // Up',

+'						evt.preventDefault();',

+'					}',

+'				};',

+'',

+'				// Prevent the keyup event blurring the input in Opera',

+'				$("command").onkeyup = function(evt) {',

+'					evt = getEvent(evt);',

+'					if (evt.keyCode == 27 && evt.preventDefault) { // Up',

+'						evt.preventDefault();',

+'						this.focus();',

+'					}',

+'				};',

+'',

+'				// Add document keyboard shortcuts',

+'				document.onkeydown = function keyEventHandler(evt) {',

+'					evt = getEvent(evt);',

+'					switch (evt.keyCode) {',

+'						case 69: // Ctrl + shift + E: re-execute last command',

+'							if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {',

+'								evalLastCommand();',

+'								cancelKeyEvent(evt);',

+'								return false;',

+'							}',

+'							break;',

+'						case 75: // Ctrl + shift + K: focus search',

+'							if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {',

+'								focusSearch();',

+'								cancelKeyEvent(evt);',

+'								return false;',

+'							}',

+'							break;',

+'						case 40: // Ctrl + shift + down arrow: focus command line',

+'						case 76: // Ctrl + shift + L: focus command line',

+'							if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {',

+'								focusCommandLine();',

+'								cancelKeyEvent(evt);',

+'								return false;',

+'							}',

+'							break;',

+'					}',

+'				};',

+'',

+'				// Workaround to make sure log div starts at the correct size',

+'				setTimeout(setLogContainerHeight, 20);',

+'',

+'				setShowCommandLine(showCommandLine);',

+'				doSearch();',

+'			};',

+'',

+'			window.onunload = function() {',

+'				if (mainWindowExists()) {',

+'					appender.unload();',

+'				}',

+'				appender = null;',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function toggleLoggingEnabled() {',

+'				setLoggingEnabled($("enableLogging").checked);',

+'			}',

+'',

+'			function setLoggingEnabled(enable) {',

+'				loggingEnabled = enable;',

+'			}',

+'',

+'			var appender = null;',

+'',

+'			function setAppender(appenderParam) {',

+'				appender = appenderParam;',

+'			}',

+'',

+'			function setShowCloseButton(showCloseButton) {',

+'				$("closeButton").style.display = showCloseButton ? "inline" : "none";',

+'			}',

+'',

+'			function setShowHideButton(showHideButton) {',

+'				$("hideButton").style.display = showHideButton ? "inline" : "none";',

+'			}',

+'',

+'			var newestAtTop = false;',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogItemContentReverser() {',

+'			}',

+'			',

+'			LogItemContentReverser.prototype = new LogItemVisitor();',

+'			',

+'			LogItemContentReverser.prototype.visitGroup = function(group) {',

+'				group.reverseChildren();',

+'				this.visitChildren(group);',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function setNewestAtTop(isNewestAtTop) {',

+'				var oldNewestAtTop = newestAtTop;',

+'				var i, iLen, j, jLen;',

+'				newestAtTop = Boolean(isNewestAtTop);',

+'				if (oldNewestAtTop != newestAtTop) {',

+'					var visitor = new LogItemContentReverser();',

+'					rootGroup.accept(visitor);',

+'',

+'					// Reassemble the matches array',

+'					if (currentSearch) {',

+'						var currentMatch = currentSearch.matches[currentMatchIndex];',

+'						var matchIndex = 0;',

+'						var matches = [];',

+'						var actOnLogEntry = function(logEntry) {',

+'							var logEntryMatches = logEntry.getSearchMatches();',

+'							for (j = 0, jLen = logEntryMatches.length; j < jLen; j++) {',

+'								matches[matchIndex] = logEntryMatches[j];',

+'								if (currentMatch && logEntryMatches[j].equals(currentMatch)) {',

+'									currentMatchIndex = matchIndex;',

+'								}',

+'								matchIndex++;',

+'							}',

+'						};',

+'						if (newestAtTop) {',

+'							for (i = logEntries.length - 1; i >= 0; i--) {',

+'								actOnLogEntry(logEntries[i]);',

+'							}',

+'						} else {',

+'							for (i = 0, iLen = logEntries.length; i < iLen; i++) {',

+'								actOnLogEntry(logEntries[i]);',

+'							}',

+'						}',

+'						currentSearch.matches = matches;',

+'						if (currentMatch) {',

+'							currentMatch.setCurrent();',

+'						}',

+'					} else if (scrollToLatest) {',

+'						doScrollToLatest();',

+'					}',

+'				}',

+'				$("newestAtTop").checked = isNewestAtTop;',

+'			}',

+'',

+'			function toggleNewestAtTop() {',

+'				var isNewestAtTop = $("newestAtTop").checked;',

+'				setNewestAtTop(isNewestAtTop);',

+'			}',

+'',

+'			var scrollToLatest = true;',

+'',

+'			function setScrollToLatest(isScrollToLatest) {',

+'				scrollToLatest = isScrollToLatest;',

+'				if (scrollToLatest) {',

+'					doScrollToLatest();',

+'				}',

+'				$("scrollToLatest").checked = isScrollToLatest;',

+'			}',

+'',

+'			function toggleScrollToLatest() {',

+'				var isScrollToLatest = $("scrollToLatest").checked;',

+'				setScrollToLatest(isScrollToLatest);',

+'			}',

+'',

+'			function doScrollToLatest() {',

+'				var l = logMainContainer;',

+'				if (typeof l.scrollTop != "undefined") {',

+'					if (newestAtTop) {',

+'						l.scrollTop = 0;',

+'					} else {',

+'						var latestLogEntry = l.lastChild;',

+'						if (latestLogEntry) {',

+'							l.scrollTop = l.scrollHeight;',

+'						}',

+'					}',

+'				}',

+'			}',

+'',

+'			var closeIfOpenerCloses = true;',

+'',

+'			function setCloseIfOpenerCloses(isCloseIfOpenerCloses) {',

+'				closeIfOpenerCloses = isCloseIfOpenerCloses;',

+'			}',

+'',

+'			var maxMessages = null;',

+'',

+'			function setMaxMessages(max) {',

+'				maxMessages = max;',

+'				pruneLogEntries();',

+'			}',

+'',

+'			var showCommandLine = false;',

+'',

+'			function setShowCommandLine(isShowCommandLine) {',

+'				showCommandLine = isShowCommandLine;',

+'				if (loaded) {',

+'					$("commandLine").style.display = showCommandLine ? "block" : "none";',

+'					setCommandInputWidth();',

+'					setLogContainerHeight();',

+'				}',

+'			}',

+'',

+'			function focusCommandLine() {',

+'				if (loaded) {',

+'					$("command").focus();',

+'				}',

+'			}',

+'',

+'			function focusSearch() {',

+'				if (loaded) {',

+'					$("searchBox").focus();',

+'				}',

+'			}',

+'',

+'			function getLogItems() {',

+'				var items = [];',

+'				for (var i = 0, len = logItems.length; i < len; i++) {',

+'					logItems[i].serialize(items);',

+'				}',

+'				return items;',

+'			}',

+'',

+'			function setLogItems(items) {',

+'				var loggingReallyEnabled = loggingEnabled;',

+'				// Temporarily turn logging on',

+'				loggingEnabled = true;',

+'				for (var i = 0, len = items.length; i < len; i++) {',

+'					switch (items[i][0]) {',

+'						case LogItem.serializedItemKeys.LOG_ENTRY:',

+'							log(items[i][1], items[i][2]);',

+'							break;',

+'						case LogItem.serializedItemKeys.GROUP_START:',

+'							group(items[i][1]);',

+'							break;',

+'						case LogItem.serializedItemKeys.GROUP_END:',

+'							groupEnd();',

+'							break;',

+'					}',

+'				}',

+'				loggingEnabled = loggingReallyEnabled;',

+'			}',

+'',

+'			function log(logLevel, formattedMessage) {',

+'				if (loggingEnabled) {',

+'					var logEntry = new LogEntry(logLevel, formattedMessage);',

+'					logEntries.push(logEntry);',

+'					logEntriesAndSeparators.push(logEntry);',

+'					logItems.push(logEntry);',

+'					currentGroup.addChild(logEntry);',

+'					if (loaded) {',

+'						if (logQueuedEventsTimer !== null) {',

+'							clearTimeout(logQueuedEventsTimer);',

+'						}',

+'						logQueuedEventsTimer = setTimeout(renderQueuedLogItems, renderDelay);',

+'						unrenderedLogItemsExist = true;',

+'					}',

+'				}',

+'			}',

+'',

+'			function renderQueuedLogItems() {',

+'				logQueuedEventsTimer = null;',

+'				var pruned = pruneLogEntries();',

+'',

+'				// Render any unrendered log entries and apply the current search to them',

+'				var initiallyHasMatches = currentSearch ? currentSearch.hasMatches() : false;',

+'				for (var i = 0, len = logItems.length; i < len; i++) {',

+'					if (!logItems[i].rendered) {',

+'						logItems[i].render();',

+'						logItems[i].appendToLog();',

+'						if (currentSearch && (logItems[i] instanceof LogEntry)) {',

+'							currentSearch.applyTo(logItems[i]);',

+'						}',

+'					}',

+'				}',

+'				if (currentSearch) {',

+'					if (pruned) {',

+'						if (currentSearch.hasVisibleMatches()) {',

+'							if (currentMatchIndex === null) {',

+'								setCurrentMatchIndex(0);',

+'							}',

+'							displayMatches();',

+'						} else {',

+'							displayNoMatches();',

+'						}',

+'					} else if (!initiallyHasMatches && currentSearch.hasVisibleMatches()) {',

+'						setCurrentMatchIndex(0);',

+'						displayMatches();',

+'					}',

+'				}',

+'				if (scrollToLatest) {',

+'					doScrollToLatest();',

+'				}',

+'				unrenderedLogItemsExist = false;',

+'			}',

+'',

+'			function pruneLogEntries() {',

+'				if ((maxMessages !== null) && (logEntriesAndSeparators.length > maxMessages)) {',

+'					var numberToDelete = logEntriesAndSeparators.length - maxMessages;',

+'					var prunedLogEntries = logEntriesAndSeparators.slice(0, numberToDelete);',

+'					if (currentSearch) {',

+'						currentSearch.removeMatches(prunedLogEntries);',

+'					}',

+'					var group;',

+'					for (var i = 0; i < numberToDelete; i++) {',

+'						group = logEntriesAndSeparators[i].group;',

+'						array_remove(logItems, logEntriesAndSeparators[i]);',

+'						array_remove(logEntries, logEntriesAndSeparators[i]);',

+'						logEntriesAndSeparators[i].remove(true, true);',

+'						if (group.children.length === 0 && group !== currentGroup && group !== rootGroup) {',

+'							array_remove(logItems, group);',

+'							group.remove(true, true);',

+'						}',

+'					}',

+'					logEntriesAndSeparators = array_removeFromStart(logEntriesAndSeparators, numberToDelete);',

+'					return true;',

+'				}',

+'				return false;',

+'			}',

+'',

+'			function group(name, startExpanded) {',

+'				if (loggingEnabled) {',

+'					initiallyExpanded = (typeof startExpanded === "undefined") ? true : Boolean(startExpanded);',

+'					var newGroup = new Group(name, false, initiallyExpanded);',

+'					currentGroup.addChild(newGroup);',

+'					currentGroup = newGroup;',

+'					logItems.push(newGroup);',

+'					if (loaded) {',

+'						if (logQueuedEventsTimer !== null) {',

+'							clearTimeout(logQueuedEventsTimer);',

+'						}',

+'						logQueuedEventsTimer = setTimeout(renderQueuedLogItems, renderDelay);',

+'						unrenderedLogItemsExist = true;',

+'					}',

+'				}',

+'			}',

+'',

+'			function groupEnd() {',

+'				currentGroup = (currentGroup === rootGroup) ? rootGroup : currentGroup.group;',

+'			}',

+'',

+'			function mainPageReloaded() {',

+'				currentGroup = rootGroup;',

+'				var separator = new Separator();',

+'				logEntriesAndSeparators.push(separator);',

+'				logItems.push(separator);',

+'				currentGroup.addChild(separator);',

+'			}',

+'',

+'			function closeWindow() {',

+'				if (appender && mainWindowExists()) {',

+'					appender.close(true);',

+'				} else {',

+'					window.close();',

+'				}',

+'			}',

+'',

+'			function hide() {',

+'				if (appender && mainWindowExists()) {',

+'					appender.hide();',

+'				}',

+'			}',

+'',

+'			var mainWindow = window;',

+'			var windowId = "log4javascriptConsoleWindow_" + new Date().getTime() + "_" + ("" + Math.random()).substr(2);',

+'',

+'			function setMainWindow(win) {',

+'				mainWindow = win;',

+'				mainWindow[windowId] = window;',

+'				// If this is a pop-up, poll the opener to see if it\'s closed',

+'				if (opener && closeIfOpenerCloses) {',

+'					pollOpener();',

+'				}',

+'			}',

+'',

+'			function pollOpener() {',

+'				if (closeIfOpenerCloses) {',

+'					if (mainWindowExists()) {',

+'						setTimeout(pollOpener, 500);',

+'					} else {',

+'						closeWindow();',

+'					}',

+'				}',

+'			}',

+'',

+'			function mainWindowExists() {',

+'				try {',

+'					return (mainWindow && !mainWindow.closed &&',

+'						mainWindow[windowId] == window);',

+'				} catch (ex) {}',

+'				return false;',

+'			}',

+'',

+'			var logLevels = ["TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"];',

+'',

+'			function getCheckBox(logLevel) {',

+'				return $("switch_" + logLevel);',

+'			}',

+'',

+'			function getIeWrappedLogContainer() {',

+'				return $("log_wrapped");',

+'			}',

+'',

+'			function getIeUnwrappedLogContainer() {',

+'				return $("log_unwrapped");',

+'			}',

+'',

+'			function applyFilters() {',

+'				for (var i = 0; i < logLevels.length; i++) {',

+'					if (getCheckBox(logLevels[i]).checked) {',

+'						addClass(logMainContainer, logLevels[i]);',

+'					} else {',

+'						removeClass(logMainContainer, logLevels[i]);',

+'					}',

+'				}',

+'				updateSearchFromFilters();',

+'			}',

+'',

+'			function toggleAllLevels() {',

+'				var turnOn = $("switch_ALL").checked;',

+'				for (var i = 0; i < logLevels.length; i++) {',

+'					getCheckBox(logLevels[i]).checked = turnOn;',

+'					if (turnOn) {',

+'						addClass(logMainContainer, logLevels[i]);',

+'					} else {',

+'						removeClass(logMainContainer, logLevels[i]);',

+'					}',

+'				}',

+'			}',

+'',

+'			function checkAllLevels() {',

+'				for (var i = 0; i < logLevels.length; i++) {',

+'					if (!getCheckBox(logLevels[i]).checked) {',

+'						getCheckBox("ALL").checked = false;',

+'						return;',

+'					}',

+'				}',

+'				getCheckBox("ALL").checked = true;',

+'			}',

+'',

+'			function clearLog() {',

+'				rootGroup.clear();',

+'				currentGroup = rootGroup;',

+'				logEntries = [];',

+'				logItems = [];',

+'				logEntriesAndSeparators = [];',

+' 				doSearch();',

+'			}',

+'',

+'			function toggleWrap() {',

+'				var enable = $("wrap").checked;',

+'				if (enable) {',

+'					addClass(logMainContainer, "wrap");',

+'				} else {',

+'					removeClass(logMainContainer, "wrap");',

+'				}',

+'				refreshCurrentMatch();',

+'			}',

+'',

+'			/* ------------------------------------------------------------------- */',

+'',

+'			// Search',

+'',

+'			var searchTimer = null;',

+'',

+'			function scheduleSearch() {',

+'				try {',

+'					clearTimeout(searchTimer);',

+'				} catch (ex) {',

+'					// Do nothing',

+'				}',

+'				searchTimer = setTimeout(doSearch, 500);',

+'			}',

+'',

+'			function Search(searchTerm, isRegex, searchRegex, isCaseSensitive) {',

+'				this.searchTerm = searchTerm;',

+'				this.isRegex = isRegex;',

+'				this.searchRegex = searchRegex;',

+'				this.isCaseSensitive = isCaseSensitive;',

+'				this.matches = [];',

+'			}',

+'',

+'			Search.prototype = {',

+'				hasMatches: function() {',

+'					return this.matches.length > 0;',

+'				},',

+'',

+'				hasVisibleMatches: function() {',

+'					if (this.hasMatches()) {',

+'						for (var i = 0; i < this.matches.length; i++) {',

+'							if (this.matches[i].isVisible()) {',

+'								return true;',

+'							}',

+'						}',

+'					}',

+'					return false;',

+'				},',

+'',

+'				match: function(logEntry) {',

+'					var entryText = String(logEntry.formattedMessage);',

+'					var matchesSearch = false;',

+'					if (this.isRegex) {',

+'						matchesSearch = this.searchRegex.test(entryText);',

+'					} else if (this.isCaseSensitive) {',

+'						matchesSearch = (entryText.indexOf(this.searchTerm) > -1);',

+'					} else {',

+'						matchesSearch = (entryText.toLowerCase().indexOf(this.searchTerm.toLowerCase()) > -1);',

+'					}',

+'					return matchesSearch;',

+'				},',

+'',

+'				getNextVisibleMatchIndex: function() {',

+'					for (var i = currentMatchIndex + 1; i < this.matches.length; i++) {',

+'						if (this.matches[i].isVisible()) {',

+'							return i;',

+'						}',

+'					}',

+'					// Start again from the first match',

+'					for (i = 0; i <= currentMatchIndex; i++) {',

+'						if (this.matches[i].isVisible()) {',

+'							return i;',

+'						}',

+'					}',

+'					return -1;',

+'				},',

+'',

+'				getPreviousVisibleMatchIndex: function() {',

+'					for (var i = currentMatchIndex - 1; i >= 0; i--) {',

+'						if (this.matches[i].isVisible()) {',

+'							return i;',

+'						}',

+'					}',

+'					// Start again from the last match',

+'					for (var i = this.matches.length - 1; i >= currentMatchIndex; i--) {',

+'						if (this.matches[i].isVisible()) {',

+'							return i;',

+'						}',

+'					}',

+'					return -1;',

+'				},',

+'',

+'				applyTo: function(logEntry) {',

+'					var doesMatch = this.match(logEntry);',

+'					if (doesMatch) {',

+'						logEntry.group.expand();',

+'						logEntry.setSearchMatch(true);',

+'						var logEntryContent;',

+'						var wrappedLogEntryContent;',

+'						var searchTermReplacementStartTag = "<span class=\\\"searchterm\\\">";',

+'						var searchTermReplacementEndTag = "<" + "/span>";',

+'						var preTagName = isIe ? "pre" : "span";',

+'						var preStartTag = "<" + preTagName + " class=\\\"pre\\\">";',

+'						var preEndTag = "<" + "/" + preTagName + ">";',

+'						var startIndex = 0;',

+'						var searchIndex, matchedText, textBeforeMatch;',

+'						if (this.isRegex) {',

+'							var flags = this.isCaseSensitive ? "g" : "gi";',

+'							var capturingRegex = new RegExp("(" + this.searchRegex.source + ")", flags);',

+'',

+'							// Replace the search term with temporary tokens for the start and end tags',

+'							var rnd = ("" + Math.random()).substr(2);',

+'							var startToken = "%%s" + rnd + "%%";',

+'							var endToken = "%%e" + rnd + "%%";',

+'							logEntryContent = logEntry.formattedMessage.replace(capturingRegex, startToken + "$1" + endToken);',

+'',

+'							// Escape the HTML to get rid of angle brackets',

+'							logEntryContent = escapeHtml(logEntryContent);',

+'',

+'							// Substitute the proper HTML back in for the search match',

+'							var result;',

+'							var searchString = logEntryContent;',

+'							logEntryContent = "";',

+'							wrappedLogEntryContent = "";',

+'							while ((searchIndex = searchString.indexOf(startToken, startIndex)) > -1) {',

+'								var endTokenIndex = searchString.indexOf(endToken, searchIndex);',

+'								matchedText = searchString.substring(searchIndex + startToken.length, endTokenIndex);',

+'								textBeforeMatch = searchString.substring(startIndex, searchIndex);',

+'								logEntryContent += preStartTag + textBeforeMatch + preEndTag;',

+'								logEntryContent += searchTermReplacementStartTag + preStartTag + matchedText +',

+'									preEndTag + searchTermReplacementEndTag;',

+'								if (isIe) {',

+'									wrappedLogEntryContent += textBeforeMatch + searchTermReplacementStartTag +',

+'										matchedText + searchTermReplacementEndTag;',

+'								}',

+'								startIndex = endTokenIndex + endToken.length;',

+'							}',

+'							logEntryContent += preStartTag + searchString.substr(startIndex) + preEndTag;',

+'							if (isIe) {',

+'								wrappedLogEntryContent += searchString.substr(startIndex);',

+'							}',

+'						} else {',

+'							logEntryContent = "";',

+'							wrappedLogEntryContent = "";',

+'							var searchTermReplacementLength = searchTermReplacementStartTag.length +',

+'								this.searchTerm.length + searchTermReplacementEndTag.length;',

+'							var searchTermLength = this.searchTerm.length;',

+'							var searchTermLowerCase = this.searchTerm.toLowerCase();',

+'							var logTextLowerCase = logEntry.formattedMessage.toLowerCase();',

+'							while ((searchIndex = logTextLowerCase.indexOf(searchTermLowerCase, startIndex)) > -1) {',

+'								matchedText = escapeHtml(logEntry.formattedMessage.substr(searchIndex, this.searchTerm.length));',

+'								textBeforeMatch = escapeHtml(logEntry.formattedMessage.substring(startIndex, searchIndex));',

+'								var searchTermReplacement = searchTermReplacementStartTag +',

+'									preStartTag + matchedText + preEndTag + searchTermReplacementEndTag;',

+'								logEntryContent += preStartTag + textBeforeMatch + preEndTag + searchTermReplacement;',

+'								if (isIe) {',

+'									wrappedLogEntryContent += textBeforeMatch + searchTermReplacementStartTag +',

+'										matchedText + searchTermReplacementEndTag;',

+'								}',

+'								startIndex = searchIndex + searchTermLength;',

+'							}',

+'							var textAfterLastMatch = escapeHtml(logEntry.formattedMessage.substr(startIndex));',

+'							logEntryContent += preStartTag + textAfterLastMatch + preEndTag;',

+'							if (isIe) {',

+'								wrappedLogEntryContent += textAfterLastMatch;',

+'							}',

+'						}',

+'						logEntry.setContent(logEntryContent, wrappedLogEntryContent);',

+'						var logEntryMatches = logEntry.getSearchMatches();',

+'						this.matches = this.matches.concat(logEntryMatches);',

+'					} else {',

+'						logEntry.setSearchMatch(false);',

+'						logEntry.setContent(logEntry.formattedMessage, logEntry.formattedMessage);',

+'					}',

+'					return doesMatch;',

+'				},',

+'',

+'				removeMatches: function(logEntries) {',

+'					var matchesToRemoveCount = 0;',

+'					var currentMatchRemoved = false;',

+'					var matchesToRemove = [];',

+'					var i, iLen, j, jLen;',

+'',

+'					// Establish the list of matches to be removed',

+'					for (i = 0, iLen = this.matches.length; i < iLen; i++) {',

+'						for (j = 0, jLen = logEntries.length; j < jLen; j++) {',

+'							if (this.matches[i].belongsTo(logEntries[j])) {',

+'								matchesToRemove.push(this.matches[i]);',

+'								if (i === currentMatchIndex) {',

+'									currentMatchRemoved = true;',

+'								}',

+'							}',

+'						}',

+'					}',

+'',

+'					// Set the new current match index if the current match has been deleted',

+'					// This will be the first match that appears after the first log entry being',

+'					// deleted, if one exists; otherwise, it\'s the first match overall',

+'					var newMatch = currentMatchRemoved ? null : this.matches[currentMatchIndex];',

+'					if (currentMatchRemoved) {',

+'						for (i = currentMatchIndex, iLen = this.matches.length; i < iLen; i++) {',

+'							if (this.matches[i].isVisible() && !array_contains(matchesToRemove, this.matches[i])) {',

+'								newMatch = this.matches[i];',

+'								break;',

+'							}',

+'						}',

+'					}',

+'',

+'					// Remove the matches',

+'					for (i = 0, iLen = matchesToRemove.length; i < iLen; i++) {',

+'						array_remove(this.matches, matchesToRemove[i]);',

+'						matchesToRemove[i].remove();',

+'					}',

+'',

+'					// Set the new match, if one exists',

+'					if (this.hasVisibleMatches()) {',

+'						if (newMatch === null) {',

+'							setCurrentMatchIndex(0);',

+'						} else {',

+'							// Get the index of the new match',

+'							var newMatchIndex = 0;',

+'							for (i = 0, iLen = this.matches.length; i < iLen; i++) {',

+'								if (newMatch === this.matches[i]) {',

+'									newMatchIndex = i;',

+'									break;',

+'								}',

+'							}',

+'							setCurrentMatchIndex(newMatchIndex);',

+'						}',

+'					} else {',

+'						currentMatchIndex = null;',

+'						displayNoMatches();',

+'					}',

+'				}',

+'			};',

+'',

+'			function getPageOffsetTop(el, container) {',

+'				var currentEl = el;',

+'				var y = 0;',

+'				while (currentEl && currentEl != container) {',

+'					y += currentEl.offsetTop;',

+'					currentEl = currentEl.offsetParent;',

+'				}',

+'				return y;',

+'			}',

+'',

+'			function scrollIntoView(el) {',

+'				var logContainer = logMainContainer;',

+'				// Check if the whole width of the element is visible and centre if not',

+'				if (!$("wrap").checked) {',

+'					var logContainerLeft = logContainer.scrollLeft;',

+'					var logContainerRight = logContainerLeft  + logContainer.offsetWidth;',

+'					var elLeft = el.offsetLeft;',

+'					var elRight = elLeft + el.offsetWidth;',

+'					if (elLeft < logContainerLeft || elRight > logContainerRight) {',

+'						logContainer.scrollLeft = elLeft - (logContainer.offsetWidth - el.offsetWidth) / 2;',

+'					}',

+'				}',

+'				// Check if the whole height of the element is visible and centre if not',

+'				var logContainerTop = logContainer.scrollTop;',

+'				var logContainerBottom = logContainerTop  + logContainer.offsetHeight;',

+'				var elTop = getPageOffsetTop(el) - getToolBarsHeight();',

+'				var elBottom = elTop + el.offsetHeight;',

+'				if (elTop < logContainerTop || elBottom > logContainerBottom) {',

+'					logContainer.scrollTop = elTop - (logContainer.offsetHeight - el.offsetHeight) / 2;',

+'				}',

+'			}',

+'',

+'			function Match(logEntryLevel, spanInMainDiv, spanInUnwrappedPre, spanInWrappedDiv) {',

+'				this.logEntryLevel = logEntryLevel;',

+'				this.spanInMainDiv = spanInMainDiv;',

+'				if (isIe) {',

+'					this.spanInUnwrappedPre = spanInUnwrappedPre;',

+'					this.spanInWrappedDiv = spanInWrappedDiv;',

+'				}',

+'				this.mainSpan = isIe ? spanInUnwrappedPre : spanInMainDiv;',

+'			}',

+'',

+'			Match.prototype = {',

+'				equals: function(match) {',

+'					return this.mainSpan === match.mainSpan;',

+'				},',

+'',

+'				setCurrent: function() {',

+'					if (isIe) {',

+'						addClass(this.spanInUnwrappedPre, "currentmatch");',

+'						addClass(this.spanInWrappedDiv, "currentmatch");',

+'						// Scroll the visible one into view',

+'						var elementToScroll = $("wrap").checked ? this.spanInWrappedDiv : this.spanInUnwrappedPre;',

+'						scrollIntoView(elementToScroll);',

+'					} else {',

+'						addClass(this.spanInMainDiv, "currentmatch");',

+'						scrollIntoView(this.spanInMainDiv);',

+'					}',

+'				},',

+'',

+'				belongsTo: function(logEntry) {',

+'					if (isIe) {',

+'						return isDescendant(this.spanInUnwrappedPre, logEntry.unwrappedPre);',

+'					} else {',

+'						return isDescendant(this.spanInMainDiv, logEntry.mainDiv);',

+'					}',

+'				},',

+'',

+'				setNotCurrent: function() {',

+'					if (isIe) {',

+'						removeClass(this.spanInUnwrappedPre, "currentmatch");',

+'						removeClass(this.spanInWrappedDiv, "currentmatch");',

+'					} else {',

+'						removeClass(this.spanInMainDiv, "currentmatch");',

+'					}',

+'				},',

+'',

+'				isOrphan: function() {',

+'					return isOrphan(this.mainSpan);',

+'				},',

+'',

+'				isVisible: function() {',

+'					return getCheckBox(this.logEntryLevel).checked;',

+'				},',

+'',

+'				remove: function() {',

+'					if (isIe) {',

+'						this.spanInUnwrappedPre = null;',

+'						this.spanInWrappedDiv = null;',

+'					} else {',

+'						this.spanInMainDiv = null;',

+'					}',

+'				}',

+'			};',

+'',

+'			var currentSearch = null;',

+'			var currentMatchIndex = null;',

+'',

+'			function doSearch() {',

+'				var searchBox = $("searchBox");',

+'				var searchTerm = searchBox.value;',

+'				var isRegex = $("searchRegex").checked;',

+'				var isCaseSensitive = $("searchCaseSensitive").checked;',

+'				var i;',

+'',

+'				if (searchTerm === "") {',

+'					$("searchReset").disabled = true;',

+'					$("searchNav").style.display = "none";',

+'					removeClass(document.body, "searching");',

+'					removeClass(searchBox, "hasmatches");',

+'					removeClass(searchBox, "nomatches");',

+'					for (i = 0; i < logEntries.length; i++) {',

+'						logEntries[i].clearSearch();',

+'						logEntries[i].setContent(logEntries[i].formattedMessage, logEntries[i].formattedMessage);',

+'					}',

+'					currentSearch = null;',

+'					setLogContainerHeight();',

+'				} else {',

+'					$("searchReset").disabled = false;',

+'					$("searchNav").style.display = "block";',

+'					var searchRegex;',

+'					var regexValid;',

+'					if (isRegex) {',

+'						try {',

+'							searchRegex = isCaseSensitive ? new RegExp(searchTerm, "g") : new RegExp(searchTerm, "gi");',

+'							regexValid = true;',

+'							replaceClass(searchBox, "validregex", "invalidregex");',

+'							searchBox.title = "Valid regex";',

+'						} catch (ex) {',

+'							regexValid = false;',

+'							replaceClass(searchBox, "invalidregex", "validregex");',

+'							searchBox.title = "Invalid regex: " + (ex.message ? ex.message : (ex.description ? ex.description : "unknown error"));',

+'							return;',

+'						}',

+'					} else {',

+'						searchBox.title = "";',

+'						removeClass(searchBox, "validregex");',

+'						removeClass(searchBox, "invalidregex");',

+'					}',

+'					addClass(document.body, "searching");',

+'					currentSearch = new Search(searchTerm, isRegex, searchRegex, isCaseSensitive);',

+'					for (i = 0; i < logEntries.length; i++) {',

+'						currentSearch.applyTo(logEntries[i]);',

+'					}',

+'					setLogContainerHeight();',

+'',

+'					// Highlight the first search match',

+'					if (currentSearch.hasVisibleMatches()) {',

+'						setCurrentMatchIndex(0);',

+'						displayMatches();',

+'					} else {',

+'						displayNoMatches();',

+'					}',

+'				}',

+'			}',

+'',

+'			function updateSearchFromFilters() {',

+'				if (currentSearch) {',

+'					if (currentSearch.hasMatches()) {',

+'						if (currentMatchIndex === null) {',

+'							currentMatchIndex = 0;',

+'						}',

+'						var currentMatch = currentSearch.matches[currentMatchIndex];',

+'						if (currentMatch.isVisible()) {',

+'							displayMatches();',

+'							setCurrentMatchIndex(currentMatchIndex);',

+'						} else {',

+'							currentMatch.setNotCurrent();',

+'							// Find the next visible match, if one exists',

+'							var nextVisibleMatchIndex = currentSearch.getNextVisibleMatchIndex();',

+'							if (nextVisibleMatchIndex > -1) {',

+'								setCurrentMatchIndex(nextVisibleMatchIndex);',

+'								displayMatches();',

+'							} else {',

+'								displayNoMatches();',

+'							}',

+'						}',

+'					} else {',

+'						displayNoMatches();',

+'					}',

+'				}',

+'			}',

+'',

+'			function refreshCurrentMatch() {',

+'				if (currentSearch && currentSearch.hasVisibleMatches()) {',

+'					setCurrentMatchIndex(currentMatchIndex);',

+'				}',

+'			}',

+'',

+'			function displayMatches() {',

+'				replaceClass($("searchBox"), "hasmatches", "nomatches");',

+'				$("searchBox").title = "" + currentSearch.matches.length + " matches found";',

+'				$("searchNav").style.display = "block";',

+'				setLogContainerHeight();',

+'			}',

+'',

+'			function displayNoMatches() {',

+'				replaceClass($("searchBox"), "nomatches", "hasmatches");',

+'				$("searchBox").title = "No matches found";',

+'				$("searchNav").style.display = "none";',

+'				setLogContainerHeight();',

+'			}',

+'',

+'			function toggleSearchEnabled(enable) {',

+'				enable = (typeof enable == "undefined") ? !$("searchDisable").checked : enable;',

+'				$("searchBox").disabled = !enable;',

+'				$("searchReset").disabled = !enable;',

+'				$("searchRegex").disabled = !enable;',

+'				$("searchNext").disabled = !enable;',

+'				$("searchPrevious").disabled = !enable;',

+'				$("searchCaseSensitive").disabled = !enable;',

+'				$("searchNav").style.display = (enable && ($("searchBox").value !== "") &&',

+'						currentSearch && currentSearch.hasVisibleMatches()) ?',

+'					"block" : "none";',

+'				if (enable) {',

+'					removeClass($("search"), "greyedout");',

+'					addClass(document.body, "searching");',

+'					if ($("searchHighlight").checked) {',

+'						addClass(logMainContainer, "searchhighlight");',

+'					} else {',

+'						removeClass(logMainContainer, "searchhighlight");',

+'					}',

+'					if ($("searchFilter").checked) {',

+'						addClass(logMainContainer, "searchfilter");',

+'					} else {',

+'						removeClass(logMainContainer, "searchfilter");',

+'					}',

+'					$("searchDisable").checked = !enable;',

+'				} else {',

+'					addClass($("search"), "greyedout");',

+'					removeClass(document.body, "searching");',

+'					removeClass(logMainContainer, "searchhighlight");',

+'					removeClass(logMainContainer, "searchfilter");',

+'				}',

+'				setLogContainerHeight();',

+'			}',

+'',

+'			function toggleSearchFilter() {',

+'				var enable = $("searchFilter").checked;',

+'				if (enable) {',

+'					addClass(logMainContainer, "searchfilter");',

+'				} else {',

+'					removeClass(logMainContainer, "searchfilter");',

+'				}',

+'				refreshCurrentMatch();',

+'			}',

+'',

+'			function toggleSearchHighlight() {',

+'				var enable = $("searchHighlight").checked;',

+'				if (enable) {',

+'					addClass(logMainContainer, "searchhighlight");',

+'				} else {',

+'					removeClass(logMainContainer, "searchhighlight");',

+'				}',

+'			}',

+'',

+'			function clearSearch() {',

+'				$("searchBox").value = "";',

+'				doSearch();',

+'			}',

+'',

+'			function searchNext() {',

+'				if (currentSearch !== null && currentMatchIndex !== null) {',

+'					currentSearch.matches[currentMatchIndex].setNotCurrent();',

+'					var nextMatchIndex = currentSearch.getNextVisibleMatchIndex();',

+'					if (nextMatchIndex > currentMatchIndex || confirm("Reached the end of the page. Start from the top?")) {',

+'						setCurrentMatchIndex(nextMatchIndex);',

+'					}',

+'				}',

+'			}',

+'',

+'			function searchPrevious() {',

+'				if (currentSearch !== null && currentMatchIndex !== null) {',

+'					currentSearch.matches[currentMatchIndex].setNotCurrent();',

+'					var previousMatchIndex = currentSearch.getPreviousVisibleMatchIndex();',

+'					if (previousMatchIndex < currentMatchIndex || confirm("Reached the start of the page. Continue from the bottom?")) {',

+'						setCurrentMatchIndex(previousMatchIndex);',

+'					}',

+'				}',

+'			}',

+'',

+'			function setCurrentMatchIndex(index) {',

+'				currentMatchIndex = index;',

+'				currentSearch.matches[currentMatchIndex].setCurrent();',

+'			}',

+'',

+'			/* ------------------------------------------------------------------------- */',

+'',

+'			// CSS Utilities',

+'',

+'			function addClass(el, cssClass) {',

+'				if (!hasClass(el, cssClass)) {',

+'					if (el.className) {',

+'						el.className += " " + cssClass;',

+'					} else {',

+'						el.className = cssClass;',

+'					}',

+'				}',

+'			}',

+'',

+'			function hasClass(el, cssClass) {',

+'				if (el.className) {',

+'					var classNames = el.className.split(" ");',

+'					return array_contains(classNames, cssClass);',

+'				}',

+'				return false;',

+'			}',

+'',

+'			function removeClass(el, cssClass) {',

+'				if (hasClass(el, cssClass)) {',

+'					// Rebuild the className property',

+'					var existingClasses = el.className.split(" ");',

+'					var newClasses = [];',

+'					for (var i = 0, len = existingClasses.length; i < len; i++) {',

+'						if (existingClasses[i] != cssClass) {',

+'							newClasses[newClasses.length] = existingClasses[i];',

+'						}',

+'					}',

+'					el.className = newClasses.join(" ");',

+'				}',

+'			}',

+'',

+'			function replaceClass(el, newCssClass, oldCssClass) {',

+'				removeClass(el, oldCssClass);',

+'				addClass(el, newCssClass);',

+'			}',

+'',

+'			/* ------------------------------------------------------------------------- */',

+'',

+'			// Other utility functions',

+'',

+'			function getElementsByClass(el, cssClass, tagName) {',

+'				var elements = el.getElementsByTagName(tagName);',

+'				var matches = [];',

+'				for (var i = 0, len = elements.length; i < len; i++) {',

+'					if (hasClass(elements[i], cssClass)) {',

+'						matches.push(elements[i]);',

+'					}',

+'				}',

+'				return matches;',

+'			}',

+'',

+'			// Syntax borrowed from Prototype library',

+'			function $(id) {',

+'				return document.getElementById(id);',

+'			}',

+'',

+'			function isDescendant(node, ancestorNode) {',

+'				while (node != null) {',

+'					if (node === ancestorNode) {',

+'						return true;',

+'					}',

+'					node = node.parentNode;',

+'				}',

+'				return false;',

+'			}',

+'',

+'			function isOrphan(node) {',

+'				var currentNode = node;',

+'				while (currentNode) {',

+'					if (currentNode == document.body) {',

+'						return false;',

+'					}',

+'					currentNode = currentNode.parentNode;',

+'				}',

+'				return true;',

+'			}',

+'',

+'			function escapeHtml(str) {',

+'				return str.replace(/&/g, "&amp;").replace(/[<]/g, "&lt;").replace(/>/g, "&gt;");',

+'			}',

+'',

+'			function getWindowWidth() {',

+'				if (window.innerWidth) {',

+'					return window.innerWidth;',

+'				} else if (document.documentElement && document.documentElement.clientWidth) {',

+'					return document.documentElement.clientWidth;',

+'				} else if (document.body) {',

+'					return document.body.clientWidth;',

+'				}',

+'				return 0;',

+'			}',

+'',

+'			function getWindowHeight() {',

+'				if (window.innerHeight) {',

+'					return window.innerHeight;',

+'				} else if (document.documentElement && document.documentElement.clientHeight) {',

+'					return document.documentElement.clientHeight;',

+'				} else if (document.body) {',

+'					return document.body.clientHeight;',

+'				}',

+'				return 0;',

+'			}',

+'',

+'			function getToolBarsHeight() {',

+'				return $("switches").offsetHeight;',

+'			}',

+'',

+'			function getChromeHeight() {',

+'				var height = getToolBarsHeight();',

+'				if (showCommandLine) {',

+'					height += $("commandLine").offsetHeight;',

+'				}',

+'				return height;',

+'			}',

+'',

+'			function setLogContainerHeight() {',

+'				if (logMainContainer) {',

+'					var windowHeight = getWindowHeight();',

+'					$("body").style.height = getWindowHeight() + "px";',

+'					logMainContainer.style.height = "" +',

+'						Math.max(0, windowHeight - getChromeHeight()) + "px";',

+'				}',

+'			}',

+'',

+'			function setCommandInputWidth() {',

+'				if (showCommandLine) {',

+'					$("command").style.width = "" + Math.max(0, $("commandLineContainer").offsetWidth -',

+'						($("evaluateButton").offsetWidth + 13)) + "px";',

+'				}',

+'			}',

+'',

+'			window.onresize = function() {',

+'				setCommandInputWidth();',

+'				setLogContainerHeight();',

+'			};',

+'',

+'			if (!Array.prototype.push) {',

+'				Array.prototype.push = function() {',

+'			        for (var i = 0, len = arguments.length; i < len; i++){',

+'			            this[this.length] = arguments[i];',

+'			        }',

+'			        return this.length;',

+'				};',

+'			}',

+'',

+'			if (!Array.prototype.pop) {',

+'				Array.prototype.pop = function() {',

+'					if (this.length > 0) {',

+'						var val = this[this.length - 1];',

+'						this.length = this.length - 1;',

+'						return val;',

+'					}',

+'				};',

+'			}',

+'',

+'			if (!Array.prototype.shift) {',

+'				Array.prototype.shift = function() {',

+'					if (this.length > 0) {',

+'						var firstItem = this[0];',

+'						for (var i = 0, len = this.length - 1; i < len; i++) {',

+'							this[i] = this[i + 1];',

+'						}',

+'						this.length = this.length - 1;',

+'						return firstItem;',

+'					}',

+'				};',

+'			}',

+'',

+'			if (!Array.prototype.splice) {',

+'				Array.prototype.splice = function(startIndex, deleteCount) {',

+'					var itemsAfterDeleted = this.slice(startIndex + deleteCount);',

+'					var itemsDeleted = this.slice(startIndex, startIndex + deleteCount);',

+'					this.length = startIndex;',

+'					// Copy the arguments into a proper Array object',

+'					var argumentsArray = [];',

+'					for (var i = 0, len = arguments.length; i < len; i++) {',

+'						argumentsArray[i] = arguments[i];',

+'					}',

+'					var itemsToAppend = (argumentsArray.length > 2) ?',

+'						itemsAfterDeleted = argumentsArray.slice(2).concat(itemsAfterDeleted) : itemsAfterDeleted;',

+'					for (i = 0, len = itemsToAppend.length; i < len; i++) {',

+'						this.push(itemsToAppend[i]);',

+'					}',

+'					return itemsDeleted;',

+'				};',

+'			}',

+'',

+'			function array_remove(arr, val) {',

+'				var index = -1;',

+'				for (var i = 0, len = arr.length; i < len; i++) {',

+'					if (arr[i] === val) {',

+'						index = i;',

+'						break;',

+'					}',

+'				}',

+'				if (index >= 0) {',

+'					arr.splice(index, 1);',

+'					return index;',

+'				} else {',

+'					return false;',

+'				}',

+'			}',

+'',

+'			function array_removeFromStart(array, numberToRemove) {',

+'				if (Array.prototype.splice) {',

+'					array.splice(0, numberToRemove);',

+'				} else {',

+'					for (var i = numberToRemove, len = array.length; i < len; i++) {',

+'						array[i - numberToRemove] = array[i];',

+'					}',

+'					array.length = array.length - numberToRemove;',

+'				}',

+'				return array;',

+'			}',

+'',

+'			function array_contains(arr, val) {',

+'				for (var i = 0, len = arr.length; i < len; i++) {',

+'					if (arr[i] == val) {',

+'						return true;',

+'					}',

+'				}',

+'				return false;',

+'			}',

+'',

+'			function getErrorMessage(ex) {',

+'				if (ex.message) {',

+'					return ex.message;',

+'				} else if (ex.description) {',

+'					return ex.description;',

+'				}',

+'				return "" + ex;',

+'			}',

+'',

+'			function moveCaretToEnd(input) {',

+'				if (input.setSelectionRange) {',

+'					input.focus();',

+'					var length = input.value.length;',

+'					input.setSelectionRange(length, length);',

+'				} else if (input.createTextRange) {',

+'					var range = input.createTextRange();',

+'					range.collapse(false);',

+'					range.select();',

+'				}',

+'				input.focus();',

+'			}',

+'',

+'			function stopPropagation(evt) {',

+'				if (evt.stopPropagation) {',

+'					evt.stopPropagation();',

+'				} else if (typeof evt.cancelBubble != "undefined") {',

+'					evt.cancelBubble = true;',

+'				}',

+'			}',

+'',

+'			function getEvent(evt) {',

+'				return evt ? evt : event;',

+'			}',

+'',

+'			function getTarget(evt) {',

+'				return evt.target ? evt.target : evt.srcElement;',

+'			}',

+'',

+'			function getRelatedTarget(evt) {',

+'				if (evt.relatedTarget) {',

+'					return evt.relatedTarget;',

+'				} else if (evt.srcElement) {',

+'					switch(evt.type) {',

+'						case "mouseover":',

+'							return evt.fromElement;',

+'						case "mouseout":',

+'							return evt.toElement;',

+'						default:',

+'							return evt.srcElement;',

+'					}',

+'				}',

+'			}',

+'',

+'			function cancelKeyEvent(evt) {',

+'				evt.returnValue = false;',

+'				stopPropagation(evt);',

+'			}',

+'',

+'			function evalCommandLine() {',

+'				var expr = $("command").value;',

+'				evalCommand(expr);',

+'				$("command").value = "";',

+'			}',

+'',

+'			function evalLastCommand() {',

+'				if (lastCommand != null) {',

+'					evalCommand(lastCommand);',

+'				}',

+'			}',

+'',

+'			var lastCommand = null;',

+'			var commandHistory = [];',

+'			var currentCommandIndex = 0;',

+'',

+'			function evalCommand(expr) {',

+'				if (appender) {',

+'					appender.evalCommandAndAppend(expr);',

+'				} else {',

+'					var prefix = ">>> " + expr + "\\r\\n";',

+'					try {',

+'						log("INFO", prefix + eval(expr));',

+'					} catch (ex) {',

+'						log("ERROR", prefix + "Error: " + getErrorMessage(ex));',

+'					}',

+'				}',

+'				// Update command history',

+'				if (expr != commandHistory[commandHistory.length - 1]) {',

+'					commandHistory.push(expr);',

+'					// Update the appender',

+'					if (appender) {',

+'						appender.storeCommandHistory(commandHistory);',

+'					}',

+'				}',

+'				currentCommandIndex = (expr == commandHistory[currentCommandIndex]) ? currentCommandIndex + 1 : commandHistory.length;',

+'				lastCommand = expr;',

+'			}',

+'			//]]>',

+'		</script>',

+'		<style type="text/css">',

+'			body {',

+'				background-color: white;',

+'				color: black;',

+'				padding: 0;',

+'				margin: 0;',

+'				font-family: tahoma, verdana, arial, helvetica, sans-serif;',

+'				overflow: hidden;',

+'			}',

+'',

+'			div#switchesContainer input {',

+'				margin-bottom: 0;',

+'			}',

+'',

+'			div.toolbar {',

+'				border-top: solid #ffffff 1px;',

+'				border-bottom: solid #aca899 1px;',

+'				background-color: #f1efe7;',

+'				padding: 3px 5px;',

+'				font-size: 68.75%;',

+'			}',

+'',

+'			div.toolbar, div#search input {',

+'				font-family: tahoma, verdana, arial, helvetica, sans-serif;',

+'			}',

+'',

+'			div.toolbar input.button {',

+'				padding: 0 5px;',

+'				font-size: 100%;',

+'			}',

+'',

+'			div.toolbar input.hidden {',

+'				display: none;',

+'			}',

+'',

+'			div#switches input#clearButton {',

+'				margin-left: 20px;',

+'			}',

+'',

+'			div#levels label {',

+'				font-weight: bold;',

+'			}',

+'',

+'			div#levels label, div#options label {',

+'				margin-right: 5px;',

+'			}',

+'',

+'			div#levels label#wrapLabel {',

+'				font-weight: normal;',

+'			}',

+'',

+'			div#search label {',

+'				margin-right: 10px;',

+'			}',

+'',

+'			div#search label.searchboxlabel {',

+'				margin-right: 0;',

+'			}',

+'',

+'			div#search input {',

+'				font-size: 100%;',

+'			}',

+'',

+'			div#search input.validregex {',

+'				color: green;',

+'			}',

+'',

+'			div#search input.invalidregex {',

+'				color: red;',

+'			}',

+'',

+'			div#search input.nomatches {',

+'				color: white;',

+'				background-color: #ff6666;',

+'			}',

+'',

+'			div#search input.nomatches {',

+'				color: white;',

+'				background-color: #ff6666;',

+'			}',

+'',

+'			div#searchNav {',

+'				display: none;',

+'			}',

+'',

+'			div#commandLine {',

+'				display: none;',

+'			}',

+'',

+'			div#commandLine input#command {',

+'				font-size: 100%;',

+'				font-family: Courier New, Courier;',

+'			}',

+'',

+'			div#commandLine input#evaluateButton {',

+'			}',

+'',

+'			*.greyedout {',

+'				color: gray !important;',

+'				border-color: gray !important;',

+'			}',

+'',

+'			*.greyedout *.alwaysenabled { color: black; }',

+'',

+'			*.unselectable {',

+'				-khtml-user-select: none;',

+'				-moz-user-select: none;',

+'				user-select: none;',

+'			}',

+'',

+'			div#log {',

+'				font-family: Courier New, Courier;',

+'				font-size: 75%;',

+'				width: 100%;',

+'				overflow: auto;',

+'				clear: both;',

+'				position: relative;',

+'			}',

+'',

+'			div.group {',

+'				border-color: #cccccc;',

+'				border-style: solid;',

+'				border-width: 1px 0 1px 1px;',

+'				overflow: visible;',

+'			}',

+'',

+'			div.oldIe div.group, div.oldIe div.group *, div.oldIe *.logentry {',

+'				height: 1%;',

+'			}',

+'',

+'			div.group div.groupheading span.expander {',

+'				border: solid black 1px;',

+'				font-family: Courier New, Courier;',

+'				font-size: 0.833em;',

+'				background-color: #eeeeee;',

+'				position: relative;',

+'				top: -1px;',

+'				color: black;',

+'				padding: 0 2px;',

+'				cursor: pointer;',

+'				cursor: hand;',

+'				height: 1%;',

+'			}',

+'',

+'			div.group div.groupcontent {',

+'				margin-left: 10px;',

+'				padding-bottom: 2px;',

+'				overflow: visible;',

+'			}',

+'',

+'			div.group div.expanded {',

+'				display: block;',

+'			}',

+'',

+'			div.group div.collapsed {',

+'				display: none;',

+'			}',

+'',

+'			*.logentry {',

+'				overflow: visible;',

+'				display: none;',

+'				white-space: pre;',

+'			}',

+'',

+'			span.pre {',

+'				white-space: pre;',

+'			}',

+'			',

+'			pre.unwrapped {',

+'				display: inline !important;',

+'			}',

+'',

+'			pre.unwrapped pre.pre, div.wrapped pre.pre {',

+'				display: inline;',

+'			}',

+'',

+'			div.wrapped pre.pre {',

+'				white-space: normal;',

+'			}',

+'',

+'			div.wrapped {',

+'				display: none;',

+'			}',

+'',

+'			body.searching *.logentry span.currentmatch {',

+'				color: white !important;',

+'				background-color: green !important;',

+'			}',

+'',

+'			body.searching div.searchhighlight *.logentry span.searchterm {',

+'				color: black;',

+'				background-color: yellow;',

+'			}',

+'',

+'			div.wrap *.logentry {',

+'				white-space: normal !important;',

+'				border-width: 0 0 1px 0;',

+'				border-color: #dddddd;',

+'				border-style: dotted;',

+'			}',

+'',

+'			div.wrap #log_wrapped, #log_unwrapped {',

+'				display: block;',

+'			}',

+'',

+'			div.wrap #log_unwrapped, #log_wrapped {',

+'				display: none;',

+'			}',

+'',

+'			div.wrap *.logentry span.pre {',

+'				overflow: visible;',

+'				white-space: normal;',

+'			}',

+'',

+'			div.wrap *.logentry pre.unwrapped {',

+'				display: none;',

+'			}',

+'',

+'			div.wrap *.logentry span.wrapped {',

+'				display: inline;',

+'			}',

+'',

+'			div.searchfilter *.searchnonmatch {',

+'				display: none !important;',

+'			}',

+'',

+'			div#log *.TRACE, label#label_TRACE {',

+'				color: #666666;',

+'			}',

+'',

+'			div#log *.DEBUG, label#label_DEBUG {',

+'				color: green;',

+'			}',

+'',

+'			div#log *.INFO, label#label_INFO {',

+'				color: #000099;',

+'			}',

+'',

+'			div#log *.WARN, label#label_WARN {',

+'				color: #999900;',

+'			}',

+'',

+'			div#log *.ERROR, label#label_ERROR {',

+'				color: red;',

+'			}',

+'',

+'			div#log *.FATAL, label#label_FATAL {',

+'				color: #660066;',

+'			}',

+'',

+'			div.TRACE#log *.TRACE,',

+'			div.DEBUG#log *.DEBUG,',

+'			div.INFO#log *.INFO,',

+'			div.WARN#log *.WARN,',

+'			div.ERROR#log *.ERROR,',

+'			div.FATAL#log *.FATAL {',

+'				display: block;',

+'			}',

+'',

+'			div#log div.separator {',

+'				background-color: #cccccc;',

+'				margin: 5px 0;',

+'				line-height: 1px;',

+'			}',

+'		</style>',

+'	</head>',

+'',

+'	<body id="body">',

+'		<div id="switchesContainer">',

+'			<div id="switches">',

+'				<div id="levels" class="toolbar">',

+'					Filters:',

+'					<input type="checkbox" id="switch_TRACE" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide trace messages" /><label for="switch_TRACE" id="label_TRACE">trace</label>',

+'					<input type="checkbox" id="switch_DEBUG" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide debug messages" /><label for="switch_DEBUG" id="label_DEBUG">debug</label>',

+'					<input type="checkbox" id="switch_INFO" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide info messages" /><label for="switch_INFO" id="label_INFO">info</label>',

+'					<input type="checkbox" id="switch_WARN" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide warn messages" /><label for="switch_WARN" id="label_WARN">warn</label>',

+'					<input type="checkbox" id="switch_ERROR" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide error messages" /><label for="switch_ERROR" id="label_ERROR">error</label>',

+'					<input type="checkbox" id="switch_FATAL" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide fatal messages" /><label for="switch_FATAL" id="label_FATAL">fatal</label>',

+'					<input type="checkbox" id="switch_ALL" onclick="toggleAllLevels(); applyFilters()" checked="checked" title="Show/hide all messages" /><label for="switch_ALL" id="label_ALL">all</label>',

+'				</div>',

+'				<div id="search" class="toolbar">',

+'					<label for="searchBox" class="searchboxlabel">Search:</label> <input type="text" id="searchBox" onclick="toggleSearchEnabled(true)" onkeyup="scheduleSearch()" size="20" />',

+'					<input type="button" id="searchReset" disabled="disabled" value="Reset" onclick="clearSearch()" class="button" title="Reset the search" />',

+'					<input type="checkbox" id="searchRegex" onclick="doSearch()" title="If checked, search is treated as a regular expression" /><label for="searchRegex">Regex</label>',

+'					<input type="checkbox" id="searchCaseSensitive" onclick="doSearch()" title="If checked, search is case sensitive" /><label for="searchCaseSensitive">Match case</label>',

+'					<input type="checkbox" id="searchDisable" onclick="toggleSearchEnabled()" title="Enable/disable search" /><label for="searchDisable" class="alwaysenabled">Disable</label>',

+'					<div id="searchNav">',

+'						<input type="button" id="searchNext" disabled="disabled" value="Next" onclick="searchNext()" class="button" title="Go to the next matching log entry" />',

+'						<input type="button" id="searchPrevious" disabled="disabled" value="Previous" onclick="searchPrevious()" class="button" title="Go to the previous matching log entry" />',

+'						<input type="checkbox" id="searchFilter" onclick="toggleSearchFilter()" title="If checked, non-matching log entries are filtered out" /><label for="searchFilter">Filter</label>',

+'						<input type="checkbox" id="searchHighlight" onclick="toggleSearchHighlight()" title="Highlight matched search terms" /><label for="searchHighlight" class="alwaysenabled">Highlight all</label>',

+'					</div>',

+'				</div>',

+'				<div id="options" class="toolbar">',

+'					Options:',

+'					<input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Log</label>',

+'					<input type="checkbox" id="wrap" onclick="toggleWrap()" title="Enable / disable word wrap" /><label for="wrap" id="wrapLabel">Wrap</label>',

+'					<input type="checkbox" id="newestAtTop" onclick="toggleNewestAtTop()" title="If checked, causes newest messages to appear at the top" /><label for="newestAtTop" id="newestAtTopLabel">Newest at the top</label>',

+'					<input type="checkbox" id="scrollToLatest" onclick="toggleScrollToLatest()" checked="checked" title="If checked, window automatically scrolls to a new message when it is added" /><label for="scrollToLatest" id="scrollToLatestLabel">Scroll to latest</label>',

+'					<input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="button" title="Clear all log messages"  />',

+'					<input type="button" id="hideButton" value="Hide" onclick="hide()" class="hidden button" title="Hide the console" />',

+'					<input type="button" id="closeButton" value="Close" onclick="closeWindow()" class="hidden button" title="Close the window" />',

+'				</div>',

+'			</div>',

+'		</div>',

+'		<div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>',

+'		<div id="commandLine" class="toolbar">',

+'			<div id="commandLineContainer">',

+'				<input type="text" id="command" title="Enter a JavaScript command here and hit return or press \'Evaluate\'" />',

+'				<input type="button" id="evaluateButton" value="Evaluate" class="button" title="Evaluate the command" onclick="evalCommandLine()" />',

+'			</div>',

+'		</div>',

+'	</body>',

+'</html>',

+''

+];

+		};

+

+		var defaultCommandLineFunctions = [];

+

+		ConsoleAppender = function() {};

+

+		var consoleAppenderIdCounter = 1;

+		ConsoleAppender.prototype = new Appender();

+

+		ConsoleAppender.prototype.create = function(inPage, container,

+				lazyInit, initiallyMinimized, useDocumentWrite, width, height, focusConsoleWindow) {

+			var appender = this;

+

+			// Common properties

+			var initialized = false;

+			var consoleWindowCreated = false;

+			var consoleWindowLoaded = false;

+			var consoleClosed = false;

+

+			var queuedLoggingEvents = [];

+			var isSupported = true;

+			var consoleAppenderId = consoleAppenderIdCounter++;

+

+			// Local variables

+			initiallyMinimized = extractBooleanFromParam(initiallyMinimized, this.defaults.initiallyMinimized);

+			lazyInit = extractBooleanFromParam(lazyInit, this.defaults.lazyInit);

+			useDocumentWrite = extractBooleanFromParam(useDocumentWrite, this.defaults.useDocumentWrite);

+			var newestMessageAtTop = this.defaults.newestMessageAtTop;

+			var scrollToLatestMessage = this.defaults.scrollToLatestMessage;

+			width = width ? width : this.defaults.width;

+			height = height ? height : this.defaults.height;

+			var maxMessages = this.defaults.maxMessages;

+			var showCommandLine = this.defaults.showCommandLine;

+			var commandLineObjectExpansionDepth = this.defaults.commandLineObjectExpansionDepth;

+			var showHideButton = this.defaults.showHideButton;

+            var showCloseButton = this.defaults.showCloseButton;

+            var showLogEntryDeleteButtons = this.defaults.showLogEntryDeleteButtons;

+

+			this.setLayout(this.defaults.layout);

+

+			// Functions whose implementations vary between subclasses

+			var init, createWindow, safeToAppend, getConsoleWindow, open;

+

+			// Configuration methods. The function scope is used to prevent

+			// direct alteration to the appender configuration properties.

+			var appenderName = inPage ? "InPageAppender" : "PopUpAppender";

+			var checkCanConfigure = function(configOptionName) {

+				if (consoleWindowCreated) {

+					handleError(appenderName + ": configuration option '" + configOptionName + "' may not be set after the appender has been initialized");

+					return false;

+				}

+				return true;

+			};

+

+			var consoleWindowExists = function() {

+				return (consoleWindowLoaded && isSupported && !consoleClosed);

+			};

+

+			this.isNewestMessageAtTop = function() { return newestMessageAtTop; };

+			this.setNewestMessageAtTop = function(newestMessageAtTopParam) {

+				newestMessageAtTop = bool(newestMessageAtTopParam);

+				if (consoleWindowExists()) {

+					getConsoleWindow().setNewestAtTop(newestMessageAtTop);

+				}

+			};

+

+			this.isScrollToLatestMessage = function() { return scrollToLatestMessage; };

+			this.setScrollToLatestMessage = function(scrollToLatestMessageParam) {

+				scrollToLatestMessage = bool(scrollToLatestMessageParam);

+				if (consoleWindowExists()) {

+					getConsoleWindow().setScrollToLatest(scrollToLatestMessage);

+				}

+			};

+

+			this.getWidth = function() { return width; };

+			this.setWidth = function(widthParam) {

+				if (checkCanConfigure("width")) {

+					width = extractStringFromParam(widthParam, width);

+				}

+			};

+

+			this.getHeight = function() { return height; };

+			this.setHeight = function(heightParam) {

+				if (checkCanConfigure("height")) {

+					height = extractStringFromParam(heightParam, height);

+				}

+			};

+

+			this.getMaxMessages = function() { return maxMessages; };

+			this.setMaxMessages = function(maxMessagesParam) {

+				maxMessages = extractIntFromParam(maxMessagesParam, maxMessages);

+				if (consoleWindowExists()) {

+					getConsoleWindow().setMaxMessages(maxMessages);

+				}

+			};

+

+			this.isShowCommandLine = function() { return showCommandLine; };

+			this.setShowCommandLine = function(showCommandLineParam) {

+				showCommandLine = bool(showCommandLineParam);

+				if (consoleWindowExists()) {

+					getConsoleWindow().setShowCommandLine(showCommandLine);

+				}

+			};

+

+			this.isShowHideButton = function() { return showHideButton; };

+			this.setShowHideButton = function(showHideButtonParam) {

+				showHideButton = bool(showHideButtonParam);

+				if (consoleWindowExists()) {

+					getConsoleWindow().setShowHideButton(showHideButton);

+				}

+			};

+

+			this.isShowCloseButton = function() { return showCloseButton; };

+			this.setShowCloseButton = function(showCloseButtonParam) {

+				showCloseButton = bool(showCloseButtonParam);

+				if (consoleWindowExists()) {

+					getConsoleWindow().setShowCloseButton(showCloseButton);

+				}

+			};

+

+			this.getCommandLineObjectExpansionDepth = function() { return commandLineObjectExpansionDepth; };

+			this.setCommandLineObjectExpansionDepth = function(commandLineObjectExpansionDepthParam) {

+				commandLineObjectExpansionDepth = extractIntFromParam(commandLineObjectExpansionDepthParam, commandLineObjectExpansionDepth);

+			};

+

+			var minimized = initiallyMinimized;

+			this.isInitiallyMinimized = function() { return initiallyMinimized; };

+			this.setInitiallyMinimized = function(initiallyMinimizedParam) {

+				if (checkCanConfigure("initiallyMinimized")) {

+					initiallyMinimized = bool(initiallyMinimizedParam);

+					minimized = initiallyMinimized;

+				}

+			};

+

+			this.isUseDocumentWrite = function() { return useDocumentWrite; };

+			this.setUseDocumentWrite = function(useDocumentWriteParam) {

+				if (checkCanConfigure("useDocumentWrite")) {

+					useDocumentWrite = bool(useDocumentWriteParam);

+				}

+			};

+

+			// Common methods

+			function QueuedLoggingEvent(loggingEvent, formattedMessage) {

+				this.loggingEvent = loggingEvent;

+				this.levelName = loggingEvent.level.name;

+				this.formattedMessage = formattedMessage;

+			}

+

+			QueuedLoggingEvent.prototype.append = function() {

+				getConsoleWindow().log(this.levelName, this.formattedMessage);

+			};

+

+			function QueuedGroup(name, initiallyExpanded) {

+				this.name = name;

+				this.initiallyExpanded = initiallyExpanded;

+			}

+

+			QueuedGroup.prototype.append = function() {

+				getConsoleWindow().group(this.name, this.initiallyExpanded);

+			};

+

+			function QueuedGroupEnd() {}

+

+			QueuedGroupEnd.prototype.append = function() {

+				getConsoleWindow().groupEnd();

+			};

+

+			var checkAndAppend = function() {

+				// Next line forces a check of whether the window has been closed

+				safeToAppend();

+				if (!initialized) {

+					init();

+				} else if (consoleClosed && reopenWhenClosed) {

+					createWindow();

+				}

+				if (safeToAppend()) {

+					appendQueuedLoggingEvents();

+				}

+			};

+

+			this.append = function(loggingEvent) {

+				if (isSupported) {

+					// Format the message

+					var formattedMessage = appender.getLayout().format(loggingEvent);

+					if (this.getLayout().ignoresThrowable()) {

+						formattedMessage += loggingEvent.getThrowableStrRep();

+					}

+					queuedLoggingEvents.push(new QueuedLoggingEvent(loggingEvent, formattedMessage));

+					checkAndAppend();

+				}

+			};

+

+            this.group = function(name, initiallyExpanded) {

+				if (isSupported) {

+					queuedLoggingEvents.push(new QueuedGroup(name, initiallyExpanded));

+					checkAndAppend();

+				}

+			};

+

+            this.groupEnd = function() {

+				if (isSupported) {

+					queuedLoggingEvents.push(new QueuedGroupEnd());

+					checkAndAppend();

+				}

+			};

+

+			var appendQueuedLoggingEvents = function() {

+				var currentLoggingEvent;

+				while (queuedLoggingEvents.length > 0) {

+					queuedLoggingEvents.shift().append();

+				}

+				if (focusConsoleWindow) {

+					getConsoleWindow().focus();

+				}

+			};

+

+			this.setAddedToLogger = function(logger) {

+				this.loggers.push(logger);

+				if (enabled && !lazyInit) {

+					init();

+				}

+			};

+

+			this.clear = function() {

+				if (consoleWindowExists()) {

+					getConsoleWindow().clearLog();

+				}

+				queuedLoggingEvents.length = 0;

+			};

+

+			this.focus = function() {

+				if (consoleWindowExists()) {

+					getConsoleWindow().focus();

+				}

+			};

+

+			this.focusCommandLine = function() {

+				if (consoleWindowExists()) {

+					getConsoleWindow().focusCommandLine();

+				}

+			};

+

+			this.focusSearch = function() {

+				if (consoleWindowExists()) {

+					getConsoleWindow().focusSearch();

+				}

+			};

+

+			var commandWindow = window;

+

+			this.getCommandWindow = function() { return commandWindow; };

+			this.setCommandWindow = function(commandWindowParam) {

+				commandWindow = commandWindowParam;

+			};

+

+			this.executeLastCommand = function() {

+				if (consoleWindowExists()) {

+					getConsoleWindow().evalLastCommand();

+				}

+			};

+

+			var commandLayout = new PatternLayout("%m");

+			this.getCommandLayout = function() { return commandLayout; };

+			this.setCommandLayout = function(commandLayoutParam) {

+				commandLayout = commandLayoutParam;

+			};

+

+			this.evalCommandAndAppend = function(expr) {

+				var commandReturnValue = { appendResult: true, isError: false };

+				var commandOutput = "";

+				// Evaluate the command

+				try {

+					var result, i;

+					// The next three lines constitute a workaround for IE. Bizarrely, iframes seem to have no

+					// eval method on the window object initially, but once execScript has been called on

+					// it once then the eval method magically appears. See http://www.thismuchiknow.co.uk/?p=25

+					if (!commandWindow.eval && commandWindow.execScript) {

+						commandWindow.execScript("null");

+					}

+

+					var commandLineFunctionsHash = {};

+					for (i = 0, len = commandLineFunctions.length; i < len; i++) {

+						commandLineFunctionsHash[commandLineFunctions[i][0]] = commandLineFunctions[i][1];

+					}

+

+					// Keep an array of variables that are being changed in the command window so that they

+					// can be restored to their original values afterwards

+					var objectsToRestore = [];

+					var addObjectToRestore = function(name) {

+						objectsToRestore.push([name, commandWindow[name]]);

+					};

+

+					addObjectToRestore("appender");

+					commandWindow.appender = appender;

+

+					addObjectToRestore("commandReturnValue");

+					commandWindow.commandReturnValue = commandReturnValue;

+

+					addObjectToRestore("commandLineFunctionsHash");

+					commandWindow.commandLineFunctionsHash = commandLineFunctionsHash;

+

+					var addFunctionToWindow = function(name) {

+						addObjectToRestore(name);

+						commandWindow[name] = function() {

+							return this.commandLineFunctionsHash[name](appender, arguments, commandReturnValue);

+						};

+					};

+

+					for (i = 0, len = commandLineFunctions.length; i < len; i++) {

+						addFunctionToWindow(commandLineFunctions[i][0]);

+					}

+

+					// Another bizarre workaround to get IE to eval in the global scope

+					if (commandWindow === window && commandWindow.execScript) {

+						addObjectToRestore("evalExpr");

+						addObjectToRestore("result");

+						window.evalExpr = expr;

+						commandWindow.execScript("window.result=eval(window.evalExpr);");

+						result = window.result;

+ 					} else {

+ 						result = commandWindow.eval(expr);

+ 					}

+					commandOutput = isUndefined(result) ? result : formatObjectExpansion(result, commandLineObjectExpansionDepth);

+

+					// Restore variables in the command window to their original state

+					for (i = 0, len = objectsToRestore.length; i < len; i++) {

+						commandWindow[objectsToRestore[i][0]] = objectsToRestore[i][1];

+					}

+				} catch (ex) {

+					commandOutput = "Error evaluating command: " + getExceptionStringRep(ex);

+					commandReturnValue.isError = true;

+				}

+				// Append command output

+				if (commandReturnValue.appendResult) {

+					var message = ">>> " + expr;

+					if (!isUndefined(commandOutput)) {

+						message += newLine + commandOutput;

+					}

+					var level = commandReturnValue.isError ? Level.ERROR : Level.INFO;

+					var loggingEvent = new LoggingEvent(null, new Date(), level, [message], null);

+					var mainLayout = this.getLayout();

+					this.setLayout(commandLayout);

+					this.append(loggingEvent);

+					this.setLayout(mainLayout);

+				}

+			};

+

+			var commandLineFunctions = defaultCommandLineFunctions.concat([]);

+

+			this.addCommandLineFunction = function(functionName, commandLineFunction) {

+				commandLineFunctions.push([functionName, commandLineFunction]);

+			};

+

+			var commandHistoryCookieName = "log4javascriptCommandHistory";

+			this.storeCommandHistory = function(commandHistory) {

+				setCookie(commandHistoryCookieName, commandHistory.join(","));

+			};

+

+			var writeHtml = function(doc) {

+				var lines = getConsoleHtmlLines();

+				doc.open();

+				for (var i = 0, len = lines.length; i < len; i++) {

+					doc.writeln(lines[i]);

+				}

+				doc.close();

+			};

+

+			// Set up event listeners

+			this.setEventTypes(["load", "unload"]);

+

+			var consoleWindowLoadHandler = function() {

+				var win = getConsoleWindow();

+				win.setAppender(appender);

+				win.setNewestAtTop(newestMessageAtTop);

+				win.setScrollToLatest(scrollToLatestMessage);

+				win.setMaxMessages(maxMessages);

+				win.setShowCommandLine(showCommandLine);

+				win.setShowHideButton(showHideButton);

+				win.setShowCloseButton(showCloseButton);

+				win.setMainWindow(window);

+

+				// Restore command history stored in cookie

+				var storedValue = getCookie(commandHistoryCookieName);

+				if (storedValue) {

+					win.commandHistory = storedValue.split(",");

+					win.currentCommandIndex = win.commandHistory.length;

+				}

+

+				appender.dispatchEvent("load", { "win" : win });

+			};

+

+			this.unload = function() {

+				logLog.debug("unload " + this + ", caller: " + this.unload.caller);

+				if (!consoleClosed) {

+					logLog.debug("really doing unload " + this);

+					consoleClosed = true;

+					consoleWindowLoaded = false;

+					consoleWindowCreated = false;

+					appender.dispatchEvent("unload", {});

+				}

+			};

+

+			var pollConsoleWindow = function(windowTest, interval, successCallback, errorMessage) {

+				function doPoll() {

+					try {

+						// Test if the console has been closed while polling

+						if (consoleClosed) {

+							clearInterval(poll);

+						}

+						if (windowTest(getConsoleWindow())) {

+							clearInterval(poll);

+							successCallback();

+						}

+					} catch (ex) {

+						clearInterval(poll);

+						isSupported = false;

+						handleError(errorMessage, ex);

+					}

+				}

+

+				// Poll the pop-up since the onload event is not reliable

+				var poll = setInterval(doPoll, interval);

+			};

+

+			var getConsoleUrl = function() {

+				var documentDomainSet = (document.domain != location.hostname);

+				return useDocumentWrite ? "" : getBaseUrl() + "console_uncompressed.html" +

+											   (documentDomainSet ? "?log4javascript_domain=" + escape(document.domain) : "");

+			};

+

+			// Define methods and properties that vary between subclasses

+			if (inPage) {

+				// InPageAppender

+

+				var containerElement = null;

+

+				// Configuration methods. The function scope is used to prevent

+				// direct alteration to the appender configuration properties.

+				var cssProperties = [];

+				this.addCssProperty = function(name, value) {

+					if (checkCanConfigure("cssProperties")) {

+						cssProperties.push([name, value]);

+					}

+				};

+

+				// Define useful variables

+				var windowCreationStarted = false;

+				var iframeContainerDiv;

+				var iframeId = uniqueId + "_InPageAppender_" + consoleAppenderId;

+

+				this.hide = function() {

+					if (initialized && consoleWindowCreated) {

+						if (consoleWindowExists()) {

+							getConsoleWindow().$("command").blur();

+						}

+						iframeContainerDiv.style.display = "none";

+						minimized = true;

+					}

+				};

+

+				this.show = function() {

+					if (initialized) {

+						if (consoleWindowCreated) {

+							iframeContainerDiv.style.display = "block";

+							this.setShowCommandLine(showCommandLine); // Force IE to update

+							minimized = false;

+						} else if (!windowCreationStarted) {

+							createWindow(true);

+						}

+					}

+				};

+

+				this.isVisible = function() {

+					return !minimized && !consoleClosed;

+				};

+

+				this.close = function(fromButton) {

+					if (!consoleClosed && (!fromButton || confirm("This will permanently remove the console from the page. No more messages will be logged. Do you wish to continue?"))) {

+						iframeContainerDiv.parentNode.removeChild(iframeContainerDiv);

+						this.unload();

+					}

+				};

+

+				// Create open, init, getConsoleWindow and safeToAppend functions

+				open = function() {

+					var initErrorMessage = "InPageAppender.open: unable to create console iframe";

+

+					function finalInit() {

+						try {

+							if (!initiallyMinimized) {

+								appender.show();

+							}

+							consoleWindowLoadHandler();

+							consoleWindowLoaded = true;

+							appendQueuedLoggingEvents();

+						} catch (ex) {

+							isSupported = false;

+							handleError(initErrorMessage, ex);

+						}

+					}

+

+					function writeToDocument() {

+						try {

+							var windowTest = function(win) { return isLoaded(win); };

+							if (useDocumentWrite) {

+								writeHtml(getConsoleWindow().document);

+							}

+							if (windowTest(getConsoleWindow())) {

+								finalInit();

+							} else {

+								pollConsoleWindow(windowTest, 100, finalInit, initErrorMessage);

+							}

+						} catch (ex) {

+							isSupported = false;

+							handleError(initErrorMessage, ex);

+						}

+					}

+

+					minimized = false;

+					iframeContainerDiv = containerElement.appendChild(document.createElement("div"));

+

+					iframeContainerDiv.style.width = width;

+					iframeContainerDiv.style.height = height;

+					iframeContainerDiv.style.border = "solid gray 1px";

+

+					for (var i = 0, len = cssProperties.length; i < len; i++) {

+						iframeContainerDiv.style[cssProperties[i][0]] = cssProperties[i][1];

+					}

+

+					var iframeSrc = useDocumentWrite ? "" : " src='" + getConsoleUrl() + "'";

+

+					// Adding an iframe using the DOM would be preferable, but it doesn't work

+					// in IE5 on Windows, or in Konqueror prior to version 3.5 - in Konqueror

+					// it creates the iframe fine but I haven't been able to find a way to obtain

+					// the iframe's window object

+					iframeContainerDiv.innerHTML = "<iframe id='" + iframeId + "' name='" + iframeId +

+						"' width='100%' height='100%' frameborder='0'" + iframeSrc +

+						" scrolling='no'></iframe>";

+					consoleClosed = false;

+

+					// Write the console HTML to the iframe

+					var iframeDocumentExistsTest = function(win) {

+						try {

+							return bool(win) && bool(win.document);

+						} catch (ex) {

+							return false;

+						}

+					};

+					if (iframeDocumentExistsTest(getConsoleWindow())) {

+						writeToDocument();

+					} else {

+						pollConsoleWindow(iframeDocumentExistsTest, 100, writeToDocument, initErrorMessage);

+					}

+					consoleWindowCreated = true;

+				};

+

+				createWindow = function(show) {

+					if (show || !initiallyMinimized) {

+						var pageLoadHandler = function() {

+							if (!container) {

+								// Set up default container element

+								containerElement = document.createElement("div");

+								containerElement.style.position = "fixed";

+								containerElement.style.left = "0";

+								containerElement.style.right = "0";

+								containerElement.style.bottom = "0";

+								document.body.appendChild(containerElement);

+								appender.addCssProperty("borderWidth", "1px 0 0 0");

+								appender.addCssProperty("zIndex", 1000000); // Can't find anything authoritative that says how big z-index can be

+								open();

+							} else {

+								try {

+									var el = document.getElementById(container);

+									if (el.nodeType == 1) {

+										containerElement = el;

+									}

+									open();

+								} catch (ex) {

+									handleError("InPageAppender.init: invalid container element '" + container + "' supplied", ex);

+								}

+							}

+						};

+

+						// Test the type of the container supplied. First, check if it's an element

+						if (pageLoaded && container && container.appendChild) {

+							containerElement = container;

+							open();

+						} else if (pageLoaded) {

+							pageLoadHandler();

+						} else {

+							log4javascript.addEventListener("load", pageLoadHandler);

+						}

+						windowCreationStarted = true;

+					}

+				};

+

+				init = function() {

+					createWindow();

+					initialized = true;

+				};

+

+				getConsoleWindow = function() {

+					var iframe = window.frames[iframeId];

+					if (iframe) {

+						return iframe;

+					}

+				};

+

+				safeToAppend = function() {

+					if (isSupported && !consoleClosed) {

+						if (consoleWindowCreated && !consoleWindowLoaded && getConsoleWindow() && isLoaded(getConsoleWindow())) {

+							consoleWindowLoaded = true;

+						}

+						return consoleWindowLoaded;

+					}

+					return false;

+				};

+			} else {

+				// PopUpAppender

+

+				// Extract params

+				var useOldPopUp = appender.defaults.useOldPopUp;

+				var complainAboutPopUpBlocking = appender.defaults.complainAboutPopUpBlocking;

+				var reopenWhenClosed = this.defaults.reopenWhenClosed;

+

+				// Configuration methods. The function scope is used to prevent

+				// direct alteration to the appender configuration properties.

+				this.isUseOldPopUp = function() { return useOldPopUp; };

+				this.setUseOldPopUp = function(useOldPopUpParam) {

+					if (checkCanConfigure("useOldPopUp")) {

+						useOldPopUp = bool(useOldPopUpParam);

+					}

+				};

+

+				this.isComplainAboutPopUpBlocking = function() { return complainAboutPopUpBlocking; };

+				this.setComplainAboutPopUpBlocking = function(complainAboutPopUpBlockingParam) {

+					if (checkCanConfigure("complainAboutPopUpBlocking")) {

+						complainAboutPopUpBlocking = bool(complainAboutPopUpBlockingParam);

+					}

+				};

+

+				this.isFocusPopUp = function() { return focusConsoleWindow; };

+				this.setFocusPopUp = function(focusPopUpParam) {

+					// This property can be safely altered after logging has started

+					focusConsoleWindow = bool(focusPopUpParam);

+				};

+

+				this.isReopenWhenClosed = function() { return reopenWhenClosed; };

+				this.setReopenWhenClosed = function(reopenWhenClosedParam) {

+					// This property can be safely altered after logging has started

+					reopenWhenClosed = bool(reopenWhenClosedParam);

+				};

+

+				this.close = function() {

+					logLog.debug("close " + this);

+					try {

+						popUp.close();

+						this.unload();

+					} catch (ex) {

+						// Do nothing

+					}

+				};

+

+				this.hide = function() {

+					logLog.debug("hide " + this);

+					if (consoleWindowExists()) {

+						this.close();

+					}

+				};

+

+				this.show = function() {

+					logLog.debug("show " + this);

+					if (!consoleWindowCreated) {

+						open();

+					}

+				};

+

+				this.isVisible = function() {

+					return safeToAppend();

+				};

+

+				// Define useful variables

+				var popUp;

+

+				// Create open, init, getConsoleWindow and safeToAppend functions

+				open = function() {

+					var windowProperties = "width=" + width + ",height=" + height + ",status,resizable";

+					var frameInfo = "";

+					try {

+						var frameEl = window.frameElement;

+						if (frameEl) {

+							frameInfo = "_" + frameEl.tagName + "_" + (frameEl.name || frameEl.id || "");

+						}

+					} catch (e) {

+						frameInfo = "_inaccessibleParentFrame";

+					}

+					var windowName = "PopUp_" + location.host.replace(/[^a-z0-9]/gi, "_") + "_" + consoleAppenderId + frameInfo;

+					if (!useOldPopUp || !useDocumentWrite) {

+						// Ensure a previous window isn't used by using a unique name

+						windowName = windowName + "_" + uniqueId;

+					}

+

+					var checkPopUpClosed = function(win) {

+						if (consoleClosed) {

+							return true;

+						} else {

+							try {

+								return bool(win) && win.closed;

+							} catch(ex) {}

+						}

+						return false;

+					};

+

+					var popUpClosedCallback = function() {

+						if (!consoleClosed) {

+							appender.unload();

+						}

+					};

+

+					function finalInit() {

+						getConsoleWindow().setCloseIfOpenerCloses(!useOldPopUp || !useDocumentWrite);

+						consoleWindowLoadHandler();

+						consoleWindowLoaded = true;

+						appendQueuedLoggingEvents();

+						pollConsoleWindow(checkPopUpClosed, 500, popUpClosedCallback,

+								"PopUpAppender.checkPopUpClosed: error checking pop-up window");

+					}

+

+					try {

+						popUp = window.open(getConsoleUrl(), windowName, windowProperties);

+						consoleClosed = false;

+						consoleWindowCreated = true;

+						if (popUp && popUp.document) {

+							if (useDocumentWrite && useOldPopUp && isLoaded(popUp)) {

+								popUp.mainPageReloaded();

+								finalInit();

+							} else {

+								if (useDocumentWrite) {

+									writeHtml(popUp.document);

+								}

+								// Check if the pop-up window object is available

+								var popUpLoadedTest = function(win) { return bool(win) && isLoaded(win); };

+								if (isLoaded(popUp)) {

+									finalInit();

+								} else {

+									pollConsoleWindow(popUpLoadedTest, 100, finalInit,

+											"PopUpAppender.init: unable to create console window");

+								}

+							}

+						} else {

+							isSupported = false;

+							logLog.warn("PopUpAppender.init: pop-ups blocked, please unblock to use PopUpAppender");

+							if (complainAboutPopUpBlocking) {

+								handleError("log4javascript: pop-up windows appear to be blocked. Please unblock them to use pop-up logging.");

+							}

+						}

+					} catch (ex) {

+						handleError("PopUpAppender.init: error creating pop-up", ex);

+					}

+				};

+

+				createWindow = function() {

+					if (!initiallyMinimized) {

+						open();

+					}

+				};

+

+				init = function() {

+					createWindow();

+					initialized = true;

+				};

+

+				getConsoleWindow = function() {

+					return popUp;

+				};

+

+				safeToAppend = function() {

+					if (isSupported && !isUndefined(popUp) && !consoleClosed) {

+						if (popUp.closed ||

+								(consoleWindowLoaded && isUndefined(popUp.closed))) { // Extra check for Opera

+							appender.unload();

+							logLog.debug("PopUpAppender: pop-up closed");

+							return false;

+						}

+						if (!consoleWindowLoaded && isLoaded(popUp)) {

+							consoleWindowLoaded = true;

+						}

+					}

+					return isSupported && consoleWindowLoaded && !consoleClosed;

+				};

+			}

+

+			// Expose getConsoleWindow so that automated tests can check the DOM

+			this.getConsoleWindow = getConsoleWindow;

+		};

+

+		ConsoleAppender.addGlobalCommandLineFunction = function(functionName, commandLineFunction) {

+			defaultCommandLineFunctions.push([functionName, commandLineFunction]);

+		};

+

+		/* ------------------------------------------------------------------ */

+

+		function PopUpAppender(lazyInit, initiallyMinimized, useDocumentWrite,

+							   width, height) {

+			this.create(false, null, lazyInit, initiallyMinimized,

+					useDocumentWrite, width, height, this.defaults.focusPopUp);

+		}

+

+		PopUpAppender.prototype = new ConsoleAppender();

+

+		PopUpAppender.prototype.defaults = {

+			layout: new PatternLayout("%d{HH:mm:ss} %-5p - %m{1}%n"),

+			initiallyMinimized: false,

+			focusPopUp: false,

+			lazyInit: true,

+			useOldPopUp: true,

+			complainAboutPopUpBlocking: true,

+			newestMessageAtTop: false,

+			scrollToLatestMessage: true,

+			width: "600",

+			height: "400",

+			reopenWhenClosed: false,

+			maxMessages: null,

+			showCommandLine: true,

+			commandLineObjectExpansionDepth: 1,

+			showHideButton: false,

+			showCloseButton: true,

+            showLogEntryDeleteButtons: true,

+            useDocumentWrite: true

+		};

+

+		PopUpAppender.prototype.toString = function() {

+			return "PopUpAppender";

+		};

+

+		log4javascript.PopUpAppender = PopUpAppender;

+

+		/* ------------------------------------------------------------------ */

+

+		function InPageAppender(container, lazyInit, initiallyMinimized,

+								useDocumentWrite, width, height) {

+			this.create(true, container, lazyInit, initiallyMinimized,

+					useDocumentWrite, width, height, false);

+		}

+

+		InPageAppender.prototype = new ConsoleAppender();

+

+		InPageAppender.prototype.defaults = {

+			layout: new PatternLayout("%d{HH:mm:ss} %-5p - %m{1}%n"),

+			initiallyMinimized: false,

+			lazyInit: true,

+			newestMessageAtTop: false,

+			scrollToLatestMessage: true,

+			width: "100%",

+			height: "220px",

+			maxMessages: null,

+			showCommandLine: true,

+			commandLineObjectExpansionDepth: 1,

+			showHideButton: false,

+			showCloseButton: false,

+            showLogEntryDeleteButtons: true,

+            useDocumentWrite: true

+		};

+

+		InPageAppender.prototype.toString = function() {

+			return "InPageAppender";

+		};

+

+		log4javascript.InPageAppender = InPageAppender;

+

+		// Next line for backwards compatibility

+		log4javascript.InlineAppender = InPageAppender;

+	})();

+	/* ---------------------------------------------------------------------- */

+	// Console extension functions

+

+	function padWithSpaces(str, len) {

+		if (str.length < len) {

+			var spaces = [];

+			var numberOfSpaces = Math.max(0, len - str.length);

+			for (var i = 0; i < numberOfSpaces; i++) {

+				spaces[i] = " ";

+			}

+			str += spaces.join("");

+		}

+		return str;

+	}

+

+	(function() {

+		function dir(obj) {

+			var maxLen = 0;

+			// Obtain the length of the longest property name

+			for (var p in obj) {

+				maxLen = Math.max(toStr(p).length, maxLen);

+			}

+			// Create the nicely formatted property list

+			var propList = [];

+			for (p in obj) {

+				var propNameStr = "  " + padWithSpaces(toStr(p), maxLen + 2);

+				var propVal;

+				try {

+					propVal = splitIntoLines(toStr(obj[p])).join(padWithSpaces(newLine, maxLen + 6));

+				} catch (ex) {

+					propVal = "[Error obtaining property. Details: " + getExceptionMessage(ex) + "]";

+				}

+				propList.push(propNameStr + propVal);

+			}

+			return propList.join(newLine);

+		}

+

+		var nodeTypes = {

+			ELEMENT_NODE: 1,

+			ATTRIBUTE_NODE: 2,

+			TEXT_NODE: 3,

+			CDATA_SECTION_NODE: 4,

+			ENTITY_REFERENCE_NODE: 5,

+			ENTITY_NODE: 6,

+			PROCESSING_INSTRUCTION_NODE: 7,

+			COMMENT_NODE: 8,

+			DOCUMENT_NODE: 9,

+			DOCUMENT_TYPE_NODE: 10,

+			DOCUMENT_FRAGMENT_NODE: 11,

+			NOTATION_NODE: 12

+		};

+

+		var preFormattedElements = ["script", "pre"];

+

+		// This should be the definitive list, as specified by the XHTML 1.0 Transitional DTD

+		var emptyElements = ["br", "img", "hr", "param", "link", "area", "input", "col", "base", "meta"];

+		var indentationUnit = "  ";

+

+		// Create and return an XHTML string from the node specified

+		function getXhtml(rootNode, includeRootNode, indentation, startNewLine, preformatted) {

+			includeRootNode = (typeof includeRootNode == "undefined") ? true : !!includeRootNode;

+			if (typeof indentation != "string") {

+				indentation = "";

+			}

+			startNewLine = !!startNewLine;

+			preformatted = !!preformatted;

+			var xhtml;

+

+			function isWhitespace(node) {

+				return ((node.nodeType == nodeTypes.TEXT_NODE) && /^[ \t\r\n]*$/.test(node.nodeValue));

+			}

+

+			function fixAttributeValue(attrValue) {

+				return attrValue.toString().replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/"/g, "&quot;");

+			}

+

+			function getStyleAttributeValue(el) {

+				var stylePairs = el.style.cssText.split(";");

+				var styleValue = "";

+				var isFirst = true;

+				for (var j = 0, len = stylePairs.length; j < len; j++) {

+					var nameValueBits = stylePairs[j].split(":");

+					var props = [];

+					if (!/^\s*$/.test(nameValueBits[0])) {

+						props.push(trim(nameValueBits[0]).toLowerCase() + ":" + trim(nameValueBits[1]));

+					}

+					styleValue = props.join(";");

+				}

+				return styleValue;

+			}

+

+			function getNamespace(el) {

+				if (el.prefix) {

+					return el.prefix;

+				} else if (el.outerHTML) {

+					var regex = new RegExp("<([^:]+):" + el.tagName + "[^>]*>", "i");

+					if (regex.test(el.outerHTML)) {

+						return RegExp.$1.toLowerCase();

+					}

+				}

+                return "";

+			}

+

+			var lt = "<";

+			var gt = ">";

+

+			if (includeRootNode && rootNode.nodeType != nodeTypes.DOCUMENT_FRAGMENT_NODE) {

+				switch (rootNode.nodeType) {

+					case nodeTypes.ELEMENT_NODE:

+						var tagName = rootNode.tagName.toLowerCase();

+						xhtml = startNewLine ? newLine + indentation : "";

+						xhtml += lt;

+						// Allow for namespaces, where present

+						var prefix = getNamespace(rootNode);

+						var hasPrefix = !!prefix;

+						if (hasPrefix) {

+							xhtml += prefix + ":";

+						}

+						xhtml += tagName;

+						for (i = 0, len = rootNode.attributes.length; i < len; i++) {

+							var currentAttr = rootNode.attributes[i];

+							// Check the attribute is valid.

+							if (!	currentAttr.specified ||

+									currentAttr.nodeValue === null ||

+									currentAttr.nodeName.toLowerCase() === "style" ||

+									typeof currentAttr.nodeValue !== "string" ||

+									currentAttr.nodeName.indexOf("_moz") === 0) {

+								continue;

+							}

+							xhtml += " " + currentAttr.nodeName.toLowerCase() + "=\"";

+							xhtml += fixAttributeValue(currentAttr.nodeValue);

+							xhtml += "\"";

+						}

+						// Style needs to be done separately as it is not reported as an

+						// attribute in IE

+						if (rootNode.style.cssText) {

+							var styleValue = getStyleAttributeValue(rootNode);

+							if (styleValue !== "") {

+								xhtml += " style=\"" + getStyleAttributeValue(rootNode) + "\"";

+							}

+						}

+						if (array_contains(emptyElements, tagName) ||

+								(hasPrefix && !rootNode.hasChildNodes())) {

+							xhtml += "/" + gt;

+						} else {

+							xhtml += gt;

+							// Add output for childNodes collection (which doesn't include attribute nodes)

+							var childStartNewLine = !(rootNode.childNodes.length === 1 &&

+								rootNode.childNodes[0].nodeType === nodeTypes.TEXT_NODE);

+							var childPreformatted = array_contains(preFormattedElements, tagName);

+							for (var i = 0, len = rootNode.childNodes.length; i < len; i++) {

+								xhtml += getXhtml(rootNode.childNodes[i], true, indentation + indentationUnit,

+									childStartNewLine, childPreformatted);

+							}

+							// Add the end tag

+							var endTag = lt + "/" + tagName + gt;

+							xhtml += childStartNewLine ? newLine + indentation + endTag : endTag;

+						}

+						return xhtml;

+					case nodeTypes.TEXT_NODE:

+						if (isWhitespace(rootNode)) {

+							xhtml = "";

+						} else {

+							if (preformatted) {

+								xhtml = rootNode.nodeValue;

+							} else {

+								// Trim whitespace from each line of the text node

+								var lines = splitIntoLines(trim(rootNode.nodeValue));

+								var trimmedLines = [];

+								for (var i = 0, len = lines.length; i < len; i++) {

+									trimmedLines[i] = trim(lines[i]);

+								}

+								xhtml = trimmedLines.join(newLine + indentation);

+							}

+							if (startNewLine) {

+								xhtml = newLine + indentation + xhtml;

+							}

+						}

+						return xhtml;

+					case nodeTypes.CDATA_SECTION_NODE:

+						return "<![CDA" + "TA[" + rootNode.nodeValue + "]" + "]>" + newLine;

+					case nodeTypes.DOCUMENT_NODE:

+						xhtml = "";

+						// Add output for childNodes collection (which doesn't include attribute nodes)

+						for (var i = 0, len = rootNode.childNodes.length; i < len; i++) {

+							xhtml += getXhtml(rootNode.childNodes[i], true, indentation);

+						}

+						return xhtml;

+					default:

+						return "";

+				}

+			} else {

+				xhtml = "";

+				// Add output for childNodes collection (which doesn't include attribute nodes)

+				for (var i = 0, len = rootNode.childNodes.length; i < len; i++) {

+					xhtml += getXhtml(rootNode.childNodes[i], true, indentation + indentationUnit);

+				}

+				return xhtml;

+			}

+		}

+

+		function createCommandLineFunctions() {

+			ConsoleAppender.addGlobalCommandLineFunction("$", function(appender, args, returnValue) {

+				return document.getElementById(args[0]);

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("dir", function(appender, args, returnValue) {

+				var lines = [];

+				for (var i = 0, len = args.length; i < len; i++) {

+					lines[i] = dir(args[i]);

+				}

+				return lines.join(newLine + newLine);

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("dirxml", function(appender, args, returnValue) {

+				var lines = [];

+				for (var i = 0, len = args.length; i < len; i++) {

+					var win = appender.getCommandWindow();

+					lines[i] = getXhtml(args[i]);

+				}

+				return lines.join(newLine + newLine);

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("cd", function(appender, args, returnValue) {

+				var win, message;

+				if (args.length === 0 || args[0] === "") {

+					win = window;

+					message = "Command line set to run in main window";

+				} else {

+					if (args[0].window == args[0]) {

+						win = args[0];

+						message = "Command line set to run in frame '" + args[0].name + "'";

+					} else {

+						win = window.frames[args[0]];

+						if (win) {

+							message = "Command line set to run in frame '" + args[0] + "'";

+						} else {

+							returnValue.isError = true;

+							message = "Frame '" + args[0] + "' does not exist";

+							win = appender.getCommandWindow();

+						}

+					}

+				}

+				appender.setCommandWindow(win);

+				return message;

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("clear", function(appender, args, returnValue) {

+				returnValue.appendResult = false;

+				appender.clear();

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("keys", function(appender, args, returnValue) {

+				var keys = [];

+				for (var k in args[0]) {

+					keys.push(k);

+				}

+				return keys;

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("values", function(appender, args, returnValue) {

+				var values = [];

+				for (var k in args[0]) {

+					try {

+						values.push(args[0][k]);

+					} catch (ex) {

+						logLog.warn("values(): Unable to obtain value for key " + k + ". Details: " + getExceptionMessage(ex));

+					}

+				}

+				return values;

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("expansionDepth", function(appender, args, returnValue) {

+				var expansionDepth = parseInt(args[0], 10);

+				if (isNaN(expansionDepth) || expansionDepth < 0) {

+					returnValue.isError = true;

+					return "" + args[0] + " is not a valid expansion depth";

+				} else {

+					appender.setCommandLineObjectExpansionDepth(expansionDepth);

+					return "Object expansion depth set to " + expansionDepth;

+				}

+			});

+		}

+

+		function init() {

+			// Add command line functions

+			createCommandLineFunctions();

+		}

+

+		/* ------------------------------------------------------------------ */

+

+		init();

+	})();

+

+	/* ---------------------------------------------------------------------- */

+	// Main load

+

+   log4javascript.setDocumentReady = function() {

+       pageLoaded = true;

+       log4javascript.dispatchEvent("load", {});

+   };

+

+    if (window.addEventListener) {

+        window.addEventListener("load", log4javascript.setDocumentReady, false);

+    } else if (window.attachEvent) {

+        window.attachEvent("onload", log4javascript.setDocumentReady);

+    } else {

+        var oldOnload = window.onload;

+        if (typeof window.onload != "function") {

+            window.onload = log4javascript.setDocumentReady;

+        } else {

+            window.onload = function(evt) {

+                if (oldOnload) {

+                    oldOnload(evt);

+                }

+                log4javascript.setDocumentReady();

+            };

+        }

+    }

+

+    // Ensure that the log4javascript object is available in the window. This

+    // is necessary for log4javascript to be available in IE if loaded using

+    // Dojo's module system

+    window.log4javascript = log4javascript;

+

+    return log4javascript;

+})();
\ No newline at end of file
diff --git a/xos/core/static/log4javascript-1.4.6/js/stubs/log4javascript.js b/xos/core/static/log4javascript-1.4.6/js/stubs/log4javascript.js
new file mode 100644
index 0000000..eae582b
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/js/stubs/log4javascript.js
@@ -0,0 +1,23 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+

+var log4javascript_stub=(function(){var log4javascript;function ff(){return function(){};}

+function copy(obj,props){for(var i in props){obj[i]=props[i];}}

+var f=ff();var Logger=ff();copy(Logger.prototype,{addChild:f,getEffectiveAppenders:f,invalidateAppenderCache:f,getAdditivity:f,setAdditivity:f,addAppender:f,removeAppender:f,removeAllAppenders:f,log:f,setLevel:f,getLevel:f,getEffectiveLevel:f,trace:f,debug:f,info:f,warn:f,error:f,fatal:f,isEnabledFor:f,isTraceEnabled:f,isDebugEnabled:f,isInfoEnabled:f,isWarnEnabled:f,isErrorEnabled:f,isFatalEnabled:f,callAppenders:f,group:f,groupEnd:f,time:f,timeEnd:f,assert:f,parent:new Logger()});var getLogger=function(){return new Logger();};function EventSupport(){}

+copy(EventSupport.prototype,{setEventTypes:f,addEventListener:f,removeEventListener:f,dispatchEvent:f,eventTypes:[],eventListeners:{}});function Log4JavaScript(){}

+Log4JavaScript.prototype=new EventSupport();log4javascript=new Log4JavaScript();log4javascript={isStub:true,version:"1.4.6",edition:"log4javascript",setDocumentReady:f,setEventTypes:f,addEventListener:f,removeEventListener:f,dispatchEvent:f,eventTypes:[],eventListeners:{},logLog:{setQuietMode:f,setAlertAllErrors:f,debug:f,displayDebug:f,warn:f,error:f},handleError:f,setEnabled:f,isEnabled:f,setTimeStampsInMilliseconds:f,isTimeStampsInMilliseconds:f,evalInScope:f,setShowStackTraces:f,getLogger:getLogger,getDefaultLogger:getLogger,getNullLogger:getLogger,getRootLogger:getLogger,resetConfiguration:f,Level:ff(),LoggingEvent:ff(),Layout:ff(),Appender:ff()};log4javascript.LoggingEvent.prototype={getThrowableStrRep:f,getCombinedMessages:f};log4javascript.Level.prototype={toString:f,equals:f,isGreaterOrEqual:f};var level=new log4javascript.Level();copy(log4javascript.Level,{ALL:level,TRACE:level,DEBUG:level,INFO:level,WARN:level,ERROR:level,FATAL:level,OFF:level});log4javascript.Layout.prototype={defaults:{},format:f,ignoresThrowable:f,getContentType:f,allowBatching:f,getDataValues:f,setKeys:f,setCustomField:f,hasCustomFields:f,setTimeStampsInMilliseconds:f,isTimeStampsInMilliseconds:f,getTimeStampValue:f,toString:f};log4javascript.SimpleDateFormat=ff();log4javascript.SimpleDateFormat.prototype={setMinimalDaysInFirstWeek:f,getMinimalDaysInFirstWeek:f,format:f};log4javascript.PatternLayout=ff();log4javascript.PatternLayout.prototype=new log4javascript.Layout();log4javascript.Appender=ff();log4javascript.Appender.prototype=new EventSupport();copy(log4javascript.Appender.prototype,{layout:new log4javascript.PatternLayout(),threshold:log4javascript.Level.ALL,loggers:[],doAppend:f,append:f,setLayout:f,getLayout:f,setThreshold:f,getThreshold:f,setAddedToLogger:f,setRemovedFromLogger:f,group:f,groupEnd:f,toString:f});log4javascript.SimpleLayout=ff();log4javascript.SimpleLayout.prototype=new log4javascript.Layout();log4javascript.NullLayout=ff();log4javascript.NullLayout.prototype=new log4javascript.Layout();log4javascript.XmlLayout=ff();log4javascript.XmlLayout.prototype=new log4javascript.Layout();copy(log4javascript.XmlLayout.prototype,{escapeCdata:f,isCombinedMessages:f});log4javascript.JsonLayout=ff();log4javascript.JsonLayout.prototype=new log4javascript.Layout();copy(log4javascript.JsonLayout.prototype,{isReadable:f,isCombinedMessages:f});log4javascript.HttpPostDataLayout=ff();log4javascript.HttpPostDataLayout.prototype=new log4javascript.Layout();log4javascript.PatternLayout=ff();log4javascript.PatternLayout.prototype=new log4javascript.Layout();log4javascript.AlertAppender=ff();log4javascript.AlertAppender.prototype=new log4javascript.Appender();log4javascript.BrowserConsoleAppender=ff();log4javascript.BrowserConsoleAppender.prototype=new log4javascript.Appender();log4javascript.AjaxAppender=ff();log4javascript.AjaxAppender.prototype=new log4javascript.Appender();copy(log4javascript.AjaxAppender.prototype,{getSessionId:f,setSessionId:f,isTimed:f,setTimed:f,getTimerInterval:f,setTimerInterval:f,isWaitForResponse:f,setWaitForResponse:f,getBatchSize:f,setBatchSize:f,isSendAllOnUnload:f,setSendAllOnUnload:f,setRequestSuccessCallback:f,setFailCallback:f,getPostVarName:f,setPostVarName:f,sendAll:f,sendAllRemaining:f,defaults:{requestSuccessCallback:null,failCallback:null}});function ConsoleAppender(){}

+ConsoleAppender.prototype=new log4javascript.Appender();copy(ConsoleAppender.prototype,{create:f,isNewestMessageAtTop:f,setNewestMessageAtTop:f,isScrollToLatestMessage:f,setScrollToLatestMessage:f,getWidth:f,setWidth:f,getHeight:f,setHeight:f,getMaxMessages:f,setMaxMessages:f,isShowCommandLine:f,setShowCommandLine:f,isShowHideButton:f,setShowHideButton:f,isShowCloseButton:f,setShowCloseButton:f,getCommandLineObjectExpansionDepth:f,setCommandLineObjectExpansionDepth:f,isInitiallyMinimized:f,setInitiallyMinimized:f,isUseDocumentWrite:f,setUseDocumentWrite:f,group:f,groupEnd:f,clear:f,focus:f,focusCommandLine:f,focusSearch:f,getCommandWindow:f,setCommandWindow:f,executeLastCommand:f,getCommandLayout:f,setCommandLayout:f,evalCommandAndAppend:f,addCommandLineFunction:f,storeCommandHistory:f,unload:f});ConsoleAppender.addGlobalCommandLineFunction=f;log4javascript.InPageAppender=ff();log4javascript.InPageAppender.prototype=new ConsoleAppender();copy(log4javascript.InPageAppender.prototype,{addCssProperty:f,hide:f,show:f,isVisible:f,close:f,defaults:{layout:new log4javascript.PatternLayout(),maxMessages:null}});log4javascript.InlineAppender=log4javascript.InPageAppender;log4javascript.PopUpAppender=ff();log4javascript.PopUpAppender.prototype=new ConsoleAppender();copy(log4javascript.PopUpAppender.prototype,{isUseOldPopUp:f,setUseOldPopUp:f,isComplainAboutPopUpBlocking:f,setComplainAboutPopUpBlocking:f,isFocusPopUp:f,setFocusPopUp:f,isReopenWhenClosed:f,setReopenWhenClosed:f,close:f,hide:f,show:f,defaults:{layout:new log4javascript.PatternLayout(),maxMessages:null}});return log4javascript;})();if(typeof window.log4javascript=="undefined"){var log4javascript=log4javascript_stub;}

diff --git a/xos/core/static/log4javascript-1.4.6/js/stubs/log4javascript_lite.js b/xos/core/static/log4javascript-1.4.6/js/stubs/log4javascript_lite.js
new file mode 100644
index 0000000..7d2ea14
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/js/stubs/log4javascript_lite.js
@@ -0,0 +1,21 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+

+var log4javascript_stub=(function(){var log4javascript;function ff(){return function(){};}

+function copy(obj,props){for(var i in props){obj[i]=props[i];}}

+var f=ff();var Logger=ff();copy(Logger.prototype,{setLevel:f,getLevel:f,trace:f,debug:f,info:f,warn:f,error:f,fatal:f,isEnabledFor:f,isTraceEnabled:f,isDebugEnabled:f,isInfoEnabled:f,isWarnEnabled:f,isErrorEnabled:f,isFatalEnabled:f});var getLogger=function(){return new Logger();};function Log4JavaScript(){}

+log4javascript=new Log4JavaScript();log4javascript={isStub:true,version:"1.4.6",edition:"log4javascript_lite",setEnabled:f,isEnabled:f,setShowStackTraces:f,getDefaultLogger:getLogger,getLogger:getLogger,getNullLogger:getLogger,Level:ff(),LoggingEvent:ff(),Appender:ff()};log4javascript.LoggingEvent.prototype={getThrowableStrRep:f,getCombinedMessages:f};log4javascript.Level.prototype={toString:f,equals:f,isGreaterOrEqual:f};var level=new log4javascript.Level();copy(log4javascript.Level,{ALL:level,TRACE:level,DEBUG:level,INFO:level,WARN:level,ERROR:level,FATAL:level,OFF:level});log4javascript.Appender.prototype.append=f;return log4javascript;})();if(typeof window.log4javascript=="undefined"){var log4javascript=log4javascript_stub;}

diff --git a/xos/core/static/log4javascript-1.4.6/js/stubs/log4javascript_lite_uncompressed.js b/xos/core/static/log4javascript-1.4.6/js/stubs/log4javascript_lite_uncompressed.js
new file mode 100644
index 0000000..afb9ba7
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/js/stubs/log4javascript_lite_uncompressed.js
@@ -0,0 +1,102 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+var log4javascript_stub = (function() {

+	var log4javascript;

+

+	function ff() {

+		return function() {};

+	}

+	function copy(obj, props) {

+		for (var i in props) {

+			obj[i] = props[i];

+		}

+	}

+	var f = ff();

+

+	// Loggers

+	var Logger = ff();

+	copy(Logger.prototype, {

+		setLevel: f,

+		getLevel: f,

+		trace: f,

+		debug: f,

+		info: f,

+		warn: f,

+		error: f,

+		fatal: f,

+		isEnabledFor: f,

+		isTraceEnabled: f,

+		isDebugEnabled: f,

+		isInfoEnabled: f,

+		isWarnEnabled: f,

+		isErrorEnabled: f,

+		isFatalEnabled: f

+	});

+

+	var getLogger = function() {

+		return new Logger();

+	};

+

+	function Log4JavaScript() {}

+	log4javascript = new Log4JavaScript();

+

+	log4javascript = {

+		isStub: true,

+		version: "1.4.6",

+		edition: "log4javascript_lite",

+		setEnabled: f,

+		isEnabled: f,

+		setShowStackTraces: f,

+		getDefaultLogger: getLogger,

+		getLogger: getLogger,

+		getNullLogger: getLogger,

+		Level: ff(),

+		LoggingEvent: ff(),

+		Appender: ff()

+	};

+

+	// LoggingEvents

+	log4javascript.LoggingEvent.prototype = {

+		getThrowableStrRep: f,

+		getCombinedMessages: f

+	};

+

+	// Levels

+	log4javascript.Level.prototype = {

+		toString: f,

+		equals: f,

+		isGreaterOrEqual: f

+	};

+	var level = new log4javascript.Level();

+	copy(log4javascript.Level, {

+		ALL: level,

+		TRACE: level,

+		DEBUG: level,

+		INFO: level,

+		WARN: level,

+		ERROR: level,

+		FATAL: level,

+		OFF: level

+	});

+	

+	log4javascript.Appender.prototype.append = f;

+

+	return log4javascript;

+})();

+if (typeof window.log4javascript == "undefined") {

+	var log4javascript = log4javascript_stub;

+}

diff --git a/xos/core/static/log4javascript-1.4.6/js/stubs/log4javascript_production.js b/xos/core/static/log4javascript-1.4.6/js/stubs/log4javascript_production.js
new file mode 100644
index 0000000..69a90a8
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/js/stubs/log4javascript_production.js
@@ -0,0 +1,22 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+

+var log4javascript_stub=(function(){var log4javascript;function ff(){return function(){};}

+function copy(obj,props){for(var i in props){obj[i]=props[i];}}

+var f=ff();var Logger=ff();copy(Logger.prototype,{addChild:f,getEffectiveAppenders:f,invalidateAppenderCache:f,getAdditivity:f,setAdditivity:f,addAppender:f,removeAppender:f,removeAllAppenders:f,log:f,setLevel:f,getLevel:f,getEffectiveLevel:f,trace:f,debug:f,info:f,warn:f,error:f,fatal:f,isEnabledFor:f,isTraceEnabled:f,isDebugEnabled:f,isInfoEnabled:f,isWarnEnabled:f,isErrorEnabled:f,isFatalEnabled:f,callAppenders:f,group:f,groupEnd:f,time:f,timeEnd:f,assert:f,parent:new Logger()});var getLogger=function(){return new Logger();};function EventSupport(){}

+copy(EventSupport.prototype,{setEventTypes:f,addEventListener:f,removeEventListener:f,dispatchEvent:f,eventTypes:[],eventListeners:{}});function Log4JavaScript(){}

+Log4JavaScript.prototype=new EventSupport();log4javascript=new Log4JavaScript();log4javascript={isStub:true,version:"1.4.6",edition:"log4javascript_production",setDocumentReady:f,setEventTypes:f,addEventListener:f,removeEventListener:f,dispatchEvent:f,eventTypes:[],eventListeners:{},logLog:{setQuietMode:f,setAlertAllErrors:f,debug:f,displayDebug:f,warn:f,error:f},handleError:f,setEnabled:f,isEnabled:f,setTimeStampsInMilliseconds:f,isTimeStampsInMilliseconds:f,evalInScope:f,setShowStackTraces:f,getLogger:getLogger,getDefaultLogger:getLogger,getNullLogger:getLogger,getRootLogger:getLogger,resetConfiguration:f,Level:ff(),LoggingEvent:ff(),Layout:ff(),Appender:ff()};log4javascript.LoggingEvent.prototype={getThrowableStrRep:f,getCombinedMessages:f};log4javascript.Level.prototype={toString:f,equals:f,isGreaterOrEqual:f};var level=new log4javascript.Level();copy(log4javascript.Level,{ALL:level,TRACE:level,DEBUG:level,INFO:level,WARN:level,ERROR:level,FATAL:level,OFF:level});log4javascript.Layout.prototype={defaults:{},format:f,ignoresThrowable:f,getContentType:f,allowBatching:f,getDataValues:f,setKeys:f,setCustomField:f,hasCustomFields:f,setTimeStampsInMilliseconds:f,isTimeStampsInMilliseconds:f,getTimeStampValue:f,toString:f};log4javascript.SimpleDateFormat=ff();log4javascript.SimpleDateFormat.prototype={setMinimalDaysInFirstWeek:f,getMinimalDaysInFirstWeek:f,format:f};log4javascript.PatternLayout=ff();log4javascript.PatternLayout.prototype=new log4javascript.Layout();log4javascript.Appender=ff();log4javascript.Appender.prototype=new EventSupport();copy(log4javascript.Appender.prototype,{layout:new log4javascript.PatternLayout(),threshold:log4javascript.Level.ALL,loggers:[],doAppend:f,append:f,setLayout:f,getLayout:f,setThreshold:f,getThreshold:f,setAddedToLogger:f,setRemovedFromLogger:f,group:f,groupEnd:f,toString:f});log4javascript.SimpleLayout=ff();log4javascript.SimpleLayout.prototype=new log4javascript.Layout();log4javascript.NullLayout=ff();log4javascript.NullLayout.prototype=new log4javascript.Layout();log4javascript.XmlLayout=ff();log4javascript.XmlLayout.prototype=new log4javascript.Layout();copy(log4javascript.XmlLayout.prototype,{escapeCdata:f,isCombinedMessages:f});log4javascript.JsonLayout=ff();log4javascript.JsonLayout.prototype=new log4javascript.Layout();copy(log4javascript.JsonLayout.prototype,{isReadable:f,isCombinedMessages:f});log4javascript.HttpPostDataLayout=ff();log4javascript.HttpPostDataLayout.prototype=new log4javascript.Layout();log4javascript.PatternLayout=ff();log4javascript.PatternLayout.prototype=new log4javascript.Layout();log4javascript.AjaxAppender=ff();log4javascript.AjaxAppender.prototype=new log4javascript.Appender();copy(log4javascript.AjaxAppender.prototype,{getSessionId:f,setSessionId:f,isTimed:f,setTimed:f,getTimerInterval:f,setTimerInterval:f,isWaitForResponse:f,setWaitForResponse:f,getBatchSize:f,setBatchSize:f,isSendAllOnUnload:f,setSendAllOnUnload:f,setRequestSuccessCallback:f,setFailCallback:f,getPostVarName:f,setPostVarName:f,sendAll:f,sendAllRemaining:f,defaults:{requestSuccessCallback:null,failCallback:null}});return log4javascript;})();if(typeof window.log4javascript=="undefined"){var log4javascript=log4javascript_stub;}

diff --git a/xos/core/static/log4javascript-1.4.6/js/stubs/log4javascript_production_uncompressed.js b/xos/core/static/log4javascript-1.4.6/js/stubs/log4javascript_production_uncompressed.js
new file mode 100644
index 0000000..79eb7ca
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/js/stubs/log4javascript_production_uncompressed.js
@@ -0,0 +1,253 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+var log4javascript_stub = (function() {

+	var log4javascript;

+

+	function ff() {

+		return function() {};

+	}

+	function copy(obj, props) {

+		for (var i in props) {

+			obj[i] = props[i];

+		}

+	}

+	var f = ff();

+

+	// Loggers

+	var Logger = ff();

+	copy(Logger.prototype, {

+		addChild: f,

+		getEffectiveAppenders: f,

+		invalidateAppenderCache: f,

+		getAdditivity: f,

+		setAdditivity: f,

+		addAppender: f,

+		removeAppender: f,

+		removeAllAppenders: f,

+		log: f,

+		setLevel: f,

+		getLevel: f,

+		getEffectiveLevel: f,

+		trace: f,

+		debug: f,

+		info: f,

+		warn: f,

+		error: f,

+		fatal: f,

+		isEnabledFor: f,

+		isTraceEnabled: f,

+		isDebugEnabled: f,

+		isInfoEnabled: f,

+		isWarnEnabled: f,

+		isErrorEnabled: f,

+		isFatalEnabled: f,

+		callAppenders: f,

+		group: f,

+		groupEnd: f,

+		time: f,

+		timeEnd: f,

+		assert: f,

+		parent: new Logger()

+	});

+

+	var getLogger = function() {

+		return new Logger();

+	};

+

+	function EventSupport() {}

+

+	copy(EventSupport.prototype, {

+		setEventTypes: f,

+		addEventListener: f,

+		removeEventListener: f,

+		dispatchEvent: f,

+		eventTypes: [],

+		eventListeners: {}

+	});

+

+	function Log4JavaScript() {}

+	Log4JavaScript.prototype = new EventSupport();

+	log4javascript = new Log4JavaScript();

+

+	log4javascript = {

+		isStub: true,

+		version: "1.4.6",

+		edition: "log4javascript_production",

+        setDocumentReady: f,

+		setEventTypes: f,

+		addEventListener: f,

+		removeEventListener: f,

+		dispatchEvent: f,

+		eventTypes: [],

+		eventListeners: {},

+		logLog: {

+			setQuietMode: f,

+			setAlertAllErrors: f,

+			debug: f,

+			displayDebug: f,

+			warn: f,

+			error: f

+		},

+		handleError: f,

+		setEnabled: f,

+		isEnabled: f,

+		setTimeStampsInMilliseconds: f,

+		isTimeStampsInMilliseconds: f,

+		evalInScope: f,

+		setShowStackTraces: f,

+		getLogger: getLogger,

+		getDefaultLogger: getLogger,

+		getNullLogger: getLogger,

+		getRootLogger: getLogger,

+		resetConfiguration: f,

+		Level: ff(),

+		LoggingEvent: ff(),

+		Layout: ff(),

+		Appender: ff()

+	};

+

+	// LoggingEvents

+	log4javascript.LoggingEvent.prototype = {

+		getThrowableStrRep: f,

+		getCombinedMessages: f

+	};

+

+	// Levels

+	log4javascript.Level.prototype = {

+		toString: f,

+		equals: f,

+		isGreaterOrEqual: f

+	};

+	var level = new log4javascript.Level();

+	copy(log4javascript.Level, {

+		ALL: level,

+		TRACE: level,

+		DEBUG: level,

+		INFO: level,

+		WARN: level,

+		ERROR: level,

+		FATAL: level,

+		OFF: level

+	});

+

+	// Layouts

+	log4javascript.Layout.prototype = {

+		defaults: {},

+		format: f,

+		ignoresThrowable: f,

+		getContentType: f,

+		allowBatching: f,

+		getDataValues: f,

+		setKeys: f,

+		setCustomField: f,

+		hasCustomFields: f,

+		setTimeStampsInMilliseconds: f,

+		isTimeStampsInMilliseconds: f,

+		getTimeStampValue: f,

+		toString: f

+	};

+

+	// PatternLayout related

+	log4javascript.SimpleDateFormat = ff();

+	log4javascript.SimpleDateFormat.prototype = {

+		setMinimalDaysInFirstWeek: f,

+		getMinimalDaysInFirstWeek: f,

+		format: f

+	};

+

+	// PatternLayout

+	log4javascript.PatternLayout = ff();

+	log4javascript.PatternLayout.prototype = new log4javascript.Layout();

+

+	// Appenders

+	log4javascript.Appender = ff();

+	log4javascript.Appender.prototype = new EventSupport();

+

+	copy(log4javascript.Appender.prototype, {

+		layout: new log4javascript.PatternLayout(),

+		threshold: log4javascript.Level.ALL,

+		loggers: [],

+		doAppend: f,

+		append: f,

+		setLayout: f,

+		getLayout: f,

+		setThreshold: f,

+		getThreshold: f,

+		setAddedToLogger: f,

+		setRemovedFromLogger: f,

+		group: f,

+		groupEnd: f,

+		toString: f

+	});

+	// SimpleLayout

+	log4javascript.SimpleLayout = ff();

+	log4javascript.SimpleLayout.prototype = new log4javascript.Layout();

+	// NullLayout

+	log4javascript.NullLayout = ff();

+	log4javascript.NullLayout.prototype = new log4javascript.Layout();

+	// ZmlLayout

+	log4javascript.XmlLayout = ff();

+	log4javascript.XmlLayout.prototype = new log4javascript.Layout();

+	copy(log4javascript.XmlLayout.prototype, {

+		escapeCdata: f,

+		isCombinedMessages: f

+	});

+	// JsonLayout

+	log4javascript.JsonLayout = ff();

+	log4javascript.JsonLayout.prototype = new log4javascript.Layout();

+	copy(log4javascript.JsonLayout.prototype, {

+		isReadable: f,

+		isCombinedMessages: f

+	});

+	// HttpPostDataLayout 

+	log4javascript.HttpPostDataLayout = ff();

+	log4javascript.HttpPostDataLayout.prototype = new log4javascript.Layout();

+	// PatternLayout

+	log4javascript.PatternLayout = ff();

+	log4javascript.PatternLayout.prototype = new log4javascript.Layout();

+	// AjaxAppender

+	log4javascript.AjaxAppender = ff();

+	log4javascript.AjaxAppender.prototype = new log4javascript.Appender();

+	copy(log4javascript.AjaxAppender.prototype, {

+		getSessionId: f,

+		setSessionId: f,

+		isTimed: f,

+		setTimed: f,

+		getTimerInterval: f,

+		setTimerInterval: f,

+		isWaitForResponse: f,

+		setWaitForResponse: f,

+		getBatchSize: f,

+		setBatchSize: f,

+		isSendAllOnUnload: f,

+		setSendAllOnUnload: f,

+		setRequestSuccessCallback: f,

+		setFailCallback: f,

+		getPostVarName: f,

+		setPostVarName: f,

+		sendAll: f,

+		sendAllRemaining: f,

+		defaults: {

+			requestSuccessCallback: null,

+			failCallback: null

+		}

+	});

+	return log4javascript;

+})();

+if (typeof window.log4javascript == "undefined") {

+	var log4javascript = log4javascript_stub;

+}

diff --git a/xos/core/static/log4javascript-1.4.6/js/stubs/log4javascript_uncompressed.js b/xos/core/static/log4javascript-1.4.6/js/stubs/log4javascript_uncompressed.js
new file mode 100644
index 0000000..1976fbc
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/js/stubs/log4javascript_uncompressed.js
@@ -0,0 +1,341 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+var log4javascript_stub = (function() {

+	var log4javascript;

+

+	function ff() {

+		return function() {};

+	}

+	function copy(obj, props) {

+		for (var i in props) {

+			obj[i] = props[i];

+		}

+	}

+	var f = ff();

+

+	// Loggers

+	var Logger = ff();

+	copy(Logger.prototype, {

+		addChild: f,

+		getEffectiveAppenders: f,

+		invalidateAppenderCache: f,

+		getAdditivity: f,

+		setAdditivity: f,

+		addAppender: f,

+		removeAppender: f,

+		removeAllAppenders: f,

+		log: f,

+		setLevel: f,

+		getLevel: f,

+		getEffectiveLevel: f,

+		trace: f,

+		debug: f,

+		info: f,

+		warn: f,

+		error: f,

+		fatal: f,

+		isEnabledFor: f,

+		isTraceEnabled: f,

+		isDebugEnabled: f,

+		isInfoEnabled: f,

+		isWarnEnabled: f,

+		isErrorEnabled: f,

+		isFatalEnabled: f,

+		callAppenders: f,

+		group: f,

+		groupEnd: f,

+		time: f,

+		timeEnd: f,

+		assert: f,

+		parent: new Logger()

+	});

+

+	var getLogger = function() {

+		return new Logger();

+	};

+

+	function EventSupport() {}

+

+	copy(EventSupport.prototype, {

+		setEventTypes: f,

+		addEventListener: f,

+		removeEventListener: f,

+		dispatchEvent: f,

+		eventTypes: [],

+		eventListeners: {}

+	});

+

+	function Log4JavaScript() {}

+	Log4JavaScript.prototype = new EventSupport();

+	log4javascript = new Log4JavaScript();

+

+	log4javascript = {

+		isStub: true,

+		version: "1.4.6",

+		edition: "log4javascript",

+        setDocumentReady: f,

+		setEventTypes: f,

+		addEventListener: f,

+		removeEventListener: f,

+		dispatchEvent: f,

+		eventTypes: [],

+		eventListeners: {},

+		logLog: {

+			setQuietMode: f,

+			setAlertAllErrors: f,

+			debug: f,

+			displayDebug: f,

+			warn: f,

+			error: f

+		},

+		handleError: f,

+		setEnabled: f,

+		isEnabled: f,

+		setTimeStampsInMilliseconds: f,

+		isTimeStampsInMilliseconds: f,

+		evalInScope: f,

+		setShowStackTraces: f,

+		getLogger: getLogger,

+		getDefaultLogger: getLogger,

+		getNullLogger: getLogger,

+		getRootLogger: getLogger,

+		resetConfiguration: f,

+		Level: ff(),

+		LoggingEvent: ff(),

+		Layout: ff(),

+		Appender: ff()

+	};

+

+	// LoggingEvents

+	log4javascript.LoggingEvent.prototype = {

+		getThrowableStrRep: f,

+		getCombinedMessages: f

+	};

+

+	// Levels

+	log4javascript.Level.prototype = {

+		toString: f,

+		equals: f,

+		isGreaterOrEqual: f

+	};

+	var level = new log4javascript.Level();

+	copy(log4javascript.Level, {

+		ALL: level,

+		TRACE: level,

+		DEBUG: level,

+		INFO: level,

+		WARN: level,

+		ERROR: level,

+		FATAL: level,

+		OFF: level

+	});

+

+	// Layouts

+	log4javascript.Layout.prototype = {

+		defaults: {},

+		format: f,

+		ignoresThrowable: f,

+		getContentType: f,

+		allowBatching: f,

+		getDataValues: f,

+		setKeys: f,

+		setCustomField: f,

+		hasCustomFields: f,

+		setTimeStampsInMilliseconds: f,

+		isTimeStampsInMilliseconds: f,

+		getTimeStampValue: f,

+		toString: f

+	};

+

+	// PatternLayout related

+	log4javascript.SimpleDateFormat = ff();

+	log4javascript.SimpleDateFormat.prototype = {

+		setMinimalDaysInFirstWeek: f,

+		getMinimalDaysInFirstWeek: f,

+		format: f

+	};

+

+	// PatternLayout

+	log4javascript.PatternLayout = ff();

+	log4javascript.PatternLayout.prototype = new log4javascript.Layout();

+

+	// Appenders

+	log4javascript.Appender = ff();

+	log4javascript.Appender.prototype = new EventSupport();

+

+	copy(log4javascript.Appender.prototype, {

+		layout: new log4javascript.PatternLayout(),

+		threshold: log4javascript.Level.ALL,

+		loggers: [],

+		doAppend: f,

+		append: f,

+		setLayout: f,

+		getLayout: f,

+		setThreshold: f,

+		getThreshold: f,

+		setAddedToLogger: f,

+		setRemovedFromLogger: f,

+		group: f,

+		groupEnd: f,

+		toString: f

+	});

+	// SimpleLayout

+	log4javascript.SimpleLayout = ff();

+	log4javascript.SimpleLayout.prototype = new log4javascript.Layout();

+	// NullLayout

+	log4javascript.NullLayout = ff();

+	log4javascript.NullLayout.prototype = new log4javascript.Layout();

+	// ZmlLayout

+	log4javascript.XmlLayout = ff();

+	log4javascript.XmlLayout.prototype = new log4javascript.Layout();

+	copy(log4javascript.XmlLayout.prototype, {

+		escapeCdata: f,

+		isCombinedMessages: f

+	});

+	// JsonLayout

+	log4javascript.JsonLayout = ff();

+	log4javascript.JsonLayout.prototype = new log4javascript.Layout();

+	copy(log4javascript.JsonLayout.prototype, {

+		isReadable: f,

+		isCombinedMessages: f

+	});

+	// HttpPostDataLayout 

+	log4javascript.HttpPostDataLayout = ff();

+	log4javascript.HttpPostDataLayout.prototype = new log4javascript.Layout();

+	// PatternLayout

+	log4javascript.PatternLayout = ff();

+	log4javascript.PatternLayout.prototype = new log4javascript.Layout();

+	// AlertAppender

+	log4javascript.AlertAppender = ff();

+	log4javascript.AlertAppender.prototype = new log4javascript.Appender();

+	// BrowserConsoleAppender

+	log4javascript.BrowserConsoleAppender = ff();

+	log4javascript.BrowserConsoleAppender.prototype = new log4javascript.Appender();

+	// AjaxAppender

+	log4javascript.AjaxAppender = ff();

+	log4javascript.AjaxAppender.prototype = new log4javascript.Appender();

+	copy(log4javascript.AjaxAppender.prototype, {

+		getSessionId: f,

+		setSessionId: f,

+		isTimed: f,

+		setTimed: f,

+		getTimerInterval: f,

+		setTimerInterval: f,

+		isWaitForResponse: f,

+		setWaitForResponse: f,

+		getBatchSize: f,

+		setBatchSize: f,

+		isSendAllOnUnload: f,

+		setSendAllOnUnload: f,

+		setRequestSuccessCallback: f,

+		setFailCallback: f,

+		getPostVarName: f,

+		setPostVarName: f,

+		sendAll: f,

+		sendAllRemaining: f,

+		defaults: {

+			requestSuccessCallback: null,

+			failCallback: null

+		}

+	});

+	// ConsoleAppender

+	function ConsoleAppender() {}

+	ConsoleAppender.prototype = new log4javascript.Appender();

+	copy(ConsoleAppender.prototype, {

+		create: f,

+		isNewestMessageAtTop: f,

+		setNewestMessageAtTop: f,

+		isScrollToLatestMessage: f,

+		setScrollToLatestMessage: f,

+		getWidth: f,

+		setWidth: f,

+		getHeight: f,

+		setHeight: f,

+		getMaxMessages: f,

+		setMaxMessages: f,

+		isShowCommandLine: f,

+		setShowCommandLine: f,

+		isShowHideButton: f,

+		setShowHideButton: f,

+		isShowCloseButton: f,

+		setShowCloseButton: f,

+		getCommandLineObjectExpansionDepth: f,

+		setCommandLineObjectExpansionDepth: f,

+		isInitiallyMinimized: f,

+		setInitiallyMinimized: f,

+		isUseDocumentWrite: f,

+		setUseDocumentWrite: f,

+		group: f,

+		groupEnd: f,

+		clear: f,

+		focus: f,

+		focusCommandLine: f,

+		focusSearch: f,

+		getCommandWindow: f,

+		setCommandWindow: f,

+		executeLastCommand: f,

+		getCommandLayout: f,

+		setCommandLayout: f,

+		evalCommandAndAppend: f,

+		addCommandLineFunction: f,

+		storeCommandHistory: f,

+		unload: f

+	});

+

+	ConsoleAppender.addGlobalCommandLineFunction = f;

+

+	// InPageAppender

+	log4javascript.InPageAppender = ff();

+	log4javascript.InPageAppender.prototype = new ConsoleAppender();

+	copy(log4javascript.InPageAppender.prototype, {

+		addCssProperty: f,

+		hide: f,

+		show: f,

+		isVisible: f,

+		close: f,

+		defaults: {

+			layout: new log4javascript.PatternLayout(),

+			maxMessages: null

+		}

+	});

+	log4javascript.InlineAppender = log4javascript.InPageAppender;

+

+	// PopUpAppender

+	log4javascript.PopUpAppender = ff();

+	log4javascript.PopUpAppender.prototype = new ConsoleAppender();

+	copy(log4javascript.PopUpAppender.prototype, {

+		isUseOldPopUp: f,

+		setUseOldPopUp: f,

+		isComplainAboutPopUpBlocking: f,

+		setComplainAboutPopUpBlocking: f,

+		isFocusPopUp: f,

+		setFocusPopUp: f,

+		isReopenWhenClosed: f,

+		setReopenWhenClosed: f,

+		close: f,

+		hide: f,

+		show: f,

+		defaults: {

+			layout: new log4javascript.PatternLayout(),

+			maxMessages: null

+		}

+	});

+	return log4javascript;

+})();

+if (typeof window.log4javascript == "undefined") {

+	var log4javascript = log4javascript_stub;

+}

diff --git a/xos/core/static/log4javascript-1.4.6/js/tests/log4javascript.js b/xos/core/static/log4javascript-1.4.6/js/tests/log4javascript.js
new file mode 100644
index 0000000..89fd903
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/js/tests/log4javascript.js
@@ -0,0 +1,32 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+

+function array_contains(arr,val){for(var i=0;i<arr.length;i++){if(arr[i]==val){return true;}}

+return false;}

+function compareObjectInterface(obj1,obj1_name,obj2,obj2_name,namePrefix){if(!namePrefix){namePrefix="";}

+var obj1PropertyNames=new Array();for(var i in obj1){if(i!="prototype"&&i!="arguments"){obj1PropertyNames.push(i);}}

+if(obj1&&obj1.prototype&&!array_contains(obj1PropertyNames,"prototype")){}

+for(var j=0;j<obj1PropertyNames.length;j++){var propertyName=obj1PropertyNames[j];if((typeof obj1[propertyName]=="function"||typeof obj1[propertyName]=="object")&&!(obj1[propertyName]instanceof Array)){var propertyFullyQualifiedName=(namePrefix=="")?propertyName:namePrefix+"."+propertyName;try{if(typeof obj2[propertyName]=="undefined"){throw new Error(obj2_name+" does not contain "+propertyFullyQualifiedName+" in "+obj1_name);}else if(typeof obj2[propertyName]!=typeof obj1[propertyName]){throw new Error(obj2_name+"'s "+propertyFullyQualifiedName+" is of the wrong type: "+typeof obj2[propertyName]+" when it is type "+typeof obj1[propertyName]+" in "+obj1_name);}else if(obj1[propertyName]!=Function.prototype.apply){if(!compareObjectInterface(obj1[propertyName],obj1_name,obj2[propertyName],obj2_name,propertyFullyQualifiedName)){throw new Error("Interfaces don't match");}}}catch(ex){throw new Error("Exception while checking property name "+propertyFullyQualifiedName+" in "+obj2_name+": "+ex.message);}}}

+return true;};var testLayoutWithVariables=function(layout,t){var emptyObject={};var emptyArray=[];var emptyString="";var localUndefined=emptyArray[0];var oneLevelObject={"name":"One-level object"};var twoLevelObject={"name":"Two-level object","data":oneLevelObject};var threeLevelObject={"name":"Three-level object","data":twoLevelObject};var anArray=[3,"stuff",true,false,0,null,localUndefined,3.14,function(p){return"I'm a function";},[1,"things"]];var arrayOfTestItems=[emptyObject,emptyString,emptyString,localUndefined,oneLevelObject,twoLevelObject,threeLevelObject,anArray];t.log("Testing layout "+layout)

+for(var i=0;i<arrayOfTestItems.length;i++){var ex=new Error("Test error");var loggingEvent=new log4javascript.LoggingEvent(t.logger,new Date(),log4javascript.Level.INFO,[arrayOfTestItems[i]],null);t.log("Formatting",arrayOfTestItems[i],result);var result=layout.format(loggingEvent);loggingEvent.exception=ex;t.log("Formatting with exception",arrayOfTestItems[i],result);result=layout.format(loggingEvent);}};xn.test.enableTestDebug=true;xn.test.enable_log4javascript=false;xn.test.suite("log4javascript tests",function(s){log4javascript.logLog.setQuietMode(true);var ArrayAppender=function(layout){if(layout){this.setLayout(layout);}

+this.logMessages=[];};ArrayAppender.prototype=new log4javascript.Appender();ArrayAppender.prototype.layout=new log4javascript.NullLayout();ArrayAppender.prototype.append=function(loggingEvent){var formattedMessage=this.getLayout().format(loggingEvent);if(this.getLayout().ignoresThrowable()){formattedMessage+=loggingEvent.getThrowableStrRep();}

+this.logMessages.push(formattedMessage);};ArrayAppender.prototype.toString=function(){return"[ArrayAppender]";};s.setUp=function(t){t.logger=log4javascript.getLogger("test");t.logger.removeAllAppenders();t.appender=new ArrayAppender();t.logger.addAppender(t.appender);};s.tearDown=function(t){t.logger.removeAppender(t.appender);log4javascript.resetConfiguration();};s.test("Stub script interface test",function(t){try{compareObjectInterface(log4javascript,"log4javascript",log4javascript_stub,"log4javascript_stub");}catch(ex){t.fail(ex);}});s.test("Disable log4javascript test",function(t){log4javascript.setEnabled(false);t.logger.debug("TEST");t.assertEquals(t.appender.logMessages.length,0);log4javascript.setEnabled(true);});s.test("Array.splice test 1",function(t){var a=["Marlon","Ashley","Darius","Lloyd"];var deletedItems=a.splice(1,2);t.assertEquals(a.join(","),"Marlon,Lloyd");t.assertEquals(deletedItems.join(","),"Ashley,Darius");});s.test("Array.splice test 2",function(t){var a=["Marlon","Ashley","Darius","Lloyd"];var deletedItems=a.splice(1,1,"Malky","Jay");t.assertEquals(a.join(","),"Marlon,Malky,Jay,Darius,Lloyd");t.assertEquals(deletedItems.join(","),"Ashley");});s.test("array_remove test",function(t){var array_remove=log4javascript.evalInScope("array_remove");var a=["Marlon","Ashley","Darius"];array_remove(a,"Darius");t.assertEquals(a.join(","),"Marlon,Ashley");});s.test("array_remove with empty array test",function(t){var array_remove=log4javascript.evalInScope("array_remove");var a=[];array_remove(a,"Darius");t.assertEquals(a.join(","),"");});s.test("Logger logging test",function(t){t.logger.debug("TEST");t.assertEquals(t.appender.logMessages.length,1);});s.test("Logger levels test",function(t){var originalLevel=t.logger.getEffectiveLevel();t.logger.setLevel(log4javascript.Level.INFO);t.logger.debug("TEST");t.logger.setLevel(originalLevel);t.assertEquals(t.appender.logMessages.length,0);});s.test("Logger getEffectiveLevel inheritance test 1",function(t){var parentLogger=log4javascript.getLogger("test1");var childLogger=log4javascript.getLogger("test1.test2");parentLogger.setLevel(log4javascript.Level.ERROR);t.assertEquals(childLogger.getEffectiveLevel(),log4javascript.Level.ERROR);});s.test("Logger getEffectiveLevel inheritance test 2",function(t){var grandParentLogger=log4javascript.getLogger("test1");var childLogger=log4javascript.getLogger("test1.test2.test3");grandParentLogger.setLevel(log4javascript.Level.ERROR);t.assertEquals(childLogger.getEffectiveLevel(),log4javascript.Level.ERROR);});s.test("Logger getEffectiveLevel inheritance test 3",function(t){var parentLogger=log4javascript.getLogger("test1");var childLogger=log4javascript.getLogger("test1.test2");parentLogger.setLevel(log4javascript.Level.ERROR);childLogger.setLevel(log4javascript.Level.INFO);t.assertEquals(childLogger.getEffectiveLevel(),log4javascript.Level.INFO);});s.test("Logger getEffectiveLevel root inheritance test",function(t){var rootLogger=log4javascript.getRootLogger();var childLogger=log4javascript.getLogger("test1.test2.test3");rootLogger.setLevel(log4javascript.Level.WARN);t.assertEquals(childLogger.getEffectiveLevel(),log4javascript.Level.WARN);});s.test("Logger null level test",function(t){t.logger.setLevel(null);t.assertEquals(t.logger.getEffectiveLevel(),log4javascript.Level.DEBUG);});s.test("Logger appender additivity test 1",function(t){var parentLogger=log4javascript.getLogger("test1");var childLogger=log4javascript.getLogger("test1.test2");var parentLoggerAppender=new ArrayAppender();var childLoggerAppender=new ArrayAppender();parentLogger.addAppender(parentLoggerAppender);childLogger.addAppender(childLoggerAppender);parentLogger.info("Parent logger test message");childLogger.info("Child logger test message");t.assertEquals(parentLoggerAppender.logMessages.length,2);t.assertEquals(childLoggerAppender.logMessages.length,1);});s.test("Logger appender additivity test 2",function(t){var parentLogger=log4javascript.getLogger("test1");var childLogger=log4javascript.getLogger("test1.test2");var parentLoggerAppender=new ArrayAppender();var childLoggerAppender=new ArrayAppender();parentLogger.addAppender(parentLoggerAppender);childLogger.addAppender(childLoggerAppender);childLogger.setAdditivity(false);parentLogger.info("Parent logger test message");childLogger.info("Child logger test message");t.assertEquals(parentLoggerAppender.logMessages.length,1);t.assertEquals(childLoggerAppender.logMessages.length,1);});s.test("Logger appender additivity test 3",function(t){var parentLogger=log4javascript.getLogger("test1");var childLogger=log4javascript.getLogger("test1.test2");var parentLoggerAppender=new ArrayAppender();var childLoggerAppender=new ArrayAppender();parentLogger.addAppender(parentLoggerAppender);childLogger.addAppender(childLoggerAppender);childLogger.setAdditivity(false);parentLogger.info("Parent logger test message");childLogger.info("Child logger test message");childLogger.setAdditivity(true);childLogger.info("Child logger test message 2");t.assertEquals(parentLoggerAppender.logMessages.length,2);t.assertEquals(childLoggerAppender.logMessages.length,2);});s.test("Appender threshold test",function(t){t.appender.setThreshold(log4javascript.Level.INFO);t.logger.debug("TEST");t.assertEquals(t.appender.logMessages.length,0);});s.test("Basic appender / layout test",function(t){t.logger.debug("TEST");t.assertEquals(t.appender.logMessages[0],"TEST");});s.test("Appender uniqueness within logger test",function(t){t.logger.addAppender(t.appender);t.logger.debug("TEST");t.assertEquals(t.appender.logMessages.length,1);});s.test("Logger remove appender test",function(t){t.logger.debug("TEST");t.logger.removeAppender(t.appender);t.logger.debug("TEST AGAIN");t.assertEquals(t.appender.logMessages.length,1);});s.test("",function(t){t.logger.debug("TEST");t.logger.removeAppender(t.appender);t.logger.debug("TEST AGAIN");t.assertEquals(t.appender.logMessages.length,1);});s.test("SimpleLayout format test",function(t){var layout=new log4javascript.SimpleLayout();testLayoutWithVariables(layout,t);});s.test("SimpleLayout test",function(t){t.appender.setLayout(new log4javascript.SimpleLayout());t.logger.debug("TEST");t.assertEquals(t.appender.logMessages[0],"DEBUG - TEST");});s.test("NullLayout format test",function(t){var layout=new log4javascript.NullLayout();testLayoutWithVariables(layout,t);});s.test("NullLayout test",function(t){t.appender.setLayout(new log4javascript.NullLayout());t.logger.debug("TEST");t.assertEquals(t.appender.logMessages[0],"TEST");});s.test("XmlLayout format test",function(t){var layout=new log4javascript.XmlLayout();testLayoutWithVariables(layout,t);});s.test("XmlLayout test",function(t){t.appender.setLayout(new log4javascript.XmlLayout());t.logger.debug("TEST");t.assertRegexMatches(/^<log4javascript:event logger="test" timestamp="\d+" level="DEBUG">\s*<log4javascript:message><!\[CDATA\[TEST\]\]><\/log4javascript:message>\s*<\/log4javascript:event>\s*$/,t.appender.logMessages[0]);});s.test("XmlLayout with exception test",function(t){t.appender.setLayout(new log4javascript.XmlLayout());t.logger.debug("TEST",new Error("Test error"));t.assertRegexMatches(/^<log4javascript:event logger="test" timestamp="\d+" level="DEBUG">\s*<log4javascript:message><!\[CDATA\[TEST\]\]><\/log4javascript:message>\s*<log4javascript:exception>\s*<!\[CDATA\[.*\]\]><\/log4javascript:exception>\s*<\/log4javascript:event>\s*$/,t.appender.logMessages[0]);});var setUpXmlLayoutMillisecondsTest=function(t){t.date=new Date();t.timeInMilliseconds=t.date.getTime();t.timeInSeconds=Math.floor(t.timeInMilliseconds/1000);t.milliseconds=t.date.getMilliseconds();t.loggingEvent=new log4javascript.LoggingEvent(t.logger,t.date,log4javascript.Level.DEBUG,["TEST"],null);t.layout=new log4javascript.XmlLayout();}

+s.test("XmlLayout seconds/milliseconds test 1",function(t){setUpXmlLayoutMillisecondsTest(t);var regex=new RegExp('^<log4javascript:event logger="test" timestamp="'+t.timeInMilliseconds+'" level="DEBUG">\\s*<log4javascript:message><!\\[CDATA\\[TEST\\]\\]></log4javascript:message>\\s*</log4javascript:event>\\s*$');t.assertRegexMatches(regex,t.layout.format(t.loggingEvent));});s.test("XmlLayout seconds/milliseconds test 2",function(t){setUpXmlLayoutMillisecondsTest(t);log4javascript.setTimeStampsInMilliseconds(false);var formatted=t.layout.format(t.loggingEvent);log4javascript.setTimeStampsInMilliseconds(true);var regex=new RegExp('^<log4javascript:event logger="test" timestamp="'+t.timeInSeconds+'" milliseconds="'+t.milliseconds+'" level="DEBUG">\\s*<log4javascript:message><!\\[CDATA\\[TEST\\]\\]></log4javascript:message>\\s*</log4javascript:event>\\s*$');t.assertRegexMatches(regex,formatted);});s.test("XmlLayout seconds/milliseconds test 3",function(t){setUpXmlLayoutMillisecondsTest(t);t.layout.setTimeStampsInMilliseconds(false);var formatted=t.layout.format(t.loggingEvent);var regex=new RegExp('^<log4javascript:event logger="test" timestamp="'+t.timeInSeconds+'" milliseconds="'+t.milliseconds+'" level="DEBUG">\\s*<log4javascript:message><!\\[CDATA\\[TEST\\]\\]></log4javascript:message>\\s*</log4javascript:event>\\s*$');t.assertRegexMatches(regex,formatted);});s.test("escapeNewLines test",function(t){var escapeNewLines=log4javascript.evalInScope("escapeNewLines");var str="1\r2\n3\n4\r\n5\r6\r\n7";t.assertEquals(escapeNewLines(str),"1\\r\\n2\\r\\n3\\r\\n4\\r\\n5\\r\\n6\\r\\n7");});s.test("JsonLayout format test",function(t){var layout=new log4javascript.JsonLayout();testLayoutWithVariables(layout,t);});s.test("JsonLayout test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug("TEST");t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TEST"}$/,t.appender.logMessages[0]);});s.test("JsonLayout JSON validity test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug("TEST");eval("var o = "+t.appender.logMessages[0]);t.assertEquals(o.message,"TEST");});s.test("JsonLayout with number type message test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug(15);t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":15}$/,t.appender.logMessages[0]);});s.test("JsonLayout with object type message test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug({});t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"\[object Object\]"}$/,t.appender.logMessages[0]);});s.test("JsonLayout with boolean type message test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug(false);t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":false}$/,t.appender.logMessages[0]);});s.test("JsonLayout with quote test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug("TE\"S\"T");t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TE\\"S\\"T"}$/,t.appender.logMessages[0]);});s.test("JsonLayout with exception test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug("TEST",new Error("Test error"));t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TEST","exception":.*}$/,t.appender.logMessages[0]);});var setUpJsonLayoutMillisecondsTest=function(t){t.date=new Date();t.timeInMilliseconds=t.date.getTime();t.timeInSeconds=Math.floor(t.timeInMilliseconds/1000);t.milliseconds=t.date.getMilliseconds();t.loggingEvent=new log4javascript.LoggingEvent(t.logger,t.date,log4javascript.Level.DEBUG,["TEST"],null);t.layout=new log4javascript.JsonLayout();};s.test("JsonLayout seconds/milliseconds test 1",function(t){setUpJsonLayoutMillisecondsTest(t);var regex=new RegExp('^{"logger":"test","timestamp":'+t.timeInMilliseconds+',"level":"DEBUG","url":".*","message":"TEST"}$');t.assertRegexMatches(regex,t.layout.format(t.loggingEvent));});s.test("JsonLayout seconds/milliseconds test 2",function(t){setUpJsonLayoutMillisecondsTest(t);log4javascript.setTimeStampsInMilliseconds(false);var formatted=t.layout.format(t.loggingEvent);log4javascript.setTimeStampsInMilliseconds(true);var regex=new RegExp('^{"logger":"test","timestamp":'+t.timeInSeconds+',"level":"DEBUG","url":".*","message":"TEST","milliseconds":'+t.milliseconds+'}$');t.assertRegexMatches(regex,formatted);});s.test("JsonLayout seconds/milliseconds test 3",function(t){setUpJsonLayoutMillisecondsTest(t);t.layout.setTimeStampsInMilliseconds(false);var formatted=t.layout.format(t.loggingEvent);var regex=new RegExp('^{"logger":"test","timestamp":'+t.timeInSeconds+',"level":"DEBUG","url":".*","message":"TEST","milliseconds":'+t.milliseconds+'}$');t.assertRegexMatches(regex,formatted);});s.test("HttpPostDataLayout format test",function(t){var layout=new log4javascript.HttpPostDataLayout();testLayoutWithVariables(layout,t);});s.test("HttpPostDataLayout test",function(t){t.appender.setLayout(new log4javascript.HttpPostDataLayout());t.logger.debug("TEST");t.assertRegexMatches(/^logger=test&timestamp=\d+&level=DEBUG&url=.*&message=TEST$/,t.appender.logMessages[0]);});s.test("HttpPostDataLayout URL encoding test",function(t){t.appender.setLayout(new log4javascript.HttpPostDataLayout());t.logger.debug("TEST +\"1\"");t.assertRegexMatches(/^logger=test&timestamp=\d+&level=DEBUG&url=.*&message=TEST%20%2B%221%22$/,t.appender.logMessages[0]);});s.test("HttpPostDataLayout with exception test",function(t){t.appender.setLayout(new log4javascript.HttpPostDataLayout());t.logger.debug("TEST",new Error("Test error"));t.assertRegexMatches(/^logger=test&timestamp=\d+&level=DEBUG&url=.*&message=TEST&exception=.*$/,t.appender.logMessages[0]);});(function(){var formatObjectExpansion=log4javascript.evalInScope("formatObjectExpansion");var newLine=log4javascript.evalInScope("newLine");var arr=[null,undefined,1.2,"A string",[1,"test"],{a:{b:1}}];s.test("Basic formatObjectExpansion array test (depth: 1)",function(t){t.assertEquals(formatObjectExpansion(arr,1),"["+newLine+"  null,"+newLine+"  undefined,"+newLine+"  1.2,"+newLine+"  A string,"+newLine+"  1,test,"+newLine+"  [object Object]"+newLine+"]");});s.test("Basic formatObjectExpansion array test (depth: 2)",function(t){t.assertEquals(formatObjectExpansion(arr,2),"["+newLine+"  null,"+newLine+"  undefined,"+newLine+"  1.2,"+newLine+"  A string,"+newLine+"  ["+newLine+"    1,"+newLine+"    test"+newLine+"  ],"+newLine+"  {"+newLine+"    a: [object Object]"+newLine+"  }"+newLine+"]");});s.test("formatObjectExpansion simple object test",function(t){var obj={STRING:"A string"};t.assertEquals(formatObjectExpansion(obj,1),"{"+newLine+"  STRING: A string"+newLine+"}");});s.test("formatObjectExpansion simple circular object test",function(t){var obj={};obj.a=obj;t.assertEquals(formatObjectExpansion(obj,2),"{"+newLine+"  a: [object Object] [already expanded]"+newLine+"}");});})();var getSampleDate=function(){var date=new Date();date.setFullYear(2006);date.setMonth(7);date.setDate(30);date.setHours(15);date.setMinutes(38);date.setSeconds(45);return date;};s.test("String.replace test",function(t){t.assertEquals("Hello world".replace(/o/g,"Z"),"HellZ wZrld");});s.test("PatternLayout format test",function(t){var layout=new log4javascript.PatternLayout();testLayoutWithVariables(layout,t);});s.test("PatternLayout dates test",function(t){var layout=new log4javascript.PatternLayout("%d %d{DATE} %d{HH:ss}");t.appender.setLayout(layout);t.logger.debug("TEST");t.assertRegexMatches(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3} \d{2} [A-Z][a-z]{2} \d{4} \d{2}:\d{2}:\d{2},\d{3} \d{2}:\d{2}$/,t.appender.logMessages[0]);});s.test("PatternLayout modifiers test",function(t){var layout=new log4javascript.PatternLayout("%m|%3m|%-3m|%6m|%-6m|%.2m|%1.2m|%6.8m|%-1.2m|%-6.8m|");t.appender.setLayout(layout);t.logger.debug("TEST");t.assertEquals(t.appender.logMessages[0],"TEST|TEST|TEST|  TEST|TEST  |ST|ST|  TEST|ST|TEST  |");});s.test("PatternLayout conversion characters test",function(t){var layout=new log4javascript.PatternLayout("%c %n %p %r literal %%");t.appender.setLayout(layout);t.logger.debug("TEST");t.assertRegexMatches(/^test \s+ DEBUG \d+ literal %$/,t.appender.logMessages[0]);});s.test("PatternLayout message test",function(t){var layout=new log4javascript.PatternLayout("%m{1} %m{2}");t.appender.setLayout(layout);var testObj={strikers:{quick:"Marlon"}};t.logger.debug(testObj);t.assertEquals("{\r\n  strikers: [object Object]\r\n} {\r\n\  strikers: {\r\n    quick: Marlon\r\n  }\r\n}",t.appender.logMessages[0]);});s.test("Logging/grouping test",function(t){var browserConsoleAppender=new log4javascript.BrowserConsoleAppender();t.logger.addAppender(browserConsoleAppender);t.logger.trace("TEST TRACE");t.logger.debug("TEST DEBUG");t.logger.info("TEST INFO");t.logger.warn("TEST WARN");t.logger.error("TEST ERROR");t.logger.fatal("TEST FATAL");t.logger.fatal("TEST FATAL",new Error("Fake error"));t.logger.info("TEST INFO","Second message",["a","b","c"]);t.logger.group("TEST GROUP");t.logger.info("TEST INFO");t.logger.groupEnd("TEST GROUP");t.logger.info("TEST INFO");t.logger.removeAppender(browserConsoleAppender);});var testConsoleAppender=function(t,appender){var timeoutCallback=function(){return(windowLoaded?"Timed out while waiting for messages to appear":"Timed out while waiting for window to load")+". Debug messages: "+

+log4javascript.logLog.debugMessages.join("\r\n");}

+t.async(60000,timeoutCallback);var windowLoaded=false;var domChecked=false;var onLoadHandler=function(){log4javascript.logLog.debug("onLoadHandler");windowLoaded=true;var win=appender.getConsoleWindow();if(win&&win.loaded){var checkDom=function(){log4javascript.logLog.debug("checkDom");domChecked=true;var logContainer=win.logMainContainer;if(logContainer.hasChildNodes()){if(logContainer.innerHTML.indexOf("TEST MESSAGE")==-1){appender.close();t.fail("Log message not correctly logged (log container innerHTML: "+logContainer.innerHTML+")");}else{t.assert(appender.isVisible());appender.close();t.assert(!appender.isVisible());t.succeed();}}else{appender.close();t.fail("Console has no log messages");}}

+window.setTimeout(checkDom,300);}else{appender.close();t.fail("Console mistakenly raised load event");}}

+appender.addEventListener("load",onLoadHandler);t.logger.addAppender(appender);t.logger.debug("TEST MESSAGE");};s.test("InlineAppender test",function(t){var inlineAppender=new log4javascript.InlineAppender();inlineAppender.setInitiallyMinimized(false);inlineAppender.setNewestMessageAtTop(false);inlineAppender.setScrollToLatestMessage(true);inlineAppender.setWidth(600);inlineAppender.setHeight(200);testConsoleAppender(t,inlineAppender);});s.test("InPageAppender with separate console HTML file test",function(t){var inPageAppender=new log4javascript.InPageAppender();inPageAppender.setInitiallyMinimized(false);inPageAppender.setNewestMessageAtTop(false);inPageAppender.setScrollToLatestMessage(true);inPageAppender.setUseDocumentWrite(false);inPageAppender.setWidth(600);inPageAppender.setHeight(200);testConsoleAppender(t,inPageAppender);});s.test("PopUpAppender test",function(t){var popUpAppender=new log4javascript.PopUpAppender();popUpAppender.setFocusPopUp(true);popUpAppender.setUseOldPopUp(false);popUpAppender.setNewestMessageAtTop(false);popUpAppender.setScrollToLatestMessage(true);popUpAppender.setComplainAboutPopUpBlocking(false);popUpAppender.setWidth(600);popUpAppender.setHeight(200);testConsoleAppender(t,popUpAppender);});s.test("PopUpAppender with separate console HTML file test",function(t){var popUpAppender=new log4javascript.PopUpAppender();popUpAppender.setFocusPopUp(true);popUpAppender.setUseOldPopUp(false);popUpAppender.setNewestMessageAtTop(false);popUpAppender.setScrollToLatestMessage(true);popUpAppender.setComplainAboutPopUpBlocking(false);popUpAppender.setUseDocumentWrite(false);popUpAppender.setWidth(600);popUpAppender.setHeight(200);testConsoleAppender(t,popUpAppender);});});

diff --git a/xos/core/static/log4javascript-1.4.6/js/tests/log4javascript_lite.js b/xos/core/static/log4javascript-1.4.6/js/tests/log4javascript_lite.js
new file mode 100644
index 0000000..b9eb6b7
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/js/tests/log4javascript_lite.js
@@ -0,0 +1,16 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

diff --git a/xos/core/static/log4javascript-1.4.6/js/tests/log4javascript_lite_uncompressed.js b/xos/core/static/log4javascript-1.4.6/js/tests/log4javascript_lite_uncompressed.js
new file mode 100644
index 0000000..b9eb6b7
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/js/tests/log4javascript_lite_uncompressed.js
@@ -0,0 +1,16 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

diff --git a/xos/core/static/log4javascript-1.4.6/js/tests/log4javascript_production.js b/xos/core/static/log4javascript-1.4.6/js/tests/log4javascript_production.js
new file mode 100644
index 0000000..f5d1090
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/js/tests/log4javascript_production.js
@@ -0,0 +1,28 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+

+function array_contains(arr,val){for(var i=0;i<arr.length;i++){if(arr[i]==val){return true;}}

+return false;}

+function compareObjectInterface(obj1,obj1_name,obj2,obj2_name,namePrefix){if(!namePrefix){namePrefix="";}

+var obj1PropertyNames=new Array();for(var i in obj1){if(i!="prototype"&&i!="arguments"){obj1PropertyNames.push(i);}}

+if(obj1&&obj1.prototype&&!array_contains(obj1PropertyNames,"prototype")){}

+for(var j=0;j<obj1PropertyNames.length;j++){var propertyName=obj1PropertyNames[j];if((typeof obj1[propertyName]=="function"||typeof obj1[propertyName]=="object")&&!(obj1[propertyName]instanceof Array)){var propertyFullyQualifiedName=(namePrefix=="")?propertyName:namePrefix+"."+propertyName;try{if(typeof obj2[propertyName]=="undefined"){throw new Error(obj2_name+" does not contain "+propertyFullyQualifiedName+" in "+obj1_name);}else if(typeof obj2[propertyName]!=typeof obj1[propertyName]){throw new Error(obj2_name+"'s "+propertyFullyQualifiedName+" is of the wrong type: "+typeof obj2[propertyName]+" when it is type "+typeof obj1[propertyName]+" in "+obj1_name);}else if(obj1[propertyName]!=Function.prototype.apply){if(!compareObjectInterface(obj1[propertyName],obj1_name,obj2[propertyName],obj2_name,propertyFullyQualifiedName)){throw new Error("Interfaces don't match");}}}catch(ex){throw new Error("Exception while checking property name "+propertyFullyQualifiedName+" in "+obj2_name+": "+ex.message);}}}

+return true;};var testLayoutWithVariables=function(layout,t){var emptyObject={};var emptyArray=[];var emptyString="";var localUndefined=emptyArray[0];var oneLevelObject={"name":"One-level object"};var twoLevelObject={"name":"Two-level object","data":oneLevelObject};var threeLevelObject={"name":"Three-level object","data":twoLevelObject};var anArray=[3,"stuff",true,false,0,null,localUndefined,3.14,function(p){return"I'm a function";},[1,"things"]];var arrayOfTestItems=[emptyObject,emptyString,emptyString,localUndefined,oneLevelObject,twoLevelObject,threeLevelObject,anArray];t.log("Testing layout "+layout)

+for(var i=0;i<arrayOfTestItems.length;i++){var ex=new Error("Test error");var loggingEvent=new log4javascript.LoggingEvent(t.logger,new Date(),log4javascript.Level.INFO,[arrayOfTestItems[i]],null);t.log("Formatting",arrayOfTestItems[i],result);var result=layout.format(loggingEvent);loggingEvent.exception=ex;t.log("Formatting with exception",arrayOfTestItems[i],result);result=layout.format(loggingEvent);}};xn.test.enableTestDebug=true;xn.test.enable_log4javascript=false;xn.test.suite("log4javascript tests",function(s){log4javascript.logLog.setQuietMode(true);var ArrayAppender=function(layout){if(layout){this.setLayout(layout);}

+this.logMessages=[];};ArrayAppender.prototype=new log4javascript.Appender();ArrayAppender.prototype.layout=new log4javascript.NullLayout();ArrayAppender.prototype.append=function(loggingEvent){var formattedMessage=this.getLayout().format(loggingEvent);if(this.getLayout().ignoresThrowable()){formattedMessage+=loggingEvent.getThrowableStrRep();}

+this.logMessages.push(formattedMessage);};ArrayAppender.prototype.toString=function(){return"[ArrayAppender]";};s.setUp=function(t){t.logger=log4javascript.getLogger("test");t.logger.removeAllAppenders();t.appender=new ArrayAppender();t.logger.addAppender(t.appender);};s.tearDown=function(t){t.logger.removeAppender(t.appender);log4javascript.resetConfiguration();};s.test("Stub script interface test",function(t){try{compareObjectInterface(log4javascript,"log4javascript",log4javascript_stub,"log4javascript_stub");}catch(ex){t.fail(ex);}});s.test("Disable log4javascript test",function(t){log4javascript.setEnabled(false);t.logger.debug("TEST");t.assertEquals(t.appender.logMessages.length,0);log4javascript.setEnabled(true);});s.test("Array.splice test 1",function(t){var a=["Marlon","Ashley","Darius","Lloyd"];var deletedItems=a.splice(1,2);t.assertEquals(a.join(","),"Marlon,Lloyd");t.assertEquals(deletedItems.join(","),"Ashley,Darius");});s.test("Array.splice test 2",function(t){var a=["Marlon","Ashley","Darius","Lloyd"];var deletedItems=a.splice(1,1,"Malky","Jay");t.assertEquals(a.join(","),"Marlon,Malky,Jay,Darius,Lloyd");t.assertEquals(deletedItems.join(","),"Ashley");});s.test("array_remove test",function(t){var array_remove=log4javascript.evalInScope("array_remove");var a=["Marlon","Ashley","Darius"];array_remove(a,"Darius");t.assertEquals(a.join(","),"Marlon,Ashley");});s.test("array_remove with empty array test",function(t){var array_remove=log4javascript.evalInScope("array_remove");var a=[];array_remove(a,"Darius");t.assertEquals(a.join(","),"");});s.test("Logger logging test",function(t){t.logger.debug("TEST");t.assertEquals(t.appender.logMessages.length,1);});s.test("Logger levels test",function(t){var originalLevel=t.logger.getEffectiveLevel();t.logger.setLevel(log4javascript.Level.INFO);t.logger.debug("TEST");t.logger.setLevel(originalLevel);t.assertEquals(t.appender.logMessages.length,0);});s.test("Logger getEffectiveLevel inheritance test 1",function(t){var parentLogger=log4javascript.getLogger("test1");var childLogger=log4javascript.getLogger("test1.test2");parentLogger.setLevel(log4javascript.Level.ERROR);t.assertEquals(childLogger.getEffectiveLevel(),log4javascript.Level.ERROR);});s.test("Logger getEffectiveLevel inheritance test 2",function(t){var grandParentLogger=log4javascript.getLogger("test1");var childLogger=log4javascript.getLogger("test1.test2.test3");grandParentLogger.setLevel(log4javascript.Level.ERROR);t.assertEquals(childLogger.getEffectiveLevel(),log4javascript.Level.ERROR);});s.test("Logger getEffectiveLevel inheritance test 3",function(t){var parentLogger=log4javascript.getLogger("test1");var childLogger=log4javascript.getLogger("test1.test2");parentLogger.setLevel(log4javascript.Level.ERROR);childLogger.setLevel(log4javascript.Level.INFO);t.assertEquals(childLogger.getEffectiveLevel(),log4javascript.Level.INFO);});s.test("Logger getEffectiveLevel root inheritance test",function(t){var rootLogger=log4javascript.getRootLogger();var childLogger=log4javascript.getLogger("test1.test2.test3");rootLogger.setLevel(log4javascript.Level.WARN);t.assertEquals(childLogger.getEffectiveLevel(),log4javascript.Level.WARN);});s.test("Logger null level test",function(t){t.logger.setLevel(null);t.assertEquals(t.logger.getEffectiveLevel(),log4javascript.Level.DEBUG);});s.test("Logger appender additivity test 1",function(t){var parentLogger=log4javascript.getLogger("test1");var childLogger=log4javascript.getLogger("test1.test2");var parentLoggerAppender=new ArrayAppender();var childLoggerAppender=new ArrayAppender();parentLogger.addAppender(parentLoggerAppender);childLogger.addAppender(childLoggerAppender);parentLogger.info("Parent logger test message");childLogger.info("Child logger test message");t.assertEquals(parentLoggerAppender.logMessages.length,2);t.assertEquals(childLoggerAppender.logMessages.length,1);});s.test("Logger appender additivity test 2",function(t){var parentLogger=log4javascript.getLogger("test1");var childLogger=log4javascript.getLogger("test1.test2");var parentLoggerAppender=new ArrayAppender();var childLoggerAppender=new ArrayAppender();parentLogger.addAppender(parentLoggerAppender);childLogger.addAppender(childLoggerAppender);childLogger.setAdditivity(false);parentLogger.info("Parent logger test message");childLogger.info("Child logger test message");t.assertEquals(parentLoggerAppender.logMessages.length,1);t.assertEquals(childLoggerAppender.logMessages.length,1);});s.test("Logger appender additivity test 3",function(t){var parentLogger=log4javascript.getLogger("test1");var childLogger=log4javascript.getLogger("test1.test2");var parentLoggerAppender=new ArrayAppender();var childLoggerAppender=new ArrayAppender();parentLogger.addAppender(parentLoggerAppender);childLogger.addAppender(childLoggerAppender);childLogger.setAdditivity(false);parentLogger.info("Parent logger test message");childLogger.info("Child logger test message");childLogger.setAdditivity(true);childLogger.info("Child logger test message 2");t.assertEquals(parentLoggerAppender.logMessages.length,2);t.assertEquals(childLoggerAppender.logMessages.length,2);});s.test("Appender threshold test",function(t){t.appender.setThreshold(log4javascript.Level.INFO);t.logger.debug("TEST");t.assertEquals(t.appender.logMessages.length,0);});s.test("Basic appender / layout test",function(t){t.logger.debug("TEST");t.assertEquals(t.appender.logMessages[0],"TEST");});s.test("Appender uniqueness within logger test",function(t){t.logger.addAppender(t.appender);t.logger.debug("TEST");t.assertEquals(t.appender.logMessages.length,1);});s.test("Logger remove appender test",function(t){t.logger.debug("TEST");t.logger.removeAppender(t.appender);t.logger.debug("TEST AGAIN");t.assertEquals(t.appender.logMessages.length,1);});s.test("",function(t){t.logger.debug("TEST");t.logger.removeAppender(t.appender);t.logger.debug("TEST AGAIN");t.assertEquals(t.appender.logMessages.length,1);});s.test("SimpleLayout format test",function(t){var layout=new log4javascript.SimpleLayout();testLayoutWithVariables(layout,t);});s.test("SimpleLayout test",function(t){t.appender.setLayout(new log4javascript.SimpleLayout());t.logger.debug("TEST");t.assertEquals(t.appender.logMessages[0],"DEBUG - TEST");});s.test("NullLayout format test",function(t){var layout=new log4javascript.NullLayout();testLayoutWithVariables(layout,t);});s.test("NullLayout test",function(t){t.appender.setLayout(new log4javascript.NullLayout());t.logger.debug("TEST");t.assertEquals(t.appender.logMessages[0],"TEST");});s.test("XmlLayout format test",function(t){var layout=new log4javascript.XmlLayout();testLayoutWithVariables(layout,t);});s.test("XmlLayout test",function(t){t.appender.setLayout(new log4javascript.XmlLayout());t.logger.debug("TEST");t.assertRegexMatches(/^<log4javascript:event logger="test" timestamp="\d+" level="DEBUG">\s*<log4javascript:message><!\[CDATA\[TEST\]\]><\/log4javascript:message>\s*<\/log4javascript:event>\s*$/,t.appender.logMessages[0]);});s.test("XmlLayout with exception test",function(t){t.appender.setLayout(new log4javascript.XmlLayout());t.logger.debug("TEST",new Error("Test error"));t.assertRegexMatches(/^<log4javascript:event logger="test" timestamp="\d+" level="DEBUG">\s*<log4javascript:message><!\[CDATA\[TEST\]\]><\/log4javascript:message>\s*<log4javascript:exception>\s*<!\[CDATA\[.*\]\]><\/log4javascript:exception>\s*<\/log4javascript:event>\s*$/,t.appender.logMessages[0]);});var setUpXmlLayoutMillisecondsTest=function(t){t.date=new Date();t.timeInMilliseconds=t.date.getTime();t.timeInSeconds=Math.floor(t.timeInMilliseconds/1000);t.milliseconds=t.date.getMilliseconds();t.loggingEvent=new log4javascript.LoggingEvent(t.logger,t.date,log4javascript.Level.DEBUG,["TEST"],null);t.layout=new log4javascript.XmlLayout();}

+s.test("XmlLayout seconds/milliseconds test 1",function(t){setUpXmlLayoutMillisecondsTest(t);var regex=new RegExp('^<log4javascript:event logger="test" timestamp="'+t.timeInMilliseconds+'" level="DEBUG">\\s*<log4javascript:message><!\\[CDATA\\[TEST\\]\\]></log4javascript:message>\\s*</log4javascript:event>\\s*$');t.assertRegexMatches(regex,t.layout.format(t.loggingEvent));});s.test("XmlLayout seconds/milliseconds test 2",function(t){setUpXmlLayoutMillisecondsTest(t);log4javascript.setTimeStampsInMilliseconds(false);var formatted=t.layout.format(t.loggingEvent);log4javascript.setTimeStampsInMilliseconds(true);var regex=new RegExp('^<log4javascript:event logger="test" timestamp="'+t.timeInSeconds+'" milliseconds="'+t.milliseconds+'" level="DEBUG">\\s*<log4javascript:message><!\\[CDATA\\[TEST\\]\\]></log4javascript:message>\\s*</log4javascript:event>\\s*$');t.assertRegexMatches(regex,formatted);});s.test("XmlLayout seconds/milliseconds test 3",function(t){setUpXmlLayoutMillisecondsTest(t);t.layout.setTimeStampsInMilliseconds(false);var formatted=t.layout.format(t.loggingEvent);var regex=new RegExp('^<log4javascript:event logger="test" timestamp="'+t.timeInSeconds+'" milliseconds="'+t.milliseconds+'" level="DEBUG">\\s*<log4javascript:message><!\\[CDATA\\[TEST\\]\\]></log4javascript:message>\\s*</log4javascript:event>\\s*$');t.assertRegexMatches(regex,formatted);});s.test("escapeNewLines test",function(t){var escapeNewLines=log4javascript.evalInScope("escapeNewLines");var str="1\r2\n3\n4\r\n5\r6\r\n7";t.assertEquals(escapeNewLines(str),"1\\r\\n2\\r\\n3\\r\\n4\\r\\n5\\r\\n6\\r\\n7");});s.test("JsonLayout format test",function(t){var layout=new log4javascript.JsonLayout();testLayoutWithVariables(layout,t);});s.test("JsonLayout test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug("TEST");t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TEST"}$/,t.appender.logMessages[0]);});s.test("JsonLayout JSON validity test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug("TEST");eval("var o = "+t.appender.logMessages[0]);t.assertEquals(o.message,"TEST");});s.test("JsonLayout with number type message test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug(15);t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":15}$/,t.appender.logMessages[0]);});s.test("JsonLayout with object type message test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug({});t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"\[object Object\]"}$/,t.appender.logMessages[0]);});s.test("JsonLayout with boolean type message test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug(false);t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":false}$/,t.appender.logMessages[0]);});s.test("JsonLayout with quote test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug("TE\"S\"T");t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TE\\"S\\"T"}$/,t.appender.logMessages[0]);});s.test("JsonLayout with exception test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug("TEST",new Error("Test error"));t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TEST","exception":.*}$/,t.appender.logMessages[0]);});var setUpJsonLayoutMillisecondsTest=function(t){t.date=new Date();t.timeInMilliseconds=t.date.getTime();t.timeInSeconds=Math.floor(t.timeInMilliseconds/1000);t.milliseconds=t.date.getMilliseconds();t.loggingEvent=new log4javascript.LoggingEvent(t.logger,t.date,log4javascript.Level.DEBUG,["TEST"],null);t.layout=new log4javascript.JsonLayout();};s.test("JsonLayout seconds/milliseconds test 1",function(t){setUpJsonLayoutMillisecondsTest(t);var regex=new RegExp('^{"logger":"test","timestamp":'+t.timeInMilliseconds+',"level":"DEBUG","url":".*","message":"TEST"}$');t.assertRegexMatches(regex,t.layout.format(t.loggingEvent));});s.test("JsonLayout seconds/milliseconds test 2",function(t){setUpJsonLayoutMillisecondsTest(t);log4javascript.setTimeStampsInMilliseconds(false);var formatted=t.layout.format(t.loggingEvent);log4javascript.setTimeStampsInMilliseconds(true);var regex=new RegExp('^{"logger":"test","timestamp":'+t.timeInSeconds+',"level":"DEBUG","url":".*","message":"TEST","milliseconds":'+t.milliseconds+'}$');t.assertRegexMatches(regex,formatted);});s.test("JsonLayout seconds/milliseconds test 3",function(t){setUpJsonLayoutMillisecondsTest(t);t.layout.setTimeStampsInMilliseconds(false);var formatted=t.layout.format(t.loggingEvent);var regex=new RegExp('^{"logger":"test","timestamp":'+t.timeInSeconds+',"level":"DEBUG","url":".*","message":"TEST","milliseconds":'+t.milliseconds+'}$');t.assertRegexMatches(regex,formatted);});s.test("HttpPostDataLayout format test",function(t){var layout=new log4javascript.HttpPostDataLayout();testLayoutWithVariables(layout,t);});s.test("HttpPostDataLayout test",function(t){t.appender.setLayout(new log4javascript.HttpPostDataLayout());t.logger.debug("TEST");t.assertRegexMatches(/^logger=test&timestamp=\d+&level=DEBUG&url=.*&message=TEST$/,t.appender.logMessages[0]);});s.test("HttpPostDataLayout URL encoding test",function(t){t.appender.setLayout(new log4javascript.HttpPostDataLayout());t.logger.debug("TEST +\"1\"");t.assertRegexMatches(/^logger=test&timestamp=\d+&level=DEBUG&url=.*&message=TEST%20%2B%221%22$/,t.appender.logMessages[0]);});s.test("HttpPostDataLayout with exception test",function(t){t.appender.setLayout(new log4javascript.HttpPostDataLayout());t.logger.debug("TEST",new Error("Test error"));t.assertRegexMatches(/^logger=test&timestamp=\d+&level=DEBUG&url=.*&message=TEST&exception=.*$/,t.appender.logMessages[0]);});(function(){var formatObjectExpansion=log4javascript.evalInScope("formatObjectExpansion");var newLine=log4javascript.evalInScope("newLine");var arr=[null,undefined,1.2,"A string",[1,"test"],{a:{b:1}}];s.test("Basic formatObjectExpansion array test (depth: 1)",function(t){t.assertEquals(formatObjectExpansion(arr,1),"["+newLine+"  null,"+newLine+"  undefined,"+newLine+"  1.2,"+newLine+"  A string,"+newLine+"  1,test,"+newLine+"  [object Object]"+newLine+"]");});s.test("Basic formatObjectExpansion array test (depth: 2)",function(t){t.assertEquals(formatObjectExpansion(arr,2),"["+newLine+"  null,"+newLine+"  undefined,"+newLine+"  1.2,"+newLine+"  A string,"+newLine+"  ["+newLine+"    1,"+newLine+"    test"+newLine+"  ],"+newLine+"  {"+newLine+"    a: [object Object]"+newLine+"  }"+newLine+"]");});s.test("formatObjectExpansion simple object test",function(t){var obj={STRING:"A string"};t.assertEquals(formatObjectExpansion(obj,1),"{"+newLine+"  STRING: A string"+newLine+"}");});s.test("formatObjectExpansion simple circular object test",function(t){var obj={};obj.a=obj;t.assertEquals(formatObjectExpansion(obj,2),"{"+newLine+"  a: [object Object] [already expanded]"+newLine+"}");});})();var getSampleDate=function(){var date=new Date();date.setFullYear(2006);date.setMonth(7);date.setDate(30);date.setHours(15);date.setMinutes(38);date.setSeconds(45);return date;};s.test("String.replace test",function(t){t.assertEquals("Hello world".replace(/o/g,"Z"),"HellZ wZrld");});s.test("PatternLayout format test",function(t){var layout=new log4javascript.PatternLayout();testLayoutWithVariables(layout,t);});s.test("PatternLayout dates test",function(t){var layout=new log4javascript.PatternLayout("%d %d{DATE} %d{HH:ss}");t.appender.setLayout(layout);t.logger.debug("TEST");t.assertRegexMatches(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3} \d{2} [A-Z][a-z]{2} \d{4} \d{2}:\d{2}:\d{2},\d{3} \d{2}:\d{2}$/,t.appender.logMessages[0]);});s.test("PatternLayout modifiers test",function(t){var layout=new log4javascript.PatternLayout("%m|%3m|%-3m|%6m|%-6m|%.2m|%1.2m|%6.8m|%-1.2m|%-6.8m|");t.appender.setLayout(layout);t.logger.debug("TEST");t.assertEquals(t.appender.logMessages[0],"TEST|TEST|TEST|  TEST|TEST  |ST|ST|  TEST|ST|TEST  |");});s.test("PatternLayout conversion characters test",function(t){var layout=new log4javascript.PatternLayout("%c %n %p %r literal %%");t.appender.setLayout(layout);t.logger.debug("TEST");t.assertRegexMatches(/^test \s+ DEBUG \d+ literal %$/,t.appender.logMessages[0]);});s.test("PatternLayout message test",function(t){var layout=new log4javascript.PatternLayout("%m{1} %m{2}");t.appender.setLayout(layout);var testObj={strikers:{quick:"Marlon"}};t.logger.debug(testObj);t.assertEquals("{\r\n  strikers: [object Object]\r\n} {\r\n\  strikers: {\r\n    quick: Marlon\r\n  }\r\n}",t.appender.logMessages[0]);});});

diff --git a/xos/core/static/log4javascript-1.4.6/js/tests/log4javascript_production_uncompressed.js b/xos/core/static/log4javascript-1.4.6/js/tests/log4javascript_production_uncompressed.js
new file mode 100644
index 0000000..e64990f
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/js/tests/log4javascript_production_uncompressed.js
@@ -0,0 +1,728 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+function array_contains(arr, val) {

+	for (var i = 0; i < arr.length; i++) {

+		if (arr[i] == val) {

+			return true;

+		}

+	}

+	return false;

+}

+

+// Recursively checks that obj2's interface contains all of obj1's

+// interface (functions and objects only)

+function compareObjectInterface(obj1, obj1_name, obj2, obj2_name, namePrefix) {

+	if (!namePrefix) {

+		namePrefix = "";

+	}

+	var obj1PropertyNames = new Array();

+	for (var i in obj1) {

+		if (i != "prototype" && i != "arguments") {

+			obj1PropertyNames.push(i);

+		}

+	}

+	if (obj1 && obj1.prototype && !array_contains(obj1PropertyNames, "prototype")) {

+		//obj1PropertyNames.push("prototype");

+	}

+	for (var j = 0; j < obj1PropertyNames.length; j++) {

+		var propertyName = obj1PropertyNames[j];

+		if ((typeof obj1[propertyName] == "function" || typeof obj1[propertyName] == "object") && !(obj1[propertyName] instanceof Array)) {

+			var propertyFullyQualifiedName = (namePrefix == "") ? propertyName : namePrefix + "." + propertyName;

+			try {

+				if (typeof obj2[propertyName] == "undefined") {

+					throw new Error(obj2_name + " does not contain " + propertyFullyQualifiedName + " in " + obj1_name);

+				} else if (typeof obj2[propertyName] != typeof obj1[propertyName]){

+					throw new Error(obj2_name + "'s " + propertyFullyQualifiedName + " is of the wrong type: " + typeof obj2[propertyName] + " when it is type " + typeof obj1[propertyName] + " in " + obj1_name);

+				} else if (obj1[propertyName] != Function.prototype.apply) {

+					if (!compareObjectInterface(obj1[propertyName], obj1_name, obj2[propertyName], obj2_name, propertyFullyQualifiedName)) {

+						throw new Error("Interfaces don't match");

+					}

+				}

+			} catch(ex) {

+				throw new Error("Exception while checking property name " + propertyFullyQualifiedName + " in " + obj2_name + ": " + ex.message);

+			}

+		}

+	}

+	return true;

+};

+

+// Simply tests a layout for exceptions when formatting

+var testLayoutWithVariables = function(layout, t) {

+	var emptyObject = {};

+	var emptyArray = [];

+	var emptyString = "";

+	var localUndefined = emptyArray[0];

+	var oneLevelObject = {

+		"name": "One-level object"

+	};

+	var twoLevelObject = {

+		"name": "Two-level object",

+		"data": oneLevelObject

+	};

+	var threeLevelObject = {

+		"name": "Three-level object",

+		"data": twoLevelObject

+	};

+	var anArray = [

+		3,

+		"stuff",

+		true,

+		false,

+		0,

+		null,

+		localUndefined,

+		3.14,

+		function(p) { return "I'm a function"; },

+		[1, "things"]

+	];

+	var arrayOfTestItems = [emptyObject, emptyString, emptyString, localUndefined, oneLevelObject,

+			twoLevelObject, threeLevelObject, anArray];

+

+	t.log("Testing layout " + layout)

+	for (var i = 0; i < arrayOfTestItems.length; i++) {

+		var ex = new Error("Test error");

+		var loggingEvent = new log4javascript.LoggingEvent(t.logger, new Date(), log4javascript.Level.INFO,

+				[arrayOfTestItems[i]], null);

+		t.log("Formatting", arrayOfTestItems[i], result);

+		var result = layout.format(loggingEvent);

+		// Now try with an exception

+		loggingEvent.exception = ex;

+		t.log("Formatting with exception", arrayOfTestItems[i], result);

+		result = layout.format(loggingEvent);

+	}

+};

+

+xn.test.enableTestDebug = true;

+xn.test.enable_log4javascript = false;

+

+xn.test.suite("log4javascript tests", function(s) {

+	log4javascript.logLog.setQuietMode(true);

+	var ArrayAppender = function(layout) {

+		if (layout) {

+			this.setLayout(layout);

+		}

+		this.logMessages = [];

+	};

+

+	ArrayAppender.prototype = new log4javascript.Appender();

+

+	ArrayAppender.prototype.layout = new log4javascript.NullLayout();

+

+	ArrayAppender.prototype.append = function(loggingEvent) {

+		var formattedMessage = this.getLayout().format(loggingEvent);

+		if (this.getLayout().ignoresThrowable()) {

+			formattedMessage += loggingEvent.getThrowableStrRep();

+		}

+		this.logMessages.push(formattedMessage);

+	};

+

+	ArrayAppender.prototype.toString = function() {

+		return "[ArrayAppender]";

+	};

+

+    s.setUp = function(t) {

+        t.logger = log4javascript.getLogger("test");

+		t.logger.removeAllAppenders();

+		t.appender = new ArrayAppender();

+        t.logger.addAppender(t.appender);

+    };

+

+    s.tearDown = function(t) {

+        t.logger.removeAppender(t.appender);

+		log4javascript.resetConfiguration();

+	};

+

+    s.test("Stub script interface test", function(t) {

+        try {

+            compareObjectInterface(log4javascript, "log4javascript", log4javascript_stub, "log4javascript_stub");

+        } catch (ex) {

+            t.fail(ex);

+        }

+    });

+

+	s.test("Disable log4javascript test", function(t) {

+		log4javascript.setEnabled(false);

+		t.logger.debug("TEST");

+		t.assertEquals(t.appender.logMessages.length, 0);

+		log4javascript.setEnabled(true);

+	});

+

+    s.test("Array.splice test 1", function(t) {

+        var a = ["Marlon", "Ashley", "Darius", "Lloyd"];

+        var deletedItems = a.splice(1, 2);

+        t.assertEquals(a.join(","), "Marlon,Lloyd");

+        t.assertEquals(deletedItems.join(","), "Ashley,Darius");

+    });

+

+    s.test("Array.splice test 2", function(t) {

+        var a = ["Marlon", "Ashley", "Darius", "Lloyd"];

+        var deletedItems = a.splice(1, 1, "Malky", "Jay");

+        t.assertEquals(a.join(","), "Marlon,Malky,Jay,Darius,Lloyd");

+        t.assertEquals(deletedItems.join(","), "Ashley");

+    });

+

+    s.test("array_remove test", function(t) {

+        var array_remove = log4javascript.evalInScope("array_remove");

+        var a = ["Marlon", "Ashley", "Darius"];

+        array_remove(a, "Darius");

+        t.assertEquals(a.join(","), "Marlon,Ashley");

+    });

+

+	s.test("array_remove with empty array test", function(t) {

+		var array_remove = log4javascript.evalInScope("array_remove");

+		var a = [];

+		array_remove(a, "Darius");

+		t.assertEquals(a.join(","), "");

+	});

+

+    s.test("Logger logging test", function(t) {

+        // Should log since the default level for loggers is DEBUG and

+        // the default threshold for appenders is ALL

+        t.logger.debug("TEST");

+        t.assertEquals(t.appender.logMessages.length, 1);

+    });

+

+    s.test("Logger levels test", function(t) {

+        var originalLevel = t.logger.getEffectiveLevel();

+        t.logger.setLevel(log4javascript.Level.INFO);

+        t.logger.debug("TEST");

+		t.logger.setLevel(originalLevel);

+        t.assertEquals(t.appender.logMessages.length, 0);

+    });

+

+	s.test("Logger getEffectiveLevel inheritance test 1", function(t) {

+		var parentLogger = log4javascript.getLogger("test1");

+		var childLogger = log4javascript.getLogger("test1.test2");

+		parentLogger.setLevel(log4javascript.Level.ERROR);

+		t.assertEquals(childLogger.getEffectiveLevel(), log4javascript.Level.ERROR);

+	});

+

+	s.test("Logger getEffectiveLevel inheritance test 2", function(t) {

+		var grandParentLogger = log4javascript.getLogger("test1");

+		var childLogger = log4javascript.getLogger("test1.test2.test3");

+		grandParentLogger.setLevel(log4javascript.Level.ERROR);

+		t.assertEquals(childLogger.getEffectiveLevel(), log4javascript.Level.ERROR);

+	});

+

+	s.test("Logger getEffectiveLevel inheritance test 3", function(t) {

+		var parentLogger = log4javascript.getLogger("test1");

+		var childLogger = log4javascript.getLogger("test1.test2");

+		parentLogger.setLevel(log4javascript.Level.ERROR);

+		childLogger.setLevel(log4javascript.Level.INFO);

+		t.assertEquals(childLogger.getEffectiveLevel(), log4javascript.Level.INFO);

+	});

+

+	s.test("Logger getEffectiveLevel root inheritance test", function(t) {

+		var rootLogger = log4javascript.getRootLogger();

+		var childLogger = log4javascript.getLogger("test1.test2.test3");

+		rootLogger.setLevel(log4javascript.Level.WARN);

+		t.assertEquals(childLogger.getEffectiveLevel(), log4javascript.Level.WARN);

+	});

+

+	s.test("Logger null level test", function(t) {

+		t.logger.setLevel(null);

+		// Should default to root logger level, which is DEBUG

+		t.assertEquals(t.logger.getEffectiveLevel(), log4javascript.Level.DEBUG);

+	});

+

+	s.test("Logger appender additivity test 1", function(t) {

+		var parentLogger = log4javascript.getLogger("test1");

+		var childLogger = log4javascript.getLogger("test1.test2");

+		var parentLoggerAppender = new ArrayAppender();

+		var childLoggerAppender = new ArrayAppender();

+

+		parentLogger.addAppender(parentLoggerAppender);

+		childLogger.addAppender(childLoggerAppender);

+

+		parentLogger.info("Parent logger test message");

+		childLogger.info("Child logger test message");

+

+		t.assertEquals(parentLoggerAppender.logMessages.length, 2);

+		t.assertEquals(childLoggerAppender.logMessages.length, 1);

+	});

+

+	s.test("Logger appender additivity test 2", function(t) {

+		var parentLogger = log4javascript.getLogger("test1");

+		var childLogger = log4javascript.getLogger("test1.test2");

+		var parentLoggerAppender = new ArrayAppender();

+		var childLoggerAppender = new ArrayAppender();

+

+		parentLogger.addAppender(parentLoggerAppender);

+		childLogger.addAppender(childLoggerAppender);

+

+		childLogger.setAdditivity(false);

+

+		parentLogger.info("Parent logger test message");

+		childLogger.info("Child logger test message");

+

+		t.assertEquals(parentLoggerAppender.logMessages.length, 1);

+		t.assertEquals(childLoggerAppender.logMessages.length, 1);

+	});

+

+	s.test("Logger appender additivity test 3", function(t) {

+		var parentLogger = log4javascript.getLogger("test1");

+		var childLogger = log4javascript.getLogger("test1.test2");

+		var parentLoggerAppender = new ArrayAppender();

+		var childLoggerAppender = new ArrayAppender();

+

+		parentLogger.addAppender(parentLoggerAppender);

+		childLogger.addAppender(childLoggerAppender);

+

+		childLogger.setAdditivity(false);

+

+		parentLogger.info("Parent logger test message");

+		childLogger.info("Child logger test message");

+

+		childLogger.setAdditivity(true);

+

+		childLogger.info("Child logger test message 2");

+

+		t.assertEquals(parentLoggerAppender.logMessages.length, 2);

+		t.assertEquals(childLoggerAppender.logMessages.length, 2);

+	});

+

+	s.test("Appender threshold test", function(t) {

+        t.appender.setThreshold(log4javascript.Level.INFO);

+        t.logger.debug("TEST");

+        t.assertEquals(t.appender.logMessages.length, 0);

+    });

+

+    s.test("Basic appender / layout test", function(t) {

+        t.logger.debug("TEST");

+		t.assertEquals(t.appender.logMessages[0], "TEST");

+    });

+

+	s.test("Appender uniqueness within logger test", function(t) {

+		// Add the same appender to the logger for a second time

+		t.logger.addAppender(t.appender);

+        t.logger.debug("TEST");

+        t.assertEquals(t.appender.logMessages.length, 1);

+    });

+

+	s.test("Logger remove appender test", function(t) {

+		t.logger.debug("TEST");

+		t.logger.removeAppender(t.appender);

+		t.logger.debug("TEST AGAIN");

+		t.assertEquals(t.appender.logMessages.length, 1);

+	});

+

+	s.test("", function(t) {

+		t.logger.debug("TEST");

+		t.logger.removeAppender(t.appender);

+		t.logger.debug("TEST AGAIN");

+		t.assertEquals(t.appender.logMessages.length, 1);

+	});

+	s.test("SimpleLayout format test", function(t) {

+		var layout = new log4javascript.SimpleLayout();

+		testLayoutWithVariables(layout, t);

+	});

+

+    s.test("SimpleLayout test", function(t) {

+        t.appender.setLayout(new log4javascript.SimpleLayout());

+        t.logger.debug("TEST");

+        t.assertEquals(t.appender.logMessages[0], "DEBUG - TEST");

+    });

+	s.test("NullLayout format test", function(t) {

+		var layout = new log4javascript.NullLayout();

+		testLayoutWithVariables(layout, t);

+	});

+

+    s.test("NullLayout test", function(t) {

+        t.appender.setLayout(new log4javascript.NullLayout());

+        t.logger.debug("TEST");

+        t.assertEquals(t.appender.logMessages[0], "TEST");

+    });

+	s.test("XmlLayout format test", function(t) {

+		var layout = new log4javascript.XmlLayout();

+		testLayoutWithVariables(layout, t);

+	});

+

+    s.test("XmlLayout test", function(t) {

+        t.appender.setLayout(new log4javascript.XmlLayout());

+        t.logger.debug("TEST");

+        t.assertRegexMatches(/^<log4javascript:event logger="test" timestamp="\d+" level="DEBUG">\s*<log4javascript:message><!\[CDATA\[TEST\]\]><\/log4javascript:message>\s*<\/log4javascript:event>\s*$/, t.appender.logMessages[0]);

+    });

+

+    s.test("XmlLayout with exception test", function(t) {

+        t.appender.setLayout(new log4javascript.XmlLayout());

+        t.logger.debug("TEST", new Error("Test error"));

+        t.assertRegexMatches(/^<log4javascript:event logger="test" timestamp="\d+" level="DEBUG">\s*<log4javascript:message><!\[CDATA\[TEST\]\]><\/log4javascript:message>\s*<log4javascript:exception>\s*<!\[CDATA\[.*\]\]><\/log4javascript:exception>\s*<\/log4javascript:event>\s*$/, t.appender.logMessages[0]);

+    });

+

+	var setUpXmlLayoutMillisecondsTest = function(t) {

+		t.date = new Date();

+		t.timeInMilliseconds = t.date.getTime();

+		t.timeInSeconds = Math.floor(t.timeInMilliseconds / 1000);

+		t.milliseconds = t.date.getMilliseconds();

+		

+		t.loggingEvent = new log4javascript.LoggingEvent(t.logger, t.date, log4javascript.Level.DEBUG, ["TEST"], null);

+		t.layout = new log4javascript.XmlLayout();

+	}

+

+	s.test("XmlLayout seconds/milliseconds test 1", function(t) {

+		setUpXmlLayoutMillisecondsTest(t);

+

+		// Test default (i.e. timestamps in milliseconds) first

+        var regex = new RegExp('^<log4javascript:event logger="test" timestamp="' + t.timeInMilliseconds + '" level="DEBUG">\\s*<log4javascript:message><!\\[CDATA\\[TEST\\]\\]></log4javascript:message>\\s*</log4javascript:event>\\s*$');

+        t.assertRegexMatches(regex, t.layout.format(t.loggingEvent));

+	});

+	

+	s.test("XmlLayout seconds/milliseconds test 2", function(t) {

+		setUpXmlLayoutMillisecondsTest(t);

+

+        // Change the global setting

+        log4javascript.setTimeStampsInMilliseconds(false);

+        var formatted = t.layout.format(t.loggingEvent);

+        log4javascript.setTimeStampsInMilliseconds(true);

+        var regex = new RegExp('^<log4javascript:event logger="test" timestamp="' + t.timeInSeconds + '" milliseconds="' + t.milliseconds + '" level="DEBUG">\\s*<log4javascript:message><!\\[CDATA\\[TEST\\]\\]></log4javascript:message>\\s*</log4javascript:event>\\s*$');

+        t.assertRegexMatches(regex, formatted);

+	});

+

+	s.test("XmlLayout seconds/milliseconds test 3", function(t) {

+		setUpXmlLayoutMillisecondsTest(t);

+

+        // Change the layout setting

+        t.layout.setTimeStampsInMilliseconds(false);

+        var formatted = t.layout.format(t.loggingEvent);

+        var regex = new RegExp('^<log4javascript:event logger="test" timestamp="' + t.timeInSeconds + '" milliseconds="' + t.milliseconds + '" level="DEBUG">\\s*<log4javascript:message><!\\[CDATA\\[TEST\\]\\]></log4javascript:message>\\s*</log4javascript:event>\\s*$');

+        t.assertRegexMatches(regex, formatted);

+	});

+	s.test("escapeNewLines test", function(t) {

+		var escapeNewLines = log4javascript.evalInScope("escapeNewLines");

+		var str = "1\r2\n3\n4\r\n5\r6\r\n7";

+		t.assertEquals(escapeNewLines(str), "1\\r\\n2\\r\\n3\\r\\n4\\r\\n5\\r\\n6\\r\\n7");

+	});

+

+	s.test("JsonLayout format test", function(t) {

+		var layout = new log4javascript.JsonLayout();

+		testLayoutWithVariables(layout, t);

+	});

+

+    s.test("JsonLayout test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug("TEST");

+        t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TEST"}$/, t.appender.logMessages[0]);

+    });

+

+    s.test("JsonLayout JSON validity test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug("TEST");

+        eval("var o = " + t.appender.logMessages[0]);

+        t.assertEquals(o.message, "TEST");

+    });

+

+    s.test("JsonLayout with number type message test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug(15);

+        t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":15}$/, t.appender.logMessages[0]);

+    });

+

+    s.test("JsonLayout with object type message test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug({});

+        t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"\[object Object\]"}$/, t.appender.logMessages[0]);

+    });

+

+    s.test("JsonLayout with boolean type message test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug(false);

+        t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":false}$/, t.appender.logMessages[0]);

+    });

+

+    s.test("JsonLayout with quote test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug("TE\"S\"T");

+        t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TE\\"S\\"T"}$/, t.appender.logMessages[0]);

+    });

+

+    s.test("JsonLayout with exception test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug("TEST", new Error("Test error"));

+        t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TEST","exception":.*}$/, t.appender.logMessages[0]);

+    });

+

+	var setUpJsonLayoutMillisecondsTest = function(t) {

+		t.date = new Date();

+		t.timeInMilliseconds = t.date.getTime();

+		t.timeInSeconds = Math.floor(t.timeInMilliseconds / 1000);

+		t.milliseconds = t.date.getMilliseconds();

+		

+		t.loggingEvent = new log4javascript.LoggingEvent(t.logger, t.date, log4javascript.Level.DEBUG, ["TEST"], null);

+		t.layout = new log4javascript.JsonLayout();

+	};

+

+	s.test("JsonLayout seconds/milliseconds test 1", function(t) {

+		setUpJsonLayoutMillisecondsTest(t);

+

+		// Test default (i.e. timestamps in milliseconds) first

+        var regex = new RegExp('^{"logger":"test","timestamp":' + t.timeInMilliseconds + ',"level":"DEBUG","url":".*","message":"TEST"}$');

+        t.assertRegexMatches(regex, t.layout.format(t.loggingEvent));

+	});

+	

+	s.test("JsonLayout seconds/milliseconds test 2", function(t) {

+		setUpJsonLayoutMillisecondsTest(t);

+

+        // Change the global setting

+        log4javascript.setTimeStampsInMilliseconds(false);

+        var formatted = t.layout.format(t.loggingEvent);

+        log4javascript.setTimeStampsInMilliseconds(true);

+        var regex = new RegExp('^{"logger":"test","timestamp":' + t.timeInSeconds + ',"level":"DEBUG","url":".*","message":"TEST","milliseconds":' + t.milliseconds + '}$');

+        t.assertRegexMatches(regex, formatted);

+	});

+

+	s.test("JsonLayout seconds/milliseconds test 3", function(t) {

+		setUpJsonLayoutMillisecondsTest(t);

+

+        // Change the layout setting

+        t.layout.setTimeStampsInMilliseconds(false);

+        var formatted = t.layout.format(t.loggingEvent);

+        var regex = new RegExp('^{"logger":"test","timestamp":' + t.timeInSeconds + ',"level":"DEBUG","url":".*","message":"TEST","milliseconds":' + t.milliseconds + '}$');

+        t.assertRegexMatches(regex, formatted);

+	});

+	s.test("HttpPostDataLayout format test", function(t) {

+		var layout = new log4javascript.HttpPostDataLayout();

+		testLayoutWithVariables(layout, t);

+	});

+

+    s.test("HttpPostDataLayout test", function(t) {

+        t.appender.setLayout(new log4javascript.HttpPostDataLayout());

+        t.logger.debug("TEST");

+        t.assertRegexMatches(/^logger=test&timestamp=\d+&level=DEBUG&url=.*&message=TEST$/, t.appender.logMessages[0]);

+    });

+

+    s.test("HttpPostDataLayout URL encoding test", function(t) {

+        t.appender.setLayout(new log4javascript.HttpPostDataLayout());

+        t.logger.debug("TEST +\"1\"");

+        t.assertRegexMatches(/^logger=test&timestamp=\d+&level=DEBUG&url=.*&message=TEST%20%2B%221%22$/, t.appender.logMessages[0]);

+    });

+

+    s.test("HttpPostDataLayout with exception test", function(t) {

+        t.appender.setLayout(new log4javascript.HttpPostDataLayout());

+        t.logger.debug("TEST", new Error("Test error"));

+        t.assertRegexMatches(/^logger=test&timestamp=\d+&level=DEBUG&url=.*&message=TEST&exception=.*$/, t.appender.logMessages[0]);

+    });

+

+	(function() {

+		var formatObjectExpansion = log4javascript.evalInScope("formatObjectExpansion");

+		var newLine = log4javascript.evalInScope("newLine");

+		var arr = [

+			null,

+			undefined,

+			1.2,

+			"A string",

+			[1, "test"],

+			{

+				a: {

+					b: 1

+				}

+			}

+		];

+

+		s.test("Basic formatObjectExpansion array test (depth: 1)", function(t) {

+			t.assertEquals(formatObjectExpansion(arr, 1),

+				"[" + newLine +

+				"  null," + newLine +

+				"  undefined," + newLine +

+				"  1.2," + newLine +

+				"  A string," + newLine +

+				"  1,test," + newLine +

+				"  [object Object]" + newLine +

+				"]"

+			);

+		});

+

+		s.test("Basic formatObjectExpansion array test (depth: 2)", function(t) {

+			t.assertEquals(formatObjectExpansion(arr, 2),

+				"[" + newLine +

+				"  null," + newLine +

+				"  undefined," + newLine +

+				"  1.2," + newLine +

+				"  A string," + newLine +

+				"  [" + newLine +

+				"    1," + newLine +

+				"    test" + newLine +

+				"  ]," + newLine +

+				"  {" + newLine +

+				"    a: [object Object]" + newLine +

+				"  }" + newLine +

+				"]"

+			);

+		});

+

+		s.test("formatObjectExpansion simple object test", function(t) {

+			var obj = {

+				STRING: "A string"

+			};

+			t.assertEquals(formatObjectExpansion(obj, 1), 

+				"{" + newLine +

+				"  STRING: A string" + newLine +

+				"}"

+			);

+		});

+

+		s.test("formatObjectExpansion simple circular object test", function(t) {

+			var obj = {};

+			obj.a = obj;

+			

+			t.assertEquals(formatObjectExpansion(obj, 2), 

+				"{" + newLine +

+				"  a: [object Object] [already expanded]" + newLine +

+				"}"

+			);

+		});

+	})();    /* ---------------------------------------------------------- */

+

+    var getSampleDate = function() {

+        var date = new Date();

+        date.setFullYear(2006);

+        date.setMonth(7);

+        date.setDate(30);

+        date.setHours(15);

+        date.setMinutes(38);

+        date.setSeconds(45);

+        return date;

+    };

+

+    /* ---------------------------------------------------------- */

+

+    s.test("String.replace test", function(t) {

+        t.assertEquals("Hello world".replace(/o/g, "Z"), "HellZ wZrld");

+    });

+

+	s.test("PatternLayout format test", function(t) {

+		var layout = new log4javascript.PatternLayout();

+		testLayoutWithVariables(layout, t);

+	});

+

+    s.test("PatternLayout dates test", function(t) {

+        var layout = new log4javascript.PatternLayout("%d %d{DATE} %d{HH:ss}");

+        t.appender.setLayout(layout);

+        t.logger.debug("TEST");

+        t.assertRegexMatches(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3} \d{2} [A-Z][a-z]{2} \d{4} \d{2}:\d{2}:\d{2},\d{3} \d{2}:\d{2}$/, t.appender.logMessages[0]);

+    });

+

+    s.test("PatternLayout modifiers test", function(t) {

+        var layout = new log4javascript.PatternLayout("%m|%3m|%-3m|%6m|%-6m|%.2m|%1.2m|%6.8m|%-1.2m|%-6.8m|");

+        t.appender.setLayout(layout);

+        t.logger.debug("TEST");

+        t.assertEquals(t.appender.logMessages[0], "TEST|TEST|TEST|  TEST|TEST  |ST|ST|  TEST|ST|TEST  |");

+    });

+

+    s.test("PatternLayout conversion characters test", function(t) {

+        var layout = new log4javascript.PatternLayout("%c %n %p %r literal %%");

+        t.appender.setLayout(layout);

+        t.logger.debug("TEST");

+        t.assertRegexMatches(/^test \s+ DEBUG \d+ literal %$/, t.appender.logMessages[0]);

+    });

+

+    s.test("PatternLayout message test", function(t) {

+        var layout = new log4javascript.PatternLayout("%m{1} %m{2}");

+        t.appender.setLayout(layout);

+        var testObj = {

+            strikers: {

+                quick: "Marlon"

+            }

+        };

+        t.logger.debug(testObj);

+        t.assertEquals("{\r\n  strikers: [object Object]\r\n} {\r\n\  strikers: {\r\n    quick: Marlon\r\n  }\r\n}", t.appender.logMessages[0]);

+    });

+/*

+	s.test("AjaxAppender JsonLayout single message test", function(t) {

+		t.async(10000);

+		// Create and add an Ajax appender

+		var ajaxAppender = new log4javascript.AjaxAppender("../log4javascript.do");

+		ajaxAppender.setLayout(new log4javascript.JsonLayout());

+		ajaxAppender.setRequestSuccessCallback(

+			function(xmlHttp) {

+				// Response comes back as JSON array of messages logged

+				var jsonResponse = xmlHttp.responseText;

+				var arr = eval(jsonResponse);

+				t.assertEquals(arr.length, 1);

+				t.assertEquals(arr[0], "TEST");

+				t.succeed();

+			}

+		);

+		ajaxAppender.setFailCallback(

+			function(msg) {

+				t.fail(msg);

+				ajaxErrorMessage = msg;

+			}

+		);

+		t.logger.addAppender(ajaxAppender);

+		t.logger.debug("TEST");

+	});

+

+	s.test("AjaxAppender JsonLayout batched messages test", function(t) {

+		t.async(10000);

+		var message1 = "TEST 1";

+		var message2 = "String with \"lots of 'quotes'\" + plusses in";

+		var message3 = "A non-threatening string";

+		// Create and add an Ajax appender

+		var ajaxAppender = new log4javascript.AjaxAppender("../log4javascript.do");

+		ajaxAppender.setLayout(new log4javascript.JsonLayout());

+		ajaxAppender.setBatchSize(3);

+		ajaxAppender.setRequestSuccessCallback(

+			function(xmlHttp) {

+				// Response comes back as JSON array of messages logged

+				var jsonResponse = xmlHttp.responseText;

+				var arr = eval(jsonResponse);

+				t.assertEquals(arr.length, 3);

+				t.assertEquals(arr[0], message1);

+				t.assertEquals(arr[1], message2);

+				t.assertEquals(arr[2], message3);

+				t.succeed();

+			}

+		);

+		ajaxAppender.setFailCallback(

+			function(msg) {

+				t.fail(msg);

+				ajaxErrorMessage = msg;

+			}

+		);

+		t.logger.addAppender(ajaxAppender);

+		t.logger.debug(message1);

+		t.logger.info(message2);

+		t.logger.warn(message3);

+	});

+

+	s.test("AjaxAppender HttpPostDataLayout single message test", function(t) {

+		t.async(10000);

+		// Create and add an Ajax appender

+		var ajaxAppender = new log4javascript.AjaxAppender("../log4javascript.do");

+		var testMessage = "TEST +\"1\"";

+		ajaxAppender.setLayout(new log4javascript.HttpPostDataLayout());

+		ajaxAppender.setRequestSuccessCallback(

+			function(xmlHttp) {

+				// Response comes back as JSON array of messages logged

+				var jsonResponse = xmlHttp.responseText;

+				var arr = eval(jsonResponse);

+				t.assertEquals(arr.length, 1);

+				t.assertEquals(arr[0], testMessage);

+				t.succeed();

+			}

+		);

+		ajaxAppender.setFailCallback(

+			function(msg) {

+				t.fail(msg);

+				ajaxErrorMessage = msg;

+			}

+		);

+		t.logger.addAppender(ajaxAppender);

+		t.logger.debug(testMessage);

+	});

+*/

+});
\ No newline at end of file
diff --git a/xos/core/static/log4javascript-1.4.6/js/tests/log4javascript_uncompressed.js b/xos/core/static/log4javascript-1.4.6/js/tests/log4javascript_uncompressed.js
new file mode 100644
index 0000000..55bd2ca
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/js/tests/log4javascript_uncompressed.js
@@ -0,0 +1,862 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+function array_contains(arr, val) {

+	for (var i = 0; i < arr.length; i++) {

+		if (arr[i] == val) {

+			return true;

+		}

+	}

+	return false;

+}

+

+// Recursively checks that obj2's interface contains all of obj1's

+// interface (functions and objects only)

+function compareObjectInterface(obj1, obj1_name, obj2, obj2_name, namePrefix) {

+	if (!namePrefix) {

+		namePrefix = "";

+	}

+	var obj1PropertyNames = new Array();

+	for (var i in obj1) {

+		if (i != "prototype" && i != "arguments") {

+			obj1PropertyNames.push(i);

+		}

+	}

+	if (obj1 && obj1.prototype && !array_contains(obj1PropertyNames, "prototype")) {

+		//obj1PropertyNames.push("prototype");

+	}

+	for (var j = 0; j < obj1PropertyNames.length; j++) {

+		var propertyName = obj1PropertyNames[j];

+		if ((typeof obj1[propertyName] == "function" || typeof obj1[propertyName] == "object") && !(obj1[propertyName] instanceof Array)) {

+			var propertyFullyQualifiedName = (namePrefix == "") ? propertyName : namePrefix + "." + propertyName;

+			try {

+				if (typeof obj2[propertyName] == "undefined") {

+					throw new Error(obj2_name + " does not contain " + propertyFullyQualifiedName + " in " + obj1_name);

+				} else if (typeof obj2[propertyName] != typeof obj1[propertyName]){

+					throw new Error(obj2_name + "'s " + propertyFullyQualifiedName + " is of the wrong type: " + typeof obj2[propertyName] + " when it is type " + typeof obj1[propertyName] + " in " + obj1_name);

+				} else if (obj1[propertyName] != Function.prototype.apply) {

+					if (!compareObjectInterface(obj1[propertyName], obj1_name, obj2[propertyName], obj2_name, propertyFullyQualifiedName)) {

+						throw new Error("Interfaces don't match");

+					}

+				}

+			} catch(ex) {

+				throw new Error("Exception while checking property name " + propertyFullyQualifiedName + " in " + obj2_name + ": " + ex.message);

+			}

+		}

+	}

+	return true;

+};

+

+// Simply tests a layout for exceptions when formatting

+var testLayoutWithVariables = function(layout, t) {

+	var emptyObject = {};

+	var emptyArray = [];

+	var emptyString = "";

+	var localUndefined = emptyArray[0];

+	var oneLevelObject = {

+		"name": "One-level object"

+	};

+	var twoLevelObject = {

+		"name": "Two-level object",

+		"data": oneLevelObject

+	};

+	var threeLevelObject = {

+		"name": "Three-level object",

+		"data": twoLevelObject

+	};

+	var anArray = [

+		3,

+		"stuff",

+		true,

+		false,

+		0,

+		null,

+		localUndefined,

+		3.14,

+		function(p) { return "I'm a function"; },

+		[1, "things"]

+	];

+	var arrayOfTestItems = [emptyObject, emptyString, emptyString, localUndefined, oneLevelObject,

+			twoLevelObject, threeLevelObject, anArray];

+

+	t.log("Testing layout " + layout)

+	for (var i = 0; i < arrayOfTestItems.length; i++) {

+		var ex = new Error("Test error");

+		var loggingEvent = new log4javascript.LoggingEvent(t.logger, new Date(), log4javascript.Level.INFO,

+				[arrayOfTestItems[i]], null);

+		t.log("Formatting", arrayOfTestItems[i], result);

+		var result = layout.format(loggingEvent);

+		// Now try with an exception

+		loggingEvent.exception = ex;

+		t.log("Formatting with exception", arrayOfTestItems[i], result);

+		result = layout.format(loggingEvent);

+	}

+};

+

+xn.test.enableTestDebug = true;

+xn.test.enable_log4javascript = false;

+

+xn.test.suite("log4javascript tests", function(s) {

+	log4javascript.logLog.setQuietMode(true);

+	var ArrayAppender = function(layout) {

+		if (layout) {

+			this.setLayout(layout);

+		}

+		this.logMessages = [];

+	};

+

+	ArrayAppender.prototype = new log4javascript.Appender();

+

+	ArrayAppender.prototype.layout = new log4javascript.NullLayout();

+

+	ArrayAppender.prototype.append = function(loggingEvent) {

+		var formattedMessage = this.getLayout().format(loggingEvent);

+		if (this.getLayout().ignoresThrowable()) {

+			formattedMessage += loggingEvent.getThrowableStrRep();

+		}

+		this.logMessages.push(formattedMessage);

+	};

+

+	ArrayAppender.prototype.toString = function() {

+		return "[ArrayAppender]";

+	};

+

+    s.setUp = function(t) {

+        t.logger = log4javascript.getLogger("test");

+		t.logger.removeAllAppenders();

+		t.appender = new ArrayAppender();

+        t.logger.addAppender(t.appender);

+    };

+

+    s.tearDown = function(t) {

+        t.logger.removeAppender(t.appender);

+		log4javascript.resetConfiguration();

+	};

+

+    s.test("Stub script interface test", function(t) {

+        try {

+            compareObjectInterface(log4javascript, "log4javascript", log4javascript_stub, "log4javascript_stub");

+        } catch (ex) {

+            t.fail(ex);

+        }

+    });

+

+	s.test("Disable log4javascript test", function(t) {

+		log4javascript.setEnabled(false);

+		t.logger.debug("TEST");

+		t.assertEquals(t.appender.logMessages.length, 0);

+		log4javascript.setEnabled(true);

+	});

+

+    s.test("Array.splice test 1", function(t) {

+        var a = ["Marlon", "Ashley", "Darius", "Lloyd"];

+        var deletedItems = a.splice(1, 2);

+        t.assertEquals(a.join(","), "Marlon,Lloyd");

+        t.assertEquals(deletedItems.join(","), "Ashley,Darius");

+    });

+

+    s.test("Array.splice test 2", function(t) {

+        var a = ["Marlon", "Ashley", "Darius", "Lloyd"];

+        var deletedItems = a.splice(1, 1, "Malky", "Jay");

+        t.assertEquals(a.join(","), "Marlon,Malky,Jay,Darius,Lloyd");

+        t.assertEquals(deletedItems.join(","), "Ashley");

+    });

+

+    s.test("array_remove test", function(t) {

+        var array_remove = log4javascript.evalInScope("array_remove");

+        var a = ["Marlon", "Ashley", "Darius"];

+        array_remove(a, "Darius");

+        t.assertEquals(a.join(","), "Marlon,Ashley");

+    });

+

+	s.test("array_remove with empty array test", function(t) {

+		var array_remove = log4javascript.evalInScope("array_remove");

+		var a = [];

+		array_remove(a, "Darius");

+		t.assertEquals(a.join(","), "");

+	});

+

+    s.test("Logger logging test", function(t) {

+        // Should log since the default level for loggers is DEBUG and

+        // the default threshold for appenders is ALL

+        t.logger.debug("TEST");

+        t.assertEquals(t.appender.logMessages.length, 1);

+    });

+

+    s.test("Logger levels test", function(t) {

+        var originalLevel = t.logger.getEffectiveLevel();

+        t.logger.setLevel(log4javascript.Level.INFO);

+        t.logger.debug("TEST");

+		t.logger.setLevel(originalLevel);

+        t.assertEquals(t.appender.logMessages.length, 0);

+    });

+

+	s.test("Logger getEffectiveLevel inheritance test 1", function(t) {

+		var parentLogger = log4javascript.getLogger("test1");

+		var childLogger = log4javascript.getLogger("test1.test2");

+		parentLogger.setLevel(log4javascript.Level.ERROR);

+		t.assertEquals(childLogger.getEffectiveLevel(), log4javascript.Level.ERROR);

+	});

+

+	s.test("Logger getEffectiveLevel inheritance test 2", function(t) {

+		var grandParentLogger = log4javascript.getLogger("test1");

+		var childLogger = log4javascript.getLogger("test1.test2.test3");

+		grandParentLogger.setLevel(log4javascript.Level.ERROR);

+		t.assertEquals(childLogger.getEffectiveLevel(), log4javascript.Level.ERROR);

+	});

+

+	s.test("Logger getEffectiveLevel inheritance test 3", function(t) {

+		var parentLogger = log4javascript.getLogger("test1");

+		var childLogger = log4javascript.getLogger("test1.test2");

+		parentLogger.setLevel(log4javascript.Level.ERROR);

+		childLogger.setLevel(log4javascript.Level.INFO);

+		t.assertEquals(childLogger.getEffectiveLevel(), log4javascript.Level.INFO);

+	});

+

+	s.test("Logger getEffectiveLevel root inheritance test", function(t) {

+		var rootLogger = log4javascript.getRootLogger();

+		var childLogger = log4javascript.getLogger("test1.test2.test3");

+		rootLogger.setLevel(log4javascript.Level.WARN);

+		t.assertEquals(childLogger.getEffectiveLevel(), log4javascript.Level.WARN);

+	});

+

+	s.test("Logger null level test", function(t) {

+		t.logger.setLevel(null);

+		// Should default to root logger level, which is DEBUG

+		t.assertEquals(t.logger.getEffectiveLevel(), log4javascript.Level.DEBUG);

+	});

+

+	s.test("Logger appender additivity test 1", function(t) {

+		var parentLogger = log4javascript.getLogger("test1");

+		var childLogger = log4javascript.getLogger("test1.test2");

+		var parentLoggerAppender = new ArrayAppender();

+		var childLoggerAppender = new ArrayAppender();

+

+		parentLogger.addAppender(parentLoggerAppender);

+		childLogger.addAppender(childLoggerAppender);

+

+		parentLogger.info("Parent logger test message");

+		childLogger.info("Child logger test message");

+

+		t.assertEquals(parentLoggerAppender.logMessages.length, 2);

+		t.assertEquals(childLoggerAppender.logMessages.length, 1);

+	});

+

+	s.test("Logger appender additivity test 2", function(t) {

+		var parentLogger = log4javascript.getLogger("test1");

+		var childLogger = log4javascript.getLogger("test1.test2");

+		var parentLoggerAppender = new ArrayAppender();

+		var childLoggerAppender = new ArrayAppender();

+

+		parentLogger.addAppender(parentLoggerAppender);

+		childLogger.addAppender(childLoggerAppender);

+

+		childLogger.setAdditivity(false);

+

+		parentLogger.info("Parent logger test message");

+		childLogger.info("Child logger test message");

+

+		t.assertEquals(parentLoggerAppender.logMessages.length, 1);

+		t.assertEquals(childLoggerAppender.logMessages.length, 1);

+	});

+

+	s.test("Logger appender additivity test 3", function(t) {

+		var parentLogger = log4javascript.getLogger("test1");

+		var childLogger = log4javascript.getLogger("test1.test2");

+		var parentLoggerAppender = new ArrayAppender();

+		var childLoggerAppender = new ArrayAppender();

+

+		parentLogger.addAppender(parentLoggerAppender);

+		childLogger.addAppender(childLoggerAppender);

+

+		childLogger.setAdditivity(false);

+

+		parentLogger.info("Parent logger test message");

+		childLogger.info("Child logger test message");

+

+		childLogger.setAdditivity(true);

+

+		childLogger.info("Child logger test message 2");

+

+		t.assertEquals(parentLoggerAppender.logMessages.length, 2);

+		t.assertEquals(childLoggerAppender.logMessages.length, 2);

+	});

+

+	s.test("Appender threshold test", function(t) {

+        t.appender.setThreshold(log4javascript.Level.INFO);

+        t.logger.debug("TEST");

+        t.assertEquals(t.appender.logMessages.length, 0);

+    });

+

+    s.test("Basic appender / layout test", function(t) {

+        t.logger.debug("TEST");

+		t.assertEquals(t.appender.logMessages[0], "TEST");

+    });

+

+	s.test("Appender uniqueness within logger test", function(t) {

+		// Add the same appender to the logger for a second time

+		t.logger.addAppender(t.appender);

+        t.logger.debug("TEST");

+        t.assertEquals(t.appender.logMessages.length, 1);

+    });

+

+	s.test("Logger remove appender test", function(t) {

+		t.logger.debug("TEST");

+		t.logger.removeAppender(t.appender);

+		t.logger.debug("TEST AGAIN");

+		t.assertEquals(t.appender.logMessages.length, 1);

+	});

+

+	s.test("", function(t) {

+		t.logger.debug("TEST");

+		t.logger.removeAppender(t.appender);

+		t.logger.debug("TEST AGAIN");

+		t.assertEquals(t.appender.logMessages.length, 1);

+	});

+	s.test("SimpleLayout format test", function(t) {

+		var layout = new log4javascript.SimpleLayout();

+		testLayoutWithVariables(layout, t);

+	});

+

+    s.test("SimpleLayout test", function(t) {

+        t.appender.setLayout(new log4javascript.SimpleLayout());

+        t.logger.debug("TEST");

+        t.assertEquals(t.appender.logMessages[0], "DEBUG - TEST");

+    });

+	s.test("NullLayout format test", function(t) {

+		var layout = new log4javascript.NullLayout();

+		testLayoutWithVariables(layout, t);

+	});

+

+    s.test("NullLayout test", function(t) {

+        t.appender.setLayout(new log4javascript.NullLayout());

+        t.logger.debug("TEST");

+        t.assertEquals(t.appender.logMessages[0], "TEST");

+    });

+	s.test("XmlLayout format test", function(t) {

+		var layout = new log4javascript.XmlLayout();

+		testLayoutWithVariables(layout, t);

+	});

+

+    s.test("XmlLayout test", function(t) {

+        t.appender.setLayout(new log4javascript.XmlLayout());

+        t.logger.debug("TEST");

+        t.assertRegexMatches(/^<log4javascript:event logger="test" timestamp="\d+" level="DEBUG">\s*<log4javascript:message><!\[CDATA\[TEST\]\]><\/log4javascript:message>\s*<\/log4javascript:event>\s*$/, t.appender.logMessages[0]);

+    });

+

+    s.test("XmlLayout with exception test", function(t) {

+        t.appender.setLayout(new log4javascript.XmlLayout());

+        t.logger.debug("TEST", new Error("Test error"));

+        t.assertRegexMatches(/^<log4javascript:event logger="test" timestamp="\d+" level="DEBUG">\s*<log4javascript:message><!\[CDATA\[TEST\]\]><\/log4javascript:message>\s*<log4javascript:exception>\s*<!\[CDATA\[.*\]\]><\/log4javascript:exception>\s*<\/log4javascript:event>\s*$/, t.appender.logMessages[0]);

+    });

+

+	var setUpXmlLayoutMillisecondsTest = function(t) {

+		t.date = new Date();

+		t.timeInMilliseconds = t.date.getTime();

+		t.timeInSeconds = Math.floor(t.timeInMilliseconds / 1000);

+		t.milliseconds = t.date.getMilliseconds();

+		

+		t.loggingEvent = new log4javascript.LoggingEvent(t.logger, t.date, log4javascript.Level.DEBUG, ["TEST"], null);

+		t.layout = new log4javascript.XmlLayout();

+	}

+

+	s.test("XmlLayout seconds/milliseconds test 1", function(t) {

+		setUpXmlLayoutMillisecondsTest(t);

+

+		// Test default (i.e. timestamps in milliseconds) first

+        var regex = new RegExp('^<log4javascript:event logger="test" timestamp="' + t.timeInMilliseconds + '" level="DEBUG">\\s*<log4javascript:message><!\\[CDATA\\[TEST\\]\\]></log4javascript:message>\\s*</log4javascript:event>\\s*$');

+        t.assertRegexMatches(regex, t.layout.format(t.loggingEvent));

+	});

+	

+	s.test("XmlLayout seconds/milliseconds test 2", function(t) {

+		setUpXmlLayoutMillisecondsTest(t);

+

+        // Change the global setting

+        log4javascript.setTimeStampsInMilliseconds(false);

+        var formatted = t.layout.format(t.loggingEvent);

+        log4javascript.setTimeStampsInMilliseconds(true);

+        var regex = new RegExp('^<log4javascript:event logger="test" timestamp="' + t.timeInSeconds + '" milliseconds="' + t.milliseconds + '" level="DEBUG">\\s*<log4javascript:message><!\\[CDATA\\[TEST\\]\\]></log4javascript:message>\\s*</log4javascript:event>\\s*$');

+        t.assertRegexMatches(regex, formatted);

+	});

+

+	s.test("XmlLayout seconds/milliseconds test 3", function(t) {

+		setUpXmlLayoutMillisecondsTest(t);

+

+        // Change the layout setting

+        t.layout.setTimeStampsInMilliseconds(false);

+        var formatted = t.layout.format(t.loggingEvent);

+        var regex = new RegExp('^<log4javascript:event logger="test" timestamp="' + t.timeInSeconds + '" milliseconds="' + t.milliseconds + '" level="DEBUG">\\s*<log4javascript:message><!\\[CDATA\\[TEST\\]\\]></log4javascript:message>\\s*</log4javascript:event>\\s*$');

+        t.assertRegexMatches(regex, formatted);

+	});

+	s.test("escapeNewLines test", function(t) {

+		var escapeNewLines = log4javascript.evalInScope("escapeNewLines");

+		var str = "1\r2\n3\n4\r\n5\r6\r\n7";

+		t.assertEquals(escapeNewLines(str), "1\\r\\n2\\r\\n3\\r\\n4\\r\\n5\\r\\n6\\r\\n7");

+	});

+

+	s.test("JsonLayout format test", function(t) {

+		var layout = new log4javascript.JsonLayout();

+		testLayoutWithVariables(layout, t);

+	});

+

+    s.test("JsonLayout test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug("TEST");

+        t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TEST"}$/, t.appender.logMessages[0]);

+    });

+

+    s.test("JsonLayout JSON validity test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug("TEST");

+        eval("var o = " + t.appender.logMessages[0]);

+        t.assertEquals(o.message, "TEST");

+    });

+

+    s.test("JsonLayout with number type message test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug(15);

+        t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":15}$/, t.appender.logMessages[0]);

+    });

+

+    s.test("JsonLayout with object type message test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug({});

+        t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"\[object Object\]"}$/, t.appender.logMessages[0]);

+    });

+

+    s.test("JsonLayout with boolean type message test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug(false);

+        t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":false}$/, t.appender.logMessages[0]);

+    });

+

+    s.test("JsonLayout with quote test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug("TE\"S\"T");

+        t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TE\\"S\\"T"}$/, t.appender.logMessages[0]);

+    });

+

+    s.test("JsonLayout with exception test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug("TEST", new Error("Test error"));

+        t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TEST","exception":.*}$/, t.appender.logMessages[0]);

+    });

+

+	var setUpJsonLayoutMillisecondsTest = function(t) {

+		t.date = new Date();

+		t.timeInMilliseconds = t.date.getTime();

+		t.timeInSeconds = Math.floor(t.timeInMilliseconds / 1000);

+		t.milliseconds = t.date.getMilliseconds();

+		

+		t.loggingEvent = new log4javascript.LoggingEvent(t.logger, t.date, log4javascript.Level.DEBUG, ["TEST"], null);

+		t.layout = new log4javascript.JsonLayout();

+	};

+

+	s.test("JsonLayout seconds/milliseconds test 1", function(t) {

+		setUpJsonLayoutMillisecondsTest(t);

+

+		// Test default (i.e. timestamps in milliseconds) first

+        var regex = new RegExp('^{"logger":"test","timestamp":' + t.timeInMilliseconds + ',"level":"DEBUG","url":".*","message":"TEST"}$');

+        t.assertRegexMatches(regex, t.layout.format(t.loggingEvent));

+	});

+	

+	s.test("JsonLayout seconds/milliseconds test 2", function(t) {

+		setUpJsonLayoutMillisecondsTest(t);

+

+        // Change the global setting

+        log4javascript.setTimeStampsInMilliseconds(false);

+        var formatted = t.layout.format(t.loggingEvent);

+        log4javascript.setTimeStampsInMilliseconds(true);

+        var regex = new RegExp('^{"logger":"test","timestamp":' + t.timeInSeconds + ',"level":"DEBUG","url":".*","message":"TEST","milliseconds":' + t.milliseconds + '}$');

+        t.assertRegexMatches(regex, formatted);

+	});

+

+	s.test("JsonLayout seconds/milliseconds test 3", function(t) {

+		setUpJsonLayoutMillisecondsTest(t);

+

+        // Change the layout setting

+        t.layout.setTimeStampsInMilliseconds(false);

+        var formatted = t.layout.format(t.loggingEvent);

+        var regex = new RegExp('^{"logger":"test","timestamp":' + t.timeInSeconds + ',"level":"DEBUG","url":".*","message":"TEST","milliseconds":' + t.milliseconds + '}$');

+        t.assertRegexMatches(regex, formatted);

+	});

+	s.test("HttpPostDataLayout format test", function(t) {

+		var layout = new log4javascript.HttpPostDataLayout();

+		testLayoutWithVariables(layout, t);

+	});

+

+    s.test("HttpPostDataLayout test", function(t) {

+        t.appender.setLayout(new log4javascript.HttpPostDataLayout());

+        t.logger.debug("TEST");

+        t.assertRegexMatches(/^logger=test&timestamp=\d+&level=DEBUG&url=.*&message=TEST$/, t.appender.logMessages[0]);

+    });

+

+    s.test("HttpPostDataLayout URL encoding test", function(t) {

+        t.appender.setLayout(new log4javascript.HttpPostDataLayout());

+        t.logger.debug("TEST +\"1\"");

+        t.assertRegexMatches(/^logger=test&timestamp=\d+&level=DEBUG&url=.*&message=TEST%20%2B%221%22$/, t.appender.logMessages[0]);

+    });

+

+    s.test("HttpPostDataLayout with exception test", function(t) {

+        t.appender.setLayout(new log4javascript.HttpPostDataLayout());

+        t.logger.debug("TEST", new Error("Test error"));

+        t.assertRegexMatches(/^logger=test&timestamp=\d+&level=DEBUG&url=.*&message=TEST&exception=.*$/, t.appender.logMessages[0]);

+    });

+

+	(function() {

+		var formatObjectExpansion = log4javascript.evalInScope("formatObjectExpansion");

+		var newLine = log4javascript.evalInScope("newLine");

+		var arr = [

+			null,

+			undefined,

+			1.2,

+			"A string",

+			[1, "test"],

+			{

+				a: {

+					b: 1

+				}

+			}

+		];

+

+		s.test("Basic formatObjectExpansion array test (depth: 1)", function(t) {

+			t.assertEquals(formatObjectExpansion(arr, 1),

+				"[" + newLine +

+				"  null," + newLine +

+				"  undefined," + newLine +

+				"  1.2," + newLine +

+				"  A string," + newLine +

+				"  1,test," + newLine +

+				"  [object Object]" + newLine +

+				"]"

+			);

+		});

+

+		s.test("Basic formatObjectExpansion array test (depth: 2)", function(t) {

+			t.assertEquals(formatObjectExpansion(arr, 2),

+				"[" + newLine +

+				"  null," + newLine +

+				"  undefined," + newLine +

+				"  1.2," + newLine +

+				"  A string," + newLine +

+				"  [" + newLine +

+				"    1," + newLine +

+				"    test" + newLine +

+				"  ]," + newLine +

+				"  {" + newLine +

+				"    a: [object Object]" + newLine +

+				"  }" + newLine +

+				"]"

+			);

+		});

+

+		s.test("formatObjectExpansion simple object test", function(t) {

+			var obj = {

+				STRING: "A string"

+			};

+			t.assertEquals(formatObjectExpansion(obj, 1), 

+				"{" + newLine +

+				"  STRING: A string" + newLine +

+				"}"

+			);

+		});

+

+		s.test("formatObjectExpansion simple circular object test", function(t) {

+			var obj = {};

+			obj.a = obj;

+			

+			t.assertEquals(formatObjectExpansion(obj, 2), 

+				"{" + newLine +

+				"  a: [object Object] [already expanded]" + newLine +

+				"}"

+			);

+		});

+	})();    /* ---------------------------------------------------------- */

+

+    var getSampleDate = function() {

+        var date = new Date();

+        date.setFullYear(2006);

+        date.setMonth(7);

+        date.setDate(30);

+        date.setHours(15);

+        date.setMinutes(38);

+        date.setSeconds(45);

+        return date;

+    };

+

+    /* ---------------------------------------------------------- */

+

+    s.test("String.replace test", function(t) {

+        t.assertEquals("Hello world".replace(/o/g, "Z"), "HellZ wZrld");

+    });

+

+	s.test("PatternLayout format test", function(t) {

+		var layout = new log4javascript.PatternLayout();

+		testLayoutWithVariables(layout, t);

+	});

+

+    s.test("PatternLayout dates test", function(t) {

+        var layout = new log4javascript.PatternLayout("%d %d{DATE} %d{HH:ss}");

+        t.appender.setLayout(layout);

+        t.logger.debug("TEST");

+        t.assertRegexMatches(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3} \d{2} [A-Z][a-z]{2} \d{4} \d{2}:\d{2}:\d{2},\d{3} \d{2}:\d{2}$/, t.appender.logMessages[0]);

+    });

+

+    s.test("PatternLayout modifiers test", function(t) {

+        var layout = new log4javascript.PatternLayout("%m|%3m|%-3m|%6m|%-6m|%.2m|%1.2m|%6.8m|%-1.2m|%-6.8m|");

+        t.appender.setLayout(layout);

+        t.logger.debug("TEST");

+        t.assertEquals(t.appender.logMessages[0], "TEST|TEST|TEST|  TEST|TEST  |ST|ST|  TEST|ST|TEST  |");

+    });

+

+    s.test("PatternLayout conversion characters test", function(t) {

+        var layout = new log4javascript.PatternLayout("%c %n %p %r literal %%");

+        t.appender.setLayout(layout);

+        t.logger.debug("TEST");

+        t.assertRegexMatches(/^test \s+ DEBUG \d+ literal %$/, t.appender.logMessages[0]);

+    });

+

+    s.test("PatternLayout message test", function(t) {

+        var layout = new log4javascript.PatternLayout("%m{1} %m{2}");

+        t.appender.setLayout(layout);

+        var testObj = {

+            strikers: {

+                quick: "Marlon"

+            }

+        };

+        t.logger.debug(testObj);

+        t.assertEquals("{\r\n  strikers: [object Object]\r\n} {\r\n\  strikers: {\r\n    quick: Marlon\r\n  }\r\n}", t.appender.logMessages[0]);

+    });

+	// Tests for exceptions when logging

+	s.test("Logging/grouping test", function(t) {

+		var browserConsoleAppender = new log4javascript.BrowserConsoleAppender();

+		t.logger.addAppender(browserConsoleAppender);

+

+		// Test each level

+		t.logger.trace("TEST TRACE");

+		t.logger.debug("TEST DEBUG");

+		t.logger.info("TEST INFO");

+		t.logger.warn("TEST WARN");

+		t.logger.error("TEST ERROR");

+		t.logger.fatal("TEST FATAL");

+		

+		// Test with exception

+		t.logger.fatal("TEST FATAL", new Error("Fake error"));

+		

+		// Test multiple messages

+		t.logger.info("TEST INFO", "Second message", ["a", "b", "c"]);

+		

+		// Test groups

+		t.logger.group("TEST GROUP");

+		t.logger.info("TEST INFO");

+		t.logger.groupEnd("TEST GROUP");

+		t.logger.info("TEST INFO");

+		

+		t.logger.removeAppender(browserConsoleAppender);

+	});

+

+/*

+	s.test("AjaxAppender JsonLayout single message test", function(t) {

+		t.async(10000);

+		// Create and add an Ajax appender

+		var ajaxAppender = new log4javascript.AjaxAppender("../log4javascript.do");

+		ajaxAppender.setLayout(new log4javascript.JsonLayout());

+		ajaxAppender.setRequestSuccessCallback(

+			function(xmlHttp) {

+				// Response comes back as JSON array of messages logged

+				var jsonResponse = xmlHttp.responseText;

+				var arr = eval(jsonResponse);

+				t.assertEquals(arr.length, 1);

+				t.assertEquals(arr[0], "TEST");

+				t.succeed();

+			}

+		);

+		ajaxAppender.setFailCallback(

+			function(msg) {

+				t.fail(msg);

+				ajaxErrorMessage = msg;

+			}

+		);

+		t.logger.addAppender(ajaxAppender);

+		t.logger.debug("TEST");

+	});

+

+	s.test("AjaxAppender JsonLayout batched messages test", function(t) {

+		t.async(10000);

+		var message1 = "TEST 1";

+		var message2 = "String with \"lots of 'quotes'\" + plusses in";

+		var message3 = "A non-threatening string";

+		// Create and add an Ajax appender

+		var ajaxAppender = new log4javascript.AjaxAppender("../log4javascript.do");

+		ajaxAppender.setLayout(new log4javascript.JsonLayout());

+		ajaxAppender.setBatchSize(3);

+		ajaxAppender.setRequestSuccessCallback(

+			function(xmlHttp) {

+				// Response comes back as JSON array of messages logged

+				var jsonResponse = xmlHttp.responseText;

+				var arr = eval(jsonResponse);

+				t.assertEquals(arr.length, 3);

+				t.assertEquals(arr[0], message1);

+				t.assertEquals(arr[1], message2);

+				t.assertEquals(arr[2], message3);

+				t.succeed();

+			}

+		);

+		ajaxAppender.setFailCallback(

+			function(msg) {

+				t.fail(msg);

+				ajaxErrorMessage = msg;

+			}

+		);

+		t.logger.addAppender(ajaxAppender);

+		t.logger.debug(message1);

+		t.logger.info(message2);

+		t.logger.warn(message3);

+	});

+

+	s.test("AjaxAppender HttpPostDataLayout single message test", function(t) {

+		t.async(10000);

+		// Create and add an Ajax appender

+		var ajaxAppender = new log4javascript.AjaxAppender("../log4javascript.do");

+		var testMessage = "TEST +\"1\"";

+		ajaxAppender.setLayout(new log4javascript.HttpPostDataLayout());

+		ajaxAppender.setRequestSuccessCallback(

+			function(xmlHttp) {

+				// Response comes back as JSON array of messages logged

+				var jsonResponse = xmlHttp.responseText;

+				var arr = eval(jsonResponse);

+				t.assertEquals(arr.length, 1);

+				t.assertEquals(arr[0], testMessage);

+				t.succeed();

+			}

+		);

+		ajaxAppender.setFailCallback(

+			function(msg) {

+				t.fail(msg);

+				ajaxErrorMessage = msg;

+			}

+		);

+		t.logger.addAppender(ajaxAppender);

+		t.logger.debug(testMessage);

+	});

+*/

+	var testConsoleAppender = function(t, appender) {

+		var timeoutCallback = function() {

+			//alert("Failed. Debug messages follow.");

+			//log4javascript.logLog.displayDebug();

+			return (windowLoaded ? "Timed out while waiting for messages to appear" :

+				   "Timed out while waiting for window to load") + ". Debug messages: " +

+				   log4javascript.logLog.debugMessages.join("\r\n");

+		}

+

+		t.async(60000, timeoutCallback);

+

+		var windowLoaded = false;

+		var domChecked = false;

+

+		// Set a timeout to allow the pop-up to appear

+		var onLoadHandler = function() {

+			log4javascript.logLog.debug("onLoadHandler");

+			windowLoaded = true;

+			var win = appender.getConsoleWindow();

+

+			if (win && win.loaded) {

+				// Check that the log container element contains the log message. Since

+				// the console window waits 100 milliseconds before actually rendering the

+				// message as a DOM element, we need to use a timer

+				var checkDom = function() {

+					log4javascript.logLog.debug("checkDom");

+					domChecked = true;

+					var logContainer = win.logMainContainer;

+					if (logContainer.hasChildNodes()) {

+						if (logContainer.innerHTML.indexOf("TEST MESSAGE") == -1) {

+							appender.close();

+							t.fail("Log message not correctly logged (log container innerHTML: " + logContainer.innerHTML + ")");

+						} else {

+							t.assert(appender.isVisible());

+							appender.close();

+							t.assert(!appender.isVisible());

+							t.succeed();

+						}

+					} else {

+						appender.close();

+						t.fail("Console has no log messages");

+					}

+				}

+				window.setTimeout(checkDom, 300);

+			} else {

+				appender.close();

+				t.fail("Console mistakenly raised load event");

+			}

+		}

+

+		appender.addEventListener("load", onLoadHandler);

+		t.logger.addAppender(appender);

+		t.logger.debug("TEST MESSAGE");

+	};

+

+	s.test("InlineAppender test", function(t) {

+		var inlineAppender = new log4javascript.InlineAppender();

+		inlineAppender.setInitiallyMinimized(false);

+		inlineAppender.setNewestMessageAtTop(false);

+		inlineAppender.setScrollToLatestMessage(true);

+		inlineAppender.setWidth(600);

+		inlineAppender.setHeight(200);

+

+		testConsoleAppender(t, inlineAppender);

+	});

+

+	s.test("InPageAppender with separate console HTML file test", function(t) {

+		var inPageAppender = new log4javascript.InPageAppender();

+		inPageAppender.setInitiallyMinimized(false);

+		inPageAppender.setNewestMessageAtTop(false);

+		inPageAppender.setScrollToLatestMessage(true);

+		inPageAppender.setUseDocumentWrite(false);

+		inPageAppender.setWidth(600);

+		inPageAppender.setHeight(200);

+

+		testConsoleAppender(t, inPageAppender);

+	});

+

+	s.test("PopUpAppender test", function(t) {

+		var popUpAppender = new log4javascript.PopUpAppender();

+		popUpAppender.setFocusPopUp(true);

+		popUpAppender.setUseOldPopUp(false);

+		popUpAppender.setNewestMessageAtTop(false);

+		popUpAppender.setScrollToLatestMessage(true);

+		popUpAppender.setComplainAboutPopUpBlocking(false);

+		popUpAppender.setWidth(600);

+		popUpAppender.setHeight(200);

+

+		testConsoleAppender(t, popUpAppender);

+		

+		

+	});

+

+	s.test("PopUpAppender with separate console HTML file test", function(t) {

+		var popUpAppender = new log4javascript.PopUpAppender();

+		popUpAppender.setFocusPopUp(true);

+		popUpAppender.setUseOldPopUp(false);

+		popUpAppender.setNewestMessageAtTop(false);

+		popUpAppender.setScrollToLatestMessage(true);

+		popUpAppender.setComplainAboutPopUpBlocking(false);

+		popUpAppender.setUseDocumentWrite(false);

+		popUpAppender.setWidth(600);

+		popUpAppender.setHeight(200);

+

+		testConsoleAppender(t, popUpAppender);

+	});

+});
\ No newline at end of file
diff --git a/xos/core/static/log4javascript-1.4.6/license.txt b/xos/core/static/log4javascript-1.4.6/license.txt
new file mode 100644
index 0000000..29f81d8
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/license.txt
@@ -0,0 +1,201 @@
+                                 Apache License

+                           Version 2.0, January 2004

+                        http://www.apache.org/licenses/

+

+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

+

+   1. Definitions.

+

+      "License" shall mean the terms and conditions for use, reproduction,

+      and distribution as defined by Sections 1 through 9 of this document.

+

+      "Licensor" shall mean the copyright owner or entity authorized by

+      the copyright owner that is granting the License.

+

+      "Legal Entity" shall mean the union of the acting entity and all

+      other entities that control, are controlled by, or are under common

+      control with that entity. For the purposes of this definition,

+      "control" means (i) the power, direct or indirect, to cause the

+      direction or management of such entity, whether by contract or

+      otherwise, or (ii) ownership of fifty percent (50%) or more of the

+      outstanding shares, or (iii) beneficial ownership of such entity.

+

+      "You" (or "Your") shall mean an individual or Legal Entity

+      exercising permissions granted by this License.

+

+      "Source" form shall mean the preferred form for making modifications,

+      including but not limited to software source code, documentation

+      source, and configuration files.

+

+      "Object" form shall mean any form resulting from mechanical

+      transformation or translation of a Source form, including but

+      not limited to compiled object code, generated documentation,

+      and conversions to other media types.

+

+      "Work" shall mean the work of authorship, whether in Source or

+      Object form, made available under the License, as indicated by a

+      copyright notice that is included in or attached to the work

+      (an example is provided in the Appendix below).

+

+      "Derivative Works" shall mean any work, whether in Source or Object

+      form, that is based on (or derived from) the Work and for which the

+      editorial revisions, annotations, elaborations, or other modifications

+      represent, as a whole, an original work of authorship. For the purposes

+      of this License, Derivative Works shall not include works that remain

+      separable from, or merely link (or bind by name) to the interfaces of,

+      the Work and Derivative Works thereof.

+

+      "Contribution" shall mean any work of authorship, including

+      the original version of the Work and any modifications or additions

+      to that Work or Derivative Works thereof, that is intentionally

+      submitted to Licensor for inclusion in the Work by the copyright owner

+      or by an individual or Legal Entity authorized to submit on behalf of

+      the copyright owner. For the purposes of this definition, "submitted"

+      means any form of electronic, verbal, or written communication sent

+      to the Licensor or its representatives, including but not limited to

+      communication on electronic mailing lists, source code control systems,

+      and issue tracking systems that are managed by, or on behalf of, the

+      Licensor for the purpose of discussing and improving the Work, but

+      excluding communication that is conspicuously marked or otherwise

+      designated in writing by the copyright owner as "Not a Contribution."

+

+      "Contributor" shall mean Licensor and any individual or Legal Entity

+      on behalf of whom a Contribution has been received by Licensor and

+      subsequently incorporated within the Work.

+

+   2. Grant of Copyright License. Subject to the terms and conditions of

+      this License, each Contributor hereby grants to You a perpetual,

+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable

+      copyright license to reproduce, prepare Derivative Works of,

+      publicly display, publicly perform, sublicense, and distribute the

+      Work and such Derivative Works in Source or Object form.

+

+   3. Grant of Patent License. Subject to the terms and conditions of

+      this License, each Contributor hereby grants to You a perpetual,

+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable

+      (except as stated in this section) patent license to make, have made,

+      use, offer to sell, sell, import, and otherwise transfer the Work,

+      where such license applies only to those patent claims licensable

+      by such Contributor that are necessarily infringed by their

+      Contribution(s) alone or by combination of their Contribution(s)

+      with the Work to which such Contribution(s) was submitted. If You

+      institute patent litigation against any entity (including a

+      cross-claim or counterclaim in a lawsuit) alleging that the Work

+      or a Contribution incorporated within the Work constitutes direct

+      or contributory patent infringement, then any patent licenses

+      granted to You under this License for that Work shall terminate

+      as of the date such litigation is filed.

+

+   4. Redistribution. You may reproduce and distribute copies of the

+      Work or Derivative Works thereof in any medium, with or without

+      modifications, and in Source or Object form, provided that You

+      meet the following conditions:

+

+      (a) You must give any other recipients of the Work or

+          Derivative Works a copy of this License; and

+

+      (b) You must cause any modified files to carry prominent notices

+          stating that You changed the files; and

+

+      (c) You must retain, in the Source form of any Derivative Works

+          that You distribute, all copyright, patent, trademark, and

+          attribution notices from the Source form of the Work,

+          excluding those notices that do not pertain to any part of

+          the Derivative Works; and

+

+      (d) If the Work includes a "NOTICE" text file as part of its

+          distribution, then any Derivative Works that You distribute must

+          include a readable copy of the attribution notices contained

+          within such NOTICE file, excluding those notices that do not

+          pertain to any part of the Derivative Works, in at least one

+          of the following places: within a NOTICE text file distributed

+          as part of the Derivative Works; within the Source form or

+          documentation, if provided along with the Derivative Works; or,

+          within a display generated by the Derivative Works, if and

+          wherever such third-party notices normally appear. The contents

+          of the NOTICE file are for informational purposes only and

+          do not modify the License. You may add Your own attribution

+          notices within Derivative Works that You distribute, alongside

+          or as an addendum to the NOTICE text from the Work, provided

+          that such additional attribution notices cannot be construed

+          as modifying the License.

+

+      You may add Your own copyright statement to Your modifications and

+      may provide additional or different license terms and conditions

+      for use, reproduction, or distribution of Your modifications, or

+      for any such Derivative Works as a whole, provided Your use,

+      reproduction, and distribution of the Work otherwise complies with

+      the conditions stated in this License.

+

+   5. Submission of Contributions. Unless You explicitly state otherwise,

+      any Contribution intentionally submitted for inclusion in the Work

+      by You to the Licensor shall be under the terms and conditions of

+      this License, without any additional terms or conditions.

+      Notwithstanding the above, nothing herein shall supersede or modify

+      the terms of any separate license agreement you may have executed

+      with Licensor regarding such Contributions.

+

+   6. Trademarks. This License does not grant permission to use the trade

+      names, trademarks, service marks, or product names of the Licensor,

+      except as required for reasonable and customary use in describing the

+      origin of the Work and reproducing the content of the NOTICE file.

+

+   7. Disclaimer of Warranty. Unless required by applicable law or

+      agreed to in writing, Licensor provides the Work (and each

+      Contributor provides its Contributions) on an "AS IS" BASIS,

+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or

+      implied, including, without limitation, any warranties or conditions

+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A

+      PARTICULAR PURPOSE. You are solely responsible for determining the

+      appropriateness of using or redistributing the Work and assume any

+      risks associated with Your exercise of permissions under this License.

+

+   8. Limitation of Liability. In no event and under no legal theory,

+      whether in tort (including negligence), contract, or otherwise,

+      unless required by applicable law (such as deliberate and grossly

+      negligent acts) or agreed to in writing, shall any Contributor be

+      liable to You for damages, including any direct, indirect, special,

+      incidental, or consequential damages of any character arising as a

+      result of this License or out of the use or inability to use the

+      Work (including but not limited to damages for loss of goodwill,

+      work stoppage, computer failure or malfunction, or any and all

+      other commercial damages or losses), even if such Contributor

+      has been advised of the possibility of such damages.

+

+   9. Accepting Warranty or Additional Liability. While redistributing

+      the Work or Derivative Works thereof, You may choose to offer,

+      and charge a fee for, acceptance of support, warranty, indemnity,

+      or other liability obligations and/or rights consistent with this

+      License. However, in accepting such obligations, You may act only

+      on Your own behalf and on Your sole responsibility, not on behalf

+      of any other Contributor, and only if You agree to indemnify,

+      defend, and hold each Contributor harmless for any liability

+      incurred by, or claims asserted against, such Contributor by reason

+      of your accepting any such warranty or additional liability.

+

+   END OF TERMS AND CONDITIONS

+

+   APPENDIX: How to apply the Apache License to your work.

+

+      To apply the Apache License to your work, attach the following

+      boilerplate notice, with the fields enclosed by brackets "[]"

+      replaced with your own identifying information. (Don't include

+      the brackets!)  The text should be enclosed in the appropriate

+      comment syntax for the file format. We also recommend that a

+      file or class name and description of purpose be included on the

+      same "printed page" as the copyright notice for easier

+      identification within third-party archives.

+

+   Copyright [yyyy] [name of copyright owner]

+

+   Licensed under the Apache License, Version 2.0 (the "License");

+   you may not use this file except in compliance with the License.

+   You may obtain a copy of the License at

+

+       http://www.apache.org/licenses/LICENSE-2.0

+

+   Unless required by applicable law or agreed to in writing, software

+   distributed under the License is distributed on an "AS IS" BASIS,

+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+   See the License for the specific language governing permissions and

+   limitations under the License.

diff --git a/xos/core/static/log4javascript-1.4.6/log4javascript.js b/xos/core/static/log4javascript-1.4.6/log4javascript.js
new file mode 100644
index 0000000..042daa9
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/log4javascript.js
@@ -0,0 +1,274 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+

+if(!Array.prototype.push){Array.prototype.push=function(){for(var i=0,len=arguments.length;i<len;i++){this[this.length]=arguments[i];}

+return this.length;};}

+if(!Array.prototype.shift){Array.prototype.shift=function(){if(this.length>0){var firstItem=this[0];for(var i=0,len=this.length-1;i<len;i++){this[i]=this[i+1];}

+this.length=this.length-1;return firstItem;}};}

+if(!Array.prototype.splice){Array.prototype.splice=function(startIndex,deleteCount){var itemsAfterDeleted=this.slice(startIndex+deleteCount);var itemsDeleted=this.slice(startIndex,startIndex+deleteCount);this.length=startIndex;var argumentsArray=[];for(var i=0,len=arguments.length;i<len;i++){argumentsArray[i]=arguments[i];}

+var itemsToAppend=(argumentsArray.length>2)?itemsAfterDeleted=argumentsArray.slice(2).concat(itemsAfterDeleted):itemsAfterDeleted;for(i=0,len=itemsToAppend.length;i<len;i++){this.push(itemsToAppend[i]);}

+return itemsDeleted;};}

+var log4javascript=(function(){function isUndefined(obj){return typeof obj=="undefined";}

+function EventSupport(){}

+EventSupport.prototype={eventTypes:[],eventListeners:{},setEventTypes:function(eventTypesParam){if(eventTypesParam instanceof Array){this.eventTypes=eventTypesParam;this.eventListeners={};for(var i=0,len=this.eventTypes.length;i<len;i++){this.eventListeners[this.eventTypes[i]]=[];}}else{handleError("log4javascript.EventSupport ["+this+"]: setEventTypes: eventTypes parameter must be an Array");}},addEventListener:function(eventType,listener){if(typeof listener=="function"){if(!array_contains(this.eventTypes,eventType)){handleError("log4javascript.EventSupport ["+this+"]: addEventListener: no event called '"+eventType+"'");}

+this.eventListeners[eventType].push(listener);}else{handleError("log4javascript.EventSupport ["+this+"]: addEventListener: listener must be a function");}},removeEventListener:function(eventType,listener){if(typeof listener=="function"){if(!array_contains(this.eventTypes,eventType)){handleError("log4javascript.EventSupport ["+this+"]: removeEventListener: no event called '"+eventType+"'");}

+array_remove(this.eventListeners[eventType],listener);}else{handleError("log4javascript.EventSupport ["+this+"]: removeEventListener: listener must be a function");}},dispatchEvent:function(eventType,eventArgs){if(array_contains(this.eventTypes,eventType)){var listeners=this.eventListeners[eventType];for(var i=0,len=listeners.length;i<len;i++){listeners[i](this,eventType,eventArgs);}}else{handleError("log4javascript.EventSupport ["+this+"]: dispatchEvent: no event called '"+eventType+"'");}}};var applicationStartDate=new Date();var uniqueId="log4javascript_"+applicationStartDate.getTime()+"_"+

+Math.floor(Math.random()*100000000);var emptyFunction=function(){};var newLine="\r\n";var pageLoaded=false;function Log4JavaScript(){}

+Log4JavaScript.prototype=new EventSupport();log4javascript=new Log4JavaScript();log4javascript.version="1.4.6";log4javascript.edition="log4javascript";function toStr(obj){if(obj&&obj.toString){return obj.toString();}else{return String(obj);}}

+function getExceptionMessage(ex){if(ex.message){return ex.message;}else if(ex.description){return ex.description;}else{return toStr(ex);}}

+function getUrlFileName(url){var lastSlashIndex=Math.max(url.lastIndexOf("/"),url.lastIndexOf("\\"));return url.substr(lastSlashIndex+1);}

+function getExceptionStringRep(ex){if(ex){var exStr="Exception: "+getExceptionMessage(ex);try{if(ex.lineNumber){exStr+=" on line number "+ex.lineNumber;}

+if(ex.fileName){exStr+=" in file "+getUrlFileName(ex.fileName);}}catch(localEx){logLog.warn("Unable to obtain file and line information for error");}

+if(showStackTraces&&ex.stack){exStr+=newLine+"Stack trace:"+newLine+ex.stack;}

+return exStr;}

+return null;}

+function bool(obj){return Boolean(obj);}

+function trim(str){return str.replace(/^\s+/,"").replace(/\s+$/,"");}

+function splitIntoLines(text){var text2=text.replace(/\r\n/g,"\n").replace(/\r/g,"\n");return text2.split("\n");}

+var urlEncode=(typeof window.encodeURIComponent!="undefined")?function(str){return encodeURIComponent(str);}:function(str){return escape(str).replace(/\+/g,"%2B").replace(/"/g,"%22").replace(/'/g,"%27").replace(/\//g,"%2F").replace(/=/g,"%3D");};var urlDecode=(typeof window.decodeURIComponent!="undefined")?function(str){return decodeURIComponent(str);}:function(str){return unescape(str).replace(/%2B/g,"+").replace(/%22/g,"\"").replace(/%27/g,"'").replace(/%2F/g,"/").replace(/%3D/g,"=");};function array_remove(arr,val){var index=-1;for(var i=0,len=arr.length;i<len;i++){if(arr[i]===val){index=i;break;}}

+if(index>=0){arr.splice(index,1);return true;}else{return false;}}

+function array_contains(arr,val){for(var i=0,len=arr.length;i<len;i++){if(arr[i]==val){return true;}}

+return false;}

+function extractBooleanFromParam(param,defaultValue){if(isUndefined(param)){return defaultValue;}else{return bool(param);}}

+function extractStringFromParam(param,defaultValue){if(isUndefined(param)){return defaultValue;}else{return String(param);}}

+function extractIntFromParam(param,defaultValue){if(isUndefined(param)){return defaultValue;}else{try{var value=parseInt(param,10);return isNaN(value)?defaultValue:value;}catch(ex){logLog.warn("Invalid int param "+param,ex);return defaultValue;}}}

+function extractFunctionFromParam(param,defaultValue){if(typeof param=="function"){return param;}else{return defaultValue;}}

+function isError(err){return(err instanceof Error);}

+if(!Function.prototype.apply){Function.prototype.apply=function(obj,args){var methodName="__apply__";if(typeof obj[methodName]!="undefined"){methodName+=String(Math.random()).substr(2);}

+obj[methodName]=this;var argsStrings=[];for(var i=0,len=args.length;i<len;i++){argsStrings[i]="args["+i+"]";}

+var script="obj."+methodName+"("+argsStrings.join(",")+")";var returnValue=eval(script);delete obj[methodName];return returnValue;};}

+if(!Function.prototype.call){Function.prototype.call=function(obj){var args=[];for(var i=1,len=arguments.length;i<len;i++){args[i-1]=arguments[i];}

+return this.apply(obj,args);};}

+function getListenersPropertyName(eventName){return"__log4javascript_listeners__"+eventName;}

+function addEvent(node,eventName,listener,useCapture,win){win=win?win:window;if(node.addEventListener){node.addEventListener(eventName,listener,useCapture);}else if(node.attachEvent){node.attachEvent("on"+eventName,listener);}else{var propertyName=getListenersPropertyName(eventName);if(!node[propertyName]){node[propertyName]=[];node["on"+eventName]=function(evt){evt=getEvent(evt,win);var listenersPropertyName=getListenersPropertyName(eventName);var listeners=this[listenersPropertyName].concat([]);var currentListener;while((currentListener=listeners.shift())){currentListener.call(this,evt);}};}

+node[propertyName].push(listener);}}

+function removeEvent(node,eventName,listener,useCapture){if(node.removeEventListener){node.removeEventListener(eventName,listener,useCapture);}else if(node.detachEvent){node.detachEvent("on"+eventName,listener);}else{var propertyName=getListenersPropertyName(eventName);if(node[propertyName]){array_remove(node[propertyName],listener);}}}

+function getEvent(evt,win){win=win?win:window;return evt?evt:win.event;}

+function stopEventPropagation(evt){if(evt.stopPropagation){evt.stopPropagation();}else if(typeof evt.cancelBubble!="undefined"){evt.cancelBubble=true;}

+evt.returnValue=false;}

+var logLog={quietMode:false,debugMessages:[],setQuietMode:function(quietMode){this.quietMode=bool(quietMode);},numberOfErrors:0,alertAllErrors:false,setAlertAllErrors:function(alertAllErrors){this.alertAllErrors=alertAllErrors;},debug:function(message){this.debugMessages.push(message);},displayDebug:function(){alert(this.debugMessages.join(newLine));},warn:function(message,exception){},error:function(message,exception){if(++this.numberOfErrors==1||this.alertAllErrors){if(!this.quietMode){var alertMessage="log4javascript error: "+message;if(exception){alertMessage+=newLine+newLine+"Original error: "+getExceptionStringRep(exception);}

+alert(alertMessage);}}}};log4javascript.logLog=logLog;log4javascript.setEventTypes(["load","error"]);function handleError(message,exception){logLog.error(message,exception);log4javascript.dispatchEvent("error",{"message":message,"exception":exception});}

+log4javascript.handleError=handleError;var enabled=!((typeof log4javascript_disabled!="undefined")&&log4javascript_disabled);log4javascript.setEnabled=function(enable){enabled=bool(enable);};log4javascript.isEnabled=function(){return enabled;};var useTimeStampsInMilliseconds=true;log4javascript.setTimeStampsInMilliseconds=function(timeStampsInMilliseconds){useTimeStampsInMilliseconds=bool(timeStampsInMilliseconds);};log4javascript.isTimeStampsInMilliseconds=function(){return useTimeStampsInMilliseconds;};log4javascript.evalInScope=function(expr){return eval(expr);};var showStackTraces=false;log4javascript.setShowStackTraces=function(show){showStackTraces=bool(show);};var Level=function(level,name){this.level=level;this.name=name;};Level.prototype={toString:function(){return this.name;},equals:function(level){return this.level==level.level;},isGreaterOrEqual:function(level){return this.level>=level.level;}};Level.ALL=new Level(Number.MIN_VALUE,"ALL");Level.TRACE=new Level(10000,"TRACE");Level.DEBUG=new Level(20000,"DEBUG");Level.INFO=new Level(30000,"INFO");Level.WARN=new Level(40000,"WARN");Level.ERROR=new Level(50000,"ERROR");Level.FATAL=new Level(60000,"FATAL");Level.OFF=new Level(Number.MAX_VALUE,"OFF");log4javascript.Level=Level;function Timer(name,level){this.name=name;this.level=isUndefined(level)?Level.INFO:level;this.start=new Date();}

+Timer.prototype.getElapsedTime=function(){return new Date().getTime()-this.start.getTime();};var anonymousLoggerName="[anonymous]";var defaultLoggerName="[default]";var nullLoggerName="[null]";var rootLoggerName="root";function Logger(name){this.name=name;this.parent=null;this.children=[];var appenders=[];var loggerLevel=null;var isRoot=(this.name===rootLoggerName);var isNull=(this.name===nullLoggerName);var appenderCache=null;var appenderCacheInvalidated=false;this.addChild=function(childLogger){this.children.push(childLogger);childLogger.parent=this;childLogger.invalidateAppenderCache();};var additive=true;this.getAdditivity=function(){return additive;};this.setAdditivity=function(additivity){var valueChanged=(additive!=additivity);additive=additivity;if(valueChanged){this.invalidateAppenderCache();}};this.addAppender=function(appender){if(isNull){handleError("Logger.addAppender: you may not add an appender to the null logger");}else{if(appender instanceof log4javascript.Appender){if(!array_contains(appenders,appender)){appenders.push(appender);appender.setAddedToLogger(this);this.invalidateAppenderCache();}}else{handleError("Logger.addAppender: appender supplied ('"+

+toStr(appender)+"') is not a subclass of Appender");}}};this.removeAppender=function(appender){array_remove(appenders,appender);appender.setRemovedFromLogger(this);this.invalidateAppenderCache();};this.removeAllAppenders=function(){var appenderCount=appenders.length;if(appenderCount>0){for(var i=0;i<appenderCount;i++){appenders[i].setRemovedFromLogger(this);}

+appenders.length=0;this.invalidateAppenderCache();}};this.getEffectiveAppenders=function(){if(appenderCache===null||appenderCacheInvalidated){var parentEffectiveAppenders=(isRoot||!this.getAdditivity())?[]:this.parent.getEffectiveAppenders();appenderCache=parentEffectiveAppenders.concat(appenders);appenderCacheInvalidated=false;}

+return appenderCache;};this.invalidateAppenderCache=function(){appenderCacheInvalidated=true;for(var i=0,len=this.children.length;i<len;i++){this.children[i].invalidateAppenderCache();}};this.log=function(level,params){if(enabled&&level.isGreaterOrEqual(this.getEffectiveLevel())){var exception;var finalParamIndex=params.length-1;var lastParam=params[finalParamIndex];if(params.length>1&&isError(lastParam)){exception=lastParam;finalParamIndex--;}

+var messages=[];for(var i=0;i<=finalParamIndex;i++){messages[i]=params[i];}

+var loggingEvent=new LoggingEvent(this,new Date(),level,messages,exception);this.callAppenders(loggingEvent);}};this.callAppenders=function(loggingEvent){var effectiveAppenders=this.getEffectiveAppenders();for(var i=0,len=effectiveAppenders.length;i<len;i++){effectiveAppenders[i].doAppend(loggingEvent);}};this.setLevel=function(level){if(isRoot&&level===null){handleError("Logger.setLevel: you cannot set the level of the root logger to null");}else if(level instanceof Level){loggerLevel=level;}else{handleError("Logger.setLevel: level supplied to logger "+

+this.name+" is not an instance of log4javascript.Level");}};this.getLevel=function(){return loggerLevel;};this.getEffectiveLevel=function(){for(var logger=this;logger!==null;logger=logger.parent){var level=logger.getLevel();if(level!==null){return level;}}};this.group=function(name,initiallyExpanded){if(enabled){var effectiveAppenders=this.getEffectiveAppenders();for(var i=0,len=effectiveAppenders.length;i<len;i++){effectiveAppenders[i].group(name,initiallyExpanded);}}};this.groupEnd=function(){if(enabled){var effectiveAppenders=this.getEffectiveAppenders();for(var i=0,len=effectiveAppenders.length;i<len;i++){effectiveAppenders[i].groupEnd();}}};var timers={};this.time=function(name,level){if(enabled){if(isUndefined(name)){handleError("Logger.time: a name for the timer must be supplied");}else if(level&&!(level instanceof Level)){handleError("Logger.time: level supplied to timer "+

+name+" is not an instance of log4javascript.Level");}else{timers[name]=new Timer(name,level);}}};this.timeEnd=function(name){if(enabled){if(isUndefined(name)){handleError("Logger.timeEnd: a name for the timer must be supplied");}else if(timers[name]){var timer=timers[name];var milliseconds=timer.getElapsedTime();this.log(timer.level,["Timer "+toStr(name)+" completed in "+milliseconds+"ms"]);delete timers[name];}else{logLog.warn("Logger.timeEnd: no timer found with name "+name);}}};this.assert=function(expr){if(enabled&&!expr){var args=[];for(var i=1,len=arguments.length;i<len;i++){args.push(arguments[i]);}

+args=(args.length>0)?args:["Assertion Failure"];args.push(newLine);args.push(expr);this.log(Level.ERROR,args);}};this.toString=function(){return"Logger["+this.name+"]";};}

+Logger.prototype={trace:function(){this.log(Level.TRACE,arguments);},debug:function(){this.log(Level.DEBUG,arguments);},info:function(){this.log(Level.INFO,arguments);},warn:function(){this.log(Level.WARN,arguments);},error:function(){this.log(Level.ERROR,arguments);},fatal:function(){this.log(Level.FATAL,arguments);},isEnabledFor:function(level){return level.isGreaterOrEqual(this.getEffectiveLevel());},isTraceEnabled:function(){return this.isEnabledFor(Level.TRACE);},isDebugEnabled:function(){return this.isEnabledFor(Level.DEBUG);},isInfoEnabled:function(){return this.isEnabledFor(Level.INFO);},isWarnEnabled:function(){return this.isEnabledFor(Level.WARN);},isErrorEnabled:function(){return this.isEnabledFor(Level.ERROR);},isFatalEnabled:function(){return this.isEnabledFor(Level.FATAL);}};Logger.prototype.trace.isEntryPoint=true;Logger.prototype.debug.isEntryPoint=true;Logger.prototype.info.isEntryPoint=true;Logger.prototype.warn.isEntryPoint=true;Logger.prototype.error.isEntryPoint=true;Logger.prototype.fatal.isEntryPoint=true;var loggers={};var loggerNames=[];var ROOT_LOGGER_DEFAULT_LEVEL=Level.DEBUG;var rootLogger=new Logger(rootLoggerName);rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);log4javascript.getRootLogger=function(){return rootLogger;};log4javascript.getLogger=function(loggerName){if(!(typeof loggerName=="string")){loggerName=anonymousLoggerName;logLog.warn("log4javascript.getLogger: non-string logger name "+

+toStr(loggerName)+" supplied, returning anonymous logger");}

+if(loggerName==rootLoggerName){handleError("log4javascript.getLogger: root logger may not be obtained by name");}

+if(!loggers[loggerName]){var logger=new Logger(loggerName);loggers[loggerName]=logger;loggerNames.push(loggerName);var lastDotIndex=loggerName.lastIndexOf(".");var parentLogger;if(lastDotIndex>-1){var parentLoggerName=loggerName.substring(0,lastDotIndex);parentLogger=log4javascript.getLogger(parentLoggerName);}else{parentLogger=rootLogger;}

+parentLogger.addChild(logger);}

+return loggers[loggerName];};var defaultLogger=null;log4javascript.getDefaultLogger=function(){if(!defaultLogger){defaultLogger=log4javascript.getLogger(defaultLoggerName);var a=new log4javascript.PopUpAppender();defaultLogger.addAppender(a);}

+return defaultLogger;};var nullLogger=null;log4javascript.getNullLogger=function(){if(!nullLogger){nullLogger=new Logger(nullLoggerName);nullLogger.setLevel(Level.OFF);}

+return nullLogger;};log4javascript.resetConfiguration=function(){rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);loggers={};};var LoggingEvent=function(logger,timeStamp,level,messages,exception){this.logger=logger;this.timeStamp=timeStamp;this.timeStampInMilliseconds=timeStamp.getTime();this.timeStampInSeconds=Math.floor(this.timeStampInMilliseconds/1000);this.milliseconds=this.timeStamp.getMilliseconds();this.level=level;this.messages=messages;this.exception=exception;};LoggingEvent.prototype={getThrowableStrRep:function(){return this.exception?getExceptionStringRep(this.exception):"";},getCombinedMessages:function(){return(this.messages.length==1)?this.messages[0]:this.messages.join(newLine);},toString:function(){return"LoggingEvent["+this.level+"]";}};log4javascript.LoggingEvent=LoggingEvent;var Layout=function(){};Layout.prototype={defaults:{loggerKey:"logger",timeStampKey:"timestamp",millisecondsKey:"milliseconds",levelKey:"level",messageKey:"message",exceptionKey:"exception",urlKey:"url"},loggerKey:"logger",timeStampKey:"timestamp",millisecondsKey:"milliseconds",levelKey:"level",messageKey:"message",exceptionKey:"exception",urlKey:"url",batchHeader:"",batchFooter:"",batchSeparator:"",returnsPostData:false,overrideTimeStampsSetting:false,useTimeStampsInMilliseconds:null,format:function(){handleError("Layout.format: layout supplied has no format() method");},ignoresThrowable:function(){handleError("Layout.ignoresThrowable: layout supplied has no ignoresThrowable() method");},getContentType:function(){return"text/plain";},allowBatching:function(){return true;},setTimeStampsInMilliseconds:function(timeStampsInMilliseconds){this.overrideTimeStampsSetting=true;this.useTimeStampsInMilliseconds=bool(timeStampsInMilliseconds);},isTimeStampsInMilliseconds:function(){return this.overrideTimeStampsSetting?this.useTimeStampsInMilliseconds:useTimeStampsInMilliseconds;},getTimeStampValue:function(loggingEvent){return this.isTimeStampsInMilliseconds()?loggingEvent.timeStampInMilliseconds:loggingEvent.timeStampInSeconds;},getDataValues:function(loggingEvent,combineMessages){var dataValues=[[this.loggerKey,loggingEvent.logger.name],[this.timeStampKey,this.getTimeStampValue(loggingEvent)],[this.levelKey,loggingEvent.level.name],[this.urlKey,window.location.href],[this.messageKey,combineMessages?loggingEvent.getCombinedMessages():loggingEvent.messages]];if(!this.isTimeStampsInMilliseconds()){dataValues.push([this.millisecondsKey,loggingEvent.milliseconds]);}

+if(loggingEvent.exception){dataValues.push([this.exceptionKey,getExceptionStringRep(loggingEvent.exception)]);}

+if(this.hasCustomFields()){for(var i=0,len=this.customFields.length;i<len;i++){var val=this.customFields[i].value;if(typeof val==="function"){val=val(this,loggingEvent);}

+dataValues.push([this.customFields[i].name,val]);}}

+return dataValues;},setKeys:function(loggerKey,timeStampKey,levelKey,messageKey,exceptionKey,urlKey,millisecondsKey){this.loggerKey=extractStringFromParam(loggerKey,this.defaults.loggerKey);this.timeStampKey=extractStringFromParam(timeStampKey,this.defaults.timeStampKey);this.levelKey=extractStringFromParam(levelKey,this.defaults.levelKey);this.messageKey=extractStringFromParam(messageKey,this.defaults.messageKey);this.exceptionKey=extractStringFromParam(exceptionKey,this.defaults.exceptionKey);this.urlKey=extractStringFromParam(urlKey,this.defaults.urlKey);this.millisecondsKey=extractStringFromParam(millisecondsKey,this.defaults.millisecondsKey);},setCustomField:function(name,value){var fieldUpdated=false;for(var i=0,len=this.customFields.length;i<len;i++){if(this.customFields[i].name===name){this.customFields[i].value=value;fieldUpdated=true;}}

+if(!fieldUpdated){this.customFields.push({"name":name,"value":value});}},hasCustomFields:function(){return(this.customFields.length>0);},toString:function(){handleError("Layout.toString: all layouts must override this method");}};log4javascript.Layout=Layout;var Appender=function(){};Appender.prototype=new EventSupport();Appender.prototype.layout=new PatternLayout();Appender.prototype.threshold=Level.ALL;Appender.prototype.loggers=[];Appender.prototype.doAppend=function(loggingEvent){if(enabled&&loggingEvent.level.level>=this.threshold.level){this.append(loggingEvent);}};Appender.prototype.append=function(loggingEvent){};Appender.prototype.setLayout=function(layout){if(layout instanceof Layout){this.layout=layout;}else{handleError("Appender.setLayout: layout supplied to "+

+this.toString()+" is not a subclass of Layout");}};Appender.prototype.getLayout=function(){return this.layout;};Appender.prototype.setThreshold=function(threshold){if(threshold instanceof Level){this.threshold=threshold;}else{handleError("Appender.setThreshold: threshold supplied to "+

+this.toString()+" is not a subclass of Level");}};Appender.prototype.getThreshold=function(){return this.threshold;};Appender.prototype.setAddedToLogger=function(logger){this.loggers.push(logger);};Appender.prototype.setRemovedFromLogger=function(logger){array_remove(this.loggers,logger);};Appender.prototype.group=emptyFunction;Appender.prototype.groupEnd=emptyFunction;Appender.prototype.toString=function(){handleError("Appender.toString: all appenders must override this method");};log4javascript.Appender=Appender;function SimpleLayout(){this.customFields=[];}

+SimpleLayout.prototype=new Layout();SimpleLayout.prototype.format=function(loggingEvent){return loggingEvent.level.name+" - "+loggingEvent.getCombinedMessages();};SimpleLayout.prototype.ignoresThrowable=function(){return true;};SimpleLayout.prototype.toString=function(){return"SimpleLayout";};log4javascript.SimpleLayout=SimpleLayout;function NullLayout(){this.customFields=[];}

+NullLayout.prototype=new Layout();NullLayout.prototype.format=function(loggingEvent){return loggingEvent.messages;};NullLayout.prototype.ignoresThrowable=function(){return true;};NullLayout.prototype.toString=function(){return"NullLayout";};log4javascript.NullLayout=NullLayout;function XmlLayout(combineMessages){this.combineMessages=extractBooleanFromParam(combineMessages,true);this.customFields=[];}

+XmlLayout.prototype=new Layout();XmlLayout.prototype.isCombinedMessages=function(){return this.combineMessages;};XmlLayout.prototype.getContentType=function(){return"text/xml";};XmlLayout.prototype.escapeCdata=function(str){return str.replace(/\]\]>/,"]]>]]&gt;<![CDATA[");};XmlLayout.prototype.format=function(loggingEvent){var layout=this;var i,len;function formatMessage(message){message=(typeof message==="string")?message:toStr(message);return"<log4javascript:message><![CDATA["+

+layout.escapeCdata(message)+"]]></log4javascript:message>";}

+var str="<log4javascript:event logger=\""+loggingEvent.logger.name+"\" timestamp=\""+this.getTimeStampValue(loggingEvent)+"\"";if(!this.isTimeStampsInMilliseconds()){str+=" milliseconds=\""+loggingEvent.milliseconds+"\"";}

+str+=" level=\""+loggingEvent.level.name+"\">"+newLine;if(this.combineMessages){str+=formatMessage(loggingEvent.getCombinedMessages());}else{str+="<log4javascript:messages>"+newLine;for(i=0,len=loggingEvent.messages.length;i<len;i++){str+=formatMessage(loggingEvent.messages[i])+newLine;}

+str+="</log4javascript:messages>"+newLine;}

+if(this.hasCustomFields()){for(i=0,len=this.customFields.length;i<len;i++){str+="<log4javascript:customfield name=\""+

+this.customFields[i].name+"\"><![CDATA["+

+this.customFields[i].value.toString()+"]]></log4javascript:customfield>"+newLine;}}

+if(loggingEvent.exception){str+="<log4javascript:exception><![CDATA["+

+getExceptionStringRep(loggingEvent.exception)+"]]></log4javascript:exception>"+newLine;}

+str+="</log4javascript:event>"+newLine+newLine;return str;};XmlLayout.prototype.ignoresThrowable=function(){return false;};XmlLayout.prototype.toString=function(){return"XmlLayout";};log4javascript.XmlLayout=XmlLayout;function escapeNewLines(str){return str.replace(/\r\n|\r|\n/g,"\\r\\n");}

+function JsonLayout(readable,combineMessages){this.readable=extractBooleanFromParam(readable,false);this.combineMessages=extractBooleanFromParam(combineMessages,true);this.batchHeader=this.readable?"["+newLine:"[";this.batchFooter=this.readable?"]"+newLine:"]";this.batchSeparator=this.readable?","+newLine:",";this.setKeys();this.colon=this.readable?": ":":";this.tab=this.readable?"\t":"";this.lineBreak=this.readable?newLine:"";this.customFields=[];}

+JsonLayout.prototype=new Layout();JsonLayout.prototype.isReadable=function(){return this.readable;};JsonLayout.prototype.isCombinedMessages=function(){return this.combineMessages;};JsonLayout.prototype.format=function(loggingEvent){var layout=this;var dataValues=this.getDataValues(loggingEvent,this.combineMessages);var str="{"+this.lineBreak;var i,len;function formatValue(val,prefix,expand){var formattedValue;var valType=typeof val;if(val instanceof Date){formattedValue=String(val.getTime());}else if(expand&&(val instanceof Array)){formattedValue="["+layout.lineBreak;for(var i=0,len=val.length;i<len;i++){var childPrefix=prefix+layout.tab;formattedValue+=childPrefix+formatValue(val[i],childPrefix,false);if(i<val.length-1){formattedValue+=",";}

+formattedValue+=layout.lineBreak;}

+formattedValue+=prefix+"]";}else if(valType!=="number"&&valType!=="boolean"){formattedValue="\""+escapeNewLines(toStr(val).replace(/\"/g,"\\\""))+"\"";}else{formattedValue=val;}

+return formattedValue;}

+for(i=0,len=dataValues.length-1;i<=len;i++){str+=this.tab+"\""+dataValues[i][0]+"\""+this.colon+formatValue(dataValues[i][1],this.tab,true);if(i<len){str+=",";}

+str+=this.lineBreak;}

+str+="}"+this.lineBreak;return str;};JsonLayout.prototype.ignoresThrowable=function(){return false;};JsonLayout.prototype.toString=function(){return"JsonLayout";};JsonLayout.prototype.getContentType=function(){return"application/json";};log4javascript.JsonLayout=JsonLayout;function HttpPostDataLayout(){this.setKeys();this.customFields=[];this.returnsPostData=true;}

+HttpPostDataLayout.prototype=new Layout();HttpPostDataLayout.prototype.allowBatching=function(){return false;};HttpPostDataLayout.prototype.format=function(loggingEvent){var dataValues=this.getDataValues(loggingEvent);var queryBits=[];for(var i=0,len=dataValues.length;i<len;i++){var val=(dataValues[i][1]instanceof Date)?String(dataValues[i][1].getTime()):dataValues[i][1];queryBits.push(urlEncode(dataValues[i][0])+"="+urlEncode(val));}

+return queryBits.join("&");};HttpPostDataLayout.prototype.ignoresThrowable=function(loggingEvent){return false;};HttpPostDataLayout.prototype.toString=function(){return"HttpPostDataLayout";};log4javascript.HttpPostDataLayout=HttpPostDataLayout;function formatObjectExpansion(obj,depth,indentation){var objectsExpanded=[];function doFormat(obj,depth,indentation){var i,j,len,childDepth,childIndentation,childLines,expansion,childExpansion;if(!indentation){indentation="";}

+function formatString(text){var lines=splitIntoLines(text);for(var j=1,jLen=lines.length;j<jLen;j++){lines[j]=indentation+lines[j];}

+return lines.join(newLine);}

+if(obj===null){return"null";}else if(typeof obj=="undefined"){return"undefined";}else if(typeof obj=="string"){return formatString(obj);}else if(typeof obj=="object"&&array_contains(objectsExpanded,obj)){try{expansion=toStr(obj);}catch(ex){expansion="Error formatting property. Details: "+getExceptionStringRep(ex);}

+return expansion+" [already expanded]";}else if((obj instanceof Array)&&depth>0){objectsExpanded.push(obj);expansion="["+newLine;childDepth=depth-1;childIndentation=indentation+"  ";childLines=[];for(i=0,len=obj.length;i<len;i++){try{childExpansion=doFormat(obj[i],childDepth,childIndentation);childLines.push(childIndentation+childExpansion);}catch(ex){childLines.push(childIndentation+"Error formatting array member. Details: "+

+getExceptionStringRep(ex)+"");}}

+expansion+=childLines.join(","+newLine)+newLine+indentation+"]";return expansion;}else if(Object.prototype.toString.call(obj)=="[object Date]"){return obj.toString();}else if(typeof obj=="object"&&depth>0){objectsExpanded.push(obj);expansion="{"+newLine;childDepth=depth-1;childIndentation=indentation+"  ";childLines=[];for(i in obj){try{childExpansion=doFormat(obj[i],childDepth,childIndentation);childLines.push(childIndentation+i+": "+childExpansion);}catch(ex){childLines.push(childIndentation+i+": Error formatting property. Details: "+

+getExceptionStringRep(ex));}}

+expansion+=childLines.join(","+newLine)+newLine+indentation+"}";return expansion;}else{return formatString(toStr(obj));}}

+return doFormat(obj,depth,indentation);}

+var SimpleDateFormat;(function(){var regex=/('[^']*')|(G+|y+|M+|w+|W+|D+|d+|F+|E+|a+|H+|k+|K+|h+|m+|s+|S+|Z+)|([a-zA-Z]+)|([^a-zA-Z']+)/;var monthNames=["January","February","March","April","May","June","July","August","September","October","November","December"];var dayNames=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];var TEXT2=0,TEXT3=1,NUMBER=2,YEAR=3,MONTH=4,TIMEZONE=5;var types={G:TEXT2,y:YEAR,M:MONTH,w:NUMBER,W:NUMBER,D:NUMBER,d:NUMBER,F:NUMBER,E:TEXT3,a:TEXT2,H:NUMBER,k:NUMBER,K:NUMBER,h:NUMBER,m:NUMBER,s:NUMBER,S:NUMBER,Z:TIMEZONE};var ONE_DAY=24*60*60*1000;var ONE_WEEK=7*ONE_DAY;var DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK=1;var newDateAtMidnight=function(year,month,day){var d=new Date(year,month,day,0,0,0);d.setMilliseconds(0);return d;};Date.prototype.getDifference=function(date){return this.getTime()-date.getTime();};Date.prototype.isBefore=function(d){return this.getTime()<d.getTime();};Date.prototype.getUTCTime=function(){return Date.UTC(this.getFullYear(),this.getMonth(),this.getDate(),this.getHours(),this.getMinutes(),this.getSeconds(),this.getMilliseconds());};Date.prototype.getTimeSince=function(d){return this.getUTCTime()-d.getUTCTime();};Date.prototype.getPreviousSunday=function(){var midday=new Date(this.getFullYear(),this.getMonth(),this.getDate(),12,0,0);var previousSunday=new Date(midday.getTime()-this.getDay()*ONE_DAY);return newDateAtMidnight(previousSunday.getFullYear(),previousSunday.getMonth(),previousSunday.getDate());};Date.prototype.getWeekInYear=function(minimalDaysInFirstWeek){if(isUndefined(this.minimalDaysInFirstWeek)){minimalDaysInFirstWeek=DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;}

+var previousSunday=this.getPreviousSunday();var startOfYear=newDateAtMidnight(this.getFullYear(),0,1);var numberOfSundays=previousSunday.isBefore(startOfYear)?0:1+Math.floor(previousSunday.getTimeSince(startOfYear)/ONE_WEEK);var numberOfDaysInFirstWeek=7-startOfYear.getDay();var weekInYear=numberOfSundays;if(numberOfDaysInFirstWeek<minimalDaysInFirstWeek){weekInYear--;}

+return weekInYear;};Date.prototype.getWeekInMonth=function(minimalDaysInFirstWeek){if(isUndefined(this.minimalDaysInFirstWeek)){minimalDaysInFirstWeek=DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;}

+var previousSunday=this.getPreviousSunday();var startOfMonth=newDateAtMidnight(this.getFullYear(),this.getMonth(),1);var numberOfSundays=previousSunday.isBefore(startOfMonth)?0:1+Math.floor(previousSunday.getTimeSince(startOfMonth)/ONE_WEEK);var numberOfDaysInFirstWeek=7-startOfMonth.getDay();var weekInMonth=numberOfSundays;if(numberOfDaysInFirstWeek>=minimalDaysInFirstWeek){weekInMonth++;}

+return weekInMonth;};Date.prototype.getDayInYear=function(){var startOfYear=newDateAtMidnight(this.getFullYear(),0,1);return 1+Math.floor(this.getTimeSince(startOfYear)/ONE_DAY);};SimpleDateFormat=function(formatString){this.formatString=formatString;};SimpleDateFormat.prototype.setMinimalDaysInFirstWeek=function(days){this.minimalDaysInFirstWeek=days;};SimpleDateFormat.prototype.getMinimalDaysInFirstWeek=function(){return isUndefined(this.minimalDaysInFirstWeek)?DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK:this.minimalDaysInFirstWeek;};var padWithZeroes=function(str,len){while(str.length<len){str="0"+str;}

+return str;};var formatText=function(data,numberOfLetters,minLength){return(numberOfLetters>=4)?data:data.substr(0,Math.max(minLength,numberOfLetters));};var formatNumber=function(data,numberOfLetters){var dataString=""+data;return padWithZeroes(dataString,numberOfLetters);};SimpleDateFormat.prototype.format=function(date){var formattedString="";var result;var searchString=this.formatString;while((result=regex.exec(searchString))){var quotedString=result[1];var patternLetters=result[2];var otherLetters=result[3];var otherCharacters=result[4];if(quotedString){if(quotedString=="''"){formattedString+="'";}else{formattedString+=quotedString.substring(1,quotedString.length-1);}}else if(otherLetters){}else if(otherCharacters){formattedString+=otherCharacters;}else if(patternLetters){var patternLetter=patternLetters.charAt(0);var numberOfLetters=patternLetters.length;var rawData="";switch(patternLetter){case"G":rawData="AD";break;case"y":rawData=date.getFullYear();break;case"M":rawData=date.getMonth();break;case"w":rawData=date.getWeekInYear(this.getMinimalDaysInFirstWeek());break;case"W":rawData=date.getWeekInMonth(this.getMinimalDaysInFirstWeek());break;case"D":rawData=date.getDayInYear();break;case"d":rawData=date.getDate();break;case"F":rawData=1+Math.floor((date.getDate()-1)/7);break;case"E":rawData=dayNames[date.getDay()];break;case"a":rawData=(date.getHours()>=12)?"PM":"AM";break;case"H":rawData=date.getHours();break;case"k":rawData=date.getHours()||24;break;case"K":rawData=date.getHours()%12;break;case"h":rawData=(date.getHours()%12)||12;break;case"m":rawData=date.getMinutes();break;case"s":rawData=date.getSeconds();break;case"S":rawData=date.getMilliseconds();break;case"Z":rawData=date.getTimezoneOffset();break;}

+switch(types[patternLetter]){case TEXT2:formattedString+=formatText(rawData,numberOfLetters,2);break;case TEXT3:formattedString+=formatText(rawData,numberOfLetters,3);break;case NUMBER:formattedString+=formatNumber(rawData,numberOfLetters);break;case YEAR:if(numberOfLetters<=3){var dataString=""+rawData;formattedString+=dataString.substr(2,2);}else{formattedString+=formatNumber(rawData,numberOfLetters);}

+break;case MONTH:if(numberOfLetters>=3){formattedString+=formatText(monthNames[rawData],numberOfLetters,numberOfLetters);}else{formattedString+=formatNumber(rawData+1,numberOfLetters);}

+break;case TIMEZONE:var isPositive=(rawData>0);var prefix=isPositive?"-":"+";var absData=Math.abs(rawData);var hours=""+Math.floor(absData/60);hours=padWithZeroes(hours,2);var minutes=""+(absData%60);minutes=padWithZeroes(minutes,2);formattedString+=prefix+hours+minutes;break;}}

+searchString=searchString.substr(result.index+result[0].length);}

+return formattedString;};})();log4javascript.SimpleDateFormat=SimpleDateFormat;function PatternLayout(pattern){if(pattern){this.pattern=pattern;}else{this.pattern=PatternLayout.DEFAULT_CONVERSION_PATTERN;}

+this.customFields=[];}

+PatternLayout.TTCC_CONVERSION_PATTERN="%r %p %c - %m%n";PatternLayout.DEFAULT_CONVERSION_PATTERN="%m%n";PatternLayout.ISO8601_DATEFORMAT="yyyy-MM-dd HH:mm:ss,SSS";PatternLayout.DATETIME_DATEFORMAT="dd MMM yyyy HH:mm:ss,SSS";PatternLayout.ABSOLUTETIME_DATEFORMAT="HH:mm:ss,SSS";PatternLayout.prototype=new Layout();PatternLayout.prototype.format=function(loggingEvent){var regex=/%(-?[0-9]+)?(\.?[0-9]+)?([acdfmMnpr%])(\{([^\}]+)\})?|([^%]+)/;var formattedString="";var result;var searchString=this.pattern;while((result=regex.exec(searchString))){var matchedString=result[0];var padding=result[1];var truncation=result[2];var conversionCharacter=result[3];var specifier=result[5];var text=result[6];if(text){formattedString+=""+text;}else{var replacement="";switch(conversionCharacter){case"a":case"m":var depth=0;if(specifier){depth=parseInt(specifier,10);if(isNaN(depth)){handleError("PatternLayout.format: invalid specifier '"+

+specifier+"' for conversion character '"+conversionCharacter+"' - should be a number");depth=0;}}

+var messages=(conversionCharacter==="a")?loggingEvent.messages[0]:loggingEvent.messages;for(var i=0,len=messages.length;i<len;i++){if(i>0&&(replacement.charAt(replacement.length-1)!==" ")){replacement+=" ";}

+if(depth===0){replacement+=messages[i];}else{replacement+=formatObjectExpansion(messages[i],depth);}}

+break;case"c":var loggerName=loggingEvent.logger.name;if(specifier){var precision=parseInt(specifier,10);var loggerNameBits=loggingEvent.logger.name.split(".");if(precision>=loggerNameBits.length){replacement=loggerName;}else{replacement=loggerNameBits.slice(loggerNameBits.length-precision).join(".");}}else{replacement=loggerName;}

+break;case"d":var dateFormat=PatternLayout.ISO8601_DATEFORMAT;if(specifier){dateFormat=specifier;if(dateFormat=="ISO8601"){dateFormat=PatternLayout.ISO8601_DATEFORMAT;}else if(dateFormat=="ABSOLUTE"){dateFormat=PatternLayout.ABSOLUTETIME_DATEFORMAT;}else if(dateFormat=="DATE"){dateFormat=PatternLayout.DATETIME_DATEFORMAT;}}

+replacement=(new SimpleDateFormat(dateFormat)).format(loggingEvent.timeStamp);break;case"f":if(this.hasCustomFields()){var fieldIndex=0;if(specifier){fieldIndex=parseInt(specifier,10);if(isNaN(fieldIndex)){handleError("PatternLayout.format: invalid specifier '"+

+specifier+"' for conversion character 'f' - should be a number");}else if(fieldIndex===0){handleError("PatternLayout.format: invalid specifier '"+

+specifier+"' for conversion character 'f' - must be greater than zero");}else if(fieldIndex>this.customFields.length){handleError("PatternLayout.format: invalid specifier '"+

+specifier+"' for conversion character 'f' - there aren't that many custom fields");}else{fieldIndex=fieldIndex-1;}}

+var val=this.customFields[fieldIndex].value;if(typeof val=="function"){val=val(this,loggingEvent);}

+replacement=val;}

+break;case"n":replacement=newLine;break;case"p":replacement=loggingEvent.level.name;break;case"r":replacement=""+loggingEvent.timeStamp.getDifference(applicationStartDate);break;case"%":replacement="%";break;default:replacement=matchedString;break;}

+var l;if(truncation){l=parseInt(truncation.substr(1),10);var strLen=replacement.length;if(l<strLen){replacement=replacement.substring(strLen-l,strLen);}}

+if(padding){if(padding.charAt(0)=="-"){l=parseInt(padding.substr(1),10);while(replacement.length<l){replacement+=" ";}}else{l=parseInt(padding,10);while(replacement.length<l){replacement=" "+replacement;}}}

+formattedString+=replacement;}

+searchString=searchString.substr(result.index+result[0].length);}

+return formattedString;};PatternLayout.prototype.ignoresThrowable=function(){return true;};PatternLayout.prototype.toString=function(){return"PatternLayout";};log4javascript.PatternLayout=PatternLayout;function AlertAppender(){}

+AlertAppender.prototype=new Appender();AlertAppender.prototype.layout=new SimpleLayout();AlertAppender.prototype.append=function(loggingEvent){var formattedMessage=this.getLayout().format(loggingEvent);if(this.getLayout().ignoresThrowable()){formattedMessage+=loggingEvent.getThrowableStrRep();}

+alert(formattedMessage);};AlertAppender.prototype.toString=function(){return"AlertAppender";};log4javascript.AlertAppender=AlertAppender;function BrowserConsoleAppender(){}

+BrowserConsoleAppender.prototype=new log4javascript.Appender();BrowserConsoleAppender.prototype.layout=new NullLayout();BrowserConsoleAppender.prototype.threshold=Level.DEBUG;BrowserConsoleAppender.prototype.append=function(loggingEvent){var appender=this;var getFormattedMessage=function(){var layout=appender.getLayout();var formattedMessage=layout.format(loggingEvent);if(layout.ignoresThrowable()&&loggingEvent.exception){formattedMessage+=loggingEvent.getThrowableStrRep();}

+return formattedMessage;};if((typeof opera!="undefined")&&opera.postError){opera.postError(getFormattedMessage());}else if(window.console&&window.console.log){var formattedMesage=getFormattedMessage();if(window.console.debug&&Level.DEBUG.isGreaterOrEqual(loggingEvent.level)){window.console.debug(formattedMesage);}else if(window.console.info&&Level.INFO.equals(loggingEvent.level)){window.console.info(formattedMesage);}else if(window.console.warn&&Level.WARN.equals(loggingEvent.level)){window.console.warn(formattedMesage);}else if(window.console.error&&loggingEvent.level.isGreaterOrEqual(Level.ERROR)){window.console.error(formattedMesage);}else{window.console.log(formattedMesage);}}};BrowserConsoleAppender.prototype.group=function(name){if(window.console&&window.console.group){window.console.group(name);}};BrowserConsoleAppender.prototype.groupEnd=function(){if(window.console&&window.console.groupEnd){window.console.groupEnd();}};BrowserConsoleAppender.prototype.toString=function(){return"BrowserConsoleAppender";};log4javascript.BrowserConsoleAppender=BrowserConsoleAppender;var xmlHttpFactories=[function(){return new XMLHttpRequest();},function(){return new ActiveXObject("Msxml2.XMLHTTP");},function(){return new ActiveXObject("Microsoft.XMLHTTP");}];var getXmlHttp=function(errorHandler){var xmlHttp=null,factory;for(var i=0,len=xmlHttpFactories.length;i<len;i++){factory=xmlHttpFactories[i];try{xmlHttp=factory();getXmlHttp=factory;return xmlHttp;}catch(e){}}

+if(errorHandler){errorHandler();}else{handleError("getXmlHttp: unable to obtain XMLHttpRequest object");}};function isHttpRequestSuccessful(xmlHttp){return isUndefined(xmlHttp.status)||xmlHttp.status===0||(xmlHttp.status>=200&&xmlHttp.status<300)||xmlHttp.status==1223;}

+function AjaxAppender(url){var appender=this;var isSupported=true;if(!url){handleError("AjaxAppender: URL must be specified in constructor");isSupported=false;}

+var timed=this.defaults.timed;var waitForResponse=this.defaults.waitForResponse;var batchSize=this.defaults.batchSize;var timerInterval=this.defaults.timerInterval;var requestSuccessCallback=this.defaults.requestSuccessCallback;var failCallback=this.defaults.failCallback;var postVarName=this.defaults.postVarName;var sendAllOnUnload=this.defaults.sendAllOnUnload;var contentType=this.defaults.contentType;var sessionId=null;var queuedLoggingEvents=[];var queuedRequests=[];var headers=[];var sending=false;var initialized=false;function checkCanConfigure(configOptionName){if(initialized){handleError("AjaxAppender: configuration option '"+

+configOptionName+"' may not be set after the appender has been initialized");return false;}

+return true;}

+this.getSessionId=function(){return sessionId;};this.setSessionId=function(sessionIdParam){sessionId=extractStringFromParam(sessionIdParam,null);this.layout.setCustomField("sessionid",sessionId);};this.setLayout=function(layoutParam){if(checkCanConfigure("layout")){this.layout=layoutParam;if(sessionId!==null){this.setSessionId(sessionId);}}};this.isTimed=function(){return timed;};this.setTimed=function(timedParam){if(checkCanConfigure("timed")){timed=bool(timedParam);}};this.getTimerInterval=function(){return timerInterval;};this.setTimerInterval=function(timerIntervalParam){if(checkCanConfigure("timerInterval")){timerInterval=extractIntFromParam(timerIntervalParam,timerInterval);}};this.isWaitForResponse=function(){return waitForResponse;};this.setWaitForResponse=function(waitForResponseParam){if(checkCanConfigure("waitForResponse")){waitForResponse=bool(waitForResponseParam);}};this.getBatchSize=function(){return batchSize;};this.setBatchSize=function(batchSizeParam){if(checkCanConfigure("batchSize")){batchSize=extractIntFromParam(batchSizeParam,batchSize);}};this.isSendAllOnUnload=function(){return sendAllOnUnload;};this.setSendAllOnUnload=function(sendAllOnUnloadParam){if(checkCanConfigure("sendAllOnUnload")){sendAllOnUnload=extractBooleanFromParam(sendAllOnUnloadParam,sendAllOnUnload);}};this.setRequestSuccessCallback=function(requestSuccessCallbackParam){requestSuccessCallback=extractFunctionFromParam(requestSuccessCallbackParam,requestSuccessCallback);};this.setFailCallback=function(failCallbackParam){failCallback=extractFunctionFromParam(failCallbackParam,failCallback);};this.getPostVarName=function(){return postVarName;};this.setPostVarName=function(postVarNameParam){if(checkCanConfigure("postVarName")){postVarName=extractStringFromParam(postVarNameParam,postVarName);}};this.getHeaders=function(){return headers;};this.addHeader=function(name,value){if(name.toLowerCase()=="content-type"){contentType=value;}else{headers.push({name:name,value:value});}};function sendAll(){if(isSupported&&enabled){sending=true;var currentRequestBatch;if(waitForResponse){if(queuedRequests.length>0){currentRequestBatch=queuedRequests.shift();sendRequest(preparePostData(currentRequestBatch),sendAll);}else{sending=false;if(timed){scheduleSending();}}}else{while((currentRequestBatch=queuedRequests.shift())){sendRequest(preparePostData(currentRequestBatch));}

+sending=false;if(timed){scheduleSending();}}}}

+this.sendAll=sendAll;function sendAllRemaining(){var sendingAnything=false;if(isSupported&&enabled){var actualBatchSize=appender.getLayout().allowBatching()?batchSize:1;var currentLoggingEvent;var batchedLoggingEvents=[];while((currentLoggingEvent=queuedLoggingEvents.shift())){batchedLoggingEvents.push(currentLoggingEvent);if(queuedLoggingEvents.length>=actualBatchSize){queuedRequests.push(batchedLoggingEvents);batchedLoggingEvents=[];}}

+if(batchedLoggingEvents.length>0){queuedRequests.push(batchedLoggingEvents);}

+sendingAnything=(queuedRequests.length>0);waitForResponse=false;timed=false;sendAll();}

+return sendingAnything;}

+this.sendAllRemaining=sendAllRemaining;function preparePostData(batchedLoggingEvents){var formattedMessages=[];var currentLoggingEvent;var postData="";while((currentLoggingEvent=batchedLoggingEvents.shift())){var currentFormattedMessage=appender.getLayout().format(currentLoggingEvent);if(appender.getLayout().ignoresThrowable()){currentFormattedMessage+=currentLoggingEvent.getThrowableStrRep();}

+formattedMessages.push(currentFormattedMessage);}

+if(batchedLoggingEvents.length==1){postData=formattedMessages.join("");}else{postData=appender.getLayout().batchHeader+

+formattedMessages.join(appender.getLayout().batchSeparator)+

+appender.getLayout().batchFooter;}

+if(contentType==appender.defaults.contentType){postData=appender.getLayout().returnsPostData?postData:urlEncode(postVarName)+"="+urlEncode(postData);if(postData.length>0){postData+="&";}

+postData+="layout="+urlEncode(appender.getLayout().toString());}

+return postData;}

+function scheduleSending(){window.setTimeout(sendAll,timerInterval);}

+function xmlHttpErrorHandler(){var msg="AjaxAppender: could not create XMLHttpRequest object. AjaxAppender disabled";handleError(msg);isSupported=false;if(failCallback){failCallback(msg);}}

+function sendRequest(postData,successCallback){try{var xmlHttp=getXmlHttp(xmlHttpErrorHandler);if(isSupported){if(xmlHttp.overrideMimeType){xmlHttp.overrideMimeType(appender.getLayout().getContentType());}

+xmlHttp.onreadystatechange=function(){if(xmlHttp.readyState==4){if(isHttpRequestSuccessful(xmlHttp)){if(requestSuccessCallback){requestSuccessCallback(xmlHttp);}

+if(successCallback){successCallback(xmlHttp);}}else{var msg="AjaxAppender.append: XMLHttpRequest request to URL "+

+url+" returned status code "+xmlHttp.status;handleError(msg);if(failCallback){failCallback(msg);}}

+xmlHttp.onreadystatechange=emptyFunction;xmlHttp=null;}};xmlHttp.open("POST",url,true);try{for(var i=0,header;header=headers[i++];){xmlHttp.setRequestHeader(header.name,header.value);}

+xmlHttp.setRequestHeader("Content-Type",contentType);}catch(headerEx){var msg="AjaxAppender.append: your browser's XMLHttpRequest implementation"+" does not support setRequestHeader, therefore cannot post data. AjaxAppender disabled";handleError(msg);isSupported=false;if(failCallback){failCallback(msg);}

+return;}

+xmlHttp.send(postData);}}catch(ex){var errMsg="AjaxAppender.append: error sending log message to "+url;handleError(errMsg,ex);isSupported=false;if(failCallback){failCallback(errMsg+". Details: "+getExceptionStringRep(ex));}}}

+this.append=function(loggingEvent){if(isSupported){if(!initialized){init();}

+queuedLoggingEvents.push(loggingEvent);var actualBatchSize=this.getLayout().allowBatching()?batchSize:1;if(queuedLoggingEvents.length>=actualBatchSize){var currentLoggingEvent;var batchedLoggingEvents=[];while((currentLoggingEvent=queuedLoggingEvents.shift())){batchedLoggingEvents.push(currentLoggingEvent);}

+queuedRequests.push(batchedLoggingEvents);if(!timed&&(!waitForResponse||(waitForResponse&&!sending))){sendAll();}}}};function init(){initialized=true;if(sendAllOnUnload){var oldBeforeUnload=window.onbeforeunload;window.onbeforeunload=function(){if(oldBeforeUnload){oldBeforeUnload();}

+if(sendAllRemaining()){return"Sending log messages";}};}

+if(timed){scheduleSending();}}}

+AjaxAppender.prototype=new Appender();AjaxAppender.prototype.defaults={waitForResponse:false,timed:false,timerInterval:1000,batchSize:1,sendAllOnUnload:false,requestSuccessCallback:null,failCallback:null,postVarName:"data",contentType:"application/x-www-form-urlencoded"};AjaxAppender.prototype.layout=new HttpPostDataLayout();AjaxAppender.prototype.toString=function(){return"AjaxAppender";};log4javascript.AjaxAppender=AjaxAppender;function setCookie(name,value,days,path){var expires;path=path?"; path="+path:"";if(days){var date=new Date();date.setTime(date.getTime()+(days*24*60*60*1000));expires="; expires="+date.toGMTString();}else{expires="";}

+document.cookie=escape(name)+"="+escape(value)+expires+path;}

+function getCookie(name){var nameEquals=escape(name)+"=";var ca=document.cookie.split(";");for(var i=0,len=ca.length;i<len;i++){var c=ca[i];while(c.charAt(0)===" "){c=c.substring(1,c.length);}

+if(c.indexOf(nameEquals)===0){return unescape(c.substring(nameEquals.length,c.length));}}

+return null;}

+function getBaseUrl(){var scripts=document.getElementsByTagName("script");for(var i=0,len=scripts.length;i<len;++i){if(scripts[i].src.indexOf("log4javascript")!=-1){var lastSlash=scripts[i].src.lastIndexOf("/");return(lastSlash==-1)?"":scripts[i].src.substr(0,lastSlash+1);}}

+return null;}

+function isLoaded(win){try{return bool(win.loaded);}catch(ex){return false;}}

+var ConsoleAppender;(function(){var getConsoleHtmlLines=function(){return['<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">','<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">','<head>','<title>log4javascript</title>','<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />','<!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->','<meta http-equiv="X-UA-Compatible" content="IE=7" />','<script type="text/javascript">var isIe = false, isIePre7 = false;</script>','<!--[if IE]><script type="text/javascript">isIe = true</script><![endif]-->','<!--[if lt IE 7]><script type="text/javascript">isIePre7 = true</script><![endif]-->','<script type="text/javascript">','//<![CDATA[','var loggingEnabled=true;var logQueuedEventsTimer=null;var logEntries=[];var logEntriesAndSeparators=[];var logItems=[];var renderDelay=100;var unrenderedLogItemsExist=false;var rootGroup,currentGroup=null;var loaded=false;var currentLogItem=null;var logMainContainer;function copyProperties(obj,props){for(var i in props){obj[i]=props[i];}}','function LogItem(){}','LogItem.prototype={mainContainer:null,wrappedContainer:null,unwrappedContainer:null,group:null,appendToLog:function(){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].appendToLog();}','this.group.update();},doRemove:function(doUpdate,removeFromGroup){if(this.rendered){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].remove();}','this.unwrappedElementContainer=null;this.wrappedElementContainer=null;this.mainElementContainer=null;}','if(this.group&&removeFromGroup){this.group.removeChild(this,doUpdate);}','if(this===currentLogItem){currentLogItem=null;}},remove:function(doUpdate,removeFromGroup){this.doRemove(doUpdate,removeFromGroup);},render:function(){},accept:function(visitor){visitor.visit(this);},getUnwrappedDomContainer:function(){return this.group.unwrappedElementContainer.contentDiv;},getWrappedDomContainer:function(){return this.group.wrappedElementContainer.contentDiv;},getMainDomContainer:function(){return this.group.mainElementContainer.contentDiv;}};LogItem.serializedItemKeys={LOG_ENTRY:0,GROUP_START:1,GROUP_END:2};function LogItemContainerElement(){}','LogItemContainerElement.prototype={appendToLog:function(){var insertBeforeFirst=(newestAtTop&&this.containerDomNode.hasChildNodes());if(insertBeforeFirst){this.containerDomNode.insertBefore(this.mainDiv,this.containerDomNode.firstChild);}else{this.containerDomNode.appendChild(this.mainDiv);}}};function SeparatorElementContainer(containerDomNode){this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.className="separator";this.mainDiv.innerHTML="&nbsp;";}','SeparatorElementContainer.prototype=new LogItemContainerElement();SeparatorElementContainer.prototype.remove=function(){this.mainDiv.parentNode.removeChild(this.mainDiv);this.mainDiv=null;};function Separator(){this.rendered=false;}','Separator.prototype=new LogItem();copyProperties(Separator.prototype,{render:function(){var containerDomNode=this.group.contentDiv;if(isIe){this.unwrappedElementContainer=new SeparatorElementContainer(this.getUnwrappedDomContainer());this.wrappedElementContainer=new SeparatorElementContainer(this.getWrappedDomContainer());this.elementContainers=[this.unwrappedElementContainer,this.wrappedElementContainer];}else{this.mainElementContainer=new SeparatorElementContainer(this.getMainDomContainer());this.elementContainers=[this.mainElementContainer];}','this.content=this.formattedMessage;this.rendered=true;}});function GroupElementContainer(group,containerDomNode,isRoot,isWrapped){this.group=group;this.containerDomNode=containerDomNode;this.isRoot=isRoot;this.isWrapped=isWrapped;this.expandable=false;if(this.isRoot){if(isIe){this.contentDiv=logMainContainer.appendChild(document.createElement("div"));this.contentDiv.id=this.isWrapped?"log_wrapped":"log_unwrapped";}else{this.contentDiv=logMainContainer;}}else{var groupElementContainer=this;this.mainDiv=document.createElement("div");this.mainDiv.className="group";this.headingDiv=this.mainDiv.appendChild(document.createElement("div"));this.headingDiv.className="groupheading";this.expander=this.headingDiv.appendChild(document.createElement("span"));this.expander.className="expander unselectable greyedout";this.expander.unselectable=true;var expanderText=this.group.expanded?"-":"+";this.expanderTextNode=this.expander.appendChild(document.createTextNode(expanderText));this.headingDiv.appendChild(document.createTextNode(" "+this.group.name));this.contentDiv=this.mainDiv.appendChild(document.createElement("div"));var contentCssClass=this.group.expanded?"expanded":"collapsed";this.contentDiv.className="groupcontent "+contentCssClass;this.expander.onclick=function(){if(groupElementContainer.group.expandable){groupElementContainer.group.toggleExpanded();}};}}','GroupElementContainer.prototype=new LogItemContainerElement();copyProperties(GroupElementContainer.prototype,{toggleExpanded:function(){if(!this.isRoot){var oldCssClass,newCssClass,expanderText;if(this.group.expanded){newCssClass="expanded";oldCssClass="collapsed";expanderText="-";}else{newCssClass="collapsed";oldCssClass="expanded";expanderText="+";}','replaceClass(this.contentDiv,newCssClass,oldCssClass);this.expanderTextNode.nodeValue=expanderText;}},remove:function(){if(!this.isRoot){this.headingDiv=null;this.expander.onclick=null;this.expander=null;this.expanderTextNode=null;this.contentDiv=null;this.containerDomNode=null;this.mainDiv.parentNode.removeChild(this.mainDiv);this.mainDiv=null;}},reverseChildren:function(){var node=null;var childDomNodes=[];while((node=this.contentDiv.firstChild)){this.contentDiv.removeChild(node);childDomNodes.push(node);}','while((node=childDomNodes.pop())){this.contentDiv.appendChild(node);}},update:function(){if(!this.isRoot){if(this.group.expandable){removeClass(this.expander,"greyedout");}else{addClass(this.expander,"greyedout");}}},clear:function(){if(this.isRoot){this.contentDiv.innerHTML="";}}});function Group(name,isRoot,initiallyExpanded){this.name=name;this.group=null;this.isRoot=isRoot;this.initiallyExpanded=initiallyExpanded;this.elementContainers=[];this.children=[];this.expanded=initiallyExpanded;this.rendered=false;this.expandable=false;}','Group.prototype=new LogItem();copyProperties(Group.prototype,{addChild:function(logItem){this.children.push(logItem);logItem.group=this;},render:function(){if(isIe){var unwrappedDomContainer,wrappedDomContainer;if(this.isRoot){unwrappedDomContainer=logMainContainer;wrappedDomContainer=logMainContainer;}else{unwrappedDomContainer=this.getUnwrappedDomContainer();wrappedDomContainer=this.getWrappedDomContainer();}','this.unwrappedElementContainer=new GroupElementContainer(this,unwrappedDomContainer,this.isRoot,false);this.wrappedElementContainer=new GroupElementContainer(this,wrappedDomContainer,this.isRoot,true);this.elementContainers=[this.unwrappedElementContainer,this.wrappedElementContainer];}else{var mainDomContainer=this.isRoot?logMainContainer:this.getMainDomContainer();this.mainElementContainer=new GroupElementContainer(this,mainDomContainer,this.isRoot,false);this.elementContainers=[this.mainElementContainer];}','this.rendered=true;},toggleExpanded:function(){this.expanded=!this.expanded;for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].toggleExpanded();}},expand:function(){if(!this.expanded){this.toggleExpanded();}},accept:function(visitor){visitor.visitGroup(this);},reverseChildren:function(){if(this.rendered){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].reverseChildren();}}},update:function(){var previouslyExpandable=this.expandable;this.expandable=(this.children.length!==0);if(this.expandable!==previouslyExpandable){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].update();}}},flatten:function(){var visitor=new GroupFlattener();this.accept(visitor);return visitor.logEntriesAndSeparators;},removeChild:function(child,doUpdate){array_remove(this.children,child);child.group=null;if(doUpdate){this.update();}},remove:function(doUpdate,removeFromGroup){for(var i=0,len=this.children.length;i<len;i++){this.children[i].remove(false,false);}','this.children=[];this.update();if(this===currentGroup){currentGroup=this.group;}','this.doRemove(doUpdate,removeFromGroup);},serialize:function(items){items.push([LogItem.serializedItemKeys.GROUP_START,this.name]);for(var i=0,len=this.children.length;i<len;i++){this.children[i].serialize(items);}','if(this!==currentGroup){items.push([LogItem.serializedItemKeys.GROUP_END]);}},clear:function(){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].clear();}}});function LogEntryElementContainer(){}','LogEntryElementContainer.prototype=new LogItemContainerElement();copyProperties(LogEntryElementContainer.prototype,{remove:function(){this.doRemove();},doRemove:function(){this.mainDiv.parentNode.removeChild(this.mainDiv);this.mainDiv=null;this.contentElement=null;this.containerDomNode=null;},setContent:function(content,wrappedContent){if(content===this.formattedMessage){this.contentElement.innerHTML="";this.contentElement.appendChild(document.createTextNode(this.formattedMessage));}else{this.contentElement.innerHTML=content;}},setSearchMatch:function(isMatch){var oldCssClass=isMatch?"searchnonmatch":"searchmatch";var newCssClass=isMatch?"searchmatch":"searchnonmatch";replaceClass(this.mainDiv,newCssClass,oldCssClass);},clearSearch:function(){removeClass(this.mainDiv,"searchmatch");removeClass(this.mainDiv,"searchnonmatch");}});function LogEntryWrappedElementContainer(logEntry,containerDomNode){this.logEntry=logEntry;this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.appendChild(document.createTextNode(this.logEntry.formattedMessage));this.mainDiv.className="logentry wrapped "+this.logEntry.level;this.contentElement=this.mainDiv;}','LogEntryWrappedElementContainer.prototype=new LogEntryElementContainer();LogEntryWrappedElementContainer.prototype.setContent=function(content,wrappedContent){if(content===this.formattedMessage){this.contentElement.innerHTML="";this.contentElement.appendChild(document.createTextNode(this.formattedMessage));}else{this.contentElement.innerHTML=wrappedContent;}};function LogEntryUnwrappedElementContainer(logEntry,containerDomNode){this.logEntry=logEntry;this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.className="logentry unwrapped "+this.logEntry.level;this.pre=this.mainDiv.appendChild(document.createElement("pre"));this.pre.appendChild(document.createTextNode(this.logEntry.formattedMessage));this.pre.className="unwrapped";this.contentElement=this.pre;}','LogEntryUnwrappedElementContainer.prototype=new LogEntryElementContainer();LogEntryUnwrappedElementContainer.prototype.remove=function(){this.doRemove();this.pre=null;};function LogEntryMainElementContainer(logEntry,containerDomNode){this.logEntry=logEntry;this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.className="logentry nonielogentry "+this.logEntry.level;this.contentElement=this.mainDiv.appendChild(document.createElement("span"));this.contentElement.appendChild(document.createTextNode(this.logEntry.formattedMessage));}','LogEntryMainElementContainer.prototype=new LogEntryElementContainer();function LogEntry(level,formattedMessage){this.level=level;this.formattedMessage=formattedMessage;this.rendered=false;}','LogEntry.prototype=new LogItem();copyProperties(LogEntry.prototype,{render:function(){var logEntry=this;var containerDomNode=this.group.contentDiv;if(isIe){this.formattedMessage=this.formattedMessage.replace(/\\r\\n/g,"\\r");this.unwrappedElementContainer=new LogEntryUnwrappedElementContainer(this,this.getUnwrappedDomContainer());this.wrappedElementContainer=new LogEntryWrappedElementContainer(this,this.getWrappedDomContainer());this.elementContainers=[this.unwrappedElementContainer,this.wrappedElementContainer];}else{this.mainElementContainer=new LogEntryMainElementContainer(this,this.getMainDomContainer());this.elementContainers=[this.mainElementContainer];}','this.content=this.formattedMessage;this.rendered=true;},setContent:function(content,wrappedContent){if(content!=this.content){if(isIe&&(content!==this.formattedMessage)){content=content.replace(/\\r\\n/g,"\\r");}','for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].setContent(content,wrappedContent);}','this.content=content;}},getSearchMatches:function(){var matches=[];var i,len;if(isIe){var unwrappedEls=getElementsByClass(this.unwrappedElementContainer.mainDiv,"searchterm","span");var wrappedEls=getElementsByClass(this.wrappedElementContainer.mainDiv,"searchterm","span");for(i=0,len=unwrappedEls.length;i<len;i++){matches[i]=new Match(this.level,null,unwrappedEls[i],wrappedEls[i]);}}else{var els=getElementsByClass(this.mainElementContainer.mainDiv,"searchterm","span");for(i=0,len=els.length;i<len;i++){matches[i]=new Match(this.level,els[i]);}}','return matches;},setSearchMatch:function(isMatch){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].setSearchMatch(isMatch);}},clearSearch:function(){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].clearSearch();}},accept:function(visitor){visitor.visitLogEntry(this);},serialize:function(items){items.push([LogItem.serializedItemKeys.LOG_ENTRY,this.level,this.formattedMessage]);}});function LogItemVisitor(){}','LogItemVisitor.prototype={visit:function(logItem){},visitParent:function(logItem){if(logItem.group){logItem.group.accept(this);}},visitChildren:function(logItem){for(var i=0,len=logItem.children.length;i<len;i++){logItem.children[i].accept(this);}},visitLogEntry:function(logEntry){this.visit(logEntry);},visitSeparator:function(separator){this.visit(separator);},visitGroup:function(group){this.visit(group);}};function GroupFlattener(){this.logEntriesAndSeparators=[];}','GroupFlattener.prototype=new LogItemVisitor();GroupFlattener.prototype.visitGroup=function(group){this.visitChildren(group);};GroupFlattener.prototype.visitLogEntry=function(logEntry){this.logEntriesAndSeparators.push(logEntry);};GroupFlattener.prototype.visitSeparator=function(separator){this.logEntriesAndSeparators.push(separator);};window.onload=function(){if(location.search){var queryBits=unescape(location.search).substr(1).split("&"),nameValueBits;for(var i=0,len=queryBits.length;i<len;i++){nameValueBits=queryBits[i].split("=");if(nameValueBits[0]=="log4javascript_domain"){document.domain=nameValueBits[1];break;}}}','logMainContainer=$("log");if(isIePre7){addClass(logMainContainer,"oldIe");}','rootGroup=new Group("root",true);rootGroup.render();currentGroup=rootGroup;setCommandInputWidth();setLogContainerHeight();toggleLoggingEnabled();toggleSearchEnabled();toggleSearchFilter();toggleSearchHighlight();applyFilters();checkAllLevels();toggleWrap();toggleNewestAtTop();toggleScrollToLatest();renderQueuedLogItems();loaded=true;$("command").value="";$("command").autocomplete="off";$("command").onkeydown=function(evt){evt=getEvent(evt);if(evt.keyCode==10||evt.keyCode==13){evalCommandLine();stopPropagation(evt);}else if(evt.keyCode==27){this.value="";this.focus();}else if(evt.keyCode==38&&commandHistory.length>0){currentCommandIndex=Math.max(0,currentCommandIndex-1);this.value=commandHistory[currentCommandIndex];moveCaretToEnd(this);}else if(evt.keyCode==40&&commandHistory.length>0){currentCommandIndex=Math.min(commandHistory.length-1,currentCommandIndex+1);this.value=commandHistory[currentCommandIndex];moveCaretToEnd(this);}};$("command").onkeypress=function(evt){evt=getEvent(evt);if(evt.keyCode==38&&commandHistory.length>0&&evt.preventDefault){evt.preventDefault();}};$("command").onkeyup=function(evt){evt=getEvent(evt);if(evt.keyCode==27&&evt.preventDefault){evt.preventDefault();this.focus();}};document.onkeydown=function keyEventHandler(evt){evt=getEvent(evt);switch(evt.keyCode){case 69:if(evt.shiftKey&&(evt.ctrlKey||evt.metaKey)){evalLastCommand();cancelKeyEvent(evt);return false;}','break;case 75:if(evt.shiftKey&&(evt.ctrlKey||evt.metaKey)){focusSearch();cancelKeyEvent(evt);return false;}','break;case 40:case 76:if(evt.shiftKey&&(evt.ctrlKey||evt.metaKey)){focusCommandLine();cancelKeyEvent(evt);return false;}','break;}};setTimeout(setLogContainerHeight,20);setShowCommandLine(showCommandLine);doSearch();};window.onunload=function(){if(mainWindowExists()){appender.unload();}','appender=null;};function toggleLoggingEnabled(){setLoggingEnabled($("enableLogging").checked);}','function setLoggingEnabled(enable){loggingEnabled=enable;}','var appender=null;function setAppender(appenderParam){appender=appenderParam;}','function setShowCloseButton(showCloseButton){$("closeButton").style.display=showCloseButton?"inline":"none";}','function setShowHideButton(showHideButton){$("hideButton").style.display=showHideButton?"inline":"none";}','var newestAtTop=false;function LogItemContentReverser(){}','LogItemContentReverser.prototype=new LogItemVisitor();LogItemContentReverser.prototype.visitGroup=function(group){group.reverseChildren();this.visitChildren(group);};function setNewestAtTop(isNewestAtTop){var oldNewestAtTop=newestAtTop;var i,iLen,j,jLen;newestAtTop=Boolean(isNewestAtTop);if(oldNewestAtTop!=newestAtTop){var visitor=new LogItemContentReverser();rootGroup.accept(visitor);if(currentSearch){var currentMatch=currentSearch.matches[currentMatchIndex];var matchIndex=0;var matches=[];var actOnLogEntry=function(logEntry){var logEntryMatches=logEntry.getSearchMatches();for(j=0,jLen=logEntryMatches.length;j<jLen;j++){matches[matchIndex]=logEntryMatches[j];if(currentMatch&&logEntryMatches[j].equals(currentMatch)){currentMatchIndex=matchIndex;}','matchIndex++;}};if(newestAtTop){for(i=logEntries.length-1;i>=0;i--){actOnLogEntry(logEntries[i]);}}else{for(i=0,iLen=logEntries.length;i<iLen;i++){actOnLogEntry(logEntries[i]);}}','currentSearch.matches=matches;if(currentMatch){currentMatch.setCurrent();}}else if(scrollToLatest){doScrollToLatest();}}','$("newestAtTop").checked=isNewestAtTop;}','function toggleNewestAtTop(){var isNewestAtTop=$("newestAtTop").checked;setNewestAtTop(isNewestAtTop);}','var scrollToLatest=true;function setScrollToLatest(isScrollToLatest){scrollToLatest=isScrollToLatest;if(scrollToLatest){doScrollToLatest();}','$("scrollToLatest").checked=isScrollToLatest;}','function toggleScrollToLatest(){var isScrollToLatest=$("scrollToLatest").checked;setScrollToLatest(isScrollToLatest);}','function doScrollToLatest(){var l=logMainContainer;if(typeof l.scrollTop!="undefined"){if(newestAtTop){l.scrollTop=0;}else{var latestLogEntry=l.lastChild;if(latestLogEntry){l.scrollTop=l.scrollHeight;}}}}','var closeIfOpenerCloses=true;function setCloseIfOpenerCloses(isCloseIfOpenerCloses){closeIfOpenerCloses=isCloseIfOpenerCloses;}','var maxMessages=null;function setMaxMessages(max){maxMessages=max;pruneLogEntries();}','var showCommandLine=false;function setShowCommandLine(isShowCommandLine){showCommandLine=isShowCommandLine;if(loaded){$("commandLine").style.display=showCommandLine?"block":"none";setCommandInputWidth();setLogContainerHeight();}}','function focusCommandLine(){if(loaded){$("command").focus();}}','function focusSearch(){if(loaded){$("searchBox").focus();}}','function getLogItems(){var items=[];for(var i=0,len=logItems.length;i<len;i++){logItems[i].serialize(items);}','return items;}','function setLogItems(items){var loggingReallyEnabled=loggingEnabled;loggingEnabled=true;for(var i=0,len=items.length;i<len;i++){switch(items[i][0]){case LogItem.serializedItemKeys.LOG_ENTRY:log(items[i][1],items[i][2]);break;case LogItem.serializedItemKeys.GROUP_START:group(items[i][1]);break;case LogItem.serializedItemKeys.GROUP_END:groupEnd();break;}}','loggingEnabled=loggingReallyEnabled;}','function log(logLevel,formattedMessage){if(loggingEnabled){var logEntry=new LogEntry(logLevel,formattedMessage);logEntries.push(logEntry);logEntriesAndSeparators.push(logEntry);logItems.push(logEntry);currentGroup.addChild(logEntry);if(loaded){if(logQueuedEventsTimer!==null){clearTimeout(logQueuedEventsTimer);}','logQueuedEventsTimer=setTimeout(renderQueuedLogItems,renderDelay);unrenderedLogItemsExist=true;}}}','function renderQueuedLogItems(){logQueuedEventsTimer=null;var pruned=pruneLogEntries();var initiallyHasMatches=currentSearch?currentSearch.hasMatches():false;for(var i=0,len=logItems.length;i<len;i++){if(!logItems[i].rendered){logItems[i].render();logItems[i].appendToLog();if(currentSearch&&(logItems[i]instanceof LogEntry)){currentSearch.applyTo(logItems[i]);}}}','if(currentSearch){if(pruned){if(currentSearch.hasVisibleMatches()){if(currentMatchIndex===null){setCurrentMatchIndex(0);}','displayMatches();}else{displayNoMatches();}}else if(!initiallyHasMatches&&currentSearch.hasVisibleMatches()){setCurrentMatchIndex(0);displayMatches();}}','if(scrollToLatest){doScrollToLatest();}','unrenderedLogItemsExist=false;}','function pruneLogEntries(){if((maxMessages!==null)&&(logEntriesAndSeparators.length>maxMessages)){var numberToDelete=logEntriesAndSeparators.length-maxMessages;var prunedLogEntries=logEntriesAndSeparators.slice(0,numberToDelete);if(currentSearch){currentSearch.removeMatches(prunedLogEntries);}','var group;for(var i=0;i<numberToDelete;i++){group=logEntriesAndSeparators[i].group;array_remove(logItems,logEntriesAndSeparators[i]);array_remove(logEntries,logEntriesAndSeparators[i]);logEntriesAndSeparators[i].remove(true,true);if(group.children.length===0&&group!==currentGroup&&group!==rootGroup){array_remove(logItems,group);group.remove(true,true);}}','logEntriesAndSeparators=array_removeFromStart(logEntriesAndSeparators,numberToDelete);return true;}','return false;}','function group(name,startExpanded){if(loggingEnabled){initiallyExpanded=(typeof startExpanded==="undefined")?true:Boolean(startExpanded);var newGroup=new Group(name,false,initiallyExpanded);currentGroup.addChild(newGroup);currentGroup=newGroup;logItems.push(newGroup);if(loaded){if(logQueuedEventsTimer!==null){clearTimeout(logQueuedEventsTimer);}','logQueuedEventsTimer=setTimeout(renderQueuedLogItems,renderDelay);unrenderedLogItemsExist=true;}}}','function groupEnd(){currentGroup=(currentGroup===rootGroup)?rootGroup:currentGroup.group;}','function mainPageReloaded(){currentGroup=rootGroup;var separator=new Separator();logEntriesAndSeparators.push(separator);logItems.push(separator);currentGroup.addChild(separator);}','function closeWindow(){if(appender&&mainWindowExists()){appender.close(true);}else{window.close();}}','function hide(){if(appender&&mainWindowExists()){appender.hide();}}','var mainWindow=window;var windowId="log4javascriptConsoleWindow_"+new Date().getTime()+"_"+(""+Math.random()).substr(2);function setMainWindow(win){mainWindow=win;mainWindow[windowId]=window;if(opener&&closeIfOpenerCloses){pollOpener();}}','function pollOpener(){if(closeIfOpenerCloses){if(mainWindowExists()){setTimeout(pollOpener,500);}else{closeWindow();}}}','function mainWindowExists(){try{return(mainWindow&&!mainWindow.closed&&mainWindow[windowId]==window);}catch(ex){}','return false;}','var logLevels=["TRACE","DEBUG","INFO","WARN","ERROR","FATAL"];function getCheckBox(logLevel){return $("switch_"+logLevel);}','function getIeWrappedLogContainer(){return $("log_wrapped");}','function getIeUnwrappedLogContainer(){return $("log_unwrapped");}','function applyFilters(){for(var i=0;i<logLevels.length;i++){if(getCheckBox(logLevels[i]).checked){addClass(logMainContainer,logLevels[i]);}else{removeClass(logMainContainer,logLevels[i]);}}','updateSearchFromFilters();}','function toggleAllLevels(){var turnOn=$("switch_ALL").checked;for(var i=0;i<logLevels.length;i++){getCheckBox(logLevels[i]).checked=turnOn;if(turnOn){addClass(logMainContainer,logLevels[i]);}else{removeClass(logMainContainer,logLevels[i]);}}}','function checkAllLevels(){for(var i=0;i<logLevels.length;i++){if(!getCheckBox(logLevels[i]).checked){getCheckBox("ALL").checked=false;return;}}','getCheckBox("ALL").checked=true;}','function clearLog(){rootGroup.clear();currentGroup=rootGroup;logEntries=[];logItems=[];logEntriesAndSeparators=[];doSearch();}','function toggleWrap(){var enable=$("wrap").checked;if(enable){addClass(logMainContainer,"wrap");}else{removeClass(logMainContainer,"wrap");}','refreshCurrentMatch();}','var searchTimer=null;function scheduleSearch(){try{clearTimeout(searchTimer);}catch(ex){}','searchTimer=setTimeout(doSearch,500);}','function Search(searchTerm,isRegex,searchRegex,isCaseSensitive){this.searchTerm=searchTerm;this.isRegex=isRegex;this.searchRegex=searchRegex;this.isCaseSensitive=isCaseSensitive;this.matches=[];}','Search.prototype={hasMatches:function(){return this.matches.length>0;},hasVisibleMatches:function(){if(this.hasMatches()){for(var i=0;i<this.matches.length;i++){if(this.matches[i].isVisible()){return true;}}}','return false;},match:function(logEntry){var entryText=String(logEntry.formattedMessage);var matchesSearch=false;if(this.isRegex){matchesSearch=this.searchRegex.test(entryText);}else if(this.isCaseSensitive){matchesSearch=(entryText.indexOf(this.searchTerm)>-1);}else{matchesSearch=(entryText.toLowerCase().indexOf(this.searchTerm.toLowerCase())>-1);}','return matchesSearch;},getNextVisibleMatchIndex:function(){for(var i=currentMatchIndex+1;i<this.matches.length;i++){if(this.matches[i].isVisible()){return i;}}','for(i=0;i<=currentMatchIndex;i++){if(this.matches[i].isVisible()){return i;}}','return-1;},getPreviousVisibleMatchIndex:function(){for(var i=currentMatchIndex-1;i>=0;i--){if(this.matches[i].isVisible()){return i;}}','for(var i=this.matches.length-1;i>=currentMatchIndex;i--){if(this.matches[i].isVisible()){return i;}}','return-1;},applyTo:function(logEntry){var doesMatch=this.match(logEntry);if(doesMatch){logEntry.group.expand();logEntry.setSearchMatch(true);var logEntryContent;var wrappedLogEntryContent;var searchTermReplacementStartTag="<span class=\\\"searchterm\\\">";var searchTermReplacementEndTag="<"+"/span>";var preTagName=isIe?"pre":"span";var preStartTag="<"+preTagName+" class=\\\"pre\\\">";var preEndTag="<"+"/"+preTagName+">";var startIndex=0;var searchIndex,matchedText,textBeforeMatch;if(this.isRegex){var flags=this.isCaseSensitive?"g":"gi";var capturingRegex=new RegExp("("+this.searchRegex.source+")",flags);var rnd=(""+Math.random()).substr(2);var startToken="%%s"+rnd+"%%";var endToken="%%e"+rnd+"%%";logEntryContent=logEntry.formattedMessage.replace(capturingRegex,startToken+"$1"+endToken);logEntryContent=escapeHtml(logEntryContent);var result;var searchString=logEntryContent;logEntryContent="";wrappedLogEntryContent="";while((searchIndex=searchString.indexOf(startToken,startIndex))>-1){var endTokenIndex=searchString.indexOf(endToken,searchIndex);matchedText=searchString.substring(searchIndex+startToken.length,endTokenIndex);textBeforeMatch=searchString.substring(startIndex,searchIndex);logEntryContent+=preStartTag+textBeforeMatch+preEndTag;logEntryContent+=searchTermReplacementStartTag+preStartTag+matchedText+','preEndTag+searchTermReplacementEndTag;if(isIe){wrappedLogEntryContent+=textBeforeMatch+searchTermReplacementStartTag+','matchedText+searchTermReplacementEndTag;}','startIndex=endTokenIndex+endToken.length;}','logEntryContent+=preStartTag+searchString.substr(startIndex)+preEndTag;if(isIe){wrappedLogEntryContent+=searchString.substr(startIndex);}}else{logEntryContent="";wrappedLogEntryContent="";var searchTermReplacementLength=searchTermReplacementStartTag.length+','this.searchTerm.length+searchTermReplacementEndTag.length;var searchTermLength=this.searchTerm.length;var searchTermLowerCase=this.searchTerm.toLowerCase();var logTextLowerCase=logEntry.formattedMessage.toLowerCase();while((searchIndex=logTextLowerCase.indexOf(searchTermLowerCase,startIndex))>-1){matchedText=escapeHtml(logEntry.formattedMessage.substr(searchIndex,this.searchTerm.length));textBeforeMatch=escapeHtml(logEntry.formattedMessage.substring(startIndex,searchIndex));var searchTermReplacement=searchTermReplacementStartTag+','preStartTag+matchedText+preEndTag+searchTermReplacementEndTag;logEntryContent+=preStartTag+textBeforeMatch+preEndTag+searchTermReplacement;if(isIe){wrappedLogEntryContent+=textBeforeMatch+searchTermReplacementStartTag+','matchedText+searchTermReplacementEndTag;}','startIndex=searchIndex+searchTermLength;}','var textAfterLastMatch=escapeHtml(logEntry.formattedMessage.substr(startIndex));logEntryContent+=preStartTag+textAfterLastMatch+preEndTag;if(isIe){wrappedLogEntryContent+=textAfterLastMatch;}}','logEntry.setContent(logEntryContent,wrappedLogEntryContent);var logEntryMatches=logEntry.getSearchMatches();this.matches=this.matches.concat(logEntryMatches);}else{logEntry.setSearchMatch(false);logEntry.setContent(logEntry.formattedMessage,logEntry.formattedMessage);}','return doesMatch;},removeMatches:function(logEntries){var matchesToRemoveCount=0;var currentMatchRemoved=false;var matchesToRemove=[];var i,iLen,j,jLen;for(i=0,iLen=this.matches.length;i<iLen;i++){for(j=0,jLen=logEntries.length;j<jLen;j++){if(this.matches[i].belongsTo(logEntries[j])){matchesToRemove.push(this.matches[i]);if(i===currentMatchIndex){currentMatchRemoved=true;}}}}','var newMatch=currentMatchRemoved?null:this.matches[currentMatchIndex];if(currentMatchRemoved){for(i=currentMatchIndex,iLen=this.matches.length;i<iLen;i++){if(this.matches[i].isVisible()&&!array_contains(matchesToRemove,this.matches[i])){newMatch=this.matches[i];break;}}}','for(i=0,iLen=matchesToRemove.length;i<iLen;i++){array_remove(this.matches,matchesToRemove[i]);matchesToRemove[i].remove();}','if(this.hasVisibleMatches()){if(newMatch===null){setCurrentMatchIndex(0);}else{var newMatchIndex=0;for(i=0,iLen=this.matches.length;i<iLen;i++){if(newMatch===this.matches[i]){newMatchIndex=i;break;}}','setCurrentMatchIndex(newMatchIndex);}}else{currentMatchIndex=null;displayNoMatches();}}};function getPageOffsetTop(el,container){var currentEl=el;var y=0;while(currentEl&&currentEl!=container){y+=currentEl.offsetTop;currentEl=currentEl.offsetParent;}','return y;}','function scrollIntoView(el){var logContainer=logMainContainer;if(!$("wrap").checked){var logContainerLeft=logContainer.scrollLeft;var logContainerRight=logContainerLeft+logContainer.offsetWidth;var elLeft=el.offsetLeft;var elRight=elLeft+el.offsetWidth;if(elLeft<logContainerLeft||elRight>logContainerRight){logContainer.scrollLeft=elLeft-(logContainer.offsetWidth-el.offsetWidth)/2;}}','var logContainerTop=logContainer.scrollTop;var logContainerBottom=logContainerTop+logContainer.offsetHeight;var elTop=getPageOffsetTop(el)-getToolBarsHeight();var elBottom=elTop+el.offsetHeight;if(elTop<logContainerTop||elBottom>logContainerBottom){logContainer.scrollTop=elTop-(logContainer.offsetHeight-el.offsetHeight)/2;}}','function Match(logEntryLevel,spanInMainDiv,spanInUnwrappedPre,spanInWrappedDiv){this.logEntryLevel=logEntryLevel;this.spanInMainDiv=spanInMainDiv;if(isIe){this.spanInUnwrappedPre=spanInUnwrappedPre;this.spanInWrappedDiv=spanInWrappedDiv;}','this.mainSpan=isIe?spanInUnwrappedPre:spanInMainDiv;}','Match.prototype={equals:function(match){return this.mainSpan===match.mainSpan;},setCurrent:function(){if(isIe){addClass(this.spanInUnwrappedPre,"currentmatch");addClass(this.spanInWrappedDiv,"currentmatch");var elementToScroll=$("wrap").checked?this.spanInWrappedDiv:this.spanInUnwrappedPre;scrollIntoView(elementToScroll);}else{addClass(this.spanInMainDiv,"currentmatch");scrollIntoView(this.spanInMainDiv);}},belongsTo:function(logEntry){if(isIe){return isDescendant(this.spanInUnwrappedPre,logEntry.unwrappedPre);}else{return isDescendant(this.spanInMainDiv,logEntry.mainDiv);}},setNotCurrent:function(){if(isIe){removeClass(this.spanInUnwrappedPre,"currentmatch");removeClass(this.spanInWrappedDiv,"currentmatch");}else{removeClass(this.spanInMainDiv,"currentmatch");}},isOrphan:function(){return isOrphan(this.mainSpan);},isVisible:function(){return getCheckBox(this.logEntryLevel).checked;},remove:function(){if(isIe){this.spanInUnwrappedPre=null;this.spanInWrappedDiv=null;}else{this.spanInMainDiv=null;}}};var currentSearch=null;var currentMatchIndex=null;function doSearch(){var searchBox=$("searchBox");var searchTerm=searchBox.value;var isRegex=$("searchRegex").checked;var isCaseSensitive=$("searchCaseSensitive").checked;var i;if(searchTerm===""){$("searchReset").disabled=true;$("searchNav").style.display="none";removeClass(document.body,"searching");removeClass(searchBox,"hasmatches");removeClass(searchBox,"nomatches");for(i=0;i<logEntries.length;i++){logEntries[i].clearSearch();logEntries[i].setContent(logEntries[i].formattedMessage,logEntries[i].formattedMessage);}','currentSearch=null;setLogContainerHeight();}else{$("searchReset").disabled=false;$("searchNav").style.display="block";var searchRegex;var regexValid;if(isRegex){try{searchRegex=isCaseSensitive?new RegExp(searchTerm,"g"):new RegExp(searchTerm,"gi");regexValid=true;replaceClass(searchBox,"validregex","invalidregex");searchBox.title="Valid regex";}catch(ex){regexValid=false;replaceClass(searchBox,"invalidregex","validregex");searchBox.title="Invalid regex: "+(ex.message?ex.message:(ex.description?ex.description:"unknown error"));return;}}else{searchBox.title="";removeClass(searchBox,"validregex");removeClass(searchBox,"invalidregex");}','addClass(document.body,"searching");currentSearch=new Search(searchTerm,isRegex,searchRegex,isCaseSensitive);for(i=0;i<logEntries.length;i++){currentSearch.applyTo(logEntries[i]);}','setLogContainerHeight();if(currentSearch.hasVisibleMatches()){setCurrentMatchIndex(0);displayMatches();}else{displayNoMatches();}}}','function updateSearchFromFilters(){if(currentSearch){if(currentSearch.hasMatches()){if(currentMatchIndex===null){currentMatchIndex=0;}','var currentMatch=currentSearch.matches[currentMatchIndex];if(currentMatch.isVisible()){displayMatches();setCurrentMatchIndex(currentMatchIndex);}else{currentMatch.setNotCurrent();var nextVisibleMatchIndex=currentSearch.getNextVisibleMatchIndex();if(nextVisibleMatchIndex>-1){setCurrentMatchIndex(nextVisibleMatchIndex);displayMatches();}else{displayNoMatches();}}}else{displayNoMatches();}}}','function refreshCurrentMatch(){if(currentSearch&&currentSearch.hasVisibleMatches()){setCurrentMatchIndex(currentMatchIndex);}}','function displayMatches(){replaceClass($("searchBox"),"hasmatches","nomatches");$("searchBox").title=""+currentSearch.matches.length+" matches found";$("searchNav").style.display="block";setLogContainerHeight();}','function displayNoMatches(){replaceClass($("searchBox"),"nomatches","hasmatches");$("searchBox").title="No matches found";$("searchNav").style.display="none";setLogContainerHeight();}','function toggleSearchEnabled(enable){enable=(typeof enable=="undefined")?!$("searchDisable").checked:enable;$("searchBox").disabled=!enable;$("searchReset").disabled=!enable;$("searchRegex").disabled=!enable;$("searchNext").disabled=!enable;$("searchPrevious").disabled=!enable;$("searchCaseSensitive").disabled=!enable;$("searchNav").style.display=(enable&&($("searchBox").value!=="")&&currentSearch&&currentSearch.hasVisibleMatches())?"block":"none";if(enable){removeClass($("search"),"greyedout");addClass(document.body,"searching");if($("searchHighlight").checked){addClass(logMainContainer,"searchhighlight");}else{removeClass(logMainContainer,"searchhighlight");}','if($("searchFilter").checked){addClass(logMainContainer,"searchfilter");}else{removeClass(logMainContainer,"searchfilter");}','$("searchDisable").checked=!enable;}else{addClass($("search"),"greyedout");removeClass(document.body,"searching");removeClass(logMainContainer,"searchhighlight");removeClass(logMainContainer,"searchfilter");}','setLogContainerHeight();}','function toggleSearchFilter(){var enable=$("searchFilter").checked;if(enable){addClass(logMainContainer,"searchfilter");}else{removeClass(logMainContainer,"searchfilter");}','refreshCurrentMatch();}','function toggleSearchHighlight(){var enable=$("searchHighlight").checked;if(enable){addClass(logMainContainer,"searchhighlight");}else{removeClass(logMainContainer,"searchhighlight");}}','function clearSearch(){$("searchBox").value="";doSearch();}','function searchNext(){if(currentSearch!==null&&currentMatchIndex!==null){currentSearch.matches[currentMatchIndex].setNotCurrent();var nextMatchIndex=currentSearch.getNextVisibleMatchIndex();if(nextMatchIndex>currentMatchIndex||confirm("Reached the end of the page. Start from the top?")){setCurrentMatchIndex(nextMatchIndex);}}}','function searchPrevious(){if(currentSearch!==null&&currentMatchIndex!==null){currentSearch.matches[currentMatchIndex].setNotCurrent();var previousMatchIndex=currentSearch.getPreviousVisibleMatchIndex();if(previousMatchIndex<currentMatchIndex||confirm("Reached the start of the page. Continue from the bottom?")){setCurrentMatchIndex(previousMatchIndex);}}}','function setCurrentMatchIndex(index){currentMatchIndex=index;currentSearch.matches[currentMatchIndex].setCurrent();}','function addClass(el,cssClass){if(!hasClass(el,cssClass)){if(el.className){el.className+=" "+cssClass;}else{el.className=cssClass;}}}','function hasClass(el,cssClass){if(el.className){var classNames=el.className.split(" ");return array_contains(classNames,cssClass);}','return false;}','function removeClass(el,cssClass){if(hasClass(el,cssClass)){var existingClasses=el.className.split(" ");var newClasses=[];for(var i=0,len=existingClasses.length;i<len;i++){if(existingClasses[i]!=cssClass){newClasses[newClasses.length]=existingClasses[i];}}','el.className=newClasses.join(" ");}}','function replaceClass(el,newCssClass,oldCssClass){removeClass(el,oldCssClass);addClass(el,newCssClass);}','function getElementsByClass(el,cssClass,tagName){var elements=el.getElementsByTagName(tagName);var matches=[];for(var i=0,len=elements.length;i<len;i++){if(hasClass(elements[i],cssClass)){matches.push(elements[i]);}}','return matches;}','function $(id){return document.getElementById(id);}','function isDescendant(node,ancestorNode){while(node!=null){if(node===ancestorNode){return true;}','node=node.parentNode;}','return false;}','function isOrphan(node){var currentNode=node;while(currentNode){if(currentNode==document.body){return false;}','currentNode=currentNode.parentNode;}','return true;}','function escapeHtml(str){return str.replace(/&/g,"&amp;").replace(/[<]/g,"&lt;").replace(/>/g,"&gt;");}','function getWindowWidth(){if(window.innerWidth){return window.innerWidth;}else if(document.documentElement&&document.documentElement.clientWidth){return document.documentElement.clientWidth;}else if(document.body){return document.body.clientWidth;}','return 0;}','function getWindowHeight(){if(window.innerHeight){return window.innerHeight;}else if(document.documentElement&&document.documentElement.clientHeight){return document.documentElement.clientHeight;}else if(document.body){return document.body.clientHeight;}','return 0;}','function getToolBarsHeight(){return $("switches").offsetHeight;}','function getChromeHeight(){var height=getToolBarsHeight();if(showCommandLine){height+=$("commandLine").offsetHeight;}','return height;}','function setLogContainerHeight(){if(logMainContainer){var windowHeight=getWindowHeight();$("body").style.height=getWindowHeight()+"px";logMainContainer.style.height=""+','Math.max(0,windowHeight-getChromeHeight())+"px";}}','function setCommandInputWidth(){if(showCommandLine){$("command").style.width=""+Math.max(0,$("commandLineContainer").offsetWidth-','($("evaluateButton").offsetWidth+13))+"px";}}','window.onresize=function(){setCommandInputWidth();setLogContainerHeight();};if(!Array.prototype.push){Array.prototype.push=function(){for(var i=0,len=arguments.length;i<len;i++){this[this.length]=arguments[i];}','return this.length;};}','if(!Array.prototype.pop){Array.prototype.pop=function(){if(this.length>0){var val=this[this.length-1];this.length=this.length-1;return val;}};}','if(!Array.prototype.shift){Array.prototype.shift=function(){if(this.length>0){var firstItem=this[0];for(var i=0,len=this.length-1;i<len;i++){this[i]=this[i+1];}','this.length=this.length-1;return firstItem;}};}','if(!Array.prototype.splice){Array.prototype.splice=function(startIndex,deleteCount){var itemsAfterDeleted=this.slice(startIndex+deleteCount);var itemsDeleted=this.slice(startIndex,startIndex+deleteCount);this.length=startIndex;var argumentsArray=[];for(var i=0,len=arguments.length;i<len;i++){argumentsArray[i]=arguments[i];}','var itemsToAppend=(argumentsArray.length>2)?itemsAfterDeleted=argumentsArray.slice(2).concat(itemsAfterDeleted):itemsAfterDeleted;for(i=0,len=itemsToAppend.length;i<len;i++){this.push(itemsToAppend[i]);}','return itemsDeleted;};}','function array_remove(arr,val){var index=-1;for(var i=0,len=arr.length;i<len;i++){if(arr[i]===val){index=i;break;}}','if(index>=0){arr.splice(index,1);return index;}else{return false;}}','function array_removeFromStart(array,numberToRemove){if(Array.prototype.splice){array.splice(0,numberToRemove);}else{for(var i=numberToRemove,len=array.length;i<len;i++){array[i-numberToRemove]=array[i];}','array.length=array.length-numberToRemove;}','return array;}','function array_contains(arr,val){for(var i=0,len=arr.length;i<len;i++){if(arr[i]==val){return true;}}','return false;}','function getErrorMessage(ex){if(ex.message){return ex.message;}else if(ex.description){return ex.description;}','return""+ex;}','function moveCaretToEnd(input){if(input.setSelectionRange){input.focus();var length=input.value.length;input.setSelectionRange(length,length);}else if(input.createTextRange){var range=input.createTextRange();range.collapse(false);range.select();}','input.focus();}','function stopPropagation(evt){if(evt.stopPropagation){evt.stopPropagation();}else if(typeof evt.cancelBubble!="undefined"){evt.cancelBubble=true;}}','function getEvent(evt){return evt?evt:event;}','function getTarget(evt){return evt.target?evt.target:evt.srcElement;}','function getRelatedTarget(evt){if(evt.relatedTarget){return evt.relatedTarget;}else if(evt.srcElement){switch(evt.type){case"mouseover":return evt.fromElement;case"mouseout":return evt.toElement;default:return evt.srcElement;}}}','function cancelKeyEvent(evt){evt.returnValue=false;stopPropagation(evt);}','function evalCommandLine(){var expr=$("command").value;evalCommand(expr);$("command").value="";}','function evalLastCommand(){if(lastCommand!=null){evalCommand(lastCommand);}}','var lastCommand=null;var commandHistory=[];var currentCommandIndex=0;function evalCommand(expr){if(appender){appender.evalCommandAndAppend(expr);}else{var prefix=">>> "+expr+"\\r\\n";try{log("INFO",prefix+eval(expr));}catch(ex){log("ERROR",prefix+"Error: "+getErrorMessage(ex));}}','if(expr!=commandHistory[commandHistory.length-1]){commandHistory.push(expr);if(appender){appender.storeCommandHistory(commandHistory);}}','currentCommandIndex=(expr==commandHistory[currentCommandIndex])?currentCommandIndex+1:commandHistory.length;lastCommand=expr;}','//]]>','</script>','<style type="text/css">','body{background-color:white;color:black;padding:0;margin:0;font-family:tahoma,verdana,arial,helvetica,sans-serif;overflow:hidden}div#switchesContainer input{margin-bottom:0}div.toolbar{border-top:solid #ffffff 1px;border-bottom:solid #aca899 1px;background-color:#f1efe7;padding:3px 5px;font-size:68.75%}div.toolbar,div#search input{font-family:tahoma,verdana,arial,helvetica,sans-serif}div.toolbar input.button{padding:0 5px;font-size:100%}div.toolbar input.hidden{display:none}div#switches input#clearButton{margin-left:20px}div#levels label{font-weight:bold}div#levels label,div#options label{margin-right:5px}div#levels label#wrapLabel{font-weight:normal}div#search label{margin-right:10px}div#search label.searchboxlabel{margin-right:0}div#search input{font-size:100%}div#search input.validregex{color:green}div#search input.invalidregex{color:red}div#search input.nomatches{color:white;background-color:#ff6666}div#search input.nomatches{color:white;background-color:#ff6666}div#searchNav{display:none}div#commandLine{display:none}div#commandLine input#command{font-size:100%;font-family:Courier New,Courier}div#commandLine input#evaluateButton{}*.greyedout{color:gray !important;border-color:gray !important}*.greyedout *.alwaysenabled{color:black}*.unselectable{-khtml-user-select:none;-moz-user-select:none;user-select:none}div#log{font-family:Courier New,Courier;font-size:75%;width:100%;overflow:auto;clear:both;position:relative}div.group{border-color:#cccccc;border-style:solid;border-width:1px 0 1px 1px;overflow:visible}div.oldIe div.group,div.oldIe div.group *,div.oldIe *.logentry{height:1%}div.group div.groupheading span.expander{border:solid black 1px;font-family:Courier New,Courier;font-size:0.833em;background-color:#eeeeee;position:relative;top:-1px;color:black;padding:0 2px;cursor:pointer;cursor:hand;height:1%}div.group div.groupcontent{margin-left:10px;padding-bottom:2px;overflow:visible}div.group div.expanded{display:block}div.group div.collapsed{display:none}*.logentry{overflow:visible;display:none;white-space:pre}span.pre{white-space:pre}pre.unwrapped{display:inline !important}pre.unwrapped pre.pre,div.wrapped pre.pre{display:inline}div.wrapped pre.pre{white-space:normal}div.wrapped{display:none}body.searching *.logentry span.currentmatch{color:white !important;background-color:green !important}body.searching div.searchhighlight *.logentry span.searchterm{color:black;background-color:yellow}div.wrap *.logentry{white-space:normal !important;border-width:0 0 1px 0;border-color:#dddddd;border-style:dotted}div.wrap #log_wrapped,#log_unwrapped{display:block}div.wrap #log_unwrapped,#log_wrapped{display:none}div.wrap *.logentry span.pre{overflow:visible;white-space:normal}div.wrap *.logentry pre.unwrapped{display:none}div.wrap *.logentry span.wrapped{display:inline}div.searchfilter *.searchnonmatch{display:none !important}div#log *.TRACE,label#label_TRACE{color:#666666}div#log *.DEBUG,label#label_DEBUG{color:green}div#log *.INFO,label#label_INFO{color:#000099}div#log *.WARN,label#label_WARN{color:#999900}div#log *.ERROR,label#label_ERROR{color:red}div#log *.FATAL,label#label_FATAL{color:#660066}div.TRACE#log *.TRACE,div.DEBUG#log *.DEBUG,div.INFO#log *.INFO,div.WARN#log *.WARN,div.ERROR#log *.ERROR,div.FATAL#log *.FATAL{display:block}div#log div.separator{background-color:#cccccc;margin:5px 0;line-height:1px}','</style>','</head>','<body id="body">','<div id="switchesContainer">','<div id="switches">','<div id="levels" class="toolbar">','Filters:','<input type="checkbox" id="switch_TRACE" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide trace messages" /><label for="switch_TRACE" id="label_TRACE">trace</label>','<input type="checkbox" id="switch_DEBUG" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide debug messages" /><label for="switch_DEBUG" id="label_DEBUG">debug</label>','<input type="checkbox" id="switch_INFO" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide info messages" /><label for="switch_INFO" id="label_INFO">info</label>','<input type="checkbox" id="switch_WARN" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide warn messages" /><label for="switch_WARN" id="label_WARN">warn</label>','<input type="checkbox" id="switch_ERROR" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide error messages" /><label for="switch_ERROR" id="label_ERROR">error</label>','<input type="checkbox" id="switch_FATAL" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide fatal messages" /><label for="switch_FATAL" id="label_FATAL">fatal</label>','<input type="checkbox" id="switch_ALL" onclick="toggleAllLevels(); applyFilters()" checked="checked" title="Show/hide all messages" /><label for="switch_ALL" id="label_ALL">all</label>','</div>','<div id="search" class="toolbar">','<label for="searchBox" class="searchboxlabel">Search:</label> <input type="text" id="searchBox" onclick="toggleSearchEnabled(true)" onkeyup="scheduleSearch()" size="20" />','<input type="button" id="searchReset" disabled="disabled" value="Reset" onclick="clearSearch()" class="button" title="Reset the search" />','<input type="checkbox" id="searchRegex" onclick="doSearch()" title="If checked, search is treated as a regular expression" /><label for="searchRegex">Regex</label>','<input type="checkbox" id="searchCaseSensitive" onclick="doSearch()" title="If checked, search is case sensitive" /><label for="searchCaseSensitive">Match case</label>','<input type="checkbox" id="searchDisable" onclick="toggleSearchEnabled()" title="Enable/disable search" /><label for="searchDisable" class="alwaysenabled">Disable</label>','<div id="searchNav">','<input type="button" id="searchNext" disabled="disabled" value="Next" onclick="searchNext()" class="button" title="Go to the next matching log entry" />','<input type="button" id="searchPrevious" disabled="disabled" value="Previous" onclick="searchPrevious()" class="button" title="Go to the previous matching log entry" />','<input type="checkbox" id="searchFilter" onclick="toggleSearchFilter()" title="If checked, non-matching log entries are filtered out" /><label for="searchFilter">Filter</label>','<input type="checkbox" id="searchHighlight" onclick="toggleSearchHighlight()" title="Highlight matched search terms" /><label for="searchHighlight" class="alwaysenabled">Highlight all</label>','</div>','</div>','<div id="options" class="toolbar">','Options:','<input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Log</label>','<input type="checkbox" id="wrap" onclick="toggleWrap()" title="Enable / disable word wrap" /><label for="wrap" id="wrapLabel">Wrap</label>','<input type="checkbox" id="newestAtTop" onclick="toggleNewestAtTop()" title="If checked, causes newest messages to appear at the top" /><label for="newestAtTop" id="newestAtTopLabel">Newest at the top</label>','<input type="checkbox" id="scrollToLatest" onclick="toggleScrollToLatest()" checked="checked" title="If checked, window automatically scrolls to a new message when it is added" /><label for="scrollToLatest" id="scrollToLatestLabel">Scroll to latest</label>','<input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="button" title="Clear all log messages"  />','<input type="button" id="hideButton" value="Hide" onclick="hide()" class="hidden button" title="Hide the console" />','<input type="button" id="closeButton" value="Close" onclick="closeWindow()" class="hidden button" title="Close the window" />','</div>','</div>','</div>','<div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>','<div id="commandLine" class="toolbar">','<div id="commandLineContainer">','<input type="text" id="command" title="Enter a JavaScript command here and hit return or press \'Evaluate\'" />','<input type="button" id="evaluateButton" value="Evaluate" class="button" title="Evaluate the command" onclick="evalCommandLine()" />','</div>','</div>','</body>','</html>',''];};var defaultCommandLineFunctions=[];ConsoleAppender=function(){};var consoleAppenderIdCounter=1;ConsoleAppender.prototype=new Appender();ConsoleAppender.prototype.create=function(inPage,container,lazyInit,initiallyMinimized,useDocumentWrite,width,height,focusConsoleWindow){var appender=this;var initialized=false;var consoleWindowCreated=false;var consoleWindowLoaded=false;var consoleClosed=false;var queuedLoggingEvents=[];var isSupported=true;var consoleAppenderId=consoleAppenderIdCounter++;initiallyMinimized=extractBooleanFromParam(initiallyMinimized,this.defaults.initiallyMinimized);lazyInit=extractBooleanFromParam(lazyInit,this.defaults.lazyInit);useDocumentWrite=extractBooleanFromParam(useDocumentWrite,this.defaults.useDocumentWrite);var newestMessageAtTop=this.defaults.newestMessageAtTop;var scrollToLatestMessage=this.defaults.scrollToLatestMessage;width=width?width:this.defaults.width;height=height?height:this.defaults.height;var maxMessages=this.defaults.maxMessages;var showCommandLine=this.defaults.showCommandLine;var commandLineObjectExpansionDepth=this.defaults.commandLineObjectExpansionDepth;var showHideButton=this.defaults.showHideButton;var showCloseButton=this.defaults.showCloseButton;var showLogEntryDeleteButtons=this.defaults.showLogEntryDeleteButtons;this.setLayout(this.defaults.layout);var init,createWindow,safeToAppend,getConsoleWindow,open;var appenderName=inPage?"InPageAppender":"PopUpAppender";var checkCanConfigure=function(configOptionName){if(consoleWindowCreated){handleError(appenderName+": configuration option '"+configOptionName+"' may not be set after the appender has been initialized");return false;}

+return true;};var consoleWindowExists=function(){return(consoleWindowLoaded&&isSupported&&!consoleClosed);};this.isNewestMessageAtTop=function(){return newestMessageAtTop;};this.setNewestMessageAtTop=function(newestMessageAtTopParam){newestMessageAtTop=bool(newestMessageAtTopParam);if(consoleWindowExists()){getConsoleWindow().setNewestAtTop(newestMessageAtTop);}};this.isScrollToLatestMessage=function(){return scrollToLatestMessage;};this.setScrollToLatestMessage=function(scrollToLatestMessageParam){scrollToLatestMessage=bool(scrollToLatestMessageParam);if(consoleWindowExists()){getConsoleWindow().setScrollToLatest(scrollToLatestMessage);}};this.getWidth=function(){return width;};this.setWidth=function(widthParam){if(checkCanConfigure("width")){width=extractStringFromParam(widthParam,width);}};this.getHeight=function(){return height;};this.setHeight=function(heightParam){if(checkCanConfigure("height")){height=extractStringFromParam(heightParam,height);}};this.getMaxMessages=function(){return maxMessages;};this.setMaxMessages=function(maxMessagesParam){maxMessages=extractIntFromParam(maxMessagesParam,maxMessages);if(consoleWindowExists()){getConsoleWindow().setMaxMessages(maxMessages);}};this.isShowCommandLine=function(){return showCommandLine;};this.setShowCommandLine=function(showCommandLineParam){showCommandLine=bool(showCommandLineParam);if(consoleWindowExists()){getConsoleWindow().setShowCommandLine(showCommandLine);}};this.isShowHideButton=function(){return showHideButton;};this.setShowHideButton=function(showHideButtonParam){showHideButton=bool(showHideButtonParam);if(consoleWindowExists()){getConsoleWindow().setShowHideButton(showHideButton);}};this.isShowCloseButton=function(){return showCloseButton;};this.setShowCloseButton=function(showCloseButtonParam){showCloseButton=bool(showCloseButtonParam);if(consoleWindowExists()){getConsoleWindow().setShowCloseButton(showCloseButton);}};this.getCommandLineObjectExpansionDepth=function(){return commandLineObjectExpansionDepth;};this.setCommandLineObjectExpansionDepth=function(commandLineObjectExpansionDepthParam){commandLineObjectExpansionDepth=extractIntFromParam(commandLineObjectExpansionDepthParam,commandLineObjectExpansionDepth);};var minimized=initiallyMinimized;this.isInitiallyMinimized=function(){return initiallyMinimized;};this.setInitiallyMinimized=function(initiallyMinimizedParam){if(checkCanConfigure("initiallyMinimized")){initiallyMinimized=bool(initiallyMinimizedParam);minimized=initiallyMinimized;}};this.isUseDocumentWrite=function(){return useDocumentWrite;};this.setUseDocumentWrite=function(useDocumentWriteParam){if(checkCanConfigure("useDocumentWrite")){useDocumentWrite=bool(useDocumentWriteParam);}};function QueuedLoggingEvent(loggingEvent,formattedMessage){this.loggingEvent=loggingEvent;this.levelName=loggingEvent.level.name;this.formattedMessage=formattedMessage;}

+QueuedLoggingEvent.prototype.append=function(){getConsoleWindow().log(this.levelName,this.formattedMessage);};function QueuedGroup(name,initiallyExpanded){this.name=name;this.initiallyExpanded=initiallyExpanded;}

+QueuedGroup.prototype.append=function(){getConsoleWindow().group(this.name,this.initiallyExpanded);};function QueuedGroupEnd(){}

+QueuedGroupEnd.prototype.append=function(){getConsoleWindow().groupEnd();};var checkAndAppend=function(){safeToAppend();if(!initialized){init();}else if(consoleClosed&&reopenWhenClosed){createWindow();}

+if(safeToAppend()){appendQueuedLoggingEvents();}};this.append=function(loggingEvent){if(isSupported){var formattedMessage=appender.getLayout().format(loggingEvent);if(this.getLayout().ignoresThrowable()){formattedMessage+=loggingEvent.getThrowableStrRep();}

+queuedLoggingEvents.push(new QueuedLoggingEvent(loggingEvent,formattedMessage));checkAndAppend();}};this.group=function(name,initiallyExpanded){if(isSupported){queuedLoggingEvents.push(new QueuedGroup(name,initiallyExpanded));checkAndAppend();}};this.groupEnd=function(){if(isSupported){queuedLoggingEvents.push(new QueuedGroupEnd());checkAndAppend();}};var appendQueuedLoggingEvents=function(){var currentLoggingEvent;while(queuedLoggingEvents.length>0){queuedLoggingEvents.shift().append();}

+if(focusConsoleWindow){getConsoleWindow().focus();}};this.setAddedToLogger=function(logger){this.loggers.push(logger);if(enabled&&!lazyInit){init();}};this.clear=function(){if(consoleWindowExists()){getConsoleWindow().clearLog();}

+queuedLoggingEvents.length=0;};this.focus=function(){if(consoleWindowExists()){getConsoleWindow().focus();}};this.focusCommandLine=function(){if(consoleWindowExists()){getConsoleWindow().focusCommandLine();}};this.focusSearch=function(){if(consoleWindowExists()){getConsoleWindow().focusSearch();}};var commandWindow=window;this.getCommandWindow=function(){return commandWindow;};this.setCommandWindow=function(commandWindowParam){commandWindow=commandWindowParam;};this.executeLastCommand=function(){if(consoleWindowExists()){getConsoleWindow().evalLastCommand();}};var commandLayout=new PatternLayout("%m");this.getCommandLayout=function(){return commandLayout;};this.setCommandLayout=function(commandLayoutParam){commandLayout=commandLayoutParam;};this.evalCommandAndAppend=function(expr){var commandReturnValue={appendResult:true,isError:false};var commandOutput="";try{var result,i;if(!commandWindow.eval&&commandWindow.execScript){commandWindow.execScript("null");}

+var commandLineFunctionsHash={};for(i=0,len=commandLineFunctions.length;i<len;i++){commandLineFunctionsHash[commandLineFunctions[i][0]]=commandLineFunctions[i][1];}

+var objectsToRestore=[];var addObjectToRestore=function(name){objectsToRestore.push([name,commandWindow[name]]);};addObjectToRestore("appender");commandWindow.appender=appender;addObjectToRestore("commandReturnValue");commandWindow.commandReturnValue=commandReturnValue;addObjectToRestore("commandLineFunctionsHash");commandWindow.commandLineFunctionsHash=commandLineFunctionsHash;var addFunctionToWindow=function(name){addObjectToRestore(name);commandWindow[name]=function(){return this.commandLineFunctionsHash[name](appender,arguments,commandReturnValue);};};for(i=0,len=commandLineFunctions.length;i<len;i++){addFunctionToWindow(commandLineFunctions[i][0]);}

+if(commandWindow===window&&commandWindow.execScript){addObjectToRestore("evalExpr");addObjectToRestore("result");window.evalExpr=expr;commandWindow.execScript("window.result=eval(window.evalExpr);");result=window.result;}else{result=commandWindow.eval(expr);}

+commandOutput=isUndefined(result)?result:formatObjectExpansion(result,commandLineObjectExpansionDepth);for(i=0,len=objectsToRestore.length;i<len;i++){commandWindow[objectsToRestore[i][0]]=objectsToRestore[i][1];}}catch(ex){commandOutput="Error evaluating command: "+getExceptionStringRep(ex);commandReturnValue.isError=true;}

+if(commandReturnValue.appendResult){var message=">>> "+expr;if(!isUndefined(commandOutput)){message+=newLine+commandOutput;}

+var level=commandReturnValue.isError?Level.ERROR:Level.INFO;var loggingEvent=new LoggingEvent(null,new Date(),level,[message],null);var mainLayout=this.getLayout();this.setLayout(commandLayout);this.append(loggingEvent);this.setLayout(mainLayout);}};var commandLineFunctions=defaultCommandLineFunctions.concat([]);this.addCommandLineFunction=function(functionName,commandLineFunction){commandLineFunctions.push([functionName,commandLineFunction]);};var commandHistoryCookieName="log4javascriptCommandHistory";this.storeCommandHistory=function(commandHistory){setCookie(commandHistoryCookieName,commandHistory.join(","));};var writeHtml=function(doc){var lines=getConsoleHtmlLines();doc.open();for(var i=0,len=lines.length;i<len;i++){doc.writeln(lines[i]);}

+doc.close();};this.setEventTypes(["load","unload"]);var consoleWindowLoadHandler=function(){var win=getConsoleWindow();win.setAppender(appender);win.setNewestAtTop(newestMessageAtTop);win.setScrollToLatest(scrollToLatestMessage);win.setMaxMessages(maxMessages);win.setShowCommandLine(showCommandLine);win.setShowHideButton(showHideButton);win.setShowCloseButton(showCloseButton);win.setMainWindow(window);var storedValue=getCookie(commandHistoryCookieName);if(storedValue){win.commandHistory=storedValue.split(",");win.currentCommandIndex=win.commandHistory.length;}

+appender.dispatchEvent("load",{"win":win});};this.unload=function(){logLog.debug("unload "+this+", caller: "+this.unload.caller);if(!consoleClosed){logLog.debug("really doing unload "+this);consoleClosed=true;consoleWindowLoaded=false;consoleWindowCreated=false;appender.dispatchEvent("unload",{});}};var pollConsoleWindow=function(windowTest,interval,successCallback,errorMessage){function doPoll(){try{if(consoleClosed){clearInterval(poll);}

+if(windowTest(getConsoleWindow())){clearInterval(poll);successCallback();}}catch(ex){clearInterval(poll);isSupported=false;handleError(errorMessage,ex);}}

+var poll=setInterval(doPoll,interval);};var getConsoleUrl=function(){var documentDomainSet=(document.domain!=location.hostname);return useDocumentWrite?"":getBaseUrl()+"console.html"+

+(documentDomainSet?"?log4javascript_domain="+escape(document.domain):"");};if(inPage){var containerElement=null;var cssProperties=[];this.addCssProperty=function(name,value){if(checkCanConfigure("cssProperties")){cssProperties.push([name,value]);}};var windowCreationStarted=false;var iframeContainerDiv;var iframeId=uniqueId+"_InPageAppender_"+consoleAppenderId;this.hide=function(){if(initialized&&consoleWindowCreated){if(consoleWindowExists()){getConsoleWindow().$("command").blur();}

+iframeContainerDiv.style.display="none";minimized=true;}};this.show=function(){if(initialized){if(consoleWindowCreated){iframeContainerDiv.style.display="block";this.setShowCommandLine(showCommandLine);minimized=false;}else if(!windowCreationStarted){createWindow(true);}}};this.isVisible=function(){return!minimized&&!consoleClosed;};this.close=function(fromButton){if(!consoleClosed&&(!fromButton||confirm("This will permanently remove the console from the page. No more messages will be logged. Do you wish to continue?"))){iframeContainerDiv.parentNode.removeChild(iframeContainerDiv);this.unload();}};open=function(){var initErrorMessage="InPageAppender.open: unable to create console iframe";function finalInit(){try{if(!initiallyMinimized){appender.show();}

+consoleWindowLoadHandler();consoleWindowLoaded=true;appendQueuedLoggingEvents();}catch(ex){isSupported=false;handleError(initErrorMessage,ex);}}

+function writeToDocument(){try{var windowTest=function(win){return isLoaded(win);};if(useDocumentWrite){writeHtml(getConsoleWindow().document);}

+if(windowTest(getConsoleWindow())){finalInit();}else{pollConsoleWindow(windowTest,100,finalInit,initErrorMessage);}}catch(ex){isSupported=false;handleError(initErrorMessage,ex);}}

+minimized=false;iframeContainerDiv=containerElement.appendChild(document.createElement("div"));iframeContainerDiv.style.width=width;iframeContainerDiv.style.height=height;iframeContainerDiv.style.border="solid gray 1px";for(var i=0,len=cssProperties.length;i<len;i++){iframeContainerDiv.style[cssProperties[i][0]]=cssProperties[i][1];}

+var iframeSrc=useDocumentWrite?"":" src='"+getConsoleUrl()+"'";iframeContainerDiv.innerHTML="<iframe id='"+iframeId+"' name='"+iframeId+"' width='100%' height='100%' frameborder='0'"+iframeSrc+" scrolling='no'></iframe>";consoleClosed=false;var iframeDocumentExistsTest=function(win){try{return bool(win)&&bool(win.document);}catch(ex){return false;}};if(iframeDocumentExistsTest(getConsoleWindow())){writeToDocument();}else{pollConsoleWindow(iframeDocumentExistsTest,100,writeToDocument,initErrorMessage);}

+consoleWindowCreated=true;};createWindow=function(show){if(show||!initiallyMinimized){var pageLoadHandler=function(){if(!container){containerElement=document.createElement("div");containerElement.style.position="fixed";containerElement.style.left="0";containerElement.style.right="0";containerElement.style.bottom="0";document.body.appendChild(containerElement);appender.addCssProperty("borderWidth","1px 0 0 0");appender.addCssProperty("zIndex",1000000);open();}else{try{var el=document.getElementById(container);if(el.nodeType==1){containerElement=el;}

+open();}catch(ex){handleError("InPageAppender.init: invalid container element '"+container+"' supplied",ex);}}};if(pageLoaded&&container&&container.appendChild){containerElement=container;open();}else if(pageLoaded){pageLoadHandler();}else{log4javascript.addEventListener("load",pageLoadHandler);}

+windowCreationStarted=true;}};init=function(){createWindow();initialized=true;};getConsoleWindow=function(){var iframe=window.frames[iframeId];if(iframe){return iframe;}};safeToAppend=function(){if(isSupported&&!consoleClosed){if(consoleWindowCreated&&!consoleWindowLoaded&&getConsoleWindow()&&isLoaded(getConsoleWindow())){consoleWindowLoaded=true;}

+return consoleWindowLoaded;}

+return false;};}else{var useOldPopUp=appender.defaults.useOldPopUp;var complainAboutPopUpBlocking=appender.defaults.complainAboutPopUpBlocking;var reopenWhenClosed=this.defaults.reopenWhenClosed;this.isUseOldPopUp=function(){return useOldPopUp;};this.setUseOldPopUp=function(useOldPopUpParam){if(checkCanConfigure("useOldPopUp")){useOldPopUp=bool(useOldPopUpParam);}};this.isComplainAboutPopUpBlocking=function(){return complainAboutPopUpBlocking;};this.setComplainAboutPopUpBlocking=function(complainAboutPopUpBlockingParam){if(checkCanConfigure("complainAboutPopUpBlocking")){complainAboutPopUpBlocking=bool(complainAboutPopUpBlockingParam);}};this.isFocusPopUp=function(){return focusConsoleWindow;};this.setFocusPopUp=function(focusPopUpParam){focusConsoleWindow=bool(focusPopUpParam);};this.isReopenWhenClosed=function(){return reopenWhenClosed;};this.setReopenWhenClosed=function(reopenWhenClosedParam){reopenWhenClosed=bool(reopenWhenClosedParam);};this.close=function(){logLog.debug("close "+this);try{popUp.close();this.unload();}catch(ex){}};this.hide=function(){logLog.debug("hide "+this);if(consoleWindowExists()){this.close();}};this.show=function(){logLog.debug("show "+this);if(!consoleWindowCreated){open();}};this.isVisible=function(){return safeToAppend();};var popUp;open=function(){var windowProperties="width="+width+",height="+height+",status,resizable";var frameInfo="";try{var frameEl=window.frameElement;if(frameEl){frameInfo="_"+frameEl.tagName+"_"+(frameEl.name||frameEl.id||"");}}catch(e){frameInfo="_inaccessibleParentFrame";}

+var windowName="PopUp_"+location.host.replace(/[^a-z0-9]/gi,"_")+"_"+consoleAppenderId+frameInfo;if(!useOldPopUp||!useDocumentWrite){windowName=windowName+"_"+uniqueId;}

+var checkPopUpClosed=function(win){if(consoleClosed){return true;}else{try{return bool(win)&&win.closed;}catch(ex){}}

+return false;};var popUpClosedCallback=function(){if(!consoleClosed){appender.unload();}};function finalInit(){getConsoleWindow().setCloseIfOpenerCloses(!useOldPopUp||!useDocumentWrite);consoleWindowLoadHandler();consoleWindowLoaded=true;appendQueuedLoggingEvents();pollConsoleWindow(checkPopUpClosed,500,popUpClosedCallback,"PopUpAppender.checkPopUpClosed: error checking pop-up window");}

+try{popUp=window.open(getConsoleUrl(),windowName,windowProperties);consoleClosed=false;consoleWindowCreated=true;if(popUp&&popUp.document){if(useDocumentWrite&&useOldPopUp&&isLoaded(popUp)){popUp.mainPageReloaded();finalInit();}else{if(useDocumentWrite){writeHtml(popUp.document);}

+var popUpLoadedTest=function(win){return bool(win)&&isLoaded(win);};if(isLoaded(popUp)){finalInit();}else{pollConsoleWindow(popUpLoadedTest,100,finalInit,"PopUpAppender.init: unable to create console window");}}}else{isSupported=false;logLog.warn("PopUpAppender.init: pop-ups blocked, please unblock to use PopUpAppender");if(complainAboutPopUpBlocking){handleError("log4javascript: pop-up windows appear to be blocked. Please unblock them to use pop-up logging.");}}}catch(ex){handleError("PopUpAppender.init: error creating pop-up",ex);}};createWindow=function(){if(!initiallyMinimized){open();}};init=function(){createWindow();initialized=true;};getConsoleWindow=function(){return popUp;};safeToAppend=function(){if(isSupported&&!isUndefined(popUp)&&!consoleClosed){if(popUp.closed||(consoleWindowLoaded&&isUndefined(popUp.closed))){appender.unload();logLog.debug("PopUpAppender: pop-up closed");return false;}

+if(!consoleWindowLoaded&&isLoaded(popUp)){consoleWindowLoaded=true;}}

+return isSupported&&consoleWindowLoaded&&!consoleClosed;};}

+this.getConsoleWindow=getConsoleWindow;};ConsoleAppender.addGlobalCommandLineFunction=function(functionName,commandLineFunction){defaultCommandLineFunctions.push([functionName,commandLineFunction]);};function PopUpAppender(lazyInit,initiallyMinimized,useDocumentWrite,width,height){this.create(false,null,lazyInit,initiallyMinimized,useDocumentWrite,width,height,this.defaults.focusPopUp);}

+PopUpAppender.prototype=new ConsoleAppender();PopUpAppender.prototype.defaults={layout:new PatternLayout("%d{HH:mm:ss} %-5p - %m{1}%n"),initiallyMinimized:false,focusPopUp:false,lazyInit:true,useOldPopUp:true,complainAboutPopUpBlocking:true,newestMessageAtTop:false,scrollToLatestMessage:true,width:"600",height:"400",reopenWhenClosed:false,maxMessages:null,showCommandLine:true,commandLineObjectExpansionDepth:1,showHideButton:false,showCloseButton:true,showLogEntryDeleteButtons:true,useDocumentWrite:true};PopUpAppender.prototype.toString=function(){return"PopUpAppender";};log4javascript.PopUpAppender=PopUpAppender;function InPageAppender(container,lazyInit,initiallyMinimized,useDocumentWrite,width,height){this.create(true,container,lazyInit,initiallyMinimized,useDocumentWrite,width,height,false);}

+InPageAppender.prototype=new ConsoleAppender();InPageAppender.prototype.defaults={layout:new PatternLayout("%d{HH:mm:ss} %-5p - %m{1}%n"),initiallyMinimized:false,lazyInit:true,newestMessageAtTop:false,scrollToLatestMessage:true,width:"100%",height:"220px",maxMessages:null,showCommandLine:true,commandLineObjectExpansionDepth:1,showHideButton:false,showCloseButton:false,showLogEntryDeleteButtons:true,useDocumentWrite:true};InPageAppender.prototype.toString=function(){return"InPageAppender";};log4javascript.InPageAppender=InPageAppender;log4javascript.InlineAppender=InPageAppender;})();function padWithSpaces(str,len){if(str.length<len){var spaces=[];var numberOfSpaces=Math.max(0,len-str.length);for(var i=0;i<numberOfSpaces;i++){spaces[i]=" ";}

+str+=spaces.join("");}

+return str;}

+(function(){function dir(obj){var maxLen=0;for(var p in obj){maxLen=Math.max(toStr(p).length,maxLen);}

+var propList=[];for(p in obj){var propNameStr="  "+padWithSpaces(toStr(p),maxLen+2);var propVal;try{propVal=splitIntoLines(toStr(obj[p])).join(padWithSpaces(newLine,maxLen+6));}catch(ex){propVal="[Error obtaining property. Details: "+getExceptionMessage(ex)+"]";}

+propList.push(propNameStr+propVal);}

+return propList.join(newLine);}

+var nodeTypes={ELEMENT_NODE:1,ATTRIBUTE_NODE:2,TEXT_NODE:3,CDATA_SECTION_NODE:4,ENTITY_REFERENCE_NODE:5,ENTITY_NODE:6,PROCESSING_INSTRUCTION_NODE:7,COMMENT_NODE:8,DOCUMENT_NODE:9,DOCUMENT_TYPE_NODE:10,DOCUMENT_FRAGMENT_NODE:11,NOTATION_NODE:12};var preFormattedElements=["script","pre"];var emptyElements=["br","img","hr","param","link","area","input","col","base","meta"];var indentationUnit="  ";function getXhtml(rootNode,includeRootNode,indentation,startNewLine,preformatted){includeRootNode=(typeof includeRootNode=="undefined")?true:!!includeRootNode;if(typeof indentation!="string"){indentation="";}

+startNewLine=!!startNewLine;preformatted=!!preformatted;var xhtml;function isWhitespace(node){return((node.nodeType==nodeTypes.TEXT_NODE)&&/^[ \t\r\n]*$/.test(node.nodeValue));}

+function fixAttributeValue(attrValue){return attrValue.toString().replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/"/g,"&quot;");}

+function getStyleAttributeValue(el){var stylePairs=el.style.cssText.split(";");var styleValue="";var isFirst=true;for(var j=0,len=stylePairs.length;j<len;j++){var nameValueBits=stylePairs[j].split(":");var props=[];if(!/^\s*$/.test(nameValueBits[0])){props.push(trim(nameValueBits[0]).toLowerCase()+":"+trim(nameValueBits[1]));}

+styleValue=props.join(";");}

+return styleValue;}

+function getNamespace(el){if(el.prefix){return el.prefix;}else if(el.outerHTML){var regex=new RegExp("<([^:]+):"+el.tagName+"[^>]*>","i");if(regex.test(el.outerHTML)){return RegExp.$1.toLowerCase();}}

+return"";}

+var lt="<";var gt=">";if(includeRootNode&&rootNode.nodeType!=nodeTypes.DOCUMENT_FRAGMENT_NODE){switch(rootNode.nodeType){case nodeTypes.ELEMENT_NODE:var tagName=rootNode.tagName.toLowerCase();xhtml=startNewLine?newLine+indentation:"";xhtml+=lt;var prefix=getNamespace(rootNode);var hasPrefix=!!prefix;if(hasPrefix){xhtml+=prefix+":";}

+xhtml+=tagName;for(i=0,len=rootNode.attributes.length;i<len;i++){var currentAttr=rootNode.attributes[i];if(!currentAttr.specified||currentAttr.nodeValue===null||currentAttr.nodeName.toLowerCase()==="style"||typeof currentAttr.nodeValue!=="string"||currentAttr.nodeName.indexOf("_moz")===0){continue;}

+xhtml+=" "+currentAttr.nodeName.toLowerCase()+"=\"";xhtml+=fixAttributeValue(currentAttr.nodeValue);xhtml+="\"";}

+if(rootNode.style.cssText){var styleValue=getStyleAttributeValue(rootNode);if(styleValue!==""){xhtml+=" style=\""+getStyleAttributeValue(rootNode)+"\"";}}

+if(array_contains(emptyElements,tagName)||(hasPrefix&&!rootNode.hasChildNodes())){xhtml+="/"+gt;}else{xhtml+=gt;var childStartNewLine=!(rootNode.childNodes.length===1&&rootNode.childNodes[0].nodeType===nodeTypes.TEXT_NODE);var childPreformatted=array_contains(preFormattedElements,tagName);for(var i=0,len=rootNode.childNodes.length;i<len;i++){xhtml+=getXhtml(rootNode.childNodes[i],true,indentation+indentationUnit,childStartNewLine,childPreformatted);}

+var endTag=lt+"/"+tagName+gt;xhtml+=childStartNewLine?newLine+indentation+endTag:endTag;}

+return xhtml;case nodeTypes.TEXT_NODE:if(isWhitespace(rootNode)){xhtml="";}else{if(preformatted){xhtml=rootNode.nodeValue;}else{var lines=splitIntoLines(trim(rootNode.nodeValue));var trimmedLines=[];for(var i=0,len=lines.length;i<len;i++){trimmedLines[i]=trim(lines[i]);}

+xhtml=trimmedLines.join(newLine+indentation);}

+if(startNewLine){xhtml=newLine+indentation+xhtml;}}

+return xhtml;case nodeTypes.CDATA_SECTION_NODE:return"<![CDA"+"TA["+rootNode.nodeValue+"]"+"]>"+newLine;case nodeTypes.DOCUMENT_NODE:xhtml="";for(var i=0,len=rootNode.childNodes.length;i<len;i++){xhtml+=getXhtml(rootNode.childNodes[i],true,indentation);}

+return xhtml;default:return"";}}else{xhtml="";for(var i=0,len=rootNode.childNodes.length;i<len;i++){xhtml+=getXhtml(rootNode.childNodes[i],true,indentation+indentationUnit);}

+return xhtml;}}

+function createCommandLineFunctions(){ConsoleAppender.addGlobalCommandLineFunction("$",function(appender,args,returnValue){return document.getElementById(args[0]);});ConsoleAppender.addGlobalCommandLineFunction("dir",function(appender,args,returnValue){var lines=[];for(var i=0,len=args.length;i<len;i++){lines[i]=dir(args[i]);}

+return lines.join(newLine+newLine);});ConsoleAppender.addGlobalCommandLineFunction("dirxml",function(appender,args,returnValue){var lines=[];for(var i=0,len=args.length;i<len;i++){var win=appender.getCommandWindow();lines[i]=getXhtml(args[i]);}

+return lines.join(newLine+newLine);});ConsoleAppender.addGlobalCommandLineFunction("cd",function(appender,args,returnValue){var win,message;if(args.length===0||args[0]===""){win=window;message="Command line set to run in main window";}else{if(args[0].window==args[0]){win=args[0];message="Command line set to run in frame '"+args[0].name+"'";}else{win=window.frames[args[0]];if(win){message="Command line set to run in frame '"+args[0]+"'";}else{returnValue.isError=true;message="Frame '"+args[0]+"' does not exist";win=appender.getCommandWindow();}}}

+appender.setCommandWindow(win);return message;});ConsoleAppender.addGlobalCommandLineFunction("clear",function(appender,args,returnValue){returnValue.appendResult=false;appender.clear();});ConsoleAppender.addGlobalCommandLineFunction("keys",function(appender,args,returnValue){var keys=[];for(var k in args[0]){keys.push(k);}

+return keys;});ConsoleAppender.addGlobalCommandLineFunction("values",function(appender,args,returnValue){var values=[];for(var k in args[0]){try{values.push(args[0][k]);}catch(ex){logLog.warn("values(): Unable to obtain value for key "+k+". Details: "+getExceptionMessage(ex));}}

+return values;});ConsoleAppender.addGlobalCommandLineFunction("expansionDepth",function(appender,args,returnValue){var expansionDepth=parseInt(args[0],10);if(isNaN(expansionDepth)||expansionDepth<0){returnValue.isError=true;return""+args[0]+" is not a valid expansion depth";}else{appender.setCommandLineObjectExpansionDepth(expansionDepth);return"Object expansion depth set to "+expansionDepth;}});}

+function init(){createCommandLineFunctions();}

+init();})();log4javascript.setDocumentReady=function(){pageLoaded=true;log4javascript.dispatchEvent("load",{});};if(window.addEventListener){window.addEventListener("load",log4javascript.setDocumentReady,false);}else if(window.attachEvent){window.attachEvent("onload",log4javascript.setDocumentReady);}else{var oldOnload=window.onload;if(typeof window.onload!="function"){window.onload=log4javascript.setDocumentReady;}else{window.onload=function(evt){if(oldOnload){oldOnload(evt);}

+log4javascript.setDocumentReady();};}}

+window.log4javascript=log4javascript;return log4javascript;})();

diff --git a/xos/core/static/log4javascript-1.4.6/log4javascript_uncompressed.js b/xos/core/static/log4javascript-1.4.6/log4javascript_uncompressed.js
new file mode 100644
index 0000000..a644e3b
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/log4javascript_uncompressed.js
@@ -0,0 +1,5879 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+/**

+ * log4javascript

+ *

+ * log4javascript is a logging framework for JavaScript based on log4j

+ * for Java. This file contains all core log4javascript code and is the only

+ * file required to use log4javascript, unless you require support for

+ * document.domain, in which case you will also need console.html, which must be

+ * stored in the same directory as the main log4javascript.js file.

+ *

+ * Author: Tim Down <tim@log4javascript.org>

+ * Version: 1.4.6

+ * Edition: log4javascript

+ * Build date: 19 March 2013

+ * Website: http://log4javascript.org

+ */

+

+/* -------------------------------------------------------------------------- */

+// Array-related stuff

+

+// Next three methods are solely for IE5, which is missing them

+if (!Array.prototype.push) {

+	Array.prototype.push = function() {

+		for (var i = 0, len = arguments.length; i < len; i++){

+			this[this.length] = arguments[i];

+		}

+		return this.length;

+	};

+}

+

+if (!Array.prototype.shift) {

+	Array.prototype.shift = function() {

+		if (this.length > 0) {

+			var firstItem = this[0];

+			for (var i = 0, len = this.length - 1; i < len; i++) {

+				this[i] = this[i + 1];

+			}

+			this.length = this.length - 1;

+			return firstItem;

+		}

+	};

+}

+

+if (!Array.prototype.splice) {

+	Array.prototype.splice = function(startIndex, deleteCount) {

+		var itemsAfterDeleted = this.slice(startIndex + deleteCount);

+		var itemsDeleted = this.slice(startIndex, startIndex + deleteCount);

+		this.length = startIndex;

+		// Copy the arguments into a proper Array object

+		var argumentsArray = [];

+		for (var i = 0, len = arguments.length; i < len; i++) {

+			argumentsArray[i] = arguments[i];

+		}

+		var itemsToAppend = (argumentsArray.length > 2) ?

+			itemsAfterDeleted = argumentsArray.slice(2).concat(itemsAfterDeleted) : itemsAfterDeleted;

+		for (i = 0, len = itemsToAppend.length; i < len; i++) {

+			this.push(itemsToAppend[i]);

+		}

+		return itemsDeleted;

+	};

+}

+

+/* -------------------------------------------------------------------------- */

+

+var log4javascript = (function() {

+

+	function isUndefined(obj) {

+		return typeof obj == "undefined";

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// Custom event support

+

+	function EventSupport() {}

+

+	EventSupport.prototype = {

+		eventTypes: [],

+		eventListeners: {},

+		setEventTypes: function(eventTypesParam) {

+			if (eventTypesParam instanceof Array) {

+				this.eventTypes = eventTypesParam;

+				this.eventListeners = {};

+				for (var i = 0, len = this.eventTypes.length; i < len; i++) {

+					this.eventListeners[this.eventTypes[i]] = [];

+				}

+			} else {

+				handleError("log4javascript.EventSupport [" + this + "]: setEventTypes: eventTypes parameter must be an Array");

+			}

+		},

+

+		addEventListener: function(eventType, listener) {

+			if (typeof listener == "function") {

+				if (!array_contains(this.eventTypes, eventType)) {

+					handleError("log4javascript.EventSupport [" + this + "]: addEventListener: no event called '" + eventType + "'");

+				}

+				this.eventListeners[eventType].push(listener);

+			} else {

+				handleError("log4javascript.EventSupport [" + this + "]: addEventListener: listener must be a function");

+			}

+		},

+

+		removeEventListener: function(eventType, listener) {

+			if (typeof listener == "function") {

+				if (!array_contains(this.eventTypes, eventType)) {

+					handleError("log4javascript.EventSupport [" + this + "]: removeEventListener: no event called '" + eventType + "'");

+				}

+				array_remove(this.eventListeners[eventType], listener);

+			} else {

+				handleError("log4javascript.EventSupport [" + this + "]: removeEventListener: listener must be a function");

+			}

+		},

+

+		dispatchEvent: function(eventType, eventArgs) {

+			if (array_contains(this.eventTypes, eventType)) {

+				var listeners = this.eventListeners[eventType];

+				for (var i = 0, len = listeners.length; i < len; i++) {

+					listeners[i](this, eventType, eventArgs);

+				}

+			} else {

+				handleError("log4javascript.EventSupport [" + this + "]: dispatchEvent: no event called '" + eventType + "'");

+			}

+		}

+	};

+

+	/* -------------------------------------------------------------------------- */

+

+	var applicationStartDate = new Date();

+	var uniqueId = "log4javascript_" + applicationStartDate.getTime() + "_" +

+		Math.floor(Math.random() * 100000000);

+	var emptyFunction = function() {};

+	var newLine = "\r\n";

+	var pageLoaded = false;

+

+	// Create main log4javascript object; this will be assigned public properties

+	function Log4JavaScript() {}

+	Log4JavaScript.prototype = new EventSupport();

+

+	log4javascript = new Log4JavaScript();

+	log4javascript.version = "1.4.6";

+	log4javascript.edition = "log4javascript";

+

+	/* -------------------------------------------------------------------------- */

+	// Utility functions

+

+	function toStr(obj) {

+		if (obj && obj.toString) {

+			return obj.toString();

+		} else {

+			return String(obj);

+		}

+	}

+

+	function getExceptionMessage(ex) {

+		if (ex.message) {

+			return ex.message;

+		} else if (ex.description) {

+			return ex.description;

+		} else {

+			return toStr(ex);

+		}

+	}

+

+	// Gets the portion of the URL after the last slash

+	function getUrlFileName(url) {

+		var lastSlashIndex = Math.max(url.lastIndexOf("/"), url.lastIndexOf("\\"));

+		return url.substr(lastSlashIndex + 1);

+	}

+

+	// Returns a nicely formatted representation of an error

+	function getExceptionStringRep(ex) {

+		if (ex) {

+			var exStr = "Exception: " + getExceptionMessage(ex);

+			try {

+				if (ex.lineNumber) {

+					exStr += " on line number " + ex.lineNumber;

+				}

+				if (ex.fileName) {

+					exStr += " in file " + getUrlFileName(ex.fileName);

+				}

+			} catch (localEx) {

+				logLog.warn("Unable to obtain file and line information for error");

+			}

+			if (showStackTraces && ex.stack) {

+				exStr += newLine + "Stack trace:" + newLine + ex.stack;

+			}

+			return exStr;

+		}

+		return null;

+	}

+

+	function bool(obj) {

+		return Boolean(obj);

+	}

+

+	function trim(str) {

+		return str.replace(/^\s+/, "").replace(/\s+$/, "");

+	}

+

+	function splitIntoLines(text) {

+		// Ensure all line breaks are \n only

+		var text2 = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");

+		return text2.split("\n");

+	}

+

+	var urlEncode = (typeof window.encodeURIComponent != "undefined") ?

+		function(str) {

+			return encodeURIComponent(str);

+		}: 

+		function(str) {

+			return escape(str).replace(/\+/g, "%2B").replace(/"/g, "%22").replace(/'/g, "%27").replace(/\//g, "%2F").replace(/=/g, "%3D");

+		};

+

+	var urlDecode = (typeof window.decodeURIComponent != "undefined") ?

+		function(str) {

+			return decodeURIComponent(str);

+		}: 

+		function(str) {

+			return unescape(str).replace(/%2B/g, "+").replace(/%22/g, "\"").replace(/%27/g, "'").replace(/%2F/g, "/").replace(/%3D/g, "=");

+		};

+

+	function array_remove(arr, val) {

+		var index = -1;

+		for (var i = 0, len = arr.length; i < len; i++) {

+			if (arr[i] === val) {

+				index = i;

+				break;

+			}

+		}

+		if (index >= 0) {

+			arr.splice(index, 1);

+			return true;

+		} else {

+			return false;

+		}

+	}

+

+	function array_contains(arr, val) {

+		for(var i = 0, len = arr.length; i < len; i++) {

+			if (arr[i] == val) {

+				return true;

+			}

+		}

+		return false;

+	}

+

+	function extractBooleanFromParam(param, defaultValue) {

+		if (isUndefined(param)) {

+			return defaultValue;

+		} else {

+			return bool(param);

+		}

+	}

+

+	function extractStringFromParam(param, defaultValue) {

+		if (isUndefined(param)) {

+			return defaultValue;

+		} else {

+			return String(param);

+		}

+	}

+

+	function extractIntFromParam(param, defaultValue) {

+		if (isUndefined(param)) {

+			return defaultValue;

+		} else {

+			try {

+				var value = parseInt(param, 10);

+				return isNaN(value) ? defaultValue : value;

+			} catch (ex) {

+				logLog.warn("Invalid int param " + param, ex);

+				return defaultValue;

+			}

+		}

+	}

+

+	function extractFunctionFromParam(param, defaultValue) {

+		if (typeof param == "function") {

+			return param;

+		} else {

+			return defaultValue;

+		}

+	}

+

+	function isError(err) {

+		return (err instanceof Error);

+	}

+

+	if (!Function.prototype.apply){

+		Function.prototype.apply = function(obj, args) {

+			var methodName = "__apply__";

+			if (typeof obj[methodName] != "undefined") {

+				methodName += String(Math.random()).substr(2);

+			}

+			obj[methodName] = this;

+

+			var argsStrings = [];

+			for (var i = 0, len = args.length; i < len; i++) {

+				argsStrings[i] = "args[" + i + "]";

+			}

+			var script = "obj." + methodName + "(" + argsStrings.join(",") + ")";

+			var returnValue = eval(script);

+			delete obj[methodName];

+			return returnValue;

+		};

+	}

+

+	if (!Function.prototype.call){

+		Function.prototype.call = function(obj) {

+			var args = [];

+			for (var i = 1, len = arguments.length; i < len; i++) {

+				args[i - 1] = arguments[i];

+			}

+			return this.apply(obj, args);

+		};

+	}

+

+	function getListenersPropertyName(eventName) {

+		return "__log4javascript_listeners__" + eventName;

+	}

+

+	function addEvent(node, eventName, listener, useCapture, win) {

+		win = win ? win : window;

+		if (node.addEventListener) {

+			node.addEventListener(eventName, listener, useCapture);

+		} else if (node.attachEvent) {

+			node.attachEvent("on" + eventName, listener);

+		} else {

+			var propertyName = getListenersPropertyName(eventName);

+			if (!node[propertyName]) {

+				node[propertyName] = [];

+				// Set event handler

+				node["on" + eventName] = function(evt) {

+					evt = getEvent(evt, win);

+					var listenersPropertyName = getListenersPropertyName(eventName);

+

+					// Clone the array of listeners to leave the original untouched

+					var listeners = this[listenersPropertyName].concat([]);

+					var currentListener;

+

+					// Call each listener in turn

+					while ((currentListener = listeners.shift())) {

+						currentListener.call(this, evt);

+					}

+				};

+			}

+			node[propertyName].push(listener);

+		}

+	}

+

+	function removeEvent(node, eventName, listener, useCapture) {

+		if (node.removeEventListener) {

+			node.removeEventListener(eventName, listener, useCapture);

+		} else if (node.detachEvent) {

+			node.detachEvent("on" + eventName, listener);

+		} else {

+			var propertyName = getListenersPropertyName(eventName);

+			if (node[propertyName]) {

+				array_remove(node[propertyName], listener);

+			}

+		}

+	}

+

+	function getEvent(evt, win) {

+		win = win ? win : window;

+		return evt ? evt : win.event;

+	}

+

+	function stopEventPropagation(evt) {

+		if (evt.stopPropagation) {

+			evt.stopPropagation();

+		} else if (typeof evt.cancelBubble != "undefined") {

+			evt.cancelBubble = true;

+		}

+		evt.returnValue = false;

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// Simple logging for log4javascript itself

+

+	var logLog = {

+		quietMode: false,

+

+		debugMessages: [],

+

+		setQuietMode: function(quietMode) {

+			this.quietMode = bool(quietMode);

+		},

+

+		numberOfErrors: 0,

+

+		alertAllErrors: false,

+

+		setAlertAllErrors: function(alertAllErrors) {

+			this.alertAllErrors = alertAllErrors;

+		},

+

+		debug: function(message) {

+			this.debugMessages.push(message);

+		},

+

+		displayDebug: function() {

+			alert(this.debugMessages.join(newLine));

+		},

+

+		warn: function(message, exception) {

+		},

+

+		error: function(message, exception) {

+			if (++this.numberOfErrors == 1 || this.alertAllErrors) {

+				if (!this.quietMode) {

+					var alertMessage = "log4javascript error: " + message;

+					if (exception) {

+						alertMessage += newLine + newLine + "Original error: " + getExceptionStringRep(exception);

+					}

+					alert(alertMessage);

+				}

+			}

+		}

+	};

+	log4javascript.logLog = logLog;

+

+	log4javascript.setEventTypes(["load", "error"]);

+

+	function handleError(message, exception) {

+		logLog.error(message, exception);

+		log4javascript.dispatchEvent("error", { "message": message, "exception": exception });

+	}

+

+	log4javascript.handleError = handleError;

+

+	/* ---------------------------------------------------------------------- */

+

+	var enabled = !((typeof log4javascript_disabled != "undefined") &&

+					log4javascript_disabled);

+

+	log4javascript.setEnabled = function(enable) {

+		enabled = bool(enable);

+	};

+

+	log4javascript.isEnabled = function() {

+		return enabled;

+	};

+

+	var useTimeStampsInMilliseconds = true;

+

+	log4javascript.setTimeStampsInMilliseconds = function(timeStampsInMilliseconds) {

+		useTimeStampsInMilliseconds = bool(timeStampsInMilliseconds);

+	};

+

+	log4javascript.isTimeStampsInMilliseconds = function() {

+		return useTimeStampsInMilliseconds;

+	};

+	

+

+	// This evaluates the given expression in the current scope, thus allowing

+	// scripts to access private variables. Particularly useful for testing

+	log4javascript.evalInScope = function(expr) {

+		return eval(expr);

+	};

+

+	var showStackTraces = false;

+

+	log4javascript.setShowStackTraces = function(show) {

+		showStackTraces = bool(show);

+	};

+

+	/* ---------------------------------------------------------------------- */

+	// Levels

+

+	var Level = function(level, name) {

+		this.level = level;

+		this.name = name;

+	};

+

+	Level.prototype = {

+		toString: function() {

+			return this.name;

+		},

+		equals: function(level) {

+			return this.level == level.level;

+		},

+		isGreaterOrEqual: function(level) {

+			return this.level >= level.level;

+		}

+	};

+

+	Level.ALL = new Level(Number.MIN_VALUE, "ALL");

+	Level.TRACE = new Level(10000, "TRACE");

+	Level.DEBUG = new Level(20000, "DEBUG");

+	Level.INFO = new Level(30000, "INFO");

+	Level.WARN = new Level(40000, "WARN");

+	Level.ERROR = new Level(50000, "ERROR");

+	Level.FATAL = new Level(60000, "FATAL");

+	Level.OFF = new Level(Number.MAX_VALUE, "OFF");

+

+	log4javascript.Level = Level;

+

+	/* ---------------------------------------------------------------------- */

+	// Timers

+

+	function Timer(name, level) {

+		this.name = name;

+		this.level = isUndefined(level) ? Level.INFO : level;

+		this.start = new Date();

+	}

+

+	Timer.prototype.getElapsedTime = function() {

+		return new Date().getTime() - this.start.getTime();

+	};

+

+	/* ---------------------------------------------------------------------- */

+	// Loggers

+

+	var anonymousLoggerName = "[anonymous]";

+	var defaultLoggerName = "[default]";

+	var nullLoggerName = "[null]";

+	var rootLoggerName = "root";

+

+	function Logger(name) {

+		this.name = name;

+		this.parent = null;

+		this.children = [];

+

+		var appenders = [];

+		var loggerLevel = null;

+		var isRoot = (this.name === rootLoggerName);

+		var isNull = (this.name === nullLoggerName);

+

+		var appenderCache = null;

+		var appenderCacheInvalidated = false;

+		

+		this.addChild = function(childLogger) {

+			this.children.push(childLogger);

+			childLogger.parent = this;

+			childLogger.invalidateAppenderCache();

+		};

+

+		// Additivity

+		var additive = true;

+		this.getAdditivity = function() {

+			return additive;

+		};

+

+		this.setAdditivity = function(additivity) {

+			var valueChanged = (additive != additivity);

+			additive = additivity;

+			if (valueChanged) {

+				this.invalidateAppenderCache();

+			}

+		};

+

+		// Create methods that use the appenders variable in this scope

+		this.addAppender = function(appender) {

+			if (isNull) {

+				handleError("Logger.addAppender: you may not add an appender to the null logger");

+			} else {

+				if (appender instanceof log4javascript.Appender) {

+					if (!array_contains(appenders, appender)) {

+						appenders.push(appender);

+						appender.setAddedToLogger(this);

+						this.invalidateAppenderCache();

+					}

+				} else {

+					handleError("Logger.addAppender: appender supplied ('" +

+						toStr(appender) + "') is not a subclass of Appender");

+				}

+			}

+		};

+

+		this.removeAppender = function(appender) {

+			array_remove(appenders, appender);

+			appender.setRemovedFromLogger(this);

+			this.invalidateAppenderCache();

+		};

+

+		this.removeAllAppenders = function() {

+			var appenderCount = appenders.length;

+			if (appenderCount > 0) {

+				for (var i = 0; i < appenderCount; i++) {

+					appenders[i].setRemovedFromLogger(this);

+				}

+				appenders.length = 0;

+				this.invalidateAppenderCache();

+			}

+		};

+

+		this.getEffectiveAppenders = function() {

+			if (appenderCache === null || appenderCacheInvalidated) {

+				// Build appender cache

+				var parentEffectiveAppenders = (isRoot || !this.getAdditivity()) ?

+					[] : this.parent.getEffectiveAppenders();

+				appenderCache = parentEffectiveAppenders.concat(appenders);

+				appenderCacheInvalidated = false;

+			}

+			return appenderCache;

+		};

+		

+		this.invalidateAppenderCache = function() {

+			appenderCacheInvalidated = true;

+			for (var i = 0, len = this.children.length; i < len; i++) {

+				this.children[i].invalidateAppenderCache();

+			}

+		};

+

+		this.log = function(level, params) {

+			if (enabled && level.isGreaterOrEqual(this.getEffectiveLevel())) {

+				// Check whether last param is an exception

+				var exception;

+				var finalParamIndex = params.length - 1;

+				var lastParam = params[finalParamIndex];

+				if (params.length > 1 && isError(lastParam)) {

+					exception = lastParam;

+					finalParamIndex--;

+				}

+

+				// Construct genuine array for the params

+				var messages = [];

+				for (var i = 0; i <= finalParamIndex; i++) {

+					messages[i] = params[i];

+				}

+

+				var loggingEvent = new LoggingEvent(

+					this, new Date(), level, messages, exception);

+

+				this.callAppenders(loggingEvent);

+			}

+		};

+

+		this.callAppenders = function(loggingEvent) {

+			var effectiveAppenders = this.getEffectiveAppenders();

+			for (var i = 0, len = effectiveAppenders.length; i < len; i++) {

+				effectiveAppenders[i].doAppend(loggingEvent);

+			}

+		};

+

+		this.setLevel = function(level) {

+			// Having a level of null on the root logger would be very bad.

+			if (isRoot && level === null) {

+				handleError("Logger.setLevel: you cannot set the level of the root logger to null");

+			} else if (level instanceof Level) {

+				loggerLevel = level;

+			} else {

+				handleError("Logger.setLevel: level supplied to logger " +

+					this.name + " is not an instance of log4javascript.Level");

+			}

+		};

+

+		this.getLevel = function() {

+			return loggerLevel;

+		};

+

+		this.getEffectiveLevel = function() {

+			for (var logger = this; logger !== null; logger = logger.parent) {

+				var level = logger.getLevel();

+				if (level !== null) {

+					return level;

+				}

+			}

+		};

+

+		this.group = function(name, initiallyExpanded) {

+			if (enabled) {

+				var effectiveAppenders = this.getEffectiveAppenders();

+				for (var i = 0, len = effectiveAppenders.length; i < len; i++) {

+					effectiveAppenders[i].group(name, initiallyExpanded);

+				}

+			}

+		};

+

+		this.groupEnd = function() {

+			if (enabled) {

+				var effectiveAppenders = this.getEffectiveAppenders();

+				for (var i = 0, len = effectiveAppenders.length; i < len; i++) {

+					effectiveAppenders[i].groupEnd();

+				}

+			}

+		};

+

+		var timers = {};

+

+		this.time = function(name, level) {

+			if (enabled) {

+				if (isUndefined(name)) {

+					handleError("Logger.time: a name for the timer must be supplied");

+				} else if (level && !(level instanceof Level)) {

+					handleError("Logger.time: level supplied to timer " +

+						name + " is not an instance of log4javascript.Level");

+				} else {

+					timers[name] = new Timer(name, level);

+				}

+			}

+		};

+

+		this.timeEnd = function(name) {

+			if (enabled) {

+				if (isUndefined(name)) {

+					handleError("Logger.timeEnd: a name for the timer must be supplied");

+				} else if (timers[name]) {

+					var timer = timers[name];

+					var milliseconds = timer.getElapsedTime();

+					this.log(timer.level, ["Timer " + toStr(name) + " completed in " + milliseconds + "ms"]);

+					delete timers[name];

+				} else {

+					logLog.warn("Logger.timeEnd: no timer found with name " + name);

+				}

+			}

+		};

+

+		this.assert = function(expr) {

+			if (enabled && !expr) {

+				var args = [];

+				for (var i = 1, len = arguments.length; i < len; i++) {

+					args.push(arguments[i]);

+				}

+				args = (args.length > 0) ? args : ["Assertion Failure"];

+				args.push(newLine);

+				args.push(expr);

+				this.log(Level.ERROR, args);

+			}

+		};

+

+		this.toString = function() {

+			return "Logger[" + this.name + "]";

+		};

+	}

+

+	Logger.prototype = {

+		trace: function() {

+			this.log(Level.TRACE, arguments);

+		},

+

+		debug: function() {

+			this.log(Level.DEBUG, arguments);

+		},

+

+		info: function() {

+			this.log(Level.INFO, arguments);

+		},

+

+		warn: function() {

+			this.log(Level.WARN, arguments);

+		},

+

+		error: function() {

+			this.log(Level.ERROR, arguments);

+		},

+

+		fatal: function() {

+			this.log(Level.FATAL, arguments);

+		},

+

+		isEnabledFor: function(level) {

+			return level.isGreaterOrEqual(this.getEffectiveLevel());

+		},

+

+		isTraceEnabled: function() {

+			return this.isEnabledFor(Level.TRACE);

+		},

+

+		isDebugEnabled: function() {

+			return this.isEnabledFor(Level.DEBUG);

+		},

+

+		isInfoEnabled: function() {

+			return this.isEnabledFor(Level.INFO);

+		},

+

+		isWarnEnabled: function() {

+			return this.isEnabledFor(Level.WARN);

+		},

+

+		isErrorEnabled: function() {

+			return this.isEnabledFor(Level.ERROR);

+		},

+

+		isFatalEnabled: function() {

+			return this.isEnabledFor(Level.FATAL);

+		}

+	};

+

+	Logger.prototype.trace.isEntryPoint = true;

+	Logger.prototype.debug.isEntryPoint = true;

+	Logger.prototype.info.isEntryPoint = true;

+	Logger.prototype.warn.isEntryPoint = true;

+	Logger.prototype.error.isEntryPoint = true;

+	Logger.prototype.fatal.isEntryPoint = true;

+

+	/* ---------------------------------------------------------------------- */

+	// Logger access methods

+

+	// Hashtable of loggers keyed by logger name

+	var loggers = {};

+	var loggerNames = [];

+

+	var ROOT_LOGGER_DEFAULT_LEVEL = Level.DEBUG;

+	var rootLogger = new Logger(rootLoggerName);

+	rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);

+

+	log4javascript.getRootLogger = function() {

+		return rootLogger;

+	};

+

+	log4javascript.getLogger = function(loggerName) {

+		// Use default logger if loggerName is not specified or invalid

+		if (!(typeof loggerName == "string")) {

+			loggerName = anonymousLoggerName;

+			logLog.warn("log4javascript.getLogger: non-string logger name "	+

+				toStr(loggerName) + " supplied, returning anonymous logger");

+		}

+

+		// Do not allow retrieval of the root logger by name

+		if (loggerName == rootLoggerName) {

+			handleError("log4javascript.getLogger: root logger may not be obtained by name");

+		}

+

+		// Create the logger for this name if it doesn't already exist

+		if (!loggers[loggerName]) {

+			var logger = new Logger(loggerName);

+			loggers[loggerName] = logger;

+			loggerNames.push(loggerName);

+

+			// Set up parent logger, if it doesn't exist

+			var lastDotIndex = loggerName.lastIndexOf(".");

+			var parentLogger;

+			if (lastDotIndex > -1) {

+				var parentLoggerName = loggerName.substring(0, lastDotIndex);

+				parentLogger = log4javascript.getLogger(parentLoggerName); // Recursively sets up grandparents etc.

+			} else {

+				parentLogger = rootLogger;

+			}

+			parentLogger.addChild(logger);

+		}

+		return loggers[loggerName];

+	};

+

+	var defaultLogger = null;

+	log4javascript.getDefaultLogger = function() {

+		if (!defaultLogger) {

+			defaultLogger = log4javascript.getLogger(defaultLoggerName);

+			var a = new log4javascript.PopUpAppender();

+			defaultLogger.addAppender(a);

+		}

+		return defaultLogger;

+	};

+

+	var nullLogger = null;

+	log4javascript.getNullLogger = function() {

+		if (!nullLogger) {

+			nullLogger = new Logger(nullLoggerName);

+			nullLogger.setLevel(Level.OFF);

+		}

+		return nullLogger;

+	};

+

+	// Destroys all loggers

+	log4javascript.resetConfiguration = function() {

+		rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);

+		loggers = {};

+	};

+

+	/* ---------------------------------------------------------------------- */

+	// Logging events

+

+	var LoggingEvent = function(logger, timeStamp, level, messages,

+			exception) {

+		this.logger = logger;

+		this.timeStamp = timeStamp;

+		this.timeStampInMilliseconds = timeStamp.getTime();

+		this.timeStampInSeconds = Math.floor(this.timeStampInMilliseconds / 1000);

+		this.milliseconds = this.timeStamp.getMilliseconds();

+		this.level = level;

+		this.messages = messages;

+		this.exception = exception;

+	};

+

+	LoggingEvent.prototype = {

+		getThrowableStrRep: function() {

+			return this.exception ?

+				getExceptionStringRep(this.exception) : "";

+		},

+		getCombinedMessages: function() {

+			return (this.messages.length == 1) ? this.messages[0] :

+				   this.messages.join(newLine);

+		},

+		toString: function() {

+			return "LoggingEvent[" + this.level + "]";

+		}

+	};

+

+	log4javascript.LoggingEvent = LoggingEvent;

+

+	/* ---------------------------------------------------------------------- */

+	// Layout prototype

+

+	var Layout = function() {

+	};

+

+	Layout.prototype = {

+		defaults: {

+			loggerKey: "logger",

+			timeStampKey: "timestamp",

+			millisecondsKey: "milliseconds",

+			levelKey: "level",

+			messageKey: "message",

+			exceptionKey: "exception",

+			urlKey: "url"

+		},

+		loggerKey: "logger",

+		timeStampKey: "timestamp",

+		millisecondsKey: "milliseconds",

+		levelKey: "level",

+		messageKey: "message",

+		exceptionKey: "exception",

+		urlKey: "url",

+		batchHeader: "",

+		batchFooter: "",

+		batchSeparator: "",

+		returnsPostData: false,

+		overrideTimeStampsSetting: false,

+		useTimeStampsInMilliseconds: null,

+

+		format: function() {

+			handleError("Layout.format: layout supplied has no format() method");

+		},

+

+		ignoresThrowable: function() {

+			handleError("Layout.ignoresThrowable: layout supplied has no ignoresThrowable() method");

+		},

+

+		getContentType: function() {

+			return "text/plain";

+		},

+

+		allowBatching: function() {

+			return true;

+		},

+

+		setTimeStampsInMilliseconds: function(timeStampsInMilliseconds) {

+			this.overrideTimeStampsSetting = true;

+			this.useTimeStampsInMilliseconds = bool(timeStampsInMilliseconds);

+		},

+

+		isTimeStampsInMilliseconds: function() {

+			return this.overrideTimeStampsSetting ?

+				this.useTimeStampsInMilliseconds : useTimeStampsInMilliseconds;

+		},

+

+		getTimeStampValue: function(loggingEvent) {

+			return this.isTimeStampsInMilliseconds() ?

+				loggingEvent.timeStampInMilliseconds : loggingEvent.timeStampInSeconds;

+		},

+

+		getDataValues: function(loggingEvent, combineMessages) {

+			var dataValues = [

+				[this.loggerKey, loggingEvent.logger.name],

+				[this.timeStampKey, this.getTimeStampValue(loggingEvent)],

+				[this.levelKey, loggingEvent.level.name],

+				[this.urlKey, window.location.href],

+				[this.messageKey, combineMessages ? loggingEvent.getCombinedMessages() : loggingEvent.messages]

+			];

+			if (!this.isTimeStampsInMilliseconds()) {

+				dataValues.push([this.millisecondsKey, loggingEvent.milliseconds]);

+			}

+			if (loggingEvent.exception) {

+				dataValues.push([this.exceptionKey, getExceptionStringRep(loggingEvent.exception)]);

+			}

+			if (this.hasCustomFields()) {

+				for (var i = 0, len = this.customFields.length; i < len; i++) {

+					var val = this.customFields[i].value;

+

+					// Check if the value is a function. If so, execute it, passing it the

+					// current layout and the logging event

+					if (typeof val === "function") {

+						val = val(this, loggingEvent);

+					}

+					dataValues.push([this.customFields[i].name, val]);

+				}

+			}

+			return dataValues;

+		},

+

+		setKeys: function(loggerKey, timeStampKey, levelKey, messageKey,

+				exceptionKey, urlKey, millisecondsKey) {

+			this.loggerKey = extractStringFromParam(loggerKey, this.defaults.loggerKey);

+			this.timeStampKey = extractStringFromParam(timeStampKey, this.defaults.timeStampKey);

+			this.levelKey = extractStringFromParam(levelKey, this.defaults.levelKey);

+			this.messageKey = extractStringFromParam(messageKey, this.defaults.messageKey);

+			this.exceptionKey = extractStringFromParam(exceptionKey, this.defaults.exceptionKey);

+			this.urlKey = extractStringFromParam(urlKey, this.defaults.urlKey);

+			this.millisecondsKey = extractStringFromParam(millisecondsKey, this.defaults.millisecondsKey);

+		},

+

+		setCustomField: function(name, value) {

+			var fieldUpdated = false;

+			for (var i = 0, len = this.customFields.length; i < len; i++) {

+				if (this.customFields[i].name === name) {

+					this.customFields[i].value = value;

+					fieldUpdated = true;

+				}

+			}

+			if (!fieldUpdated) {

+				this.customFields.push({"name": name, "value": value});

+			}

+		},

+

+		hasCustomFields: function() {

+			return (this.customFields.length > 0);

+		},

+

+		toString: function() {

+			handleError("Layout.toString: all layouts must override this method");

+		}

+	};

+

+	log4javascript.Layout = Layout;

+

+	/* ---------------------------------------------------------------------- */

+	// Appender prototype

+

+	var Appender = function() {};

+

+	Appender.prototype = new EventSupport();

+

+	Appender.prototype.layout = new PatternLayout();

+	Appender.prototype.threshold = Level.ALL;

+	Appender.prototype.loggers = [];

+

+	// Performs threshold checks before delegating actual logging to the

+	// subclass's specific append method.

+	Appender.prototype.doAppend = function(loggingEvent) {

+		if (enabled && loggingEvent.level.level >= this.threshold.level) {

+			this.append(loggingEvent);

+		}

+	};

+

+	Appender.prototype.append = function(loggingEvent) {};

+

+	Appender.prototype.setLayout = function(layout) {

+		if (layout instanceof Layout) {

+			this.layout = layout;

+		} else {

+			handleError("Appender.setLayout: layout supplied to " +

+				this.toString() + " is not a subclass of Layout");

+		}

+	};

+

+	Appender.prototype.getLayout = function() {

+		return this.layout;

+	};

+

+	Appender.prototype.setThreshold = function(threshold) {

+		if (threshold instanceof Level) {

+			this.threshold = threshold;

+		} else {

+			handleError("Appender.setThreshold: threshold supplied to " +

+				this.toString() + " is not a subclass of Level");

+		}

+	};

+

+	Appender.prototype.getThreshold = function() {

+		return this.threshold;

+	};

+

+	Appender.prototype.setAddedToLogger = function(logger) {

+		this.loggers.push(logger);

+	};

+

+	Appender.prototype.setRemovedFromLogger = function(logger) {

+		array_remove(this.loggers, logger);

+	};

+

+	Appender.prototype.group = emptyFunction;

+	Appender.prototype.groupEnd = emptyFunction;

+

+	Appender.prototype.toString = function() {

+		handleError("Appender.toString: all appenders must override this method");

+	};

+

+	log4javascript.Appender = Appender;

+

+	/* ---------------------------------------------------------------------- */

+	// SimpleLayout 

+

+	function SimpleLayout() {

+		this.customFields = [];

+	}

+

+	SimpleLayout.prototype = new Layout();

+

+	SimpleLayout.prototype.format = function(loggingEvent) {

+		return loggingEvent.level.name + " - " + loggingEvent.getCombinedMessages();

+	};

+

+	SimpleLayout.prototype.ignoresThrowable = function() {

+	    return true;

+	};

+

+	SimpleLayout.prototype.toString = function() {

+	    return "SimpleLayout";

+	};

+

+	log4javascript.SimpleLayout = SimpleLayout;

+	/* ----------------------------------------------------------------------- */

+	// NullLayout 

+

+	function NullLayout() {

+		this.customFields = [];

+	}

+

+	NullLayout.prototype = new Layout();

+

+	NullLayout.prototype.format = function(loggingEvent) {

+		return loggingEvent.messages;

+	};

+

+	NullLayout.prototype.ignoresThrowable = function() {

+	    return true;

+	};

+

+	NullLayout.prototype.toString = function() {

+	    return "NullLayout";

+	};

+

+	log4javascript.NullLayout = NullLayout;

+/* ---------------------------------------------------------------------- */

+	// XmlLayout

+

+	function XmlLayout(combineMessages) {

+		this.combineMessages = extractBooleanFromParam(combineMessages, true);

+		this.customFields = [];

+	}

+

+	XmlLayout.prototype = new Layout();

+

+	XmlLayout.prototype.isCombinedMessages = function() {

+		return this.combineMessages;

+	};

+

+	XmlLayout.prototype.getContentType = function() {

+		return "text/xml";

+	};

+

+	XmlLayout.prototype.escapeCdata = function(str) {

+		return str.replace(/\]\]>/, "]]>]]&gt;<![CDATA[");

+	};

+

+	XmlLayout.prototype.format = function(loggingEvent) {

+		var layout = this;

+		var i, len;

+		function formatMessage(message) {

+			message = (typeof message === "string") ? message : toStr(message);

+			return "<log4javascript:message><![CDATA[" +

+				layout.escapeCdata(message) + "]]></log4javascript:message>";

+		}

+

+		var str = "<log4javascript:event logger=\"" + loggingEvent.logger.name +

+			"\" timestamp=\"" + this.getTimeStampValue(loggingEvent) + "\"";

+		if (!this.isTimeStampsInMilliseconds()) {

+			str += " milliseconds=\"" + loggingEvent.milliseconds + "\"";

+		}

+		str += " level=\"" + loggingEvent.level.name + "\">" + newLine;

+		if (this.combineMessages) {

+			str += formatMessage(loggingEvent.getCombinedMessages());

+		} else {

+			str += "<log4javascript:messages>" + newLine;

+			for (i = 0, len = loggingEvent.messages.length; i < len; i++) {

+				str += formatMessage(loggingEvent.messages[i]) + newLine;

+			}

+			str += "</log4javascript:messages>" + newLine;

+		}

+		if (this.hasCustomFields()) {

+			for (i = 0, len = this.customFields.length; i < len; i++) {

+				str += "<log4javascript:customfield name=\"" +

+					this.customFields[i].name + "\"><![CDATA[" +

+					this.customFields[i].value.toString() +

+					"]]></log4javascript:customfield>" + newLine;

+			}

+		}

+		if (loggingEvent.exception) {

+			str += "<log4javascript:exception><![CDATA[" +

+				getExceptionStringRep(loggingEvent.exception) +

+				"]]></log4javascript:exception>" + newLine;

+		}

+		str += "</log4javascript:event>" + newLine + newLine;

+		return str;

+	};

+

+	XmlLayout.prototype.ignoresThrowable = function() {

+	    return false;

+	};

+

+	XmlLayout.prototype.toString = function() {

+	    return "XmlLayout";

+	};

+

+	log4javascript.XmlLayout = XmlLayout;

+	/* ---------------------------------------------------------------------- */

+	// JsonLayout related

+

+	function escapeNewLines(str) {

+		return str.replace(/\r\n|\r|\n/g, "\\r\\n");

+	}

+

+	function JsonLayout(readable, combineMessages) {

+		this.readable = extractBooleanFromParam(readable, false);

+		this.combineMessages = extractBooleanFromParam(combineMessages, true);

+		this.batchHeader = this.readable ? "[" + newLine : "[";

+		this.batchFooter = this.readable ? "]" + newLine : "]";

+		this.batchSeparator = this.readable ? "," + newLine : ",";

+		this.setKeys();

+		this.colon = this.readable ? ": " : ":";

+		this.tab = this.readable ? "\t" : "";

+		this.lineBreak = this.readable ? newLine : "";

+		this.customFields = [];

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// JsonLayout

+

+	JsonLayout.prototype = new Layout();

+

+	JsonLayout.prototype.isReadable = function() {

+		return this.readable;

+	};

+

+	JsonLayout.prototype.isCombinedMessages = function() {

+		return this.combineMessages;

+	};

+

+    JsonLayout.prototype.format = function(loggingEvent) {

+        var layout = this;

+        var dataValues = this.getDataValues(loggingEvent, this.combineMessages);

+        var str = "{" + this.lineBreak;

+        var i, len;

+

+        function formatValue(val, prefix, expand) {

+            // Check the type of the data value to decide whether quotation marks

+            // or expansion are required

+            var formattedValue;

+            var valType = typeof val;

+            if (val instanceof Date) {

+                formattedValue = String(val.getTime());

+            } else if (expand && (val instanceof Array)) {

+                formattedValue = "[" + layout.lineBreak;

+                for (var i = 0, len = val.length; i < len; i++) {

+                    var childPrefix = prefix + layout.tab;

+                    formattedValue += childPrefix + formatValue(val[i], childPrefix, false);

+                    if (i < val.length - 1) {

+                        formattedValue += ",";

+                    }

+                    formattedValue += layout.lineBreak;

+                }

+                formattedValue += prefix + "]";

+            } else if (valType !== "number" && valType !== "boolean") {

+                formattedValue = "\"" + escapeNewLines(toStr(val).replace(/\"/g, "\\\"")) + "\"";

+            } else {

+                formattedValue = val;

+            }

+            return formattedValue;

+        }

+

+        for (i = 0, len = dataValues.length - 1; i <= len; i++) {

+            str += this.tab + "\"" + dataValues[i][0] + "\"" + this.colon + formatValue(dataValues[i][1], this.tab, true);

+            if (i < len) {

+                str += ",";

+            }

+            str += this.lineBreak;

+        }

+

+        str += "}" + this.lineBreak;

+        return str;

+    };

+

+	JsonLayout.prototype.ignoresThrowable = function() {

+	    return false;

+	};

+

+	JsonLayout.prototype.toString = function() {

+	    return "JsonLayout";

+	};

+

+	JsonLayout.prototype.getContentType = function() {

+		return "application/json";

+	};

+

+	log4javascript.JsonLayout = JsonLayout;

+	/* ---------------------------------------------------------------------- */

+	// HttpPostDataLayout

+

+	function HttpPostDataLayout() {

+		this.setKeys();

+		this.customFields = [];

+		this.returnsPostData = true;

+	}

+

+	HttpPostDataLayout.prototype = new Layout();

+

+	// Disable batching

+	HttpPostDataLayout.prototype.allowBatching = function() {

+		return false;

+	};

+

+	HttpPostDataLayout.prototype.format = function(loggingEvent) {

+		var dataValues = this.getDataValues(loggingEvent);

+		var queryBits = [];

+		for (var i = 0, len = dataValues.length; i < len; i++) {

+			var val = (dataValues[i][1] instanceof Date) ?

+				String(dataValues[i][1].getTime()) : dataValues[i][1];

+			queryBits.push(urlEncode(dataValues[i][0]) + "=" + urlEncode(val));

+		}

+		return queryBits.join("&");

+	};

+

+	HttpPostDataLayout.prototype.ignoresThrowable = function(loggingEvent) {

+	    return false;

+	};

+

+	HttpPostDataLayout.prototype.toString = function() {

+	    return "HttpPostDataLayout";

+	};

+

+	log4javascript.HttpPostDataLayout = HttpPostDataLayout;

+	/* ---------------------------------------------------------------------- */

+	// formatObjectExpansion

+

+	function formatObjectExpansion(obj, depth, indentation) {

+		var objectsExpanded = [];

+

+		function doFormat(obj, depth, indentation) {

+			var i, j, len, childDepth, childIndentation, childLines, expansion,

+				childExpansion;

+

+			if (!indentation) {

+				indentation = "";

+			}

+

+			function formatString(text) {

+				var lines = splitIntoLines(text);

+				for (var j = 1, jLen = lines.length; j < jLen; j++) {

+					lines[j] = indentation + lines[j];

+				}

+				return lines.join(newLine);

+			}

+

+			if (obj === null) {

+				return "null";

+			} else if (typeof obj == "undefined") {

+				return "undefined";

+			} else if (typeof obj == "string") {

+				return formatString(obj);

+			} else if (typeof obj == "object" && array_contains(objectsExpanded, obj)) {

+				try {

+					expansion = toStr(obj);

+				} catch (ex) {

+					expansion = "Error formatting property. Details: " + getExceptionStringRep(ex);

+				}

+				return expansion + " [already expanded]";

+			} else if ((obj instanceof Array) && depth > 0) {

+				objectsExpanded.push(obj);

+				expansion = "[" + newLine;

+				childDepth = depth - 1;

+				childIndentation = indentation + "  ";

+				childLines = [];

+				for (i = 0, len = obj.length; i < len; i++) {

+					try {

+						childExpansion = doFormat(obj[i], childDepth, childIndentation);

+						childLines.push(childIndentation + childExpansion);

+					} catch (ex) {

+						childLines.push(childIndentation + "Error formatting array member. Details: " +

+							getExceptionStringRep(ex) + "");

+					}

+				}

+				expansion += childLines.join("," + newLine) + newLine + indentation + "]";

+				return expansion;

+            } else if (Object.prototype.toString.call(obj) == "[object Date]") {

+                return obj.toString();

+			} else if (typeof obj == "object" && depth > 0) {

+				objectsExpanded.push(obj);

+				expansion = "{" + newLine;

+				childDepth = depth - 1;

+				childIndentation = indentation + "  ";

+				childLines = [];

+				for (i in obj) {

+					try {

+						childExpansion = doFormat(obj[i], childDepth, childIndentation);

+						childLines.push(childIndentation + i + ": " + childExpansion);

+					} catch (ex) {

+						childLines.push(childIndentation + i + ": Error formatting property. Details: " +

+							getExceptionStringRep(ex));

+					}

+				}

+				expansion += childLines.join("," + newLine) + newLine + indentation + "}";

+				return expansion;

+			} else {

+				return formatString(toStr(obj));

+			}

+		}

+		return doFormat(obj, depth, indentation);

+	}

+	/* ---------------------------------------------------------------------- */

+	// Date-related stuff

+

+	var SimpleDateFormat;

+

+	(function() {

+		var regex = /('[^']*')|(G+|y+|M+|w+|W+|D+|d+|F+|E+|a+|H+|k+|K+|h+|m+|s+|S+|Z+)|([a-zA-Z]+)|([^a-zA-Z']+)/;

+		var monthNames = ["January", "February", "March", "April", "May", "June",

+			"July", "August", "September", "October", "November", "December"];

+		var dayNames = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];

+		var TEXT2 = 0, TEXT3 = 1, NUMBER = 2, YEAR = 3, MONTH = 4, TIMEZONE = 5;

+		var types = {

+			G : TEXT2,

+			y : YEAR,

+			M : MONTH,

+			w : NUMBER,

+			W : NUMBER,

+			D : NUMBER,

+			d : NUMBER,

+			F : NUMBER,

+			E : TEXT3,

+			a : TEXT2,

+			H : NUMBER,

+			k : NUMBER,

+			K : NUMBER,

+			h : NUMBER,

+			m : NUMBER,

+			s : NUMBER,

+			S : NUMBER,

+			Z : TIMEZONE

+		};

+		var ONE_DAY = 24 * 60 * 60 * 1000;

+		var ONE_WEEK = 7 * ONE_DAY;

+		var DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK = 1;

+

+		var newDateAtMidnight = function(year, month, day) {

+			var d = new Date(year, month, day, 0, 0, 0);

+			d.setMilliseconds(0);

+			return d;

+		};

+

+		Date.prototype.getDifference = function(date) {

+			return this.getTime() - date.getTime();

+		};

+

+		Date.prototype.isBefore = function(d) {

+			return this.getTime() < d.getTime();

+		};

+

+		Date.prototype.getUTCTime = function() {

+			return Date.UTC(this.getFullYear(), this.getMonth(), this.getDate(), this.getHours(), this.getMinutes(),

+					this.getSeconds(), this.getMilliseconds());

+		};

+

+		Date.prototype.getTimeSince = function(d) {

+			return this.getUTCTime() - d.getUTCTime();

+		};

+

+		Date.prototype.getPreviousSunday = function() {

+			// Using midday avoids any possibility of DST messing things up

+			var midday = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 12, 0, 0);

+			var previousSunday = new Date(midday.getTime() - this.getDay() * ONE_DAY);

+			return newDateAtMidnight(previousSunday.getFullYear(), previousSunday.getMonth(),

+					previousSunday.getDate());

+		};

+

+		Date.prototype.getWeekInYear = function(minimalDaysInFirstWeek) {

+			if (isUndefined(this.minimalDaysInFirstWeek)) {

+				minimalDaysInFirstWeek = DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;

+			}

+			var previousSunday = this.getPreviousSunday();

+			var startOfYear = newDateAtMidnight(this.getFullYear(), 0, 1);

+			var numberOfSundays = previousSunday.isBefore(startOfYear) ?

+				0 : 1 + Math.floor(previousSunday.getTimeSince(startOfYear) / ONE_WEEK);

+			var numberOfDaysInFirstWeek =  7 - startOfYear.getDay();

+			var weekInYear = numberOfSundays;

+			if (numberOfDaysInFirstWeek < minimalDaysInFirstWeek) {

+				weekInYear--;

+			}

+			return weekInYear;

+		};

+

+		Date.prototype.getWeekInMonth = function(minimalDaysInFirstWeek) {

+			if (isUndefined(this.minimalDaysInFirstWeek)) {

+				minimalDaysInFirstWeek = DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;

+			}

+			var previousSunday = this.getPreviousSunday();

+			var startOfMonth = newDateAtMidnight(this.getFullYear(), this.getMonth(), 1);

+			var numberOfSundays = previousSunday.isBefore(startOfMonth) ?

+				0 : 1 + Math.floor(previousSunday.getTimeSince(startOfMonth) / ONE_WEEK);

+			var numberOfDaysInFirstWeek =  7 - startOfMonth.getDay();

+			var weekInMonth = numberOfSundays;

+			if (numberOfDaysInFirstWeek >= minimalDaysInFirstWeek) {

+				weekInMonth++;

+			}

+			return weekInMonth;

+		};

+

+		Date.prototype.getDayInYear = function() {

+			var startOfYear = newDateAtMidnight(this.getFullYear(), 0, 1);

+			return 1 + Math.floor(this.getTimeSince(startOfYear) / ONE_DAY);

+		};

+

+		/* ------------------------------------------------------------------ */

+

+		SimpleDateFormat = function(formatString) {

+			this.formatString = formatString;

+		};

+

+		/**

+		 * Sets the minimum number of days in a week in order for that week to

+		 * be considered as belonging to a particular month or year

+		 */

+		SimpleDateFormat.prototype.setMinimalDaysInFirstWeek = function(days) {

+			this.minimalDaysInFirstWeek = days;

+		};

+

+		SimpleDateFormat.prototype.getMinimalDaysInFirstWeek = function() {

+			return isUndefined(this.minimalDaysInFirstWeek)	?

+				DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK : this.minimalDaysInFirstWeek;

+		};

+

+		var padWithZeroes = function(str, len) {

+			while (str.length < len) {

+				str = "0" + str;

+			}

+			return str;

+		};

+

+		var formatText = function(data, numberOfLetters, minLength) {

+			return (numberOfLetters >= 4) ? data : data.substr(0, Math.max(minLength, numberOfLetters));

+		};

+

+		var formatNumber = function(data, numberOfLetters) {

+			var dataString = "" + data;

+			// Pad with 0s as necessary

+			return padWithZeroes(dataString, numberOfLetters);

+		};

+

+		SimpleDateFormat.prototype.format = function(date) {

+			var formattedString = "";

+			var result;

+			var searchString = this.formatString;

+			while ((result = regex.exec(searchString))) {

+				var quotedString = result[1];

+				var patternLetters = result[2];

+				var otherLetters = result[3];

+				var otherCharacters = result[4];

+

+				// If the pattern matched is quoted string, output the text between the quotes

+				if (quotedString) {

+					if (quotedString == "''") {

+						formattedString += "'";

+					} else {

+						formattedString += quotedString.substring(1, quotedString.length - 1);

+					}

+				} else if (otherLetters) {

+					// Swallow non-pattern letters by doing nothing here

+				} else if (otherCharacters) {

+					// Simply output other characters

+					formattedString += otherCharacters;

+				} else if (patternLetters) {

+					// Replace pattern letters

+					var patternLetter = patternLetters.charAt(0);

+					var numberOfLetters = patternLetters.length;

+					var rawData = "";

+					switch(patternLetter) {

+						case "G":

+							rawData = "AD";

+							break;

+						case "y":

+							rawData = date.getFullYear();

+							break;

+						case "M":

+							rawData = date.getMonth();

+							break;

+						case "w":

+							rawData = date.getWeekInYear(this.getMinimalDaysInFirstWeek());

+							break;

+						case "W":

+							rawData = date.getWeekInMonth(this.getMinimalDaysInFirstWeek());

+							break;

+						case "D":

+							rawData = date.getDayInYear();

+							break;

+						case "d":

+							rawData = date.getDate();

+							break;

+						case "F":

+							rawData = 1 + Math.floor((date.getDate() - 1) / 7);

+							break;

+						case "E":

+							rawData = dayNames[date.getDay()];

+							break;

+						case "a":

+							rawData = (date.getHours() >= 12) ? "PM" : "AM";

+							break;

+						case "H":

+							rawData = date.getHours();

+							break;

+						case "k":

+							rawData = date.getHours() || 24;

+							break;

+						case "K":

+							rawData = date.getHours() % 12;

+							break;

+						case "h":

+							rawData = (date.getHours() % 12) || 12;

+							break;

+						case "m":

+							rawData = date.getMinutes();

+							break;

+						case "s":

+							rawData = date.getSeconds();

+							break;

+						case "S":

+							rawData = date.getMilliseconds();

+							break;

+						case "Z":

+							rawData = date.getTimezoneOffset(); // This returns the number of minutes since GMT was this time.

+							break;

+					}

+					// Format the raw data depending on the type

+					switch(types[patternLetter]) {

+						case TEXT2:

+							formattedString += formatText(rawData, numberOfLetters, 2);

+							break;

+						case TEXT3:

+							formattedString += formatText(rawData, numberOfLetters, 3);

+							break;

+						case NUMBER:

+							formattedString += formatNumber(rawData, numberOfLetters);

+							break;

+						case YEAR:

+							if (numberOfLetters <= 3) {

+								// Output a 2-digit year

+								var dataString = "" + rawData;

+								formattedString += dataString.substr(2, 2);

+							} else {

+								formattedString += formatNumber(rawData, numberOfLetters);

+							}

+							break;

+						case MONTH:

+							if (numberOfLetters >= 3) {

+								formattedString += formatText(monthNames[rawData], numberOfLetters, numberOfLetters);

+							} else {

+								// NB. Months returned by getMonth are zero-based

+								formattedString += formatNumber(rawData + 1, numberOfLetters);

+							}

+							break;

+						case TIMEZONE:

+							var isPositive = (rawData > 0);

+							// The following line looks like a mistake but isn't

+							// because of the way getTimezoneOffset measures.

+							var prefix = isPositive ? "-" : "+";

+							var absData = Math.abs(rawData);

+

+							// Hours

+							var hours = "" + Math.floor(absData / 60);

+							hours = padWithZeroes(hours, 2);

+							// Minutes

+							var minutes = "" + (absData % 60);

+							minutes = padWithZeroes(minutes, 2);

+

+							formattedString += prefix + hours + minutes;

+							break;

+					}

+				}

+				searchString = searchString.substr(result.index + result[0].length);

+			}

+			return formattedString;

+		};

+	})();

+

+	log4javascript.SimpleDateFormat = SimpleDateFormat;

+

+	/* ---------------------------------------------------------------------- */

+	// PatternLayout

+

+	function PatternLayout(pattern) {

+		if (pattern) {

+			this.pattern = pattern;

+		} else {

+			this.pattern = PatternLayout.DEFAULT_CONVERSION_PATTERN;

+		}

+		this.customFields = [];

+	}

+

+	PatternLayout.TTCC_CONVERSION_PATTERN = "%r %p %c - %m%n";

+	PatternLayout.DEFAULT_CONVERSION_PATTERN = "%m%n";

+	PatternLayout.ISO8601_DATEFORMAT = "yyyy-MM-dd HH:mm:ss,SSS";

+	PatternLayout.DATETIME_DATEFORMAT = "dd MMM yyyy HH:mm:ss,SSS";

+	PatternLayout.ABSOLUTETIME_DATEFORMAT = "HH:mm:ss,SSS";

+

+	PatternLayout.prototype = new Layout();

+

+	PatternLayout.prototype.format = function(loggingEvent) {

+		var regex = /%(-?[0-9]+)?(\.?[0-9]+)?([acdfmMnpr%])(\{([^\}]+)\})?|([^%]+)/;

+		var formattedString = "";

+		var result;

+		var searchString = this.pattern;

+

+		// Cannot use regex global flag since it doesn't work with exec in IE5

+		while ((result = regex.exec(searchString))) {

+			var matchedString = result[0];

+			var padding = result[1];

+			var truncation = result[2];

+			var conversionCharacter = result[3];

+			var specifier = result[5];

+			var text = result[6];

+

+			// Check if the pattern matched was just normal text

+			if (text) {

+				formattedString += "" + text;

+			} else {

+				// Create a raw replacement string based on the conversion

+				// character and specifier

+				var replacement = "";

+				switch(conversionCharacter) {

+					case "a": // Array of messages

+					case "m": // Message

+						var depth = 0;

+						if (specifier) {

+							depth = parseInt(specifier, 10);

+							if (isNaN(depth)) {

+								handleError("PatternLayout.format: invalid specifier '" +

+									specifier + "' for conversion character '" + conversionCharacter +

+									"' - should be a number");

+								depth = 0;

+							}

+						}

+						var messages = (conversionCharacter === "a") ? loggingEvent.messages[0] : loggingEvent.messages;

+						for (var i = 0, len = messages.length; i < len; i++) {

+							if (i > 0 && (replacement.charAt(replacement.length - 1) !== " ")) {

+								replacement += " ";

+							}

+							if (depth === 0) {

+								replacement += messages[i];

+							} else {

+								replacement += formatObjectExpansion(messages[i], depth);

+							}

+						}

+						break;

+					case "c": // Logger name

+						var loggerName = loggingEvent.logger.name;

+						if (specifier) {

+							var precision = parseInt(specifier, 10);

+							var loggerNameBits = loggingEvent.logger.name.split(".");

+							if (precision >= loggerNameBits.length) {

+								replacement = loggerName;

+							} else {

+								replacement = loggerNameBits.slice(loggerNameBits.length - precision).join(".");

+							}

+						} else {

+							replacement = loggerName;

+						}

+						break;

+					case "d": // Date

+						var dateFormat = PatternLayout.ISO8601_DATEFORMAT;

+						if (specifier) {

+							dateFormat = specifier;

+							// Pick up special cases

+							if (dateFormat == "ISO8601") {

+								dateFormat = PatternLayout.ISO8601_DATEFORMAT;

+							} else if (dateFormat == "ABSOLUTE") {

+								dateFormat = PatternLayout.ABSOLUTETIME_DATEFORMAT;

+							} else if (dateFormat == "DATE") {

+								dateFormat = PatternLayout.DATETIME_DATEFORMAT;

+							}

+						}

+						// Format the date

+						replacement = (new SimpleDateFormat(dateFormat)).format(loggingEvent.timeStamp);

+						break;

+					case "f": // Custom field

+						if (this.hasCustomFields()) {

+							var fieldIndex = 0;

+							if (specifier) {

+								fieldIndex = parseInt(specifier, 10);

+								if (isNaN(fieldIndex)) {

+									handleError("PatternLayout.format: invalid specifier '" +

+										specifier + "' for conversion character 'f' - should be a number");

+								} else if (fieldIndex === 0) {

+									handleError("PatternLayout.format: invalid specifier '" +

+										specifier + "' for conversion character 'f' - must be greater than zero");

+								} else if (fieldIndex > this.customFields.length) {

+									handleError("PatternLayout.format: invalid specifier '" +

+										specifier + "' for conversion character 'f' - there aren't that many custom fields");

+								} else {

+									fieldIndex = fieldIndex - 1;

+								}

+							}

+                            var val = this.customFields[fieldIndex].value;

+                            if (typeof val == "function") {

+                                val = val(this, loggingEvent);

+                            }

+                            replacement = val;

+						}

+						break;

+					case "n": // New line

+						replacement = newLine;

+						break;

+					case "p": // Level

+						replacement = loggingEvent.level.name;

+						break;

+					case "r": // Milliseconds since log4javascript startup

+						replacement = "" + loggingEvent.timeStamp.getDifference(applicationStartDate);

+						break;

+					case "%": // Literal % sign

+						replacement = "%";

+						break;

+					default:

+						replacement = matchedString;

+						break;

+				}

+				// Format the replacement according to any padding or

+				// truncation specified

+				var l;

+

+				// First, truncation

+				if (truncation) {

+					l = parseInt(truncation.substr(1), 10);

+					var strLen = replacement.length;

+					if (l < strLen) {

+						replacement = replacement.substring(strLen - l, strLen);

+					}

+				}

+				// Next, padding

+				if (padding) {

+					if (padding.charAt(0) == "-") {

+						l = parseInt(padding.substr(1), 10);

+						// Right pad with spaces

+						while (replacement.length < l) {

+							replacement += " ";

+						}

+					} else {

+						l = parseInt(padding, 10);

+						// Left pad with spaces

+						while (replacement.length < l) {

+							replacement = " " + replacement;

+						}

+					}

+				}

+				formattedString += replacement;

+			}

+			searchString = searchString.substr(result.index + result[0].length);

+		}

+		return formattedString;

+	};

+

+	PatternLayout.prototype.ignoresThrowable = function() {

+	    return true;

+	};

+

+	PatternLayout.prototype.toString = function() {

+	    return "PatternLayout";

+	};

+

+	log4javascript.PatternLayout = PatternLayout;

+	/* ---------------------------------------------------------------------- */

+	// AlertAppender

+

+	function AlertAppender() {}

+

+	AlertAppender.prototype = new Appender();

+

+	AlertAppender.prototype.layout = new SimpleLayout();

+

+	AlertAppender.prototype.append = function(loggingEvent) {

+		var formattedMessage = this.getLayout().format(loggingEvent);

+		if (this.getLayout().ignoresThrowable()) {

+			formattedMessage += loggingEvent.getThrowableStrRep();

+		}

+		alert(formattedMessage);

+	};

+

+	AlertAppender.prototype.toString = function() {

+		return "AlertAppender";

+	};

+

+	log4javascript.AlertAppender = AlertAppender;

+	/* ---------------------------------------------------------------------- */

+	// BrowserConsoleAppender (only works in Opera and Safari and Firefox with

+	// Firebug extension)

+

+	function BrowserConsoleAppender() {}

+

+	BrowserConsoleAppender.prototype = new log4javascript.Appender();

+	BrowserConsoleAppender.prototype.layout = new NullLayout();

+	BrowserConsoleAppender.prototype.threshold = Level.DEBUG;

+

+	BrowserConsoleAppender.prototype.append = function(loggingEvent) {

+		var appender = this;

+

+		var getFormattedMessage = function() {

+			var layout = appender.getLayout();

+			var formattedMessage = layout.format(loggingEvent);

+			if (layout.ignoresThrowable() && loggingEvent.exception) {

+				formattedMessage += loggingEvent.getThrowableStrRep();

+			}

+			return formattedMessage;

+		};

+

+		if ((typeof opera != "undefined") && opera.postError) { // Opera

+			opera.postError(getFormattedMessage());

+		} else if (window.console && window.console.log) { // Safari and Firebug

+			var formattedMesage = getFormattedMessage();

+			// Log to Firebug using its logging methods or revert to the console.log

+			// method in Safari

+			if (window.console.debug && Level.DEBUG.isGreaterOrEqual(loggingEvent.level)) {

+				window.console.debug(formattedMesage);

+			} else if (window.console.info && Level.INFO.equals(loggingEvent.level)) {

+				window.console.info(formattedMesage);

+			} else if (window.console.warn && Level.WARN.equals(loggingEvent.level)) {

+				window.console.warn(formattedMesage);

+			} else if (window.console.error && loggingEvent.level.isGreaterOrEqual(Level.ERROR)) {

+				window.console.error(formattedMesage);

+			} else {

+				window.console.log(formattedMesage);

+			}

+		}

+	};

+

+	BrowserConsoleAppender.prototype.group = function(name) {

+		if (window.console && window.console.group) {

+			window.console.group(name);

+		}

+	};

+

+	BrowserConsoleAppender.prototype.groupEnd = function() {

+		if (window.console && window.console.groupEnd) {

+			window.console.groupEnd();

+		}

+	};

+

+	BrowserConsoleAppender.prototype.toString = function() {

+		return "BrowserConsoleAppender";

+	};

+

+	log4javascript.BrowserConsoleAppender = BrowserConsoleAppender;

+	/* ---------------------------------------------------------------------- */

+	// AjaxAppender related

+

+	var xmlHttpFactories = [

+		function() { return new XMLHttpRequest(); },

+		function() { return new ActiveXObject("Msxml2.XMLHTTP"); },

+		function() { return new ActiveXObject("Microsoft.XMLHTTP"); }

+	];

+

+	var getXmlHttp = function(errorHandler) {

+		// This is only run the first time; the value of getXmlHttp gets

+		// replaced with the factory that succeeds on the first run

+		var xmlHttp = null, factory;

+		for (var i = 0, len = xmlHttpFactories.length; i < len; i++) {

+			factory = xmlHttpFactories[i];

+			try {

+				xmlHttp = factory();

+				getXmlHttp = factory;

+				return xmlHttp;

+			} catch (e) {

+			}

+		}

+		// If we're here, all factories have failed, so throw an error

+		if (errorHandler) {

+			errorHandler();

+		} else {

+			handleError("getXmlHttp: unable to obtain XMLHttpRequest object");

+		}

+	};

+

+	function isHttpRequestSuccessful(xmlHttp) {

+		return isUndefined(xmlHttp.status) || xmlHttp.status === 0 ||

+			(xmlHttp.status >= 200 && xmlHttp.status < 300) ||

+			xmlHttp.status == 1223 /* Fix for IE */;

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// AjaxAppender

+

+	function AjaxAppender(url) {

+		var appender = this;

+		var isSupported = true;

+		if (!url) {

+			handleError("AjaxAppender: URL must be specified in constructor");

+			isSupported = false;

+		}

+

+		var timed = this.defaults.timed;

+		var waitForResponse = this.defaults.waitForResponse;

+		var batchSize = this.defaults.batchSize;

+		var timerInterval = this.defaults.timerInterval;

+		var requestSuccessCallback = this.defaults.requestSuccessCallback;

+		var failCallback = this.defaults.failCallback;

+		var postVarName = this.defaults.postVarName;

+		var sendAllOnUnload = this.defaults.sendAllOnUnload;

+		var contentType = this.defaults.contentType;

+		var sessionId = null;

+

+		var queuedLoggingEvents = [];

+		var queuedRequests = [];

+		var headers = [];

+		var sending = false;

+		var initialized = false;

+

+		// Configuration methods. The function scope is used to prevent

+		// direct alteration to the appender configuration properties.

+		function checkCanConfigure(configOptionName) {

+			if (initialized) {

+				handleError("AjaxAppender: configuration option '" +

+					configOptionName +

+					"' may not be set after the appender has been initialized");

+				return false;

+			}

+			return true;

+		}

+

+		this.getSessionId = function() { return sessionId; };

+		this.setSessionId = function(sessionIdParam) {

+			sessionId = extractStringFromParam(sessionIdParam, null);

+			this.layout.setCustomField("sessionid", sessionId);

+		};

+

+		this.setLayout = function(layoutParam) {

+			if (checkCanConfigure("layout")) {

+				this.layout = layoutParam;

+				// Set the session id as a custom field on the layout, if not already present

+				if (sessionId !== null) {

+					this.setSessionId(sessionId);

+				}

+			}

+		};

+

+		this.isTimed = function() { return timed; };

+		this.setTimed = function(timedParam) {

+			if (checkCanConfigure("timed")) {

+				timed = bool(timedParam);

+			}

+		};

+

+		this.getTimerInterval = function() { return timerInterval; };

+		this.setTimerInterval = function(timerIntervalParam) {

+			if (checkCanConfigure("timerInterval")) {

+				timerInterval = extractIntFromParam(timerIntervalParam, timerInterval);

+			}

+		};

+

+		this.isWaitForResponse = function() { return waitForResponse; };

+		this.setWaitForResponse = function(waitForResponseParam) {

+			if (checkCanConfigure("waitForResponse")) {

+				waitForResponse = bool(waitForResponseParam);

+			}

+		};

+

+		this.getBatchSize = function() { return batchSize; };

+		this.setBatchSize = function(batchSizeParam) {

+			if (checkCanConfigure("batchSize")) {

+				batchSize = extractIntFromParam(batchSizeParam, batchSize);

+			}

+		};

+

+		this.isSendAllOnUnload = function() { return sendAllOnUnload; };

+		this.setSendAllOnUnload = function(sendAllOnUnloadParam) {

+			if (checkCanConfigure("sendAllOnUnload")) {

+				sendAllOnUnload = extractBooleanFromParam(sendAllOnUnloadParam, sendAllOnUnload);

+			}

+		};

+

+		this.setRequestSuccessCallback = function(requestSuccessCallbackParam) {

+			requestSuccessCallback = extractFunctionFromParam(requestSuccessCallbackParam, requestSuccessCallback);

+		};

+

+		this.setFailCallback = function(failCallbackParam) {

+			failCallback = extractFunctionFromParam(failCallbackParam, failCallback);

+		};

+

+		this.getPostVarName = function() { return postVarName; };

+		this.setPostVarName = function(postVarNameParam) {

+			if (checkCanConfigure("postVarName")) {

+				postVarName = extractStringFromParam(postVarNameParam, postVarName);

+			}

+		};

+

+		this.getHeaders = function() { return headers; };

+		this.addHeader = function(name, value) {

+			if (name.toLowerCase() == "content-type") {

+				contentType = value;

+			} else {

+				headers.push( { name: name, value: value } );

+			}

+		};

+

+		// Internal functions

+		function sendAll() {

+			if (isSupported && enabled) {

+				sending = true;

+				var currentRequestBatch;

+				if (waitForResponse) {

+					// Send the first request then use this function as the callback once

+					// the response comes back

+					if (queuedRequests.length > 0) {

+						currentRequestBatch = queuedRequests.shift();

+						sendRequest(preparePostData(currentRequestBatch), sendAll);

+					} else {

+						sending = false;

+						if (timed) {

+							scheduleSending();

+						}

+					}

+				} else {

+					// Rattle off all the requests without waiting to see the response

+					while ((currentRequestBatch = queuedRequests.shift())) {

+						sendRequest(preparePostData(currentRequestBatch));

+					}

+					sending = false;

+					if (timed) {

+						scheduleSending();

+					}

+				}

+			}

+		}

+

+		this.sendAll = sendAll;

+

+		// Called when the window unloads. At this point we're past caring about

+		// waiting for responses or timers or incomplete batches - everything

+		// must go, now

+		function sendAllRemaining() {

+			var sendingAnything = false;

+			if (isSupported && enabled) {

+				// Create requests for everything left over, batched as normal

+				var actualBatchSize = appender.getLayout().allowBatching() ? batchSize : 1;

+				var currentLoggingEvent;

+				var batchedLoggingEvents = [];

+				while ((currentLoggingEvent = queuedLoggingEvents.shift())) {

+					batchedLoggingEvents.push(currentLoggingEvent);

+					if (queuedLoggingEvents.length >= actualBatchSize) {

+						// Queue this batch of log entries

+						queuedRequests.push(batchedLoggingEvents);

+						batchedLoggingEvents = [];

+					}

+				}

+				// If there's a partially completed batch, add it

+				if (batchedLoggingEvents.length > 0) {

+					queuedRequests.push(batchedLoggingEvents);

+				}

+				sendingAnything = (queuedRequests.length > 0);

+				waitForResponse = false;

+				timed = false;

+				sendAll();

+			}

+			return sendingAnything;

+		}

+

+		this.sendAllRemaining = sendAllRemaining;

+

+		function preparePostData(batchedLoggingEvents) {

+			// Format the logging events

+			var formattedMessages = [];

+			var currentLoggingEvent;

+			var postData = "";

+			while ((currentLoggingEvent = batchedLoggingEvents.shift())) {

+				var currentFormattedMessage = appender.getLayout().format(currentLoggingEvent);

+				if (appender.getLayout().ignoresThrowable()) {

+					currentFormattedMessage += currentLoggingEvent.getThrowableStrRep();

+				}

+				formattedMessages.push(currentFormattedMessage);

+			}

+			// Create the post data string

+			if (batchedLoggingEvents.length == 1) {

+				postData = formattedMessages.join("");

+			} else {

+				postData = appender.getLayout().batchHeader +

+					formattedMessages.join(appender.getLayout().batchSeparator) +

+					appender.getLayout().batchFooter;

+			}

+			if (contentType == appender.defaults.contentType) {

+				postData = appender.getLayout().returnsPostData ? postData :

+					urlEncode(postVarName) + "=" + urlEncode(postData);

+				// Add the layout name to the post data

+				if (postData.length > 0) {

+					postData += "&";

+				}

+				postData += "layout=" + urlEncode(appender.getLayout().toString());

+			}

+			return postData;

+		}

+

+		function scheduleSending() {

+			window.setTimeout(sendAll, timerInterval);

+		}

+

+		function xmlHttpErrorHandler() {

+			var msg = "AjaxAppender: could not create XMLHttpRequest object. AjaxAppender disabled";

+			handleError(msg);

+			isSupported = false;

+			if (failCallback) {

+				failCallback(msg);

+			}

+		}

+

+		function sendRequest(postData, successCallback) {

+			try {

+				var xmlHttp = getXmlHttp(xmlHttpErrorHandler);

+				if (isSupported) {

+					if (xmlHttp.overrideMimeType) {

+						xmlHttp.overrideMimeType(appender.getLayout().getContentType());

+					}

+					xmlHttp.onreadystatechange = function() {

+						if (xmlHttp.readyState == 4) {

+							if (isHttpRequestSuccessful(xmlHttp)) {

+								if (requestSuccessCallback) {

+									requestSuccessCallback(xmlHttp);

+								}

+								if (successCallback) {

+									successCallback(xmlHttp);

+								}

+							} else {

+								var msg = "AjaxAppender.append: XMLHttpRequest request to URL " +

+									url + " returned status code " + xmlHttp.status;

+								handleError(msg);

+								if (failCallback) {

+									failCallback(msg);

+								}

+							}

+							xmlHttp.onreadystatechange = emptyFunction;

+							xmlHttp = null;

+						}

+					};

+					xmlHttp.open("POST", url, true);

+					try {

+						for (var i = 0, header; header = headers[i++]; ) {

+							xmlHttp.setRequestHeader(header.name, header.value);

+						}

+						xmlHttp.setRequestHeader("Content-Type", contentType);

+					} catch (headerEx) {

+						var msg = "AjaxAppender.append: your browser's XMLHttpRequest implementation" +

+							" does not support setRequestHeader, therefore cannot post data. AjaxAppender disabled";

+						handleError(msg);

+						isSupported = false;

+						if (failCallback) {

+							failCallback(msg);

+						}

+						return;

+					}

+					xmlHttp.send(postData);

+				}

+			} catch (ex) {

+				var errMsg = "AjaxAppender.append: error sending log message to " + url;

+				handleError(errMsg, ex);

+				isSupported = false;

+				if (failCallback) {

+					failCallback(errMsg + ". Details: " + getExceptionStringRep(ex));

+				}

+			}

+		}

+

+		this.append = function(loggingEvent) {

+			if (isSupported) {

+				if (!initialized) {

+					init();

+				}

+				queuedLoggingEvents.push(loggingEvent);

+				var actualBatchSize = this.getLayout().allowBatching() ? batchSize : 1;

+

+				if (queuedLoggingEvents.length >= actualBatchSize) {

+					var currentLoggingEvent;

+					var batchedLoggingEvents = [];

+					while ((currentLoggingEvent = queuedLoggingEvents.shift())) {

+						batchedLoggingEvents.push(currentLoggingEvent);

+					}

+					// Queue this batch of log entries

+					queuedRequests.push(batchedLoggingEvents);

+

+					// If using a timer, the queue of requests will be processed by the

+					// timer function, so nothing needs to be done here.

+					if (!timed && (!waitForResponse || (waitForResponse && !sending))) {

+						sendAll();

+					}

+				}

+			}

+		};

+

+		function init() {

+			initialized = true;

+			// Add unload event to send outstanding messages

+			if (sendAllOnUnload) {

+				var oldBeforeUnload = window.onbeforeunload;

+				window.onbeforeunload = function() {

+					if (oldBeforeUnload) {

+						oldBeforeUnload();

+					}

+					if (sendAllRemaining()) {

+						return "Sending log messages";

+					}

+				};

+			}

+			// Start timer

+			if (timed) {

+				scheduleSending();

+			}

+		}

+	}

+

+	AjaxAppender.prototype = new Appender();

+

+	AjaxAppender.prototype.defaults = {

+		waitForResponse: false,

+		timed: false,

+		timerInterval: 1000,

+		batchSize: 1,

+		sendAllOnUnload: false,

+		requestSuccessCallback: null,

+		failCallback: null,

+		postVarName: "data",

+		contentType: "application/x-www-form-urlencoded"

+	};

+

+	AjaxAppender.prototype.layout = new HttpPostDataLayout();

+

+	AjaxAppender.prototype.toString = function() {

+		return "AjaxAppender";

+	};

+

+	log4javascript.AjaxAppender = AjaxAppender;

+	/* ---------------------------------------------------------------------- */

+	// PopUpAppender and InPageAppender related

+

+	function setCookie(name, value, days, path) {

+	    var expires;

+	    path = path ? "; path=" + path : "";

+		if (days) {

+			var date = new Date();

+			date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));

+			expires = "; expires=" + date.toGMTString();

+		} else {

+		    expires = "";

+	    }

+		document.cookie = escape(name) + "=" + escape(value) + expires + path;

+	}

+

+	function getCookie(name) {

+		var nameEquals = escape(name) + "=";

+		var ca = document.cookie.split(";");

+		for (var i = 0, len = ca.length; i < len; i++) {

+			var c = ca[i];

+			while (c.charAt(0) === " ") {

+			    c = c.substring(1, c.length);

+			}

+			if (c.indexOf(nameEquals) === 0) {

+			    return unescape(c.substring(nameEquals.length, c.length));

+	        }

+		}

+		return null;

+	}

+

+	// Gets the base URL of the location of the log4javascript script.

+	// This is far from infallible.

+	function getBaseUrl() {

+		var scripts = document.getElementsByTagName("script");

+		for (var i = 0, len = scripts.length; i < len; ++i) {

+			if (scripts[i].src.indexOf("log4javascript") != -1) {

+				var lastSlash = scripts[i].src.lastIndexOf("/");

+				return (lastSlash == -1) ? "" : scripts[i].src.substr(0, lastSlash + 1);

+			}

+		}

+        return null;

+    }

+

+	function isLoaded(win) {

+		try {

+			return bool(win.loaded);

+		} catch (ex) {

+			return false;

+		}

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// ConsoleAppender (prototype for PopUpAppender and InPageAppender)

+

+	var ConsoleAppender;

+

+	// Create an anonymous function to protect base console methods

+	(function() {

+		var getConsoleHtmlLines = function() {

+			return [

+'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',

+'<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">',

+'	<head>',

+'		<title>log4javascript</title>',

+'		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />',

+'		<!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->',

+'		<meta http-equiv="X-UA-Compatible" content="IE=7" />',

+'		<script type="text/javascript">var isIe = false, isIePre7 = false;</script>',

+'		<!--[if IE]><script type="text/javascript">isIe = true</script><![endif]-->',

+'		<!--[if lt IE 7]><script type="text/javascript">isIePre7 = true</script><![endif]-->',

+'		<script type="text/javascript">',

+'			//<![CDATA[',

+'			var loggingEnabled = true;',

+'			var logQueuedEventsTimer = null;',

+'			var logEntries = [];',

+'			var logEntriesAndSeparators = [];',

+'			var logItems = [];',

+'			var renderDelay = 100;',

+'			var unrenderedLogItemsExist = false;',

+'			var rootGroup, currentGroup = null;',

+'			var loaded = false;',

+'			var currentLogItem = null;',

+'			var logMainContainer;',

+'',

+'			function copyProperties(obj, props) {',

+'				for (var i in props) {',

+'					obj[i] = props[i];',

+'				}',

+'			}',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogItem() {',

+'			}',

+'',

+'			LogItem.prototype = {',

+'				mainContainer: null,',

+'				wrappedContainer: null,',

+'				unwrappedContainer: null,',

+'				group: null,',

+'',

+'				appendToLog: function() {',

+'					for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'						this.elementContainers[i].appendToLog();',

+'					}',

+'					this.group.update();',

+'				},',

+'',

+'				doRemove: function(doUpdate, removeFromGroup) {',

+'					if (this.rendered) {',

+'						for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'							this.elementContainers[i].remove();',

+'						}',

+'						this.unwrappedElementContainer = null;',

+'						this.wrappedElementContainer = null;',

+'						this.mainElementContainer = null;',

+'					}',

+'					if (this.group && removeFromGroup) {',

+'						this.group.removeChild(this, doUpdate);',

+'					}',

+'					if (this === currentLogItem) {',

+'						currentLogItem = null;',

+'					}',

+'				},',

+'',

+'				remove: function(doUpdate, removeFromGroup) {',

+'					this.doRemove(doUpdate, removeFromGroup);',

+'				},',

+'',

+'				render: function() {},',

+'',

+'				accept: function(visitor) {',

+'					visitor.visit(this);',

+'				},',

+'',

+'				getUnwrappedDomContainer: function() {',

+'					return this.group.unwrappedElementContainer.contentDiv;',

+'				},',

+'',

+'				getWrappedDomContainer: function() {',

+'					return this.group.wrappedElementContainer.contentDiv;',

+'				},',

+'',

+'				getMainDomContainer: function() {',

+'					return this.group.mainElementContainer.contentDiv;',

+'				}',

+'			};',

+'',

+'			LogItem.serializedItemKeys = {LOG_ENTRY: 0, GROUP_START: 1, GROUP_END: 2};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogItemContainerElement() {',

+'			}',

+'',

+'			LogItemContainerElement.prototype = {',

+'				appendToLog: function() {',

+'					var insertBeforeFirst = (newestAtTop && this.containerDomNode.hasChildNodes());',

+'					if (insertBeforeFirst) {',

+'						this.containerDomNode.insertBefore(this.mainDiv, this.containerDomNode.firstChild);',

+'					} else {',

+'						this.containerDomNode.appendChild(this.mainDiv);',

+'					}',

+'				}',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function SeparatorElementContainer(containerDomNode) {',

+'				this.containerDomNode = containerDomNode;',

+'				this.mainDiv = document.createElement("div");',

+'				this.mainDiv.className = "separator";',

+'				this.mainDiv.innerHTML = "&nbsp;";',

+'			}',

+'',

+'			SeparatorElementContainer.prototype = new LogItemContainerElement();',

+'',

+'			SeparatorElementContainer.prototype.remove = function() {',

+'				this.mainDiv.parentNode.removeChild(this.mainDiv);',

+'				this.mainDiv = null;',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function Separator() {',

+'				this.rendered = false;',

+'			}',

+'',

+'			Separator.prototype = new LogItem();',

+'',

+'			copyProperties(Separator.prototype, {',

+'				render: function() {',

+'					var containerDomNode = this.group.contentDiv;',

+'					if (isIe) {',

+'						this.unwrappedElementContainer = new SeparatorElementContainer(this.getUnwrappedDomContainer());',

+'						this.wrappedElementContainer = new SeparatorElementContainer(this.getWrappedDomContainer());',

+'						this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];',

+'					} else {',

+'						this.mainElementContainer = new SeparatorElementContainer(this.getMainDomContainer());',

+'						this.elementContainers = [this.mainElementContainer];',

+'					}',

+'					this.content = this.formattedMessage;',

+'					this.rendered = true;',

+'				}',

+'			});',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function GroupElementContainer(group, containerDomNode, isRoot, isWrapped) {',

+'				this.group = group;',

+'				this.containerDomNode = containerDomNode;',

+'				this.isRoot = isRoot;',

+'				this.isWrapped = isWrapped;',

+'				this.expandable = false;',

+'',

+'				if (this.isRoot) {',

+'					if (isIe) {',

+'						this.contentDiv = logMainContainer.appendChild(document.createElement("div"));',

+'						this.contentDiv.id = this.isWrapped ? "log_wrapped" : "log_unwrapped";',

+'					} else {',

+'						this.contentDiv = logMainContainer;',

+'					}',

+'				} else {',

+'					var groupElementContainer = this;',

+'					',

+'					this.mainDiv = document.createElement("div");',

+'					this.mainDiv.className = "group";',

+'',

+'					this.headingDiv = this.mainDiv.appendChild(document.createElement("div"));',

+'					this.headingDiv.className = "groupheading";',

+'',

+'					this.expander = this.headingDiv.appendChild(document.createElement("span"));',

+'					this.expander.className = "expander unselectable greyedout";',

+'					this.expander.unselectable = true;',

+'					var expanderText = this.group.expanded ? "-" : "+";',

+'					this.expanderTextNode = this.expander.appendChild(document.createTextNode(expanderText));',

+'					',

+'					this.headingDiv.appendChild(document.createTextNode(" " + this.group.name));',

+'',

+'					this.contentDiv = this.mainDiv.appendChild(document.createElement("div"));',

+'					var contentCssClass = this.group.expanded ? "expanded" : "collapsed";',

+'					this.contentDiv.className = "groupcontent " + contentCssClass;',

+'',

+'					this.expander.onclick = function() {',

+'						if (groupElementContainer.group.expandable) {',

+'							groupElementContainer.group.toggleExpanded();',

+'						}',

+'					};',

+'				}',

+'			}',

+'',

+'			GroupElementContainer.prototype = new LogItemContainerElement();',

+'',

+'			copyProperties(GroupElementContainer.prototype, {',

+'				toggleExpanded: function() {',

+'					if (!this.isRoot) {',

+'						var oldCssClass, newCssClass, expanderText;',

+'						if (this.group.expanded) {',

+'							newCssClass = "expanded";',

+'							oldCssClass = "collapsed";',

+'							expanderText = "-";',

+'						} else {',

+'							newCssClass = "collapsed";',

+'							oldCssClass = "expanded";',

+'							expanderText = "+";',

+'						}',

+'						replaceClass(this.contentDiv, newCssClass, oldCssClass);',

+'						this.expanderTextNode.nodeValue = expanderText;',

+'					}',

+'				},',

+'',

+'				remove: function() {',

+'					if (!this.isRoot) {',

+'						this.headingDiv = null;',

+'						this.expander.onclick = null;',

+'						this.expander = null;',

+'						this.expanderTextNode = null;',

+'						this.contentDiv = null;',

+'						this.containerDomNode = null;',

+'						this.mainDiv.parentNode.removeChild(this.mainDiv);',

+'						this.mainDiv = null;',

+'					}',

+'				},',

+'',

+'				reverseChildren: function() {',

+'					// Invert the order of the log entries',

+'					var node = null;',

+'',

+'					// Remove all the log container nodes',

+'					var childDomNodes = [];',

+'					while ((node = this.contentDiv.firstChild)) {',

+'						this.contentDiv.removeChild(node);',

+'						childDomNodes.push(node);',

+'					}',

+'',

+'					// Put them all back in reverse order',

+'					while ((node = childDomNodes.pop())) {',

+'						this.contentDiv.appendChild(node);',

+'					}',

+'				},',

+'',

+'				update: function() {',

+'					if (!this.isRoot) {',

+'						if (this.group.expandable) {',

+'							removeClass(this.expander, "greyedout");',

+'						} else {',

+'							addClass(this.expander, "greyedout");',

+'						}',

+'					}',

+'				},',

+'',

+'				clear: function() {',

+'					if (this.isRoot) {',

+'						this.contentDiv.innerHTML = "";',

+'					}',

+'				}',

+'			});',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function Group(name, isRoot, initiallyExpanded) {',

+'				this.name = name;',

+'				this.group = null;',

+'				this.isRoot = isRoot;',

+'				this.initiallyExpanded = initiallyExpanded;',

+'				this.elementContainers = [];',

+'				this.children = [];',

+'				this.expanded = initiallyExpanded;',

+'				this.rendered = false;',

+'				this.expandable = false;',

+'			}',

+'',

+'			Group.prototype = new LogItem();',

+'',

+'			copyProperties(Group.prototype, {',

+'				addChild: function(logItem) {',

+'					this.children.push(logItem);',

+'					logItem.group = this;',

+'				},',

+'',

+'				render: function() {',

+'					if (isIe) {',

+'						var unwrappedDomContainer, wrappedDomContainer;',

+'						if (this.isRoot) {',

+'							unwrappedDomContainer = logMainContainer;',

+'							wrappedDomContainer = logMainContainer;',

+'						} else {',

+'							unwrappedDomContainer = this.getUnwrappedDomContainer();',

+'							wrappedDomContainer = this.getWrappedDomContainer();',

+'						}',

+'						this.unwrappedElementContainer = new GroupElementContainer(this, unwrappedDomContainer, this.isRoot, false);',

+'						this.wrappedElementContainer = new GroupElementContainer(this, wrappedDomContainer, this.isRoot, true);',

+'						this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];',

+'					} else {',

+'						var mainDomContainer = this.isRoot ? logMainContainer : this.getMainDomContainer();',

+'						this.mainElementContainer = new GroupElementContainer(this, mainDomContainer, this.isRoot, false);',

+'						this.elementContainers = [this.mainElementContainer];',

+'					}',

+'					this.rendered = true;',

+'				},',

+'',

+'				toggleExpanded: function() {',

+'					this.expanded = !this.expanded;',

+'					for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'						this.elementContainers[i].toggleExpanded();',

+'					}',

+'				},',

+'',

+'				expand: function() {',

+'					if (!this.expanded) {',

+'						this.toggleExpanded();',

+'					}',

+'				},',

+'',

+'				accept: function(visitor) {',

+'					visitor.visitGroup(this);',

+'				},',

+'',

+'				reverseChildren: function() {',

+'					if (this.rendered) {',

+'						for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'							this.elementContainers[i].reverseChildren();',

+'						}',

+'					}',

+'				},',

+'',

+'				update: function() {',

+'					var previouslyExpandable = this.expandable;',

+'					this.expandable = (this.children.length !== 0);',

+'					if (this.expandable !== previouslyExpandable) {',

+'						for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'							this.elementContainers[i].update();',

+'						}',

+'					}',

+'				},',

+'',

+'				flatten: function() {',

+'					var visitor = new GroupFlattener();',

+'					this.accept(visitor);',

+'					return visitor.logEntriesAndSeparators;',

+'				},',

+'',

+'				removeChild: function(child, doUpdate) {',

+'					array_remove(this.children, child);',

+'					child.group = null;',

+'					if (doUpdate) {',

+'						this.update();',

+'					}',

+'				},',

+'',

+'				remove: function(doUpdate, removeFromGroup) {',

+'					for (var i = 0, len = this.children.length; i < len; i++) {',

+'						this.children[i].remove(false, false);',

+'					}',

+'					this.children = [];',

+'					this.update();',

+'					if (this === currentGroup) {',

+'						currentGroup = this.group;',

+'					}',

+'					this.doRemove(doUpdate, removeFromGroup);',

+'				},',

+'',

+'				serialize: function(items) {',

+'					items.push([LogItem.serializedItemKeys.GROUP_START, this.name]);',

+'					for (var i = 0, len = this.children.length; i < len; i++) {',

+'						this.children[i].serialize(items);',

+'					}',

+'					if (this !== currentGroup) {',

+'						items.push([LogItem.serializedItemKeys.GROUP_END]);',

+'					}',

+'				},',

+'',

+'				clear: function() {',

+'					for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'						this.elementContainers[i].clear();',

+'					}',

+'				}',

+'			});',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogEntryElementContainer() {',

+'			}',

+'',

+'			LogEntryElementContainer.prototype = new LogItemContainerElement();',

+'',

+'			copyProperties(LogEntryElementContainer.prototype, {',

+'				remove: function() {',

+'					this.doRemove();',

+'				},',

+'',

+'				doRemove: function() {',

+'					this.mainDiv.parentNode.removeChild(this.mainDiv);',

+'					this.mainDiv = null;',

+'					this.contentElement = null;',

+'					this.containerDomNode = null;',

+'				},',

+'',

+'				setContent: function(content, wrappedContent) {',

+'					if (content === this.formattedMessage) {',

+'						this.contentElement.innerHTML = "";',

+'						this.contentElement.appendChild(document.createTextNode(this.formattedMessage));',

+'					} else {',

+'						this.contentElement.innerHTML = content;',

+'					}',

+'				},',

+'',

+'				setSearchMatch: function(isMatch) {',

+'					var oldCssClass = isMatch ? "searchnonmatch" : "searchmatch";',

+'					var newCssClass = isMatch ? "searchmatch" : "searchnonmatch";',

+'					replaceClass(this.mainDiv, newCssClass, oldCssClass);',

+'				},',

+'',

+'				clearSearch: function() {',

+'					removeClass(this.mainDiv, "searchmatch");',

+'					removeClass(this.mainDiv, "searchnonmatch");',

+'				}',

+'			});',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogEntryWrappedElementContainer(logEntry, containerDomNode) {',

+'				this.logEntry = logEntry;',

+'				this.containerDomNode = containerDomNode;',

+'				this.mainDiv = document.createElement("div");',

+'				this.mainDiv.appendChild(document.createTextNode(this.logEntry.formattedMessage));',

+'				this.mainDiv.className = "logentry wrapped " + this.logEntry.level;',

+'				this.contentElement = this.mainDiv;',

+'			}',

+'',

+'			LogEntryWrappedElementContainer.prototype = new LogEntryElementContainer();',

+'',

+'			LogEntryWrappedElementContainer.prototype.setContent = function(content, wrappedContent) {',

+'				if (content === this.formattedMessage) {',

+'					this.contentElement.innerHTML = "";',

+'					this.contentElement.appendChild(document.createTextNode(this.formattedMessage));',

+'				} else {',

+'					this.contentElement.innerHTML = wrappedContent;',

+'				}',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogEntryUnwrappedElementContainer(logEntry, containerDomNode) {',

+'				this.logEntry = logEntry;',

+'				this.containerDomNode = containerDomNode;',

+'				this.mainDiv = document.createElement("div");',

+'				this.mainDiv.className = "logentry unwrapped " + this.logEntry.level;',

+'				this.pre = this.mainDiv.appendChild(document.createElement("pre"));',

+'				this.pre.appendChild(document.createTextNode(this.logEntry.formattedMessage));',

+'				this.pre.className = "unwrapped";',

+'				this.contentElement = this.pre;',

+'			}',

+'',

+'			LogEntryUnwrappedElementContainer.prototype = new LogEntryElementContainer();',

+'',

+'			LogEntryUnwrappedElementContainer.prototype.remove = function() {',

+'				this.doRemove();',

+'				this.pre = null;',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogEntryMainElementContainer(logEntry, containerDomNode) {',

+'				this.logEntry = logEntry;',

+'				this.containerDomNode = containerDomNode;',

+'				this.mainDiv = document.createElement("div");',

+'				this.mainDiv.className = "logentry nonielogentry " + this.logEntry.level;',

+'				this.contentElement = this.mainDiv.appendChild(document.createElement("span"));',

+'				this.contentElement.appendChild(document.createTextNode(this.logEntry.formattedMessage));',

+'			}',

+'',

+'			LogEntryMainElementContainer.prototype = new LogEntryElementContainer();',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogEntry(level, formattedMessage) {',

+'				this.level = level;',

+'				this.formattedMessage = formattedMessage;',

+'				this.rendered = false;',

+'			}',

+'',

+'			LogEntry.prototype = new LogItem();',

+'',

+'			copyProperties(LogEntry.prototype, {',

+'				render: function() {',

+'					var logEntry = this;',

+'					var containerDomNode = this.group.contentDiv;',

+'',

+'					// Support for the CSS attribute white-space in IE for Windows is',

+'					// non-existent pre version 6 and slightly odd in 6, so instead',

+'					// use two different HTML elements',

+'					if (isIe) {',

+'						this.formattedMessage = this.formattedMessage.replace(/\\r\\n/g, "\\r"); // Workaround for IE\'s treatment of white space',

+'						this.unwrappedElementContainer = new LogEntryUnwrappedElementContainer(this, this.getUnwrappedDomContainer());',

+'						this.wrappedElementContainer = new LogEntryWrappedElementContainer(this, this.getWrappedDomContainer());',

+'						this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];',

+'					} else {',

+'						this.mainElementContainer = new LogEntryMainElementContainer(this, this.getMainDomContainer());',

+'						this.elementContainers = [this.mainElementContainer];',

+'					}',

+'					this.content = this.formattedMessage;',

+'					this.rendered = true;',

+'				},',

+'',

+'				setContent: function(content, wrappedContent) {',

+'					if (content != this.content) {',

+'						if (isIe && (content !== this.formattedMessage)) {',

+'							content = content.replace(/\\r\\n/g, "\\r"); // Workaround for IE\'s treatment of white space',

+'						}',

+'						for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'							this.elementContainers[i].setContent(content, wrappedContent);',

+'						}',

+'						this.content = content;',

+'					}',

+'				},',

+'',

+'				getSearchMatches: function() {',

+'					var matches = [];',

+'					var i, len;',

+'					if (isIe) {',

+'						var unwrappedEls = getElementsByClass(this.unwrappedElementContainer.mainDiv, "searchterm", "span");',

+'						var wrappedEls = getElementsByClass(this.wrappedElementContainer.mainDiv, "searchterm", "span");',

+'						for (i = 0, len = unwrappedEls.length; i < len; i++) {',

+'							matches[i] = new Match(this.level, null, unwrappedEls[i], wrappedEls[i]);',

+'						}',

+'					} else {',

+'						var els = getElementsByClass(this.mainElementContainer.mainDiv, "searchterm", "span");',

+'						for (i = 0, len = els.length; i < len; i++) {',

+'							matches[i] = new Match(this.level, els[i]);',

+'						}',

+'					}',

+'					return matches;',

+'				},',

+'',

+'				setSearchMatch: function(isMatch) {',

+'					for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'						this.elementContainers[i].setSearchMatch(isMatch);',

+'					}',

+'				},',

+'',

+'				clearSearch: function() {',

+'					for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'						this.elementContainers[i].clearSearch();',

+'					}',

+'				},',

+'',

+'				accept: function(visitor) {',

+'					visitor.visitLogEntry(this);',

+'				},',

+'',

+'				serialize: function(items) {',

+'					items.push([LogItem.serializedItemKeys.LOG_ENTRY, this.level, this.formattedMessage]);',

+'				}',

+'			});',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogItemVisitor() {',

+'			}',

+'',

+'			LogItemVisitor.prototype = {',

+'				visit: function(logItem) {',

+'				},',

+'',

+'				visitParent: function(logItem) {',

+'					if (logItem.group) {',

+'						logItem.group.accept(this);',

+'					}',

+'				},',

+'',

+'				visitChildren: function(logItem) {',

+'					for (var i = 0, len = logItem.children.length; i < len; i++) {',

+'						logItem.children[i].accept(this);',

+'					}',

+'				},',

+'',

+'				visitLogEntry: function(logEntry) {',

+'					this.visit(logEntry);',

+'				},',

+'',

+'				visitSeparator: function(separator) {',

+'					this.visit(separator);',

+'				},',

+'',

+'				visitGroup: function(group) {',

+'					this.visit(group);',

+'				}',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function GroupFlattener() {',

+'				this.logEntriesAndSeparators = [];',

+'			}',

+'',

+'			GroupFlattener.prototype = new LogItemVisitor();',

+'',

+'			GroupFlattener.prototype.visitGroup = function(group) {',

+'				this.visitChildren(group);',

+'			};',

+'',

+'			GroupFlattener.prototype.visitLogEntry = function(logEntry) {',

+'				this.logEntriesAndSeparators.push(logEntry);',

+'			};',

+'',

+'			GroupFlattener.prototype.visitSeparator = function(separator) {',

+'				this.logEntriesAndSeparators.push(separator);',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			window.onload = function() {',

+'				// Sort out document.domain',

+'				if (location.search) {',

+'					var queryBits = unescape(location.search).substr(1).split("&"), nameValueBits;',

+'					for (var i = 0, len = queryBits.length; i < len; i++) {',

+'						nameValueBits = queryBits[i].split("=");',

+'						if (nameValueBits[0] == "log4javascript_domain") {',

+'							document.domain = nameValueBits[1];',

+'							break;',

+'						}',

+'					}',

+'				}',

+'',

+'				// Create DOM objects',

+'				logMainContainer = $("log");',

+'				if (isIePre7) {',

+'					addClass(logMainContainer, "oldIe");',

+'				}',

+'',

+'				rootGroup = new Group("root", true);',

+'				rootGroup.render();',

+'				currentGroup = rootGroup;',

+'				',

+'				setCommandInputWidth();',

+'				setLogContainerHeight();',

+'				toggleLoggingEnabled();',

+'				toggleSearchEnabled();',

+'				toggleSearchFilter();',

+'				toggleSearchHighlight();',

+'				applyFilters();',

+'				checkAllLevels();',

+'				toggleWrap();',

+'				toggleNewestAtTop();',

+'				toggleScrollToLatest();',

+'				renderQueuedLogItems();',

+'				loaded = true;',

+'				$("command").value = "";',

+'				$("command").autocomplete = "off";',

+'				$("command").onkeydown = function(evt) {',

+'					evt = getEvent(evt);',

+'					if (evt.keyCode == 10 || evt.keyCode == 13) { // Return/Enter',

+'						evalCommandLine();',

+'						stopPropagation(evt);',

+'					} else if (evt.keyCode == 27) { // Escape',

+'						this.value = "";',

+'						this.focus();',

+'					} else if (evt.keyCode == 38 && commandHistory.length > 0) { // Up',

+'						currentCommandIndex = Math.max(0, currentCommandIndex - 1);',

+'						this.value = commandHistory[currentCommandIndex];',

+'						moveCaretToEnd(this);',

+'					} else if (evt.keyCode == 40 && commandHistory.length > 0) { // Down',

+'						currentCommandIndex = Math.min(commandHistory.length - 1, currentCommandIndex + 1);',

+'						this.value = commandHistory[currentCommandIndex];',

+'						moveCaretToEnd(this);',

+'					}',

+'				};',

+'',

+'				// Prevent the keypress moving the caret in Firefox',

+'				$("command").onkeypress = function(evt) {',

+'					evt = getEvent(evt);',

+'					if (evt.keyCode == 38 && commandHistory.length > 0 && evt.preventDefault) { // Up',

+'						evt.preventDefault();',

+'					}',

+'				};',

+'',

+'				// Prevent the keyup event blurring the input in Opera',

+'				$("command").onkeyup = function(evt) {',

+'					evt = getEvent(evt);',

+'					if (evt.keyCode == 27 && evt.preventDefault) { // Up',

+'						evt.preventDefault();',

+'						this.focus();',

+'					}',

+'				};',

+'',

+'				// Add document keyboard shortcuts',

+'				document.onkeydown = function keyEventHandler(evt) {',

+'					evt = getEvent(evt);',

+'					switch (evt.keyCode) {',

+'						case 69: // Ctrl + shift + E: re-execute last command',

+'							if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {',

+'								evalLastCommand();',

+'								cancelKeyEvent(evt);',

+'								return false;',

+'							}',

+'							break;',

+'						case 75: // Ctrl + shift + K: focus search',

+'							if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {',

+'								focusSearch();',

+'								cancelKeyEvent(evt);',

+'								return false;',

+'							}',

+'							break;',

+'						case 40: // Ctrl + shift + down arrow: focus command line',

+'						case 76: // Ctrl + shift + L: focus command line',

+'							if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {',

+'								focusCommandLine();',

+'								cancelKeyEvent(evt);',

+'								return false;',

+'							}',

+'							break;',

+'					}',

+'				};',

+'',

+'				// Workaround to make sure log div starts at the correct size',

+'				setTimeout(setLogContainerHeight, 20);',

+'',

+'				setShowCommandLine(showCommandLine);',

+'				doSearch();',

+'			};',

+'',

+'			window.onunload = function() {',

+'				if (mainWindowExists()) {',

+'					appender.unload();',

+'				}',

+'				appender = null;',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function toggleLoggingEnabled() {',

+'				setLoggingEnabled($("enableLogging").checked);',

+'			}',

+'',

+'			function setLoggingEnabled(enable) {',

+'				loggingEnabled = enable;',

+'			}',

+'',

+'			var appender = null;',

+'',

+'			function setAppender(appenderParam) {',

+'				appender = appenderParam;',

+'			}',

+'',

+'			function setShowCloseButton(showCloseButton) {',

+'				$("closeButton").style.display = showCloseButton ? "inline" : "none";',

+'			}',

+'',

+'			function setShowHideButton(showHideButton) {',

+'				$("hideButton").style.display = showHideButton ? "inline" : "none";',

+'			}',

+'',

+'			var newestAtTop = false;',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogItemContentReverser() {',

+'			}',

+'			',

+'			LogItemContentReverser.prototype = new LogItemVisitor();',

+'			',

+'			LogItemContentReverser.prototype.visitGroup = function(group) {',

+'				group.reverseChildren();',

+'				this.visitChildren(group);',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function setNewestAtTop(isNewestAtTop) {',

+'				var oldNewestAtTop = newestAtTop;',

+'				var i, iLen, j, jLen;',

+'				newestAtTop = Boolean(isNewestAtTop);',

+'				if (oldNewestAtTop != newestAtTop) {',

+'					var visitor = new LogItemContentReverser();',

+'					rootGroup.accept(visitor);',

+'',

+'					// Reassemble the matches array',

+'					if (currentSearch) {',

+'						var currentMatch = currentSearch.matches[currentMatchIndex];',

+'						var matchIndex = 0;',

+'						var matches = [];',

+'						var actOnLogEntry = function(logEntry) {',

+'							var logEntryMatches = logEntry.getSearchMatches();',

+'							for (j = 0, jLen = logEntryMatches.length; j < jLen; j++) {',

+'								matches[matchIndex] = logEntryMatches[j];',

+'								if (currentMatch && logEntryMatches[j].equals(currentMatch)) {',

+'									currentMatchIndex = matchIndex;',

+'								}',

+'								matchIndex++;',

+'							}',

+'						};',

+'						if (newestAtTop) {',

+'							for (i = logEntries.length - 1; i >= 0; i--) {',

+'								actOnLogEntry(logEntries[i]);',

+'							}',

+'						} else {',

+'							for (i = 0, iLen = logEntries.length; i < iLen; i++) {',

+'								actOnLogEntry(logEntries[i]);',

+'							}',

+'						}',

+'						currentSearch.matches = matches;',

+'						if (currentMatch) {',

+'							currentMatch.setCurrent();',

+'						}',

+'					} else if (scrollToLatest) {',

+'						doScrollToLatest();',

+'					}',

+'				}',

+'				$("newestAtTop").checked = isNewestAtTop;',

+'			}',

+'',

+'			function toggleNewestAtTop() {',

+'				var isNewestAtTop = $("newestAtTop").checked;',

+'				setNewestAtTop(isNewestAtTop);',

+'			}',

+'',

+'			var scrollToLatest = true;',

+'',

+'			function setScrollToLatest(isScrollToLatest) {',

+'				scrollToLatest = isScrollToLatest;',

+'				if (scrollToLatest) {',

+'					doScrollToLatest();',

+'				}',

+'				$("scrollToLatest").checked = isScrollToLatest;',

+'			}',

+'',

+'			function toggleScrollToLatest() {',

+'				var isScrollToLatest = $("scrollToLatest").checked;',

+'				setScrollToLatest(isScrollToLatest);',

+'			}',

+'',

+'			function doScrollToLatest() {',

+'				var l = logMainContainer;',

+'				if (typeof l.scrollTop != "undefined") {',

+'					if (newestAtTop) {',

+'						l.scrollTop = 0;',

+'					} else {',

+'						var latestLogEntry = l.lastChild;',

+'						if (latestLogEntry) {',

+'							l.scrollTop = l.scrollHeight;',

+'						}',

+'					}',

+'				}',

+'			}',

+'',

+'			var closeIfOpenerCloses = true;',

+'',

+'			function setCloseIfOpenerCloses(isCloseIfOpenerCloses) {',

+'				closeIfOpenerCloses = isCloseIfOpenerCloses;',

+'			}',

+'',

+'			var maxMessages = null;',

+'',

+'			function setMaxMessages(max) {',

+'				maxMessages = max;',

+'				pruneLogEntries();',

+'			}',

+'',

+'			var showCommandLine = false;',

+'',

+'			function setShowCommandLine(isShowCommandLine) {',

+'				showCommandLine = isShowCommandLine;',

+'				if (loaded) {',

+'					$("commandLine").style.display = showCommandLine ? "block" : "none";',

+'					setCommandInputWidth();',

+'					setLogContainerHeight();',

+'				}',

+'			}',

+'',

+'			function focusCommandLine() {',

+'				if (loaded) {',

+'					$("command").focus();',

+'				}',

+'			}',

+'',

+'			function focusSearch() {',

+'				if (loaded) {',

+'					$("searchBox").focus();',

+'				}',

+'			}',

+'',

+'			function getLogItems() {',

+'				var items = [];',

+'				for (var i = 0, len = logItems.length; i < len; i++) {',

+'					logItems[i].serialize(items);',

+'				}',

+'				return items;',

+'			}',

+'',

+'			function setLogItems(items) {',

+'				var loggingReallyEnabled = loggingEnabled;',

+'				// Temporarily turn logging on',

+'				loggingEnabled = true;',

+'				for (var i = 0, len = items.length; i < len; i++) {',

+'					switch (items[i][0]) {',

+'						case LogItem.serializedItemKeys.LOG_ENTRY:',

+'							log(items[i][1], items[i][2]);',

+'							break;',

+'						case LogItem.serializedItemKeys.GROUP_START:',

+'							group(items[i][1]);',

+'							break;',

+'						case LogItem.serializedItemKeys.GROUP_END:',

+'							groupEnd();',

+'							break;',

+'					}',

+'				}',

+'				loggingEnabled = loggingReallyEnabled;',

+'			}',

+'',

+'			function log(logLevel, formattedMessage) {',

+'				if (loggingEnabled) {',

+'					var logEntry = new LogEntry(logLevel, formattedMessage);',

+'					logEntries.push(logEntry);',

+'					logEntriesAndSeparators.push(logEntry);',

+'					logItems.push(logEntry);',

+'					currentGroup.addChild(logEntry);',

+'					if (loaded) {',

+'						if (logQueuedEventsTimer !== null) {',

+'							clearTimeout(logQueuedEventsTimer);',

+'						}',

+'						logQueuedEventsTimer = setTimeout(renderQueuedLogItems, renderDelay);',

+'						unrenderedLogItemsExist = true;',

+'					}',

+'				}',

+'			}',

+'',

+'			function renderQueuedLogItems() {',

+'				logQueuedEventsTimer = null;',

+'				var pruned = pruneLogEntries();',

+'',

+'				// Render any unrendered log entries and apply the current search to them',

+'				var initiallyHasMatches = currentSearch ? currentSearch.hasMatches() : false;',

+'				for (var i = 0, len = logItems.length; i < len; i++) {',

+'					if (!logItems[i].rendered) {',

+'						logItems[i].render();',

+'						logItems[i].appendToLog();',

+'						if (currentSearch && (logItems[i] instanceof LogEntry)) {',

+'							currentSearch.applyTo(logItems[i]);',

+'						}',

+'					}',

+'				}',

+'				if (currentSearch) {',

+'					if (pruned) {',

+'						if (currentSearch.hasVisibleMatches()) {',

+'							if (currentMatchIndex === null) {',

+'								setCurrentMatchIndex(0);',

+'							}',

+'							displayMatches();',

+'						} else {',

+'							displayNoMatches();',

+'						}',

+'					} else if (!initiallyHasMatches && currentSearch.hasVisibleMatches()) {',

+'						setCurrentMatchIndex(0);',

+'						displayMatches();',

+'					}',

+'				}',

+'				if (scrollToLatest) {',

+'					doScrollToLatest();',

+'				}',

+'				unrenderedLogItemsExist = false;',

+'			}',

+'',

+'			function pruneLogEntries() {',

+'				if ((maxMessages !== null) && (logEntriesAndSeparators.length > maxMessages)) {',

+'					var numberToDelete = logEntriesAndSeparators.length - maxMessages;',

+'					var prunedLogEntries = logEntriesAndSeparators.slice(0, numberToDelete);',

+'					if (currentSearch) {',

+'						currentSearch.removeMatches(prunedLogEntries);',

+'					}',

+'					var group;',

+'					for (var i = 0; i < numberToDelete; i++) {',

+'						group = logEntriesAndSeparators[i].group;',

+'						array_remove(logItems, logEntriesAndSeparators[i]);',

+'						array_remove(logEntries, logEntriesAndSeparators[i]);',

+'						logEntriesAndSeparators[i].remove(true, true);',

+'						if (group.children.length === 0 && group !== currentGroup && group !== rootGroup) {',

+'							array_remove(logItems, group);',

+'							group.remove(true, true);',

+'						}',

+'					}',

+'					logEntriesAndSeparators = array_removeFromStart(logEntriesAndSeparators, numberToDelete);',

+'					return true;',

+'				}',

+'				return false;',

+'			}',

+'',

+'			function group(name, startExpanded) {',

+'				if (loggingEnabled) {',

+'					initiallyExpanded = (typeof startExpanded === "undefined") ? true : Boolean(startExpanded);',

+'					var newGroup = new Group(name, false, initiallyExpanded);',

+'					currentGroup.addChild(newGroup);',

+'					currentGroup = newGroup;',

+'					logItems.push(newGroup);',

+'					if (loaded) {',

+'						if (logQueuedEventsTimer !== null) {',

+'							clearTimeout(logQueuedEventsTimer);',

+'						}',

+'						logQueuedEventsTimer = setTimeout(renderQueuedLogItems, renderDelay);',

+'						unrenderedLogItemsExist = true;',

+'					}',

+'				}',

+'			}',

+'',

+'			function groupEnd() {',

+'				currentGroup = (currentGroup === rootGroup) ? rootGroup : currentGroup.group;',

+'			}',

+'',

+'			function mainPageReloaded() {',

+'				currentGroup = rootGroup;',

+'				var separator = new Separator();',

+'				logEntriesAndSeparators.push(separator);',

+'				logItems.push(separator);',

+'				currentGroup.addChild(separator);',

+'			}',

+'',

+'			function closeWindow() {',

+'				if (appender && mainWindowExists()) {',

+'					appender.close(true);',

+'				} else {',

+'					window.close();',

+'				}',

+'			}',

+'',

+'			function hide() {',

+'				if (appender && mainWindowExists()) {',

+'					appender.hide();',

+'				}',

+'			}',

+'',

+'			var mainWindow = window;',

+'			var windowId = "log4javascriptConsoleWindow_" + new Date().getTime() + "_" + ("" + Math.random()).substr(2);',

+'',

+'			function setMainWindow(win) {',

+'				mainWindow = win;',

+'				mainWindow[windowId] = window;',

+'				// If this is a pop-up, poll the opener to see if it\'s closed',

+'				if (opener && closeIfOpenerCloses) {',

+'					pollOpener();',

+'				}',

+'			}',

+'',

+'			function pollOpener() {',

+'				if (closeIfOpenerCloses) {',

+'					if (mainWindowExists()) {',

+'						setTimeout(pollOpener, 500);',

+'					} else {',

+'						closeWindow();',

+'					}',

+'				}',

+'			}',

+'',

+'			function mainWindowExists() {',

+'				try {',

+'					return (mainWindow && !mainWindow.closed &&',

+'						mainWindow[windowId] == window);',

+'				} catch (ex) {}',

+'				return false;',

+'			}',

+'',

+'			var logLevels = ["TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"];',

+'',

+'			function getCheckBox(logLevel) {',

+'				return $("switch_" + logLevel);',

+'			}',

+'',

+'			function getIeWrappedLogContainer() {',

+'				return $("log_wrapped");',

+'			}',

+'',

+'			function getIeUnwrappedLogContainer() {',

+'				return $("log_unwrapped");',

+'			}',

+'',

+'			function applyFilters() {',

+'				for (var i = 0; i < logLevels.length; i++) {',

+'					if (getCheckBox(logLevels[i]).checked) {',

+'						addClass(logMainContainer, logLevels[i]);',

+'					} else {',

+'						removeClass(logMainContainer, logLevels[i]);',

+'					}',

+'				}',

+'				updateSearchFromFilters();',

+'			}',

+'',

+'			function toggleAllLevels() {',

+'				var turnOn = $("switch_ALL").checked;',

+'				for (var i = 0; i < logLevels.length; i++) {',

+'					getCheckBox(logLevels[i]).checked = turnOn;',

+'					if (turnOn) {',

+'						addClass(logMainContainer, logLevels[i]);',

+'					} else {',

+'						removeClass(logMainContainer, logLevels[i]);',

+'					}',

+'				}',

+'			}',

+'',

+'			function checkAllLevels() {',

+'				for (var i = 0; i < logLevels.length; i++) {',

+'					if (!getCheckBox(logLevels[i]).checked) {',

+'						getCheckBox("ALL").checked = false;',

+'						return;',

+'					}',

+'				}',

+'				getCheckBox("ALL").checked = true;',

+'			}',

+'',

+'			function clearLog() {',

+'				rootGroup.clear();',

+'				currentGroup = rootGroup;',

+'				logEntries = [];',

+'				logItems = [];',

+'				logEntriesAndSeparators = [];',

+' 				doSearch();',

+'			}',

+'',

+'			function toggleWrap() {',

+'				var enable = $("wrap").checked;',

+'				if (enable) {',

+'					addClass(logMainContainer, "wrap");',

+'				} else {',

+'					removeClass(logMainContainer, "wrap");',

+'				}',

+'				refreshCurrentMatch();',

+'			}',

+'',

+'			/* ------------------------------------------------------------------- */',

+'',

+'			// Search',

+'',

+'			var searchTimer = null;',

+'',

+'			function scheduleSearch() {',

+'				try {',

+'					clearTimeout(searchTimer);',

+'				} catch (ex) {',

+'					// Do nothing',

+'				}',

+'				searchTimer = setTimeout(doSearch, 500);',

+'			}',

+'',

+'			function Search(searchTerm, isRegex, searchRegex, isCaseSensitive) {',

+'				this.searchTerm = searchTerm;',

+'				this.isRegex = isRegex;',

+'				this.searchRegex = searchRegex;',

+'				this.isCaseSensitive = isCaseSensitive;',

+'				this.matches = [];',

+'			}',

+'',

+'			Search.prototype = {',

+'				hasMatches: function() {',

+'					return this.matches.length > 0;',

+'				},',

+'',

+'				hasVisibleMatches: function() {',

+'					if (this.hasMatches()) {',

+'						for (var i = 0; i < this.matches.length; i++) {',

+'							if (this.matches[i].isVisible()) {',

+'								return true;',

+'							}',

+'						}',

+'					}',

+'					return false;',

+'				},',

+'',

+'				match: function(logEntry) {',

+'					var entryText = String(logEntry.formattedMessage);',

+'					var matchesSearch = false;',

+'					if (this.isRegex) {',

+'						matchesSearch = this.searchRegex.test(entryText);',

+'					} else if (this.isCaseSensitive) {',

+'						matchesSearch = (entryText.indexOf(this.searchTerm) > -1);',

+'					} else {',

+'						matchesSearch = (entryText.toLowerCase().indexOf(this.searchTerm.toLowerCase()) > -1);',

+'					}',

+'					return matchesSearch;',

+'				},',

+'',

+'				getNextVisibleMatchIndex: function() {',

+'					for (var i = currentMatchIndex + 1; i < this.matches.length; i++) {',

+'						if (this.matches[i].isVisible()) {',

+'							return i;',

+'						}',

+'					}',

+'					// Start again from the first match',

+'					for (i = 0; i <= currentMatchIndex; i++) {',

+'						if (this.matches[i].isVisible()) {',

+'							return i;',

+'						}',

+'					}',

+'					return -1;',

+'				},',

+'',

+'				getPreviousVisibleMatchIndex: function() {',

+'					for (var i = currentMatchIndex - 1; i >= 0; i--) {',

+'						if (this.matches[i].isVisible()) {',

+'							return i;',

+'						}',

+'					}',

+'					// Start again from the last match',

+'					for (var i = this.matches.length - 1; i >= currentMatchIndex; i--) {',

+'						if (this.matches[i].isVisible()) {',

+'							return i;',

+'						}',

+'					}',

+'					return -1;',

+'				},',

+'',

+'				applyTo: function(logEntry) {',

+'					var doesMatch = this.match(logEntry);',

+'					if (doesMatch) {',

+'						logEntry.group.expand();',

+'						logEntry.setSearchMatch(true);',

+'						var logEntryContent;',

+'						var wrappedLogEntryContent;',

+'						var searchTermReplacementStartTag = "<span class=\\\"searchterm\\\">";',

+'						var searchTermReplacementEndTag = "<" + "/span>";',

+'						var preTagName = isIe ? "pre" : "span";',

+'						var preStartTag = "<" + preTagName + " class=\\\"pre\\\">";',

+'						var preEndTag = "<" + "/" + preTagName + ">";',

+'						var startIndex = 0;',

+'						var searchIndex, matchedText, textBeforeMatch;',

+'						if (this.isRegex) {',

+'							var flags = this.isCaseSensitive ? "g" : "gi";',

+'							var capturingRegex = new RegExp("(" + this.searchRegex.source + ")", flags);',

+'',

+'							// Replace the search term with temporary tokens for the start and end tags',

+'							var rnd = ("" + Math.random()).substr(2);',

+'							var startToken = "%%s" + rnd + "%%";',

+'							var endToken = "%%e" + rnd + "%%";',

+'							logEntryContent = logEntry.formattedMessage.replace(capturingRegex, startToken + "$1" + endToken);',

+'',

+'							// Escape the HTML to get rid of angle brackets',

+'							logEntryContent = escapeHtml(logEntryContent);',

+'',

+'							// Substitute the proper HTML back in for the search match',

+'							var result;',

+'							var searchString = logEntryContent;',

+'							logEntryContent = "";',

+'							wrappedLogEntryContent = "";',

+'							while ((searchIndex = searchString.indexOf(startToken, startIndex)) > -1) {',

+'								var endTokenIndex = searchString.indexOf(endToken, searchIndex);',

+'								matchedText = searchString.substring(searchIndex + startToken.length, endTokenIndex);',

+'								textBeforeMatch = searchString.substring(startIndex, searchIndex);',

+'								logEntryContent += preStartTag + textBeforeMatch + preEndTag;',

+'								logEntryContent += searchTermReplacementStartTag + preStartTag + matchedText +',

+'									preEndTag + searchTermReplacementEndTag;',

+'								if (isIe) {',

+'									wrappedLogEntryContent += textBeforeMatch + searchTermReplacementStartTag +',

+'										matchedText + searchTermReplacementEndTag;',

+'								}',

+'								startIndex = endTokenIndex + endToken.length;',

+'							}',

+'							logEntryContent += preStartTag + searchString.substr(startIndex) + preEndTag;',

+'							if (isIe) {',

+'								wrappedLogEntryContent += searchString.substr(startIndex);',

+'							}',

+'						} else {',

+'							logEntryContent = "";',

+'							wrappedLogEntryContent = "";',

+'							var searchTermReplacementLength = searchTermReplacementStartTag.length +',

+'								this.searchTerm.length + searchTermReplacementEndTag.length;',

+'							var searchTermLength = this.searchTerm.length;',

+'							var searchTermLowerCase = this.searchTerm.toLowerCase();',

+'							var logTextLowerCase = logEntry.formattedMessage.toLowerCase();',

+'							while ((searchIndex = logTextLowerCase.indexOf(searchTermLowerCase, startIndex)) > -1) {',

+'								matchedText = escapeHtml(logEntry.formattedMessage.substr(searchIndex, this.searchTerm.length));',

+'								textBeforeMatch = escapeHtml(logEntry.formattedMessage.substring(startIndex, searchIndex));',

+'								var searchTermReplacement = searchTermReplacementStartTag +',

+'									preStartTag + matchedText + preEndTag + searchTermReplacementEndTag;',

+'								logEntryContent += preStartTag + textBeforeMatch + preEndTag + searchTermReplacement;',

+'								if (isIe) {',

+'									wrappedLogEntryContent += textBeforeMatch + searchTermReplacementStartTag +',

+'										matchedText + searchTermReplacementEndTag;',

+'								}',

+'								startIndex = searchIndex + searchTermLength;',

+'							}',

+'							var textAfterLastMatch = escapeHtml(logEntry.formattedMessage.substr(startIndex));',

+'							logEntryContent += preStartTag + textAfterLastMatch + preEndTag;',

+'							if (isIe) {',

+'								wrappedLogEntryContent += textAfterLastMatch;',

+'							}',

+'						}',

+'						logEntry.setContent(logEntryContent, wrappedLogEntryContent);',

+'						var logEntryMatches = logEntry.getSearchMatches();',

+'						this.matches = this.matches.concat(logEntryMatches);',

+'					} else {',

+'						logEntry.setSearchMatch(false);',

+'						logEntry.setContent(logEntry.formattedMessage, logEntry.formattedMessage);',

+'					}',

+'					return doesMatch;',

+'				},',

+'',

+'				removeMatches: function(logEntries) {',

+'					var matchesToRemoveCount = 0;',

+'					var currentMatchRemoved = false;',

+'					var matchesToRemove = [];',

+'					var i, iLen, j, jLen;',

+'',

+'					// Establish the list of matches to be removed',

+'					for (i = 0, iLen = this.matches.length; i < iLen; i++) {',

+'						for (j = 0, jLen = logEntries.length; j < jLen; j++) {',

+'							if (this.matches[i].belongsTo(logEntries[j])) {',

+'								matchesToRemove.push(this.matches[i]);',

+'								if (i === currentMatchIndex) {',

+'									currentMatchRemoved = true;',

+'								}',

+'							}',

+'						}',

+'					}',

+'',

+'					// Set the new current match index if the current match has been deleted',

+'					// This will be the first match that appears after the first log entry being',

+'					// deleted, if one exists; otherwise, it\'s the first match overall',

+'					var newMatch = currentMatchRemoved ? null : this.matches[currentMatchIndex];',

+'					if (currentMatchRemoved) {',

+'						for (i = currentMatchIndex, iLen = this.matches.length; i < iLen; i++) {',

+'							if (this.matches[i].isVisible() && !array_contains(matchesToRemove, this.matches[i])) {',

+'								newMatch = this.matches[i];',

+'								break;',

+'							}',

+'						}',

+'					}',

+'',

+'					// Remove the matches',

+'					for (i = 0, iLen = matchesToRemove.length; i < iLen; i++) {',

+'						array_remove(this.matches, matchesToRemove[i]);',

+'						matchesToRemove[i].remove();',

+'					}',

+'',

+'					// Set the new match, if one exists',

+'					if (this.hasVisibleMatches()) {',

+'						if (newMatch === null) {',

+'							setCurrentMatchIndex(0);',

+'						} else {',

+'							// Get the index of the new match',

+'							var newMatchIndex = 0;',

+'							for (i = 0, iLen = this.matches.length; i < iLen; i++) {',

+'								if (newMatch === this.matches[i]) {',

+'									newMatchIndex = i;',

+'									break;',

+'								}',

+'							}',

+'							setCurrentMatchIndex(newMatchIndex);',

+'						}',

+'					} else {',

+'						currentMatchIndex = null;',

+'						displayNoMatches();',

+'					}',

+'				}',

+'			};',

+'',

+'			function getPageOffsetTop(el, container) {',

+'				var currentEl = el;',

+'				var y = 0;',

+'				while (currentEl && currentEl != container) {',

+'					y += currentEl.offsetTop;',

+'					currentEl = currentEl.offsetParent;',

+'				}',

+'				return y;',

+'			}',

+'',

+'			function scrollIntoView(el) {',

+'				var logContainer = logMainContainer;',

+'				// Check if the whole width of the element is visible and centre if not',

+'				if (!$("wrap").checked) {',

+'					var logContainerLeft = logContainer.scrollLeft;',

+'					var logContainerRight = logContainerLeft  + logContainer.offsetWidth;',

+'					var elLeft = el.offsetLeft;',

+'					var elRight = elLeft + el.offsetWidth;',

+'					if (elLeft < logContainerLeft || elRight > logContainerRight) {',

+'						logContainer.scrollLeft = elLeft - (logContainer.offsetWidth - el.offsetWidth) / 2;',

+'					}',

+'				}',

+'				// Check if the whole height of the element is visible and centre if not',

+'				var logContainerTop = logContainer.scrollTop;',

+'				var logContainerBottom = logContainerTop  + logContainer.offsetHeight;',

+'				var elTop = getPageOffsetTop(el) - getToolBarsHeight();',

+'				var elBottom = elTop + el.offsetHeight;',

+'				if (elTop < logContainerTop || elBottom > logContainerBottom) {',

+'					logContainer.scrollTop = elTop - (logContainer.offsetHeight - el.offsetHeight) / 2;',

+'				}',

+'			}',

+'',

+'			function Match(logEntryLevel, spanInMainDiv, spanInUnwrappedPre, spanInWrappedDiv) {',

+'				this.logEntryLevel = logEntryLevel;',

+'				this.spanInMainDiv = spanInMainDiv;',

+'				if (isIe) {',

+'					this.spanInUnwrappedPre = spanInUnwrappedPre;',

+'					this.spanInWrappedDiv = spanInWrappedDiv;',

+'				}',

+'				this.mainSpan = isIe ? spanInUnwrappedPre : spanInMainDiv;',

+'			}',

+'',

+'			Match.prototype = {',

+'				equals: function(match) {',

+'					return this.mainSpan === match.mainSpan;',

+'				},',

+'',

+'				setCurrent: function() {',

+'					if (isIe) {',

+'						addClass(this.spanInUnwrappedPre, "currentmatch");',

+'						addClass(this.spanInWrappedDiv, "currentmatch");',

+'						// Scroll the visible one into view',

+'						var elementToScroll = $("wrap").checked ? this.spanInWrappedDiv : this.spanInUnwrappedPre;',

+'						scrollIntoView(elementToScroll);',

+'					} else {',

+'						addClass(this.spanInMainDiv, "currentmatch");',

+'						scrollIntoView(this.spanInMainDiv);',

+'					}',

+'				},',

+'',

+'				belongsTo: function(logEntry) {',

+'					if (isIe) {',

+'						return isDescendant(this.spanInUnwrappedPre, logEntry.unwrappedPre);',

+'					} else {',

+'						return isDescendant(this.spanInMainDiv, logEntry.mainDiv);',

+'					}',

+'				},',

+'',

+'				setNotCurrent: function() {',

+'					if (isIe) {',

+'						removeClass(this.spanInUnwrappedPre, "currentmatch");',

+'						removeClass(this.spanInWrappedDiv, "currentmatch");',

+'					} else {',

+'						removeClass(this.spanInMainDiv, "currentmatch");',

+'					}',

+'				},',

+'',

+'				isOrphan: function() {',

+'					return isOrphan(this.mainSpan);',

+'				},',

+'',

+'				isVisible: function() {',

+'					return getCheckBox(this.logEntryLevel).checked;',

+'				},',

+'',

+'				remove: function() {',

+'					if (isIe) {',

+'						this.spanInUnwrappedPre = null;',

+'						this.spanInWrappedDiv = null;',

+'					} else {',

+'						this.spanInMainDiv = null;',

+'					}',

+'				}',

+'			};',

+'',

+'			var currentSearch = null;',

+'			var currentMatchIndex = null;',

+'',

+'			function doSearch() {',

+'				var searchBox = $("searchBox");',

+'				var searchTerm = searchBox.value;',

+'				var isRegex = $("searchRegex").checked;',

+'				var isCaseSensitive = $("searchCaseSensitive").checked;',

+'				var i;',

+'',

+'				if (searchTerm === "") {',

+'					$("searchReset").disabled = true;',

+'					$("searchNav").style.display = "none";',

+'					removeClass(document.body, "searching");',

+'					removeClass(searchBox, "hasmatches");',

+'					removeClass(searchBox, "nomatches");',

+'					for (i = 0; i < logEntries.length; i++) {',

+'						logEntries[i].clearSearch();',

+'						logEntries[i].setContent(logEntries[i].formattedMessage, logEntries[i].formattedMessage);',

+'					}',

+'					currentSearch = null;',

+'					setLogContainerHeight();',

+'				} else {',

+'					$("searchReset").disabled = false;',

+'					$("searchNav").style.display = "block";',

+'					var searchRegex;',

+'					var regexValid;',

+'					if (isRegex) {',

+'						try {',

+'							searchRegex = isCaseSensitive ? new RegExp(searchTerm, "g") : new RegExp(searchTerm, "gi");',

+'							regexValid = true;',

+'							replaceClass(searchBox, "validregex", "invalidregex");',

+'							searchBox.title = "Valid regex";',

+'						} catch (ex) {',

+'							regexValid = false;',

+'							replaceClass(searchBox, "invalidregex", "validregex");',

+'							searchBox.title = "Invalid regex: " + (ex.message ? ex.message : (ex.description ? ex.description : "unknown error"));',

+'							return;',

+'						}',

+'					} else {',

+'						searchBox.title = "";',

+'						removeClass(searchBox, "validregex");',

+'						removeClass(searchBox, "invalidregex");',

+'					}',

+'					addClass(document.body, "searching");',

+'					currentSearch = new Search(searchTerm, isRegex, searchRegex, isCaseSensitive);',

+'					for (i = 0; i < logEntries.length; i++) {',

+'						currentSearch.applyTo(logEntries[i]);',

+'					}',

+'					setLogContainerHeight();',

+'',

+'					// Highlight the first search match',

+'					if (currentSearch.hasVisibleMatches()) {',

+'						setCurrentMatchIndex(0);',

+'						displayMatches();',

+'					} else {',

+'						displayNoMatches();',

+'					}',

+'				}',

+'			}',

+'',

+'			function updateSearchFromFilters() {',

+'				if (currentSearch) {',

+'					if (currentSearch.hasMatches()) {',

+'						if (currentMatchIndex === null) {',

+'							currentMatchIndex = 0;',

+'						}',

+'						var currentMatch = currentSearch.matches[currentMatchIndex];',

+'						if (currentMatch.isVisible()) {',

+'							displayMatches();',

+'							setCurrentMatchIndex(currentMatchIndex);',

+'						} else {',

+'							currentMatch.setNotCurrent();',

+'							// Find the next visible match, if one exists',

+'							var nextVisibleMatchIndex = currentSearch.getNextVisibleMatchIndex();',

+'							if (nextVisibleMatchIndex > -1) {',

+'								setCurrentMatchIndex(nextVisibleMatchIndex);',

+'								displayMatches();',

+'							} else {',

+'								displayNoMatches();',

+'							}',

+'						}',

+'					} else {',

+'						displayNoMatches();',

+'					}',

+'				}',

+'			}',

+'',

+'			function refreshCurrentMatch() {',

+'				if (currentSearch && currentSearch.hasVisibleMatches()) {',

+'					setCurrentMatchIndex(currentMatchIndex);',

+'				}',

+'			}',

+'',

+'			function displayMatches() {',

+'				replaceClass($("searchBox"), "hasmatches", "nomatches");',

+'				$("searchBox").title = "" + currentSearch.matches.length + " matches found";',

+'				$("searchNav").style.display = "block";',

+'				setLogContainerHeight();',

+'			}',

+'',

+'			function displayNoMatches() {',

+'				replaceClass($("searchBox"), "nomatches", "hasmatches");',

+'				$("searchBox").title = "No matches found";',

+'				$("searchNav").style.display = "none";',

+'				setLogContainerHeight();',

+'			}',

+'',

+'			function toggleSearchEnabled(enable) {',

+'				enable = (typeof enable == "undefined") ? !$("searchDisable").checked : enable;',

+'				$("searchBox").disabled = !enable;',

+'				$("searchReset").disabled = !enable;',

+'				$("searchRegex").disabled = !enable;',

+'				$("searchNext").disabled = !enable;',

+'				$("searchPrevious").disabled = !enable;',

+'				$("searchCaseSensitive").disabled = !enable;',

+'				$("searchNav").style.display = (enable && ($("searchBox").value !== "") &&',

+'						currentSearch && currentSearch.hasVisibleMatches()) ?',

+'					"block" : "none";',

+'				if (enable) {',

+'					removeClass($("search"), "greyedout");',

+'					addClass(document.body, "searching");',

+'					if ($("searchHighlight").checked) {',

+'						addClass(logMainContainer, "searchhighlight");',

+'					} else {',

+'						removeClass(logMainContainer, "searchhighlight");',

+'					}',

+'					if ($("searchFilter").checked) {',

+'						addClass(logMainContainer, "searchfilter");',

+'					} else {',

+'						removeClass(logMainContainer, "searchfilter");',

+'					}',

+'					$("searchDisable").checked = !enable;',

+'				} else {',

+'					addClass($("search"), "greyedout");',

+'					removeClass(document.body, "searching");',

+'					removeClass(logMainContainer, "searchhighlight");',

+'					removeClass(logMainContainer, "searchfilter");',

+'				}',

+'				setLogContainerHeight();',

+'			}',

+'',

+'			function toggleSearchFilter() {',

+'				var enable = $("searchFilter").checked;',

+'				if (enable) {',

+'					addClass(logMainContainer, "searchfilter");',

+'				} else {',

+'					removeClass(logMainContainer, "searchfilter");',

+'				}',

+'				refreshCurrentMatch();',

+'			}',

+'',

+'			function toggleSearchHighlight() {',

+'				var enable = $("searchHighlight").checked;',

+'				if (enable) {',

+'					addClass(logMainContainer, "searchhighlight");',

+'				} else {',

+'					removeClass(logMainContainer, "searchhighlight");',

+'				}',

+'			}',

+'',

+'			function clearSearch() {',

+'				$("searchBox").value = "";',

+'				doSearch();',

+'			}',

+'',

+'			function searchNext() {',

+'				if (currentSearch !== null && currentMatchIndex !== null) {',

+'					currentSearch.matches[currentMatchIndex].setNotCurrent();',

+'					var nextMatchIndex = currentSearch.getNextVisibleMatchIndex();',

+'					if (nextMatchIndex > currentMatchIndex || confirm("Reached the end of the page. Start from the top?")) {',

+'						setCurrentMatchIndex(nextMatchIndex);',

+'					}',

+'				}',

+'			}',

+'',

+'			function searchPrevious() {',

+'				if (currentSearch !== null && currentMatchIndex !== null) {',

+'					currentSearch.matches[currentMatchIndex].setNotCurrent();',

+'					var previousMatchIndex = currentSearch.getPreviousVisibleMatchIndex();',

+'					if (previousMatchIndex < currentMatchIndex || confirm("Reached the start of the page. Continue from the bottom?")) {',

+'						setCurrentMatchIndex(previousMatchIndex);',

+'					}',

+'				}',

+'			}',

+'',

+'			function setCurrentMatchIndex(index) {',

+'				currentMatchIndex = index;',

+'				currentSearch.matches[currentMatchIndex].setCurrent();',

+'			}',

+'',

+'			/* ------------------------------------------------------------------------- */',

+'',

+'			// CSS Utilities',

+'',

+'			function addClass(el, cssClass) {',

+'				if (!hasClass(el, cssClass)) {',

+'					if (el.className) {',

+'						el.className += " " + cssClass;',

+'					} else {',

+'						el.className = cssClass;',

+'					}',

+'				}',

+'			}',

+'',

+'			function hasClass(el, cssClass) {',

+'				if (el.className) {',

+'					var classNames = el.className.split(" ");',

+'					return array_contains(classNames, cssClass);',

+'				}',

+'				return false;',

+'			}',

+'',

+'			function removeClass(el, cssClass) {',

+'				if (hasClass(el, cssClass)) {',

+'					// Rebuild the className property',

+'					var existingClasses = el.className.split(" ");',

+'					var newClasses = [];',

+'					for (var i = 0, len = existingClasses.length; i < len; i++) {',

+'						if (existingClasses[i] != cssClass) {',

+'							newClasses[newClasses.length] = existingClasses[i];',

+'						}',

+'					}',

+'					el.className = newClasses.join(" ");',

+'				}',

+'			}',

+'',

+'			function replaceClass(el, newCssClass, oldCssClass) {',

+'				removeClass(el, oldCssClass);',

+'				addClass(el, newCssClass);',

+'			}',

+'',

+'			/* ------------------------------------------------------------------------- */',

+'',

+'			// Other utility functions',

+'',

+'			function getElementsByClass(el, cssClass, tagName) {',

+'				var elements = el.getElementsByTagName(tagName);',

+'				var matches = [];',

+'				for (var i = 0, len = elements.length; i < len; i++) {',

+'					if (hasClass(elements[i], cssClass)) {',

+'						matches.push(elements[i]);',

+'					}',

+'				}',

+'				return matches;',

+'			}',

+'',

+'			// Syntax borrowed from Prototype library',

+'			function $(id) {',

+'				return document.getElementById(id);',

+'			}',

+'',

+'			function isDescendant(node, ancestorNode) {',

+'				while (node != null) {',

+'					if (node === ancestorNode) {',

+'						return true;',

+'					}',

+'					node = node.parentNode;',

+'				}',

+'				return false;',

+'			}',

+'',

+'			function isOrphan(node) {',

+'				var currentNode = node;',

+'				while (currentNode) {',

+'					if (currentNode == document.body) {',

+'						return false;',

+'					}',

+'					currentNode = currentNode.parentNode;',

+'				}',

+'				return true;',

+'			}',

+'',

+'			function escapeHtml(str) {',

+'				return str.replace(/&/g, "&amp;").replace(/[<]/g, "&lt;").replace(/>/g, "&gt;");',

+'			}',

+'',

+'			function getWindowWidth() {',

+'				if (window.innerWidth) {',

+'					return window.innerWidth;',

+'				} else if (document.documentElement && document.documentElement.clientWidth) {',

+'					return document.documentElement.clientWidth;',

+'				} else if (document.body) {',

+'					return document.body.clientWidth;',

+'				}',

+'				return 0;',

+'			}',

+'',

+'			function getWindowHeight() {',

+'				if (window.innerHeight) {',

+'					return window.innerHeight;',

+'				} else if (document.documentElement && document.documentElement.clientHeight) {',

+'					return document.documentElement.clientHeight;',

+'				} else if (document.body) {',

+'					return document.body.clientHeight;',

+'				}',

+'				return 0;',

+'			}',

+'',

+'			function getToolBarsHeight() {',

+'				return $("switches").offsetHeight;',

+'			}',

+'',

+'			function getChromeHeight() {',

+'				var height = getToolBarsHeight();',

+'				if (showCommandLine) {',

+'					height += $("commandLine").offsetHeight;',

+'				}',

+'				return height;',

+'			}',

+'',

+'			function setLogContainerHeight() {',

+'				if (logMainContainer) {',

+'					var windowHeight = getWindowHeight();',

+'					$("body").style.height = getWindowHeight() + "px";',

+'					logMainContainer.style.height = "" +',

+'						Math.max(0, windowHeight - getChromeHeight()) + "px";',

+'				}',

+'			}',

+'',

+'			function setCommandInputWidth() {',

+'				if (showCommandLine) {',

+'					$("command").style.width = "" + Math.max(0, $("commandLineContainer").offsetWidth -',

+'						($("evaluateButton").offsetWidth + 13)) + "px";',

+'				}',

+'			}',

+'',

+'			window.onresize = function() {',

+'				setCommandInputWidth();',

+'				setLogContainerHeight();',

+'			};',

+'',

+'			if (!Array.prototype.push) {',

+'				Array.prototype.push = function() {',

+'			        for (var i = 0, len = arguments.length; i < len; i++){',

+'			            this[this.length] = arguments[i];',

+'			        }',

+'			        return this.length;',

+'				};',

+'			}',

+'',

+'			if (!Array.prototype.pop) {',

+'				Array.prototype.pop = function() {',

+'					if (this.length > 0) {',

+'						var val = this[this.length - 1];',

+'						this.length = this.length - 1;',

+'						return val;',

+'					}',

+'				};',

+'			}',

+'',

+'			if (!Array.prototype.shift) {',

+'				Array.prototype.shift = function() {',

+'					if (this.length > 0) {',

+'						var firstItem = this[0];',

+'						for (var i = 0, len = this.length - 1; i < len; i++) {',

+'							this[i] = this[i + 1];',

+'						}',

+'						this.length = this.length - 1;',

+'						return firstItem;',

+'					}',

+'				};',

+'			}',

+'',

+'			if (!Array.prototype.splice) {',

+'				Array.prototype.splice = function(startIndex, deleteCount) {',

+'					var itemsAfterDeleted = this.slice(startIndex + deleteCount);',

+'					var itemsDeleted = this.slice(startIndex, startIndex + deleteCount);',

+'					this.length = startIndex;',

+'					// Copy the arguments into a proper Array object',

+'					var argumentsArray = [];',

+'					for (var i = 0, len = arguments.length; i < len; i++) {',

+'						argumentsArray[i] = arguments[i];',

+'					}',

+'					var itemsToAppend = (argumentsArray.length > 2) ?',

+'						itemsAfterDeleted = argumentsArray.slice(2).concat(itemsAfterDeleted) : itemsAfterDeleted;',

+'					for (i = 0, len = itemsToAppend.length; i < len; i++) {',

+'						this.push(itemsToAppend[i]);',

+'					}',

+'					return itemsDeleted;',

+'				};',

+'			}',

+'',

+'			function array_remove(arr, val) {',

+'				var index = -1;',

+'				for (var i = 0, len = arr.length; i < len; i++) {',

+'					if (arr[i] === val) {',

+'						index = i;',

+'						break;',

+'					}',

+'				}',

+'				if (index >= 0) {',

+'					arr.splice(index, 1);',

+'					return index;',

+'				} else {',

+'					return false;',

+'				}',

+'			}',

+'',

+'			function array_removeFromStart(array, numberToRemove) {',

+'				if (Array.prototype.splice) {',

+'					array.splice(0, numberToRemove);',

+'				} else {',

+'					for (var i = numberToRemove, len = array.length; i < len; i++) {',

+'						array[i - numberToRemove] = array[i];',

+'					}',

+'					array.length = array.length - numberToRemove;',

+'				}',

+'				return array;',

+'			}',

+'',

+'			function array_contains(arr, val) {',

+'				for (var i = 0, len = arr.length; i < len; i++) {',

+'					if (arr[i] == val) {',

+'						return true;',

+'					}',

+'				}',

+'				return false;',

+'			}',

+'',

+'			function getErrorMessage(ex) {',

+'				if (ex.message) {',

+'					return ex.message;',

+'				} else if (ex.description) {',

+'					return ex.description;',

+'				}',

+'				return "" + ex;',

+'			}',

+'',

+'			function moveCaretToEnd(input) {',

+'				if (input.setSelectionRange) {',

+'					input.focus();',

+'					var length = input.value.length;',

+'					input.setSelectionRange(length, length);',

+'				} else if (input.createTextRange) {',

+'					var range = input.createTextRange();',

+'					range.collapse(false);',

+'					range.select();',

+'				}',

+'				input.focus();',

+'			}',

+'',

+'			function stopPropagation(evt) {',

+'				if (evt.stopPropagation) {',

+'					evt.stopPropagation();',

+'				} else if (typeof evt.cancelBubble != "undefined") {',

+'					evt.cancelBubble = true;',

+'				}',

+'			}',

+'',

+'			function getEvent(evt) {',

+'				return evt ? evt : event;',

+'			}',

+'',

+'			function getTarget(evt) {',

+'				return evt.target ? evt.target : evt.srcElement;',

+'			}',

+'',

+'			function getRelatedTarget(evt) {',

+'				if (evt.relatedTarget) {',

+'					return evt.relatedTarget;',

+'				} else if (evt.srcElement) {',

+'					switch(evt.type) {',

+'						case "mouseover":',

+'							return evt.fromElement;',

+'						case "mouseout":',

+'							return evt.toElement;',

+'						default:',

+'							return evt.srcElement;',

+'					}',

+'				}',

+'			}',

+'',

+'			function cancelKeyEvent(evt) {',

+'				evt.returnValue = false;',

+'				stopPropagation(evt);',

+'			}',

+'',

+'			function evalCommandLine() {',

+'				var expr = $("command").value;',

+'				evalCommand(expr);',

+'				$("command").value = "";',

+'			}',

+'',

+'			function evalLastCommand() {',

+'				if (lastCommand != null) {',

+'					evalCommand(lastCommand);',

+'				}',

+'			}',

+'',

+'			var lastCommand = null;',

+'			var commandHistory = [];',

+'			var currentCommandIndex = 0;',

+'',

+'			function evalCommand(expr) {',

+'				if (appender) {',

+'					appender.evalCommandAndAppend(expr);',

+'				} else {',

+'					var prefix = ">>> " + expr + "\\r\\n";',

+'					try {',

+'						log("INFO", prefix + eval(expr));',

+'					} catch (ex) {',

+'						log("ERROR", prefix + "Error: " + getErrorMessage(ex));',

+'					}',

+'				}',

+'				// Update command history',

+'				if (expr != commandHistory[commandHistory.length - 1]) {',

+'					commandHistory.push(expr);',

+'					// Update the appender',

+'					if (appender) {',

+'						appender.storeCommandHistory(commandHistory);',

+'					}',

+'				}',

+'				currentCommandIndex = (expr == commandHistory[currentCommandIndex]) ? currentCommandIndex + 1 : commandHistory.length;',

+'				lastCommand = expr;',

+'			}',

+'			//]]>',

+'		</script>',

+'		<style type="text/css">',

+'			body {',

+'				background-color: white;',

+'				color: black;',

+'				padding: 0;',

+'				margin: 0;',

+'				font-family: tahoma, verdana, arial, helvetica, sans-serif;',

+'				overflow: hidden;',

+'			}',

+'',

+'			div#switchesContainer input {',

+'				margin-bottom: 0;',

+'			}',

+'',

+'			div.toolbar {',

+'				border-top: solid #ffffff 1px;',

+'				border-bottom: solid #aca899 1px;',

+'				background-color: #f1efe7;',

+'				padding: 3px 5px;',

+'				font-size: 68.75%;',

+'			}',

+'',

+'			div.toolbar, div#search input {',

+'				font-family: tahoma, verdana, arial, helvetica, sans-serif;',

+'			}',

+'',

+'			div.toolbar input.button {',

+'				padding: 0 5px;',

+'				font-size: 100%;',

+'			}',

+'',

+'			div.toolbar input.hidden {',

+'				display: none;',

+'			}',

+'',

+'			div#switches input#clearButton {',

+'				margin-left: 20px;',

+'			}',

+'',

+'			div#levels label {',

+'				font-weight: bold;',

+'			}',

+'',

+'			div#levels label, div#options label {',

+'				margin-right: 5px;',

+'			}',

+'',

+'			div#levels label#wrapLabel {',

+'				font-weight: normal;',

+'			}',

+'',

+'			div#search label {',

+'				margin-right: 10px;',

+'			}',

+'',

+'			div#search label.searchboxlabel {',

+'				margin-right: 0;',

+'			}',

+'',

+'			div#search input {',

+'				font-size: 100%;',

+'			}',

+'',

+'			div#search input.validregex {',

+'				color: green;',

+'			}',

+'',

+'			div#search input.invalidregex {',

+'				color: red;',

+'			}',

+'',

+'			div#search input.nomatches {',

+'				color: white;',

+'				background-color: #ff6666;',

+'			}',

+'',

+'			div#search input.nomatches {',

+'				color: white;',

+'				background-color: #ff6666;',

+'			}',

+'',

+'			div#searchNav {',

+'				display: none;',

+'			}',

+'',

+'			div#commandLine {',

+'				display: none;',

+'			}',

+'',

+'			div#commandLine input#command {',

+'				font-size: 100%;',

+'				font-family: Courier New, Courier;',

+'			}',

+'',

+'			div#commandLine input#evaluateButton {',

+'			}',

+'',

+'			*.greyedout {',

+'				color: gray !important;',

+'				border-color: gray !important;',

+'			}',

+'',

+'			*.greyedout *.alwaysenabled { color: black; }',

+'',

+'			*.unselectable {',

+'				-khtml-user-select: none;',

+'				-moz-user-select: none;',

+'				user-select: none;',

+'			}',

+'',

+'			div#log {',

+'				font-family: Courier New, Courier;',

+'				font-size: 75%;',

+'				width: 100%;',

+'				overflow: auto;',

+'				clear: both;',

+'				position: relative;',

+'			}',

+'',

+'			div.group {',

+'				border-color: #cccccc;',

+'				border-style: solid;',

+'				border-width: 1px 0 1px 1px;',

+'				overflow: visible;',

+'			}',

+'',

+'			div.oldIe div.group, div.oldIe div.group *, div.oldIe *.logentry {',

+'				height: 1%;',

+'			}',

+'',

+'			div.group div.groupheading span.expander {',

+'				border: solid black 1px;',

+'				font-family: Courier New, Courier;',

+'				font-size: 0.833em;',

+'				background-color: #eeeeee;',

+'				position: relative;',

+'				top: -1px;',

+'				color: black;',

+'				padding: 0 2px;',

+'				cursor: pointer;',

+'				cursor: hand;',

+'				height: 1%;',

+'			}',

+'',

+'			div.group div.groupcontent {',

+'				margin-left: 10px;',

+'				padding-bottom: 2px;',

+'				overflow: visible;',

+'			}',

+'',

+'			div.group div.expanded {',

+'				display: block;',

+'			}',

+'',

+'			div.group div.collapsed {',

+'				display: none;',

+'			}',

+'',

+'			*.logentry {',

+'				overflow: visible;',

+'				display: none;',

+'				white-space: pre;',

+'			}',

+'',

+'			span.pre {',

+'				white-space: pre;',

+'			}',

+'			',

+'			pre.unwrapped {',

+'				display: inline !important;',

+'			}',

+'',

+'			pre.unwrapped pre.pre, div.wrapped pre.pre {',

+'				display: inline;',

+'			}',

+'',

+'			div.wrapped pre.pre {',

+'				white-space: normal;',

+'			}',

+'',

+'			div.wrapped {',

+'				display: none;',

+'			}',

+'',

+'			body.searching *.logentry span.currentmatch {',

+'				color: white !important;',

+'				background-color: green !important;',

+'			}',

+'',

+'			body.searching div.searchhighlight *.logentry span.searchterm {',

+'				color: black;',

+'				background-color: yellow;',

+'			}',

+'',

+'			div.wrap *.logentry {',

+'				white-space: normal !important;',

+'				border-width: 0 0 1px 0;',

+'				border-color: #dddddd;',

+'				border-style: dotted;',

+'			}',

+'',

+'			div.wrap #log_wrapped, #log_unwrapped {',

+'				display: block;',

+'			}',

+'',

+'			div.wrap #log_unwrapped, #log_wrapped {',

+'				display: none;',

+'			}',

+'',

+'			div.wrap *.logentry span.pre {',

+'				overflow: visible;',

+'				white-space: normal;',

+'			}',

+'',

+'			div.wrap *.logentry pre.unwrapped {',

+'				display: none;',

+'			}',

+'',

+'			div.wrap *.logentry span.wrapped {',

+'				display: inline;',

+'			}',

+'',

+'			div.searchfilter *.searchnonmatch {',

+'				display: none !important;',

+'			}',

+'',

+'			div#log *.TRACE, label#label_TRACE {',

+'				color: #666666;',

+'			}',

+'',

+'			div#log *.DEBUG, label#label_DEBUG {',

+'				color: green;',

+'			}',

+'',

+'			div#log *.INFO, label#label_INFO {',

+'				color: #000099;',

+'			}',

+'',

+'			div#log *.WARN, label#label_WARN {',

+'				color: #999900;',

+'			}',

+'',

+'			div#log *.ERROR, label#label_ERROR {',

+'				color: red;',

+'			}',

+'',

+'			div#log *.FATAL, label#label_FATAL {',

+'				color: #660066;',

+'			}',

+'',

+'			div.TRACE#log *.TRACE,',

+'			div.DEBUG#log *.DEBUG,',

+'			div.INFO#log *.INFO,',

+'			div.WARN#log *.WARN,',

+'			div.ERROR#log *.ERROR,',

+'			div.FATAL#log *.FATAL {',

+'				display: block;',

+'			}',

+'',

+'			div#log div.separator {',

+'				background-color: #cccccc;',

+'				margin: 5px 0;',

+'				line-height: 1px;',

+'			}',

+'		</style>',

+'	</head>',

+'',

+'	<body id="body">',

+'		<div id="switchesContainer">',

+'			<div id="switches">',

+'				<div id="levels" class="toolbar">',

+'					Filters:',

+'					<input type="checkbox" id="switch_TRACE" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide trace messages" /><label for="switch_TRACE" id="label_TRACE">trace</label>',

+'					<input type="checkbox" id="switch_DEBUG" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide debug messages" /><label for="switch_DEBUG" id="label_DEBUG">debug</label>',

+'					<input type="checkbox" id="switch_INFO" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide info messages" /><label for="switch_INFO" id="label_INFO">info</label>',

+'					<input type="checkbox" id="switch_WARN" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide warn messages" /><label for="switch_WARN" id="label_WARN">warn</label>',

+'					<input type="checkbox" id="switch_ERROR" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide error messages" /><label for="switch_ERROR" id="label_ERROR">error</label>',

+'					<input type="checkbox" id="switch_FATAL" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide fatal messages" /><label for="switch_FATAL" id="label_FATAL">fatal</label>',

+'					<input type="checkbox" id="switch_ALL" onclick="toggleAllLevels(); applyFilters()" checked="checked" title="Show/hide all messages" /><label for="switch_ALL" id="label_ALL">all</label>',

+'				</div>',

+'				<div id="search" class="toolbar">',

+'					<label for="searchBox" class="searchboxlabel">Search:</label> <input type="text" id="searchBox" onclick="toggleSearchEnabled(true)" onkeyup="scheduleSearch()" size="20" />',

+'					<input type="button" id="searchReset" disabled="disabled" value="Reset" onclick="clearSearch()" class="button" title="Reset the search" />',

+'					<input type="checkbox" id="searchRegex" onclick="doSearch()" title="If checked, search is treated as a regular expression" /><label for="searchRegex">Regex</label>',

+'					<input type="checkbox" id="searchCaseSensitive" onclick="doSearch()" title="If checked, search is case sensitive" /><label for="searchCaseSensitive">Match case</label>',

+'					<input type="checkbox" id="searchDisable" onclick="toggleSearchEnabled()" title="Enable/disable search" /><label for="searchDisable" class="alwaysenabled">Disable</label>',

+'					<div id="searchNav">',

+'						<input type="button" id="searchNext" disabled="disabled" value="Next" onclick="searchNext()" class="button" title="Go to the next matching log entry" />',

+'						<input type="button" id="searchPrevious" disabled="disabled" value="Previous" onclick="searchPrevious()" class="button" title="Go to the previous matching log entry" />',

+'						<input type="checkbox" id="searchFilter" onclick="toggleSearchFilter()" title="If checked, non-matching log entries are filtered out" /><label for="searchFilter">Filter</label>',

+'						<input type="checkbox" id="searchHighlight" onclick="toggleSearchHighlight()" title="Highlight matched search terms" /><label for="searchHighlight" class="alwaysenabled">Highlight all</label>',

+'					</div>',

+'				</div>',

+'				<div id="options" class="toolbar">',

+'					Options:',

+'					<input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Log</label>',

+'					<input type="checkbox" id="wrap" onclick="toggleWrap()" title="Enable / disable word wrap" /><label for="wrap" id="wrapLabel">Wrap</label>',

+'					<input type="checkbox" id="newestAtTop" onclick="toggleNewestAtTop()" title="If checked, causes newest messages to appear at the top" /><label for="newestAtTop" id="newestAtTopLabel">Newest at the top</label>',

+'					<input type="checkbox" id="scrollToLatest" onclick="toggleScrollToLatest()" checked="checked" title="If checked, window automatically scrolls to a new message when it is added" /><label for="scrollToLatest" id="scrollToLatestLabel">Scroll to latest</label>',

+'					<input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="button" title="Clear all log messages"  />',

+'					<input type="button" id="hideButton" value="Hide" onclick="hide()" class="hidden button" title="Hide the console" />',

+'					<input type="button" id="closeButton" value="Close" onclick="closeWindow()" class="hidden button" title="Close the window" />',

+'				</div>',

+'			</div>',

+'		</div>',

+'		<div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>',

+'		<div id="commandLine" class="toolbar">',

+'			<div id="commandLineContainer">',

+'				<input type="text" id="command" title="Enter a JavaScript command here and hit return or press \'Evaluate\'" />',

+'				<input type="button" id="evaluateButton" value="Evaluate" class="button" title="Evaluate the command" onclick="evalCommandLine()" />',

+'			</div>',

+'		</div>',

+'	</body>',

+'</html>',

+''

+];

+		};

+

+		var defaultCommandLineFunctions = [];

+

+		ConsoleAppender = function() {};

+

+		var consoleAppenderIdCounter = 1;

+		ConsoleAppender.prototype = new Appender();

+

+		ConsoleAppender.prototype.create = function(inPage, container,

+				lazyInit, initiallyMinimized, useDocumentWrite, width, height, focusConsoleWindow) {

+			var appender = this;

+

+			// Common properties

+			var initialized = false;

+			var consoleWindowCreated = false;

+			var consoleWindowLoaded = false;

+			var consoleClosed = false;

+

+			var queuedLoggingEvents = [];

+			var isSupported = true;

+			var consoleAppenderId = consoleAppenderIdCounter++;

+

+			// Local variables

+			initiallyMinimized = extractBooleanFromParam(initiallyMinimized, this.defaults.initiallyMinimized);

+			lazyInit = extractBooleanFromParam(lazyInit, this.defaults.lazyInit);

+			useDocumentWrite = extractBooleanFromParam(useDocumentWrite, this.defaults.useDocumentWrite);

+			var newestMessageAtTop = this.defaults.newestMessageAtTop;

+			var scrollToLatestMessage = this.defaults.scrollToLatestMessage;

+			width = width ? width : this.defaults.width;

+			height = height ? height : this.defaults.height;

+			var maxMessages = this.defaults.maxMessages;

+			var showCommandLine = this.defaults.showCommandLine;

+			var commandLineObjectExpansionDepth = this.defaults.commandLineObjectExpansionDepth;

+			var showHideButton = this.defaults.showHideButton;

+            var showCloseButton = this.defaults.showCloseButton;

+            var showLogEntryDeleteButtons = this.defaults.showLogEntryDeleteButtons;

+

+			this.setLayout(this.defaults.layout);

+

+			// Functions whose implementations vary between subclasses

+			var init, createWindow, safeToAppend, getConsoleWindow, open;

+

+			// Configuration methods. The function scope is used to prevent

+			// direct alteration to the appender configuration properties.

+			var appenderName = inPage ? "InPageAppender" : "PopUpAppender";

+			var checkCanConfigure = function(configOptionName) {

+				if (consoleWindowCreated) {

+					handleError(appenderName + ": configuration option '" + configOptionName + "' may not be set after the appender has been initialized");

+					return false;

+				}

+				return true;

+			};

+

+			var consoleWindowExists = function() {

+				return (consoleWindowLoaded && isSupported && !consoleClosed);

+			};

+

+			this.isNewestMessageAtTop = function() { return newestMessageAtTop; };

+			this.setNewestMessageAtTop = function(newestMessageAtTopParam) {

+				newestMessageAtTop = bool(newestMessageAtTopParam);

+				if (consoleWindowExists()) {

+					getConsoleWindow().setNewestAtTop(newestMessageAtTop);

+				}

+			};

+

+			this.isScrollToLatestMessage = function() { return scrollToLatestMessage; };

+			this.setScrollToLatestMessage = function(scrollToLatestMessageParam) {

+				scrollToLatestMessage = bool(scrollToLatestMessageParam);

+				if (consoleWindowExists()) {

+					getConsoleWindow().setScrollToLatest(scrollToLatestMessage);

+				}

+			};

+

+			this.getWidth = function() { return width; };

+			this.setWidth = function(widthParam) {

+				if (checkCanConfigure("width")) {

+					width = extractStringFromParam(widthParam, width);

+				}

+			};

+

+			this.getHeight = function() { return height; };

+			this.setHeight = function(heightParam) {

+				if (checkCanConfigure("height")) {

+					height = extractStringFromParam(heightParam, height);

+				}

+			};

+

+			this.getMaxMessages = function() { return maxMessages; };

+			this.setMaxMessages = function(maxMessagesParam) {

+				maxMessages = extractIntFromParam(maxMessagesParam, maxMessages);

+				if (consoleWindowExists()) {

+					getConsoleWindow().setMaxMessages(maxMessages);

+				}

+			};

+

+			this.isShowCommandLine = function() { return showCommandLine; };

+			this.setShowCommandLine = function(showCommandLineParam) {

+				showCommandLine = bool(showCommandLineParam);

+				if (consoleWindowExists()) {

+					getConsoleWindow().setShowCommandLine(showCommandLine);

+				}

+			};

+

+			this.isShowHideButton = function() { return showHideButton; };

+			this.setShowHideButton = function(showHideButtonParam) {

+				showHideButton = bool(showHideButtonParam);

+				if (consoleWindowExists()) {

+					getConsoleWindow().setShowHideButton(showHideButton);

+				}

+			};

+

+			this.isShowCloseButton = function() { return showCloseButton; };

+			this.setShowCloseButton = function(showCloseButtonParam) {

+				showCloseButton = bool(showCloseButtonParam);

+				if (consoleWindowExists()) {

+					getConsoleWindow().setShowCloseButton(showCloseButton);

+				}

+			};

+

+			this.getCommandLineObjectExpansionDepth = function() { return commandLineObjectExpansionDepth; };

+			this.setCommandLineObjectExpansionDepth = function(commandLineObjectExpansionDepthParam) {

+				commandLineObjectExpansionDepth = extractIntFromParam(commandLineObjectExpansionDepthParam, commandLineObjectExpansionDepth);

+			};

+

+			var minimized = initiallyMinimized;

+			this.isInitiallyMinimized = function() { return initiallyMinimized; };

+			this.setInitiallyMinimized = function(initiallyMinimizedParam) {

+				if (checkCanConfigure("initiallyMinimized")) {

+					initiallyMinimized = bool(initiallyMinimizedParam);

+					minimized = initiallyMinimized;

+				}

+			};

+

+			this.isUseDocumentWrite = function() { return useDocumentWrite; };

+			this.setUseDocumentWrite = function(useDocumentWriteParam) {

+				if (checkCanConfigure("useDocumentWrite")) {

+					useDocumentWrite = bool(useDocumentWriteParam);

+				}

+			};

+

+			// Common methods

+			function QueuedLoggingEvent(loggingEvent, formattedMessage) {

+				this.loggingEvent = loggingEvent;

+				this.levelName = loggingEvent.level.name;

+				this.formattedMessage = formattedMessage;

+			}

+

+			QueuedLoggingEvent.prototype.append = function() {

+				getConsoleWindow().log(this.levelName, this.formattedMessage);

+			};

+

+			function QueuedGroup(name, initiallyExpanded) {

+				this.name = name;

+				this.initiallyExpanded = initiallyExpanded;

+			}

+

+			QueuedGroup.prototype.append = function() {

+				getConsoleWindow().group(this.name, this.initiallyExpanded);

+			};

+

+			function QueuedGroupEnd() {}

+

+			QueuedGroupEnd.prototype.append = function() {

+				getConsoleWindow().groupEnd();

+			};

+

+			var checkAndAppend = function() {

+				// Next line forces a check of whether the window has been closed

+				safeToAppend();

+				if (!initialized) {

+					init();

+				} else if (consoleClosed && reopenWhenClosed) {

+					createWindow();

+				}

+				if (safeToAppend()) {

+					appendQueuedLoggingEvents();

+				}

+			};

+

+			this.append = function(loggingEvent) {

+				if (isSupported) {

+					// Format the message

+					var formattedMessage = appender.getLayout().format(loggingEvent);

+					if (this.getLayout().ignoresThrowable()) {

+						formattedMessage += loggingEvent.getThrowableStrRep();

+					}

+					queuedLoggingEvents.push(new QueuedLoggingEvent(loggingEvent, formattedMessage));

+					checkAndAppend();

+				}

+			};

+

+            this.group = function(name, initiallyExpanded) {

+				if (isSupported) {

+					queuedLoggingEvents.push(new QueuedGroup(name, initiallyExpanded));

+					checkAndAppend();

+				}

+			};

+

+            this.groupEnd = function() {

+				if (isSupported) {

+					queuedLoggingEvents.push(new QueuedGroupEnd());

+					checkAndAppend();

+				}

+			};

+

+			var appendQueuedLoggingEvents = function() {

+				var currentLoggingEvent;

+				while (queuedLoggingEvents.length > 0) {

+					queuedLoggingEvents.shift().append();

+				}

+				if (focusConsoleWindow) {

+					getConsoleWindow().focus();

+				}

+			};

+

+			this.setAddedToLogger = function(logger) {

+				this.loggers.push(logger);

+				if (enabled && !lazyInit) {

+					init();

+				}

+			};

+

+			this.clear = function() {

+				if (consoleWindowExists()) {

+					getConsoleWindow().clearLog();

+				}

+				queuedLoggingEvents.length = 0;

+			};

+

+			this.focus = function() {

+				if (consoleWindowExists()) {

+					getConsoleWindow().focus();

+				}

+			};

+

+			this.focusCommandLine = function() {

+				if (consoleWindowExists()) {

+					getConsoleWindow().focusCommandLine();

+				}

+			};

+

+			this.focusSearch = function() {

+				if (consoleWindowExists()) {

+					getConsoleWindow().focusSearch();

+				}

+			};

+

+			var commandWindow = window;

+

+			this.getCommandWindow = function() { return commandWindow; };

+			this.setCommandWindow = function(commandWindowParam) {

+				commandWindow = commandWindowParam;

+			};

+

+			this.executeLastCommand = function() {

+				if (consoleWindowExists()) {

+					getConsoleWindow().evalLastCommand();

+				}

+			};

+

+			var commandLayout = new PatternLayout("%m");

+			this.getCommandLayout = function() { return commandLayout; };

+			this.setCommandLayout = function(commandLayoutParam) {

+				commandLayout = commandLayoutParam;

+			};

+

+			this.evalCommandAndAppend = function(expr) {

+				var commandReturnValue = { appendResult: true, isError: false };

+				var commandOutput = "";

+				// Evaluate the command

+				try {

+					var result, i;

+					// The next three lines constitute a workaround for IE. Bizarrely, iframes seem to have no

+					// eval method on the window object initially, but once execScript has been called on

+					// it once then the eval method magically appears. See http://www.thismuchiknow.co.uk/?p=25

+					if (!commandWindow.eval && commandWindow.execScript) {

+						commandWindow.execScript("null");

+					}

+

+					var commandLineFunctionsHash = {};

+					for (i = 0, len = commandLineFunctions.length; i < len; i++) {

+						commandLineFunctionsHash[commandLineFunctions[i][0]] = commandLineFunctions[i][1];

+					}

+

+					// Keep an array of variables that are being changed in the command window so that they

+					// can be restored to their original values afterwards

+					var objectsToRestore = [];

+					var addObjectToRestore = function(name) {

+						objectsToRestore.push([name, commandWindow[name]]);

+					};

+

+					addObjectToRestore("appender");

+					commandWindow.appender = appender;

+

+					addObjectToRestore("commandReturnValue");

+					commandWindow.commandReturnValue = commandReturnValue;

+

+					addObjectToRestore("commandLineFunctionsHash");

+					commandWindow.commandLineFunctionsHash = commandLineFunctionsHash;

+

+					var addFunctionToWindow = function(name) {

+						addObjectToRestore(name);

+						commandWindow[name] = function() {

+							return this.commandLineFunctionsHash[name](appender, arguments, commandReturnValue);

+						};

+					};

+

+					for (i = 0, len = commandLineFunctions.length; i < len; i++) {

+						addFunctionToWindow(commandLineFunctions[i][0]);

+					}

+

+					// Another bizarre workaround to get IE to eval in the global scope

+					if (commandWindow === window && commandWindow.execScript) {

+						addObjectToRestore("evalExpr");

+						addObjectToRestore("result");

+						window.evalExpr = expr;

+						commandWindow.execScript("window.result=eval(window.evalExpr);");

+						result = window.result;

+ 					} else {

+ 						result = commandWindow.eval(expr);

+ 					}

+					commandOutput = isUndefined(result) ? result : formatObjectExpansion(result, commandLineObjectExpansionDepth);

+

+					// Restore variables in the command window to their original state

+					for (i = 0, len = objectsToRestore.length; i < len; i++) {

+						commandWindow[objectsToRestore[i][0]] = objectsToRestore[i][1];

+					}

+				} catch (ex) {

+					commandOutput = "Error evaluating command: " + getExceptionStringRep(ex);

+					commandReturnValue.isError = true;

+				}

+				// Append command output

+				if (commandReturnValue.appendResult) {

+					var message = ">>> " + expr;

+					if (!isUndefined(commandOutput)) {

+						message += newLine + commandOutput;

+					}

+					var level = commandReturnValue.isError ? Level.ERROR : Level.INFO;

+					var loggingEvent = new LoggingEvent(null, new Date(), level, [message], null);

+					var mainLayout = this.getLayout();

+					this.setLayout(commandLayout);

+					this.append(loggingEvent);

+					this.setLayout(mainLayout);

+				}

+			};

+

+			var commandLineFunctions = defaultCommandLineFunctions.concat([]);

+

+			this.addCommandLineFunction = function(functionName, commandLineFunction) {

+				commandLineFunctions.push([functionName, commandLineFunction]);

+			};

+

+			var commandHistoryCookieName = "log4javascriptCommandHistory";

+			this.storeCommandHistory = function(commandHistory) {

+				setCookie(commandHistoryCookieName, commandHistory.join(","));

+			};

+

+			var writeHtml = function(doc) {

+				var lines = getConsoleHtmlLines();

+				doc.open();

+				for (var i = 0, len = lines.length; i < len; i++) {

+					doc.writeln(lines[i]);

+				}

+				doc.close();

+			};

+

+			// Set up event listeners

+			this.setEventTypes(["load", "unload"]);

+

+			var consoleWindowLoadHandler = function() {

+				var win = getConsoleWindow();

+				win.setAppender(appender);

+				win.setNewestAtTop(newestMessageAtTop);

+				win.setScrollToLatest(scrollToLatestMessage);

+				win.setMaxMessages(maxMessages);

+				win.setShowCommandLine(showCommandLine);

+				win.setShowHideButton(showHideButton);

+				win.setShowCloseButton(showCloseButton);

+				win.setMainWindow(window);

+

+				// Restore command history stored in cookie

+				var storedValue = getCookie(commandHistoryCookieName);

+				if (storedValue) {

+					win.commandHistory = storedValue.split(",");

+					win.currentCommandIndex = win.commandHistory.length;

+				}

+

+				appender.dispatchEvent("load", { "win" : win });

+			};

+

+			this.unload = function() {

+				logLog.debug("unload " + this + ", caller: " + this.unload.caller);

+				if (!consoleClosed) {

+					logLog.debug("really doing unload " + this);

+					consoleClosed = true;

+					consoleWindowLoaded = false;

+					consoleWindowCreated = false;

+					appender.dispatchEvent("unload", {});

+				}

+			};

+

+			var pollConsoleWindow = function(windowTest, interval, successCallback, errorMessage) {

+				function doPoll() {

+					try {

+						// Test if the console has been closed while polling

+						if (consoleClosed) {

+							clearInterval(poll);

+						}

+						if (windowTest(getConsoleWindow())) {

+							clearInterval(poll);

+							successCallback();

+						}

+					} catch (ex) {

+						clearInterval(poll);

+						isSupported = false;

+						handleError(errorMessage, ex);

+					}

+				}

+

+				// Poll the pop-up since the onload event is not reliable

+				var poll = setInterval(doPoll, interval);

+			};

+

+			var getConsoleUrl = function() {

+				var documentDomainSet = (document.domain != location.hostname);

+				return useDocumentWrite ? "" : getBaseUrl() + "console_uncompressed.html" +

+											   (documentDomainSet ? "?log4javascript_domain=" + escape(document.domain) : "");

+			};

+

+			// Define methods and properties that vary between subclasses

+			if (inPage) {

+				// InPageAppender

+

+				var containerElement = null;

+

+				// Configuration methods. The function scope is used to prevent

+				// direct alteration to the appender configuration properties.

+				var cssProperties = [];

+				this.addCssProperty = function(name, value) {

+					if (checkCanConfigure("cssProperties")) {

+						cssProperties.push([name, value]);

+					}

+				};

+

+				// Define useful variables

+				var windowCreationStarted = false;

+				var iframeContainerDiv;

+				var iframeId = uniqueId + "_InPageAppender_" + consoleAppenderId;

+

+				this.hide = function() {

+					if (initialized && consoleWindowCreated) {

+						if (consoleWindowExists()) {

+							getConsoleWindow().$("command").blur();

+						}

+						iframeContainerDiv.style.display = "none";

+						minimized = true;

+					}

+				};

+

+				this.show = function() {

+					if (initialized) {

+						if (consoleWindowCreated) {

+							iframeContainerDiv.style.display = "block";

+							this.setShowCommandLine(showCommandLine); // Force IE to update

+							minimized = false;

+						} else if (!windowCreationStarted) {

+							createWindow(true);

+						}

+					}

+				};

+

+				this.isVisible = function() {

+					return !minimized && !consoleClosed;

+				};

+

+				this.close = function(fromButton) {

+					if (!consoleClosed && (!fromButton || confirm("This will permanently remove the console from the page. No more messages will be logged. Do you wish to continue?"))) {

+						iframeContainerDiv.parentNode.removeChild(iframeContainerDiv);

+						this.unload();

+					}

+				};

+

+				// Create open, init, getConsoleWindow and safeToAppend functions

+				open = function() {

+					var initErrorMessage = "InPageAppender.open: unable to create console iframe";

+

+					function finalInit() {

+						try {

+							if (!initiallyMinimized) {

+								appender.show();

+							}

+							consoleWindowLoadHandler();

+							consoleWindowLoaded = true;

+							appendQueuedLoggingEvents();

+						} catch (ex) {

+							isSupported = false;

+							handleError(initErrorMessage, ex);

+						}

+					}

+

+					function writeToDocument() {

+						try {

+							var windowTest = function(win) { return isLoaded(win); };

+							if (useDocumentWrite) {

+								writeHtml(getConsoleWindow().document);

+							}

+							if (windowTest(getConsoleWindow())) {

+								finalInit();

+							} else {

+								pollConsoleWindow(windowTest, 100, finalInit, initErrorMessage);

+							}

+						} catch (ex) {

+							isSupported = false;

+							handleError(initErrorMessage, ex);

+						}

+					}

+

+					minimized = false;

+					iframeContainerDiv = containerElement.appendChild(document.createElement("div"));

+

+					iframeContainerDiv.style.width = width;

+					iframeContainerDiv.style.height = height;

+					iframeContainerDiv.style.border = "solid gray 1px";

+

+					for (var i = 0, len = cssProperties.length; i < len; i++) {

+						iframeContainerDiv.style[cssProperties[i][0]] = cssProperties[i][1];

+					}

+

+					var iframeSrc = useDocumentWrite ? "" : " src='" + getConsoleUrl() + "'";

+

+					// Adding an iframe using the DOM would be preferable, but it doesn't work

+					// in IE5 on Windows, or in Konqueror prior to version 3.5 - in Konqueror

+					// it creates the iframe fine but I haven't been able to find a way to obtain

+					// the iframe's window object

+					iframeContainerDiv.innerHTML = "<iframe id='" + iframeId + "' name='" + iframeId +

+						"' width='100%' height='100%' frameborder='0'" + iframeSrc +

+						" scrolling='no'></iframe>";

+					consoleClosed = false;

+

+					// Write the console HTML to the iframe

+					var iframeDocumentExistsTest = function(win) {

+						try {

+							return bool(win) && bool(win.document);

+						} catch (ex) {

+							return false;

+						}

+					};

+					if (iframeDocumentExistsTest(getConsoleWindow())) {

+						writeToDocument();

+					} else {

+						pollConsoleWindow(iframeDocumentExistsTest, 100, writeToDocument, initErrorMessage);

+					}

+					consoleWindowCreated = true;

+				};

+

+				createWindow = function(show) {

+					if (show || !initiallyMinimized) {

+						var pageLoadHandler = function() {

+							if (!container) {

+								// Set up default container element

+								containerElement = document.createElement("div");

+								containerElement.style.position = "fixed";

+								containerElement.style.left = "0";

+								containerElement.style.right = "0";

+								containerElement.style.bottom = "0";

+								document.body.appendChild(containerElement);

+								appender.addCssProperty("borderWidth", "1px 0 0 0");

+								appender.addCssProperty("zIndex", 1000000); // Can't find anything authoritative that says how big z-index can be

+								open();

+							} else {

+								try {

+									var el = document.getElementById(container);

+									if (el.nodeType == 1) {

+										containerElement = el;

+									}

+									open();

+								} catch (ex) {

+									handleError("InPageAppender.init: invalid container element '" + container + "' supplied", ex);

+								}

+							}

+						};

+

+						// Test the type of the container supplied. First, check if it's an element

+						if (pageLoaded && container && container.appendChild) {

+							containerElement = container;

+							open();

+						} else if (pageLoaded) {

+							pageLoadHandler();

+						} else {

+							log4javascript.addEventListener("load", pageLoadHandler);

+						}

+						windowCreationStarted = true;

+					}

+				};

+

+				init = function() {

+					createWindow();

+					initialized = true;

+				};

+

+				getConsoleWindow = function() {

+					var iframe = window.frames[iframeId];

+					if (iframe) {

+						return iframe;

+					}

+				};

+

+				safeToAppend = function() {

+					if (isSupported && !consoleClosed) {

+						if (consoleWindowCreated && !consoleWindowLoaded && getConsoleWindow() && isLoaded(getConsoleWindow())) {

+							consoleWindowLoaded = true;

+						}

+						return consoleWindowLoaded;

+					}

+					return false;

+				};

+			} else {

+				// PopUpAppender

+

+				// Extract params

+				var useOldPopUp = appender.defaults.useOldPopUp;

+				var complainAboutPopUpBlocking = appender.defaults.complainAboutPopUpBlocking;

+				var reopenWhenClosed = this.defaults.reopenWhenClosed;

+

+				// Configuration methods. The function scope is used to prevent

+				// direct alteration to the appender configuration properties.

+				this.isUseOldPopUp = function() { return useOldPopUp; };

+				this.setUseOldPopUp = function(useOldPopUpParam) {

+					if (checkCanConfigure("useOldPopUp")) {

+						useOldPopUp = bool(useOldPopUpParam);

+					}

+				};

+

+				this.isComplainAboutPopUpBlocking = function() { return complainAboutPopUpBlocking; };

+				this.setComplainAboutPopUpBlocking = function(complainAboutPopUpBlockingParam) {

+					if (checkCanConfigure("complainAboutPopUpBlocking")) {

+						complainAboutPopUpBlocking = bool(complainAboutPopUpBlockingParam);

+					}

+				};

+

+				this.isFocusPopUp = function() { return focusConsoleWindow; };

+				this.setFocusPopUp = function(focusPopUpParam) {

+					// This property can be safely altered after logging has started

+					focusConsoleWindow = bool(focusPopUpParam);

+				};

+

+				this.isReopenWhenClosed = function() { return reopenWhenClosed; };

+				this.setReopenWhenClosed = function(reopenWhenClosedParam) {

+					// This property can be safely altered after logging has started

+					reopenWhenClosed = bool(reopenWhenClosedParam);

+				};

+

+				this.close = function() {

+					logLog.debug("close " + this);

+					try {

+						popUp.close();

+						this.unload();

+					} catch (ex) {

+						// Do nothing

+					}

+				};

+

+				this.hide = function() {

+					logLog.debug("hide " + this);

+					if (consoleWindowExists()) {

+						this.close();

+					}

+				};

+

+				this.show = function() {

+					logLog.debug("show " + this);

+					if (!consoleWindowCreated) {

+						open();

+					}

+				};

+

+				this.isVisible = function() {

+					return safeToAppend();

+				};

+

+				// Define useful variables

+				var popUp;

+

+				// Create open, init, getConsoleWindow and safeToAppend functions

+				open = function() {

+					var windowProperties = "width=" + width + ",height=" + height + ",status,resizable";

+					var frameInfo = "";

+					try {

+						var frameEl = window.frameElement;

+						if (frameEl) {

+							frameInfo = "_" + frameEl.tagName + "_" + (frameEl.name || frameEl.id || "");

+						}

+					} catch (e) {

+						frameInfo = "_inaccessibleParentFrame";

+					}

+					var windowName = "PopUp_" + location.host.replace(/[^a-z0-9]/gi, "_") + "_" + consoleAppenderId + frameInfo;

+					if (!useOldPopUp || !useDocumentWrite) {

+						// Ensure a previous window isn't used by using a unique name

+						windowName = windowName + "_" + uniqueId;

+					}

+

+					var checkPopUpClosed = function(win) {

+						if (consoleClosed) {

+							return true;

+						} else {

+							try {

+								return bool(win) && win.closed;

+							} catch(ex) {}

+						}

+						return false;

+					};

+

+					var popUpClosedCallback = function() {

+						if (!consoleClosed) {

+							appender.unload();

+						}

+					};

+

+					function finalInit() {

+						getConsoleWindow().setCloseIfOpenerCloses(!useOldPopUp || !useDocumentWrite);

+						consoleWindowLoadHandler();

+						consoleWindowLoaded = true;

+						appendQueuedLoggingEvents();

+						pollConsoleWindow(checkPopUpClosed, 500, popUpClosedCallback,

+								"PopUpAppender.checkPopUpClosed: error checking pop-up window");

+					}

+

+					try {

+						popUp = window.open(getConsoleUrl(), windowName, windowProperties);

+						consoleClosed = false;

+						consoleWindowCreated = true;

+						if (popUp && popUp.document) {

+							if (useDocumentWrite && useOldPopUp && isLoaded(popUp)) {

+								popUp.mainPageReloaded();

+								finalInit();

+							} else {

+								if (useDocumentWrite) {

+									writeHtml(popUp.document);

+								}

+								// Check if the pop-up window object is available

+								var popUpLoadedTest = function(win) { return bool(win) && isLoaded(win); };

+								if (isLoaded(popUp)) {

+									finalInit();

+								} else {

+									pollConsoleWindow(popUpLoadedTest, 100, finalInit,

+											"PopUpAppender.init: unable to create console window");

+								}

+							}

+						} else {

+							isSupported = false;

+							logLog.warn("PopUpAppender.init: pop-ups blocked, please unblock to use PopUpAppender");

+							if (complainAboutPopUpBlocking) {

+								handleError("log4javascript: pop-up windows appear to be blocked. Please unblock them to use pop-up logging.");

+							}

+						}

+					} catch (ex) {

+						handleError("PopUpAppender.init: error creating pop-up", ex);

+					}

+				};

+

+				createWindow = function() {

+					if (!initiallyMinimized) {

+						open();

+					}

+				};

+

+				init = function() {

+					createWindow();

+					initialized = true;

+				};

+

+				getConsoleWindow = function() {

+					return popUp;

+				};

+

+				safeToAppend = function() {

+					if (isSupported && !isUndefined(popUp) && !consoleClosed) {

+						if (popUp.closed ||

+								(consoleWindowLoaded && isUndefined(popUp.closed))) { // Extra check for Opera

+							appender.unload();

+							logLog.debug("PopUpAppender: pop-up closed");

+							return false;

+						}

+						if (!consoleWindowLoaded && isLoaded(popUp)) {

+							consoleWindowLoaded = true;

+						}

+					}

+					return isSupported && consoleWindowLoaded && !consoleClosed;

+				};

+			}

+

+			// Expose getConsoleWindow so that automated tests can check the DOM

+			this.getConsoleWindow = getConsoleWindow;

+		};

+

+		ConsoleAppender.addGlobalCommandLineFunction = function(functionName, commandLineFunction) {

+			defaultCommandLineFunctions.push([functionName, commandLineFunction]);

+		};

+

+		/* ------------------------------------------------------------------ */

+

+		function PopUpAppender(lazyInit, initiallyMinimized, useDocumentWrite,

+							   width, height) {

+			this.create(false, null, lazyInit, initiallyMinimized,

+					useDocumentWrite, width, height, this.defaults.focusPopUp);

+		}

+

+		PopUpAppender.prototype = new ConsoleAppender();

+

+		PopUpAppender.prototype.defaults = {

+			layout: new PatternLayout("%d{HH:mm:ss} %-5p - %m{1}%n"),

+			initiallyMinimized: false,

+			focusPopUp: false,

+			lazyInit: true,

+			useOldPopUp: true,

+			complainAboutPopUpBlocking: true,

+			newestMessageAtTop: false,

+			scrollToLatestMessage: true,

+			width: "600",

+			height: "400",

+			reopenWhenClosed: false,

+			maxMessages: null,

+			showCommandLine: true,

+			commandLineObjectExpansionDepth: 1,

+			showHideButton: false,

+			showCloseButton: true,

+            showLogEntryDeleteButtons: true,

+            useDocumentWrite: true

+		};

+

+		PopUpAppender.prototype.toString = function() {

+			return "PopUpAppender";

+		};

+

+		log4javascript.PopUpAppender = PopUpAppender;

+

+		/* ------------------------------------------------------------------ */

+

+		function InPageAppender(container, lazyInit, initiallyMinimized,

+								useDocumentWrite, width, height) {

+			this.create(true, container, lazyInit, initiallyMinimized,

+					useDocumentWrite, width, height, false);

+		}

+

+		InPageAppender.prototype = new ConsoleAppender();

+

+		InPageAppender.prototype.defaults = {

+			layout: new PatternLayout("%d{HH:mm:ss} %-5p - %m{1}%n"),

+			initiallyMinimized: false,

+			lazyInit: true,

+			newestMessageAtTop: false,

+			scrollToLatestMessage: true,

+			width: "100%",

+			height: "220px",

+			maxMessages: null,

+			showCommandLine: true,

+			commandLineObjectExpansionDepth: 1,

+			showHideButton: false,

+			showCloseButton: false,

+            showLogEntryDeleteButtons: true,

+            useDocumentWrite: true

+		};

+

+		InPageAppender.prototype.toString = function() {

+			return "InPageAppender";

+		};

+

+		log4javascript.InPageAppender = InPageAppender;

+

+		// Next line for backwards compatibility

+		log4javascript.InlineAppender = InPageAppender;

+	})();

+	/* ---------------------------------------------------------------------- */

+	// Console extension functions

+

+	function padWithSpaces(str, len) {

+		if (str.length < len) {

+			var spaces = [];

+			var numberOfSpaces = Math.max(0, len - str.length);

+			for (var i = 0; i < numberOfSpaces; i++) {

+				spaces[i] = " ";

+			}

+			str += spaces.join("");

+		}

+		return str;

+	}

+

+	(function() {

+		function dir(obj) {

+			var maxLen = 0;

+			// Obtain the length of the longest property name

+			for (var p in obj) {

+				maxLen = Math.max(toStr(p).length, maxLen);

+			}

+			// Create the nicely formatted property list

+			var propList = [];

+			for (p in obj) {

+				var propNameStr = "  " + padWithSpaces(toStr(p), maxLen + 2);

+				var propVal;

+				try {

+					propVal = splitIntoLines(toStr(obj[p])).join(padWithSpaces(newLine, maxLen + 6));

+				} catch (ex) {

+					propVal = "[Error obtaining property. Details: " + getExceptionMessage(ex) + "]";

+				}

+				propList.push(propNameStr + propVal);

+			}

+			return propList.join(newLine);

+		}

+

+		var nodeTypes = {

+			ELEMENT_NODE: 1,

+			ATTRIBUTE_NODE: 2,

+			TEXT_NODE: 3,

+			CDATA_SECTION_NODE: 4,

+			ENTITY_REFERENCE_NODE: 5,

+			ENTITY_NODE: 6,

+			PROCESSING_INSTRUCTION_NODE: 7,

+			COMMENT_NODE: 8,

+			DOCUMENT_NODE: 9,

+			DOCUMENT_TYPE_NODE: 10,

+			DOCUMENT_FRAGMENT_NODE: 11,

+			NOTATION_NODE: 12

+		};

+

+		var preFormattedElements = ["script", "pre"];

+

+		// This should be the definitive list, as specified by the XHTML 1.0 Transitional DTD

+		var emptyElements = ["br", "img", "hr", "param", "link", "area", "input", "col", "base", "meta"];

+		var indentationUnit = "  ";

+

+		// Create and return an XHTML string from the node specified

+		function getXhtml(rootNode, includeRootNode, indentation, startNewLine, preformatted) {

+			includeRootNode = (typeof includeRootNode == "undefined") ? true : !!includeRootNode;

+			if (typeof indentation != "string") {

+				indentation = "";

+			}

+			startNewLine = !!startNewLine;

+			preformatted = !!preformatted;

+			var xhtml;

+

+			function isWhitespace(node) {

+				return ((node.nodeType == nodeTypes.TEXT_NODE) && /^[ \t\r\n]*$/.test(node.nodeValue));

+			}

+

+			function fixAttributeValue(attrValue) {

+				return attrValue.toString().replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/"/g, "&quot;");

+			}

+

+			function getStyleAttributeValue(el) {

+				var stylePairs = el.style.cssText.split(";");

+				var styleValue = "";

+				var isFirst = true;

+				for (var j = 0, len = stylePairs.length; j < len; j++) {

+					var nameValueBits = stylePairs[j].split(":");

+					var props = [];

+					if (!/^\s*$/.test(nameValueBits[0])) {

+						props.push(trim(nameValueBits[0]).toLowerCase() + ":" + trim(nameValueBits[1]));

+					}

+					styleValue = props.join(";");

+				}

+				return styleValue;

+			}

+

+			function getNamespace(el) {

+				if (el.prefix) {

+					return el.prefix;

+				} else if (el.outerHTML) {

+					var regex = new RegExp("<([^:]+):" + el.tagName + "[^>]*>", "i");

+					if (regex.test(el.outerHTML)) {

+						return RegExp.$1.toLowerCase();

+					}

+				}

+                return "";

+			}

+

+			var lt = "<";

+			var gt = ">";

+

+			if (includeRootNode && rootNode.nodeType != nodeTypes.DOCUMENT_FRAGMENT_NODE) {

+				switch (rootNode.nodeType) {

+					case nodeTypes.ELEMENT_NODE:

+						var tagName = rootNode.tagName.toLowerCase();

+						xhtml = startNewLine ? newLine + indentation : "";

+						xhtml += lt;

+						// Allow for namespaces, where present

+						var prefix = getNamespace(rootNode);

+						var hasPrefix = !!prefix;

+						if (hasPrefix) {

+							xhtml += prefix + ":";

+						}

+						xhtml += tagName;

+						for (i = 0, len = rootNode.attributes.length; i < len; i++) {

+							var currentAttr = rootNode.attributes[i];

+							// Check the attribute is valid.

+							if (!	currentAttr.specified ||

+									currentAttr.nodeValue === null ||

+									currentAttr.nodeName.toLowerCase() === "style" ||

+									typeof currentAttr.nodeValue !== "string" ||

+									currentAttr.nodeName.indexOf("_moz") === 0) {

+								continue;

+							}

+							xhtml += " " + currentAttr.nodeName.toLowerCase() + "=\"";

+							xhtml += fixAttributeValue(currentAttr.nodeValue);

+							xhtml += "\"";

+						}

+						// Style needs to be done separately as it is not reported as an

+						// attribute in IE

+						if (rootNode.style.cssText) {

+							var styleValue = getStyleAttributeValue(rootNode);

+							if (styleValue !== "") {

+								xhtml += " style=\"" + getStyleAttributeValue(rootNode) + "\"";

+							}

+						}

+						if (array_contains(emptyElements, tagName) ||

+								(hasPrefix && !rootNode.hasChildNodes())) {

+							xhtml += "/" + gt;

+						} else {

+							xhtml += gt;

+							// Add output for childNodes collection (which doesn't include attribute nodes)

+							var childStartNewLine = !(rootNode.childNodes.length === 1 &&

+								rootNode.childNodes[0].nodeType === nodeTypes.TEXT_NODE);

+							var childPreformatted = array_contains(preFormattedElements, tagName);

+							for (var i = 0, len = rootNode.childNodes.length; i < len; i++) {

+								xhtml += getXhtml(rootNode.childNodes[i], true, indentation + indentationUnit,

+									childStartNewLine, childPreformatted);

+							}

+							// Add the end tag

+							var endTag = lt + "/" + tagName + gt;

+							xhtml += childStartNewLine ? newLine + indentation + endTag : endTag;

+						}

+						return xhtml;

+					case nodeTypes.TEXT_NODE:

+						if (isWhitespace(rootNode)) {

+							xhtml = "";

+						} else {

+							if (preformatted) {

+								xhtml = rootNode.nodeValue;

+							} else {

+								// Trim whitespace from each line of the text node

+								var lines = splitIntoLines(trim(rootNode.nodeValue));

+								var trimmedLines = [];

+								for (var i = 0, len = lines.length; i < len; i++) {

+									trimmedLines[i] = trim(lines[i]);

+								}

+								xhtml = trimmedLines.join(newLine + indentation);

+							}

+							if (startNewLine) {

+								xhtml = newLine + indentation + xhtml;

+							}

+						}

+						return xhtml;

+					case nodeTypes.CDATA_SECTION_NODE:

+						return "<![CDA" + "TA[" + rootNode.nodeValue + "]" + "]>" + newLine;

+					case nodeTypes.DOCUMENT_NODE:

+						xhtml = "";

+						// Add output for childNodes collection (which doesn't include attribute nodes)

+						for (var i = 0, len = rootNode.childNodes.length; i < len; i++) {

+							xhtml += getXhtml(rootNode.childNodes[i], true, indentation);

+						}

+						return xhtml;

+					default:

+						return "";

+				}

+			} else {

+				xhtml = "";

+				// Add output for childNodes collection (which doesn't include attribute nodes)

+				for (var i = 0, len = rootNode.childNodes.length; i < len; i++) {

+					xhtml += getXhtml(rootNode.childNodes[i], true, indentation + indentationUnit);

+				}

+				return xhtml;

+			}

+		}

+

+		function createCommandLineFunctions() {

+			ConsoleAppender.addGlobalCommandLineFunction("$", function(appender, args, returnValue) {

+				return document.getElementById(args[0]);

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("dir", function(appender, args, returnValue) {

+				var lines = [];

+				for (var i = 0, len = args.length; i < len; i++) {

+					lines[i] = dir(args[i]);

+				}

+				return lines.join(newLine + newLine);

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("dirxml", function(appender, args, returnValue) {

+				var lines = [];

+				for (var i = 0, len = args.length; i < len; i++) {

+					var win = appender.getCommandWindow();

+					lines[i] = getXhtml(args[i]);

+				}

+				return lines.join(newLine + newLine);

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("cd", function(appender, args, returnValue) {

+				var win, message;

+				if (args.length === 0 || args[0] === "") {

+					win = window;

+					message = "Command line set to run in main window";

+				} else {

+					if (args[0].window == args[0]) {

+						win = args[0];

+						message = "Command line set to run in frame '" + args[0].name + "'";

+					} else {

+						win = window.frames[args[0]];

+						if (win) {

+							message = "Command line set to run in frame '" + args[0] + "'";

+						} else {

+							returnValue.isError = true;

+							message = "Frame '" + args[0] + "' does not exist";

+							win = appender.getCommandWindow();

+						}

+					}

+				}

+				appender.setCommandWindow(win);

+				return message;

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("clear", function(appender, args, returnValue) {

+				returnValue.appendResult = false;

+				appender.clear();

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("keys", function(appender, args, returnValue) {

+				var keys = [];

+				for (var k in args[0]) {

+					keys.push(k);

+				}

+				return keys;

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("values", function(appender, args, returnValue) {

+				var values = [];

+				for (var k in args[0]) {

+					try {

+						values.push(args[0][k]);

+					} catch (ex) {

+						logLog.warn("values(): Unable to obtain value for key " + k + ". Details: " + getExceptionMessage(ex));

+					}

+				}

+				return values;

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("expansionDepth", function(appender, args, returnValue) {

+				var expansionDepth = parseInt(args[0], 10);

+				if (isNaN(expansionDepth) || expansionDepth < 0) {

+					returnValue.isError = true;

+					return "" + args[0] + " is not a valid expansion depth";

+				} else {

+					appender.setCommandLineObjectExpansionDepth(expansionDepth);

+					return "Object expansion depth set to " + expansionDepth;

+				}

+			});

+		}

+

+		function init() {

+			// Add command line functions

+			createCommandLineFunctions();

+		}

+

+		/* ------------------------------------------------------------------ */

+

+		init();

+	})();

+

+	/* ---------------------------------------------------------------------- */

+	// Main load

+

+   log4javascript.setDocumentReady = function() {

+       pageLoaded = true;

+       log4javascript.dispatchEvent("load", {});

+   };

+

+    if (window.addEventListener) {

+        window.addEventListener("load", log4javascript.setDocumentReady, false);

+    } else if (window.attachEvent) {

+        window.attachEvent("onload", log4javascript.setDocumentReady);

+    } else {

+        var oldOnload = window.onload;

+        if (typeof window.onload != "function") {

+            window.onload = log4javascript.setDocumentReady;

+        } else {

+            window.onload = function(evt) {

+                if (oldOnload) {

+                    oldOnload(evt);

+                }

+                log4javascript.setDocumentReady();

+            };

+        }

+    }

+

+    // Ensure that the log4javascript object is available in the window. This

+    // is necessary for log4javascript to be available in IE if loaded using

+    // Dojo's module system

+    window.log4javascript = log4javascript;

+

+    return log4javascript;

+})();
\ No newline at end of file
diff --git a/xos/core/static/log4javascript-1.4.6/main.css b/xos/core/static/log4javascript-1.4.6/main.css
new file mode 100644
index 0000000..5ac3df3
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/main.css
@@ -0,0 +1,300 @@
+body {

+	font-family: Verdana, Arial, Helvetica, Sans-serif;

+	font-size: 75%;

+	color: black;

+	background-color: #eeeeee;

+	text-align: center;

+	padding: 0px;

+	margin: 0px;

+}

+

+div#container {

+	width: 770px;

+	text-align: left;

+	line-height: 150%;

+	border-width: 0px 1px 1px 1px;

+	border-color: #cccccc;

+	border-style: solid;

+	background-color: white;

+	color: black;

+	padding: 10px;

+	margin: 0px auto 10px auto;

+}

+

+div#header {

+	margin: 0px;

+}

+

+div#header h1 {

+	font-family: Courier New, Courier, Monospace, Serif;

+	padding: 8px 0 15px 0;

+	margin: 0px;

+	font-size: 200%;

+	font-weight: bold;

+	text-align: right;

+}

+

+div#header h1 a {

+	color: black;

+}

+

+div#nav {

+	font-size: 91.66%;

+	font-weight: bold;

+	padding-top: 5px;

+	padding-bottom: 5px;

+	border-bottom: solid #cccccc 1px;

+	text-align: right;

+	background-color: #f0f0fa;

+}

+

+div#container.nonav div#content {

+	float: none;

+	width: auto;

+}

+

+*.externallinkinfo {

+	float: right;

+	font-style: italic;

+}

+

+div#content h1 {

+	padding: 10px 3px 5px 3px;

+	margin: 5px 0px;

+	font-size: 175%;

+	font-weight: normal;

+}

+

+div#content h2 {

+	background-color: darkgreen;

+	color: white;

+	padding: 0px 3px;

+	font-size: 116.66%;

+	font-weight: bold;

+}

+

+div#content h2 a {

+	color: white;

+}

+

+div#content h3 {

+	padding: 0px 3px;

+	font-size: 116.66%;

+	font-weight: bold;

+	border-style: solid;

+	border-color: #003399;

+	border-width: 1px 0px;

+}

+

+div#content h4 {

+	padding: 0px 3px;

+	font-size: 100%;

+	font-weight: bold;

+	border-top: solid #eeeeee 1px;

+}

+

+div#content h5 {

+	padding: 0px;

+	margin: 3px 0px;

+}

+

+div#footer {

+	margin-top: 20px;

+	padding: 2px;

+	border-top: solid #cccccc 1px;

+	font-size: 91.66%;

+}

+

+a {

+	color: #003399;

+	text-decoration: none;

+}

+

+a:hover {

+	text-decoration: underline;

+}

+

+a.bold {

+	font-weight: bold;

+}

+

+a.underlined {

+	text-decoration: underline;

+}

+

+a img {

+	border-width: 0px;

+}

+

+br.clear {

+	clear: both;

+}

+

+table {

+	font-size: 100%;

+}

+

+/* Code */

+pre, code {

+	font-family: Courier New, Courier;

+	font-size: 108.33%;

+}

+

+pre.code, pre.console {

+	border: solid 1px #cccccc;

+	padding: 3px;

+}

+

+pre.code {

+	background-color: #eeeeee;

+}

+

+*.trace {

+	color: #666666;

+}

+

+*.debug {

+	color: green;

+}

+

+*.info {

+	color: #000099;

+}

+

+*.warn {

+	color: #999900;

+}

+

+*.error {

+	color: red;

+}

+

+*.fatal {

+	color: #660066;

+}

+

+

+div.example, div.panel {

+	border: solid 1px #cccccc;

+	background-color: #f5f5f5;

+	padding: 3px;

+	margin-bottom: 10px;

+}

+

+div.panel h2 {

+	margin: 5px 0px;

+}

+

+div.padded {

+	padding: 10px;

+}

+

+div.hidden {

+	display: none;

+}

+

+div.active {

+	background-color: #fcfffc;

+	border-color: green;

+}

+

+label.rightofinput, input.rightoflabel {

+	margin-right: 20px;

+}

+

+/* 'Back to top' link */

+p.linktotop {

+	text-align: right;

+}

+

+ul.propertieslist li.method, ul.propertieslist li.property {

+	margin: 0;

+	padding: 0px 0px 15px 0px;

+}

+

+ul.propertieslist li *.name {

+	font-size: 116.66%;

+	font-weight: bold;

+}

+

+ul.propertieslist li.method div.methodsignature {

+	margin: 10px 0px;

+	font-size: 116.66%;

+	background-color: #eeeeee;

+}

+

+ul.propertieslist li.method *.paramsheading {

+	font-weight: bold;

+}

+

+ul.propertieslist li.method *.params {

+	padding-top: 5px;

+	padding-bottom: 5px;

+}

+

+ul.propertieslist li.method *.params li.param {

+	padding-bottom: 10px;

+}

+

+ul.propertieslist li.method *.params li.param *.paramname {

+	font-style: italic;

+}

+

+div.serverlog {

+	height: 200px;

+	/*border: solid 1px #cccccc;*/

+}

+

+div#inPageConsole {

+	margin-top: 10px;

+}

+

+div.iframecontainer {

+	background-color: white;

+	border: solid #cccccc 1px;

+	width: 100%;

+}

+

+div.veryprominent {

+	background-color: darkgreen;

+	color: white;

+	font-weight: bold;

+	padding: 10px;

+	font-size: 133.33%;

+	margin-bottom: 10px;

+}

+

+div.veryprominent a {

+	color: white;

+}

+

+*.largetext {

+	font-size: 116.66%;

+}

+

+div#leftcolumn {

+	float: left;

+	width: 160px;

+}

+

+div#rightcolumn {

+	float: right;

+	width: 580px;

+}

+

+td.fullsupport {

+	background-color: lightgreen;

+}

+

+td.partialsupport {

+	background-color: gold;

+}

+

+td.nosupport {

+	background-color: lightcoral;

+}

+

+p.editions {

+	text-align: right;

+	font-style: italic;

+}
\ No newline at end of file
diff --git a/xos/core/static/log4javascript-1.4.6/test/index.html b/xos/core/static/log4javascript-1.4.6/test/index.html
new file mode 100644
index 0000000..e01f13c
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/test/index.html
@@ -0,0 +1,15 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript - Tests</title>

+	</head>

+	<body>

+		<ul>

+			<li><a href="log4javascript.html">Standard edition tests</a></li>

+			<li><a href="log4javascript_uncompressed.html">Standard edition uncompressed tests</a></li>

+			<li><a href="log4javascript_production.html">Production edition tests</a></li>

+			<li><a href="log4javascript_production_uncompressed.html">Production edition uncompressed tests</a></li>

+		</ul>

+	</body>

+</html>

diff --git a/xos/core/static/log4javascript-1.4.6/test/log4javascript.html b/xos/core/static/log4javascript-1.4.6/test/log4javascript.html
new file mode 100644
index 0000000..8e426b9
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/test/log4javascript.html
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript - log4javascript - Tests</title>

+		<script type="text/javascript" src="../js/log4javascript.js"></script>

+		<script type="text/javascript" src="../js/stubs/log4javascript.js"></script>

+		<script type="text/javascript" src="xntest.js"></script>

+		<script type="text/javascript" src="../js/tests/log4javascript.js"></script>

+		<link rel="stylesheet" type="text/css" href="tests.css"/>

+	</head>

+	<body>

+		<div id="messages"></div>

+		<div id="inlineAppenderContainer"></div>

+	</body>

+</html>

diff --git a/xos/core/static/log4javascript-1.4.6/test/log4javascript_lite.html b/xos/core/static/log4javascript-1.4.6/test/log4javascript_lite.html
new file mode 100644
index 0000000..508dc83
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/test/log4javascript_lite.html
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript - log4javascript_lite - Tests</title>

+		<script type="text/javascript" src="../js/log4javascript_lite.js"></script>

+		<script type="text/javascript" src="../js/stubs/log4javascript_lite.js"></script>

+		<script type="text/javascript" src="xntest.js"></script>

+		<script type="text/javascript" src="../js/tests/log4javascript_lite.js"></script>

+		<link rel="stylesheet" type="text/css" href="tests.css"/>

+	</head>

+	<body>

+		<div id="messages"></div>

+		<div id="inlineAppenderContainer"></div>

+	</body>

+</html>

diff --git a/xos/core/static/log4javascript-1.4.6/test/log4javascript_lite_uncompressed.html b/xos/core/static/log4javascript-1.4.6/test/log4javascript_lite_uncompressed.html
new file mode 100644
index 0000000..968019c
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/test/log4javascript_lite_uncompressed.html
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript - log4javascript_lite_uncompressed - Tests</title>

+		<script type="text/javascript" src="../js/log4javascript_lite_uncompressed.js"></script>

+		<script type="text/javascript" src="../js/stubs/log4javascript_lite_uncompressed.js"></script>

+		<script type="text/javascript" src="xntest.js"></script>

+		<script type="text/javascript" src="../js/tests/log4javascript_lite_uncompressed.js"></script>

+		<link rel="stylesheet" type="text/css" href="tests.css"/>

+	</head>

+	<body>

+		<div id="messages"></div>

+		<div id="inlineAppenderContainer"></div>

+	</body>

+</html>

diff --git a/xos/core/static/log4javascript-1.4.6/test/log4javascript_production.html b/xos/core/static/log4javascript-1.4.6/test/log4javascript_production.html
new file mode 100644
index 0000000..e5308b1
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/test/log4javascript_production.html
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript - log4javascript_production - Tests</title>

+		<script type="text/javascript" src="../js/log4javascript_production.js"></script>

+		<script type="text/javascript" src="../js/stubs/log4javascript_production.js"></script>

+		<script type="text/javascript" src="xntest.js"></script>

+		<script type="text/javascript" src="../js/tests/log4javascript_production.js"></script>

+		<link rel="stylesheet" type="text/css" href="tests.css"/>

+	</head>

+	<body>

+		<div id="messages"></div>

+		<div id="inlineAppenderContainer"></div>

+	</body>

+</html>

diff --git a/xos/core/static/log4javascript-1.4.6/test/log4javascript_production_uncompressed.html b/xos/core/static/log4javascript-1.4.6/test/log4javascript_production_uncompressed.html
new file mode 100644
index 0000000..21f84d7
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/test/log4javascript_production_uncompressed.html
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript - log4javascript_production_uncompressed - Tests</title>

+		<script type="text/javascript" src="../js/log4javascript_production_uncompressed.js"></script>

+		<script type="text/javascript" src="../js/stubs/log4javascript_production_uncompressed.js"></script>

+		<script type="text/javascript" src="xntest.js"></script>

+		<script type="text/javascript" src="../js/tests/log4javascript_production_uncompressed.js"></script>

+		<link rel="stylesheet" type="text/css" href="tests.css"/>

+	</head>

+	<body>

+		<div id="messages"></div>

+		<div id="inlineAppenderContainer"></div>

+	</body>

+</html>

diff --git a/xos/core/static/log4javascript-1.4.6/test/log4javascript_uncompressed.html b/xos/core/static/log4javascript-1.4.6/test/log4javascript_uncompressed.html
new file mode 100644
index 0000000..3db9241
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/test/log4javascript_uncompressed.html
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript - log4javascript_uncompressed - Tests</title>

+		<script type="text/javascript" src="../js/log4javascript_uncompressed.js"></script>

+		<script type="text/javascript" src="../js/stubs/log4javascript_uncompressed.js"></script>

+		<script type="text/javascript" src="xntest.js"></script>

+		<script type="text/javascript" src="../js/tests/log4javascript_uncompressed.js"></script>

+		<link rel="stylesheet" type="text/css" href="tests.css"/>

+	</head>

+	<body>

+		<div id="messages"></div>

+		<div id="inlineAppenderContainer"></div>

+	</body>

+</html>

diff --git a/xos/core/static/log4javascript-1.4.6/test/main.html b/xos/core/static/log4javascript-1.4.6/test/main.html
new file mode 100644
index 0000000..176098f
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/test/main.html
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript - %%build:edition%% - Tests</title>

+		<script type="text/javascript" src="../js/%%build:edition%%.js"></script>

+		<script type="text/javascript" src="../js/stubs/%%build:edition%%.js"></script>

+		<script type="text/javascript" src="xntest.js"></script>

+		<script type="text/javascript" src="../js/tests/%%build:edition%%.js"></script>

+		<link rel="stylesheet" type="text/css" href="tests.css"/>

+	</head>

+	<body>

+		<div id="messages"></div>

+		<div id="inlineAppenderContainer"></div>

+	</body>

+</html>

diff --git a/xos/core/static/log4javascript-1.4.6/test/tests.css b/xos/core/static/log4javascript-1.4.6/test/tests.css
new file mode 100644
index 0000000..9cddef8
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/test/tests.css
@@ -0,0 +1,88 @@
+body {

+	font-family: verdana, arial, helvetica, sans-serif;

+	font-size: 81.25%;

+}

+

+h2 {

+	font-size: 100%;

+	padding: 0;

+	margin: 0.1em 0 0.1em 0;

+}

+

+div.xn_test_suite_container {

+	border: solid #cccccc 1px;

+	padding: 2px 5px;

+	margin: 2px 0px;

+}

+

+div.xn_test_progressbar_container {

+	border: solid black 1px;

+}

+

+div.xn_test_progressbar_container *.success {

+	background-color: #00ff00;

+}

+

+div.xn_test_progressbar_container *.failure {

+	background-color: red;

+}

+

+div.xn_test_overallprogressbar_container {

+	position: relative;

+}

+

+div.xn_test_overallprogressbar_container h1 {

+	margin: 0;

+	padding: 2px;

+	font-size: 125%;

+	font-weight: bold;

+	white-space: nowrap;

+}

+

+dl *.success {

+	color: green;

+}

+

+dl *.failure {

+	color: red;

+}

+

+span.xn_test_expander {

+	padding: 0;

+	border: solid black 1px;

+	cursor: pointer;

+	cursor: hand;

+	line-height: 100%; 

+	font-weight: bold;

+	margin-right: 1em;

+	font-size: 11px;

+}

+

+dl.xn_test_expanded {

+	display: block;

+}

+

+dl.xn_test_collapsed {

+	display: none;

+}

+

+div.xn_test_suite_success {

+	border: solid 2px limegreen;

+}

+

+div.xn_test_suite_failure {

+	border: solid 2px red;

+}

+

+pre.xn_test_log_report {

+	background-color: #f5f5f5;

+	padding: 3px;

+	border: solid gray 1px;

+	font-size: 11px;

+	font-family: Courier New, Courier, monospace;

+}

+

+code.xn_test_stacktrace {

+	color: red;

+	overflow: 

+}
\ No newline at end of file
diff --git a/xos/core/static/log4javascript-1.4.6/test/xntest.js b/xos/core/static/log4javascript-1.4.6/test/xntest.js
new file mode 100644
index 0000000..1b8f475
--- /dev/null
+++ b/xos/core/static/log4javascript-1.4.6/test/xntest.js
@@ -0,0 +1,739 @@
+// Next three methods are primarily for IE5, which is missing them
+if (!Array.prototype.push) {
+	Array.prototype.push = function() {
+		for (var i = 0; i < arguments.length; i++){
+				this[this.length] = arguments[i];
+		}
+		return this.length;
+	};
+}
+
+if (!Array.prototype.shift) {
+	Array.prototype.shift = function() {
+		if (this.length > 0) {
+			var firstItem = this[0];
+			for (var i = 0; i < this.length - 1; i++) {
+				this[i] = this[i + 1];
+			}
+			this.length = this.length - 1;
+			return firstItem;
+		}
+	};
+}
+
+if (!Function.prototype.apply) {
+	Function.prototype.apply = function(obj, args) {
+		var methodName = "__apply__";
+		if (typeof obj[methodName] != "undefined") {
+			methodName += (String(Math.random())).substr(2);
+		}
+		obj[methodName] = this;
+
+		var argsStrings = new Array(args.length);
+		for (var i = 0; i < args.length; i++) {
+			argsStrings[i] = "args[" + i + "]";
+		}
+		var script = "obj." + methodName + "(" + argsStrings.join(",") + ")";
+		var returnValue = eval(script);
+		delete obj[methodName];
+		return returnValue;
+	};
+}
+
+/* -------------------------------------------------------------------------- */
+
+var xn = new Object();
+
+(function() {
+	// Utility functions
+
+	// Event listeners
+	var getListenersPropertyName = function(eventName) {
+		return "__listeners__" + eventName;
+	};
+
+	var addEventListener = function(node, eventName, listener, useCapture) {
+		useCapture = Boolean(useCapture);
+		if (node.addEventListener) {
+			node.addEventListener(eventName, listener, useCapture);
+		} else if (node.attachEvent) {
+			node.attachEvent("on" + eventName, listener);
+		} else {
+			var propertyName = getListenersPropertyName(eventName);
+			if (!node[propertyName]) {
+				node[propertyName] = new Array();
+
+				// Set event handler
+				node["on" + eventName] = function(evt) {
+					evt = module.getEvent(evt);
+					var listenersPropertyName = getListenersPropertyName(eventName);
+
+					// Clone the array of listeners to leave the original untouched
+					var listeners = cloneArray(this[listenersPropertyName]);
+					var currentListener;
+
+					// Call each listener in turn
+					while (currentListener = listeners.shift()) {
+						currentListener.call(this, evt);
+					}
+				};
+			}
+			node[propertyName].push(listener);
+		}
+	};
+
+	// Clones an array
+	var cloneArray = function(arr) {
+		var clonedArray = [];
+		for (var i = 0; i < arr.length; i++) {
+			clonedArray[i] = arr[i];
+		}
+		return clonedArray;
+	}
+
+	var isFunction = function(f) {
+		if (!f){ return false; }
+		return (f instanceof Function || typeof f == "function");
+	};
+
+	// CSS Utilities
+	
+	function array_contains(arr, val) {
+		for (var i = 0, len = arr.length; i < len; i++) {
+			if (arr[i] === val) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	function addClass(el, cssClass) {
+		if (!hasClass(el, cssClass)) {
+			if (el.className) {
+				el.className += " " + cssClass;
+			} else {
+				el.className = cssClass;
+			}
+		}
+	}
+
+	function hasClass(el, cssClass) {
+		if (el.className) {
+			var classNames = el.className.split(" ");
+			return array_contains(classNames, cssClass);
+		}
+		return false;
+	}
+
+	function removeClass(el, cssClass) {
+		if (hasClass(el, cssClass)) {
+			// Rebuild the className property
+			var existingClasses = el.className.split(" ");
+			var newClasses = [];
+			for (var i = 0; i < existingClasses.length; i++) {
+				if (existingClasses[i] != cssClass) {
+					newClasses[newClasses.length] = existingClasses[i];
+				}
+			}
+			el.className = newClasses.join(" ");
+		}
+	}
+
+	function replaceClass(el, newCssClass, oldCssClass) {
+		removeClass(el, oldCssClass);
+		addClass(el, newCssClass);
+	}
+
+	function getExceptionStringRep(ex) {
+		if (ex) {
+			var exStr = "Exception: ";
+			if (ex.message) {
+				exStr += ex.message;
+			} else if (ex.description) {
+				exStr += ex.description;
+			}
+			if (ex.lineNumber) {
+				exStr += " on line number " + ex.lineNumber;
+			}
+			if (ex.fileName) {
+				exStr += " in file " + ex.fileName;
+			}
+			return exStr;
+		}
+		return null;
+	}
+
+
+	/* ---------------------------------------------------------------------- */
+
+	/* Configure the test logger try to use FireBug */
+	var log, error;
+	if (window["console"] && typeof console.log == "function") {
+		log = function() {
+			if (xn.test.enableTestDebug) {
+				console.log.apply(console, arguments);
+			}
+		};
+		error = function() {
+			if (xn.test.enableTestDebug) {
+				console.error.apply(console, arguments);
+			}
+		};
+	} else {
+		log = function() {};
+	}
+
+	/* Set up something to report to */
+
+	var initialized = false;
+	var container;
+	var progressBarContainer, progressBar, overallSummaryText;
+	var currentTest = null;
+	var suites = [];
+	var totalTestCount = 0;
+	var currentTestIndex = 0;
+	var testFailed = false;
+	var testsPassedCount = 0;
+	var startTime;
+	
+	var log4javascriptEnabled = false;
+	
+	var nextSuiteIndex = 0;
+	
+	function runNextSuite() {
+		if (nextSuiteIndex < suites.length) {
+			suites[nextSuiteIndex++].run();
+		}
+	}
+	
+	var init = function() {
+		if (initialized) { return true; }
+		
+		container = document.createElement("div");
+		
+		// Create the overall progress bar
+		progressBarContainer = container.appendChild(document.createElement("div"));
+		progressBarContainer.className = "xn_test_progressbar_container xn_test_overallprogressbar_container";
+		progressBar = progressBarContainer.appendChild(document.createElement("div"));
+		progressBar.className = "success";
+
+		document.body.appendChild(container);
+
+		var h1 = progressBar.appendChild(document.createElement("h1"));
+		overallSummaryText = h1.appendChild(document.createTextNode(""));
+
+		initialized = true;
+		
+		// Set up logging
+		log4javascriptEnabled = !!log4javascript && xn.test.enable_log4javascript;
+		
+		function TestLogAppender() {}
+		
+		if (log4javascriptEnabled) {
+			TestLogAppender.prototype = new log4javascript.Appender();
+			TestLogAppender.prototype.layout = new log4javascript.PatternLayout("%d{HH:mm:ss,SSS} %-5p %m");
+			TestLogAppender.prototype.append = function(loggingEvent) {
+				var formattedMessage = this.getLayout().format(loggingEvent);
+				if (this.getLayout().ignoresThrowable()) {
+					formattedMessage += loggingEvent.getThrowableStrRep();
+				}
+				currentTest.addLogMessage(formattedMessage);
+			};
+			
+			var appender = new TestLogAppender();
+			appender.setThreshold(log4javascript.Level.ALL);
+			log4javascript.getRootLogger().addAppender(appender);
+			log4javascript.getRootLogger().setLevel(log4javascript.Level.ALL);
+		}
+
+		startTime = new Date();
+
+		// First, build each suite
+		for (var i = 0; i < suites.length; i++) {
+			suites[i].build();
+			totalTestCount += suites[i].tests.length;
+		}
+		
+		// Now run each suite
+		runNextSuite();
+	};
+	
+	function updateProgressBar() {
+		progressBar.style.width = "" + parseInt(100 * (currentTestIndex) / totalTestCount) + "%";
+		var s = (totalTestCount === 1) ? "" : "s";
+		var timeTaken = new Date().getTime() - startTime.getTime();
+		overallSummaryText.nodeValue = "" + testsPassedCount + " of " + totalTestCount + " test" + s + " passed in " + timeTaken + "ms";
+	}
+
+	addEventListener(window, "load", init);
+
+	/* ---------------------------------------------------------------------- */
+
+	/* Test Suite */
+	var Suite = function(name, callback, hideSuccessful) {
+		this.name = name;
+		this.callback = callback;
+		this.hideSuccessful = hideSuccessful;
+		this.tests = [];
+		this.log = log;
+		this.error = error;
+		this.expanded = true;
+		suites.push(this);
+	}
+
+	Suite.prototype.test = function(name, callback, setUp, tearDown) {
+		this.log("adding a test named " + name)
+		var t = new Test(name, callback, this, setUp, tearDown);
+		this.tests.push(t);
+	};
+
+	Suite.prototype.build = function() {
+		// Build the elements used by the suite
+		var suite = this;
+		this.testFailed = false;
+		this.container = document.createElement("div");
+		this.container.className = "xn_test_suite_container";
+
+		var heading = document.createElement("h2");
+		this.expander = document.createElement("span");
+		this.expander.className = "xn_test_expander";
+		this.expander.onclick = function() {
+			if (suite.expanded) {
+				suite.collapse();
+			} else {
+				suite.expand();
+			}
+		};
+		heading.appendChild(this.expander);
+		
+		this.headingTextNode = document.createTextNode(this.name);
+		heading.appendChild(this.headingTextNode);
+		this.container.appendChild(heading);
+
+		this.reportContainer = document.createElement("dl");
+		this.container.appendChild(this.reportContainer);
+
+		this.progressBarContainer = document.createElement("div");
+		this.progressBarContainer.className = "xn_test_progressbar_container";
+		this.progressBar = document.createElement("div");
+		this.progressBar.className = "success";
+		this.progressBar.innerHTML = "&nbsp;";
+		this.progressBarContainer.appendChild(this.progressBar);
+		this.reportContainer.appendChild(this.progressBarContainer);
+
+		this.expand();
+
+		container.appendChild(this.container);
+
+		// invoke callback to build the tests
+		this.callback.apply(this, [this]);
+	};
+
+	Suite.prototype.run = function() {
+		this.log("running suite '%s'", this.name)
+		this.startTime = new Date();
+
+		// now run the first test
+		this._currentIndex = 0;
+		this.runNextTest();
+	};
+
+	Suite.prototype.updateProgressBar = function() {
+		// Update progress bar
+		this.progressBar.style.width = "" + parseInt(100 * (this._currentIndex) / this.tests.length) + "%";
+		//log(this._currentIndex + ", " + this.tests.length + ", " + progressBar.style.width + ", " + progressBar.className);
+	};
+
+	Suite.prototype.expand = function() {
+		this.expander.innerHTML = "-";
+		replaceClass(this.reportContainer, "xn_test_expanded", "xn_test_collapsed");
+		this.expanded = true;
+	};
+
+	Suite.prototype.collapse = function() {
+		this.expander.innerHTML = "+";
+		replaceClass(this.reportContainer, "xn_test_collapsed", "xn_test_expanded");
+		this.expanded = false;
+	};
+
+	Suite.prototype.finish = function(timeTaken) {
+		var newClass = this.testFailed ? "xn_test_suite_failure" : "xn_test_suite_success";
+		var oldClass = this.testFailed ? "xn_test_suite_success" : "xn_test_suite_failure";
+		replaceClass(this.container, newClass, oldClass);
+
+		this.headingTextNode.nodeValue += " (" + timeTaken + "ms)";
+
+		if (this.hideSuccessful && !this.testFailed) {
+			this.collapse();
+		}
+		runNextSuite();
+	};
+
+	/**
+	 * Works recursively with external state (the next index)
+	 * so that we can handle async tests differently
+	 */
+	Suite.prototype.runNextTest = function() {
+		if (this._currentIndex == this.tests.length) {
+			// finished!
+			var timeTaken = new Date().getTime() - this.startTime.getTime();
+
+			this.finish(timeTaken);
+			return;
+		}
+
+		var suite = this;
+		var t = this.tests[this._currentIndex++];
+		currentTestIndex++;
+
+		if (isFunction(suite.setUp)) {
+			suite.setUp.apply(suite, [t]);
+		}
+		if (isFunction(t.setUp)) {
+			t.setUp.apply(t, [t]);
+		}
+
+		t._run();
+		
+		function afterTest() {
+			if (isFunction(suite.tearDown)) {
+				suite.tearDown.apply(suite, [t]);
+			}
+			if (isFunction(t.tearDown)) {
+				t.tearDown.apply(t, [t]);
+			}
+			suite.log("finished test [%s]", t.name);
+			updateProgressBar();
+			suite.updateProgressBar();
+			suite.runNextTest();
+		}
+		
+		if (t.isAsync) {
+			t.whenFinished = afterTest;
+		} else {
+			setTimeout(afterTest, 1);
+		}
+	};
+
+	Suite.prototype.reportSuccess = function() {
+	};
+
+	/* ---------------------------------------------------------------------- */
+	/**
+	 * Create a new test
+	 */
+	var Test = function(name, callback, suite, setUp, tearDown) {
+		this.name = name;
+		this.callback = callback;
+		this.suite = suite;
+		this.setUp = setUp;
+		this.tearDown = tearDown;
+		this.log = log;
+		this.error = error;
+		this.assertCount = 0;
+		this.logMessages = [];
+		this.logExpanded = false;
+	};
+
+	/**
+	 * Default success reporter, please override
+	 */
+	Test.prototype.reportSuccess = function(name, timeTaken) {
+		/* default success reporting handler */
+		this.reportHeading = document.createElement("dt");
+		var text = this.name + " passed in " + timeTaken + "ms";
+		
+		this.reportHeading.appendChild(document.createTextNode(text));
+
+		this.reportHeading.className = "success";
+		var dd = document.createElement("dd");
+		dd.className = "success";
+
+		this.suite.reportContainer.appendChild(this.reportHeading);
+		this.suite.reportContainer.appendChild(dd);
+		this.createLogReport();
+	};
+
+	/**
+	 * Cause the test to immediately fail
+	 */
+	Test.prototype.reportFailure = function(name, msg, ex) {
+		this.suite.testFailed = true;
+		this.suite.progressBar.className = "failure";
+		progressBar.className = "failure";
+		this.reportHeading = document.createElement("dt");
+		this.reportHeading.className = "failure";
+		var text = document.createTextNode(this.name);
+		this.reportHeading.appendChild(text);
+
+		var dd = document.createElement("dd");
+		dd.appendChild(document.createTextNode(msg));
+		dd.className = "failure";
+
+		this.suite.reportContainer.appendChild(this.reportHeading);
+		this.suite.reportContainer.appendChild(dd);
+		if (ex && ex.stack) {
+			var stackTraceContainer = this.suite.reportContainer.appendChild(document.createElement("code"));
+			stackTraceContainer.className = "xn_test_stacktrace";
+			stackTraceContainer.innerHTML = ex.stack.replace(/\r/g, "\n").replace(/\n{1,2}/g, "<br />");
+		}
+		this.createLogReport();
+	};
+	
+	Test.prototype.createLogReport = function() {
+		if (this.logMessages.length > 0) {
+			this.reportHeading.appendChild(document.createTextNode(" ("));
+			var logToggler = this.reportHeading.appendChild(document.createElement("a"));
+			logToggler.href = "#";
+			logToggler.innerHTML = "show log";
+			var test = this;
+			
+			logToggler.onclick = function() {
+				if (test.logExpanded) {
+					test.hideLogReport();
+					this.innerHTML = "show log";
+					test.logExpanded = false;
+				} else {
+					test.showLogReport();
+					this.innerHTML = "hide log";
+					test.logExpanded = true;
+				}
+				return false;
+			};
+
+			this.reportHeading.appendChild(document.createTextNode(")"));
+			
+			// Create log report
+			this.logReport = this.suite.reportContainer.appendChild(document.createElement("pre"));
+			this.logReport.style.display = "none";
+			this.logReport.className = "xn_test_log_report";
+			var logMessageDiv;
+			for (var i = 0, len = this.logMessages.length; i < len; i++) {
+				logMessageDiv = this.logReport.appendChild(document.createElement("div"));
+				logMessageDiv.appendChild(document.createTextNode(this.logMessages[i]));
+			}
+		}
+	};
+
+	Test.prototype.showLogReport = function() {
+		this.logReport.style.display = "inline-block";
+	};
+		
+	Test.prototype.hideLogReport = function() {
+		this.logReport.style.display = "none";
+	};
+
+	Test.prototype.async = function(timeout, callback) {
+		timeout = timeout || 250;
+		var self = this;
+		var timedOutFunc = function() {
+			if (!self.completed) {
+				var message = (typeof callback === "undefined") ?
+							"Asynchronous test timed out" : callback(self);
+				self.fail(message);
+			}
+		}
+		var timer = setTimeout(function () { timedOutFunc.apply(self, []); }, timeout)
+		this.isAsync = true;
+	};
+
+	/**
+	 * Run the test
+	 */
+	Test.prototype._run = function() {
+		this.log("starting test [%s]", this.name);
+		this.startTime = new Date();
+		currentTest = this;
+		try {
+			this.callback(this);
+			if (!this.completed && !this.isAsync) {
+				this.succeed();
+			}
+		} catch (e) {
+			this.log("test [%s] threw exception [%s]", this.name, e);
+			var s = (this.assertCount === 1) ? "" : "s";
+			this.fail("Exception thrown after " + this.assertCount + " successful assertion" + s + ": " + getExceptionStringRep(e), e);
+		}
+	};
+
+	/**
+	 * Cause the test to immediately succeed
+	 */
+	Test.prototype.succeed = function() {
+		if (this.completed) { return false; }
+		// this.log("test [%s] succeeded", this.name);
+		this.completed = true;
+		var timeTaken = new Date().getTime() - this.startTime.getTime();
+		testsPassedCount++;
+		this.reportSuccess(this.name, timeTaken);
+		if (this.whenFinished) {
+			this.whenFinished();
+		}
+	};
+
+	Test.prototype.fail = function(msg, ex)	{
+		if (typeof msg != "string") {
+			msg = getExceptionStringRep(msg);
+		}
+		if (this.completed) { return false; }
+		this.completed = true;
+		// this.log("test [%s] failed", this.name);
+		this.reportFailure(this.name, msg, ex);
+		if (this.whenFinished) {
+			this.whenFinished();
+		}
+	};
+	
+	Test.prototype.addLogMessage = function(logMessage) {
+		this.logMessages.push(logMessage);
+	};
+
+	/* assertions */
+	var displayStringForValue = function(obj) {
+		if (obj === null) {
+			return "null";
+		} else if (typeof obj === "undefined") {
+			return "undefined";
+		}
+		return obj.toString();
+	};
+
+	var assert = function(args, expectedArgsCount, testFunction, defaultComment) {
+		this.assertCount++;
+		var comment = defaultComment;
+		var i;
+		var success;
+		var values = [];
+		if (args.length == expectedArgsCount) {
+			for (i = 0; i < args.length; i++) {
+				values[i] = args[i];
+			}
+		} else if (args.length == expectedArgsCount + 1) {
+			comment = args[0];
+			for (i = 1; i < args.length; i++) {
+				values[i - 1] = args[i];
+			}
+		} else {
+			throw new Error("Invalid number of arguments passed to assert function");
+		}
+		success = testFunction(values);
+		if (!success) {
+			var regex = /\{([0-9]+)\}/;
+			while (regex.test(comment)) {
+				comment = comment.replace(regex, displayStringForValue(values[parseInt(RegExp.$1)]));
+			}
+			this.fail("Test failed on assertion " + this.assertCount + ": " + comment);
+		}
+	};
+
+	var testNull = function(values) {
+		return (values[0] === null);
+	};
+
+	Test.prototype.assertNull = function() {
+		assert.apply(this, [arguments, 1, testNull, "Expected to be null but was {0}"]);
+	}
+
+	var testNotNull = function(values) {
+		return (values[0] !== null);
+	};
+
+	Test.prototype.assertNotNull = function() {
+		assert.apply(this, [arguments, 1, testNotNull, "Expected not to be null but was {0}"]);
+	}
+
+	var testBoolean = function(values) {
+		return (Boolean(values[0]));
+	};
+
+	Test.prototype.assert = function() {
+		assert.apply(this, [arguments, 1, testBoolean, "Expected not to be equivalent to false"]);
+	};
+
+	var testTrue = function(values) {
+		return (values[0] === true);
+	};
+
+	Test.prototype.assertTrue = function() {
+		assert.apply(this, [arguments, 1, testTrue, "Expected to be true but was {0}"]);
+	};
+
+	Test.prototype.assert = function() {
+		assert.apply(this, [arguments, 1, testTrue, "Expected to be true but was {0}"]);
+	};
+
+	var testFalse = function(values) {
+		return (values[0] === false);
+	};
+
+	Test.prototype.assertFalse = function() {
+		assert.apply(this, [arguments, 1, testFalse, "Expected to be false but was {0}"]);
+	}
+
+	var testEquivalent = function(values) {
+		return (values[0] === values[1]);
+	};
+
+	Test.prototype.assertEquivalent = function() {
+		assert.apply(this, [arguments, 2, testEquivalent, "Expected to be equal but values were {0} and {1}"]);
+	}
+
+	var testNotEquivalent = function(values) {
+		return (values[0] !== values[1]);
+	};
+
+	Test.prototype.assertNotEquivalent = function() {
+		assert.apply(this, [arguments, 2, testNotEquivalent, "Expected to be not equal but values were {0} and {1}"]);
+	}
+
+	var testEquals = function(values) {
+		return (values[0] == values[1]);
+	};
+
+	Test.prototype.assertEquals = function() {
+		assert.apply(this, [arguments, 2, testEquals, "Expected to be equal but values were {0} and {1}"]);
+	}
+
+	var testNotEquals = function(values) {
+		return (values[0] != values[1]);
+	};
+
+	Test.prototype.assertNotEquals = function() {
+		assert.apply(this, [arguments, 2, testNotEquals, "Expected to be not equal but values were {0} and {1}"]);
+	}
+
+	var testRegexMatches = function(values) {
+		return (values[0].test(values[1]));
+	};
+
+	Test.prototype.assertRegexMatches = function() {
+		assert.apply(this, [arguments, 2, testRegexMatches, "Expected regex {0} to match value {1} but it didn't"]);
+	}
+
+	Test.prototype.assertError = function(f, errorType) {
+		try {
+			f();
+			this.fail("Expected error to be thrown");
+		} catch (e) {
+			if (errorType && (!(e instanceof errorType))) {
+				this.fail("Expected error of type " + errorType + " to be thrown but error thrown was " + e);
+			}
+		}
+	};
+
+	/**
+	 * Execute a synchronous test
+	 */
+	xn.test = function(name, callback) {
+		xn.test.suite("Anonymous", function(s) {
+			s.test(name, callback);
+		});
+	}
+
+	/**
+	 * Create a test suite with a given name
+	 */
+	xn.test.suite = function(name, callback, hideSuccessful) {
+		var s = new Suite(name, callback, hideSuccessful);
+	}
+})();
\ No newline at end of file
diff --git a/xos/core/static/logo.png b/xos/core/static/logo.png
new file mode 100644
index 0000000..a55f86a
--- /dev/null
+++ b/xos/core/static/logo.png
Binary files differ
diff --git a/xos/core/static/logo_opague_circles.png b/xos/core/static/logo_opague_circles.png
new file mode 100644
index 0000000..306fc46
--- /dev/null
+++ b/xos/core/static/logo_opague_circles.png
Binary files differ
diff --git a/xos/core/static/mCordServices/service_cache.png b/xos/core/static/mCordServices/service_cache.png
new file mode 100644
index 0000000..a8b5480
--- /dev/null
+++ b/xos/core/static/mCordServices/service_cache.png
Binary files differ
diff --git a/xos/core/static/mCordServices/service_common.png b/xos/core/static/mCordServices/service_common.png
new file mode 100644
index 0000000..9fda14e
--- /dev/null
+++ b/xos/core/static/mCordServices/service_common.png
Binary files differ
diff --git a/xos/core/static/mCordServices/service_firewall.png b/xos/core/static/mCordServices/service_firewall.png
new file mode 100644
index 0000000..17e87be
--- /dev/null
+++ b/xos/core/static/mCordServices/service_firewall.png
Binary files differ
diff --git a/xos/core/static/mCordServices/service_rru.png b/xos/core/static/mCordServices/service_rru.png
new file mode 100644
index 0000000..8a667c0
--- /dev/null
+++ b/xos/core/static/mCordServices/service_rru.png
Binary files differ
diff --git a/xos/core/static/mCordServices/service_server.png b/xos/core/static/mCordServices/service_server.png
new file mode 100644
index 0000000..17ce83d
--- /dev/null
+++ b/xos/core/static/mCordServices/service_server.png
Binary files differ
diff --git a/xos/core/static/mCordServices/service_video.png b/xos/core/static/mCordServices/service_video.png
new file mode 100644
index 0000000..91ad760
--- /dev/null
+++ b/xos/core/static/mCordServices/service_video.png
Binary files differ
diff --git a/xos/core/static/main.js b/xos/core/static/main.js
new file mode 100644
index 0000000..486d65a
--- /dev/null
+++ b/xos/core/static/main.js
@@ -0,0 +1,153 @@
+$(document).ready(function() {
+
+	
+	function getServerData(url, label, value) {
+		var jqxhr = $.getJSON( url, function(data) {
+			if (value == 'nodesValue') {
+				var unit = '';
+				window.nodesCnt = data;
+			} else if (value == 'cpuValue'){
+				var unit = '%';
+				window.cpuCnt = data;
+			} else if (value == 'bandwidthValue'){
+				var unit = '';
+				window.bandData = data;
+			}
+			var legend = data.legend;
+			var data = data.data;
+			var dataLength = data.length - 1;
+			$('.'+label).text(legend).show();
+			$('.'+value).text(Math.round(data[dataLength][1])+unit).show();
+		})
+		
+	}
+	var selectedNodeTxt = $('.currentOriginalNode').text();
+	selectedNodeTxt = selectedNodeTxt.trim();
+	selectedNodeTxt = selectedNodeTxt.split(' ').join('');//selectedNodeTxt.replace(" ", "")
+	var parentNodeTxt = $('.selectedMainNav').text();
+	parentNodeTxt = parentNodeTxt.replace("/\n","");
+ 	parentNodeTxt = parentNodeTxt.replace("»","");
+	parentNodeTxt = parentNodeTxt.trim();
+	
+	baseNodeQuery = 'SELECT Minute(time) as Minute,COUNT(distinct %hostname) FROM [vicci.demoevents]';
+	baseCpuQuery = 'SELECT Minute(time) as Minute,AVG(i0) as Cpu FROM [vicci.demoevents]';
+	baseBwQuery = 'SELECT Minute(time) as Minute,AVG(i1) as Requests FROM [vicci.demoevents]';
+	groupByClause = ' GROUP BY Minute ORDER BY Minute';
+
+	if (selectedNodeTxt ) {
+		if (parentNodeTxt.length > 0 && parentNodeTxt.charAt(parentNodeTxt.length-1)=='s') {
+			parentNodeTxt = parentNodeTxt.substring(0, parentNodeTxt.length-1);
+		}
+		if (parentNodeTxt=='Slice') {
+			whereClause = " WHERE s3='"+selectedNodeTxt+"'";
+		} 
+		else if (parentNodeTxt=='Site') {
+			whereClause = " WHERE s2='"+selectedNodeTxt+"' OR %hostname CONTAINS '"+selectedNodeTxt+"'";
+		} 
+		else if (parentNodeTxt=='Node') {
+			whereClause = " WHERE %hostname='"+selectedNodeTxt+"'";
+			alert(whereClause);
+		} else {
+			console.log('Error: Unkown object type:'+parentNodeTxt);
+		}
+	} else {
+		whereClause = '';
+	}
+	finalNodeQuery = encodeURIComponent(baseNodeQuery + whereClause + groupByClause);
+	finalCpuQuery = encodeURIComponent(baseCpuQuery + whereClause + groupByClause);
+	finalBwQuery = encodeURIComponent(baseBwQuery + whereClause + groupByClause);
+	getServerData('http://cloud-scrutiny.appspot.com/command?action=send_query&legend=Node+Count&tqx=saber&q='+finalNodeQuery,'nodesLabel','nodesValue');
+	getServerData('http://cloud-scrutiny.appspot.com/command?action=send_query&legend=Load&tqx=saber&q='+finalCpuQuery,'cpuLabel','cpuValue');
+	getServerData('http://cloud-scrutiny.appspot.com/command?action=send_query&legend=Bandwidth&tqx=saber&q='+finalBwQuery,'bandwidthLabel','bandwidthValue');
+
+	$('.nodesLabel, .nodesValue').click(function() {
+		var jsonData = window.nodesCnt;
+		renderChart(jsonData);
+	});
+	$('.cpuLabel, .cpuValue').click(function() {
+		var jsonData = window.cpuCnt;
+		renderChart(jsonData);
+	});
+	$('.bandwidthLabel, .bandwidthValue').click(function() {
+		var jsonData = window.bandData;
+		renderChart(jsonData);
+	});
+
+	function renderChart(jsonData) {
+		$('#graph').empty();
+		$('#chartsModal').modal('show');
+		$('.modal-body').scrollTop(0)
+		var margin = {top: 0, right: 100, bottom: 100, left: 175},
+		width = 520 - margin.left - margin.right,
+		height = 300 - margin.top - margin.bottom;
+
+		var parseDate = d3.time.format("%Y-%m-%m-%H-%M").parse;
+
+		var x = d3.time.scale()
+		.range([0, width]);
+
+		var y = d3.scale.linear()
+		.range([height, 0]);
+
+		var xAxis = d3.svg.axis()
+		.scale(x)
+		.ticks(d3.time.minutes, 15)
+		.orient("bottom");
+
+		var yAxis = d3.svg.axis()
+		.scale(y)
+		.ticks(4)
+		.orient("left");
+
+		var line = d3.svg.line()
+		.x(function(d) { return x(d.date); })
+		.y(function(d) { return y(d.value); });
+
+		var svg = d3.select("#graph").append("svg")
+		.attr("width", width + margin.left + margin.right)
+		.attr("height", height + margin.top + margin.bottom)
+		.append("g")
+		.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
+
+		/*var data_path = "http://sabertooth.cs.princeton.edu/graphs/UpNodes";
+		d3.json(data_path, function(error, input) {*/
+			//jsonData = JSON.stringify(eval("(" + jsonData + ")"));
+			data = jsonData.data;//input['data'];
+			legend = jsonData.legend;//input['legend']
+			$('#chartHeading').text(legend);
+			data.forEach(function(d) {
+				d.date = new Date(d[0]*1000);
+				d.value = +d[1];
+				});
+					x.domain(d3.extent(data, function(d) { return d.date; }));
+
+					var e = d3.extent(data, function(d) { return d.value;});
+					e = [e[0]-1,e[1]+1];
+
+					y.domain(e);
+
+					svg.append("g")
+					.attr("class", "x axis")
+					.attr("transform", "translate(0," + height + ")")
+					.attr("x", 5)
+					.call(xAxis);
+
+					svg.append("g")
+					.attr("class", "y axis")
+					.call(yAxis)
+					.append("text")
+					.attr("transform", "rotate(-90)")
+					.attr("y", 6)
+					.attr("dy", ".71em")
+					.style("text-anchor", "end")
+					.text(legend)
+					.attr("class", "legend");
+
+					svg.append("path")
+					.datum(data)
+					.attr("class", "line")
+					.attr("d", line);
+				//});
+	}
+
+})
diff --git a/xos/core/static/mcord-bg.jpg b/xos/core/static/mcord-bg.jpg
new file mode 100644
index 0000000..e378fda
--- /dev/null
+++ b/xos/core/static/mcord-bg.jpg
Binary files differ
diff --git a/xos/core/static/name.png b/xos/core/static/name.png
new file mode 100644
index 0000000..e8145d6
--- /dev/null
+++ b/xos/core/static/name.png
Binary files differ
diff --git a/xos/core/static/name_old.png b/xos/core/static/name_old.png
new file mode 100644
index 0000000..0ab31a3
--- /dev/null
+++ b/xos/core/static/name_old.png
Binary files differ
diff --git a/xos/core/static/observer_status.js b/xos/core/static/observer_status.js
new file mode 100644
index 0000000..2e46a16
--- /dev/null
+++ b/xos/core/static/observer_status.js
@@ -0,0 +1,45 @@
+function updateObserverStatus() {
+    var url="/observer";
+    $.ajax({ url: url,
+             dataType : 'json',
+             type : 'GET',
+             success: function(newData) {
+                  console.log(newData);
+                  if (newData.health==":-)") {
+                      tooltip = 'last synchronizer run time = ' + Math.floor(newData.last_duration) + ' seconds';
+                      icon = "/static/img/green-cloud.gif";
+                  } else {
+                      tooltip = "synchronizer is offline";
+                      icon = "/static/img/red-cloud.gif";
+                  }
+
+                  html = '<span style="margin-left: 16px; cursor: pointer;" title="' + tooltip + '"><img src="' + icon +
+                         '" width=16 height=16 onClick="showObserverCalendar();"></span>';
+
+                  $("#observer-status").html(html);
+                  setTimeout(function() { updateObserverStatus(); }, 60000);
+             },
+             error: function() {
+                  setTimeout(function() { updateObserverStatus(); }, 60000);
+             }
+});
+}
+
+function showObserverCalendar() {
+    $("#dialog-placeholder").html('<iframe src="https://www.google.com/calendar/embed?src=qlnr1b3rsquq702nbns42l88s4%40group.calendar.google.com&ctz=America/New_York" style="border: 0" width="800" height="600" frameborder="0" scrolling="no"></iframe>');
+    $("#dialog-placeholder").dialog({
+           autoOpen: false,
+           modal: true,
+           width: 850,
+           buttons : {
+                "Ok" : function() {
+                  $(this).dialog("close");
+                }
+              }
+            });
+        $("#dialog-placeholder").dialog("open");
+}
+
+$( document ).ready(function() {
+    updateObserverStatus();
+});
diff --git a/xos/core/static/onos-logo.png b/xos/core/static/onos-logo.png
new file mode 100644
index 0000000..8688cd6
--- /dev/null
+++ b/xos/core/static/onos-logo.png
Binary files differ
diff --git a/xos/core/static/open-cloud-login-themed-light.png b/xos/core/static/open-cloud-login-themed-light.png
new file mode 100644
index 0000000..f926301
--- /dev/null
+++ b/xos/core/static/open-cloud-login-themed-light.png
Binary files differ
diff --git a/xos/core/static/open-cloud-login-themed-light_old.png b/xos/core/static/open-cloud-login-themed-light_old.png
new file mode 100644
index 0000000..af8f582
--- /dev/null
+++ b/xos/core/static/open-cloud-login-themed-light_old.png
Binary files differ
diff --git a/xos/core/static/open-cloud-themed.png b/xos/core/static/open-cloud-themed.png
new file mode 100644
index 0000000..82d0c8d
--- /dev/null
+++ b/xos/core/static/open-cloud-themed.png
Binary files differ
diff --git a/xos/core/static/open-cloud-themed1.png b/xos/core/static/open-cloud-themed1.png
new file mode 100644
index 0000000..2aefd87
--- /dev/null
+++ b/xos/core/static/open-cloud-themed1.png
Binary files differ
diff --git a/xos/core/static/open-cloud-themed2.png b/xos/core/static/open-cloud-themed2.png
new file mode 100644
index 0000000..975146b
--- /dev/null
+++ b/xos/core/static/open-cloud-themed2.png
Binary files differ
diff --git a/xos/core/static/open-cloud-themed_old.png b/xos/core/static/open-cloud-themed_old.png
new file mode 100644
index 0000000..975146b
--- /dev/null
+++ b/xos/core/static/open-cloud-themed_old.png
Binary files differ
diff --git a/xos/core/static/opencloudApp.png b/xos/core/static/opencloudApp.png
new file mode 100644
index 0000000..f6b0660
--- /dev/null
+++ b/xos/core/static/opencloudApp.png
Binary files differ
diff --git a/xos/core/static/page_analytics.js b/xos/core/static/page_analytics.js
new file mode 100644
index 0000000..42058b1
--- /dev/null
+++ b/xos/core/static/page_analytics.js
@@ -0,0 +1,36 @@
+// ----------------------------------------------------------------------------
+// node count and average cpu utilization
+
+function updateMiniDashStatistic(meter, buttonSelector) {
+    var url="/stats/?model_name=" + admin_object_name + "&pk=" + admin_object_id + "&meter=" + meter + "&controller_name=" + admin_object_controller;
+    console.log("fetching stats url " + url);
+    $.ajax({
+    url: url,
+    dataType : 'json',
+    type : 'GET',
+    success: function(newData) {
+        console.log(newData);
+        if (newData.error) {
+            $(buttonSelector).text(newData.error);
+        } else if (newData.stat_list.length > 0) {
+            value = newData.stat_list.slice(-1)[0].value;
+            console.log(value);
+            $(buttonSelector).text(Math.round(value)).show();
+        } else {
+            $(buttonSelector).text("no data").show();
+        }
+        setTimeout(function() { updateMiniDashStatistic(meter, buttonSelector); }, 30000);
+    },
+    error: function() {
+    }
+});
+}
+
+$( document ).ready(function() {
+    if (admin_object_name == "Instance" && admin_object_id != undefined) {
+        updateMiniDashStatistic("cpu", "#miniDashCPU");
+        updateMiniDashStatistic("network.outgoing.bytes", "#miniDashBandwidthIn");
+        updateMiniDashStatistic("network.incoming.bytes", "#miniDashBandwidthOut");
+    }
+});
+
diff --git a/xos/core/static/password.png b/xos/core/static/password.png
new file mode 100644
index 0000000..131490b
--- /dev/null
+++ b/xos/core/static/password.png
Binary files differ
diff --git a/xos/core/static/password_old.png b/xos/core/static/password_old.png
new file mode 100644
index 0000000..8eccd01
--- /dev/null
+++ b/xos/core/static/password_old.png
Binary files differ
diff --git a/xos/core/static/planetstack_graphs_old.js b/xos/core/static/planetstack_graphs_old.js
new file mode 100644
index 0000000..806afe6
--- /dev/null
+++ b/xos/core/static/planetstack_graphs_old.js
@@ -0,0 +1,89 @@
+$(document).ready(function() {
+
+function renderChart(jsonData, yField, xField, legend) {
+    $('#graph').empty();
+    $('#chartsModal').modal('show');
+    $('.modal-body').scrollTop(0)
+    var margin = {top: 0, right: 100, bottom: 100, left: 175},
+    width = 520 - margin.left - margin.right,
+    height = 300 - margin.top - margin.bottom;
+
+    var parseDate = d3.time.format("%Y-%m-%m-%H-%M").parse;
+
+    var x = d3.time.scale()
+    .range([0, width]);
+
+    var y = d3.scale.linear()
+    .range([height, 0]);
+
+    var xAxis = d3.svg.axis()
+    .scale(x)
+    .ticks(d3.time.minutes, 15)
+    .orient("bottom");
+
+    var yAxis = d3.svg.axis()
+    .scale(y)
+    .ticks(4)
+    .orient("left");
+
+    var line = d3.svg.line()
+    .x(function(d) { return x(d.date); })
+    .y(function(d) { return y(d.value); });
+
+    var svg = d3.select("#graph").append("svg")
+    .attr("width", width + margin.left + margin.right)
+    .attr("height", height + margin.top + margin.bottom)
+    .append("g")
+    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
+
+    data = jsonData.rows;
+    $('#chartHeading').text(legend);
+    data.forEach(function(d) {
+            d.date = new Date(d[yField]*1000);
+            d.value = +d[xField];
+            });
+
+    x.domain(d3.extent(data, function(d) { return d.date; }));
+
+    var e = d3.extent(data, function(d) { return d.value;});
+    e = [e[0]-1,e[1]+1];
+
+    y.domain(e);
+
+    svg.append("g")
+    .attr("class", "x axis")
+    .attr("transform", "translate(0," + height + ")")
+    .attr("x", 5)
+    .call(xAxis);
+
+    svg.append("g")
+    .attr("class", "y axis")
+    .call(yAxis)
+    .append("text")
+    .attr("transform", "rotate(-90)")
+    .attr("y", 6)
+    .attr("dy", ".71em")
+    .style("text-anchor", "end")
+    .text(legend)
+    .attr("class", "legend");
+
+    svg.append("path")
+    .datum(data)
+    .attr("class", "line")
+    .attr("d", line);
+}
+
+$('.nodesLabel, .nodesValue').click(function() {
+        var jsonData = window.pageAnalyticsData;
+        renderChart(jsonData, "MinuteTime", "count_hostname", "Node Count");
+});
+$('.cpuLabel, .cpuValue').click(function() {
+        var jsonData = window.pageAnalyticsData;
+        renderChart(jsonData, "MinuteTime", "avg_cpu", "Average Cpu");
+});
+$('.bandwidthLabel, .bandwidthValue').click(function() {
+        var jsonData = window.pageBandData;
+        renderChart(jsonData, "MinuteTime", "sum_computed_bytes_sent_div_elapsed", "Bandwidth");
+});
+
+})
diff --git a/xos/core/static/primarycons_blue/License.txt b/xos/core/static/primarycons_blue/License.txt
new file mode 100644
index 0000000..da57598
--- /dev/null
+++ b/xos/core/static/primarycons_blue/License.txt
@@ -0,0 +1,21 @@
+Thank you for downloading these graphics from MouseRunner.com. 

+

+While I want you to enjoy these free graphics (free as in free of monetary charge, not entirely free usage), I ask that you please abide by the terms that they are licensed under.

+

+-------------------------------------------------------------------------

+

+The graphics contained in these files are being released under a Creative Commons

+Attribution-NonCommercial-ShareAlike 3.0 Unported license.

+

+Furthermore;

+You may not claim the works as your own.

+You must provide a link back to www.MouseRunner.com when using on a website, blog, etc. 

+You may not redistribute these as a package as-is.

+You must seek approval for commercial purposes, and for applications.

+

+Visit the address below to learn more about the Creative Commons license.

+http://creativecommons.org/licenses/by-nc-sa/3.0/

+

+-------------------------------------------------------------------------

+Questions? Contact:

+KenSaunders@MouseRunner.com

diff --git a/xos/core/static/primarycons_blue/folder_1.png b/xos/core/static/primarycons_blue/folder_1.png
new file mode 100644
index 0000000..2c7dc1f
--- /dev/null
+++ b/xos/core/static/primarycons_blue/folder_1.png
Binary files differ
diff --git a/xos/core/static/primarycons_blue/gear_2.png b/xos/core/static/primarycons_blue/gear_2.png
new file mode 100644
index 0000000..4a9e9d0
--- /dev/null
+++ b/xos/core/static/primarycons_blue/gear_2.png
Binary files differ
diff --git a/xos/core/static/primarycons_blue/internet.png b/xos/core/static/primarycons_blue/internet.png
new file mode 100644
index 0000000..89e0de4
--- /dev/null
+++ b/xos/core/static/primarycons_blue/internet.png
Binary files differ
diff --git a/xos/core/static/primarycons_blue/network.png b/xos/core/static/primarycons_blue/network.png
new file mode 100644
index 0000000..37d2241
--- /dev/null
+++ b/xos/core/static/primarycons_blue/network.png
Binary files differ
diff --git a/xos/core/static/primarycons_blue/plus.png b/xos/core/static/primarycons_blue/plus.png
new file mode 100644
index 0000000..a00ab89
--- /dev/null
+++ b/xos/core/static/primarycons_blue/plus.png
Binary files differ
diff --git a/xos/core/static/primarycons_blue/service_graph.png b/xos/core/static/primarycons_blue/service_graph.png
new file mode 100644
index 0000000..e2e8c5b
--- /dev/null
+++ b/xos/core/static/primarycons_blue/service_graph.png
Binary files differ
diff --git a/xos/core/static/right_arrow.png b/xos/core/static/right_arrow.png
new file mode 100644
index 0000000..416828e
--- /dev/null
+++ b/xos/core/static/right_arrow.png
Binary files differ
diff --git a/xos/core/static/shell/opencloud_shell.css b/xos/core/static/shell/opencloud_shell.css
new file mode 100644
index 0000000..4a24cf0
--- /dev/null
+++ b/xos/core/static/shell/opencloud_shell.css
@@ -0,0 +1,85 @@
+#terminal {
+  width: 960px;
+  margin:50px auto 50px auto;
+  border: 1px solid black;
+  height: 400px;
+  background: #002b36;
+  overflow: scroll;
+}
+
+#terminal div.terminal_line {
+  width: 940px;
+  margin-bottom: 5px;
+}
+
+#terminal input {
+  width: 875px;
+  margin: 1px 0 1px 10px;
+  border: none;
+  display: inline;
+  padding: 2px;
+  background: #002b36;
+  color: #839496;
+  font-size: 15px;
+  font-family: Menlo, Monaco, 'Andale Mono', 'lucida console', 'Courier New', monospace;
+  border-radius:0;
+}
+
+#terminal input:focus {
+  box-shadow:none;
+}
+
+#terminal p {
+  margin: 2px;
+  color: #839496;
+  font-size: 15px;
+  font-family: Menlo, Monaco, 'Andale Mono', 'lucida console', 'Courier New', monospace;
+}
+
+.terminal_help {
+  margin: 2px;
+  color: #839496;
+  font-size: 15px;
+  font-family: Menlo, Monaco, 'Andale Mono', 'lucida console', 'Courier New', monospace;
+  background: #002b36;
+  padding:0;
+  line-height:normal;
+}
+
+#terminal a {
+  color: #6495ED;
+}
+
+#terminal span.prompt {
+  color: #839496;
+  font-size: 16px;
+  margin-left: 2px;
+}
+
+/* an experiment with syntax hilighting */
+
+.terminal_string {
+    /*color:green; */
+    color:#859900;
+}
+
+.terminal_number {
+    /*color:darkorange;*/
+    color:#d33682;
+}
+
+.terminal_boolean {
+    /*color:blue;*/
+    color:#7777A0;
+}
+
+.terminal_null {
+    /*color:magenta;*/
+    color:#A000A0;
+}
+
+.terminal_key {
+    /*color:red;*/
+    color:#268bd2;
+}
+
diff --git a/xos/core/static/uploadTextarea.js b/xos/core/static/uploadTextarea.js
new file mode 100644
index 0000000..a7f76bf
--- /dev/null
+++ b/xos/core/static/uploadTextarea.js
@@ -0,0 +1,19 @@
+function uploadTextarea(event,textarea_id) {
+    var input = event.target;
+
+    var reader = new FileReader();
+    //reader.onloadstart = function() {
+    //	reader.abort();
+    //};
+
+    reader.onloadend = function() {
+        if (reader.error) {
+   	    alert(reader.error.message);
+        } else {
+            $("#" + textarea_id).val(this.result);
+	    //console.log(this.result);
+        }
+    };
+
+    reader.readAsText(input.files[0]);
+};
diff --git a/xos/core/static/xos.css b/xos/core/static/xos.css
new file mode 100644
index 0000000..47d1e36
--- /dev/null
+++ b/xos/core/static/xos.css
@@ -0,0 +1,6943 @@
+@charset "UTF-8";
+/*!
+ * Bootstrap v3.3.6 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
+html {
+  font-family: sans-serif;
+  -ms-text-size-adjust: 100%;
+  -webkit-text-size-adjust: 100%; }
+
+body {
+  margin: 0; }
+
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+main,
+menu,
+nav,
+section,
+summary {
+  display: block; }
+
+audio,
+canvas,
+progress,
+video {
+  display: inline-block;
+  vertical-align: baseline; }
+
+audio:not([controls]) {
+  display: none;
+  height: 0; }
+
+[hidden],
+template {
+  display: none; }
+
+a {
+  background-color: transparent; }
+
+a:active,
+a:hover {
+  outline: 0; }
+
+abbr[title] {
+  border-bottom: 1px dotted; }
+
+b,
+strong {
+  font-weight: bold; }
+
+dfn {
+  font-style: italic; }
+
+h1 {
+  font-size: 2em;
+  margin: 0.67em 0; }
+
+mark {
+  background: #ff0;
+  color: #000; }
+
+small {
+  font-size: 80%; }
+
+sub,
+sup {
+  font-size: 75%;
+  line-height: 0;
+  position: relative;
+  vertical-align: baseline; }
+
+sup {
+  top: -0.5em; }
+
+sub {
+  bottom: -0.25em; }
+
+img {
+  border: 0; }
+
+svg:not(:root) {
+  overflow: hidden; }
+
+figure {
+  margin: 1em 40px; }
+
+hr {
+  box-sizing: content-box;
+  height: 0; }
+
+pre {
+  overflow: auto; }
+
+code,
+kbd,
+pre,
+samp {
+  font-family: monospace, monospace;
+  font-size: 1em; }
+
+button,
+input,
+optgroup,
+select,
+textarea {
+  color: inherit;
+  font: inherit;
+  margin: 0; }
+
+button {
+  overflow: visible; }
+
+button,
+select {
+  text-transform: none; }
+
+button,
+html input[type="button"],
+input[type="reset"],
+input[type="submit"] {
+  -webkit-appearance: button;
+  cursor: pointer; }
+
+button[disabled],
+html input[disabled] {
+  cursor: default; }
+
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+  border: 0;
+  padding: 0; }
+
+input {
+  line-height: normal; }
+
+input[type="checkbox"],
+input[type="radio"] {
+  box-sizing: border-box;
+  padding: 0; }
+
+input[type="number"]::-webkit-inner-spin-button,
+input[type="number"]::-webkit-outer-spin-button {
+  height: auto; }
+
+input[type="search"] {
+  -webkit-appearance: textfield;
+  box-sizing: content-box; }
+
+input[type="search"]::-webkit-search-cancel-button,
+input[type="search"]::-webkit-search-decoration {
+  -webkit-appearance: none; }
+
+fieldset {
+  border: 1px solid #c0c0c0;
+  margin: 0 2px;
+  padding: 0.35em 0.625em 0.75em; }
+
+legend {
+  border: 0;
+  padding: 0; }
+
+textarea {
+  overflow: auto; }
+
+optgroup {
+  font-weight: bold; }
+
+table {
+  border-collapse: collapse;
+  border-spacing: 0; }
+
+td,
+th {
+  padding: 0; }
+
+/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */
+@media print {
+  *,
+  *:before,
+  *:after {
+    background: transparent !important;
+    color: #000 !important;
+    box-shadow: none !important;
+    text-shadow: none !important; }
+  a,
+  a:visited {
+    text-decoration: underline; }
+  a[href]:after {
+    content: " (" attr(href) ")"; }
+  abbr[title]:after {
+    content: " (" attr(title) ")"; }
+  a[href^="#"]:after,
+  a[href^="javascript:"]:after {
+    content: ""; }
+  pre,
+  blockquote {
+    border: 1px solid #999;
+    page-break-inside: avoid; }
+  thead {
+    display: table-header-group; }
+  tr,
+  img {
+    page-break-inside: avoid; }
+  img {
+    max-width: 100% !important; }
+  p,
+  h2,
+  h3 {
+    orphans: 3;
+    widows: 3; }
+  h2,
+  h3 {
+    page-break-after: avoid; }
+  .navbar {
+    display: none; }
+  .btn > .caret,
+  .dropup > .btn > .caret {
+    border-top-color: #000 !important; }
+  .label {
+    border: 1px solid #000; }
+  .table {
+    border-collapse: collapse !important; }
+    .table td,
+    .table th {
+      background-color: #fff !important; }
+  .table-bordered th,
+  .table-bordered td {
+    border: 1px solid #ddd !important; } }
+
+@font-face {
+  font-family: 'Glyphicons Halflings';
+  src: url("/static/suit/bootstrap/fonts/glyphicons-halflings-regular.eot");
+  src: url("/static/suit/bootstrap/fonts/glyphicons-halflings-regular.eot?#iefix") format("embedded-opentype"), url("/static/suit/bootstrap/fonts/glyphicons-halflings-regular.woff2") format("woff2"), url("/static/suit/bootstrap/fonts/glyphicons-halflings-regular.woff") format("woff"), url("/static/suit/bootstrap/fonts/glyphicons-halflings-regular.ttf") format("truetype"), url("/static/suit/bootstrap/fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular") format("svg"); }
+
+.glyphicon {
+  position: relative;
+  top: 1px;
+  display: inline-block;
+  font-family: 'Glyphicons Halflings';
+  font-style: normal;
+  font-weight: normal;
+  line-height: 1;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale; }
+
+.glyphicon-asterisk:before {
+  content: "\002a"; }
+
+.glyphicon-plus:before {
+  content: "\002b"; }
+
+#wrapper.toggled #page-content-wrapper {
+    position: absolute;
+    margin-right: -250px;
+}
+
+.glyphicon-euro:before,
+.glyphicon-eur:before {
+  content: "\20ac"; }
+
+.glyphicon-minus:before {
+  content: "\2212"; }
+
+.glyphicon-cloud:before {
+  content: "\2601"; }
+
+.glyphicon-envelope:before {
+  content: "\2709"; }
+
+.glyphicon-pencil:before {
+  content: "\270f"; }
+
+.glyphicon-glass:before {
+  content: "\e001"; }
+
+.glyphicon-music:before {
+  content: "\e002"; }
+
+.glyphicon-search:before {
+  content: "\e003"; }
+
+.glyphicon-heart:before {
+  content: "\e005"; }
+
+.glyphicon-star:before {
+  content: "\e006"; }
+
+.glyphicon-star-empty:before {
+  content: "\e007"; }
+
+.glyphicon-user:before {
+  content: "\e008"; }
+
+.glyphicon-film:before {
+  content: "\e009"; }
+
+.glyphicon-th-large:before {
+  content: "\e010"; }
+
+.glyphicon-th:before {
+  content: "\e011"; }
+
+.glyphicon-th-list:before {
+  content: "\e012"; }
+
+.glyphicon-ok:before {
+  content: "\e013"; }
+
+.glyphicon-remove:before {
+  content: "\e014"; }
+
+.glyphicon-zoom-in:before {
+  content: "\e015"; }
+
+.glyphicon-zoom-out:before {
+  content: "\e016"; }
+
+.glyphicon-off:before {
+  content: "\e017"; }
+
+.glyphicon-signal:before {
+  content: "\e018"; }
+
+.glyphicon-cog:before {
+  content: "\e019"; }
+
+.glyphicon-trash:before {
+  content: "\e020"; }
+
+.glyphicon-home:before {
+  content: "\e021"; }
+
+.glyphicon-file:before {
+  content: "\e022"; }
+
+.glyphicon-time:before {
+  content: "\e023"; }
+
+.glyphicon-road:before {
+  content: "\e024"; }
+
+.glyphicon-download-alt:before {
+  content: "\e025"; }
+
+.glyphicon-download:before {
+  content: "\e026"; }
+
+.glyphicon-upload:before {
+  content: "\e027"; }
+
+.glyphicon-inbox:before {
+  content: "\e028"; }
+
+.glyphicon-play-circle:before {
+  content: "\e029"; }
+
+.glyphicon-repeat:before {
+  content: "\e030"; }
+
+.glyphicon-refresh:before {
+  content: "\e031"; }
+
+.glyphicon-list-alt:before {
+  content: "\e032"; }
+
+.ui-tabs-panel {
+  min-height: 700px;
+  position: relative;
+}
+
+.ui-tabs .ui-tabs-nav {
+  padding: 0 !important;
+}
+
+.glyphicon-lock:before {
+  content: "\e033"; }
+
+
+.glyphicon-flag:before {
+  content: "\e034"; }
+
+.glyphicon-headphones:before {
+  content: "\e035"; }
+
+.glyphicon-volume-off:before {
+  content: "\e036"; }
+
+.glyphicon-volume-down:before {
+  content: "\e037"; }
+
+.glyphicon-volume-up:before {
+  content: "\e038"; }
+
+.glyphicon-qrcode:before {
+  content: "\e039"; }
+
+.glyphicon-barcode:before {
+  content: "\e040"; }
+
+.glyphicon-tag:before {
+  content: "\e041"; }
+
+.glyphicon-tags:before {
+  content: "\e042"; }
+
+.glyphicon-book:before {
+  content: "\e043"; }
+
+.glyphicon-bookmark:before {
+  content: "\e044"; }
+
+.glyphicon-print:before {
+  content: "\e045"; }
+
+.glyphicon-camera:before {
+  content: "\e046"; }
+
+.glyphicon-font:before {
+  content: "\e047"; }
+
+.glyphicon-bold:before {
+  content: "\e048"; }
+
+.glyphicon-italic:before {
+  content: "\e049"; }
+
+.glyphicon-text-height:before {
+  content: "\e050"; }
+
+.glyphicon-text-width:before {
+  content: "\e051"; }
+
+.glyphicon-align-left:before {
+  content: "\e052"; }
+
+.glyphicon-align-center:before {
+  content: "\e053"; }
+
+.glyphicon-align-right:before {
+  content: "\e054"; }
+
+.glyphicon-align-justify:before {
+  content: "\e055"; }
+
+.glyphicon-list:before {
+  content: "\e056"; }
+
+.glyphicon-indent-left:before {
+  content: "\e057"; }
+
+.glyphicon-indent-right:before {
+  content: "\e058"; }
+
+.glyphicon-facetime-video:before {
+  content: "\e059"; }
+
+.glyphicon-picture:before {
+  content: "\e060"; }
+
+.glyphicon-map-marker:before {
+  content: "\e062"; }
+
+.glyphicon-adjust:before {
+  content: "\e063"; }
+
+.glyphicon-tint:before {
+  content: "\e064"; }
+
+.glyphicon-edit:before {
+  content: "\e065"; }
+
+.glyphicon-share:before {
+  content: "\e066"; }
+
+.glyphicon-check:before {
+  content: "\e067"; }
+
+.glyphicon-move:before {
+  content: "\e068"; }
+
+.glyphicon-step-backward:before {
+  content: "\e069"; }
+
+.glyphicon-fast-backward:before {
+  content: "\e070"; }
+
+.glyphicon-backward:before {
+  content: "\e071"; }
+
+.glyphicon-play:before {
+  content: "\e072"; }
+
+.glyphicon-pause:before {
+  content: "\e073"; }
+
+.glyphicon-stop:before {
+  content: "\e074"; }
+
+.glyphicon-forward:before {
+  content: "\e075"; }
+
+.glyphicon-fast-forward:before {
+  content: "\e076"; }
+
+.glyphicon-step-forward:before {
+  content: "\e077"; }
+
+.glyphicon-eject:before {
+  content: "\e078"; }
+
+.glyphicon-chevron-left:before {
+  content: "\e079"; }
+
+.glyphicon-chevron-right:before {
+  content: "\e080"; }
+
+.glyphicon-plus-sign:before {
+  content: "\e081"; }
+
+.glyphicon-minus-sign:before {
+  content: "\e082"; }
+
+.glyphicon-remove-sign:before {
+  content: "\e083"; }
+
+.glyphicon-ok-sign:before {
+  content: "\e084"; }
+
+.glyphicon-question-sign:before {
+  content: "\e085"; }
+
+.glyphicon-info-sign:before {
+  content: "\e086"; }
+
+.glyphicon-screenshot:before {
+  content: "\e087"; }
+
+.glyphicon-remove-circle:before {
+  content: "\e088"; }
+
+.glyphicon-ok-circle:before {
+  content: "\e089"; }
+
+.glyphicon-ban-circle:before {
+  content: "\e090"; }
+
+.glyphicon-arrow-left:before {
+  content: "\e091"; }
+
+.glyphicon-arrow-right:before {
+  content: "\e092"; }
+
+.glyphicon-arrow-up:before {
+  content: "\e093"; }
+
+.glyphicon-arrow-down:before {
+  content: "\e094"; }
+
+.glyphicon-share-alt:before {
+  content: "\e095"; }
+
+.glyphicon-resize-full:before {
+  content: "\e096"; }
+
+.glyphicon-resize-small:before {
+  content: "\e097"; }
+
+.glyphicon-exclamation-sign:before {
+  content: "\e101"; }
+
+.glyphicon-gift:before {
+  content: "\e102"; }
+
+.glyphicon-leaf:before {
+  content: "\e103"; }
+
+.glyphicon-fire:before {
+  content: "\e104"; }
+
+.glyphicon-eye-open:before {
+  content: "\e105"; }
+
+.glyphicon-eye-close:before {
+  content: "\e106"; }
+
+.glyphicon-warning-sign:before {
+  content: "\e107"; }
+
+.glyphicon-plane:before {
+  content: "\e108"; }
+
+.glyphicon-calendar:before {
+  content: "\e109"; }
+
+.glyphicon-random:before {
+  content: "\e110"; }
+
+.glyphicon-comment:before {
+  content: "\e111"; }
+
+.glyphicon-magnet:before {
+  content: "\e112"; }
+
+.glyphicon-chevron-up:before {
+  content: "\e113"; }
+
+.glyphicon-chevron-down:before {
+  content: "\e114"; }
+
+.glyphicon-retweet:before {
+  content: "\e115"; }
+
+.glyphicon-shopping-cart:before {
+  content: "\e116"; }
+
+.glyphicon-folder-close:before {
+  content: "\e117"; }
+
+.glyphicon-folder-open:before {
+  content: "\e118"; }
+
+.glyphicon-resize-vertical:before {
+  content: "\e119"; }
+
+.glyphicon-resize-horizontal:before {
+  content: "\e120"; }
+
+.glyphicon-hdd:before {
+  content: "\e121"; }
+
+.glyphicon-bullhorn:before {
+  content: "\e122"; }
+
+.glyphicon-bell:before {
+  content: "\e123"; }
+
+.glyphicon-certificate:before {
+  content: "\e124"; }
+
+.glyphicon-thumbs-up:before {
+  content: "\e125"; }
+
+.glyphicon-thumbs-down:before {
+  content: "\e126"; }
+
+.glyphicon-hand-right:before {
+  content: "\e127"; }
+
+.glyphicon-hand-left:before {
+  content: "\e128"; }
+
+.glyphicon-hand-up:before {
+  content: "\e129"; }
+
+.glyphicon-hand-down:before {
+  content: "\e130"; }
+
+.glyphicon-circle-arrow-right:before {
+  content: "\e131"; }
+
+.glyphicon-circle-arrow-left:before {
+  content: "\e132"; }
+
+.glyphicon-circle-arrow-up:before {
+  content: "\e133"; }
+
+.glyphicon-circle-arrow-down:before {
+  content: "\e134"; }
+
+.glyphicon-globe:before {
+  content: "\e135"; }
+
+.glyphicon-wrench:before {
+  content: "\e136"; }
+
+.glyphicon-tasks:before {
+  content: "\e137"; }
+
+.glyphicon-filter:before {
+  content: "\e138"; }
+
+.glyphicon-briefcase:before {
+  content: "\e139"; }
+
+.glyphicon-fullscreen:before {
+  content: "\e140"; }
+
+.glyphicon-dashboard:before {
+  content: "\e141"; }
+
+.glyphicon-paperclip:before {
+  content: "\e142"; }
+
+.glyphicon-heart-empty:before {
+  content: "\e143"; }
+
+.glyphicon-link:before {
+  content: "\e144"; }
+
+.glyphicon-phone:before {
+  content: "\e145"; }
+
+.glyphicon-pushpin:before {
+  content: "\e146"; }
+
+.glyphicon-usd:before {
+  content: "\e148"; }
+
+.glyphicon-gbp:before {
+  content: "\e149"; }
+
+.glyphicon-sort:before {
+  content: "\e150"; }
+
+.glyphicon-sort-by-alphabet:before {
+  content: "\e151"; }
+
+.glyphicon-sort-by-alphabet-alt:before {
+  content: "\e152"; }
+
+.glyphicon-sort-by-order:before {
+  content: "\e153"; }
+
+.glyphicon-sort-by-order-alt:before {
+  content: "\e154"; }
+
+.glyphicon-sort-by-attributes:before {
+  content: "\e155"; }
+
+.glyphicon-sort-by-attributes-alt:before {
+  content: "\e156"; }
+
+.glyphicon-unchecked:before {
+  content: "\e157"; }
+
+.glyphicon-expand:before {
+  content: "\e158"; }
+
+.glyphicon-collapse-down:before {
+  content: "\e159"; }
+
+.glyphicon-collapse-up:before {
+  content: "\e160"; }
+
+.glyphicon-log-in:before {
+  content: "\e161"; }
+
+.glyphicon-flash:before {
+  content: "\e162"; }
+
+.glyphicon-log-out:before {
+  content: "\e163"; }
+
+.glyphicon-new-window:before {
+  content: "\e164"; }
+
+.glyphicon-record:before {
+  content: "\e165"; }
+
+.glyphicon-save:before {
+  content: "\e166"; }
+
+.glyphicon-open:before {
+  content: "\e167"; }
+
+.glyphicon-saved:before {
+  content: "\e168"; }
+
+.glyphicon-import:before {
+  content: "\e169"; }
+
+.glyphicon-export:before {
+  content: "\e170"; }
+
+.glyphicon-send:before {
+  content: "\e171"; }
+
+.glyphicon-floppy-disk:before {
+  content: "\e172"; }
+
+.glyphicon-floppy-saved:before {
+  content: "\e173"; }
+
+.glyphicon-floppy-remove:before {
+  content: "\e174"; }
+
+.glyphicon-floppy-save:before {
+  content: "\e175"; }
+
+.glyphicon-floppy-open:before {
+  content: "\e176"; }
+
+.glyphicon-credit-card:before {
+  content: "\e177"; }
+
+.glyphicon-transfer:before {
+  content: "\e178"; }
+
+.glyphicon-cutlery:before {
+  content: "\e179"; }
+
+.glyphicon-header:before {
+  content: "\e180"; }
+
+.glyphicon-compressed:before {
+  content: "\e181"; }
+
+.glyphicon-earphone:before {
+  content: "\e182"; }
+
+.glyphicon-phone-alt:before {
+  content: "\e183"; }
+
+.glyphicon-tower:before {
+  content: "\e184"; }
+
+.glyphicon-stats:before {
+  content: "\e185"; }
+
+.glyphicon-sd-video:before {
+  content: "\e186"; }
+
+.glyphicon-hd-video:before {
+  content: "\e187"; }
+
+.glyphicon-subtitles:before {
+  content: "\e188"; }
+
+.glyphicon-sound-stereo:before {
+  content: "\e189"; }
+
+.glyphicon-sound-dolby:before {
+  content: "\e190"; }
+
+.glyphicon-sound-5-1:before {
+  content: "\e191"; }
+
+.glyphicon-sound-6-1:before {
+  content: "\e192"; }
+
+.glyphicon-sound-7-1:before {
+  content: "\e193"; }
+
+.glyphicon-copyright-mark:before {
+  content: "\e194"; }
+
+.glyphicon-registration-mark:before {
+  content: "\e195"; }
+
+.glyphicon-cloud-download:before {
+  content: "\e197"; }
+
+.glyphicon-cloud-upload:before {
+  content: "\e198"; }
+
+.glyphicon-tree-conifer:before {
+  content: "\e199"; }
+
+.glyphicon-tree-deciduous:before {
+  content: "\e200"; }
+
+.glyphicon-cd:before {
+  content: "\e201"; }
+
+.glyphicon-save-file:before {
+  content: "\e202"; }
+
+.glyphicon-open-file:before {
+  content: "\e203"; }
+
+.glyphicon-level-up:before {
+  content: "\e204"; }
+
+.glyphicon-copy:before {
+  content: "\e205"; }
+
+.glyphicon-paste:before {
+  content: "\e206"; }
+
+.glyphicon-alert:before {
+  content: "\e209"; }
+
+.glyphicon-equalizer:before {
+  content: "\e210"; }
+
+.glyphicon-king:before {
+  content: "\e211"; }
+
+.glyphicon-queen:before {
+  content: "\e212"; }
+
+.glyphicon-pawn:before {
+  content: "\e213"; }
+
+.glyphicon-bishop:before {
+  content: "\e214"; }
+
+.glyphicon-knight:before {
+  content: "\e215"; }
+
+.glyphicon-baby-formula:before {
+  content: "\e216"; }
+
+.glyphicon-tent:before {
+  content: "\26fa"; }
+
+.glyphicon-blackboard:before {
+  content: "\e218"; }
+
+.glyphicon-bed:before {
+  content: "\e219"; }
+
+.glyphicon-apple:before {
+  content: "\f8ff"; }
+
+.glyphicon-erase:before {
+  content: "\e221"; }
+
+.glyphicon-hourglass:before {
+  content: "\231b"; }
+
+.glyphicon-lamp:before {
+  content: "\e223"; }
+
+.glyphicon-duplicate:before {
+  content: "\e224"; }
+
+.glyphicon-piggy-bank:before {
+  content: "\e225"; }
+
+.glyphicon-scissors:before {
+  content: "\e226"; }
+
+.glyphicon-bitcoin:before {
+  content: "\e227"; }
+
+.glyphicon-btc:before {
+  content: "\e227"; }
+
+.glyphicon-xbt:before {
+  content: "\e227"; }
+
+.glyphicon-yen:before {
+  content: "\00a5"; }
+
+.glyphicon-jpy:before {
+  content: "\00a5"; }
+
+.glyphicon-ruble:before {
+  content: "\20bd"; }
+
+.glyphicon-rub:before {
+  content: "\20bd"; }
+
+.glyphicon-scale:before {
+  content: "\e230"; }
+
+.glyphicon-ice-lolly:before {
+  content: "\e231"; }
+
+.glyphicon-ice-lolly-tasted:before {
+  content: "\e232"; }
+
+.glyphicon-education:before {
+  content: "\e233"; }
+
+.glyphicon-option-horizontal:before {
+  content: "\e234"; }
+
+.glyphicon-option-vertical:before {
+  content: "\e235"; }
+
+.glyphicon-menu-hamburger:before {
+  content: "\e236"; }
+
+.glyphicon-modal-window:before {
+  content: "\e237"; }
+
+.glyphicon-oil:before {
+  content: "\e238"; }
+
+.glyphicon-grain:before {
+  content: "\e239"; }
+
+.glyphicon-sunglasses:before {
+  content: "\e240"; }
+
+.glyphicon-text-size:before {
+  content: "\e241"; }
+
+.glyphicon-text-color:before {
+  content: "\e242"; }
+
+.glyphicon-text-background:before {
+  content: "\e243"; }
+
+.glyphicon-object-align-top:before {
+  content: "\e244"; }
+
+.glyphicon-object-align-bottom:before {
+  content: "\e245"; }
+
+.glyphicon-object-align-horizontal:before {
+  content: "\e246"; }
+
+.glyphicon-object-align-left:before {
+  content: "\e247"; }
+
+.glyphicon-object-align-vertical:before {
+  content: "\e248"; }
+
+.glyphicon-object-align-right:before {
+  content: "\e249"; }
+
+.glyphicon-triangle-right:before {
+  content: "\e250"; }
+
+.glyphicon-triangle-left:before {
+  content: "\e251"; }
+
+.glyphicon-triangle-bottom:before {
+  content: "\e252"; }
+
+.glyphicon-triangle-top:before {
+  content: "\e253"; }
+
+.glyphicon-console:before {
+  content: "\e254"; }
+
+.glyphicon-superscript:before {
+  content: "\e255"; }
+
+.glyphicon-subscript:before {
+  content: "\e256"; }
+
+.glyphicon-menu-left:before {
+  content: "\e257"; }
+
+.glyphicon-menu-right:before {
+  content: "\e258"; }
+
+.glyphicon-menu-down:before {
+  content: "\e259"; }
+
+.glyphicon-menu-up:before {
+  content: "\e260"; }
+
+* {
+  -webkit-box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  box-sizing: border-box; }
+
+*:before,
+*:after {
+  -webkit-box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  box-sizing: border-box; }
+
+html {
+  font-size: 10px;
+  -webkit-tap-highlight-color: transparent; }
+
+body {
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+  font-size: 14px;
+  line-height: 1.42857;
+  color: #333333;
+  background-color: #fff; }
+
+input,
+button,
+select,
+textarea {
+  font-family: inherit;
+  font-size: inherit;
+  line-height: inherit; }
+
+a {
+  color: #337ab7;
+  text-decoration: none; }
+  a:hover, a:focus {
+    color: #23527c;
+    text-decoration: underline; }
+  a:focus {
+    outline: thin dotted;
+    outline: 5px auto -webkit-focus-ring-color;
+    outline-offset: -2px; }
+
+figure {
+  margin: 0; }
+
+img {
+  vertical-align: middle; }
+
+.img-responsive {
+  display: block;
+  max-width: 100%;
+  height: auto; }
+
+.img-rounded {
+  border-radius: 6px; }
+
+.img-thumbnail {
+  padding: 4px;
+  line-height: 1.42857;
+  background-color: #fff;
+  border: 1px solid #ddd;
+  border-radius: 4px;
+  -webkit-transition: all 0.2s ease-in-out;
+  -o-transition: all 0.2s ease-in-out;
+  transition: all 0.2s ease-in-out;
+  display: inline-block;
+  max-width: 100%;
+  height: auto; }
+
+.img-circle {
+  border-radius: 50%; }
+
+hr {
+  margin-top: 20px;
+  margin-bottom: 20px;
+  border: 0;
+  border-top: 1px solid #eeeeee; }
+
+.sr-only {
+  position: absolute;
+  width: 1px;
+  height: 1px;
+  margin: -1px;
+  padding: 0;
+  overflow: hidden;
+  clip: rect(0, 0, 0, 0);
+  border: 0; }
+
+.sr-only-focusable:active, .sr-only-focusable:focus {
+  position: static;
+  width: auto;
+  height: auto;
+  margin: 0;
+  overflow: visible;
+  clip: auto; }
+
+[role="button"] {
+  cursor: pointer; }
+
+h1, h2, h3, h4, h5, h6,
+.h1, .h2, .h3, .h4, .h5, .h6 {
+  font-family: inherit;
+  font-weight: 500;
+  line-height: 1.1;
+  color: inherit; }
+  h1 small,
+  h1 .small, h2 small,
+  h2 .small, h3 small,
+  h3 .small, h4 small,
+  h4 .small, h5 small,
+  h5 .small, h6 small,
+  h6 .small,
+  .h1 small,
+  .h1 .small, .h2 small,
+  .h2 .small, .h3 small,
+  .h3 .small, .h4 small,
+  .h4 .small, .h5 small,
+  .h5 .small, .h6 small,
+  .h6 .small {
+    font-weight: normal;
+    line-height: 1;
+    color: #777777; }
+
+h1, .h1,
+h2, .h2,
+h3, .h3 {
+  margin-top: 20px;
+  margin-bottom: 10px; }
+  h1 small,
+  h1 .small, .h1 small,
+  .h1 .small,
+  h2 small,
+  h2 .small, .h2 small,
+  .h2 .small,
+  h3 small,
+  h3 .small, .h3 small,
+  .h3 .small {
+    font-size: 65%; }
+
+h4, .h4,
+h5, .h5,
+h6, .h6 {
+  margin-top: 10px;
+  margin-bottom: 10px; }
+  h4 small,
+  h4 .small, .h4 small,
+  .h4 .small,
+  h5 small,
+  h5 .small, .h5 small,
+  .h5 .small,
+  h6 small,
+  h6 .small, .h6 small,
+  .h6 .small {
+    font-size: 75%; }
+
+h1, .h1 {
+  font-size: 36px; }
+
+h2, .h2 {
+  font-size: 30px; }
+
+h3, .h3 {
+  font-size: 24px; }
+
+h4, .h4 {
+  font-size: 18px; }
+
+h5, .h5 {
+  font-size: 14px; }
+
+h6, .h6 {
+  font-size: 12px; }
+
+p {
+  margin: 0 0 10px; }
+
+.lead {
+  margin-bottom: 20px;
+  font-size: 16px;
+  font-weight: 300;
+  line-height: 1.4; }
+  @media (min-width: 768px) {
+    .lead {
+      font-size: 21px; } }
+
+small,
+.small {
+  font-size: 85%; }
+
+mark,
+.mark {
+  background-color: #fcf8e3;
+  padding: .2em; }
+
+.text-left {
+  text-align: left; }
+
+.text-right {
+  text-align: right; }
+
+.text-center {
+  text-align: center; }
+
+.text-justify {
+  text-align: justify; }
+
+.text-nowrap {
+  white-space: nowrap; }
+
+.text-lowercase {
+  text-transform: lowercase; }
+
+.text-uppercase, .initialism {
+  text-transform: uppercase; }
+
+.text-capitalize {
+  text-transform: capitalize; }
+
+.text-muted {
+  color: #777777; }
+
+.text-primary {
+  color: #337ab7; }
+
+a.text-primary:hover,
+a.text-primary:focus {
+  color: #286090; }
+
+.text-success {
+  color: #3c763d; }
+
+a.text-success:hover,
+a.text-success:focus {
+  color: #2b542c; }
+
+.text-info {
+  color: #31708f; }
+
+a.text-info:hover,
+a.text-info:focus {
+  color: #245269; }
+
+.text-warning {
+  color: #8a6d3b; }
+
+a.text-warning:hover,
+a.text-warning:focus {
+  color: #66512c; }
+
+.text-danger {
+  color: #a94442; }
+
+a.text-danger:hover,
+a.text-danger:focus {
+  color: #843534; }
+
+.bg-primary {
+  color: #fff; }
+
+.bg-primary {
+  background-color: #337ab7; }
+
+a.bg-primary:hover,
+a.bg-primary:focus {
+  background-color: #286090; }
+
+.bg-success {
+  background-color: #dff0d8; }
+
+a.bg-success:hover,
+a.bg-success:focus {
+  background-color: #c1e2b3; }
+
+.bg-info {
+  background-color: #d9edf7; }
+
+a.bg-info:hover,
+a.bg-info:focus {
+  background-color: #afd9ee; }
+
+.bg-warning {
+  background-color: #fcf8e3; }
+
+a.bg-warning:hover,
+a.bg-warning:focus {
+  background-color: #f7ecb5; }
+
+.bg-danger {
+  background-color: #f2dede; }
+
+a.bg-danger:hover,
+a.bg-danger:focus {
+  background-color: #e4b9b9; }
+
+.page-header {
+  padding-bottom: 9px;
+  margin: 40px 0 20px;
+  border-bottom: 1px solid #eeeeee; }
+
+ul,
+ol {
+  margin-top: 0;
+  margin-bottom: 10px; }
+  ul ul,
+  ul ol,
+  ol ul,
+  ol ol {
+    margin-bottom: 0; }
+
+.list-unstyled {
+  padding-left: 0;
+  list-style: none; }
+
+.list-inline {
+  padding-left: 0;
+  list-style: none;
+  margin-left: -5px; }
+  .list-inline > li {
+    display: inline-block;
+    padding-left: 5px;
+    padding-right: 5px; }
+
+dl {
+  margin-top: 0;
+  margin-bottom: 20px; }
+
+dt,
+dd {
+  line-height: 1.42857; }
+
+dt {
+  font-weight: bold; }
+
+dd {
+  margin-left: 0; }
+
+.dl-horizontal dd:before, .dl-horizontal dd:after {
+  content: " ";
+  display: table; }
+
+.dl-horizontal dd:after {
+  clear: both; }
+
+@media (min-width: 768px) {
+  .dl-horizontal dt {
+    float: left;
+    width: 160px;
+    clear: left;
+    text-align: right;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap; }
+  .dl-horizontal dd {
+    margin-left: 180px; } }
+
+abbr[title],
+abbr[data-original-title] {
+  cursor: help;
+  border-bottom: 1px dotted #777777; }
+
+.initialism {
+  font-size: 90%; }
+
+blockquote {
+  padding: 10px 20px;
+  margin: 0 0 20px;
+  font-size: 17.5px;
+  border-left: 5px solid #eeeeee; }
+  blockquote p:last-child,
+  blockquote ul:last-child,
+  blockquote ol:last-child {
+    margin-bottom: 0; }
+  blockquote footer,
+  blockquote small,
+  blockquote .small {
+    display: block;
+    font-size: 80%;
+    line-height: 1.42857;
+    color: #777777; }
+    blockquote footer:before,
+    blockquote small:before,
+    blockquote .small:before {
+      content: '\2014 \00A0'; }
+
+.blockquote-reverse,
+blockquote.pull-right {
+  padding-right: 15px;
+  padding-left: 0;
+  border-right: 5px solid #eeeeee;
+  border-left: 0;
+  text-align: right; }
+  .blockquote-reverse footer:before,
+  .blockquote-reverse small:before,
+  .blockquote-reverse .small:before,
+  blockquote.pull-right footer:before,
+  blockquote.pull-right small:before,
+  blockquote.pull-right .small:before {
+    content: ''; }
+  .blockquote-reverse footer:after,
+  .blockquote-reverse small:after,
+  .blockquote-reverse .small:after,
+  blockquote.pull-right footer:after,
+  blockquote.pull-right small:after,
+  blockquote.pull-right .small:after {
+    content: '\00A0 \2014'; }
+
+address {
+  margin-bottom: 20px;
+  font-style: normal;
+  line-height: 1.42857; }
+
+code,
+kbd,
+pre,
+samp {
+  font-family: Menlo, Monaco, Consolas, "Courier New", monospace; }
+
+code {
+  padding: 2px 4px;
+  font-size: 90%;
+  color: #c7254e;
+  background-color: #f9f2f4;
+  border-radius: 4px; }
+
+kbd {
+  padding: 2px 4px;
+  font-size: 90%;
+  color: #fff;
+  background-color: #333;
+  border-radius: 3px;
+  box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25); }
+  kbd kbd {
+    padding: 0;
+    font-size: 100%;
+    font-weight: bold;
+    box-shadow: none; }
+
+pre {
+  display: block;
+  padding: 9.5px;
+  margin: 0 0 10px;
+  font-size: 13px;
+  line-height: 1.42857;
+  word-break: break-all;
+  word-wrap: break-word;
+  color: #333333;
+  background-color: #f5f5f5;
+  border: 1px solid #ccc;
+  border-radius: 4px; }
+  pre code {
+    padding: 0;
+    font-size: inherit;
+    color: inherit;
+    white-space: pre-wrap;
+    background-color: transparent;
+    border-radius: 0; }
+
+.pre-scrollable {
+  max-height: 340px;
+  overflow-y: scroll; }
+
+.container {
+  margin-right: auto;
+  margin-left: auto;
+  padding-left: 15px;
+  padding-right: 15px; }
+  .container:before, .container:after {
+    content: " ";
+    display: table; }
+  .container:after {
+    clear: both; }
+  @media (min-width: 768px) {
+    .container {
+      width: 750px; } }
+  @media (min-width: 992px) {
+    .container {
+      width: 970px; } }
+  @media (min-width: 1200px) {
+    .container {
+      width: 1170px; } }
+
+.container-fluid {
+  margin-right: auto;
+  margin-left: auto;
+  padding-left: 15px;
+  padding-right: 15px; }
+  .container-fluid:before, .container-fluid:after {
+    content: " ";
+    display: table; }
+  .container-fluid:after {
+    clear: both; }
+
+.row {
+  margin-left: -15px;
+  margin-right: -15px; }
+  .row:before, .row:after {
+    content: " ";
+    display: table; }
+  .row:after {
+    clear: both; }
+
+.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 {
+  position: relative;
+  min-height: 1px;
+  padding-left: 15px;
+  padding-right: 15px; }
+
+.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 {
+  float: left; }
+
+.col-xs-1 {
+  width: 8.33333%; }
+
+.col-xs-2 {
+  width: 16.66667%; }
+
+.col-xs-3 {
+  width: 25%; }
+
+.col-xs-4 {
+  width: 33.33333%; }
+
+.col-xs-5 {
+  width: 41.66667%; }
+
+.col-xs-6 {
+  width: 50%; }
+
+.col-xs-7 {
+  width: 58.33333%; }
+
+.col-xs-8 {
+  width: 66.66667%; }
+
+.col-xs-9 {
+  width: 75%; }
+
+.col-xs-10 {
+  width: 83.33333%; }
+
+.col-xs-11 {
+  width: 91.66667%; }
+
+.col-xs-12 {
+  width: 100%; }
+
+.col-xs-pull-0 {
+  right: auto; }
+
+.col-xs-pull-1 {
+  right: 8.33333%; }
+
+.col-xs-pull-2 {
+  right: 16.66667%; }
+
+.col-xs-pull-3 {
+  right: 25%; }
+
+.col-xs-pull-4 {
+  right: 33.33333%; }
+
+.col-xs-pull-5 {
+  right: 41.66667%; }
+
+.col-xs-pull-6 {
+  right: 50%; }
+
+.col-xs-pull-7 {
+  right: 58.33333%; }
+
+.col-xs-pull-8 {
+  right: 66.66667%; }
+
+.col-xs-pull-9 {
+  right: 75%; }
+
+.col-xs-pull-10 {
+  right: 83.33333%; }
+
+.col-xs-pull-11 {
+  right: 91.66667%; }
+
+.col-xs-pull-12 {
+  right: 100%; }
+
+.col-xs-push-0 {
+  left: auto; }
+
+.col-xs-push-1 {
+  left: 8.33333%; }
+
+.col-xs-push-2 {
+  left: 16.66667%; }
+
+.col-xs-push-3 {
+  left: 25%; }
+
+.col-xs-push-4 {
+  left: 33.33333%; }
+
+.col-xs-push-5 {
+  left: 41.66667%; }
+
+.col-xs-push-6 {
+  left: 50%; }
+
+.col-xs-push-7 {
+  left: 58.33333%; }
+
+.col-xs-push-8 {
+  left: 66.66667%; }
+
+.col-xs-push-9 {
+  left: 75%; }
+
+.col-xs-push-10 {
+  left: 83.33333%; }
+
+.col-xs-push-11 {
+  left: 91.66667%; }
+
+.col-xs-push-12 {
+  left: 100%; }
+
+.col-xs-offset-0 {
+  margin-left: 0%; }
+
+.col-xs-offset-1 {
+  margin-left: 8.33333%; }
+
+.col-xs-offset-2 {
+  margin-left: 16.66667%; }
+
+.col-xs-offset-3 {
+  margin-left: 25%; }
+
+.col-xs-offset-4 {
+  margin-left: 33.33333%; }
+
+.col-xs-offset-5 {
+  margin-left: 41.66667%; }
+
+.col-xs-offset-6 {
+  margin-left: 50%; }
+
+.col-xs-offset-7 {
+  margin-left: 58.33333%; }
+
+.col-xs-offset-8 {
+  margin-left: 66.66667%; }
+
+.col-xs-offset-9 {
+  margin-left: 75%; }
+
+.col-xs-offset-10 {
+  margin-left: 83.33333%; }
+
+.col-xs-offset-11 {
+  margin-left: 91.66667%; }
+
+.col-xs-offset-12 {
+  margin-left: 100%; }
+
+@media (min-width: 768px) {
+  .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 {
+    float: left; }
+  .col-sm-1 {
+    width: 8.33333%; }
+  .col-sm-2 {
+    width: 16.66667%; }
+  .col-sm-3 {
+    width: 25%; }
+  .col-sm-4 {
+    width: 33.33333%; }
+  .col-sm-5 {
+    width: 41.66667%; }
+  .col-sm-6 {
+    width: 50%; }
+  .col-sm-7 {
+    width: 58.33333%; }
+  .col-sm-8 {
+    width: 66.66667%; }
+  .col-sm-9 {
+    width: 75%; }
+  .col-sm-10 {
+    width: 83.33333%; }
+  .col-sm-11 {
+    width: 91.66667%; }
+  .col-sm-12 {
+    width: 100%; }
+  .col-sm-pull-0 {
+    right: auto; }
+  .col-sm-pull-1 {
+    right: 8.33333%; }
+  .col-sm-pull-2 {
+    right: 16.66667%; }
+  .col-sm-pull-3 {
+    right: 25%; }
+  .col-sm-pull-4 {
+    right: 33.33333%; }
+  .col-sm-pull-5 {
+    right: 41.66667%; }
+  .col-sm-pull-6 {
+    right: 50%; }
+  .col-sm-pull-7 {
+    right: 58.33333%; }
+  .col-sm-pull-8 {
+    right: 66.66667%; }
+  .col-sm-pull-9 {
+    right: 75%; }
+  .col-sm-pull-10 {
+    right: 83.33333%; }
+  .col-sm-pull-11 {
+    right: 91.66667%; }
+  .col-sm-pull-12 {
+    right: 100%; }
+  .col-sm-push-0 {
+    left: auto; }
+  .col-sm-push-1 {
+    left: 8.33333%; }
+  .col-sm-push-2 {
+    left: 16.66667%; }
+  .col-sm-push-3 {
+    left: 25%; }
+  .col-sm-push-4 {
+    left: 33.33333%; }
+  .col-sm-push-5 {
+    left: 41.66667%; }
+  .col-sm-push-6 {
+    left: 50%; }
+  .col-sm-push-7 {
+    left: 58.33333%; }
+  .col-sm-push-8 {
+    left: 66.66667%; }
+  .col-sm-push-9 {
+    left: 75%; }
+  .col-sm-push-10 {
+    left: 83.33333%; }
+  .col-sm-push-11 {
+    left: 91.66667%; }
+  .col-sm-push-12 {
+    left: 100%; }
+  .col-sm-offset-0 {
+    margin-left: 0%; }
+  .col-sm-offset-1 {
+    margin-left: 8.33333%; }
+  .col-sm-offset-2 {
+    margin-left: 16.66667%; }
+  .col-sm-offset-3 {
+    margin-left: 25%; }
+  .col-sm-offset-4 {
+    margin-left: 33.33333%; }
+  .col-sm-offset-5 {
+    margin-left: 41.66667%; }
+  .col-sm-offset-6 {
+    margin-left: 50%; }
+  .col-sm-offset-7 {
+    margin-left: 58.33333%; }
+  .col-sm-offset-8 {
+    margin-left: 66.66667%; }
+  .col-sm-offset-9 {
+    margin-left: 75%; }
+  .col-sm-offset-10 {
+    margin-left: 83.33333%; }
+  .col-sm-offset-11 {
+    margin-left: 91.66667%; }
+  .col-sm-offset-12 {
+    margin-left: 100%; } }
+
+@media (min-width: 992px) {
+  .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 {
+    float: left; }
+  .col-md-1 {
+    width: 8.33333%; }
+  .col-md-2 {
+    width: 16.66667%; }
+  .col-md-3 {
+    width: 25%; }
+  .col-md-4 {
+    width: 33.33333%; }
+  .col-md-5 {
+    width: 41.66667%; }
+  .col-md-6 {
+    width: 50%; }
+  .col-md-7 {
+    width: 58.33333%; }
+  .col-md-8 {
+    width: 66.66667%; }
+  .col-md-9 {
+    width: 75%; }
+  .col-md-10 {
+    width: 83.33333%; }
+  .col-md-11 {
+    width: 91.66667%; }
+  .col-md-12 {
+    width: 100%; }
+  .col-md-pull-0 {
+    right: auto; }
+  .col-md-pull-1 {
+    right: 8.33333%; }
+  .col-md-pull-2 {
+    right: 16.66667%; }
+  .col-md-pull-3 {
+    right: 25%; }
+  .col-md-pull-4 {
+    right: 33.33333%; }
+  .col-md-pull-5 {
+    right: 41.66667%; }
+  .col-md-pull-6 {
+    right: 50%; }
+  .col-md-pull-7 {
+    right: 58.33333%; }
+  .col-md-pull-8 {
+    right: 66.66667%; }
+  .col-md-pull-9 {
+    right: 75%; }
+  .col-md-pull-10 {
+    right: 83.33333%; }
+  .col-md-pull-11 {
+    right: 91.66667%; }
+  .col-md-pull-12 {
+    right: 100%; }
+  .col-md-push-0 {
+    left: auto; }
+  .col-md-push-1 {
+    left: 8.33333%; }
+  .col-md-push-2 {
+    left: 16.66667%; }
+  .col-md-push-3 {
+    left: 25%; }
+  .col-md-push-4 {
+    left: 33.33333%; }
+  .col-md-push-5 {
+    left: 41.66667%; }
+  .col-md-push-6 {
+    left: 50%; }
+  .col-md-push-7 {
+    left: 58.33333%; }
+  .col-md-push-8 {
+    left: 66.66667%; }
+  .col-md-push-9 {
+    left: 75%; }
+  .col-md-push-10 {
+    left: 83.33333%; }
+  .col-md-push-11 {
+    left: 91.66667%; }
+  .col-md-push-12 {
+    left: 100%; }
+  .col-md-offset-0 {
+    margin-left: 0%; }
+  .col-md-offset-1 {
+    margin-left: 8.33333%; }
+  .col-md-offset-2 {
+    margin-left: 16.66667%; }
+  .col-md-offset-3 {
+    margin-left: 25%; }
+  .col-md-offset-4 {
+    margin-left: 33.33333%; }
+  .col-md-offset-5 {
+    margin-left: 41.66667%; }
+  .col-md-offset-6 {
+    margin-left: 50%; }
+  .col-md-offset-7 {
+    margin-left: 58.33333%; }
+  .col-md-offset-8 {
+    margin-left: 66.66667%; }
+  .col-md-offset-9 {
+    margin-left: 75%; }
+  .col-md-offset-10 {
+    margin-left: 83.33333%; }
+  .col-md-offset-11 {
+    margin-left: 91.66667%; }
+  .col-md-offset-12 {
+    margin-left: 100%; } }
+
+@media (min-width: 1200px) {
+  .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 {
+    float: left; }
+  .col-lg-1 {
+    width: 8.33333%; }
+  .col-lg-2 {
+    width: 16.66667%; }
+  .col-lg-3 {
+    width: 25%; }
+  .col-lg-4 {
+    width: 33.33333%; }
+  .col-lg-5 {
+    width: 41.66667%; }
+  .col-lg-6 {
+    width: 50%; }
+  .col-lg-7 {
+    width: 58.33333%; }
+  .col-lg-8 {
+    width: 66.66667%; }
+  .col-lg-9 {
+    width: 75%; }
+  .col-lg-10 {
+    width: 83.33333%; }
+  .col-lg-11 {
+    width: 91.66667%; }
+  .col-lg-12 {
+    width: 100%; }
+  .col-lg-pull-0 {
+    right: auto; }
+  .col-lg-pull-1 {
+    right: 8.33333%; }
+  .col-lg-pull-2 {
+    right: 16.66667%; }
+  .col-lg-pull-3 {
+    right: 25%; }
+  .col-lg-pull-4 {
+    right: 33.33333%; }
+  .col-lg-pull-5 {
+    right: 41.66667%; }
+  .col-lg-pull-6 {
+    right: 50%; }
+  .col-lg-pull-7 {
+    right: 58.33333%; }
+  .col-lg-pull-8 {
+    right: 66.66667%; }
+  .col-lg-pull-9 {
+    right: 75%; }
+  .col-lg-pull-10 {
+    right: 83.33333%; }
+  .col-lg-pull-11 {
+    right: 91.66667%; }
+  .col-lg-pull-12 {
+    right: 100%; }
+  .col-lg-push-0 {
+    left: auto; }
+  .col-lg-push-1 {
+    left: 8.33333%; }
+  .col-lg-push-2 {
+    left: 16.66667%; }
+  .col-lg-push-3 {
+    left: 25%; }
+  .col-lg-push-4 {
+    left: 33.33333%; }
+  .col-lg-push-5 {
+    left: 41.66667%; }
+  .col-lg-push-6 {
+    left: 50%; }
+  .col-lg-push-7 {
+    left: 58.33333%; }
+  .col-lg-push-8 {
+    left: 66.66667%; }
+  .col-lg-push-9 {
+    left: 75%; }
+  .col-lg-push-10 {
+    left: 83.33333%; }
+  .col-lg-push-11 {
+    left: 91.66667%; }
+  .col-lg-push-12 {
+    left: 100%; }
+  .col-lg-offset-0 {
+    margin-left: 0%; }
+  .col-lg-offset-1 {
+    margin-left: 8.33333%; }
+  .col-lg-offset-2 {
+    margin-left: 16.66667%; }
+  .col-lg-offset-3 {
+    margin-left: 25%; }
+  .col-lg-offset-4 {
+    margin-left: 33.33333%; }
+  .col-lg-offset-5 {
+    margin-left: 41.66667%; }
+  .col-lg-offset-6 {
+    margin-left: 50%; }
+  .col-lg-offset-7 {
+    margin-left: 58.33333%; }
+  .col-lg-offset-8 {
+    margin-left: 66.66667%; }
+  .col-lg-offset-9 {
+    margin-left: 75%; }
+  .col-lg-offset-10 {
+    margin-left: 83.33333%; }
+  .col-lg-offset-11 {
+    margin-left: 91.66667%; }
+  .col-lg-offset-12 {
+    margin-left: 100%; } }
+
+table {
+  background-color: transparent; }
+
+caption {
+  padding-top: 8px;
+  padding-bottom: 8px;
+  color: #777777;
+  text-align: left; }
+
+th {
+  text-align: left; }
+
+.table {
+  width: 100%;
+  max-width: 100%;
+  margin-bottom: 20px; }
+  .table > thead > tr > th,
+  .table > thead > tr > td,
+  .table > tbody > tr > th,
+  .table > tbody > tr > td,
+  .table > tfoot > tr > th,
+  .table > tfoot > tr > td {
+    padding: 8px;
+    line-height: 1.42857;
+    vertical-align: top;
+    border-top: 1px solid #ddd; }
+  .table > thead > tr > th {
+    vertical-align: bottom;
+    border-bottom: 2px solid #ddd; }
+  .table > caption + thead > tr:first-child > th,
+  .table > caption + thead > tr:first-child > td,
+  .table > colgroup + thead > tr:first-child > th,
+  .table > colgroup + thead > tr:first-child > td,
+  .table > thead:first-child > tr:first-child > th,
+  .table > thead:first-child > tr:first-child > td {
+    border-top: 0; }
+  .table > tbody + tbody {
+    border-top: 2px solid #ddd; }
+  .table .table {
+    background-color: #fff; }
+
+.table-condensed > thead > tr > th,
+.table-condensed > thead > tr > td,
+.table-condensed > tbody > tr > th,
+.table-condensed > tbody > tr > td,
+.table-condensed > tfoot > tr > th,
+.table-condensed > tfoot > tr > td {
+  padding: 5px; }
+
+.table-bordered {
+  border: 1px solid #ddd; }
+  .table-bordered > thead > tr > th,
+  .table-bordered > thead > tr > td,
+  .table-bordered > tbody > tr > th,
+  .table-bordered > tbody > tr > td,
+  .table-bordered > tfoot > tr > th,
+  .table-bordered > tfoot > tr > td {
+    border: 1px solid #ddd; }
+  .table-bordered > thead > tr > th,
+  .table-bordered > thead > tr > td {
+    border-bottom-width: 2px; }
+
+.table-striped > tbody > tr:nth-of-type(odd) {
+  background-color: #f9f9f9; }
+
+.table-hover > tbody > tr:hover {
+  background-color: #f5f5f5; }
+
+table col[class*="col-"] {
+  position: static;
+  float: none;
+  display: table-column; }
+
+table td[class*="col-"],
+table th[class*="col-"] {
+  position: static;
+  float: none;
+  display: table-cell; }
+
+.table > thead > tr > td.active,
+.table > thead > tr > th.active,
+.table > thead > tr.active > td,
+.table > thead > tr.active > th,
+.table > tbody > tr > td.active,
+.table > tbody > tr > th.active,
+.table > tbody > tr.active > td,
+.table > tbody > tr.active > th,
+.table > tfoot > tr > td.active,
+.table > tfoot > tr > th.active,
+.table > tfoot > tr.active > td,
+.table > tfoot > tr.active > th {
+  background-color: #f5f5f5; }
+
+.table-hover > tbody > tr > td.active:hover,
+.table-hover > tbody > tr > th.active:hover,
+.table-hover > tbody > tr.active:hover > td,
+.table-hover > tbody > tr:hover > .active,
+.table-hover > tbody > tr.active:hover > th {
+  background-color: #e8e8e8; }
+
+.table > thead > tr > td.success,
+.table > thead > tr > th.success,
+.table > thead > tr.success > td,
+.table > thead > tr.success > th,
+.table > tbody > tr > td.success,
+.table > tbody > tr > th.success,
+.table > tbody > tr.success > td,
+.table > tbody > tr.success > th,
+.table > tfoot > tr > td.success,
+.table > tfoot > tr > th.success,
+.table > tfoot > tr.success > td,
+.table > tfoot > tr.success > th {
+  background-color: #dff0d8; }
+
+.table-hover > tbody > tr > td.success:hover,
+.table-hover > tbody > tr > th.success:hover,
+.table-hover > tbody > tr.success:hover > td,
+.table-hover > tbody > tr:hover > .success,
+.table-hover > tbody > tr.success:hover > th {
+  background-color: #d0e9c6; }
+
+.table > thead > tr > td.info,
+.table > thead > tr > th.info,
+.table > thead > tr.info > td,
+.table > thead > tr.info > th,
+.table > tbody > tr > td.info,
+.table > tbody > tr > th.info,
+.table > tbody > tr.info > td,
+.table > tbody > tr.info > th,
+.table > tfoot > tr > td.info,
+.table > tfoot > tr > th.info,
+.table > tfoot > tr.info > td,
+.table > tfoot > tr.info > th {
+  background-color: #d9edf7; }
+
+.table-hover > tbody > tr > td.info:hover,
+.table-hover > tbody > tr > th.info:hover,
+.table-hover > tbody > tr.info:hover > td,
+.table-hover > tbody > tr:hover > .info,
+.table-hover > tbody > tr.info:hover > th {
+  background-color: #c4e3f3; }
+
+.table > thead > tr > td.warning,
+.table > thead > tr > th.warning,
+.table > thead > tr.warning > td,
+.table > thead > tr.warning > th,
+.table > tbody > tr > td.warning,
+.table > tbody > tr > th.warning,
+.table > tbody > tr.warning > td,
+.table > tbody > tr.warning > th,
+.table > tfoot > tr > td.warning,
+.table > tfoot > tr > th.warning,
+.table > tfoot > tr.warning > td,
+.table > tfoot > tr.warning > th {
+  background-color: #fcf8e3; }
+
+.table-hover > tbody > tr > td.warning:hover,
+.table-hover > tbody > tr > th.warning:hover,
+.table-hover > tbody > tr.warning:hover > td,
+.table-hover > tbody > tr:hover > .warning,
+.table-hover > tbody > tr.warning:hover > th {
+  background-color: #faf2cc; }
+
+.table > thead > tr > td.danger,
+.table > thead > tr > th.danger,
+.table > thead > tr.danger > td,
+.table > thead > tr.danger > th,
+.table > tbody > tr > td.danger,
+.table > tbody > tr > th.danger,
+.table > tbody > tr.danger > td,
+.table > tbody > tr.danger > th,
+.table > tfoot > tr > td.danger,
+.table > tfoot > tr > th.danger,
+.table > tfoot > tr.danger > td,
+.table > tfoot > tr.danger > th {
+  background-color: #f2dede; }
+
+.table-hover > tbody > tr > td.danger:hover,
+.table-hover > tbody > tr > th.danger:hover,
+.table-hover > tbody > tr.danger:hover > td,
+.table-hover > tbody > tr:hover > .danger,
+.table-hover > tbody > tr.danger:hover > th {
+  background-color: #ebcccc; }
+
+.table-responsive {
+  overflow-x: auto;
+  min-height: 0.01%; }
+  @media screen and (max-width: 767px) {
+    .table-responsive {
+      width: 100%;
+      margin-bottom: 15px;
+      overflow-y: hidden;
+      -ms-overflow-style: -ms-autohiding-scrollbar;
+      border: 1px solid #ddd; }
+      .table-responsive > .table {
+        margin-bottom: 0; }
+        .table-responsive > .table > thead > tr > th,
+        .table-responsive > .table > thead > tr > td,
+        .table-responsive > .table > tbody > tr > th,
+        .table-responsive > .table > tbody > tr > td,
+        .table-responsive > .table > tfoot > tr > th,
+        .table-responsive > .table > tfoot > tr > td {
+          white-space: nowrap; }
+      .table-responsive > .table-bordered {
+        border: 0; }
+        .table-responsive > .table-bordered > thead > tr > th:first-child,
+        .table-responsive > .table-bordered > thead > tr > td:first-child,
+        .table-responsive > .table-bordered > tbody > tr > th:first-child,
+        .table-responsive > .table-bordered > tbody > tr > td:first-child,
+        .table-responsive > .table-bordered > tfoot > tr > th:first-child,
+        .table-responsive > .table-bordered > tfoot > tr > td:first-child {
+          border-left: 0; }
+        .table-responsive > .table-bordered > thead > tr > th:last-child,
+        .table-responsive > .table-bordered > thead > tr > td:last-child,
+        .table-responsive > .table-bordered > tbody > tr > th:last-child,
+        .table-responsive > .table-bordered > tbody > tr > td:last-child,
+        .table-responsive > .table-bordered > tfoot > tr > th:last-child,
+        .table-responsive > .table-bordered > tfoot > tr > td:last-child {
+          border-right: 0; }
+        .table-responsive > .table-bordered > tbody > tr:last-child > th,
+        .table-responsive > .table-bordered > tbody > tr:last-child > td,
+        .table-responsive > .table-bordered > tfoot > tr:last-child > th,
+        .table-responsive > .table-bordered > tfoot > tr:last-child > td {
+          border-bottom: 0; } }
+
+fieldset {
+  padding: 0;
+  margin: 0;
+  border: 0;
+  min-width: 0; }
+
+legend {
+  display: block;
+  width: 100%;
+  padding: 0;
+  margin-bottom: 20px;
+  font-size: 21px;
+  line-height: inherit;
+  color: #333333;
+  border: 0;
+  border-bottom: 1px solid #e5e5e5; }
+
+label {
+  display: inline-block;
+  max-width: 100%;
+  margin-bottom: 5px;
+  font-weight: bold; }
+
+input[type="search"] {
+  -webkit-box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  box-sizing: border-box; }
+
+input[type="radio"],
+input[type="checkbox"] {
+  margin: 4px 0 0;
+  margin-top: 1px \9;
+  line-height: normal; }
+
+input[type="file"] {
+  display: block; }
+
+input[type="range"] {
+  display: block;
+  width: 100%; }
+
+select[multiple],
+select[size] {
+  height: auto; }
+
+input[type="file"]:focus,
+input[type="radio"]:focus,
+input[type="checkbox"]:focus {
+  outline: thin dotted;
+  outline: 5px auto -webkit-focus-ring-color;
+  outline-offset: -2px; }
+
+output {
+  display: block;
+  padding-top: 7px;
+  font-size: 14px;
+  line-height: 1.42857;
+  color: #555555; }
+
+.form-control {
+  display: block;
+  width: 100%;
+  height: 34px;
+  padding: 6px 12px;
+  font-size: 14px;
+  line-height: 1.42857;
+  color: #555555;
+  background-color: #fff;
+  background-image: none;
+  border: 1px solid #ccc;
+  border-radius: 4px;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+  -webkit-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
+  -o-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
+  transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s; }
+  .form-control:focus {
+    border-color: #66afe9;
+    outline: 0;
+    -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6);
+    box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6); }
+  .form-control::-moz-placeholder {
+    color: #999;
+    opacity: 1; }
+  .form-control:-ms-input-placeholder {
+    color: #999; }
+  .form-control::-webkit-input-placeholder {
+    color: #999; }
+  .form-control::-ms-expand {
+    border: 0;
+    background-color: transparent; }
+  .form-control[disabled], .form-control[readonly],
+  fieldset[disabled] .form-control {
+    background-color: #eeeeee;
+    opacity: 1; }
+  .form-control[disabled],
+  fieldset[disabled] .form-control {
+    cursor: not-allowed; }
+
+textarea.form-control {
+  height: auto; }
+
+input[type="search"] {
+  -webkit-appearance: none; }
+
+@media screen and (-webkit-min-device-pixel-ratio: 0) {
+  input[type="date"].form-control,
+  input[type="time"].form-control,
+  input[type="datetime-local"].form-control,
+  input[type="month"].form-control {
+    line-height: 34px; }
+  input[type="date"].input-sm, .input-group-sm > input[type="date"].form-control,
+  .input-group-sm > input[type="date"].input-group-addon,
+  .input-group-sm > .input-group-btn > input[type="date"].btn,
+  .input-group-sm input[type="date"],
+  input[type="time"].input-sm,
+  .input-group-sm > input[type="time"].form-control,
+  .input-group-sm > input[type="time"].input-group-addon,
+  .input-group-sm > .input-group-btn > input[type="time"].btn,
+  .input-group-sm
+  input[type="time"],
+  input[type="datetime-local"].input-sm,
+  .input-group-sm > input[type="datetime-local"].form-control,
+  .input-group-sm > input[type="datetime-local"].input-group-addon,
+  .input-group-sm > .input-group-btn > input[type="datetime-local"].btn,
+  .input-group-sm
+  input[type="datetime-local"],
+  input[type="month"].input-sm,
+  .input-group-sm > input[type="month"].form-control,
+  .input-group-sm > input[type="month"].input-group-addon,
+  .input-group-sm > .input-group-btn > input[type="month"].btn,
+  .input-group-sm
+  input[type="month"] {
+    line-height: 30px; }
+  input[type="date"].input-lg, .input-group-lg > input[type="date"].form-control,
+  .input-group-lg > input[type="date"].input-group-addon,
+  .input-group-lg > .input-group-btn > input[type="date"].btn,
+  .input-group-lg input[type="date"],
+  input[type="time"].input-lg,
+  .input-group-lg > input[type="time"].form-control,
+  .input-group-lg > input[type="time"].input-group-addon,
+  .input-group-lg > .input-group-btn > input[type="time"].btn,
+  .input-group-lg
+  input[type="time"],
+  input[type="datetime-local"].input-lg,
+  .input-group-lg > input[type="datetime-local"].form-control,
+  .input-group-lg > input[type="datetime-local"].input-group-addon,
+  .input-group-lg > .input-group-btn > input[type="datetime-local"].btn,
+  .input-group-lg
+  input[type="datetime-local"],
+  input[type="month"].input-lg,
+  .input-group-lg > input[type="month"].form-control,
+  .input-group-lg > input[type="month"].input-group-addon,
+  .input-group-lg > .input-group-btn > input[type="month"].btn,
+  .input-group-lg
+  input[type="month"] {
+    line-height: 46px; } }
+
+.form-group {
+  margin-bottom: 15px; }
+
+.radio,
+.checkbox {
+  position: relative;
+  display: block;
+  margin-top: 10px;
+  margin-bottom: 10px; }
+  .radio label,
+  .checkbox label {
+    min-height: 20px;
+    padding-left: 20px;
+    margin-bottom: 0;
+    font-weight: normal;
+    cursor: pointer; }
+
+.radio input[type="radio"],
+.radio-inline input[type="radio"],
+.checkbox input[type="checkbox"],
+.checkbox-inline input[type="checkbox"] {
+  position: absolute;
+  margin-left: -20px;
+  margin-top: 4px \9; }
+
+.radio + .radio,
+.checkbox + .checkbox {
+  margin-top: -5px; }
+
+.radio-inline,
+.checkbox-inline {
+  position: relative;
+  display: inline-block;
+  padding-left: 20px;
+  margin-bottom: 0;
+  vertical-align: middle;
+  font-weight: normal;
+  cursor: pointer; }
+
+.radio-inline + .radio-inline,
+.checkbox-inline + .checkbox-inline {
+  margin-top: 0;
+  margin-left: 10px; }
+
+input[type="radio"][disabled], input[type="radio"].disabled,
+fieldset[disabled] input[type="radio"],
+input[type="checkbox"][disabled],
+input[type="checkbox"].disabled,
+fieldset[disabled]
+input[type="checkbox"] {
+  cursor: not-allowed; }
+
+.radio-inline.disabled,
+fieldset[disabled] .radio-inline,
+.checkbox-inline.disabled,
+fieldset[disabled]
+.checkbox-inline {
+  cursor: not-allowed; }
+
+.radio.disabled label,
+fieldset[disabled] .radio label,
+.checkbox.disabled label,
+fieldset[disabled]
+.checkbox label {
+  cursor: not-allowed; }
+
+.form-control-static {
+  padding-top: 7px;
+  padding-bottom: 7px;
+  margin-bottom: 0;
+  min-height: 34px; }
+  .form-control-static.input-lg, .input-group-lg > .form-control-static.form-control,
+  .input-group-lg > .form-control-static.input-group-addon,
+  .input-group-lg > .input-group-btn > .form-control-static.btn, .form-control-static.input-sm, .input-group-sm > .form-control-static.form-control,
+  .input-group-sm > .form-control-static.input-group-addon,
+  .input-group-sm > .input-group-btn > .form-control-static.btn {
+    padding-left: 0;
+    padding-right: 0; }
+
+.input-sm, .input-group-sm > .form-control,
+.input-group-sm > .input-group-addon,
+.input-group-sm > .input-group-btn > .btn {
+  height: 30px;
+  padding: 5px 10px;
+  font-size: 12px;
+  line-height: 1.5;
+  border-radius: 3px; }
+
+select.input-sm, .input-group-sm > select.form-control,
+.input-group-sm > select.input-group-addon,
+.input-group-sm > .input-group-btn > select.btn {
+  height: 30px;
+  line-height: 30px; }
+
+textarea.input-sm, .input-group-sm > textarea.form-control,
+.input-group-sm > textarea.input-group-addon,
+.input-group-sm > .input-group-btn > textarea.btn,
+select[multiple].input-sm,
+.input-group-sm > select[multiple].form-control,
+.input-group-sm > select[multiple].input-group-addon,
+.input-group-sm > .input-group-btn > select[multiple].btn {
+  height: auto; }
+
+.form-group-sm .form-control {
+  height: 30px;
+  padding: 5px 10px;
+  font-size: 12px;
+  line-height: 1.5;
+  border-radius: 3px; }
+
+.form-group-sm select.form-control {
+  height: 30px;
+  line-height: 30px; }
+
+.form-group-sm textarea.form-control,
+.form-group-sm select[multiple].form-control {
+  height: auto; }
+
+.form-group-sm .form-control-static {
+  height: 30px;
+  min-height: 32px;
+  padding: 6px 10px;
+  font-size: 12px;
+  line-height: 1.5; }
+
+.input-lg, .input-group-lg > .form-control,
+.input-group-lg > .input-group-addon,
+.input-group-lg > .input-group-btn > .btn {
+  height: 46px;
+  padding: 10px 16px;
+  font-size: 18px;
+  line-height: 1.33333;
+  border-radius: 6px; }
+
+select.input-lg, .input-group-lg > select.form-control,
+.input-group-lg > select.input-group-addon,
+.input-group-lg > .input-group-btn > select.btn {
+  height: 46px;
+  line-height: 46px; }
+
+textarea.input-lg, .input-group-lg > textarea.form-control,
+.input-group-lg > textarea.input-group-addon,
+.input-group-lg > .input-group-btn > textarea.btn,
+select[multiple].input-lg,
+.input-group-lg > select[multiple].form-control,
+.input-group-lg > select[multiple].input-group-addon,
+.input-group-lg > .input-group-btn > select[multiple].btn {
+  height: auto; }
+
+.form-group-lg .form-control {
+  height: 46px;
+  padding: 10px 16px;
+  font-size: 18px;
+  line-height: 1.33333;
+  border-radius: 6px; }
+
+.form-group-lg select.form-control {
+  height: 46px;
+  line-height: 46px; }
+
+.form-group-lg textarea.form-control,
+.form-group-lg select[multiple].form-control {
+  height: auto; }
+
+.form-group-lg .form-control-static {
+  height: 46px;
+  min-height: 38px;
+  padding: 11px 16px;
+  font-size: 18px;
+  line-height: 1.33333; }
+
+.has-feedback {
+  position: relative; }
+  .has-feedback .form-control {
+    padding-right: 42.5px; }
+
+.form-control-feedback {
+  position: absolute;
+  top: 0;
+  right: 0;
+  z-index: 2;
+  display: block;
+  width: 34px;
+  height: 34px;
+  line-height: 34px;
+  text-align: center;
+  pointer-events: none; }
+
+.input-lg + .form-control-feedback, .input-group-lg > .form-control + .form-control-feedback,
+.input-group-lg > .input-group-addon + .form-control-feedback,
+.input-group-lg > .input-group-btn > .btn + .form-control-feedback,
+.input-group-lg + .form-control-feedback,
+.form-group-lg .form-control + .form-control-feedback {
+  width: 46px;
+  height: 46px;
+  line-height: 46px; }
+
+.input-sm + .form-control-feedback, .input-group-sm > .form-control + .form-control-feedback,
+.input-group-sm > .input-group-addon + .form-control-feedback,
+.input-group-sm > .input-group-btn > .btn + .form-control-feedback,
+.input-group-sm + .form-control-feedback,
+.form-group-sm .form-control + .form-control-feedback {
+  width: 30px;
+  height: 30px;
+  line-height: 30px; }
+
+.has-success .help-block,
+.has-success .control-label,
+.has-success .radio,
+.has-success .checkbox,
+.has-success .radio-inline,
+.has-success .checkbox-inline,
+.has-success.radio label,
+.has-success.checkbox label,
+.has-success.radio-inline label,
+.has-success.checkbox-inline label {
+  color: #3c763d; }
+
+.has-success .form-control {
+  border-color: #3c763d;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); }
+  .has-success .form-control:focus {
+    border-color: #2b542c;
+    -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;
+    box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168; }
+
+.has-success .input-group-addon {
+  color: #3c763d;
+  border-color: #3c763d;
+  background-color: #dff0d8; }
+
+.has-success .form-control-feedback {
+  color: #3c763d; }
+
+.has-warning .help-block,
+.has-warning .control-label,
+.has-warning .radio,
+.has-warning .checkbox,
+.has-warning .radio-inline,
+.has-warning .checkbox-inline,
+.has-warning.radio label,
+.has-warning.checkbox label,
+.has-warning.radio-inline label,
+.has-warning.checkbox-inline label {
+  color: #8a6d3b; }
+
+.has-warning .form-control {
+  border-color: #8a6d3b;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); }
+  .has-warning .form-control:focus {
+    border-color: #66512c;
+    -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;
+    box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b; }
+
+.has-warning .input-group-addon {
+  color: #8a6d3b;
+  border-color: #8a6d3b;
+  background-color: #fcf8e3; }
+
+.has-warning .form-control-feedback {
+  color: #8a6d3b; }
+
+.has-error .help-block,
+.has-error .control-label,
+.has-error .radio,
+.has-error .checkbox,
+.has-error .radio-inline,
+.has-error .checkbox-inline,
+.has-error.radio label,
+.has-error.checkbox label,
+.has-error.radio-inline label,
+.has-error.checkbox-inline label {
+  color: #a94442; }
+
+.has-error .form-control {
+  border-color: #a94442;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); }
+  .has-error .form-control:focus {
+    border-color: #843534;
+    -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;
+    box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483; }
+
+.has-error .input-group-addon {
+  color: #a94442;
+  border-color: #a94442;
+  background-color: #f2dede; }
+
+.has-error .form-control-feedback {
+  color: #a94442; }
+
+.has-feedback label ~ .form-control-feedback {
+  top: 25px; }
+
+.has-feedback label.sr-only ~ .form-control-feedback {
+  top: 0; }
+
+.help-block {
+  display: block;
+  margin-top: 5px;
+  margin-bottom: 10px;
+  color: #737373; }
+
+@media (min-width: 768px) {
+  .form-inline .form-group {
+    display: inline-block;
+    margin-bottom: 0;
+    vertical-align: middle; }
+  .form-inline .form-control {
+    display: inline-block;
+    width: auto;
+    vertical-align: middle; }
+  .form-inline .form-control-static {
+    display: inline-block; }
+  .form-inline .input-group {
+    display: inline-table;
+    vertical-align: middle; }
+    .form-inline .input-group .input-group-addon,
+    .form-inline .input-group .input-group-btn,
+    .form-inline .input-group .form-control {
+      width: auto; }
+  .form-inline .input-group > .form-control {
+    width: 100%; }
+  .form-inline .control-label {
+    margin-bottom: 0;
+    vertical-align: middle; }
+  .form-inline .radio,
+  .form-inline .checkbox {
+    display: inline-block;
+    margin-top: 0;
+    margin-bottom: 0;
+    vertical-align: middle; }
+    .form-inline .radio label,
+    .form-inline .checkbox label {
+      padding-left: 0; }
+  .form-inline .radio input[type="radio"],
+  .form-inline .checkbox input[type="checkbox"] {
+    position: relative;
+    margin-left: 0; }
+  .form-inline .has-feedback .form-control-feedback {
+    top: 0; } }
+
+.form-horizontal .radio,
+.form-horizontal .checkbox,
+.form-horizontal .radio-inline,
+.form-horizontal .checkbox-inline {
+  margin-top: 0;
+  margin-bottom: 0;
+  padding-top: 7px; }
+
+.form-horizontal .radio,
+.form-horizontal .checkbox {
+  min-height: 27px; }
+
+.form-horizontal .form-group {
+  margin-left: -15px;
+  margin-right: -15px; }
+  .form-horizontal .form-group:before, .form-horizontal .form-group:after {
+    content: " ";
+    display: table; }
+  .form-horizontal .form-group:after {
+    clear: both; }
+
+@media (min-width: 768px) {
+  .form-horizontal .control-label {
+    text-align: right;
+    margin-bottom: 0;
+    padding-top: 7px; } }
+
+.form-horizontal .has-feedback .form-control-feedback {
+  right: 15px; }
+
+@media (min-width: 768px) {
+  .form-horizontal .form-group-lg .control-label {
+    padding-top: 11px;
+    font-size: 18px; } }
+
+@media (min-width: 768px) {
+  .form-horizontal .form-group-sm .control-label {
+    padding-top: 6px;
+    font-size: 12px; } }
+
+.btn {
+  display: inline-block;
+  margin-bottom: 0;
+  font-weight: normal;
+  text-align: center;
+  vertical-align: middle;
+  touch-action: manipulation;
+  cursor: pointer;
+  background-image: none;
+  border: 1px solid transparent;
+  white-space: nowrap;
+  padding: 6px 12px;
+  font-size: 14px;
+  line-height: 1.42857;
+  border-radius: 4px;
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  user-select: none; }
+  .btn:focus, .btn.focus, .btn:active:focus, .btn:active.focus, .btn.active:focus, .btn.active.focus {
+    outline: thin dotted;
+    outline: 5px auto -webkit-focus-ring-color;
+    outline-offset: -2px; }
+  .btn:hover, .btn:focus, .btn.focus {
+    color: #333;
+    text-decoration: none; }
+  .btn:active, .btn.active {
+    outline: 0;
+    background-image: none;
+    -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
+    box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); }
+  .btn.disabled, .btn[disabled],
+  fieldset[disabled] .btn {
+    cursor: not-allowed;
+    opacity: 0.65;
+    filter: alpha(opacity=65);
+    -webkit-box-shadow: none;
+    box-shadow: none; }
+
+a.btn.disabled,
+fieldset[disabled] a.btn {
+  pointer-events: none; }
+
+.btn-default {
+  color: #333;
+  background-color: #fff;
+  border-color: #ccc; }
+  .btn-default:focus, .btn-default.focus {
+    color: #333;
+    background-color: #e6e6e6;
+    border-color: #8c8c8c; }
+  .btn-default:hover {
+    color: #333;
+    background-color: #e6e6e6;
+    border-color: #adadad; }
+  .btn-default:active, .btn-default.active,
+  .open > .btn-default.dropdown-toggle {
+    color: #333;
+    background-color: #e6e6e6;
+    border-color: #adadad; }
+    .btn-default:active:hover, .btn-default:active:focus, .btn-default:active.focus, .btn-default.active:hover, .btn-default.active:focus, .btn-default.active.focus,
+    .open > .btn-default.dropdown-toggle:hover,
+    .open > .btn-default.dropdown-toggle:focus,
+    .open > .btn-default.dropdown-toggle.focus {
+      color: #333;
+      background-color: #d4d4d4;
+      border-color: #8c8c8c; }
+  .btn-default:active, .btn-default.active,
+  .open > .btn-default.dropdown-toggle {
+    background-image: none; }
+  .btn-default.disabled:hover, .btn-default.disabled:focus, .btn-default.disabled.focus, .btn-default[disabled]:hover, .btn-default[disabled]:focus, .btn-default[disabled].focus,
+  fieldset[disabled] .btn-default:hover,
+  fieldset[disabled] .btn-default:focus,
+  fieldset[disabled] .btn-default.focus {
+    background-color: #fff;
+    border-color: #ccc; }
+  .btn-default .badge {
+    color: #fff;
+    background-color: #333; }
+
+.btn-primary {
+  color: #fff;
+  background-color: #337ab7;
+  border-color: #2e6da4; }
+  .btn-primary:focus, .btn-primary.focus {
+    color: #fff;
+    background-color: #286090;
+    border-color: #122b40; }
+  .btn-primary:hover {
+    color: #fff;
+    background-color: #286090;
+    border-color: #204d74; }
+  .btn-primary:active, .btn-primary.active,
+  .open > .btn-primary.dropdown-toggle {
+    color: #fff;
+    background-color: #286090;
+    border-color: #204d74; }
+    .btn-primary:active:hover, .btn-primary:active:focus, .btn-primary:active.focus, .btn-primary.active:hover, .btn-primary.active:focus, .btn-primary.active.focus,
+    .open > .btn-primary.dropdown-toggle:hover,
+    .open > .btn-primary.dropdown-toggle:focus,
+    .open > .btn-primary.dropdown-toggle.focus {
+      color: #fff;
+      background-color: #204d74;
+      border-color: #122b40; }
+  .btn-primary:active, .btn-primary.active,
+  .open > .btn-primary.dropdown-toggle {
+    background-image: none; }
+  .btn-primary.disabled:hover, .btn-primary.disabled:focus, .btn-primary.disabled.focus, .btn-primary[disabled]:hover, .btn-primary[disabled]:focus, .btn-primary[disabled].focus,
+  fieldset[disabled] .btn-primary:hover,
+  fieldset[disabled] .btn-primary:focus,
+  fieldset[disabled] .btn-primary.focus {
+    background-color: #337ab7;
+    border-color: #2e6da4; }
+  .btn-primary .badge {
+    color: #337ab7;
+    background-color: #fff; }
+
+.btn-success {
+  color: #fff;
+  background-color: #5cb85c;
+  border-color: #4cae4c; }
+  .btn-success:focus, .btn-success.focus {
+    color: #fff;
+    background-color: #449d44;
+    border-color: #255625; }
+  .btn-success:hover {
+    color: #fff;
+    background-color: #449d44;
+    border-color: #398439; }
+  .btn-success:active, .btn-success.active,
+  .open > .btn-success.dropdown-toggle {
+    color: #fff;
+    background-color: #449d44;
+    border-color: #398439; }
+    .btn-success:active:hover, .btn-success:active:focus, .btn-success:active.focus, .btn-success.active:hover, .btn-success.active:focus, .btn-success.active.focus,
+    .open > .btn-success.dropdown-toggle:hover,
+    .open > .btn-success.dropdown-toggle:focus,
+    .open > .btn-success.dropdown-toggle.focus {
+      color: #fff;
+      background-color: #398439;
+      border-color: #255625; }
+  .btn-success:active, .btn-success.active,
+  .open > .btn-success.dropdown-toggle {
+    background-image: none; }
+  .btn-success.disabled:hover, .btn-success.disabled:focus, .btn-success.disabled.focus, .btn-success[disabled]:hover, .btn-success[disabled]:focus, .btn-success[disabled].focus,
+  fieldset[disabled] .btn-success:hover,
+  fieldset[disabled] .btn-success:focus,
+  fieldset[disabled] .btn-success.focus {
+    background-color: #5cb85c;
+    border-color: #4cae4c; }
+  .btn-success .badge {
+    color: #5cb85c;
+    background-color: #fff; }
+
+.btn-info {
+  color: #fff;
+  background-color: #5bc0de;
+  border-color: #46b8da; }
+  .btn-info:focus, .btn-info.focus {
+    color: #fff;
+    background-color: #31b0d5;
+    border-color: #1b6d85; }
+  .btn-info:hover {
+    color: #fff;
+    background-color: #31b0d5;
+    border-color: #269abc; }
+  .btn-info:active, .btn-info.active,
+  .open > .btn-info.dropdown-toggle {
+    color: #fff;
+    background-color: #31b0d5;
+    border-color: #269abc; }
+    .btn-info:active:hover, .btn-info:active:focus, .btn-info:active.focus, .btn-info.active:hover, .btn-info.active:focus, .btn-info.active.focus,
+    .open > .btn-info.dropdown-toggle:hover,
+    .open > .btn-info.dropdown-toggle:focus,
+    .open > .btn-info.dropdown-toggle.focus {
+      color: #fff;
+      background-color: #269abc;
+      border-color: #1b6d85; }
+  .btn-info:active, .btn-info.active,
+  .open > .btn-info.dropdown-toggle {
+    background-image: none; }
+  .btn-info.disabled:hover, .btn-info.disabled:focus, .btn-info.disabled.focus, .btn-info[disabled]:hover, .btn-info[disabled]:focus, .btn-info[disabled].focus,
+  fieldset[disabled] .btn-info:hover,
+  fieldset[disabled] .btn-info:focus,
+  fieldset[disabled] .btn-info.focus {
+    background-color: #5bc0de;
+    border-color: #46b8da; }
+  .btn-info .badge {
+    color: #5bc0de;
+    background-color: #fff; }
+
+.btn-warning {
+  color: #fff;
+  background-color: #f0ad4e;
+  border-color: #eea236; }
+  .btn-warning:focus, .btn-warning.focus {
+    color: #fff;
+    background-color: #ec971f;
+    border-color: #985f0d; }
+  .btn-warning:hover {
+    color: #fff;
+    background-color: #ec971f;
+    border-color: #d58512; }
+  .btn-warning:active, .btn-warning.active,
+  .open > .btn-warning.dropdown-toggle {
+    color: #fff;
+    background-color: #ec971f;
+    border-color: #d58512; }
+    .btn-warning:active:hover, .btn-warning:active:focus, .btn-warning:active.focus, .btn-warning.active:hover, .btn-warning.active:focus, .btn-warning.active.focus,
+    .open > .btn-warning.dropdown-toggle:hover,
+    .open > .btn-warning.dropdown-toggle:focus,
+    .open > .btn-warning.dropdown-toggle.focus {
+      color: #fff;
+      background-color: #d58512;
+      border-color: #985f0d; }
+  .btn-warning:active, .btn-warning.active,
+  .open > .btn-warning.dropdown-toggle {
+    background-image: none; }
+  .btn-warning.disabled:hover, .btn-warning.disabled:focus, .btn-warning.disabled.focus, .btn-warning[disabled]:hover, .btn-warning[disabled]:focus, .btn-warning[disabled].focus,
+  fieldset[disabled] .btn-warning:hover,
+  fieldset[disabled] .btn-warning:focus,
+  fieldset[disabled] .btn-warning.focus {
+    background-color: #f0ad4e;
+    border-color: #eea236; }
+  .btn-warning .badge {
+    color: #f0ad4e;
+    background-color: #fff; }
+
+.btn-danger {
+  color: #fff;
+  background-color: #d9534f;
+  border-color: #d43f3a; }
+  .btn-danger:focus, .btn-danger.focus {
+    color: #fff;
+    background-color: #c9302c;
+    border-color: #761c19; }
+  .btn-danger:hover {
+    color: #fff;
+    background-color: #c9302c;
+    border-color: #ac2925; }
+  .btn-danger:active, .btn-danger.active,
+  .open > .btn-danger.dropdown-toggle {
+    color: #fff;
+    background-color: #c9302c;
+    border-color: #ac2925; }
+    .btn-danger:active:hover, .btn-danger:active:focus, .btn-danger:active.focus, .btn-danger.active:hover, .btn-danger.active:focus, .btn-danger.active.focus,
+    .open > .btn-danger.dropdown-toggle:hover,
+    .open > .btn-danger.dropdown-toggle:focus,
+    .open > .btn-danger.dropdown-toggle.focus {
+      color: #fff;
+      background-color: #ac2925;
+      border-color: #761c19; }
+  .btn-danger:active, .btn-danger.active,
+  .open > .btn-danger.dropdown-toggle {
+    background-image: none; }
+  .btn-danger.disabled:hover, .btn-danger.disabled:focus, .btn-danger.disabled.focus, .btn-danger[disabled]:hover, .btn-danger[disabled]:focus, .btn-danger[disabled].focus,
+  fieldset[disabled] .btn-danger:hover,
+  fieldset[disabled] .btn-danger:focus,
+  fieldset[disabled] .btn-danger.focus {
+    background-color: #d9534f;
+    border-color: #d43f3a; }
+  .btn-danger .badge {
+    color: #d9534f;
+    background-color: #fff; }
+
+.btn-link {
+  color: #337ab7;
+  font-weight: normal;
+  border-radius: 0; }
+  .btn-link, .btn-link:active, .btn-link.active, .btn-link[disabled],
+  fieldset[disabled] .btn-link {
+    background-color: transparent;
+    -webkit-box-shadow: none;
+    box-shadow: none; }
+  .btn-link, .btn-link:hover, .btn-link:focus, .btn-link:active {
+    border-color: transparent; }
+  .btn-link:hover, .btn-link:focus {
+    color: #23527c;
+    text-decoration: underline;
+    background-color: transparent; }
+  .btn-link[disabled]:hover, .btn-link[disabled]:focus,
+  fieldset[disabled] .btn-link:hover,
+  fieldset[disabled] .btn-link:focus {
+    color: #777777;
+    text-decoration: none; }
+
+.btn-lg, .btn-group-lg > .btn {
+  padding: 10px 16px;
+  font-size: 18px;
+  line-height: 1.33333;
+  border-radius: 6px; }
+
+.btn-sm, .btn-group-sm > .btn {
+  padding: 5px 10px;
+  font-size: 12px;
+  line-height: 1.5;
+  border-radius: 3px; }
+
+.btn-xs, .btn-group-xs > .btn {
+  padding: 1px 5px;
+  font-size: 12px;
+  line-height: 1.5;
+  border-radius: 3px; }
+
+.btn-block {
+  display: block;
+  width: 100%; }
+
+.btn-block + .btn-block {
+  margin-top: 5px; }
+
+input[type="submit"].btn-block,
+input[type="reset"].btn-block,
+input[type="button"].btn-block {
+  width: 100%; }
+
+.fade {
+  opacity: 0;
+  -webkit-transition: opacity 0.15s linear;
+  -o-transition: opacity 0.15s linear;
+  transition: opacity 0.15s linear; }
+  .fade.in {
+    opacity: 1; }
+
+.collapse {
+  display: none; }
+  .collapse.in {
+    display: block; }
+
+tr.collapse.in {
+  display: table-row; }
+
+tbody.collapse.in {
+  display: table-row-group; }
+
+.collapsing {
+  position: relative;
+  height: 0;
+  overflow: hidden;
+  -webkit-transition-property: height, visibility;
+  transition-property: height, visibility;
+  -webkit-transition-duration: 0.35s;
+  transition-duration: 0.35s;
+  -webkit-transition-timing-function: ease;
+  transition-timing-function: ease; }
+
+.caret {
+  display: inline-block;
+  width: 0;
+  height: 0;
+  margin-left: 2px;
+  vertical-align: middle;
+  border-top: 4px dashed;
+  border-top: 4px solid \9;
+  border-right: 4px solid transparent;
+  border-left: 4px solid transparent; }
+
+.dropup,
+.dropdown {
+  position: relative; }
+
+.dropdown-toggle:focus {
+  outline: 0; }
+
+.dropdown-menu {
+  position: absolute;
+  top: 100%;
+  left: 0;
+  z-index: 1000;
+  display: none;
+  float: left;
+  min-width: 160px;
+  padding: 5px 0;
+  margin: 2px 0 0;
+  list-style: none;
+  font-size: 14px;
+  text-align: left;
+  background-color: #fff;
+  border: 1px solid #ccc;
+  border: 1px solid rgba(0, 0, 0, 0.15);
+  border-radius: 4px;
+  -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
+  box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
+  background-clip: padding-box; }
+  .dropdown-menu.pull-right {
+    right: 0;
+    left: auto; }
+  .dropdown-menu .divider {
+    height: 1px;
+    margin: 9px 0;
+    overflow: hidden;
+    background-color: #e5e5e5; }
+  .dropdown-menu > li > a {
+    display: block;
+    padding: 3px 20px;
+    clear: both;
+    font-weight: normal;
+    line-height: 1.42857;
+    color: #333333;
+    white-space: nowrap; }
+
+.dropdown-menu > li > a:hover, .dropdown-menu > li > a:focus {
+  text-decoration: none;
+  color: #262626;
+  background-color: #f5f5f5; }
+
+.dropdown-menu > .active > a, .dropdown-menu > .active > a:hover, .dropdown-menu > .active > a:focus {
+  color: #fff;
+  text-decoration: none;
+  outline: 0;
+  background-color: #337ab7; }
+
+.dropdown-menu > .disabled > a, .dropdown-menu > .disabled > a:hover, .dropdown-menu > .disabled > a:focus {
+  color: #777777; }
+
+.dropdown-menu > .disabled > a:hover, .dropdown-menu > .disabled > a:focus {
+  text-decoration: none;
+  background-color: transparent;
+  background-image: none;
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+  cursor: not-allowed; }
+
+.open > .dropdown-menu {
+  display: block; }
+
+.open > a {
+  outline: 0; }
+
+.dropdown-menu-right {
+  left: auto;
+  right: 0; }
+
+.dropdown-menu-left {
+  left: 0;
+  right: auto; }
+
+.dropdown-header {
+  display: block;
+  padding: 3px 20px;
+  font-size: 12px;
+  line-height: 1.42857;
+  color: #777777;
+  white-space: nowrap; }
+
+.dropdown-backdrop {
+  position: fixed;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  top: 0;
+  z-index: 990; }
+
+.pull-right > .dropdown-menu {
+  right: 0;
+  left: auto; }
+
+.dropup .caret,
+.navbar-fixed-bottom .dropdown .caret {
+  border-top: 0;
+  border-bottom: 4px dashed;
+  border-bottom: 4px solid \9;
+  content: ""; }
+
+.dropup .dropdown-menu,
+.navbar-fixed-bottom .dropdown .dropdown-menu {
+  top: auto;
+  bottom: 100%;
+  margin-bottom: 2px; }
+
+@media (min-width: 768px) {
+  .navbar-right .dropdown-menu {
+    right: 0;
+    left: auto; }
+  .navbar-right .dropdown-menu-left {
+    left: 0;
+    right: auto; } }
+
+.btn-group,
+.btn-group-vertical {
+  position: relative;
+  display: inline-block;
+  vertical-align: middle; }
+  .btn-group > .btn,
+  .btn-group-vertical > .btn {
+    position: relative;
+    float: left; }
+    .btn-group > .btn:hover, .btn-group > .btn:focus, .btn-group > .btn:active, .btn-group > .btn.active,
+    .btn-group-vertical > .btn:hover,
+    .btn-group-vertical > .btn:focus,
+    .btn-group-vertical > .btn:active,
+    .btn-group-vertical > .btn.active {
+      z-index: 2; }
+
+.btn-group .btn + .btn,
+.btn-group .btn + .btn-group,
+.btn-group .btn-group + .btn,
+.btn-group .btn-group + .btn-group {
+  margin-left: -1px; }
+
+.btn-toolbar {
+  margin-left: -5px; }
+  .btn-toolbar:before, .btn-toolbar:after {
+    content: " ";
+    display: table; }
+  .btn-toolbar:after {
+    clear: both; }
+  .btn-toolbar .btn,
+  .btn-toolbar .btn-group,
+  .btn-toolbar .input-group {
+    float: left; }
+  .btn-toolbar > .btn,
+  .btn-toolbar > .btn-group,
+  .btn-toolbar > .input-group {
+    margin-left: 5px; }
+
+.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {
+  border-radius: 0; }
+
+.btn-group > .btn:first-child {
+  margin-left: 0; }
+  .btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {
+    border-bottom-right-radius: 0;
+    border-top-right-radius: 0; }
+
+.btn-group > .btn:last-child:not(:first-child),
+.btn-group > .dropdown-toggle:not(:first-child) {
+  border-bottom-left-radius: 0;
+  border-top-left-radius: 0; }
+
+.btn-group > .btn-group {
+  float: left; }
+
+.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {
+  border-radius: 0; }
+
+.btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child,
+.btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle {
+  border-bottom-right-radius: 0;
+  border-top-right-radius: 0; }
+
+.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {
+  border-bottom-left-radius: 0;
+  border-top-left-radius: 0; }
+
+.btn-group .dropdown-toggle:active,
+.btn-group.open .dropdown-toggle {
+  outline: 0; }
+
+.btn-group > .btn + .dropdown-toggle {
+  padding-left: 8px;
+  padding-right: 8px; }
+
+.btn-group > .btn-lg + .dropdown-toggle, .btn-group-lg.btn-group > .btn + .dropdown-toggle {
+  padding-left: 12px;
+  padding-right: 12px; }
+
+.btn-group.open .dropdown-toggle {
+  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
+  box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); }
+  .btn-group.open .dropdown-toggle.btn-link {
+    -webkit-box-shadow: none;
+    box-shadow: none; }
+
+.btn .caret {
+  margin-left: 0; }
+
+.btn-lg .caret, .btn-group-lg > .btn .caret {
+  border-width: 5px 5px 0;
+  border-bottom-width: 0; }
+
+.dropup .btn-lg .caret, .dropup .btn-group-lg > .btn .caret {
+  border-width: 0 5px 5px; }
+
+.btn-group-vertical > .btn,
+.btn-group-vertical > .btn-group,
+.btn-group-vertical > .btn-group > .btn {
+  display: block;
+  float: none;
+  width: 100%;
+  max-width: 100%; }
+
+.btn-group-vertical > .btn-group:before, .btn-group-vertical > .btn-group:after {
+  content: " ";
+  display: table; }
+
+.btn-group-vertical > .btn-group:after {
+  clear: both; }
+
+.btn-group-vertical > .btn-group > .btn {
+  float: none; }
+
+.btn-group-vertical > .btn + .btn,
+.btn-group-vertical > .btn + .btn-group,
+.btn-group-vertical > .btn-group + .btn,
+.btn-group-vertical > .btn-group + .btn-group {
+  margin-top: -1px;
+  margin-left: 0; }
+
+.btn-group-vertical > .btn:not(:first-child):not(:last-child) {
+  border-radius: 0; }
+
+.btn-group-vertical > .btn:first-child:not(:last-child) {
+  border-top-right-radius: 4px;
+  border-top-left-radius: 4px;
+  border-bottom-right-radius: 0;
+  border-bottom-left-radius: 0; }
+
+.btn-group-vertical > .btn:last-child:not(:first-child) {
+  border-top-right-radius: 0;
+  border-top-left-radius: 0;
+  border-bottom-right-radius: 4px;
+  border-bottom-left-radius: 4px; }
+
+.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {
+  border-radius: 0; }
+
+.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,
+.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {
+  border-bottom-right-radius: 0;
+  border-bottom-left-radius: 0; }
+
+.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {
+  border-top-right-radius: 0;
+  border-top-left-radius: 0; }
+
+.btn-group-justified {
+  display: table;
+  width: 100%;
+  table-layout: fixed;
+  border-collapse: separate; }
+  .btn-group-justified > .btn,
+  .btn-group-justified > .btn-group {
+    float: none;
+    display: table-cell;
+    width: 1%; }
+  .btn-group-justified > .btn-group .btn {
+    width: 100%; }
+  .btn-group-justified > .btn-group .dropdown-menu {
+    left: auto; }
+
+[data-toggle="buttons"] > .btn input[type="radio"],
+[data-toggle="buttons"] > .btn input[type="checkbox"],
+[data-toggle="buttons"] > .btn-group > .btn input[type="radio"],
+[data-toggle="buttons"] > .btn-group > .btn input[type="checkbox"] {
+  position: absolute;
+  clip: rect(0, 0, 0, 0);
+  pointer-events: none; }
+
+.input-group {
+  position: relative;
+  display: table;
+  border-collapse: separate; }
+  .input-group[class*="col-"] {
+    float: none;
+    padding-left: 0;
+    padding-right: 0; }
+  .input-group .form-control {
+    position: relative;
+    z-index: 2;
+    float: left;
+    width: 100%;
+    margin-bottom: 0; }
+    .input-group .form-control:focus {
+      z-index: 3; }
+
+.input-group-addon,
+.input-group-btn,
+.input-group .form-control {
+  display: table-cell; }
+  .input-group-addon:not(:first-child):not(:last-child),
+  .input-group-btn:not(:first-child):not(:last-child),
+  .input-group .form-control:not(:first-child):not(:last-child) {
+    border-radius: 0; }
+
+.input-group-addon,
+.input-group-btn {
+  width: 1%;
+  white-space: nowrap;
+  vertical-align: middle; }
+
+.input-group-addon {
+  padding: 6px 12px;
+  font-size: 14px;
+  font-weight: normal;
+  line-height: 1;
+  color: #555555;
+  text-align: center;
+  background-color: #eeeeee;
+  border: 1px solid #ccc;
+  border-radius: 4px; }
+  .input-group-addon.input-sm,
+  .input-group-sm > .input-group-addon,
+  .input-group-sm > .input-group-btn > .input-group-addon.btn {
+    padding: 5px 10px;
+    font-size: 12px;
+    border-radius: 3px; }
+  .input-group-addon.input-lg,
+  .input-group-lg > .input-group-addon,
+  .input-group-lg > .input-group-btn > .input-group-addon.btn {
+    padding: 10px 16px;
+    font-size: 18px;
+    border-radius: 6px; }
+  .input-group-addon input[type="radio"],
+  .input-group-addon input[type="checkbox"] {
+    margin-top: 0; }
+
+.input-group .form-control:first-child,
+.input-group-addon:first-child,
+.input-group-btn:first-child > .btn,
+.input-group-btn:first-child > .btn-group > .btn,
+.input-group-btn:first-child > .dropdown-toggle,
+.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),
+.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {
+  border-bottom-right-radius: 0;
+  border-top-right-radius: 0; }
+
+.input-group-addon:first-child {
+  border-right: 0; }
+
+.input-group .form-control:last-child,
+.input-group-addon:last-child,
+.input-group-btn:last-child > .btn,
+.input-group-btn:last-child > .btn-group > .btn,
+.input-group-btn:last-child > .dropdown-toggle,
+.input-group-btn:first-child > .btn:not(:first-child),
+.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {
+  border-bottom-left-radius: 0;
+  border-top-left-radius: 0; }
+
+.input-group-addon:last-child {
+  border-left: 0; }
+
+.input-group-btn {
+  position: relative;
+  font-size: 0;
+  white-space: nowrap; }
+  .input-group-btn > .btn {
+    position: relative; }
+    .input-group-btn > .btn + .btn {
+      margin-left: -1px; }
+    .input-group-btn > .btn:hover, .input-group-btn > .btn:focus, .input-group-btn > .btn:active {
+      z-index: 2; }
+  .input-group-btn:first-child > .btn,
+  .input-group-btn:first-child > .btn-group {
+    margin-right: -1px; }
+  .input-group-btn:last-child > .btn,
+  .input-group-btn:last-child > .btn-group {
+    z-index: 2;
+    margin-left: -1px; }
+
+.nav {
+  margin-bottom: 0;
+  padding-left: 0;
+  list-style: none; }
+  .nav:before, .nav:after {
+    content: " ";
+    display: table; }
+  .nav:after {
+    clear: both; }
+  .nav > li {
+    position: relative;
+    display: block; }
+    .nav > li > a {
+      position: relative;
+      display: block;
+      padding: 10px 15px; }
+      .nav > li > a:hover, .nav > li > a:focus {
+        text-decoration: none;
+        background-color: #eeeeee; }
+    .nav > li.disabled > a {
+      color: #777777; }
+      .nav > li.disabled > a:hover, .nav > li.disabled > a:focus {
+        color: #777777;
+        text-decoration: none;
+        background-color: transparent;
+        cursor: not-allowed; }
+  .nav .open > a, .nav .open > a:hover, .nav .open > a:focus {
+    background-color: #eeeeee;
+    border-color: #337ab7; }
+  .nav .nav-divider {
+    height: 1px;
+    margin: 9px 0;
+    overflow: hidden;
+    background-color: #e5e5e5; }
+  .nav > li > a > img {
+    max-width: none; }
+
+.nav-tabs {
+  border-bottom: 1px solid #ddd; }
+  .nav-tabs > li {
+    float: left;
+    margin-bottom: -1px; }
+    .nav-tabs > li > a {
+      margin-right: 2px;
+      line-height: 1.42857;
+      border: 1px solid transparent;
+      border-radius: 4px 4px 0 0; }
+      .nav-tabs > li > a:hover {
+        border-color: #eeeeee #eeeeee #ddd; }
+    .nav-tabs > li.active > a, .nav-tabs > li.active > a:hover, .nav-tabs > li.active > a:focus {
+      color: #555555;
+      background-color: #fff;
+      border: 1px solid #ddd;
+      border-bottom-color: transparent;
+      cursor: default; }
+
+.nav-pills > li {
+  float: left; }
+  .nav-pills > li > a {
+    border-radius: 4px; }
+  .nav-pills > li + li {
+    margin-left: 2px; }
+  .nav-pills > li.active > a, .nav-pills > li.active > a:hover, .nav-pills > li.active > a:focus {
+    color: #fff;
+    background-color: #337ab7; }
+
+.nav-stacked > li {
+  float: none; }
+  .nav-stacked > li + li {
+    margin-top: 2px;
+    margin-left: 0; }
+
+.nav-justified, .nav-tabs.nav-justified {
+  width: 100%; }
+  .nav-justified > li, .nav-tabs.nav-justified > li {
+    float: none; }
+    .nav-justified > li > a, .nav-tabs.nav-justified > li > a {
+      text-align: center;
+      margin-bottom: 5px; }
+  .nav-justified > .dropdown .dropdown-menu {
+    top: auto;
+    left: auto; }
+  @media (min-width: 768px) {
+    .nav-justified > li, .nav-tabs.nav-justified > li {
+      display: table-cell;
+      width: 1%; }
+      .nav-justified > li > a, .nav-tabs.nav-justified > li > a {
+        margin-bottom: 0; } }
+
+.nav-tabs-justified, .nav-tabs.nav-justified {
+  border-bottom: 0; }
+  .nav-tabs-justified > li > a, .nav-tabs.nav-justified > li > a {
+    margin-right: 0;
+    border-radius: 4px; }
+  .nav-tabs-justified > .active > a, .nav-tabs.nav-justified > .active > a,
+  .nav-tabs-justified > .active > a:hover, .nav-tabs.nav-justified > .active > a:hover,
+  .nav-tabs-justified > .active > a:focus, .nav-tabs.nav-justified > .active > a:focus {
+    border: 1px solid #ddd; }
+  @media (min-width: 768px) {
+    .nav-tabs-justified > li > a, .nav-tabs.nav-justified > li > a {
+      border-bottom: 1px solid #ddd;
+      border-radius: 4px 4px 0 0; }
+    .nav-tabs-justified > .active > a, .nav-tabs.nav-justified > .active > a,
+    .nav-tabs-justified > .active > a:hover, .nav-tabs.nav-justified > .active > a:hover,
+    .nav-tabs-justified > .active > a:focus, .nav-tabs.nav-justified > .active > a:focus {
+      border-bottom-color: #fff; } }
+
+.tab-content > .tab-pane {
+  display: none; }
+
+.tab-content > .active {
+  display: block; }
+
+.nav-tabs .dropdown-menu {
+  margin-top: -1px;
+  border-top-right-radius: 0;
+  border-top-left-radius: 0; }
+
+.navbar {
+  position: relative;
+  min-height: 50px;
+  margin-bottom: 20px;
+  border: 1px solid transparent; }
+  .navbar:before, .navbar:after {
+    content: " ";
+    display: table; }
+  .navbar:after {
+    clear: both; }
+  @media (min-width: 768px) {
+    .navbar {
+      border-radius: 4px; } }
+
+.navbar-header:before, .navbar-header:after {
+  content: " ";
+  display: table; }
+
+.navbar-header:after {
+  clear: both; }
+
+@media (min-width: 768px) {
+  .navbar-header {
+    float: left; } }
+
+.navbar-collapse {
+  overflow-x: visible;
+  padding-right: 15px;
+  padding-left: 15px;
+  border-top: 1px solid transparent;
+  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);
+  -webkit-overflow-scrolling: touch; }
+  .navbar-collapse:before, .navbar-collapse:after {
+    content: " ";
+    display: table; }
+  .navbar-collapse:after {
+    clear: both; }
+  .navbar-collapse.in {
+    overflow-y: auto; }
+  @media (min-width: 768px) {
+    .navbar-collapse {
+      width: auto;
+      border-top: 0;
+      box-shadow: none; }
+      .navbar-collapse.collapse {
+        display: block !important;
+        height: auto !important;
+        padding-bottom: 0;
+        overflow: visible !important; }
+      .navbar-collapse.in {
+        overflow-y: visible; }
+      .navbar-fixed-top .navbar-collapse,
+      .navbar-static-top .navbar-collapse,
+      .navbar-fixed-bottom .navbar-collapse {
+        padding-left: 0;
+        padding-right: 0; } }
+
+.navbar-fixed-top .navbar-collapse,
+.navbar-fixed-bottom .navbar-collapse {
+  max-height: 340px; }
+  @media (max-device-width: 480px) and (orientation: landscape) {
+    .navbar-fixed-top .navbar-collapse,
+    .navbar-fixed-bottom .navbar-collapse {
+      max-height: 200px; } }
+
+.container > .navbar-header,
+.container > .navbar-collapse,
+.container-fluid > .navbar-header,
+.container-fluid > .navbar-collapse {
+  margin-right: -15px;
+  margin-left: -15px; }
+  @media (min-width: 768px) {
+    .container > .navbar-header,
+    .container > .navbar-collapse,
+    .container-fluid > .navbar-header,
+    .container-fluid > .navbar-collapse {
+      margin-right: 0;
+      margin-left: 0; } }
+
+.navbar-static-top {
+  z-index: 1000;
+  border-width: 0 0 1px; }
+  @media (min-width: 768px) {
+    .navbar-static-top {
+      border-radius: 0; } }
+
+.navbar-fixed-top,
+.navbar-fixed-bottom {
+  position: fixed;
+  right: 0;
+  left: 0;
+  z-index: 1030; }
+  @media (min-width: 768px) {
+    .navbar-fixed-top,
+    .navbar-fixed-bottom {
+      border-radius: 0; } }
+
+.navbar-fixed-top {
+  top: 0;
+  border-width: 0 0 1px; }
+
+.navbar-fixed-bottom {
+  bottom: 0;
+  margin-bottom: 0;
+  border-width: 1px 0 0; }
+
+.navbar-brand {
+  float: left;
+  padding: 15px 15px;
+  font-size: 18px;
+  line-height: 20px;
+  height: 50px; }
+  .navbar-brand:hover, .navbar-brand:focus {
+    text-decoration: none; }
+  .navbar-brand > img {
+    display: block; }
+  @media (min-width: 768px) {
+    .navbar > .container .navbar-brand,
+    .navbar > .container-fluid .navbar-brand {
+      margin-left: -15px; } }
+
+.navbar-toggle {
+  position: relative;
+  float: right;
+  margin-right: 15px;
+  padding: 9px 10px;
+  margin-top: 8px;
+  margin-bottom: 8px;
+  background-color: transparent;
+  background-image: none;
+  border: 1px solid transparent;
+  border-radius: 4px; }
+  .navbar-toggle:focus {
+    outline: 0; }
+  .navbar-toggle .icon-bar {
+    display: block;
+    width: 22px;
+    height: 2px;
+    border-radius: 1px; }
+  .navbar-toggle .icon-bar + .icon-bar {
+    margin-top: 4px; }
+  @media (min-width: 768px) {
+    .navbar-toggle {
+      display: none; } }
+
+.navbar-nav {
+  margin: 7.5px -15px; }
+  .navbar-nav > li > a {
+    padding-top: 10px;
+    padding-bottom: 10px;
+    line-height: 20px; }
+  @media (max-width: 767px) {
+    .navbar-nav .open .dropdown-menu {
+      position: static;
+      float: none;
+      width: auto;
+      margin-top: 0;
+      background-color: transparent;
+      border: 0;
+      box-shadow: none; }
+      .navbar-nav .open .dropdown-menu > li > a,
+      .navbar-nav .open .dropdown-menu .dropdown-header {
+        padding: 5px 15px 5px 25px; }
+      .navbar-nav .open .dropdown-menu > li > a {
+        line-height: 20px; }
+        .navbar-nav .open .dropdown-menu > li > a:hover, .navbar-nav .open .dropdown-menu > li > a:focus {
+          background-image: none; } }
+  @media (min-width: 768px) {
+    .navbar-nav {
+      float: left;
+      margin: 0; }
+      .navbar-nav > li {
+        float: left; }
+        .navbar-nav > li > a {
+          padding-top: 15px;
+          padding-bottom: 15px; } }
+
+.navbar-form {
+  margin-left: -15px;
+  margin-right: -15px;
+  padding: 10px 15px;
+  border-top: 1px solid transparent;
+  border-bottom: 1px solid transparent;
+  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
+  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
+  margin-top: 8px;
+  margin-bottom: 8px; }
+  @media (min-width: 768px) {
+    .navbar-form .form-group {
+      display: inline-block;
+      margin-bottom: 0;
+      vertical-align: middle; }
+    .navbar-form .form-control {
+      display: inline-block;
+      width: auto;
+      vertical-align: middle; }
+    .navbar-form .form-control-static {
+      display: inline-block; }
+    .navbar-form .input-group {
+      display: inline-table;
+      vertical-align: middle; }
+      .navbar-form .input-group .input-group-addon,
+      .navbar-form .input-group .input-group-btn,
+      .navbar-form .input-group .form-control {
+        width: auto; }
+    .navbar-form .input-group > .form-control {
+      width: 100%; }
+    .navbar-form .control-label {
+      margin-bottom: 0;
+      vertical-align: middle; }
+    .navbar-form .radio,
+    .navbar-form .checkbox {
+      display: inline-block;
+      margin-top: 0;
+      margin-bottom: 0;
+      vertical-align: middle; }
+      .navbar-form .radio label,
+      .navbar-form .checkbox label {
+        padding-left: 0; }
+    .navbar-form .radio input[type="radio"],
+    .navbar-form .checkbox input[type="checkbox"] {
+      position: relative;
+      margin-left: 0; }
+    .navbar-form .has-feedback .form-control-feedback {
+      top: 0; } }
+  @media (max-width: 767px) {
+    .navbar-form .form-group {
+      margin-bottom: 5px; }
+      .navbar-form .form-group:last-child {
+        margin-bottom: 0; } }
+  @media (min-width: 768px) {
+    .navbar-form {
+      width: auto;
+      border: 0;
+      margin-left: 0;
+      margin-right: 0;
+      padding-top: 0;
+      padding-bottom: 0;
+      -webkit-box-shadow: none;
+      box-shadow: none; } }
+
+.navbar-nav > li > .dropdown-menu {
+  margin-top: 0;
+  border-top-right-radius: 0;
+  border-top-left-radius: 0; }
+
+.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {
+  margin-bottom: 0;
+  border-top-right-radius: 4px;
+  border-top-left-radius: 4px;
+  border-bottom-right-radius: 0;
+  border-bottom-left-radius: 0; }
+
+.navbar-btn {
+  margin-top: 8px;
+  margin-bottom: 8px; }
+  .navbar-btn.btn-sm, .btn-group-sm > .navbar-btn.btn {
+    margin-top: 10px;
+    margin-bottom: 10px; }
+  .navbar-btn.btn-xs, .btn-group-xs > .navbar-btn.btn {
+    margin-top: 14px;
+    margin-bottom: 14px; }
+
+.navbar-text {
+  margin-top: 15px;
+  margin-bottom: 15px; }
+  @media (min-width: 768px) {
+    .navbar-text {
+      float: left;
+      margin-left: 15px;
+      margin-right: 15px; } }
+
+@media (min-width: 768px) {
+  .navbar-left {
+    float: left !important; }
+  .navbar-right {
+    float: right !important;
+    margin-right: -15px; }
+    .navbar-right ~ .navbar-right {
+      margin-right: 0; } }
+
+.navbar-default {
+  background-color: #f8f8f8;
+  border-color: #e7e7e7; }
+  .navbar-default .navbar-brand {
+    color: #777; }
+    .navbar-default .navbar-brand:hover, .navbar-default .navbar-brand:focus {
+      color: #5e5e5e;
+      background-color: transparent; }
+  .navbar-default .navbar-text {
+    color: #777; }
+  .navbar-default .navbar-nav > li > a {
+    color: #777; }
+    .navbar-default .navbar-nav > li > a:hover, .navbar-default .navbar-nav > li > a:focus {
+      color: #333;
+      background-color: transparent; }
+  .navbar-default .navbar-nav > .active > a, .navbar-default .navbar-nav > .active > a:hover, .navbar-default .navbar-nav > .active > a:focus {
+    color: #555;
+    background-color: #e7e7e7; }
+  .navbar-default .navbar-nav > .disabled > a, .navbar-default .navbar-nav > .disabled > a:hover, .navbar-default .navbar-nav > .disabled > a:focus {
+    color: #ccc;
+    background-color: transparent; }
+  .navbar-default .navbar-toggle {
+    border-color: #ddd; }
+    .navbar-default .navbar-toggle:hover, .navbar-default .navbar-toggle:focus {
+      background-color: #ddd; }
+    .navbar-default .navbar-toggle .icon-bar {
+      background-color: #888; }
+  .navbar-default .navbar-collapse,
+  .navbar-default .navbar-form {
+    border-color: #e7e7e7; }
+  .navbar-default .navbar-nav > .open > a, .navbar-default .navbar-nav > .open > a:hover, .navbar-default .navbar-nav > .open > a:focus {
+    background-color: #e7e7e7;
+    color: #555; }
+  @media (max-width: 767px) {
+    .navbar-default .navbar-nav .open .dropdown-menu > li > a {
+      color: #777; }
+      .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover, .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {
+        color: #333;
+        background-color: transparent; }
+    .navbar-default .navbar-nav .open .dropdown-menu > .active > a, .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover, .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {
+      color: #555;
+      background-color: #e7e7e7; }
+    .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a, .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover, .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {
+      color: #ccc;
+      background-color: transparent; } }
+  .navbar-default .navbar-link {
+    color: #777; }
+    .navbar-default .navbar-link:hover {
+      color: #333; }
+  .navbar-default .btn-link {
+    color: #777; }
+    .navbar-default .btn-link:hover, .navbar-default .btn-link:focus {
+      color: #333; }
+    .navbar-default .btn-link[disabled]:hover, .navbar-default .btn-link[disabled]:focus,
+    fieldset[disabled] .navbar-default .btn-link:hover,
+    fieldset[disabled] .navbar-default .btn-link:focus {
+      color: #ccc; }
+
+.navbar-inverse {
+  background-color: #222;
+  border-color: #090909; }
+  .navbar-inverse .navbar-brand {
+    color: #9d9d9d; }
+    .navbar-inverse .navbar-brand:hover, .navbar-inverse .navbar-brand:focus {
+      color: #fff;
+      background-color: transparent; }
+  .navbar-inverse .navbar-text {
+    color: #9d9d9d; }
+  .navbar-inverse .navbar-nav > li > a {
+    color: #9d9d9d; }
+    .navbar-inverse .navbar-nav > li > a:hover, .navbar-inverse .navbar-nav > li > a:focus {
+      color: #fff;
+      background-color: transparent; }
+  .navbar-inverse .navbar-nav > .active > a, .navbar-inverse .navbar-nav > .active > a:hover, .navbar-inverse .navbar-nav > .active > a:focus {
+    color: #fff;
+    background-color: #090909; }
+  .navbar-inverse .navbar-nav > .disabled > a, .navbar-inverse .navbar-nav > .disabled > a:hover, .navbar-inverse .navbar-nav > .disabled > a:focus {
+    color: #444;
+    background-color: transparent; }
+  .navbar-inverse .navbar-toggle {
+    border-color: #333; }
+    .navbar-inverse .navbar-toggle:hover, .navbar-inverse .navbar-toggle:focus {
+      background-color: #333; }
+    .navbar-inverse .navbar-toggle .icon-bar {
+      background-color: #fff; }
+  .navbar-inverse .navbar-collapse,
+  .navbar-inverse .navbar-form {
+    border-color: #101010; }
+  .navbar-inverse .navbar-nav > .open > a, .navbar-inverse .navbar-nav > .open > a:hover, .navbar-inverse .navbar-nav > .open > a:focus {
+    background-color: #090909;
+    color: #fff; }
+  @media (max-width: 767px) {
+    .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {
+      border-color: #090909; }
+    .navbar-inverse .navbar-nav .open .dropdown-menu .divider {
+      background-color: #090909; }
+    .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {
+      color: #9d9d9d; }
+      .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover, .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {
+        color: #fff;
+        background-color: transparent; }
+    .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a, .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover, .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus {
+      color: #fff;
+      background-color: #090909; }
+    .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a, .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover, .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus {
+      color: #444;
+      background-color: transparent; } }
+  .navbar-inverse .navbar-link {
+    color: #9d9d9d; }
+    .navbar-inverse .navbar-link:hover {
+      color: #fff; }
+  .navbar-inverse .btn-link {
+    color: #9d9d9d; }
+    .navbar-inverse .btn-link:hover, .navbar-inverse .btn-link:focus {
+      color: #fff; }
+    .navbar-inverse .btn-link[disabled]:hover, .navbar-inverse .btn-link[disabled]:focus,
+    fieldset[disabled] .navbar-inverse .btn-link:hover,
+    fieldset[disabled] .navbar-inverse .btn-link:focus {
+      color: #444; }
+
+.breadcrumb {
+  padding: 8px 15px;
+  margin-bottom: 20px;
+  list-style: none;
+  background-color: #f5f5f5;
+  border-radius: 4px; }
+  .breadcrumb > li {
+    display: inline-block; }
+    .breadcrumb > li + li:before {
+      content: "/ ";
+      padding: 0 5px;
+      color: #ccc; }
+  .breadcrumb > .active {
+    color: #777777; }
+
+.pagination {
+  display: inline-block;
+  padding-left: 0;
+  margin: 20px 0;
+  border-radius: 4px; }
+  .pagination > li {
+    display: inline; }
+    .pagination > li > a,
+    .pagination > li > span {
+      position: relative;
+      float: left;
+      padding: 6px 12px;
+      line-height: 1.42857;
+      text-decoration: none;
+      color: #337ab7;
+      background-color: #fff;
+      border: 1px solid #ddd;
+      margin-left: -1px; }
+    .pagination > li:first-child > a,
+    .pagination > li:first-child > span {
+      margin-left: 0;
+      border-bottom-left-radius: 4px;
+      border-top-left-radius: 4px; }
+    .pagination > li:last-child > a,
+    .pagination > li:last-child > span {
+      border-bottom-right-radius: 4px;
+      border-top-right-radius: 4px; }
+  .pagination > li > a:hover, .pagination > li > a:focus,
+  .pagination > li > span:hover,
+  .pagination > li > span:focus {
+    z-index: 2;
+    color: #23527c;
+    background-color: #eeeeee;
+    border-color: #ddd; }
+  .pagination > .active > a, .pagination > .active > a:hover, .pagination > .active > a:focus,
+  .pagination > .active > span,
+  .pagination > .active > span:hover,
+  .pagination > .active > span:focus {
+    z-index: 3;
+    color: #fff;
+    background-color: #337ab7;
+    border-color: #337ab7;
+    cursor: default; }
+  .pagination > .disabled > span,
+  .pagination > .disabled > span:hover,
+  .pagination > .disabled > span:focus,
+  .pagination > .disabled > a,
+  .pagination > .disabled > a:hover,
+  .pagination > .disabled > a:focus {
+    color: #777777;
+    background-color: #fff;
+    border-color: #ddd;
+    cursor: not-allowed; }
+
+.pagination-lg > li > a,
+.pagination-lg > li > span {
+  padding: 10px 16px;
+  font-size: 18px;
+  line-height: 1.33333; }
+
+.pagination-lg > li:first-child > a,
+.pagination-lg > li:first-child > span {
+  border-bottom-left-radius: 6px;
+  border-top-left-radius: 6px; }
+
+.pagination-lg > li:last-child > a,
+.pagination-lg > li:last-child > span {
+  border-bottom-right-radius: 6px;
+  border-top-right-radius: 6px; }
+
+.pagination-sm > li > a,
+.pagination-sm > li > span {
+  padding: 5px 10px;
+  font-size: 12px;
+  line-height: 1.5; }
+
+.pagination-sm > li:first-child > a,
+.pagination-sm > li:first-child > span {
+  border-bottom-left-radius: 3px;
+  border-top-left-radius: 3px; }
+
+.pagination-sm > li:last-child > a,
+.pagination-sm > li:last-child > span {
+  border-bottom-right-radius: 3px;
+  border-top-right-radius: 3px; }
+
+.pager {
+  padding-left: 0;
+  margin: 20px 0;
+  list-style: none;
+  text-align: center; }
+  .pager:before, .pager:after {
+    content: " ";
+    display: table; }
+  .pager:after {
+    clear: both; }
+  .pager li {
+    display: inline; }
+    .pager li > a,
+    .pager li > span {
+      display: inline-block;
+      padding: 5px 14px;
+      background-color: #fff;
+      border: 1px solid #ddd;
+      border-radius: 15px; }
+    .pager li > a:hover,
+    .pager li > a:focus {
+      text-decoration: none;
+      background-color: #eeeeee; }
+  .pager .next > a,
+  .pager .next > span {
+    float: right; }
+  .pager .previous > a,
+  .pager .previous > span {
+    float: left; }
+  .pager .disabled > a,
+  .pager .disabled > a:hover,
+  .pager .disabled > a:focus,
+  .pager .disabled > span {
+    color: #777777;
+    background-color: #fff;
+    cursor: not-allowed; }
+
+.label {
+  display: inline;
+  padding: .2em .6em .3em;
+  font-size: 75%;
+  font-weight: bold;
+  line-height: 1;
+  color: #fff;
+  text-align: center;
+  white-space: nowrap;
+  vertical-align: baseline;
+  border-radius: .25em; }
+  .label:empty {
+    display: none; }
+  .btn .label {
+    position: relative;
+    top: -1px; }
+
+a.label:hover, a.label:focus {
+  color: #fff;
+  text-decoration: none;
+  cursor: pointer; }
+
+.label-default {
+  background-color: #777777; }
+  .label-default[href]:hover, .label-default[href]:focus {
+    background-color: #5e5e5e; }
+
+.label-primary {
+  background-color: #337ab7; }
+  .label-primary[href]:hover, .label-primary[href]:focus {
+    background-color: #286090; }
+
+.label-success {
+  background-color: #5cb85c; }
+  .label-success[href]:hover, .label-success[href]:focus {
+    background-color: #449d44; }
+
+.label-info {
+  background-color: #5bc0de; }
+  .label-info[href]:hover, .label-info[href]:focus {
+    background-color: #31b0d5; }
+
+.label-warning {
+  background-color: #f0ad4e; }
+  .label-warning[href]:hover, .label-warning[href]:focus {
+    background-color: #ec971f; }
+
+.label-danger {
+  background-color: #d9534f; }
+  .label-danger[href]:hover, .label-danger[href]:focus {
+    background-color: #c9302c; }
+
+.badge {
+  display: inline-block;
+  min-width: 10px;
+  padding: 3px 7px;
+  font-size: 12px;
+  font-weight: bold;
+  color: #fff;
+  line-height: 1;
+  vertical-align: middle;
+  white-space: nowrap;
+  text-align: center;
+  background-color: #777777;
+  border-radius: 10px; }
+  .badge:empty {
+    display: none; }
+  .btn .badge {
+    position: relative;
+    top: -1px; }
+  .btn-xs .badge, .btn-group-xs > .btn .badge,
+  .btn-group-xs > .btn .badge {
+    top: 0;
+    padding: 1px 5px; }
+  .list-group-item.active > .badge,
+  .nav-pills > .active > a > .badge {
+    color: #337ab7;
+    background-color: #fff; }
+  .list-group-item > .badge {
+    float: right; }
+  .list-group-item > .badge + .badge {
+    margin-right: 5px; }
+  .nav-pills > li > a > .badge {
+    margin-left: 3px; }
+
+a.badge:hover, a.badge:focus {
+  color: #fff;
+  text-decoration: none;
+  cursor: pointer; }
+
+.jumbotron {
+  padding-top: 30px;
+  padding-bottom: 30px;
+  margin-bottom: 30px;
+  color: inherit;
+  background-color: #eeeeee; }
+  .jumbotron h1,
+  .jumbotron .h1 {
+    color: inherit; }
+  .jumbotron p {
+    margin-bottom: 15px;
+    font-size: 21px;
+    font-weight: 200; }
+  .jumbotron > hr {
+    border-top-color: #d5d5d5; }
+  .container .jumbotron,
+  .container-fluid .jumbotron {
+    border-radius: 6px;
+    padding-left: 15px;
+    padding-right: 15px; }
+  .jumbotron .container {
+    max-width: 100%; }
+  @media screen and (min-width: 768px) {
+    .jumbotron {
+      padding-top: 48px;
+      padding-bottom: 48px; }
+      .container .jumbotron,
+      .container-fluid .jumbotron {
+        padding-left: 60px;
+        padding-right: 60px; }
+      .jumbotron h1,
+      .jumbotron .h1 {
+        font-size: 63px; } }
+
+.thumbnail {
+  display: block;
+  padding: 4px;
+  margin-bottom: 20px;
+  line-height: 1.42857;
+  background-color: #fff;
+  border: 1px solid #ddd;
+  border-radius: 4px;
+  -webkit-transition: border 0.2s ease-in-out;
+  -o-transition: border 0.2s ease-in-out;
+  transition: border 0.2s ease-in-out; }
+  .thumbnail > img,
+  .thumbnail a > img {
+    display: block;
+    max-width: 100%;
+    height: auto;
+    margin-left: auto;
+    margin-right: auto; }
+  .thumbnail .caption {
+    padding: 9px;
+    color: #333333; }
+
+a.thumbnail:hover,
+a.thumbnail:focus,
+a.thumbnail.active {
+  border-color: #337ab7; }
+
+.alert {
+  padding: 15px;
+  margin-bottom: 20px;
+  border: 1px solid transparent;
+  border-radius: 4px; }
+  .alert h4 {
+    margin-top: 0;
+    color: inherit; }
+  .alert .alert-link {
+    font-weight: bold; }
+  .alert > p,
+  .alert > ul {
+    margin-bottom: 0; }
+  .alert > p + p {
+    margin-top: 5px; }
+
+.alert-dismissable,
+.alert-dismissible {
+  padding-right: 35px; }
+  .alert-dismissable .close,
+  .alert-dismissible .close {
+    position: relative;
+    top: -2px;
+    right: -21px;
+    color: inherit; }
+
+.alert-success {
+  background-color: #dff0d8;
+  border-color: #d6e9c6;
+  color: #3c763d; }
+  .alert-success hr {
+    border-top-color: #c9e2b3; }
+  .alert-success .alert-link {
+    color: #2b542c; }
+
+.alert-info {
+  background-color: #d9edf7;
+  border-color: #bce8f1;
+  color: #31708f; }
+  .alert-info hr {
+    border-top-color: #a6e1ec; }
+  .alert-info .alert-link {
+    color: #245269; }
+
+.alert-warning {
+  background-color: #fcf8e3;
+  border-color: #faebcc;
+  color: #8a6d3b; }
+  .alert-warning hr {
+    border-top-color: #f7e1b5; }
+  .alert-warning .alert-link {
+    color: #66512c; }
+
+.alert-danger {
+  background-color: #f2dede;
+  border-color: #ebccd1;
+  color: #a94442; }
+  .alert-danger hr {
+    border-top-color: #e4b9c0; }
+  .alert-danger .alert-link {
+    color: #843534; }
+
+@-webkit-keyframes progress-bar-stripes {
+  from {
+    background-position: 40px 0; }
+  to {
+    background-position: 0 0; } }
+
+@keyframes progress-bar-stripes {
+  from {
+    background-position: 40px 0; }
+  to {
+    background-position: 0 0; } }
+
+.progress {
+  overflow: hidden;
+  height: 20px;
+  margin-bottom: 20px;
+  background-color: #f5f5f5;
+  border-radius: 4px;
+  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
+  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); }
+
+.progress-bar {
+  float: left;
+  width: 0%;
+  height: 100%;
+  font-size: 12px;
+  line-height: 20px;
+  color: #fff;
+  text-align: center;
+  background-color: #337ab7;
+  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
+  box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
+  -webkit-transition: width 0.6s ease;
+  -o-transition: width 0.6s ease;
+  transition: width 0.6s ease; }
+
+.progress-striped .progress-bar,
+.progress-bar-striped {
+  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-size: 40px 40px; }
+
+.progress.active .progress-bar,
+.progress-bar.active {
+  -webkit-animation: progress-bar-stripes 2s linear infinite;
+  -o-animation: progress-bar-stripes 2s linear infinite;
+  animation: progress-bar-stripes 2s linear infinite; }
+
+.progress-bar-success {
+  background-color: #5cb85c; }
+  .progress-striped .progress-bar-success {
+    background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+    background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+    background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); }
+
+.progress-bar-info {
+  background-color: #5bc0de; }
+  .progress-striped .progress-bar-info {
+    background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+    background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+    background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); }
+
+.progress-bar-warning {
+  background-color: #f0ad4e; }
+  .progress-striped .progress-bar-warning {
+    background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+    background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+    background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); }
+
+.progress-bar-danger {
+  background-color: #d9534f; }
+  .progress-striped .progress-bar-danger {
+    background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+    background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+    background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); }
+
+.media {
+  margin-top: 15px; }
+  .media:first-child {
+    margin-top: 0; }
+
+.media,
+.media-body {
+  zoom: 1;
+  overflow: hidden; }
+
+.media-body {
+  width: 10000px; }
+
+.media-object {
+  display: block; }
+  .media-object.img-thumbnail {
+    max-width: none; }
+
+.media-right,
+.media > .pull-right {
+  padding-left: 10px; }
+
+.media-left,
+.media > .pull-left {
+  padding-right: 10px; }
+
+.media-left,
+.media-right,
+.media-body {
+  display: table-cell;
+  vertical-align: top; }
+
+.media-middle {
+  vertical-align: middle; }
+
+.media-bottom {
+  vertical-align: bottom; }
+
+.media-heading {
+  margin-top: 0;
+  margin-bottom: 5px; }
+
+.media-list {
+  padding-left: 0;
+  list-style: none; }
+
+.list-group {
+  margin-bottom: 20px;
+  padding-left: 0; }
+
+.list-group-item {
+  position: relative;
+  display: block;
+  padding: 10px 15px;
+  margin-bottom: -1px;
+  background-color: #fff;
+  border: 1px solid #ddd; }
+  .list-group-item:first-child {
+    border-top-right-radius: 4px;
+    border-top-left-radius: 4px; }
+  .list-group-item:last-child {
+    margin-bottom: 0;
+    border-bottom-right-radius: 4px;
+    border-bottom-left-radius: 4px; }
+
+a.list-group-item,
+button.list-group-item {
+  color: #555; }
+  a.list-group-item .list-group-item-heading,
+  button.list-group-item .list-group-item-heading {
+    color: #333; }
+  a.list-group-item:hover, a.list-group-item:focus,
+  button.list-group-item:hover,
+  button.list-group-item:focus {
+    text-decoration: none;
+    color: #555;
+    background-color: #f5f5f5; }
+
+button.list-group-item {
+  width: 100%;
+  text-align: left; }
+
+.list-group-item.disabled, .list-group-item.disabled:hover, .list-group-item.disabled:focus {
+  background-color: #eeeeee;
+  color: #777777;
+  cursor: not-allowed; }
+  .list-group-item.disabled .list-group-item-heading, .list-group-item.disabled:hover .list-group-item-heading, .list-group-item.disabled:focus .list-group-item-heading {
+    color: inherit; }
+  .list-group-item.disabled .list-group-item-text, .list-group-item.disabled:hover .list-group-item-text, .list-group-item.disabled:focus .list-group-item-text {
+    color: #777777; }
+
+.list-group-item.active, .list-group-item.active:hover, .list-group-item.active:focus {
+  z-index: 2;
+  color: #fff;
+  background-color: #337ab7;
+  border-color: #337ab7; }
+  .list-group-item.active .list-group-item-heading,
+  .list-group-item.active .list-group-item-heading > small,
+  .list-group-item.active .list-group-item-heading > .small, .list-group-item.active:hover .list-group-item-heading,
+  .list-group-item.active:hover .list-group-item-heading > small,
+  .list-group-item.active:hover .list-group-item-heading > .small, .list-group-item.active:focus .list-group-item-heading,
+  .list-group-item.active:focus .list-group-item-heading > small,
+  .list-group-item.active:focus .list-group-item-heading > .small {
+    color: inherit; }
+  .list-group-item.active .list-group-item-text, .list-group-item.active:hover .list-group-item-text, .list-group-item.active:focus .list-group-item-text {
+    color: #c7ddef; }
+
+.list-group-item-success {
+  color: #3c763d;
+  background-color: #dff0d8; }
+
+a.list-group-item-success,
+button.list-group-item-success {
+  color: #3c763d; }
+  a.list-group-item-success .list-group-item-heading,
+  button.list-group-item-success .list-group-item-heading {
+    color: inherit; }
+  a.list-group-item-success:hover, a.list-group-item-success:focus,
+  button.list-group-item-success:hover,
+  button.list-group-item-success:focus {
+    color: #3c763d;
+    background-color: #d0e9c6; }
+  a.list-group-item-success.active, a.list-group-item-success.active:hover, a.list-group-item-success.active:focus,
+  button.list-group-item-success.active,
+  button.list-group-item-success.active:hover,
+  button.list-group-item-success.active:focus {
+    color: #fff;
+    background-color: #3c763d;
+    border-color: #3c763d; }
+
+.list-group-item-info {
+  color: #31708f;
+  background-color: #d9edf7; }
+
+a.list-group-item-info,
+button.list-group-item-info {
+  color: #31708f; }
+  a.list-group-item-info .list-group-item-heading,
+  button.list-group-item-info .list-group-item-heading {
+    color: inherit; }
+  a.list-group-item-info:hover, a.list-group-item-info:focus,
+  button.list-group-item-info:hover,
+  button.list-group-item-info:focus {
+    color: #31708f;
+    background-color: #c4e3f3; }
+  a.list-group-item-info.active, a.list-group-item-info.active:hover, a.list-group-item-info.active:focus,
+  button.list-group-item-info.active,
+  button.list-group-item-info.active:hover,
+  button.list-group-item-info.active:focus {
+    color: #fff;
+    background-color: #31708f;
+    border-color: #31708f; }
+
+.list-group-item-warning {
+  color: #8a6d3b;
+  background-color: #fcf8e3; }
+
+a.list-group-item-warning,
+button.list-group-item-warning {
+  color: #8a6d3b; }
+  a.list-group-item-warning .list-group-item-heading,
+  button.list-group-item-warning .list-group-item-heading {
+    color: inherit; }
+  a.list-group-item-warning:hover, a.list-group-item-warning:focus,
+  button.list-group-item-warning:hover,
+  button.list-group-item-warning:focus {
+    color: #8a6d3b;
+    background-color: #faf2cc; }
+  a.list-group-item-warning.active, a.list-group-item-warning.active:hover, a.list-group-item-warning.active:focus,
+  button.list-group-item-warning.active,
+  button.list-group-item-warning.active:hover,
+  button.list-group-item-warning.active:focus {
+    color: #fff;
+    background-color: #8a6d3b;
+    border-color: #8a6d3b; }
+
+.list-group-item-danger {
+  color: #a94442;
+  background-color: #f2dede; }
+
+a.list-group-item-danger,
+button.list-group-item-danger {
+  color: #a94442; }
+  a.list-group-item-danger .list-group-item-heading,
+  button.list-group-item-danger .list-group-item-heading {
+    color: inherit; }
+  a.list-group-item-danger:hover, a.list-group-item-danger:focus,
+  button.list-group-item-danger:hover,
+  button.list-group-item-danger:focus {
+    color: #a94442;
+    background-color: #ebcccc; }
+  a.list-group-item-danger.active, a.list-group-item-danger.active:hover, a.list-group-item-danger.active:focus,
+  button.list-group-item-danger.active,
+  button.list-group-item-danger.active:hover,
+  button.list-group-item-danger.active:focus {
+    color: #fff;
+    background-color: #a94442;
+    border-color: #a94442; }
+
+.list-group-item-heading {
+  margin-top: 0;
+  margin-bottom: 5px; }
+
+.list-group-item-text {
+  margin-bottom: 0;
+  line-height: 1.3; }
+
+.panel {
+  margin-bottom: 20px;
+  background-color: #fff;
+  border: 1px solid transparent;
+  border-radius: 4px;
+  -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
+  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); }
+
+.panel-body {
+  padding: 15px; }
+  .panel-body:before, .panel-body:after {
+    content: " ";
+    display: table; }
+  .panel-body:after {
+    clear: both; }
+
+.panel-heading {
+  padding: 10px 15px;
+  border-bottom: 1px solid transparent;
+  border-top-right-radius: 3px;
+  border-top-left-radius: 3px; }
+  .panel-heading > .dropdown .dropdown-toggle {
+    color: inherit; }
+
+.panel-title {
+  margin-top: 0;
+  margin-bottom: 0;
+  font-size: 16px;
+  color: inherit; }
+  .panel-title > a,
+  .panel-title > small,
+  .panel-title > .small,
+  .panel-title > small > a,
+  .panel-title > .small > a {
+    color: inherit; }
+
+.panel-footer {
+  padding: 10px 15px;
+  background-color: #f5f5f5;
+  border-top: 1px solid #ddd;
+  border-bottom-right-radius: 3px;
+  border-bottom-left-radius: 3px; }
+
+.panel > .list-group,
+.panel > .panel-collapse > .list-group {
+  margin-bottom: 0; }
+  .panel > .list-group .list-group-item,
+  .panel > .panel-collapse > .list-group .list-group-item {
+    border-width: 1px 0;
+    border-radius: 0; }
+  .panel > .list-group:first-child .list-group-item:first-child,
+  .panel > .panel-collapse > .list-group:first-child .list-group-item:first-child {
+    border-top: 0;
+    border-top-right-radius: 3px;
+    border-top-left-radius: 3px; }
+  .panel > .list-group:last-child .list-group-item:last-child,
+  .panel > .panel-collapse > .list-group:last-child .list-group-item:last-child {
+    border-bottom: 0;
+    border-bottom-right-radius: 3px;
+    border-bottom-left-radius: 3px; }
+
+.panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child {
+  border-top-right-radius: 0;
+  border-top-left-radius: 0; }
+
+.panel-heading + .list-group .list-group-item:first-child {
+  border-top-width: 0; }
+
+.list-group + .panel-footer {
+  border-top-width: 0; }
+
+.panel > .table,
+.panel > .table-responsive > .table,
+.panel > .panel-collapse > .table {
+  margin-bottom: 0; }
+  .panel > .table caption,
+  .panel > .table-responsive > .table caption,
+  .panel > .panel-collapse > .table caption {
+    padding-left: 15px;
+    padding-right: 15px; }
+
+.panel > .table:first-child,
+.panel > .table-responsive:first-child > .table:first-child {
+  border-top-right-radius: 3px;
+  border-top-left-radius: 3px; }
+  .panel > .table:first-child > thead:first-child > tr:first-child,
+  .panel > .table:first-child > tbody:first-child > tr:first-child,
+  .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child,
+  .panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child {
+    border-top-left-radius: 3px;
+    border-top-right-radius: 3px; }
+    .panel > .table:first-child > thead:first-child > tr:first-child td:first-child,
+    .panel > .table:first-child > thead:first-child > tr:first-child th:first-child,
+    .panel > .table:first-child > tbody:first-child > tr:first-child td:first-child,
+    .panel > .table:first-child > tbody:first-child > tr:first-child th:first-child,
+    .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child,
+    .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child,
+    .panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child,
+    .panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child {
+      border-top-left-radius: 3px; }
+    .panel > .table:first-child > thead:first-child > tr:first-child td:last-child,
+    .panel > .table:first-child > thead:first-child > tr:first-child th:last-child,
+    .panel > .table:first-child > tbody:first-child > tr:first-child td:last-child,
+    .panel > .table:first-child > tbody:first-child > tr:first-child th:last-child,
+    .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child,
+    .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child,
+    .panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child,
+    .panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child {
+      border-top-right-radius: 3px; }
+
+.panel > .table:last-child,
+.panel > .table-responsive:last-child > .table:last-child {
+  border-bottom-right-radius: 3px;
+  border-bottom-left-radius: 3px; }
+  .panel > .table:last-child > tbody:last-child > tr:last-child,
+  .panel > .table:last-child > tfoot:last-child > tr:last-child,
+  .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child,
+  .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child {
+    border-bottom-left-radius: 3px;
+    border-bottom-right-radius: 3px; }
+    .panel > .table:last-child > tbody:last-child > tr:last-child td:first-child,
+    .panel > .table:last-child > tbody:last-child > tr:last-child th:first-child,
+    .panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child,
+    .panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child,
+    .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child,
+    .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child,
+    .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child,
+    .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child {
+      border-bottom-left-radius: 3px; }
+    .panel > .table:last-child > tbody:last-child > tr:last-child td:last-child,
+    .panel > .table:last-child > tbody:last-child > tr:last-child th:last-child,
+    .panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child,
+    .panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child,
+    .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child,
+    .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child,
+    .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child,
+    .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child {
+      border-bottom-right-radius: 3px; }
+
+.panel > .panel-body + .table,
+.panel > .panel-body + .table-responsive,
+.panel > .table + .panel-body,
+.panel > .table-responsive + .panel-body {
+  border-top: 1px solid #ddd; }
+
+.panel > .table > tbody:first-child > tr:first-child th,
+.panel > .table > tbody:first-child > tr:first-child td {
+  border-top: 0; }
+
+.panel > .table-bordered,
+.panel > .table-responsive > .table-bordered {
+  border: 0; }
+  .panel > .table-bordered > thead > tr > th:first-child,
+  .panel > .table-bordered > thead > tr > td:first-child,
+  .panel > .table-bordered > tbody > tr > th:first-child,
+  .panel > .table-bordered > tbody > tr > td:first-child,
+  .panel > .table-bordered > tfoot > tr > th:first-child,
+  .panel > .table-bordered > tfoot > tr > td:first-child,
+  .panel > .table-responsive > .table-bordered > thead > tr > th:first-child,
+  .panel > .table-responsive > .table-bordered > thead > tr > td:first-child,
+  .panel > .table-responsive > .table-bordered > tbody > tr > th:first-child,
+  .panel > .table-responsive > .table-bordered > tbody > tr > td:first-child,
+  .panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child,
+  .panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child {
+    border-left: 0; }
+  .panel > .table-bordered > thead > tr > th:last-child,
+  .panel > .table-bordered > thead > tr > td:last-child,
+  .panel > .table-bordered > tbody > tr > th:last-child,
+  .panel > .table-bordered > tbody > tr > td:last-child,
+  .panel > .table-bordered > tfoot > tr > th:last-child,
+  .panel > .table-bordered > tfoot > tr > td:last-child,
+  .panel > .table-responsive > .table-bordered > thead > tr > th:last-child,
+  .panel > .table-responsive > .table-bordered > thead > tr > td:last-child,
+  .panel > .table-responsive > .table-bordered > tbody > tr > th:last-child,
+  .panel > .table-responsive > .table-bordered > tbody > tr > td:last-child,
+  .panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child,
+  .panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child {
+    border-right: 0; }
+  .panel > .table-bordered > thead > tr:first-child > td,
+  .panel > .table-bordered > thead > tr:first-child > th,
+  .panel > .table-bordered > tbody > tr:first-child > td,
+  .panel > .table-bordered > tbody > tr:first-child > th,
+  .panel > .table-responsive > .table-bordered > thead > tr:first-child > td,
+  .panel > .table-responsive > .table-bordered > thead > tr:first-child > th,
+  .panel > .table-responsive > .table-bordered > tbody > tr:first-child > td,
+  .panel > .table-responsive > .table-bordered > tbody > tr:first-child > th {
+    border-bottom: 0; }
+  .panel > .table-bordered > tbody > tr:last-child > td,
+  .panel > .table-bordered > tbody > tr:last-child > th,
+  .panel > .table-bordered > tfoot > tr:last-child > td,
+  .panel > .table-bordered > tfoot > tr:last-child > th,
+  .panel > .table-responsive > .table-bordered > tbody > tr:last-child > td,
+  .panel > .table-responsive > .table-bordered > tbody > tr:last-child > th,
+  .panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td,
+  .panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th {
+    border-bottom: 0; }
+
+.panel > .table-responsive {
+  border: 0;
+  margin-bottom: 0; }
+
+.panel-group {
+  margin-bottom: 20px; }
+  .panel-group .panel {
+    margin-bottom: 0;
+    border-radius: 4px; }
+    .panel-group .panel + .panel {
+      margin-top: 5px; }
+  .panel-group .panel-heading {
+    border-bottom: 0; }
+    .panel-group .panel-heading + .panel-collapse > .panel-body,
+    .panel-group .panel-heading + .panel-collapse > .list-group {
+      border-top: 1px solid #ddd; }
+  .panel-group .panel-footer {
+    border-top: 0; }
+    .panel-group .panel-footer + .panel-collapse .panel-body {
+      border-bottom: 1px solid #ddd; }
+
+.panel-default {
+  border-color: #ddd; }
+  .panel-default > .panel-heading {
+    color: #333333;
+    background-color: #f5f5f5;
+    border-color: #ddd; }
+    .panel-default > .panel-heading + .panel-collapse > .panel-body {
+      border-top-color: #ddd; }
+    .panel-default > .panel-heading .badge {
+      color: #f5f5f5;
+      background-color: #333333; }
+  .panel-default > .panel-footer + .panel-collapse > .panel-body {
+    border-bottom-color: #ddd; }
+
+.panel-primary {
+  border-color: #337ab7; }
+  .panel-primary > .panel-heading {
+    color: #fff;
+    background-color: #337ab7;
+    border-color: #337ab7; }
+    .panel-primary > .panel-heading + .panel-collapse > .panel-body {
+      border-top-color: #337ab7; }
+    .panel-primary > .panel-heading .badge {
+      color: #337ab7;
+      background-color: #fff; }
+  .panel-primary > .panel-footer + .panel-collapse > .panel-body {
+    border-bottom-color: #337ab7; }
+
+.panel-success {
+  border-color: #d6e9c6; }
+  .panel-success > .panel-heading {
+    color: #3c763d;
+    background-color: #dff0d8;
+    border-color: #d6e9c6; }
+    .panel-success > .panel-heading + .panel-collapse > .panel-body {
+      border-top-color: #d6e9c6; }
+    .panel-success > .panel-heading .badge {
+      color: #dff0d8;
+      background-color: #3c763d; }
+  .panel-success > .panel-footer + .panel-collapse > .panel-body {
+    border-bottom-color: #d6e9c6; }
+
+.panel-info {
+  border-color: #bce8f1; }
+  .panel-info > .panel-heading {
+    color: #31708f;
+    background-color: #d9edf7;
+    border-color: #bce8f1; }
+    .panel-info > .panel-heading + .panel-collapse > .panel-body {
+      border-top-color: #bce8f1; }
+    .panel-info > .panel-heading .badge {
+      color: #d9edf7;
+      background-color: #31708f; }
+  .panel-info > .panel-footer + .panel-collapse > .panel-body {
+    border-bottom-color: #bce8f1; }
+
+.panel-warning {
+  border-color: #faebcc; }
+  .panel-warning > .panel-heading {
+    color: #8a6d3b;
+    background-color: #fcf8e3;
+    border-color: #faebcc; }
+    .panel-warning > .panel-heading + .panel-collapse > .panel-body {
+      border-top-color: #faebcc; }
+    .panel-warning > .panel-heading .badge {
+      color: #fcf8e3;
+      background-color: #8a6d3b; }
+  .panel-warning > .panel-footer + .panel-collapse > .panel-body {
+    border-bottom-color: #faebcc; }
+
+.panel-danger {
+  border-color: #ebccd1; }
+  .panel-danger > .panel-heading {
+    color: #a94442;
+    background-color: #f2dede;
+    border-color: #ebccd1; }
+    .panel-danger > .panel-heading + .panel-collapse > .panel-body {
+      border-top-color: #ebccd1; }
+    .panel-danger > .panel-heading .badge {
+      color: #f2dede;
+      background-color: #a94442; }
+  .panel-danger > .panel-footer + .panel-collapse > .panel-body {
+    border-bottom-color: #ebccd1; }
+
+.embed-responsive {
+  position: relative;
+  display: block;
+  height: 0;
+  padding: 0;
+  overflow: hidden; }
+  .embed-responsive .embed-responsive-item,
+  .embed-responsive iframe,
+  .embed-responsive embed,
+  .embed-responsive object,
+  .embed-responsive video {
+    position: absolute;
+    top: 0;
+    left: 0;
+    bottom: 0;
+    height: 100%;
+    width: 100%;
+    border: 0; }
+
+.embed-responsive-16by9 {
+  padding-bottom: 56.25%; }
+
+.embed-responsive-4by3 {
+  padding-bottom: 75%; }
+
+.well {
+  min-height: 20px;
+  padding: 19px;
+  margin-bottom: 20px;
+  background-color: #f5f5f5;
+  border: 1px solid #e3e3e3;
+  border-radius: 4px;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); }
+  .well blockquote {
+    border-color: #ddd;
+    border-color: rgba(0, 0, 0, 0.15); }
+
+.well-lg {
+  padding: 24px;
+  border-radius: 6px; }
+
+.well-sm {
+  padding: 9px;
+  border-radius: 3px; }
+
+.close {
+  float: right;
+  font-size: 21px;
+  font-weight: bold;
+  line-height: 1;
+  color: #000;
+  text-shadow: 0 1px 0 #fff;
+  opacity: 0.2;
+  filter: alpha(opacity=20); }
+  .close:hover, .close:focus {
+    color: #000;
+    text-decoration: none;
+    cursor: pointer;
+    opacity: 0.5;
+    filter: alpha(opacity=50); }
+
+button.close {
+  padding: 0;
+  cursor: pointer;
+  background: transparent;
+  border: 0;
+  -webkit-appearance: none; }
+
+.modal-open {
+  overflow: hidden; }
+
+.modal {
+  display: none;
+  overflow: hidden;
+  position: fixed;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  z-index: 1050;
+  -webkit-overflow-scrolling: touch;
+  outline: 0; }
+  .modal.fade .modal-dialog {
+    -webkit-transform: translate(0, -25%);
+    -ms-transform: translate(0, -25%);
+    -o-transform: translate(0, -25%);
+    transform: translate(0, -25%);
+    -webkit-transition: -webkit-transform 0.3s ease-out;
+    -moz-transition: -moz-transform 0.3s ease-out;
+    -o-transition: -o-transform 0.3s ease-out;
+    transition: transform 0.3s ease-out; }
+  .modal.in .modal-dialog {
+    -webkit-transform: translate(0, 0);
+    -ms-transform: translate(0, 0);
+    -o-transform: translate(0, 0);
+    transform: translate(0, 0); }
+
+.modal-open .modal {
+  overflow-x: hidden;
+  overflow-y: auto; }
+
+.modal-dialog {
+  position: relative;
+  width: auto;
+  margin: 10px; }
+
+.modal-content {
+  position: relative;
+  background-color: #fff;
+  border: 1px solid #999;
+  border: 1px solid rgba(0, 0, 0, 0.2);
+  border-radius: 6px;
+  -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);
+  box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);
+  background-clip: padding-box;
+  outline: 0; }
+
+.modal-backdrop {
+  position: fixed;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  z-index: 1040;
+  background-color: #000; }
+  .modal-backdrop.fade {
+    opacity: 0;
+    filter: alpha(opacity=0); }
+  .modal-backdrop.in {
+    opacity: 0.5;
+    filter: alpha(opacity=50); }
+
+.modal-header {
+  padding: 15px;
+  border-bottom: 1px solid #e5e5e5; }
+  .modal-header:before, .modal-header:after {
+    content: " ";
+    display: table; }
+  .modal-header:after {
+    clear: both; }
+
+.modal-header .close {
+  margin-top: -2px; }
+
+.modal-title {
+  margin: 0;
+  line-height: 1.42857; }
+
+.modal-body {
+  position: relative;
+  padding: 15px; }
+
+.modal-footer {
+  padding: 15px;
+  text-align: right;
+  border-top: 1px solid #e5e5e5; }
+  .modal-footer:before, .modal-footer:after {
+    content: " ";
+    display: table; }
+  .modal-footer:after {
+    clear: both; }
+  .modal-footer .btn + .btn {
+    margin-left: 5px;
+    margin-bottom: 0; }
+  .modal-footer .btn-group .btn + .btn {
+    margin-left: -1px; }
+  .modal-footer .btn-block + .btn-block {
+    margin-left: 0; }
+
+.modal-scrollbar-measure {
+  position: absolute;
+  top: -9999px;
+  width: 50px;
+  height: 50px;
+  overflow: scroll; }
+
+@media (min-width: 768px) {
+  .modal-dialog {
+    width: 600px;
+    margin: 30px auto; }
+  .modal-content {
+    -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);
+    box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); }
+  .modal-sm {
+    width: 300px; } }
+
+@media (min-width: 992px) {
+  .modal-lg {
+    width: 900px; } }
+
+.tooltip {
+  position: absolute;
+  z-index: 1070;
+  display: block;
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+  font-style: normal;
+  font-weight: normal;
+  letter-spacing: normal;
+  line-break: auto;
+  line-height: 1.42857;
+  text-align: left;
+  text-align: start;
+  text-decoration: none;
+  text-shadow: none;
+  text-transform: none;
+  white-space: normal;
+  word-break: normal;
+  word-spacing: normal;
+  word-wrap: normal;
+  font-size: 12px;
+  opacity: 0;
+  filter: alpha(opacity=0); }
+  .tooltip.in {
+    opacity: 0.9;
+    filter: alpha(opacity=90); }
+  .tooltip.top {
+    margin-top: -3px;
+    padding: 5px 0; }
+  .tooltip.right {
+    margin-left: 3px;
+    padding: 0 5px; }
+  .tooltip.bottom {
+    margin-top: 3px;
+    padding: 5px 0; }
+  .tooltip.left {
+    margin-left: -3px;
+    padding: 0 5px; }
+
+.tooltip-inner {
+  max-width: 200px;
+  padding: 3px 8px;
+  color: #fff;
+  text-align: center;
+  background-color: #000;
+  border-radius: 4px; }
+
+.tooltip-arrow {
+  position: absolute;
+  width: 0;
+  height: 0;
+  border-color: transparent;
+  border-style: solid; }
+
+.tooltip.top .tooltip-arrow {
+  bottom: 0;
+  left: 50%;
+  margin-left: -5px;
+  border-width: 5px 5px 0;
+  border-top-color: #000; }
+
+.tooltip.top-left .tooltip-arrow {
+  bottom: 0;
+  right: 5px;
+  margin-bottom: -5px;
+  border-width: 5px 5px 0;
+  border-top-color: #000; }
+
+.tooltip.top-right .tooltip-arrow {
+  bottom: 0;
+  left: 5px;
+  margin-bottom: -5px;
+  border-width: 5px 5px 0;
+  border-top-color: #000; }
+
+.tooltip.right .tooltip-arrow {
+  top: 50%;
+  left: 0;
+  margin-top: -5px;
+  border-width: 5px 5px 5px 0;
+  border-right-color: #000; }
+
+.tooltip.left .tooltip-arrow {
+  top: 50%;
+  right: 0;
+  margin-top: -5px;
+  border-width: 5px 0 5px 5px;
+  border-left-color: #000; }
+
+.tooltip.bottom .tooltip-arrow {
+  top: 0;
+  left: 50%;
+  margin-left: -5px;
+  border-width: 0 5px 5px;
+  border-bottom-color: #000; }
+
+.tooltip.bottom-left .tooltip-arrow {
+  top: 0;
+  right: 5px;
+  margin-top: -5px;
+  border-width: 0 5px 5px;
+  border-bottom-color: #000; }
+
+.tooltip.bottom-right .tooltip-arrow {
+  top: 0;
+  left: 5px;
+  margin-top: -5px;
+  border-width: 0 5px 5px;
+  border-bottom-color: #000; }
+
+.popover {
+  position: absolute;
+  top: 0;
+  left: 0;
+  z-index: 1060;
+  display: none;
+  max-width: 276px;
+  padding: 1px;
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+  font-style: normal;
+  font-weight: normal;
+  letter-spacing: normal;
+  line-break: auto;
+  line-height: 1.42857;
+  text-align: left;
+  text-align: start;
+  text-decoration: none;
+  text-shadow: none;
+  text-transform: none;
+  white-space: normal;
+  word-break: normal;
+  word-spacing: normal;
+  word-wrap: normal;
+  font-size: 14px;
+  background-color: #fff;
+  background-clip: padding-box;
+  border: 1px solid #ccc;
+  border: 1px solid rgba(0, 0, 0, 0.2);
+  border-radius: 6px;
+  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+  box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); }
+  .popover.top {
+    margin-top: -10px; }
+  .popover.right {
+    margin-left: 10px; }
+  .popover.bottom {
+    margin-top: 10px; }
+  .popover.left {
+    margin-left: -10px; }
+
+.popover-title {
+  margin: 0;
+  padding: 8px 14px;
+  font-size: 14px;
+  background-color: #f7f7f7;
+  border-bottom: 1px solid #ebebeb;
+  border-radius: 5px 5px 0 0; }
+
+.popover-content {
+  padding: 9px 14px; }
+
+.popover > .arrow, .popover > .arrow:after {
+  position: absolute;
+  display: block;
+  width: 0;
+  height: 0;
+  border-color: transparent;
+  border-style: solid; }
+
+.popover > .arrow {
+  border-width: 11px; }
+
+.popover > .arrow:after {
+  border-width: 10px;
+  content: ""; }
+
+.popover.top > .arrow {
+  left: 50%;
+  margin-left: -11px;
+  border-bottom-width: 0;
+  border-top-color: #999999;
+  border-top-color: rgba(0, 0, 0, 0.25);
+  bottom: -11px; }
+  .popover.top > .arrow:after {
+    content: " ";
+    bottom: 1px;
+    margin-left: -10px;
+    border-bottom-width: 0;
+    border-top-color: #fff; }
+
+.popover.right > .arrow {
+  top: 50%;
+  left: -11px;
+  margin-top: -11px;
+  border-left-width: 0;
+  border-right-color: #999999;
+  border-right-color: rgba(0, 0, 0, 0.25); }
+  .popover.right > .arrow:after {
+    content: " ";
+    left: 1px;
+    bottom: -10px;
+    border-left-width: 0;
+    border-right-color: #fff; }
+
+.popover.bottom > .arrow {
+  left: 50%;
+  margin-left: -11px;
+  border-top-width: 0;
+  border-bottom-color: #999999;
+  border-bottom-color: rgba(0, 0, 0, 0.25);
+  top: -11px; }
+  .popover.bottom > .arrow:after {
+    content: " ";
+    top: 1px;
+    margin-left: -10px;
+    border-top-width: 0;
+    border-bottom-color: #fff; }
+
+.popover.left > .arrow {
+  top: 50%;
+  right: -11px;
+  margin-top: -11px;
+  border-right-width: 0;
+  border-left-color: #999999;
+  border-left-color: rgba(0, 0, 0, 0.25); }
+  .popover.left > .arrow:after {
+    content: " ";
+    right: 1px;
+    border-right-width: 0;
+    border-left-color: #fff;
+    bottom: -10px; }
+
+.carousel {
+  position: relative; }
+
+.carousel-inner {
+  position: relative;
+  overflow: hidden;
+  width: 100%; }
+  .carousel-inner > .item {
+    display: none;
+    position: relative;
+    -webkit-transition: 0.6s ease-in-out left;
+    -o-transition: 0.6s ease-in-out left;
+    transition: 0.6s ease-in-out left; }
+    .carousel-inner > .item > img,
+    .carousel-inner > .item > a > img {
+      display: block;
+      max-width: 100%;
+      height: auto;
+      line-height: 1; }
+    @media all and (transform-3d), (-webkit-transform-3d) {
+      .carousel-inner > .item {
+        -webkit-transition: -webkit-transform 0.6s ease-in-out;
+        -moz-transition: -moz-transform 0.6s ease-in-out;
+        -o-transition: -o-transform 0.6s ease-in-out;
+        transition: transform 0.6s ease-in-out;
+        -webkit-backface-visibility: hidden;
+        -moz-backface-visibility: hidden;
+        backface-visibility: hidden;
+        -webkit-perspective: 1000px;
+        -moz-perspective: 1000px;
+        perspective: 1000px; }
+        .carousel-inner > .item.next, .carousel-inner > .item.active.right {
+          -webkit-transform: translate3d(100%, 0, 0);
+          transform: translate3d(100%, 0, 0);
+          left: 0; }
+        .carousel-inner > .item.prev, .carousel-inner > .item.active.left {
+          -webkit-transform: translate3d(-100%, 0, 0);
+          transform: translate3d(-100%, 0, 0);
+          left: 0; }
+        .carousel-inner > .item.next.left, .carousel-inner > .item.prev.right, .carousel-inner > .item.active {
+          -webkit-transform: translate3d(0, 0, 0);
+          transform: translate3d(0, 0, 0);
+          left: 0; } }
+  .carousel-inner > .active,
+  .carousel-inner > .next,
+  .carousel-inner > .prev {
+    display: block; }
+  .carousel-inner > .active {
+    left: 0; }
+  .carousel-inner > .next,
+  .carousel-inner > .prev {
+    position: absolute;
+    top: 0;
+    width: 100%; }
+  .carousel-inner > .next {
+    left: 100%; }
+  .carousel-inner > .prev {
+    left: -100%; }
+  .carousel-inner > .next.left,
+  .carousel-inner > .prev.right {
+    left: 0; }
+  .carousel-inner > .active.left {
+    left: -100%; }
+  .carousel-inner > .active.right {
+    left: 100%; }
+
+.carousel-control {
+  position: absolute;
+  top: 0;
+  left: 0;
+  bottom: 0;
+  width: 15%;
+  opacity: 0.5;
+  filter: alpha(opacity=50);
+  font-size: 20px;
+  color: #fff;
+  text-align: center;
+  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
+  background-color: transparent; }
+  .carousel-control.left {
+    background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);
+    background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);
+    background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);
+    background-repeat: repeat-x;
+    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1); }
+  .carousel-control.right {
+    left: auto;
+    right: 0;
+    background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);
+    background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);
+    background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);
+    background-repeat: repeat-x;
+    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1); }
+  .carousel-control:hover, .carousel-control:focus {
+    outline: 0;
+    color: #fff;
+    text-decoration: none;
+    opacity: 0.9;
+    filter: alpha(opacity=90); }
+  .carousel-control .icon-prev,
+  .carousel-control .icon-next,
+  .carousel-control .glyphicon-chevron-left,
+  .carousel-control .glyphicon-chevron-right {
+    position: absolute;
+    top: 50%;
+    margin-top: -10px;
+    z-index: 5;
+    display: inline-block; }
+  .carousel-control .icon-prev,
+  .carousel-control .glyphicon-chevron-left {
+    left: 50%;
+    margin-left: -10px; }
+  .carousel-control .icon-next,
+  .carousel-control .glyphicon-chevron-right {
+    right: 50%;
+    margin-right: -10px; }
+  .carousel-control .icon-prev,
+  .carousel-control .icon-next {
+    width: 20px;
+    height: 20px;
+    line-height: 1;
+    font-family: serif; }
+  .carousel-control .icon-prev:before {
+    content: '\2039'; }
+  .carousel-control .icon-next:before {
+    content: '\203a'; }
+
+.carousel-indicators {
+  position: absolute;
+  bottom: 10px;
+  left: 50%;
+  z-index: 15;
+  width: 60%;
+  margin-left: -30%;
+  padding-left: 0;
+  list-style: none;
+  text-align: center; }
+  .carousel-indicators li {
+    display: inline-block;
+    width: 10px;
+    height: 10px;
+    margin: 1px;
+    text-indent: -999px;
+    border: 1px solid #fff;
+    border-radius: 10px;
+    cursor: pointer;
+    background-color: #000 \9;
+    background-color: transparent; }
+  .carousel-indicators .active {
+    margin: 0;
+    width: 12px;
+    height: 12px;
+    background-color: #fff; }
+
+.carousel-caption {
+  position: absolute;
+  left: 15%;
+  right: 15%;
+  bottom: 20px;
+  z-index: 10;
+  padding-top: 20px;
+  padding-bottom: 20px;
+  color: #fff;
+  text-align: center;
+  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); }
+  .carousel-caption .btn {
+    text-shadow: none; }
+
+@media screen and (min-width: 768px) {
+  .carousel-control .glyphicon-chevron-left,
+  .carousel-control .glyphicon-chevron-right,
+  .carousel-control .icon-prev,
+  .carousel-control .icon-next {
+    width: 30px;
+    height: 30px;
+    margin-top: -10px;
+    font-size: 30px; }
+  .carousel-control .glyphicon-chevron-left,
+  .carousel-control .icon-prev {
+    margin-left: -10px; }
+  .carousel-control .glyphicon-chevron-right,
+  .carousel-control .icon-next {
+    margin-right: -10px; }
+  .carousel-caption {
+    left: 20%;
+    right: 20%;
+    padding-bottom: 30px; }
+  .carousel-indicators {
+    bottom: 20px; } }
+
+.clearfix:before, .clearfix:after {
+  content: " ";
+  display: table; }
+
+.clearfix:after {
+  clear: both; }
+
+.center-block {
+  display: block;
+  margin-left: auto;
+  margin-right: auto; }
+
+.pull-right {
+  float: right !important; }
+
+.pull-left {
+  float: left !important; }
+
+.hide {
+  display: none !important; }
+
+.show {
+  display: block !important; }
+
+.invisible {
+  visibility: hidden; }
+
+.text-hide {
+  font: 0/0 a;
+  color: transparent;
+  text-shadow: none;
+  background-color: transparent;
+  border: 0; }
+
+.hidden {
+  display: none !important; }
+
+.affix {
+  position: fixed; }
+
+@-ms-viewport {
+  width: device-width; }
+
+.visible-xs {
+  display: none !important; }
+
+.visible-sm {
+  display: none !important; }
+
+.visible-md {
+  display: none !important; }
+
+.visible-lg {
+  display: none !important; }
+
+.visible-xs-block,
+.visible-xs-inline,
+.visible-xs-inline-block,
+.visible-sm-block,
+.visible-sm-inline,
+.visible-sm-inline-block,
+.visible-md-block,
+.visible-md-inline,
+.visible-md-inline-block,
+.visible-lg-block,
+.visible-lg-inline,
+.visible-lg-inline-block {
+  display: none !important; }
+
+@media (max-width: 767px) {
+  .visible-xs {
+    display: block !important; }
+  table.visible-xs {
+    display: table !important; }
+  tr.visible-xs {
+    display: table-row !important; }
+  th.visible-xs,
+  td.visible-xs {
+    display: table-cell !important; } }
+
+@media (max-width: 767px) {
+  .visible-xs-block {
+    display: block !important; } }
+
+@media (max-width: 767px) {
+  .visible-xs-inline {
+    display: inline !important; } }
+
+@media (max-width: 767px) {
+  .visible-xs-inline-block {
+    display: inline-block !important; } }
+
+@media (min-width: 768px) and (max-width: 991px) {
+  .visible-sm {
+    display: block !important; }
+  table.visible-sm {
+    display: table !important; }
+  tr.visible-sm {
+    display: table-row !important; }
+  th.visible-sm,
+  td.visible-sm {
+    display: table-cell !important; } }
+
+@media (min-width: 768px) and (max-width: 991px) {
+  .visible-sm-block {
+    display: block !important; } }
+
+@media (min-width: 768px) and (max-width: 991px) {
+  .visible-sm-inline {
+    display: inline !important; } }
+
+@media (min-width: 768px) and (max-width: 991px) {
+  .visible-sm-inline-block {
+    display: inline-block !important; } }
+
+@media (min-width: 992px) and (max-width: 1199px) {
+  .visible-md {
+    display: block !important; }
+  table.visible-md {
+    display: table !important; }
+  tr.visible-md {
+    display: table-row !important; }
+  th.visible-md,
+  td.visible-md {
+    display: table-cell !important; } }
+
+@media (min-width: 992px) and (max-width: 1199px) {
+  .visible-md-block {
+    display: block !important; } }
+
+@media (min-width: 992px) and (max-width: 1199px) {
+  .visible-md-inline {
+    display: inline !important; } }
+
+@media (min-width: 992px) and (max-width: 1199px) {
+  .visible-md-inline-block {
+    display: inline-block !important; } }
+
+@media (min-width: 1200px) {
+  .visible-lg {
+    display: block !important; }
+  table.visible-lg {
+    display: table !important; }
+  tr.visible-lg {
+    display: table-row !important; }
+  th.visible-lg,
+  td.visible-lg {
+    display: table-cell !important; } }
+
+@media (min-width: 1200px) {
+  .visible-lg-block {
+    display: block !important; } }
+
+@media (min-width: 1200px) {
+  .visible-lg-inline {
+    display: inline !important; } }
+
+@media (min-width: 1200px) {
+  .visible-lg-inline-block {
+    display: inline-block !important; } }
+
+@media (max-width: 767px) {
+  .hidden-xs {
+    display: none !important; } }
+
+@media (min-width: 768px) and (max-width: 991px) {
+  .hidden-sm {
+    display: none !important; } }
+
+@media (min-width: 992px) and (max-width: 1199px) {
+  .hidden-md {
+    display: none !important; } }
+
+@media (min-width: 1200px) {
+  .hidden-lg {
+    display: none !important; } }
+
+.visible-print {
+  display: none !important; }
+
+@media print {
+  .visible-print {
+    display: block !important; }
+  table.visible-print {
+    display: table !important; }
+  tr.visible-print {
+    display: table-row !important; }
+  th.visible-print,
+  td.visible-print {
+    display: table-cell !important; } }
+
+.visible-print-block {
+  display: none !important; }
+  @media print {
+    .visible-print-block {
+      display: block !important; } }
+
+.visible-print-inline {
+  display: none !important; }
+  @media print {
+    .visible-print-inline {
+      display: inline !important; } }
+
+.visible-print-inline-block {
+  display: none !important; }
+  @media print {
+    .visible-print-inline-block {
+      display: inline-block !important; } }
+
+@media print {
+  .hidden-print {
+    display: none !important; } }
+
+/* ************************* HEADER STYLE ************************* */
+.header {
+  background-color: #ffffff !important;
+  border-bottom: 3px solid #C5CCD4;
+  margin-bottom: 14px;
+  height: 85px; }
+  .header .logo {
+    max-height: 80px; }
+  .header a {
+    font-weight: bold; }
+  .header #user-tools {
+    padding: 12px 20px 0px 0px;
+    float: right;
+    margin-top: -5px; }
+    @media (max-width: 991px) {
+      .header #user-tools .user-links *:not(:last-child) {
+        display: none; } }
+
+/************************* END HEADER *************************/
+/************************* NAV *************************/
+#sidebar-wrapper {
+  -webkit-box-shadow: 3px 0px 5px 0px rgba(50, 50, 50, 0.75);
+  -moz-box-shadow: 3px 0px 5px 0px rgba(50, 50, 50, 0.75);
+  box-shadow: 3px 0px 5px 0px rgba(50, 50, 50, 0.75); }
+  #sidebar-wrapper .logo {
+    max-width: 100%; }
+  #sidebar-wrapper a {
+    font-weight: bold; }
+  #sidebar-wrapper .icon-app {
+    background-image: url("opencloudApp.png"); }
+  #sidebar-wrapper .icon-home {
+    /*  Going with darker standard color nav -- so using over png's background-image: url("Home.png"); */
+    background-image: url("Home.png"); }
+  #sidebar-wrapper .icon-deployment {
+    background-image: url("Deployments.png"); }
+  #sidebar-wrapper .icon-site {
+    background-image: url("Sites.png"); }
+  #sidebar-wrapper .icon-slice {
+    background-image: url("Slices.png"); }
+  #sidebar-wrapper .icon-user {
+    background-image: url("Users.png"); }
+  #sidebar-wrapper .icon-reservation {
+    background-image: url("Reservations.png"); }
+  #sidebar-wrapper .icon-cog {
+    background-image: url("Services.png"); }
+  #sidebar-wrapper li.active a .icon-home,
+  #sidebar-wrapper li.focus a .icon-home {
+    background-image: url("Home_over.png"); }
+  #sidebar-wrapper li.active a .icon-deployment,
+  #sidebar-wrapper li.focus a .icon-deployment {
+    background-image: url("Deployments_over.png"); }
+  #sidebar-wrapper li.active a .icon-site,
+  #sidebar-wrapper li.focus a .icon-site {
+    background-image: url("Sites_over.png"); }
+  #sidebar-wrapper li.active a .icon-slice,
+  #sidebar-wrapper li.focus a .icon-slice {
+    background-image: url("Slices_over.png"); }
+  #sidebar-wrapper li.active a .icon-user,
+  #sidebar-wrapper li.focus a .icon-user {
+    background-image: url("Users_over.png"); }
+  #sidebar-wrapper li.active a .icon-reservation,
+  #sidebar-wrapper li.focus a .icon-reservation {
+    background-image: url("Reservations_over.png"); }
+  #sidebar-wrapper li.active a .icon-cog,
+  #sidebar-wrapper li.focus a .icon-cog {
+    background-image: url("Services_over.png"); }
+  #sidebar-wrapper [class^="icon-"] {
+    background-position: left center;
+    width: 22px;
+    height: 22px;
+    display: inline-block;
+    margin-right: 10px;
+    position: relative;
+    top: 5px; }
+
+/************************* END NAV *************************/
+/************************* FOOTER *************************/
+.footer {
+  z-index: 99;
+  position: fixed; }
+
+/* FIXME */
+@media (max-width: 768px) {
+  .footer {
+    display: none; }
+  #page-content-wrapper {
+    padding-bottom: 60px; } }
+
+.footer .content .statusMsg {
+  float: right;
+  padding: 15px 20px 0 0;
+  display: block; }
+
+/************************* END FOOTER *************************/
+table.dataTable thead th div.DataTables_sort_wrapper {
+  font-weight: normal !important; }
+
+table.dataTable thead tr {
+  background-color: #6e7277; }
+  table.dataTable thead tr th.ui-state-default {
+    background: transparent !important;
+    color: #fff !important; }
+
+table.dataTable tr.odd,
+table.dataTable tr.odd td.sorting_1 {
+  background-color: #eeeeee !important; }
+
+table.dataTable tr.even td.sorting_1 {
+  background-color: #fff; }
+
+table.dataTable thead th div.DataTables_sort_wrapper {
+  font-weight: bold; }
+
+.nav-tabs-suit li.active a,
+.nav-tabs-suit li.active a:hover,
+.nav-tabs-suit li a:hover,
+.nav-tabs-suit > li.active > a:focus {
+  background-color: #337ab7;
+  color: #fff;
+  outline: none; }
+
+.nav-tabs > li {
+  margin-bottom: 0px; }
+
+.nav-tabs-suit li a {
+  letter-spacing: 1px; }
+
+#suit_form_tabs {
+  border-bottom-width: 5px !important;
+  border-bottom-style: solid;
+  border-bottom-color: #337ab7; }
+
+.ui-widget-header {
+  background: none !important;
+  border: none !important; }
+
+body.login img.logo {
+  width: 250px;
+  display: block;
+  margin: 20px auto;
+  padding-top: 20px; }
+
+.login {
+  background-image: url("bg.jpg");
+  background-size: cover;
+  background-position: center;
+  background-repeat: no-repeat; }
+
+.login #content-main {
+  float: none;
+  height: 330px;
+  margin: 100px auto 0;
+  width: 265px; }
+
+.login {
+  /*#forgot_pwd{
+    font-size: 11px;
+    font-style: normal;
+    text-decoration: none;
+  }
+  
+  #create_acct{
+    font-size: 11px;
+    font-style: normal;
+    text-decoration: none;
+    padding-left: 45px;
+  }*/ }
+  .login #content-main {
+    background: rgba(255, 255, 255, 0.82); }
+  .login #content-main form input[type=text],
+  .login #content-main form input[type=password],
+  .login .requestDialog.ui-widget input {
+    background-color: #faffbd; }
+  .login .row + .row {
+    margin-top: 10px; }
+  .login #content-main form {
+    margin: 5px 15px 0; }
+  .login .btn-primary {
+    color: #fff;
+    background-color: #337ab7;
+    border-color: #2e6da4;
+    background: #337ab7; }
+    .login .btn-primary:focus, .login .btn-primary.focus {
+      color: #fff;
+      background-color: #286090;
+      border-color: #122b40; }
+    .login .btn-primary:hover {
+      color: #fff;
+      background-color: #286090;
+      border-color: #204d74; }
+    .login .btn-primary:active, .login .btn-primary.active,
+    .open > .login .btn-primary.dropdown-toggle {
+      color: #fff;
+      background-color: #286090;
+      border-color: #204d74; }
+      .login .btn-primary:active:hover, .login .btn-primary:active:focus, .login .btn-primary:active.focus, .login .btn-primary.active:hover, .login .btn-primary.active:focus, .login .btn-primary.active.focus,
+      .open > .login .btn-primary.dropdown-toggle:hover,
+      .open > .login .btn-primary.dropdown-toggle:focus,
+      .open > .login .btn-primary.dropdown-toggle.focus {
+        color: #fff;
+        background-color: #204d74;
+        border-color: #122b40; }
+    .login .btn-primary:active, .login .btn-primary.active,
+    .open > .login .btn-primary.dropdown-toggle {
+      background-image: none; }
+    .login .btn-primary.disabled:hover, .login .btn-primary.disabled:focus, .login .btn-primary.disabled.focus, .login .btn-primary[disabled]:hover, .login .btn-primary[disabled]:focus, .login .btn-primary[disabled].focus,
+    fieldset[disabled] .login .btn-primary:hover,
+    fieldset[disabled] .login .btn-primary:focus,
+    fieldset[disabled] .login .btn-primary.focus {
+      background-color: #337ab7;
+      border-color: #2e6da4; }
+    .login .btn-primary .badge {
+      color: #337ab7;
+      background-color: #fff; }
+  .login .forgotLink {
+    width: 45%;
+    text-align: left;
+    float: left; }
+  .login #request-account-form {
+    display: none; }
+  .login #requestAccountLink {
+    margin-top: 10px;
+    cursor: pointer;
+    color: #337ab7;
+    text-decoration: underline; }
+
+.breadcrumb li a {
+  font-weight: bold; }
+
+.form-control {
+  width: auto;
+  min-width: 100%; }
+
+body.logout img.logo {
+  width: 250px;
+  display: block;
+  margin: 20px auto;
+  padding-top: 20px; }
+
+h1.logouth1tag {
+  text-align: center; }
+
+.logout #content-main {
+  float: none;
+  width: 300px;
+  overflow-x: hidden; }
+
+.logout {
+  background: rgba(255, 255, 255, 0.82);
+  float: none;
+  height: 330px;
+  margin: 100px auto 0;
+  width: 316px;
+  overflow-x: hidden;
+  overflow-y: hidden;
+  padding: 10px 0px 0px 10px; }
+  .logout .requestDialog.ui-widget input {
+    background-color: #faffbd; }
+  .logout .row + .row {
+    margin-top: 10px; }
+  .logout .btn-primary {
+    color: #fff;
+    background-color: #337ab7;
+    border-color: #2e6da4;
+    background: #337ab7; }
+    .logout .btn-primary:focus, .logout .btn-primary.focus {
+      color: #fff;
+      background-color: #286090;
+      border-color: #122b40; }
+    .logout .btn-primary:hover {
+      color: #fff;
+      background-color: #286090;
+      border-color: #204d74; }
+    .logout .btn-primary:active, .logout .btn-primary.active,
+    .open > .logout .btn-primary.dropdown-toggle {
+      color: #fff;
+      background-color: #286090;
+      border-color: #204d74; }
+      .logout .btn-primary:active:hover, .logout .btn-primary:active:focus, .logout .btn-primary:active.focus, .logout .btn-primary.active:hover, .logout .btn-primary.active:focus, .logout .btn-primary.active.focus,
+      .open > .logout .btn-primary.dropdown-toggle:hover,
+      .open > .logout .btn-primary.dropdown-toggle:focus,
+      .open > .logout .btn-primary.dropdown-toggle.focus {
+        color: #fff;
+        background-color: #204d74;
+        border-color: #122b40; }
+    .logout .btn-primary:active, .logout .btn-primary.active,
+    .open > .logout .btn-primary.dropdown-toggle {
+      background-image: none; }
+    .logout .btn-primary.disabled:hover, .logout .btn-primary.disabled:focus, .logout .btn-primary.disabled.focus, .logout .btn-primary[disabled]:hover, .logout .btn-primary[disabled]:focus, .logout .btn-primary[disabled].focus,
+    fieldset[disabled] .logout .btn-primary:hover,
+    fieldset[disabled] .logout .btn-primary:focus,
+    fieldset[disabled] .logout .btn-primary.focus {
+      background-color: #337ab7;
+      border-color: #2e6da4; }
+    .logout .btn-primary .badge {
+      color: #337ab7;
+      background-color: #fff; }
+  .logout p.logoutptag {
+    margin: 20px 10px 20px;
+    font-size: 16px;
+    text-align: center; }
+
+/************************
+colors:
+    tab - active/focus color
+    background-color: #105E9E !important;
+
+ONLab darker blue select :: background-color: #004775;
+#0170BB
+    left-nav
+    background-color: #448CCA;
+    background-color // normal: #B4CADF
+91BFE4
+
+*************************/
+html, body, body.login {
+  height: 100%;
+  min-height: 100%;
+  margin: 0; }
+
+body {
+  max-width: 100%;
+  overflow-x: hidden; }
+
+#wrap {
+  height: 100%;
+  min-height: 100%;
+  padding-bottom: 60px; }
+
+/* ************************* SIDENAV TOGGLE ************************* */
+#wrapper {
+  padding-left: 0;
+  transition: all 0.5s ease;
+  min-height: 100%;
+  height: 100%; }
+
+#wrapper.toggled {
+  padding-left: 250px; }
+
+#sidebar-wrapper {
+  z-index: 99;
+  position: fixed;
+  left: 250px;
+  width: 0;
+  height: 100%;
+  margin-left: -250px;
+  overflow-y: auto;
+  transition: all 0.5s ease;
+  background: white; }
+
+#wrapper.toggled #sidebar-wrapper {
+  width: 250px;
+  padding: 10px; }
+
+#page-content-wrapper {
+  width: 100%;
+  position: absolute;
+  padding: 15px;
+  min-height: 100%;
+  height: 100%; }
+  #page-content-wrapper .container-fluid,
+  #page-content-wrapper .content-wrapper,
+  #page-content-wrapper .content-wrapper .col-lg-12,
+  #page-content-wrapper .suit-columns,
+  #page-content-wrapper #content {
+    min-height: 100%;
+    height: 100%; }
+  #page-content-wrapper #content {
+    padding-left: 15px;
+    padding-right: 15px; }
+  #page-content-wrapper #content-main {
+    padding-bottom: 60px; }
+
+.ui-tabs-panel {
+  min-height: 700px; }
+
+#wrapper.toggled #page-content-wrapper {
+  position: absolute;
+  margin-right: -250px; }
+
+@media (min-width: 768px) {
+  #wrapper {
+    padding-left: 250px; }
+  #wrapper.toggled {
+    padding-left: 0; }
+  #sidebar-wrapper {
+    width: 250px;
+    padding: 10px; }
+  #wrapper.toggled #sidebar-wrapper {
+    width: 0; }
+  #page-content-wrapper {
+    padding: 20px;
+    position: relative; }
+  #wrapper.toggled #page-content-wrapper {
+    position: relative;
+    margin-right: 0; } }
+
+.navbar-toggle {
+  border: 1px solid #08C; }
+
+.navbar-toggle .icon-bar {
+  background: #08C; }
+
+/* ************************* END SIDENAV TOGGLE ************************* */
+/************************* FORM TWEAKS *************************/
+@media (min-width: 992px) {
+  .form-column.col-lg-4 {
+    width: 66.66666667%; } }
+
+/************************* FORM TWEAKS *************************/
+/*   CSS for jquery Tabs */
+.alignCenter {
+  text-align: center !important;
+  align: center !important; }
+
+.ui-widget-overlay {
+  background: black !important; }
+
+.ui-corner-all {
+  border-bottom-left-radius: 0px !important;
+  border-bottom-right-radius: 0px !important; }
+
+#openCloudTopPage {
+  margin-top: -25px;
+  margin-right: -90;
+  float: right; }
+
+#minDashboard {
+  /*min-width:625px; */
+  display: inline;
+  float: right;
+  border: 2px darkGrey; }
+
+.save-box {
+  background-color: #ffffff;
+  margin: 2px; }
+
+.save-box .btn-info {
+  font-size: 14px;
+  padding: 10px 20px 10px 20px; }
+
+.required:after {
+  color: red !important;
+  font-size: 18px; }
+
+/*.btn-success {color:black}*/
+#suit-center {
+  padding: 20px;
+  width: 100%;
+  /*min-width:650px;*/ }
+
+.inner-two-columns .inner-center-column .tab-content {
+  overflow-x: auto;
+  margin-bottom: 15px;
+  /*min-width: auto;*/
+  width: 100%; }
+
+/*.inner-two-columns .inner-center-column {
+  margin-right: 200px;
+  background-color: rgb(158, 163, 159);
+}*/
+label {
+  display: block;
+  font-weight: bold;
+  margin-bottom: 5px; }
+
+/*For changing background color of suit center*/
+#suit-center {
+  background-color: #ffffff; }
+
+/** Leave room for scroll bar now that contents can be appropriately scrolled **/
+.form-horizontal .inline-group .add-row {
+  margin: -1px -1px 15px 0px; }
+
+/** Setting overflow and 1kpx to deal with inlines/forms overlapping on 
+    browser resizes **/
+#content-main {
+  overflow-x: auto;
+  /*min-width: 1000px;*/ }
+
+.tab-content tab-content-main {
+  overflow-x: auto !important; }
+
+#wrap {
+  background: none; }
+
+.noclearfix {
+  display: block;
+  clear: left;
+  width: 0px;
+  height: 0px; }
+
+body {
+  background-color: #ffffff; }
+
+.suit-column {
+  background-color: #ffffff; }
+
+.nav-tabs > .active > a, .nav-tabs > .active > a:hover, .nav-tabs > .active > a:focus {
+  /*background-color: #448CCA;*/
+  background-color: #105E9E;
+  color: #FFF;
+  border: none; }
+
+/*Added by Beena for adding the three components in dashboard*/
+.breadcrumb {
+  display: inline-block;
+  background-color: #fff; }
+
+.nodetextbox {
+  /*background-color: #ededed;*/
+  line-height: 25px;
+  width: 150px;
+  text-align: center;
+  font-weight: bold;
+  margin-left: 0px;
+  display: inline-block;
+  border: none;
+  font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
+  font-size: 8px; }
+
+.nodelabel {
+  width: 20px;
+  display: inline-block;
+  border-radius: 0px;
+  border: 1px solid #000;
+  /*line-height: 23px;*/
+  text-align: center;
+  font-weight: normal; }
+
+#user-tools {
+  font-weight: bold; }
+
+.header-content .header-column {
+  display: none; }
+
+.header .input-icon {
+  background-image: url("Search.png");
+  background-repeat: no-repeat;
+  background-position: left center;
+  opacity: 1;
+  background-size: 100%;
+  vertical-align: middle;
+  margin-right: -30px;
+  /*margin-top: 5px;*/
+  position: relative;
+  height: 22px;
+  width: 22px; }
+
+.header .icon-search {
+  /*background-image: url("search.png") !important;
+    background-repeat: no-repeat !important;
+    background-size: 120% auto !important;
+    background-position: 0;*/ }
+
+#dashboardHPC {
+  padding-bottom: 10px; }
+
+.summary-attr {
+  padding-right: 20px; }
+
+.summary-attr-util {
+  padding-right: 20px;
+  color: green; }
+
+.SiteDetail {
+  color: darkBlue;
+  font-size: 1.5em; }
+
+#addInstances {
+  color: green;
+  text-decoration: underline;
+  padding-right: 20px; }
+
+#remInstances {
+  color: red;
+  text-decoration: underline; }
+
+#map-us {
+  padding-top: 10px;
+  width: 700px;
+  height: 400px; }
+
+.minidashbutton {
+  -moz-box-shadow: inset 0px 1px 0px 0px #ffffff;
+  -webkit-box-shadow: inset 0px 1px 0px 0px #ffffff;
+  box-shadow: inset 0px 1px 0px 0px #ffffff;
+  background: -webkit-gradient(linear, left top, left bottom, color-stop(0.05, #ffffff), color-stop(1, #f6f6f6));
+  background: -moz-linear-gradient(top, #ffffff 5%, #f6f6f6 100%);
+  background: -webkit-linear-gradient(top, #ffffff 5%, #f6f6f6 100%);
+  background: -o-linear-gradient(top, #ffffff 5%, #f6f6f6 100%);
+  background: -ms-linear-gradient(top, #ffffff 5%, #f6f6f6 100%);
+  background: linear-gradient(to bottom, #ffffff 5%, #f6f6f6 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f6f6f6',GradientType=0);
+  background-color: #ffffff;
+  -moz-border-radius: 6px;
+  -webkit-border-radius: 6px;
+  border-radius: 6px;
+  border: 1px solid #dcdcdc;
+  display: inline-block;
+  cursor: pointer;
+  color: #666666;
+  font-family: arial;
+  font-size: 15px;
+  font-weight: bold;
+  padding: 6px 24px;
+  text-decoration: none;
+  text-shadow: 0px 1px 0px #ffffff; }
+
+.minidashbutton:hover {
+  background: -webkit-gradient(linear, left top, left bottom, color-stop(0.05, #f6f6f6), color-stop(1, #ffffff));
+  background: -moz-linear-gradient(top, #f6f6f6 5%, #ffffff 100%);
+  background: -webkit-linear-gradient(top, #f6f6f6 5%, #ffffff 100%);
+  background: -o-linear-gradient(top, #f6f6f6 5%, #ffffff 100%);
+  background: -ms-linear-gradient(top, #f6f6f6 5%, #ffffff 100%);
+  background: linear-gradient(to bottom, #f6f6f6 5%, #ffffff 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f6f6f6', endColorstr='#ffffff',GradientType=0);
+  background-color: #f6f6f6; }
+
+.newMiniDashboard {
+  border: 1px solid green;
+  width: auto; }
+
+.endDashPair {
+  clear: left; }
+
+.miniDashPair {
+  float: left;
+  width: auto;
+  margin-left: 20px; }
+
+.miniDashPair label {
+  text-align: center; }
+
+/* Charts CSS */
+p.numeral {
+  font-size: 32pt;
+  color: #ffffff;
+  opacity: 0.7;
+  font-family: Helvetica Neue;
+  font-weight: 100;
+  text-align: center;
+  line-height: 75%; }
+
+.helper-text {
+  border: 1px solid #fff;
+  padding: 7px;
+  border-radius: 18px;
+  font-size: 13pt;
+  color: #ffffff;
+  opacity: 0.7;
+  font-family: Helvetica Neue;
+  font-weight: 200;
+  text-align: center;
+  line-height: 100%; }
+
+p.osobject {
+  font-size: 12pt;
+  color: #ffffff;
+  opacity: 0.7;
+  font-family: Helvetica Neue;
+  font-weight: 200;
+  text-align: center;
+  line-height: 100%; }
+
+p.heading {
+  font-size: 20px;
+  letter-spacing: 1px;
+  color: black;
+  font-family: Arial;
+  font-weight: bold;
+  text-align: center; }
+
+/*p.heading
+{
+	font-size:32pt;
+	color:#ffffff;
+	opacity: 0.7;
+	font-family:Helvetica Neue;
+	font-weight:200;
+	text-align:center;
+}*/
+div.graph {
+  height: 340px; }
+
+div.numeral {
+  height: 120px; }
+
+div.heading {
+  height: 10px; }
+
+div.padding {
+  height: 20px; }
+
+div.chartContainer {
+  /*background-image:url('chartsBg.jpg');*/
+  width: 527px;
+  height: 400px;
+  border: 1px; }
+
+/* D3 */
+.axis path,
+.axis line {
+  fill: none;
+  stroke: #ffffff;
+  opacity: 0.7;
+  shape-rendering: crispEdges; }
+
+.x.axis path {
+  display: none; }
+
+.x.axis text {
+  fill: white;
+  opacity: 0.5; }
+
+.y.axis text {
+  opacity: 0.5;
+  fill: white; }
+
+.y.axis text.legend {
+  opacity: 1.0;
+  fill: white;
+  font-size: 8pt; }
+
+.line {
+  fill: none;
+  stroke: white;
+  stroke-width: 3px;
+  opacity: 0.6; }
+
+/******  Added in so that we can have a loader show as charts get ready to render ***/
+.loading {
+  background-image: url(spinner.gif) no-repeat center middle;
+  text-align: center;
+  font-size: 20px;
+  height: 100%;
+  /*    width: auto;*/
+  float: left;
+  padding: 10px; }
+
+/* Charts CSS */
+#tabs-4 {
+  margin: 40px;
+  font-size: 24px;
+  font-weight: bold; }
+
+.tenant-row {
+  padding-bottom: 0.7%; }
+
+/***********TENANT VIEW*************/
+#image-dropdown, #slice-image-value, #adv-slice-image-value {
+  margin-left: 5%; }
+
+#adv-slice-image-value {
+  margin-right: 0.5%; }
+
+#adv-network-value {
+  margin-right: 0.3%; }
+
+#network-dropdown, #adv-network-dropdown, #adv-network-value {
+  margin-left: 3.7%; }
+
+#service-level-dropdown, #service-level-value, #adv-service-level-dropdown, #adv-service-level-value {
+  margin-left: 0.2% !important; }
+
+#slice-name-value, #adv-slice-name-value {
+  margin-left: 2%; }
+
+#adv-dataset-dropdown {
+  margin-left: 3.7%; }
+
+#advanced-tenant, #basic-tenant, #instance-btn, #save-btn {
+  float: right; }
+
+#delete-slice-btn, #download-details, #add-user-btn {
+  margin-left: 1%; }
+
+#instance-btn, #save-btn, #create-slice-btn, #delete-slice-btn, #add-user-btn, #download-details {
+  margin-top: 1%; }
+
+.tenantDialog.ui-widget input {
+  border-radius: 0px !important;
+  height: 12px !important;
+  width: 180px !important;
+  margin-right: 10% !important;
+  float: right; }
+
+.tenantDialog .ui-dialog-buttonset .ui-button {
+  border-radius: 0 !important;
+  background-color: grey !important;
+  font-weight: bold !important;
+  font-size: 0.9em !important; }
+
+.tenantDialog .ui-dialog-titlebar {
+  border-radius: 0 !important;
+  background-color: grey !important; }
+
+.create-slice-row {
+  margin-bottom: 4%;
+  clear: both;
+  height: 25px; }
+
+.create-slice-row label, .tenantDialog label {
+  margin-right: 1%;
+  float: left; }
+
+.create-slice-row select {
+  height: 24px;
+  width: 196px;
+  font-size: 0.9em !important; }
+
+.tenant-create-slice {
+  float: right;
+  margin-right: 10% !important; }
+
+#delete-slice {
+  float: right; }
+
+#tooltip, #adv-tooltip, #basic-tooltip {
+  font-size: 0.7em;
+  color: red;
+  display: none; }
+
+#tenantSliceDataWrapper {
+  padding: 1% 0; }
+
+#advancedTenantSliceDataWrapper .help-inline {
+  font-size: 11px;
+  color: #999;
+  padding-bottom: 1%; }
+
+.create-slice-row label {
+  clear: both;
+  margin-right: 1%; }
+
+#advNumOfInstances {
+  margin-right: 1% !important; }
+
+#private-vol-checkbox {
+  margin: 0 0 1% 1%; }
+
+.public-key-warning {
+  text-align: center;
+  display: none; }
+
+#private-vol {
+  margin-right: 15% !important; }
+
+.customize_row {
+  display: table; }
+
+.customize_column {
+  display: table-cell;
+  padding: 10px; }
+
+.request-form-row {
+  padding: 1% 8%; }
+
+.requestDialog {
+  background-color: white;
+  border-radius: 8px;
+  width: 30% !important;
+  height: 40% !important;
+  margin-top: -16%;
+  top: -103.703125px !important; }
+
+.request-form-row label {
+  float: left; }
+
+.requestDialog .ui-dialog-buttonset .ui-button {
+  border-radius: 0 !important;
+  background-color: grey !important;
+  font-weight: bold !important;
+  font-size: 0.9em !important; }
+
+.requestDialog .ui-dialog-titlebar-close {
+  float: right; }
+
+#request-signup {
+  height: 40px !important;
+  margin: 0 14%;
+  float: left;
+  background-color: #448CCA;
+  background-image: none;
+  width: 70% !important; }
+
+.requestDialog .ui-dialog-titlebar {
+  border-radius: 0 !important;
+  height: 25px;
+  padding-top: 2%; }
+
+.requestDialog #ui-id-1 {
+  padding-left: 28%;
+  font-size: medium; }
+
+#request-site-name {
+  width: 98%; }
+
+/* SUIT CHANGES */
+.form-buttons {
+  margin-top: 20px;
+  padding: 10px;
+  border-top: 1px solid #cccccc; }
+
+.form-horizontal .selector .selector-chooser li .selector-remove,
+.form-horizontal .selector .selector-chooser li .selector-remove:hover {
+  padding: 6px 12px;
+  font-size: 14px;
+  line-height: 1.42857;
+  border-radius: 4px;
+  color: #fff;
+  background-color: #d9534f;
+  border-color: #d43f3a; }
+  .form-horizontal .selector .selector-chooser li .selector-remove:focus, .form-horizontal .selector .selector-chooser li .selector-remove.focus,
+  .form-horizontal .selector .selector-chooser li .selector-remove:hover:focus,
+  .form-horizontal .selector .selector-chooser li .selector-remove:hover.focus {
+    color: #fff;
+    background-color: #c9302c;
+    border-color: #761c19; }
+  .form-horizontal .selector .selector-chooser li .selector-remove:hover,
+  .form-horizontal .selector .selector-chooser li .selector-remove:hover:hover {
+    color: #fff;
+    background-color: #c9302c;
+    border-color: #ac2925; }
+  .form-horizontal .selector .selector-chooser li .selector-remove:active, .form-horizontal .selector .selector-chooser li .selector-remove.active,
+  .open > .form-horizontal .selector .selector-chooser li .selector-remove.dropdown-toggle,
+  .form-horizontal .selector .selector-chooser li .selector-remove:hover:active,
+  .form-horizontal .selector .selector-chooser li .selector-remove:hover.active,
+  .open >
+  .form-horizontal .selector .selector-chooser li .selector-remove:hover.dropdown-toggle {
+    color: #fff;
+    background-color: #c9302c;
+    border-color: #ac2925; }
+    .form-horizontal .selector .selector-chooser li .selector-remove:active:hover, .form-horizontal .selector .selector-chooser li .selector-remove:active:focus, .form-horizontal .selector .selector-chooser li .selector-remove:active.focus, .form-horizontal .selector .selector-chooser li .selector-remove.active:hover, .form-horizontal .selector .selector-chooser li .selector-remove.active:focus, .form-horizontal .selector .selector-chooser li .selector-remove.active.focus,
+    .open > .form-horizontal .selector .selector-chooser li .selector-remove.dropdown-toggle:hover,
+    .open > .form-horizontal .selector .selector-chooser li .selector-remove.dropdown-toggle:focus,
+    .open > .form-horizontal .selector .selector-chooser li .selector-remove.dropdown-toggle.focus,
+    .form-horizontal .selector .selector-chooser li .selector-remove:hover:active:hover,
+    .form-horizontal .selector .selector-chooser li .selector-remove:hover:active:focus,
+    .form-horizontal .selector .selector-chooser li .selector-remove:hover:active.focus,
+    .form-horizontal .selector .selector-chooser li .selector-remove:hover.active:hover,
+    .form-horizontal .selector .selector-chooser li .selector-remove:hover.active:focus,
+    .form-horizontal .selector .selector-chooser li .selector-remove:hover.active.focus,
+    .open >
+    .form-horizontal .selector .selector-chooser li .selector-remove:hover.dropdown-toggle:hover,
+    .open >
+    .form-horizontal .selector .selector-chooser li .selector-remove:hover.dropdown-toggle:focus,
+    .open >
+    .form-horizontal .selector .selector-chooser li .selector-remove:hover.dropdown-toggle.focus {
+      color: #fff;
+      background-color: #ac2925;
+      border-color: #761c19; }
+  .form-horizontal .selector .selector-chooser li .selector-remove:active, .form-horizontal .selector .selector-chooser li .selector-remove.active,
+  .open > .form-horizontal .selector .selector-chooser li .selector-remove.dropdown-toggle,
+  .form-horizontal .selector .selector-chooser li .selector-remove:hover:active,
+  .form-horizontal .selector .selector-chooser li .selector-remove:hover.active,
+  .open >
+  .form-horizontal .selector .selector-chooser li .selector-remove:hover.dropdown-toggle {
+    background-image: none; }
+  .form-horizontal .selector .selector-chooser li .selector-remove.disabled:hover, .form-horizontal .selector .selector-chooser li .selector-remove.disabled:focus, .form-horizontal .selector .selector-chooser li .selector-remove.disabled.focus, .form-horizontal .selector .selector-chooser li .selector-remove[disabled]:hover, .form-horizontal .selector .selector-chooser li .selector-remove[disabled]:focus, .form-horizontal .selector .selector-chooser li .selector-remove[disabled].focus,
+  fieldset[disabled] .form-horizontal .selector .selector-chooser li .selector-remove:hover,
+  fieldset[disabled] .form-horizontal .selector .selector-chooser li .selector-remove:focus,
+  fieldset[disabled] .form-horizontal .selector .selector-chooser li .selector-remove.focus,
+  .form-horizontal .selector .selector-chooser li .selector-remove:hover.disabled:hover,
+  .form-horizontal .selector .selector-chooser li .selector-remove:hover.disabled:focus,
+  .form-horizontal .selector .selector-chooser li .selector-remove:hover.disabled.focus,
+  .form-horizontal .selector .selector-chooser li .selector-remove:hover[disabled]:hover,
+  .form-horizontal .selector .selector-chooser li .selector-remove:hover[disabled]:focus,
+  .form-horizontal .selector .selector-chooser li .selector-remove:hover[disabled].focus,
+  fieldset[disabled]
+  .form-horizontal .selector .selector-chooser li .selector-remove:hover:hover,
+  fieldset[disabled]
+  .form-horizontal .selector .selector-chooser li .selector-remove:hover:focus,
+  fieldset[disabled]
+  .form-horizontal .selector .selector-chooser li .selector-remove:hover.focus {
+    background-color: #d9534f;
+    border-color: #d43f3a; }
+  .form-horizontal .selector .selector-chooser li .selector-remove .badge,
+  .form-horizontal .selector .selector-chooser li .selector-remove:hover .badge {
+    color: #d9534f;
+    background-color: #fff; }
+
+.form-horizontal .selector .selector-chooser li .selector-add,
+.form-horizontal .selector .selector-chooser li .selector-add:hover {
+  margin-bottom: 15px;
+  padding: 6px 12px;
+  font-size: 14px;
+  line-height: 1.42857;
+  border-radius: 4px;
+  color: #fff;
+  background-color: #5cb85c;
+  border-color: #4cae4c; }
+  .form-horizontal .selector .selector-chooser li .selector-add:focus, .form-horizontal .selector .selector-chooser li .selector-add.focus,
+  .form-horizontal .selector .selector-chooser li .selector-add:hover:focus,
+  .form-horizontal .selector .selector-chooser li .selector-add:hover.focus {
+    color: #fff;
+    background-color: #449d44;
+    border-color: #255625; }
+  .form-horizontal .selector .selector-chooser li .selector-add:hover,
+  .form-horizontal .selector .selector-chooser li .selector-add:hover:hover {
+    color: #fff;
+    background-color: #449d44;
+    border-color: #398439; }
+  .form-horizontal .selector .selector-chooser li .selector-add:active, .form-horizontal .selector .selector-chooser li .selector-add.active,
+  .open > .form-horizontal .selector .selector-chooser li .selector-add.dropdown-toggle,
+  .form-horizontal .selector .selector-chooser li .selector-add:hover:active,
+  .form-horizontal .selector .selector-chooser li .selector-add:hover.active,
+  .open >
+  .form-horizontal .selector .selector-chooser li .selector-add:hover.dropdown-toggle {
+    color: #fff;
+    background-color: #449d44;
+    border-color: #398439; }
+    .form-horizontal .selector .selector-chooser li .selector-add:active:hover, .form-horizontal .selector .selector-chooser li .selector-add:active:focus, .form-horizontal .selector .selector-chooser li .selector-add:active.focus, .form-horizontal .selector .selector-chooser li .selector-add.active:hover, .form-horizontal .selector .selector-chooser li .selector-add.active:focus, .form-horizontal .selector .selector-chooser li .selector-add.active.focus,
+    .open > .form-horizontal .selector .selector-chooser li .selector-add.dropdown-toggle:hover,
+    .open > .form-horizontal .selector .selector-chooser li .selector-add.dropdown-toggle:focus,
+    .open > .form-horizontal .selector .selector-chooser li .selector-add.dropdown-toggle.focus,
+    .form-horizontal .selector .selector-chooser li .selector-add:hover:active:hover,
+    .form-horizontal .selector .selector-chooser li .selector-add:hover:active:focus,
+    .form-horizontal .selector .selector-chooser li .selector-add:hover:active.focus,
+    .form-horizontal .selector .selector-chooser li .selector-add:hover.active:hover,
+    .form-horizontal .selector .selector-chooser li .selector-add:hover.active:focus,
+    .form-horizontal .selector .selector-chooser li .selector-add:hover.active.focus,
+    .open >
+    .form-horizontal .selector .selector-chooser li .selector-add:hover.dropdown-toggle:hover,
+    .open >
+    .form-horizontal .selector .selector-chooser li .selector-add:hover.dropdown-toggle:focus,
+    .open >
+    .form-horizontal .selector .selector-chooser li .selector-add:hover.dropdown-toggle.focus {
+      color: #fff;
+      background-color: #398439;
+      border-color: #255625; }
+  .form-horizontal .selector .selector-chooser li .selector-add:active, .form-horizontal .selector .selector-chooser li .selector-add.active,
+  .open > .form-horizontal .selector .selector-chooser li .selector-add.dropdown-toggle,
+  .form-horizontal .selector .selector-chooser li .selector-add:hover:active,
+  .form-horizontal .selector .selector-chooser li .selector-add:hover.active,
+  .open >
+  .form-horizontal .selector .selector-chooser li .selector-add:hover.dropdown-toggle {
+    background-image: none; }
+  .form-horizontal .selector .selector-chooser li .selector-add.disabled:hover, .form-horizontal .selector .selector-chooser li .selector-add.disabled:focus, .form-horizontal .selector .selector-chooser li .selector-add.disabled.focus, .form-horizontal .selector .selector-chooser li .selector-add[disabled]:hover, .form-horizontal .selector .selector-chooser li .selector-add[disabled]:focus, .form-horizontal .selector .selector-chooser li .selector-add[disabled].focus,
+  fieldset[disabled] .form-horizontal .selector .selector-chooser li .selector-add:hover,
+  fieldset[disabled] .form-horizontal .selector .selector-chooser li .selector-add:focus,
+  fieldset[disabled] .form-horizontal .selector .selector-chooser li .selector-add.focus,
+  .form-horizontal .selector .selector-chooser li .selector-add:hover.disabled:hover,
+  .form-horizontal .selector .selector-chooser li .selector-add:hover.disabled:focus,
+  .form-horizontal .selector .selector-chooser li .selector-add:hover.disabled.focus,
+  .form-horizontal .selector .selector-chooser li .selector-add:hover[disabled]:hover,
+  .form-horizontal .selector .selector-chooser li .selector-add:hover[disabled]:focus,
+  .form-horizontal .selector .selector-chooser li .selector-add:hover[disabled].focus,
+  fieldset[disabled]
+  .form-horizontal .selector .selector-chooser li .selector-add:hover:hover,
+  fieldset[disabled]
+  .form-horizontal .selector .selector-chooser li .selector-add:hover:focus,
+  fieldset[disabled]
+  .form-horizontal .selector .selector-chooser li .selector-add:hover.focus {
+    background-color: #5cb85c;
+    border-color: #4cae4c; }
+  .form-horizontal .selector .selector-chooser li .selector-add .badge,
+  .form-horizontal .selector .selector-chooser li .selector-add:hover .badge {
+    color: #5cb85c;
+    background-color: #fff; }
+
+/* MODAL */
+.ui-dialog {
+  z-index: 4000 !important; }
+
+button.ui-dialog-titlebar-close {
+  font-family: 'Glyphicons Halflings' !important;
+  display: inline-block; }
+
+button.ui-dialog-titlebar-close:after {
+    content: "\e014";
+}
+/* M-CORD SERVICE GRID */
+.m-cord .kind-container h2{
+  background-color: #9c0001;
+  padding: 10px;
+  color: #fff;
+  border-radius: 4px;
+  cursor: pointer;
+  box-shadow: 1px 2px 2px black;
+}
+
+.m-cord .kind-container img.img-responsive {
+  display: inline-block;
+}
+
+.m-cord .kind-container .service-container{
+  height: 0px;
+  overflow: hidden;
+  opacity: 0;
+  transition: all .5s ease-in-out;
+}
+
+.m-cord .kind-container.active .service-container{
+  height: 162px;
+  opacity: 1;
+}
+  /*content: "\e014"; }*/
+
+/* VCPe ADMIN FIX
+form#vcpeservice_form ul li {
+    display: inline-block;
+    background: red;
+    margin-top: 10px;
+    width: auto;
+    padding: 10px;
+    border-radius: 5px;
+}
+*/
\ No newline at end of file
diff --git a/xos/core/static/xosNgLib.css b/xos/core/static/xosNgLib.css
new file mode 100644
index 0000000..91a1574
--- /dev/null
+++ b/xos/core/static/xosNgLib.css
@@ -0,0 +1,248 @@
+@keyframes slideInRight {
+  from {
+    transform: translate3d(100%, 0, 0);
+    visibility: visible; }
+  to {
+    transform: translate3d(0, 0, 0); } }
+
+@keyframes slideOutRight {
+  from {
+    transform: translate3d(0, 0, 0); }
+  to {
+    visibility: hidden;
+    transform: translate3d(100%, 0, 0); } }
+
+@keyframes fadeInUp {
+  from {
+    opacity: 0;
+    transform: translate3d(0, 100%, 0); }
+  to {
+    opacity: 1;
+    transform: none; } }
+
+@keyframes fadeOutDown {
+  from {
+    opacity: 1; }
+  to {
+    opacity: 0;
+    transform: translate3d(0, 100%, 0); } }
+
+.loader {
+  font-size: 10px;
+  margin: 0 auto;
+  text-indent: -9999em;
+  width: 11em;
+  height: 11em;
+  border-radius: 50%;
+  background: #ffffff;
+  background: -moz-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
+  background: -webkit-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
+  background: -o-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
+  background: -ms-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
+  background: linear-gradient(to right, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
+  position: relative;
+  animation: loaderSpinner 1.4s infinite linear;
+  transform: translateZ(0); }
+
+.loader:before {
+  width: 50%;
+  height: 50%;
+  background: #337ab7;
+  border-radius: 100% 0 0 0;
+  position: absolute;
+  top: 0;
+  left: 0;
+  content: ''; }
+
+.loader:after {
+  background: #fff;
+  width: 75%;
+  height: 75%;
+  border-radius: 50%;
+  content: '';
+  margin: auto;
+  position: absolute;
+  top: 0;
+  left: 0;
+  bottom: 0;
+  right: 0; }
+
+@keyframes loaderSpinner {
+  0% {
+    -webkit-transform: rotate(0deg);
+    transform: rotate(0deg); }
+  100% {
+    -webkit-transform: rotate(360deg);
+    transform: rotate(360deg); } }
+
+@keyframes slideInRight {
+  from {
+    transform: translate3d(100%, 0, 0);
+    visibility: visible; }
+  to {
+    transform: translate3d(0, 0, 0); } }
+
+@keyframes slideOutRight {
+  from {
+    transform: translate3d(0, 0, 0); }
+  to {
+    visibility: hidden;
+    transform: translate3d(100%, 0, 0); } }
+
+@keyframes fadeInUp {
+  from {
+    opacity: 0;
+    transform: translate3d(0, 100%, 0); }
+  to {
+    opacity: 1;
+    transform: none; } }
+
+@keyframes fadeOutDown {
+  from {
+    opacity: 1; }
+  to {
+    opacity: 0;
+    transform: translate3d(0, 100%, 0); } }
+
+xos-table {
+  display: block; }
+  xos-table tr.ng-move,
+  xos-table tr.ng-enter,
+  xos-table tr.ng-leave {
+    transition: all linear 0.5s; }
+  xos-table tr.ng-leave.ng-leave-active,
+  xos-table tr.ng-move,
+  xos-table tr.ng-enter {
+    opacity: 0;
+    animation: 0.5s slideOutRight ease-in-out; }
+  xos-table tr.ng-leave,
+  xos-table tr.ng-move.ng-move-active,
+  xos-table tr.ng-enter.ng-enter-active {
+    opacity: 1;
+    animation: 0.5s slideInRight ease-in-out; }
+  xos-table td dl {
+    margin-bottom: 0; }
+    xos-table td dl dt {
+      width: auto !important;
+      margin-right: 10px; }
+    xos-table td dl dt:after {
+      /*display: block;*/
+      content: ':'; }
+    xos-table td dl dd {
+      margin-left: 0 !important; }
+
+@keyframes slideInRight {
+  from {
+    transform: translate3d(100%, 0, 0);
+    visibility: visible; }
+  to {
+    transform: translate3d(0, 0, 0); } }
+
+@keyframes slideOutRight {
+  from {
+    transform: translate3d(0, 0, 0); }
+  to {
+    visibility: hidden;
+    transform: translate3d(100%, 0, 0); } }
+
+@keyframes fadeInUp {
+  from {
+    opacity: 0;
+    transform: translate3d(0, 100%, 0); }
+  to {
+    opacity: 1;
+    transform: none; } }
+
+@keyframes fadeOutDown {
+  from {
+    opacity: 1; }
+  to {
+    opacity: 0;
+    transform: translate3d(0, 100%, 0); } }
+
+xos-alert {
+  margin-top: 15px;
+  display: block;
+  /* when hiding */
+  /* when showing */ }
+  xos-alert .ng-hide-add {
+    animation: 0.5s fadeOutDown ease-in-out; }
+  xos-alert .ng-hide-remove {
+    animation: 0.5s fadeInUp ease-in-out; }
+
+@keyframes slideInRight {
+  from {
+    transform: translate3d(100%, 0, 0);
+    visibility: visible; }
+  to {
+    transform: translate3d(0, 0, 0); } }
+
+@keyframes slideOutRight {
+  from {
+    transform: translate3d(0, 0, 0); }
+  to {
+    visibility: hidden;
+    transform: translate3d(100%, 0, 0); } }
+
+@keyframes fadeInUp {
+  from {
+    opacity: 0;
+    transform: translate3d(0, 100%, 0); }
+  to {
+    opacity: 1;
+    transform: none; } }
+
+@keyframes fadeOutDown {
+  from {
+    opacity: 1; }
+  to {
+    opacity: 0;
+    transform: translate3d(0, 100%, 0); } }
+
+input + xos-validation {
+  margin-top: 15px;
+  display: block; }
+
+xos-field {
+  display: block; }
+
+@keyframes slideInRight {
+  from {
+    transform: translate3d(100%, 0, 0);
+    visibility: visible; }
+  to {
+    transform: translate3d(0, 0, 0); } }
+
+@keyframes slideOutRight {
+  from {
+    transform: translate3d(0, 0, 0); }
+  to {
+    visibility: hidden;
+    transform: translate3d(100%, 0, 0); } }
+
+@keyframes fadeInUp {
+  from {
+    opacity: 0;
+    transform: translate3d(0, 100%, 0); }
+  to {
+    opacity: 1;
+    transform: none; } }
+
+@keyframes fadeOutDown {
+  from {
+    opacity: 1; }
+  to {
+    opacity: 0;
+    transform: translate3d(0, 100%, 0); } }
+
+xos-form button {
+  margin-bottom: 15px; }
+
+[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
+  display: none !important; }
+
+.row + .row {
+  /* TODO move in xos.scss*/
+  margin-top: 15px; }
+
+/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoieG9zTmdMaWIuY3NzIiwic291cmNlcyI6WyJtYWluLnNjc3MiLCJhbmltYXRpb25zLnNjc3MiLCIuLi8uLi8uLi8uLi9zdHlsZS9zYXNzL2Jvb3RzdHJhcC9ib290c3RyYXAvX3ZhcmlhYmxlcy5zY3NzIiwibG9hZGVyLnNjc3MiLCIuLi91aV9jb21wb25lbnRzL2R1bWJDb21wb25lbnRzL3RhYmxlL3RhYmxlLnNjc3MiLCIuLi91aV9jb21wb25lbnRzL2R1bWJDb21wb25lbnRzL2FsZXJ0L2FsZXJ0LnNjc3MiLCIuLi91aV9jb21wb25lbnRzL2R1bWJDb21wb25lbnRzL3ZhbGlkYXRpb24vdmFsaWRhdGlvbi5zY3NzIiwiLi4vdWlfY29tcG9uZW50cy9kdW1iQ29tcG9uZW50cy9maWVsZC9maWVsZC5zY3NzIiwiLi4vdWlfY29tcG9uZW50cy9kdW1iQ29tcG9uZW50cy9mb3JtL2Zvcm0uc2NzcyIsIi4uL3VpX2NvbXBvbmVudHMvc21hcnRDb21wb25lbnRzL3NtYXJ0VGFibGUvc21hcnRUYWJsZS5zY3NzIl0sInNvdXJjZXNDb250ZW50IjpbIkBpbXBvcnQgJy4vYW5pbWF0aW9ucy5zY3NzJztcbkBpbXBvcnQgJy4uLy4uLy4uLy4uLy4uL3ZpZXdzL3N0eWxlL3Nhc3MvYm9vdHN0cmFwL2Jvb3RzdHJhcC9fdmFyaWFibGVzLnNjc3MnO1xuQGltcG9ydCAnLi9sb2FkZXIuc2Nzcyc7XG5cbkBpbXBvcnQgJy4uL3VpX2NvbXBvbmVudHMvZHVtYkNvbXBvbmVudHMvdGFibGUvdGFibGUuc2Nzcyc7XG5AaW1wb3J0ICcuLi91aV9jb21wb25lbnRzL2R1bWJDb21wb25lbnRzL2FsZXJ0L2FsZXJ0LnNjc3MnO1xuQGltcG9ydCAnLi4vdWlfY29tcG9uZW50cy9kdW1iQ29tcG9uZW50cy92YWxpZGF0aW9uL3ZhbGlkYXRpb24uc2Nzcyc7XG5AaW1wb3J0ICcuLi91aV9jb21wb25lbnRzL2R1bWJDb21wb25lbnRzL2ZpZWxkL2ZpZWxkLnNjc3MnO1xuQGltcG9ydCAnLi4vdWlfY29tcG9uZW50cy9kdW1iQ29tcG9uZW50cy9mb3JtL2Zvcm0uc2Nzcyc7XG5cbkBpbXBvcnQgJy4uL3VpX2NvbXBvbmVudHMvc21hcnRDb21wb25lbnRzL3NtYXJ0VGFibGUvc21hcnRUYWJsZS5zY3NzJztcblxuW25nXFw6Y2xvYWtdLCBbbmctY2xvYWtdLCBbZGF0YS1uZy1jbG9ha10sIFt4LW5nLWNsb2FrXSwgLm5nLWNsb2FrLCAueC1uZy1jbG9hayB7XG4gIGRpc3BsYXk6IG5vbmUgIWltcG9ydGFudDtcbn1cblxuLnJvdyArIC5yb3cge1xuICAvKiBUT0RPIG1vdmUgaW4geG9zLnNjc3MqLyBcbiAgbWFyZ2luLXRvcDogJGZvcm0tZ3JvdXAtbWFyZ2luLWJvdHRvbTtcbn0iLCJAa2V5ZnJhbWVzIHNsaWRlSW5SaWdodCB7XG4gIGZyb20ge1xuICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlM2QoMTAwJSwgMCwgMCk7XG4gICAgdmlzaWJpbGl0eTogdmlzaWJsZTtcbiAgfVxuXG4gIHRvIHtcbiAgICB0cmFuc2Zvcm06IHRyYW5zbGF0ZTNkKDAsIDAsIDApO1xuICB9XG59XG5cbkBrZXlmcmFtZXMgc2xpZGVPdXRSaWdodCB7XG4gIGZyb20ge1xuICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlM2QoMCwgMCwgMCk7XG4gIH1cblxuICB0byB7XG4gICAgdmlzaWJpbGl0eTogaGlkZGVuO1xuICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlM2QoMTAwJSwgMCwgMCk7XG4gIH1cbn1cblxuQGtleWZyYW1lcyBmYWRlSW5VcCB7XG4gIGZyb20ge1xuICAgIG9wYWNpdHk6IDA7XG4gICAgdHJhbnNmb3JtOiB0cmFuc2xhdGUzZCgwLCAxMDAlLCAwKTtcbiAgfVxuXG4gIHRvIHtcbiAgICBvcGFjaXR5OiAxO1xuICAgIHRyYW5zZm9ybTogbm9uZTtcbiAgfVxufVxuXG5Aa2V5ZnJhbWVzIGZhZGVPdXREb3duIHtcbiAgZnJvbSB7XG4gICAgb3BhY2l0eTogMTtcbiAgfVxuXG4gIHRvIHtcbiAgICBvcGFjaXR5OiAwO1xuICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlM2QoMCwgMTAwJSwgMCk7XG4gIH1cbn0iLCIkYm9vdHN0cmFwLXNhc3MtYXNzZXQtaGVscGVyOiBmYWxzZSAhZGVmYXVsdDtcbi8vXG4vLyBWYXJpYWJsZXNcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblxuLy89PSBDb2xvcnNcbi8vXG4vLyMjIEdyYXkgYW5kIGJyYW5kIGNvbG9ycyBmb3IgdXNlIGFjcm9zcyBCb290c3RyYXAuXG5cbiRncmF5LWJhc2U6ICAgICAgICAgICAgICAjMDAwICFkZWZhdWx0O1xuJGdyYXktZGFya2VyOiAgICAgICAgICAgIGxpZ2h0ZW4oJGdyYXktYmFzZSwgMTMuNSUpICFkZWZhdWx0OyAvLyAjMjIyXG4kZ3JheS1kYXJrOiAgICAgICAgICAgICAgbGlnaHRlbigkZ3JheS1iYXNlLCAyMCUpICFkZWZhdWx0OyAgIC8vICMzMzNcbiRncmF5OiAgICAgICAgICAgICAgICAgICBsaWdodGVuKCRncmF5LWJhc2UsIDMzLjUlKSAhZGVmYXVsdDsgLy8gIzU1NVxuJGdyYXktbGlnaHQ6ICAgICAgICAgICAgIGxpZ2h0ZW4oJGdyYXktYmFzZSwgNDYuNyUpICFkZWZhdWx0OyAvLyAjNzc3XG4kZ3JheS1saWdodGVyOiAgICAgICAgICAgbGlnaHRlbigkZ3JheS1iYXNlLCA5My41JSkgIWRlZmF1bHQ7IC8vICNlZWVcblxuJGJyYW5kLXByaW1hcnk6ICAgICAgICAgZGFya2VuKCM0MjhiY2EsIDYuNSUpICFkZWZhdWx0OyAvLyAjMzM3YWI3XG4kYnJhbmQtc3VjY2VzczogICAgICAgICAjNWNiODVjICFkZWZhdWx0O1xuJGJyYW5kLWluZm86ICAgICAgICAgICAgIzViYzBkZSAhZGVmYXVsdDtcbiRicmFuZC13YXJuaW5nOiAgICAgICAgICNmMGFkNGUgIWRlZmF1bHQ7XG4kYnJhbmQtZGFuZ2VyOiAgICAgICAgICAjZDk1MzRmICFkZWZhdWx0O1xuXG5cbi8vPT0gU2NhZmZvbGRpbmdcbi8vXG4vLyMjIFNldHRpbmdzIGZvciBzb21lIG9mIHRoZSBtb3N0IGdsb2JhbCBzdHlsZXMuXG5cbi8vKiogQmFja2dyb3VuZCBjb2xvciBmb3IgYDxib2R5PmAuXG4kYm9keS1iZzogICAgICAgICAgICAgICAjZmZmICFkZWZhdWx0O1xuLy8qKiBHbG9iYWwgdGV4dCBjb2xvciBvbiBgPGJvZHk+YC5cbiR0ZXh0LWNvbG9yOiAgICAgICAgICAgICRncmF5LWRhcmsgIWRlZmF1bHQ7XG5cbi8vKiogR2xvYmFsIHRleHR1YWwgbGluayBjb2xvci5cbiRsaW5rLWNvbG9yOiAgICAgICAgICAgICRicmFuZC1wcmltYXJ5ICFkZWZhdWx0O1xuLy8qKiBMaW5rIGhvdmVyIGNvbG9yIHNldCB2aWEgYGRhcmtlbigpYCBmdW5jdGlvbi5cbiRsaW5rLWhvdmVyLWNvbG9yOiAgICAgIGRhcmtlbigkbGluay1jb2xvciwgMTUlKSAhZGVmYXVsdDtcbi8vKiogTGluayBob3ZlciBkZWNvcmF0aW9uLlxuJGxpbmstaG92ZXItZGVjb3JhdGlvbjogdW5kZXJsaW5lICFkZWZhdWx0O1xuXG5cbi8vPT0gVHlwb2dyYXBoeVxuLy9cbi8vIyMgRm9udCwgbGluZS1oZWlnaHQsIGFuZCBjb2xvciBmb3IgYm9keSB0ZXh0LCBoZWFkaW5ncywgYW5kIG1vcmUuXG5cbiRmb250LWZhbWlseS1zYW5zLXNlcmlmOiAgXCJIZWx2ZXRpY2EgTmV1ZVwiLCBIZWx2ZXRpY2EsIEFyaWFsLCBzYW5zLXNlcmlmICFkZWZhdWx0O1xuJGZvbnQtZmFtaWx5LXNlcmlmOiAgICAgICBHZW9yZ2lhLCBcIlRpbWVzIE5ldyBSb21hblwiLCBUaW1lcywgc2VyaWYgIWRlZmF1bHQ7XG4vLyoqIERlZmF1bHQgbW9ub3NwYWNlIGZvbnRzIGZvciBgPGNvZGU+YCwgYDxrYmQ+YCwgYW5kIGA8cHJlPmAuXG4kZm9udC1mYW1pbHktbW9ub3NwYWNlOiAgIE1lbmxvLCBNb25hY28sIENvbnNvbGFzLCBcIkNvdXJpZXIgTmV3XCIsIG1vbm9zcGFjZSAhZGVmYXVsdDtcbiRmb250LWZhbWlseS1iYXNlOiAgICAgICAgJGZvbnQtZmFtaWx5LXNhbnMtc2VyaWYgIWRlZmF1bHQ7XG5cbiRmb250LXNpemUtYmFzZTogICAgICAgICAgMTRweCAhZGVmYXVsdDtcbiRmb250LXNpemUtbGFyZ2U6ICAgICAgICAgY2VpbCgoJGZvbnQtc2l6ZS1iYXNlICogMS4yNSkpICFkZWZhdWx0OyAvLyB+MThweFxuJGZvbnQtc2l6ZS1zbWFsbDogICAgICAgICBjZWlsKCgkZm9udC1zaXplLWJhc2UgKiAwLjg1KSkgIWRlZmF1bHQ7IC8vIH4xMnB4XG5cbiRmb250LXNpemUtaDE6ICAgICAgICAgICAgZmxvb3IoKCRmb250LXNpemUtYmFzZSAqIDIuNikpICFkZWZhdWx0OyAvLyB+MzZweFxuJGZvbnQtc2l6ZS1oMjogICAgICAgICAgICBmbG9vcigoJGZvbnQtc2l6ZS1iYXNlICogMi4xNSkpICFkZWZhdWx0OyAvLyB+MzBweFxuJGZvbnQtc2l6ZS1oMzogICAgICAgICAgICBjZWlsKCgkZm9udC1zaXplLWJhc2UgKiAxLjcpKSAhZGVmYXVsdDsgLy8gfjI0cHhcbiRmb250LXNpemUtaDQ6ICAgICAgICAgICAgY2VpbCgoJGZvbnQtc2l6ZS1iYXNlICogMS4yNSkpICFkZWZhdWx0OyAvLyB+MThweFxuJGZvbnQtc2l6ZS1oNTogICAgICAgICAgICAkZm9udC1zaXplLWJhc2UgIWRlZmF1bHQ7XG4kZm9udC1zaXplLWg2OiAgICAgICAgICAgIGNlaWwoKCRmb250LXNpemUtYmFzZSAqIDAuODUpKSAhZGVmYXVsdDsgLy8gfjEycHhcblxuLy8qKiBVbml0LWxlc3MgYGxpbmUtaGVpZ2h0YCBmb3IgdXNlIGluIGNvbXBvbmVudHMgbGlrZSBidXR0b25zLlxuJGxpbmUtaGVpZ2h0LWJhc2U6ICAgICAgICAxLjQyODU3MTQyOSAhZGVmYXVsdDsgLy8gMjAvMTRcbi8vKiogQ29tcHV0ZWQgXCJsaW5lLWhlaWdodFwiIChgZm9udC1zaXplYCAqIGBsaW5lLWhlaWdodGApIGZvciB1c2Ugd2l0aCBgbWFyZ2luYCwgYHBhZGRpbmdgLCBldGMuXG4kbGluZS1oZWlnaHQtY29tcHV0ZWQ6ICAgIGZsb29yKCgkZm9udC1zaXplLWJhc2UgKiAkbGluZS1oZWlnaHQtYmFzZSkpICFkZWZhdWx0OyAvLyB+MjBweFxuXG4vLyoqIEJ5IGRlZmF1bHQsIHRoaXMgaW5oZXJpdHMgZnJvbSB0aGUgYDxib2R5PmAuXG4kaGVhZGluZ3MtZm9udC1mYW1pbHk6ICAgIGluaGVyaXQgIWRlZmF1bHQ7XG4kaGVhZGluZ3MtZm9udC13ZWlnaHQ6ICAgIDUwMCAhZGVmYXVsdDtcbiRoZWFkaW5ncy1saW5lLWhlaWdodDogICAgMS4xICFkZWZhdWx0O1xuJGhlYWRpbmdzLWNvbG9yOiAgICAgICAgICBpbmhlcml0ICFkZWZhdWx0O1xuXG5cbi8vPT0gSWNvbm9ncmFwaHlcbi8vXG4vLyMjIFNwZWNpZnkgY3VzdG9tIGxvY2F0aW9uIGFuZCBmaWxlbmFtZSBvZiB0aGUgaW5jbHVkZWQgR2x5cGhpY29ucyBpY29uIGZvbnQuIFVzZWZ1bCBmb3IgdGhvc2UgaW5jbHVkaW5nIEJvb3RzdHJhcCB2aWEgQm93ZXIuXG5cbi8vKiogTG9hZCBmb250cyBmcm9tIHRoaXMgZGlyZWN0b3J5LlxuXG4vLyBbY29udmVydGVyXSBJZiAkYm9vdHN0cmFwLXNhc3MtYXNzZXQtaGVscGVyIGlmIHVzZWQsIHByb3ZpZGUgcGF0aCByZWxhdGl2ZSB0byB0aGUgYXNzZXRzIGxvYWQgcGF0aC5cbi8vIFtjb252ZXJ0ZXJdIFRoaXMgaXMgYmVjYXVzZSBzb21lIGFzc2V0IGhlbHBlcnMsIHN1Y2ggYXMgU3Byb2NrZXRzLCBkbyBub3Qgd29yayB3aXRoIGZpbGUtcmVsYXRpdmUgcGF0aHMuXG4kaWNvbi1mb250LXBhdGg6IGlmKCRib290c3RyYXAtc2Fzcy1hc3NldC1oZWxwZXIsIFwiYm9vdHN0cmFwL1wiLCBcIi4uL2ZvbnRzL2Jvb3RzdHJhcC9cIikgIWRlZmF1bHQ7XG5cbi8vKiogRmlsZSBuYW1lIGZvciBhbGwgZm9udCBmaWxlcy5cbiRpY29uLWZvbnQtbmFtZTogICAgICAgICAgXCJnbHlwaGljb25zLWhhbGZsaW5ncy1yZWd1bGFyXCIgIWRlZmF1bHQ7XG4vLyoqIEVsZW1lbnQgSUQgd2l0aGluIFNWRyBpY29uIGZpbGUuXG4kaWNvbi1mb250LXN2Zy1pZDogICAgICAgIFwiZ2x5cGhpY29uc19oYWxmbGluZ3NyZWd1bGFyXCIgIWRlZmF1bHQ7XG5cblxuLy89PSBDb21wb25lbnRzXG4vL1xuLy8jIyBEZWZpbmUgY29tbW9uIHBhZGRpbmcgYW5kIGJvcmRlciByYWRpdXMgc2l6ZXMgYW5kIG1vcmUuIFZhbHVlcyBiYXNlZCBvbiAxNHB4IHRleHQgYW5kIDEuNDI4IGxpbmUtaGVpZ2h0ICh+MjBweCB0byBzdGFydCkuXG5cbiRwYWRkaW5nLWJhc2UtdmVydGljYWw6ICAgICA2cHggIWRlZmF1bHQ7XG4kcGFkZGluZy1iYXNlLWhvcml6b250YWw6ICAgMTJweCAhZGVmYXVsdDtcblxuJHBhZGRpbmctbGFyZ2UtdmVydGljYWw6ICAgIDEwcHggIWRlZmF1bHQ7XG4kcGFkZGluZy1sYXJnZS1ob3Jpem9udGFsOiAgMTZweCAhZGVmYXVsdDtcblxuJHBhZGRpbmctc21hbGwtdmVydGljYWw6ICAgIDVweCAhZGVmYXVsdDtcbiRwYWRkaW5nLXNtYWxsLWhvcml6b250YWw6ICAxMHB4ICFkZWZhdWx0O1xuXG4kcGFkZGluZy14cy12ZXJ0aWNhbDogICAgICAgMXB4ICFkZWZhdWx0O1xuJHBhZGRpbmcteHMtaG9yaXpvbnRhbDogICAgIDVweCAhZGVmYXVsdDtcblxuJGxpbmUtaGVpZ2h0LWxhcmdlOiAgICAgICAgIDEuMzMzMzMzMyAhZGVmYXVsdDsgLy8gZXh0cmEgZGVjaW1hbHMgZm9yIFdpbiA4LjEgQ2hyb21lXG4kbGluZS1oZWlnaHQtc21hbGw6ICAgICAgICAgMS41ICFkZWZhdWx0O1xuXG4kYm9yZGVyLXJhZGl1cy1iYXNlOiAgICAgICAgNHB4ICFkZWZhdWx0O1xuJGJvcmRlci1yYWRpdXMtbGFyZ2U6ICAgICAgIDZweCAhZGVmYXVsdDtcbiRib3JkZXItcmFkaXVzLXNtYWxsOiAgICAgICAzcHggIWRlZmF1bHQ7XG5cbi8vKiogR2xvYmFsIGNvbG9yIGZvciBhY3RpdmUgaXRlbXMgKGUuZy4sIG5hdnMgb3IgZHJvcGRvd25zKS5cbiRjb21wb25lbnQtYWN0aXZlLWNvbG9yOiAgICAjZmZmICFkZWZhdWx0O1xuLy8qKiBHbG9iYWwgYmFja2dyb3VuZCBjb2xvciBmb3IgYWN0aXZlIGl0ZW1zIChlLmcuLCBuYXZzIG9yIGRyb3Bkb3ducykuXG4kY29tcG9uZW50LWFjdGl2ZS1iZzogICAgICAgJGJyYW5kLXByaW1hcnkgIWRlZmF1bHQ7XG5cbi8vKiogV2lkdGggb2YgdGhlIGBib3JkZXJgIGZvciBnZW5lcmF0aW5nIGNhcmV0cyB0aGF0IGluZGljYXRvciBkcm9wZG93bnMuXG4kY2FyZXQtd2lkdGgtYmFzZTogICAgICAgICAgNHB4ICFkZWZhdWx0O1xuLy8qKiBDYXJldHMgaW5jcmVhc2Ugc2xpZ2h0bHkgaW4gc2l6ZSBmb3IgbGFyZ2VyIGNvbXBvbmVudHMuXG4kY2FyZXQtd2lkdGgtbGFyZ2U6ICAgICAgICAgNXB4ICFkZWZhdWx0O1xuXG5cbi8vPT0gVGFibGVzXG4vL1xuLy8jIyBDdXN0b21pemVzIHRoZSBgLnRhYmxlYCBjb21wb25lbnQgd2l0aCBiYXNpYyB2YWx1ZXMsIGVhY2ggdXNlZCBhY3Jvc3MgYWxsIHRhYmxlIHZhcmlhdGlvbnMuXG5cbi8vKiogUGFkZGluZyBmb3IgYDx0aD5gcyBhbmQgYDx0ZD5gcy5cbiR0YWJsZS1jZWxsLXBhZGRpbmc6ICAgICAgICAgICAgOHB4ICFkZWZhdWx0O1xuLy8qKiBQYWRkaW5nIGZvciBjZWxscyBpbiBgLnRhYmxlLWNvbmRlbnNlZGAuXG4kdGFibGUtY29uZGVuc2VkLWNlbGwtcGFkZGluZzogIDVweCAhZGVmYXVsdDtcblxuLy8qKiBEZWZhdWx0IGJhY2tncm91bmQgY29sb3IgdXNlZCBmb3IgYWxsIHRhYmxlcy5cbiR0YWJsZS1iZzogICAgICAgICAgICAgICAgICAgICAgdHJhbnNwYXJlbnQgIWRlZmF1bHQ7XG4vLyoqIEJhY2tncm91bmQgY29sb3IgdXNlZCBmb3IgYC50YWJsZS1zdHJpcGVkYC5cbiR0YWJsZS1iZy1hY2NlbnQ6ICAgICAgICAgICAgICAgI2Y5ZjlmOSAhZGVmYXVsdDtcbi8vKiogQmFja2dyb3VuZCBjb2xvciB1c2VkIGZvciBgLnRhYmxlLWhvdmVyYC5cbiR0YWJsZS1iZy1ob3ZlcjogICAgICAgICAgICAgICAgI2Y1ZjVmNSAhZGVmYXVsdDtcbiR0YWJsZS1iZy1hY3RpdmU6ICAgICAgICAgICAgICAgJHRhYmxlLWJnLWhvdmVyICFkZWZhdWx0O1xuXG4vLyoqIEJvcmRlciBjb2xvciBmb3IgdGFibGUgYW5kIGNlbGwgYm9yZGVycy5cbiR0YWJsZS1ib3JkZXItY29sb3I6ICAgICAgICAgICAgI2RkZCAhZGVmYXVsdDtcblxuXG4vLz09IEJ1dHRvbnNcbi8vXG4vLyMjIEZvciBlYWNoIG9mIEJvb3RzdHJhcCdzIGJ1dHRvbnMsIGRlZmluZSB0ZXh0LCBiYWNrZ3JvdW5kIGFuZCBib3JkZXIgY29sb3IuXG5cbiRidG4tZm9udC13ZWlnaHQ6ICAgICAgICAgICAgICAgIG5vcm1hbCAhZGVmYXVsdDtcblxuJGJ0bi1kZWZhdWx0LWNvbG9yOiAgICAgICAgICAgICAgIzMzMyAhZGVmYXVsdDtcbiRidG4tZGVmYXVsdC1iZzogICAgICAgICAgICAgICAgICNmZmYgIWRlZmF1bHQ7XG4kYnRuLWRlZmF1bHQtYm9yZGVyOiAgICAgICAgICAgICAjY2NjICFkZWZhdWx0O1xuXG4kYnRuLXByaW1hcnktY29sb3I6ICAgICAgICAgICAgICAjZmZmICFkZWZhdWx0O1xuJGJ0bi1wcmltYXJ5LWJnOiAgICAgICAgICAgICAgICAgJGJyYW5kLXByaW1hcnkgIWRlZmF1bHQ7XG4kYnRuLXByaW1hcnktYm9yZGVyOiAgICAgICAgICAgICBkYXJrZW4oJGJ0bi1wcmltYXJ5LWJnLCA1JSkgIWRlZmF1bHQ7XG5cbiRidG4tc3VjY2Vzcy1jb2xvcjogICAgICAgICAgICAgICNmZmYgIWRlZmF1bHQ7XG4kYnRuLXN1Y2Nlc3MtYmc6ICAgICAgICAgICAgICAgICAkYnJhbmQtc3VjY2VzcyAhZGVmYXVsdDtcbiRidG4tc3VjY2Vzcy1ib3JkZXI6ICAgICAgICAgICAgIGRhcmtlbigkYnRuLXN1Y2Nlc3MtYmcsIDUlKSAhZGVmYXVsdDtcblxuJGJ0bi1pbmZvLWNvbG9yOiAgICAgICAgICAgICAgICAgI2ZmZiAhZGVmYXVsdDtcbiRidG4taW5mby1iZzogICAgICAgICAgICAgICAgICAgICRicmFuZC1pbmZvICFkZWZhdWx0O1xuJGJ0bi1pbmZvLWJvcmRlcjogICAgICAgICAgICAgICAgZGFya2VuKCRidG4taW5mby1iZywgNSUpICFkZWZhdWx0O1xuXG4kYnRuLXdhcm5pbmctY29sb3I6ICAgICAgICAgICAgICAjZmZmICFkZWZhdWx0O1xuJGJ0bi13YXJuaW5nLWJnOiAgICAgICAgICAgICAgICAgJGJyYW5kLXdhcm5pbmcgIWRlZmF1bHQ7XG4kYnRuLXdhcm5pbmctYm9yZGVyOiAgICAgICAgICAgICBkYXJrZW4oJGJ0bi13YXJuaW5nLWJnLCA1JSkgIWRlZmF1bHQ7XG5cbiRidG4tZGFuZ2VyLWNvbG9yOiAgICAgICAgICAgICAgICNmZmYgIWRlZmF1bHQ7XG4kYnRuLWRhbmdlci1iZzogICAgICAgICAgICAgICAgICAkYnJhbmQtZGFuZ2VyICFkZWZhdWx0O1xuJGJ0bi1kYW5nZXItYm9yZGVyOiAgICAgICAgICAgICAgZGFya2VuKCRidG4tZGFuZ2VyLWJnLCA1JSkgIWRlZmF1bHQ7XG5cbiRidG4tbGluay1kaXNhYmxlZC1jb2xvcjogICAgICAgICRncmF5LWxpZ2h0ICFkZWZhdWx0O1xuXG4vLyBBbGxvd3MgZm9yIGN1c3RvbWl6aW5nIGJ1dHRvbiByYWRpdXMgaW5kZXBlbmRlbnRseSBmcm9tIGdsb2JhbCBib3JkZXIgcmFkaXVzXG4kYnRuLWJvcmRlci1yYWRpdXMtYmFzZTogICAgICAgICAkYm9yZGVyLXJhZGl1cy1iYXNlICFkZWZhdWx0O1xuJGJ0bi1ib3JkZXItcmFkaXVzLWxhcmdlOiAgICAgICAgJGJvcmRlci1yYWRpdXMtbGFyZ2UgIWRlZmF1bHQ7XG4kYnRuLWJvcmRlci1yYWRpdXMtc21hbGw6ICAgICAgICAkYm9yZGVyLXJhZGl1cy1zbWFsbCAhZGVmYXVsdDtcblxuXG4vLz09IEZvcm1zXG4vL1xuLy8jI1xuXG4vLyoqIGA8aW5wdXQ+YCBiYWNrZ3JvdW5kIGNvbG9yXG4kaW5wdXQtYmc6ICAgICAgICAgICAgICAgICAgICAgICAjZmZmICFkZWZhdWx0O1xuLy8qKiBgPGlucHV0IGRpc2FibGVkPmAgYmFja2dyb3VuZCBjb2xvclxuJGlucHV0LWJnLWRpc2FibGVkOiAgICAgICAgICAgICAgJGdyYXktbGlnaHRlciAhZGVmYXVsdDtcblxuLy8qKiBUZXh0IGNvbG9yIGZvciBgPGlucHV0PmBzXG4kaW5wdXQtY29sb3I6ICAgICAgICAgICAgICAgICAgICAkZ3JheSAhZGVmYXVsdDtcbi8vKiogYDxpbnB1dD5gIGJvcmRlciBjb2xvclxuJGlucHV0LWJvcmRlcjogICAgICAgICAgICAgICAgICAgI2NjYyAhZGVmYXVsdDtcblxuLy8gVE9ETzogUmVuYW1lIGAkaW5wdXQtYm9yZGVyLXJhZGl1c2AgdG8gYCRpbnB1dC1ib3JkZXItcmFkaXVzLWJhc2VgIGluIHY0XG4vLyoqIERlZmF1bHQgYC5mb3JtLWNvbnRyb2xgIGJvcmRlciByYWRpdXNcbi8vIFRoaXMgaGFzIG5vIGVmZmVjdCBvbiBgPHNlbGVjdD5gcyBpbiBzb21lIGJyb3dzZXJzLCBkdWUgdG8gdGhlIGxpbWl0ZWQgc3R5bGFiaWxpdHkgb2YgYDxzZWxlY3Q+YHMgaW4gQ1NTLlxuJGlucHV0LWJvcmRlci1yYWRpdXM6ICAgICAgICAgICAgJGJvcmRlci1yYWRpdXMtYmFzZSAhZGVmYXVsdDtcbi8vKiogTGFyZ2UgYC5mb3JtLWNvbnRyb2xgIGJvcmRlciByYWRpdXNcbiRpbnB1dC1ib3JkZXItcmFkaXVzLWxhcmdlOiAgICAgICRib3JkZXItcmFkaXVzLWxhcmdlICFkZWZhdWx0O1xuLy8qKiBTbWFsbCBgLmZvcm0tY29udHJvbGAgYm9yZGVyIHJhZGl1c1xuJGlucHV0LWJvcmRlci1yYWRpdXMtc21hbGw6ICAgICAgJGJvcmRlci1yYWRpdXMtc21hbGwgIWRlZmF1bHQ7XG5cbi8vKiogQm9yZGVyIGNvbG9yIGZvciBpbnB1dHMgb24gZm9jdXNcbiRpbnB1dC1ib3JkZXItZm9jdXM6ICAgICAgICAgICAgICM2NmFmZTkgIWRlZmF1bHQ7XG5cbi8vKiogUGxhY2Vob2xkZXIgdGV4dCBjb2xvclxuJGlucHV0LWNvbG9yLXBsYWNlaG9sZGVyOiAgICAgICAgIzk5OSAhZGVmYXVsdDtcblxuLy8qKiBEZWZhdWx0IGAuZm9ybS1jb250cm9sYCBoZWlnaHRcbiRpbnB1dC1oZWlnaHQtYmFzZTogICAgICAgICAgICAgICgkbGluZS1oZWlnaHQtY29tcHV0ZWQgKyAoJHBhZGRpbmctYmFzZS12ZXJ0aWNhbCAqIDIpICsgMikgIWRlZmF1bHQ7XG4vLyoqIExhcmdlIGAuZm9ybS1jb250cm9sYCBoZWlnaHRcbiRpbnB1dC1oZWlnaHQtbGFyZ2U6ICAgICAgICAgICAgIChjZWlsKCRmb250LXNpemUtbGFyZ2UgKiAkbGluZS1oZWlnaHQtbGFyZ2UpICsgKCRwYWRkaW5nLWxhcmdlLXZlcnRpY2FsICogMikgKyAyKSAhZGVmYXVsdDtcbi8vKiogU21hbGwgYC5mb3JtLWNvbnRyb2xgIGhlaWdodFxuJGlucHV0LWhlaWdodC1zbWFsbDogICAgICAgICAgICAgKGZsb29yKCRmb250LXNpemUtc21hbGwgKiAkbGluZS1oZWlnaHQtc21hbGwpICsgKCRwYWRkaW5nLXNtYWxsLXZlcnRpY2FsICogMikgKyAyKSAhZGVmYXVsdDtcblxuLy8qKiBgLmZvcm0tZ3JvdXBgIG1hcmdpblxuJGZvcm0tZ3JvdXAtbWFyZ2luLWJvdHRvbTogICAgICAgMTVweCAhZGVmYXVsdDtcblxuJGxlZ2VuZC1jb2xvcjogICAgICAgICAgICAgICAgICAgJGdyYXktZGFyayAhZGVmYXVsdDtcbiRsZWdlbmQtYm9yZGVyLWNvbG9yOiAgICAgICAgICAgICNlNWU1ZTUgIWRlZmF1bHQ7XG5cbi8vKiogQmFja2dyb3VuZCBjb2xvciBmb3IgdGV4dHVhbCBpbnB1dCBhZGRvbnNcbiRpbnB1dC1ncm91cC1hZGRvbi1iZzogICAgICAgICAgICRncmF5LWxpZ2h0ZXIgIWRlZmF1bHQ7XG4vLyoqIEJvcmRlciBjb2xvciBmb3IgdGV4dHVhbCBpbnB1dCBhZGRvbnNcbiRpbnB1dC1ncm91cC1hZGRvbi1ib3JkZXItY29sb3I6ICRpbnB1dC1ib3JkZXIgIWRlZmF1bHQ7XG5cbi8vKiogRGlzYWJsZWQgY3Vyc29yIGZvciBmb3JtIGNvbnRyb2xzIGFuZCBidXR0b25zLlxuJGN1cnNvci1kaXNhYmxlZDogICAgICAgICAgICAgICAgbm90LWFsbG93ZWQgIWRlZmF1bHQ7XG5cblxuLy89PSBEcm9wZG93bnNcbi8vXG4vLyMjIERyb3Bkb3duIG1lbnUgY29udGFpbmVyIGFuZCBjb250ZW50cy5cblxuLy8qKiBCYWNrZ3JvdW5kIGZvciB0aGUgZHJvcGRvd24gbWVudS5cbiRkcm9wZG93bi1iZzogICAgICAgICAgICAgICAgICAgICNmZmYgIWRlZmF1bHQ7XG4vLyoqIERyb3Bkb3duIG1lbnUgYGJvcmRlci1jb2xvcmAuXG4kZHJvcGRvd24tYm9yZGVyOiAgICAgICAgICAgICAgICByZ2JhKDAsMCwwLC4xNSkgIWRlZmF1bHQ7XG4vLyoqIERyb3Bkb3duIG1lbnUgYGJvcmRlci1jb2xvcmAgKipmb3IgSUU4KiouXG4kZHJvcGRvd24tZmFsbGJhY2stYm9yZGVyOiAgICAgICAjY2NjICFkZWZhdWx0O1xuLy8qKiBEaXZpZGVyIGNvbG9yIGZvciBiZXR3ZWVuIGRyb3Bkb3duIGl0ZW1zLlxuJGRyb3Bkb3duLWRpdmlkZXItYmc6ICAgICAgICAgICAgI2U1ZTVlNSAhZGVmYXVsdDtcblxuLy8qKiBEcm9wZG93biBsaW5rIHRleHQgY29sb3IuXG4kZHJvcGRvd24tbGluay1jb2xvcjogICAgICAgICAgICAkZ3JheS1kYXJrICFkZWZhdWx0O1xuLy8qKiBIb3ZlciBjb2xvciBmb3IgZHJvcGRvd24gbGlua3MuXG4kZHJvcGRvd24tbGluay1ob3Zlci1jb2xvcjogICAgICBkYXJrZW4oJGdyYXktZGFyaywgNSUpICFkZWZhdWx0O1xuLy8qKiBIb3ZlciBiYWNrZ3JvdW5kIGZvciBkcm9wZG93biBsaW5rcy5cbiRkcm9wZG93bi1saW5rLWhvdmVyLWJnOiAgICAgICAgICNmNWY1ZjUgIWRlZmF1bHQ7XG5cbi8vKiogQWN0aXZlIGRyb3Bkb3duIG1lbnUgaXRlbSB0ZXh0IGNvbG9yLlxuJGRyb3Bkb3duLWxpbmstYWN0aXZlLWNvbG9yOiAgICAgJGNvbXBvbmVudC1hY3RpdmUtY29sb3IgIWRlZmF1bHQ7XG4vLyoqIEFjdGl2ZSBkcm9wZG93biBtZW51IGl0ZW0gYmFja2dyb3VuZCBjb2xvci5cbiRkcm9wZG93bi1saW5rLWFjdGl2ZS1iZzogICAgICAgICRjb21wb25lbnQtYWN0aXZlLWJnICFkZWZhdWx0O1xuXG4vLyoqIERpc2FibGVkIGRyb3Bkb3duIG1lbnUgaXRlbSBiYWNrZ3JvdW5kIGNvbG9yLlxuJGRyb3Bkb3duLWxpbmstZGlzYWJsZWQtY29sb3I6ICAgJGdyYXktbGlnaHQgIWRlZmF1bHQ7XG5cbi8vKiogVGV4dCBjb2xvciBmb3IgaGVhZGVycyB3aXRoaW4gZHJvcGRvd24gbWVudXMuXG4kZHJvcGRvd24taGVhZGVyLWNvbG9yOiAgICAgICAgICAkZ3JheS1saWdodCAhZGVmYXVsdDtcblxuLy8qKiBEZXByZWNhdGVkIGAkZHJvcGRvd24tY2FyZXQtY29sb3JgIGFzIG9mIHYzLjEuMFxuJGRyb3Bkb3duLWNhcmV0LWNvbG9yOiAgICAgICAgICAgIzAwMCAhZGVmYXVsdDtcblxuXG4vLy0tIFotaW5kZXggbWFzdGVyIGxpc3Rcbi8vXG4vLyBXYXJuaW5nOiBBdm9pZCBjdXN0b21pemluZyB0aGVzZSB2YWx1ZXMuIFRoZXkncmUgdXNlZCBmb3IgYSBiaXJkJ3MgZXllIHZpZXdcbi8vIG9mIGNvbXBvbmVudHMgZGVwZW5kZW50IG9uIHRoZSB6LWF4aXMgYW5kIGFyZSBkZXNpZ25lZCB0byBhbGwgd29yayB0b2dldGhlci5cbi8vXG4vLyBOb3RlOiBUaGVzZSB2YXJpYWJsZXMgYXJlIG5vdCBnZW5lcmF0ZWQgaW50byB0aGUgQ3VzdG9taXplci5cblxuJHppbmRleC1uYXZiYXI6ICAgICAgICAgICAgMTAwMCAhZGVmYXVsdDtcbiR6aW5kZXgtZHJvcGRvd246ICAgICAgICAgIDEwMDAgIWRlZmF1bHQ7XG4kemluZGV4LXBvcG92ZXI6ICAgICAgICAgICAxMDYwICFkZWZhdWx0O1xuJHppbmRleC10b29sdGlwOiAgICAgICAgICAgMTA3MCAhZGVmYXVsdDtcbiR6aW5kZXgtbmF2YmFyLWZpeGVkOiAgICAgIDEwMzAgIWRlZmF1bHQ7XG4kemluZGV4LW1vZGFsLWJhY2tncm91bmQ6ICAxMDQwICFkZWZhdWx0O1xuJHppbmRleC1tb2RhbDogICAgICAgICAgICAgMTA1MCAhZGVmYXVsdDtcblxuXG4vLz09IE1lZGlhIHF1ZXJpZXMgYnJlYWtwb2ludHNcbi8vXG4vLyMjIERlZmluZSB0aGUgYnJlYWtwb2ludHMgYXQgd2hpY2ggeW91ciBsYXlvdXQgd2lsbCBjaGFuZ2UsIGFkYXB0aW5nIHRvIGRpZmZlcmVudCBzY3JlZW4gc2l6ZXMuXG5cbi8vIEV4dHJhIHNtYWxsIHNjcmVlbiAvIHBob25lXG4vLyoqIERlcHJlY2F0ZWQgYCRzY3JlZW4teHNgIGFzIG9mIHYzLjAuMVxuJHNjcmVlbi14czogICAgICAgICAgICAgICAgICA0ODBweCAhZGVmYXVsdDtcbi8vKiogRGVwcmVjYXRlZCBgJHNjcmVlbi14cy1taW5gIGFzIG9mIHYzLjIuMFxuJHNjcmVlbi14cy1taW46ICAgICAgICAgICAgICAkc2NyZWVuLXhzICFkZWZhdWx0O1xuLy8qKiBEZXByZWNhdGVkIGAkc2NyZWVuLXBob25lYCBhcyBvZiB2My4wLjFcbiRzY3JlZW4tcGhvbmU6ICAgICAgICAgICAgICAgJHNjcmVlbi14cy1taW4gIWRlZmF1bHQ7XG5cbi8vIFNtYWxsIHNjcmVlbiAvIHRhYmxldFxuLy8qKiBEZXByZWNhdGVkIGAkc2NyZWVuLXNtYCBhcyBvZiB2My4wLjFcbiRzY3JlZW4tc206ICAgICAgICAgICAgICAgICAgNzY4cHggIWRlZmF1bHQ7XG4kc2NyZWVuLXNtLW1pbjogICAgICAgICAgICAgICRzY3JlZW4tc20gIWRlZmF1bHQ7XG4vLyoqIERlcHJlY2F0ZWQgYCRzY3JlZW4tdGFibGV0YCBhcyBvZiB2My4wLjFcbiRzY3JlZW4tdGFibGV0OiAgICAgICAgICAgICAgJHNjcmVlbi1zbS1taW4gIWRlZmF1bHQ7XG5cbi8vIE1lZGl1bSBzY3JlZW4gLyBkZXNrdG9wXG4vLyoqIERlcHJlY2F0ZWQgYCRzY3JlZW4tbWRgIGFzIG9mIHYzLjAuMVxuJHNjcmVlbi1tZDogICAgICAgICAgICAgICAgICA5OTJweCAhZGVmYXVsdDtcbiRzY3JlZW4tbWQtbWluOiAgICAgICAgICAgICAgJHNjcmVlbi1tZCAhZGVmYXVsdDtcbi8vKiogRGVwcmVjYXRlZCBgJHNjcmVlbi1kZXNrdG9wYCBhcyBvZiB2My4wLjFcbiRzY3JlZW4tZGVza3RvcDogICAgICAgICAgICAgJHNjcmVlbi1tZC1taW4gIWRlZmF1bHQ7XG5cbi8vIExhcmdlIHNjcmVlbiAvIHdpZGUgZGVza3RvcFxuLy8qKiBEZXByZWNhdGVkIGAkc2NyZWVuLWxnYCBhcyBvZiB2My4wLjFcbiRzY3JlZW4tbGc6ICAgICAgICAgICAgICAgICAgMTIwMHB4ICFkZWZhdWx0O1xuJHNjcmVlbi1sZy1taW46ICAgICAgICAgICAgICAkc2NyZWVuLWxnICFkZWZhdWx0O1xuLy8qKiBEZXByZWNhdGVkIGAkc2NyZWVuLWxnLWRlc2t0b3BgIGFzIG9mIHYzLjAuMVxuJHNjcmVlbi1sZy1kZXNrdG9wOiAgICAgICAgICAkc2NyZWVuLWxnLW1pbiAhZGVmYXVsdDtcblxuLy8gU28gbWVkaWEgcXVlcmllcyBkb24ndCBvdmVybGFwIHdoZW4gcmVxdWlyZWQsIHByb3ZpZGUgYSBtYXhpbXVtXG4kc2NyZWVuLXhzLW1heDogICAgICAgICAgICAgICgkc2NyZWVuLXNtLW1pbiAtIDEpICFkZWZhdWx0O1xuJHNjcmVlbi1zbS1tYXg6ICAgICAgICAgICAgICAoJHNjcmVlbi1tZC1taW4gLSAxKSAhZGVmYXVsdDtcbiRzY3JlZW4tbWQtbWF4OiAgICAgICAgICAgICAgKCRzY3JlZW4tbGctbWluIC0gMSkgIWRlZmF1bHQ7XG5cblxuLy89PSBHcmlkIHN5c3RlbVxuLy9cbi8vIyMgRGVmaW5lIHlvdXIgY3VzdG9tIHJlc3BvbnNpdmUgZ3JpZC5cblxuLy8qKiBOdW1iZXIgb2YgY29sdW1ucyBpbiB0aGUgZ3JpZC5cbiRncmlkLWNvbHVtbnM6ICAgICAgICAgICAgICAxMiAhZGVmYXVsdDtcbi8vKiogUGFkZGluZyBiZXR3ZWVuIGNvbHVtbnMuIEdldHMgZGl2aWRlZCBpbiBoYWxmIGZvciB0aGUgbGVmdCBhbmQgcmlnaHQuXG4kZ3JpZC1ndXR0ZXItd2lkdGg6ICAgICAgICAgMzBweCAhZGVmYXVsdDtcbi8vIE5hdmJhciBjb2xsYXBzZVxuLy8qKiBQb2ludCBhdCB3aGljaCB0aGUgbmF2YmFyIGJlY29tZXMgdW5jb2xsYXBzZWQuXG4kZ3JpZC1mbG9hdC1icmVha3BvaW50OiAgICAgJHNjcmVlbi1zbS1taW4gIWRlZmF1bHQ7XG4vLyoqIFBvaW50IGF0IHdoaWNoIHRoZSBuYXZiYXIgYmVnaW5zIGNvbGxhcHNpbmcuXG4kZ3JpZC1mbG9hdC1icmVha3BvaW50LW1heDogKCRncmlkLWZsb2F0LWJyZWFrcG9pbnQgLSAxKSAhZGVmYXVsdDtcblxuXG4vLz09IENvbnRhaW5lciBzaXplc1xuLy9cbi8vIyMgRGVmaW5lIHRoZSBtYXhpbXVtIHdpZHRoIG9mIGAuY29udGFpbmVyYCBmb3IgZGlmZmVyZW50IHNjcmVlbiBzaXplcy5cblxuLy8gU21hbGwgc2NyZWVuIC8gdGFibGV0XG4kY29udGFpbmVyLXRhYmxldDogICAgICAgICAgICAgKDcyMHB4ICsgJGdyaWQtZ3V0dGVyLXdpZHRoKSAhZGVmYXVsdDtcbi8vKiogRm9yIGAkc2NyZWVuLXNtLW1pbmAgYW5kIHVwLlxuJGNvbnRhaW5lci1zbTogICAgICAgICAgICAgICAgICRjb250YWluZXItdGFibGV0ICFkZWZhdWx0O1xuXG4vLyBNZWRpdW0gc2NyZWVuIC8gZGVza3RvcFxuJGNvbnRhaW5lci1kZXNrdG9wOiAgICAgICAgICAgICg5NDBweCArICRncmlkLWd1dHRlci13aWR0aCkgIWRlZmF1bHQ7XG4vLyoqIEZvciBgJHNjcmVlbi1tZC1taW5gIGFuZCB1cC5cbiRjb250YWluZXItbWQ6ICAgICAgICAgICAgICAgICAkY29udGFpbmVyLWRlc2t0b3AgIWRlZmF1bHQ7XG5cbi8vIExhcmdlIHNjcmVlbiAvIHdpZGUgZGVza3RvcFxuJGNvbnRhaW5lci1sYXJnZS1kZXNrdG9wOiAgICAgICgxMTQwcHggKyAkZ3JpZC1ndXR0ZXItd2lkdGgpICFkZWZhdWx0O1xuLy8qKiBGb3IgYCRzY3JlZW4tbGctbWluYCBhbmQgdXAuXG4kY29udGFpbmVyLWxnOiAgICAgICAgICAgICAgICAgJGNvbnRhaW5lci1sYXJnZS1kZXNrdG9wICFkZWZhdWx0O1xuXG5cbi8vPT0gTmF2YmFyXG4vL1xuLy8jI1xuXG4vLyBCYXNpY3Mgb2YgYSBuYXZiYXJcbiRuYXZiYXItaGVpZ2h0OiAgICAgICAgICAgICAgICAgICAgNTBweCAhZGVmYXVsdDtcbiRuYXZiYXItbWFyZ2luLWJvdHRvbTogICAgICAgICAgICAgJGxpbmUtaGVpZ2h0LWNvbXB1dGVkICFkZWZhdWx0O1xuJG5hdmJhci1ib3JkZXItcmFkaXVzOiAgICAgICAgICAgICAkYm9yZGVyLXJhZGl1cy1iYXNlICFkZWZhdWx0O1xuJG5hdmJhci1wYWRkaW5nLWhvcml6b250YWw6ICAgICAgICBmbG9vcigoJGdyaWQtZ3V0dGVyLXdpZHRoIC8gMikpICFkZWZhdWx0O1xuJG5hdmJhci1wYWRkaW5nLXZlcnRpY2FsOiAgICAgICAgICAoKCRuYXZiYXItaGVpZ2h0IC0gJGxpbmUtaGVpZ2h0LWNvbXB1dGVkKSAvIDIpICFkZWZhdWx0O1xuJG5hdmJhci1jb2xsYXBzZS1tYXgtaGVpZ2h0OiAgICAgICAzNDBweCAhZGVmYXVsdDtcblxuJG5hdmJhci1kZWZhdWx0LWNvbG9yOiAgICAgICAgICAgICAjNzc3ICFkZWZhdWx0O1xuJG5hdmJhci1kZWZhdWx0LWJnOiAgICAgICAgICAgICAgICAjZjhmOGY4ICFkZWZhdWx0O1xuJG5hdmJhci1kZWZhdWx0LWJvcmRlcjogICAgICAgICAgICBkYXJrZW4oJG5hdmJhci1kZWZhdWx0LWJnLCA2LjUlKSAhZGVmYXVsdDtcblxuLy8gTmF2YmFyIGxpbmtzXG4kbmF2YmFyLWRlZmF1bHQtbGluay1jb2xvcjogICAgICAgICAgICAgICAgIzc3NyAhZGVmYXVsdDtcbiRuYXZiYXItZGVmYXVsdC1saW5rLWhvdmVyLWNvbG9yOiAgICAgICAgICAjMzMzICFkZWZhdWx0O1xuJG5hdmJhci1kZWZhdWx0LWxpbmstaG92ZXItYmc6ICAgICAgICAgICAgIHRyYW5zcGFyZW50ICFkZWZhdWx0O1xuJG5hdmJhci1kZWZhdWx0LWxpbmstYWN0aXZlLWNvbG9yOiAgICAgICAgICM1NTUgIWRlZmF1bHQ7XG4kbmF2YmFyLWRlZmF1bHQtbGluay1hY3RpdmUtYmc6ICAgICAgICAgICAgZGFya2VuKCRuYXZiYXItZGVmYXVsdC1iZywgNi41JSkgIWRlZmF1bHQ7XG4kbmF2YmFyLWRlZmF1bHQtbGluay1kaXNhYmxlZC1jb2xvcjogICAgICAgI2NjYyAhZGVmYXVsdDtcbiRuYXZiYXItZGVmYXVsdC1saW5rLWRpc2FibGVkLWJnOiAgICAgICAgICB0cmFuc3BhcmVudCAhZGVmYXVsdDtcblxuLy8gTmF2YmFyIGJyYW5kIGxhYmVsXG4kbmF2YmFyLWRlZmF1bHQtYnJhbmQtY29sb3I6ICAgICAgICAgICAgICAgJG5hdmJhci1kZWZhdWx0LWxpbmstY29sb3IgIWRlZmF1bHQ7XG4kbmF2YmFyLWRlZmF1bHQtYnJhbmQtaG92ZXItY29sb3I6ICAgICAgICAgZGFya2VuKCRuYXZiYXItZGVmYXVsdC1icmFuZC1jb2xvciwgMTAlKSAhZGVmYXVsdDtcbiRuYXZiYXItZGVmYXVsdC1icmFuZC1ob3Zlci1iZzogICAgICAgICAgICB0cmFuc3BhcmVudCAhZGVmYXVsdDtcblxuLy8gTmF2YmFyIHRvZ2dsZVxuJG5hdmJhci1kZWZhdWx0LXRvZ2dsZS1ob3Zlci1iZzogICAgICAgICAgICNkZGQgIWRlZmF1bHQ7XG4kbmF2YmFyLWRlZmF1bHQtdG9nZ2xlLWljb24tYmFyLWJnOiAgICAgICAgIzg4OCAhZGVmYXVsdDtcbiRuYXZiYXItZGVmYXVsdC10b2dnbGUtYm9yZGVyLWNvbG9yOiAgICAgICAjZGRkICFkZWZhdWx0O1xuXG5cbi8vPT09IEludmVydGVkIG5hdmJhclxuLy8gUmVzZXQgaW52ZXJ0ZWQgbmF2YmFyIGJhc2ljc1xuJG5hdmJhci1pbnZlcnNlLWNvbG9yOiAgICAgICAgICAgICAgICAgICAgICBsaWdodGVuKCRncmF5LWxpZ2h0LCAxNSUpICFkZWZhdWx0O1xuJG5hdmJhci1pbnZlcnNlLWJnOiAgICAgICAgICAgICAgICAgICAgICAgICAjMjIyICFkZWZhdWx0O1xuJG5hdmJhci1pbnZlcnNlLWJvcmRlcjogICAgICAgICAgICAgICAgICAgICBkYXJrZW4oJG5hdmJhci1pbnZlcnNlLWJnLCAxMCUpICFkZWZhdWx0O1xuXG4vLyBJbnZlcnRlZCBuYXZiYXIgbGlua3NcbiRuYXZiYXItaW52ZXJzZS1saW5rLWNvbG9yOiAgICAgICAgICAgICAgICAgbGlnaHRlbigkZ3JheS1saWdodCwgMTUlKSAhZGVmYXVsdDtcbiRuYXZiYXItaW52ZXJzZS1saW5rLWhvdmVyLWNvbG9yOiAgICAgICAgICAgI2ZmZiAhZGVmYXVsdDtcbiRuYXZiYXItaW52ZXJzZS1saW5rLWhvdmVyLWJnOiAgICAgICAgICAgICAgdHJhbnNwYXJlbnQgIWRlZmF1bHQ7XG4kbmF2YmFyLWludmVyc2UtbGluay1hY3RpdmUtY29sb3I6ICAgICAgICAgICRuYXZiYXItaW52ZXJzZS1saW5rLWhvdmVyLWNvbG9yICFkZWZhdWx0O1xuJG5hdmJhci1pbnZlcnNlLWxpbmstYWN0aXZlLWJnOiAgICAgICAgICAgICBkYXJrZW4oJG5hdmJhci1pbnZlcnNlLWJnLCAxMCUpICFkZWZhdWx0O1xuJG5hdmJhci1pbnZlcnNlLWxpbmstZGlzYWJsZWQtY29sb3I6ICAgICAgICAjNDQ0ICFkZWZhdWx0O1xuJG5hdmJhci1pbnZlcnNlLWxpbmstZGlzYWJsZWQtYmc6ICAgICAgICAgICB0cmFuc3BhcmVudCAhZGVmYXVsdDtcblxuLy8gSW52ZXJ0ZWQgbmF2YmFyIGJyYW5kIGxhYmVsXG4kbmF2YmFyLWludmVyc2UtYnJhbmQtY29sb3I6ICAgICAgICAgICAgICAgICRuYXZiYXItaW52ZXJzZS1saW5rLWNvbG9yICFkZWZhdWx0O1xuJG5hdmJhci1pbnZlcnNlLWJyYW5kLWhvdmVyLWNvbG9yOiAgICAgICAgICAjZmZmICFkZWZhdWx0O1xuJG5hdmJhci1pbnZlcnNlLWJyYW5kLWhvdmVyLWJnOiAgICAgICAgICAgICB0cmFuc3BhcmVudCAhZGVmYXVsdDtcblxuLy8gSW52ZXJ0ZWQgbmF2YmFyIHRvZ2dsZVxuJG5hdmJhci1pbnZlcnNlLXRvZ2dsZS1ob3Zlci1iZzogICAgICAgICAgICAjMzMzICFkZWZhdWx0O1xuJG5hdmJhci1pbnZlcnNlLXRvZ2dsZS1pY29uLWJhci1iZzogICAgICAgICAjZmZmICFkZWZhdWx0O1xuJG5hdmJhci1pbnZlcnNlLXRvZ2dsZS1ib3JkZXItY29sb3I6ICAgICAgICAjMzMzICFkZWZhdWx0O1xuXG5cbi8vPT0gTmF2c1xuLy9cbi8vIyNcblxuLy89PT0gU2hhcmVkIG5hdiBzdHlsZXNcbiRuYXYtbGluay1wYWRkaW5nOiAgICAgICAgICAgICAgICAgICAgICAgICAgMTBweCAxNXB4ICFkZWZhdWx0O1xuJG5hdi1saW5rLWhvdmVyLWJnOiAgICAgICAgICAgICAgICAgICAgICAgICAkZ3JheS1saWdodGVyICFkZWZhdWx0O1xuXG4kbmF2LWRpc2FibGVkLWxpbmstY29sb3I6ICAgICAgICAgICAgICAgICAgICRncmF5LWxpZ2h0ICFkZWZhdWx0O1xuJG5hdi1kaXNhYmxlZC1saW5rLWhvdmVyLWNvbG9yOiAgICAgICAgICAgICAkZ3JheS1saWdodCAhZGVmYXVsdDtcblxuLy89PSBUYWJzXG4kbmF2LXRhYnMtYm9yZGVyLWNvbG9yOiAgICAgICAgICAgICAgICAgICAgICNkZGQgIWRlZmF1bHQ7XG5cbiRuYXYtdGFicy1saW5rLWhvdmVyLWJvcmRlci1jb2xvcjogICAgICAgICAgJGdyYXktbGlnaHRlciAhZGVmYXVsdDtcblxuJG5hdi10YWJzLWFjdGl2ZS1saW5rLWhvdmVyLWJnOiAgICAgICAgICAgICAkYm9keS1iZyAhZGVmYXVsdDtcbiRuYXYtdGFicy1hY3RpdmUtbGluay1ob3Zlci1jb2xvcjogICAgICAgICAgJGdyYXkgIWRlZmF1bHQ7XG4kbmF2LXRhYnMtYWN0aXZlLWxpbmstaG92ZXItYm9yZGVyLWNvbG9yOiAgICNkZGQgIWRlZmF1bHQ7XG5cbiRuYXYtdGFicy1qdXN0aWZpZWQtbGluay1ib3JkZXItY29sb3I6ICAgICAgICAgICAgI2RkZCAhZGVmYXVsdDtcbiRuYXYtdGFicy1qdXN0aWZpZWQtYWN0aXZlLWxpbmstYm9yZGVyLWNvbG9yOiAgICAgJGJvZHktYmcgIWRlZmF1bHQ7XG5cbi8vPT0gUGlsbHNcbiRuYXYtcGlsbHMtYm9yZGVyLXJhZGl1czogICAgICAgICAgICAgICAgICAgJGJvcmRlci1yYWRpdXMtYmFzZSAhZGVmYXVsdDtcbiRuYXYtcGlsbHMtYWN0aXZlLWxpbmstaG92ZXItYmc6ICAgICAgICAgICAgJGNvbXBvbmVudC1hY3RpdmUtYmcgIWRlZmF1bHQ7XG4kbmF2LXBpbGxzLWFjdGl2ZS1saW5rLWhvdmVyLWNvbG9yOiAgICAgICAgICRjb21wb25lbnQtYWN0aXZlLWNvbG9yICFkZWZhdWx0O1xuXG5cbi8vPT0gUGFnaW5hdGlvblxuLy9cbi8vIyNcblxuJHBhZ2luYXRpb24tY29sb3I6ICAgICAgICAgICAgICAgICAgICAgJGxpbmstY29sb3IgIWRlZmF1bHQ7XG4kcGFnaW5hdGlvbi1iZzogICAgICAgICAgICAgICAgICAgICAgICAjZmZmICFkZWZhdWx0O1xuJHBhZ2luYXRpb24tYm9yZGVyOiAgICAgICAgICAgICAgICAgICAgI2RkZCAhZGVmYXVsdDtcblxuJHBhZ2luYXRpb24taG92ZXItY29sb3I6ICAgICAgICAgICAgICAgJGxpbmstaG92ZXItY29sb3IgIWRlZmF1bHQ7XG4kcGFnaW5hdGlvbi1ob3Zlci1iZzogICAgICAgICAgICAgICAgICAkZ3JheS1saWdodGVyICFkZWZhdWx0O1xuJHBhZ2luYXRpb24taG92ZXItYm9yZGVyOiAgICAgICAgICAgICAgI2RkZCAhZGVmYXVsdDtcblxuJHBhZ2luYXRpb24tYWN0aXZlLWNvbG9yOiAgICAgICAgICAgICAgI2ZmZiAhZGVmYXVsdDtcbiRwYWdpbmF0aW9uLWFjdGl2ZS1iZzogICAgICAgICAgICAgICAgICRicmFuZC1wcmltYXJ5ICFkZWZhdWx0O1xuJHBhZ2luYXRpb24tYWN0aXZlLWJvcmRlcjogICAgICAgICAgICAgJGJyYW5kLXByaW1hcnkgIWRlZmF1bHQ7XG5cbiRwYWdpbmF0aW9uLWRpc2FibGVkLWNvbG9yOiAgICAgICAgICAgICRncmF5LWxpZ2h0ICFkZWZhdWx0O1xuJHBhZ2luYXRpb24tZGlzYWJsZWQtYmc6ICAgICAgICAgICAgICAgI2ZmZiAhZGVmYXVsdDtcbiRwYWdpbmF0aW9uLWRpc2FibGVkLWJvcmRlcjogICAgICAgICAgICNkZGQgIWRlZmF1bHQ7XG5cblxuLy89PSBQYWdlclxuLy9cbi8vIyNcblxuJHBhZ2VyLWJnOiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJHBhZ2luYXRpb24tYmcgIWRlZmF1bHQ7XG4kcGFnZXItYm9yZGVyOiAgICAgICAgICAgICAgICAgICAgICAgICAkcGFnaW5hdGlvbi1ib3JkZXIgIWRlZmF1bHQ7XG4kcGFnZXItYm9yZGVyLXJhZGl1czogICAgICAgICAgICAgICAgICAxNXB4ICFkZWZhdWx0O1xuXG4kcGFnZXItaG92ZXItYmc6ICAgICAgICAgICAgICAgICAgICAgICAkcGFnaW5hdGlvbi1ob3Zlci1iZyAhZGVmYXVsdDtcblxuJHBhZ2VyLWFjdGl2ZS1iZzogICAgICAgICAgICAgICAgICAgICAgJHBhZ2luYXRpb24tYWN0aXZlLWJnICFkZWZhdWx0O1xuJHBhZ2VyLWFjdGl2ZS1jb2xvcjogICAgICAgICAgICAgICAgICAgJHBhZ2luYXRpb24tYWN0aXZlLWNvbG9yICFkZWZhdWx0O1xuXG4kcGFnZXItZGlzYWJsZWQtY29sb3I6ICAgICAgICAgICAgICAgICAkcGFnaW5hdGlvbi1kaXNhYmxlZC1jb2xvciAhZGVmYXVsdDtcblxuXG4vLz09IEp1bWJvdHJvblxuLy9cbi8vIyNcblxuJGp1bWJvdHJvbi1wYWRkaW5nOiAgICAgICAgICAgICAgMzBweCAhZGVmYXVsdDtcbiRqdW1ib3Ryb24tY29sb3I6ICAgICAgICAgICAgICAgIGluaGVyaXQgIWRlZmF1bHQ7XG4kanVtYm90cm9uLWJnOiAgICAgICAgICAgICAgICAgICAkZ3JheS1saWdodGVyICFkZWZhdWx0O1xuJGp1bWJvdHJvbi1oZWFkaW5nLWNvbG9yOiAgICAgICAgaW5oZXJpdCAhZGVmYXVsdDtcbiRqdW1ib3Ryb24tZm9udC1zaXplOiAgICAgICAgICAgIGNlaWwoKCRmb250LXNpemUtYmFzZSAqIDEuNSkpICFkZWZhdWx0O1xuJGp1bWJvdHJvbi1oZWFkaW5nLWZvbnQtc2l6ZTogICAgY2VpbCgoJGZvbnQtc2l6ZS1iYXNlICogNC41KSkgIWRlZmF1bHQ7XG5cblxuLy89PSBGb3JtIHN0YXRlcyBhbmQgYWxlcnRzXG4vL1xuLy8jIyBEZWZpbmUgY29sb3JzIGZvciBmb3JtIGZlZWRiYWNrIHN0YXRlcyBhbmQsIGJ5IGRlZmF1bHQsIGFsZXJ0cy5cblxuJHN0YXRlLXN1Y2Nlc3MtdGV4dDogICAgICAgICAgICAgIzNjNzYzZCAhZGVmYXVsdDtcbiRzdGF0ZS1zdWNjZXNzLWJnOiAgICAgICAgICAgICAgICNkZmYwZDggIWRlZmF1bHQ7XG4kc3RhdGUtc3VjY2Vzcy1ib3JkZXI6ICAgICAgICAgICBkYXJrZW4oYWRqdXN0LWh1ZSgkc3RhdGUtc3VjY2Vzcy1iZywgLTEwKSwgNSUpICFkZWZhdWx0O1xuXG4kc3RhdGUtaW5mby10ZXh0OiAgICAgICAgICAgICAgICAjMzE3MDhmICFkZWZhdWx0O1xuJHN0YXRlLWluZm8tYmc6ICAgICAgICAgICAgICAgICAgI2Q5ZWRmNyAhZGVmYXVsdDtcbiRzdGF0ZS1pbmZvLWJvcmRlcjogICAgICAgICAgICAgIGRhcmtlbihhZGp1c3QtaHVlKCRzdGF0ZS1pbmZvLWJnLCAtMTApLCA3JSkgIWRlZmF1bHQ7XG5cbiRzdGF0ZS13YXJuaW5nLXRleHQ6ICAgICAgICAgICAgICM4YTZkM2IgIWRlZmF1bHQ7XG4kc3RhdGUtd2FybmluZy1iZzogICAgICAgICAgICAgICAjZmNmOGUzICFkZWZhdWx0O1xuJHN0YXRlLXdhcm5pbmctYm9yZGVyOiAgICAgICAgICAgZGFya2VuKGFkanVzdC1odWUoJHN0YXRlLXdhcm5pbmctYmcsIC0xMCksIDUlKSAhZGVmYXVsdDtcblxuJHN0YXRlLWRhbmdlci10ZXh0OiAgICAgICAgICAgICAgI2E5NDQ0MiAhZGVmYXVsdDtcbiRzdGF0ZS1kYW5nZXItYmc6ICAgICAgICAgICAgICAgICNmMmRlZGUgIWRlZmF1bHQ7XG4kc3RhdGUtZGFuZ2VyLWJvcmRlcjogICAgICAgICAgICBkYXJrZW4oYWRqdXN0LWh1ZSgkc3RhdGUtZGFuZ2VyLWJnLCAtMTApLCA1JSkgIWRlZmF1bHQ7XG5cblxuLy89PSBUb29sdGlwc1xuLy9cbi8vIyNcblxuLy8qKiBUb29sdGlwIG1heCB3aWR0aFxuJHRvb2x0aXAtbWF4LXdpZHRoOiAgICAgICAgICAgMjAwcHggIWRlZmF1bHQ7XG4vLyoqIFRvb2x0aXAgdGV4dCBjb2xvclxuJHRvb2x0aXAtY29sb3I6ICAgICAgICAgICAgICAgI2ZmZiAhZGVmYXVsdDtcbi8vKiogVG9vbHRpcCBiYWNrZ3JvdW5kIGNvbG9yXG4kdG9vbHRpcC1iZzogICAgICAgICAgICAgICAgICAjMDAwICFkZWZhdWx0O1xuJHRvb2x0aXAtb3BhY2l0eTogICAgICAgICAgICAgLjkgIWRlZmF1bHQ7XG5cbi8vKiogVG9vbHRpcCBhcnJvdyB3aWR0aFxuJHRvb2x0aXAtYXJyb3ctd2lkdGg6ICAgICAgICAgNXB4ICFkZWZhdWx0O1xuLy8qKiBUb29sdGlwIGFycm93IGNvbG9yXG4kdG9vbHRpcC1hcnJvdy1jb2xvcjogICAgICAgICAkdG9vbHRpcC1iZyAhZGVmYXVsdDtcblxuXG4vLz09IFBvcG92ZXJzXG4vL1xuLy8jI1xuXG4vLyoqIFBvcG92ZXIgYm9keSBiYWNrZ3JvdW5kIGNvbG9yXG4kcG9wb3Zlci1iZzogICAgICAgICAgICAgICAgICAgICAgICAgICNmZmYgIWRlZmF1bHQ7XG4vLyoqIFBvcG92ZXIgbWF4aW11bSB3aWR0aFxuJHBvcG92ZXItbWF4LXdpZHRoOiAgICAgICAgICAgICAgICAgICAyNzZweCAhZGVmYXVsdDtcbi8vKiogUG9wb3ZlciBib3JkZXIgY29sb3JcbiRwb3BvdmVyLWJvcmRlci1jb2xvcjogICAgICAgICAgICAgICAgcmdiYSgwLDAsMCwuMikgIWRlZmF1bHQ7XG4vLyoqIFBvcG92ZXIgZmFsbGJhY2sgYm9yZGVyIGNvbG9yXG4kcG9wb3Zlci1mYWxsYmFjay1ib3JkZXItY29sb3I6ICAgICAgICNjY2MgIWRlZmF1bHQ7XG5cbi8vKiogUG9wb3ZlciB0aXRsZSBiYWNrZ3JvdW5kIGNvbG9yXG4kcG9wb3Zlci10aXRsZS1iZzogICAgICAgICAgICAgICAgICAgIGRhcmtlbigkcG9wb3Zlci1iZywgMyUpICFkZWZhdWx0O1xuXG4vLyoqIFBvcG92ZXIgYXJyb3cgd2lkdGhcbiRwb3BvdmVyLWFycm93LXdpZHRoOiAgICAgICAgICAgICAgICAgMTBweCAhZGVmYXVsdDtcbi8vKiogUG9wb3ZlciBhcnJvdyBjb2xvclxuJHBvcG92ZXItYXJyb3ctY29sb3I6ICAgICAgICAgICAgICAgICAkcG9wb3Zlci1iZyAhZGVmYXVsdDtcblxuLy8qKiBQb3BvdmVyIG91dGVyIGFycm93IHdpZHRoXG4kcG9wb3Zlci1hcnJvdy1vdXRlci13aWR0aDogICAgICAgICAgICgkcG9wb3Zlci1hcnJvdy13aWR0aCArIDEpICFkZWZhdWx0O1xuLy8qKiBQb3BvdmVyIG91dGVyIGFycm93IGNvbG9yXG4kcG9wb3Zlci1hcnJvdy1vdXRlci1jb2xvcjogICAgICAgICAgIGZhZGVfaW4oJHBvcG92ZXItYm9yZGVyLWNvbG9yLCAwLjA1KSAhZGVmYXVsdDtcbi8vKiogUG9wb3ZlciBvdXRlciBhcnJvdyBmYWxsYmFjayBjb2xvclxuJHBvcG92ZXItYXJyb3ctb3V0ZXItZmFsbGJhY2stY29sb3I6ICBkYXJrZW4oJHBvcG92ZXItZmFsbGJhY2stYm9yZGVyLWNvbG9yLCAyMCUpICFkZWZhdWx0O1xuXG5cbi8vPT0gTGFiZWxzXG4vL1xuLy8jI1xuXG4vLyoqIERlZmF1bHQgbGFiZWwgYmFja2dyb3VuZCBjb2xvclxuJGxhYmVsLWRlZmF1bHQtYmc6ICAgICAgICAgICAgJGdyYXktbGlnaHQgIWRlZmF1bHQ7XG4vLyoqIFByaW1hcnkgbGFiZWwgYmFja2dyb3VuZCBjb2xvclxuJGxhYmVsLXByaW1hcnktYmc6ICAgICAgICAgICAgJGJyYW5kLXByaW1hcnkgIWRlZmF1bHQ7XG4vLyoqIFN1Y2Nlc3MgbGFiZWwgYmFja2dyb3VuZCBjb2xvclxuJGxhYmVsLXN1Y2Nlc3MtYmc6ICAgICAgICAgICAgJGJyYW5kLXN1Y2Nlc3MgIWRlZmF1bHQ7XG4vLyoqIEluZm8gbGFiZWwgYmFja2dyb3VuZCBjb2xvclxuJGxhYmVsLWluZm8tYmc6ICAgICAgICAgICAgICAgJGJyYW5kLWluZm8gIWRlZmF1bHQ7XG4vLyoqIFdhcm5pbmcgbGFiZWwgYmFja2dyb3VuZCBjb2xvclxuJGxhYmVsLXdhcm5pbmctYmc6ICAgICAgICAgICAgJGJyYW5kLXdhcm5pbmcgIWRlZmF1bHQ7XG4vLyoqIERhbmdlciBsYWJlbCBiYWNrZ3JvdW5kIGNvbG9yXG4kbGFiZWwtZGFuZ2VyLWJnOiAgICAgICAgICAgICAkYnJhbmQtZGFuZ2VyICFkZWZhdWx0O1xuXG4vLyoqIERlZmF1bHQgbGFiZWwgdGV4dCBjb2xvclxuJGxhYmVsLWNvbG9yOiAgICAgICAgICAgICAgICAgI2ZmZiAhZGVmYXVsdDtcbi8vKiogRGVmYXVsdCB0ZXh0IGNvbG9yIG9mIGEgbGlua2VkIGxhYmVsXG4kbGFiZWwtbGluay1ob3Zlci1jb2xvcjogICAgICAjZmZmICFkZWZhdWx0O1xuXG5cbi8vPT0gTW9kYWxzXG4vL1xuLy8jI1xuXG4vLyoqIFBhZGRpbmcgYXBwbGllZCB0byB0aGUgbW9kYWwgYm9keVxuJG1vZGFsLWlubmVyLXBhZGRpbmc6ICAgICAgICAgMTVweCAhZGVmYXVsdDtcblxuLy8qKiBQYWRkaW5nIGFwcGxpZWQgdG8gdGhlIG1vZGFsIHRpdGxlXG4kbW9kYWwtdGl0bGUtcGFkZGluZzogICAgICAgICAxNXB4ICFkZWZhdWx0O1xuLy8qKiBNb2RhbCB0aXRsZSBsaW5lLWhlaWdodFxuJG1vZGFsLXRpdGxlLWxpbmUtaGVpZ2h0OiAgICAgJGxpbmUtaGVpZ2h0LWJhc2UgIWRlZmF1bHQ7XG5cbi8vKiogQmFja2dyb3VuZCBjb2xvciBvZiBtb2RhbCBjb250ZW50IGFyZWFcbiRtb2RhbC1jb250ZW50LWJnOiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI2ZmZiAhZGVmYXVsdDtcbi8vKiogTW9kYWwgY29udGVudCBib3JkZXIgY29sb3JcbiRtb2RhbC1jb250ZW50LWJvcmRlci1jb2xvcjogICAgICAgICAgICAgICAgICAgcmdiYSgwLDAsMCwuMikgIWRlZmF1bHQ7XG4vLyoqIE1vZGFsIGNvbnRlbnQgYm9yZGVyIGNvbG9yICoqZm9yIElFOCoqXG4kbW9kYWwtY29udGVudC1mYWxsYmFjay1ib3JkZXItY29sb3I6ICAgICAgICAgICM5OTkgIWRlZmF1bHQ7XG5cbi8vKiogTW9kYWwgYmFja2Ryb3AgYmFja2dyb3VuZCBjb2xvclxuJG1vZGFsLWJhY2tkcm9wLWJnOiAgICAgICAgICAgIzAwMCAhZGVmYXVsdDtcbi8vKiogTW9kYWwgYmFja2Ryb3Agb3BhY2l0eVxuJG1vZGFsLWJhY2tkcm9wLW9wYWNpdHk6ICAgICAgLjUgIWRlZmF1bHQ7XG4vLyoqIE1vZGFsIGhlYWRlciBib3JkZXIgY29sb3JcbiRtb2RhbC1oZWFkZXItYm9yZGVyLWNvbG9yOiAgICNlNWU1ZTUgIWRlZmF1bHQ7XG4vLyoqIE1vZGFsIGZvb3RlciBib3JkZXIgY29sb3JcbiRtb2RhbC1mb290ZXItYm9yZGVyLWNvbG9yOiAgICRtb2RhbC1oZWFkZXItYm9yZGVyLWNvbG9yICFkZWZhdWx0O1xuXG4kbW9kYWwtbGc6ICAgICAgICAgICAgICAgICAgICA5MDBweCAhZGVmYXVsdDtcbiRtb2RhbC1tZDogICAgICAgICAgICAgICAgICAgIDYwMHB4ICFkZWZhdWx0O1xuJG1vZGFsLXNtOiAgICAgICAgICAgICAgICAgICAgMzAwcHggIWRlZmF1bHQ7XG5cblxuLy89PSBBbGVydHNcbi8vXG4vLyMjIERlZmluZSBhbGVydCBjb2xvcnMsIGJvcmRlciByYWRpdXMsIGFuZCBwYWRkaW5nLlxuXG4kYWxlcnQtcGFkZGluZzogICAgICAgICAgICAgICAxNXB4ICFkZWZhdWx0O1xuJGFsZXJ0LWJvcmRlci1yYWRpdXM6ICAgICAgICAgJGJvcmRlci1yYWRpdXMtYmFzZSAhZGVmYXVsdDtcbiRhbGVydC1saW5rLWZvbnQtd2VpZ2h0OiAgICAgIGJvbGQgIWRlZmF1bHQ7XG5cbiRhbGVydC1zdWNjZXNzLWJnOiAgICAgICAgICAgICRzdGF0ZS1zdWNjZXNzLWJnICFkZWZhdWx0O1xuJGFsZXJ0LXN1Y2Nlc3MtdGV4dDogICAgICAgICAgJHN0YXRlLXN1Y2Nlc3MtdGV4dCAhZGVmYXVsdDtcbiRhbGVydC1zdWNjZXNzLWJvcmRlcjogICAgICAgICRzdGF0ZS1zdWNjZXNzLWJvcmRlciAhZGVmYXVsdDtcblxuJGFsZXJ0LWluZm8tYmc6ICAgICAgICAgICAgICAgJHN0YXRlLWluZm8tYmcgIWRlZmF1bHQ7XG4kYWxlcnQtaW5mby10ZXh0OiAgICAgICAgICAgICAkc3RhdGUtaW5mby10ZXh0ICFkZWZhdWx0O1xuJGFsZXJ0LWluZm8tYm9yZGVyOiAgICAgICAgICAgJHN0YXRlLWluZm8tYm9yZGVyICFkZWZhdWx0O1xuXG4kYWxlcnQtd2FybmluZy1iZzogICAgICAgICAgICAkc3RhdGUtd2FybmluZy1iZyAhZGVmYXVsdDtcbiRhbGVydC13YXJuaW5nLXRleHQ6ICAgICAgICAgICRzdGF0ZS13YXJuaW5nLXRleHQgIWRlZmF1bHQ7XG4kYWxlcnQtd2FybmluZy1ib3JkZXI6ICAgICAgICAkc3RhdGUtd2FybmluZy1ib3JkZXIgIWRlZmF1bHQ7XG5cbiRhbGVydC1kYW5nZXItYmc6ICAgICAgICAgICAgICRzdGF0ZS1kYW5nZXItYmcgIWRlZmF1bHQ7XG4kYWxlcnQtZGFuZ2VyLXRleHQ6ICAgICAgICAgICAkc3RhdGUtZGFuZ2VyLXRleHQgIWRlZmF1bHQ7XG4kYWxlcnQtZGFuZ2VyLWJvcmRlcjogICAgICAgICAkc3RhdGUtZGFuZ2VyLWJvcmRlciAhZGVmYXVsdDtcblxuXG4vLz09IFByb2dyZXNzIGJhcnNcbi8vXG4vLyMjXG5cbi8vKiogQmFja2dyb3VuZCBjb2xvciBvZiB0aGUgd2hvbGUgcHJvZ3Jlc3MgY29tcG9uZW50XG4kcHJvZ3Jlc3MtYmc6ICAgICAgICAgICAgICAgICAjZjVmNWY1ICFkZWZhdWx0O1xuLy8qKiBQcm9ncmVzcyBiYXIgdGV4dCBjb2xvclxuJHByb2dyZXNzLWJhci1jb2xvcjogICAgICAgICAgI2ZmZiAhZGVmYXVsdDtcbi8vKiogVmFyaWFibGUgZm9yIHNldHRpbmcgcm91bmRlZCBjb3JuZXJzIG9uIHByb2dyZXNzIGJhci5cbiRwcm9ncmVzcy1ib3JkZXItcmFkaXVzOiAgICAgICRib3JkZXItcmFkaXVzLWJhc2UgIWRlZmF1bHQ7XG5cbi8vKiogRGVmYXVsdCBwcm9ncmVzcyBiYXIgY29sb3JcbiRwcm9ncmVzcy1iYXItYmc6ICAgICAgICAgICAgICRicmFuZC1wcmltYXJ5ICFkZWZhdWx0O1xuLy8qKiBTdWNjZXNzIHByb2dyZXNzIGJhciBjb2xvclxuJHByb2dyZXNzLWJhci1zdWNjZXNzLWJnOiAgICAgJGJyYW5kLXN1Y2Nlc3MgIWRlZmF1bHQ7XG4vLyoqIFdhcm5pbmcgcHJvZ3Jlc3MgYmFyIGNvbG9yXG4kcHJvZ3Jlc3MtYmFyLXdhcm5pbmctYmc6ICAgICAkYnJhbmQtd2FybmluZyAhZGVmYXVsdDtcbi8vKiogRGFuZ2VyIHByb2dyZXNzIGJhciBjb2xvclxuJHByb2dyZXNzLWJhci1kYW5nZXItYmc6ICAgICAgJGJyYW5kLWRhbmdlciAhZGVmYXVsdDtcbi8vKiogSW5mbyBwcm9ncmVzcyBiYXIgY29sb3JcbiRwcm9ncmVzcy1iYXItaW5mby1iZzogICAgICAgICRicmFuZC1pbmZvICFkZWZhdWx0O1xuXG5cbi8vPT0gTGlzdCBncm91cFxuLy9cbi8vIyNcblxuLy8qKiBCYWNrZ3JvdW5kIGNvbG9yIG9uIGAubGlzdC1ncm91cC1pdGVtYFxuJGxpc3QtZ3JvdXAtYmc6ICAgICAgICAgICAgICAgICAjZmZmICFkZWZhdWx0O1xuLy8qKiBgLmxpc3QtZ3JvdXAtaXRlbWAgYm9yZGVyIGNvbG9yXG4kbGlzdC1ncm91cC1ib3JkZXI6ICAgICAgICAgICAgICNkZGQgIWRlZmF1bHQ7XG4vLyoqIExpc3QgZ3JvdXAgYm9yZGVyIHJhZGl1c1xuJGxpc3QtZ3JvdXAtYm9yZGVyLXJhZGl1czogICAgICAkYm9yZGVyLXJhZGl1cy1iYXNlICFkZWZhdWx0O1xuXG4vLyoqIEJhY2tncm91bmQgY29sb3Igb2Ygc2luZ2xlIGxpc3QgaXRlbXMgb24gaG92ZXJcbiRsaXN0LWdyb3VwLWhvdmVyLWJnOiAgICAgICAgICAgI2Y1ZjVmNSAhZGVmYXVsdDtcbi8vKiogVGV4dCBjb2xvciBvZiBhY3RpdmUgbGlzdCBpdGVtc1xuJGxpc3QtZ3JvdXAtYWN0aXZlLWNvbG9yOiAgICAgICAkY29tcG9uZW50LWFjdGl2ZS1jb2xvciAhZGVmYXVsdDtcbi8vKiogQmFja2dyb3VuZCBjb2xvciBvZiBhY3RpdmUgbGlzdCBpdGVtc1xuJGxpc3QtZ3JvdXAtYWN0aXZlLWJnOiAgICAgICAgICAkY29tcG9uZW50LWFjdGl2ZS1iZyAhZGVmYXVsdDtcbi8vKiogQm9yZGVyIGNvbG9yIG9mIGFjdGl2ZSBsaXN0IGVsZW1lbnRzXG4kbGlzdC1ncm91cC1hY3RpdmUtYm9yZGVyOiAgICAgICRsaXN0LWdyb3VwLWFjdGl2ZS1iZyAhZGVmYXVsdDtcbi8vKiogVGV4dCBjb2xvciBmb3IgY29udGVudCB3aXRoaW4gYWN0aXZlIGxpc3QgaXRlbXNcbiRsaXN0LWdyb3VwLWFjdGl2ZS10ZXh0LWNvbG9yOiAgbGlnaHRlbigkbGlzdC1ncm91cC1hY3RpdmUtYmcsIDQwJSkgIWRlZmF1bHQ7XG5cbi8vKiogVGV4dCBjb2xvciBvZiBkaXNhYmxlZCBsaXN0IGl0ZW1zXG4kbGlzdC1ncm91cC1kaXNhYmxlZC1jb2xvcjogICAgICAkZ3JheS1saWdodCAhZGVmYXVsdDtcbi8vKiogQmFja2dyb3VuZCBjb2xvciBvZiBkaXNhYmxlZCBsaXN0IGl0ZW1zXG4kbGlzdC1ncm91cC1kaXNhYmxlZC1iZzogICAgICAgICAkZ3JheS1saWdodGVyICFkZWZhdWx0O1xuLy8qKiBUZXh0IGNvbG9yIGZvciBjb250ZW50IHdpdGhpbiBkaXNhYmxlZCBsaXN0IGl0ZW1zXG4kbGlzdC1ncm91cC1kaXNhYmxlZC10ZXh0LWNvbG9yOiAkbGlzdC1ncm91cC1kaXNhYmxlZC1jb2xvciAhZGVmYXVsdDtcblxuJGxpc3QtZ3JvdXAtbGluay1jb2xvcjogICAgICAgICAjNTU1ICFkZWZhdWx0O1xuJGxpc3QtZ3JvdXAtbGluay1ob3Zlci1jb2xvcjogICAkbGlzdC1ncm91cC1saW5rLWNvbG9yICFkZWZhdWx0O1xuJGxpc3QtZ3JvdXAtbGluay1oZWFkaW5nLWNvbG9yOiAjMzMzICFkZWZhdWx0O1xuXG5cbi8vPT0gUGFuZWxzXG4vL1xuLy8jI1xuXG4kcGFuZWwtYmc6ICAgICAgICAgICAgICAgICAgICAjZmZmICFkZWZhdWx0O1xuJHBhbmVsLWJvZHktcGFkZGluZzogICAgICAgICAgMTVweCAhZGVmYXVsdDtcbiRwYW5lbC1oZWFkaW5nLXBhZGRpbmc6ICAgICAgIDEwcHggMTVweCAhZGVmYXVsdDtcbiRwYW5lbC1mb290ZXItcGFkZGluZzogICAgICAgICRwYW5lbC1oZWFkaW5nLXBhZGRpbmcgIWRlZmF1bHQ7XG4kcGFuZWwtYm9yZGVyLXJhZGl1czogICAgICAgICAkYm9yZGVyLXJhZGl1cy1iYXNlICFkZWZhdWx0O1xuXG4vLyoqIEJvcmRlciBjb2xvciBmb3IgZWxlbWVudHMgd2l0aGluIHBhbmVsc1xuJHBhbmVsLWlubmVyLWJvcmRlcjogICAgICAgICAgI2RkZCAhZGVmYXVsdDtcbiRwYW5lbC1mb290ZXItYmc6ICAgICAgICAgICAgICNmNWY1ZjUgIWRlZmF1bHQ7XG5cbiRwYW5lbC1kZWZhdWx0LXRleHQ6ICAgICAgICAgICRncmF5LWRhcmsgIWRlZmF1bHQ7XG4kcGFuZWwtZGVmYXVsdC1ib3JkZXI6ICAgICAgICAjZGRkICFkZWZhdWx0O1xuJHBhbmVsLWRlZmF1bHQtaGVhZGluZy1iZzogICAgI2Y1ZjVmNSAhZGVmYXVsdDtcblxuJHBhbmVsLXByaW1hcnktdGV4dDogICAgICAgICAgI2ZmZiAhZGVmYXVsdDtcbiRwYW5lbC1wcmltYXJ5LWJvcmRlcjogICAgICAgICRicmFuZC1wcmltYXJ5ICFkZWZhdWx0O1xuJHBhbmVsLXByaW1hcnktaGVhZGluZy1iZzogICAgJGJyYW5kLXByaW1hcnkgIWRlZmF1bHQ7XG5cbiRwYW5lbC1zdWNjZXNzLXRleHQ6ICAgICAgICAgICRzdGF0ZS1zdWNjZXNzLXRleHQgIWRlZmF1bHQ7XG4kcGFuZWwtc3VjY2Vzcy1ib3JkZXI6ICAgICAgICAkc3RhdGUtc3VjY2Vzcy1ib3JkZXIgIWRlZmF1bHQ7XG4kcGFuZWwtc3VjY2Vzcy1oZWFkaW5nLWJnOiAgICAkc3RhdGUtc3VjY2Vzcy1iZyAhZGVmYXVsdDtcblxuJHBhbmVsLWluZm8tdGV4dDogICAgICAgICAgICAgJHN0YXRlLWluZm8tdGV4dCAhZGVmYXVsdDtcbiRwYW5lbC1pbmZvLWJvcmRlcjogICAgICAgICAgICRzdGF0ZS1pbmZvLWJvcmRlciAhZGVmYXVsdDtcbiRwYW5lbC1pbmZvLWhlYWRpbmctYmc6ICAgICAgICRzdGF0ZS1pbmZvLWJnICFkZWZhdWx0O1xuXG4kcGFuZWwtd2FybmluZy10ZXh0OiAgICAgICAgICAkc3RhdGUtd2FybmluZy10ZXh0ICFkZWZhdWx0O1xuJHBhbmVsLXdhcm5pbmctYm9yZGVyOiAgICAgICAgJHN0YXRlLXdhcm5pbmctYm9yZGVyICFkZWZhdWx0O1xuJHBhbmVsLXdhcm5pbmctaGVhZGluZy1iZzogICAgJHN0YXRlLXdhcm5pbmctYmcgIWRlZmF1bHQ7XG5cbiRwYW5lbC1kYW5nZXItdGV4dDogICAgICAgICAgICRzdGF0ZS1kYW5nZXItdGV4dCAhZGVmYXVsdDtcbiRwYW5lbC1kYW5nZXItYm9yZGVyOiAgICAgICAgICRzdGF0ZS1kYW5nZXItYm9yZGVyICFkZWZhdWx0O1xuJHBhbmVsLWRhbmdlci1oZWFkaW5nLWJnOiAgICAgJHN0YXRlLWRhbmdlci1iZyAhZGVmYXVsdDtcblxuXG4vLz09IFRodW1ibmFpbHNcbi8vXG4vLyMjXG5cbi8vKiogUGFkZGluZyBhcm91bmQgdGhlIHRodW1ibmFpbCBpbWFnZVxuJHRodW1ibmFpbC1wYWRkaW5nOiAgICAgICAgICAgNHB4ICFkZWZhdWx0O1xuLy8qKiBUaHVtYm5haWwgYmFja2dyb3VuZCBjb2xvclxuJHRodW1ibmFpbC1iZzogICAgICAgICAgICAgICAgJGJvZHktYmcgIWRlZmF1bHQ7XG4vLyoqIFRodW1ibmFpbCBib3JkZXIgY29sb3JcbiR0aHVtYm5haWwtYm9yZGVyOiAgICAgICAgICAgICNkZGQgIWRlZmF1bHQ7XG4vLyoqIFRodW1ibmFpbCBib3JkZXIgcmFkaXVzXG4kdGh1bWJuYWlsLWJvcmRlci1yYWRpdXM6ICAgICAkYm9yZGVyLXJhZGl1cy1iYXNlICFkZWZhdWx0O1xuXG4vLyoqIEN1c3RvbSB0ZXh0IGNvbG9yIGZvciB0aHVtYm5haWwgY2FwdGlvbnNcbiR0aHVtYm5haWwtY2FwdGlvbi1jb2xvcjogICAgICR0ZXh0LWNvbG9yICFkZWZhdWx0O1xuLy8qKiBQYWRkaW5nIGFyb3VuZCB0aGUgdGh1bWJuYWlsIGNhcHRpb25cbiR0aHVtYm5haWwtY2FwdGlvbi1wYWRkaW5nOiAgIDlweCAhZGVmYXVsdDtcblxuXG4vLz09IFdlbGxzXG4vL1xuLy8jI1xuXG4kd2VsbC1iZzogICAgICAgICAgICAgICAgICAgICAjZjVmNWY1ICFkZWZhdWx0O1xuJHdlbGwtYm9yZGVyOiAgICAgICAgICAgICAgICAgZGFya2VuKCR3ZWxsLWJnLCA3JSkgIWRlZmF1bHQ7XG5cblxuLy89PSBCYWRnZXNcbi8vXG4vLyMjXG5cbiRiYWRnZS1jb2xvcjogICAgICAgICAgICAgICAgICNmZmYgIWRlZmF1bHQ7XG4vLyoqIExpbmtlZCBiYWRnZSB0ZXh0IGNvbG9yIG9uIGhvdmVyXG4kYmFkZ2UtbGluay1ob3Zlci1jb2xvcjogICAgICAjZmZmICFkZWZhdWx0O1xuJGJhZGdlLWJnOiAgICAgICAgICAgICAgICAgICAgJGdyYXktbGlnaHQgIWRlZmF1bHQ7XG5cbi8vKiogQmFkZ2UgdGV4dCBjb2xvciBpbiBhY3RpdmUgbmF2IGxpbmtcbiRiYWRnZS1hY3RpdmUtY29sb3I6ICAgICAgICAgICRsaW5rLWNvbG9yICFkZWZhdWx0O1xuLy8qKiBCYWRnZSBiYWNrZ3JvdW5kIGNvbG9yIGluIGFjdGl2ZSBuYXYgbGlua1xuJGJhZGdlLWFjdGl2ZS1iZzogICAgICAgICAgICAgI2ZmZiAhZGVmYXVsdDtcblxuJGJhZGdlLWZvbnQtd2VpZ2h0OiAgICAgICAgICAgYm9sZCAhZGVmYXVsdDtcbiRiYWRnZS1saW5lLWhlaWdodDogICAgICAgICAgIDEgIWRlZmF1bHQ7XG4kYmFkZ2UtYm9yZGVyLXJhZGl1czogICAgICAgICAxMHB4ICFkZWZhdWx0O1xuXG5cbi8vPT0gQnJlYWRjcnVtYnNcbi8vXG4vLyMjXG5cbiRicmVhZGNydW1iLXBhZGRpbmctdmVydGljYWw6ICAgOHB4ICFkZWZhdWx0O1xuJGJyZWFkY3J1bWItcGFkZGluZy1ob3Jpem9udGFsOiAxNXB4ICFkZWZhdWx0O1xuLy8qKiBCcmVhZGNydW1iIGJhY2tncm91bmQgY29sb3JcbiRicmVhZGNydW1iLWJnOiAgICAgICAgICAgICAgICAgI2Y1ZjVmNSAhZGVmYXVsdDtcbi8vKiogQnJlYWRjcnVtYiB0ZXh0IGNvbG9yXG4kYnJlYWRjcnVtYi1jb2xvcjogICAgICAgICAgICAgICNjY2MgIWRlZmF1bHQ7XG4vLyoqIFRleHQgY29sb3Igb2YgY3VycmVudCBwYWdlIGluIHRoZSBicmVhZGNydW1iXG4kYnJlYWRjcnVtYi1hY3RpdmUtY29sb3I6ICAgICAgICRncmF5LWxpZ2h0ICFkZWZhdWx0O1xuLy8qKiBUZXh0dWFsIHNlcGFyYXRvciBmb3IgYmV0d2VlbiBicmVhZGNydW1iIGVsZW1lbnRzXG4kYnJlYWRjcnVtYi1zZXBhcmF0b3I6ICAgICAgICAgIFwiL1wiICFkZWZhdWx0O1xuXG5cbi8vPT0gQ2Fyb3VzZWxcbi8vXG4vLyMjXG5cbiRjYXJvdXNlbC10ZXh0LXNoYWRvdzogICAgICAgICAgICAgICAgICAgICAgICAwIDFweCAycHggcmdiYSgwLDAsMCwuNikgIWRlZmF1bHQ7XG5cbiRjYXJvdXNlbC1jb250cm9sLWNvbG9yOiAgICAgICAgICAgICAgICAgICAgICAjZmZmICFkZWZhdWx0O1xuJGNhcm91c2VsLWNvbnRyb2wtd2lkdGg6ICAgICAgICAgICAgICAgICAgICAgIDE1JSAhZGVmYXVsdDtcbiRjYXJvdXNlbC1jb250cm9sLW9wYWNpdHk6ICAgICAgICAgICAgICAgICAgICAuNSAhZGVmYXVsdDtcbiRjYXJvdXNlbC1jb250cm9sLWZvbnQtc2l6ZTogICAgICAgICAgICAgICAgICAyMHB4ICFkZWZhdWx0O1xuXG4kY2Fyb3VzZWwtaW5kaWNhdG9yLWFjdGl2ZS1iZzogICAgICAgICAgICAgICAgI2ZmZiAhZGVmYXVsdDtcbiRjYXJvdXNlbC1pbmRpY2F0b3ItYm9yZGVyLWNvbG9yOiAgICAgICAgICAgICAjZmZmICFkZWZhdWx0O1xuXG4kY2Fyb3VzZWwtY2FwdGlvbi1jb2xvcjogICAgICAgICAgICAgICAgICAgICAgI2ZmZiAhZGVmYXVsdDtcblxuXG4vLz09IENsb3NlXG4vL1xuLy8jI1xuXG4kY2xvc2UtZm9udC13ZWlnaHQ6ICAgICAgICAgICBib2xkICFkZWZhdWx0O1xuJGNsb3NlLWNvbG9yOiAgICAgICAgICAgICAgICAgIzAwMCAhZGVmYXVsdDtcbiRjbG9zZS10ZXh0LXNoYWRvdzogICAgICAgICAgIDAgMXB4IDAgI2ZmZiAhZGVmYXVsdDtcblxuXG4vLz09IENvZGVcbi8vXG4vLyMjXG5cbiRjb2RlLWNvbG9yOiAgICAgICAgICAgICAgICAgICNjNzI1NGUgIWRlZmF1bHQ7XG4kY29kZS1iZzogICAgICAgICAgICAgICAgICAgICAjZjlmMmY0ICFkZWZhdWx0O1xuXG4ka2JkLWNvbG9yOiAgICAgICAgICAgICAgICAgICAjZmZmICFkZWZhdWx0O1xuJGtiZC1iZzogICAgICAgICAgICAgICAgICAgICAgIzMzMyAhZGVmYXVsdDtcblxuJHByZS1iZzogICAgICAgICAgICAgICAgICAgICAgI2Y1ZjVmNSAhZGVmYXVsdDtcbiRwcmUtY29sb3I6ICAgICAgICAgICAgICAgICAgICRncmF5LWRhcmsgIWRlZmF1bHQ7XG4kcHJlLWJvcmRlci1jb2xvcjogICAgICAgICAgICAjY2NjICFkZWZhdWx0O1xuJHByZS1zY3JvbGxhYmxlLW1heC1oZWlnaHQ6ICAgMzQwcHggIWRlZmF1bHQ7XG5cblxuLy89PSBUeXBlXG4vL1xuLy8jI1xuXG4vLyoqIEhvcml6b250YWwgb2Zmc2V0IGZvciBmb3JtcyBhbmQgbGlzdHMuXG4kY29tcG9uZW50LW9mZnNldC1ob3Jpem9udGFsOiAxODBweCAhZGVmYXVsdDtcbi8vKiogVGV4dCBtdXRlZCBjb2xvclxuJHRleHQtbXV0ZWQ6ICAgICAgICAgICAgICAgICAgJGdyYXktbGlnaHQgIWRlZmF1bHQ7XG4vLyoqIEFiYnJldmlhdGlvbnMgYW5kIGFjcm9ueW1zIGJvcmRlciBjb2xvclxuJGFiYnItYm9yZGVyLWNvbG9yOiAgICAgICAgICAgJGdyYXktbGlnaHQgIWRlZmF1bHQ7XG4vLyoqIEhlYWRpbmdzIHNtYWxsIGNvbG9yXG4kaGVhZGluZ3Mtc21hbGwtY29sb3I6ICAgICAgICAkZ3JheS1saWdodCAhZGVmYXVsdDtcbi8vKiogQmxvY2txdW90ZSBzbWFsbCBjb2xvclxuJGJsb2NrcXVvdGUtc21hbGwtY29sb3I6ICAgICAgJGdyYXktbGlnaHQgIWRlZmF1bHQ7XG4vLyoqIEJsb2NrcXVvdGUgZm9udCBzaXplXG4kYmxvY2txdW90ZS1mb250LXNpemU6ICAgICAgICAoJGZvbnQtc2l6ZS1iYXNlICogMS4yNSkgIWRlZmF1bHQ7XG4vLyoqIEJsb2NrcXVvdGUgYm9yZGVyIGNvbG9yXG4kYmxvY2txdW90ZS1ib3JkZXItY29sb3I6ICAgICAkZ3JheS1saWdodGVyICFkZWZhdWx0O1xuLy8qKiBQYWdlIGhlYWRlciBib3JkZXIgY29sb3JcbiRwYWdlLWhlYWRlci1ib3JkZXItY29sb3I6ICAgICRncmF5LWxpZ2h0ZXIgIWRlZmF1bHQ7XG4vLyoqIFdpZHRoIG9mIGhvcml6b250YWwgZGVzY3JpcHRpb24gbGlzdCB0aXRsZXNcbiRkbC1ob3Jpem9udGFsLW9mZnNldDogICAgICAgICRjb21wb25lbnQtb2Zmc2V0LWhvcml6b250YWwgIWRlZmF1bHQ7XG4vLyoqIFBvaW50IGF0IHdoaWNoIC5kbC1ob3Jpem9udGFsIGJlY29tZXMgaG9yaXpvbnRhbFxuJGRsLWhvcml6b250YWwtYnJlYWtwb2ludDogICAgJGdyaWQtZmxvYXQtYnJlYWtwb2ludCAhZGVmYXVsdDtcbi8vKiogSG9yaXpvbnRhbCBsaW5lIGNvbG9yLlxuJGhyLWJvcmRlcjogICAgICAgICAgICAgICAgICAgJGdyYXktbGlnaHRlciAhZGVmYXVsdDtcbiIsIi5sb2FkZXIge1xuICBmb250LXNpemU6IDEwcHg7XG4gIG1hcmdpbjogMCBhdXRvO1xuICB0ZXh0LWluZGVudDogLTk5OTllbTtcbiAgd2lkdGg6IDExZW07XG4gIGhlaWdodDogMTFlbTtcbiAgYm9yZGVyLXJhZGl1czogNTAlO1xuICBiYWNrZ3JvdW5kOiAjZmZmZmZmO1xuICBiYWNrZ3JvdW5kOiAtbW96LWxpbmVhci1ncmFkaWVudChsZWZ0LCAjZmZmZmZmIDEwJSwgcmdiYSgyNTUsIDI1NSwgMjU1LCAwKSA0MiUpO1xuICBiYWNrZ3JvdW5kOiAtd2Via2l0LWxpbmVhci1ncmFkaWVudChsZWZ0LCAjZmZmZmZmIDEwJSwgcmdiYSgyNTUsIDI1NSwgMjU1LCAwKSA0MiUpO1xuICBiYWNrZ3JvdW5kOiAtby1saW5lYXItZ3JhZGllbnQobGVmdCwgI2ZmZmZmZiAxMCUsIHJnYmEoMjU1LCAyNTUsIDI1NSwgMCkgNDIlKTtcbiAgYmFja2dyb3VuZDogLW1zLWxpbmVhci1ncmFkaWVudChsZWZ0LCAjZmZmZmZmIDEwJSwgcmdiYSgyNTUsIDI1NSwgMjU1LCAwKSA0MiUpO1xuICBiYWNrZ3JvdW5kOiBsaW5lYXItZ3JhZGllbnQodG8gcmlnaHQsICNmZmZmZmYgMTAlLCByZ2JhKDI1NSwgMjU1LCAyNTUsIDApIDQyJSk7XG4gIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgYW5pbWF0aW9uOiBsb2FkZXJTcGlubmVyIDEuNHMgaW5maW5pdGUgbGluZWFyO1xuICB0cmFuc2Zvcm06IHRyYW5zbGF0ZVooMCk7XG59XG4ubG9hZGVyOmJlZm9yZSB7XG4gIHdpZHRoOiA1MCU7XG4gIGhlaWdodDogNTAlO1xuICBiYWNrZ3JvdW5kOiAkYnJhbmQtcHJpbWFyeTtcbiAgYm9yZGVyLXJhZGl1czogMTAwJSAwIDAgMDtcbiAgcG9zaXRpb246IGFic29sdXRlO1xuICB0b3A6IDA7XG4gIGxlZnQ6IDA7XG4gIGNvbnRlbnQ6ICcnO1xufVxuLmxvYWRlcjphZnRlciB7XG4gIGJhY2tncm91bmQ6ICNmZmY7XG4gIHdpZHRoOiA3NSU7XG4gIGhlaWdodDogNzUlO1xuICBib3JkZXItcmFkaXVzOiA1MCU7XG4gIGNvbnRlbnQ6ICcnO1xuICBtYXJnaW46IGF1dG87XG4gIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgdG9wOiAwO1xuICBsZWZ0OiAwO1xuICBib3R0b206IDA7XG4gIHJpZ2h0OiAwO1xufVxuXG5Aa2V5ZnJhbWVzIGxvYWRlclNwaW5uZXIge1xuICAwJSB7XG4gICAgLXdlYmtpdC10cmFuc2Zvcm06IHJvdGF0ZSgwZGVnKTtcbiAgICB0cmFuc2Zvcm06IHJvdGF0ZSgwZGVnKTtcbiAgfVxuICAxMDAlIHtcbiAgICAtd2Via2l0LXRyYW5zZm9ybTogcm90YXRlKDM2MGRlZyk7XG4gICAgdHJhbnNmb3JtOiByb3RhdGUoMzYwZGVnKTtcbiAgfVxufSIsIkBpbXBvcnQgJy4uLy4uLy4uL3N0eWxlcy9hbmltYXRpb25zLnNjc3MnO1xuXG54b3MtdGFibGUge1xuXG4gIGRpc3BsYXk6IGJsb2NrO1xuXG4gIHRyLm5nLW1vdmUsXG4gIHRyLm5nLWVudGVyLFxuICB0ci5uZy1sZWF2ZSB7XG4gICAgdHJhbnNpdGlvbjphbGwgbGluZWFyIDAuNXM7XG4gIH1cblxuICB0ci5uZy1sZWF2ZS5uZy1sZWF2ZS1hY3RpdmUsXG4gIHRyLm5nLW1vdmUsXG4gIHRyLm5nLWVudGVyIHtcbiAgICBvcGFjaXR5OjA7XG4gICAgYW5pbWF0aW9uOiAwLjVzIHNsaWRlT3V0UmlnaHQgZWFzZS1pbi1vdXQ7XG4gIH1cblxuICB0ci5uZy1sZWF2ZSxcbiAgdHIubmctbW92ZS5uZy1tb3ZlLWFjdGl2ZSxcbiAgdHIubmctZW50ZXIubmctZW50ZXItYWN0aXZlIHtcbiAgICBvcGFjaXR5OjE7XG4gICAgYW5pbWF0aW9uOiAwLjVzIHNsaWRlSW5SaWdodCBlYXNlLWluLW91dDtcbiAgfVxuXG4gIHRkIGRsIHtcbiAgICBtYXJnaW4tYm90dG9tOiAwO1xuXG4gICAgZHQge1xuICAgICAgd2lkdGg6IGF1dG8gIWltcG9ydGFudDtcbiAgICAgIG1hcmdpbi1yaWdodDogMTBweDtcbiAgICB9XG4gICAgXG4gICAgZHQ6YWZ0ZXIge1xuICAgICAgLypkaXNwbGF5OiBibG9jazsqL1xuICAgICAgY29udGVudDogJzonO1xuICAgIH1cblxuICAgIGRkIHtcbiAgICAgIG1hcmdpbi1sZWZ0OiAwICFpbXBvcnRhbnQ7XG4gICAgfVxuICB9XG59IiwiQGltcG9ydCAnLi4vLi4vLi4vc3R5bGVzL2FuaW1hdGlvbnMuc2Nzcyc7XG5cbnhvcy1hbGVydCB7XG4gIG1hcmdpbi10b3A6ICRmb3JtLWdyb3VwLW1hcmdpbi1ib3R0b207XG4gIGRpc3BsYXk6IGJsb2NrO1xuXG4gIC8qIHdoZW4gaGlkaW5nICovXG4gIC5uZy1oaWRlLWFkZCAgICAgICAgIHsgYW5pbWF0aW9uOjAuNXMgZmFkZU91dERvd24gZWFzZS1pbi1vdXQ7IH1cblxuICAvKiB3aGVuIHNob3dpbmcgKi9cbiAgLm5nLWhpZGUtcmVtb3ZlICAgICAgeyBhbmltYXRpb246MC41cyBmYWRlSW5VcCBlYXNlLWluLW91dDsgfVxufSIsIkBpbXBvcnQgJy4uLy4uLy4uL3N0eWxlcy9hbmltYXRpb25zLnNjc3MnO1xuQGltcG9ydCAnLi4vLi4vLi4vLi4vLi4vLi4vc3R5bGUvc2Fzcy9ib290c3RyYXAvYm9vdHN0cmFwL192YXJpYWJsZXMuc2Nzcyc7XG5cbmlucHV0ICsgeG9zLXZhbGlkYXRpb24ge1xuICBtYXJnaW4tdG9wOiAkZm9ybS1ncm91cC1tYXJnaW4tYm90dG9tO1xuICBkaXNwbGF5OiBibG9jaztcbn0iLCJ4b3MtZmllbGQge1xuICBkaXNwbGF5OiBibG9jaztcbn0iLCJAaW1wb3J0ICcuLi8uLi8uLi9zdHlsZXMvYW5pbWF0aW9ucy5zY3NzJztcbkBpbXBvcnQgJy4uLy4uLy4uLy4uLy4uLy4uL3N0eWxlL3Nhc3MvYm9vdHN0cmFwL2Jvb3RzdHJhcC9fdmFyaWFibGVzLnNjc3MnO1xuXG54b3MtZm9ybSB7XG4gIGJ1dHRvbiB7XG4gICAgbWFyZ2luLWJvdHRvbTogJGZvcm0tZ3JvdXAtbWFyZ2luLWJvdHRvbTtcbiAgfVxufSIsInhvcy1zbWFydC10YWJsZXtcbiAgXG59Il0sIm1hcHBpbmdzIjoiQUNBQSxVQUFVLENBQUMsQUFBQSxZQUFZO0VBQ3JCLEFBQUEsSUFBSTtJQUNGLFNBQVMsRUFBRSx1QkFBVztJQUN0QixVQUFVLEVBQUUsT0FBUTtFQUd0QixBQUFBLEVBQUU7SUFDQSxTQUFTLEVBQUUsb0JBQVc7O0FBSTFCLFVBQVUsQ0FBQyxBQUFBLGFBQWE7RUFDdEIsQUFBQSxJQUFJO0lBQ0YsU0FBUyxFQUFFLG9CQUFXO0VBR3hCLEFBQUEsRUFBRTtJQUNBLFVBQVUsRUFBRSxNQUFPO0lBQ25CLFNBQVMsRUFBRSx1QkFBVzs7QUFJMUIsVUFBVSxDQUFDLEFBQUEsUUFBUTtFQUNqQixBQUFBLElBQUk7SUFDRixPQUFPLEVBQUUsQ0FBRTtJQUNYLFNBQVMsRUFBRSx1QkFBVztFQUd4QixBQUFBLEVBQUU7SUFDQSxPQUFPLEVBQUUsQ0FBRTtJQUNYLFNBQVMsRUFBRSxJQUFLOztBQUlwQixVQUFVLENBQUMsQUFBQSxXQUFXO0VBQ3BCLEFBQUEsSUFBSTtJQUNGLE9BQU8sRUFBRSxDQUFFO0VBR2IsQUFBQSxFQUFFO0lBQ0EsT0FBTyxFQUFFLENBQUU7SUFDWCxTQUFTLEVBQUUsdUJBQVc7O0FFekMxQixBQUFBLE9BQU8sQ0FBQztFQUNOLFNBQVMsRUFBRSxJQUFLO0VBQ2hCLE1BQU0sRUFBRSxNQUFPO0VBQ2YsV0FBVyxFQUFFLE9BQVE7RUFDckIsS0FBSyxFQUFFLElBQUs7RUFDWixNQUFNLEVBQUUsSUFBSztFQUNiLGFBQWEsRUFBRSxHQUFJO0VBQ25CLFVBQVUsRUFBRSxPQUFRO0VBQ3BCLFVBQVUsRUFBRSxtRUFBb0I7RUFDaEMsVUFBVSxFQUFFLHNFQUF1QjtFQUNuQyxVQUFVLEVBQUUsaUVBQWtCO0VBQzlCLFVBQVUsRUFBRSxrRUFBbUI7RUFDL0IsVUFBVSxFQUFFLGtFQUFlO0VBQzNCLFFBQVEsRUFBRSxRQUFTO0VBQ25CLFNBQVMsRUFBRSxrQ0FBbUM7RUFDOUMsU0FBUyxFQUFFLGFBQVUsR0FDdEI7O0FBQ0QsQUFBTyxPQUFBLEFBQUEsT0FBTyxDQUFDO0VBQ2IsS0FBSyxFQUFFLEdBQUk7RUFDWCxNQUFNLEVBQUUsR0FBSTtFQUNaLFVBQVUsRURIWSxPQUFNO0VDSTVCLGFBQWEsRUFBRSxVQUFXO0VBQzFCLFFBQVEsRUFBRSxRQUFTO0VBQ25CLEdBQUcsRUFBRSxDQUFFO0VBQ1AsSUFBSSxFQUFFLENBQUU7RUFDUixPQUFPLEVBQUUsRUFBRyxHQUNiOztBQUNELEFBQU8sT0FBQSxBQUFBLE1BQU0sQ0FBQztFQUNaLFVBQVUsRUFBRSxJQUFLO0VBQ2pCLEtBQUssRUFBRSxHQUFJO0VBQ1gsTUFBTSxFQUFFLEdBQUk7RUFDWixhQUFhLEVBQUUsR0FBSTtFQUNuQixPQUFPLEVBQUUsRUFBRztFQUNaLE1BQU0sRUFBRSxJQUFLO0VBQ2IsUUFBUSxFQUFFLFFBQVM7RUFDbkIsR0FBRyxFQUFFLENBQUU7RUFDUCxJQUFJLEVBQUUsQ0FBRTtFQUNSLE1BQU0sRUFBRSxDQUFFO0VBQ1YsS0FBSyxFQUFFLENBQUUsR0FDVjs7QUFFRCxVQUFVLENBQUMsQUFBQSxhQUFhO0VBQ3RCLEFBQUEsRUFBRTtJQUNBLGlCQUFpQixFQUFFLFlBQU07SUFDekIsU0FBUyxFQUFFLFlBQU07RUFFbkIsQUFBQSxJQUFJO0lBQ0YsaUJBQWlCLEVBQUUsY0FBTTtJQUN6QixTQUFTLEVBQUUsY0FBTTs7QUZoRHJCLFVBQVUsQ0FBQyxBQUFBLFlBQVk7RUFDckIsQUFBQSxJQUFJO0lBQ0YsU0FBUyxFQUFFLHVCQUFXO0lBQ3RCLFVBQVUsRUFBRSxPQUFRO0VBR3RCLEFBQUEsRUFBRTtJQUNBLFNBQVMsRUFBRSxvQkFBVzs7QUFJMUIsVUFBVSxDQUFDLEFBQUEsYUFBYTtFQUN0QixBQUFBLElBQUk7SUFDRixTQUFTLEVBQUUsb0JBQVc7RUFHeEIsQUFBQSxFQUFFO0lBQ0EsVUFBVSxFQUFFLE1BQU87SUFDbkIsU0FBUyxFQUFFLHVCQUFXOztBQUkxQixVQUFVLENBQUMsQUFBQSxRQUFRO0VBQ2pCLEFBQUEsSUFBSTtJQUNGLE9BQU8sRUFBRSxDQUFFO0lBQ1gsU0FBUyxFQUFFLHVCQUFXO0VBR3hCLEFBQUEsRUFBRTtJQUNBLE9BQU8sRUFBRSxDQUFFO0lBQ1gsU0FBUyxFQUFFLElBQUs7O0FBSXBCLFVBQVUsQ0FBQyxBQUFBLFdBQVc7RUFDcEIsQUFBQSxJQUFJO0lBQ0YsT0FBTyxFQUFFLENBQUU7RUFHYixBQUFBLEVBQUU7SUFDQSxPQUFPLEVBQUUsQ0FBRTtJQUNYLFNBQVMsRUFBRSx1QkFBVzs7QUd2QzFCLEFBQUEsU0FBUyxDQUFDO0VBRVIsT0FBTyxFQUFFLEtBQU0sR0F1Q2hCO0VBekNELEFBSUksU0FKSyxDQUlQLEVBQUUsQUFBQSxRQUFRO0VBSlosQUFLSSxTQUxLLENBS1AsRUFBRSxBQUFBLFNBQVM7RUFMYixBQU1JLFNBTkssQ0FNUCxFQUFFLEFBQUEsU0FBUyxDQUFDO0lBQ1YsVUFBVSxFQUFDLGVBQWdCLEdBQzVCO0VBUkgsQUFVYSxTQVZKLENBVVAsRUFBRSxBQUFBLFNBQVMsQUFBQSxnQkFBZ0I7RUFWN0IsQUFXSSxTQVhLLENBV1AsRUFBRSxBQUFBLFFBQVE7RUFYWixBQVlJLFNBWkssQ0FZUCxFQUFFLEFBQUEsU0FBUyxDQUFDO0lBQ1YsT0FBTyxFQUFDLENBQUU7SUFDVixTQUFTLEVBQUUsOEJBQStCLEdBQzNDO0VBZkgsQUFpQkksU0FqQkssQ0FpQlAsRUFBRSxBQUFBLFNBQVM7RUFqQmIsQUFrQlksU0FsQkgsQ0FrQlAsRUFBRSxBQUFBLFFBQVEsQUFBQSxlQUFlO0VBbEIzQixBQW1CYSxTQW5CSixDQW1CUCxFQUFFLEFBQUEsU0FBUyxBQUFBLGdCQUFnQixDQUFDO0lBQzFCLE9BQU8sRUFBQyxDQUFFO0lBQ1YsU0FBUyxFQUFFLDZCQUE4QixHQUMxQztFQXRCSCxBQXdCSyxTQXhCSSxDQXdCUCxFQUFFLENBQUMsRUFBRSxDQUFDO0lBQ0osYUFBYSxFQUFFLENBQUUsR0FlbEI7SUF4Q0gsQUEyQkksU0EzQkssQ0F3QlAsRUFBRSxDQUFDLEVBQUUsQ0FHSCxFQUFFLENBQUM7TUFDRCxLQUFLLEVBQUUsZUFBZ0I7TUFDdkIsWUFBWSxFQUFFLElBQUssR0FDcEI7SUE5QkwsQUFnQ00sU0FoQ0csQ0F3QlAsRUFBRSxDQUFDLEVBQUUsQ0FRSCxFQUFFLEFBQUEsTUFBTSxDQUFDO01BQ1AsbUJBQW1CO01BQ25CLE9BQU8sRUFBRSxHQUFJLEdBQ2Q7SUFuQ0wsQUFxQ0ksU0FyQ0ssQ0F3QlAsRUFBRSxDQUFDLEVBQUUsQ0FhSCxFQUFFLENBQUM7TUFDRCxXQUFXLEVBQUUsWUFBYSxHQUMzQjs7QUh6Q0wsVUFBVSxDQUFDLEFBQUEsWUFBWTtFQUNyQixBQUFBLElBQUk7SUFDRixTQUFTLEVBQUUsdUJBQVc7SUFDdEIsVUFBVSxFQUFFLE9BQVE7RUFHdEIsQUFBQSxFQUFFO0lBQ0EsU0FBUyxFQUFFLG9CQUFXOztBQUkxQixVQUFVLENBQUMsQUFBQSxhQUFhO0VBQ3RCLEFBQUEsSUFBSTtJQUNGLFNBQVMsRUFBRSxvQkFBVztFQUd4QixBQUFBLEVBQUU7SUFDQSxVQUFVLEVBQUUsTUFBTztJQUNuQixTQUFTLEVBQUUsdUJBQVc7O0FBSTFCLFVBQVUsQ0FBQyxBQUFBLFFBQVE7RUFDakIsQUFBQSxJQUFJO0lBQ0YsT0FBTyxFQUFFLENBQUU7SUFDWCxTQUFTLEVBQUUsdUJBQVc7RUFHeEIsQUFBQSxFQUFFO0lBQ0EsT0FBTyxFQUFFLENBQUU7SUFDWCxTQUFTLEVBQUUsSUFBSzs7QUFJcEIsVUFBVSxDQUFDLEFBQUEsV0FBVztFQUNwQixBQUFBLElBQUk7SUFDRixPQUFPLEVBQUUsQ0FBRTtFQUdiLEFBQUEsRUFBRTtJQUNBLE9BQU8sRUFBRSxDQUFFO0lBQ1gsU0FBUyxFQUFFLHVCQUFXOztBSXZDMUIsQUFBQSxTQUFTLENBQUM7RUFDUixVQUFVLEVIeU5xQixJQUFJO0VHeE5uQyxPQUFPLEVBQUUsS0FBTTtFQUVmLGlCQUFpQjtFQUdqQixrQkFBa0IsRUFFbkI7RUFURCxBQUtFLFNBTE8sQ0FLUCxZQUFZLENBQVM7SUFBRSxTQUFTLEVBQUMsNEJBQTZCLEdBQUk7RUFMcEUsQUFRRSxTQVJPLENBUVAsZUFBZSxDQUFNO0lBQUUsU0FBUyxFQUFDLHlCQUEwQixHQUFJOztBSlZqRSxVQUFVLENBQUMsQUFBQSxZQUFZO0VBQ3JCLEFBQUEsSUFBSTtJQUNGLFNBQVMsRUFBRSx1QkFBVztJQUN0QixVQUFVLEVBQUUsT0FBUTtFQUd0QixBQUFBLEVBQUU7SUFDQSxTQUFTLEVBQUUsb0JBQVc7O0FBSTFCLFVBQVUsQ0FBQyxBQUFBLGFBQWE7RUFDdEIsQUFBQSxJQUFJO0lBQ0YsU0FBUyxFQUFFLG9CQUFXO0VBR3hCLEFBQUEsRUFBRTtJQUNBLFVBQVUsRUFBRSxNQUFPO0lBQ25CLFNBQVMsRUFBRSx1QkFBVzs7QUFJMUIsVUFBVSxDQUFDLEFBQUEsUUFBUTtFQUNqQixBQUFBLElBQUk7SUFDRixPQUFPLEVBQUUsQ0FBRTtJQUNYLFNBQVMsRUFBRSx1QkFBVztFQUd4QixBQUFBLEVBQUU7SUFDQSxPQUFPLEVBQUUsQ0FBRTtJQUNYLFNBQVMsRUFBRSxJQUFLOztBQUlwQixVQUFVLENBQUMsQUFBQSxXQUFXO0VBQ3BCLEFBQUEsSUFBSTtJQUNGLE9BQU8sRUFBRSxDQUFFO0VBR2IsQUFBQSxFQUFFO0lBQ0EsT0FBTyxFQUFFLENBQUU7SUFDWCxTQUFTLEVBQUUsdUJBQVc7O0FLdEMxQixBQUFRLEtBQUgsR0FBRyxjQUFjLENBQUM7RUFDckIsVUFBVSxFSndOcUIsSUFBSTtFSXZObkMsT0FBTyxFQUFFLEtBQU0sR0FDaEI7O0FDTkQsQUFBQSxTQUFTLENBQUM7RUFDUixPQUFPLEVBQUUsS0FBTSxHQUNoQjs7QU5GRCxVQUFVLENBQUMsQUFBQSxZQUFZO0VBQ3JCLEFBQUEsSUFBSTtJQUNGLFNBQVMsRUFBRSx1QkFBVztJQUN0QixVQUFVLEVBQUUsT0FBUTtFQUd0QixBQUFBLEVBQUU7SUFDQSxTQUFTLEVBQUUsb0JBQVc7O0FBSTFCLFVBQVUsQ0FBQyxBQUFBLGFBQWE7RUFDdEIsQUFBQSxJQUFJO0lBQ0YsU0FBUyxFQUFFLG9CQUFXO0VBR3hCLEFBQUEsRUFBRTtJQUNBLFVBQVUsRUFBRSxNQUFPO0lBQ25CLFNBQVMsRUFBRSx1QkFBVzs7QUFJMUIsVUFBVSxDQUFDLEFBQUEsUUFBUTtFQUNqQixBQUFBLElBQUk7SUFDRixPQUFPLEVBQUUsQ0FBRTtJQUNYLFNBQVMsRUFBRSx1QkFBVztFQUd4QixBQUFBLEVBQUU7SUFDQSxPQUFPLEVBQUUsQ0FBRTtJQUNYLFNBQVMsRUFBRSxJQUFLOztBQUlwQixVQUFVLENBQUMsQUFBQSxXQUFXO0VBQ3BCLEFBQUEsSUFBSTtJQUNGLE9BQU8sRUFBRSxDQUFFO0VBR2IsQUFBQSxFQUFFO0lBQ0EsT0FBTyxFQUFFLENBQUU7SUFDWCxTQUFTLEVBQUUsdUJBQVc7O0FPdEMxQixBQUNFLFFBRE0sQ0FDTixNQUFNLENBQUM7RUFDTCxhQUFhLEVOdU5nQixJQUFJLEdNdE5sQzs7Q1JNSCxBQUFBLEFBQVUsU0FBVCxBQUFBLElBQVksQUFBQSxBQUFTLFFBQVIsQUFBQSxJQUFXLEFBQUEsQUFBYyxhQUFiLEFBQUEsSUFBZ0IsQUFBQSxBQUFXLFVBQVYsQUFBQSxHQUFhLEFBQUEsU0FBUyxFQUFFLEFBQUEsV0FBVyxDQUFDO0VBQzdFLE9BQU8sRUFBRSxlQUFnQixHQUMxQjs7QUFFRCxBQUFPLElBQUgsR0FBRyxJQUFJLENBQUM7RUFDViwwQkFBMEI7RUFDMUIsVUFBVSxFRTBNcUIsSUFBSSxHRnpNcEMiLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIvc291cmNlLyJ9 */
diff --git a/xos/core/static/xos_graphs.js b/xos/core/static/xos_graphs.js
new file mode 100644
index 0000000..d8690ed
--- /dev/null
+++ b/xos/core/static/xos_graphs.js
@@ -0,0 +1,120 @@
+google.load('visualization', '1', {'packages' : ['controls','table','corechart','geochart']});
+
+function renderChart(newStyle, dialog, container, dataSourceUrl, yColumn, xColumn, aggFunc, options) {
+    if ( newStyle ) {
+        $(dialog).dialog("open");
+    }
+    else {
+        $(container).empty();
+        $(dialog).modal('show');
+        $('.modal-body').scrollTop(0);
+    }
+
+    startQuery(container, dataSourceUrl, yColumn, xColumn, aggFunc, options)
+}
+
+function startQuery(container, dataSourceUrl, yColumn, xColumn, aggFunc, options) {
+    var query = new google.visualization.Query(dataSourceUrl);
+    query && query.abort();
+    query.send(function(response) {handleResponse_psg(container, dataSourceUrl, response, yColumn, xColumn, aggFunc, options);});
+}
+
+// NOTE: appended _psg to showLine() and handleResponse() to prevent conflict
+//       with Sapan's analytics page.
+
+function agg_bandwidth(arr) {
+        var ret = 0;
+        for (var i = 0; i < arr.length; i++) {
+                ret+=arr[i]*8.0/1024.0/1024.0/1024.0;
+        }
+        return ret;
+}
+
+function showLine_psg(container, dt, options) {
+    var base_options = {
+            'width': 520,
+            'height': 300,
+  	    'pages': true,
+	    'numRows': 9,
+            'backgroundColor': 'transparent',
+            'titleTextStyle': {"color": "black"},
+            'legend': 'none',
+            'hAxis': {"baselineColor": "darkBlue",
+                      "textStyle": {"color": "black"}},
+            'vAxis': {"baselineColor": "darkBlue",
+                      "textStyle": {"color": "black"}},
+          }
+
+    options = $.extend(true, {}, base_options, options);
+
+    var lineChart = new google.visualization.ChartWrapper({
+          'chartType': 'LineChart',
+          'containerId': container.substring(1),
+          'view': {'columns': [0, 1]},
+          'options': options
+        });
+        lineChart.setDataTable(dt);
+        lineChart.draw();
+
+}
+
+function fixDate(unixDate) {
+    return new Date(unixDate*1000);
+}
+
+function fixDate2(unixDate) {
+    return new Date(unixDate);
+}
+
+function handleResponse_psg(container, dataSourceUrl, response, yColumn, xColumn, aggFunc, options) {
+    var supportedClasses = {
+                    'Table':google.visualization.Table,
+                    'LineChart':google.visualization.LineChart,
+                    'ScatterChart':google.visualization.ScatterChart,
+                    'ColumnChart':google.visualization.ColumnChart,
+                    'GeoChart':google.visualization.GeoChart,
+                    'PieChart':google.visualization.PieChart,
+                    'Histogram':google.visualization.Histogram};
+
+    if (response.isError()) {
+        //console.log("retry chart");
+        setTimeout(function () { startQuery(container, dataSourceUrl, yColumn, xColumn, aggFunc, options) }, 5000);
+        return
+    }
+
+    var proxy = new google.visualization.ChartWrapper({
+      'chartType': 'Table',
+      'containerId': 'graph_work',
+      'options': {
+        'width': 800,
+        'height': 300,
+         pageSize:5,
+         page:'enable',
+        'legend': 'none',
+        'title': 'Nodes'
+      },
+      'view': {'columns': [0,1]}
+    });
+
+    google.visualization.events.addListener(proxy, 'ready', function () {
+        var dt = proxy.getDataTable();
+        var groupedData1 = google.visualization.data.group(dt, [{
+           column: yColumn,
+           type: 'datetime',
+           modifier: fixDate2,
+           }],
+           [{
+            column: xColumn,
+            type: 'number',
+            label: dt.getColumnLabel(xColumn),
+            aggregation: aggFunc}]);
+
+        showLine_psg(container, groupedData1, options);
+    });
+
+    proxy.setDataTable(response.getDataTable());
+
+    proxy.draw();
+}
+
+
diff --git a/xos/core/templates/slice_instance_tab.html b/xos/core/templates/slice_instance_tab.html
new file mode 100644
index 0000000..abcfea4
--- /dev/null
+++ b/xos/core/templates/slice_instance_tab.html
@@ -0,0 +1,82 @@
+{% if slice_id %}
+
+<a href="/admin/core/instance/add/?_to_field=id&slice={{ slice_id }}" id="add_instance_advanced"
+onclick="return addInstanceClicked(this);">
+Add Instance
+</a>
+<input type="hidden" id="instance_advanced" name="instance_advanced" onchange="console.log('changed');" value="initial">
+
+<script>
+
+// ugly - poll for django to change "instance_advanced", and it it does, then refresh the
+// page so the instance list gets updated.
+var last_instance_advanced = $("#instance_advanced").val();
+checkInstanceAdvanced = function() {
+    cur = $("#instance_advanced").val();
+    if (cur != last_instance_advanced) {
+        last_instance_advanced = cur;
+        location.reload();
+   }
+};
+
+setInterval(function() { checkInstanceAdvanced(); }, 1000);
+
+function showAddInstancePopup(triggeringLink) {
+    var name = triggeringLink.id.replace(/^add_/, '');
+    name = id_to_windowname(name);
+    var href = triggeringLink.href;
+    if (href.indexOf('?') == -1) {
+        href += '?_popup=1';
+    } else {
+        href  += '&_popup=1';
+    }
+    var win = window.open(href, name, 'height=500,width=1080,resizable=yes,scrollbars=yes');
+    win.focus();
+    return false;
+}
+
+function formIsDirty(form) {
+  console.log(form);
+  for (var i = 0; i < form.elements.length; i++) {

+    var element = form.elements[i];

+    var type = element.type;

+    if (type == "checkbox" || type == "radio") {

+      if (element.checked != element.defaultChecked) {

+        return true;

+      }

+    }

+    else if (type == "hidden" || type == "password" ||

+             type == "text" || type == "textarea") {

+      if (element.value != element.defaultValue) {

+        return true;

+      }

+    }

+    else if (type == "select-one" || type == "select-multiple") {

+      for (var j = 0; j < element.options.length; j++) {

+        if (element.options[j].selected !=

+            element.options[j].defaultSelected) {

+          return true;

+        }

+      }

+    }

+  }

+  return false;

+}
+
+function addInstanceClicked(link) {
+    if (formIsDirty($("#slice_form")[0])) {
+        console.log("dirty!!");
+        alert("Slice has modified fields. Please save the slice before adding instances.");
+        return false;
+    } else {
+        return showAddInstancePopup(link);
+    }
+}
+
+</script>
+
+{% else %}
+
+Please save this slice before adding Instances.
+
+{% endif %}
diff --git a/xos/core/templatetags/__init__.py b/xos/core/templatetags/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xos/core/templatetags/__init__.py
diff --git a/xos/core/templatetags/core_tags.py b/xos/core/templatetags/core_tags.py
new file mode 100644
index 0000000..a17be08
--- /dev/null
+++ b/xos/core/templatetags/core_tags.py
@@ -0,0 +1,25 @@
+from django import template
+# import sys
+from core.models import DashboardView
+from itertools import chain
+from core.dashboard.views.home import DashboardDynamicView
+
+register = template.Library()
+
+
+@register.inclusion_tag('admin/tags/dashboard_list.html', takes_context=True)
+def dashboard_list(context):
+    request = context['request']
+    if request.user.is_authenticated():
+        dashboards = request.user.get_dashboards()
+        customize = DashboardView.objects.filter(name="Customize")
+        result_list = list(chain(dashboards, customize))
+    else:
+        result_list = []
+    return {'dashboards': result_list, 'path': request.path}
+
+
+@register.inclusion_tag('admin/tags/notification.html', takes_context=True)
+def notification(context):
+    template = DashboardDynamicView.readTemplate(DashboardDynamicView(), "xosSynchronizerNotifier")
+    return {'template': template}
diff --git a/xos/core/tests.py b/xos/core/tests.py
new file mode 100644
index 0000000..06bf678
--- /dev/null
+++ b/xos/core/tests.py
@@ -0,0 +1,337 @@
+# TEST
+# To execute these tests use `python manage.py test core`
+
+#!/usr/bin/env python
+from django.test import TestCase
+from django.contrib.auth.models import User
+from rest_framework import status
+from rest_framework.test import APIClient
+from rest_framework.test import APITestCase
+import json
+from django.forms.models import model_to_dict
+
+from core.models import *
+
+print "-------------------------- Let's test!!!!!!!! --------------------------"
+
+from django.apps import apps
+from django.test.client import Client
+from django.test import testcases
+from django.http import SimpleCookie, HttpRequest, QueryDict
+from importlib import import_module
+from django.conf import settings
+class FixedClient(Client):
+    def login(self, **credentials):
+        """
+        Sets the Factory to appear as if it has successfully logged into a site.
+
+        Returns True if login is possible; False if the provided credentials
+        are incorrect, or the user is inactive, or if the sessions framework is
+        not available.
+        """
+        from django.contrib.auth import authenticate, login
+        user = authenticate(**credentials)
+        if (user and user.is_active and
+                apps.is_installed('django.contrib.sessions')):
+            engine = import_module(settings.SESSION_ENGINE)
+
+            # Create a fake request to store login details.
+            request = HttpRequest()
+
+            # XOS's admin.py requires these to be filled in
+            request.POST = {"username": credentials["username"],
+                            "password": credentials["password"]}
+
+            if self.session:
+                request.session = self.session
+            else:
+                request.session = engine.SessionStore()
+            login(request, user)
+
+            # Save the session values.
+            request.session.save()
+
+            # Set the cookie to represent the session.
+            session_cookie = settings.SESSION_COOKIE_NAME
+            self.cookies[session_cookie] = request.session.session_key
+            cookie_data = {
+                'max-age': None,
+                'path': '/',
+                'domain': settings.SESSION_COOKIE_DOMAIN,
+                'secure': settings.SESSION_COOKIE_SECURE or None,
+                'expires': None,
+                }
+            self.cookies[session_cookie].update(cookie_data)
+
+            return True
+        else:
+            return False
+
+class FixedAPITestCase(testcases.TestCase):
+    client_class = FixedClient
+
+# Environment Tests - Should pass everytime, if not something in the config is broken.
+class SimpleTest(TestCase):
+    fixtures = []
+
+    def test_basic_addition(self):
+        """
+        Tests that 1 + 1 always equals 2.
+        """
+        self.assertEqual(1 + 1, 2)
+
+
+# Site Test
+class SiteTest(TestCase):
+    fixtures = []
+
+    def setUp(self):
+        Site.objects.create(
+            name="Test Site",
+            login_base="test_"
+        )
+
+    def test_read_site(self):
+        """
+        Should read a site in the DB.
+        """
+        site = Site.objects.get(name="Test Site")
+        # print(site._meta.get_all_field_names())
+        self.assertEqual(site.login_base, "test_")
+
+
+class UnautheticatedRequest(FixedAPITestCase):
+    fixtures = []
+
+    def test_require_authentication(self):
+        """
+        Ensure that request must be authenticated
+        """
+        response = self.client.get('/xos/sites/', format='json')
+        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
+
+
+class SiteTestAPI(FixedAPITestCase):
+    fixtures = []
+
+    def setUp(self):
+        self.site = Site.objects.create(
+            name="Test Site",
+            login_base="test_"
+        )
+        self.user = User(
+            username='testuser',
+            email='test@mail.org',
+            password='testing',
+            site=self.site,
+            is_admin=True
+        )
+        self.user.save()
+        self.client.login(username='test@mail.org', password='testing')
+
+    def test_read_site_API(self):
+        """
+        Read a Site trough API
+        """
+        response = self.client.get('/xos/sites/', format='json')
+        parsed = json.loads(response.content)
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        self.assertEqual(len(parsed), 1)
+        self.assertEqual(parsed[0]['login_base'], 'test_')
+
+    def test_create_site_API(self):
+        """
+        Create a Site trough API
+        """
+        data = {
+            'name': "Another Test Site",
+            'login_base': "another_test_",
+            'location': [10, 20],
+            'abbreviated_name': 'test'
+        }
+        response = self.client.post('/xos/sites/', data, format='json')
+        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
+        self.assertEqual(Site.objects.count(), 2)
+        self.assertEqual(Site.objects.filter(name="Another Test Site").count(), 1)
+
+
+class SliceTestAPI(FixedAPITestCase):
+    fixtures = []
+
+    def setUp(self):
+        self.site = Site.objects.create(
+            name="Test Site",
+            login_base="test_"
+        )
+        self.pi = SiteRole.objects.create(role='pi')
+        self.user = User(
+            username='testuser',
+            email='test@mail.org',
+            password='testing',
+            site=self.site
+        )
+        self.user.save()
+        self.siteprivileges = SitePrivilege.objects.create(
+            user=self.user,
+            site=self.site,
+            role=self.pi
+        )
+        self.serviceClass = ServiceClass.objects.create(
+            name='Test Service Class'
+        )
+        self.client.login(username='test@mail.org', password='testing')
+
+    def test_create_site_slice(self):
+        """
+        Add a slice to a given site
+        """
+        data = {
+            'name': "test_slice",
+            'site': self.site.id,
+            'serviceClass': self.serviceClass.id
+        }
+        response = self.client.post('/xos/slices/?no_hyperlinks=1', data, format='json')
+        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
+
+    def test_validation_slice_name(self):
+        """
+        The slice name should start with site.login_base
+        curl -H "Accept: application/json; indent=4" -u padmin@vicci.org:letmein 'http://xos:9999/xos/slices/?no_hyperlinks=1' -H "Content-Type: application/json" -X POST --data '{"name": "test", "site":"1", "serviceClass":1}'
+        """
+        data = {
+            'name': "wrong_slice",
+            'site': self.site.id,
+            'serviceClass': self.serviceClass.id
+        }
+        response = self.client.post('/xos/slices/?no_hyperlinks=1', data, format='json')
+        parsed = json.loads(response.content)
+        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
+        self.assertEqual(parsed['detail']['specific_error'], "slice name must begin with test_")
+
+    def test_only_admin_can_change_creator(self):
+        """
+        Only an admin can change the creator of a slice
+        """
+        slice = Slice.objects.create(
+            name="test_slice",
+            site=self.site,
+            serviceClass=self.serviceClass,
+            creator=self.user
+        )
+
+        user2 = User(
+            username='another_testuser',
+            email='another_test@mail.org',
+            password='testing',
+            site=self.site
+        )
+        user2.save()
+
+        data = model_to_dict(slice)
+        data['creator'] = user2.id
+        json_data = json.dumps(data)
+
+        response = self.client.put('/xos/slices/%s/?no_hyperlinks=1' % slice.id, json_data, format='json', content_type="application/json")
+        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
+        parsed = json.loads(response.content)
+        self.assertEqual(parsed['detail']['specific_error'], "Insufficient privileges to change slice creator")
+
+class ServiceTestAPI(FixedAPITestCase):
+    fixtures = []
+
+    def setUp(self):
+        self.site = Site.objects.create(
+            name="Test Site",
+            login_base="test_"
+        )
+        self.admin = User(
+            username='testadmin',
+            email='admin@mail.org',
+            password='testing',
+            site=self.site,
+            is_admin=True
+        )
+        self.admin.save()
+
+        self.user = User(
+            username='testuser',
+            email='user@mail.org',
+            password='testing',
+            site=self.site
+        )
+        self.user.save()
+
+        self.service1 = Service.objects.create(
+            name="fakeService1",
+            versionNumber="1.0.0",
+            published=True,
+            enabled=True
+        )
+
+        self.service2 = Service.objects.create(
+            name="fakeService1",
+            versionNumber="1.0.0",
+            published=True,
+            enabled=True
+        )
+
+        self.service_role = ServiceRole.objects.create(role='admin')
+
+        self.service_privileges = ServicePrivilege.objects.create(
+            user=self.user,
+            service=self.service2,
+            role=self.service_role
+        )
+
+    # TODO
+    # [x] admin view all service
+    # [ ] user view only service2
+    # [x] admin view a specific service service
+    # [ ] user view can't view a specific service
+    # [ ] user update service2
+    # [ ] usercan NOT update service2
+    # [x] admin update service1
+    def test_admin_read_all_service(self):
+        """
+        Admin should read all the services
+        """
+        self.client.login(username='admin@mail.org', password='testing')
+        response = self.client.get('/xos/services/', format='json')
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        self.assertEqual(len(json.loads(response.content)), 2)
+
+    # need to understand how slices are related
+    def xtest_user_read_all_service(self):
+        """
+        User should read only service for which have privileges
+        """
+        self.client.login(username='user@mail.org', password='testing')
+        response = self.client.get('/xos/services/', format='json')
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        self.assertEqual(len(json.loads(response.content)), 1)
+
+    def test_admin_read_one_service(self):
+        """
+        Read a given service
+        """
+        self.client.login(username='admin@mail.org', password='testing')
+        response = self.client.get('/xos/services/%s/' % self.service1.id, format='json')
+        parsed = json.loads(response.content)
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        self.assertEqual(parsed['name'], self.service1.name)
+
+    def test_admin_update_service(self):
+        """
+        Update a given service
+        """
+        data = model_to_dict(self.service1)
+        data['name'] = "newName"
+        json_data = json.dumps(data)
+
+        self.client.login(username='admin@mail.org', password='testing')
+        response = self.client.put('/xos/services/%s/' % self.service1.id, json_data, format='json', content_type="application/json")
+        parsed = json.loads(response.content)
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        model = Service.objects.get(id=self.service1.id)
+        self.assertEqual(model.name, data['name'])
+        
\ No newline at end of file
diff --git a/xos/core/views/__init__.py b/xos/core/views/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xos/core/views/__init__.py
diff --git a/xos/core/views/hpc_config.py b/xos/core/views/hpc_config.py
new file mode 100644
index 0000000..a181a1c
--- /dev/null
+++ b/xos/core/views/hpc_config.py
@@ -0,0 +1,131 @@
+from django.http import HttpResponse, HttpResponseServerError
+from core.models import *
+from services.hpc.models import *
+from services.requestrouter.models import *
+import xos.settings
+import json
+import os
+import time
+
+def get_service_slices(service):
+    try:
+       return service.slices.all()
+    except:
+       # this field used to be improperly named, and makemigrations won't fix it
+       return service.service.all()
+
+def HpcConfig(request):
+    hpcSlice=None
+    cmiSlice=None
+    redirSlice=None
+    demuxSlice=None
+
+    node_slicename = request.GET.get("slicename", None)
+    if not node_slicename:
+        return HttpResponseServerError("Error: no slicename passed in request")
+
+    # search for an HPC Service that owns the slicename that was passed
+    # to us.
+    hpc=None
+    for candidate in HpcService.objects.all():
+        if candidate.cmi_hostname == node_slicename:
+            # A hack for standalone CMIs that aren't managed by XOS. Set
+            # /etc/slicename to cmi_hostname that's configured in the
+            # HPCService object.
+            hpc = candidate
+
+        for slice in get_service_slices(candidate):
+            if slice.name == node_slicename:
+                hpc = candidate
+
+    if (not hpc):
+        return HttpResponseServerError("Error: no HPC service")
+
+    for slice in get_service_slices(hpc):
+        if "cmi" in slice.name:
+            cmiSlice = slice
+        elif ("hpc" in slice.name) or ("vcoblitz" in slice.name):
+            hpcSlice = slice
+        elif "redir" in slice.name:
+            redirSlice = slice
+        elif "demux" in slice.name:
+            demuxSlice = slice
+
+    if (hpc.cmi_hostname):
+        cmi_hostname = hpc.cmi_hostname
+    else:
+        if not cmiSlice:
+            return HttpResponseServerError("Error: no CMI slice")
+
+        if len(cmiSlice.instances.all())==0:
+            return HttpResponseServerError("Error: CMI slice has no instances")
+
+        # for now, assuming using NAT
+        cmi_hostname = cmiSlice.instances.all()[0].node.name
+
+    if not hpcSlice:
+        return HttpResponseServerError("Error: no HPC slice")
+
+    if (redirSlice==None) or (demuxSlice==None):
+        # The HPC Service didn't have a dnsredir or a dnsdemux, so try looking
+        # in the RequestRouterService for one.
+
+        rr = RequestRouterService.objects.all()
+        if not (rr):
+            return HttpResponseServerError("Error: no RR service")
+
+        rr = rr[0]
+        try:
+           slices = rr.slices.all()
+        except:
+           # this field used to be improperly named, and makemigrations won't fix it
+           slices = rr.service.all()
+        for slice in slices:
+            if "redir" in slice.name:
+                redirSlice = slice
+            elif "demux" in slice.name:
+                demuxSlice = slice
+
+    if not redirSlice:
+        return HttpResponseServerError("Error: no dnsredir slice")
+
+    if not demuxSlice:
+        return HttpResponseServerError("Error: no dnsdemux slice")
+
+    d = {}
+    d["hpc_slicename"] = hpcSlice.name
+    d["redir_slicename"] = redirSlice.name
+    d["demux_slicename"] = demuxSlice.name
+    d["cmi_hostname"] = cmi_hostname
+    d["xos_hostname"] = xos.settings.RESTAPI_HOSTNAME
+    d["xos_port"] = str(xos.settings.RESTAPI_PORT)
+
+    if hpc.hpc_port80:
+        d["hpc_port80"] = "True"
+    else:
+        d["hpc_port80"] = "False"
+
+    return HttpResponse("""# auto-generated by HpcConfig
+ENABLE_PLC=False
+ENABLE_PS=True
+BASE_HRN="princeton"
+RELEVANT_SERVICE_NAMES=['vcoblitz', 'coredirect', 'codnsdemux', "syndicate_comon_server"]
+COBLITZ_SLICE_NAME=BASE_HRN+"_vcoblitz"
+COBLITZ_SLICE_ID=70
+COBLITZ_PS_SLICE_NAME="{hpc_slicename}"
+DNSREDIR_SLICE_NAME=BASE_HRN+"_coredirect"
+DNSREDIR_SLICE_ID=71
+DNSREDIR_PS_SLICE_NAME="{redir_slicename}"
+DNSDEMUX_SLICE_NAME=BASE_HRN+"_codnsdemux"
+DNSDEMUX_SLICE_ID=69
+DNSDEMUX_PS_SLICE_NAME="{demux_slicename}"
+CMI_URL="http://{cmi_hostname}/"
+CMI_HTTP_PORT="8004"
+CMI_HTTPS_PORT="8003"
+PUPPET_MASTER_HOSTNAME="{cmi_hostname}"
+PUPPET_MASTER_PORT="8140"
+PS_HOSTNAME="{xos_hostname}"
+PS_PORT="{xos_port}"
+COBLITZ_PORT_80={hpc_port80}
+""".format(**d))
+
diff --git a/xos/core/views/legacyapi.py b/xos/core/views/legacyapi.py
new file mode 100644
index 0000000..b5592c0
--- /dev/null
+++ b/xos/core/views/legacyapi.py
@@ -0,0 +1,353 @@
+import os
+import json
+import socket
+import sys
+import time
+import traceback
+import xmlrpclib
+
+from core.models import Slice, Instance, ServiceClass, Reservation, Tag, Network, User, Node, Image, Deployment, Site, NetworkTemplate, NetworkSlice
+
+from django.http import HttpResponse
+from django.views.decorators.csrf import csrf_exempt
+
+def ps_id_to_pl_id(x):
+    # Since we don't want the XOS object IDs to conflict with existing
+    # PlanetLab object IDs in the CMI, just add 100000 to the XOS object
+    # IDs.
+    return 100000 + x
+
+def pl_id_to_ps_id(x):
+    return x - 100000
+
+# slice_remap is a dict of ps_slice_name -> (pl_slice_name, pl_slice_id)
+
+def pl_slice_id(slice, slice_remap={}):
+    if slice.name in slice_remap:
+        return int(slice_remap[slice.name][1])
+    else:
+        return ps_id_to_pl_id(slice.id)
+
+def pl_slicename(slice, slice_remap={}):
+    if slice.name in slice_remap:
+        return slice_remap[slice.name][0]
+    else:
+        return slice.name
+
+def filter_fields(src, fields):
+    dest = {}
+    for (key,value) in src.items():
+        if (not fields) or (key in fields):
+            dest[key] = value
+    return dest
+
+def GetSlices(filter={}, slice_remap={}):
+    #ps_slices = Slice.objects.filter(**filter)
+    ps_slices = Slice.objects.all()
+    slices = []
+    for ps_slice in ps_slices:
+        if (filter) and ("name" in filter):
+            remapped_name = slice_remap.get(ps_slice.name, (ps_slice.name,))[0]
+            if (remapped_name != filter["name"]):
+                continue
+
+        node_ids=[]
+        for ps_instance in ps_slice.instances.all():
+            node_ids.append(ps_id_to_pl_id(ps_instance.node.id))
+
+        slice = {"instantiation": "plc-instantiated",
+                 "description": "XOS slice",
+                 "slice_id": pl_slice_id(ps_slice, slice_remap),
+                 "node_ids": node_ids,
+                 "url": "xos",
+                 "max_nodes": 1000,
+                 "peer_slice_id": None,
+                 "slice_tag_ids": [],
+                 "peer_id": None,
+                 "site_id": ps_id_to_pl_id(ps_slice.site_id),
+                 "name": pl_slicename(ps_slice, slice_remap),
+                 "planetstack_name": ps_slice.name}     # keeping planetstack_name for now, to match the modified config.py
+
+                 # creator_person_id, person_ids, expires, created
+
+        slices.append(slice)
+    return slices
+
+def GetNodes(node_ids=None, fields=None, slice_remap={}):
+    if node_ids:
+        ps_nodes = Node.objects.filter(id__in=[pl_id_to_ps_id(nid) for nid in node_ids])
+    else:
+        ps_nodes = Node.objects.all()
+    nodes = []
+    for ps_node in ps_nodes:
+        slice_ids=[]
+        for ps_instance in ps_node.instances.all():
+            slice_ids.append(pl_slice_id(ps_instance.slice, slice_remap))
+
+        node = {"node_id": ps_id_to_pl_id(ps_node.id),
+                "site_id": ps_id_to_pl_id(ps_node.site_id),
+                "node_type": "regular",
+                "peer_node_id": None,
+                "hostname": ps_node.name.lower(),
+                "conf_file_ids": [],
+                "slice_ids": slice_ids,
+                "model": "xos",
+                "peer_id": None,
+                "node_tag_ids": []}
+
+                # last_updated, key, boot_state, pcu_ids, node_type, session, last_boot,
+                # interface_ids, slice_ids_whitelist, run_level, ssh_rsa_key, last_pcu_reboot,
+                # nodegroup_ids, verified, last_contact, boot_nonce, version,
+                # last_pcu_configuration, last_download, date_created, ports
+
+        nodes.append(node)
+
+    nodes = [filter_fields(node, fields) for node in nodes]
+
+    return nodes
+
+def GetTags(slicename,node_id):
+    return {}
+
+def GetSites(slice_remap={}):
+    ps_sites = Site.objects.all()
+    sites = []
+    for ps_site in ps_sites:
+        slice_ids=[]
+        for ps_slice in ps_site.slices.all():
+            slice_ids.append(pl_slice_id(ps_slice, slice_remap))
+
+        node_ids=[]
+        for ps_node in ps_site.nodes.all():
+            node_ids.append(ps_id_to_pl_id(ps_node.id))
+
+        if ps_site.location:
+            longitude = ps_site.location.longitude
+            latitude = ps_site.location.latitude
+        else:
+            longitude = 0
+            latitude = 0
+
+        site = {"site_id": ps_id_to_pl_id(ps_site.id),
+                "node_ids": node_ids,
+                "pcu_ids": [],
+                "max_slices": 100,
+                "max_instances": 1000,
+                "is_public": False,
+                "peer_site_id": None,
+                "abbrebiated_name": ps_site.abbreviated_name,
+                "address_ids": [],
+                "name": ps_site.name,
+                "url": None,
+                "site_tag_ids": [],
+                "enabled": True,
+                "longitude": float(longitude),
+                "latitude": float(latitude),
+                "slice_ids": slice_ids,
+                "login_base": ps_site.login_base,
+                "peer_id": None}
+
+                # last_updated, ext_consortium_id, person_ids, date_created
+
+        sites.append(site)
+
+    return sites
+
+def GetInterfaces(slicename, node_ids, return_nat=False, return_private=False):
+    interfaces = []
+    ps_slices = Slice.objects.filter(name=slicename)
+    for ps_slice in ps_slices:
+        for ps_instance in ps_slice.instances.all():
+            node_id = ps_id_to_pl_id(ps_instance.node_id)
+            if node_id in node_ids:
+                ps_node = ps_instance.node
+
+                ip = socket.gethostbyname(ps_node.name.strip())
+
+                # If the slice has a network that's labeled for hpc_client, then
+                # return that network.
+                found_labeled_network = False
+                for port in ps_instance.ports.all():
+                    if (not port.ip):
+                        continue
+                    if (port.network.owner != ps_slice):
+                        continue
+                    if port.network.labels and ("hpc_client" in port.network.labels):
+                        ip=port.ip
+                        found_labeled_network = True
+
+                if not found_labeled_network:
+                    # search for a dedicated public IP address
+                    for port in ps_instance.ports.all():
+                        if (not port.ip):
+                            continue
+                        template = port.network.template
+                        if (template.visibility=="public") and (template.translation=="none"):
+                            ip=port.ip
+
+                if return_nat:
+                    ip = None
+                    for port in ps_instance.ports.all():
+                        if (not port.ip):
+                            continue
+                        template = port.network.template
+                        if (template.visibility=="private") and (template.translation=="NAT"):
+                            ip=port.ip
+                    if not ip:
+                        continue
+
+                if return_private:
+                    ip = None
+                    for port in ps_instance.ports.all():
+                        if (not port.ip):
+                            continue
+                        template = port.network.template
+                        if (template.visibility=="private") and (template.translation=="none"):
+                            ip=port.ip
+                    if not ip:
+                        continue
+
+                interface = {"node_id": node_id,
+                             "ip": ip,
+                             "broadcast": None,
+                             "mac": "11:22:33:44:55:66",
+                             "bwlimit": None,
+                             "network": None,
+                             "is_primary": True,
+                             "dns1": None,
+                             "hostname": None,
+                             "netmask": None,
+                             "interface_tag_ids": [],
+                             "interface_id": node_id,     # assume each node has only one interface
+                             "gateway": None,
+                             "dns2": None,
+                             "type": "ipv4",
+                             "method": "dhcp"}
+                interfaces.append(interface)
+    return interfaces
+
+def GetConfiguration(name, slice_remap={}):
+    slicename = name["name"]
+    if "node_id" in name:
+        node_id = name["node_id"]
+    else:
+        node_id = 0
+
+    node_instance_tags = GetTags(slicename, node_id)
+
+    slices = GetSlices({"name": slicename}, slice_remap=slice_remap)
+    perhost = {}
+    allinterfaces = {}
+    hostprivmap = {}
+    hostipmap = {}
+    hostnatmap = {}
+    nodes = []
+    if len(slices)==1:
+        slice = slices[0]
+        node_ids = slice['node_ids']
+        nodes = GetNodes(node_ids, ['hostname', 'node_id', 'site_id'], slice_remap=slice_remap)
+        nodemap = {}
+        for node in nodes:
+            nodemap[node['node_id']]=node['hostname']
+
+        interfaces = GetInterfaces(slice["planetstack_name"], node_ids)
+        hostipmap = {}
+        for interface in interfaces:
+            if nodemap[interface['node_id']] not in allinterfaces:
+                allinterfaces[nodemap[interface['node_id']]] = []
+            interface['interface_tags'] = []
+            allinterfaces[nodemap[interface['node_id']]].append(interface)
+            if interface['is_primary']:
+                hostipmap[nodemap[interface['node_id']]] = interface['ip']
+
+        hostnatmap = {}
+        interfaces = GetInterfaces(slice["planetstack_name"], node_ids, return_nat=True)
+        for interface in interfaces:
+            interface['interface_tags'] = []
+            hostnatmap[nodemap[interface['node_id']]] = interface['ip']
+
+        hostprivmap = {}
+        interfaces = GetInterfaces(slice["planetstack_name"], node_ids, return_private=True)
+        for interface in interfaces:
+            interface['interface_tags'] = []
+            hostprivmap[nodemap[interface['node_id']]] = interface['ip']
+
+        for nid in node_ids:
+            instance_tags = GetTags(slicename,nid)
+            perhost[nodemap[nid]] = instance_tags
+
+    instances = GetSlices(slice_remap=slice_remap)
+    if node_id != 0:
+        instances = [slice for slice in instances if (node_id in slice.node_ids)]
+
+    sites = GetSites(slice_remap=slice_remap)
+    for site in sites:
+        site["site_tags"] = []
+
+    timestamp = int(time.time())
+    return {'version': 3,
+            'timestamp': timestamp,
+            'configuration': node_instance_tags,
+            'allconfigurations':perhost,
+            'hostipmap':hostipmap,
+            'hostnatmap':hostnatmap,
+            'hostprivmap':hostprivmap,
+            'slivers': instances,
+            'interfaces': allinterfaces,
+            'sites': sites,
+            'nodes': nodes}
+
+DEFAULT_REMAP = {"princeton_vcoblitz2": ["princeton_vcoblitz", 70]}
+
+def HandleGetConfiguration1():
+    configs={}
+    for slicename in ["princeton_vcoblitz"]:
+        configs[slicename] = GetConfiguration({"name": slicename}, DEFAULT_REMAP)
+    return configs
+
+def HandleGetNodes1():
+    return GetNodes(slice_remap=DEFAULT_REMAP)
+
+def HandleGetSlices1():
+    return GetSlices(slice_remap=DEFAULT_REMAP)
+
+def HandleGetConfiguration2(name, slice_remap):
+    return GetConfiguration(name, slice_remap=slice_remap)
+
+def HandleGetNodes2(slice_remap):
+    return GetNodes(slice_remap=slice_remap)
+
+def HandleGetSlices2(slice_remap):
+    return GetSlices(slice_remap=slice_remap)
+
+FUNCS = {"GetConfiguration": HandleGetConfiguration1,
+         "GetNodes": HandleGetNodes1,
+         "GetSlices": HandleGetSlices1,
+         "GetConfiguration2": HandleGetConfiguration2,
+         "GetNodes2": HandleGetNodes2,
+         "GetSlices2": HandleGetSlices2}
+
+@csrf_exempt
+def LegacyXMLRPC(request):
+    if request.method == "POST":
+        try:
+            (args, method) = xmlrpclib.loads(request.body)
+            result = None
+            if method in FUNCS:
+                result = FUNCS[method](*args)
+            return HttpResponse(xmlrpclib.dumps((result,), methodresponse=True, allow_none=1))
+        except:
+            traceback.print_exc()
+            return HttpResponseServerError()
+    else:
+        return HttpResponse("Not Implemented")
+
+if __name__ == '__main__':
+    slices = GetSlices(slice_remap = DEFAULT_REMAP)
+    nodes = GetNodes(slice_remap = DEFAULT_REMAP)
+
+    config = GetConfiguration({"name": "princeton_vcoblitz"}, slice_remap = DEFAULT_REMAP)
+    print config
+    print slices
+    print nodes
+
diff --git a/xos/core/views/mCordServiceGrid.py b/xos/core/views/mCordServiceGrid.py
new file mode 100644
index 0000000..56c820a
--- /dev/null
+++ b/xos/core/views/mCordServiceGrid.py
@@ -0,0 +1,72 @@
+from django.http import HttpResponse
+from django.views.generic import TemplateView, View
+from django import template
+from django.shortcuts import render
+from core.models import *
+import json
+import os
+import time
+import tempfile
+
+
+class ServiceGridView(TemplateView):
+    head_template = r"""{% extends "admin/dashboard/dashboard_base.html" %}
+       {% load admin_static %}
+       {% block content %}
+    """
+
+    # I hate myself for doing this
+    script = """
+    <script type="text/javascript">
+        $(window).ready(function(){
+            $('.kind-container').on('click', function(){
+                $(this).toggleClass('active')
+            });
+        })
+    </script>
+    """
+
+    tail_template = r"{% endblock %}"
+
+    def get(self, request, name="root", *args, **kwargs):
+        head_template = self.head_template
+        tail_template = self.tail_template
+        html = self.script
+        html = html + '<div class="col-xs-12 m-cord">'
+
+        # Select the unique kind of services
+        for kind in Service.objects.values('kind').distinct():
+
+            html = html + '<div class="kind-container row">'
+            html = html + '<div class="col-xs-12"><h2>%s</h2></div>' % (kind["kind"])
+
+            # for each kind select services
+            for service in Service.objects.filter(kind=kind["kind"]):
+                image_url = service.icon_url
+                if (not image_url):
+                    image_url = "/static/mCordServices/service_common.png"
+                #if service.view_url.startswith("http"):
+                #    target = 'target="_blank"'
+                #else:
+                #    target = ''
+                target = ''
+
+                html = html + '<div class="col-xs-4 text-center service-container">'
+                html = html + '<a href="%s" %s>' % (service.view_url, target)
+                html = html + '<img class="img-responsive" src="%s">' % (image_url)
+                html = html + "<h4>" + service.name + "</h4>"
+                html = html + '</a>'
+                html = html + "</div>"
+
+            html = html + "</div>"
+
+        html = html + "</div>"
+        t = template.Template(head_template + html + self.tail_template)
+
+        response_kwargs = {}
+        response_kwargs.setdefault('content_type', self.content_type)
+        return self.response_class(
+            request=request,
+            template=t,
+            **response_kwargs
+        )
diff --git a/xos/core/views/observer.py b/xos/core/views/observer.py
new file mode 100644
index 0000000..ff3ee28
--- /dev/null
+++ b/xos/core/views/observer.py
@@ -0,0 +1,31 @@
+from django.http import HttpResponse
+from core.models import *
+from xos.config import Config
+import json
+import os
+import time
+
+def Observer(request):
+    try:
+        observer_name = Config().observer_name
+    except AttributeError:
+        observer_name = 'openstack'
+
+    diag = Diag.objects.filter(name=observer_name).first()
+    if not diag:
+        return HttpResponse(json.dumps({"health": ":-X", "time": time.time(), "comp": 0}))
+
+    t = time.time()
+
+    
+    d = json.loads(diag.backend_register)
+
+    comp = d['last_run'] + d['last_duration']*2 + 300
+    if comp>t:
+        d['health'] = ':-)'
+    else:
+        d['health'] = ':-X'
+    d['time'] = t
+    d['comp'] = comp
+
+    return HttpResponse(json.dumps(d))
diff --git a/xos/core/views/serviceGraph.py b/xos/core/views/serviceGraph.py
new file mode 100644
index 0000000..69631b9
--- /dev/null
+++ b/xos/core/views/serviceGraph.py
@@ -0,0 +1,186 @@
+from django.http import HttpResponse
+from django.views.generic import TemplateView, View
+from django import template
+from core.models import *
+from core.dashboard.views import DashboardDynamicView
+from xos.config import XOS_DIR
+import json
+import os
+import time
+import tempfile
+
+
+class ServiceGridView(TemplateView):
+
+    head_template = r"""{% extends "admin/dashboard/dashboard_base.html" %}
+       {% load admin_static %}
+       {% block content %}
+    """
+
+    tail_template = r"{% endblock %}"
+
+    def readTemplate(self, fn):
+        TEMPLATE_DIRS = [XOS_DIR + "/templates/admin/dashboard/",
+                         XOS_DIR + "/core/xoslib/dashboards/"]
+
+        for template_dir in TEMPLATE_DIRS:
+            pathname = os.path.join(template_dir, fn) + ".html"
+            if os.path.exists(pathname):
+                break
+        else:
+            return "failed to find %s in %s" % (fn, TEMPLATE_DIRS)
+
+        template = open(pathname, "r").read()
+        return template
+
+    def get(self, request, name="root", *args, **kwargs):
+
+        dash = DashboardView.objects.get(name="Services Grid")
+
+        gridTemplate = self.readTemplate(dash.url[9:])
+
+        t = template.Template(self.head_template + gridTemplate + self.tail_template)
+
+        response_kwargs = {}
+        response_kwargs.setdefault('content_type', self.content_type)
+
+        return self.response_class(
+            request=request,
+            template=t,
+            **response_kwargs)
+
+
+class ServiceGridViewPy(TemplateView):
+    head_template = r"""{% extends "admin/dashboard/dashboard_base.html" %}
+       {% load admin_static %}
+       {% block content %}
+    """
+
+    tail_template = r"{% endblock %}"
+
+    def get(self, request, name="root", *args, **kwargs):
+        head_template = self.head_template
+        tail_template = self.tail_template
+
+        html = '<table class="service-grid"><tr>'
+
+        icons = []
+        for service in Service.objects.all():
+            view_url = service.view_url
+            if (not view_url):
+                view_url = "/admin/core/service/$id$/"
+            view_url = view_url.replace("$id$", str(service.id))
+
+            image_url = service.icon_url
+            if (not image_url):
+                image_url = "/static/primarycons_blue/gear_2.png"
+
+            icons.append({"name": service.name, "view_url": view_url, "image_url": image_url})
+
+        icons.append({"name": "Tenancy Graph", "view_url": "/serviceGraph.png", "image_url": "/static/primarycons_blue/service_graph.png", "horiz_rule": True})
+        icons.append({"name": "Add Service", "view_url": "/admin/core/service/add/", "image_url": "/static/primarycons_blue/plus.png"})
+
+        i = 0
+        for icon in icons:
+            if icon.get("horiz_rule", False):
+                html = html + "</tr><tr><td colspan=4><hr></td></tr><tr>"
+                i = 0
+
+            service_name = icon["name"]
+            view_url = icon["view_url"]
+            image_url = icon["image_url"]
+
+            if (i % 4) == 0:
+                html = html + '</tr><tr>'
+
+            html = html + '<td width=96 height=128 valign=top align=center><a class="service-grid-icon" href="%s"><img src="%s" height=64 width=64></img></a>' % (view_url, image_url)
+            html = html + '<p><a class="service-grid-icon-link" href="%s">%s</a></p></td>' % (view_url, service_name)
+            i = i+1
+
+        html = html + '</tr></table>'
+
+        t = template.Template(head_template + html + self.tail_template)
+
+        response_kwargs = {}
+        response_kwargs.setdefault('content_type', self.content_type)
+        return self.response_class(
+            request=request,
+            template=t,
+            **response_kwargs
+        )
+
+
+class ServiceGraphViewOld(TemplateView):
+    #  this attempt used networkx
+    # yum -y install python-matplotlib python-networkx
+    # pip-python install -upgrade networkx
+    # pip-python install graphviz pygraphviz
+
+    def get(self, request, name="root", *args, **kwargs):
+        import networkx as nx
+        import matplotlib as mpl
+        mpl.use("Agg")
+        import matplotlib.pyplot as plt
+        import nxedges
+
+        plt.figure(figsize=(10, 8))
+
+        g = nx.DiGraph()
+
+        labels = {}
+        for service in Service.objects.all():
+            g.add_node(service.id)
+            if len(service.name) > 8:
+                labels[service.id] = service.name[:8] + "\n" + service.name[8:]
+            else:
+                labels[service.id] = service.name
+
+        for tenant in CoarseTenant.objects.all():
+            if (not tenant.provider_service) or (not tenant.subscriber_service):
+                continue
+            g.add_edge(tenant.subscriber_service.id, tenant.provider_service.id)
+
+        pos = nx.graphviz_layout(g)
+        nxedges.xos_draw_networkx_edges(g, pos, arrow_len=30)
+        nx.draw_networkx_nodes(g, pos, node_size=5000)
+        nx.draw_networkx_labels(g, pos, labels, font_size=12)
+        # plt.axis('off')
+        plt.savefig("/tmp/foo.png")
+
+        return HttpResponse(open("/tmp/foo.png", "r").read(), content_type="image/png")
+
+
+class ServiceGraphView(TemplateView):
+    # this attempt just uses graphviz directly
+    # yum -y install graphviz
+    # pip-python install pygraphviz
+
+    def get(self, request, name="root", *args, **kwargs):
+        import pygraphviz as pgv
+
+        g = pgv.AGraph(directed=True)
+        g.graph_attr.update(size="8,4!")
+        g.graph_attr.update(dpi="100")
+        # g.graph_attr.update(nodesep="2.5")
+        g.graph_attr.update(overlap="false")
+        g.graph_attr.update(graphdir="TB")
+
+        for service in Service.objects.all():
+            provided_tenants = Tenant.objects.filter(provider_service=service, subscriber_service__isnull=False)
+            subscribed_tenants = Tenant.objects.filter(subscriber_service=service, provider_service__isnull=False)
+            if not (provided_tenants or subscribed_tenants):
+                # nodes with no edges aren't interesting
+                continue
+            g.add_node(service.id, label=service.name)
+
+        for tenant in Tenant.objects.all():
+            if (not tenant.provider_service) or (not tenant.subscriber_service):
+                continue
+            g.add_edge(tenant.subscriber_service.id, tenant.provider_service.id)
+
+        tf = tempfile.TemporaryFile()
+        g.layout(prog="dot")
+        g.draw(path=tf, format="png")
+        tf.seek(0)
+
+        return HttpResponse(tf.read(), content_type="image/png")
diff --git a/xos/core/xoslib/.eslintignore b/xos/core/xoslib/.eslintignore
new file mode 100644
index 0000000..f848d64
--- /dev/null
+++ b/xos/core/xoslib/.eslintignore
@@ -0,0 +1,6 @@
+node_modules/**/*.js
+xos-builder/node_modules/**/*.js
+static/js/xsh/**/*.js
+static/js/vendor/**/*.js
+spec/helpers/*.js
+coverage/**/*
\ No newline at end of file
diff --git a/xos/core/xoslib/.yo-rc.json b/xos/core/xoslib/.yo-rc.json
new file mode 100644
index 0000000..33606db
--- /dev/null
+++ b/xos/core/xoslib/.yo-rc.json
@@ -0,0 +1,6 @@
+{
+  "generator-xos": {
+    "name": "sampleView",
+    "folder": "ngXosViews"
+  }
+}
\ No newline at end of file
diff --git a/xos/core/xoslib/README b/xos/core/xoslib/README
new file mode 100644
index 0000000..6d69629
--- /dev/null
+++ b/xos/core/xoslib/README
@@ -0,0 +1,7 @@
+Add to the following in settings.py
+
+    STATICFILES_DIRS=
+	XOS_DIR + "/core/xoslib/static/",
+
+    TEMPLATE_DIRS=
+        XOS_DIR + "/xoslib/templates",
\ No newline at end of file
diff --git a/xos/core/xoslib/__init__.py b/xos/core/xoslib/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/xos/core/xoslib/__init__.py
@@ -0,0 +1 @@
+
diff --git a/xos/core/xoslib/dashboards/cord.html b/xos/core/xoslib/dashboards/cord.html
new file mode 100644
index 0000000..475bfbf
--- /dev/null
+++ b/xos/core/xoslib/dashboards/cord.html
@@ -0,0 +1,71 @@
+<script src="{{ STATIC_URL }}/js/vendor/underscore-min.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.syphon.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.wreqr.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.babysitter.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.marionette.js"></script>
+
+<link rel="stylesheet" href="//code.jquery.com/ui/1.11.2/themes/smoothness/jquery-ui.css">
+<link rel="stylesheet" type="text/css" href="{% static 'css/xosAdminDashboard.css' %}" media="all" >
+<link rel="stylesheet" type="text/css" href="{% static 'css/xosAdminSite.css' %}" media="all" >
+<link rel="stylesheet" type="text/css" href="{% static 'css/cord.css' %}" media="all" >
+
+<script src="{{ STATIC_URL }}/js/xoslib/xos-util.js"></script>
+<script src="{{ STATIC_URL }}/js/xoslib/xos-defaults.js"></script>
+<script src="{{ STATIC_URL }}/js/xoslib/xos-validators.js"></script>
+<script src="{{ STATIC_URL }}/js/xoslib/xos-backbone.js"></script>
+<script src="{{ STATIC_URL }}/js/xoslib/xosHelper.js"></script>
+<script src="{{ STATIC_URL }}/js/picker.js"></script>
+<script src="{{ STATIC_URL }}/js/xosCord.js"></script>
+
+<script type="text/template" id="xos-log-template">
+  <tr id="<%= logMessageId %>" class="xos-log xos-<%= statusclass %>">
+     <td><%= what %><br>
+         <%= status %> <%= statusText %>
+     </td>
+  </tr>
+</script>
+
+<div id="xos-confirm-dialog" title="Confirmation Required">
+  Are you sure about this?

+</div>
+
+<div id="xos-error-dialog" title="Error Message">
+</div>

+

+<div id="xos-addchild-dialog" title="Add Child">

+<div id="xos-addchild-detail"></div>

+</div>

+
+<div id="contentPanel">
+<div id="contentTitle">
+</div>
+<div id="contentButtonPanel">
+<!-- This is really a convoluted way of handling the buttons. The onClick
+     handler for this Save button tells the save button inside the detail
+     form to click itself.
+-->
+
+<div id="rightButtonPanel"></div>
+
+<div class="box" id="logPanel">
+<table id="logTable">
+<tbody>
+</tbody>
+</table> <!-- end logTable -->
+</div> <!-- end logPanel -->
+</div> <!-- end contentButtonPanel -->
+<div id="contentInner">
+<div id="tabs">
+</div>
+<div id="detail"></div>
+<div id="linkedObjs1"></div>
+<div id="linkedObjs2"></div>
+<div id="linkedObjs3"></div>
+<div id="linkedObjs4"></div>
+</div> <!-- end contentInner -->
+</div> <!-- end contentPanel -->
+
+{% include 'xosAdmin.html' %}
+{% include 'xosCordSubscriber.html' %}
+
diff --git a/xos/core/xoslib/dashboards/gentle.html b/xos/core/xoslib/dashboards/gentle.html
new file mode 100644
index 0000000..47386e8
--- /dev/null
+++ b/xos/core/xoslib/dashboards/gentle.html
@@ -0,0 +1,26 @@
+    <div class="navbar navbar-inverse navbar-fixed-top">
+      <div class="navbar-inner">
+        <div class="container">
+          <span class="brand">Contact manager</span>
+        </div>
+      </div>
+    </div>
+
+    <div id="main-region" class="container">
+      <p>Here is static content in the web page. You'll notice that it gets replaced by our app as soon as we start it.</p>
+    </div>
+
+    <script type="text/template" id="contact-list-item">
+      <p><%- firstName %> <%- lastName %></p>
+    </script>
+
+<script src="{{ STATIC_URL }}/js/vendor/underscore-min.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.wreqr.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.babysitter.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.marionette.js"></script>
+<script src="{{ STATIC_URL }}/js/xoslib/xos-defaults.js"></script>
+<script src="{{ STATIC_URL }}/js/xoslib/xos-backbone.js"></script>
+<script src="{{ STATIC_URL }}/js/gentle.js"></script>
+
+
diff --git a/xos/core/xoslib/dashboards/index.html b/xos/core/xoslib/dashboards/index.html
new file mode 100644
index 0000000..04ef136
--- /dev/null
+++ b/xos/core/xoslib/dashboards/index.html
@@ -0,0 +1,15 @@
+<p>xoslib demo views</p>
+
+<table>
+<tr><td><a href="/dashboard/xosDeveloper/">xosDeveloper</a></td>
+<td>Demonstrates using xoslib + marionette to render a list of slices</td>
+</tr>
+
+<tr><td><a href="/dashboard/xosDeveloper_datatables/">xosDeveloper_datatables</a></td>
+<td>Demonstrates using xoslib + datatables to render a list of slices</td>
+</tr>
+
+<tr><td><a href="/dashboard/sliceEditor/">sliceEditor</a></td>
+<td>Demonstrates how to commit data back to the data model using xoslib</td>
+</tr>
+</table>
diff --git a/xos/core/xoslib/dashboards/sliceEditor.html b/xos/core/xoslib/dashboards/sliceEditor.html
new file mode 100644
index 0000000..c68f66b
--- /dev/null
+++ b/xos/core/xoslib/dashboards/sliceEditor.html
@@ -0,0 +1,41 @@
+<script src="{{ STATIC_URL }}/js/vendor/underscore-min.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.syphon.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.wreqr.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.babysitter.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.marionette.js"></script>
+
+<link rel="stylesheet" type="text/css" href="{% static 'css/sliceEditor.css' %}" media="all">
+
+<script src="{{ STATIC_URL }}/js/xoslib/xos-defaults.js"></script>
+<script src="{{ STATIC_URL }}/js/xoslib/xos-backbone.js"></script>
+<script src="{{ STATIC_URL }}/js/sliceEditor.js"></script>
+
+<p>This is a demo of modifying objects using xoslib. Pick a slice in the list on
+the left. Then edit any of it's fields on the right, and press the (save)
+button.</p>
+
+<table class="table table-bordered"><tr><td valign=top>
+<div id="sliceEditorList">
+</div>
+</td>
+<td valign=top>
+<div id="sliceEditorDetail">
+</div>
+</td></tr></table>
+
+<script type="text/template" id="sliceeditor-listitem-template">
+  <%= name %>

+</script>

+

+<script type="text/template" id="sliceeditor-sliceedit-template">

+  <form>

+  <table>

+  <tr><td>Slice Name:</td><td><input type="text" name="name" value="<%= name %>" id="foo"></td></tr>

+  <tr><td>Description:</td><td><input type="text" name="description" value="<%= description %>"></td></tr>

+  <tr><td colspan=2><button class="btn js-submit">Save</button></td></tr>

+  </table>

+  </form>

+

+</script>

+
diff --git a/xos/core/xoslib/dashboards/sliverListTest.html b/xos/core/xoslib/dashboards/sliverListTest.html
new file mode 100644
index 0000000..0e912c5
--- /dev/null
+++ b/xos/core/xoslib/dashboards/sliverListTest.html
@@ -0,0 +1,26 @@
+{% load mustache %}
+{% load straight_include %}
+
+<script src="{{ STATIC_URL }}/js/vendor/underscore-min.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone-min.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/ICanHaz.min.js"></script>
+
+<script src="{{ STATIC_URL }}/js/xoslib/xos-defaults.js"></script>
+<script src="{{ STATIC_URL }}/js/xoslib/xos-backbone.js"></script>
+<script src="{{ STATIC_URL }}/js/instanceListTest.js"></script>
+
+<script type="text/html" id="instanceTemplate">
+  {% straight_include "mustache/instanceTemplate.mustache" %}
+</script>
+
+<script type="text/html" id="listApp">
+  {% straight_include "mustache/listApp.mustache" %}
+</script>
+
+<script type="text/html" id="detailApp">
+  {% straight_include "mustache/detailApp.mustache" %}
+</script>
+
+<div id="app">
+  {% mustache "mustache/listApp" %}
+</div>
diff --git a/xos/core/xoslib/dashboards/test.html b/xos/core/xoslib/dashboards/test.html
new file mode 100644
index 0000000..0add2a8
--- /dev/null
+++ b/xos/core/xoslib/dashboards/test.html
@@ -0,0 +1,65 @@
+<script src="{{ STATIC_URL }}/js/vendor/underscore-min.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.syphon.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.wreqr.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.babysitter.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.marionette.js"></script>
+
+<link rel="stylesheet" type="text/css" href="{% static 'css/test.css' %}" media="all" >
+
+<script src="{{ STATIC_URL }}/js/xoslib/xos-util.js"></script>
+<script src="{{ STATIC_URL }}/js/xoslib/xos-defaults.js"></script>
+<script src="{{ STATIC_URL }}/js/xoslib/xos-validators.js"></script>
+<script src="{{ STATIC_URL }}/js/xoslib/xos-backbone.js"></script>
+<script src="{{ STATIC_URL }}/js/xoslib/xosHelper.js"></script>
+<script src="{{ STATIC_URL }}/js/test.js"></script>
+
+<p>This shows all of the things you can see using xosLib</p>
+
+<div id="deploymentList">
+</div>
+
+<div id="imageList">
+</div>
+
+<div id="networkTemplateList">
+</div>
+
+<div id="networkList">
+</div>
+
+<div id="nodeList">
+</div>
+
+<div id="serviceList">
+</div>
+
+<div id="siteList">
+</div>
+
+<div id="sliceList">
+</div>
+
+<div id="instanceList">
+</div>
+
+<div id="userList">
+</div>
+
+<div id="rightSide">
+<div id="successBox">
+</div>
+<div id="errorBox">
+</div>
+
+<div id="detailBox">
+<button id="close-detail-view">Close Detail View</button>
+<div id="detail"></div>

+<div id="linkedObjs1"></div>
+<div id="linkedObjs2"></div>
+<div id="linkedObjs3"></div>
+<div id="linkedObjs4"></div>
+</div>
+</div>
+
+{% include 'xosAdmin.html' %}
diff --git a/xos/core/xoslib/dashboards/xosAdminDashboard.html b/xos/core/xoslib/dashboards/xosAdminDashboard.html
new file mode 100644
index 0000000..bf10240
--- /dev/null
+++ b/xos/core/xoslib/dashboards/xosAdminDashboard.html
@@ -0,0 +1,81 @@
+<script src="{{ STATIC_URL }}/js/vendor/underscore-min.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.syphon.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.wreqr.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.babysitter.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.marionette.js"></script>
+
+<link rel="stylesheet" href="//code.jquery.com/ui/1.11.2/themes/smoothness/jquery-ui.css">
+<link rel="stylesheet" type="text/css" href="{% static 'css/xosAdminDashboard.css' %}" media="all" >
+<link rel="stylesheet" type="text/css" href="{% static 'css/xosAdminSite.css' %}" media="all" >
+
+<script src="{{ STATIC_URL }}/js/xoslib/xos-util.js"></script>
+<script src="{{ STATIC_URL }}/js/xoslib/xos-defaults.js"></script>
+<script src="{{ STATIC_URL }}/js/xoslib/xos-validators.js"></script>
+<script src="{{ STATIC_URL }}/js/xoslib/xos-backbone.js"></script>
+<script src="{{ STATIC_URL }}/js/xoslib/xosHelper.js"></script>
+<script src="{{ STATIC_URL }}/js/picker.js"></script>
+<script src="{{ STATIC_URL }}/js/xosAdminSite.js"></script>
+
+<script type="text/template" id="xos-log-template">
+  <tr id="<%= logMessageId %>" class="xos-log xos-<%= statusclass %>">
+     <td><%= what %><br>
+         <%= status %> <%= statusText %>
+     </td>
+  </tr>
+</script>
+
+<div id="xos-confirm-dialog" title="Confirmation Required">
+  Are you sure about this?

+</div>
+
+<div id="xos-error-dialog" title="Error Message">
+</div>

+

+<div id="xos-addchild-dialog" title="Add Child">

+<div id="xos-addchild-detail"></div>

+</div>

+
+<div id="contentPanel">
+<div id="contentTitle">
+</div>
+<div id="contentButtonPanel">
+<!-- This is really a convoluted way of handling the buttons. The onClick
+     handler for this Save button tells the save button inside the detail
+     form to click itself.
+-->
+
+<div id="rightButtonPanel"></div>
+
+<!--
+<div class="box save-box" id="xos-detail-button-box">
+<button class="btn btn-high btn-info btn-xos-contentButtonPanel" onclick="$('button.btn-xos-save-leave').click()">Save</button>
+<button class="btn btn-high btn-xos-contentButtonPanel" onclick="$('button.btn-xos-save-continue').click()">Save and continue editing</button>
+<button class="btn btn-high btn-xos-contentButtonPanel" onclick="$('button.btn-xos-save-another').click()">Save and add another</button>
+<button class="btn btn-danger btn-xos-contentButtonPanel" onclick="$('button.btn-xos-delete').click()">Delete</button>
+</div>
+<div class="box save-box" id="xos-listview-button-box">
+<button class="btn btn-high btn-primary btn-xos-contentButtonPanel" onclick="$('button.btn-xos-refresh').click()">Refresh</button>
+<button class="btn btn-high btn-success btn-xos-contentButtonPanel" onclick="$('button.btn-xos-add').click()">Add</button>
+</div>
+-->
+
+<div class="box" id="logPanel">
+<table id="logTable">
+<tbody>
+</tbody>
+</table> <!-- end logTable -->
+</div> <!-- end logPanel -->
+</div> <!-- end contentButtonPanel -->
+<div id="contentInner">
+<div id="tabs">
+</div>
+<div id="detail"></div>
+<div id="linkedObjs1"></div>
+<div id="linkedObjs2"></div>
+<div id="linkedObjs3"></div>
+<div id="linkedObjs4"></div>
+</div> <!-- end contentInner -->
+</div> <!-- end contentPanel -->
+
+{% include 'xosAdmin.html' %}
diff --git a/xos/core/xoslib/dashboards/xosAdminWholePage.html b/xos/core/xoslib/dashboards/xosAdminWholePage.html
new file mode 100644
index 0000000..8aaa8c1
--- /dev/null
+++ b/xos/core/xoslib/dashboards/xosAdminWholePage.html
@@ -0,0 +1,58 @@
+<script src="{{ STATIC_URL }}/js/vendor/underscore-min.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.syphon.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.wreqr.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.babysitter.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.marionette.js"></script>
+
+<link rel="stylesheet" href="//code.jquery.com/ui/1.11.2/themes/smoothness/jquery-ui.css">
+<link rel="stylesheet" type="text/css" href="{% static 'css/xosAdminWholePage.css' %}" media="all" >
+<link rel="stylesheet" type="text/css" href="{% static 'css/xosAdminSite.css' %}" media="all" >
+
+<script src="{{ STATIC_URL }}/js/xoslib/xos-util.js"></script>
+<script src="{{ STATIC_URL }}/js/xoslib/xos-defaults.js"></script>
+<script src="{{ STATIC_URL }}/js/xoslib/xos-validators.js"></script>
+<script src="{{ STATIC_URL }}/js/xoslib/xos-backbone.js"></script>
+<script src="{{ STATIC_URL }}/js/xoslib/xosHelper.js"></script>
+<script src="{{ STATIC_URL }}/js/xosAdminSite.js"></script>
+
+<script type="text/template" id="xos-log-template">
+  <tr id="<%= logMessageId %>" class="xos-log xos-<%= statusclass %>">
+     <td><%= what %></td>
+     <td><%= status %></td>
+     <td><%= statusText %></td>
+  </tr>
+</script>
+
+<div id="headerPanel">
+{% include 'xosAdminHeader.html' %}
+</div>
+
+<div id="navigationPanel">
+nav
+</div>
+
+<div id="contentPanel">
+<div id="contentTitle">
+</div>
+<div id="tabs">
+</div>
+<div id="detail"></div>
+<div id="linkedObjs1"></div>
+<div id="linkedObjs2"></div>
+<div id="linkedObjs3"></div>
+<div id="linkedObjs4"></div>
+</div>
+
+<div id="logPanel">
+<table id="logTable">
+<thead>
+<tr><th>status</th><th>operation</th><th>code</th><th>message</th></tr>
+</thead>
+<tbody>
+</tbody>
+</table>
+
+</div>
+
+{% include 'xosAdmin.html' %}
diff --git a/xos/core/xoslib/dashboards/xosCeilometerDashboard.html b/xos/core/xoslib/dashboards/xosCeilometerDashboard.html
new file mode 100644
index 0000000..42e22f8
--- /dev/null
+++ b/xos/core/xoslib/dashboards/xosCeilometerDashboard.html
@@ -0,0 +1,17 @@
+<meta http-equiv="X-UA-Compatible" content="IE=edge">
+<meta name="viewport" content="width=device-width, initial-scale=1, max-scale=1">
+<!-- browserSync -->
+<!-- endcss -->
+<!-- inject:css -->
+<link rel="stylesheet" href="/static/css/xosCeilometerDashboard.css">
+<!-- endinject -->
+<div ng-app="xos.ceilometerDashboard" id="xosCeilometerDashboard">
+  <div ui-view ng-class="stateName"></div>
+</div>
+
+<!-- endjs -->
+
+<!-- inject:js -->
+<script src="/static/js/vendor/xosCeilometerDashboardVendor.js"></script>
+<script src="/static/js/xosCeilometerDashboard.js"></script>
+<!-- endinject -->
diff --git a/xos/core/xoslib/dashboards/xosContentProvider.html b/xos/core/xoslib/dashboards/xosContentProvider.html
new file mode 100644
index 0000000..cdaeac4
--- /dev/null
+++ b/xos/core/xoslib/dashboards/xosContentProvider.html
@@ -0,0 +1,14 @@
+<!-- browserSync -->
+<!-- endcss -->
+<!-- inject:css -->
+<link rel="stylesheet" href="/static/css/xosContentProvider.css">
+<!-- endinject -->
+
+<div ng-app="xos.contentProvider" id="xosContentProvider">
+    <div ui-view></div>
+</div>
+
+<!-- endjs -->
+<!-- inject:js -->
+<script src="/static/js/xosContentProvider.js"></script>
+<!-- endinject -->
diff --git a/xos/core/xoslib/dashboards/xosDeveloper.html b/xos/core/xoslib/dashboards/xosDeveloper.html
new file mode 100644
index 0000000..f3abf18
--- /dev/null
+++ b/xos/core/xoslib/dashboards/xosDeveloper.html
@@ -0,0 +1,16 @@
+<!-- browserSync -->
+
+<!-- endcss -->
+<!-- inject:css -->
+<link rel="stylesheet" href="/static/css/xosDeveloper.css">
+<!-- endinject -->
+
+<div ng-app="xos.developer" id="xosDeveloper" class="container-fluid">
+  <div ui-view></div>
+</div>
+
+
+<!-- endjs -->
+<!-- inject:js -->
+<script src="/static/js/xosDeveloper.js"></script>
+<!-- endinject -->
\ No newline at end of file
diff --git a/xos/core/xoslib/dashboards/xosDiagnostic.html b/xos/core/xoslib/dashboards/xosDiagnostic.html
new file mode 100644
index 0000000..f87baae
--- /dev/null
+++ b/xos/core/xoslib/dashboards/xosDiagnostic.html
@@ -0,0 +1,15 @@
+<!-- browserSync -->
+
+<!-- inject:css -->
+<link rel="stylesheet" href="/static/css/xosDiagnostic.css">
+<!-- endinject -->
+
+<div ng-app="xos.diagnostic" id="xosDiagnostic">
+    <div ui-view></div>
+</div>
+
+
+<!-- inject:js -->
+<script src="/static/js/vendor/xosDiagnosticVendor.js"></script>
+<script src="/static/js/xosDiagnostic.js"></script>
+<!-- endinject -->
diff --git a/xos/core/xoslib/dashboards/xosHpc.html b/xos/core/xoslib/dashboards/xosHpc.html
new file mode 100644
index 0000000..6248e74
--- /dev/null
+++ b/xos/core/xoslib/dashboards/xosHpc.html
@@ -0,0 +1,16 @@
+<!-- browserSync -->
+
+<!-- endcss -->
+<!-- inject:css -->
+<link rel="stylesheet" href="/static/css/xosHpc.css">
+<!-- endinject -->
+
+<div ng-app="xos.hpc" id="xosHpc" class="container-fluid">
+  <div ui-view></div>
+</div>
+
+
+<!-- endjs -->
+<!-- inject:js -->
+<script src="/static/js/xosHpc.js"></script>
+<!-- endinject -->
\ No newline at end of file
diff --git a/xos/core/xoslib/dashboards/xosHpcNodes.html b/xos/core/xoslib/dashboards/xosHpcNodes.html
new file mode 100644
index 0000000..4682ca5
--- /dev/null
+++ b/xos/core/xoslib/dashboards/xosHpcNodes.html
@@ -0,0 +1,32 @@
+<script src="{{ STATIC_URL }}/js/vendor/underscore-min.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.syphon.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.wreqr.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.babysitter.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.marionette.js"></script>
+
+<link rel="stylesheet" href="//code.jquery.com/ui/1.11.2/themes/smoothness/jquery-ui.css">
+<link rel="stylesheet" type="text/css" href="{% static 'css/xosTenantDashboard.css' %}" media="all" >
+<link rel="stylesheet" type="text/css" href="{% static 'css/xosAdminSite.css' %}" media="all" >
+
+<script src="{{ STATIC_URL }}/js/xoslib/xos-util.js"></script>
+<script src="{{ STATIC_URL }}/js/xoslib/xos-defaults.js"></script>
+<script src="{{ STATIC_URL }}/js/xoslib/xos-validators.js"></script>
+<script src="{{ STATIC_URL }}/js/xoslib/xos-backbone.js"></script>
+<script src="{{ STATIC_URL }}/js/xoslib/xosHelper.js"></script>
+<script src="{{ STATIC_URL }}/js/xosHpcNodes.js"></script>
+
+<div id="xos-hpc-view-panel"> <!-- contentPanel"> -->
+<div id="contentTitle">
+</div>
+
+<div id="contentInner">
+
+Url: <select id="xos-hpc-url-select"></select>
+
+<div id="xos-hpc-urls"></div>
+
+</div> <!-- end contentInner -->
+</div> <!-- end contentPanel -->
+
+{% include 'xosAdmin.html' %}
diff --git a/xos/core/xoslib/dashboards/xosHpcUrls.html b/xos/core/xoslib/dashboards/xosHpcUrls.html
new file mode 100644
index 0000000..4bfa263
--- /dev/null
+++ b/xos/core/xoslib/dashboards/xosHpcUrls.html
@@ -0,0 +1,32 @@
+<script src="{{ STATIC_URL }}/js/vendor/underscore-min.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.syphon.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.wreqr.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.babysitter.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.marionette.js"></script>
+
+<link rel="stylesheet" href="//code.jquery.com/ui/1.11.2/themes/smoothness/jquery-ui.css">
+<link rel="stylesheet" type="text/css" href="{% static 'css/xosTenantDashboard.css' %}" media="all" >
+<link rel="stylesheet" type="text/css" href="{% static 'css/xosAdminSite.css' %}" media="all" >
+
+<script src="{{ STATIC_URL }}/js/xoslib/xos-util.js"></script>
+<script src="{{ STATIC_URL }}/js/xoslib/xos-defaults.js"></script>
+<script src="{{ STATIC_URL }}/js/xoslib/xos-validators.js"></script>
+<script src="{{ STATIC_URL }}/js/xoslib/xos-backbone.js"></script>
+<script src="{{ STATIC_URL }}/js/xoslib/xosHelper.js"></script>
+<script src="{{ STATIC_URL }}/js/xosHpcUrls.js"></script>
+
+<div id="xos-hpc-view-panel"> <!-- contentPanel"> -->
+<div id="contentTitle">
+</div>
+
+<div id="contentInner">
+
+Node: <select id="xos-hpc-node-select"></select>
+
+<div id="xos-hpc-urls"></div>
+
+</div> <!-- end contentInner -->
+</div> <!-- end contentPanel -->
+
+{% include 'xosAdmin.html' %}
diff --git a/xos/core/xoslib/dashboards/xosMcordTopology.html b/xos/core/xoslib/dashboards/xosMcordTopology.html
new file mode 100644
index 0000000..a4b67a0
--- /dev/null
+++ b/xos/core/xoslib/dashboards/xosMcordTopology.html
@@ -0,0 +1,15 @@
+<!-- browserSync -->
+
+<!-- inject:css -->
+<link rel="stylesheet" href="/static/css/xosMcordTopology.css">
+<!-- endinject -->
+
+<div ng-app="xos.mcordTopology" id="xosMcordTopology" class="container-fluid">
+    <div ui-view></div>
+</div>
+
+
+<!-- inject:js -->
+<script src="/static/js/vendor/xosMcordTopologyVendor.js"></script>
+<script src="/static/js/xosMcordTopology.js"></script>
+<!-- endinject -->
diff --git a/xos/core/xoslib/dashboards/xosOpenVPNDashboard.html b/xos/core/xoslib/dashboards/xosOpenVPNDashboard.html
new file mode 100644
index 0000000..6963cd2
--- /dev/null
+++ b/xos/core/xoslib/dashboards/xosOpenVPNDashboard.html
@@ -0,0 +1,14 @@
+<!-- browserSync -->
+<!-- endcss -->
+<!-- inject:css -->
+<link rel="stylesheet" href="/static/css/xosOpenVPNDashboard.css">
+<!-- endinject -->
+
+<div ng-app="xos.openVPNDashboard" id="xosOpenVPNDashboard">
+    <div ui-view></div>
+</div>
+
+<!-- endjs -->
+<!-- inject:js -->
+<script src="/static/js/xosOpenVPNDashboard.js"></script>
+<!-- endinject -->
diff --git a/xos/core/xoslib/dashboards/xosServiceGrid.html b/xos/core/xoslib/dashboards/xosServiceGrid.html
new file mode 100644
index 0000000..c0d58dc
--- /dev/null
+++ b/xos/core/xoslib/dashboards/xosServiceGrid.html
@@ -0,0 +1,32 @@
+<!-- browserSync -->
+<!-- bower:css -->
+<link rel="stylesheet" href="vendor/bootstrap-css/css/bootstrap.min.css" />
+<link rel="stylesheet" href="vendor/angular-chart.js/dist/angular-chart.css" />
+<!-- endbower -->
+<!-- endcss -->
+<!-- inject:css -->
+<link rel="stylesheet" href="/static/css/xosServiceGrid.css">
+<!-- endinject -->
+
+<div ng-app="xos.serviceGrid" id="xosServiceGrid" class="container-fluid">
+  <div ui-view></div>
+</div>
+
+<!-- bower:js -->
+<script src="vendor/jquery/dist/jquery.js"></script>
+<script src="vendor/angular/angular.js"></script>
+<script src="vendor/angular-mocks/angular-mocks.js"></script>
+<script src="vendor/angular-ui-router/release/angular-ui-router.js"></script>
+<script src="vendor/angular-cookies/angular-cookies.js"></script>
+<script src="vendor/angular-animate/angular-animate.js"></script>
+<script src="vendor/angular-resource/angular-resource.js"></script>
+<script src="vendor/lodash/lodash.js"></script>
+<script src="vendor/bootstrap-css/js/bootstrap.min.js"></script>
+<script src="vendor/Chart.js/Chart.js"></script>
+<script src="vendor/angular-chart.js/dist/angular-chart.js"></script>
+<script src="vendor/d3/d3.js"></script>
+<!-- endbower -->
+<!-- endjs -->
+<!-- inject:js -->
+<script src="/static/js/xosServiceGrid.js"></script>
+<!-- endinject -->
\ No newline at end of file
diff --git a/xos/core/xoslib/dashboards/xosSubscribers.html b/xos/core/xoslib/dashboards/xosSubscribers.html
new file mode 100644
index 0000000..cb58882
--- /dev/null
+++ b/xos/core/xoslib/dashboards/xosSubscribers.html
@@ -0,0 +1,16 @@
+<!-- browserSync -->
+
+<!-- endcss -->
+<!-- inject:css -->
+<link rel="stylesheet" href="/static/css/xosSubscribers.css">
+<!-- endinject -->
+
+<div ng-app="xos.subscribers" id="xosSubscribers" class="container-fluid">
+  <div ui-view></div>
+</div>
+
+
+<!-- endjs -->
+<!-- inject:js -->
+<script src="/static/js/xosSubscribers.js"></script>
+<!-- endinject -->
\ No newline at end of file
diff --git a/xos/core/xoslib/dashboards/xosSynchronizerNotifier.html b/xos/core/xoslib/dashboards/xosSynchronizerNotifier.html
new file mode 100644
index 0000000..ef69861
--- /dev/null
+++ b/xos/core/xoslib/dashboards/xosSynchronizerNotifier.html
@@ -0,0 +1,16 @@
+<!-- browserSync -->
+
+<!-- endcss -->
+<!-- inject:css -->
+<link rel="stylesheet" href="/static/css/xosSynchronizerNotifier.css">
+<!-- endinject -->
+
+<div id="xosSynchronizerNotifier">
+  <sync-status></sync-status>
+</div>
+
+
+<!-- endjs -->
+<!-- inject:js -->
+<script src="/static/js/xosSynchronizerNotifier.js"></script>
+<!-- endinject -->
\ No newline at end of file
diff --git a/xos/core/xoslib/dashboards/xosTenant.html b/xos/core/xoslib/dashboards/xosTenant.html
new file mode 100644
index 0000000..814f3de
--- /dev/null
+++ b/xos/core/xoslib/dashboards/xosTenant.html
@@ -0,0 +1,17 @@
+<!-- browserSync -->
+
+<!-- endcss -->
+<!-- inject:css -->
+<link rel="stylesheet" href="/static/css/xosTenant.css">
+<!-- endinject -->
+
+
+<div ng-app="xos.tenant" id="xosTenant" class="container-fluid">
+   <div ui-view></div>
+</div>
+
+
+<!-- endjs -->
+<!-- inject:js -->
+<script src="/static/js/xosTenant.js"></script>
+<!-- endinject -->
diff --git a/xos/core/xoslib/dashboards/xosTruckroll.html b/xos/core/xoslib/dashboards/xosTruckroll.html
new file mode 100644
index 0000000..2068e6c
--- /dev/null
+++ b/xos/core/xoslib/dashboards/xosTruckroll.html
@@ -0,0 +1,16 @@
+<!-- browserSync -->
+
+<!-- endcss -->
+<!-- inject:css -->
+<link rel="stylesheet" href="/static/css/xosTruckroll.css">
+<!-- endinject -->
+
+<div ng-app="xos.truckroll" id="xosTruckroll" class="container-fluid">
+  <div ui-view></div>
+</div>
+
+
+<!-- endjs -->
+<!-- inject:js -->
+<script src="/static/js/xosTruckroll.js"></script>
+<!-- endinject -->
\ No newline at end of file
diff --git a/xos/core/xoslib/dashboards/xsh.html b/xos/core/xoslib/dashboards/xsh.html
new file mode 100644
index 0000000..65a44da
--- /dev/null
+++ b/xos/core/xoslib/dashboards/xsh.html
@@ -0,0 +1,21 @@
+  <div id="terminal">
+    <p class="response">XSH - The XOS Shell</p>
+    <br />
+    <p id="terminal_help1" style="display: none;">type "help" for help</p>
+    <p id="terminal_help2" style="display: none;">type "tutorial" to start the tutorial</p>
+
+  </div>
+  <link rel="stylesheet" type="text/css" href="{% static 'shell/opencloud_shell.css' %}" media="all">
+  <script src="{{ STATIC_URL }}/js/vendor/underscore-min.js"></script>
+  <script src="{{ STATIC_URL }}/js/vendor/backbone-min.js"></script>
+  <script src="{{ STATIC_URL }}/js/vendor/ICanHaz.min.js"></script>
+  <script src="{{ STATIC_URL }}/js/xoslib/xos-backbone.js"></script>
+  <script src="{% static 'js/xsh/xsh.js' %}"></script>
+  <script src="{% static 'js/xsh/object_id.js' %}"></script>
+  <script src="{% static 'js/xsh/constants.js' %}"></script>
+  <script src="{% static 'js/xsh/utils.js' %}"></script>
+  <script src="{% static 'js/xsh/shell_utils.js' %}"></script>
+  <script src="{% static 'js/xsh/tokens.js' %}"></script>
+
+
+
diff --git a/xos/core/xoslib/jsdoc.conf.json b/xos/core/xoslib/jsdoc.conf.json
new file mode 100644
index 0000000..3352b79
--- /dev/null
+++ b/xos/core/xoslib/jsdoc.conf.json
@@ -0,0 +1,30 @@
+{
+  "tags": {
+    "allowUnknownTags": true
+  },
+  "plugins": ["plugins/markdown"],
+  "templates": {
+    "cleverLinks": false,
+    "monospaceLinks": false,
+    "dateFormat": "ddd MMM Do YYYY",
+    "outputSourceFiles": true,
+    "outputSourcePath": true,
+    "systemName": "XOS Lib",
+    "footer": "",
+    "copyright": "DocStrap Copyright © 2012-2014 The contributors to the JSDoc3 and DocStrap projects.",
+    "navType": "vertical",
+    "theme": "cosmo",
+    "linenums": true,
+    "collapseSymbols": false,
+    "inverseNav": true,
+    "highlightTutorialCode": true,
+    "protocol": "html://"
+  },
+  "markdown": {
+    "parser": "gfm",
+    "hardwrap": true
+  },
+  "opts": {
+    "template": "./node_modules/ink-docstrap/template/"
+  }
+}
diff --git a/xos/core/xoslib/karma.conf.js b/xos/core/xoslib/karma.conf.js
new file mode 100644
index 0000000..cea4d8c
--- /dev/null
+++ b/xos/core/xoslib/karma.conf.js
@@ -0,0 +1,103 @@
+// Karma configuration
+// Generated on Tue Oct 06 2015 09:27:10 GMT+0000 (UTC)
+
+/* eslint indent: [2,2], quotes: [2, "single"]*/
+
+/*eslint-disable*/
+var wiredep = require('wiredep');
+var path = require('path');
+
+module.exports = function(config) {
+/*eslint-enable*/
+  config.set({
+
+    // base path that will be used to resolve all patterns (eg. files, exclude)
+    basePath: '',
+
+
+    // frameworks to use
+    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
+    frameworks: ['jasmine'],
+
+
+    // list of files / patterns to load in the browser
+    files: [
+      'static/js/vendor/jquery-1.11.3.js',
+      'static/js/vendor/underscore-min.js',
+      'static/js/vendor/backbone.js',
+      'static/js/vendor/backbone.wreqr.js',
+      'static/js/vendor/backbone.babysitter.js',
+      'static/js/vendor/backbone.marionette.js',
+      'static/js/vendor/backbone.syphon.js',
+      'static/js/xoslib/*.js',
+
+      'spec/helpers/jasmine-jquery.js',
+      'spec/**/*.mock.js',
+      'spec/**/*.test.js',
+
+      'spec/**/*.html',
+
+      //ng stuff
+      // 'static/js/xosContentProvider.js'
+    ],
+
+
+    // list of files to exclude
+    exclude: [
+      // '**/xos-utils.test.js', //skip this test, useful in dev, comment before commit
+      // '**/xos-backbone.test.js',
+      // '**/xoslib/**/*.js'
+    ],
+
+
+    // preprocess matching files before serving them to the browser
+    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
+    preprocessors: {
+      'spec/**/*.test.js': ['babel'],
+      'static/js/xoslib/*.js': ['coverage'],
+      'static/js/*.js': ['coverage']
+    },
+
+    ngHtml2JsPreprocessor: {
+      prependPrefix: '../../', //strip the src path from template url (http://stackoverflow.com/questions/22869668/karma-unexpected-request-when-testing-angular-directive-even-with-ng-html2js)
+      moduleName: 'templates' // define the template module name
+    },
+
+    coverageReporter: {
+      type: 'html',
+      dir: 'coverage/'
+    },
+
+    // test results reporter to use
+    // possible values: 'dots', 'progress'
+    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
+    reporters: ['mocha', 'coverage'],
+
+
+    // web server port
+    port: 9876,
+
+
+    // enable / disable colors in the output (reporters and logs)
+    colors: true,
+
+
+    // level of logging
+    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+    logLevel: config.LOG_INFO,
+
+
+    // enable / disable watching file and executing tests whenever any file changes
+    autoWatch: true,
+
+
+    // start these browsers
+    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
+    browsers: ['PhantomJS'],
+
+
+    // Continuous Integration mode
+    // if true, Karma captures browsers, runs the tests and exits
+    singleRun: false
+  });
+};
diff --git a/xos/core/xoslib/methods/__init__.py b/xos/core/xoslib/methods/__init__.py
new file mode 100644
index 0000000..c777668
--- /dev/null
+++ b/xos/core/xoslib/methods/__init__.py
@@ -0,0 +1,59 @@
+from django.views.generic import View
+from django.conf.urls import patterns, url
+from rest_framework.routers import DefaultRouter
+import os, sys
+import inspect
+import importlib
+
+# XXX based on core/dashboard/views/__init__.py
+
+# Find all modules in the current directory that have descendents of the View
+# object, and add them as globals to this module. Also, build up a list of urls
+# based on the "url" field of the view classes.
+
+urlpatterns=[]
+
+sys_path_save = sys.path
+try:
+    # __import__() and importlib.import_module() both import modules from
+    # sys.path. So we make sure that the path where we can find the views is
+    # the first thing in sys.path.
+    view_dir = os.path.dirname(os.path.abspath(__file__))
+    sys.path = [view_dir] + sys.path
+    view_urls = []
+    for fn in os.listdir(view_dir):
+        pathname = os.path.join(view_dir,fn)
+        if os.path.isfile(pathname) and fn.endswith(".py") and (fn!="__init__.py"):
+            module = __import__(fn[:-3])
+            for classname in dir(module):
+                c = getattr(module, classname, None)
+
+                if inspect.isclass(c) and issubclass(c, View) and (classname not in globals()):
+                    globals()[classname] = c
+
+                    method_kind = getattr(c, "method_kind", None)
+                    method_name = getattr(c, "method_name", None)
+                    if method_kind and method_name:
+                        view_urls.append( (method_kind, method_name, classname, c) )
+
+    for view_url in view_urls:
+        if view_url[0] == "list":
+           urlpatterns.append(url(r'^' + view_url[1] + '/$',  view_url[3].as_view(), name=view_url[1]+'list'))
+        elif view_url[0] == "detail":
+           urlpatterns.append(url(r'^' + view_url[1] + '/(?P<pk>[a-zA-Z0-9\-]+)/$',  view_url[3].as_view(), name=view_url[1]+'detail'))
+        elif view_url[0] == "viewset":
+           viewset = view_url[3]
+
+           urlpatterns.extend(viewset.get_urlpatterns())
+
+           #urlpatterns.append(url(r'^' + view_url[1] + '/$', viewset.as_view({'get': 'list'}), name=view_url[1]+'list'))
+           #urlpatterns.append(url(r'^' + view_url[1] + '/(?P<pk>[a-zA-Z0-9\-]+)/$', viewset.as_view({'get': 'retrieve', 'put': 'update', 'post': 'create', 'delete': 'destroy', 'patch': 'partial_update'}), name=view_url[1]+'detail'))
+           #urlpatterns.extend(
+
+           #router = DefaultRouter()
+           #router.register(r'^' + view_url[1], view_url[3], base_name="foo")
+           #urlpatterns.extend(router.urls)
+           #urlpatterns.append(url(r'^' + view_url[1], view_url[3]))
+
+finally:
+    sys.path = sys_path_save
diff --git a/xos/core/xoslib/methods/ceilometerview._unused b/xos/core/xoslib/methods/ceilometerview._unused
new file mode 100644
index 0000000..9c87e40
--- /dev/null
+++ b/xos/core/xoslib/methods/ceilometerview._unused
@@ -0,0 +1,1451 @@
+import requests
+from six.moves import urllib
+import urllib2
+import pytz
+import datetime
+import time
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+from rest_framework import serializers
+from rest_framework import generics
+from rest_framework.views import APIView
+from core.models import *
+from services.ceilometer.models import *
+from django.forms import widgets
+from django.utils import datastructures
+from django.utils.translation import ugettext_lazy as _
+from django.utils import timezone
+from django.core.exceptions import PermissionDenied
+from xos.logger import observer_logger as logger
+
+# This REST API endpoint provides information that the ceilometer view needs to display
+
+def getTenantCeilometerProxyURL(user):
+    monitoring_channel = None
+    for obj in MonitoringChannel.get_tenant_objects().all():
+        if (obj.creator.username == user.username):
+            monitoring_channel = obj
+            break
+    if not monitoring_channel:
+        raise XOSMissingField("Monitoring channel is missing for this tenant...Create one and invoke this REST API")
+    #TODO: Wait until URL is completely UP
+    MAX_ATTEMPTS = 5
+    attempts = 0
+    while True:
+        try:
+            response = urllib2.urlopen(monitoring_channel.ceilometer_url)
+            break
+        except urllib2.HTTPError, e:
+            logger.info('HTTP error %(reason)s' % {'reason':e.reason})
+            break
+        except urllib2.URLError, e:
+            attempts += 1
+            if attempts >= MAX_ATTEMPTS:
+                raise XOSServiceUnavailable("Ceilometer channel is not ready yet...Try again later")
+            logger.info('URL error %(reason)s' % {'reason':e.reason})
+            time.sleep(1)
+            pass
+    logger.info("Ceilometer proxy URL for user %(user)s is %(url)s" % {'user':user.username,'url':monitoring_channel.ceilometer_url})
+    return monitoring_channel.ceilometer_url
+
+def getTenantControllerTenantMap(user, slice=None):
+    tenantmap={}
+    if not slice:
+        slices = Slice.objects.filter(creator=user)
+    else:
+        slices = [slice]
+    for s in slices:
+        for cs in s.controllerslices.all():
+            if cs.tenant_id:
+                tenantmap[cs.tenant_id] = {"slice": cs.slice.name}
+                if cs.slice.service:
+                    tenantmap[cs.tenant_id]["service"] = cs.slice.service.name
+                else:
+                    logger.warn("SRIKANTH: Slice %(slice)s is not associated with any service" % {'slice':cs.slice.name})
+                    tenantmap[cs.tenant_id]["service"] = "Other"
+    if not slice:
+        #TEMPORARY WORK AROUND: There are some resource in network like whitebox switches does not belong to a specific tenant.
+        #They are all associated with "default_admin_tenant" tenant
+        tenantmap["default_admin_tenant"] = {"slice": "default_admin_tenant", "service": "Other"}
+    return tenantmap
+
+def build_url(path, q, params=None):
+    """Convert list of dicts and a list of params to query url format.
+
+    This will convert the following:
+        "[{field=this,op=le,value=34},
+          {field=that,op=eq,value=foo,type=string}],
+         ['foo=bar','sna=fu']"
+    to:
+        "?q.field=this&q.field=that&
+          q.op=le&q.op=eq&
+          q.type=&q.type=string&
+          q.value=34&q.value=foo&
+          foo=bar&sna=fu"
+    """
+    if q:
+        query_params = {'q.field': [],
+                        'q.value': [],
+                        'q.op': [],
+                        'q.type': []}
+
+        for query in q:
+            for name in ['field', 'op', 'value', 'type']:
+                query_params['q.%s' % name].append(query.get(name, ''))
+
+        # Transform the dict to a sequence of two-element tuples in fixed
+        # order, then the encoded string will be consistent in Python 2&3.
+        new_qparams = sorted(query_params.items(), key=lambda x: x[0])
+        path += "?" + urllib.parse.urlencode(new_qparams, doseq=True)
+
+        if params:
+            for p in params:
+                path += '&%s' % p
+    elif params:
+        path += '?%s' % params[0]
+        for p in params[1:]:
+            path += '&%s' % p
+    return path
+
+def concat_url(endpoint, url):
+    """Concatenate endpoint and final URL.
+
+    E.g., "http://keystone/v2.0/" and "/tokens" are concatenated to
+    "http://keystone/v2.0/tokens".
+
+    :param endpoint: the base URL
+    :param url: the final URL
+    """
+    return "%s/%s" % (endpoint.rstrip("/"), url.strip("/"))
+
+def resource_list(request, query=None, ceilometer_url=None, ceilometer_usage_object=None):
+    """List the resources."""
+    url = concat_url(ceilometer_url, build_url('/v2/resources', query))
+    try:
+        response = requests.get(url)
+    except requests.exceptions.RequestException as e:
+        raise e
+    return response.json()
+
+def sample_list(request, meter_name, ceilometer_url=None, query=None, limit=None):
+    """List the samples for this meters."""
+    params = ['limit=%s' % limit] if limit else []
+    url = concat_url(ceilometer_url, build_url('/v2/samples', query, params))
+    try:
+        response = requests.get(url)
+    except requests.exceptions.RequestException as e:
+        raise e
+    return response.json()
+
+def meter_list(request, ceilometer_url=None, query=None):
+    """List the user's meters."""
+    url = concat_url(ceilometer_url, build_url('/v2/meters', query))
+    try:
+        response = requests.get(url)
+    except requests.exceptions.RequestException as e:
+        raise e
+    return response.json()
+
+
+def statistic_list(request, meter_name, ceilometer_url=None, query=None, period=None):
+    """List of statistics."""
+    p = ['period=%s' % period] if period else []
+    url = concat_url(ceilometer_url, build_url('/v2/meters/' + meter_name + '/statistics', query, p))
+    try:
+        response = requests.get(url)
+    except requests.exceptions.RequestException as e:
+        raise e
+    return response.json()
+
+def diff_lists(a, b):
+    if not a:
+        return []
+    elif not b:
+        return a
+    else:
+        return list(set(a) - set(b))
+
+def get_resource_map(request, ceilometer_url, query=None):
+    resource_map = {}
+    try:
+        resources = resource_list(request, ceilometer_url=ceilometer_url, query=query)
+        for r in resources:
+            if 'display_name' in r['metadata']:
+                name = r['metadata']['display_name']
+            elif 'name' in r['metadata']:
+                name = r['metadata']['name']
+            else:
+                name = r['resource_id']
+            resource_map[r['resource_id']] = name
+    except requests.exceptions.RequestException as e:
+        raise e
+
+    return resource_map
+
+class Meters(object):
+    """Class for listing of available meters.
+
+    It is listing meters defined in this class that are available
+    in Ceilometer meter_list.
+
+    It is storing information that is not available in Ceilometer, i.e.
+    label, description.
+
+    """
+
+    def __init__(self, request=None, ceilometer_meter_list=None, ceilometer_url=None, query=None, tenant_map=None, resource_map=None):
+        # Storing the request.
+        self._request = request
+        self.ceilometer_url = ceilometer_url
+        self.tenant_map = tenant_map
+        self.resource_map = resource_map
+
+        # Storing the Ceilometer meter list
+        if ceilometer_meter_list:
+            self._ceilometer_meter_list = ceilometer_meter_list
+        else:
+            try:
+                meter_query=[]
+                if query:
+                    meter_query = query
+                self._ceilometer_meter_list = meter_list(request, self.ceilometer_url, meter_query)
+            except requests.exceptions.RequestException as e:
+                self._ceilometer_meter_list = []
+                raise e
+
+        # Storing the meters info categorized by their services.
+        self._nova_meters_info = self._get_nova_meters_info()
+        self._neutron_meters_info = self._get_neutron_meters_info()
+        self._glance_meters_info = self._get_glance_meters_info()
+        self._cinder_meters_info = self._get_cinder_meters_info()
+        self._swift_meters_info = self._get_swift_meters_info()
+        self._kwapi_meters_info = self._get_kwapi_meters_info()
+        self._ipmi_meters_info = self._get_ipmi_meters_info()
+        self._vcpe_meters_info = self._get_vcpe_meters_info()
+        self._volt_meters_info = self._get_volt_meters_info()
+        self._sdn_meters_info = self._get_sdn_meters_info()
+
+        # Storing the meters info of all services together.
+        all_services_meters = (self._nova_meters_info,
+                               self._neutron_meters_info,
+                               self._glance_meters_info,
+                               self._cinder_meters_info,
+                               self._swift_meters_info,
+                               self._kwapi_meters_info,
+                               self._ipmi_meters_info,
+                               self._vcpe_meters_info,
+                               self._volt_meters_info,
+                               self._sdn_meters_info)
+        self._all_meters_info = {}
+        for service_meters in all_services_meters:
+            self._all_meters_info.update(dict([(meter_name, meter_info)
+                                               for meter_name, meter_info
+                                               in service_meters.items()]))
+
+        # Here will be the cached Meter objects, that will be reused for
+        # repeated listing.
+        self._cached_meters = {}
+
+    def list_all(self, only_meters=None, except_meters=None):
+        """Returns a list of meters based on the meters names.
+
+        :Parameters:
+          - `only_meters`: The list of meter names we want to show.
+          - `except_meters`: The list of meter names we don't want to show.
+        """
+
+        return self._list(only_meters=only_meters,
+                          except_meters=except_meters)
+
+    def list_nova(self, except_meters=None):
+        """Returns a list of meters tied to nova.
+
+        :Parameters:
+          - `except_meters`: The list of meter names we don't want to show.
+        """
+
+        return self._list(only_meters=self._nova_meters_info.keys(),
+                          except_meters=except_meters)
+
+    def list_neutron(self, except_meters=None):
+        """Returns a list of meters tied to neutron.
+
+        :Parameters:
+          - `except_meters`: The list of meter names we don't want to show.
+        """
+
+        return self._list(only_meters=self._neutron_meters_info.keys(),
+                          except_meters=except_meters)
+
+    def list_glance(self, except_meters=None):
+        """Returns a list of meters tied to glance.
+
+        :Parameters:
+          - `except_meters`: The list of meter names we don't want to show.
+        """
+
+        return self._list(only_meters=self._glance_meters_info.keys(),
+                          except_meters=except_meters)
+
+    def list_cinder(self, except_meters=None):
+        """Returns a list of meters tied to cinder.
+
+        :Parameters:
+          - `except_meters`: The list of meter names we don't want to show.
+        """
+
+        return self._list(only_meters=self._cinder_meters_info.keys(),
+                          except_meters=except_meters)
+
+    def list_swift(self, except_meters=None):
+        """Returns a list of meters tied to swift.
+
+        :Parameters:
+          - `except_meters`: The list of meter names we don't want to show.
+        """
+
+        return self._list(only_meters=self._swift_meters_info.keys(),
+                          except_meters=except_meters)
+
+    def list_kwapi(self, except_meters=None):
+        """Returns a list of meters tied to kwapi.
+
+        :Parameters:
+          - `except_meters`: The list of meter names we don't want to show.
+        """
+
+        return self._list(only_meters=self._kwapi_meters_info.keys(),
+                          except_meters=except_meters)
+
+    def list_ipmi(self, except_meters=None):
+        """Returns a list of meters tied to ipmi
+
+        :Parameters:
+          - `except_meters`: The list of meter names we don't want to show
+        """
+
+        return self._list(only_meters=self._ipmi_meters_info.keys(),
+                          except_meters=except_meters)
+
+    def list_vcpe(self, except_meters=None):
+        """Returns a list of meters tied to vcpe service
+
+        :Parameters:
+          - `except_meters`: The list of meter names we don't want to show
+        """
+
+        return self._list(only_meters=self._vcpe_meters_info.keys(),
+                          except_meters=except_meters)
+
+    def list_volt(self, except_meters=None):
+        """Returns a list of meters tied to volt service
+
+        :Parameters:
+          - `except_meters`: The list of meter names we don't want to show
+        """
+
+        return self._list(only_meters=self._volt_meters_info.keys(),
+                          except_meters=except_meters)
+
+    def list_sdn(self, except_meters=None):
+        """Returns a list of meters tied to sdn service
+
+        :Parameters:
+          - `except_meters`: The list of meter names we don't want to show
+        """
+
+        return self._list(only_meters=self._sdn_meters_info.keys(),
+                          except_meters=except_meters)
+
+    def list_other_services(self, except_meters=None):
+        """Returns a list of meters tied to ipmi
+
+        :Parameters:
+          - `except_meters`: The list of meter names we don't want to show
+        """
+        other_service_meters = [m for m in self._ceilometer_meter_list
+                                if m.name not in self._all_meters_info.keys()]
+        other_service_meters = diff_lists(other_service_meters, except_meters)
+
+        meters = []
+        for meter in other_service_meters:
+            self._cached_meters[meter.name] = meter
+            meters.append(meter)
+        return meters
+
+    def _list(self, only_meters=None, except_meters=None):
+        """Returns a list of meters based on the meters names.
+
+        :Parameters:
+          - `only_meters`: The list of meter names we want to show.
+          - `except_meters`: The list of meter names we don't want to show.
+        """
+
+        # Get all wanted meter names.
+        if only_meters:
+            meter_names = only_meters
+        else:
+            meter_names = [meter_name for meter_name
+                           in self._all_meters_info.keys()]
+
+        meter_names = diff_lists(meter_names, except_meters)
+        # Collect meters for wanted meter names.
+        return self._get_meters(meter_names)
+
+    def _get_meters(self, meter_names):
+        """Obtain meters based on meter_names.
+
+        The meters that do not exist in Ceilometer meter list are left out.
+
+        :Parameters:
+          - `meter_names`: A list of meter names we want to fetch.
+        """
+
+        meters = []
+        for meter_name in meter_names:
+            meter_candidates = self._get_meter(meter_name)
+            if meter_candidates:
+                meters.extend(meter_candidates)
+        return meters
+
+    def _get_meter(self, meter_name):
+        """Obtains a meter.
+
+        Obtains meter either from cache or from Ceilometer meter list
+        joined with statically defined meter info like label and description.
+
+        :Parameters:
+          - `meter_name`: A meter name we want to fetch.
+        """
+        meter_candidates = self._cached_meters.get(meter_name, None)
+        if not meter_candidates:
+            meter_candidates = [m for m in self._ceilometer_meter_list
+                                if m["name"] == meter_name]
+
+            if meter_candidates:
+                meter_info = self._all_meters_info.get(meter_name, None)
+                if meter_info:
+                    label = meter_info["label"]
+                    description = meter_info["description"]
+                    meter_category = meter_info["type"]
+                else:
+                    label = ""
+                    description = ""
+                    meter_category = "Other"
+                for meter in meter_candidates:
+                    meter["label"] = label
+                    meter["description"] = description
+                    meter["category"] = meter_category
+                    if meter["project_id"] in self.tenant_map.keys():
+                        meter["slice"] = self.tenant_map[meter["project_id"]]["slice"]
+                        meter["service"] = self.tenant_map[meter["project_id"]]["service"]
+                    else:
+                        meter["slice"] = meter["project_id"]
+                        meter["service"] = "Other"
+                    if meter["resource_id"] in self.resource_map.keys():
+                        meter["resource_name"] = self.resource_map[meter["resource_id"]]
+
+                self._cached_meters[meter_name] = meter_candidates
+
+        return meter_candidates
+
+    def _get_nova_meters_info(self):
+        """Returns additional info for each meter.
+
+        That will be used for augmenting the Ceilometer meter.
+        """
+
+        # TODO(lsmola) Unless the Ceilometer will provide the information
+        # below, I need to define it as a static here. I will be joining this
+        # to info that I am able to obtain from Ceilometer meters, hopefully
+        # some day it will be supported all.
+        meters_info = datastructures.SortedDict([
+            ("instance", {
+                'type': _("Nova"),
+                'label': '',
+                'description': _("Existence of instance"),
+            }),
+            ("instance:<type>", {
+                'type': _("Nova"),
+                'label': '',
+                'description': _("Existence of instance <type> "
+                                 "(openstack types)"),
+            }),
+            ("memory", {
+                'type': _("Nova"),
+                'label': '',
+                'description': _("Volume of RAM"),
+            }),
+            ("memory.usage", {
+                'type': _("Nova"),
+                'label': '',
+                'description': _("Volume of RAM used"),
+            }),
+            ("cpu", {
+                'type': _("Nova"),
+                'label': '',
+                'description': _("CPU time used"),
+            }),
+            ("cpu_util", {
+                'type': _("Nova"),
+                'label': '',
+                'description': _("Average CPU utilization"),
+            }),
+            ("vcpus", {
+                'type': _("Nova"),
+                'label': '',
+                'description': _("Number of VCPUs"),
+            }),
+            ("disk.read.requests", {
+                'type': _("Nova"),
+                'label': '',
+                'description': _("Number of read requests"),
+            }),
+            ("disk.write.requests", {
+                'type': _("Nova"),
+                'label': '',
+                'description': _("Number of write requests"),
+            }),
+            ("disk.read.bytes", {
+                'type': _("Nova"),
+                'label': '',
+                'description': _("Volume of reads"),
+            }),
+            ("disk.write.bytes", {
+                'type': _("Nova"),
+                'label': '',
+                'description': _("Volume of writes"),
+            }),
+            ("disk.read.requests.rate", {
+                'type': _("Nova"),
+                'label': '',
+                'description': _("Average rate of read requests"),
+            }),
+            ("disk.write.requests.rate", {
+                'type': _("Nova"),
+                'label': '',
+                'description': _("Average rate of write requests"),
+            }),
+            ("disk.read.bytes.rate", {
+                'type': _("Nova"),
+                'label': '',
+                'description': _("Average rate of reads"),
+            }),
+            ("disk.write.bytes.rate", {
+                'type': _("Nova"),
+                'label': '',
+                'description': _("Average volume of writes"),
+            }),
+            ("disk.root.size", {
+                'type': _("Nova"),
+                'label': '',
+                'description': _("Size of root disk"),
+            }),
+            ("disk.ephemeral.size", {
+                'type': _("Nova"),
+                'label': '',
+                'description': _("Size of ephemeral disk"),
+            }),
+            ("network.incoming.bytes", {
+                'type': _("Nova"),
+                'label': '',
+                'description': _("Number of incoming bytes "
+                                 "on the network for a VM interface"),
+            }),
+            ("network.outgoing.bytes", {
+                'type': _("Nova"),
+                'label': '',
+                'description': _("Number of outgoing bytes "
+                                 "on the network for a VM interface"),
+            }),
+            ("network.incoming.packets", {
+                'type': _("Nova"),
+                'label': '',
+                'description': _("Number of incoming "
+                                 "packets for a VM interface"),
+            }),
+            ("network.outgoing.packets", {
+                'type': _("Nova"),
+                'label': '',
+                'description': _("Number of outgoing "
+                                 "packets for a VM interface"),
+            }),
+            ("network.incoming.bytes.rate", {
+                'type': _("Nova"),
+                'label': '',
+                'description': _("Average rate per sec of incoming "
+                                 "bytes on a VM network interface"),
+            }),
+            ("network.outgoing.bytes.rate", {
+                'type': _("Nova"),
+                'label': '',
+                'description': _("Average rate per sec of outgoing "
+                                 "bytes on a VM network interface"),
+            }),
+            ("network.incoming.packets.rate", {
+                'type': _("Nova"),
+                'label': '',
+                'description': _("Average rate per sec of incoming "
+                                 "packets on a VM network interface"),
+            }),
+            ("network.outgoing.packets.rate", {
+                'type': _("Nova"),
+                'label': '',
+                'description': _("Average rate per sec of outgoing "
+                                 "packets on a VM network interface"),
+            }),
+        ])
+        # Adding flavor based meters into meters_info dict
+        # TODO(lsmola) this kind of meter will be probably deprecated
+        # https://bugs.launchpad.net/ceilometer/+bug/1208365 . Delete it then.
+        #for flavor in get_flavor_names(self._request):
+        #    name = 'instance:%s' % flavor
+        #    meters_info[name] = dict(meters_info["instance:<type>"])
+
+        #    meters_info[name]['description'] = (
+        #        _('Duration of instance type %s (openstack flavor)') %
+        #        flavor)
+
+        # TODO(lsmola) allow to set specific in local_settings. For all meters
+        # because users can have their own agents and meters.
+        return meters_info
+
+    def _get_neutron_meters_info(self):
+        """Returns additional info for each meter.
+
+        That will be used for augmenting the Ceilometer meter.
+        """
+
+        # TODO(lsmola) Unless the Ceilometer will provide the information
+        # below, I need to define it as a static here. I will be joining this
+        # to info that I am able to obtain from Ceilometer meters, hopefully
+        # some day it will be supported all.
+        return datastructures.SortedDict([
+            ('network', {
+                'type': _("Neutron"),
+                'label': '',
+                'description': _("Existence of network"),
+            }),
+            ('network.create', {
+                'type': _("Neutron"),
+                'label': '',
+                'description': _("Creation requests for this network"),
+            }),
+            ('network.update', {
+                'type': _("Neutron"),
+                'label': '',
+                'description': _("Update requests for this network"),
+            }),
+            ('subnet', {
+                'type': _("Neutron"),
+                'label': '',
+                'description': _("Existence of subnet"),
+            }),
+            ('subnet.create', {
+                'type': _("Neutron"),
+                'label': '',
+                'description': _("Creation requests for this subnet"),
+            }),
+            ('subnet.update', {
+                'type': _("Neutron"),
+                'label': '',
+                'description': _("Update requests for this subnet"),
+            }),
+            ('port', {
+                'type': _("Neutron"),
+                'label': '',
+                'description': _("Existence of port"),
+            }),
+            ('port.create', {
+                'type': _("Neutron"),
+                'label': '',
+                'description': _("Creation requests for this port"),
+            }),
+            ('port.update', {
+                'type': _("Neutron"),
+                'label': '',
+                'description': _("Update requests for this port"),
+            }),
+            ('router', {
+                'type': _("Neutron"),
+                'label': '',
+                'description': _("Existence of router"),
+            }),
+            ('router.create', {
+                'type': _("Neutron"),
+                'label': '',
+                'description': _("Creation requests for this router"),
+            }),
+            ('router.update', {
+                'type': _("Neutron"),
+                'label': '',
+                'description': _("Update requests for this router"),
+            }),
+            ('ip.floating', {
+                'type': _("Neutron"),
+                'label': '',
+                'description': _("Existence of floating ip"),
+            }),
+            ('ip.floating.create', {
+                'type': _("Neutron"),
+                'label': '',
+                'description': _("Creation requests for this floating ip"),
+            }),
+            ('ip.floating.update', {
+                'type': _("Neutron"),
+                'label': '',
+                'description': _("Update requests for this floating ip"),
+            }),
+        ])
+
+    def _get_glance_meters_info(self):
+        """Returns additional info for each meter.
+
+        That will be used for augmenting the Ceilometer meter.
+        """
+
+        # TODO(lsmola) Unless the Ceilometer will provide the information
+        # below, I need to define it as a static here. I will be joining this
+        # to info that I am able to obtain from Ceilometer meters, hopefully
+        # some day it will be supported all.
+        return datastructures.SortedDict([
+            ('image', {
+                'type': _("Glance"),
+                'label': '',
+                'description': _("Image existence check"),
+            }),
+            ('image.size', {
+                'type': _("Glance"),
+                'label': '',
+                'description': _("Uploaded image size"),
+            }),
+            ('image.update', {
+                'type': _("Glance"),
+                'label': '',
+                'description': _("Number of image updates"),
+            }),
+            ('image.upload', {
+                'type': _("Glance"),
+                'label': '',
+                'description': _("Number of image uploads"),
+            }),
+            ('image.delete', {
+                'type': _("Glance"),
+                'label': '',
+                'description': _("Number of image deletions"),
+            }),
+            ('image.download', {
+                'type': _("Glance"),
+                'label': '',
+                'description': _("Image is downloaded"),
+            }),
+            ('image.serve', {
+                'type': _("Glance"),
+                'label': '',
+                'description': _("Image is served out"),
+            }),
+        ])
+
+    def _get_cinder_meters_info(self):
+        """Returns additional info for each meter.
+
+        That will be used for augmenting the Ceilometer meter.
+        """
+
+        # TODO(lsmola) Unless the Ceilometer will provide the information
+        # below, I need to define it as a static here. I will be joining this
+        # to info that I am able to obtain from Ceilometer meters, hopefully
+        # some day it will be supported all.
+        return datastructures.SortedDict([
+            ('volume', {
+                'type': _("Cinder"),
+                'label': '',
+                'description': _("Existence of volume"),
+            }),
+            ('volume.size', {
+                'type': _("Cinder"),
+                'label': '',
+                'description': _("Size of volume"),
+            }),
+        ])
+
+    def _get_swift_meters_info(self):
+        """Returns additional info for each meter.
+
+        That will be used for augmenting the Ceilometer meter.
+        """
+
+        # TODO(lsmola) Unless the Ceilometer will provide the information
+        # below, I need to define it as a static here. I will be joining this
+        # to info that I am able to obtain from Ceilometer meters, hopefully
+        # some day it will be supported all.
+        return datastructures.SortedDict([
+            ('storage.objects', {
+                'type': _("Swift"),
+                'label': '',
+                'description': _("Number of objects"),
+            }),
+            ('storage.objects.size', {
+                'type': _("Swift"),
+                'label': '',
+                'description': _("Total size of stored objects"),
+            }),
+            ('storage.objects.containers', {
+                'type': _("Swift"),
+                'label': '',
+                'description': _("Number of containers"),
+            }),
+            ('storage.objects.incoming.bytes', {
+                'type': _("Swift"),
+                'label': '',
+                'description': _("Number of incoming bytes"),
+            }),
+            ('storage.objects.outgoing.bytes', {
+                'type': _("Swift"),
+                'label': '',
+                'description': _("Number of outgoing bytes"),
+            }),
+            ('storage.api.request', {
+                'type': _("Swift"),
+                'label': '',
+                'description': _("Number of API requests against swift"),
+            }),
+        ])
+
+    def _get_kwapi_meters_info(self):
+        """Returns additional info for each meter.
+
+        That will be used for augmenting the Ceilometer meter.
+        """
+
+        # TODO(lsmola) Unless the Ceilometer will provide the information
+        # below, I need to define it as a static here. I will be joining this
+        # to info that I am able to obtain from Ceilometer meters, hopefully
+        # some day it will be supported all.
+        return datastructures.SortedDict([
+            ('energy', {
+                'type': _("Kwapi"),
+                'label': '',
+                'description': _("Amount of energy"),
+            }),
+            ('power', {
+                'type': _("Kwapi"),
+                'label': '',
+                'description': _("Power consumption"),
+            }),
+        ])
+
+    def _get_ipmi_meters_info(self):
+        """Returns additional info for each meter
+
+        That will be used for augmenting the Ceilometer meter
+        """
+
+        # TODO(lsmola) Unless the Ceilometer will provide the information
+        # below, I need to define it as a static here. I will be joining this
+        # to info that I am able to obtain from Ceilometer meters, hopefully
+        # some day it will be supported all.
+        return datastructures.SortedDict([
+            ('hardware.ipmi.node.power', {
+                'type': _("IPMI"),
+                'label': '',
+                'description': _("System Current Power"),
+            }),
+            ('hardware.ipmi.fan', {
+                'type': _("IPMI"),
+                'label': '',
+                'description': _("Fan RPM"),
+            }),
+            ('hardware.ipmi.temperature', {
+                'type': _("IPMI"),
+                'label': '',
+                'description': _("Sensor Temperature Reading"),
+            }),
+            ('hardware.ipmi.current', {
+                'type': _("IPMI"),
+                'label': '',
+                'description': _("Sensor Current Reading"),
+            }),
+            ('hardware.ipmi.voltage', {
+                'type': _("IPMI"),
+                'label': '',
+                'description': _("Sensor Voltage Reading"),
+            }),
+            ('hardware.ipmi.node.inlet_temperature', {
+                'type': _("IPMI"),
+                'label': '',
+                'description': _("System Inlet Temperature Reading"),
+            }),
+            ('hardware.ipmi.node.outlet_temperature', {
+                'type': _("IPMI"),
+                'label': '',
+                'description': _("System Outlet Temperature Reading"),
+            }),
+            ('hardware.ipmi.node.airflow', {
+                'type': _("IPMI"),
+                'label': '',
+                'description': _("System Airflow Reading"),
+            }),
+            ('hardware.ipmi.node.cups', {
+                'type': _("IPMI"),
+                'label': '',
+                'description': _("System CUPS Reading"),
+            }),
+            ('hardware.ipmi.node.cpu_util', {
+                'type': _("IPMI"),
+                'label': '',
+                'description': _("System CPU Utility Reading"),
+            }),
+            ('hardware.ipmi.node.mem_util', {
+                'type': _("IPMI"),
+                'label': '',
+                'description': _("System Memory Utility Reading"),
+            }),
+            ('hardware.ipmi.node.io_util', {
+                'type': _("IPMI"),
+                'label': '',
+                'description': _("System IO Utility Reading"),
+            }),
+        ])
+
+    def _get_vcpe_meters_info(self):
+        """Returns additional info for each meter
+
+        That will be used for augmenting the Ceilometer meter
+        """
+
+        # TODO(lsmola) Unless the Ceilometer will provide the information
+        # below, I need to define it as a static here. I will be joining this
+        # to info that I am able to obtain from Ceilometer meters, hopefully
+        # some day it will be supported all.
+        return datastructures.SortedDict([
+            ('vsg', {
+                'type': _("VSG"),
+                'label': '',
+                'description': _("Existence of vsg instance"),
+            }),
+            ('vsg.dns.cache.size', {
+                'type': _("VSG"),
+                'label': '',
+                'description': _("Number of entries in DNS cache"),
+            }),
+            ('vsg.dns.total_instered_entries', {
+                'type': _("VSG"),
+                'label': '',
+                'description': _("Total number of inserted entries into the cache"),
+            }),
+            ('vsg.dns.replaced_unexpired_entries', {
+                'type': _("VSG"),
+                'label': '',
+                'description': _("Unexpired entries that were thrown out of cache"),
+            }),
+            ('vsg.dns.queries_answered_locally', {
+                'type': _("VSG"),
+                'label': '',
+                'description': _("Number of cache hits"),
+            }),
+            ('vsg.dns.queries_forwarded', {
+                'type': _("VSG"),
+                'label': '',
+                'description': _("Number of cache misses"),
+            }),
+            ('vsg.dns.server.queries_sent', {
+                'type': _("VSG"),
+                'label': '',
+                'description': _("For each upstream server, the number of queries sent"),
+            }),
+            ('vsg.dns.server.queries_failed', {
+                'type': _("VSG"),
+                'label': '',
+                'description': _("For each upstream server, the number of queries failed"),
+            }),
+        ])
+
+    def _get_volt_meters_info(self):
+        """Returns additional info for each meter
+
+        That will be used for augmenting the Ceilometer meter
+        """
+
+        # TODO(lsmola) Unless the Ceilometer will provide the information
+        # below, I need to define it as a static here. I will be joining this
+        # to info that I am able to obtain from Ceilometer meters, hopefully
+        # some day it will be supported all.
+        return datastructures.SortedDict([
+            ('volt.device', {
+                'type': _("VOLT"),
+                'label': '',
+                'description': _("Existence of olt device"),
+            }),
+            ('volt.device.disconnect', {
+                'type': _("VOLT"),
+                'label': '',
+                'description': _("Olt device disconnected"),
+            }),
+            ('volt.device.subscriber', {
+                'type': _("VOLT"),
+                'label': '',
+                'description': _("Existence of olt subscriber"),
+            }),
+            ('volt.device.subscriber.unregister', {
+                'type': _("VOLT"),
+                'label': '',
+                'description': _("Olt subscriber unregistered"),
+            }),
+        ])
+
+    def _get_sdn_meters_info(self):
+        """Returns additional info for each meter
+
+        That will be used for augmenting the Ceilometer meter
+        """
+
+        # TODO(lsmola) Unless the Ceilometer will provide the information
+        # below, I need to define it as a static here. I will be joining this
+        # to info that I am able to obtain from Ceilometer meters, hopefully
+        # some day it will be supported all.
+        return datastructures.SortedDict([
+            ('switch', {
+                'type': _("SDN"),
+                'label': '',
+                'description': _("Existence of switch"),
+            }),
+            ('switch.port', {
+                'type': _("SDN"),
+                'label': '',
+                'description': _("Existence of port"),
+            }),
+            ('switch.port.receive.packets', {
+                'type': _("SDN"),
+                'label': '',
+                'description': _("Packets received on port"),
+            }),
+            ('switch.port.transmit.packets', {
+                'type': _("SDN"),
+                'label': '',
+                'description': _("Packets transmitted on port"),
+            }),
+            ('switch.port.receive.drops', {
+                'type': _("SDN"),
+                'label': '',
+                'description': _("Drops received on port"),
+            }),
+            ('switch.port.transmit.drops', {
+                'type': _("SDN"),
+                'label': '',
+                'description': _("Drops transmitted on port"),
+            }),
+            ('switch.port.receive.errors', {
+                'type': _("SDN"),
+                'label': '',
+                'description': _("Errors received on port"),
+            }),
+            ('switch.port.transmit.errors', {
+                'type': _("SDN"),
+                'label': '',
+                'description': _("Errors transmitted on port"),
+            }),
+            ('switch.flow', {
+                'type': _("SDN"),
+                'label': '',
+                'description': _("Duration of flow"),
+            }),
+            ('switch.flow.packets', {
+                'type': _("SDN"),
+                'label': '',
+                'description': _("Packets received"),
+            }),
+            ('switch.table', {
+                'type': _("SDN"),
+                'label': '',
+                'description': _("Existence of table"),
+            }),
+            ('switch.table.active.entries', {
+                'type': _("SDN"),
+                'label': '',
+                'description': _("Active entries in table"),
+            }),
+        ])
+
+def make_query(user_id=None, tenant_id=None, resource_id=None,
+               user_ids=None, tenant_ids=None, resource_ids=None):
+    """Returns query built from given parameters.
+
+    This query can be then used for querying resources, meters and
+    statistics.
+
+    :Parameters:
+      - `user_id`: user_id, has a priority over list of ids
+      - `tenant_id`: tenant_id, has a priority over list of ids
+      - `resource_id`: resource_id, has a priority over list of ids
+      - `user_ids`: list of user_ids
+      - `tenant_ids`: list of tenant_ids
+      - `resource_ids`: list of resource_ids
+    """
+    user_ids = user_ids or []
+    tenant_ids = tenant_ids or []
+    resource_ids = resource_ids or []
+
+    query = []
+    if user_id:
+        user_ids = [user_id]
+    for u_id in user_ids:
+        query.append({"field": "user_id", "op": "eq", "value": u_id})
+
+    if tenant_id:
+        tenant_ids = [tenant_id]
+    for t_id in tenant_ids:
+        query.append({"field": "project_id", "op": "eq", "value": t_id})
+
+    if resource_id:
+        resource_ids = [resource_id]
+    for r_id in resource_ids:
+        query.append({"field": "resource_id", "op": "eq", "value": r_id})
+
+    return query
+
+def calc_date_args(date_from, date_to, date_options):
+    # TODO(lsmola) all timestamps should probably work with
+    # current timezone. And also show the current timezone in chart.
+    if date_options == "other":
+        try:
+            if date_from:
+                date_from = pytz.utc.localize(
+                    datetime.datetime.strptime(str(date_from), "%Y-%m-%d"))
+            else:
+                # TODO(lsmola) there should be probably the date
+                # of the first sample as default, so it correctly
+                # counts the time window. Though I need ordering
+                # and limit of samples to obtain that.
+                pass
+            if date_to:
+                date_to = pytz.utc.localize(
+                    datetime.datetime.strptime(str(date_to), "%Y-%m-%d"))
+                # It returns the beginning of the day, I want the end of
+                # the day, so I add one day without a second.
+                date_to = (date_to + datetime.timedelta(days=1) -
+                           datetime.timedelta(seconds=1))
+            else:
+                date_to = timezone.now()
+        except Exception:
+            raise ValueError(_("The dates haven't been recognized"))
+    else:
+        try:
+            date_to = timezone.now()
+            date_from = date_to - datetime.timedelta(days=float(date_options))
+        except Exception as e:
+            raise e
+            #raise ValueError(_("The time delta must be a number representing "
+            #                   "the time span in days"))
+    return date_from, date_to
+
+class MetersList(APIView):
+    method_kind = "list"
+    method_name = "meters"
+
+    def get(self, request, format=None):
+        if (not request.user.is_authenticated()):
+            raise PermissionDenied("You must be authenticated in order to use this API")
+        tenant_ceilometer_url = getTenantCeilometerProxyURL(request.user)
+        if (not tenant_ceilometer_url):
+            raise XOSMissingField("Tenant ceilometer URL is missing")
+
+        tenant_id = request.query_params.get('tenant', None)
+        resource_id = request.query_params.get('resource', None)
+
+        query = []
+        if tenant_id:
+            query.extend(make_query(tenant_id=tenant_id))
+        if resource_id:
+            query.extend(make_query(resource_id=resource_id))
+
+        tenant_map = getTenantControllerTenantMap(request.user)
+        resource_map = get_resource_map(request, ceilometer_url=tenant_ceilometer_url, query=query)
+        meters = Meters(request, ceilometer_url=tenant_ceilometer_url, query=query, tenant_map=tenant_map, resource_map=resource_map)
+        services = {
+            _('Nova'): meters.list_nova(),
+            _('Neutron'): meters.list_neutron(),
+            _('VSG'): meters.list_vcpe(),
+            _('VOLT'): meters.list_volt(),
+            _('SDN'): meters.list_sdn(),
+        }
+        meters = []
+        for service,smeters in services.iteritems():
+             meters.extend(smeters)
+        return Response(meters)
+
+class MeterStatisticsList(APIView):
+    method_kind = "list"
+    method_name = "meterstatistics"
+
+    def get(self, request, format=None):
+        if (not request.user.is_authenticated()):
+            raise PermissionDenied("You must be authenticated in order to use this API")
+        tenant_ceilometer_url = getTenantCeilometerProxyURL(request.user)
+        if (not tenant_ceilometer_url):
+            raise XOSMissingField("Tenant ceilometer URL is missing")
+        tenant_map = getTenantControllerTenantMap(request.user)
+        
+        date_options = request.query_params.get('period', 1)
+        date_from = request.query_params.get('date_from', '')
+        date_to = request.query_params.get('date_to', '')
+
+        try:
+            date_from, date_to = calc_date_args(date_from,
+                                                date_to,
+                                                date_options)
+        except Exception as e:
+           raise e 
+
+        additional_query = []
+        if date_from:
+            additional_query.append({'field': 'timestamp',
+                                     'op': 'ge',
+                                     'value': date_from})
+        if date_to:
+            additional_query.append({'field': 'timestamp',
+                                     'op': 'le',
+                                     'value': date_to})
+
+        meter_name = request.query_params.get('meter', None)
+        tenant_id = request.query_params.get('tenant', None)
+        resource_id = request.query_params.get('resource', None)
+
+        query = []
+        if tenant_id:
+            query.extend(make_query(tenant_id=tenant_id))
+        if resource_id:
+            query.extend(make_query(resource_id=resource_id))
+
+        if meter_name:
+            #Statistics query for one meter
+            if additional_query:
+                query = query + additional_query
+            statistics = statistic_list(request, meter_name,
+                                        ceilometer_url=tenant_ceilometer_url, query=query, period=3600*24)
+            statistic = statistics[-1]
+            row = {"name": 'none',
+                   "meter": meter_name,
+                   "time": statistic["period_end"],
+                   "value": statistic["avg"]}
+            return Response(row)
+
+        #Statistics query for all meter
+        resource_map = get_resource_map(request, ceilometer_url=tenant_ceilometer_url, query=query)
+        meters = Meters(request, ceilometer_url=tenant_ceilometer_url, query=query, tenant_map=tenant_map, resource_map=resource_map)
+        services = {
+            _('Nova'): meters.list_nova(),
+            _('Neutron'): meters.list_neutron(),
+            _('VSG'): meters.list_vcpe(),
+            _('VOLT'): meters.list_volt(),
+            _('SDN'): meters.list_sdn(),
+        }
+        report_rows = []
+        for service,meters in services.items():
+            for meter in meters:
+                query = make_query(tenant_id=meter["project_id"],resource_id=meter["resource_id"])
+                if additional_query:
+                    query = query + additional_query
+                try:
+                    statistics = statistic_list(request, meter["name"],
+                                        ceilometer_url=tenant_ceilometer_url, query=query, period=3600*24)
+                except Exception as e:
+                    logger.error('Exception during statistics query for meter %(meter)s and reason:%(reason)s' % {'meter':meter["name"], 'reason':str(e)})
+                    statistics = None
+
+                if not statistics:
+                    continue
+                statistic = statistics[-1]
+                row = {"name": 'none',
+                       "slice": meter["slice"],
+                       "project_id": meter["project_id"],
+                       "service": meter["service"],
+                       "resource_id": meter["resource_id"],
+                       "resource_name": meter["resource_name"],
+                       "meter": meter["name"],
+                       "description": meter["description"],
+                       "category": service,
+                       "time": statistic["period_end"],
+                       "value": statistic["avg"],
+                       "unit": meter["unit"]}
+                report_rows.append(row)
+
+        return Response(report_rows)
+
+
+class MeterSamplesList(APIView):
+    method_kind = "list"
+    method_name = "metersamples"
+
+    def get(self, request, format=None):
+        if (not request.user.is_authenticated()):
+            raise PermissionDenied("You must be authenticated in order to use this API")
+        tenant_ceilometer_url = getTenantCeilometerProxyURL(request.user)
+        if (not tenant_ceilometer_url):
+            raise XOSMissingField("Tenant ceilometer URL is missing")
+        meter_name = request.query_params.get('meter', None)
+        if not meter_name:
+            raise XOSMissingField("Meter name in query params is missing")
+        limit = request.query_params.get('limit', 10)
+        tenant_id = request.query_params.get('tenant', None)
+        resource_id = request.query_params.get('resource', None)
+        query = []
+        if tenant_id:
+            query.extend(make_query(tenant_id=tenant_id))
+        if resource_id:
+            query.extend(make_query(resource_id=resource_id))
+        query.append({"field": "meter", "op": "eq", "value": meter_name})
+        samples = sample_list(request, meter_name,
+                           ceilometer_url=tenant_ceilometer_url, query=query, limit=limit) 
+        if samples:
+            tenant_map = getTenantControllerTenantMap(request.user)
+            resource_map = get_resource_map(request, ceilometer_url=tenant_ceilometer_url)
+            for sample in samples:
+                 if sample["project_id"] in tenant_map.keys():
+                     sample["slice"] = tenant_map[sample["project_id"]]["slice"]
+                 else:
+                     sample["slice"] = sample["project_id"]
+                 if sample["resource_id"] in resource_map.keys():
+                     sample["resource_name"] = resource_map[sample["resource_id"]]
+                 else:
+                     sample["resource_name"] = sample["resource_id"]
+        return Response(samples)
+
+class XOSSliceServiceList(APIView):
+    method_kind = "list"
+    method_name = "xos-slice-service-mapping"
+
+    def get(self, request, format=None):
+        if (not request.user.is_authenticated()):
+            raise PermissionDenied("You must be authenticated in order to use this API")
+        tenant_map = getTenantControllerTenantMap(request.user)
+        service_map={}
+        for k,v in tenant_map.iteritems():
+            if not (v['service'] in service_map.keys()):
+                service_map[v['service']] = {}
+                service_map[v['service']]['service'] = v['service']
+                service_map[v['service']]['slices'] = []
+            slice_details = {'slice':v['slice'], 'project_id':k}
+            service_map[v['service']]['slices'].append(slice_details)
+        return Response(service_map.values())
+
+class XOSInstanceStatisticsList(APIView):
+    method_kind = "list"
+    method_name = "xos-instance-statistics"
+
+    def get(self, request, format=None):
+        if (not request.user.is_authenticated()):
+            raise PermissionDenied("You must be authenticated in order to use this API")
+        tenant_ceilometer_url = getTenantCeilometerProxyURL(request.user)
+        if (not tenant_ceilometer_url):
+            raise XOSMissingField("Tenant ceilometer URL is missing")
+        instance_uuid = request.query_params.get('instance-uuid', None)
+        if not instance_uuid:
+            raise XOSMissingField("Instance UUID in query params is missing")
+        if not Instance.objects.filter(instance_uuid=instance_uuid):
+            raise XOSMissingField("XOS Instance object is missing for this uuid")
+        xos_instance = Instance.objects.filter(instance_uuid=instance_uuid)[0]
+        tenant_map = getTenantControllerTenantMap(request.user, xos_instance.slice)
+        tenant_id = tenant_map.keys()[0]
+        resource_ids = []
+        resource_ids.append(instance_uuid)
+        for p in xos_instance.ports.all():
+            #neutron port resource id is represented in ceilometer as "nova instance-name"+"-"+"nova instance-id"+"-"+"tap"+first 11 characters of port-id
+            resource_ids.append(xos_instance.instance_id+"-"+instance_uuid+"-tap"+p.port_id[:11])
+        
+        date_options = request.query_params.get('period', 1)
+        date_from = request.query_params.get('date_from', '')
+        date_to = request.query_params.get('date_to', '')
+
+        try:
+            date_from, date_to = calc_date_args(date_from,
+                                                date_to,
+                                                date_options)
+        except Exception as e:
+           raise e 
+
+        additional_query = []
+        if date_from:
+            additional_query.append({'field': 'timestamp',
+                                     'op': 'ge',
+                                     'value': date_from})
+        if date_to:
+            additional_query.append({'field': 'timestamp',
+                                     'op': 'le',
+                                     'value': date_to})
+
+        report_rows = []
+        for resource_id in resource_ids:
+            query = []
+            if tenant_id:
+                query.extend(make_query(tenant_id=tenant_id))
+            if resource_id:
+                query.extend(make_query(resource_id=resource_id))
+
+            #Statistics query for all meter
+            resource_map = get_resource_map(request, ceilometer_url=tenant_ceilometer_url, query=query)
+            meters = Meters(request, ceilometer_url=tenant_ceilometer_url, query=query, tenant_map=tenant_map, resource_map=resource_map)
+            exclude_nova_meters_info = [ "instance", "instance:<type>", "disk.read.requests", "disk.write.requests",
+                "disk.read.bytes", "disk.write.bytes", "disk.read.requests.rate", "disk.write.requests.rate", "disk.read.bytes.rate",
+                "disk.write.bytes.rate", "disk.root.size", "disk.ephemeral.size"]
+            exclude_neutron_meters_info = [ 'network.create', 'network.update', 'subnet.create',
+                'subnet.update', 'port.create', 'port.update', 'router.create', 'router.update',
+                'ip.floating.create', 'ip.floating.update']
+            services = {
+                _('Nova'): meters.list_nova(except_meters=exclude_nova_meters_info),
+                _('Neutron'): meters.list_neutron(except_meters=exclude_neutron_meters_info),
+                _('VSG'): meters.list_vcpe(),
+                _('VOLT'): meters.list_volt(),
+                _('SDN'): meters.list_sdn(),
+            }
+            for service,meters in services.items():
+                for meter in meters:
+                    query = make_query(tenant_id=meter["project_id"],resource_id=meter["resource_id"])
+                    if additional_query:
+                        query = query + additional_query
+                    try:
+                        statistics = statistic_list(request, meter["name"],
+                                            ceilometer_url=tenant_ceilometer_url, query=query, period=3600*24)
+                    except Exception as e:
+                        logger.error('Exception during statistics query for meter %(meter)s and reason:%(reason)s' % {'meter':meter["name"], 'reason':str(e)})
+                        statistics = None
+
+                    if not statistics:
+                        continue
+                    statistic = statistics[-1]
+                    row = {"name": 'none',
+                           "slice": meter["slice"],
+                           "project_id": meter["project_id"],
+                           "service": meter["service"],
+                           "resource_id": meter["resource_id"],
+                           "resource_name": meter["resource_name"],
+                           "meter": meter["name"],
+                           "description": meter["description"],
+                           "category": service,
+                           "time": statistic["period_end"],
+                           "value": statistic["avg"],
+                           "unit": meter["unit"]}
+                    report_rows.append(row)
+
+        return Response(report_rows)
+
+class ServiceAdjustScale(APIView):
+    method_kind = "list"
+    method_name = "serviceadjustscale"
+
+    def get(self, request, format=None):
+        if (not request.user.is_authenticated()) or (not request.user.is_admin):
+            raise PermissionDenied("You must be authenticated admin user in order to use this API")
+        service = request.query_params.get('service', None)
+        slice_hint = request.query_params.get('slice_hint', None)
+        scale = request.query_params.get('scale', None)
+        if not service or not slice_hint or not scale:
+            raise XOSMissingField("Mandatory fields missing")
+        services = Service.select_by_user(request.user)
+        logger.info('SRIKANTH: Services for this user %(services)s' % {'services':services})
+        if not services or (not services.get(name=service)):
+            raise XOSMissingField("Service not found")
+        service = services.get(name=service)
+        service.adjust_scale(slice_hint, int(scale))
+        return Response("Success")
diff --git a/xos/core/xoslib/methods/cordsubscriber._unused b/xos/core/xoslib/methods/cordsubscriber._unused
new file mode 100644
index 0000000..8fc88e0
--- /dev/null
+++ b/xos/core/xoslib/methods/cordsubscriber._unused
@@ -0,0 +1,380 @@
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+from rest_framework import serializers
+from rest_framework import generics
+from rest_framework import viewsets
+from rest_framework.decorators import detail_route, list_route
+from rest_framework.views import APIView
+from core.models import *
+from django.forms import widgets
+from django.conf.urls import patterns, url
+from services.volt.models import VOLTTenant, CordSubscriberRoot
+from core.xoslib.objects.cordsubscriber import CordSubscriber
+from plus import PlusSerializerMixin, XOSViewSet
+from django.shortcuts import get_object_or_404
+from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
+from xos.exceptions import *
+import json
+import subprocess
+
+if hasattr(serializers, "ReadOnlyField"):
+    # rest_framework 3.x
+    ReadOnlyField = serializers.ReadOnlyField
+else:
+    # rest_framework 2.x
+    ReadOnlyField = serializers.Field
+
+class CordSubscriberIdSerializer(serializers.ModelSerializer, PlusSerializerMixin):
+        id = ReadOnlyField()
+        service_specific_id = ReadOnlyField()
+        c_tag = ReadOnlyField()
+        s_tag = ReadOnlyField()
+        vcpe_id = ReadOnlyField()
+        instance = ReadOnlyField()
+        image = ReadOnlyField()
+        vbng_id = ReadOnlyField()
+        firewall_enable = serializers.BooleanField()
+        firewall_rules = serializers.CharField()
+        url_filter_enable = serializers.BooleanField()
+        url_filter_rules = serializers.CharField()
+        url_filter_level = serializers.CharField(required=False)
+        cdn_enable = serializers.BooleanField()
+        instance_name = ReadOnlyField()
+        image_name = ReadOnlyField()
+        routeable_subnet = serializers.CharField(required=False)
+        ssh_command = ReadOnlyField()
+        bbs_account = ReadOnlyField()
+
+        wan_container_ip = ReadOnlyField()
+        uplink_speed = serializers.CharField(required=False)
+        downlink_speed = serializers.CharField(required=False)
+        status = serializers.CharField()
+        enable_uverse = serializers.BooleanField()
+
+        lan_ip = ReadOnlyField()
+        wan_ip = ReadOnlyField()
+        nat_ip = ReadOnlyField()
+        private_ip = ReadOnlyField()
+
+        wan_mac = ReadOnlyField()
+
+        vcpe_synced = serializers.BooleanField()
+
+        humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+
+        class Meta:
+            model = CordSubscriber
+            fields = ('humanReadableName', 'id',
+                      'service_specific_id', 's_tag', 'c_tag',
+                      'vcpe_id', 'instance', 'instance_name', 'image', 'image_name',
+                      'firewall_enable', 'firewall_rules',
+                      'url_filter_enable', 'url_filter_rules', 'url_filter_level',
+                      'bbs_account',
+                      'ssh_command',
+                      'vcpe_synced',
+                      'cdn_enable', 'vbng_id', 'routeable_subnet', 'nat_ip', 'lan_ip', 'wan_ip', 'private_ip', 'wan_mac',
+                      'wan_container_ip',
+                      'uplink_speed', 'downlink_speed', 'status', 'enable_uverse')
+
+
+        def getHumanReadableName(self, obj):
+            return obj.__unicode__()
+
+#------------------------------------------------------------------------------
+# The "old" API
+# This is used by the xoslib-based GUI
+#------------------------------------------------------------------------------
+
+class CordSubscriberList(XOSListCreateAPIView):
+    queryset = CordSubscriber.get_tenant_objects().select_related().all()
+    serializer_class = CordSubscriberIdSerializer
+
+    method_kind = "list"
+    method_name = "cordsubscriber"
+
+class CordSubscriberDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = CordSubscriber.get_tenant_objects().select_related().all()
+    serializer_class = CordSubscriberIdSerializer
+
+    method_kind = "detail"
+    method_name = "cordsubscriber"
+
+# We fake a user object by pulling the user data struct out of the
+# subscriber object...
+
+def serialize_user(subscriber, user):
+    return {"id": "%d-%d" % (subscriber.id, user["id"]),
+            "name": user["name"],
+            "level": user.get("level",""),
+            "mac": user.get("mac", ""),
+            "subscriber": subscriber.id }
+
+class CordUserList(APIView):
+    method_kind = "list"
+    method_name = "corduser"
+
+    def get(self, request, format=None):
+        instances=[]
+        for subscriber in CordSubscriber.get_tenant_objects().all():
+            for user in subscriber.devices:
+                instances.append( serialize_user(subscriber, user) )
+
+        return Response(instances)
+
+    def post(self, request, format=None):
+        data = request.DATA
+        subscriber = CordSubscriber.get_tenant_objects().get(id=int(data["subscriber"]))
+        user = subscriber.create_user(name=data["name"],
+                                    level=data["level"],
+                                    mac=data["mac"])
+        subscriber.save()
+
+        return Response(serialize_user(subscriber,user))
+
+class CordUserDetail(APIView):
+    method_kind = "detail"
+    method_name = "corduser"
+
+    def get(self, request, format=None, pk=0):
+        parts = pk.split("-")
+        subscriber = CordSubscriber.get_tenant_objects().filter(id=parts[0])
+        for user in subscriber.devices:
+            return Response( [ serialize_user(subscriber, user) ] )
+        raise XOSNotFound("Failed to find user %s" % pk)
+
+    def delete(self, request, pk):
+        parts = pk.split("-")
+        subscriber = CordSubscriber.get_tenant_objects().get(id=int(parts[0]))
+        subscriber.delete_user(parts[1])
+        subscriber.save()
+        return Response("okay")
+
+    def put(self, request, pk):
+        kwargs={}
+        if "name" in request.DATA:
+             kwargs["name"] = request.DATA["name"]
+        if "level" in request.DATA:
+             kwargs["level"] = request.DATA["level"]
+        if "mac" in request.DATA:
+             kwargs["mac"] = request.DATA["mac"]
+
+        parts = pk.split("-")
+        subscriber = CordSubscriber.get_tenant_objects().get(id=int(parts[0]))
+        user = subscriber.update_user(parts[1], **kwargs)
+        subscriber.save()
+        return Response(serialize_user(subscriber,user))
+
+#------------------------------------------------------------------------------
+# The "new" API with many more REST endpoints.
+# This is for integration with with the subscriber GUI
+#------------------------------------------------------------------------------
+
+class CordSubscriberViewSet(XOSViewSet):
+    base_name = "subscriber"
+    method_name = "rs/subscriber"
+    method_kind = "viewset"
+    queryset = CordSubscriber.get_tenant_objects().select_related().all()
+    serializer_class = CordSubscriberIdSerializer
+
+    def get_vcpe(self):
+        subscriber = self.get_object()
+        if not subscriber.vcpe:
+            raise XOSMissingField("vCPE object is not present for subscriber")
+        return subscriber.vcpe
+
+    @classmethod
+    def get_urlpatterns(self):
+        patterns = super(CordSubscriberViewSet, self).get_urlpatterns()
+        patterns.append( self.detail_url("vcpe_synced/$", {"get": "get_vcpe_synced"}, "vcpe_synced") )
+        patterns.append( self.detail_url("url_filter/$", {"get": "get_url_filter"}, "url_filter") )
+        patterns.append( self.detail_url("url_filter/(?P<level>[a-zA-Z0-9\-_]+)/$", {"put": "set_url_filter"}, "url_filter") )
+        patterns.append( self.detail_url("services/$", {"get": "get_services"}, "services") )
+        patterns.append( self.detail_url("services/(?P<service>[a-zA-Z0-9\-_]+)/$", {"get": "get_service"}, "get_service") )
+        patterns.append( self.detail_url("services/(?P<service>[a-zA-Z0-9\-_]+)/true/$", {"put": "enable_service"}, "enable_service") )
+        patterns.append( self.detail_url("services/(?P<service>[a-zA-Z0-9\-_]+)/false/$", {"put": "disable_service"}, "disable_service") )
+
+        patterns.append( self.detail_url("users/$", {"get": "get_users", "post": "create_user"}, "users") )
+        patterns.append( self.detail_url("users/clearusers/$", {"get": "clear_users", "put": "clear_users", "post": "clear_users"}, "clearusers") )
+        patterns.append( self.detail_url("users/newuser/$", {"put": "create_user", "post": "create_user"}, "newuser") )
+        patterns.append( self.detail_url("users/(?P<uid>[0-9\-]+)/$", {"delete": "delete_user"}, "user") )
+        patterns.append( self.detail_url("users/(?P<uid>[0-9\-]+)/url_filter/$", {"get": "get_user_level"}, "user_level") )
+        patterns.append( self.detail_url("users/(?P<uid>[0-9\-]+)/url_filter/(?P<level>[a-zA-Z0-9\-_]+)/$", {"put": "set_user_level"}, "set_user_level") )
+
+        patterns.append( self.detail_url("bbsdump/$", {"get": "get_bbsdump"}, "bbsdump") )
+
+        patterns.append( url("^rs/initdemo/$", self.as_view({"put": "initdemo", "get": "initdemo"}), name="initdemo") )
+
+        patterns.append( url("^rs/subidlookup/(?P<ssid>[0-9\-]+)/$", self.as_view({"get": "ssiddetail"}), name="ssiddetail") )
+        patterns.append( url("^rs/subidlookup/$", self.as_view({"get": "ssidlist"}), name="ssidlist") )
+
+        #patterns.append( url("^rs/vbng_mapping/$", self.as_view({"get": "get_vbng_mapping"}), name="vbng_mapping") )
+
+        return patterns
+
+    def list(self, request):
+        object_list = self.filter_queryset(self.get_queryset())
+
+        serializer = self.get_serializer(object_list, many=True)
+
+        return Response({"subscribers": serializer.data})
+
+    def get_vcpe_synced(self, request, pk=None):
+        subscriber = self.get_object()
+        return Response({"vcpe_synced": subscriber.vcpe_synced})
+
+    def get_url_filter(self, request, pk=None):
+        subscriber = self.get_object()
+        return Response({"level": subscriber.url_filter_level})
+
+    def set_url_filter(self, request, pk=None, level=None):
+        subscriber = self.get_object()
+        subscriber.url_filter_level = level
+        subscriber.save()
+        return Response({"level": subscriber.url_filter_level})
+
+    def get_users(self, request, pk=None):
+        subscriber = self.get_object()
+        return Response(subscriber.devices)
+
+    def get_user_level(self, request, pk=None, uid=None):
+        subscriber = self.get_object()
+        user = subscriber.find_user(uid)
+        if user and user.get("level", None):
+            level = user["level"]
+        else:
+            level = self.get_object().url_filter_level
+
+        return Response( {"id": uid, "level": level} )
+
+    def set_user_level(self, request, pk=None, uid=None, level=None):
+        subscriber = self.get_object()
+        subscriber.update_user(uid, level=level)
+        subscriber.save()
+        return self.get_user_level(request, pk, uid)
+
+    def create_user(self, request, pk=None):
+        data = request.DATA
+        name = data.get("name",None)
+        mac = data.get("mac",None)
+        if (not name):
+             raise XOSMissingField("name must be specified when creating user")
+        if (not mac):
+             raise XOSMissingField("mac must be specified when creating user")
+
+        subscriber = self.get_object()
+        newuser = subscriber.create_user(name=name, mac=mac)
+        subscriber.save()
+
+        return Response(newuser)
+
+    def delete_user(self, request, pk=None, uid=None):
+        subscriber = self.get_object()
+        subscriber.delete_user(uid)
+        subscriber.save()
+
+        return Response( {"id": uid, "deleted": True} )
+
+    def clear_users(self, request, pk=None):
+        subscriber = self.get_object()
+        subscriber.devices = []
+        subscriber.save()
+
+        return Response( "Okay" )
+
+    def get_services(self, request, pk=None):
+        subscriber = self.get_object()
+        return Response(subscriber.services)
+
+    def get_service(self, request, pk=None, service=None):
+        service_attr = service+"_enable"
+        subscriber = self.get_object()
+        return Response({service: getattr(subscriber, service_attr)})
+
+    def enable_service(self, request, pk=None, service=None):
+        service_attr = service+"_enable"
+        subscriber = self.get_object()
+        setattr(subscriber, service_attr, True)
+        subscriber.save()
+        return Response({service: getattr(subscriber, service_attr)})
+
+    def disable_service(self, request, pk=None, service=None):
+        service_attr = service+"_enable"
+        subscriber = self.get_object()
+        setattr(subscriber, service_attr, False)
+        subscriber.save()
+        return Response({service: getattr(subscriber, service_attr)})
+
+    def get_bbsdump(self, request, pk=None):
+        subscriber = self.get_object()
+        if not subsciber.volt or not subscriber.volt.vcpe:
+            raise XOSMissingField("subscriber has no vCPE")
+        if not subscriber.volt.vcpe.bbs_account:
+            raise XOSMissingField("subscriber has no bbs_account")
+
+        result=subprocess.check_output(["python", "/opt/xos/observers/vcpe/broadbandshield.py", "dump", subscriber.volt.vcpe.bbs_account, "123"])
+        if request.GET.get("theformat",None)=="text":
+            from django.http import HttpResponse
+            return HttpResponse(result, content_type="text/plain")
+        else:
+            return Response( {"bbs_dump": result } )
+
+    def setup_demo_subscriber(self, subscriber):
+        # nuke the users and start over
+        subscriber.devices = []
+        subscriber.create_user(name="Mom's PC",      mac="010203040506", level="PG_13")
+        subscriber.create_user(name="Dad's PC",      mac="90E2Ba82F975", level="PG_13")
+        subscriber.create_user(name="Jack's Laptop", mac="685B359D91D5", level="PG_13")
+        subscriber.create_user(name="Jill's Laptop", mac="34363BC9B6A6", level="PG_13")
+        subscriber.save()
+
+    def initdemo(self, request):
+        object_list = CordSubscriber.get_tenant_objects().all()
+
+        # reset the parental controls in any existing demo vCPEs
+        for o in object_list:
+            if str(o.service_specific_id) in ["0", "1"]:
+                self.setup_demo_subscriber(o)
+
+        demo_subscribers = [o for o in object_list if o.is_demo_user]
+
+        if demo_subscribers:
+            return Response({"id": demo_subscribers[0].id})
+
+        subscriber = CordSubscriberRoot(service_specific_id=1234,
+                                        name="demo-subscriber",)
+        subscriber.is_demo_user = True
+        subscriber.save()
+
+        self.setup_demo_subscriber(subscriber)
+
+        return Response({"id": subscriber.id})
+
+    def ssidlist(self, request):
+        object_list = CordSubscriber.get_tenant_objects().all()
+
+        ssidmap = [ {"service_specific_id": x.service_specific_id, "subscriber_id": x.id} for x in object_list ]
+
+        return Response({"ssidmap": ssidmap})
+
+    def ssiddetail(self, pk=None, ssid=None):
+        object_list = CordSubscriber.get_tenant_objects().all()
+
+        ssidmap = [ {"service_specific_id": x.service_specific_id, "subscriber_id": x.id} for x in object_list if str(x.service_specific_id)==str(ssid) ]
+
+        if len(ssidmap)==0:
+            raise XOSNotFound("didn't find ssid %s" % str(ssid))
+
+        return Response( ssidmap[0] )
+
+    #def get_vbng_mapping(self, request):
+    #    object_list = VBNGTenant.get_tenant_objects().all()
+    #
+    #    mappings = []
+    #    for vbng in object_list:
+    #        if vbng.mapped_ip and vbng.routeable_subnet:
+    #            mappings.append( {"private_ip": vbng.mapped_ip, "routeable_subnet": vbng.routeable_subnet, "mac": vbng.mapped_mac, "hostname": vbng.mapped_hostname} )
+    #
+    #    return Response( {"vbng_mapping": mappings} )
+
+
diff --git a/xos/core/xoslib/methods/hpcview.py b/xos/core/xoslib/methods/hpcview.py
new file mode 100644
index 0000000..199bc09
--- /dev/null
+++ b/xos/core/xoslib/methods/hpcview.py
@@ -0,0 +1,219 @@
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+from rest_framework import serializers
+from rest_framework import generics
+from rest_framework.views import APIView
+from core.models import *
+from services.hpc.models import *
+from services.requestrouter.models import *
+from django.forms import widgets
+from django.core.exceptions import PermissionDenied
+from django.contrib.contenttypes.models import ContentType
+import json
+import socket
+import time
+
+# This REST API endpoint contains a bunch of misc information that the
+# tenant view needs to display
+
+def get_service_slices(service):
+    try:
+        return service.slices.all()
+    except:
+        return service.service.all()
+
+def lookup_tag(service, instance, name, default=None):
+    instance_type = ContentType.objects.get_for_model(instance)
+    t = Tag.objects.filter(service=service, name=name, content_type__pk=instance_type.id, object_id=instance.id)
+    if t:
+        return t[0].value
+    else:
+        return default
+
+def lookup_time(service, instance, name):
+    v = lookup_tag(service, instance, name)
+    if v:
+        return str(time.time() - float(v))
+    else:
+        return None
+
+def json_default(d, default):
+    if not d:
+        return default
+    return json.loads(d)
+
+def compute_config_run(d):
+    if not d:
+        return "null"
+
+    try:
+        d = json.loads(d)
+    except:
+        return "error decoding json '%s'" % str(d)
+
+    status = d.get("status", "null")
+    if status!="success":
+        return status
+
+    config_run = d.get("config.run")
+    if not config_run:
+        return "null"
+
+    try:
+        config_run = max(0, int(time.time()) - int(float(config_run)))
+    except:
+        pass
+
+    return config_run
+
+# from hpc_watcher.py
+def get_public_ip(service, instance):
+    network_name = None
+    if "hpc" in instance.slice.name:
+        network_name = getattr(service, "watcher_hpc_network", None)
+    elif "demux" in instance.slice.name:
+        network_name = getattr(service, "watcher_dnsdemux_network", None)
+    elif "redir" in instance.slice.name:
+        network_name = getattr(service, "watcher_dnsredir_network", None)
+
+    if network_name and network_name.lower()=="nat":
+        return None
+
+    if (network_name is None) or (network_name=="") or (network_name.lower()=="public"):
+        return instance.get_public_ip()
+
+    for ns in instance.ports.all():
+        if (ns.ip) and (ns.network.name==network_name):
+            return ns.ip
+
+    raise ValueError("Couldn't find network %s" % str(network_name))
+
+def getHpcDict(user, pk):
+    hpc = HpcService.objects.get(pk=pk)
+    slices = get_service_slices(hpc)
+
+    dnsdemux_slice = None
+    dnsredir_slice = None
+    hpc_slice = None
+    for slice in slices:
+        if "dnsdemux" in slice.name:
+            dnsdemux_service = hpc
+            dnsdemux_slice = slice
+        if "dnsredir" in slice.name:
+            dnsredir_service = hpc
+            dnsredir_slice = slice
+        if "hpc" in slice.name:
+            hpc_service = hpc
+            hpc_slice = slice
+
+    if not dnsdemux_slice:
+        rr = RequestRouterService.objects.all()
+        if rr:
+            rr=rr[0]
+            slices = get_service_slices(rr)
+            for slice in slices:
+                if "dnsdemux" in slice.name:
+                    dnsdemux_service = rr
+                    dnsdemux_slice = slice
+                if "dnsredir" in slice.name:
+                    dnsredir_service = rr
+                    dnsredir_slice = slice
+
+    if not dnsredir_slice:
+        print "no dnsredir slice"
+        return
+
+    if not dnsdemux_slice:
+        print "no dnsdemux slice"
+        return
+
+    #dnsdemux_has_public_network = False
+    #for network in dnsdemux_slice.networks.all():
+    #    if (network.template) and (network.template.visibility=="public") and (network.template.translation=="none"):
+    #        dnsdemux_has_public_network = True
+
+    nameservers = {}
+    for nshc in hpc.hpchealthcheck_set.filter(kind="nameserver"):
+        nameserver = nshc.resource_name
+        try:
+            nameservers[nameserver] = {"name": nameserver, "ip": socket.gethostbyname(nameserver), "hit": False}
+        except:
+            nameservers[nameserver] = {"name": nameserver, "ip": "exception", "hit": False}
+
+    dnsdemux=[]
+    for instance in dnsdemux_slice.instances.all():
+        ip=None
+        try:
+            ip = get_public_ip(dnsdemux_service, instance)
+        except Exception, e:
+            ip = "Exception: " + str(e)
+        if not ip:
+            try:
+                ip = socket.gethostbyname(instance.node.name)
+            except:
+                ip = "??? " + instance.node.name
+
+        instance_nameservers = []
+        for ns in nameservers.values():
+            if ns["ip"]==ip:
+                instance_nameservers.append(ns["name"])
+                ns["hit"]=True
+
+        # now find the dnsredir instance that is also on this node
+        watcherd_dnsredir = "no-redir-instance"
+        for dnsredir_instance in dnsredir_slice.instances.all():
+            if dnsredir_instance.node == instance.node:
+                watcherd_dnsredir = lookup_tag(dnsredir_service, dnsredir_instance, "watcher.watcher.msg")
+
+        watcherd_dnsdemux = lookup_tag(dnsdemux_service, instance, "watcher.watcher.msg")
+
+        dnsdemux.append( {"name": instance.node.name,
+                       "watcher.DNS.msg": lookup_tag(dnsdemux_service, instance, "watcher.DNS.msg"),
+                       "watcher.DNS.time": lookup_time(dnsdemux_service, instance, "watcher.DNS.time"),
+                       "ip": ip,
+                       "nameservers": instance_nameservers,
+                       "dnsdemux_config_age": compute_config_run(watcherd_dnsdemux),
+                       "dnsredir_config_age": compute_config_run(watcherd_dnsredir) })
+
+    hpc=[]
+    for instance in hpc_slice.instances.all():
+        watcherd_hpc = lookup_tag(hpc_service, instance, "watcher.watcher.msg")
+
+        hpc.append( {"name": instance.node.name,
+                     "watcher.HPC-hb.msg": lookup_tag(hpc_service, instance, "watcher.HPC-hb.msg"),
+                     "watcher.HPC-hb.time": lookup_time(hpc_service, instance, "watcher.HPC-hb.time"),
+                     "watcher.HPC-fetch.msg": lookup_tag(hpc_service, instance, "watcher.HPC-fetch.msg"),
+                     "watcher.HPC-fetch.time": lookup_time(hpc_service, instance, "watcher.HPC-fetch.time"),
+                     "watcher.HPC-fetch.urls": json_default(lookup_tag(hpc_service, instance, "watcher.HPC-fetch-urls.msg"), []),
+                     "config_age": compute_config_run(watcherd_hpc),
+
+        })
+
+    return { "id": pk,
+             "dnsdemux": dnsdemux,
+             "hpc": hpc,
+             "nameservers": nameservers,}
+
+
+class HpcList(APIView):
+    method_kind = "list"
+    method_name = "hpcview"
+
+    def get(self, request, format=None):
+        if (not request.user.is_authenticated()):
+            raise PermissionDenied("You must be authenticated in order to use this API")
+        results = []
+        for hpc in HpcService.objects.all():
+            results.append(getHpcDict(request.user, hpc.pk))
+        return Response( results )
+
+class HpcDetail(APIView):
+    method_kind = "detail"
+    method_name = "hpcview"
+
+    def get(self, request, format=None, pk=0):
+        if (not request.user.is_authenticated()):
+            raise PermissionDenied("You must be authenticated in order to use this API")
+        return Response( [getHpcDict(request.user, pk)] )
+
diff --git a/xos/core/xoslib/methods/loginview.py b/xos/core/xoslib/methods/loginview.py
new file mode 100644
index 0000000..2dc79c6
--- /dev/null
+++ b/xos/core/xoslib/methods/loginview.py
@@ -0,0 +1,101 @@
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+from rest_framework import serializers
+from rest_framework import generics
+from rest_framework.views import APIView
+from core.models import *
+from services.hpc.models import *
+from services.requestrouter.models import *
+from django.forms import widgets
+from django.core.exceptions import PermissionDenied
+from django.contrib.contenttypes.models import ContentType
+import json
+import socket
+import time
+import django.middleware.csrf
+from xos.exceptions import *
+from django.contrib.sessions.backends.db import SessionStore
+from django.contrib.sessions.models import Session
+from django.contrib.auth import authenticate
+
+def date_handler(obj):
+    return obj.isoformat() if hasattr(obj, 'isoformat') else obj
+
+def serialize_user(model):
+    serialized = model_to_dict(model)
+    del serialized['timezone']
+    del serialized['password']
+    return json.dumps(serialized, default=date_handler)
+
+class LoginView(APIView):
+    method_kind = "list"
+    method_name = "login"
+
+    def do_login(self, request, username, password):
+        if not username:
+            raise XOSMissingField("No username specified")
+
+        if not password:
+            raise XOSMissingField("No password specified")
+
+        u=authenticate(username=username, password=password)
+        if not u:
+            raise PermissionDenied("Failed to authenticate user %s" % username)
+
+        auth = {"username": username, "password": password}
+        request.session["auth"] = auth
+        request.session['_auth_user_id'] = u.pk
+        request.session['_auth_user_backend'] = u.backend
+        request.session.save()
+
+        return Response({
+            "xoscsrftoken": django.middleware.csrf.get_token(request),
+            "xossessionid": request.session.session_key,
+            "user": serialize_user(u)
+        })
+
+    def get(self, request, format=None):
+        username = request.GET.get("username", None)
+        password = request.GET.get("password", None)
+
+        return self.do_login(request, username, password)
+
+    def post(self, request, format=None):
+        username = request.data.get("username", None)
+        password = request.data.get("password", None)
+
+        return self.do_login(request, username, password)
+
+class LogoutView(APIView):
+    method_kind = "list"
+    method_name = "logout"
+
+    def do_logout(self, request, sessionid):
+        if not sessionid:
+            raise XOSMissingField("No xossessionid specified")
+
+        # Make sure the session exists. This prevents us from accidentally
+        # creating empty sessions with SessionStore()
+        session = Session.objects.filter(session_key=sessionid)
+        if not session:
+            # session doesn't exist
+            raise PermissionDenied("Session does not exist")
+
+        session = SessionStore(session_key=sessionid)
+        if "auth" in session:
+            del session["auth"]
+            session.save()
+        if "_auth_user_id" in session:
+            del session["_auth_user_id"]
+            session.save()
+
+        return Response("Logged Out")
+
+    def get(self, request, format=None):
+        sessionid = request.GET.get("xossessionid", None)
+        return self.do_logout(request, sessionid)
+
+    def post(self, request, format=None):
+        sessionid = request.data.get("xossessionid", None)
+        return self.do_logout(request, sessionid)
\ No newline at end of file
diff --git a/xos/core/xoslib/methods/monitoringchannel._unused b/xos/core/xoslib/methods/monitoringchannel._unused
new file mode 100644
index 0000000..66ca2ae
--- /dev/null
+++ b/xos/core/xoslib/methods/monitoringchannel._unused
@@ -0,0 +1,89 @@
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+from rest_framework import serializers
+from rest_framework import generics
+from rest_framework import status
+from core.models import *
+from django.forms import widgets
+from services.ceilometer.models import MonitoringChannel, CeilometerService
+from plus import PlusSerializerMixin
+from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
+
+if hasattr(serializers, "ReadOnlyField"):
+    # rest_framework 3.x
+    ReadOnlyField = serializers.ReadOnlyField
+else:
+    # rest_framework 2.x
+    ReadOnlyField = serializers.Field
+
+def get_default_ceilometer_service():
+    ceilometer_services = CeilometerService.get_service_objects().all()
+    if ceilometer_services:
+        return ceilometer_services[0].id
+    return None
+
+class MonitoringChannelSerializer(serializers.ModelSerializer, PlusSerializerMixin):
+        id = ReadOnlyField()
+        service_specific_attribute = ReadOnlyField()
+        ceilometer_url = ReadOnlyField()
+        tenant_list_str = ReadOnlyField()
+        creator = ReadOnlyField()
+        instance = ReadOnlyField()
+        provider_service = serializers.PrimaryKeyRelatedField(queryset=CeilometerService.get_service_objects().all(), default=get_default_ceilometer_service)
+
+        humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+
+        computeNodeName = serializers.SerializerMethodField("getComputeNodeName")
+
+        class Meta:
+            model = MonitoringChannel
+            fields = ('humanReadableName', 'id', 'provider_service', 'service_specific_attribute', 'ceilometer_url', 'tenant_list_str', 'creator', 'instance', 'computeNodeName' )
+
+        def getHumanReadableName(self, obj):
+            return obj.__unicode__()
+
+        def getComputeNodeName(self, obj):
+            instance = obj.instance
+            if not instance:
+                return None
+            return instance.node.name
+
+class MonitoringChannelList(XOSListCreateAPIView):
+    serializer_class = MonitoringChannelSerializer
+
+    method_kind = "list"
+    method_name = "monitoringchannel"
+
+    def get_queryset(self):
+        queryset = MonitoringChannel.get_tenant_objects().select_related().all()
+
+        current_user = self.request.user.username
+        if current_user is not None:
+            ids = [x.id for x in queryset if x.creator.username==current_user]
+            queryset = queryset.filter(id__in=ids)
+
+        return queryset
+
+    def post(self, request, format=None):
+        current_user = request.user.username
+        existing_obj = None
+        for obj in MonitoringChannel.get_tenant_objects().all():
+            if (obj.creator.username == current_user):
+               existing_obj = obj
+               break
+
+        if existing_obj:
+            serializer = MonitoringChannelSerializer(existing_obj)
+            headers = self.get_success_headers(serializer.data)
+            return Response( serializer.data, status=status.HTTP_200_OK )
+
+        return super(MonitoringChannelList, self).post(request, format)
+
+class MonitoringChannelDetail(XOSRetrieveUpdateDestroyAPIView):
+    serializer_class = MonitoringChannelSerializer
+    queryset = MonitoringChannel.get_tenant_objects().select_related().all()
+
+    method_kind = "detail"
+    method_name = "monitoringchannel"
+
diff --git a/xos/core/xoslib/methods/plus.py b/xos/core/xoslib/methods/plus.py
new file mode 100644
index 0000000..294fba8
--- /dev/null
+++ b/xos/core/xoslib/methods/plus.py
@@ -0,0 +1,51 @@
+from rest_framework import generics
+from rest_framework import serializers
+from rest_framework.response import Response
+from rest_framework import status
+from xos.apibase import XOSRetrieveUpdateDestroyAPIView, XOSListCreateAPIView
+from rest_framework import viewsets
+from django.conf.urls import patterns, url
+
+""" PlusSerializerMixin
+
+    Implements Serializer fields that are common to all OpenCloud objects. For
+    example, stuff related to backend fields.
+"""
+
+class PlusSerializerMixin():
+    backendIcon = serializers.SerializerMethodField("getBackendIcon")
+    backendHtml = serializers.SerializerMethodField("getBackendHtml")
+
+    # This will cause a descendant class to pull in the methods defined
+    # above. See rest_framework/serializers.py: _get_declared_fields().
+    base_fields = {"backendIcon": backendIcon, "backendHtml": backendHtml}
+    # Rest_framework 3.0 uses _declared_fields instead of base_fields
+    _declared_fields = {"backendIcon": backendIcon, "backendHtml": backendHtml}
+
+    def getBackendIcon(self, obj):
+        return obj.getBackendIcon()
+
+    def getBackendHtml(self, obj):
+        return obj.getBackendHtml()
+
+class XOSViewSet(viewsets.ModelViewSet):
+    @classmethod
+    def detail_url(self, pattern, viewdict, name):
+        return url(r'^' + self.method_name + r'/(?P<pk>[a-zA-Z0-9\-]+)/' + pattern,
+                   self.as_view(viewdict),
+                   name=self.base_name+"_"+name)
+
+    @classmethod
+    def list_url(self, pattern, viewdict, name):
+        return url(r'^' + self.method_name + r'/' + pattern,
+                   self.as_view(viewdict),
+                   name=self.base_name+"_"+name)
+
+    @classmethod
+    def get_urlpatterns(self):
+        patterns = []
+
+        patterns.append(url(r'^' + self.method_name + '/$', self.as_view({'get': 'list'}), name=self.base_name+'_list'))
+        patterns.append(url(r'^' + self.method_name + '/(?P<pk>[a-zA-Z0-9\-]+)/$', self.as_view({'get': 'retrieve', 'put': 'update', 'post': 'update', 'delete': 'destroy', 'patch': 'partial_update'}), name=self.base_name+'_detail'))
+
+        return patterns
diff --git a/xos/core/xoslib/methods/portforwarding.py b/xos/core/xoslib/methods/portforwarding.py
new file mode 100644
index 0000000..c98b1bd
--- /dev/null
+++ b/xos/core/xoslib/methods/portforwarding.py
@@ -0,0 +1,59 @@
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+from rest_framework import serializers
+from rest_framework import generics
+from rest_framework.views import APIView
+from core.models import *
+from django.forms import widgets
+from django.core.exceptions import PermissionDenied
+from xos.exceptions import XOSNotFound
+
+class PortForwardingList(APIView):
+    method_kind = "list"
+    method_name = "portforwarding"
+
+    def get(self, request, format=None):
+        ports=[]
+        for port in self.get_queryset().all():
+            if port.network and port.network.ports and port.instance and port.instance.node and port.ip:
+                ports.append( {"id": port.id,
+                               "ip": port.ip,
+                               "ports": port.network.ports,
+                               "hostname": port.instance.node.name} )
+
+        return Response(ports)
+
+    def get_queryset(self):
+        queryset = queryset=Port.objects.all()
+
+        node_name = self.request.query_params.get('node_name', None)
+        if node_name is not None:
+            queryset = queryset.filter(instance__node__name = node_name)
+
+        return queryset
+
+class PortForwardingDetail(APIView):
+    method_kind = "detail"
+    method_name = "portforwarding"
+
+    def get(self, request, format=None, pk=0):
+        ports = self.get_queryset().filter(id=pk)
+        if not ports:
+            raise XOSNotFound("didn't find port for port_id %s" % pk)
+
+        port = ports[0]
+        return Response( {"id": port.id,
+                          "ip": port.ip,
+                          "ports": port.network.ports,
+                          "hostname": port.instance.node.name} )
+
+    def get_queryset(self):
+        queryset = queryset=Port.objects.all()
+
+        node_name = self.request.query_params.get('node_name', None)
+        if node_name is not None:
+            queryset = queryset.filter(instance__node__name = node_name)
+
+        return queryset
+
diff --git a/xos/core/xoslib/methods/sliceplus.py b/xos/core/xoslib/methods/sliceplus.py
new file mode 100644
index 0000000..6908d3c
--- /dev/null
+++ b/xos/core/xoslib/methods/sliceplus.py
@@ -0,0 +1,118 @@
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+from rest_framework import serializers
+from rest_framework import generics
+from core.models import *
+from django.forms import widgets
+from core.xoslib.objects.sliceplus import SlicePlus
+from plus import PlusSerializerMixin
+from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
+import json
+
+if hasattr(serializers, "ReadOnlyField"):
+    # rest_framework 3.x
+    IdField = serializers.ReadOnlyField
+    WritableField = serializers.Field
+    DictionaryField = serializers.DictField
+    ListField = serializers.ListField
+else:
+    # rest_framework 2.x
+    IdField = serializers.Field
+    WritableField = serializers.WritableField
+
+    class DictionaryField(WritableField):   # note: maybe just Field in rest_framework 3.x instead of WritableField
+        def to_representation(self, obj):
+            return json.dumps(obj)
+
+        def to_internal_value(self, data):
+            return json.loads(data)
+
+    class ListField(WritableField):   # note: maybe just Field in rest_framework 3.x instead of WritableField
+        def to_representation(self, obj):
+            return json.dumps(obj)
+
+        def to_internal_value(self, data):
+            return json.loads(data)
+
+class SlicePlusIdSerializer(serializers.ModelSerializer, PlusSerializerMixin):
+        id = IdField()
+
+        sliceInfo = serializers.SerializerMethodField("getSliceInfo")
+        humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+        network_ports = serializers.CharField(required=False)
+        site_allocation = DictionaryField(required=False)
+        site_ready = DictionaryField(required=False)
+        users = ListField(required=False)
+        user_names = ListField(required=False) # readonly = True ?
+        current_user_can_see = serializers.SerializerMethodField("getCurrentUserCanSee")
+
+        def getCurrentUserCanSee(self, slice):
+            # user can 'see' the slice if he is the creator or he has a role
+            current_user = self.context['request'].user
+            if (slice.creator and slice.creator==current_user):
+                return True;
+            return (len(slice.getSliceInfo(current_user)["roles"]) > 0)
+
+        def getSliceInfo(self, slice):
+            return slice.getSliceInfo(user=self.context['request'].user)
+
+        def getHumanReadableName(self, obj):
+            return str(obj)
+
+        networks = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
+
+        class Meta:
+            model = SlicePlus
+            fields = ('humanReadableName', 'id','created','updated','enacted','name','enabled','omf_friendly','description','slice_url','site','max_instances','service','network','mount_data_sets',
+                      'default_image', 'default_flavor',
+                      'serviceClass','creator','networks','sliceInfo','network_ports','backendIcon','backendHtml','site_allocation','site_ready','users',"user_names","current_user_can_see")
+
+class SlicePlusList(XOSListCreateAPIView):
+    queryset = SlicePlus.objects.select_related().all()
+    serializer_class = SlicePlusIdSerializer
+
+    method_kind = "list"
+    method_name = "slicesplus"
+
+    def get_queryset(self):
+        current_user_can_see = self.request.query_params.get('current_user_can_see', False)
+        site_filter = self.request.query_params.get('site', False)
+
+        if (not self.request.user.is_authenticated()):
+            raise XOSPermissionDenied("You must be authenticated in order to use this API")
+
+        slices = SlicePlus.select_by_user(self.request.user)
+
+        if (site_filter and not current_user_can_see):
+            slices = SlicePlus.objects.filter(site=site_filter)
+
+        # If current_user_can_see is set, then filter the queryset to return
+        # only those slices that the user is either creator or has privilege
+        # on.
+        if (current_user_can_see):
+            slice_ids = []
+            for slice in slices:
+                if (self.request.user == slice.creator) or (len(slice.getSliceInfo(self.request.user)["roles"]) > 0):
+                    slice_ids.append(slice.id)
+            if (site_filter):
+                slices = SlicePlus.objects.filter(id__in=slice_ids, site=site_filter)
+            else:
+                slices = SlicePlus.objects.filter(id__in=slice_ids)
+
+        return slices
+
+
+class SlicePlusDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = SlicePlus.objects.select_related().all()
+    serializer_class = SlicePlusIdSerializer
+
+    method_kind = "detail"
+    method_name = "slicesplus"
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSPermissionDenied("You must be authenticated in order to use this API")
+        return SlicePlus.select_by_user(self.request.user)
+
+
diff --git a/xos/core/xoslib/methods/sshkeys.py b/xos/core/xoslib/methods/sshkeys.py
new file mode 100644
index 0000000..705a968
--- /dev/null
+++ b/xos/core/xoslib/methods/sshkeys.py
@@ -0,0 +1,55 @@
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+from rest_framework import serializers
+from rest_framework import generics
+from rest_framework.views import APIView
+from core.models import *
+from django.forms import widgets
+from django.core.exceptions import PermissionDenied
+from xos.exceptions import XOSNotFound
+
+class SSHKeyList(APIView):
+    method_kind = "list"
+    method_name = "sshkeys"
+
+    def get(self, request, format=None):
+        instances=[]
+        for instance in self.get_queryset().all():
+            if instance.instance_id:
+                instances.append( {"id": instance.instance_id,
+                                   "public_keys": instance.get_public_keys(),
+                                   "node_name": instance.node.name } )
+
+        return Response(instances)
+
+    def get_queryset(self):
+        queryset = queryset=Instance.objects.all()
+
+        node_name = self.request.query_params.get('node_name', None)
+        if node_name is not None:
+            queryset = queryset.filter(node__name = node_name)
+
+        return queryset
+
+class SSHKeyDetail(APIView):
+    method_kind = "detail"
+    method_name = "sshkeys"
+
+    def get(self, request, format=None, pk=0):
+        instances = self.get_queryset().filter(instance_id=pk)
+        if not instances:
+            raise XOSNotFound("didn't find instance for instance %s" % pk)
+        return Response( [ {"id": instances[0].instance_id,
+                            "public_keys": instances[0].get_public_keys(),
+                            "node_name": instances[0].node.name } ])
+
+    def get_queryset(self):
+        queryset = queryset=Instance.objects.all()
+
+        node_name = self.request.query_params.get('node_name', None)
+        if node_name is not None:
+            queryset = queryset.filter(node__name = node_name)
+
+        return queryset
+
diff --git a/xos/core/xoslib/methods/tenantview.py b/xos/core/xoslib/methods/tenantview.py
new file mode 100644
index 0000000..e505b1c
--- /dev/null
+++ b/xos/core/xoslib/methods/tenantview.py
@@ -0,0 +1,118 @@
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+from rest_framework import serializers
+from rest_framework import generics
+from rest_framework.views import APIView
+from core.models import *
+from django.forms import widgets
+from services.syndicate_storage.models import Volume
+from django.core.exceptions import PermissionDenied
+
+# This REST API endpoint contains a bunch of misc information that the
+# tenant view needs to display
+
+def getTenantViewDict(user):
+    # compute blessed_deployments by looking for the tenant view, and seeing what
+    # deployments are attached to it.
+    blessed_deployments=[]
+    for dash in DashboardView.objects.all():
+        if (dash.url=="template:xosTenant"):
+            for deployment in dash.deployments.all():
+                if deployment not in blessed_deployments:
+                    blessed_deployments.append(deployment)
+
+    blessed_deployment_ids = [d.id for d in blessed_deployments]
+
+    blessed_sites = []
+    for site in Site.objects.all():
+        good=False
+        for deployment in site.deployments.all():
+            if deployment.id in blessed_deployment_ids:
+                # only bless sites that have at least one node in the deployment
+                sitedeployments = SiteDeployment.objects.filter(site=site, deployment=deployment)
+                for sd in sitedeployments.all():
+                    if sd.nodes.count()>0:
+                        good=True
+        if good:
+            blessed_sites.append(site)
+
+    blessed_images=[]
+    for image in Image.objects.all():
+        good = False
+        for deployment in image.deployments.all():
+            if deployment.id in blessed_deployment_ids:
+                 good=True
+        if good:
+            blessed_images.append(image)
+
+    blessed_flavors=[]
+    for flavor in Flavor.objects.all():
+        good = False
+        for deployment in flavor.deployments.all():
+            if deployment.id in blessed_deployment_ids:
+                 good=True
+        if good:
+            blessed_flavors.append(flavor)
+
+    volumes=[]
+    for volume in Volume.objects.all():
+        if not volume.private:
+            volumes.append(volume)
+
+    site_users=[]
+    user_site_roles=[]
+    user_site_id=None
+    user_site_login_base=None
+    if not user.site:
+        pass # this is probably an error
+    else:
+        user_site_id = user.site.id
+        user_site_login_base = user.site.login_base
+        for auser in user.site.users.all():
+            site_users.append(auser)
+
+        for priv in user.site.siteprivileges.filter(user=user):
+            user_site_roles.append(priv.role.role)
+
+    blessed_service_classes = [ServiceClass.objects.get(name="Best Effort")]
+
+    return {"id": 0,
+            "blessed_deployment_names": [deployment.name for deployment in blessed_deployments],
+            "blessed_deployments": [deployment.id for deployment in blessed_deployments],
+            "blessed_site_names": [site.name for site in blessed_sites],
+            "blessed_sites": [site.id for site in blessed_sites],
+            "blessed_image_names": [image.name for image in blessed_images],
+            "blessed_images": [image.id for image in blessed_images],
+            "blessed_flavor_names": [flavor.name for flavor in blessed_flavors],
+            "blessed_flavors": [flavor.id for flavor in blessed_flavors],
+            "blessed_service_class_names": [serviceclass.name for serviceclass in blessed_service_classes],
+            "blessed_service_classes": [serviceclass.id for serviceclass in blessed_service_classes],
+            "public_volume_names": [volume.name for volume in volumes],
+            "public_volumes": [volume.id for volume in volumes],
+            "current_user_site_id": user_site_id,
+            "current_user_login_base": user_site_login_base,
+            "current_user_site_users": [auser.id for auser in site_users],
+            "current_user_site_user_names": [auser.email for auser in site_users],
+            "current_user_can_create_slice": user.is_admin or ("pi" in user_site_roles) or ("admin" in user_site_roles),
+            "current_user_id": user.id,
+            }
+
+class TenantList(APIView):
+    method_kind = "list"
+    method_name = "tenantview"
+
+    def get(self, request, format=None):
+        if (not request.user.is_authenticated()):
+            raise PermissionDenied("You must be authenticated in order to use this API")
+        return Response( getTenantViewDict(request.user) )
+
+class TenantDetail(APIView):
+    method_kind = "detail"
+    method_name = "tenantview"
+
+    def get(self, request, format=None, pk=0):
+        if (not request.user.is_authenticated()):
+            raise PermissionDenied("You must be authenticated in order to use this API")
+        return Response( [getTenantViewDict(request.user)] )
+
diff --git a/xos/core/xoslib/methods/volttenant._unused b/xos/core/xoslib/methods/volttenant._unused
new file mode 100644
index 0000000..03a2a97
--- /dev/null
+++ b/xos/core/xoslib/methods/volttenant._unused
@@ -0,0 +1,104 @@
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+from rest_framework import serializers
+from rest_framework import generics
+from rest_framework import status
+from core.models import *
+from django.forms import widgets
+from services.volt.models import VOLTTenant, VOLTService, CordSubscriberRoot
+from plus import PlusSerializerMixin
+from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
+
+if hasattr(serializers, "ReadOnlyField"):
+    # rest_framework 3.x
+    ReadOnlyField = serializers.ReadOnlyField
+else:
+    # rest_framework 2.x
+    ReadOnlyField = serializers.Field
+
+def get_default_volt_service():
+    volt_services = VOLTService.get_service_objects().all()
+    if volt_services:
+        return volt_services[0].id
+    return None
+
+class VOLTTenantIdSerializer(serializers.ModelSerializer, PlusSerializerMixin):
+        id = ReadOnlyField()
+        service_specific_id = serializers.CharField()
+        s_tag = serializers.CharField()
+        c_tag = serializers.CharField()
+        provider_service = serializers.PrimaryKeyRelatedField(queryset=VOLTService.get_service_objects().all(), default=get_default_volt_service)
+        subscriber_root = serializers.PrimaryKeyRelatedField(queryset=CordSubscriberRoot.get_tenant_objects().all(), required=False)
+
+        humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+
+        computeNodeName = serializers.SerializerMethodField("getComputeNodeName")
+
+        class Meta:
+            model = VOLTTenant
+            fields = ('humanReadableName', 'id', 'provider_service', 'service_specific_id', 's_tag', 'c_tag', 'computeNodeName', 'subscriber_root' )
+
+        def getHumanReadableName(self, obj):
+            return obj.__unicode__()
+
+        def getComputeNodeName(self, obj):
+            vcpe = obj.vcpe
+            if not vcpe:
+                return None
+            instance = vcpe.instance
+            if not instance:
+                return None
+            return instance.node.name
+
+class VOLTTenantList(XOSListCreateAPIView):
+    serializer_class = VOLTTenantIdSerializer
+
+    method_kind = "list"
+    method_name = "volttenant"
+
+    def get_queryset(self):
+        queryset = VOLTTenant.get_tenant_objects().select_related().all()
+
+        service_specific_id = self.request.query_params.get('service_specific_id', None)
+        if service_specific_id is not None:
+            queryset = queryset.filter(service_specific_id=service_specific_id)
+
+        c_tag = self.request.query_params.get('c_tag', None)
+        if c_tag is not None:
+            ids = [x.id for x in queryset if x.get_attribute("c_tag", None)==c_tag]
+            queryset = queryset.filter(id__in=ids)
+
+        s_tag = self.request.query_params.get('s_tag', None)
+        if s_tag is not None:
+            ids = [x.id for x in queryset if x.get_attribute("s_tag", None)==s_tag]
+            queryset = queryset.filter(id__in=ids)
+
+        return queryset
+
+    def post(self, request, format=None):
+        data = request.DATA
+
+        existing_obj = None
+        for obj in VOLTTenant.get_tenant_objects().all():
+            if (obj.c_tag == data.get("c_tag", None)) and (obj.s_tag == data.get("s_tag", None)) and  (obj.service_specific_id == data.get("service_specific_id",None)):
+               existing_obj = obj
+
+        if existing_obj:
+            serializer = VOLTTenantIdSerializer(existing_obj)
+            headers = self.get_success_headers(serializer.data)
+            return Response( serializer.data, status=status.HTTP_200_OK )
+
+        return super(VOLTTenantList, self).post(request, format)
+
+class VOLTTenantDetail(XOSRetrieveUpdateDestroyAPIView):
+    serializer_class = VOLTTenantIdSerializer
+    queryset = VOLTTenant.get_tenant_objects().select_related().all()
+
+    method_kind = "detail"
+    method_name = "volttenant"
+
+
+
+
+
diff --git a/xos/core/xoslib/methods/vtn._unused b/xos/core/xoslib/methods/vtn._unused
new file mode 100644
index 0000000..c9dbf3a
--- /dev/null
+++ b/xos/core/xoslib/methods/vtn._unused
@@ -0,0 +1,65 @@
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+from rest_framework import serializers
+from rest_framework import generics
+from rest_framework import viewsets
+from rest_framework.decorators import detail_route, list_route
+from rest_framework.views import APIView
+from core.models import *
+from django.forms import widgets
+from django.conf.urls import patterns, url
+from plus import PlusSerializerMixin, XOSViewSet
+from django.shortcuts import get_object_or_404
+from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
+from xos.exceptions import *
+import json
+import subprocess
+
+class VTNViewSet(XOSViewSet):
+    base_name = "vtn"
+    method_name = "rs/vtn"
+    method_kind = "viewset"
+
+    # these are just because ViewSet needs some queryset and model, even if we don't use the
+    # default endpoints
+    queryset = Service.objects.none() # CordSubscriber.get_tenant_objects().select_related().all()
+    model = Service
+
+    @classmethod
+    def get_urlpatterns(self):
+        patterns = []
+        patterns.append( self.list_url("services/$", {"get": "get_services"}, "services") )
+        patterns.append( self.list_url("services_names/$", {"get": "get_services_names"}, "services") )
+        patterns.append( self.list_url("services/(?P<service>[a-zA-Z0-9\-_]+)/$", {"get": "get_service"}, "get_service") )
+
+        return patterns
+
+    def get_services_names(self, request, pk=None):
+        result = {}
+        for service in Service.objects.all():
+           for id in service.get_vtn_src_names():
+               dependencies = service.get_vtn_dependencies_names()
+               if dependencies:
+                   result[id] = dependencies
+        return Response(result)
+
+    def get_services(self, request, pk=None):
+        result = {}
+        for service in Service.objects.all():
+           for id in service.get_vtn_src_ids():
+               dependencies = service.get_vtn_dependencies_ids()
+               if dependencies:
+                   result[id] = dependencies
+        return Response(result)
+
+    def get_service(self, request, pk=None, service=None):
+        for xos_service in Service.objects.all():
+            if service in xos_service.get_vtn_src_ids():
+                return Response(xos_service.get_vtn_dependencies_ids())
+        return Response([])
+        # raise DoesNotExist()
+
+    def list(self, request):
+        raise Exception("Not Implemented")
+
diff --git a/xos/core/xoslib/objects/__init__.py b/xos/core/xoslib/objects/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/xos/core/xoslib/objects/__init__.py
@@ -0,0 +1 @@
+
diff --git a/xos/core/xoslib/objects/cordsubscriber.py b/xos/core/xoslib/objects/cordsubscriber.py
new file mode 100644
index 0000000..d97bd5a
--- /dev/null
+++ b/xos/core/xoslib/objects/cordsubscriber.py
@@ -0,0 +1,99 @@
+from core.models import Slice, SlicePrivilege, SliceRole, Instance, Site, Node, User
+from services.volt.models import VOLTTenant, CordSubscriberRoot
+from plus import PlusObjectMixin
+from operator import itemgetter, attrgetter
+from rest_framework.exceptions import APIException
+
+class CordSubscriber(CordSubscriberRoot):
+    class Meta:
+        proxy = True
+
+    def __init__(self, *args, **kwargs):
+        super(CordSubscriber, self).__init__(*args, **kwargs)
+
+    def __unicode__(self):
+        return u"cordSubscriber-%s" % str(self.id)
+
+    passthroughs = ( # the following are now fields of CordSubscriberRoot
+                     # ("firewall_enable", "vcpe.firewall_enable"),
+                     # ("firewall_rules", "vcpe.firewall_rules"),
+                     # ("url_filter_enable", "vcpe.url_filter_enable"),
+                     # ("url_filter_rules", "vcpe.url_filter_rules"),
+                     # ("url_filter_level", "vcpe.url_filter_level"),
+                     # ("users", "vcpe.users"),
+                     # ("services", "vcpe.services"),
+                     # ("cdn_enable", "vcpe.cdn_enable"),
+                     # uplink_speed, downlink_speed, status, enable_uverse
+
+                     ("c_tag", "volt.c_tag"),
+                     ("s_tag", "volt.s_tag"),
+
+                     ("bbs_account", "volt.vcpe.bbs_account"),
+                     ("ssh_command", "volt.vcpe.ssh_command"),
+                     ("image", "volt.vcpe.image.id"),
+                     ("image_name", "volt.vcpe.image.name"),
+                     ("instance", "volt.vcpe.instance.id"),
+                     ("instance_name", "volt.vcpe.instance.name"),
+                     ("routeable_subnet", "volt.vcpe.vbng.routeable_subnet"),
+                     ("vcpe_id", "volt.vcpe.id"),
+                     ("vbng_id", "volt.vcpe.vbng.id"),
+                     ("nat_ip", "volt.vcpe.nat_ip"),
+                     ("lan_ip", "volt.vcpe.lan_ip"),
+                     ("private_ip", "volt.vcpe.private_ip"),
+                     ("wan_ip", "volt.vcpe.wan_ip"),
+                     ("wan_mac", "volt.vcpe.wan_mac"),
+                     ("vcpe_synced", "volt.vcpe.is_synced"),
+                     ("wan_container_ip", "volt.vcpe.wan_container_ip"),
+                     )
+
+    def __getattr__(self, key):
+        #print "XXX getattr", self, key
+        for (member_name, passthrough_name) in self.passthroughs:
+            if key==member_name:
+                parts = passthrough_name.split(".")
+                obj = self
+                for part in parts[:-1]:
+                    obj = getattr(obj, part)
+                    if not obj:
+                        return None
+                return getattr(obj, parts[-1])
+
+        raise AttributeError("getattr: %r object has no attribute %r" %
+                         (self.__class__, key))
+
+    def __setattr__(self, key, value):
+        for (member_name, passthrough_name) in self.passthroughs:
+            if key==member_name:
+                parts = passthrough_name.split(".")
+                obj = self
+                for part in parts[:-1]:
+                     obj = getattr(obj, part)
+                     if not obj:
+                         return
+                setattr(obj, parts[-1], value)
+
+        super(CordSubscriber, self).__setattr__(key, value)
+
+    def save(self, *args, **kwargs):
+        super(CordSubscriber, self).save(*args, **kwargs)
+
+        # in case the vcpe or vbng fields were altered
+        #   TODO: dirty detection?
+        if (self.volt):
+            print "save volt"
+            self.volt.save()
+            if (self.volt.vcpe):
+                print "save vcpe"
+                self.volt.vcpe.save()
+                if (self.volt.vcpe.vbng):
+                    print "save vbng", self.volt.vcpe.vbng
+                    print "attr", self.volt.vcpe.vbng.service_specific_attribute
+                    self.volt.vcpe.vbng.save()
+
+
+
+
+
+
+
+
diff --git a/xos/core/xoslib/objects/plus.py b/xos/core/xoslib/objects/plus.py
new file mode 100644
index 0000000..da59ac7
--- /dev/null
+++ b/xos/core/xoslib/objects/plus.py
@@ -0,0 +1,28 @@
+""" PlusObjectMixin
+
+    Implements fields that are common to all OpenCloud objects. For example,
+    stuff related to backend icons.
+"""
+
+ICON_URLS = {"success": "/static/admin/img/icon_success.gif",
+            "clock": "/static/admin/img/icon_clock.gif",
+            "error": "/static/admin/img/icon_error.gif"}
+
+
+
+class PlusObjectMixin:
+    def getBackendIcon(self):
+        (icon, tooltip) = self.get_backend_icon()
+        icon_url = ICON_URLS.get(icon, "unknown")
+        return icon_url
+
+    def getBackendHtml(self):
+        (icon, tooltip) = self.get_backend_icon()
+        icon_url = ICON_URLS.get(icon, "unknown")
+
+        if tooltip:
+            return '<span title="%s"><img src="%s"></span>' % (tooltip, icon_url)
+        else:
+            return '<img src="%s">' % icon_url
+
+
diff --git a/xos/core/xoslib/objects/sliceplus.py b/xos/core/xoslib/objects/sliceplus.py
new file mode 100644
index 0000000..9d2868f
--- /dev/null
+++ b/xos/core/xoslib/objects/sliceplus.py
@@ -0,0 +1,292 @@
+from core.models import Slice, SlicePrivilege, SliceRole, Instance, Site, Node, User
+from plus import PlusObjectMixin
+from operator import itemgetter, attrgetter
+from rest_framework.exceptions import APIException
+
+class SlicePlus(Slice, PlusObjectMixin):
+    class Meta:
+        proxy = True
+
+    def __init__(self, *args, **kwargs):
+        super(SlicePlus, self).__init__(*args, **kwargs)
+        self._update_users = None
+        self._sliceInfo = None
+        self.getSliceInfo()
+        self._site_allocation = self._sliceInfo["sitesUsed"]
+        self._initial_site_allocation = self._site_allocation
+        self._network_ports = self._sliceInfo["networkPorts"]
+        self._initial_network_ports = self._network_ports
+
+    def getSliceInfo(self, user=None):
+        if not self._sliceInfo:
+            used_sites = {}
+            ready_sites = {}
+            used_deployments = {}
+            instanceCount = 0
+            sshCommands = []
+            for instance in self.instances.all():
+                site = instance.node.site_deployment.site
+                deployment = instance.node.site_deployment.deployment
+                used_sites[site.name] = used_sites.get(site.name, 0) + 1
+                used_deployments[deployment.name] = used_deployments.get(deployment.name, 0) + 1
+                instanceCount = instanceCount + 1
+
+                sshCommand = instance.get_ssh_command()
+                if sshCommand:
+                    sshCommands.append(sshCommand)
+
+                    ready_sites[site.name] = ready_sites.get(site.name, 0) + 1
+
+            users = {}
+            for priv in SlicePrivilege.objects.filter(slice=self):
+                if not (priv.user.id in users.keys()):
+                    users[priv.user.id] = {"name": priv.user.email, "id": priv.user.id, "roles": []}
+                users[priv.user.id]["roles"].append(priv.role.role)
+
+            # XXX this assumes there is only one network that can have ports bound
+            # to it for a given slice. This is intended for the tenant view, which
+            # will obey this field.
+            networkPorts = ""
+            for networkSlice in self.networkslices.all():
+                network = networkSlice.network
+                if (network.owner.id != self.id):
+                    continue
+                if network.ports:
+                    networkPorts = network.ports
+
+            self._sliceInfo= {"sitesUsed": used_sites,
+                    "sitesReady": ready_sites,
+                    "deploymentsUsed": used_deployments,
+                    "instanceCount": instanceCount,
+                    "siteCount": len(used_sites.keys()),
+                    "users": users,
+                    "roles": [],
+                    "sshCommands": sshCommands,
+                    "networkPorts": networkPorts}
+
+        if user:
+            auser = self._sliceInfo["users"].get(user.id, None)
+            if (auser):
+                self._sliceInfo["roles"] = auser["roles"]
+
+        return self._sliceInfo
+
+    @property
+    def site_ready(self):
+        return self.getSliceInfo()["sitesReady"]
+
+    @site_ready.setter
+    def site_ready(self, value):
+        pass
+
+    @property
+    def site_allocation(self):
+        return self._site_allocation
+
+    @site_allocation.setter
+    def site_allocation(self, value):
+        self._site_allocation = value
+
+    @property
+    def user_names(self):
+        return [user["name"] for user in self.getSliceInfo()["users"].values()]
+
+    @user_names.setter
+    def user_names(self, value):
+        pass # it's read-only
+
+    @property
+    def users(self):
+        return [user["id"] for user in self.getSliceInfo()["users"].values()]
+
+    @users.setter
+    def users(self, value):
+        self._update_users = value
+        #print "XXX set users to", value
+
+    @property
+    def network_ports(self):
+        return self._network_ports
+
+    @network_ports.setter
+    def network_ports(self, value):
+        self._network_ports = value
+        #print "XXX set networkPorts to", value
+
+    @staticmethod
+    def select_by_user(user):
+        if user.is_admin:
+            qs = SlicePlus.objects.all()
+        else:
+            slice_ids = [sp.slice.id for sp in SlicePrivilege.objects.filter(user=user)]
+            qs = SlicePlus.objects.filter(id__in=slice_ids)
+        return qs
+
+    def get_node_allocation(self, siteList):
+        siteIDList = [site.id for site in siteList]
+        nodeList = []
+        for node in Node.objects.all():
+            if (node.site_deployment.site.id in siteIDList):
+                node.instanceCount = 0
+                for instance in node.instances.all():
+                     if instance.slice.id == self.id:
+                         node.instanceCount = node.instanceCount + 1
+                nodeList.append(node)
+        return nodeList
+
+    def save(self, *args, **kwargs):
+        if (not hasattr(self,"caller")) or self.caller==None:
+            raise APIException("no self.caller in SlicePlus.save")
+
+        updated_image = self.has_field_changed("default_image")
+        updated_flavor = self.has_field_changed("default_flavor")
+
+        super(SlicePlus, self).save(*args, **kwargs)
+
+        # try things out first
+
+        updated_sites = (self._site_allocation != self._initial_site_allocation) or updated_image or updated_flavor
+        if updated_sites:
+            self.save_site_allocation(noAct=True, reset=(updated_image or updated_flavor))
+
+        if self._update_users:
+            self.save_users(noAct=True)
+
+        if (self._network_ports != self._initial_network_ports):
+            self.save_network_ports(noAct=True)
+
+        # now actually save them
+
+        if updated_sites:
+            self.save_site_allocation(reset=(updated_image or updated_flavor))
+
+        if self._update_users:
+            self.save_users()
+
+        if (self._network_ports != self._initial_network_ports):
+            self.save_network_ports()
+
+    def save_site_allocation(self, noAct = False, reset=False):
+        print "save_site_allocation, reset=",reset
+
+        if (not self._site_allocation):
+            # Must be a instance that was just created, and has not site_allocation
+            # field.
+            return
+
+        all_slice_instances = self.instances.all()
+        for site_name in self._site_allocation.keys():
+            desired_allocation = self._site_allocation[site_name]
+
+            # make a list of the instances for this site
+            instances = []
+            for instance in all_slice_instances:
+                if instance.node.site_deployment.site.name == site_name:
+                    instances.append(instance)
+
+            # delete extra instances
+            while (reset and len(instances)>0) or (len(instances) > desired_allocation):
+                instance = instances.pop()
+                if (not noAct):
+                    print "deleting instance", instance
+                    instance.delete()
+                else:
+                    print "would delete instance", instance
+
+            # add more instances
+            if (len(instances) < desired_allocation):
+                site = Site.objects.get(name = site_name)
+                nodes = self.get_node_allocation([site])
+
+                if (not nodes):
+                    raise APIException(detail="no nodes in site %s" % site_name)
+
+                while (len(instances) < desired_allocation):
+                    # pick the least allocated node
+                    nodes = sorted(nodes, key=attrgetter("instanceCount"))
+                    node = nodes[0]
+
+                    instance = Instance(name=node.name,
+                            slice=self,
+                            node=node,
+                            image = self.default_image,
+                            flavor = self.default_flavor,
+                            creator = self.creator,
+                            deployment = node.site_deployment.deployment)
+                    instance.caller = self.caller
+                    instances.append(instance)
+                    if (not noAct):
+                        print "added instance", instance
+                        instance.save()
+                    else:
+                        print "would add instance", instance
+
+                    node.instanceCount = node.instanceCount + 1
+
+    def save_users(self, noAct = False):
+        new_users = self._update_users
+
+        try:
+            default_role = SliceRole.objects.get(role="access")
+        except:
+            default_role = SliceRole.objects.get(role="default")
+
+        slice_privs = self.sliceprivileges.all()
+        slice_user_ids = [priv.user.id for priv in slice_privs]
+
+        for user_id in new_users:
+            if (user_id not in slice_user_ids):
+                priv = SlicePrivilege(slice=self, user=User.objects.get(id=user_id), role=default_role)
+                priv.caller = self.caller
+                if (not noAct):
+                    priv.save()
+
+                print "added user id", user_id
+
+        for priv in slice_privs:
+             if (priv.role.id != default_role.id):
+                 # only mess with 'default' users; don't kill an admin
+                 continue
+
+             if (priv.user.id not in new_users):
+                 if (not noAct):
+                     priv.delete()
+
+                 print "deleted user id", user_id
+
+    def save_network_ports(self, noAct=False):
+        # First search for any network that already has a filled in 'ports'
+        # field. We'll assume there can only be one, so it must be the right
+        # one.
+        for networkSlice in self.networkslices.all():
+            network = networkSlice.network
+            if (network.owner.id != self.id):
+                continue
+            if network.ports:
+                network.ports = self._network_ports
+                network.caller = self.caller
+                if (not noAct):
+                    network.save()
+                return
+
+        # Now try a network that is a "NAT", since setting ports on a non-NAT
+        # network doesn't make much sense.
+        for networkSlice in self.networkslices.all():
+            network = networkSlice.network
+            if (network.owner.id != self.id):
+                continue
+            if network.template.translation=="NAT":
+                network.ports = self._network_ports
+                network.caller = self.caller
+                if (not noAct):
+                    network.save()
+                return
+
+        # uh oh, we didn't find a network
+
+        raise APIException(detail="No network was found that ports could be set on")
+
+
+
+
+
diff --git a/xos/core/xoslib/package.json b/xos/core/xoslib/package.json
new file mode 100644
index 0000000..dd4ea4c
--- /dev/null
+++ b/xos/core/xoslib/package.json
@@ -0,0 +1,31 @@
+{
+  "name": "xoslib",
+  "version": "0.0.0",
+  "description": "Add to the following in settings.py",
+  "main": "index.js",
+  "scripts": {
+    "pretest": "npm install",
+    "test": "karma start",
+    "lint": "eslint .",
+    "docs": "jsdoc static/js -r -c ./jsdoc.conf.json -d docs"
+  },
+  "author": "",
+  "license": "BSD-2-Clause",
+  "devDependencies": {
+    "eslint": "~1.6.0",
+    "eslint-config-defaults": "^7.0.1",
+    "ink-docstrap": "^0.5.2",
+    "jasmine-core": "~2.3.4",
+    "jsdoc": "^3.3.3",
+    "karma": "^0.13.14",
+    "karma-babel-preprocessor": "~5.2.2",
+    "karma-coverage": "^0.5.3",
+    "karma-jasmine": "~0.3.6",
+    "karma-mocha-reporter": "~1.1.1",
+    "karma-ng-html2js-preprocessor": "^0.2.0",
+    "karma-phantomjs-launcher": "~0.2.1",
+    "phantomjs": "~1.9.18",
+    "wiredep": "^3.0.0-beta"
+  },
+  "dependencies": {}
+}
diff --git a/xos/core/xoslib/spec/.eslintrc b/xos/core/xoslib/spec/.eslintrc
new file mode 100644
index 0000000..eb98f18
--- /dev/null
+++ b/xos/core/xoslib/spec/.eslintrc
@@ -0,0 +1,50 @@
+{
+  "ecmaFeatures": {
+    "blockBindings": true,
+    "forOf" : true,
+    "generators": true,
+    "destructuring": true,
+    "forOf": true,
+    "arrowFunctions": true,
+    "templateStrings": true,
+    "destructuring": true,
+    "forOf": true,
+    "arrowFunctions": true,
+    "templateStrings": true,
+    "generators": true
+  },
+  "env" : {
+    "browser": true,
+    "node": true,
+    "es6": true
+  },
+  "rules" : {
+    "quotes": [1, "single"],
+    "camelcase": [0],
+    "no-underscore-dangle": [0],
+    "eqeqeq": [1],
+    "no-alert": [1],
+    "no-unused-vars": [1],
+    "key-spacing": [2, {
+        "beforeColon": false,
+        "afterColon": true
+    }],
+    "indent": [2, 2],
+    "no-undef": [0],
+    "newline-after-var": [0]
+  },
+  "globals": {
+    "console": false,
+    "describe": false,
+    "xdescribe": false,
+    "it": false,
+    "xit": false,
+    "before": false,
+    "beforeEach": false,
+    "after": false,
+    "afterEach": false,
+    "expect": false,
+    "jasmine": false,
+    "spyOn": false
+  }
+}
diff --git a/xos/core/xoslib/spec/helpers/jasmine-jquery.js b/xos/core/xoslib/spec/helpers/jasmine-jquery.js
new file mode 100644
index 0000000..7713331
--- /dev/null
+++ b/xos/core/xoslib/spec/helpers/jasmine-jquery.js
@@ -0,0 +1,840 @@
+/*!
+Jasmine-jQuery: a set of jQuery helpers for Jasmine tests.
+
+Version 2.1.1
+
+https://github.com/velesin/jasmine-jquery
+
+Copyright (c) 2010-2014 Wojciech Zawistowski, Travis Jeffery
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+(function (root, factory) {
+     if (typeof module !== 'undefined' && module.exports) {
+        factory(root, root.jasmine, require('jquery'));
+    } else {
+        factory(root, root.jasmine, root.jQuery);
+    }
+}((function() {return this; })(), function (window, jasmine, $) { "use strict";
+
+  jasmine.spiedEventsKey = function (selector, eventName) {
+    return [$(selector).selector, eventName].toString()
+  }
+
+  jasmine.getFixtures = function () {
+    return jasmine.currentFixtures_ = jasmine.currentFixtures_ || new jasmine.Fixtures()
+  }
+
+  jasmine.getStyleFixtures = function () {
+    return jasmine.currentStyleFixtures_ = jasmine.currentStyleFixtures_ || new jasmine.StyleFixtures()
+  }
+
+  jasmine.Fixtures = function () {
+    this.containerId = 'jasmine-fixtures'
+    this.fixturesCache_ = {}
+    this.fixturesPath = 'spec/javascripts/fixtures'
+  }
+
+  jasmine.Fixtures.prototype.set = function (html) {
+    this.cleanUp()
+    return this.createContainer_(html)
+  }
+
+  jasmine.Fixtures.prototype.appendSet= function (html) {
+    this.addToContainer_(html)
+  }
+
+  jasmine.Fixtures.prototype.preload = function () {
+    this.read.apply(this, arguments)
+  }
+
+  jasmine.Fixtures.prototype.load = function () {
+    this.cleanUp()
+    this.createContainer_(this.read.apply(this, arguments))
+  }
+
+  jasmine.Fixtures.prototype.appendLoad = function () {
+    this.addToContainer_(this.read.apply(this, arguments))
+  }
+
+  jasmine.Fixtures.prototype.read = function () {
+    var htmlChunks = []
+      , fixtureUrls = arguments
+
+    for(var urlCount = fixtureUrls.length, urlIndex = 0; urlIndex < urlCount; urlIndex++) {
+      htmlChunks.push(this.getFixtureHtml_(fixtureUrls[urlIndex]))
+    }
+
+    return htmlChunks.join('')
+  }
+
+  jasmine.Fixtures.prototype.clearCache = function () {
+    this.fixturesCache_ = {}
+  }
+
+  jasmine.Fixtures.prototype.cleanUp = function () {
+    $('#' + this.containerId).remove()
+  }
+
+  jasmine.Fixtures.prototype.sandbox = function (attributes) {
+    var attributesToSet = attributes || {}
+    return $('<div id="sandbox" />').attr(attributesToSet)
+  }
+
+  jasmine.Fixtures.prototype.createContainer_ = function (html) {
+    var container = $('<div>')
+    .attr('id', this.containerId)
+    .html(html)
+
+    $(document.body).append(container)
+    return container
+  }
+
+  jasmine.Fixtures.prototype.addToContainer_ = function (html){
+    var container = $(document.body).find('#'+this.containerId).append(html)
+
+    if (!container.length) {
+      this.createContainer_(html)
+    }
+  }
+
+  jasmine.Fixtures.prototype.getFixtureHtml_ = function (url) {
+    if (typeof this.fixturesCache_[url] === 'undefined') {
+      this.loadFixtureIntoCache_(url)
+    }
+    return this.fixturesCache_[url]
+  }
+
+  jasmine.Fixtures.prototype.loadFixtureIntoCache_ = function (relativeUrl) {
+    var self = this
+      , url = this.makeFixtureUrl_(relativeUrl)
+      , htmlText = ''
+      , request = $.ajax({
+        async: false, // must be synchronous to guarantee that no tests are run before fixture is loaded
+        cache: false,
+        url: url,
+        dataType: 'html',
+        success: function (data, status, $xhr) {
+          htmlText = $xhr.responseText
+        }
+      }).fail(function ($xhr, status, err) {
+          console.log($xhr.responseText);
+          console.log($xhr.getAllResponseHeaders());
+          throw new Error('Fixture could not be loaded: ' + url + ' (status: ' + status + ', message: ' + err.message + ')')
+      })
+
+      var scripts = $($.parseHTML(htmlText, true)).find('script[src]') || [];
+
+      scripts.each(function(){
+        $.ajax({
+            async: false, // must be synchronous to guarantee that no tests are run before fixture is loaded
+            cache: false,
+            dataType: 'script',
+            url: $(this).attr('src'),
+            success: function (data, status, $xhr) {
+                htmlText += '<script>' + $xhr.responseText + '</script>'
+            },
+            error: function ($xhr, status, err) {
+                throw new Error('Script could not be loaded: ' + url + ' (status: ' + status + ', message: ' + err.message + ')')
+            }
+        });
+      })
+
+      self.fixturesCache_[relativeUrl] = htmlText;
+  }
+
+  jasmine.Fixtures.prototype.makeFixtureUrl_ = function (relativeUrl){
+    return this.fixturesPath.match('/$') ? this.fixturesPath + relativeUrl : this.fixturesPath + '/' + relativeUrl
+  }
+
+  jasmine.Fixtures.prototype.proxyCallTo_ = function (methodName, passedArguments) {
+    return this[methodName].apply(this, passedArguments)
+  }
+
+
+  jasmine.StyleFixtures = function () {
+    this.fixturesCache_ = {}
+    this.fixturesNodes_ = []
+    this.fixturesPath = 'spec/javascripts/fixtures'
+  }
+
+  jasmine.StyleFixtures.prototype.set = function (css) {
+    this.cleanUp()
+    this.createStyle_(css)
+  }
+
+  jasmine.StyleFixtures.prototype.appendSet = function (css) {
+    this.createStyle_(css)
+  }
+
+  jasmine.StyleFixtures.prototype.preload = function () {
+    this.read_.apply(this, arguments)
+  }
+
+  jasmine.StyleFixtures.prototype.load = function () {
+    this.cleanUp()
+    this.createStyle_(this.read_.apply(this, arguments))
+  }
+
+  jasmine.StyleFixtures.prototype.appendLoad = function () {
+    this.createStyle_(this.read_.apply(this, arguments))
+  }
+
+  jasmine.StyleFixtures.prototype.cleanUp = function () {
+    while(this.fixturesNodes_.length) {
+      this.fixturesNodes_.pop().remove()
+    }
+  }
+
+  jasmine.StyleFixtures.prototype.createStyle_ = function (html) {
+    var styleText = $('<div></div>').html(html).text()
+      , style = $('<style>' + styleText + '</style>')
+
+    this.fixturesNodes_.push(style)
+    $('head').append(style)
+  }
+
+  jasmine.StyleFixtures.prototype.clearCache = jasmine.Fixtures.prototype.clearCache
+  jasmine.StyleFixtures.prototype.read_ = jasmine.Fixtures.prototype.read
+  jasmine.StyleFixtures.prototype.getFixtureHtml_ = jasmine.Fixtures.prototype.getFixtureHtml_
+  jasmine.StyleFixtures.prototype.loadFixtureIntoCache_ = jasmine.Fixtures.prototype.loadFixtureIntoCache_
+  jasmine.StyleFixtures.prototype.makeFixtureUrl_ = jasmine.Fixtures.prototype.makeFixtureUrl_
+  jasmine.StyleFixtures.prototype.proxyCallTo_ = jasmine.Fixtures.prototype.proxyCallTo_
+
+  jasmine.getJSONFixtures = function () {
+    return jasmine.currentJSONFixtures_ = jasmine.currentJSONFixtures_ || new jasmine.JSONFixtures()
+  }
+
+  jasmine.JSONFixtures = function () {
+    this.fixturesCache_ = {}
+    this.fixturesPath = 'spec/javascripts/fixtures/json'
+  }
+
+  jasmine.JSONFixtures.prototype.load = function () {
+    this.read.apply(this, arguments)
+    return this.fixturesCache_
+  }
+
+  jasmine.JSONFixtures.prototype.read = function () {
+    var fixtureUrls = arguments
+
+    for(var urlCount = fixtureUrls.length, urlIndex = 0; urlIndex < urlCount; urlIndex++) {
+      this.getFixtureData_(fixtureUrls[urlIndex])
+    }
+
+    return this.fixturesCache_
+  }
+
+  jasmine.JSONFixtures.prototype.clearCache = function () {
+    this.fixturesCache_ = {}
+  }
+
+  jasmine.JSONFixtures.prototype.getFixtureData_ = function (url) {
+    if (!this.fixturesCache_[url]) this.loadFixtureIntoCache_(url)
+    return this.fixturesCache_[url]
+  }
+
+  jasmine.JSONFixtures.prototype.loadFixtureIntoCache_ = function (relativeUrl) {
+    var self = this
+      , url = this.fixturesPath.match('/$') ? this.fixturesPath + relativeUrl : this.fixturesPath + '/' + relativeUrl
+
+    $.ajax({
+      async: false, // must be synchronous to guarantee that no tests are run before fixture is loaded
+      cache: false,
+      dataType: 'json',
+      url: url,
+      success: function (data) {
+        self.fixturesCache_[relativeUrl] = data
+      },
+      error: function ($xhr, status, err) {
+        throw new Error('JSONFixture could not be loaded: ' + url + ' (status: ' + status + ', message: ' + err.message + ')')
+      }
+    })
+  }
+
+  jasmine.JSONFixtures.prototype.proxyCallTo_ = function (methodName, passedArguments) {
+    return this[methodName].apply(this, passedArguments)
+  }
+
+  jasmine.jQuery = function () {}
+
+  jasmine.jQuery.browserTagCaseIndependentHtml = function (html) {
+    return $('<div/>').append(html).html()
+  }
+
+  jasmine.jQuery.elementToString = function (element) {
+    return $(element).map(function () { return this.outerHTML; }).toArray().join(', ')
+  }
+
+  var data = {
+      spiedEvents: {}
+    , handlers:    []
+  }
+
+  jasmine.jQuery.events = {
+    spyOn: function (selector, eventName) {
+      var handler = function (e) {
+        var calls = (typeof data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)] !== 'undefined') ? data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)].calls : 0
+        data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)] = {
+          args: jasmine.util.argsToArray(arguments),
+          calls: ++calls
+        }
+      }
+
+      $(selector).on(eventName, handler)
+      data.handlers.push(handler)
+
+      return {
+        selector: selector,
+        eventName: eventName,
+        handler: handler,
+        reset: function (){
+          delete data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)]
+        },
+        calls: {
+          count: function () {
+              return data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)] ?
+                data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)].calls : 0;
+          },
+          any: function () {
+              return data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)] ?
+                !!data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)].calls : false;
+          }
+        }
+      }
+    },
+
+    args: function (selector, eventName) {
+      var actualArgs = data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)].args
+
+      if (!actualArgs) {
+        throw "There is no spy for " + eventName + " on " + selector.toString() + ". Make sure to create a spy using spyOnEvent."
+      }
+
+      return actualArgs
+    },
+
+    wasTriggered: function (selector, eventName) {
+      return !!(data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)])
+    },
+
+    wasTriggeredWith: function (selector, eventName, expectedArgs, util, customEqualityTesters) {
+      var actualArgs = jasmine.jQuery.events.args(selector, eventName).slice(1)
+
+      if (Object.prototype.toString.call(expectedArgs) !== '[object Array]')
+        actualArgs = actualArgs[0]
+
+      return util.equals(actualArgs, expectedArgs, customEqualityTesters)
+    },
+
+    wasPrevented: function (selector, eventName) {
+      var spiedEvent = data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)]
+        , args = (jasmine.util.isUndefined(spiedEvent)) ? {} : spiedEvent.args
+        , e = args ? args[0] : undefined
+
+      return e && e.isDefaultPrevented()
+    },
+
+    wasStopped: function (selector, eventName) {
+      var spiedEvent = data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)]
+        , args = (jasmine.util.isUndefined(spiedEvent)) ? {} : spiedEvent.args
+        , e = args ? args[0] : undefined
+
+      return e && e.isPropagationStopped()
+    },
+
+    cleanUp: function () {
+      data.spiedEvents = {}
+      data.handlers    = []
+    }
+  }
+
+  var hasProperty = function (actualValue, expectedValue) {
+    if (expectedValue === undefined)
+      return actualValue !== undefined
+
+    return actualValue === expectedValue
+  }
+
+  beforeEach(function () {
+    jasmine.addMatchers({
+      toHaveClass: function () {
+        return {
+          compare: function (actual, className) {
+            return { pass: $(actual).hasClass(className) }
+          }
+        }
+      },
+
+      toHaveCss: function () {
+        return {
+          compare: function (actual, css) {
+            for (var prop in css){
+              var value = css[prop]
+              // see issue #147 on gh
+              ;if (value === 'auto' && $(actual).get(0).style[prop] === 'auto') continue
+              if ($(actual).css(prop) !== value) return { pass: false }
+            }
+            return { pass: true }
+          }
+        }
+      },
+
+      toBeVisible: function () {
+        return {
+          compare: function (actual) {
+            return { pass: $(actual).is(':visible') }
+          }
+        }
+      },
+
+      toBeHidden: function () {
+        return {
+          compare: function (actual) {
+            return { pass: $(actual).is(':hidden') }
+          }
+        }
+      },
+
+      toBeSelected: function () {
+        return {
+          compare: function (actual) {
+            return { pass: $(actual).is(':selected') }
+          }
+        }
+      },
+
+      toBeChecked: function () {
+        return {
+          compare: function (actual) {
+            return { pass: $(actual).is(':checked') }
+          }
+        }
+      },
+
+      toBeEmpty: function () {
+        return {
+          compare: function (actual) {
+            return { pass: $(actual).is(':empty') }
+          }
+        }
+      },
+
+      toBeInDOM: function () {
+        return {
+          compare: function (actual) {
+            return { pass: $.contains(document.documentElement, $(actual)[0]) }
+          }
+        }
+      },
+
+      toExist: function () {
+        return {
+          compare: function (actual) {
+            return { pass: $(actual).length }
+          }
+        }
+      },
+
+      toHaveLength: function () {
+        return {
+          compare: function (actual, length) {
+            return { pass: $(actual).length === length }
+          }
+        }
+      },
+
+      toHaveAttr: function () {
+        return {
+          compare: function (actual, attributeName, expectedAttributeValue) {
+            return { pass: hasProperty($(actual).attr(attributeName), expectedAttributeValue) }
+          }
+        }
+      },
+
+      toHaveProp: function () {
+        return {
+          compare: function (actual, propertyName, expectedPropertyValue) {
+            return { pass: hasProperty($(actual).prop(propertyName), expectedPropertyValue) }
+          }
+        }
+      },
+
+      toHaveId: function () {
+        return {
+          compare: function (actual, id) {
+            return { pass: $(actual).attr('id') == id }
+          }
+        }
+      },
+
+      toHaveHtml: function () {
+        return {
+          compare: function (actual, html) {
+            return { pass: $(actual).html() == jasmine.jQuery.browserTagCaseIndependentHtml(html) }
+          }
+        }
+      },
+
+      toContainHtml: function () {
+        return {
+          compare: function (actual, html) {
+            var actualHtml = $(actual).html()
+              , expectedHtml = jasmine.jQuery.browserTagCaseIndependentHtml(html)
+
+            return { pass: (actualHtml.indexOf(expectedHtml) >= 0) }
+          }
+        }
+      },
+
+      toHaveText: function () {
+        return {
+          compare: function (actual, text) {
+            var actualText = $(actual).text()
+            var trimmedText = $.trim(actualText)
+
+            if (text && $.isFunction(text.test)) {
+              return { pass: text.test(actualText) || text.test(trimmedText) }
+            } else {
+              return { pass: (actualText == text || trimmedText == text) }
+            }
+          }
+        }
+      },
+
+      toContainText: function () {
+        return {
+          compare: function (actual, text) {
+            var trimmedText = $.trim($(actual).text())
+
+            if (text && $.isFunction(text.test)) {
+              return { pass: text.test(trimmedText) }
+            } else {
+              return { pass: trimmedText.indexOf(text) != -1 }
+            }
+          }
+        }
+      },
+
+      toHaveValue: function () {
+        return {
+          compare: function (actual, value) {
+            return { pass: $(actual).val() === value }
+          }
+        }
+      },
+
+      toHaveData: function () {
+        return {
+          compare: function (actual, key, expectedValue) {
+            return { pass: hasProperty($(actual).data(key), expectedValue) }
+          }
+        }
+      },
+
+      toContainElement: function () {
+        return {
+          compare: function (actual, selector) {
+            return { pass: $(actual).find(selector).length }
+          }
+        }
+      },
+
+      toBeMatchedBy: function () {
+        return {
+          compare: function (actual, selector) {
+            return { pass: $(actual).filter(selector).length }
+          }
+        }
+      },
+
+      toBeDisabled: function () {
+        return {
+          compare: function (actual, selector) {
+            return { pass: $(actual).is(':disabled') }
+          }
+        }
+      },
+
+      toBeFocused: function (selector) {
+        return {
+          compare: function (actual, selector) {
+            return { pass: $(actual)[0] === $(actual)[0].ownerDocument.activeElement }
+          }
+        }
+      },
+
+      toHandle: function () {
+        return {
+          compare: function (actual, event) {
+            if ( !actual || actual.length === 0 ) return { pass: false };
+            var events = $._data($(actual).get(0), "events")
+
+            if (!events || !event || typeof event !== "string") {
+              return { pass: false }
+            }
+
+            var namespaces = event.split(".")
+              , eventType = namespaces.shift()
+              , sortedNamespaces = namespaces.slice(0).sort()
+              , namespaceRegExp = new RegExp("(^|\\.)" + sortedNamespaces.join("\\.(?:.*\\.)?") + "(\\.|$)")
+
+            if (events[eventType] && namespaces.length) {
+              for (var i = 0; i < events[eventType].length; i++) {
+                var namespace = events[eventType][i].namespace
+
+                if (namespaceRegExp.test(namespace))
+                  return { pass: true }
+              }
+            } else {
+              return { pass: (events[eventType] && events[eventType].length > 0) }
+            }
+
+            return { pass: false }
+          }
+        }
+      },
+
+      toHandleWith: function () {
+        return {
+          compare: function (actual, eventName, eventHandler) {
+            if ( !actual || actual.length === 0 ) return { pass: false };
+            var normalizedEventName = eventName.split('.')[0]
+              , stack = $._data($(actual).get(0), "events")[normalizedEventName]
+
+            for (var i = 0; i < stack.length; i++) {
+              if (stack[i].handler == eventHandler) return { pass: true }
+            }
+
+            return { pass: false }
+          }
+        }
+      },
+
+      toHaveBeenTriggeredOn: function () {
+        return {
+          compare: function (actual, selector) {
+            var result = { pass: jasmine.jQuery.events.wasTriggered(selector, actual) }
+
+            result.message = result.pass ?
+              "Expected event " + $(actual) + " not to have been triggered on " + selector :
+              "Expected event " + $(actual) + " to have been triggered on " + selector
+
+            return result;
+          }
+        }
+      },
+
+      toHaveBeenTriggered: function (){
+        return {
+          compare: function (actual) {
+            var eventName = actual.eventName
+              , selector = actual.selector
+              , result = { pass: jasmine.jQuery.events.wasTriggered(selector, eventName) }
+
+            result.message = result.pass ?
+            "Expected event " + eventName + " not to have been triggered on " + selector :
+              "Expected event " + eventName + " to have been triggered on " + selector
+
+            return result
+          }
+        }
+      },
+
+      toHaveBeenTriggeredOnAndWith: function (j$, customEqualityTesters) {
+        return {
+          compare: function (actual, selector, expectedArgs) {
+            var wasTriggered = jasmine.jQuery.events.wasTriggered(selector, actual)
+              , result = { pass: wasTriggered && jasmine.jQuery.events.wasTriggeredWith(selector, actual, expectedArgs, j$, customEqualityTesters) }
+
+              if (wasTriggered) {
+                var actualArgs = jasmine.jQuery.events.args(selector, actual, expectedArgs)[1]
+                result.message = result.pass ?
+                  "Expected event " + actual + " not to have been triggered with " + jasmine.pp(expectedArgs) + " but it was triggered with " + jasmine.pp(actualArgs) :
+                  "Expected event " + actual + " to have been triggered with " + jasmine.pp(expectedArgs) + "  but it was triggered with " + jasmine.pp(actualArgs)
+
+              } else {
+                // todo check on this
+                result.message = result.pass ?
+                  "Expected event " + actual + " not to have been triggered on " + selector :
+                  "Expected event " + actual + " to have been triggered on " + selector
+              }
+
+              return result
+          }
+        }
+      },
+
+      toHaveBeenPreventedOn: function () {
+        return {
+          compare: function (actual, selector) {
+            var result = { pass: jasmine.jQuery.events.wasPrevented(selector, actual) }
+
+            result.message = result.pass ?
+              "Expected event " + actual + " not to have been prevented on " + selector :
+              "Expected event " + actual + " to have been prevented on " + selector
+
+            return result
+          }
+        }
+      },
+
+      toHaveBeenPrevented: function () {
+        return {
+          compare: function (actual) {
+            var eventName = actual.eventName
+              , selector = actual.selector
+              , result = { pass: jasmine.jQuery.events.wasPrevented(selector, eventName) }
+
+            result.message = result.pass ?
+              "Expected event " + eventName + " not to have been prevented on " + selector :
+              "Expected event " + eventName + " to have been prevented on " + selector
+
+            return result
+          }
+        }
+      },
+
+      toHaveBeenStoppedOn: function () {
+        return {
+          compare: function (actual, selector) {
+            var result = { pass: jasmine.jQuery.events.wasStopped(selector, actual) }
+
+            result.message = result.pass ?
+              "Expected event " + actual + " not to have been stopped on " + selector :
+              "Expected event " + actual + " to have been stopped on " + selector
+
+            return result;
+          }
+        }
+      },
+
+      toHaveBeenStopped: function () {
+        return {
+          compare: function (actual) {
+            var eventName = actual.eventName
+              , selector = actual.selector
+              , result = { pass: jasmine.jQuery.events.wasStopped(selector, eventName) }
+
+            result.message = result.pass ?
+              "Expected event " + eventName + " not to have been stopped on " + selector :
+              "Expected event " + eventName + " to have been stopped on " + selector
+
+            return result
+          }
+        }
+      }
+    })
+
+    jasmine.getEnv().addCustomEqualityTester(function(a, b) {
+     if (a && b) {
+       if (a instanceof $ || jasmine.isDomNode(a)) {
+         var $a = $(a)
+
+         if (b instanceof $)
+           return $a.length == b.length && a.is(b)
+
+         return $a.is(b);
+       }
+
+       if (b instanceof $ || jasmine.isDomNode(b)) {
+         var $b = $(b)
+
+         if (a instanceof $)
+           return a.length == $b.length && $b.is(a)
+
+         return $(b).is(a);
+       }
+     }
+    })
+
+    jasmine.getEnv().addCustomEqualityTester(function (a, b) {
+     if (a instanceof $ && b instanceof $ && a.size() == b.size())
+        return a.is(b)
+    })
+  })
+
+  afterEach(function () {
+    jasmine.getFixtures().cleanUp()
+    jasmine.getStyleFixtures().cleanUp()
+    jasmine.jQuery.events.cleanUp()
+  })
+
+  window.readFixtures = function () {
+    return jasmine.getFixtures().proxyCallTo_('read', arguments)
+  }
+
+  window.preloadFixtures = function () {
+    jasmine.getFixtures().proxyCallTo_('preload', arguments)
+  }
+
+  window.loadFixtures = function () {
+    jasmine.getFixtures().proxyCallTo_('load', arguments)
+  }
+
+  window.appendLoadFixtures = function () {
+    jasmine.getFixtures().proxyCallTo_('appendLoad', arguments)
+  }
+
+  window.setFixtures = function (html) {
+    return jasmine.getFixtures().proxyCallTo_('set', arguments)
+  }
+
+  window.appendSetFixtures = function () {
+    jasmine.getFixtures().proxyCallTo_('appendSet', arguments)
+  }
+
+  window.sandbox = function (attributes) {
+    return jasmine.getFixtures().sandbox(attributes)
+  }
+
+  window.spyOnEvent = function (selector, eventName) {
+    return jasmine.jQuery.events.spyOn(selector, eventName)
+  }
+
+  window.preloadStyleFixtures = function () {
+    jasmine.getStyleFixtures().proxyCallTo_('preload', arguments)
+  }
+
+  window.loadStyleFixtures = function () {
+    jasmine.getStyleFixtures().proxyCallTo_('load', arguments)
+  }
+
+  window.appendLoadStyleFixtures = function () {
+    jasmine.getStyleFixtures().proxyCallTo_('appendLoad', arguments)
+  }
+
+  window.setStyleFixtures = function (html) {
+    jasmine.getStyleFixtures().proxyCallTo_('set', arguments)
+  }
+
+  window.appendSetStyleFixtures = function (html) {
+    jasmine.getStyleFixtures().proxyCallTo_('appendSet', arguments)
+  }
+
+  window.loadJSONFixtures = function () {
+    return jasmine.getJSONFixtures().proxyCallTo_('load', arguments)
+  }
+
+  window.getJSONFixture = function (url) {
+    return jasmine.getJSONFixtures().proxyCallTo_('read', arguments)[url]
+  }
+}));
diff --git a/xos/core/xoslib/spec/smoke.test.js b/xos/core/xoslib/spec/smoke.test.js
new file mode 100644
index 0000000..2c27544
--- /dev/null
+++ b/xos/core/xoslib/spec/smoke.test.js
@@ -0,0 +1,7 @@
+'use strict';
+
+describe('The test environment', () => {
+  it('should correctly work', () => {
+    expect(true).toBe(true);
+  });
+});
diff --git a/xos/core/xoslib/spec/xoslib/fixtures/xos-utils/make_same_width.html b/xos/core/xoslib/spec/xoslib/fixtures/xos-utils/make_same_width.html
new file mode 100644
index 0000000..8227c99
--- /dev/null
+++ b/xos/core/xoslib/spec/xoslib/fixtures/xos-utils/make_same_width.html
@@ -0,0 +1,5 @@
+<div class="container">
+  <div style="width: 200px"></div>
+  <div style="width: 300px"></div>
+  <div style="width: 400px"></div>
+</div>
\ No newline at end of file
diff --git a/xos/core/xoslib/spec/xoslib/fixtures/xos-utils/table_rows.html b/xos/core/xoslib/spec/xoslib/fixtures/xos-utils/table_rows.html
new file mode 100644
index 0000000..417108d
--- /dev/null
+++ b/xos/core/xoslib/spec/xoslib/fixtures/xos-utils/table_rows.html
@@ -0,0 +1,19 @@
+<div class="container">
+  <table class="test-table" border="2">
+    <tr>
+      <td height="150">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sequi eaque voluptatum, itaque dolor ut animi ea, laboriosam nobis perspiciatis ducimus asperiores excepturi. Architecto earum, harum nesciunt libero maxime repellat dicta.</td>
+    </tr>
+    <tr>
+      <td height="150">Autem esse, accusantium adipisci, aliquid debitis inventore alias error dolores veniam nesciunt possimus animi dolorum magnam nostrum et asperiores id natus, deleniti ullam illum magni cupiditate suscipit hic. Temporibus, non?</td>
+    </tr>
+    <tr>
+      <td height="150">Tempore sapiente sed laborum commodi explicabo praesentium, molestiae repellendus sit minima magni natus doloremque eius vel voluptatem officiis, blanditiis incidunt nobis! Aut, dolorum, impedit assumenda inventore blanditiis voluptas mollitia nihil.</td>
+    </tr>
+    <tr>
+      <td height="150">Quae esse, earum tenetur, quam at iure cumque unde suscipit corporis, nemo voluptatibus. Ducimus, ratione quidem ut earum? Error, esse quae. Quis ea vero, tempore minus voluptates possimus iure deleniti.</td>
+    </tr>
+    <tr>
+      <td height="150">Asperiores sequi dignissimos doloribus commodi tenetur blanditiis eaque accusantium, hic molestias quas modi minima ratione reiciendis ut id voluptatem eveniet, culpa placeat? Dolor soluta, non cumque adipisci architecto sapiente ullam!</td>
+    </tr>
+  </table>
+</div>
\ No newline at end of file
diff --git a/xos/core/xoslib/spec/xoslib/fixtures/xos-utils/template_from_id.html b/xos/core/xoslib/spec/xoslib/fixtures/xos-utils/template_from_id.html
new file mode 100644
index 0000000..02dcb96
--- /dev/null
+++ b/xos/core/xoslib/spec/xoslib/fixtures/xos-utils/template_from_id.html
@@ -0,0 +1,7 @@
+<script type="text/template" id="static-test">
+  <p>Test Template</p>
+</script>
+
+<script type="text/template" id="dynamic-test">
+  <p>Test <%= stuff %></p>
+</script>
\ No newline at end of file
diff --git a/xos/core/xoslib/spec/xoslib/xos-backbone.test.js b/xos/core/xoslib/spec/xoslib/xos-backbone.test.js
new file mode 100644
index 0000000..90d3c83
--- /dev/null
+++ b/xos/core/xoslib/spec/xoslib/xos-backbone.test.js
@@ -0,0 +1,371 @@
+'use strict';
+
+describe('The Xos Backbone', () => {
+
+  beforeEach(() => {
+    $.extend(xosdefaults,{
+      test: {config: true}
+    });
+  });
+
+  describe('get_defaults mehod', () => {
+
+    it('should return default config', () => {
+      let res = get_defaults('test');
+      expect(res).toEqual({config: true});
+    });
+
+    it('should return undefined', () => {
+      let res = get_defaults('notset');
+      expect(res).toBeUndefined();
+    });
+
+  });
+
+  describe('The extend_defaults method', () => {
+
+    it('should return an extended config', () => {
+      let extended = extend_defaults('test', {extended: true});
+      expect(extended).toEqual({config: true, extended: true});
+    });
+
+    it('should return an new config', () => {
+      let extended = extend_defaults('notset', {extended: true});
+      expect(extended).toEqual({extended: true});
+    });
+
+  });
+
+  describe('The define_model method', () => {
+
+    var testLib;
+
+    beforeEach(() => {
+      var TestLibDefinition = function(){
+        /* eslint-disable no-invalid-this*/
+        this.allCollectionNames = [];
+        this.allCollections = [];
+        /* eslint-enable no-invalid-this*/
+      };
+
+      testLib = new TestLibDefinition();
+    });
+
+    it('should create a model and attach it to xos lib', () => {
+      define_model(testLib, {
+        urlRoot: 'testUrl',
+        modelName: 'testModel'
+      });
+
+      expect(testLib.allCollectionNames[0]).toEqual('testModels');
+      expect(typeof testLib['testModel']).toBe('function');
+
+    });
+
+    describe('when a model is created', () => {
+      var model;
+      beforeEach(() => {
+        define_model(testLib, {
+          urlRoot: 'testUrl',
+          modelName: 'testModel',
+          // collectionName: 'testCollection',
+          relatedCollections: {instances: 'slices'},
+          foreignCollections: ['sites'],
+          foreignFields: {slice: 'slices'},
+          m2mFields: {sites: 'sites'},
+          listFields: ['name'],
+          detailFields: ['name', 'age'],
+          addFields: ['add'],
+          inputType: {add: 'checkbox'}
+        });
+        /*eslint-disable new-cap*/
+        model = new testLib.testModel();
+        /*eslint-enable new-cap*/
+
+        // add defaults and validator for `testModel`
+        xosdefaults['testModel'] = {name: 'Scott'};
+        xosvalidators['testModel'] = {network_ports: ['portspec']};
+      });
+
+      it('should have a name', () => {
+        expect(model.modelName).toEqual('testModel');
+      });
+
+      it('should have a default collectionName', () => {
+        expect(model.collectionName).toEqual('testModels');
+      });
+
+      describe('whith a custom collectionName', () => {
+        var customCollectionName;
+        beforeEach(() => {
+          define_model(testLib, {
+            urlRoot: 'collUrl',
+            modelName: 'customCollectionName',
+            collectionName: 'myCollection'
+          });
+
+          /*eslint-disable new-cap*/
+          customCollectionName = new testLib.customCollectionName();
+          /*eslint-enable new-cap*/
+        });
+
+        it('should have the custom collectionName', () => {
+          expect(customCollectionName.collectionName).toBe('myCollection');
+        });
+
+        afterEach(() => {
+          customCollectionName = null;
+        });
+      });
+
+      it('should have a valid url', () => {
+        expect(model.url()).toEqual('testUrl/?no_hyperlinks=1');
+      });
+
+      it('should have related collections', () => {
+        expect(model.relatedCollections).toEqual({instances: 'slices'});
+      });
+
+      it('should have foreign collections', () => {
+        expect(model.foreignCollections).toEqual(['sites']);
+      });
+
+      it('should have foreign fields', () => {
+        expect(model.foreignFields).toEqual({slice: 'slices'});
+      });
+
+      it('should have m2m fields', () => {
+        expect(model.m2mFields).toEqual({sites: 'sites'});
+      });
+
+      it('should have list field', () => {
+        expect(model.listFields).toEqual(['name']);
+      });
+
+      it('should have deatil field', () => {
+        expect(model.detailFields).toEqual(['name', 'age']);
+      });
+
+      it('should have add field', () => {
+        expect(model.addFields).toEqual(['add']);
+      });
+
+      it('should have input types defined', () => {
+        expect(model.inputType).toEqual({add: 'checkbox'});
+      });
+
+      it('should have standard defaults', () => {
+        expect(model.defaults).toEqual({name: 'Scott'});
+      });
+
+      describe('when default are defined', () => {
+
+        var extendDefault;
+        beforeEach(() => {
+          define_model(testLib, {
+            urlRoot: 'collUrl',
+            modelName: 'extendDefault',
+            defaults: extend_defaults('testModel', {surname: 'Baker'})
+          });
+
+          /*eslint-disable new-cap*/
+          extendDefault = new testLib.extendDefault();
+          /*eslint-enable new-cap*/
+        });
+
+        it('should return new defaults', () => {
+          expect(extendDefault.defaults).toEqual({name: 'Scott', surname: 'Baker'});
+        });
+
+        afterEach(() => {
+          extendDefault = null;
+        });
+      });
+
+      it('should add default validators', () => {
+        expect(model.validators).toEqual({network_ports: ['portspec']});
+      });
+
+      describe('when validators are defined', () => {
+
+        var extendValidators;
+        beforeEach(() => {
+          define_model(testLib, {
+            urlRoot: 'collUrl',
+            modelName: 'testModel',
+            validators: {site: ['notBlank']}
+          });
+
+          /*eslint-disable new-cap*/
+          extendValidators = new testLib.testModel();
+          /*eslint-enable new-cap*/
+        });
+
+        it('should return extended validators', () => {
+          expect(extendValidators.validators).toEqual({network_ports: ['portspec'], site: ['notBlank']});
+        });
+
+        afterEach(() => {
+          extendValidators = null;
+        });
+      });
+
+      it('should have the default xosValidate method', () => {
+        expect(typeof model.xosValidate).toEqual('function');
+      });
+
+      describe('when xosValidate is defined', () => {
+
+        var extendXosValidate;
+        beforeEach(() => {
+          define_model(testLib, {
+            urlRoot: 'collUrl',
+            modelName: 'testModel',
+            xosValidate: {site: ['notBlank']}
+          });
+
+          /*eslint-disable new-cap*/
+          extendXosValidate = new testLib.testModel();
+          /*eslint-enable new-cap*/
+        });
+
+        // NOTE if I can override with an object a also can override with functions
+        // testing with the object is mush simpler
+
+        it('should be overwritten', () => {
+          expect(extendXosValidate.xosValidate).toEqual({site: ['notBlank']});
+        });
+
+        afterEach(() => {
+          extendXosValidate = null;
+        });
+      });
+
+      // TBT
+      // - xosValidate
+      // - Test the default
+      // - Test override
+
+    });
+  });
+
+  describe('getCookie method with no cookie', () => {
+
+    beforeEach(() => {
+      document.cookie = 'fakeCookie=true=;expires=Thu, 01 Jan 1970 00:00:01 GMT;';
+    });
+
+    it('should return null', () => {
+      let res = getCookie('fakeCookie');
+      expect(res).toBeNull();
+    });
+  });
+
+  describe('getCookie method with a fake cookie', () => {
+
+    beforeEach(() => {
+      document.cookie = 'fakeCookie=true';
+    });
+
+    it('should return a cookie value', () => {
+      let res = getCookie('fakeCookie');
+      expect(res).toEqual('true');
+    });
+  });
+});
+
+describe('The XOSModel', () => {
+
+  var model;
+
+  beforeEach(() => {
+    model = new XOSModel();
+  });
+
+  describe('url method', () => {
+    it('should set the correct url', () => {
+      const ctx = {attributes: {resource_uri: 'onlab.us'}};
+      let res = model.url.apply(ctx);
+      expect(res).toEqual('onlab.us/?no_hyperlinks=1');
+    });
+
+    it('should remove query params', () => {
+      const ctx = {attributes: {resource_uri: 'onlab.us?query=params'}};
+      let res = model.url.apply(ctx);
+      expect(res).toEqual('onlab.us/?no_hyperlinks=1');
+    });
+  });
+
+  describe('listMethods method', () => {
+
+    const instance = {
+      m1: () => {},
+      m2: () => {}
+    };
+
+    it('should list all methods in instance', () => {
+      let res = model.listMethods.apply(instance);
+      expect(res.length).toBe(2);
+      expect(res[0]).toEqual('m1');
+    });
+  });
+
+  describe('the Save method', () => {
+    const ctxPS = {
+      preSave: () => {}
+    };
+
+    const args = ['attr', 'opts'];
+
+    beforeEach(() => {
+      spyOn(ctxPS, 'preSave');
+      spyOn(Backbone.Model.prototype, 'save');
+    });
+
+    it('should call the preSave method', () => {
+      model.save.apply(ctxPS, args);
+      expect(ctxPS.preSave).toHaveBeenCalled();
+      expect(Backbone.Model.prototype.save).toHaveBeenCalledWith(args[0], args[1]);
+    });
+
+    it('should not call the preSave method', () => {
+      model.save.apply({}, args);
+      expect(ctxPS.preSave).not.toHaveBeenCalled();
+      expect(Backbone.Model.prototype.save).toHaveBeenCalledWith(args[0], args[1]);
+    });
+  });
+
+  describe('the getChoices method', () => {
+
+    const instance = {
+      m2mFields: {'flavors': 'flavors', 'sites': 'sites', 'images': 'images'}
+    };
+
+    xit('should be tested, what is this doing?', () => {
+      model.getChoices.apply(instance);
+    });
+  });
+
+  describe('the xosValidate method', () => {
+
+    const instance = {
+      validators: {'network_ports': ['portspec']}
+    };
+
+    const validAttrs = {network_ports: 'tcp 123'};
+
+    it('should call specified validator on a field and pass', () => {
+      let err = model.xosValidate.apply(instance, [validAttrs]);
+      expect(err).toBeUndefined();
+    });
+
+    // set wrong value and recall xosValidate
+    const invalidAttrs = {network_ports: 'abd 456'};
+
+    it('should call specified validator on a field and not pass', () => {
+      let err = model.xosValidate.apply(instance, [invalidAttrs]);
+      expect(err).not.toBeUndefined();
+      expect(err).toEqual({network_ports: 'must be a valid portspec (example: \'tcp 123, udp 456-789\')'});
+    });
+  });
+});
\ No newline at end of file
diff --git a/xos/core/xoslib/spec/xoslib/xos-helper.test.js b/xos/core/xoslib/spec/xoslib/xos-helper.test.js
new file mode 100644
index 0000000..7c0a506
--- /dev/null
+++ b/xos/core/xoslib/spec/xoslib/xos-helper.test.js
@@ -0,0 +1,50 @@
+/* eslint-disable no-unused-vars*/
+'use strict';
+
+describe('The Xos Helper', () => {
+  var f;
+  beforeEach(() => {
+    f = jasmine.getFixtures();
+    f.fixturesPath = 'base/spec/xoslib/fixtures/xos-utils';
+  });
+
+  describe('XOSDetailView', () => {
+
+    describe('onFormDataInvalid', () => {
+
+      // TODO understand how to attach XOSDetailView to a custom template and test its methods
+
+      const err = {name: 'must start with mysite_'};
+      var view;
+      beforeEach(() => {
+        try{
+          f.set(`
+            <script type="text/template" id="fake-template">
+              <div>
+                <input name="name" />
+              </div>
+            </script>
+          `);
+        }
+        catch(e){
+          console.log('err: ' + e);
+        }
+
+        view = XOSDetailView.extend({
+          template: '#fake-template'
+        });
+
+      });
+
+      xit('should show an error', () => {
+
+        // view.onFormDataInvalid(err);
+        // view().onFormDataInvalid(err)
+
+        expect($('.alert').length).toBe(1);
+      });
+    });
+
+  });
+
+});
\ No newline at end of file
diff --git a/xos/core/xoslib/spec/xoslib/xos-utils.test.js b/xos/core/xoslib/spec/xoslib/xos-utils.test.js
new file mode 100644
index 0000000..52de8d8
--- /dev/null
+++ b/xos/core/xoslib/spec/xoslib/xos-utils.test.js
@@ -0,0 +1,253 @@
+'use strict';
+
+describe('The XOS Lib Utilities', function(){
+
+  var f;
+
+  beforeEach(() => {
+    f = jasmine.getFixtures();
+    f.fixturesPath = 'base/spec/xoslib/fixtures/xos-utils';
+  });
+
+  describe('The idInArray method', function(){
+    it('should match a string ID', () => {
+      let res = idInArray('1', [1, 2, 3]);
+      expect(res).toBeTruthy();
+    });
+
+    it('should march a number ID', () => {
+      let res = idInArray(1, [1, 2, 3]);
+      expect(res).toBeTruthy();
+    });
+
+    it('should not match this ID', () => {
+      let res = idInArray(4, [1, 2, 3]);
+      expect(res).toBeFalsy();
+    });
+  });
+
+  describe('The templateFromId method', () => {
+
+    beforeEach(() => {
+      f.load('template_from_id.html');
+    });
+
+    it('should load a static template', () => {
+      let st = templateFromId('#static-test');
+      expect($(st()).text()).toEqual('Test Template');
+    });
+
+    it('should load a dynamic template', () => {
+      let dn = templateFromId('#dynamic-test');
+      expect($(dn({stuff: 'Template'})).text()).toEqual('Test Template');
+    });
+  });
+
+  describe('The firstCharUpper', () => {
+    it('should return the first char UPPERCASE', () => {
+      let res = firstCharUpper('test');
+      expect(res).toEqual('Test');
+    });
+  });
+
+  describe('The toTitleCase', () => {
+    it('should convert all word\'s first letter to uppercase and the other to lowercase', () => {
+      let res = toTitleCase('tesT tEst');
+      expect(res).toEqual('Test Test');
+    });
+  });
+
+  describe('The fieldNameToHumanReadable method', () => {
+    it('should convert lodash to spaces and apply toTitleCase', () => {
+      let res = fieldNameToHumanReadable('tEst_fIelD');
+      expect(res).toEqual('Test Field');
+    });
+  });
+
+  describe('The limitTableRows', () => {
+
+    beforeEach(() => {
+      f.load('table_rows.html');
+    });
+
+    it('should limit the table container height', () => {
+
+      // table border = 2, td height = 150, see fixture html
+      // resulting table height: 308
+      // .conatiner height: 308 + 2 (table border top)
+
+      limitTableRows('table.test-table', 2);
+      expect($('.container')[0]).toHaveCss({height: '310px'});
+    });
+  });
+
+  describe('The validateField', () => {
+    it('should should validate notBlank', () => {
+      let res = validateField('notBlank', null);
+      expect(res).toEqual('can not be blank');
+    });
+
+    it('should validate a url', () => {
+      let res = validateField('url', 'test a fake url');
+      expect(res).toEqual('must be a valid url');
+    });
+
+    it('should validate a port', () => {
+      let res = validateField('portspec', 'i a not a port');
+      expect(res).toEqual('must be a valid portspec (example: \'tcp 123, udp 456-789\')');
+    });
+
+    it('should return true for a valid url', () => {
+      let res = validateField('url', 'www.onlab.us');
+      expect(res).toBeTruthy();
+    });
+  });
+
+  describe('The array_diff method', () => {
+    it('should return the difference between two array', () => {
+      let res = array_diff([1,2,3], [1,2,5]);
+      expect(res).toEqual(['3', '5']); //is this right?
+      console.log('convert the array to a string, can\'t we use lodash?');
+    });
+  });
+
+  describe('The array_subtract method', () => {
+    it('should substract two arrays', () => {
+      let res = array_subtract([1,2],[1,2,3]);
+      expect(res).toEqual([1,2]);
+      console.log('[1,2] - [1,2,3] = [1,2]?');
+    });
+  });
+
+  describe('The array_same_elements method', () => {
+    it('should return true if array have same elements', () => {
+      let res = array_same_elements([1,2],[2,1]);
+      expect(res).toBeTruthy();
+    });
+
+    it('should return false if array have different elements', () => {
+      let res = array_same_elements([1,2],[2,2]);
+      expect(res).toBeFalsy();
+    });
+  });
+
+  describe('The array_pair_lookup method', () => {
+    it('should return corresponding values in other array', () => {
+      let res = array_pair_lookup('Baker', ['Scott', 'Jhon'], ['Baker', 'Snow']);
+      expect(res).toEqual('Scott');
+    });
+
+    it('should return missing value', () => {
+      let res = array_pair_lookup('Larry', ['Scott', 'Jhon'], ['Baker', 'Snow']);
+      expect(res).toEqual('object #Larry');
+    });
+  });
+
+  describe('The all_options method', () => {
+
+    beforeEach(() => {
+      f.set(`
+        <select id="test-select">
+          <option value="1">1</option>
+          <option value="2">2</option>
+          <option value="3">3/option>
+        </select>
+      `);
+    });
+
+    it('should return all options from a select', () => {
+      let res = all_options('#test-select');
+      expect(res).toEqual(['1','2','3']);
+    });
+  });
+
+  describe('The make_same_width method', () => {
+
+    beforeEach(() => {
+      f.load('make_same_width.html');
+    });
+
+    it('should set elements to same width', () => {
+      make_same_width('.container', 'div');
+      $('.container div').each(function(index, item){
+        expect($(item)).toHaveCss({width: '400px'});
+      });
+    });
+  });
+
+  describe('The strip_scripts method', () => {
+    it('should strip scripts tag', () => {
+      const mockHtml = `
+        <!DOCTYPE html>
+        <html lang="en">
+          <head>
+            <meta charset="UTF-8" />
+            <title>Test</title>
+            <script src="myScript.js"></script>
+          </head>
+          <body></body>
+        </html>
+      `;
+
+      let res = strip_scripts(mockHtml);
+      expect(res.indexOf('script')).toBe(-1);
+    });
+  });
+
+  describe('The parse_portlist method', () => {
+    it('should parse space separated ports', () => {
+      let res = parse_portlist('tcp 123, tcp 124');
+      expect(res).toEqual([{l4_protocol: 'tcp', l4_port: '123'},{l4_protocol: 'tcp', l4_port: '124'}]);
+    });
+
+    it('should parse / separated ports', () => {
+      let res = parse_portlist('tcp/123, tcp/124');
+      expect(res).toEqual([{l4_protocol: 'tcp', l4_port: '123'},{l4_protocol: 'tcp', l4_port: '124'}]);
+    });
+
+    it('should parse : joined ports', () => {
+      let res = parse_portlist('tcp 123:124');
+      expect(res).toEqual([{l4_protocol: 'tcp', l4_port: '123:124'}]);
+    });
+
+    it('should parse - joined ports', () => {
+      let res = parse_portlist('tcp 123-124');
+      expect(res).toEqual([{l4_protocol: 'tcp', l4_port: '123:124'}]);
+    });
+
+    it('should throw an error for malformed separator', () => {
+      let res = () => {
+        return parse_portlist('tcp+123, tcp+124');
+      };
+      expect(res).toThrow('malformed port specifier tcp+123, format example: "tcp 123, tcp 201:206, udp 333"');
+    });
+
+    it('should should throw if unknown protocol', () => {
+      let res = () => {
+        parse_portlist('abc 123');
+      };
+      expect(res).toThrow('unknown protocol abc');
+    });
+  });
+
+  describe('The portlist_regexp', () => {
+
+    const r = portlist_regexp();
+
+    it('should not match tcp', () => {
+      expect('tcp'.match(r)).toBeNull();
+    });
+
+    it('should match tcp 123', () => {
+      expect('tcp 123'.match(r)[0]).toEqual('tcp 123');
+    });
+
+    it('should match udp 123', () => {
+      expect('udp 123'.match(r)[0]).toEqual('udp 123');
+    });
+
+    it('should match tcp 123, upd 456', () => {
+      expect('tcp 123, udp 456'.match(r)[0]).toEqual('tcp 123, udp 456');
+    });
+  });
+});
\ No newline at end of file
diff --git a/xos/core/xoslib/spec/xoslib/xoslib.test.js b/xos/core/xoslib/spec/xoslib/xoslib.test.js
new file mode 100644
index 0000000..97d85f9
--- /dev/null
+++ b/xos/core/xoslib/spec/xoslib/xoslib.test.js
@@ -0,0 +1,48 @@
+/* eslint-disable new-cap*/
+'use strict';
+
+describe('When XOS Lib is created', () => {
+  let _slicePlus, _slice;
+
+  console.log(xos.slice, xos.slices);
+
+  beforeEach(() => {
+    _slicePlus = xos.slicesPlus;
+    _slice = xos.slices;
+
+    xos.tenantview.models.push({
+      attributes: {
+        current_user_login_base: 'test'
+      }
+    });
+  });
+
+  it('should have a slicePlus collection', () => {
+    expect(_slicePlus.modelName).toEqual('slicePlus');
+  });
+
+  it('should have a slice collection', () => {
+    // console.log(_slicePlus, '********************',_slice);
+    expect(_slice.modelName).toEqual('slice');
+  });
+
+  describe('and slicePlus model is saved', () => {
+    var _slicePlusModel;
+    beforeEach(() => {
+      _slicePlusModel = new xos.slicesPlus.model({
+        creator: 1
+      });
+    });
+
+    it('should not validate a wrong name', () => {
+      const err = _slicePlusModel.xosValidate({name: 'mysite_aaaa', description: ''});
+      expect(err).toEqual({name: 'must start with test_'});
+    });
+
+    it('should not validate a name with spaces', () => {
+      const err = _slicePlusModel.xosValidate({name: 'test_ aaaa', description: ''});
+      expect(err).toEqual({name: 'must not contain spaces'});
+    });
+  });
+
+});
\ No newline at end of file
diff --git a/xos/core/xoslib/static/css/cord.css b/xos/core/xoslib/static/css/cord.css
new file mode 100644
index 0000000..9757f5d
--- /dev/null
+++ b/xos/core/xoslib/static/css/cord.css
@@ -0,0 +1,30 @@
+.cord-subscriber-table-old td {
+    padding-top: 5px;
+}
+
+.cord-subscriber-table-old .xos-label-cell {
+    vertical-align: top;
+    font-weight: bold;
+}
+
+.cord-subscriber-box {
+    margin-right: 20px;
+}
+
+.cord-subscriber-table {
+    width: 100%;
+}
+
+.cord-subscriber-table td {
+    padding-top: 10px;
+    padding-bottom: 10px;
+    background-color: #f6f7f8;
+}
+
+.cord-subscriber-table .xos-label-cell {
+    vertical-align: top;
+    font-weight: bold;
+    border-bottom: 1px solid #ededed;
+    background-color: white;
+    width: 160px;
+}
diff --git a/xos/core/xoslib/static/css/sliceEditor.css b/xos/core/xoslib/static/css/sliceEditor.css
new file mode 100644
index 0000000..9825efc
--- /dev/null
+++ b/xos/core/xoslib/static/css/sliceEditor.css
@@ -0,0 +1,3 @@
+.sliceeditor-listitem { cursor: pointer; color: blue; }
+
+.sliceeditor-listitem:hover { font-weight: bold; }
diff --git a/xos/core/xoslib/static/css/test.css b/xos/core/xoslib/static/css/test.css
new file mode 100644
index 0000000..dee32d8
--- /dev/null
+++ b/xos/core/xoslib/static/css/test.css
@@ -0,0 +1,43 @@
+.test-table td, th {
+    border: 1px solid black;
+}
+
+#rightSide {
+    position: fixed;
+    top: 1em;
+    right: 1em;
+    width: 450px;
+}
+
+#detailBox {
+    padding: 10px;
+    border: 2px solid;
+    background-color: #f0f0f0;
+    margin-bottom:30px;
+    display:none;
+    overflow:auto;
+    max-height:80vh;
+}
+
+#errorBox {
+    padding: 10px;
+    border: 2px solid;
+    background-color: #f00000;
+    margin-bottom:30px;
+    display:none;
+}
+
+#successBox {
+    padding: 10px;
+    border: 2px solid;
+    background-color: #00f000;
+    margin-bottom:30px;
+    display:none;
+}
+
+.objectLink {
+    cursor:pointer;
+    color:blue;
+    text-decoration:underline;
+}
+
diff --git a/xos/core/xoslib/static/css/xosAdminDashboard.css b/xos/core/xoslib/static/css/xosAdminDashboard.css
new file mode 100644
index 0000000..d707ffd
--- /dev/null
+++ b/xos/core/xoslib/static/css/xosAdminDashboard.css
@@ -0,0 +1,38 @@
+.breadcrumb {
+    display: none;
+}
+
+.btn-xos-detail {
+    display: none;
+}
+
+.btn-xos-list {
+    display: none;
+}
+
+#logPanel {
+    overflow-y: auto;
+    overflow-x: hidden;
+}
+
+#logTable {
+    width: 100%;
+    white-space: nowrap;
+}
+
+#logTable tr {
+  border-bottom: 1px solid;
+}
+
+#logTable tr:last-child {
+  border-bottom: none;

+}
+
+#contentButtonPanel {
+    float: right;
+    width: 200px;
+}
+
+#contentInner {
+    margin-right: 200px;
+}
diff --git a/xos/core/xoslib/static/css/xosAdminSite.css b/xos/core/xoslib/static/css/xosAdminSite.css
new file mode 100644
index 0000000..dc463e7
--- /dev/null
+++ b/xos/core/xoslib/static/css/xosAdminSite.css
@@ -0,0 +1,128 @@
+.xos-help-cell {
+    font-size: 11px;
+    color: #999;
+    padding-bottom: 1%;
+}
+
+.xos-detail-table td {
+    padding-left: 10px;
+    padding-right: 10px;
+}
+
+.test-table td, th {
+    border: 1px solid black;
+}
+.objectLink {
+    cursor:pointer;
+    color:blue;
+    text-decoration:underline;
+}
+
+.xos-log.xos-success {
+    background-color: #00ff00;
+}
+
+.xos-log.xos-inprog {
+    background-color: #ffff00;
+}
+
+.xos-log.xos-failure {
+    background-color: #ff0000;
+}
+
+.btn-xosnav {
+    width: 120px;
+}
+
+.xos-nav-list {
+    list-style:none;
+    border-bottom-style: solid;
+    border-bottom-color: #105E9E;
+    color: #105E93;
+    margin: 0px 4px 15px 5px;
+}
+
+.xos-nav-item {
+    background-color: #E0E0E0;
+    border-top-left-radius: 3px;
+    border-top-right-radius: 3px;
+    border-bottom-left-radius: 0px;
+    border-bottom-right-radius: 0px;
+
+    display: inline-block;
+    content: normal;
+    clear: none;
+
+    padding:8px 20px 7px;
+
+    font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
+    font-size: 13px;
+    font-weight: bold;
+    color: #105E9E;
+    border: none;
+    box-shadow: none;
+    cursor: pointer;
+}
+
+.xos-nav-item:hover {
+    background-color: #A0A0A0;
+    letter-spacing: 1px;
+}
+
+.xos-nav-item.active  {
+    background-color: #105E9E;
+    color:#ffffff;
+    font-weight:normal;
+    padding-top:10px;
+    text-decoration:none;
+}
+
+.help-inline.error {
+    color: red;
+    font-weight: bold;
+}
+
+/* these are for the inline list and detail titles */
+
+.xos-list-title {
+    display: none;
+}
+
+.xos-detail-title {
+    display: none;
+}
+
+/* this one goes with contenttitle */
+
+#xos-list-title-spinner {
+    display: none;
+}
+
+/* undo what xos.css does to the progressbar */
+#xos-startup-progress .ui-progressbar-value {
+    background-color: rgb(204,204,204) !important;
+    background-image: url(http://code.jquery.com/ui/1.11.2/themes/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png) !important;
+    border-top: 1px !important;
+    border-right: 1px !important;
+    border-left: 1px !important;
+}
+
+#xos-detail-button-box {
+    display: none;
+}
+
+#xos-listview-button-box {
+    display: none;
+}
+
+#xos-confirm-dialog {
+    display: none;
+}
+
+.picker_row {
+  display: table;
+}
+.picker_column {
+  display: table-cell;
+  padding: 10px;
+}
diff --git a/xos/core/xoslib/static/css/xosAdminWholePage.css b/xos/core/xoslib/static/css/xosAdminWholePage.css
new file mode 100644
index 0000000..a280fac
--- /dev/null
+++ b/xos/core/xoslib/static/css/xosAdminWholePage.css
@@ -0,0 +1,110 @@
+.test-table td, th {
+    border: 1px solid black;
+}
+.objectLink {
+    cursor:pointer;
+    color:blue;
+    text-decoration:underline;
+}
+#logTable td, th {
+    border: 1px solid black;
+}
+
+#navigationPanel {
+  position: absolute;
+  top: 100px;
+  left: 0;
+  width: 220px;
+  bottom: 0;
+  overflow: hidden;
+  //background-color: #F0F0F0;
+}
+
+#headerPanel {
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  width: auto;
+  height: 100px;
+  overflow: hidden;
+  //background-color: #F0E0E0;
+}
+
+#logPanel {
+  position: absolute;
+  top: auto;
+  left: 220px;
+  right: 0;
+  bottom: 0;
+  width: auto;
+  height: 100px;
+  overflow: hidden;
+  //background-color: #F0E0E0;
+}
+
+#contentPanel {
+    position: fixed;
+    top: 100px;
+    bottom: 100px;
+    left: 220px;
+    right: 0;
+    overflow: auto;
+    //background: #f0F0E0;
+}
+
+.btn-xosnav {
+    width: 120px;
+}
+
+.xos-nav-list {
+    list-style:none;
+    border-bottom-style: solid;
+    border-bottom-color: #105E9E;
+    color: #105E93;
+    margin: 0px 4px 15px 5px;
+}
+
+.xos-nav-item {
+    background-color: #E0E0E0;
+    border-top-left-radius: 3px;
+    border-top-right-radius: 3px;
+    border-bottom-left-radius: 0px;
+    border-bottom-right-radius: 0px;
+
+    display: inline-block;
+    content: normal;
+    clear: none;
+
+    padding:8px 20px 7px;
+
+    font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
+    font-size: 13px;
+    font-weight: bold;
+    color: #105E9E;
+    border: none;
+    box-shadow: none;
+    cursor: pointer;
+}
+
+.xos-nav-item:hover {
+    background-color: #A0A0A0;
+    letter-spacing: 1px;
+}
+
+.xos-nav-item.active  {
+    background-color: #105E9E;
+    color:#ffffff;
+    font-weight:normal;
+    padding-top:10px;
+    text-decoration:none;
+}
+
+.xos-list-title {
+    display: none;
+}
+
+.xos-detail-title {
+    display: none;
+}
+
diff --git a/xos/core/xoslib/static/css/xosCeilometerDashboard.css b/xos/core/xoslib/static/css/xosCeilometerDashboard.css
new file mode 100644
index 0000000..5242fda
--- /dev/null
+++ b/xos/core/xoslib/static/css/xosCeilometerDashboard.css
@@ -0,0 +1 @@
+#xosCeilometerDashboard{position:relative}.panel{margin-top:10px}.panel-body:not(:first-child){border-top:1px solid #e3e3e3}.panel-body .row{margin-top:10px}.chart{width:100%;height:300px}.btn-chart,.btn-chart:hover{color:#fff}.side-container{position:relative}.service-list{margin-top:-10px}.service-list h3{margin-top:0;margin-bottom:0}.service-list a{text-decoration:none;color:#333}.meters,.stats{margin-top:25px;position:absolute;top:0;left:0;width:100%;margin-bottom:50px}.loader{font-size:10px;margin:150px auto;text-indent:-9999em;width:11em;height:11em;border-radius:50%;background:#fff;background:linear-gradient(to right,#fff 10%,rgba(255,255,255,0) 42%);position:relative;animation:load3 1.4s infinite linear;transform:translateZ(0)}.loader:before{width:50%;height:50%;background:#105e9e;border-radius:100% 0 0;position:absolute;top:0;left:0;content:''}.loader:after{background:#fff;width:75%;height:75%;border-radius:50%;content:'';margin:auto;position:absolute;top:0;left:0;bottom:0;right:0}@keyframes load3{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}[ui-view]{position:absolute;top:0;left:0;width:100%;margin-bottom:100px}[ui-view].ceilometerDashboard.ng-leave{animation:1s bounceOutLeft ease}[ui-view].samples.ng-enter{animation:1s bounceInRight ease}[ui-view].samples.ng-leave{animation:1s bounceOutRight ease}[ui-view].ceilometerDashboard.ng-enter{animation:1s bounceInLeft ease}.animate .animate-slide-left.ng-hide-remove{animation:.5s bounceInRight ease}.animate .animate-slide-left.ng-hide-add{animation:.5s bounceOutRight ease}@keyframes bounceInRight{from,60%,75%,90%,to{animation-timing-function:cubic-bezier(.215,.61,.355,1.000)}from{opacity:0;transform:translate3d(3000px,0,0)}60%{opacity:1;transform:translate3d(-25px,0,0)}75%{transform:translate3d(10px,0,0)}90%{transform:translate3d(-5px,0,0)}to{transform:none}}@keyframes bounceInLeft{from,60%,75%,90%,to{animation-timing-function:cubic-bezier(.215,.61,.355,1.000)}0%{opacity:0;transform:translate3d(-3000px,0,0)}60%{opacity:1;transform:translate3d(25px,0,0)}75%{transform:translate3d(-10px,0,0)}90%{transform:translate3d(5px,0,0)}to{transform:none}}@keyframes slideInUp{from{transform:translate3d(0,100%,0);visibility:visible}to{transform:translate3d(0,0,0)}}@keyframes bounceOutRight{20%{opacity:1;transform:translate3d(-20px,0,0)}to{opacity:0;transform:translate3d(2000px,0,0)}}@keyframes bounceOutLeft{20%{opacity:1;transform:translate3d(20px,0,0)}to{opacity:0;transform:translate3d(-2000px,0,0)}}@keyframes slideOutDown{from{transform:translate3d(0,0,0)}to{visibility:hidden;transform:translate3d(0,100%,0)}}
diff --git a/xos/core/xoslib/static/css/xosContentProvider.css b/xos/core/xoslib/static/css/xosContentProvider.css
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xos/core/xoslib/static/css/xosContentProvider.css
diff --git a/xos/core/xoslib/static/css/xosDeveloper.css b/xos/core/xoslib/static/css/xosDeveloper.css
new file mode 100644
index 0000000..dee3249
--- /dev/null
+++ b/xos/core/xoslib/static/css/xosDeveloper.css
@@ -0,0 +1 @@
+#xosDeveloper .pie-legend li{display:inline-block;white-space:nowrap;position:relative;margin-bottom:4px;border-radius:5px;padding:2px 8px 2px 28px;font-size:smaller;cursor:default}#xosDeveloper .pie-legend-icon{display:block;position:absolute;left:0;top:0;width:20px;height:20px;border-radius:5px}
\ No newline at end of file
diff --git a/xos/core/xoslib/static/css/xosDiagnostic.css b/xos/core/xoslib/static/css/xosDiagnostic.css
new file mode 100644
index 0000000..f96d289
--- /dev/null
+++ b/xos/core/xoslib/static/css/xosDiagnostic.css
@@ -0,0 +1 @@
+#xosDiagnostic,[ui-view]{min-height:700px;position:relative}diagnostic-container .form-control.small-padding{padding:6px}diagnostic-container .half-height{position:relative;height:50%}diagnostic-container .onethird-height{position:relative;height:33%;border-bottom:1px solid #999}diagnostic-container .twothird-height{position:relative;height:67%}diagnostic-container .subscriber-select{max-width:200px;position:absolute;top:20px;right:20px;z-index:1}diagnostic-container .onethird-height .well,diagnostic-container .twothird-height .well{font-weight:700;max-width:165px;text-align:center;margin-top:15px;background:#eee;border-color:steelblue;padding:10px}diagnostic-container .onethird-height .well.pull-right{position:absolute;right:0;top:-15px;cursor:pointer;z-index:200}subscriber-status-modal .row+.row{margin-top:20px}.half-height+.half-height{border-top:1px solid black}service-topology,logic-topology{height:100%;width:100%;display:block;position:absolute;top:0}logic-topology .subscriber circle,logic-topology .device circle{fill:#fff;stroke:green;stroke-width:1px}logic-topology>svg{position:absolute;top:0}logic-topology .network .cloud{fill:#fff;stroke:green;stroke-width:1px}logic-topology .node.rack>g>rect{fill:#ccc;stroke:steelblue;stroke-width:1px}logic-topology .compute-node>rect{fill:#fff;stroke:steelblue;stroke-width:1px}logic-topology .compute-node>text{font-size:16px}logic-topology .instance>rect{fill:#eee;stroke:steelblue;stroke-width:1px}logic-topology .node .instance.active rect{fill:lightsteelblue;stroke:steelblue;stroke-width:1px}logic-topology .node .instance.active.good>rect{fill:green}logic-topology .node .instance.active.provisioning>rect{fill:yellow}logic-topology .node .instance.active.bad>rect{fill:red}logic-topology .node .instance .stats-container rect{fill:white}logic-topology .node .instance .stats-container text.name{font-weight:700}logic-topology .node .instance .stats-container text.ip{font-style:italic;font-size:10px}logic-topology .node .instance .stats-container .container rect{fill:#eee;stroke:steelblue;stroke-width:1px}.legend{fill:#fff;stroke:#ccc;stroke-width:1px;position:relative}.legend text{stroke:#000}.node{cursor:pointer}.node circle,.node rect{fill:#fff;stroke:steelblue;stroke-width:1px}.node.subscriber circle,.node.subscriber rect,.node.router circle,.node.router rect{stroke:#05ffcb}.node.slice rect{stroke:#b01dff}.node.instance rect{stroke:#ccc}.node.instance rect.active{stroke:#ff8b00}.node rect.slice-detail{fill:#fff;stroke:steelblue;stroke-width:3px}.node text{font:18px sans-serif}.node .instance text{font:12px sans-serif}.node text.small{font-size:10px}.link,.device-link{fill:none;stroke:#ccc;stroke-width:2px}.link.slice{stroke:rgba(157,4,183,.29)}.link.instance{stroke:#ccc}.link.instance.active{stroke:rgba(255,138,0,.65)}.service-details{width:200px;position:absolute;top:20px;right:20px}.animate.ng-hide-remove{animation:.5s bounceInRight ease}.animate.ng-hide-add{animation:.5s bounceOutRight ease}.loader{font-size:10px;margin:150px auto;text-indent:-9999em;width:11em;height:11em;border-radius:50%;background:#fff;background:linear-gradient(to right,#fff 10%,rgba(255,255,255,0) 42%);position:relative;animation:load3 1.4s infinite linear;transform:translateZ(0)}.loader:before{width:50%;height:50%;background:#105e9e;border-radius:100% 0 0;position:absolute;top:0;left:0;content:''}.loader:after{background:#fff;width:75%;height:75%;border-radius:50%;content:'';margin:auto;position:absolute;top:0;left:0;bottom:0;right:0}@keyframes load3{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}.modal.fade.in{display:block}@keyframes bounceInRight{from,60%,75%,90%,to{animation-timing-function:cubic-bezier(.215,.61,.355,1)}from{opacity:0;transform:translate3d(3000px,0,0)}60%{opacity:1;transform:translate3d(-25px,0,0)}75%{transform:translate3d(10px,0,0)}90%{transform:translate3d(-5px,0,0)}to{transform:none}}@keyframes bounceOutRight{20%{opacity:1;transform:translate3d(-20px,0,0)}to{opacity:0;transform:translate3d(2000px,0,0)}}
diff --git a/xos/core/xoslib/static/css/xosHpc.css b/xos/core/xoslib/static/css/xosHpc.css
new file mode 100644
index 0000000..e9458ad
--- /dev/null
+++ b/xos/core/xoslib/static/css/xosHpc.css
@@ -0,0 +1 @@
+#xosHpc .btn.btn-reload{margin-top:20px}
\ No newline at end of file
diff --git a/xos/core/xoslib/static/css/xosLib.css b/xos/core/xoslib/static/css/xosLib.css
new file mode 100644
index 0000000..d2f9349
--- /dev/null
+++ b/xos/core/xoslib/static/css/xosLib.css
@@ -0,0 +1,13 @@
+/* Style helpers for xoslib*/
+
+
+/* gives an element the same spacing as it is inside a well*/
+.margin-wells {
+  margin: 12px;
+}
+
+/* if inside a form set margin-top to align with inputs instead of labels*/
+/* TODO once scss use a form like form [class^=span] > label + &[class^=span] > .margin-wells to match only if label is set*/
+form button.margin-wells {
+  margin-top: 20px;
+}
\ No newline at end of file
diff --git a/xos/core/xoslib/static/css/xosMcordTopology.css b/xos/core/xoslib/static/css/xosMcordTopology.css
new file mode 100644
index 0000000..fe0343c
--- /dev/null
+++ b/xos/core/xoslib/static/css/xosMcordTopology.css
@@ -0,0 +1,2 @@
+
+#xosMcordTopology{height:700px}[ui-view],m-cord-topology{width:100%;height:100%;display:block}line{stroke:blue}line.big{stroke-width:2}circle,rect{fill:#fff;stroke-width:1}.fabric{stroke:none;fill:#123456;fill-rule:evenodd}.fabric-container{fill:transparent;stroke:#000;stroke-width:1}.bbu{stroke:black;fill:#ff7f0e}.rru{stroke:#000;fill:#ffbb78}.rru.antenna{stroke:#000;fill:brown}.rru-shadow{fill:#ffbb78;opacity:.4}.MME,.SGW,.PGW,.Vid{fill:purple;stroke:#000}rect.MME,rect.SGW,rect.PGW,rect.bbu,rect.Vid{fill:#fff;stroke:#fff}.bbu text,.MME text,.SGW text,.PGW text,.Vid text{font-size:10px;stroke-width:0;fill:#000}
\ No newline at end of file
diff --git a/xos/core/xoslib/static/css/xosOpenVPNDashboard.css b/xos/core/xoslib/static/css/xosOpenVPNDashboard.css
new file mode 100644
index 0000000..022e50e
--- /dev/null
+++ b/xos/core/xoslib/static/css/xosOpenVPNDashboard.css
@@ -0,0 +1 @@
+#xosOpenVPNDashboard{width:70%;margin:auto}#xosOpenVPNDashboard .vpn-row{display:table-row}#xosOpenVPNDashboard .vpn-cell{display:table-cell;padding:5px}#xosOpenVPNDashboard .vpn-header{font-weight:700}
\ No newline at end of file
diff --git a/xos/core/xoslib/static/css/xosSampleView.css b/xos/core/xoslib/static/css/xosSampleView.css
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xos/core/xoslib/static/css/xosSampleView.css
diff --git a/xos/core/xoslib/static/css/xosServiceGrid.css b/xos/core/xoslib/static/css/xosServiceGrid.css
new file mode 100644
index 0000000..c722065
--- /dev/null
+++ b/xos/core/xoslib/static/css/xosServiceGrid.css
@@ -0,0 +1 @@
+#xosServiceGrid service-graph{display:block;width:100%;height:600px}#xosServiceGrid .node{stroke:#337ab7;fill:white}#xosServiceGrid .node.xos{fill:#d9534f}#xosServiceGrid .link{stroke:black;stroke-width:2px}
\ No newline at end of file
diff --git a/xos/core/xoslib/static/css/xosSubscribers.css b/xos/core/xoslib/static/css/xosSubscribers.css
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xos/core/xoslib/static/css/xosSubscribers.css
diff --git a/xos/core/xoslib/static/css/xosSynchronizerNotifier.css b/xos/core/xoslib/static/css/xosSynchronizerNotifier.css
new file mode 100644
index 0000000..89374fb
--- /dev/null
+++ b/xos/core/xoslib/static/css/xosSynchronizerNotifier.css
@@ -0,0 +1 @@
+#xosSynchronizerNotifier{float:left}#xosSynchronizerNotifier .alert{margin-bottom:0!important}#xosSynchronizerNotifier .sync-status-container{position:relative;z-index:200}#xosSynchronizerNotifier .notification-panel{position:absolute;width:200px}#xosSynchronizerNotifier sync-status .badge.success{background-color:#5cb85c}#xosSynchronizerNotifier sync-status .badge.warning{background-color:#f0ad4e}
\ No newline at end of file
diff --git a/xos/core/xoslib/static/css/xosTenant.css b/xos/core/xoslib/static/css/xosTenant.css
new file mode 100644
index 0000000..1675325
--- /dev/null
+++ b/xos/core/xoslib/static/css/xosTenant.css
@@ -0,0 +1 @@
+#xosTenant a{margin-bottom:15px}
\ No newline at end of file
diff --git a/xos/core/xoslib/static/css/xosTenantDashboard.css b/xos/core/xoslib/static/css/xosTenantDashboard.css
new file mode 100644
index 0000000..c574ad6
--- /dev/null
+++ b/xos/core/xoslib/static/css/xosTenantDashboard.css
@@ -0,0 +1,34 @@
+.btn-xos-detail {
+    display: none;
+}
+
+.btn-xos-list {
+    display: none;
+}
+
+#logPanel {
+    overflow-y: auto;
+    overflow-x: hidden;
+}
+
+#logTable {
+    width: 100%;
+    white-space: nowrap;
+}
+
+#logTable tr {
+  border-bottom: 1px solid;
+}
+
+#logTable tr:last-child {
+  border-bottom: none;
+}
+
+#contentButtonPanel {
+    float: right;
+    width: 200px;
+}
+
+/*#contentInner {
+    margin-right: 200px;
+}*/
diff --git a/xos/core/xoslib/static/css/xosTruckroll.css b/xos/core/xoslib/static/css/xosTruckroll.css
new file mode 100644
index 0000000..3d1fd2f
--- /dev/null
+++ b/xos/core/xoslib/static/css/xosTruckroll.css
@@ -0,0 +1,2 @@
+
+.row+.row{margin-top:20px}.animate-vertical.ng-hide-add{animation:.5s slideOutDown ease-in-out}.animate-vertical.ng-hide-remove{animation:.5s slideInUp ease-in-out}@keyframes slideInUp{from{transform:translate3d(0,100%,0);opacity:0}to{transform:translate3d(0,0,0);opacity:1}}@keyframes slideOutDown{from{transform:translate3d(0,0,0);opacity:1}to{opacity:0;transform:translate3d(0,100%,0)}}.loader{font-size:10px;margin:0 auto;text-indent:-9999em;width:11em;height:11em;border-radius:50%;background:#fff;background:linear-gradient(to right,#fff 10%,rgba(255,255,255,0) 42%);position:relative;animation:load3 1.4s infinite linear;transform:translateZ(0)}.loader:before{width:50%;height:50%;background:#105e9e;border-radius:100% 0 0;position:absolute;top:0;left:0;content:''}.loader:after{background:#fff;width:75%;height:75%;border-radius:50%;content:'';margin:auto;position:absolute;top:0;left:0;bottom:0;right:0}@keyframes load3{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}
\ No newline at end of file
diff --git a/xos/core/xoslib/static/js/.eslintrc b/xos/core/xoslib/static/js/.eslintrc
new file mode 100644
index 0000000..7cbab96
--- /dev/null
+++ b/xos/core/xoslib/static/js/.eslintrc
@@ -0,0 +1,28 @@
+{
+  "extends": "defaults/configurations/google",
+  "env" : {
+    "browser": true
+  },
+  "rules" : {
+    "camelcase": [0],
+    "no-underscore-dangle": [0],
+    "eqeqeq": [1],
+    "no-alert": [1],
+    "no-unused-vars": [1],
+    "key-spacing": [2, {
+        "beforeColon": false,
+        "afterColon": true
+    }],
+    "valid-jsdoc": 2,
+    "max-len": [1, 120, 4],
+    brace-style: [2, "stroustrup"],
+    space-before-blocks: [1, 'never']
+  },
+  "globals": {
+    "$": false,
+    "_": false,
+    "Backbone": false,
+    "Marionette": false,
+    "xos": false
+  }
+}
diff --git a/xos/core/xoslib/static/js/gentle.js b/xos/core/xoslib/static/js/gentle.js
new file mode 100644
index 0000000..a0d8dde
--- /dev/null
+++ b/xos/core/xoslib/static/js/gentle.js
@@ -0,0 +1,50 @@
+
+var ContactManager = new Marionette.Application();
+
+ContactManager.addRegions({
+  mainRegion: '#main-region'
+});
+
+ContactManager.Contact = Backbone.Model.extend({});
+
+ContactManager.ContactCollection = Backbone.Collection.extend({
+  model: ContactManager.Contact
+});
+
+ContactManager.ContactItemView = Marionette.ItemView.extend({
+  tagName: 'li',
+  template: '#contact-list-item'
+});
+
+ContactManager.ContactsView = Marionette.CollectionView.extend({
+  tagName: 'ul',
+  childView: ContactManager.ContactItemView
+});
+
+ContactManager.on('start', function(){
+  var contacts = new ContactManager.ContactCollection([
+    {
+      firstName: 'Bob',
+      lastName: 'Brigham',
+      phoneNumber: '555-0163'
+    },
+    {
+      firstName: 'Alice',
+      lastName: 'Arten',
+      phoneNumber: '555-0184'
+    },
+    {
+      firstName: 'Charlie',
+      lastName: 'Campbell',
+      phoneNumber: '555-0129'
+    }
+  ]);
+
+  var contactsView = new ContactManager.ContactsView({
+    collection: contacts
+  });
+
+  ContactManager.mainRegion.show(contactsView);
+});
+
+ContactManager.start();
diff --git a/xos/core/xoslib/static/js/picker.js b/xos/core/xoslib/static/js/picker.js
new file mode 100644
index 0000000..3303197
--- /dev/null
+++ b/xos/core/xoslib/static/js/picker.js
@@ -0,0 +1,61 @@
+/* eslint-disable space-before-blocks, no-unused-vars */

+

+function init_picker(selector, ordered) {

+  //console.log("init_picker");

+  //console.log($(selector));

+

+  var addBtn = $(selector).find('.btn-picker-add');

+  var removeBtn = $(selector).find('.btn-picker-remove');

+  var upBtn = $(selector).find('.btn-picker-up');

+  var downBtn = $(selector).find('.btn-picker-down');

+  var from = $(selector).find('.select-picker-from');

+  var to = $(selector).find('.select-picker-to');

+

+  if (!ordered) {

+    upBtn.hide();

+    downBtn.hide();

+  }

+

+  addBtn.click(function() {

+    from.find(':selected').each(function() {

+      to.append('<option value="' + $(this).val() + '"">' + $(this).text() + '</option>');

+      $(this).remove();

+    });

+  });

+  removeBtn.click(function() {

+    to.find(':selected').each(function() {

+      from.append('<option value="' + $(this).val() + '">' + $(this).text() + '</option>');

+      $(this).remove();

+    });

+  });

+  upBtn.bind('click', function() {

+    to.find(':selected').each(function() {

+      var newPos = to.find('option').index(this) - 1;

+

+      if (newPos > -1) {

+        to.find('option').eq(newPos).before(

+          '<option value="' + $(this).val() + '" selected="selected">' + $(this).text() + '</option>'

+        );

+        $(this).remove();

+      }

+    });

+  });

+  downBtn.bind('click', function() {

+    var countOptions = to.find('option').size();

+

+    to.find(':selected').each(function() {

+      var newPos = to.find('option').index(this) + 1;

+

+      if (newPos < countOptions) {

+        to.find('option').eq(newPos).after(

+          '<option value="' + $(this).val() + '" selected="selected">' + $(this).text() + '</option>'

+        );

+        $(this).remove();

+      }

+    });

+  });

+};

+

+function init_spinner(selector, value) {

+  $(selector).spinner('value', value);

+};

diff --git a/xos/core/xoslib/static/js/sliceEditor.js b/xos/core/xoslib/static/js/sliceEditor.js
new file mode 100644
index 0000000..12ed86f
--- /dev/null
+++ b/xos/core/xoslib/static/js/sliceEditor.js
@@ -0,0 +1,111 @@
+/* eslint-disable */

+/* This is a demo of using xoslib with Marionette

+

+   The main window is split into two halves. The left half has a CollectionView

+   (SliceListView) that lists all slices the user has access to. The right half

+   has an ItemView (SliceDetailView) that allows the user to edit the

+   name and description of a slice, as well as a <Save> button to save it.

+*/

+

+SliceEditorApp = new Marionette.Application();

+

+SliceEditorApp.addRegions({

+  sliceList: "#sliceEditorList",

+  sliceDetail: "#sliceEditorDetail",

+});

+

+/* SliceListItemView: This is the item view that is used by SliceListView to

+   display slice names.

+*/

+

+SliceEditorApp.SliceListItemView = Marionette.ItemView.extend({

+  template: "#sliceeditor-listitem-template",

+  tagName: 'li',

+  className: 'sliceeditor-listitem',

+

+  events: {"click": "changeSlice"},

+

+  changeSlice: function(e) {

+        e.preventDefault();

+        e.stopPropagation();

+

+        if (SliceEditorApp.sliceDetail.currentView && SliceEditorApp.sliceDetail.currentView.dirty) {

+            if (!confirm("discard current changes?")) {

+                return;

+            }

+        }

+

+        /* create a new SliceDetailView and set the sliceDetail region to

+           display it.

+        */

+

+        var sliceDetailView = new SliceEditorApp.SliceDetailView({

+            model: this.model,

+        });

+        SliceEditorApp.sliceDetail.show(sliceDetailView);

+  },

+});

+

+/* SliceListView: This displays a list of slice names.

+*/

+

+SliceEditorApp.SliceListView = Marionette.CollectionView.extend({

+  tagName: "ul",

+  childView: SliceEditorApp.SliceListItemView,

+

+  initialize: function() {

+      /* CollectionViews don't automatically listen for change events, but we

+         want to, so we pick up changes from the DetailView, and we pick up

+         changes from the server.

+      */

+      this.listenTo(this.collection, 'change', this._renderChildren);

+  },

+

+  attachHtml: function(compositeView, childView, index) {

+      // The REST API will let admin users see everything. For the developer

+      // view we still want to hide slices we are not members of.

+      if (childView.model.get("sliceInfo").roles.length == 0) {

+          return;

+      }

+      SliceEditorApp.SliceListView.__super__.attachHtml(compositeView, childView, index);

+  },

+});

+

+/* SliceDetailView: Display the slice and allow it to be edited */

+

+SliceEditorApp.SliceDetailView = Marionette.ItemView.extend({

+    template: "#sliceeditor-sliceedit-template",

+    tagName: 'div',

+

+    events: {"click button.js-submit": "submitClicked",

+             "change input": "inputChanged"},

+

+    /* inputChanged is watching the onChange events of the input controls. We

+       do this to track when this view is 'dirty', so we can throw up a warning

+       if the user tries to change his slices without saving first.

+    */

+

+    inputChanged: function(e) {

+        this.dirty = true;

+    },

+

+    submitClicked: function(e) {

+        e.preventDefault();

+        var data = Backbone.Syphon.serialize(this);

+        this.model.save(data);

+        this.dirty = false;

+    },

+});

+

+SliceEditorApp.on("start", function() {

+  var sliceListView = new SliceEditorApp.SliceListView({

+    collection: xos.slicesPlus

+  });

+  SliceEditorApp.sliceList.show(sliceListView);

+  xos.slicesPlus.startPolling();

+});

+

+$(document).ready(function(){

+  SliceEditorApp.start();

+});

+/* eslint-enable */

diff --git a/xos/core/xoslib/static/js/sliverListTest.js b/xos/core/xoslib/static/js/sliverListTest.js
new file mode 100644
index 0000000..4b60697
--- /dev/null
+++ b/xos/core/xoslib/static/js/sliverListTest.js
@@ -0,0 +1,148 @@
+/* eslint-disable */
+(function(){
+
+window.InstanceView = Backbone.View.extend({
+    tagName: 'li',
+    className: 'instance',
+
+    events: {
+        'click .permalink': 'navigate'
+    },
+
+    initialize: function(){
+        this.model.bind('change', this.render, this);
+    },
+
+    navigate: function(e){
+        this.trigger('navigate', this.model);
+        e.preventDefault();
+    },
+
+    render: function(){
+        $(this.el).html(ich.instanceTemplate(this.model.toJSON()));
+        return this;
+    }
+});
+
+
+window.DetailApp = Backbone.View.extend({
+    events: {
+        'click .home': 'home'
+    },
+
+    home: function(e){
+        this.trigger('home');
+        e.preventDefault();
+    },
+
+    render: function(){
+        $(this.el).html(ich.detailApp(this.model.toJSON()));
+        return this;
+    }
+});
+
+window.ListView = Backbone.View.extend({
+    initialize: function(){
+        _.bindAll(this, 'addOne', 'addAll');
+
+        this.collection.bind('add', this.addOne);
+        this.collection.bind('reset', this.addAll, this);
+        this.views = [];
+    },
+
+    addAll: function(){
+        this.views = [];
+        this.collection.each(this.addOne);
+    },
+
+    addOne: function(instance){
+        var view = new InstanceView({
+            model: instance
+        });
+        $(this.el).prepend(view.render().el);
+        this.views.push(view);
+        view.bind('all', this.rethrow, this);
+    },
+
+    rethrow: function(){
+        this.trigger.apply(this, arguments);
+    }
+
+});
+
+window.ListApp = Backbone.View.extend({
+    el: "#app",
+
+    rethrow: function(){
+        this.trigger.apply(this, arguments);
+    },
+
+    render: function(){
+        console.log("listApp.render");
+        console.log(this.collection);
+        $(this.el).html(ich.listApp({}));
+        var list = new ListView({
+            collection: this.collection,
+            el: this.$('#instances')
+        });
+        list.addAll();
+        list.bind('all', this.rethrow, this);
+    }
+});
+
+
+window.Router = Backbone.Router.extend({
+    routes: {
+        '': 'list',
+        ':id/': 'detail'
+    },
+
+    navigate_to: function(model){
+        var path = (model && model.get('id') + '/') || '';
+        console.log("Router.navigate_to");
+        this.navigate(path, true);
+    },
+
+    detail: function(){ console.log("Router.detail"); },
+
+    list: function(){ console.log("Router.list"); }
+});
+
+$(function(){
+    window.app = window.app || {};
+    app.router = new Router();
+    app.instances = xos.instances; //new XOSLib.instances();
+    app.list = new ListApp({
+        el: $("#app"),
+        collection: app.instances
+    });
+    app.detail = new DetailApp({
+        el: $("#app")
+    });
+    app.router.bind('route:list', function(){
+        app.instances.maybeFetch({
+            success: _.bind(app.list.render, app.list)
+        });
+    });
+    app.router.bind('route:detail', function(id){
+        app.instances.getOrFetch(app.instances.urlRoot + id + '/', {
+            success: function(model){
+                app.detail.model = model;
+                app.detail.render();
+            }
+        });
+    });
+
+    app.instances.maybeFetch({
+        success: _.bind(app.list.render, app.list)
+    });
+
+    app.list.bind('navigate', app.router.navigate_to, app.router);
+    app.detail.bind('home', app.router.navigate_to, app.router);
+    Backbone.history.start({
+        pushState: true,
+        silent: app.loaded
+    });
+});
+})();
+/* eslint-enable */
diff --git a/xos/core/xoslib/static/js/test.js b/xos/core/xoslib/static/js/test.js
new file mode 100644
index 0000000..9135134
--- /dev/null
+++ b/xos/core/xoslib/static/js/test.js
@@ -0,0 +1,85 @@
+/* eslint-disable */
+TestApp = new XOSApplication();
+
+TestApp.addRegions({
+    deploymentList: "#deploymentList",
+    imageList: "#imageList",
+    networkTemplateList: "#networkTemplateList",
+    networkList: "#networkList",
+    nodeList: "#nodeList",
+    serviceList: "#serviceList",
+    siteList: "#siteList",
+    sliceList: "#sliceList",
+    instanceList: "#instanceList",
+    userList: "#userList",
+    detail: "#detail",
+    linkedObjs1: "#linkedObjs1",
+    linkedObjs2: "#linkedObjs2",
+    linkedObjs3: "#linkedObjs3",
+    linkedObjs4: "#linkedObjs4"
+});
+
+//TestApp.navigateToDetail = function(detailView) {
+//     $(TestApp.detailBoxId).show();
+//     TestApp.detail.show(detailView);
+//};
+
+TestApp.navigateToModel = function(app, detailClass, detailNavLink, model) {
+
+    var detailView = new detailClass({
+        model: model,
+    });
+
+    $(app.detailBoxId).show();
+    app.detail.show(detailView);
+    detailView.showLinkedItems();
+};
+
+TestApp.on("start", function() {
+     var objs = ['deployment', 'image', 'networkTemplate', 'network', 'port', 'networkDeployment', 'node', 'service', 'site', 'slice', 'sliceDeployment', 'slicePrivilege', 'instance', 'user', 'sliceRole', 'userDeployment'];
+
+     for (var index in objs) {
+         name = objs[index];
+         tr_template = '#xosAdmin-' + name + '-listitem-template';
+         table_template = '#xosAdmin-' + name + '-list-template';
+         detail_template = '#xosAdmin-' + name + '-detail-template';
+         collection_name = name + "s";
+         region_name = name + "List";
+
+         detailClass = XOSDetailView.extend({
+            template: detail_template,
+            app: TestApp,
+         });
+
+         itemViewClass = XOSItemView.extend({
+             detailClass: detailClass,
+             template: tr_template,
+             app: TestApp,
+         });
+
+         listViewClass = XOSListView.extend({
+             childView: itemViewClass,
+             template: table_template,
+             collection: xos[collection_name],
+             title: name + "s",
+             app: TestApp,
+         });
+         TestApp[collection_name + "ListView"] = listViewClass;
+
+         var listView = new listViewClass();
+
+         if (region_name in TestApp.getRegions()) {
+             TestApp[region_name].show(listView);
+         }
+         xos[collection_name].fetch(); //startPolling();
+     }
+
+     $('#close-detail-view').unbind().bind('click', function() {
+         $('#detailBox').hide();
+     });
+});
+
+$(document).ready(function(){
+    TestApp.start();
+});
+/* eslint-enable */
diff --git a/xos/core/xoslib/static/js/vendor/ICanHaz.min.js b/xos/core/xoslib/static/js/vendor/ICanHaz.min.js
new file mode 100644
index 0000000..18ef653
--- /dev/null
+++ b/xos/core/xoslib/static/js/vendor/ICanHaz.min.js
@@ -0,0 +1,10 @@
+(function(){var m=function(){var f=function(){};f.prototype={otag:"{{",ctag:"}}",pragmas:{},buffer:[],pragmas_implemented:{"IMPLICIT-ITERATOR":true},context:{},render:function(a,b,c,d){if(!d){this.context=b;this.buffer=[]}if(!this.includes("",a))if(d)return a;else{this.send(a);return}a=this.render_pragmas(a);a=this.render_section(a,b,c);if(d)return this.render_tags(a,b,c,d);this.render_tags(a,b,c,d)},send:function(a){a!=""&&this.buffer.push(a)},render_pragmas:function(a){if(!this.includes("%",a))return a;
+var b=this;return a.replace(RegExp(this.otag+"%([\\w-]+) ?([\\w]+=[\\w]+)?"+this.ctag),function(c,d,e){if(!b.pragmas_implemented[d])throw{message:"This implementation of mustache doesn't understand the '"+d+"' pragma"};b.pragmas[d]={};if(e){c=e.split("=");b.pragmas[d][c[0]]=c[1]}return""})},render_partial:function(a,b,c){a=this.trim(a);if(!c||c[a]===undefined)throw{message:"unknown_partial '"+a+"'"};if(typeof b[a]!="object")return this.render(c[a],b,c,true);return this.render(c[a],b[a],c,true)},render_section:function(a,
+b,c){if(!this.includes("#",a)&&!this.includes("^",a))return a;var d=this;return a.replace(RegExp(this.otag+"(\\^|\\#)\\s*(.+)\\s*"+this.ctag+"\n*([\\s\\S]+?)"+this.otag+"\\/\\s*\\2\\s*"+this.ctag+"\\s*","mg"),function(e,i,j,h){e=d.find(j,b);if(i=="^")return!e||d.is_array(e)&&e.length===0?d.render(h,b,c,true):"";else if(i=="#")return d.is_array(e)?d.map(e,function(g){return d.render(h,d.create_context(g),c,true)}).join(""):d.is_object(e)?d.render(h,d.create_context(e),c,true):typeof e==="function"?
+e.call(b,h,function(g){return d.render(g,b,c,true)}):e?d.render(h,b,c,true):""})},render_tags:function(a,b,c,d){var e=this,i=function(){return RegExp(e.otag+"(=|!|>|\\{|%)?([^\\/#\\^]+?)\\1?"+e.ctag+"+","g")},j=i(),h=function(n,l,k){switch(l){case "!":return"";case "=":e.set_delimiters(k);j=i();return"";case ">":return e.render_partial(k,b,c);case "{":return e.find(k,b);default:return e.escape(e.find(k,b))}};a=a.split("\n");for(var g=0;g<a.length;g++){a[g]=a[g].replace(j,h,this);d||this.send(a[g])}if(d)return a.join("\n")},
+set_delimiters:function(a){a=a.split(" ");this.otag=this.escape_regex(a[0]);this.ctag=this.escape_regex(a[1])},escape_regex:function(a){if(!arguments.callee.sRE)arguments.callee.sRE=RegExp("(\\/|\\.|\\*|\\+|\\?|\\||\\(|\\)|\\[|\\]|\\{|\\}|\\\\)","g");return a.replace(arguments.callee.sRE,"\\$1")},find:function(a,b){a=this.trim(a);var c;if(b[a]===false||b[a]===0||b[a])c=b[a];else if(this.context[a]===false||this.context[a]===0||this.context[a])c=this.context[a];if(typeof c==="function")return c.apply(b);
+if(c!==undefined)return c;return""},includes:function(a,b){return b.indexOf(this.otag+a)!=-1},escape:function(a){return String(a===null?"":a).replace(/&(?!\w+;)|["<>\\]/g,function(b){switch(b){case "&":return"&amp;";case "\\":return"\\\\";case '"':return'"';case "<":return"&lt;";case ">":return"&gt;";default:return b}})},create_context:function(a){if(this.is_object(a))return a;else{var b=".";if(this.pragmas["IMPLICIT-ITERATOR"])b=this.pragmas["IMPLICIT-ITERATOR"].iterator;var c={};c[b]=a;return c}},
+is_object:function(a){return a&&typeof a=="object"},is_array:function(a){return Object.prototype.toString.call(a)==="[object Array]"},trim:function(a){return a.replace(/^\s*|\s*$/g,"")},map:function(a,b){if(typeof a.map=="function")return a.map(b);else{for(var c=[],d=a.length,e=0;e<d;e++)c.push(b(a[e]));return c}}};return{name:"mustache.js",version:"0.3.0",to_html:function(a,b,c,d){var e=new f;if(d)e.send=d;e.render(a,b,c);if(!d)return e.buffer.join("\n")}}}();(function(){var f={VERSION:"0.9",templates:{},
+$:typeof window!=="undefined"?window.jQuery||window.Zepto||null:null,addTemplate:function(a,b){if(f[a])throw"Invalid name: "+a+".";if(f.templates[a])throw'Template " + name + " exists';f.templates[a]=b;f[a]=function(c,d){c=c||{};var e=m.to_html(f.templates[a],c,f.templates);return f.$&&!d?f.$(e):e}},clearAll:function(){for(var a in f.templates)delete f[a];f.templates={}},refresh:function(){f.clearAll();f.grabTemplates()},grabTemplates:function(){var a,b=document.getElementsByTagName("script"),c=b!==
+undefined?b.length:0,d,e=[];for(a=0;a<c;a++)if((d=b[a])&&d.innerHTML&&d.id&&(d.type==="text/html"||d.type==="text/x-icanhaz")){f.addTemplate(d.id,"".trim?d.innerHTML.trim():s.replace(/^\s+/,"").replace(/\s+$/,""));e.unshift(d)}a=0;for(c=e.length;a<c;a++)e[a].parentNode.removeChild(e[a])}};if(typeof require!=="undefined")module.exports=f;else window.ich=f;if(typeof document!=="undefined")f.$?f.$(function(){f.grabTemplates()}):document.addEventListener("DOMContentLoaded",function(){f.grabTemplates()},
+false)})()})();
diff --git a/xos/core/xoslib/static/js/vendor/backbone-min.js b/xos/core/xoslib/static/js/vendor/backbone-min.js
new file mode 100644
index 0000000..8ea4b13
--- /dev/null
+++ b/xos/core/xoslib/static/js/vendor/backbone-min.js
@@ -0,0 +1,2 @@
+(function(t,e){if(typeof define==="function"&&define.amd){define(["underscore","jquery","exports"],function(i,r,s){t.Backbone=e(t,s,i,r)})}else if(typeof exports!=="undefined"){var i=require("underscore");e(t,exports,i)}else{t.Backbone=e(t,{},t._,t.jQuery||t.Zepto||t.ender||t.$)}})(this,function(t,e,i,r){var s=t.Backbone;var n=[];var a=n.push;var o=n.slice;var h=n.splice;e.VERSION="1.1.2";e.$=r;e.noConflict=function(){t.Backbone=s;return this};e.emulateHTTP=false;e.emulateJSON=false;var u=e.Events={on:function(t,e,i){if(!c(this,"on",t,[e,i])||!e)return this;this._events||(this._events={});var r=this._events[t]||(this._events[t]=[]);r.push({callback:e,context:i,ctx:i||this});return this},once:function(t,e,r){if(!c(this,"once",t,[e,r])||!e)return this;var s=this;var n=i.once(function(){s.off(t,n);e.apply(this,arguments)});n._callback=e;return this.on(t,n,r)},off:function(t,e,r){var s,n,a,o,h,u,l,f;if(!this._events||!c(this,"off",t,[e,r]))return this;if(!t&&!e&&!r){this._events=void 0;return this}o=t?[t]:i.keys(this._events);for(h=0,u=o.length;h<u;h++){t=o[h];if(a=this._events[t]){this._events[t]=s=[];if(e||r){for(l=0,f=a.length;l<f;l++){n=a[l];if(e&&e!==n.callback&&e!==n.callback._callback||r&&r!==n.context){s.push(n)}}}if(!s.length)delete this._events[t]}}return this},trigger:function(t){if(!this._events)return this;var e=o.call(arguments,1);if(!c(this,"trigger",t,e))return this;var i=this._events[t];var r=this._events.all;if(i)f(i,e);if(r)f(r,arguments);return this},stopListening:function(t,e,r){var s=this._listeningTo;if(!s)return this;var n=!e&&!r;if(!r&&typeof e==="object")r=this;if(t)(s={})[t._listenId]=t;for(var a in s){t=s[a];t.off(e,r,this);if(n||i.isEmpty(t._events))delete this._listeningTo[a]}return this}};var l=/\s+/;var c=function(t,e,i,r){if(!i)return true;if(typeof i==="object"){for(var s in i){t[e].apply(t,[s,i[s]].concat(r))}return false}if(l.test(i)){var n=i.split(l);for(var a=0,o=n.length;a<o;a++){t[e].apply(t,[n[a]].concat(r))}return false}return true};var f=function(t,e){var i,r=-1,s=t.length,n=e[0],a=e[1],o=e[2];switch(e.length){case 0:while(++r<s)(i=t[r]).callback.call(i.ctx);return;case 1:while(++r<s)(i=t[r]).callback.call(i.ctx,n);return;case 2:while(++r<s)(i=t[r]).callback.call(i.ctx,n,a);return;case 3:while(++r<s)(i=t[r]).callback.call(i.ctx,n,a,o);return;default:while(++r<s)(i=t[r]).callback.apply(i.ctx,e);return}};var d={listenTo:"on",listenToOnce:"once"};i.each(d,function(t,e){u[e]=function(e,r,s){var n=this._listeningTo||(this._listeningTo={});var a=e._listenId||(e._listenId=i.uniqueId("l"));n[a]=e;if(!s&&typeof r==="object")s=this;e[t](r,s,this);return this}});u.bind=u.on;u.unbind=u.off;i.extend(e,u);var p=e.Model=function(t,e){var r=t||{};e||(e={});this.cid=i.uniqueId("c");this.attributes={};if(e.collection)this.collection=e.collection;if(e.parse)r=this.parse(r,e)||{};r=i.defaults({},r,i.result(this,"defaults"));this.set(r,e);this.changed={};this.initialize.apply(this,arguments)};i.extend(p.prototype,u,{changed:null,validationError:null,idAttribute:"id",initialize:function(){},toJSON:function(t){return i.clone(this.attributes)},sync:function(){return e.sync.apply(this,arguments)},get:function(t){return this.attributes[t]},escape:function(t){return i.escape(this.get(t))},has:function(t){return this.get(t)!=null},set:function(t,e,r){var s,n,a,o,h,u,l,c;if(t==null)return this;if(typeof t==="object"){n=t;r=e}else{(n={})[t]=e}r||(r={});if(!this._validate(n,r))return false;a=r.unset;h=r.silent;o=[];u=this._changing;this._changing=true;if(!u){this._previousAttributes=i.clone(this.attributes);this.changed={}}c=this.attributes,l=this._previousAttributes;if(this.idAttribute in n)this.id=n[this.idAttribute];for(s in n){e=n[s];if(!i.isEqual(c[s],e))o.push(s);if(!i.isEqual(l[s],e)){this.changed[s]=e}else{delete this.changed[s]}a?delete c[s]:c[s]=e}if(!h){if(o.length)this._pending=r;for(var f=0,d=o.length;f<d;f++){this.trigger("change:"+o[f],this,c[o[f]],r)}}if(u)return this;if(!h){while(this._pending){r=this._pending;this._pending=false;this.trigger("change",this,r)}}this._pending=false;this._changing=false;return this},unset:function(t,e){return this.set(t,void 0,i.extend({},e,{unset:true}))},clear:function(t){var e={};for(var r in this.attributes)e[r]=void 0;return this.set(e,i.extend({},t,{unset:true}))},hasChanged:function(t){if(t==null)return!i.isEmpty(this.changed);return i.has(this.changed,t)},changedAttributes:function(t){if(!t)return this.hasChanged()?i.clone(this.changed):false;var e,r=false;var s=this._changing?this._previousAttributes:this.attributes;for(var n in t){if(i.isEqual(s[n],e=t[n]))continue;(r||(r={}))[n]=e}return r},previous:function(t){if(t==null||!this._previousAttributes)return null;return this._previousAttributes[t]},previousAttributes:function(){return i.clone(this._previousAttributes)},fetch:function(t){t=t?i.clone(t):{};if(t.parse===void 0)t.parse=true;var e=this;var r=t.success;t.success=function(i){if(!e.set(e.parse(i,t),t))return false;if(r)r(e,i,t);e.trigger("sync",e,i,t)};q(this,t);return this.sync("read",this,t)},save:function(t,e,r){var s,n,a,o=this.attributes;if(t==null||typeof t==="object"){s=t;r=e}else{(s={})[t]=e}r=i.extend({validate:true},r);if(s&&!r.wait){if(!this.set(s,r))return false}else{if(!this._validate(s,r))return false}if(s&&r.wait){this.attributes=i.extend({},o,s)}if(r.parse===void 0)r.parse=true;var h=this;var u=r.success;r.success=function(t){h.attributes=o;var e=h.parse(t,r);if(r.wait)e=i.extend(s||{},e);if(i.isObject(e)&&!h.set(e,r)){return false}if(u)u(h,t,r);h.trigger("sync",h,t,r)};q(this,r);n=this.isNew()?"create":r.patch?"patch":"update";if(n==="patch")r.attrs=s;a=this.sync(n,this,r);if(s&&r.wait)this.attributes=o;return a},destroy:function(t){t=t?i.clone(t):{};var e=this;var r=t.success;var s=function(){e.trigger("destroy",e,e.collection,t)};t.success=function(i){if(t.wait||e.isNew())s();if(r)r(e,i,t);if(!e.isNew())e.trigger("sync",e,i,t)};if(this.isNew()){t.success();return false}q(this,t);var n=this.sync("delete",this,t);if(!t.wait)s();return n},url:function(){var t=i.result(this,"urlRoot")||i.result(this.collection,"url")||M();if(this.isNew())return t;return t.replace(/([^\/])$/,"$1/")+encodeURIComponent(this.id)},parse:function(t,e){return t},clone:function(){return new this.constructor(this.attributes)},isNew:function(){return!this.has(this.idAttribute)},isValid:function(t){return this._validate({},i.extend(t||{},{validate:true}))},_validate:function(t,e){if(!e.validate||!this.validate)return true;t=i.extend({},this.attributes,t);var r=this.validationError=this.validate(t,e)||null;if(!r)return true;this.trigger("invalid",this,r,i.extend(e,{validationError:r}));return false}});var v=["keys","values","pairs","invert","pick","omit"];i.each(v,function(t){p.prototype[t]=function(){var e=o.call(arguments);e.unshift(this.attributes);return i[t].apply(i,e)}});var g=e.Collection=function(t,e){e||(e={});if(e.model)this.model=e.model;if(e.comparator!==void 0)this.comparator=e.comparator;this._reset();this.initialize.apply(this,arguments);if(t)this.reset(t,i.extend({silent:true},e))};var m={add:true,remove:true,merge:true};var y={add:true,remove:false};i.extend(g.prototype,u,{model:p,initialize:function(){},toJSON:function(t){return this.map(function(e){return e.toJSON(t)})},sync:function(){return e.sync.apply(this,arguments)},add:function(t,e){return this.set(t,i.extend({merge:false},e,y))},remove:function(t,e){var r=!i.isArray(t);t=r?[t]:i.clone(t);e||(e={});var s,n,a,o;for(s=0,n=t.length;s<n;s++){o=t[s]=this.get(t[s]);if(!o)continue;delete this._byId[o.id];delete this._byId[o.cid];a=this.indexOf(o);this.models.splice(a,1);this.length--;if(!e.silent){e.index=a;o.trigger("remove",o,this,e)}this._removeReference(o,e)}return r?t[0]:t},set:function(t,e){e=i.defaults({},e,m);if(e.parse)t=this.parse(t,e);var r=!i.isArray(t);t=r?t?[t]:[]:i.clone(t);var s,n,a,o,h,u,l;var c=e.at;var f=this.model;var d=this.comparator&&c==null&&e.sort!==false;var v=i.isString(this.comparator)?this.comparator:null;var g=[],y=[],_={};var b=e.add,w=e.merge,x=e.remove;var E=!d&&b&&x?[]:false;for(s=0,n=t.length;s<n;s++){h=t[s]||{};if(h instanceof p){a=o=h}else{a=h[f.prototype.idAttribute||"id"]}if(u=this.get(a)){if(x)_[u.cid]=true;if(w){h=h===o?o.attributes:h;if(e.parse)h=u.parse(h,e);u.set(h,e);if(d&&!l&&u.hasChanged(v))l=true}t[s]=u}else if(b){o=t[s]=this._prepareModel(h,e);if(!o)continue;g.push(o);this._addReference(o,e)}o=u||o;if(E&&(o.isNew()||!_[o.id]))E.push(o);_[o.id]=true}if(x){for(s=0,n=this.length;s<n;++s){if(!_[(o=this.models[s]).cid])y.push(o)}if(y.length)this.remove(y,e)}if(g.length||E&&E.length){if(d)l=true;this.length+=g.length;if(c!=null){for(s=0,n=g.length;s<n;s++){this.models.splice(c+s,0,g[s])}}else{if(E)this.models.length=0;var k=E||g;for(s=0,n=k.length;s<n;s++){this.models.push(k[s])}}}if(l)this.sort({silent:true});if(!e.silent){for(s=0,n=g.length;s<n;s++){(o=g[s]).trigger("add",o,this,e)}if(l||E&&E.length)this.trigger("sort",this,e)}return r?t[0]:t},reset:function(t,e){e||(e={});for(var r=0,s=this.models.length;r<s;r++){this._removeReference(this.models[r],e)}e.previousModels=this.models;this._reset();t=this.add(t,i.extend({silent:true},e));if(!e.silent)this.trigger("reset",this,e);return t},push:function(t,e){return this.add(t,i.extend({at:this.length},e))},pop:function(t){var e=this.at(this.length-1);this.remove(e,t);return e},unshift:function(t,e){return this.add(t,i.extend({at:0},e))},shift:function(t){var e=this.at(0);this.remove(e,t);return e},slice:function(){return o.apply(this.models,arguments)},get:function(t){if(t==null)return void 0;return this._byId[t]||this._byId[t.id]||this._byId[t.cid]},at:function(t){return this.models[t]},where:function(t,e){if(i.isEmpty(t))return e?void 0:[];return this[e?"find":"filter"](function(e){for(var i in t){if(t[i]!==e.get(i))return false}return true})},findWhere:function(t){return this.where(t,true)},sort:function(t){if(!this.comparator)throw new Error("Cannot sort a set without a comparator");t||(t={});if(i.isString(this.comparator)||this.comparator.length===1){this.models=this.sortBy(this.comparator,this)}else{this.models.sort(i.bind(this.comparator,this))}if(!t.silent)this.trigger("sort",this,t);return this},pluck:function(t){return i.invoke(this.models,"get",t)},fetch:function(t){t=t?i.clone(t):{};if(t.parse===void 0)t.parse=true;var e=t.success;var r=this;t.success=function(i){var s=t.reset?"reset":"set";r[s](i,t);if(e)e(r,i,t);r.trigger("sync",r,i,t)};q(this,t);return this.sync("read",this,t)},create:function(t,e){e=e?i.clone(e):{};if(!(t=this._prepareModel(t,e)))return false;if(!e.wait)this.add(t,e);var r=this;var s=e.success;e.success=function(t,i){if(e.wait)r.add(t,e);if(s)s(t,i,e)};t.save(null,e);return t},parse:function(t,e){return t},clone:function(){return new this.constructor(this.models)},_reset:function(){this.length=0;this.models=[];this._byId={}},_prepareModel:function(t,e){if(t instanceof p)return t;e=e?i.clone(e):{};e.collection=this;var r=new this.model(t,e);if(!r.validationError)return r;this.trigger("invalid",this,r.validationError,e);return false},_addReference:function(t,e){this._byId[t.cid]=t;if(t.id!=null)this._byId[t.id]=t;if(!t.collection)t.collection=this;t.on("all",this._onModelEvent,this)},_removeReference:function(t,e){if(this===t.collection)delete t.collection;t.off("all",this._onModelEvent,this)},_onModelEvent:function(t,e,i,r){if((t==="add"||t==="remove")&&i!==this)return;if(t==="destroy")this.remove(e,r);if(e&&t==="change:"+e.idAttribute){delete this._byId[e.previous(e.idAttribute)];if(e.id!=null)this._byId[e.id]=e}this.trigger.apply(this,arguments)}});var _=["forEach","each","map","collect","reduce","foldl","inject","reduceRight","foldr","find","detect","filter","select","reject","every","all","some","any","include","contains","invoke","max","min","toArray","size","first","head","take","initial","rest","tail","drop","last","without","difference","indexOf","shuffle","lastIndexOf","isEmpty","chain","sample"];i.each(_,function(t){g.prototype[t]=function(){var e=o.call(arguments);e.unshift(this.models);return i[t].apply(i,e)}});var b=["groupBy","countBy","sortBy","indexBy"];i.each(b,function(t){g.prototype[t]=function(e,r){var s=i.isFunction(e)?e:function(t){return t.get(e)};return i[t](this.models,s,r)}});var w=e.View=function(t){this.cid=i.uniqueId("view");t||(t={});i.extend(this,i.pick(t,E));this._ensureElement();this.initialize.apply(this,arguments);this.delegateEvents()};var x=/^(\S+)\s*(.*)$/;var E=["model","collection","el","id","attributes","className","tagName","events"];i.extend(w.prototype,u,{tagName:"div",$:function(t){return this.$el.find(t)},initialize:function(){},render:function(){return this},remove:function(){this.$el.remove();this.stopListening();return this},setElement:function(t,i){if(this.$el)this.undelegateEvents();this.$el=t instanceof e.$?t:e.$(t);this.el=this.$el[0];if(i!==false)this.delegateEvents();return this},delegateEvents:function(t){if(!(t||(t=i.result(this,"events"))))return this;this.undelegateEvents();for(var e in t){var r=t[e];if(!i.isFunction(r))r=this[t[e]];if(!r)continue;var s=e.match(x);var n=s[1],a=s[2];r=i.bind(r,this);n+=".delegateEvents"+this.cid;if(a===""){this.$el.on(n,r)}else{this.$el.on(n,a,r)}}return this},undelegateEvents:function(){this.$el.off(".delegateEvents"+this.cid);return this},_ensureElement:function(){if(!this.el){var t=i.extend({},i.result(this,"attributes"));if(this.id)t.id=i.result(this,"id");if(this.className)t["class"]=i.result(this,"className");var r=e.$("<"+i.result(this,"tagName")+">").attr(t);this.setElement(r,false)}else{this.setElement(i.result(this,"el"),false)}}});e.sync=function(t,r,s){var n=T[t];i.defaults(s||(s={}),{emulateHTTP:e.emulateHTTP,emulateJSON:e.emulateJSON});var a={type:n,dataType:"json"};if(!s.url){a.url=i.result(r,"url")||M()}if(s.data==null&&r&&(t==="create"||t==="update"||t==="patch")){a.contentType="application/json";a.data=JSON.stringify(s.attrs||r.toJSON(s))}if(s.emulateJSON){a.contentType="application/x-www-form-urlencoded";a.data=a.data?{model:a.data}:{}}if(s.emulateHTTP&&(n==="PUT"||n==="DELETE"||n==="PATCH")){a.type="POST";if(s.emulateJSON)a.data._method=n;var o=s.beforeSend;s.beforeSend=function(t){t.setRequestHeader("X-HTTP-Method-Override",n);if(o)return o.apply(this,arguments)}}if(a.type!=="GET"&&!s.emulateJSON){a.processData=false}if(a.type==="PATCH"&&k){a.xhr=function(){return new ActiveXObject("Microsoft.XMLHTTP")}}var h=s.xhr=e.ajax(i.extend(a,s));r.trigger("request",r,h,s);return h};var k=typeof window!=="undefined"&&!!window.ActiveXObject&&!(window.XMLHttpRequest&&(new XMLHttpRequest).dispatchEvent);var T={create:"POST",update:"PUT",patch:"PATCH","delete":"DELETE",read:"GET"};e.ajax=function(){return e.$.ajax.apply(e.$,arguments)};var $=e.Router=function(t){t||(t={});if(t.routes)this.routes=t.routes;this._bindRoutes();this.initialize.apply(this,arguments)};var S=/\((.*?)\)/g;var H=/(\(\?)?:\w+/g;var A=/\*\w+/g;var I=/[\-{}\[\]+?.,\\\^$|#\s]/g;i.extend($.prototype,u,{initialize:function(){},route:function(t,r,s){if(!i.isRegExp(t))t=this._routeToRegExp(t);if(i.isFunction(r)){s=r;r=""}if(!s)s=this[r];var n=this;e.history.route(t,function(i){var a=n._extractParameters(t,i);n.execute(s,a);n.trigger.apply(n,["route:"+r].concat(a));n.trigger("route",r,a);e.history.trigger("route",n,r,a)});return this},execute:function(t,e){if(t)t.apply(this,e)},navigate:function(t,i){e.history.navigate(t,i);return this},_bindRoutes:function(){if(!this.routes)return;this.routes=i.result(this,"routes");var t,e=i.keys(this.routes);while((t=e.pop())!=null){this.route(t,this.routes[t])}},_routeToRegExp:function(t){t=t.replace(I,"\\$&").replace(S,"(?:$1)?").replace(H,function(t,e){return e?t:"([^/?]+)"}).replace(A,"([^?]*?)");return new RegExp("^"+t+"(?:\\?([\\s\\S]*))?$")},_extractParameters:function(t,e){var r=t.exec(e).slice(1);return i.map(r,function(t,e){if(e===r.length-1)return t||null;return t?decodeURIComponent(t):null})}});var N=e.History=function(){this.handlers=[];i.bindAll(this,"checkUrl");if(typeof window!=="undefined"){this.location=window.location;this.history=window.history}};var R=/^[#\/]|\s+$/g;var O=/^\/+|\/+$/g;var P=/msie [\w.]+/;var C=/\/$/;var j=/#.*$/;N.started=false;i.extend(N.prototype,u,{interval:50,atRoot:function(){return this.location.pathname.replace(/[^\/]$/,"$&/")===this.root},getHash:function(t){var e=(t||this).location.href.match(/#(.*)$/);return e?e[1]:""},getFragment:function(t,e){if(t==null){if(this._hasPushState||!this._wantsHashChange||e){t=decodeURI(this.location.pathname+this.location.search);var i=this.root.replace(C,"");if(!t.indexOf(i))t=t.slice(i.length)}else{t=this.getHash()}}return t.replace(R,"")},start:function(t){if(N.started)throw new Error("Backbone.history has already been started");N.started=true;this.options=i.extend({root:"/"},this.options,t);this.root=this.options.root;this._wantsHashChange=this.options.hashChange!==false;this._wantsPushState=!!this.options.pushState;this._hasPushState=!!(this.options.pushState&&this.history&&this.history.pushState);var r=this.getFragment();var s=document.documentMode;var n=P.exec(navigator.userAgent.toLowerCase())&&(!s||s<=7);this.root=("/"+this.root+"/").replace(O,"/");if(n&&this._wantsHashChange){var a=e.$('<iframe src="javascript:0" tabindex="-1">');this.iframe=a.hide().appendTo("body")[0].contentWindow;this.navigate(r)}if(this._hasPushState){e.$(window).on("popstate",this.checkUrl)}else if(this._wantsHashChange&&"onhashchange"in window&&!n){e.$(window).on("hashchange",this.checkUrl)}else if(this._wantsHashChange){this._checkUrlInterval=setInterval(this.checkUrl,this.interval)}this.fragment=r;var o=this.location;if(this._wantsHashChange&&this._wantsPushState){if(!this._hasPushState&&!this.atRoot()){this.fragment=this.getFragment(null,true);this.location.replace(this.root+"#"+this.fragment);return true}else if(this._hasPushState&&this.atRoot()&&o.hash){this.fragment=this.getHash().replace(R,"");this.history.replaceState({},document.title,this.root+this.fragment)}}if(!this.options.silent)return this.loadUrl()},stop:function(){e.$(window).off("popstate",this.checkUrl).off("hashchange",this.checkUrl);if(this._checkUrlInterval)clearInterval(this._checkUrlInterval);N.started=false},route:function(t,e){this.handlers.unshift({route:t,callback:e})},checkUrl:function(t){var e=this.getFragment();if(e===this.fragment&&this.iframe){e=this.getFragment(this.getHash(this.iframe))}if(e===this.fragment)return false;if(this.iframe)this.navigate(e);this.loadUrl()},loadUrl:function(t){t=this.fragment=this.getFragment(t);return i.any(this.handlers,function(e){if(e.route.test(t)){e.callback(t);return true}})},navigate:function(t,e){if(!N.started)return false;if(!e||e===true)e={trigger:!!e};var i=this.root+(t=this.getFragment(t||""));t=t.replace(j,"");if(this.fragment===t)return;this.fragment=t;if(t===""&&i!=="/")i=i.slice(0,-1);if(this._hasPushState){this.history[e.replace?"replaceState":"pushState"]({},document.title,i)}else if(this._wantsHashChange){this._updateHash(this.location,t,e.replace);if(this.iframe&&t!==this.getFragment(this.getHash(this.iframe))){if(!e.replace)this.iframe.document.open().close();this._updateHash(this.iframe.location,t,e.replace)}}else{return this.location.assign(i)}if(e.trigger)return this.loadUrl(t)},_updateHash:function(t,e,i){if(i){var r=t.href.replace(/(javascript:|#).*$/,"");t.replace(r+"#"+e)}else{t.hash="#"+e}}});e.history=new N;var U=function(t,e){var r=this;var s;if(t&&i.has(t,"constructor")){s=t.constructor}else{s=function(){return r.apply(this,arguments)}}i.extend(s,r,e);var n=function(){this.constructor=s};n.prototype=r.prototype;s.prototype=new n;if(t)i.extend(s.prototype,t);s.__super__=r.prototype;return s};p.extend=g.extend=$.extend=w.extend=N.extend=U;var M=function(){throw new Error('A "url" property or function must be specified')};var q=function(t,e){var i=e.error;e.error=function(r){if(i)i(t,r,e);t.trigger("error",t,r,e)}};return e});
+//# sourceMappingURL=backbone-min.map
\ No newline at end of file
diff --git a/xos/core/xoslib/static/js/vendor/backbone-tastypie.js b/xos/core/xoslib/static/js/vendor/backbone-tastypie.js
new file mode 100644
index 0000000..69a4d56
--- /dev/null
+++ b/xos/core/xoslib/static/js/vendor/backbone-tastypie.js
@@ -0,0 +1,95 @@
+/**
+ * Backbone-tastypie.js 0.1
+ * (c) 2011 Paul Uithol
+ * 
+ * Backbone-tastypie may be freely distributed under the MIT license.
+ * Add or override Backbone.js functionality, for compatibility with django-tastypie.
+ */
+(function( undefined ) {
+	var Backbone = this.Backbone;
+	
+	/**
+	 * Override Backbone's sync function, to do a GET upon receiving a HTTP CREATED.
+	 * This requires 2 requests to do a create, so you may want to use some other method in production.
+	 * Modified from http://joshbohde.com/blog/backbonejs-and-django
+	 */
+	Backbone.oldSync = Backbone.sync;
+	Backbone.sync = function( method, model, options ) {
+		if ( method === 'create' ) {
+			var dfd = new $.Deferred();
+			
+			// Set up 'success' handling
+			dfd.done( options.success );
+			options.success = function( resp, status, xhr ) {
+				// If create is successful but doesn't return a response, fire an extra GET.
+				// Otherwise, resolve the deferred (which triggers the original 'success' callbacks).
+				if ( xhr.status === 201 && !resp ) { // 201 CREATED; response null or empty.
+					var location = xhr.getResponseHeader( 'Location' );
+					return $.ajax( {
+						   url: location,
+						   success: dfd.resolve,
+						   error: dfd.reject
+						});
+				}
+				else {
+					return dfd.resolveWith( options.context || options, [ resp, status, xhr ] );
+				}
+			};
+			
+			// Set up 'error' handling
+			dfd.fail( options.error );
+			options.error = dfd.reject;
+			
+			// Make the request, make it accessibly by assigning it to the 'request' property on the deferred 
+			dfd.request = Backbone.oldSync( method, model, options );
+			return dfd;
+		}
+		
+		return Backbone.oldSync( method, model, options );
+	};
+
+	Backbone.Model.prototype.idAttribute = 'resource_uri';
+	
+	Backbone.Model.prototype.url = function() {
+		// Use the id if possible
+		var url = this.id;
+		
+		// If there's no idAttribute, try to have the collection construct a url. Fallback to 'urlRoot'.
+		if ( !url ) {
+			url = this.collection && ( _.isFunction( this.collection.url ) ? this.collection.url() : this.collection.url );
+			url = url || this.urlRoot;
+		}
+		
+		url && ( url += ( url.length > 0 && url.charAt( url.length - 1 ) === '/' ) ? '' : '/' );
+		
+		return url;
+	};
+	
+	/**
+	 * Return 'data.objects' if it exists and is an array, or else just plain 'data'.
+	 */
+	Backbone.Model.prototype.parse = function( data ) {
+		return data && data.objects && ( _.isArray( data.objects ) ? data.objects[ 0 ] : data.objects ) || data;
+	};
+	
+	Backbone.Collection.prototype.parse = function( data ) {
+		return data && data.objects;
+	};
+	
+	Backbone.Collection.prototype.url = function( models ) {
+		var url = this.urlRoot || ( models && models.length && models[0].urlRoot );
+		url && ( url += ( url.length > 0 && url.charAt( url.length - 1 ) === '/' ) ? '' : '/' );
+		
+		// Build a url to retrieve a set of models. This assume the last part of each model's idAttribute
+		// (set to 'resource_uri') contains the model's id.
+		if ( models && models.length ) {
+			var ids = _.map( models, function( model ) {
+					var parts = _.compact( model.id.split('/') );
+					return parts[ parts.length - 1 ];
+				});
+			url += 'set/' + ids.join(';') + '/';
+		}
+		
+		return url;
+	};
+})();
diff --git a/xos/core/xoslib/static/js/vendor/backbone.babysitter.js b/xos/core/xoslib/static/js/vendor/backbone.babysitter.js
new file mode 100644
index 0000000..eeb92a2
--- /dev/null
+++ b/xos/core/xoslib/static/js/vendor/backbone.babysitter.js
@@ -0,0 +1,190 @@
+// Backbone.BabySitter
+// -------------------
+// v0.1.4
+//
+// Copyright (c)2014 Derick Bailey, Muted Solutions, LLC.
+// Distributed under MIT license
+//
+// http://github.com/marionettejs/backbone.babysitter
+
+(function(root, factory) {
+
+  if (typeof define === 'function' && define.amd) {
+    define(['backbone', 'underscore'], function(Backbone, _) {
+      return factory(Backbone, _);
+    });
+  } else if (typeof exports !== 'undefined') {
+    var Backbone = require('backbone');
+    var _ = require('underscore');
+    module.exports = factory(Backbone, _);
+  } else {
+    factory(root.Backbone, root._);
+  }
+
+}(this, function(Backbone, _) {
+  'use strict';
+
+  var previousChildViewContainer = Backbone.ChildViewContainer;
+
+  // BabySitter.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();
+        return this;
+      },
+  
+      // 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 its `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();
+        return this;
+      },
+  
+      // 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, _);
+  
+
+  Backbone.ChildViewContainer.VERSION = '0.1.4';
+
+  Backbone.ChildViewContainer.noConflict = function () {
+    Backbone.ChildViewContainer = previousChildViewContainer;
+    return this;
+  };
+
+  return Backbone.ChildViewContainer;
+
+}));
diff --git a/xos/core/xoslib/static/js/vendor/backbone.js b/xos/core/xoslib/static/js/vendor/backbone.js
new file mode 100644
index 0000000..24a550a
--- /dev/null
+++ b/xos/core/xoslib/static/js/vendor/backbone.js
@@ -0,0 +1,1608 @@
+//     Backbone.js 1.1.2
+
+//     (c) 2010-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+//     Backbone may be freely distributed under the MIT license.
+//     For all details and documentation:
+//     http://backbonejs.org
+
+(function(root, factory) {
+
+  // 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');
+    factory(root, exports, _);
+
+  // Finally, as a browser global.
+  } else {
+    root.Backbone = factory(root, {}, root._, (root.jQuery || root.Zepto || root.ender || root.$));
+  }
+
+}(this, 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 local references to array methods we'll want to use later.
+  var array = [];
+  var push = array.push;
+  var slice = array.slice;
+  var splice = array.splice;
+
+  // Current version of the library. Keep in sync with `package.json`.
+  Backbone.VERSION = '1.1.2';
+
+  // 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 ... 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
+  // custom events. You may bind with `on` or remove with `off` callback
+  // functions to an event; `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 = {
+
+    // Bind an event to a `callback` function. Passing `"all"` will bind
+    // the callback to all events fired.
+    on: function(name, callback, context) {
+      if (!eventsApi(this, 'on', name, [callback, context]) || !callback) return this;
+      this._events || (this._events = {});
+      var events = this._events[name] || (this._events[name] = []);
+      events.push({callback: callback, context: context, ctx: context || this});
+      return this;
+    },
+
+    // Bind an event to only be triggered a single time. After the first time
+    // the callback is invoked, it will be removed.
+    once: function(name, callback, context) {
+      if (!eventsApi(this, 'once', name, [callback, context]) || !callback) return this;
+      var self = this;
+      var once = _.once(function() {
+        self.off(name, once);
+        callback.apply(this, arguments);
+      });
+      once._callback = callback;
+      return this.on(name, once, context);
+    },
+
+    // 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.
+    off: function(name, callback, context) {
+      var retain, ev, events, names, i, l, j, k;
+      if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this;
+      if (!name && !callback && !context) {
+        this._events = void 0;
+        return this;
+      }
+      names = name ? [name] : _.keys(this._events);
+      for (i = 0, l = names.length; i < l; i++) {
+        name = names[i];
+        if (events = this._events[name]) {
+          this._events[name] = retain = [];
+          if (callback || context) {
+            for (j = 0, k = events.length; j < k; j++) {
+              ev = events[j];
+              if ((callback && callback !== ev.callback && callback !== ev.callback._callback) ||
+                  (context && context !== ev.context)) {
+                retain.push(ev);
+              }
+            }
+          }
+          if (!retain.length) delete this._events[name];
+        }
+      }
+
+      return this;
+    },
+
+    // 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).
+    trigger: function(name) {
+      if (!this._events) return this;
+      var args = slice.call(arguments, 1);
+      if (!eventsApi(this, 'trigger', name, args)) return this;
+      var events = this._events[name];
+      var allEvents = this._events.all;
+      if (events) triggerEvents(events, args);
+      if (allEvents) triggerEvents(allEvents, arguments);
+      return this;
+    },
+
+    // Tell this object to stop listening to either specific events ... or
+    // to every object it's currently listening to.
+    stopListening: function(obj, name, callback) {
+      var listeningTo = this._listeningTo;
+      if (!listeningTo) return this;
+      var remove = !name && !callback;
+      if (!callback && typeof name === 'object') callback = this;
+      if (obj) (listeningTo = {})[obj._listenId] = obj;
+      for (var id in listeningTo) {
+        obj = listeningTo[id];
+        obj.off(name, callback, this);
+        if (remove || _.isEmpty(obj._events)) delete this._listeningTo[id];
+      }
+      return this;
+    }
+
+  };
+
+  // Regular expression used to split event strings.
+  var eventSplitter = /\s+/;
+
+  // Implement fancy features of the Events API such as multiple event
+  // names `"change blur"` and jQuery-style event maps `{change: action}`
+  // in terms of the existing API.
+  var eventsApi = function(obj, action, name, rest) {
+    if (!name) return true;
+
+    // Handle event maps.
+    if (typeof name === 'object') {
+      for (var key in name) {
+        obj[action].apply(obj, [key, name[key]].concat(rest));
+      }
+      return false;
+    }
+
+    // Handle space separated event names.
+    if (eventSplitter.test(name)) {
+      var names = name.split(eventSplitter);
+      for (var i = 0, l = names.length; i < l; i++) {
+        obj[action].apply(obj, [names[i]].concat(rest));
+      }
+      return false;
+    }
+
+    return true;
+  };
+
+  // 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;
+    }
+  };
+
+  var listenMethods = {listenTo: 'on', listenToOnce: 'once'};
+
+  // Inversion-of-control versions of `on` and `once`. Tell *this* object to
+  // listen to an event in another object ... keeping track of what it's
+  // listening to.
+  _.each(listenMethods, function(implementation, method) {
+    Events[method] = function(obj, name, callback) {
+      var listeningTo = this._listeningTo || (this._listeningTo = {});
+      var id = obj._listenId || (obj._listenId = _.uniqueId('l'));
+      listeningTo[id] = obj;
+      if (!callback && typeof name === 'object') callback = this;
+      obj[implementation](name, callback, this);
+      return this;
+    };
+  });
+
+  // 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.cid = _.uniqueId('c');
+    this.attributes = {};
+    if (options.collection) this.collection = options.collection;
+    if (options.parse) attrs = this.parse(attrs, options) || {};
+    attrs = _.defaults({}, attrs, _.result(this, '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',
+
+    // 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;
+    },
+
+    // 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) {
+      var attr, attrs, unset, changes, silent, changing, prev, current;
+      if (key == null) return this;
+
+      // Handle both `"key", value` and `{key: value}` -style arguments.
+      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.
+      unset           = options.unset;
+      silent          = options.silent;
+      changes         = [];
+      changing        = this._changing;
+      this._changing  = true;
+
+      if (!changing) {
+        this._previousAttributes = _.clone(this.attributes);
+        this.changed = {};
+      }
+      current = this.attributes, prev = this._previousAttributes;
+
+      // Check for changes of `id`.
+      if (this.idAttribute in attrs) this.id = attrs[this.idAttribute];
+
+      // For each `set` attribute, update or delete the current value.
+      for (attr in attrs) {
+        val = attrs[attr];
+        if (!_.isEqual(current[attr], val)) changes.push(attr);
+        if (!_.isEqual(prev[attr], val)) {
+          this.changed[attr] = val;
+        } else {
+          delete this.changed[attr];
+        }
+        unset ? delete current[attr] : current[attr] = val;
+      }
+
+      // Trigger all relevant attribute changes.
+      if (!silent) {
+        if (changes.length) this._pending = options;
+        for (var i = 0, l = changes.length; i < l; 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 val, changed = false;
+      var old = this._changing ? this._previousAttributes : this.attributes;
+      for (var attr in diff) {
+        if (_.isEqual(old[attr], (val = diff[attr]))) continue;
+        (changed || (changed = {}))[attr] = val;
+      }
+      return changed;
+    },
+
+    // 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. If the server's representation of the
+    // model differs from its current attributes, they will be overridden,
+    // triggering a `"change"` event.
+    fetch: function(options) {
+      options = options ? _.clone(options) : {};
+      if (options.parse === void 0) options.parse = true;
+      var model = this;
+      var success = options.success;
+      options.success = function(resp) {
+        if (!model.set(model.parse(resp, options), options)) return false;
+        if (success) success(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) {
+      var attrs, method, xhr, attributes = this.attributes;
+
+      // Handle both `"key", value` and `{key: value}` -style arguments.
+      if (key == null || typeof key === 'object') {
+        attrs = key;
+        options = val;
+      } else {
+        (attrs = {})[key] = val;
+      }
+
+      options = _.extend({validate: true}, options);
+
+      // 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 && !options.wait) {
+        if (!this.set(attrs, options)) return false;
+      } else {
+        if (!this._validate(attrs, options)) return false;
+      }
+
+      // Set temporary attributes if `{wait: true}`.
+      if (attrs && options.wait) {
+        this.attributes = _.extend({}, attributes, attrs);
+      }
+
+      // After a successful server-side save, the client is (optionally)
+      // updated with the server-side state.
+      if (options.parse === void 0) options.parse = true;
+      var model = this;
+      var success = options.success;
+      options.success = function(resp) {
+        // Ensure attributes are restored during synchronous saves.
+        model.attributes = attributes;
+        var serverAttrs = model.parse(resp, options);
+        if (options.wait) serverAttrs = _.extend(attrs || {}, serverAttrs);
+        if (_.isObject(serverAttrs) && !model.set(serverAttrs, options)) {
+          return false;
+        }
+        if (success) success(model, resp, options);
+        model.trigger('sync', model, resp, options);
+      };
+      wrapError(this, options);
+
+      method = this.isNew() ? 'create' : (options.patch ? 'patch' : 'update');
+      if (method === 'patch') options.attrs = attrs;
+      xhr = this.sync(method, this, options);
+
+      // Restore attributes.
+      if (attrs && options.wait) 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 destroy = function() {
+        model.trigger('destroy', model, model.collection, options);
+      };
+
+      options.success = function(resp) {
+        if (options.wait || model.isNew()) destroy();
+        if (success) success(model, resp, options);
+        if (!model.isNew()) model.trigger('sync', model, resp, options);
+      };
+
+      if (this.isNew()) {
+        options.success();
+        return false;
+      }
+      wrapError(this, options);
+
+      var xhr = this.sync('delete', this, options);
+      if (!options.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;
+      return base.replace(/([^\/])$/, '$1/') + encodeURIComponent(this.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;
+    }
+
+  });
+
+  // Underscore methods that we want to implement on the Model.
+  var modelMethods = ['keys', 'values', 'pairs', 'invert', 'pick', 'omit'];
+
+  // Mix in each Underscore method as a proxy to `Model#attributes`.
+  _.each(modelMethods, function(method) {
+    Model.prototype[method] = function() {
+      var args = slice.call(arguments);
+      args.unshift(this.attributes);
+      return _[method].apply(_, args);
+    };
+  });
+
+  // Backbone.Collection
+  // -------------------
+
+  // If models tend to represent a single row of data, a Backbone Collection is
+  // more analagous 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 = {});
+    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};
+
+  // 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,
+
+    // 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.
+    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) {
+      var singular = !_.isArray(models);
+      models = singular ? [models] : _.clone(models);
+      options || (options = {});
+      var i, l, index, model;
+      for (i = 0, l = models.length; i < l; i++) {
+        model = models[i] = this.get(models[i]);
+        if (!model) continue;
+        delete this._byId[model.id];
+        delete this._byId[model.cid];
+        index = this.indexOf(model);
+        this.models.splice(index, 1);
+        this.length--;
+        if (!options.silent) {
+          options.index = index;
+          model.trigger('remove', model, this, options);
+        }
+        this._removeReference(model, options);
+      }
+      return singular ? models[0] : models;
+    },
+
+    // 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) {
+      options = _.defaults({}, options, setOptions);
+      if (options.parse) models = this.parse(models, options);
+      var singular = !_.isArray(models);
+      models = singular ? (models ? [models] : []) : _.clone(models);
+      var i, l, id, model, attrs, existing, sort;
+      var at = options.at;
+      var targetModel = this.model;
+      var sortable = this.comparator && (at == null) && options.sort !== false;
+      var sortAttr = _.isString(this.comparator) ? this.comparator : null;
+      var toAdd = [], toRemove = [], modelMap = {};
+      var add = options.add, merge = options.merge, remove = options.remove;
+      var order = !sortable && add && remove ? [] : false;
+
+      // Turn bare objects into model references, and prevent invalid models
+      // from being added.
+      for (i = 0, l = models.length; i < l; i++) {
+        attrs = models[i] || {};
+        if (attrs instanceof Model) {
+          id = model = attrs;
+        } else {
+          id = attrs[targetModel.prototype.idAttribute || 'id'];
+        }
+
+        // If a duplicate is found, prevent it from being added and
+        // optionally merge it into the existing model.
+        if (existing = this.get(id)) {
+          if (remove) modelMap[existing.cid] = true;
+          if (merge) {
+            attrs = attrs === model ? model.attributes : attrs;
+            if (options.parse) attrs = existing.parse(attrs, options);
+            existing.set(attrs, options);
+            if (sortable && !sort && existing.hasChanged(sortAttr)) sort = true;
+          }
+          models[i] = existing;
+
+        // If this is a new, valid model, push it to the `toAdd` list.
+        } else if (add) {
+          model = models[i] = this._prepareModel(attrs, options);
+          if (!model) continue;
+          toAdd.push(model);
+          this._addReference(model, options);
+        }
+
+        // Do not add multiple models with the same `id`.
+        model = existing || model;
+        if (order && (model.isNew() || !modelMap[model.id])) order.push(model);
+        modelMap[model.id] = true;
+      }
+
+      // Remove nonexistent models if appropriate.
+      if (remove) {
+        for (i = 0, l = this.length; i < l; ++i) {
+          if (!modelMap[(model = this.models[i]).cid]) toRemove.push(model);
+        }
+        if (toRemove.length) this.remove(toRemove, options);
+      }
+
+      // See if sorting is needed, update `length` and splice in new models.
+      if (toAdd.length || (order && order.length)) {
+        if (sortable) sort = true;
+        this.length += toAdd.length;
+        if (at != null) {
+          for (i = 0, l = toAdd.length; i < l; i++) {
+            this.models.splice(at + i, 0, toAdd[i]);
+          }
+        } else {
+          if (order) this.models.length = 0;
+          var orderedModels = order || toAdd;
+          for (i = 0, l = orderedModels.length; i < l; i++) {
+            this.models.push(orderedModels[i]);
+          }
+        }
+      }
+
+      // Silently sort the collection if appropriate.
+      if (sort) this.sort({silent: true});
+
+      // Unless silenced, it's time to fire all appropriate add/sort events.
+      if (!options.silent) {
+        for (i = 0, l = toAdd.length; i < l; i++) {
+          (model = toAdd[i]).trigger('add', model, this, options);
+        }
+        if (sort || (order && order.length)) this.trigger('sort', 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 = {});
+      for (var i = 0, l = this.models.length; i < l; 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);
+      this.remove(model, options);
+      return model;
+    },
+
+    // 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);
+      this.remove(model, options);
+      return model;
+    },
+
+    // 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.
+    get: function(obj) {
+      if (obj == null) return void 0;
+      return this._byId[obj] || this._byId[obj.id] || this._byId[obj.cid];
+    },
+
+    // Get the model at the given index.
+    at: function(index) {
+      return this.models[index];
+    },
+
+    // Return models with matching attributes. Useful for simple cases of
+    // `filter`.
+    where: function(attrs, first) {
+      if (_.isEmpty(attrs)) return first ? void 0 : [];
+      return this[first ? 'find' : 'filter'](function(model) {
+        for (var key in attrs) {
+          if (attrs[key] !== model.get(key)) return false;
+        }
+        return true;
+      });
+    },
+
+    // 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) {
+      if (!this.comparator) throw new Error('Cannot sort a set without a comparator');
+      options || (options = {});
+
+      // Run sort based on type of `comparator`.
+      if (_.isString(this.comparator) || this.comparator.length === 1) {
+        this.models = this.sortBy(this.comparator, this);
+      } else {
+        this.models.sort(_.bind(this.comparator, this));
+      }
+
+      if (!options.silent) this.trigger('sort', this, options);
+      return this;
+    },
+
+    // Pluck an attribute from each model in the collection.
+    pluck: function(attr) {
+      return _.invoke(this.models, 'get', 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 = options ? _.clone(options) : {};
+      if (options.parse === void 0) options.parse = true;
+      var success = options.success;
+      var collection = this;
+      options.success = function(resp) {
+        var method = options.reset ? 'reset' : 'set';
+        collection[method](resp, options);
+        if (success) success(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) : {};
+      if (!(model = this._prepareModel(model, options))) return false;
+      if (!options.wait) this.add(model, options);
+      var collection = this;
+      var success = options.success;
+      options.success = function(model, resp) {
+        if (options.wait) collection.add(model, options);
+        if (success) success(model, resp, options);
+      };
+      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);
+    },
+
+    // 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 (attrs instanceof Model) 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 to create a model's ties to a collection.
+    _addReference: function(model, options) {
+      this._byId[model.cid] = model;
+      if (model.id != null) this._byId[model.id] = model;
+      if (!model.collection) model.collection = this;
+      model.on('all', this._onModelEvent, this);
+    },
+
+    // Internal method to sever a model's ties to a collection.
+    _removeReference: function(model, options) {
+      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 ((event === 'add' || event === 'remove') && collection !== this) return;
+      if (event === 'destroy') this.remove(model, options);
+      if (model && event === 'change:' + model.idAttribute) {
+        delete this._byId[model.previous(model.idAttribute)];
+        if (model.id != null) this._byId[model.id] = model;
+      }
+      this.trigger.apply(this, arguments);
+    }
+
+  });
+
+  // Underscore methods that we want to implement on the Collection.
+  // 90% of the core usefulness of Backbone Collections is actually implemented
+  // right here:
+  var methods = ['forEach', 'each', 'map', 'collect', 'reduce', 'foldl',
+    'inject', 'reduceRight', 'foldr', 'find', 'detect', 'filter', 'select',
+    'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke',
+    'max', 'min', 'toArray', 'size', 'first', 'head', 'take', 'initial', 'rest',
+    'tail', 'drop', 'last', 'without', 'difference', 'indexOf', 'shuffle',
+    'lastIndexOf', 'isEmpty', 'chain', 'sample'];
+
+  // Mix in each Underscore method as a proxy to `Collection#models`.
+  _.each(methods, function(method) {
+    Collection.prototype[method] = function() {
+      var args = slice.call(arguments);
+      args.unshift(this.models);
+      return _[method].apply(_, args);
+    };
+  });
+
+  // Underscore methods that take a property name as an argument.
+  var attributeMethods = ['groupBy', 'countBy', 'sortBy', 'indexBy'];
+
+  // Use attributes instead of properties.
+  _.each(attributeMethods, function(method) {
+    Collection.prototype[method] = function(value, context) {
+      var iterator = _.isFunction(value) ? value : function(model) {
+        return model.get(value);
+      };
+      return _[method](this.models, iterator, context);
+    };
+  });
+
+  // Backbone.View
+  // -------------
+
+  // Backbone Views are almost more convention than they are actual code. A View
+  // is simply a JavaScript object that represents a logical chunk of UI in the
+  // DOM. This might be a single item, an entire list, a sidebar or panel, or
+  // even the surrounding frame which wraps your whole app. Defining a chunk of
+  // UI as a **View** allows you to define your DOM events declaratively, without
+  // having to worry about render order ... and makes it easy for the view to
+  // react to specific changes in the state of your models.
+
+  // Creating a Backbone.View creates its initial element outside of the DOM,
+  // if an existing element is not provided...
+  var View = Backbone.View = function(options) {
+    this.cid = _.uniqueId('view');
+    options || (options = {});
+    _.extend(this, _.pick(options, viewOptions));
+    this._ensureElement();
+    this.initialize.apply(this, arguments);
+    this.delegateEvents();
+  };
+
+  // Cached regex to split keys for `delegate`.
+  var delegateEventSplitter = /^(\S+)\s*(.*)$/;
+
+  // List of view options to be merged as properties.
+  var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events'];
+
+  // Set up all inheritable **Backbone.View** properties and methods.
+  _.extend(View.prototype, Events, {
+
+    // The default `tagName` of a View's element is `"div"`.
+    tagName: 'div',
+
+    // jQuery delegate for element lookup, scoped to DOM elements within the
+    // current view. This should be preferred to global lookups where possible.
+    $: function(selector) {
+      return this.$el.find(selector);
+    },
+
+    // Initialize is an empty function by default. Override it with your own
+    // initialization logic.
+    initialize: function(){},
+
+    // **render** is the core function that your view should override, in order
+    // to populate its element (`this.el`), with the appropriate HTML. The
+    // convention is for **render** to always return `this`.
+    render: function() {
+      return this;
+    },
+
+    // Remove this view by taking the element out of the DOM, and removing any
+    // applicable Backbone.Events listeners.
+    remove: function() {
+      this.$el.remove();
+      this.stopListening();
+      return this;
+    },
+
+    // Change the view's element (`this.el` property), including event
+    // re-delegation.
+    setElement: function(element, delegate) {
+      if (this.$el) this.undelegateEvents();
+      this.$el = element instanceof Backbone.$ ? element : Backbone.$(element);
+      this.el = this.$el[0];
+      if (delegate !== false) this.delegateEvents();
+      return this;
+    },
+
+    // Set callbacks, where `this.events` is a hash of
+    //
+    // *{"event selector": "callback"}*
+    //
+    //     {
+    //       'mousedown .title':  'edit',
+    //       'click .button':     'save',
+    //       'click .open':       function(e) { ... }
+    //     }
+    //
+    // pairs. Callbacks will be bound to the view, with `this` set properly.
+    // Uses event delegation for efficiency.
+    // Omitting the selector binds the event to `this.el`.
+    // This only works for delegate-able events: not `focus`, `blur`, and
+    // not `change`, `submit`, and `reset` in Internet Explorer.
+    delegateEvents: function(events) {
+      if (!(events || (events = _.result(this, 'events')))) return this;
+      this.undelegateEvents();
+      for (var key in events) {
+        var method = events[key];
+        if (!_.isFunction(method)) method = this[events[key]];
+        if (!method) continue;
+
+        var match = key.match(delegateEventSplitter);
+        var eventName = match[1], selector = match[2];
+        method = _.bind(method, this);
+        eventName += '.delegateEvents' + this.cid;
+        if (selector === '') {
+          this.$el.on(eventName, method);
+        } else {
+          this.$el.on(eventName, selector, method);
+        }
+      }
+      return this;
+    },
+
+    // Clears all callbacks previously bound to the view with `delegateEvents`.
+    // You usually don't need to use this, but may wish to if you have multiple
+    // Backbone views attached to the same DOM element.
+    undelegateEvents: function() {
+      this.$el.off('.delegateEvents' + this.cid);
+      return this;
+    },
+
+    // Ensure that the View has a DOM element to render into.
+    // If `this.el` is a string, pass it through `$()`, take the first
+    // matching element, and re-assign it to `el`. Otherwise, create
+    // an element from the `id`, `className` and `tagName` properties.
+    _ensureElement: function() {
+      if (!this.el) {
+        var attrs = _.extend({}, _.result(this, 'attributes'));
+        if (this.id) attrs.id = _.result(this, 'id');
+        if (this.className) attrs['class'] = _.result(this, 'className');
+        var $el = Backbone.$('<' + _.result(this, 'tagName') + '>').attr(attrs);
+        this.setElement($el, false);
+      } else {
+        this.setElement(_.result(this, 'el'), false);
+      }
+    }
+
+  });
+
+  // Backbone.sync
+  // -------------
+
+  // Override this function to change the manner in which Backbone persists
+  // models to the server. You will be passed the type of request, and the
+  // model in question. By default, makes a RESTful Ajax request
+  // to the model's `url()`. Some possible customizations could be:
+  //
+  // * Use `setTimeout` to batch rapid-fire updates into a single request.
+  // * Send up the models as XML instead of JSON.
+  // * Persist models via WebSockets instead of Ajax.
+  //
+  // Turn on `Backbone.emulateHTTP` in order to send `PUT` and `DELETE` requests
+  // as `POST`, with a `_method` parameter containing the true HTTP method,
+  // as well as all requests with the body as `application/x-www-form-urlencoded`
+  // instead of `application/json` with the model in a param named `model`.
+  // Useful when interfacing with server-side languages like **PHP** that make
+  // it difficult to read the body of `PUT` requests.
+  Backbone.sync = function(method, model, options) {
+    var type = methodMap[method];
+
+    // Default options, unless specified.
+    _.defaults(options || (options = {}), {
+      emulateHTTP: Backbone.emulateHTTP,
+      emulateJSON: Backbone.emulateJSON
+    });
+
+    // Default JSON-request options.
+    var params = {type: type, dataType: 'json'};
+
+    // Ensure that we have a URL.
+    if (!options.url) {
+      params.url = _.result(model, 'url') || urlError();
+    }
+
+    // Ensure that we have the appropriate request data.
+    if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) {
+      params.contentType = 'application/json';
+      params.data = JSON.stringify(options.attrs || model.toJSON(options));
+    }
+
+    // For older servers, emulate JSON by encoding the request into an HTML-form.
+    if (options.emulateJSON) {
+      params.contentType = 'application/x-www-form-urlencoded';
+      params.data = params.data ? {model: params.data} : {};
+    }
+
+    // For older servers, emulate HTTP by mimicking the HTTP method with `_method`
+    // And an `X-HTTP-Method-Override` header.
+    if (options.emulateHTTP && (type === 'PUT' || type === 'DELETE' || type === 'PATCH')) {
+      params.type = 'POST';
+      if (options.emulateJSON) params.data._method = type;
+      var beforeSend = options.beforeSend;
+      options.beforeSend = function(xhr) {
+        xhr.setRequestHeader('X-HTTP-Method-Override', type);
+        if (beforeSend) return beforeSend.apply(this, arguments);
+      };
+    }
+
+    // Don't process data on a non-GET request.
+    if (params.type !== 'GET' && !options.emulateJSON) {
+      params.processData = false;
+    }
+
+    // If we're sending a `PATCH` request, and we're in an old Internet Explorer
+    // that still has ActiveX enabled by default, override jQuery to use that
+    // for XHR instead. Remove this line when jQuery supports `PATCH` on IE8.
+    if (params.type === 'PATCH' && noXhrPatch) {
+      params.xhr = function() {
+        return new ActiveXObject("Microsoft.XMLHTTP");
+      };
+    }
+
+    // Make the request, allowing the user to override any Ajax options.
+    var xhr = options.xhr = Backbone.ajax(_.extend(params, options));
+    model.trigger('request', model, xhr, options);
+    return xhr;
+  };
+
+  var noXhrPatch =
+    typeof window !== 'undefined' && !!window.ActiveXObject &&
+      !(window.XMLHttpRequest && (new XMLHttpRequest).dispatchEvent);
+
+  // Map from CRUD to HTTP for our default `Backbone.sync` implementation.
+  var methodMap = {
+    'create': 'POST',
+    'update': 'PUT',
+    'patch':  'PATCH',
+    'delete': 'DELETE',
+    'read':   'GET'
+  };
+
+  // Set the default implementation of `Backbone.ajax` to proxy through to `$`.
+  // Override this if you'd like to use a different library.
+  Backbone.ajax = function() {
+    return Backbone.$.ajax.apply(Backbone.$, arguments);
+  };
+
+  // Backbone.Router
+  // ---------------
+
+  // Routers map faux-URLs to actions, and fire events when routes are
+  // matched. Creating a new one sets its `routes` hash, if not set statically.
+  var Router = Backbone.Router = function(options) {
+    options || (options = {});
+    if (options.routes) this.routes = options.routes;
+    this._bindRoutes();
+    this.initialize.apply(this, arguments);
+  };
+
+  // Cached regular expressions for matching named param parts and splatted
+  // parts of route strings.
+  var optionalParam = /\((.*?)\)/g;
+  var namedParam    = /(\(\?)?:\w+/g;
+  var splatParam    = /\*\w+/g;
+  var escapeRegExp  = /[\-{}\[\]+?.,\\\^$|#\s]/g;
+
+  // Set up all inheritable **Backbone.Router** properties and methods.
+  _.extend(Router.prototype, Events, {
+
+    // Initialize is an empty function by default. Override it with your own
+    // initialization logic.
+    initialize: function(){},
+
+    // Manually bind a single named route to a callback. For example:
+    //
+    //     this.route('search/:query/p:num', 'search', function(query, num) {
+    //       ...
+    //     });
+    //
+    route: function(route, name, callback) {
+      if (!_.isRegExp(route)) route = this._routeToRegExp(route);
+      if (_.isFunction(name)) {
+        callback = name;
+        name = '';
+      }
+      if (!callback) callback = this[name];
+      var router = this;
+      Backbone.history.route(route, function(fragment) {
+        var args = router._extractParameters(route, fragment);
+        router.execute(callback, args);
+        router.trigger.apply(router, ['route:' + name].concat(args));
+        router.trigger('route', name, args);
+        Backbone.history.trigger('route', router, name, args);
+      });
+      return this;
+    },
+
+    // Execute a route handler with the provided parameters.  This is an
+    // excellent place to do pre-route setup or post-route cleanup.
+    execute: function(callback, args) {
+      if (callback) callback.apply(this, args);
+    },
+
+    // Simple proxy to `Backbone.history` to save a fragment into the history.
+    navigate: function(fragment, options) {
+      Backbone.history.navigate(fragment, options);
+      return this;
+    },
+
+    // Bind all defined routes to `Backbone.history`. We have to reverse the
+    // order of the routes here to support behavior where the most general
+    // routes can be defined at the bottom of the route map.
+    _bindRoutes: function() {
+      if (!this.routes) return;
+      this.routes = _.result(this, 'routes');
+      var route, routes = _.keys(this.routes);
+      while ((route = routes.pop()) != null) {
+        this.route(route, this.routes[route]);
+      }
+    },
+
+    // Convert a route string into a regular expression, suitable for matching
+    // against the current location hash.
+    _routeToRegExp: function(route) {
+      route = route.replace(escapeRegExp, '\\$&')
+                   .replace(optionalParam, '(?:$1)?')
+                   .replace(namedParam, function(match, optional) {
+                     return optional ? match : '([^/?]+)';
+                   })
+                   .replace(splatParam, '([^?]*?)');
+      return new RegExp('^' + route + '(?:\\?([\\s\\S]*))?$');
+    },
+
+    // Given a route, and a URL fragment that it matches, return the array of
+    // extracted decoded parameters. Empty or unmatched parameters will be
+    // treated as `null` to normalize cross-browser behavior.
+    _extractParameters: function(route, fragment) {
+      var params = route.exec(fragment).slice(1);
+      return _.map(params, function(param, i) {
+        // Don't decode the search params.
+        if (i === params.length - 1) return param || null;
+        return param ? decodeURIComponent(param) : null;
+      });
+    }
+
+  });
+
+  // Backbone.History
+  // ----------------
+
+  // Handles cross-browser history management, based on either
+  // [pushState](http://diveintohtml5.info/history.html) and real URLs, or
+  // [onhashchange](https://developer.mozilla.org/en-US/docs/DOM/window.onhashchange)
+  // and URL fragments. If the browser supports neither (old IE, natch),
+  // falls back to polling.
+  var History = Backbone.History = function() {
+    this.handlers = [];
+    _.bindAll(this, 'checkUrl');
+
+    // Ensure that `History` can be used outside of the browser.
+    if (typeof window !== 'undefined') {
+      this.location = window.location;
+      this.history = window.history;
+    }
+  };
+
+  // Cached regex for stripping a leading hash/slash and trailing space.
+  var routeStripper = /^[#\/]|\s+$/g;
+
+  // Cached regex for stripping leading and trailing slashes.
+  var rootStripper = /^\/+|\/+$/g;
+
+  // Cached regex for detecting MSIE.
+  var isExplorer = /msie [\w.]+/;
+
+  // Cached regex for removing a trailing slash.
+  var trailingSlash = /\/$/;
+
+  // Cached regex for stripping urls of hash.
+  var pathStripper = /#.*$/;
+
+  // Has the history handling already been started?
+  History.started = false;
+
+  // Set up all inheritable **Backbone.History** properties and methods.
+  _.extend(History.prototype, Events, {
+
+    // The default interval to poll for hash changes, if necessary, is
+    // twenty times a second.
+    interval: 50,
+
+    // Are we at the app root?
+    atRoot: function() {
+      return this.location.pathname.replace(/[^\/]$/, '$&/') === this.root;
+    },
+
+    // Gets the true hash value. Cannot use location.hash directly due to bug
+    // in Firefox where location.hash will always be decoded.
+    getHash: function(window) {
+      var match = (window || this).location.href.match(/#(.*)$/);
+      return match ? match[1] : '';
+    },
+
+    // Get the cross-browser normalized URL fragment, either from the URL,
+    // the hash, or the override.
+    getFragment: function(fragment, forcePushState) {
+      if (fragment == null) {
+        if (this._hasPushState || !this._wantsHashChange || forcePushState) {
+          fragment = decodeURI(this.location.pathname + this.location.search);
+          var root = this.root.replace(trailingSlash, '');
+          if (!fragment.indexOf(root)) fragment = fragment.slice(root.length);
+        } else {
+          fragment = this.getHash();
+        }
+      }
+      return fragment.replace(routeStripper, '');
+    },
+
+    // Start the hash change handling, returning `true` if the current URL matches
+    // an existing route, and `false` otherwise.
+    start: function(options) {
+      if (History.started) throw new Error("Backbone.history has already been started");
+      History.started = true;
+
+      // Figure out the initial configuration. Do we need an iframe?
+      // Is pushState desired ... is it available?
+      this.options          = _.extend({root: '/'}, this.options, options);
+      this.root             = this.options.root;
+      this._wantsHashChange = this.options.hashChange !== false;
+      this._wantsPushState  = !!this.options.pushState;
+      this._hasPushState    = !!(this.options.pushState && this.history && this.history.pushState);
+      var fragment          = this.getFragment();
+      var docMode           = document.documentMode;
+      var oldIE             = (isExplorer.exec(navigator.userAgent.toLowerCase()) && (!docMode || docMode <= 7));
+
+      // Normalize root to always include a leading and trailing slash.
+      this.root = ('/' + this.root + '/').replace(rootStripper, '/');
+
+      if (oldIE && this._wantsHashChange) {
+        var frame = Backbone.$('<iframe src="javascript:0" tabindex="-1">');
+        this.iframe = frame.hide().appendTo('body')[0].contentWindow;
+        this.navigate(fragment);
+      }
+
+      // Depending on whether we're using pushState or hashes, and whether
+      // 'onhashchange' is supported, determine how we check the URL state.
+      if (this._hasPushState) {
+        Backbone.$(window).on('popstate', this.checkUrl);
+      } else if (this._wantsHashChange && ('onhashchange' in window) && !oldIE) {
+        Backbone.$(window).on('hashchange', this.checkUrl);
+      } else if (this._wantsHashChange) {
+        this._checkUrlInterval = setInterval(this.checkUrl, this.interval);
+      }
+
+      // Determine if we need to change the base url, for a pushState link
+      // opened by a non-pushState browser.
+      this.fragment = fragment;
+      var loc = this.location;
+
+      // Transition from hashChange to pushState or vice versa if both are
+      // requested.
+      if (this._wantsHashChange && this._wantsPushState) {
+
+        // If we've started off with a route from a `pushState`-enabled
+        // browser, but we're currently in a browser that doesn't support it...
+        if (!this._hasPushState && !this.atRoot()) {
+          this.fragment = this.getFragment(null, true);
+          this.location.replace(this.root + '#' + this.fragment);
+          // Return immediately as browser will do redirect to new url
+          return true;
+
+        // Or if we've started out with a hash-based route, but we're currently
+        // in a browser where it could be `pushState`-based instead...
+        } else if (this._hasPushState && this.atRoot() && loc.hash) {
+          this.fragment = this.getHash().replace(routeStripper, '');
+          this.history.replaceState({}, document.title, this.root + this.fragment);
+        }
+
+      }
+
+      if (!this.options.silent) return this.loadUrl();
+    },
+
+    // Disable Backbone.history, perhaps temporarily. Not useful in a real app,
+    // but possibly useful for unit testing Routers.
+    stop: function() {
+      Backbone.$(window).off('popstate', this.checkUrl).off('hashchange', this.checkUrl);
+      if (this._checkUrlInterval) clearInterval(this._checkUrlInterval);
+      History.started = false;
+    },
+
+    // Add a route to be tested when the fragment changes. Routes added later
+    // may override previous routes.
+    route: function(route, callback) {
+      this.handlers.unshift({route: route, callback: callback});
+    },
+
+    // Checks the current URL to see if it has changed, and if it has,
+    // calls `loadUrl`, normalizing across the hidden iframe.
+    checkUrl: function(e) {
+      var current = this.getFragment();
+      if (current === this.fragment && this.iframe) {
+        current = this.getFragment(this.getHash(this.iframe));
+      }
+      if (current === this.fragment) return false;
+      if (this.iframe) this.navigate(current);
+      this.loadUrl();
+    },
+
+    // Attempt to load the current URL fragment. If a route succeeds with a
+    // match, returns `true`. If no defined routes matches the fragment,
+    // returns `false`.
+    loadUrl: function(fragment) {
+      fragment = this.fragment = this.getFragment(fragment);
+      return _.any(this.handlers, function(handler) {
+        if (handler.route.test(fragment)) {
+          handler.callback(fragment);
+          return true;
+        }
+      });
+    },
+
+    // Save a fragment into the hash history, or replace the URL state if the
+    // 'replace' option is passed. You are responsible for properly URL-encoding
+    // the fragment in advance.
+    //
+    // The options object can contain `trigger: true` if you wish to have the
+    // route callback be fired (not usually desirable), or `replace: true`, if
+    // you wish to modify the current URL without adding an entry to the history.
+    navigate: function(fragment, options) {
+      if (!History.started) return false;
+      if (!options || options === true) options = {trigger: !!options};
+
+      var url = this.root + (fragment = this.getFragment(fragment || ''));
+
+      // Strip the hash for matching.
+      fragment = fragment.replace(pathStripper, '');
+
+      if (this.fragment === fragment) return;
+      this.fragment = fragment;
+
+      // Don't include a trailing slash on the root.
+      if (fragment === '' && url !== '/') url = url.slice(0, -1);
+
+      // If pushState is available, we use it to set the fragment as a real URL.
+      if (this._hasPushState) {
+        this.history[options.replace ? 'replaceState' : 'pushState']({}, document.title, url);
+
+      // If hash changes haven't been explicitly disabled, update the hash
+      // fragment to store history.
+      } else if (this._wantsHashChange) {
+        this._updateHash(this.location, fragment, options.replace);
+        if (this.iframe && (fragment !== this.getFragment(this.getHash(this.iframe)))) {
+          // Opening and closing the iframe tricks IE7 and earlier to push a
+          // history entry on hash-tag change.  When replace is true, we don't
+          // want this.
+          if(!options.replace) this.iframe.document.open().close();
+          this._updateHash(this.iframe.location, fragment, options.replace);
+        }
+
+      // If you've told us that you explicitly don't want fallback hashchange-
+      // based history, then `navigate` becomes a page refresh.
+      } else {
+        return this.location.assign(url);
+      }
+      if (options.trigger) return this.loadUrl(fragment);
+    },
+
+    // Update the hash location, either replacing the current entry, or adding
+    // a new one to the browser history.
+    _updateHash: function(location, fragment, replace) {
+      if (replace) {
+        var href = location.href.replace(/(javascript:|#).*$/, '');
+        location.replace(href + '#' + fragment);
+      } else {
+        // Some browsers require that `hash` contains a leading #.
+        location.hash = '#' + fragment;
+      }
+    }
+
+  });
+
+  // Create the default Backbone.history.
+  Backbone.history = new History;
+
+  // Helpers
+  // -------
+
+  // Helper function to correctly set up the prototype chain, for subclasses.
+  // Similar to `goog.inherits`, but uses a hash of prototype properties and
+  // class properties to be extended.
+  var extend = function(protoProps, staticProps) {
+    var parent = this;
+    var child;
+
+    // The constructor function for the new subclass is either defined by you
+    // (the "constructor" property in your `extend` definition), or defaulted
+    // by us to simply call the parent's constructor.
+    if (protoProps && _.has(protoProps, 'constructor')) {
+      child = protoProps.constructor;
+    } else {
+      child = function(){ return parent.apply(this, arguments); };
+    }
+
+    // Add static properties to the constructor function, if supplied.
+    _.extend(child, parent, staticProps);
+
+    // Set the prototype chain to inherit from `parent`, without calling
+    // `parent`'s constructor function.
+    var Surrogate = function(){ this.constructor = child; };
+    Surrogate.prototype = parent.prototype;
+    child.prototype = new Surrogate;
+
+    // Add prototype properties (instance properties) to the subclass,
+    // if supplied.
+    if (protoProps) _.extend(child.prototype, protoProps);
+
+    // Set a convenience property in case the parent's prototype is needed
+    // later.
+    child.__super__ = parent.prototype;
+
+    return child;
+  };
+
+  // Set up inheritance for the model, collection, router, view and history.
+  Model.extend = Collection.extend = Router.extend = View.extend = History.extend = extend;
+
+  // Throw an error when a URL is needed, and none is supplied.
+  var urlError = function() {
+    throw new Error('A "url" property or function must be specified');
+  };
+
+  // Wrap an optional error callback with a fallback error event.
+  var wrapError = function(model, options) {
+    var error = options.error;
+    options.error = function(resp) {
+      if (error) error(model, resp, options);
+      model.trigger('error', model, resp, options);
+    };
+  };
+
+  return Backbone;
+
+}));
diff --git a/xos/core/xoslib/static/js/vendor/backbone.marionette.js b/xos/core/xoslib/static/js/vendor/backbone.marionette.js
new file mode 100644
index 0000000..cebd22b
--- /dev/null
+++ b/xos/core/xoslib/static/js/vendor/backbone.marionette.js
@@ -0,0 +1,2793 @@
+// MarionetteJS (Backbone.Marionette)
+// ----------------------------------
+// v2.0.1
+//
+// Copyright (c)2014 Derick Bailey, Muted Solutions, LLC.
+// Distributed under MIT license
+//
+// http://marionettejs.com
+
+(function(root, factory) {
+
+  if (typeof define === 'function' && define.amd) {
+    define(['backbone', 'underscore', 'backbone.wreqr', 'backbone.babysitter'], function(Backbone, _) {
+      return (root.Marionette = factory(root, Backbone, _));
+    });
+  } else if (typeof exports !== 'undefined') {
+    var Backbone = require('backbone');
+    var _ = require('underscore');
+    var Wreqr = require('backbone.wreqr');
+    var BabySitter = require('backbone.babysitter');
+    module.exports = factory(root, Backbone, _);
+  } else {
+    root.Marionette = factory(root, root.Backbone, root._);
+  }
+
+}(this, function(root, Backbone, _) {
+  'use strict';
+
+  var previousMarionette = root.Marionette;
+
+  var Marionette = Backbone.Marionette = {};
+
+  Marionette.VERSION = '2.0.1';
+
+  Marionette.noConflict = function() {
+    root.Marionette = previousMarionette;
+    return this;
+  };
+
+  // Get the Deferred creator for later use
+  Marionette.Deferred = Backbone.$.Deferred;
+
+  /* jshint unused: false */
+  
+  // Helpers
+  // -------
+  
+  // For slicing `arguments` in functions
+  var slice = Array.prototype.slice;
+  
+  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 && (target.options[optionName] !== undefined)) {
+      value = target.options[optionName];
+    } else {
+      value = target[optionName];
+    }
+  
+    return value;
+  };
+  
+  // Proxy `Marionette.getOption`
+  Marionette.proxyGetOption = function(optionName) {
+    return Marionette.getOption(this, optionName);
+  };
+  
+  // Marionette.normalizeMethods
+  // ----------------------
+  
+  // Pass in a mapping of events => functions or function names
+  // and return a mapping of events => functions
+  Marionette.normalizeMethods = function(hash) {
+    var normalizedHash = {}, method;
+    _.each(hash, function(fn, name) {
+      method = fn;
+      if (!_.isFunction(method)) {
+        method = this[method];
+      }
+      if (!method) {
+        return;
+      }
+      normalizedHash[name] = method;
+    }, this);
+    return normalizedHash;
+  };
+  
+  
+  // allows for the use of the @ui. syntax within
+  // a given key for triggers and events
+  // swaps the @ui with the associated selector
+  Marionette.normalizeUIKeys = function(hash, ui) {
+    if (typeof(hash) === 'undefined') {
+      return;
+    }
+  
+    _.each(_.keys(hash), function(v) {
+      var pattern = /@ui.[a-zA-Z_$0-9]*/g;
+      if (v.match(pattern)) {
+        hash[v.replace(pattern, function(r) {
+          return ui[r.slice(4)];
+        })] = hash[v];
+        delete hash[v];
+      }
+    });
+  
+    return hash;
+  };
+  
+  // Mix in methods from Underscore, for iteration, and other
+  // collection related features.
+  // Borrowing this code from Backbone.Collection:
+  // http://backbonejs.org/docs/backbone.html#section-106
+  Marionette.actAsCollection = function(object, listProperty) {
+    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) {
+      object[method] = function() {
+        var list = _.values(_.result(this, listProperty));
+        var args = [list].concat(_.toArray(arguments));
+        return _[method].apply(_, args);
+      };
+    });
+  };
+  
+  // 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 implementation
+    var triggerMethod = function(event) {
+      // get the method name from the event name
+      var methodName = 'on' + event.replace(splitter, getEventName);
+      var method = this[methodName];
+      var result;
+  
+      // call the onMethodName if it exists
+      if (_.isFunction(method)) {
+        // pass all arguments, except the event name
+        result = method.apply(this, _.tail(arguments));
+      }
+  
+      // trigger the event, if a trigger method exists
+      if (_.isFunction(this.trigger)) {
+        this.trigger.apply(this, arguments);
+      }
+  
+      return result;
+    };
+  
+    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(documentElement) {
+    // 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 && isInDOM(view)) {
+        if (_.isFunction(view.triggerMethod)) {
+          view.triggerMethod('dom:refresh');
+        }
+      }
+    }
+  
+    function isInDOM(view) {
+      return documentElement.contains(view.el);
+    }
+  
+    // Export public API
+    return function(view) {
+      view.listenTo(view, 'show', function() {
+        handleShow(view);
+      });
+  
+      view.listenTo(view, 'render', function() {
+        handleRender(view);
+      });
+    };
+  })(document.documentElement);
+  
+
+  /* jshint maxparams: 5 */
+  
+  // 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);
+      });
+    }
+  
+    // Bind the event to a supplied callback function
+    function bindToFunction(target, entity, evt, method) {
+      target.listenTo(entity, evt, method);
+    }
+  
+    // 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);
+      });
+    }
+  
+    // Bind the event to a supplied callback function
+    function unbindToFunction(target, entity, evt, method) {
+      target.stopListening(entity, evt, method);
+    }
+  
+  
+    // 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);
+    };
+  
+    // Proxy `bindEntityEvents`
+    Marionette.proxyBindEntityEvents = function(entity, bindings) {
+      return Marionette.bindEntityEvents(this, entity, bindings);
+    };
+  
+    // Proxy `unbindEntityEvents`
+    Marionette.proxyUnbindEntityEvents = function(entity, bindings) {
+      return Marionette.unbindEntityEvents(this, entity, bindings);
+    };
+  })(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) {
+      var promise = _.result(this._deferred, 'promise');
+  
+      this._callbacks.push({cb: callback, ctx: contextOverride});
+  
+      promise.then(function(args) {
+        if (contextOverride){ args.context = contextOverride; }
+        callback.call(args.context, args.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({
+        options: options,
+        context: context
+      });
+    },
+  
+    // 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, {
+    destroy: function() {
+      var args = Array.prototype.slice.call(arguments);
+      this.triggerMethod.apply(this, ['before:destroy'].concat(args));
+      this.triggerMethod.apply(this, ['destroy'].concat(args));
+  
+      this.stopListening();
+      this.off();
+    },
+  
+    // import the `triggerMethod` to trigger events with corresponding
+    // methods if the method exists
+    triggerMethod: Marionette.triggerMethod,
+  
+    // Proxy `getOption` to enable getting options from this or this.options by name.
+    getOption: Marionette.proxyGetOption
+  
+  });
+  
+  /* jshint maxcomplexity: 10, maxstatements: 27 */
+  
+  // 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 = this.getOption('el');
+  
+    // Handle when this.el is passed in as a $ wrapped element.
+    this.el = this.el instanceof Backbone.$ ? this.el[0] : this.el;
+  
+    if (!this.el) {
+      throwError('An "el" must be specified for a region.', 'NoElError');
+    }
+  
+    this.$el = this.getEl(this.el);
+  
+    if (this.initialize) {
+      var args = Array.prototype.slice.apply(arguments);
+      this.initialize.apply(this, args);
+    }
+  };
+  
+  
+  // Region Class methods
+  // -------------------
+  
+  _.extend(Marionette.Region, {
+  
+    // Build an instance of a region by passing in a configuration object
+    // and a default region class to use if none is specified in the config.
+    //
+    // The config object should either be a string as a jQuery DOM selector,
+    // a Region class directly, or an object literal that specifies both
+    // a selector and regionClass:
+    //
+    // ```js
+    // {
+    //   selector: "#foo",
+    //   regionClass: MyCustomRegion
+    // }
+    // ```
+    //
+    buildRegion: function(regionConfig, defaultRegionClass) {
+      var regionIsString = _.isString(regionConfig);
+      var regionSelectorIsString = _.isString(regionConfig.selector);
+      var regionClassIsUndefined = _.isUndefined(regionConfig.regionClass);
+      var regionIsClass = _.isFunction(regionConfig);
+  
+      if (!regionIsClass && !regionIsString && !regionSelectorIsString) {
+        throwError('Region must be specified as a Region class,' +
+          'a selector string or an object with selector property');
+      }
+  
+      var selector, RegionClass;
+  
+      // get the selector for the region
+  
+      if (regionIsString) {
+        selector = regionConfig;
+      }
+  
+      if (regionConfig.selector) {
+        selector = regionConfig.selector;
+        delete regionConfig.selector;
+      }
+  
+      // get the class for the region
+  
+      if (regionIsClass) {
+        RegionClass = regionConfig;
+      }
+  
+      if (!regionIsClass && regionClassIsUndefined) {
+        RegionClass = defaultRegionClass;
+      }
+  
+      if (regionConfig.regionClass) {
+        RegionClass = regionConfig.regionClass;
+        delete regionConfig.regionClass;
+      }
+  
+      if (regionIsString || regionIsClass) {
+        regionConfig = {};
+      }
+  
+      regionConfig.el = selector;
+  
+      // build the region instance
+      var region = new RegionClass(regionConfig);
+  
+      // 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(el) {
+          if (_.isObject(el)) {
+            return Backbone.$(el);
+          }
+          var parentEl = regionConfig.parentEl;
+          if (_.isFunction(parentEl)) {
+            parentEl = parentEl();
+          }
+          return parentEl.find(el);
+        };
+      }
+  
+      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 `onDestroy` method on your view, just after showing
+    // or just before destroying the view, respectively.
+    // The `preventDestroy` option can be used to prevent a view from
+    // the old view being destroyed on show.
+    // The `forceShow` option can be used to force a view to be
+    // re-rendered if it's already shown in the region.
+  
+    show: function(view, options){
+      this._ensureElement();
+  
+      var showOptions = options || {};
+      var isDifferentView = view !== this.currentView;
+      var preventDestroy =  !!showOptions.preventDestroy;
+      var forceShow = !!showOptions.forceShow;
+  
+      // we are only changing the view if there is a view to change to begin with
+      var isChangingView = !!this.currentView;
+  
+      // only destroy the view if we don't want to preventDestroy and the view is different
+      var _shouldDestroyView = !preventDestroy && isDifferentView;
+  
+      if (_shouldDestroyView) {
+        this.empty();
+      }
+  
+      // show the view if the view is different or if you want to re-show the view
+      var _shouldShowView = isDifferentView || forceShow;
+  
+      if (_shouldShowView) {
+        view.render();
+  
+        if (isChangingView) {
+          this.triggerMethod('before:swap', view);
+        }
+  
+        this.triggerMethod('before:show', view);
+        this.triggerMethod.call(view, 'before:show');
+  
+        this.attachHtml(view);
+        this.currentView = view;
+  
+        if (isChangingView) {
+          this.triggerMethod('swap', view);
+        }
+  
+        this.triggerMethod('show', view);
+  
+        if (_.isFunction(view.triggerMethod)) {
+          view.triggerMethod('show');
+        } else {
+          this.triggerMethod.call(view, 'show');
+        }
+  
+        return this;
+      }
+  
+      return this;
+    },
+  
+    _ensureElement: function(){
+      if (!_.isObject(this.el)) {
+        this.$el = this.getEl(this.el);
+        this.el = this.$el[0];
+      }
+  
+      if (!this.$el || this.$el.length === 0) {
+        throwError('An "el" ' + this.$el.selector + ' must exist in DOM');
+      }
+    },
+  
+    // Override this method to change how the region finds the
+    // DOM element that it manages. Return a jQuery selector object.
+    getEl: function(el) {
+      return Backbone.$(el);
+    },
+  
+    // Override this method to change how the new view is
+    // appended to the `$el` that the region is managing
+    attachHtml: function(view) {
+      // empty the node and append new view
+      this.el.innerHTML='';
+      this.el.appendChild(view.el);
+    },
+  
+    // Destroy the current view, if there is one. If there is no
+    // current view, it does nothing and returns immediately.
+    empty: function() {
+      var view = this.currentView;
+      if (!view || view.isDestroyed) { return; }
+  
+      this.triggerMethod('before:empty', view);
+  
+      // call 'destroy' or 'remove', depending on which is found
+      if (view.destroy) { view.destroy(); }
+      else if (view.remove) { view.remove(); }
+  
+      this.triggerMethod('empty', view);
+  
+      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 destroying 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.empty();
+  
+      if (this.$el) {
+        this.el = this.$el.selector;
+      }
+  
+      delete this.$el;
+    },
+  
+    // Proxy `getOption` to enable getting options from this or this.options by name.
+    getOption: Marionette.proxyGetOption,
+  
+    // import the `triggerMethod` to trigger events with corresponding
+    // methods if the method exists
+    triggerMethod: Marionette.triggerMethod
+  });
+  
+  // 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.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 (_.isString(definition)) {
+            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.triggerMethod('before:add:region', name, region);
+  
+        this._store(name, region);
+  
+        this.triggerMethod('add:region', name, region);
+        return region;
+      },
+  
+      // Get a region by name
+      get: function(name) {
+        return this._regions[name];
+      },
+  
+      // Gets all the regions contained within
+      // the `regionManager` instance.
+      getRegions: function(){
+        return _.clone(this._regions);
+      },
+  
+      // Remove a region by name
+      removeRegion: function(name) {
+        var region = this._regions[name];
+        this._remove(name, region);
+      },
+  
+      // Empty all regions in the region manager, and
+      // remove them
+      removeRegions: function() {
+        _.each(this._regions, function(region, name) {
+          this._remove(name, region);
+        }, this);
+      },
+  
+      // Empty all regions in the region manager, but
+      // leave them attached
+      emptyRegions: function() {
+        _.each(this._regions, function(region) {
+          region.empty();
+        }, this);
+      },
+  
+      // Destroy all regions and shut down the region
+      // manager entirely
+      destroy: function() {
+        this.removeRegions();
+        Marionette.Controller.prototype.destroy.apply(this, arguments);
+      },
+  
+      // 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) {
+        this.triggerMethod('before:remove:region', name, region);
+        region.empty();
+        region.stopListening();
+        delete this._regions[name];
+        this._setLength();
+        this.triggerMethod('remove:region', name, region);
+      },
+  
+      // set the number of regions current held
+      _setLength: function() {
+        this.length = _.size(this._regions);
+      }
+  
+    });
+  
+    Marionette.actAsCollection(RegionManager.prototype, '_regions');
+  
+    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.call(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 = Backbone.$(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) {
+        throwError('Cannot render the template since its false, null or undefined.',
+          'TemplateNotFoundError');
+      }
+  
+      var templateFunc;
+      if (typeof template === 'function') {
+        templateFunc = template;
+      } else {
+        templateFunc = Marionette.TemplateCache.get(template);
+      }
+  
+      return templateFunc(data);
+    }
+  };
+  
+
+  /* jshint maxlen: 114, nonew: false */
+  // Marionette.View
+  // ---------------
+  
+  // The core view class that other Marionette views extend from.
+  Marionette.View = Backbone.View.extend({
+  
+    constructor: function(options) {
+      _.bindAll(this, 'render');
+  
+      // this exposes view options to the view initializer
+      // this is a backfill since backbone removed the assignment
+      // of this.options
+      // at some point however this may be removed
+      this.options = _.extend({}, _.result(this, 'options'), _.isFunction(options) ? options.call(this) : options);
+      // parses out the @ui DSL for events
+      this.events = this.normalizeUIKeys(_.result(this, 'events'));
+  
+      if (_.isObject(this.behaviors)) {
+        new Marionette.Behaviors(this);
+      }
+  
+      Backbone.View.apply(this, arguments);
+  
+      Marionette.MonitorDOMRefresh(this);
+      this.listenTo(this, 'show', this.onShowCalled);
+    },
+  
+    // 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 this.getOption('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 = this.getOption('templateHelpers');
+      if (_.isFunction(templateHelpers)) {
+        templateHelpers = templateHelpers.call(this);
+      }
+      return _.extend(target, templateHelpers);
+    },
+  
+  
+    normalizeUIKeys: function(hash) {
+      var ui = _.result(this, 'ui');
+      var uiBindings = _.result(this, '_uiBindings');
+      return Marionette.normalizeUIKeys(hash, uiBindings || ui);
+    },
+  
+    // 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 = this.normalizeUIKeys(_.result(this, 'triggers'));
+  
+      // Configure the triggers, prevent default
+      // action and stop propagation of DOM events
+      _.each(triggers, function(value, key) {
+  
+        var hasOptions = _.isObject(value);
+        var eventName = hasOptions ? value.event : value;
+  
+        // build the event handler function for the DOM event
+        triggerEvents[key] = function(e) {
+  
+          // stop the event in its tracks
+          if (e) {
+            var prevent = e.preventDefault;
+            var stop = e.stopPropagation;
+  
+            var shouldPrevent = hasOptions ? value.preventDefault : prevent;
+            var shouldStop = hasOptions ? value.stopPropagation : stop;
+  
+            if (shouldPrevent && prevent) { prevent.apply(e); }
+            if (shouldStop && stop) { stop.apply(e); }
+          }
+  
+          // build the args for the event
+          var args = {
+            view: this,
+            model: this.model,
+            collection: this.collection
+          };
+  
+          // trigger the event
+          this.triggerMethod(eventName, args);
+        };
+  
+      }, this);
+  
+      return triggerEvents;
+    },
+  
+    // Overriding Backbone.View's delegateEvents to handle
+    // the `triggers`, `modelEvents`, and `collectionEvents` configuration
+    delegateEvents: function(events) {
+      this._delegateDOMEvents(events);
+      this.bindEntityEvents(this.model, this.getOption('modelEvents'));
+      this.bindEntityEvents(this.collection, this.getOption('collectionEvents'));
+    },
+  
+    // internal method to delegate DOM events and triggers
+    _delegateDOMEvents: function(events) {
+      events = events || this.events;
+      if (_.isFunction(events)) { events = events.call(this); }
+  
+      // normalize ui keys
+      events = this.normalizeUIKeys(events);
+  
+      var combinedEvents = {};
+  
+      // look up if this view has behavior events
+      var behaviorEvents = _.result(this, 'behaviorEvents') || {};
+      var triggers = this.configureTriggers();
+  
+      // behavior events will be overriden by view events and or triggers
+      _.extend(combinedEvents, behaviorEvents, 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);
+      this.unbindEntityEvents(this.model, this.getOption('modelEvents'));
+      this.unbindEntityEvents(this.collection, this.getOption('collectionEvents'));
+    },
+  
+    // Internal method, handles the `show` event.
+    onShowCalled: function() {},
+  
+    // Internal helper method to verify whether the view hasn't been destroyed
+    _ensureViewIsIntact: function() {
+      if (this.isDestroyed) {
+        var err = new Error('Cannot use a view thats already been destroyed.');
+        err.name = 'ViewDestroyedError';
+        throw err;
+      }
+    },
+  
+    // Default `destroy` implementation, for removing a view from the
+    // DOM and unbinding it. Regions will call this method
+    // for you. You can specify an `onDestroy` method in your view to
+    // add custom code that is called after the view is destroyed.
+    destroy: function() {
+      if (this.isDestroyed) { return; }
+  
+      var args = Array.prototype.slice.call(arguments);
+  
+      this.triggerMethod.apply(this, ['before:destroy'].concat(args));
+  
+      // mark as destroyed before doing the actual destroy, to
+      // prevent infinite loops within "destroy" event handlers
+      // that are trying to destroy other views
+      this.isDestroyed = true;
+      this.triggerMethod.apply(this, ['destroy'].concat(args));
+  
+      // 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;
+    },
+  
+    // import the `triggerMethod` to trigger events with corresponding
+    // methods if the method exists
+    triggerMethod: Marionette.triggerMethod,
+  
+    // Imports the "normalizeMethods" to transform hashes of
+    // events=>function references/names to a hash of events=>function references
+    normalizeMethods: Marionette.normalizeMethods,
+  
+    // Proxy `getOption` to enable getting options from this or this.options by name.
+    getOption: Marionette.proxyGetOption,
+  
+    // Proxy `unbindEntityEvents` to enable binding view's events from another entity.
+    bindEntityEvents: Marionette.proxyBindEntityEvents,
+  
+    // Proxy `unbindEntityEvents` to enable unbinding view's events from another entity.
+    unbindEntityEvents: Marionette.proxyUnbindEntityEvents
+  });
+  
+  // 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.apply(this, 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._ensureViewIsIntact();
+  
+      this.triggerMethod('before:render', this);
+  
+      var data = this.serializeData();
+      data = this.mixinTemplateHelpers(data);
+  
+      var template = this.getTemplate();
+      var html = Marionette.Renderer.render(template, data);
+      this.attachElContent(html);
+      this.bindUIElements();
+  
+      this.triggerMethod('render', this);
+  
+      return this;
+    },
+  
+    // Attaches the content of a given view.
+    // This method can be overriden to optimize rendering,
+    // or to render in a non standard way.
+    //
+    // For example, using `innerHTML` instead of `$el.html`
+    //
+    // ```js
+    // attachElContent: function(html) {
+    //   this.el.innerHTML = html;
+    //   return this;
+    // }
+    // ```
+    attachElContent: function(html) {
+      this.$el.html(html);
+  
+      return this;
+    },
+  
+    // Override the default destroy event to add a few
+    // more events that are triggered.
+    destroy: function() {
+      if (this.isDestroyed) { return; }
+  
+      Marionette.View.prototype.destroy.apply(this, arguments);
+    }
+  });
+  
+  /* jshint maxstatements: 14 */
+  
+  // Collection View
+  // ---------------
+  
+  // A view that iterates over a Backbone.Collection
+  // and renders an individual child view for each model.
+  Marionette.CollectionView = Marionette.View.extend({
+  
+    // used as the prefix for child view events
+    // that are forwarded through the collectionview
+    childViewEventPrefix: 'childview',
+  
+    // constructor
+    // option to pass `{sort: false}` to prevent the `CollectionView` from
+    // maintaining the sorted order of the collection.
+    // This will fallback onto appending childView's to the end.
+    constructor: function(options){
+      var initOptions = options || {};
+      this.sort = _.isUndefined(initOptions.sort) ? true : initOptions.sort;
+  
+      this._initChildViewStorage();
+  
+      Marionette.View.apply(this, arguments);
+  
+      this._initialEvents();
+      this.initRenderBuffer();
+    },
+  
+    // Instead of inserting elements one by one into the page,
+    // it's much more performant to insert elements into a document
+    // fragment and then insert that document fragment into the page
+    initRenderBuffer: function() {
+      this.elBuffer = document.createDocumentFragment();
+      this._bufferedChildren = [];
+    },
+  
+    startBuffering: function() {
+      this.initRenderBuffer();
+      this.isBuffering = true;
+    },
+  
+    endBuffering: function() {
+      this.isBuffering = false;
+      this._triggerBeforeShowBufferedChildren();
+      this.attachBuffer(this, this.elBuffer);
+      this._triggerShowBufferedChildren();
+      this.initRenderBuffer();
+    },
+  
+    _triggerBeforeShowBufferedChildren: function() {
+      if (this._isShown) {
+        _.invoke(this._bufferedChildren, 'triggerMethod', 'before:show');
+      }
+    },
+  
+    _triggerShowBufferedChildren: function() {
+      if (this._isShown) {
+        _.each(this._bufferedChildren, function (child) {
+          if (_.isFunction(child.triggerMethod)) {
+            child.triggerMethod('show');
+          } else {
+            Marionette.triggerMethod.call(child, 'show');
+          }
+        });
+        this._bufferedChildren = [];
+      }
+    },
+  
+    // Configured the initial events that the collection view
+    // binds to.
+    _initialEvents: function() {
+      if (this.collection) {
+        this.listenTo(this.collection, 'add', this._onCollectionAdd);
+        this.listenTo(this.collection, 'remove', this._onCollectionRemove);
+        this.listenTo(this.collection, 'reset', this.render);
+  
+        if (this.sort) {
+          this.listenTo(this.collection, 'sort', this._sortViews);
+        }
+      }
+    },
+  
+    // Handle a child added to the collection
+    _onCollectionAdd: function(child, collection, options) {
+      this.destroyEmptyView();
+      var ChildView = this.getChildView(child);
+      var index = this.collection.indexOf(child);
+      this.addChild(child, ChildView, index);
+    },
+  
+    // get the child view by model it holds, and remove it
+    _onCollectionRemove: function(model) {
+      var view = this.children.findByModel(model);
+      this.removeChildView(view);
+      this.checkEmpty();
+    },
+  
+    // Override from `Marionette.View` to trigger show on child views
+    onShowCalled: function(){
+      this.children.each(function(child){
+        if (_.isFunction(child.triggerMethod)) {
+          child.triggerMethod('show');
+        } else {
+          Marionette.triggerMethod.call(child, 'show');
+        }
+      });
+    },
+  
+    // Render children views. Override this method to
+    // provide your own implementation of a render function for
+    // the collection view.
+    render: function() {
+      this._ensureViewIsIntact();
+      this.triggerMethod('before:render', this);
+      this._renderChildren();
+      this.triggerMethod('render', this);
+      return this;
+    },
+  
+    // Internal method. This checks for any changes in the order of the collection.
+    // If the index of any view doesn't match, it will render.
+    _sortViews: function(){
+      // check for any changes in sort order of views
+      var orderChanged = this.collection.find(function(item, index){
+        var view = this.children.findByModel(item);
+        return view && view._index !== index;
+      }, this);
+  
+      if (orderChanged) {
+        this.render();
+      }
+    },
+  
+    // Internal method. Separated so that CompositeView can have
+    // more control over events being triggered, around the rendering
+    // process
+    _renderChildren: function() {
+      this.startBuffering();
+  
+      this.destroyEmptyView();
+      this.destroyChildren();
+  
+      if (!this.isEmpty(this.collection)) {
+        this.triggerMethod('before:render:collection', this);
+        this.showCollection();
+        this.triggerMethod('render:collection', this);
+      } else {
+        this.showEmptyView();
+      }
+  
+      this.endBuffering();
+    },
+  
+    // Internal method to loop through collection and show each child view.
+    showCollection: function() {
+      var ChildView;
+      this.collection.each(function(child, index) {
+        ChildView = this.getChildView(child);
+        this.addChild(child, ChildView, index);
+      }, this);
+    },
+  
+    // Internal method to show an empty view in place of
+    // a collection of child views, when the collection is empty
+    showEmptyView: function() {
+      var EmptyView = this.getEmptyView();
+  
+      if (EmptyView && !this._showingEmptyView) {
+        this.triggerMethod('before:render:empty');
+  
+        this._showingEmptyView = true;
+        var model = new Backbone.Model();
+        this.addEmptyView(model, EmptyView);
+  
+        this.triggerMethod('render:empty');
+      }
+    },
+  
+    // Internal method to destroy an existing emptyView instance
+    // if one exists. Called when a collection view has been
+    // rendered empty, and then a child is added to the collection.
+    destroyEmptyView: function() {
+      if (this._showingEmptyView) {
+        this.destroyChildren();
+        delete this._showingEmptyView;
+      }
+    },
+  
+    // Retrieve the empty view class
+    getEmptyView: function() {
+      return this.getOption('emptyView');
+    },
+  
+    // Render and show the emptyView. Similar to addChild method
+    // but "child:added" events are not fired, and the event from
+    // emptyView are not forwarded
+    addEmptyView: function(child, EmptyView){
+  
+      // get the emptyViewOptions, falling back to childViewOptions
+      var emptyViewOptions = this.getOption('emptyViewOptions') ||
+                            this.getOption('childViewOptions');
+  
+      if (_.isFunction(emptyViewOptions)){
+        emptyViewOptions = emptyViewOptions.call(this);
+      }
+  
+      // build the empty view
+      var view = this.buildChildView(child, EmptyView, emptyViewOptions);
+  
+      // trigger the 'before:show' event on `view` if the collection view
+      // has already been shown
+      if (this._isShown){
+        this.triggerMethod.call(view, 'before:show');
+      }
+  
+      // Store the `emptyView` like a `childView` so we can properly
+      // remove and/or close it later
+      this.children.add(view);
+  
+      // Render it and show it
+      this.renderChildView(view, -1);
+  
+      // call the 'show' method if the collection view
+      // has already been shown
+      if (this._isShown){
+        this.triggerMethod.call(view, 'show');
+      }
+    },
+  
+    // Retrieve the childView class, either from `this.options.childView`
+    // or from the `childView` in the object definition. The "options"
+    // takes precedence.
+    getChildView: function(child) {
+      var childView = this.getOption('childView');
+  
+      if (!childView) {
+        throwError('A "childView" must be specified', 'NoChildViewError');
+      }
+  
+      return childView;
+    },
+  
+    // Render the child's view and add it to the
+    // HTML for the collection view at a given index.
+    // This will also update the indices of later views in the collection
+    // in order to keep the children in sync with the collection.
+    addChild: function(child, ChildView, index) {
+      var childViewOptions = this.getOption('childViewOptions');
+      if (_.isFunction(childViewOptions)) {
+        childViewOptions = childViewOptions.call(this, child, index);
+      }
+  
+      var view = this.buildChildView(child, ChildView, childViewOptions);
+  
+      // increment indices of views after this one
+      this._updateIndices(view, true, index);
+  
+      this._addChildView(view, index);
+  
+      return view;
+    },
+  
+    // Internal method. This decrements or increments the indices of views after the
+    // added/removed view to keep in sync with the collection.
+    _updateIndices: function(view, increment, index) {
+      if (!this.sort) {
+        return;
+      }
+  
+      if (increment) {
+        // assign the index to the view
+        view._index = index;
+  
+        // increment the index of views after this one
+        this.children.each(function (laterView) {
+          if (laterView._index >= view._index) {
+            laterView._index++;
+          }
+        });
+      }
+      else {
+        // decrement the index of views after this one
+        this.children.each(function (laterView) {
+          if (laterView._index >= view._index) {
+            laterView._index--;
+          }
+        });
+      }
+    },
+  
+  
+    // Internal Method. Add the view to children and render it at
+    // the given index.
+    _addChildView: function(view, index) {
+      // set up the child view event forwarding
+      this.proxyChildEvents(view);
+  
+      this.triggerMethod('before:add:child', view);
+  
+      // Store the child view itself so we can properly
+      // remove and/or destroy it later
+      this.children.add(view);
+      this.renderChildView(view, index);
+  
+      if (this._isShown && !this.isBuffering){
+        if (_.isFunction(view.triggerMethod)) {
+          view.triggerMethod('show');
+        } else {
+          Marionette.triggerMethod.call(view, 'show');
+        }
+      }
+  
+      this.triggerMethod('add:child', view);
+    },
+  
+    // render the child view
+    renderChildView: function(view, index) {
+      view.render();
+      this.attachHtml(this, view, index);
+    },
+  
+    // Build a `childView` for a model in the collection.
+    buildChildView: function(child, ChildViewClass, childViewOptions) {
+      var options = _.extend({model: child}, childViewOptions);
+      return new ChildViewClass(options);
+    },
+  
+    // Remove the child view and destroy it.
+    // This function also updates the indices of
+    // later views in the collection in order to keep
+    // the children in sync with the collection.
+    removeChildView: function(view) {
+  
+      if (view) {
+        this.triggerMethod('before:remove:child', view);
+        // call 'destroy' or 'remove', depending on which is found
+        if (view.destroy) { view.destroy(); }
+        else if (view.remove) { view.remove(); }
+  
+        this.stopListening(view);
+        this.children.remove(view);
+        this.triggerMethod('remove:child', view);
+  
+        // decrement the index of views after this one
+        this._updateIndices(view, false);
+      }
+  
+    },
+  
+    // check if the collection is empty
+    isEmpty: function(collection) {
+      return !this.collection || this.collection.length === 0;
+    },
+  
+    // If empty, show the empty view
+    checkEmpty: function() {
+      if (this.isEmpty(this.collection)) {
+        this.showEmptyView();
+      }
+    },
+  
+    // You might need to override this if you've overridden attachHtml
+    attachBuffer: function(collectionView, buffer) {
+      collectionView.$el.append(buffer);
+    },
+  
+    // Append the HTML to the collection's `el`.
+    // Override this method to do something other
+    // than `.append`.
+    attachHtml: function(collectionView, childView, index) {
+      if (collectionView.isBuffering) {
+        // buffering happens on reset events and initial renders
+        // in order to reduce the number of inserts into the
+        // document, which are expensive.
+        collectionView.elBuffer.appendChild(childView.el);
+        collectionView._bufferedChildren.push(childView);
+      }
+      else {
+        // If we've already rendered the main collection, append
+        // the new child into the correct order if we need to. Otherwise
+        // append to the end.
+        if (!collectionView._insertBefore(childView, index)){
+          collectionView._insertAfter(childView);
+        }
+      }
+    },
+  
+    // Internal method. Check whether we need to insert the view into
+    // the correct position.
+    _insertBefore: function(childView, index) {
+      var currentView;
+      var findPosition = this.sort && (index < this.children.length - 1);
+      if (findPosition) {
+        // Find the view after this one
+        currentView = this.children.find(function (view) {
+          return view._index === index + 1;
+        });
+      }
+  
+      if (currentView) {
+        currentView.$el.before(childView.el);
+        return true;
+      }
+  
+      return false;
+    },
+  
+    // Internal method. Append a view to the end of the $el
+    _insertAfter: function(childView) {
+      this.$el.append(childView.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 destroying needs for the collection of views
+    destroy: function() {
+      if (this.isDestroyed) { return; }
+  
+      this.triggerMethod('before:destroy:collection');
+      this.destroyChildren();
+      this.triggerMethod('destroy:collection');
+  
+      Marionette.View.prototype.destroy.apply(this, arguments);
+    },
+  
+    // Destroy the child views that this collection view
+    // is holding on to, if any
+    destroyChildren: function() {
+      this.children.each(this.removeChildView, this);
+      this.checkEmpty();
+    },
+  
+    // Set up the child view event forwarding. Uses a "childview:"
+    // prefix in front of all forwarded events.
+    proxyChildEvents: function(view) {
+      var prefix = this.getOption('childViewEventPrefix');
+  
+      // Forward all child view events through the parent,
+      // prepending "childview:" to the event name
+      this.listenTo(view, 'all', function() {
+        var args = Array.prototype.slice.call(arguments);
+        var rootEvent = args[0];
+        var childEvents = this.normalizeMethods(_.result(this, 'childEvents'));
+  
+        args[0] = prefix + ':' + rootEvent;
+        args.splice(1, 0, view);
+  
+        // call collectionView childEvent if defined
+        if (typeof childEvents !== 'undefined' && _.isFunction(childEvents[rootEvent])) {
+          childEvents[rootEvent].apply(this, args.slice(1));
+        }
+  
+        this.triggerMethod.apply(this, args);
+      }, this);
+    }
+  });
+  
+  /* jshint maxstatements: 17, maxlen: 117 */
+  
+  // Composite View
+  // --------------
+  
+  // Used for rendering a branch-leaf, hierarchical structure.
+  // Extends directly from CollectionView and also renders an
+  // a child 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
+    // option to pass '{sort: false}' to prevent the CompositeView from
+    // maintaining the sorted order of the collection.
+    // This will fallback onto appending childView's to the end.
+    constructor: function() {
+      Marionette.CollectionView.apply(this, 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() {
+  
+      // Bind only after composite view is rendered to avoid adding child views
+      // to nonexistent childViewContainer
+      this.once('render', function() {
+        if (this.collection) {
+          this.listenTo(this.collection, 'add', this._onCollectionAdd);
+          this.listenTo(this.collection, 'remove', this._onCollectionRemove);
+          this.listenTo(this.collection, 'reset', this._renderChildren);
+  
+          if (this.sort) {
+            this.listenTo(this.collection, 'sort', this._sortViews);
+          }
+        }
+      });
+  
+    },
+  
+    // Retrieve the `childView` to be used when rendering each of
+    // the items in the collection. The default is to return
+    // `this.childView` or Marionette.CompositeView if no `childView`
+    // has been defined
+    getChildView: function(child) {
+      var childView = this.getOption('childView') || this.constructor;
+  
+      if (!childView) {
+        throwError('A "childView" must be specified', 'NoChildViewError');
+      }
+  
+      return childView;
+    },
+  
+    // 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._ensureViewIsIntact();
+      this.isRendered = true;
+      this.resetChildViewContainer();
+  
+      this.triggerMethod('before:render', this);
+  
+      this._renderRoot();
+      this._renderChildren();
+  
+      this.triggerMethod('render', this);
+      return this;
+    },
+  
+    _renderChildren: function() {
+      if (this.isRendered) {
+        Marionette.CollectionView.prototype._renderChildren.call(this);
+      }
+    },
+  
+    // Render the root template that the children
+    // views are appended to
+    _renderRoot: function() {
+      var data = {};
+      data = this.serializeData();
+      data = this.mixinTemplateHelpers(data);
+  
+      this.triggerMethod('before:render:template');
+  
+      var template = this.getTemplate();
+      var html = Marionette.Renderer.render(template, data);
+      this.attachElContent(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('render:template');
+    },
+  
+    // Attaches the content of the root.
+    // This method can be overriden to optimize rendering,
+    // or to render in a non standard way.
+    //
+    // For example, using `innerHTML` instead of `$el.html`
+    //
+    // ```js
+    // attachElContent: function(html) {
+    //   this.el.innerHTML = html;
+    //   return this;
+    // }
+    // ```
+    attachElContent: function(html) {
+      this.$el.html(html);
+  
+      return this;
+    },
+  
+    // You might need to override this if you've overridden attachHtml
+    attachBuffer: function(compositeView, buffer) {
+      var $container = this.getChildViewContainer(compositeView);
+      $container.append(buffer);
+    },
+  
+    // Internal method. Append a view to the end of the $el.
+    // Overidden from CollectionView to ensure view is appended to
+    // childViewContainer
+    _insertAfter: function (childView) {
+      var $container = this.getChildViewContainer(this);
+      $container.append(childView.el);
+    },
+  
+    // Internal method to ensure an `$childViewContainer` exists, for the
+    // `attachHtml` method to use.
+    getChildViewContainer: function(containerView) {
+      if ('$childViewContainer' in containerView) {
+        return containerView.$childViewContainer;
+      }
+  
+      var container;
+      var childViewContainer = Marionette.getOption(containerView, 'childViewContainer');
+      if (childViewContainer) {
+  
+        var selector = _.isFunction(childViewContainer) ? childViewContainer.call(containerView) : childViewContainer;
+  
+        if (selector.charAt(0) === '@' && containerView.ui) {
+          container = containerView.ui[selector.substr(4)];
+        } else {
+          container = containerView.$(selector);
+        }
+  
+        if (container.length <= 0) {
+          throwError('The specified "childViewContainer" was not found: ' +
+            containerView.childViewContainer, 'ChildViewContainerMissingError');
+        }
+  
+      } else {
+        container = containerView.$el;
+      }
+  
+      containerView.$childViewContainer = container;
+      return container;
+    },
+  
+    // Internal method to reset the `$childViewContainer` on render
+    resetChildViewContainer: function() {
+      if (this.$childViewContainer) {
+        delete this.$childViewContainer;
+      }
+    }
+  });
+  
+  // LayoutView
+  // ----------
+  
+  // Used for managing application layoutViews, nested layoutViews and
+  // multiple regions within an application or sub-application.
+  //
+  // A specialized view class 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.LayoutView = Marionette.ItemView.extend({
+    regionClass: 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.call(this, options);
+    },
+  
+    // LayoutView's render will use the existing region objects the
+    // first time it is called. Subsequent calls will destroy the
+    // views that the regions are showing and then reset the `el`
+    // for the regions to the newly rendered DOM elements.
+    render: function() {
+      this._ensureViewIsIntact();
+  
+      if (this._firstRender) {
+        // if this is the first render, don't do anything to
+        // reset the regions
+        this._firstRender = false;
+      } else {
+        // If this is not the first render call, then we need to
+        // re-initialize the `el` for each region
+        this._reInitializeRegions();
+      }
+  
+      return Marionette.ItemView.prototype.render.apply(this, arguments);
+    },
+  
+    // Handle destroying regions, and then destroy the view itself.
+    destroy: function() {
+      if (this.isDestroyed) { return; }
+  
+      this.regionManager.destroy();
+      Marionette.ItemView.prototype.destroy.apply(this, arguments);
+    },
+  
+    // Add a single region, by name, to the layoutView
+    addRegion: function(name, definition) {
+      this.triggerMethod('before:region:add', name);
+      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 LayoutView, by name
+    removeRegion: function(name) {
+      this.triggerMethod('before:region:remove', name);
+      delete this.regions[name];
+      return this.regionManager.removeRegion(name);
+    },
+  
+    // Provides alternative access to regions
+    // Accepts the region name
+    // getRegion('main')
+    getRegion: function(region) {
+      return this.regionManager.get(region);
+    },
+  
+    // Get all regions
+    getRegions: function(){
+      return this.regionManager.getRegions();
+    },
+  
+    // internal method to build regions
+    _buildRegions: function(regions) {
+      var that = this;
+  
+      var defaults = {
+        regionClass: this.getOption('regionClass'),
+        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 layoutView.
+    _initializeRegions: function(options) {
+      var regions;
+      this._initRegionManager();
+  
+      if (_.isFunction(this.regions)) {
+        regions = this.regions(options);
+      } else {
+        regions = this.regions || {};
+      }
+  
+      // Enable users to define `regions` as instance options.
+      var regionOptions = this.getOption.call(options, 'regions');
+  
+      // enable region options to be a function
+      if (_.isFunction(regionOptions)) {
+        regionOptions = regionOptions.call(this, options);
+      }
+  
+      _.extend(regions, regionOptions);
+  
+      this.addRegions(regions);
+    },
+  
+    // Internal method to re-initialize all of the regions by updating the `el` that
+    // they point to
+    _reInitializeRegions: function() {
+      this.regionManager.emptyRegions();
+      this.regionManager.each(function(region) {
+        region.reset();
+      });
+    },
+  
+    // Enable easy overiding of the default `RegionManager`
+    // for customized region interactions and buisness specific
+    // view logic for better control over single regions.
+    getRegionManager: function() {
+      return new Marionette.RegionManager();
+    },
+  
+    // Internal method to initialize the region manager
+    // and all regions in it
+    _initRegionManager: function() {
+      this.regionManager = this.getRegionManager();
+  
+      this.listenTo(this.regionManager, 'before:add:region', function(name) {
+        this.triggerMethod('before:add:region', name);
+      });
+  
+      this.listenTo(this.regionManager, 'add:region', function(name, region) {
+        this[name] = region;
+        this.triggerMethod('add:region', name, region);
+      });
+  
+      this.listenTo(this.regionManager, 'before:remove:region', function(name) {
+        this.triggerMethod('before:remove:region', name);
+      });
+  
+      this.listenTo(this.regionManager, 'remove:region', function(name, region) {
+        delete this[name];
+        this.triggerMethod('remove:region', name, region);
+      });
+    }
+  });
+  
+
+  // Behavior
+  // -----------
+  
+  // A Behavior is an isolated set of DOM /
+  // user interactions that can be mixed into any View.
+  // Behaviors allow you to blackbox View specific interactions
+  // into portable logical chunks, keeping your views simple and your code DRY.
+  
+  Marionette.Behavior = (function(_, Backbone) {
+    function Behavior(options, view) {
+      // Setup reference to the view.
+      // this comes in handle when a behavior
+      // wants to directly talk up the chain
+      // to the view.
+      this.view = view;
+      this.defaults = _.result(this, 'defaults') || {};
+      this.options  = _.extend({}, this.defaults, options);
+  
+      // proxy behavior $ method to the view
+      // this is useful for doing jquery DOM lookups
+      // scoped to behaviors view.
+      this.$ = function() {
+        return this.view.$.apply(this.view, arguments);
+      };
+  
+      // Call the initialize method passing
+      // the arguments from the instance constructor
+      this.initialize.apply(this, arguments);
+    }
+  
+    _.extend(Behavior.prototype, Backbone.Events, {
+      initialize: function() {},
+  
+      // stopListening to behavior `onListen` events.
+      destroy: function() {
+        this.stopListening();
+      },
+  
+      // import the `triggerMethod` to trigger events with corresponding
+      // methods if the method exists
+      triggerMethod: Marionette.triggerMethod,
+  
+      // Proxy `getOption` to enable getting options from this or this.options by name.
+      getOption: Marionette.proxyGetOption,
+  
+      // Proxy `unbindEntityEvents` to enable binding view's events from another entity.
+      bindEntityEvents: Marionette.proxyBindEntityEvents,
+  
+      // Proxy `unbindEntityEvents` to enable unbinding view's events from another entity.
+      unbindEntityEvents: Marionette.proxyUnbindEntityEvents
+    });
+  
+    // Borrow Backbones extend implementation
+    // this allows us to setup a proper
+    // inheritence pattern that follow in suite
+    // with the rest of Marionette views.
+    Behavior.extend = Marionette.extend;
+  
+    return Behavior;
+  })(_, Backbone);
+  
+  /* jshint maxlen: 143, nonew: false */
+  // Marionette.Behaviors
+  // --------
+  
+  // Behaviors is a utility class that takes care of
+  // glueing your behavior instances to their given View.
+  // The most important part of this class is that you
+  // **MUST** override the class level behaviorsLookup
+  // method for things to work properly.
+  
+  Marionette.Behaviors = (function(Marionette, _) {
+  
+    function Behaviors(view, behaviors) {
+      // Behaviors defined on a view can be a flat object literal
+      // or it can be a function that returns an object.
+      behaviors = Behaviors.parseBehaviors(view, behaviors || _.result(view, 'behaviors'));
+  
+      // Wraps several of the view's methods
+      // calling the methods first on each behavior
+      // and then eventually calling the method on the view.
+      Behaviors.wrap(view, behaviors, [
+        'bindUIElements', 'unbindUIElements',
+        'delegateEvents', 'undelegateEvents',
+        'behaviorEvents', 'triggerMethod',
+        'setElement', 'destroy'
+      ]);
+    }
+  
+    var methods = {
+      setElement: function(setElement, behaviors) {
+        setElement.apply(this, _.tail(arguments, 2));
+  
+        // proxy behavior $el to the view's $el.
+        // This is needed because a view's $el proxy
+        // is not set until after setElement is called.
+        _.each(behaviors, function(b) {
+          b.$el = this.$el;
+        }, this);
+      },
+  
+      destroy: function(destroy, behaviors) {
+        var args = _.tail(arguments, 2);
+        destroy.apply(this, args);
+  
+        // Call destroy on each behavior after
+        // destroying the view.
+        // This unbinds event listeners
+        // that behaviors have registerd for.
+        _.invoke(behaviors, 'destroy', args);
+      },
+  
+      bindUIElements: function(bindUIElements, behaviors) {
+        bindUIElements.apply(this);
+        _.invoke(behaviors, bindUIElements);
+      },
+  
+      unbindUIElements: function(unbindUIElements, behaviors) {
+        unbindUIElements.apply(this);
+        _.invoke(behaviors, unbindUIElements);
+      },
+  
+      triggerMethod: function(triggerMethod, behaviors) {
+        var args = _.tail(arguments, 2);
+        triggerMethod.apply(this, args);
+  
+        _.each(behaviors, function(b) {
+          triggerMethod.apply(b, args);
+        });
+      },
+  
+      delegateEvents: function(delegateEvents, behaviors) {
+        var args = _.tail(arguments, 2);
+        delegateEvents.apply(this, args);
+  
+        _.each(behaviors, function(b) {
+          Marionette.bindEntityEvents(b, this.model, Marionette.getOption(b, 'modelEvents'));
+          Marionette.bindEntityEvents(b, this.collection, Marionette.getOption(b, 'collectionEvents'));
+        }, this);
+      },
+  
+      undelegateEvents: function(undelegateEvents, behaviors) {
+        var args = _.tail(arguments, 2);
+        undelegateEvents.apply(this, args);
+  
+        _.each(behaviors, function(b) {
+          Marionette.unbindEntityEvents(b, this.model, Marionette.getOption(b, 'modelEvents'));
+          Marionette.unbindEntityEvents(b, this.collection, Marionette.getOption(b, 'collectionEvents'));
+        }, this);
+      },
+  
+      behaviorEvents: function(behaviorEvents, behaviors) {
+        var _behaviorsEvents = {};
+        var viewUI = _.result(this, 'ui');
+  
+        _.each(behaviors, function(b, i) {
+          var _events = {};
+          var behaviorEvents = _.clone(_.result(b, 'events')) || {};
+          var behaviorUI = _.result(b, 'ui');
+  
+          // Construct an internal UI hash first using
+          // the views UI hash and then the behaviors UI hash.
+          // This allows the user to use UI hash elements
+          // defined in the parent view as well as those
+          // defined in the given behavior.
+          var ui = _.extend({}, viewUI, behaviorUI);
+  
+          // Normalize behavior events hash to allow
+          // a user to use the @ui. syntax.
+          behaviorEvents = Marionette.normalizeUIKeys(behaviorEvents, ui);
+  
+          _.each(_.keys(behaviorEvents), function(key) {
+            // Append white-space at the end of each key to prevent behavior key collisions.
+            // This is relying on the fact that backbone events considers "click .foo" the same as
+            // "click .foo ".
+  
+            // +2 is used because new Array(1) or 0 is "" and not " "
+            var whitespace = (new Array(i + 2)).join(' ');
+            var eventKey   = key + whitespace;
+            var handler    = _.isFunction(behaviorEvents[key]) ? behaviorEvents[key] : b[behaviorEvents[key]];
+  
+            _events[eventKey] = _.bind(handler, b);
+          });
+  
+          _behaviorsEvents = _.extend(_behaviorsEvents, _events);
+        });
+  
+        return _behaviorsEvents;
+      }
+    };
+  
+    _.extend(Behaviors, {
+  
+      // Placeholder method to be extended by the user.
+      // The method should define the object that stores the behaviors.
+      // i.e.
+      //
+      // ```js
+      // Marionette.Behaviors.behaviorsLookup: function() {
+      //   return App.Behaviors
+      // }
+      // ```
+      behaviorsLookup: function() {
+        throw new Error('You must define where your behaviors are stored.' +
+          'See https://github.com/marionettejs/backbone.marionette' +
+          '/blob/master/docs/marionette.behaviors.md#behaviorslookup');
+      },
+  
+      // Takes care of getting the behavior class
+      // given options and a key.
+      // If a user passes in options.behaviorClass
+      // default to using that. Otherwise delegate
+      // the lookup to the users `behaviorsLookup` implementation.
+      getBehaviorClass: function(options, key) {
+        if (options.behaviorClass) {
+          return options.behaviorClass;
+        }
+  
+        // Get behavior class can be either a flat object or a method
+        return _.isFunction(Behaviors.behaviorsLookup) ? Behaviors.behaviorsLookup.apply(this, arguments)[key] : Behaviors.behaviorsLookup[key];
+      },
+  
+      // Iterate over the behaviors object, for each behavior
+      // instantiate it and get its grouped behaviors.
+      parseBehaviors: function(view, behaviors) {
+        return _.chain(behaviors).map(function(options, key) {
+          var BehaviorClass = Behaviors.getBehaviorClass(options, key);
+  
+          var behavior = new BehaviorClass(options, view);
+          var nestedBehaviors = Behaviors.parseBehaviors(view, _.result(behavior, 'behaviors'));
+  
+          return [behavior].concat(nestedBehaviors);
+        }).flatten().value();
+      },
+  
+      // Wrap view internal methods so that they delegate to behaviors. For example,
+      // `onDestroy` should trigger destroy on all of the behaviors and then destroy itself.
+      // i.e.
+      //
+      // `view.delegateEvents = _.partial(methods.delegateEvents, view.delegateEvents, behaviors);`
+      wrap: function(view, behaviors, methodNames) {
+        _.each(methodNames, function(methodName) {
+          view[methodName] = _.partial(methods[methodName], view[methodName], behaviors);
+        });
+      }
+    });
+  
+    return Behaviors;
+  
+  })(Marionette, _);
+  
+
+  // 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.apply(this, arguments);
+  
+      this.options = options || {};
+  
+      var appRoutes = this.getOption('appRoutes');
+      var controller = this._getController();
+      this.processAppRoutes(controller, appRoutes);
+      this.on('route', this._processOnRoute, this);
+    },
+  
+    // 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);
+    },
+  
+    // process the route event and trigger the onRoute
+    // method call, if it exists
+    _processOnRoute: function(routeName, routeArgs) {
+      // find the path that matched
+      var routePath = _.invert(this.appRoutes)[routeName];
+  
+      // make sure an onRoute is there, and call it
+      if (_.isFunction(this.onRoute)) {
+        this.onRoute(routeName, routePath, routeArgs);
+      }
+    },
+  
+    // 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 this.getOption('controller');
+    },
+  
+    _addAppRoute: function(controller, route, methodName) {
+      var method = controller[methodName];
+  
+      if (!method) {
+        throwError('Method "' + methodName + '" was not found on the controller');
+      }
+  
+      this.route(route, methodName, _.bind(method, controller));
+    },
+  
+    // Proxy `getOption` to enable getting options from this or this.options by name.
+    getOption: Marionette.proxyGetOption
+  });
+  
+  // 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();
+    var globalCh = Backbone.Wreqr.radio.channel('global');
+    this.vent = globalCh.vent;
+    this.commands = globalCh.commands;
+    this.reqres = globalCh.reqres;
+    this.submodules = {};
+  
+    _.extend(this, options);
+  };
+  
+  _.extend(Marionette.Application.prototype, Backbone.Events, {
+    // Command execution, facilitated by Backbone.Wreqr.Commands
+    execute: function() {
+      this.commands.execute.apply(this.commands, arguments);
+    },
+  
+    // Request/response, facilitated by Backbone.Wreqr.RequestResponse
+    request: function() {
+      return this.reqres.request.apply(this.reqres, arguments);
+    },
+  
+    // 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('before:start', options);
+      this._initCallbacks.run(options, this);
+      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);
+    },
+  
+    // Empty all regions in the app, without removing them
+    emptyRegions: function() {
+      this._regionManager.emptyRegions();
+    },
+  
+    // 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);
+    },
+  
+    // Get all the regions from the region manager
+    getRegions: function(){
+      return this._regionManager.getRegions();
+    },
+  
+    // Create a module, attached to the application
+    module: function(moduleNames, moduleDefinition) {
+  
+      // Overwrite the module class if the user specifies one
+      var ModuleClass = Marionette.Module.getClass(moduleDefinition);
+  
+      // slice the args, and add this application object as the
+      // first argument of the array
+      var args = slice.call(arguments);
+      args.unshift(this);
+  
+      // see the Marionette.Module object for more information
+      return ModuleClass.create.apply(ModuleClass, args);
+    },
+  
+    // Internal method to set up the region manager
+    _initRegionManager: function() {
+      this._regionManager = new Marionette.RegionManager();
+  
+      this.listenTo(this._regionManager, 'before:add:region', function(name) {
+        this.triggerMethod('before:add:region', name);
+      });
+  
+      this.listenTo(this._regionManager, 'add:region', function(name, region) {
+        this[name] = region;
+        this.triggerMethod('add:region', name, region);
+      });
+  
+      this.listenTo(this._regionManager, 'before:remove:region', function(name) {
+        this.triggerMethod('before:remove:region', name);
+      });
+  
+      this.listenTo(this._regionManager, 'remove:region', function(name, region) {
+        delete this[name];
+        this.triggerMethod('remove:region', name, region);
+      });
+    },
+  
+    // import the `triggerMethod` to trigger events with corresponding
+    // methods if the method exists
+    triggerMethod: Marionette.triggerMethod
+  });
+  
+  // Copy the `extend` function used by Backbone's classes
+  Marionette.Application.extend = Marionette.extend;
+  
+  /* jshint maxparams: 9 */
+  
+  // Module
+  // ------
+  
+  // A simple module system, used to create privacy and encapsulation in
+  // Marionette applications
+  Marionette.Module = function(moduleName, app, options) {
+    this.moduleName = moduleName;
+    this.options = _.extend({}, this.options, options);
+    // Allow for a user to overide the initialize
+    // for a given module instance.
+    this.initialize = options.initialize || this.initialize;
+  
+    // Set up an internal store for sub-modules.
+    this.submodules = {};
+  
+    this._setupInitializersAndFinalizers();
+  
+    // Set an internal reference to the app
+    // within a module.
+    this.app = app;
+  
+    // By default modules start with their parents.
+    this.startWithParent = true;
+  
+    if (_.isFunction(this.initialize)) {
+      this.initialize(moduleName, app, this.options);
+    }
+  };
+  
+  Marionette.Module.extend = Marionette.extend;
+  
+  // 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, {
+  
+    // Initialize is an empty function by default. Override it with your own
+    // initialization logic when extending Marionette.Module.
+    initialize: function() {},
+  
+    // 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;
+  
+      this.triggerMethod('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();
+  
+      this.triggerMethod('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 there is no definition short circut the method.
+      if (!definition) { return; }
+  
+      // build the correct list of arguments for the module definition
+      var args = _.flatten([
+        this,
+        this.app,
+        Backbone,
+        Marionette,
+        Backbone.$, _,
+        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();
+    },
+  
+    // import the `triggerMethod` to trigger events with corresponding
+    // methods if the method exists
+    triggerMethod: Marionette.triggerMethod
+  });
+  
+  // Class 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.call(arguments);
+      customArgs.splice(0, 3);
+  
+      // Split the module names and get the number of submodules.
+      // i.e. an example module name of `Doge.Wow.Amaze` would
+      // then have the potential for 3 module definitions.
+      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, moduleDefinition);
+        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) {
+      var options = _.extend({}, def);
+      var ModuleClass = this.getClass(def);
+  
+      // 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 ModuleClass(moduleName, app, options);
+        parentModule[moduleName] = module;
+        // store the module on the parent
+        parentModule.submodules[moduleName] = module;
+      }
+  
+      return module;
+    },
+  
+    // ## Module Classes
+    //
+    // Module classes can be used as an alternative to the define pattern.
+    // The extend function of a Module is identical to the extend functions
+    // on other Backbone and Marionette classes.
+    // This allows module lifecyle events like `onStart` and `onStop` to be called directly.
+    getClass: function(moduleDefinition) {
+      var ModuleClass = Marionette.Module;
+  
+      if (!moduleDefinition) {
+        return ModuleClass;
+      }
+  
+      // If all of the module's functionality is defined inside its class,
+      // then the class can be passed in directly. `MyApp.module("Foo", FooModule)`.
+      if (moduleDefinition.prototype instanceof ModuleClass) {
+        return moduleDefinition;
+      }
+  
+      return moduleDefinition.moduleClass || ModuleClass;
+    },
+  
+    // Add the module definition and add a startWithParent initializer function.
+    // This is complicated because module definitions are heavily overloaded
+    // and support an anonymous function, module class, or options object
+    _addModuleDefinition: function(parentModule, module, def, args) {
+      var fn = this._getDefine(def);
+      var startWithParent = this._getStartWithParent(def, module);
+  
+      if (fn) {
+        module.addDefinition(fn, args);
+      }
+  
+      this._addStartWithParent(parentModule, module, startWithParent);
+    },
+  
+    _getStartWithParent: function(def, module) {
+      var swp;
+  
+      if (_.isFunction(def) && (def.prototype instanceof Marionette.Module)) {
+        swp = module.constructor.prototype.startWithParent;
+        return _.isUndefined(swp) ? true : swp;
+      }
+  
+      if (_.isObject(def)) {
+        swp = def.startWithParent;
+        return _.isUndefined(swp) ? true : swp;
+      }
+  
+      return true;
+    },
+  
+    _getDefine: function(def) {
+      if (_.isFunction(def) && !(def.prototype instanceof Marionette.Module)) {
+        return def;
+      }
+  
+      if (_.isObject(def)) {
+        return def.define;
+      }
+  
+      return null;
+    },
+  
+    _addStartWithParent: function(parentModule, module, startWithParent) {
+      module.startWithParent = module.startWithParent && startWithParent;
+  
+      if (!module.startWithParent || !!module.startWithParentIsConfigured) {
+        return;
+      }
+  
+      module.startWithParentIsConfigured = true;
+  
+      parentModule.addInitializer(function(options) {
+        if (module.startWithParent) {
+          module.start(options);
+        }
+      });
+    }
+  });
+  
+
+  return Marionette;
+}));
diff --git a/xos/core/xoslib/static/js/vendor/backbone.marionette.min.js b/xos/core/xoslib/static/js/vendor/backbone.marionette.min.js
new file mode 100644
index 0000000..29fe58c
--- /dev/null
+++ b/xos/core/xoslib/static/js/vendor/backbone.marionette.min.js
@@ -0,0 +1,2 @@
+!function(a,b){if("function"==typeof define&&define.amd)define(["backbone","underscore","backbone.wreqr","backbone.babysitter"],function(c,d){return a.Marionette=b(a,c,d)});else if("undefined"!=typeof exports){{var c=require("backbone"),d=require("underscore");require("backbone.wreqr"),require("backbone.babysitter")}module.exports=b(a,c,d)}else a.Marionette=b(a,a.Backbone,a._)}(this,function(a,b,c){"use strict";function d(a,b){var c=new Error(a);throw c.name=b||"Error",c}var e=a.Marionette,f=b.Marionette={};f.VERSION="2.0.1",f.noConflict=function(){return a.Marionette=e,this},f.Deferred=b.$.Deferred;var g=Array.prototype.slice;return f.extend=b.Model.extend,f.getOption=function(a,b){if(a&&b){var c;return c=a.options&&void 0!==a.options[b]?a.options[b]:a[b]}},f.proxyGetOption=function(a){return f.getOption(this,a)},f.normalizeMethods=function(a){var b,d={};return c.each(a,function(a,e){b=a,c.isFunction(b)||(b=this[b]),b&&(d[e]=b)},this),d},f.normalizeUIKeys=function(a,b){return"undefined"!=typeof a?(c.each(c.keys(a),function(c){var d=/@ui.[a-zA-Z_$0-9]*/g;c.match(d)&&(a[c.replace(d,function(a){return b[a.slice(4)]})]=a[c],delete a[c])}),a):void 0},f.actAsCollection=function(a,b){var d=["forEach","each","map","find","detect","filter","select","reject","every","all","some","any","include","contains","invoke","toArray","first","initial","rest","last","without","isEmpty","pluck"];c.each(d,function(d){a[d]=function(){var a=c.values(c.result(this,b)),e=[a].concat(c.toArray(arguments));return c[d].apply(c,e)}})},f.triggerMethod=function(){function a(a,b,c){return c.toUpperCase()}var b=/(^|:)(\w)/gi,d=function(d){var e,f="on"+d.replace(b,a),g=this[f];return c.isFunction(g)&&(e=g.apply(this,c.tail(arguments))),c.isFunction(this.trigger)&&this.trigger.apply(this,arguments),e};return d}(),f.MonitorDOMRefresh=function(a){function b(a){a._isShown=!0,e(a)}function d(a){a._isRendered=!0,e(a)}function e(a){a._isShown&&a._isRendered&&f(a)&&c.isFunction(a.triggerMethod)&&a.triggerMethod("dom:refresh")}function f(b){return a.contains(b.el)}return function(a){a.listenTo(a,"show",function(){b(a)}),a.listenTo(a,"render",function(){d(a)})}}(document.documentElement),function(a){function b(a,b,e,f){var g=f.split(/\s+/);c.each(g,function(c){var f=a[c];f||d('Method "'+c+'" was configured as an event handler, but does not exist.'),a.listenTo(b,e,f)})}function e(a,b,c,d){a.listenTo(b,c,d)}function f(a,b,d,e){var f=e.split(/\s+/);c.each(f,function(c){var e=a[c];a.stopListening(b,d,e)})}function g(a,b,c,d){a.stopListening(b,c,d)}function h(a,b,d,e,f){b&&d&&(c.isFunction(d)&&(d=d.call(a)),c.each(d,function(d,g){c.isFunction(d)?e(a,b,g,d):f(a,b,g,d)}))}a.bindEntityEvents=function(a,c,d){h(a,c,d,e,b)},a.unbindEntityEvents=function(a,b,c){h(a,b,c,g,f)},a.proxyBindEntityEvents=function(b,c){return a.bindEntityEvents(this,b,c)},a.proxyUnbindEntityEvents=function(b,c){return a.unbindEntityEvents(this,b,c)}}(f),f.Callbacks=function(){this._deferred=f.Deferred(),this._callbacks=[]},c.extend(f.Callbacks.prototype,{add:function(a,b){var d=c.result(this._deferred,"promise");this._callbacks.push({cb:a,ctx:b}),d.then(function(c){b&&(c.context=b),a.call(c.context,c.options)})},run:function(a,b){this._deferred.resolve({options:a,context:b})},reset:function(){var a=this._callbacks;this._deferred=f.Deferred(),this._callbacks=[],c.each(a,function(a){this.add(a.cb,a.ctx)},this)}}),f.Controller=function(a){this.triggerMethod=f.triggerMethod,this.options=a||{},c.isFunction(this.initialize)&&this.initialize(this.options)},f.Controller.extend=f.extend,c.extend(f.Controller.prototype,b.Events,{destroy:function(){var a=Array.prototype.slice.call(arguments);this.triggerMethod.apply(this,["before:destroy"].concat(a)),this.triggerMethod.apply(this,["destroy"].concat(a)),this.stopListening(),this.off()},triggerMethod:f.triggerMethod,getOption:f.proxyGetOption}),f.Region=function(a){if(this.options=a||{},this.el=this.getOption("el"),this.el=this.el instanceof b.$?this.el[0]:this.el,this.el||d('An "el" must be specified for a region.',"NoElError"),this.$el=this.getEl(this.el),this.initialize){var c=Array.prototype.slice.apply(arguments);this.initialize.apply(this,c)}},c.extend(f.Region,{buildRegion:function(a,e){var f=c.isString(a),g=c.isString(a.selector),h=c.isUndefined(a.regionClass),i=c.isFunction(a);i||f||g||d("Region must be specified as a Region class,a selector string or an object with selector property");var j,k;f&&(j=a),a.selector&&(j=a.selector,delete a.selector),i&&(k=a),!i&&h&&(k=e),a.regionClass&&(k=a.regionClass,delete a.regionClass),(f||i)&&(a={}),a.el=j;var l=new k(a);return a.parentEl&&(l.getEl=function(d){if(c.isObject(d))return b.$(d);var e=a.parentEl;return c.isFunction(e)&&(e=e()),e.find(d)}),l}}),c.extend(f.Region.prototype,b.Events,{show:function(a,b){this._ensureElement();var d=b||{},e=a!==this.currentView,f=!!d.preventDestroy,g=!!d.forceShow,h=!!this.currentView,i=!f&&e;i&&this.empty();var j=e||g;return j?(a.render(),h&&this.triggerMethod("before:swap",a),this.triggerMethod("before:show",a),this.triggerMethod.call(a,"before:show"),this.attachHtml(a),this.currentView=a,h&&this.triggerMethod("swap",a),this.triggerMethod("show",a),c.isFunction(a.triggerMethod)?a.triggerMethod("show"):this.triggerMethod.call(a,"show"),this):this},_ensureElement:function(){c.isObject(this.el)||(this.$el=this.getEl(this.el),this.el=this.$el[0]),this.$el&&0!==this.$el.length||d('An "el" '+this.$el.selector+" must exist in DOM")},getEl:function(a){return b.$(a)},attachHtml:function(a){this.el.innerHTML="",this.el.appendChild(a.el)},empty:function(){var a=this.currentView;a&&!a.isDestroyed&&(this.triggerMethod("before:empty",a),a.destroy?a.destroy():a.remove&&a.remove(),this.triggerMethod("empty",a),delete this.currentView)},attachView:function(a){this.currentView=a},reset:function(){this.empty(),this.$el&&(this.el=this.$el.selector),delete this.$el},getOption:f.proxyGetOption,triggerMethod:f.triggerMethod}),f.Region.extend=f.extend,f.RegionManager=function(a){var b=a.Controller.extend({constructor:function(b){this._regions={},a.Controller.call(this,b)},addRegions:function(a,b){var d={};return c.each(a,function(a,e){c.isString(a)&&(a={selector:a}),a.selector&&(a=c.defaults({},a,b));var f=this.addRegion(e,a);d[e]=f},this),d},addRegion:function(b,d){var e,f=c.isObject(d),g=c.isString(d),h=!!d.selector;return e=g||f&&h?a.Region.buildRegion(d,a.Region):c.isFunction(d)?a.Region.buildRegion(d,a.Region):d,this.triggerMethod("before:add:region",b,e),this._store(b,e),this.triggerMethod("add:region",b,e),e},get:function(a){return this._regions[a]},getRegions:function(){return c.clone(this._regions)},removeRegion:function(a){var b=this._regions[a];this._remove(a,b)},removeRegions:function(){c.each(this._regions,function(a,b){this._remove(b,a)},this)},emptyRegions:function(){c.each(this._regions,function(a){a.empty()},this)},destroy:function(){this.removeRegions(),a.Controller.prototype.destroy.apply(this,arguments)},_store:function(a,b){this._regions[a]=b,this._setLength()},_remove:function(a,b){this.triggerMethod("before:remove:region",a,b),b.empty(),b.stopListening(),delete this._regions[a],this._setLength(),this.triggerMethod("remove:region",a,b)},_setLength:function(){this.length=c.size(this._regions)}});return a.actAsCollection(b.prototype,"_regions"),b}(f),f.TemplateCache=function(a){this.templateId=a},c.extend(f.TemplateCache,{templateCaches:{},get:function(a){var b=this.templateCaches[a];return b||(b=new f.TemplateCache(a),this.templateCaches[a]=b),b.load()},clear:function(){var a,b=g.call(arguments),c=b.length;if(c>0)for(a=0;c>a;a++)delete this.templateCaches[b[a]];else this.templateCaches={}}}),c.extend(f.TemplateCache.prototype,{load:function(){if(this.compiledTemplate)return this.compiledTemplate;var a=this.loadTemplate(this.templateId);return this.compiledTemplate=this.compileTemplate(a),this.compiledTemplate},loadTemplate:function(a){var c=b.$(a).html();return c&&0!==c.length||d('Could not find template: "'+a+'"',"NoTemplateError"),c},compileTemplate:function(a){return c.template(a)}}),f.Renderer={render:function(a,b){a||d("Cannot render the template since its false, null or undefined.","TemplateNotFoundError");var c;return(c="function"==typeof a?a:f.TemplateCache.get(a))(b)}},f.View=b.View.extend({constructor:function(a){c.bindAll(this,"render"),this.options=c.extend({},c.result(this,"options"),c.isFunction(a)?a.call(this):a),this.events=this.normalizeUIKeys(c.result(this,"events")),c.isObject(this.behaviors)&&new f.Behaviors(this),b.View.apply(this,arguments),f.MonitorDOMRefresh(this),this.listenTo(this,"show",this.onShowCalled)},getTemplate:function(){return this.getOption("template")},mixinTemplateHelpers:function(a){a=a||{};var b=this.getOption("templateHelpers");return c.isFunction(b)&&(b=b.call(this)),c.extend(a,b)},normalizeUIKeys:function(a){var b=c.result(this,"ui"),d=c.result(this,"_uiBindings");return f.normalizeUIKeys(a,d||b)},configureTriggers:function(){if(this.triggers){var a={},b=this.normalizeUIKeys(c.result(this,"triggers"));return c.each(b,function(b,d){var e=c.isObject(b),f=e?b.event:b;a[d]=function(a){if(a){var c=a.preventDefault,d=a.stopPropagation,g=e?b.preventDefault:c,h=e?b.stopPropagation:d;g&&c&&c.apply(a),h&&d&&d.apply(a)}var i={view:this,model:this.model,collection:this.collection};this.triggerMethod(f,i)}},this),a}},delegateEvents:function(a){this._delegateDOMEvents(a),this.bindEntityEvents(this.model,this.getOption("modelEvents")),this.bindEntityEvents(this.collection,this.getOption("collectionEvents"))},_delegateDOMEvents:function(a){a=a||this.events,c.isFunction(a)&&(a=a.call(this)),a=this.normalizeUIKeys(a);var d={},e=c.result(this,"behaviorEvents")||{},f=this.configureTriggers();c.extend(d,e,a,f),b.View.prototype.delegateEvents.call(this,d)},undelegateEvents:function(){var a=Array.prototype.slice.call(arguments);b.View.prototype.undelegateEvents.apply(this,a),this.unbindEntityEvents(this.model,this.getOption("modelEvents")),this.unbindEntityEvents(this.collection,this.getOption("collectionEvents"))},onShowCalled:function(){},_ensureViewIsIntact:function(){if(this.isDestroyed){var a=new Error("Cannot use a view thats already been destroyed.");throw a.name="ViewDestroyedError",a}},destroy:function(){if(!this.isDestroyed){var a=Array.prototype.slice.call(arguments);this.triggerMethod.apply(this,["before:destroy"].concat(a)),this.isDestroyed=!0,this.triggerMethod.apply(this,["destroy"].concat(a)),this.unbindUIElements(),this.remove()}},bindUIElements:function(){if(this.ui){this._uiBindings||(this._uiBindings=this.ui);var a=c.result(this,"_uiBindings");this.ui={},c.each(c.keys(a),function(b){var c=a[b];this.ui[b]=this.$(c)},this)}},unbindUIElements:function(){this.ui&&this._uiBindings&&(c.each(this.ui,function(a,b){delete this.ui[b]},this),this.ui=this._uiBindings,delete this._uiBindings)},triggerMethod:f.triggerMethod,normalizeMethods:f.normalizeMethods,getOption:f.proxyGetOption,bindEntityEvents:f.proxyBindEntityEvents,unbindEntityEvents:f.proxyUnbindEntityEvents}),f.ItemView=f.View.extend({constructor:function(){f.View.apply(this,arguments)},serializeData:function(){var a={};return this.model?a=this.model.toJSON():this.collection&&(a={items:this.collection.toJSON()}),a},render:function(){this._ensureViewIsIntact(),this.triggerMethod("before:render",this);var a=this.serializeData();a=this.mixinTemplateHelpers(a);var b=this.getTemplate(),c=f.Renderer.render(b,a);return this.attachElContent(c),this.bindUIElements(),this.triggerMethod("render",this),this},attachElContent:function(a){return this.$el.html(a),this},destroy:function(){this.isDestroyed||f.View.prototype.destroy.apply(this,arguments)}}),f.CollectionView=f.View.extend({childViewEventPrefix:"childview",constructor:function(a){var b=a||{};this.sort=c.isUndefined(b.sort)?!0:b.sort,this._initChildViewStorage(),f.View.apply(this,arguments),this._initialEvents(),this.initRenderBuffer()},initRenderBuffer:function(){this.elBuffer=document.createDocumentFragment(),this._bufferedChildren=[]},startBuffering:function(){this.initRenderBuffer(),this.isBuffering=!0},endBuffering:function(){this.isBuffering=!1,this._triggerBeforeShowBufferedChildren(),this.attachBuffer(this,this.elBuffer),this._triggerShowBufferedChildren(),this.initRenderBuffer()},_triggerBeforeShowBufferedChildren:function(){this._isShown&&c.invoke(this._bufferedChildren,"triggerMethod","before:show")},_triggerShowBufferedChildren:function(){this._isShown&&(c.each(this._bufferedChildren,function(a){c.isFunction(a.triggerMethod)?a.triggerMethod("show"):f.triggerMethod.call(a,"show")}),this._bufferedChildren=[])},_initialEvents:function(){this.collection&&(this.listenTo(this.collection,"add",this._onCollectionAdd),this.listenTo(this.collection,"remove",this._onCollectionRemove),this.listenTo(this.collection,"reset",this.render),this.sort&&this.listenTo(this.collection,"sort",this._sortViews))},_onCollectionAdd:function(a){this.destroyEmptyView();var b=this.getChildView(a),c=this.collection.indexOf(a);this.addChild(a,b,c)},_onCollectionRemove:function(a){var b=this.children.findByModel(a);this.removeChildView(b),this.checkEmpty()},onShowCalled:function(){this.children.each(function(a){c.isFunction(a.triggerMethod)?a.triggerMethod("show"):f.triggerMethod.call(a,"show")})},render:function(){return this._ensureViewIsIntact(),this.triggerMethod("before:render",this),this._renderChildren(),this.triggerMethod("render",this),this},_sortViews:function(){var a=this.collection.find(function(a,b){var c=this.children.findByModel(a);return c&&c._index!==b},this);a&&this.render()},_renderChildren:function(){this.startBuffering(),this.destroyEmptyView(),this.destroyChildren(),this.isEmpty(this.collection)?this.showEmptyView():(this.triggerMethod("before:render:collection",this),this.showCollection(),this.triggerMethod("render:collection",this)),this.endBuffering()},showCollection:function(){var a;this.collection.each(function(b,c){a=this.getChildView(b),this.addChild(b,a,c)},this)},showEmptyView:function(){var a=this.getEmptyView();if(a&&!this._showingEmptyView){this.triggerMethod("before:render:empty"),this._showingEmptyView=!0;var c=new b.Model;this.addEmptyView(c,a),this.triggerMethod("render:empty")}},destroyEmptyView:function(){this._showingEmptyView&&(this.destroyChildren(),delete this._showingEmptyView)},getEmptyView:function(){return this.getOption("emptyView")},addEmptyView:function(a,b){var d=this.getOption("emptyViewOptions")||this.getOption("childViewOptions");c.isFunction(d)&&(d=d.call(this));var e=this.buildChildView(a,b,d);this._isShown&&this.triggerMethod.call(e,"before:show"),this.children.add(e),this.renderChildView(e,-1),this._isShown&&this.triggerMethod.call(e,"show")},getChildView:function(){var a=this.getOption("childView");return a||d('A "childView" must be specified',"NoChildViewError"),a},addChild:function(a,b,d){var e=this.getOption("childViewOptions");c.isFunction(e)&&(e=e.call(this,a,d));var f=this.buildChildView(a,b,e);return this._updateIndices(f,!0,d),this._addChildView(f,d),f},_updateIndices:function(a,b,c){this.sort&&(b?(a._index=c,this.children.each(function(b){b._index>=a._index&&b._index++})):this.children.each(function(b){b._index>=a._index&&b._index--}))},_addChildView:function(a,b){this.proxyChildEvents(a),this.triggerMethod("before:add:child",a),this.children.add(a),this.renderChildView(a,b),this._isShown&&!this.isBuffering&&(c.isFunction(a.triggerMethod)?a.triggerMethod("show"):f.triggerMethod.call(a,"show")),this.triggerMethod("add:child",a)},renderChildView:function(a,b){a.render(),this.attachHtml(this,a,b)},buildChildView:function(a,b,d){var e=c.extend({model:a},d);return new b(e)},removeChildView:function(a){a&&(this.triggerMethod("before:remove:child",a),a.destroy?a.destroy():a.remove&&a.remove(),this.stopListening(a),this.children.remove(a),this.triggerMethod("remove:child",a),this._updateIndices(a,!1))},isEmpty:function(){return!this.collection||0===this.collection.length},checkEmpty:function(){this.isEmpty(this.collection)&&this.showEmptyView()},attachBuffer:function(a,b){a.$el.append(b)},attachHtml:function(a,b,c){a.isBuffering?(a.elBuffer.appendChild(b.el),a._bufferedChildren.push(b)):a._insertBefore(b,c)||a._insertAfter(b)},_insertBefore:function(a,b){var c,d=this.sort&&b<this.children.length-1;return d&&(c=this.children.find(function(a){return a._index===b+1})),c?(c.$el.before(a.el),!0):!1},_insertAfter:function(a){this.$el.append(a.el)},_initChildViewStorage:function(){this.children=new b.ChildViewContainer},destroy:function(){this.isDestroyed||(this.triggerMethod("before:destroy:collection"),this.destroyChildren(),this.triggerMethod("destroy:collection"),f.View.prototype.destroy.apply(this,arguments))},destroyChildren:function(){this.children.each(this.removeChildView,this),this.checkEmpty()},proxyChildEvents:function(a){var b=this.getOption("childViewEventPrefix");this.listenTo(a,"all",function(){var d=Array.prototype.slice.call(arguments),e=d[0],f=this.normalizeMethods(c.result(this,"childEvents"));d[0]=b+":"+e,d.splice(1,0,a),"undefined"!=typeof f&&c.isFunction(f[e])&&f[e].apply(this,d.slice(1)),this.triggerMethod.apply(this,d)},this)}}),f.CompositeView=f.CollectionView.extend({constructor:function(){f.CollectionView.apply(this,arguments)},_initialEvents:function(){this.once("render",function(){this.collection&&(this.listenTo(this.collection,"add",this._onCollectionAdd),this.listenTo(this.collection,"remove",this._onCollectionRemove),this.listenTo(this.collection,"reset",this._renderChildren),this.sort&&this.listenTo(this.collection,"sort",this._sortViews))})},getChildView:function(){var a=this.getOption("childView")||this.constructor;return a||d('A "childView" must be specified',"NoChildViewError"),a},serializeData:function(){var a={};return this.model&&(a=this.model.toJSON()),a},render:function(){return this._ensureViewIsIntact(),this.isRendered=!0,this.resetChildViewContainer(),this.triggerMethod("before:render",this),this._renderRoot(),this._renderChildren(),this.triggerMethod("render",this),this},_renderChildren:function(){this.isRendered&&f.CollectionView.prototype._renderChildren.call(this)},_renderRoot:function(){var a={};a=this.serializeData(),a=this.mixinTemplateHelpers(a),this.triggerMethod("before:render:template");var b=this.getTemplate(),c=f.Renderer.render(b,a);this.attachElContent(c),this.bindUIElements(),this.triggerMethod("render:template")},attachElContent:function(a){return this.$el.html(a),this},attachBuffer:function(a,b){var c=this.getChildViewContainer(a);c.append(b)},_insertAfter:function(a){var b=this.getChildViewContainer(this);b.append(a.el)},getChildViewContainer:function(a){if("$childViewContainer"in a)return a.$childViewContainer;var b,e=f.getOption(a,"childViewContainer");if(e){var g=c.isFunction(e)?e.call(a):e;b="@"===g.charAt(0)&&a.ui?a.ui[g.substr(4)]:a.$(g),b.length<=0&&d('The specified "childViewContainer" was not found: '+a.childViewContainer,"ChildViewContainerMissingError")}else b=a.$el;return a.$childViewContainer=b,b},resetChildViewContainer:function(){this.$childViewContainer&&delete this.$childViewContainer}}),f.LayoutView=f.ItemView.extend({regionClass:f.Region,constructor:function(a){a=a||{},this._firstRender=!0,this._initializeRegions(a),f.ItemView.call(this,a)},render:function(){return this._ensureViewIsIntact(),this._firstRender?this._firstRender=!1:this._reInitializeRegions(),f.ItemView.prototype.render.apply(this,arguments)},destroy:function(){this.isDestroyed||(this.regionManager.destroy(),f.ItemView.prototype.destroy.apply(this,arguments))},addRegion:function(a,b){this.triggerMethod("before:region:add",a);var c={};return c[a]=b,this._buildRegions(c)[a]},addRegions:function(a){return this.regions=c.extend({},this.regions,a),this._buildRegions(a)},removeRegion:function(a){return this.triggerMethod("before:region:remove",a),delete this.regions[a],this.regionManager.removeRegion(a)},getRegion:function(a){return this.regionManager.get(a)},getRegions:function(){return this.regionManager.getRegions()},_buildRegions:function(a){var b=this,c={regionClass:this.getOption("regionClass"),parentEl:function(){return b.$el}};return this.regionManager.addRegions(a,c)},_initializeRegions:function(a){var b;this._initRegionManager(),b=c.isFunction(this.regions)?this.regions(a):this.regions||{};var d=this.getOption.call(a,"regions");c.isFunction(d)&&(d=d.call(this,a)),c.extend(b,d),this.addRegions(b)},_reInitializeRegions:function(){this.regionManager.emptyRegions(),this.regionManager.each(function(a){a.reset()})},getRegionManager:function(){return new f.RegionManager},_initRegionManager:function(){this.regionManager=this.getRegionManager(),this.listenTo(this.regionManager,"before:add:region",function(a){this.triggerMethod("before:add:region",a)}),this.listenTo(this.regionManager,"add:region",function(a,b){this[a]=b,this.triggerMethod("add:region",a,b)}),this.listenTo(this.regionManager,"before:remove:region",function(a){this.triggerMethod("before:remove:region",a)}),this.listenTo(this.regionManager,"remove:region",function(a,b){delete this[a],this.triggerMethod("remove:region",a,b)})}}),f.Behavior=function(a,b){function c(b,c){this.view=c,this.defaults=a.result(this,"defaults")||{},this.options=a.extend({},this.defaults,b),this.$=function(){return this.view.$.apply(this.view,arguments)},this.initialize.apply(this,arguments)}return a.extend(c.prototype,b.Events,{initialize:function(){},destroy:function(){this.stopListening()},triggerMethod:f.triggerMethod,getOption:f.proxyGetOption,bindEntityEvents:f.proxyBindEntityEvents,unbindEntityEvents:f.proxyUnbindEntityEvents}),c.extend=f.extend,c}(c,b),f.Behaviors=function(a,b){function c(a,d){d=c.parseBehaviors(a,d||b.result(a,"behaviors")),c.wrap(a,d,["bindUIElements","unbindUIElements","delegateEvents","undelegateEvents","behaviorEvents","triggerMethod","setElement","destroy"])}var d={setElement:function(a,c){a.apply(this,b.tail(arguments,2)),b.each(c,function(a){a.$el=this.$el},this)},destroy:function(a,c){var d=b.tail(arguments,2);a.apply(this,d),b.invoke(c,"destroy",d)},bindUIElements:function(a,c){a.apply(this),b.invoke(c,a)},unbindUIElements:function(a,c){a.apply(this),b.invoke(c,a)},triggerMethod:function(a,c){var d=b.tail(arguments,2);a.apply(this,d),b.each(c,function(b){a.apply(b,d)})},delegateEvents:function(c,d){var e=b.tail(arguments,2);c.apply(this,e),b.each(d,function(b){a.bindEntityEvents(b,this.model,a.getOption(b,"modelEvents")),a.bindEntityEvents(b,this.collection,a.getOption(b,"collectionEvents"))},this)},undelegateEvents:function(c,d){var e=b.tail(arguments,2);c.apply(this,e),b.each(d,function(b){a.unbindEntityEvents(b,this.model,a.getOption(b,"modelEvents")),a.unbindEntityEvents(b,this.collection,a.getOption(b,"collectionEvents"))},this)},behaviorEvents:function(c,d){var e={},f=b.result(this,"ui");return b.each(d,function(c,d){var g={},h=b.clone(b.result(c,"events"))||{},i=b.result(c,"ui"),j=b.extend({},f,i);h=a.normalizeUIKeys(h,j),b.each(b.keys(h),function(a){var e=new Array(d+2).join(" "),f=a+e,i=b.isFunction(h[a])?h[a]:c[h[a]];g[f]=b.bind(i,c)}),e=b.extend(e,g)}),e}};return b.extend(c,{behaviorsLookup:function(){throw new Error("You must define where your behaviors are stored.See https://github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.behaviors.md#behaviorslookup")},getBehaviorClass:function(a,d){return a.behaviorClass?a.behaviorClass:b.isFunction(c.behaviorsLookup)?c.behaviorsLookup.apply(this,arguments)[d]:c.behaviorsLookup[d]},parseBehaviors:function(a,d){return b.chain(d).map(function(d,e){var f=c.getBehaviorClass(d,e),g=new f(d,a),h=c.parseBehaviors(a,b.result(g,"behaviors"));return[g].concat(h)}).flatten().value()},wrap:function(a,c,e){b.each(e,function(e){a[e]=b.partial(d[e],a[e],c)})}}),c}(f,c),f.AppRouter=b.Router.extend({constructor:function(a){b.Router.apply(this,arguments),this.options=a||{};var c=this.getOption("appRoutes"),d=this._getController();this.processAppRoutes(d,c),this.on("route",this._processOnRoute,this)},appRoute:function(a,b){var c=this._getController();this._addAppRoute(c,a,b)},_processOnRoute:function(a,b){var d=c.invert(this.appRoutes)[a];c.isFunction(this.onRoute)&&this.onRoute(a,d,b)},processAppRoutes:function(a,b){if(b){var d=c.keys(b).reverse();c.each(d,function(c){this._addAppRoute(a,c,b[c])},this)}},_getController:function(){return this.getOption("controller")},_addAppRoute:function(a,b,e){var f=a[e];f||d('Method "'+e+'" was not found on the controller'),this.route(b,e,c.bind(f,a))},getOption:f.proxyGetOption}),f.Application=function(a){this._initRegionManager(),this._initCallbacks=new f.Callbacks;var d=b.Wreqr.radio.channel("global");this.vent=d.vent,this.commands=d.commands,this.reqres=d.reqres,this.submodules={},c.extend(this,a)},c.extend(f.Application.prototype,b.Events,{execute:function(){this.commands.execute.apply(this.commands,arguments)},request:function(){return this.reqres.request.apply(this.reqres,arguments)},addInitializer:function(a){this._initCallbacks.add(a)},start:function(a){this.triggerMethod("before:start",a),this._initCallbacks.run(a,this),this.triggerMethod("start",a)},addRegions:function(a){return this._regionManager.addRegions(a)},emptyRegions:function(){this._regionManager.emptyRegions()},removeRegion:function(a){this._regionManager.removeRegion(a)},getRegion:function(a){return this._regionManager.get(a)},getRegions:function(){return this._regionManager.getRegions()},module:function(a,b){var c=f.Module.getClass(b),d=g.call(arguments);return d.unshift(this),c.create.apply(c,d)},_initRegionManager:function(){this._regionManager=new f.RegionManager,this.listenTo(this._regionManager,"before:add:region",function(a){this.triggerMethod("before:add:region",a)}),this.listenTo(this._regionManager,"add:region",function(a,b){this[a]=b,this.triggerMethod("add:region",a,b)}),this.listenTo(this._regionManager,"before:remove:region",function(a){this.triggerMethod("before:remove:region",a)}),this.listenTo(this._regionManager,"remove:region",function(a,b){delete this[a],this.triggerMethod("remove:region",a,b)})},triggerMethod:f.triggerMethod}),f.Application.extend=f.extend,f.Module=function(a,b,d){this.moduleName=a,this.options=c.extend({},this.options,d),this.initialize=d.initialize||this.initialize,this.submodules={},this._setupInitializersAndFinalizers(),this.app=b,this.startWithParent=!0,c.isFunction(this.initialize)&&this.initialize(a,b,this.options)},f.Module.extend=f.extend,c.extend(f.Module.prototype,b.Events,{initialize:function(){},addInitializer:function(a){this._initializerCallbacks.add(a)},addFinalizer:function(a){this._finalizerCallbacks.add(a)},start:function(a){this._isInitialized||(c.each(this.submodules,function(b){b.startWithParent&&b.start(a)}),this.triggerMethod("before:start",a),this._initializerCallbacks.run(a,this),this._isInitialized=!0,this.triggerMethod("start",a))},stop:function(){this._isInitialized&&(this._isInitialized=!1,this.triggerMethod("before:stop"),c.each(this.submodules,function(a){a.stop()}),this._finalizerCallbacks.run(void 0,this),this._initializerCallbacks.reset(),this._finalizerCallbacks.reset(),this.triggerMethod("stop"))},addDefinition:function(a,b){this._runModuleDefinition(a,b)},_runModuleDefinition:function(a,d){if(a){var e=c.flatten([this,this.app,b,f,b.$,c,d]);a.apply(this,e)}},_setupInitializersAndFinalizers:function(){this._initializerCallbacks=new f.Callbacks,this._finalizerCallbacks=new f.Callbacks},triggerMethod:f.triggerMethod}),c.extend(f.Module,{create:function(a,b,d){var e=a,f=g.call(arguments);f.splice(0,3),b=b.split(".");var h=b.length,i=[];return i[h-1]=d,c.each(b,function(b,c){var g=e;e=this._getModule(g,b,a,d),this._addModuleDefinition(g,e,i[c],f)},this),e},_getModule:function(a,b,d,e){var f=c.extend({},e),g=this.getClass(e),h=a[b];return h||(h=new g(b,d,f),a[b]=h,a.submodules[b]=h),h},getClass:function(a){var b=f.Module;return a?a.prototype instanceof b?a:a.moduleClass||b:b},_addModuleDefinition:function(a,b,c,d){var e=this._getDefine(c),f=this._getStartWithParent(c,b);e&&b.addDefinition(e,d),this._addStartWithParent(a,b,f)},_getStartWithParent:function(a,b){var d;return c.isFunction(a)&&a.prototype instanceof f.Module?(d=b.constructor.prototype.startWithParent,c.isUndefined(d)?!0:d):c.isObject(a)?(d=a.startWithParent,c.isUndefined(d)?!0:d):!0},_getDefine:function(a){return!c.isFunction(a)||a.prototype instanceof f.Module?c.isObject(a)?a.define:null:a},_addStartWithParent:function(a,b,c){b.startWithParent=b.startWithParent&&c,b.startWithParent&&!b.startWithParentIsConfigured&&(b.startWithParentIsConfigured=!0,a.addInitializer(function(a){b.startWithParent&&b.start(a)}))}}),f});
+//# sourceMappingURL=backbone.marionette.map
\ No newline at end of file
diff --git a/xos/core/xoslib/static/js/vendor/backbone.syphon.js b/xos/core/xoslib/static/js/vendor/backbone.syphon.js
new file mode 100644
index 0000000..3cd1537
--- /dev/null
+++ b/xos/core/xoslib/static/js/vendor/backbone.syphon.js
@@ -0,0 +1,469 @@
+// Backbone.Syphon, v0.4.1
+// Copyright (c)2012 Derick Bailey, Muted Solutions, LLC.
+// Distributed under MIT license
+// http://github.com/derickbailey/backbone.syphon
+Backbone.Syphon = (function(Backbone, $, _){
+  var Syphon = {};
+
+  // Ignore Element Types
+  // --------------------
+
+  // Tell Syphon to ignore all elements of these types. You can
+  // push new types to ignore directly in to this array.
+  Syphon.ignoredTypes = ["button", "submit", "reset", "fieldset"];
+
+  // Syphon
+  // ------
+
+  // Get a JSON object that represents
+  // all of the form inputs, in this view.
+  // Alternately, pass a form element directly
+  // in place of the view.
+  Syphon.serialize = function(view, options){
+    var data = {};
+
+    // Build the configuration
+    var config = buildConfig(options);
+
+    // Get all of the elements to process
+    var elements = getInputElements(view, config);
+
+    // Process all of the elements
+    _.each(elements, function(el){
+      var $el = $(el);
+      var type = getElementType($el); 
+
+      // Get the key for the input
+      var keyExtractor = config.keyExtractors.get(type);
+      var key = keyExtractor($el);
+
+      // Get the value for the input
+      var inputReader = config.inputReaders.get(type);
+      var value = inputReader($el);
+
+      // Get the key assignment validator and make sure
+      // it's valid before assigning the value to the key
+      var validKeyAssignment = config.keyAssignmentValidators.get(type);
+      if (validKeyAssignment($el, key, value)){
+        var keychain = config.keySplitter(key);
+        data = assignKeyValue(data, keychain, value);
+      }
+    });
+
+    // Done; send back the results.
+    return data;
+  };
+  
+  // Use the given JSON object to populate
+  // all of the form inputs, in this view.
+  // Alternately, pass a form element directly
+  // in place of the view.
+  Syphon.deserialize = function(view, data, options){
+    // Build the configuration
+    var config = buildConfig(options);
+
+    // Get all of the elements to process
+    var elements = getInputElements(view, config);
+
+    // Flatten the data structure that we are deserializing
+    var flattenedData = flattenData(config, data);
+
+    // Process all of the elements
+    _.each(elements, function(el){
+      var $el = $(el);
+      var type = getElementType($el); 
+
+      // Get the key for the input
+      var keyExtractor = config.keyExtractors.get(type);
+      var key = keyExtractor($el);
+
+      // Get the input writer and the value to write
+      var inputWriter = config.inputWriters.get(type);
+      var value = flattenedData[key];
+
+      // Write the value to the input
+      inputWriter($el, value);
+    });
+  };
+
+  // Helpers
+  // -------
+
+  // Retrieve all of the form inputs
+  // from the form
+  var getInputElements = function(view, config){
+    var form = getForm(view);
+    var elements = form.elements;
+
+    elements = _.reject(elements, function(el){
+      var reject;
+      var type = getElementType(el);
+      var extractor = config.keyExtractors.get(type);
+      var identifier = extractor($(el));
+     
+      var foundInIgnored = _.include(config.ignoredTypes, type);
+      var foundInInclude = _.include(config.include, identifier);
+      var foundInExclude = _.include(config.exclude, identifier);
+
+      if (foundInInclude){
+        reject = false;
+      } else {
+        if (config.include){
+          reject = true;
+        } else {
+          reject = (foundInExclude || foundInIgnored);
+        }
+      }
+
+      return reject;
+    });
+
+    return elements;
+  };
+
+  // Determine what type of element this is. It
+  // will either return the `type` attribute of
+  // an `<input>` element, or the `tagName` of
+  // the element when the element is not an `<input>`.
+  var getElementType = function(el){
+    var typeAttr;
+    var $el = $(el);
+    var tagName = $el[0].tagName;
+    var type = tagName;
+
+    if (tagName.toLowerCase() === "input"){
+      typeAttr = $el.attr("type");
+      if (typeAttr){
+        type = typeAttr;
+      } else {
+        type = "text";
+      }
+    }
+    
+    // Always return the type as lowercase
+    // so it can be matched to lowercase
+    // type registrations.
+    return type.toLowerCase();
+  };
+  
+  // If a form element is given, just return it. 
+  // Otherwise, get the form element from the view.
+  var getForm = function(viewOrForm){
+    if (_.isUndefined(viewOrForm.$el) && viewOrForm.tagName.toLowerCase() === 'form'){
+      return viewOrForm;
+    } else {
+      return viewOrForm.$el.is("form") ? viewOrForm.el : viewOrForm.$("form")[0];
+    }
+  };
+
+  // Build a configuration object and initialize
+  // default values.
+  var buildConfig = function(options){
+    var config = _.clone(options) || {};
+    
+    config.ignoredTypes = _.clone(Syphon.ignoredTypes);
+    config.inputReaders = config.inputReaders || Syphon.InputReaders;
+    config.inputWriters = config.inputWriters || Syphon.InputWriters;
+    config.keyExtractors = config.keyExtractors || Syphon.KeyExtractors;
+    config.keySplitter = config.keySplitter || Syphon.KeySplitter;
+    config.keyJoiner = config.keyJoiner || Syphon.KeyJoiner;
+    config.keyAssignmentValidators = config.keyAssignmentValidators || Syphon.KeyAssignmentValidators;
+    
+    return config;
+  };
+
+  // Assigns `value` to a parsed JSON key. 
+  //
+  // The first parameter is the object which will be
+  // modified to store the key/value pair.
+  //
+  // The second parameter accepts an array of keys as a 
+  // string with an option array containing a 
+  // single string as the last option.
+  //
+  // The third parameter is the value to be assigned.
+  //
+  // Examples:
+  //
+  // `["foo", "bar", "baz"] => {foo: {bar: {baz: "value"}}}`
+  // 
+  // `["foo", "bar", ["baz"]] => {foo: {bar: {baz: ["value"]}}}`
+  // 
+  // When the final value is an array with a string, the key
+  // becomes an array, and values are pushed in to the array,
+  // allowing multiple fields with the same name to be 
+  // assigned to the array.
+  var assignKeyValue = function(obj, keychain, value) {
+    if (!keychain){ return obj; }
+
+    var key = keychain.shift();
+
+    // build the current object we need to store data
+    if (!obj[key]){
+      obj[key] = _.isArray(key) ? [] : {};
+    }
+
+    // if it's the last key in the chain, assign the value directly
+    if (keychain.length === 0){
+      if (_.isArray(obj[key])){
+        obj[key].push(value);
+      } else {
+        obj[key] = value;
+      }
+    }
+
+    // recursive parsing of the array, depth-first
+    if (keychain.length > 0){
+      assignKeyValue(obj[key], keychain, value);
+    }
+    
+    return obj;
+  };
+
+  // Flatten the data structure in to nested strings, using the
+  // provided `KeyJoiner` function.
+  //
+  // Example:
+  //
+  // This input:
+  //
+  // ```js
+  // {
+  //   widget: "wombat",
+  //   foo: {
+  //     bar: "baz",
+  //     baz: {
+  //       quux: "qux"
+  //     },
+  //     quux: ["foo", "bar"]
+  //   }
+  // }
+  // ```
+  //
+  // With a KeyJoiner that uses [ ] square brackets, 
+  // should produce this output:
+  //
+  // ```js
+  // {
+  //  "widget": "wombat",
+  //  "foo[bar]": "baz",
+  //  "foo[baz][quux]": "qux",
+  //  "foo[quux]": ["foo", "bar"]
+  // }
+  // ```
+  var flattenData = function(config, data, parentKey){
+    var flatData = {};
+
+    _.each(data, function(value, keyName){
+      var hash = {};
+
+      // If there is a parent key, join it with
+      // the current, child key.
+      if (parentKey){
+        keyName = config.keyJoiner(parentKey, keyName);
+      }
+
+      if (_.isArray(value)){
+        keyName += "[]";
+        hash[keyName] = value;
+      } else if (_.isObject(value)){
+        hash = flattenData(config, value, keyName);
+      } else {
+        hash[keyName] = value;
+      }
+
+      // Store the resulting key/value pairs in the
+      // final flattened data object
+      _.extend(flatData, hash);
+    });
+
+    return flatData;
+  };
+
+  return Syphon;
+})(Backbone, jQuery, _);
+
+// Type Registry
+// -------------
+
+// Type Registries allow you to register something to
+// an input type, and retrieve either the item registered
+// for a specific type or the default registration
+Backbone.Syphon.TypeRegistry = function(){
+  this.registeredTypes = {};
+};
+
+// Borrow Backbone's `extend` keyword for our TypeRegistry
+Backbone.Syphon.TypeRegistry.extend = Backbone.Model.extend;
+
+_.extend(Backbone.Syphon.TypeRegistry.prototype, {
+
+  // Get the registered item by type. If nothing is
+  // found for the specified type, the default is
+  // returned.
+  get: function(type){
+    var item = this.registeredTypes[type];
+
+    if (!item){
+      item = this.registeredTypes["default"];
+    }
+
+    return item;
+  },
+
+  // Register a new item for a specified type
+  register: function(type, item){
+    this.registeredTypes[type] = item;
+  },
+
+  // Register a default item to be used when no
+  // item for a specified type is found
+  registerDefault: function(item){
+    this.registeredTypes["default"] = item;
+  },
+
+  // Remove an item from a given type registration
+  unregister: function(type){
+    if (this.registeredTypes[type]){
+      delete this.registeredTypes[type];
+    }
+  }
+});
+
+
+
+
+// Key Extractors
+// --------------
+
+// Key extractors produce the "key" in `{key: "value"}`
+// pairs, when serializing.
+Backbone.Syphon.KeyExtractorSet = Backbone.Syphon.TypeRegistry.extend();
+
+// Built-in Key Extractors
+Backbone.Syphon.KeyExtractors = new Backbone.Syphon.KeyExtractorSet();
+
+// The default key extractor, which uses the
+// input element's "id" attribute
+Backbone.Syphon.KeyExtractors.registerDefault(function($el){
+  return $el.prop("name");
+});
+
+
+// Input Readers
+// -------------
+
+// Input Readers are used to extract the value from
+// an input element, for the serialized object result
+Backbone.Syphon.InputReaderSet = Backbone.Syphon.TypeRegistry.extend();
+
+// Built-in Input Readers
+Backbone.Syphon.InputReaders = new Backbone.Syphon.InputReaderSet();
+
+// The default input reader, which uses an input
+// element's "value"
+Backbone.Syphon.InputReaders.registerDefault(function($el){
+  return $el.val();
+});
+
+// Checkbox reader, returning a boolean value for
+// whether or not the checkbox is checked.
+Backbone.Syphon.InputReaders.register("checkbox", function($el){
+  var checked = $el.prop("checked");
+  return checked;
+});
+
+
+// Input Writers
+// -------------
+
+// Input Writers are used to insert a value from an
+// object into an input element.
+Backbone.Syphon.InputWriterSet = Backbone.Syphon.TypeRegistry.extend();
+
+// Built-in Input Writers
+Backbone.Syphon.InputWriters = new Backbone.Syphon.InputWriterSet();
+
+// The default input writer, which sets an input
+// element's "value"
+Backbone.Syphon.InputWriters.registerDefault(function($el, value){
+  $el.val(value);
+});
+
+// Checkbox writer, set whether or not the checkbox is checked
+// depending on the boolean value.
+Backbone.Syphon.InputWriters.register("checkbox", function($el, value){
+  $el.prop("checked", value);
+});
+
+// Radio button writer, set whether or not the radio button is
+// checked.  The button should only be checked if it's value
+// equals the given value.
+Backbone.Syphon.InputWriters.register("radio", function($el, value){
+  $el.prop("checked", $el.val() === value);
+});
+
+// Key Assignment Validators
+// -------------------------
+
+// Key Assignment Validators are used to determine whether or not a
+// key should be assigned to a value, after the key and value have been
+// extracted from the element. This is the last opportunity to prevent
+// bad data from getting serialized to your object.
+
+Backbone.Syphon.KeyAssignmentValidatorSet = Backbone.Syphon.TypeRegistry.extend();
+
+// Build-in Key Assignment Validators
+Backbone.Syphon.KeyAssignmentValidators = new Backbone.Syphon.KeyAssignmentValidatorSet();
+
+// Everything is valid by default
+Backbone.Syphon.KeyAssignmentValidators.registerDefault(function(){ return true; });
+
+// But only the "checked" radio button for a given
+// radio button group is valid
+Backbone.Syphon.KeyAssignmentValidators.register("radio", function($el, key, value){ 
+  return $el.prop("checked");
+});
+
+
+// Backbone.Syphon.KeySplitter
+// ---------------------------
+
+// This function is used to split DOM element keys in to an array
+// of parts, which are then used to create a nested result structure.
+// returning `["foo", "bar"]` results in `{foo: { bar: "value" }}`.
+//
+// Override this method to use a custom key splitter, such as:
+// `<input name="foo.bar.baz">`, `return key.split(".")`
+Backbone.Syphon.KeySplitter = function(key){
+  var matches = key.match(/[^\[\]]+/g);
+
+  if (key.indexOf("[]") === key.length - 2){
+    lastKey = matches.pop();
+    matches.push([lastKey]);
+  }
+
+  return matches;
+}
+
+
+// Backbone.Syphon.KeyJoiner
+// -------------------------
+
+// Take two segments of a key and join them together, to create the
+// de-normalized key name, when deserializing a data structure back
+// in to a form.
+//
+// Example: 
+//
+// With this data strucutre `{foo: { bar: {baz: "value", quux: "another"} } }`,
+// the key joiner will be called with these parameters, and assuming the
+// join happens with "[ ]" square brackets, the specified output:
+// 
+// `KeyJoiner("foo", "bar")` //=> "foo[bar]"
+// `KeyJoiner("foo[bar]", "baz")` //=> "foo[bar][baz]"
+// `KeyJoiner("foo[bar]", "quux")` //=> "foo[bar][quux]"
+
+Backbone.Syphon.KeyJoiner = function(parentKey, childKey){
+  return parentKey + "[" + childKey + "]";
+}
diff --git a/xos/core/xoslib/static/js/vendor/backbone.wreqr.js b/xos/core/xoslib/static/js/vendor/backbone.wreqr.js
new file mode 100644
index 0000000..66de72f
--- /dev/null
+++ b/xos/core/xoslib/static/js/vendor/backbone.wreqr.js
@@ -0,0 +1,440 @@
+// Backbone.Wreqr (Backbone.Marionette)
+// ----------------------------------
+// v1.3.1
+//
+// Copyright (c)2014 Derick Bailey, Muted Solutions, LLC.
+// Distributed under MIT license
+//
+// http://github.com/marionettejs/backbone.wreqr
+
+
+(function(root, factory) {
+
+  if (typeof define === 'function' && define.amd) {
+    define(['backbone', 'underscore'], function(Backbone, _) {
+      return factory(Backbone, _);
+    });
+  } else if (typeof exports !== 'undefined') {
+    var Backbone = require('backbone');
+    var _ = require('underscore');
+    module.exports = factory(Backbone, _);
+  } else {
+    factory(root.Backbone, root._);
+  }
+
+}(this, function(Backbone, _) {
+  "use strict";
+
+  var previousWreqr = Backbone.Wreqr;
+
+  var Wreqr = Backbone.Wreqr = {};
+
+  Backbone.Wreqr.VERSION = '1.3.1';
+
+  Backbone.Wreqr.noConflict = function () {
+    Backbone.Wreqr = previousWreqr;
+    return this;
+  };
+
+  // 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){
+          return;
+        }
+  
+        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);
+        if (this.hasHandler(name)) {
+          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, _);
+  
+  // Wreqr.Channel
+  // --------------
+  //
+  // An object that wraps the three messaging systems:
+  // EventAggregator, RequestResponse, Commands
+  Wreqr.Channel = (function(Wreqr){
+    "use strict";
+  
+    var Channel = function(channelName) {
+      this.vent        = new Backbone.Wreqr.EventAggregator();
+      this.reqres      = new Backbone.Wreqr.RequestResponse();
+      this.commands    = new Backbone.Wreqr.Commands();
+      this.channelName = channelName;
+    };
+  
+    _.extend(Channel.prototype, {
+  
+      // Remove all handlers from the messaging systems of this channel
+      reset: function() {
+        this.vent.off();
+        this.vent.stopListening();
+        this.reqres.removeAllHandlers();
+        this.commands.removeAllHandlers();
+        return this;
+      },
+  
+      // Connect a hash of events; one for each messaging system
+      connectEvents: function(hash, context) {
+        this._connect('vent', hash, context);
+        return this;
+      },
+  
+      connectCommands: function(hash, context) {
+        this._connect('commands', hash, context);
+        return this;
+      },
+  
+      connectRequests: function(hash, context) {
+        this._connect('reqres', hash, context);
+        return this;
+      },
+  
+      // Attach the handlers to a given message system `type`
+      _connect: function(type, hash, context) {
+        if (!hash) {
+          return;
+        }
+  
+        context = context || this;
+        var method = (type === 'vent') ? 'on' : 'setHandler';
+  
+        _.each(hash, function(fn, eventName) {
+          this[type][method](eventName, _.bind(fn, context));
+        }, this);
+      }
+    });
+  
+  
+    return Channel;
+  })(Wreqr);
+  
+  // Wreqr.Radio
+  // --------------
+  //
+  // An object that lets you communicate with many channels.
+  Wreqr.radio = (function(Wreqr){
+    "use strict";
+  
+    var Radio = function() {
+      this._channels = {};
+      this.vent = {};
+      this.commands = {};
+      this.reqres = {};
+      this._proxyMethods();
+    };
+  
+    _.extend(Radio.prototype, {
+  
+      channel: function(channelName) {
+        if (!channelName) {
+          throw new Error('Channel must receive a name');
+        }
+  
+        return this._getChannel( channelName );
+      },
+  
+      _getChannel: function(channelName) {
+        var channel = this._channels[channelName];
+  
+        if(!channel) {
+          channel = new Wreqr.Channel(channelName);
+          this._channels[channelName] = channel;
+        }
+  
+        return channel;
+      },
+  
+      _proxyMethods: function() {
+        _.each(['vent', 'commands', 'reqres'], function(system) {
+          _.each( messageSystems[system], function(method) {
+            this[system][method] = proxyMethod(this, system, method);
+          }, this);
+        }, this);
+      }
+    });
+  
+  
+    var messageSystems = {
+      vent: [
+        'on',
+        'off',
+        'trigger',
+        'once',
+        'stopListening',
+        'listenTo',
+        'listenToOnce'
+      ],
+  
+      commands: [
+        'execute',
+        'setHandler',
+        'setHandlers',
+        'removeHandler',
+        'removeAllHandlers'
+      ],
+  
+      reqres: [
+        'request',
+        'setHandler',
+        'setHandlers',
+        'removeHandler',
+        'removeAllHandlers'
+      ]
+    };
+  
+    var proxyMethod = function(radio, system, method) {
+      return function(channelName) {
+        var messageSystem = radio._getChannel(channelName)[system];
+        var args = Array.prototype.slice.call(arguments, 1);
+  
+        return messageSystem[method].apply(messageSystem, args);
+      };
+    };
+  
+    return new Radio();
+  
+  })(Wreqr);
+  
+
+  return Backbone.Wreqr;
+
+}));
diff --git a/xos/core/xoslib/static/js/vendor/jquery-1.11.3.js b/xos/core/xoslib/static/js/vendor/jquery-1.11.3.js
new file mode 100644
index 0000000..6feb110
--- /dev/null
+++ b/xos/core/xoslib/static/js/vendor/jquery-1.11.3.js
@@ -0,0 +1,10351 @@
+/*!
+ * jQuery JavaScript Library v1.11.3
+ * http://jquery.com/
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ *
+ * Copyright 2005, 2014 jQuery Foundation, Inc. and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: 2015-04-28T16:19Z
+ */
+
+(function( global, factory ) {
+
+	if ( typeof module === "object" && typeof module.exports === "object" ) {
+		// For CommonJS and CommonJS-like environments where a proper window is present,
+		// execute the factory and get jQuery
+		// For environments that do not inherently posses a window with a document
+		// (such as Node.js), expose a jQuery-making factory as module.exports
+		// This accentuates the need for the creation of a real window
+		// e.g. var jQuery = require("jquery")(window);
+		// See ticket #14549 for more info
+		module.exports = global.document ?
+			factory( global, true ) :
+			function( w ) {
+				if ( !w.document ) {
+					throw new Error( "jQuery requires a window with a document" );
+				}
+				return factory( w );
+			};
+	} else {
+		factory( global );
+	}
+
+// Pass this if window is not defined yet
+}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
+
+// Can't do this because several apps including ASP.NET trace
+// the stack via arguments.caller.callee and Firefox dies if
+// you try to trace through "use strict" call chains. (#13335)
+// Support: Firefox 18+
+//
+
+var deletedIds = [];
+
+var slice = deletedIds.slice;
+
+var concat = deletedIds.concat;
+
+var push = deletedIds.push;
+
+var indexOf = deletedIds.indexOf;
+
+var class2type = {};
+
+var toString = class2type.toString;
+
+var hasOwn = class2type.hasOwnProperty;
+
+var support = {};
+
+
+
+var
+	version = "1.11.3",
+
+	// Define a local copy of jQuery
+	jQuery = function( selector, context ) {
+		// The jQuery object is actually just the init constructor 'enhanced'
+		// Need init if jQuery is called (just allow error to be thrown if not included)
+		return new jQuery.fn.init( selector, context );
+	},
+
+	// Support: Android<4.1, IE<9
+	// Make sure we trim BOM and NBSP
+	rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
+
+	// Matches dashed string for camelizing
+	rmsPrefix = /^-ms-/,
+	rdashAlpha = /-([\da-z])/gi,
+
+	// Used by jQuery.camelCase as callback to replace()
+	fcamelCase = function( all, letter ) {
+		return letter.toUpperCase();
+	};
+
+jQuery.fn = jQuery.prototype = {
+	// The current version of jQuery being used
+	jquery: version,
+
+	constructor: jQuery,
+
+	// Start with an empty selector
+	selector: "",
+
+	// The default length of a jQuery object is 0
+	length: 0,
+
+	toArray: function() {
+		return slice.call( this );
+	},
+
+	// Get the Nth element in the matched element set OR
+	// Get the whole matched element set as a clean array
+	get: function( num ) {
+		return num != null ?
+
+			// Return just the one element from the set
+			( num < 0 ? this[ num + this.length ] : this[ num ] ) :
+
+			// Return all the elements in a clean array
+			slice.call( this );
+	},
+
+	// Take an array of elements and push it onto the stack
+	// (returning the new matched element set)
+	pushStack: function( elems ) {
+
+		// Build a new jQuery matched element set
+		var ret = jQuery.merge( this.constructor(), elems );
+
+		// Add the old object onto the stack (as a reference)
+		ret.prevObject = this;
+		ret.context = this.context;
+
+		// Return the newly-formed element set
+		return ret;
+	},
+
+	// Execute a callback for every element in the matched set.
+	// (You can seed the arguments with an array of args, but this is
+	// only used internally.)
+	each: function( callback, args ) {
+		return jQuery.each( this, callback, args );
+	},
+
+	map: function( callback ) {
+		return this.pushStack( jQuery.map(this, function( elem, i ) {
+			return callback.call( elem, i, elem );
+		}));
+	},
+
+	slice: function() {
+		return this.pushStack( slice.apply( this, arguments ) );
+	},
+
+	first: function() {
+		return this.eq( 0 );
+	},
+
+	last: function() {
+		return this.eq( -1 );
+	},
+
+	eq: function( i ) {
+		var len = this.length,
+			j = +i + ( i < 0 ? len : 0 );
+		return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );
+	},
+
+	end: function() {
+		return this.prevObject || this.constructor(null);
+	},
+
+	// For internal use only.
+	// Behaves like an Array's method, not like a jQuery method.
+	push: push,
+	sort: deletedIds.sort,
+	splice: deletedIds.splice
+};
+
+jQuery.extend = jQuery.fn.extend = function() {
+	var src, copyIsArray, copy, name, options, clone,
+		target = arguments[0] || {},
+		i = 1,
+		length = arguments.length,
+		deep = false;
+
+	// Handle a deep copy situation
+	if ( typeof target === "boolean" ) {
+		deep = target;
+
+		// skip the boolean and the target
+		target = arguments[ i ] || {};
+		i++;
+	}
+
+	// Handle case when target is a string or something (possible in deep copy)
+	if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
+		target = {};
+	}
+
+	// extend jQuery itself if only one argument is passed
+	if ( i === length ) {
+		target = this;
+		i--;
+	}
+
+	for ( ; i < length; i++ ) {
+		// Only deal with non-null/undefined values
+		if ( (options = arguments[ i ]) != null ) {
+			// Extend the base object
+			for ( name in options ) {
+				src = target[ name ];
+				copy = options[ name ];
+
+				// Prevent never-ending loop
+				if ( target === copy ) {
+					continue;
+				}
+
+				// Recurse if we're merging plain objects or arrays
+				if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
+					if ( copyIsArray ) {
+						copyIsArray = false;
+						clone = src && jQuery.isArray(src) ? src : [];
+
+					} else {
+						clone = src && jQuery.isPlainObject(src) ? src : {};
+					}
+
+					// Never move original objects, clone them
+					target[ name ] = jQuery.extend( deep, clone, copy );
+
+				// Don't bring in undefined values
+				} else if ( copy !== undefined ) {
+					target[ name ] = copy;
+				}
+			}
+		}
+	}
+
+	// Return the modified object
+	return target;
+};
+
+jQuery.extend({
+	// Unique for each copy of jQuery on the page
+	expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),
+
+	// Assume jQuery is ready without the ready module
+	isReady: true,
+
+	error: function( msg ) {
+		throw new Error( msg );
+	},
+
+	noop: function() {},
+
+	// See test/unit/core.js for details concerning isFunction.
+	// Since version 1.3, DOM methods and functions like alert
+	// aren't supported. They return false on IE (#2968).
+	isFunction: function( obj ) {
+		return jQuery.type(obj) === "function";
+	},
+
+	isArray: Array.isArray || function( obj ) {
+		return jQuery.type(obj) === "array";
+	},
+
+	isWindow: function( obj ) {
+		/* jshint eqeqeq: false */
+		return obj != null && obj == obj.window;
+	},
+
+	isNumeric: function( obj ) {
+		// parseFloat NaNs numeric-cast false positives (null|true|false|"")
+		// ...but misinterprets leading-number strings, particularly hex literals ("0x...")
+		// subtraction forces infinities to NaN
+		// adding 1 corrects loss of precision from parseFloat (#15100)
+		return !jQuery.isArray( obj ) && (obj - parseFloat( obj ) + 1) >= 0;
+	},
+
+	isEmptyObject: function( obj ) {
+		var name;
+		for ( name in obj ) {
+			return false;
+		}
+		return true;
+	},
+
+	isPlainObject: function( obj ) {
+		var key;
+
+		// Must be an Object.
+		// Because of IE, we also have to check the presence of the constructor property.
+		// Make sure that DOM nodes and window objects don't pass through, as well
+		if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
+			return false;
+		}
+
+		try {
+			// Not own constructor property must be Object
+			if ( obj.constructor &&
+				!hasOwn.call(obj, "constructor") &&
+				!hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
+				return false;
+			}
+		} catch ( e ) {
+			// IE8,9 Will throw exceptions on certain host objects #9897
+			return false;
+		}
+
+		// Support: IE<9
+		// Handle iteration over inherited properties before own properties.
+		if ( support.ownLast ) {
+			for ( key in obj ) {
+				return hasOwn.call( obj, key );
+			}
+		}
+
+		// Own properties are enumerated firstly, so to speed up,
+		// if last one is own, then all properties are own.
+		for ( key in obj ) {}
+
+		return key === undefined || hasOwn.call( obj, key );
+	},
+
+	type: function( obj ) {
+		if ( obj == null ) {
+			return obj + "";
+		}
+		return typeof obj === "object" || typeof obj === "function" ?
+			class2type[ toString.call(obj) ] || "object" :
+			typeof obj;
+	},
+
+	// Evaluates a script in a global context
+	// Workarounds based on findings by Jim Driscoll
+	// http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
+	globalEval: function( data ) {
+		if ( data && jQuery.trim( data ) ) {
+			// We use execScript on Internet Explorer
+			// We use an anonymous function so that context is window
+			// rather than jQuery in Firefox
+			( window.execScript || function( data ) {
+				window[ "eval" ].call( window, data );
+			} )( data );
+		}
+	},
+
+	// Convert dashed to camelCase; used by the css and data modules
+	// Microsoft forgot to hump their vendor prefix (#9572)
+	camelCase: function( string ) {
+		return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
+	},
+
+	nodeName: function( elem, name ) {
+		return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
+	},
+
+	// args is for internal usage only
+	each: function( obj, callback, args ) {
+		var value,
+			i = 0,
+			length = obj.length,
+			isArray = isArraylike( obj );
+
+		if ( args ) {
+			if ( isArray ) {
+				for ( ; i < length; i++ ) {
+					value = callback.apply( obj[ i ], args );
+
+					if ( value === false ) {
+						break;
+					}
+				}
+			} else {
+				for ( i in obj ) {
+					value = callback.apply( obj[ i ], args );
+
+					if ( value === false ) {
+						break;
+					}
+				}
+			}
+
+		// A special, fast, case for the most common use of each
+		} else {
+			if ( isArray ) {
+				for ( ; i < length; i++ ) {
+					value = callback.call( obj[ i ], i, obj[ i ] );
+
+					if ( value === false ) {
+						break;
+					}
+				}
+			} else {
+				for ( i in obj ) {
+					value = callback.call( obj[ i ], i, obj[ i ] );
+
+					if ( value === false ) {
+						break;
+					}
+				}
+			}
+		}
+
+		return obj;
+	},
+
+	// Support: Android<4.1, IE<9
+	trim: function( text ) {
+		return text == null ?
+			"" :
+			( text + "" ).replace( rtrim, "" );
+	},
+
+	// results is for internal usage only
+	makeArray: function( arr, results ) {
+		var ret = results || [];
+
+		if ( arr != null ) {
+			if ( isArraylike( Object(arr) ) ) {
+				jQuery.merge( ret,
+					typeof arr === "string" ?
+					[ arr ] : arr
+				);
+			} else {
+				push.call( ret, arr );
+			}
+		}
+
+		return ret;
+	},
+
+	inArray: function( elem, arr, i ) {
+		var len;
+
+		if ( arr ) {
+			if ( indexOf ) {
+				return indexOf.call( arr, elem, i );
+			}
+
+			len = arr.length;
+			i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
+
+			for ( ; i < len; i++ ) {
+				// Skip accessing in sparse arrays
+				if ( i in arr && arr[ i ] === elem ) {
+					return i;
+				}
+			}
+		}
+
+		return -1;
+	},
+
+	merge: function( first, second ) {
+		var len = +second.length,
+			j = 0,
+			i = first.length;
+
+		while ( j < len ) {
+			first[ i++ ] = second[ j++ ];
+		}
+
+		// Support: IE<9
+		// Workaround casting of .length to NaN on otherwise arraylike objects (e.g., NodeLists)
+		if ( len !== len ) {
+			while ( second[j] !== undefined ) {
+				first[ i++ ] = second[ j++ ];
+			}
+		}
+
+		first.length = i;
+
+		return first;
+	},
+
+	grep: function( elems, callback, invert ) {
+		var callbackInverse,
+			matches = [],
+			i = 0,
+			length = elems.length,
+			callbackExpect = !invert;
+
+		// Go through the array, only saving the items
+		// that pass the validator function
+		for ( ; i < length; i++ ) {
+			callbackInverse = !callback( elems[ i ], i );
+			if ( callbackInverse !== callbackExpect ) {
+				matches.push( elems[ i ] );
+			}
+		}
+
+		return matches;
+	},
+
+	// arg is for internal usage only
+	map: function( elems, callback, arg ) {
+		var value,
+			i = 0,
+			length = elems.length,
+			isArray = isArraylike( elems ),
+			ret = [];
+
+		// Go through the array, translating each of the items to their new values
+		if ( isArray ) {
+			for ( ; i < length; i++ ) {
+				value = callback( elems[ i ], i, arg );
+
+				if ( value != null ) {
+					ret.push( value );
+				}
+			}
+
+		// Go through every key on the object,
+		} else {
+			for ( i in elems ) {
+				value = callback( elems[ i ], i, arg );
+
+				if ( value != null ) {
+					ret.push( value );
+				}
+			}
+		}
+
+		// Flatten any nested arrays
+		return concat.apply( [], ret );
+	},
+
+	// A global GUID counter for objects
+	guid: 1,
+
+	// Bind a function to a context, optionally partially applying any
+	// arguments.
+	proxy: function( fn, context ) {
+		var args, proxy, tmp;
+
+		if ( typeof context === "string" ) {
+			tmp = fn[ context ];
+			context = fn;
+			fn = tmp;
+		}
+
+		// Quick check to determine if target is callable, in the spec
+		// this throws a TypeError, but we will just return undefined.
+		if ( !jQuery.isFunction( fn ) ) {
+			return undefined;
+		}
+
+		// Simulated bind
+		args = slice.call( arguments, 2 );
+		proxy = function() {
+			return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
+		};
+
+		// Set the guid of unique handler to the same of original handler, so it can be removed
+		proxy.guid = fn.guid = fn.guid || jQuery.guid++;
+
+		return proxy;
+	},
+
+	now: function() {
+		return +( new Date() );
+	},
+
+	// jQuery.support is not used in Core but other projects attach their
+	// properties to it so it needs to exist.
+	support: support
+});
+
+// Populate the class2type map
+jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
+	class2type[ "[object " + name + "]" ] = name.toLowerCase();
+});
+
+function isArraylike( obj ) {
+
+	// Support: iOS 8.2 (not reproducible in simulator)
+	// `in` check used to prevent JIT error (gh-2145)
+	// hasOwn isn't used here due to false negatives
+	// regarding Nodelist length in IE
+	var length = "length" in obj && obj.length,
+		type = jQuery.type( obj );
+
+	if ( type === "function" || jQuery.isWindow( obj ) ) {
+		return false;
+	}
+
+	if ( obj.nodeType === 1 && length ) {
+		return true;
+	}
+
+	return type === "array" || length === 0 ||
+		typeof length === "number" && length > 0 && ( length - 1 ) in obj;
+}
+var Sizzle =
+/*!
+ * Sizzle CSS Selector Engine v2.2.0-pre
+ * http://sizzlejs.com/
+ *
+ * Copyright 2008, 2014 jQuery Foundation, Inc. and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: 2014-12-16
+ */
+(function( window ) {
+
+var i,
+	support,
+	Expr,
+	getText,
+	isXML,
+	tokenize,
+	compile,
+	select,
+	outermostContext,
+	sortInput,
+	hasDuplicate,
+
+	// Local document vars
+	setDocument,
+	document,
+	docElem,
+	documentIsHTML,
+	rbuggyQSA,
+	rbuggyMatches,
+	matches,
+	contains,
+
+	// Instance-specific data
+	expando = "sizzle" + 1 * new Date(),
+	preferredDoc = window.document,
+	dirruns = 0,
+	done = 0,
+	classCache = createCache(),
+	tokenCache = createCache(),
+	compilerCache = createCache(),
+	sortOrder = function( a, b ) {
+		if ( a === b ) {
+			hasDuplicate = true;
+		}
+		return 0;
+	},
+
+	// General-purpose constants
+	MAX_NEGATIVE = 1 << 31,
+
+	// Instance methods
+	hasOwn = ({}).hasOwnProperty,
+	arr = [],
+	pop = arr.pop,
+	push_native = arr.push,
+	push = arr.push,
+	slice = arr.slice,
+	// Use a stripped-down indexOf as it's faster than native
+	// http://jsperf.com/thor-indexof-vs-for/5
+	indexOf = function( list, elem ) {
+		var i = 0,
+			len = list.length;
+		for ( ; i < len; i++ ) {
+			if ( list[i] === elem ) {
+				return i;
+			}
+		}
+		return -1;
+	},
+
+	booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
+
+	// Regular expressions
+
+	// Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
+	whitespace = "[\\x20\\t\\r\\n\\f]",
+	// http://www.w3.org/TR/css3-syntax/#characters
+	characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
+
+	// Loosely modeled on CSS identifier characters
+	// An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors
+	// Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
+	identifier = characterEncoding.replace( "w", "w#" ),
+
+	// Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
+	attributes = "\\[" + whitespace + "*(" + characterEncoding + ")(?:" + whitespace +
+		// Operator (capture 2)
+		"*([*^$|!~]?=)" + whitespace +
+		// "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
+		"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace +
+		"*\\]",
+
+	pseudos = ":(" + characterEncoding + ")(?:\\((" +
+		// To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
+		// 1. quoted (capture 3; capture 4 or capture 5)
+		"('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
+		// 2. simple (capture 6)
+		"((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
+		// 3. anything else (capture 2)
+		".*" +
+		")\\)|)",
+
+	// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
+	rwhitespace = new RegExp( whitespace + "+", "g" ),
+	rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
+
+	rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
+	rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
+
+	rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ),
+
+	rpseudo = new RegExp( pseudos ),
+	ridentifier = new RegExp( "^" + identifier + "$" ),
+
+	matchExpr = {
+		"ID": new RegExp( "^#(" + characterEncoding + ")" ),
+		"CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
+		"TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
+		"ATTR": new RegExp( "^" + attributes ),
+		"PSEUDO": new RegExp( "^" + pseudos ),
+		"CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
+			"*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
+			"*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
+		"bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
+		// For use in libraries implementing .is()
+		// We use this for POS matching in `select`
+		"needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
+			whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
+	},
+
+	rinputs = /^(?:input|select|textarea|button)$/i,
+	rheader = /^h\d$/i,
+
+	rnative = /^[^{]+\{\s*\[native \w/,
+
+	// Easily-parseable/retrievable ID or TAG or CLASS selectors
+	rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
+
+	rsibling = /[+~]/,
+	rescape = /'|\\/g,
+
+	// CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
+	runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
+	funescape = function( _, escaped, escapedWhitespace ) {
+		var high = "0x" + escaped - 0x10000;
+		// NaN means non-codepoint
+		// Support: Firefox<24
+		// Workaround erroneous numeric interpretation of +"0x"
+		return high !== high || escapedWhitespace ?
+			escaped :
+			high < 0 ?
+				// BMP codepoint
+				String.fromCharCode( high + 0x10000 ) :
+				// Supplemental Plane codepoint (surrogate pair)
+				String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
+	},
+
+	// Used for iframes
+	// See setDocument()
+	// Removing the function wrapper causes a "Permission Denied"
+	// error in IE
+	unloadHandler = function() {
+		setDocument();
+	};
+
+// Optimize for push.apply( _, NodeList )
+try {
+	push.apply(
+		(arr = slice.call( preferredDoc.childNodes )),
+		preferredDoc.childNodes
+	);
+	// Support: Android<4.0
+	// Detect silently failing push.apply
+	arr[ preferredDoc.childNodes.length ].nodeType;
+} catch ( e ) {
+	push = { apply: arr.length ?
+
+		// Leverage slice if possible
+		function( target, els ) {
+			push_native.apply( target, slice.call(els) );
+		} :
+
+		// Support: IE<9
+		// Otherwise append directly
+		function( target, els ) {
+			var j = target.length,
+				i = 0;
+			// Can't trust NodeList.length
+			while ( (target[j++] = els[i++]) ) {}
+			target.length = j - 1;
+		}
+	};
+}
+
+function Sizzle( selector, context, results, seed ) {
+	var match, elem, m, nodeType,
+		// QSA vars
+		i, groups, old, nid, newContext, newSelector;
+
+	if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
+		setDocument( context );
+	}
+
+	context = context || document;
+	results = results || [];
+	nodeType = context.nodeType;
+
+	if ( typeof selector !== "string" || !selector ||
+		nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {
+
+		return results;
+	}
+
+	if ( !seed && documentIsHTML ) {
+
+		// Try to shortcut find operations when possible (e.g., not under DocumentFragment)
+		if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) {
+			// Speed-up: Sizzle("#ID")
+			if ( (m = match[1]) ) {
+				if ( nodeType === 9 ) {
+					elem = context.getElementById( m );
+					// Check parentNode to catch when Blackberry 4.6 returns
+					// nodes that are no longer in the document (jQuery #6963)
+					if ( elem && elem.parentNode ) {
+						// Handle the case where IE, Opera, and Webkit return items
+						// by name instead of ID
+						if ( elem.id === m ) {
+							results.push( elem );
+							return results;
+						}
+					} else {
+						return results;
+					}
+				} else {
+					// Context is not a document
+					if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
+						contains( context, elem ) && elem.id === m ) {
+						results.push( elem );
+						return results;
+					}
+				}
+
+			// Speed-up: Sizzle("TAG")
+			} else if ( match[2] ) {
+				push.apply( results, context.getElementsByTagName( selector ) );
+				return results;
+
+			// Speed-up: Sizzle(".CLASS")
+			} else if ( (m = match[3]) && support.getElementsByClassName ) {
+				push.apply( results, context.getElementsByClassName( m ) );
+				return results;
+			}
+		}
+
+		// QSA path
+		if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
+			nid = old = expando;
+			newContext = context;
+			newSelector = nodeType !== 1 && selector;
+
+			// qSA works strangely on Element-rooted queries
+			// We can work around this by specifying an extra ID on the root
+			// and working up from there (Thanks to Andrew Dupont for the technique)
+			// IE 8 doesn't work on object elements
+			if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
+				groups = tokenize( selector );
+
+				if ( (old = context.getAttribute("id")) ) {
+					nid = old.replace( rescape, "\\$&" );
+				} else {
+					context.setAttribute( "id", nid );
+				}
+				nid = "[id='" + nid + "'] ";
+
+				i = groups.length;
+				while ( i-- ) {
+					groups[i] = nid + toSelector( groups[i] );
+				}
+				newContext = rsibling.test( selector ) && testContext( context.parentNode ) || context;
+				newSelector = groups.join(",");
+			}
+
+			if ( newSelector ) {
+				try {
+					push.apply( results,
+						newContext.querySelectorAll( newSelector )
+					);
+					return results;
+				} catch(qsaError) {
+				} finally {
+					if ( !old ) {
+						context.removeAttribute("id");
+					}
+				}
+			}
+		}
+	}
+
+	// All others
+	return select( selector.replace( rtrim, "$1" ), context, results, seed );
+}
+
+/**
+ * Create key-value caches of limited size
+ * @returns {Function(string, Object)} Returns the Object data after storing it on itself with
+ *	property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
+ *	deleting the oldest entry
+ */
+function createCache() {
+	var keys = [];
+
+	function cache( key, value ) {
+		// Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
+		if ( keys.push( key + " " ) > Expr.cacheLength ) {
+			// Only keep the most recent entries
+			delete cache[ keys.shift() ];
+		}
+		return (cache[ key + " " ] = value);
+	}
+	return cache;
+}
+
+/**
+ * Mark a function for special use by Sizzle
+ * @param {Function} fn The function to mark
+ */
+function markFunction( fn ) {
+	fn[ expando ] = true;
+	return fn;
+}
+
+/**
+ * Support testing using an element
+ * @param {Function} fn Passed the created div and expects a boolean result
+ */
+function assert( fn ) {
+	var div = document.createElement("div");
+
+	try {
+		return !!fn( div );
+	} catch (e) {
+		return false;
+	} finally {
+		// Remove from its parent by default
+		if ( div.parentNode ) {
+			div.parentNode.removeChild( div );
+		}
+		// release memory in IE
+		div = null;
+	}
+}
+
+/**
+ * Adds the same handler for all of the specified attrs
+ * @param {String} attrs Pipe-separated list of attributes
+ * @param {Function} handler The method that will be applied
+ */
+function addHandle( attrs, handler ) {
+	var arr = attrs.split("|"),
+		i = attrs.length;
+
+	while ( i-- ) {
+		Expr.attrHandle[ arr[i] ] = handler;
+	}
+}
+
+/**
+ * Checks document order of two siblings
+ * @param {Element} a
+ * @param {Element} b
+ * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
+ */
+function siblingCheck( a, b ) {
+	var cur = b && a,
+		diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
+			( ~b.sourceIndex || MAX_NEGATIVE ) -
+			( ~a.sourceIndex || MAX_NEGATIVE );
+
+	// Use IE sourceIndex if available on both nodes
+	if ( diff ) {
+		return diff;
+	}
+
+	// Check if b follows a
+	if ( cur ) {
+		while ( (cur = cur.nextSibling) ) {
+			if ( cur === b ) {
+				return -1;
+			}
+		}
+	}
+
+	return a ? 1 : -1;
+}
+
+/**
+ * Returns a function to use in pseudos for input types
+ * @param {String} type
+ */
+function createInputPseudo( type ) {
+	return function( elem ) {
+		var name = elem.nodeName.toLowerCase();
+		return name === "input" && elem.type === type;
+	};
+}
+
+/**
+ * Returns a function to use in pseudos for buttons
+ * @param {String} type
+ */
+function createButtonPseudo( type ) {
+	return function( elem ) {
+		var name = elem.nodeName.toLowerCase();
+		return (name === "input" || name === "button") && elem.type === type;
+	};
+}
+
+/**
+ * Returns a function to use in pseudos for positionals
+ * @param {Function} fn
+ */
+function createPositionalPseudo( fn ) {
+	return markFunction(function( argument ) {
+		argument = +argument;
+		return markFunction(function( seed, matches ) {
+			var j,
+				matchIndexes = fn( [], seed.length, argument ),
+				i = matchIndexes.length;
+
+			// Match elements found at the specified indexes
+			while ( i-- ) {
+				if ( seed[ (j = matchIndexes[i]) ] ) {
+					seed[j] = !(matches[j] = seed[j]);
+				}
+			}
+		});
+	});
+}
+
+/**
+ * Checks a node for validity as a Sizzle context
+ * @param {Element|Object=} context
+ * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
+ */
+function testContext( context ) {
+	return context && typeof context.getElementsByTagName !== "undefined" && context;
+}
+
+// Expose support vars for convenience
+support = Sizzle.support = {};
+
+/**
+ * Detects XML nodes
+ * @param {Element|Object} elem An element or a document
+ * @returns {Boolean} True iff elem is a non-HTML XML node
+ */
+isXML = Sizzle.isXML = function( elem ) {
+	// documentElement is verified for cases where it doesn't yet exist
+	// (such as loading iframes in IE - #4833)
+	var documentElement = elem && (elem.ownerDocument || elem).documentElement;
+	return documentElement ? documentElement.nodeName !== "HTML" : false;
+};
+
+/**
+ * Sets document-related variables once based on the current document
+ * @param {Element|Object} [doc] An element or document object to use to set the document
+ * @returns {Object} Returns the current document
+ */
+setDocument = Sizzle.setDocument = function( node ) {
+	var hasCompare, parent,
+		doc = node ? node.ownerDocument || node : preferredDoc;
+
+	// If no document and documentElement is available, return
+	if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
+		return document;
+	}
+
+	// Set our document
+	document = doc;
+	docElem = doc.documentElement;
+	parent = doc.defaultView;
+
+	// Support: IE>8
+	// If iframe document is assigned to "document" variable and if iframe has been reloaded,
+	// IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936
+	// IE6-8 do not support the defaultView property so parent will be undefined
+	if ( parent && parent !== parent.top ) {
+		// IE11 does not have attachEvent, so all must suffer
+		if ( parent.addEventListener ) {
+			parent.addEventListener( "unload", unloadHandler, false );
+		} else if ( parent.attachEvent ) {
+			parent.attachEvent( "onunload", unloadHandler );
+		}
+	}
+
+	/* Support tests
+	---------------------------------------------------------------------- */
+	documentIsHTML = !isXML( doc );
+
+	/* Attributes
+	---------------------------------------------------------------------- */
+
+	// Support: IE<8
+	// Verify that getAttribute really returns attributes and not properties
+	// (excepting IE8 booleans)
+	support.attributes = assert(function( div ) {
+		div.className = "i";
+		return !div.getAttribute("className");
+	});
+
+	/* getElement(s)By*
+	---------------------------------------------------------------------- */
+
+	// Check if getElementsByTagName("*") returns only elements
+	support.getElementsByTagName = assert(function( div ) {
+		div.appendChild( doc.createComment("") );
+		return !div.getElementsByTagName("*").length;
+	});
+
+	// Support: IE<9
+	support.getElementsByClassName = rnative.test( doc.getElementsByClassName );
+
+	// Support: IE<10
+	// Check if getElementById returns elements by name
+	// The broken getElementById methods don't pick up programatically-set names,
+	// so use a roundabout getElementsByName test
+	support.getById = assert(function( div ) {
+		docElem.appendChild( div ).id = expando;
+		return !doc.getElementsByName || !doc.getElementsByName( expando ).length;
+	});
+
+	// ID find and filter
+	if ( support.getById ) {
+		Expr.find["ID"] = function( id, context ) {
+			if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
+				var m = context.getElementById( id );
+				// Check parentNode to catch when Blackberry 4.6 returns
+				// nodes that are no longer in the document #6963
+				return m && m.parentNode ? [ m ] : [];
+			}
+		};
+		Expr.filter["ID"] = function( id ) {
+			var attrId = id.replace( runescape, funescape );
+			return function( elem ) {
+				return elem.getAttribute("id") === attrId;
+			};
+		};
+	} else {
+		// Support: IE6/7
+		// getElementById is not reliable as a find shortcut
+		delete Expr.find["ID"];
+
+		Expr.filter["ID"] =  function( id ) {
+			var attrId = id.replace( runescape, funescape );
+			return function( elem ) {
+				var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
+				return node && node.value === attrId;
+			};
+		};
+	}
+
+	// Tag
+	Expr.find["TAG"] = support.getElementsByTagName ?
+		function( tag, context ) {
+			if ( typeof context.getElementsByTagName !== "undefined" ) {
+				return context.getElementsByTagName( tag );
+
+			// DocumentFragment nodes don't have gEBTN
+			} else if ( support.qsa ) {
+				return context.querySelectorAll( tag );
+			}
+		} :
+
+		function( tag, context ) {
+			var elem,
+				tmp = [],
+				i = 0,
+				// By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too
+				results = context.getElementsByTagName( tag );
+
+			// Filter out possible comments
+			if ( tag === "*" ) {
+				while ( (elem = results[i++]) ) {
+					if ( elem.nodeType === 1 ) {
+						tmp.push( elem );
+					}
+				}
+
+				return tmp;
+			}
+			return results;
+		};
+
+	// Class
+	Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
+		if ( documentIsHTML ) {
+			return context.getElementsByClassName( className );
+		}
+	};
+
+	/* QSA/matchesSelector
+	---------------------------------------------------------------------- */
+
+	// QSA and matchesSelector support
+
+	// matchesSelector(:active) reports false when true (IE9/Opera 11.5)
+	rbuggyMatches = [];
+
+	// qSa(:focus) reports false when true (Chrome 21)
+	// We allow this because of a bug in IE8/9 that throws an error
+	// whenever `document.activeElement` is accessed on an iframe
+	// So, we allow :focus to pass through QSA all the time to avoid the IE error
+	// See http://bugs.jquery.com/ticket/13378
+	rbuggyQSA = [];
+
+	if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) {
+		// Build QSA regex
+		// Regex strategy adopted from Diego Perini
+		assert(function( div ) {
+			// Select is set to empty string on purpose
+			// This is to test IE's treatment of not explicitly
+			// setting a boolean content attribute,
+			// since its presence should be enough
+			// http://bugs.jquery.com/ticket/12359
+			docElem.appendChild( div ).innerHTML = "<a id='" + expando + "'></a>" +
+				"<select id='" + expando + "-\f]' msallowcapture=''>" +
+				"<option selected=''></option></select>";
+
+			// Support: IE8, Opera 11-12.16
+			// Nothing should be selected when empty strings follow ^= or $= or *=
+			// The test attribute must be unknown in Opera but "safe" for WinRT
+			// http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
+			if ( div.querySelectorAll("[msallowcapture^='']").length ) {
+				rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
+			}
+
+			// Support: IE8
+			// Boolean attributes and "value" are not treated correctly
+			if ( !div.querySelectorAll("[selected]").length ) {
+				rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
+			}
+
+			// Support: Chrome<29, Android<4.2+, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.7+
+			if ( !div.querySelectorAll( "[id~=" + expando + "-]" ).length ) {
+				rbuggyQSA.push("~=");
+			}
+
+			// Webkit/Opera - :checked should return selected option elements
+			// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+			// IE8 throws error here and will not see later tests
+			if ( !div.querySelectorAll(":checked").length ) {
+				rbuggyQSA.push(":checked");
+			}
+
+			// Support: Safari 8+, iOS 8+
+			// https://bugs.webkit.org/show_bug.cgi?id=136851
+			// In-page `selector#id sibing-combinator selector` fails
+			if ( !div.querySelectorAll( "a#" + expando + "+*" ).length ) {
+				rbuggyQSA.push(".#.+[+~]");
+			}
+		});
+
+		assert(function( div ) {
+			// Support: Windows 8 Native Apps
+			// The type and name attributes are restricted during .innerHTML assignment
+			var input = doc.createElement("input");
+			input.setAttribute( "type", "hidden" );
+			div.appendChild( input ).setAttribute( "name", "D" );
+
+			// Support: IE8
+			// Enforce case-sensitivity of name attribute
+			if ( div.querySelectorAll("[name=d]").length ) {
+				rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
+			}
+
+			// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
+			// IE8 throws error here and will not see later tests
+			if ( !div.querySelectorAll(":enabled").length ) {
+				rbuggyQSA.push( ":enabled", ":disabled" );
+			}
+
+			// Opera 10-11 does not throw on post-comma invalid pseudos
+			div.querySelectorAll("*,:x");
+			rbuggyQSA.push(",.*:");
+		});
+	}
+
+	if ( (support.matchesSelector = rnative.test( (matches = docElem.matches ||
+		docElem.webkitMatchesSelector ||
+		docElem.mozMatchesSelector ||
+		docElem.oMatchesSelector ||
+		docElem.msMatchesSelector) )) ) {
+
+		assert(function( div ) {
+			// Check to see if it's possible to do matchesSelector
+			// on a disconnected node (IE 9)
+			support.disconnectedMatch = matches.call( div, "div" );
+
+			// This should fail with an exception
+			// Gecko does not error, returns false instead
+			matches.call( div, "[s!='']:x" );
+			rbuggyMatches.push( "!=", pseudos );
+		});
+	}
+
+	rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
+	rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
+
+	/* Contains
+	---------------------------------------------------------------------- */
+	hasCompare = rnative.test( docElem.compareDocumentPosition );
+
+	// Element contains another
+	// Purposefully does not implement inclusive descendent
+	// As in, an element does not contain itself
+	contains = hasCompare || rnative.test( docElem.contains ) ?
+		function( a, b ) {
+			var adown = a.nodeType === 9 ? a.documentElement : a,
+				bup = b && b.parentNode;
+			return a === bup || !!( bup && bup.nodeType === 1 && (
+				adown.contains ?
+					adown.contains( bup ) :
+					a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
+			));
+		} :
+		function( a, b ) {
+			if ( b ) {
+				while ( (b = b.parentNode) ) {
+					if ( b === a ) {
+						return true;
+					}
+				}
+			}
+			return false;
+		};
+
+	/* Sorting
+	---------------------------------------------------------------------- */
+
+	// Document order sorting
+	sortOrder = hasCompare ?
+	function( a, b ) {
+
+		// Flag for duplicate removal
+		if ( a === b ) {
+			hasDuplicate = true;
+			return 0;
+		}
+
+		// Sort on method existence if only one input has compareDocumentPosition
+		var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
+		if ( compare ) {
+			return compare;
+		}
+
+		// Calculate position if both inputs belong to the same document
+		compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
+			a.compareDocumentPosition( b ) :
+
+			// Otherwise we know they are disconnected
+			1;
+
+		// Disconnected nodes
+		if ( compare & 1 ||
+			(!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
+
+			// Choose the first element that is related to our preferred document
+			if ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
+				return -1;
+			}
+			if ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
+				return 1;
+			}
+
+			// Maintain original order
+			return sortInput ?
+				( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
+				0;
+		}
+
+		return compare & 4 ? -1 : 1;
+	} :
+	function( a, b ) {
+		// Exit early if the nodes are identical
+		if ( a === b ) {
+			hasDuplicate = true;
+			return 0;
+		}
+
+		var cur,
+			i = 0,
+			aup = a.parentNode,
+			bup = b.parentNode,
+			ap = [ a ],
+			bp = [ b ];
+
+		// Parentless nodes are either documents or disconnected
+		if ( !aup || !bup ) {
+			return a === doc ? -1 :
+				b === doc ? 1 :
+				aup ? -1 :
+				bup ? 1 :
+				sortInput ?
+				( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
+				0;
+
+		// If the nodes are siblings, we can do a quick check
+		} else if ( aup === bup ) {
+			return siblingCheck( a, b );
+		}
+
+		// Otherwise we need full lists of their ancestors for comparison
+		cur = a;
+		while ( (cur = cur.parentNode) ) {
+			ap.unshift( cur );
+		}
+		cur = b;
+		while ( (cur = cur.parentNode) ) {
+			bp.unshift( cur );
+		}
+
+		// Walk down the tree looking for a discrepancy
+		while ( ap[i] === bp[i] ) {
+			i++;
+		}
+
+		return i ?
+			// Do a sibling check if the nodes have a common ancestor
+			siblingCheck( ap[i], bp[i] ) :
+
+			// Otherwise nodes in our document sort first
+			ap[i] === preferredDoc ? -1 :
+			bp[i] === preferredDoc ? 1 :
+			0;
+	};
+
+	return doc;
+};
+
+Sizzle.matches = function( expr, elements ) {
+	return Sizzle( expr, null, null, elements );
+};
+
+Sizzle.matchesSelector = function( elem, expr ) {
+	// Set document vars if needed
+	if ( ( elem.ownerDocument || elem ) !== document ) {
+		setDocument( elem );
+	}
+
+	// Make sure that attribute selectors are quoted
+	expr = expr.replace( rattributeQuotes, "='$1']" );
+
+	if ( support.matchesSelector && documentIsHTML &&
+		( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
+		( !rbuggyQSA     || !rbuggyQSA.test( expr ) ) ) {
+
+		try {
+			var ret = matches.call( elem, expr );
+
+			// IE 9's matchesSelector returns false on disconnected nodes
+			if ( ret || support.disconnectedMatch ||
+					// As well, disconnected nodes are said to be in a document
+					// fragment in IE 9
+					elem.document && elem.document.nodeType !== 11 ) {
+				return ret;
+			}
+		} catch (e) {}
+	}
+
+	return Sizzle( expr, document, null, [ elem ] ).length > 0;
+};
+
+Sizzle.contains = function( context, elem ) {
+	// Set document vars if needed
+	if ( ( context.ownerDocument || context ) !== document ) {
+		setDocument( context );
+	}
+	return contains( context, elem );
+};
+
+Sizzle.attr = function( elem, name ) {
+	// Set document vars if needed
+	if ( ( elem.ownerDocument || elem ) !== document ) {
+		setDocument( elem );
+	}
+
+	var fn = Expr.attrHandle[ name.toLowerCase() ],
+		// Don't get fooled by Object.prototype properties (jQuery #13807)
+		val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
+			fn( elem, name, !documentIsHTML ) :
+			undefined;
+
+	return val !== undefined ?
+		val :
+		support.attributes || !documentIsHTML ?
+			elem.getAttribute( name ) :
+			(val = elem.getAttributeNode(name)) && val.specified ?
+				val.value :
+				null;
+};
+
+Sizzle.error = function( msg ) {
+	throw new Error( "Syntax error, unrecognized expression: " + msg );
+};
+
+/**
+ * Document sorting and removing duplicates
+ * @param {ArrayLike} results
+ */
+Sizzle.uniqueSort = function( results ) {
+	var elem,
+		duplicates = [],
+		j = 0,
+		i = 0;
+
+	// Unless we *know* we can detect duplicates, assume their presence
+	hasDuplicate = !support.detectDuplicates;
+	sortInput = !support.sortStable && results.slice( 0 );
+	results.sort( sortOrder );
+
+	if ( hasDuplicate ) {
+		while ( (elem = results[i++]) ) {
+			if ( elem === results[ i ] ) {
+				j = duplicates.push( i );
+			}
+		}
+		while ( j-- ) {
+			results.splice( duplicates[ j ], 1 );
+		}
+	}
+
+	// Clear input after sorting to release objects
+	// See https://github.com/jquery/sizzle/pull/225
+	sortInput = null;
+
+	return results;
+};
+
+/**
+ * Utility function for retrieving the text value of an array of DOM nodes
+ * @param {Array|Element} elem
+ */
+getText = Sizzle.getText = function( elem ) {
+	var node,
+		ret = "",
+		i = 0,
+		nodeType = elem.nodeType;
+
+	if ( !nodeType ) {
+		// If no nodeType, this is expected to be an array
+		while ( (node = elem[i++]) ) {
+			// Do not traverse comment nodes
+			ret += getText( node );
+		}
+	} else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
+		// Use textContent for elements
+		// innerText usage removed for consistency of new lines (jQuery #11153)
+		if ( typeof elem.textContent === "string" ) {
+			return elem.textContent;
+		} else {
+			// Traverse its children
+			for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+				ret += getText( elem );
+			}
+		}
+	} else if ( nodeType === 3 || nodeType === 4 ) {
+		return elem.nodeValue;
+	}
+	// Do not include comment or processing instruction nodes
+
+	return ret;
+};
+
+Expr = Sizzle.selectors = {
+
+	// Can be adjusted by the user
+	cacheLength: 50,
+
+	createPseudo: markFunction,
+
+	match: matchExpr,
+
+	attrHandle: {},
+
+	find: {},
+
+	relative: {
+		">": { dir: "parentNode", first: true },
+		" ": { dir: "parentNode" },
+		"+": { dir: "previousSibling", first: true },
+		"~": { dir: "previousSibling" }
+	},
+
+	preFilter: {
+		"ATTR": function( match ) {
+			match[1] = match[1].replace( runescape, funescape );
+
+			// Move the given value to match[3] whether quoted or unquoted
+			match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape );
+
+			if ( match[2] === "~=" ) {
+				match[3] = " " + match[3] + " ";
+			}
+
+			return match.slice( 0, 4 );
+		},
+
+		"CHILD": function( match ) {
+			/* matches from matchExpr["CHILD"]
+				1 type (only|nth|...)
+				2 what (child|of-type)
+				3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
+				4 xn-component of xn+y argument ([+-]?\d*n|)
+				5 sign of xn-component
+				6 x of xn-component
+				7 sign of y-component
+				8 y of y-component
+			*/
+			match[1] = match[1].toLowerCase();
+
+			if ( match[1].slice( 0, 3 ) === "nth" ) {
+				// nth-* requires argument
+				if ( !match[3] ) {
+					Sizzle.error( match[0] );
+				}
+
+				// numeric x and y parameters for Expr.filter.CHILD
+				// remember that false/true cast respectively to 0/1
+				match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
+				match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
+
+			// other types prohibit arguments
+			} else if ( match[3] ) {
+				Sizzle.error( match[0] );
+			}
+
+			return match;
+		},
+
+		"PSEUDO": function( match ) {
+			var excess,
+				unquoted = !match[6] && match[2];
+
+			if ( matchExpr["CHILD"].test( match[0] ) ) {
+				return null;
+			}
+
+			// Accept quoted arguments as-is
+			if ( match[3] ) {
+				match[2] = match[4] || match[5] || "";
+
+			// Strip excess characters from unquoted arguments
+			} else if ( unquoted && rpseudo.test( unquoted ) &&
+				// Get excess from tokenize (recursively)
+				(excess = tokenize( unquoted, true )) &&
+				// advance to the next closing parenthesis
+				(excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
+
+				// excess is a negative index
+				match[0] = match[0].slice( 0, excess );
+				match[2] = unquoted.slice( 0, excess );
+			}
+
+			// Return only captures needed by the pseudo filter method (type and argument)
+			return match.slice( 0, 3 );
+		}
+	},
+
+	filter: {
+
+		"TAG": function( nodeNameSelector ) {
+			var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
+			return nodeNameSelector === "*" ?
+				function() { return true; } :
+				function( elem ) {
+					return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
+				};
+		},
+
+		"CLASS": function( className ) {
+			var pattern = classCache[ className + " " ];
+
+			return pattern ||
+				(pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
+				classCache( className, function( elem ) {
+					return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" );
+				});
+		},
+
+		"ATTR": function( name, operator, check ) {
+			return function( elem ) {
+				var result = Sizzle.attr( elem, name );
+
+				if ( result == null ) {
+					return operator === "!=";
+				}
+				if ( !operator ) {
+					return true;
+				}
+
+				result += "";
+
+				return operator === "=" ? result === check :
+					operator === "!=" ? result !== check :
+					operator === "^=" ? check && result.indexOf( check ) === 0 :
+					operator === "*=" ? check && result.indexOf( check ) > -1 :
+					operator === "$=" ? check && result.slice( -check.length ) === check :
+					operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 :
+					operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
+					false;
+			};
+		},
+
+		"CHILD": function( type, what, argument, first, last ) {
+			var simple = type.slice( 0, 3 ) !== "nth",
+				forward = type.slice( -4 ) !== "last",
+				ofType = what === "of-type";
+
+			return first === 1 && last === 0 ?
+
+				// Shortcut for :nth-*(n)
+				function( elem ) {
+					return !!elem.parentNode;
+				} :
+
+				function( elem, context, xml ) {
+					var cache, outerCache, node, diff, nodeIndex, start,
+						dir = simple !== forward ? "nextSibling" : "previousSibling",
+						parent = elem.parentNode,
+						name = ofType && elem.nodeName.toLowerCase(),
+						useCache = !xml && !ofType;
+
+					if ( parent ) {
+
+						// :(first|last|only)-(child|of-type)
+						if ( simple ) {
+							while ( dir ) {
+								node = elem;
+								while ( (node = node[ dir ]) ) {
+									if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
+										return false;
+									}
+								}
+								// Reverse direction for :only-* (if we haven't yet done so)
+								start = dir = type === "only" && !start && "nextSibling";
+							}
+							return true;
+						}
+
+						start = [ forward ? parent.firstChild : parent.lastChild ];
+
+						// non-xml :nth-child(...) stores cache data on `parent`
+						if ( forward && useCache ) {
+							// Seek `elem` from a previously-cached index
+							outerCache = parent[ expando ] || (parent[ expando ] = {});
+							cache = outerCache[ type ] || [];
+							nodeIndex = cache[0] === dirruns && cache[1];
+							diff = cache[0] === dirruns && cache[2];
+							node = nodeIndex && parent.childNodes[ nodeIndex ];
+
+							while ( (node = ++nodeIndex && node && node[ dir ] ||
+
+								// Fallback to seeking `elem` from the start
+								(diff = nodeIndex = 0) || start.pop()) ) {
+
+								// When found, cache indexes on `parent` and break
+								if ( node.nodeType === 1 && ++diff && node === elem ) {
+									outerCache[ type ] = [ dirruns, nodeIndex, diff ];
+									break;
+								}
+							}
+
+						// Use previously-cached element index if available
+						} else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
+							diff = cache[1];
+
+						// xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)
+						} else {
+							// Use the same loop as above to seek `elem` from the start
+							while ( (node = ++nodeIndex && node && node[ dir ] ||
+								(diff = nodeIndex = 0) || start.pop()) ) {
+
+								if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
+									// Cache the index of each encountered element
+									if ( useCache ) {
+										(node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
+									}
+
+									if ( node === elem ) {
+										break;
+									}
+								}
+							}
+						}
+
+						// Incorporate the offset, then check against cycle size
+						diff -= last;
+						return diff === first || ( diff % first === 0 && diff / first >= 0 );
+					}
+				};
+		},
+
+		"PSEUDO": function( pseudo, argument ) {
+			// pseudo-class names are case-insensitive
+			// http://www.w3.org/TR/selectors/#pseudo-classes
+			// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
+			// Remember that setFilters inherits from pseudos
+			var args,
+				fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
+					Sizzle.error( "unsupported pseudo: " + pseudo );
+
+			// The user may use createPseudo to indicate that
+			// arguments are needed to create the filter function
+			// just as Sizzle does
+			if ( fn[ expando ] ) {
+				return fn( argument );
+			}
+
+			// But maintain support for old signatures
+			if ( fn.length > 1 ) {
+				args = [ pseudo, pseudo, "", argument ];
+				return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
+					markFunction(function( seed, matches ) {
+						var idx,
+							matched = fn( seed, argument ),
+							i = matched.length;
+						while ( i-- ) {
+							idx = indexOf( seed, matched[i] );
+							seed[ idx ] = !( matches[ idx ] = matched[i] );
+						}
+					}) :
+					function( elem ) {
+						return fn( elem, 0, args );
+					};
+			}
+
+			return fn;
+		}
+	},
+
+	pseudos: {
+		// Potentially complex pseudos
+		"not": markFunction(function( selector ) {
+			// Trim the selector passed to compile
+			// to avoid treating leading and trailing
+			// spaces as combinators
+			var input = [],
+				results = [],
+				matcher = compile( selector.replace( rtrim, "$1" ) );
+
+			return matcher[ expando ] ?
+				markFunction(function( seed, matches, context, xml ) {
+					var elem,
+						unmatched = matcher( seed, null, xml, [] ),
+						i = seed.length;
+
+					// Match elements unmatched by `matcher`
+					while ( i-- ) {
+						if ( (elem = unmatched[i]) ) {
+							seed[i] = !(matches[i] = elem);
+						}
+					}
+				}) :
+				function( elem, context, xml ) {
+					input[0] = elem;
+					matcher( input, null, xml, results );
+					// Don't keep the element (issue #299)
+					input[0] = null;
+					return !results.pop();
+				};
+		}),
+
+		"has": markFunction(function( selector ) {
+			return function( elem ) {
+				return Sizzle( selector, elem ).length > 0;
+			};
+		}),
+
+		"contains": markFunction(function( text ) {
+			text = text.replace( runescape, funescape );
+			return function( elem ) {
+				return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
+			};
+		}),
+
+		// "Whether an element is represented by a :lang() selector
+		// is based solely on the element's language value
+		// being equal to the identifier C,
+		// or beginning with the identifier C immediately followed by "-".
+		// The matching of C against the element's language value is performed case-insensitively.
+		// The identifier C does not have to be a valid language name."
+		// http://www.w3.org/TR/selectors/#lang-pseudo
+		"lang": markFunction( function( lang ) {
+			// lang value must be a valid identifier
+			if ( !ridentifier.test(lang || "") ) {
+				Sizzle.error( "unsupported lang: " + lang );
+			}
+			lang = lang.replace( runescape, funescape ).toLowerCase();
+			return function( elem ) {
+				var elemLang;
+				do {
+					if ( (elemLang = documentIsHTML ?
+						elem.lang :
+						elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
+
+						elemLang = elemLang.toLowerCase();
+						return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
+					}
+				} while ( (elem = elem.parentNode) && elem.nodeType === 1 );
+				return false;
+			};
+		}),
+
+		// Miscellaneous
+		"target": function( elem ) {
+			var hash = window.location && window.location.hash;
+			return hash && hash.slice( 1 ) === elem.id;
+		},
+
+		"root": function( elem ) {
+			return elem === docElem;
+		},
+
+		"focus": function( elem ) {
+			return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
+		},
+
+		// Boolean properties
+		"enabled": function( elem ) {
+			return elem.disabled === false;
+		},
+
+		"disabled": function( elem ) {
+			return elem.disabled === true;
+		},
+
+		"checked": function( elem ) {
+			// In CSS3, :checked should return both checked and selected elements
+			// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+			var nodeName = elem.nodeName.toLowerCase();
+			return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
+		},
+
+		"selected": function( elem ) {
+			// Accessing this property makes selected-by-default
+			// options in Safari work properly
+			if ( elem.parentNode ) {
+				elem.parentNode.selectedIndex;
+			}
+
+			return elem.selected === true;
+		},
+
+		// Contents
+		"empty": function( elem ) {
+			// http://www.w3.org/TR/selectors/#empty-pseudo
+			// :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
+			//   but not by others (comment: 8; processing instruction: 7; etc.)
+			// nodeType < 6 works because attributes (2) do not appear as children
+			for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+				if ( elem.nodeType < 6 ) {
+					return false;
+				}
+			}
+			return true;
+		},
+
+		"parent": function( elem ) {
+			return !Expr.pseudos["empty"]( elem );
+		},
+
+		// Element/input types
+		"header": function( elem ) {
+			return rheader.test( elem.nodeName );
+		},
+
+		"input": function( elem ) {
+			return rinputs.test( elem.nodeName );
+		},
+
+		"button": function( elem ) {
+			var name = elem.nodeName.toLowerCase();
+			return name === "input" && elem.type === "button" || name === "button";
+		},
+
+		"text": function( elem ) {
+			var attr;
+			return elem.nodeName.toLowerCase() === "input" &&
+				elem.type === "text" &&
+
+				// Support: IE<8
+				// New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
+				( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" );
+		},
+
+		// Position-in-collection
+		"first": createPositionalPseudo(function() {
+			return [ 0 ];
+		}),
+
+		"last": createPositionalPseudo(function( matchIndexes, length ) {
+			return [ length - 1 ];
+		}),
+
+		"eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
+			return [ argument < 0 ? argument + length : argument ];
+		}),
+
+		"even": createPositionalPseudo(function( matchIndexes, length ) {
+			var i = 0;
+			for ( ; i < length; i += 2 ) {
+				matchIndexes.push( i );
+			}
+			return matchIndexes;
+		}),
+
+		"odd": createPositionalPseudo(function( matchIndexes, length ) {
+			var i = 1;
+			for ( ; i < length; i += 2 ) {
+				matchIndexes.push( i );
+			}
+			return matchIndexes;
+		}),
+
+		"lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
+			var i = argument < 0 ? argument + length : argument;
+			for ( ; --i >= 0; ) {
+				matchIndexes.push( i );
+			}
+			return matchIndexes;
+		}),
+
+		"gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
+			var i = argument < 0 ? argument + length : argument;
+			for ( ; ++i < length; ) {
+				matchIndexes.push( i );
+			}
+			return matchIndexes;
+		})
+	}
+};
+
+Expr.pseudos["nth"] = Expr.pseudos["eq"];
+
+// Add button/input type pseudos
+for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
+	Expr.pseudos[ i ] = createInputPseudo( i );
+}
+for ( i in { submit: true, reset: true } ) {
+	Expr.pseudos[ i ] = createButtonPseudo( i );
+}
+
+// Easy API for creating new setFilters
+function setFilters() {}
+setFilters.prototype = Expr.filters = Expr.pseudos;
+Expr.setFilters = new setFilters();
+
+tokenize = Sizzle.tokenize = function( selector, parseOnly ) {
+	var matched, match, tokens, type,
+		soFar, groups, preFilters,
+		cached = tokenCache[ selector + " " ];
+
+	if ( cached ) {
+		return parseOnly ? 0 : cached.slice( 0 );
+	}
+
+	soFar = selector;
+	groups = [];
+	preFilters = Expr.preFilter;
+
+	while ( soFar ) {
+
+		// Comma and first run
+		if ( !matched || (match = rcomma.exec( soFar )) ) {
+			if ( match ) {
+				// Don't consume trailing commas as valid
+				soFar = soFar.slice( match[0].length ) || soFar;
+			}
+			groups.push( (tokens = []) );
+		}
+
+		matched = false;
+
+		// Combinators
+		if ( (match = rcombinators.exec( soFar )) ) {
+			matched = match.shift();
+			tokens.push({
+				value: matched,
+				// Cast descendant combinators to space
+				type: match[0].replace( rtrim, " " )
+			});
+			soFar = soFar.slice( matched.length );
+		}
+
+		// Filters
+		for ( type in Expr.filter ) {
+			if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
+				(match = preFilters[ type ]( match ))) ) {
+				matched = match.shift();
+				tokens.push({
+					value: matched,
+					type: type,
+					matches: match
+				});
+				soFar = soFar.slice( matched.length );
+			}
+		}
+
+		if ( !matched ) {
+			break;
+		}
+	}
+
+	// Return the length of the invalid excess
+	// if we're just parsing
+	// Otherwise, throw an error or return tokens
+	return parseOnly ?
+		soFar.length :
+		soFar ?
+			Sizzle.error( selector ) :
+			// Cache the tokens
+			tokenCache( selector, groups ).slice( 0 );
+};
+
+function toSelector( tokens ) {
+	var i = 0,
+		len = tokens.length,
+		selector = "";
+	for ( ; i < len; i++ ) {
+		selector += tokens[i].value;
+	}
+	return selector;
+}
+
+function addCombinator( matcher, combinator, base ) {
+	var dir = combinator.dir,
+		checkNonElements = base && dir === "parentNode",
+		doneName = done++;
+
+	return combinator.first ?
+		// Check against closest ancestor/preceding element
+		function( elem, context, xml ) {
+			while ( (elem = elem[ dir ]) ) {
+				if ( elem.nodeType === 1 || checkNonElements ) {
+					return matcher( elem, context, xml );
+				}
+			}
+		} :
+
+		// Check against all ancestor/preceding elements
+		function( elem, context, xml ) {
+			var oldCache, outerCache,
+				newCache = [ dirruns, doneName ];
+
+			// We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
+			if ( xml ) {
+				while ( (elem = elem[ dir ]) ) {
+					if ( elem.nodeType === 1 || checkNonElements ) {
+						if ( matcher( elem, context, xml ) ) {
+							return true;
+						}
+					}
+				}
+			} else {
+				while ( (elem = elem[ dir ]) ) {
+					if ( elem.nodeType === 1 || checkNonElements ) {
+						outerCache = elem[ expando ] || (elem[ expando ] = {});
+						if ( (oldCache = outerCache[ dir ]) &&
+							oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
+
+							// Assign to newCache so results back-propagate to previous elements
+							return (newCache[ 2 ] = oldCache[ 2 ]);
+						} else {
+							// Reuse newcache so results back-propagate to previous elements
+							outerCache[ dir ] = newCache;
+
+							// A match means we're done; a fail means we have to keep checking
+							if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {
+								return true;
+							}
+						}
+					}
+				}
+			}
+		};
+}
+
+function elementMatcher( matchers ) {
+	return matchers.length > 1 ?
+		function( elem, context, xml ) {
+			var i = matchers.length;
+			while ( i-- ) {
+				if ( !matchers[i]( elem, context, xml ) ) {
+					return false;
+				}
+			}
+			return true;
+		} :
+		matchers[0];
+}
+
+function multipleContexts( selector, contexts, results ) {
+	var i = 0,
+		len = contexts.length;
+	for ( ; i < len; i++ ) {
+		Sizzle( selector, contexts[i], results );
+	}
+	return results;
+}
+
+function condense( unmatched, map, filter, context, xml ) {
+	var elem,
+		newUnmatched = [],
+		i = 0,
+		len = unmatched.length,
+		mapped = map != null;
+
+	for ( ; i < len; i++ ) {
+		if ( (elem = unmatched[i]) ) {
+			if ( !filter || filter( elem, context, xml ) ) {
+				newUnmatched.push( elem );
+				if ( mapped ) {
+					map.push( i );
+				}
+			}
+		}
+	}
+
+	return newUnmatched;
+}
+
+function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
+	if ( postFilter && !postFilter[ expando ] ) {
+		postFilter = setMatcher( postFilter );
+	}
+	if ( postFinder && !postFinder[ expando ] ) {
+		postFinder = setMatcher( postFinder, postSelector );
+	}
+	return markFunction(function( seed, results, context, xml ) {
+		var temp, i, elem,
+			preMap = [],
+			postMap = [],
+			preexisting = results.length,
+
+			// Get initial elements from seed or context
+			elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
+
+			// Prefilter to get matcher input, preserving a map for seed-results synchronization
+			matcherIn = preFilter && ( seed || !selector ) ?
+				condense( elems, preMap, preFilter, context, xml ) :
+				elems,
+
+			matcherOut = matcher ?
+				// If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
+				postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
+
+					// ...intermediate processing is necessary
+					[] :
+
+					// ...otherwise use results directly
+					results :
+				matcherIn;
+
+		// Find primary matches
+		if ( matcher ) {
+			matcher( matcherIn, matcherOut, context, xml );
+		}
+
+		// Apply postFilter
+		if ( postFilter ) {
+			temp = condense( matcherOut, postMap );
+			postFilter( temp, [], context, xml );
+
+			// Un-match failing elements by moving them back to matcherIn
+			i = temp.length;
+			while ( i-- ) {
+				if ( (elem = temp[i]) ) {
+					matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
+				}
+			}
+		}
+
+		if ( seed ) {
+			if ( postFinder || preFilter ) {
+				if ( postFinder ) {
+					// Get the final matcherOut by condensing this intermediate into postFinder contexts
+					temp = [];
+					i = matcherOut.length;
+					while ( i-- ) {
+						if ( (elem = matcherOut[i]) ) {
+							// Restore matcherIn since elem is not yet a final match
+							temp.push( (matcherIn[i] = elem) );
+						}
+					}
+					postFinder( null, (matcherOut = []), temp, xml );
+				}
+
+				// Move matched elements from seed to results to keep them synchronized
+				i = matcherOut.length;
+				while ( i-- ) {
+					if ( (elem = matcherOut[i]) &&
+						(temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) {
+
+						seed[temp] = !(results[temp] = elem);
+					}
+				}
+			}
+
+		// Add elements to results, through postFinder if defined
+		} else {
+			matcherOut = condense(
+				matcherOut === results ?
+					matcherOut.splice( preexisting, matcherOut.length ) :
+					matcherOut
+			);
+			if ( postFinder ) {
+				postFinder( null, results, matcherOut, xml );
+			} else {
+				push.apply( results, matcherOut );
+			}
+		}
+	});
+}
+
+function matcherFromTokens( tokens ) {
+	var checkContext, matcher, j,
+		len = tokens.length,
+		leadingRelative = Expr.relative[ tokens[0].type ],
+		implicitRelative = leadingRelative || Expr.relative[" "],
+		i = leadingRelative ? 1 : 0,
+
+		// The foundational matcher ensures that elements are reachable from top-level context(s)
+		matchContext = addCombinator( function( elem ) {
+			return elem === checkContext;
+		}, implicitRelative, true ),
+		matchAnyContext = addCombinator( function( elem ) {
+			return indexOf( checkContext, elem ) > -1;
+		}, implicitRelative, true ),
+		matchers = [ function( elem, context, xml ) {
+			var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
+				(checkContext = context).nodeType ?
+					matchContext( elem, context, xml ) :
+					matchAnyContext( elem, context, xml ) );
+			// Avoid hanging onto element (issue #299)
+			checkContext = null;
+			return ret;
+		} ];
+
+	for ( ; i < len; i++ ) {
+		if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
+			matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
+		} else {
+			matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
+
+			// Return special upon seeing a positional matcher
+			if ( matcher[ expando ] ) {
+				// Find the next relative operator (if any) for proper handling
+				j = ++i;
+				for ( ; j < len; j++ ) {
+					if ( Expr.relative[ tokens[j].type ] ) {
+						break;
+					}
+				}
+				return setMatcher(
+					i > 1 && elementMatcher( matchers ),
+					i > 1 && toSelector(
+						// If the preceding token was a descendant combinator, insert an implicit any-element `*`
+						tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
+					).replace( rtrim, "$1" ),
+					matcher,
+					i < j && matcherFromTokens( tokens.slice( i, j ) ),
+					j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
+					j < len && toSelector( tokens )
+				);
+			}
+			matchers.push( matcher );
+		}
+	}
+
+	return elementMatcher( matchers );
+}
+
+function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
+	var bySet = setMatchers.length > 0,
+		byElement = elementMatchers.length > 0,
+		superMatcher = function( seed, context, xml, results, outermost ) {
+			var elem, j, matcher,
+				matchedCount = 0,
+				i = "0",
+				unmatched = seed && [],
+				setMatched = [],
+				contextBackup = outermostContext,
+				// We must always have either seed elements or outermost context
+				elems = seed || byElement && Expr.find["TAG"]( "*", outermost ),
+				// Use integer dirruns iff this is the outermost matcher
+				dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
+				len = elems.length;
+
+			if ( outermost ) {
+				outermostContext = context !== document && context;
+			}
+
+			// Add elements passing elementMatchers directly to results
+			// Keep `i` a string if there are no elements so `matchedCount` will be "00" below
+			// Support: IE<9, Safari
+			// Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id
+			for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
+				if ( byElement && elem ) {
+					j = 0;
+					while ( (matcher = elementMatchers[j++]) ) {
+						if ( matcher( elem, context, xml ) ) {
+							results.push( elem );
+							break;
+						}
+					}
+					if ( outermost ) {
+						dirruns = dirrunsUnique;
+					}
+				}
+
+				// Track unmatched elements for set filters
+				if ( bySet ) {
+					// They will have gone through all possible matchers
+					if ( (elem = !matcher && elem) ) {
+						matchedCount--;
+					}
+
+					// Lengthen the array for every element, matched or not
+					if ( seed ) {
+						unmatched.push( elem );
+					}
+				}
+			}
+
+			// Apply set filters to unmatched elements
+			matchedCount += i;
+			if ( bySet && i !== matchedCount ) {
+				j = 0;
+				while ( (matcher = setMatchers[j++]) ) {
+					matcher( unmatched, setMatched, context, xml );
+				}
+
+				if ( seed ) {
+					// Reintegrate element matches to eliminate the need for sorting
+					if ( matchedCount > 0 ) {
+						while ( i-- ) {
+							if ( !(unmatched[i] || setMatched[i]) ) {
+								setMatched[i] = pop.call( results );
+							}
+						}
+					}
+
+					// Discard index placeholder values to get only actual matches
+					setMatched = condense( setMatched );
+				}
+
+				// Add matches to results
+				push.apply( results, setMatched );
+
+				// Seedless set matches succeeding multiple successful matchers stipulate sorting
+				if ( outermost && !seed && setMatched.length > 0 &&
+					( matchedCount + setMatchers.length ) > 1 ) {
+
+					Sizzle.uniqueSort( results );
+				}
+			}
+
+			// Override manipulation of globals by nested matchers
+			if ( outermost ) {
+				dirruns = dirrunsUnique;
+				outermostContext = contextBackup;
+			}
+
+			return unmatched;
+		};
+
+	return bySet ?
+		markFunction( superMatcher ) :
+		superMatcher;
+}
+
+compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
+	var i,
+		setMatchers = [],
+		elementMatchers = [],
+		cached = compilerCache[ selector + " " ];
+
+	if ( !cached ) {
+		// Generate a function of recursive functions that can be used to check each element
+		if ( !match ) {
+			match = tokenize( selector );
+		}
+		i = match.length;
+		while ( i-- ) {
+			cached = matcherFromTokens( match[i] );
+			if ( cached[ expando ] ) {
+				setMatchers.push( cached );
+			} else {
+				elementMatchers.push( cached );
+			}
+		}
+
+		// Cache the compiled function
+		cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
+
+		// Save selector and tokenization
+		cached.selector = selector;
+	}
+	return cached;
+};
+
+/**
+ * A low-level selection function that works with Sizzle's compiled
+ *  selector functions
+ * @param {String|Function} selector A selector or a pre-compiled
+ *  selector function built with Sizzle.compile
+ * @param {Element} context
+ * @param {Array} [results]
+ * @param {Array} [seed] A set of elements to match against
+ */
+select = Sizzle.select = function( selector, context, results, seed ) {
+	var i, tokens, token, type, find,
+		compiled = typeof selector === "function" && selector,
+		match = !seed && tokenize( (selector = compiled.selector || selector) );
+
+	results = results || [];
+
+	// Try to minimize operations if there is no seed and only one group
+	if ( match.length === 1 ) {
+
+		// Take a shortcut and set the context if the root selector is an ID
+		tokens = match[0] = match[0].slice( 0 );
+		if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
+				support.getById && context.nodeType === 9 && documentIsHTML &&
+				Expr.relative[ tokens[1].type ] ) {
+
+			context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
+			if ( !context ) {
+				return results;
+
+			// Precompiled matchers will still verify ancestry, so step up a level
+			} else if ( compiled ) {
+				context = context.parentNode;
+			}
+
+			selector = selector.slice( tokens.shift().value.length );
+		}
+
+		// Fetch a seed set for right-to-left matching
+		i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
+		while ( i-- ) {
+			token = tokens[i];
+
+			// Abort if we hit a combinator
+			if ( Expr.relative[ (type = token.type) ] ) {
+				break;
+			}
+			if ( (find = Expr.find[ type ]) ) {
+				// Search, expanding context for leading sibling combinators
+				if ( (seed = find(
+					token.matches[0].replace( runescape, funescape ),
+					rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context
+				)) ) {
+
+					// If seed is empty or no tokens remain, we can return early
+					tokens.splice( i, 1 );
+					selector = seed.length && toSelector( tokens );
+					if ( !selector ) {
+						push.apply( results, seed );
+						return results;
+					}
+
+					break;
+				}
+			}
+		}
+	}
+
+	// Compile and execute a filtering function if one is not provided
+	// Provide `match` to avoid retokenization if we modified the selector above
+	( compiled || compile( selector, match ) )(
+		seed,
+		context,
+		!documentIsHTML,
+		results,
+		rsibling.test( selector ) && testContext( context.parentNode ) || context
+	);
+	return results;
+};
+
+// One-time assignments
+
+// Sort stability
+support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
+
+// Support: Chrome 14-35+
+// Always assume duplicates if they aren't passed to the comparison function
+support.detectDuplicates = !!hasDuplicate;
+
+// Initialize against the default document
+setDocument();
+
+// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
+// Detached nodes confoundingly follow *each other*
+support.sortDetached = assert(function( div1 ) {
+	// Should return 1, but returns 4 (following)
+	return div1.compareDocumentPosition( document.createElement("div") ) & 1;
+});
+
+// Support: IE<8
+// Prevent attribute/property "interpolation"
+// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
+if ( !assert(function( div ) {
+	div.innerHTML = "<a href='#'></a>";
+	return div.firstChild.getAttribute("href") === "#" ;
+}) ) {
+	addHandle( "type|href|height|width", function( elem, name, isXML ) {
+		if ( !isXML ) {
+			return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
+		}
+	});
+}
+
+// Support: IE<9
+// Use defaultValue in place of getAttribute("value")
+if ( !support.attributes || !assert(function( div ) {
+	div.innerHTML = "<input/>";
+	div.firstChild.setAttribute( "value", "" );
+	return div.firstChild.getAttribute( "value" ) === "";
+}) ) {
+	addHandle( "value", function( elem, name, isXML ) {
+		if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
+			return elem.defaultValue;
+		}
+	});
+}
+
+// Support: IE<9
+// Use getAttributeNode to fetch booleans when getAttribute lies
+if ( !assert(function( div ) {
+	return div.getAttribute("disabled") == null;
+}) ) {
+	addHandle( booleans, function( elem, name, isXML ) {
+		var val;
+		if ( !isXML ) {
+			return elem[ name ] === true ? name.toLowerCase() :
+					(val = elem.getAttributeNode( name )) && val.specified ?
+					val.value :
+				null;
+		}
+	});
+}
+
+return Sizzle;
+
+})( window );
+
+
+
+jQuery.find = Sizzle;
+jQuery.expr = Sizzle.selectors;
+jQuery.expr[":"] = jQuery.expr.pseudos;
+jQuery.unique = Sizzle.uniqueSort;
+jQuery.text = Sizzle.getText;
+jQuery.isXMLDoc = Sizzle.isXML;
+jQuery.contains = Sizzle.contains;
+
+
+
+var rneedsContext = jQuery.expr.match.needsContext;
+
+var rsingleTag = (/^<(\w+)\s*\/?>(?:<\/\1>|)$/);
+
+
+
+var risSimple = /^.[^:#\[\.,]*$/;
+
+// Implement the identical functionality for filter and not
+function winnow( elements, qualifier, not ) {
+	if ( jQuery.isFunction( qualifier ) ) {
+		return jQuery.grep( elements, function( elem, i ) {
+			/* jshint -W018 */
+			return !!qualifier.call( elem, i, elem ) !== not;
+		});
+
+	}
+
+	if ( qualifier.nodeType ) {
+		return jQuery.grep( elements, function( elem ) {
+			return ( elem === qualifier ) !== not;
+		});
+
+	}
+
+	if ( typeof qualifier === "string" ) {
+		if ( risSimple.test( qualifier ) ) {
+			return jQuery.filter( qualifier, elements, not );
+		}
+
+		qualifier = jQuery.filter( qualifier, elements );
+	}
+
+	return jQuery.grep( elements, function( elem ) {
+		return ( jQuery.inArray( elem, qualifier ) >= 0 ) !== not;
+	});
+}
+
+jQuery.filter = function( expr, elems, not ) {
+	var elem = elems[ 0 ];
+
+	if ( not ) {
+		expr = ":not(" + expr + ")";
+	}
+
+	return elems.length === 1 && elem.nodeType === 1 ?
+		jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :
+		jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
+			return elem.nodeType === 1;
+		}));
+};
+
+jQuery.fn.extend({
+	find: function( selector ) {
+		var i,
+			ret = [],
+			self = this,
+			len = self.length;
+
+		if ( typeof selector !== "string" ) {
+			return this.pushStack( jQuery( selector ).filter(function() {
+				for ( i = 0; i < len; i++ ) {
+					if ( jQuery.contains( self[ i ], this ) ) {
+						return true;
+					}
+				}
+			}) );
+		}
+
+		for ( i = 0; i < len; i++ ) {
+			jQuery.find( selector, self[ i ], ret );
+		}
+
+		// Needed because $( selector, context ) becomes $( context ).find( selector )
+		ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
+		ret.selector = this.selector ? this.selector + " " + selector : selector;
+		return ret;
+	},
+	filter: function( selector ) {
+		return this.pushStack( winnow(this, selector || [], false) );
+	},
+	not: function( selector ) {
+		return this.pushStack( winnow(this, selector || [], true) );
+	},
+	is: function( selector ) {
+		return !!winnow(
+			this,
+
+			// If this is a positional/relative selector, check membership in the returned set
+			// so $("p:first").is("p:last") won't return true for a doc with two "p".
+			typeof selector === "string" && rneedsContext.test( selector ) ?
+				jQuery( selector ) :
+				selector || [],
+			false
+		).length;
+	}
+});
+
+
+// Initialize a jQuery object
+
+
+// A central reference to the root jQuery(document)
+var rootjQuery,
+
+	// Use the correct document accordingly with window argument (sandbox)
+	document = window.document,
+
+	// A simple way to check for HTML strings
+	// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
+	// Strict HTML recognition (#11290: must start with <)
+	rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,
+
+	init = jQuery.fn.init = function( selector, context ) {
+		var match, elem;
+
+		// HANDLE: $(""), $(null), $(undefined), $(false)
+		if ( !selector ) {
+			return this;
+		}
+
+		// Handle HTML strings
+		if ( typeof selector === "string" ) {
+			if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
+				// Assume that strings that start and end with <> are HTML and skip the regex check
+				match = [ null, selector, null ];
+
+			} else {
+				match = rquickExpr.exec( selector );
+			}
+
+			// Match html or make sure no context is specified for #id
+			if ( match && (match[1] || !context) ) {
+
+				// HANDLE: $(html) -> $(array)
+				if ( match[1] ) {
+					context = context instanceof jQuery ? context[0] : context;
+
+					// scripts is true for back-compat
+					// Intentionally let the error be thrown if parseHTML is not present
+					jQuery.merge( this, jQuery.parseHTML(
+						match[1],
+						context && context.nodeType ? context.ownerDocument || context : document,
+						true
+					) );
+
+					// HANDLE: $(html, props)
+					if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
+						for ( match in context ) {
+							// Properties of context are called as methods if possible
+							if ( jQuery.isFunction( this[ match ] ) ) {
+								this[ match ]( context[ match ] );
+
+							// ...and otherwise set as attributes
+							} else {
+								this.attr( match, context[ match ] );
+							}
+						}
+					}
+
+					return this;
+
+				// HANDLE: $(#id)
+				} else {
+					elem = document.getElementById( match[2] );
+
+					// Check parentNode to catch when Blackberry 4.6 returns
+					// nodes that are no longer in the document #6963
+					if ( elem && elem.parentNode ) {
+						// Handle the case where IE and Opera return items
+						// by name instead of ID
+						if ( elem.id !== match[2] ) {
+							return rootjQuery.find( selector );
+						}
+
+						// Otherwise, we inject the element directly into the jQuery object
+						this.length = 1;
+						this[0] = elem;
+					}
+
+					this.context = document;
+					this.selector = selector;
+					return this;
+				}
+
+			// HANDLE: $(expr, $(...))
+			} else if ( !context || context.jquery ) {
+				return ( context || rootjQuery ).find( selector );
+
+			// HANDLE: $(expr, context)
+			// (which is just equivalent to: $(context).find(expr)
+			} else {
+				return this.constructor( context ).find( selector );
+			}
+
+		// HANDLE: $(DOMElement)
+		} else if ( selector.nodeType ) {
+			this.context = this[0] = selector;
+			this.length = 1;
+			return this;
+
+		// HANDLE: $(function)
+		// Shortcut for document ready
+		} else if ( jQuery.isFunction( selector ) ) {
+			return typeof rootjQuery.ready !== "undefined" ?
+				rootjQuery.ready( selector ) :
+				// Execute immediately if ready is not present
+				selector( jQuery );
+		}
+
+		if ( selector.selector !== undefined ) {
+			this.selector = selector.selector;
+			this.context = selector.context;
+		}
+
+		return jQuery.makeArray( selector, this );
+	};
+
+// Give the init function the jQuery prototype for later instantiation
+init.prototype = jQuery.fn;
+
+// Initialize central reference
+rootjQuery = jQuery( document );
+
+
+var rparentsprev = /^(?:parents|prev(?:Until|All))/,
+	// methods guaranteed to produce a unique set when starting from a unique set
+	guaranteedUnique = {
+		children: true,
+		contents: true,
+		next: true,
+		prev: true
+	};
+
+jQuery.extend({
+	dir: function( elem, dir, until ) {
+		var matched = [],
+			cur = elem[ dir ];
+
+		while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
+			if ( cur.nodeType === 1 ) {
+				matched.push( cur );
+			}
+			cur = cur[dir];
+		}
+		return matched;
+	},
+
+	sibling: function( n, elem ) {
+		var r = [];
+
+		for ( ; n; n = n.nextSibling ) {
+			if ( n.nodeType === 1 && n !== elem ) {
+				r.push( n );
+			}
+		}
+
+		return r;
+	}
+});
+
+jQuery.fn.extend({
+	has: function( target ) {
+		var i,
+			targets = jQuery( target, this ),
+			len = targets.length;
+
+		return this.filter(function() {
+			for ( i = 0; i < len; i++ ) {
+				if ( jQuery.contains( this, targets[i] ) ) {
+					return true;
+				}
+			}
+		});
+	},
+
+	closest: function( selectors, context ) {
+		var cur,
+			i = 0,
+			l = this.length,
+			matched = [],
+			pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
+				jQuery( selectors, context || this.context ) :
+				0;
+
+		for ( ; i < l; i++ ) {
+			for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) {
+				// Always skip document fragments
+				if ( cur.nodeType < 11 && (pos ?
+					pos.index(cur) > -1 :
+
+					// Don't pass non-elements to Sizzle
+					cur.nodeType === 1 &&
+						jQuery.find.matchesSelector(cur, selectors)) ) {
+
+					matched.push( cur );
+					break;
+				}
+			}
+		}
+
+		return this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched );
+	},
+
+	// Determine the position of an element within
+	// the matched set of elements
+	index: function( elem ) {
+
+		// No argument, return index in parent
+		if ( !elem ) {
+			return ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1;
+		}
+
+		// index in selector
+		if ( typeof elem === "string" ) {
+			return jQuery.inArray( this[0], jQuery( elem ) );
+		}
+
+		// Locate the position of the desired element
+		return jQuery.inArray(
+			// If it receives a jQuery object, the first element is used
+			elem.jquery ? elem[0] : elem, this );
+	},
+
+	add: function( selector, context ) {
+		return this.pushStack(
+			jQuery.unique(
+				jQuery.merge( this.get(), jQuery( selector, context ) )
+			)
+		);
+	},
+
+	addBack: function( selector ) {
+		return this.add( selector == null ?
+			this.prevObject : this.prevObject.filter(selector)
+		);
+	}
+});
+
+function sibling( cur, dir ) {
+	do {
+		cur = cur[ dir ];
+	} while ( cur && cur.nodeType !== 1 );
+
+	return cur;
+}
+
+jQuery.each({
+	parent: function( elem ) {
+		var parent = elem.parentNode;
+		return parent && parent.nodeType !== 11 ? parent : null;
+	},
+	parents: function( elem ) {
+		return jQuery.dir( elem, "parentNode" );
+	},
+	parentsUntil: function( elem, i, until ) {
+		return jQuery.dir( elem, "parentNode", until );
+	},
+	next: function( elem ) {
+		return sibling( elem, "nextSibling" );
+	},
+	prev: function( elem ) {
+		return sibling( elem, "previousSibling" );
+	},
+	nextAll: function( elem ) {
+		return jQuery.dir( elem, "nextSibling" );
+	},
+	prevAll: function( elem ) {
+		return jQuery.dir( elem, "previousSibling" );
+	},
+	nextUntil: function( elem, i, until ) {
+		return jQuery.dir( elem, "nextSibling", until );
+	},
+	prevUntil: function( elem, i, until ) {
+		return jQuery.dir( elem, "previousSibling", until );
+	},
+	siblings: function( elem ) {
+		return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
+	},
+	children: function( elem ) {
+		return jQuery.sibling( elem.firstChild );
+	},
+	contents: function( elem ) {
+		return jQuery.nodeName( elem, "iframe" ) ?
+			elem.contentDocument || elem.contentWindow.document :
+			jQuery.merge( [], elem.childNodes );
+	}
+}, function( name, fn ) {
+	jQuery.fn[ name ] = function( until, selector ) {
+		var ret = jQuery.map( this, fn, until );
+
+		if ( name.slice( -5 ) !== "Until" ) {
+			selector = until;
+		}
+
+		if ( selector && typeof selector === "string" ) {
+			ret = jQuery.filter( selector, ret );
+		}
+
+		if ( this.length > 1 ) {
+			// Remove duplicates
+			if ( !guaranteedUnique[ name ] ) {
+				ret = jQuery.unique( ret );
+			}
+
+			// Reverse order for parents* and prev-derivatives
+			if ( rparentsprev.test( name ) ) {
+				ret = ret.reverse();
+			}
+		}
+
+		return this.pushStack( ret );
+	};
+});
+var rnotwhite = (/\S+/g);
+
+
+
+// String to Object options format cache
+var optionsCache = {};
+
+// Convert String-formatted options into Object-formatted ones and store in cache
+function createOptions( options ) {
+	var object = optionsCache[ options ] = {};
+	jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) {
+		object[ flag ] = true;
+	});
+	return object;
+}
+
+/*
+ * Create a callback list using the following parameters:
+ *
+ *	options: an optional list of space-separated options that will change how
+ *			the callback list behaves or a more traditional option object
+ *
+ * By default a callback list will act like an event callback list and can be
+ * "fired" multiple times.
+ *
+ * Possible options:
+ *
+ *	once:			will ensure the callback list can only be fired once (like a Deferred)
+ *
+ *	memory:			will keep track of previous values and will call any callback added
+ *					after the list has been fired right away with the latest "memorized"
+ *					values (like a Deferred)
+ *
+ *	unique:			will ensure a callback can only be added once (no duplicate in the list)
+ *
+ *	stopOnFalse:	interrupt callings when a callback returns false
+ *
+ */
+jQuery.Callbacks = function( options ) {
+
+	// Convert options from String-formatted to Object-formatted if needed
+	// (we check in cache first)
+	options = typeof options === "string" ?
+		( optionsCache[ options ] || createOptions( options ) ) :
+		jQuery.extend( {}, options );
+
+	var // Flag to know if list is currently firing
+		firing,
+		// Last fire value (for non-forgettable lists)
+		memory,
+		// Flag to know if list was already fired
+		fired,
+		// End of the loop when firing
+		firingLength,
+		// Index of currently firing callback (modified by remove if needed)
+		firingIndex,
+		// First callback to fire (used internally by add and fireWith)
+		firingStart,
+		// Actual callback list
+		list = [],
+		// Stack of fire calls for repeatable lists
+		stack = !options.once && [],
+		// Fire callbacks
+		fire = function( data ) {
+			memory = options.memory && data;
+			fired = true;
+			firingIndex = firingStart || 0;
+			firingStart = 0;
+			firingLength = list.length;
+			firing = true;
+			for ( ; list && firingIndex < firingLength; firingIndex++ ) {
+				if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
+					memory = false; // To prevent further calls using add
+					break;
+				}
+			}
+			firing = false;
+			if ( list ) {
+				if ( stack ) {
+					if ( stack.length ) {
+						fire( stack.shift() );
+					}
+				} else if ( memory ) {
+					list = [];
+				} else {
+					self.disable();
+				}
+			}
+		},
+		// Actual Callbacks object
+		self = {
+			// Add a callback or a collection of callbacks to the list
+			add: function() {
+				if ( list ) {
+					// First, we save the current length
+					var start = list.length;
+					(function add( args ) {
+						jQuery.each( args, function( _, arg ) {
+							var type = jQuery.type( arg );
+							if ( type === "function" ) {
+								if ( !options.unique || !self.has( arg ) ) {
+									list.push( arg );
+								}
+							} else if ( arg && arg.length && type !== "string" ) {
+								// Inspect recursively
+								add( arg );
+							}
+						});
+					})( arguments );
+					// Do we need to add the callbacks to the
+					// current firing batch?
+					if ( firing ) {
+						firingLength = list.length;
+					// With memory, if we're not firing then
+					// we should call right away
+					} else if ( memory ) {
+						firingStart = start;
+						fire( memory );
+					}
+				}
+				return this;
+			},
+			// Remove a callback from the list
+			remove: function() {
+				if ( list ) {
+					jQuery.each( arguments, function( _, arg ) {
+						var index;
+						while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
+							list.splice( index, 1 );
+							// Handle firing indexes
+							if ( firing ) {
+								if ( index <= firingLength ) {
+									firingLength--;
+								}
+								if ( index <= firingIndex ) {
+									firingIndex--;
+								}
+							}
+						}
+					});
+				}
+				return this;
+			},
+			// Check if a given callback is in the list.
+			// If no argument is given, return whether or not list has callbacks attached.
+			has: function( fn ) {
+				return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
+			},
+			// Remove all callbacks from the list
+			empty: function() {
+				list = [];
+				firingLength = 0;
+				return this;
+			},
+			// Have the list do nothing anymore
+			disable: function() {
+				list = stack = memory = undefined;
+				return this;
+			},
+			// Is it disabled?
+			disabled: function() {
+				return !list;
+			},
+			// Lock the list in its current state
+			lock: function() {
+				stack = undefined;
+				if ( !memory ) {
+					self.disable();
+				}
+				return this;
+			},
+			// Is it locked?
+			locked: function() {
+				return !stack;
+			},
+			// Call all callbacks with the given context and arguments
+			fireWith: function( context, args ) {
+				if ( list && ( !fired || stack ) ) {
+					args = args || [];
+					args = [ context, args.slice ? args.slice() : args ];
+					if ( firing ) {
+						stack.push( args );
+					} else {
+						fire( args );
+					}
+				}
+				return this;
+			},
+			// Call all the callbacks with the given arguments
+			fire: function() {
+				self.fireWith( this, arguments );
+				return this;
+			},
+			// To know if the callbacks have already been called at least once
+			fired: function() {
+				return !!fired;
+			}
+		};
+
+	return self;
+};
+
+
+jQuery.extend({
+
+	Deferred: function( func ) {
+		var tuples = [
+				// action, add listener, listener list, final state
+				[ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
+				[ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
+				[ "notify", "progress", jQuery.Callbacks("memory") ]
+			],
+			state = "pending",
+			promise = {
+				state: function() {
+					return state;
+				},
+				always: function() {
+					deferred.done( arguments ).fail( arguments );
+					return this;
+				},
+				then: function( /* fnDone, fnFail, fnProgress */ ) {
+					var fns = arguments;
+					return jQuery.Deferred(function( newDefer ) {
+						jQuery.each( tuples, function( i, tuple ) {
+							var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
+							// deferred[ done | fail | progress ] for forwarding actions to newDefer
+							deferred[ tuple[1] ](function() {
+								var returned = fn && fn.apply( this, arguments );
+								if ( returned && jQuery.isFunction( returned.promise ) ) {
+									returned.promise()
+										.done( newDefer.resolve )
+										.fail( newDefer.reject )
+										.progress( newDefer.notify );
+								} else {
+									newDefer[ tuple[ 0 ] + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
+								}
+							});
+						});
+						fns = null;
+					}).promise();
+				},
+				// Get a promise for this deferred
+				// If obj is provided, the promise aspect is added to the object
+				promise: function( obj ) {
+					return obj != null ? jQuery.extend( obj, promise ) : promise;
+				}
+			},
+			deferred = {};
+
+		// Keep pipe for back-compat
+		promise.pipe = promise.then;
+
+		// Add list-specific methods
+		jQuery.each( tuples, function( i, tuple ) {
+			var list = tuple[ 2 ],
+				stateString = tuple[ 3 ];
+
+			// promise[ done | fail | progress ] = list.add
+			promise[ tuple[1] ] = list.add;
+
+			// Handle state
+			if ( stateString ) {
+				list.add(function() {
+					// state = [ resolved | rejected ]
+					state = stateString;
+
+				// [ reject_list | resolve_list ].disable; progress_list.lock
+				}, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
+			}
+
+			// deferred[ resolve | reject | notify ]
+			deferred[ tuple[0] ] = function() {
+				deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
+				return this;
+			};
+			deferred[ tuple[0] + "With" ] = list.fireWith;
+		});
+
+		// Make the deferred a promise
+		promise.promise( deferred );
+
+		// Call given func if any
+		if ( func ) {
+			func.call( deferred, deferred );
+		}
+
+		// All done!
+		return deferred;
+	},
+
+	// Deferred helper
+	when: function( subordinate /* , ..., subordinateN */ ) {
+		var i = 0,
+			resolveValues = slice.call( arguments ),
+			length = resolveValues.length,
+
+			// the count of uncompleted subordinates
+			remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
+
+			// the master Deferred. If resolveValues consist of only a single Deferred, just use that.
+			deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
+
+			// Update function for both resolve and progress values
+			updateFunc = function( i, contexts, values ) {
+				return function( value ) {
+					contexts[ i ] = this;
+					values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
+					if ( values === progressValues ) {
+						deferred.notifyWith( contexts, values );
+
+					} else if ( !(--remaining) ) {
+						deferred.resolveWith( contexts, values );
+					}
+				};
+			},
+
+			progressValues, progressContexts, resolveContexts;
+
+		// add listeners to Deferred subordinates; treat others as resolved
+		if ( length > 1 ) {
+			progressValues = new Array( length );
+			progressContexts = new Array( length );
+			resolveContexts = new Array( length );
+			for ( ; i < length; i++ ) {
+				if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
+					resolveValues[ i ].promise()
+						.done( updateFunc( i, resolveContexts, resolveValues ) )
+						.fail( deferred.reject )
+						.progress( updateFunc( i, progressContexts, progressValues ) );
+				} else {
+					--remaining;
+				}
+			}
+		}
+
+		// if we're not waiting on anything, resolve the master
+		if ( !remaining ) {
+			deferred.resolveWith( resolveContexts, resolveValues );
+		}
+
+		return deferred.promise();
+	}
+});
+
+
+// The deferred used on DOM ready
+var readyList;
+
+jQuery.fn.ready = function( fn ) {
+	// Add the callback
+	jQuery.ready.promise().done( fn );
+
+	return this;
+};
+
+jQuery.extend({
+	// Is the DOM ready to be used? Set to true once it occurs.
+	isReady: false,
+
+	// A counter to track how many items to wait for before
+	// the ready event fires. See #6781
+	readyWait: 1,
+
+	// Hold (or release) the ready event
+	holdReady: function( hold ) {
+		if ( hold ) {
+			jQuery.readyWait++;
+		} else {
+			jQuery.ready( true );
+		}
+	},
+
+	// Handle when the DOM is ready
+	ready: function( wait ) {
+
+		// Abort if there are pending holds or we're already ready
+		if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
+			return;
+		}
+
+		// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
+		if ( !document.body ) {
+			return setTimeout( jQuery.ready );
+		}
+
+		// Remember that the DOM is ready
+		jQuery.isReady = true;
+
+		// If a normal DOM Ready event fired, decrement, and wait if need be
+		if ( wait !== true && --jQuery.readyWait > 0 ) {
+			return;
+		}
+
+		// If there are functions bound, to execute
+		readyList.resolveWith( document, [ jQuery ] );
+
+		// Trigger any bound ready events
+		if ( jQuery.fn.triggerHandler ) {
+			jQuery( document ).triggerHandler( "ready" );
+			jQuery( document ).off( "ready" );
+		}
+	}
+});
+
+/**
+ * Clean-up method for dom ready events
+ */
+function detach() {
+	if ( document.addEventListener ) {
+		document.removeEventListener( "DOMContentLoaded", completed, false );
+		window.removeEventListener( "load", completed, false );
+
+	} else {
+		document.detachEvent( "onreadystatechange", completed );
+		window.detachEvent( "onload", completed );
+	}
+}
+
+/**
+ * The ready event handler and self cleanup method
+ */
+function completed() {
+	// readyState === "complete" is good enough for us to call the dom ready in oldIE
+	if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) {
+		detach();
+		jQuery.ready();
+	}
+}
+
+jQuery.ready.promise = function( obj ) {
+	if ( !readyList ) {
+
+		readyList = jQuery.Deferred();
+
+		// Catch cases where $(document).ready() is called after the browser event has already occurred.
+		// we once tried to use readyState "interactive" here, but it caused issues like the one
+		// discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
+		if ( document.readyState === "complete" ) {
+			// Handle it asynchronously to allow scripts the opportunity to delay ready
+			setTimeout( jQuery.ready );
+
+		// Standards-based browsers support DOMContentLoaded
+		} else if ( document.addEventListener ) {
+			// Use the handy event callback
+			document.addEventListener( "DOMContentLoaded", completed, false );
+
+			// A fallback to window.onload, that will always work
+			window.addEventListener( "load", completed, false );
+
+		// If IE event model is used
+		} else {
+			// Ensure firing before onload, maybe late but safe also for iframes
+			document.attachEvent( "onreadystatechange", completed );
+
+			// A fallback to window.onload, that will always work
+			window.attachEvent( "onload", completed );
+
+			// If IE and not a frame
+			// continually check to see if the document is ready
+			var top = false;
+
+			try {
+				top = window.frameElement == null && document.documentElement;
+			} catch(e) {}
+
+			if ( top && top.doScroll ) {
+				(function doScrollCheck() {
+					if ( !jQuery.isReady ) {
+
+						try {
+							// Use the trick by Diego Perini
+							// http://javascript.nwbox.com/IEContentLoaded/
+							top.doScroll("left");
+						} catch(e) {
+							return setTimeout( doScrollCheck, 50 );
+						}
+
+						// detach all dom ready events
+						detach();
+
+						// and execute any waiting functions
+						jQuery.ready();
+					}
+				})();
+			}
+		}
+	}
+	return readyList.promise( obj );
+};
+
+
+var strundefined = typeof undefined;
+
+
+
+// Support: IE<9
+// Iteration over object's inherited properties before its own
+var i;
+for ( i in jQuery( support ) ) {
+	break;
+}
+support.ownLast = i !== "0";
+
+// Note: most support tests are defined in their respective modules.
+// false until the test is run
+support.inlineBlockNeedsLayout = false;
+
+// Execute ASAP in case we need to set body.style.zoom
+jQuery(function() {
+	// Minified: var a,b,c,d
+	var val, div, body, container;
+
+	body = document.getElementsByTagName( "body" )[ 0 ];
+	if ( !body || !body.style ) {
+		// Return for frameset docs that don't have a body
+		return;
+	}
+
+	// Setup
+	div = document.createElement( "div" );
+	container = document.createElement( "div" );
+	container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px";
+	body.appendChild( container ).appendChild( div );
+
+	if ( typeof div.style.zoom !== strundefined ) {
+		// Support: IE<8
+		// Check if natively block-level elements act like inline-block
+		// elements when setting their display to 'inline' and giving
+		// them layout
+		div.style.cssText = "display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1";
+
+		support.inlineBlockNeedsLayout = val = div.offsetWidth === 3;
+		if ( val ) {
+			// Prevent IE 6 from affecting layout for positioned elements #11048
+			// Prevent IE from shrinking the body in IE 7 mode #12869
+			// Support: IE<8
+			body.style.zoom = 1;
+		}
+	}
+
+	body.removeChild( container );
+});
+
+
+
+
+(function() {
+	var div = document.createElement( "div" );
+
+	// Execute the test only if not already executed in another module.
+	if (support.deleteExpando == null) {
+		// Support: IE<9
+		support.deleteExpando = true;
+		try {
+			delete div.test;
+		} catch( e ) {
+			support.deleteExpando = false;
+		}
+	}
+
+	// Null elements to avoid leaks in IE.
+	div = null;
+})();
+
+
+/**
+ * Determines whether an object can have data
+ */
+jQuery.acceptData = function( elem ) {
+	var noData = jQuery.noData[ (elem.nodeName + " ").toLowerCase() ],
+		nodeType = +elem.nodeType || 1;
+
+	// Do not set data on non-element DOM nodes because it will not be cleared (#8335).
+	return nodeType !== 1 && nodeType !== 9 ?
+		false :
+
+		// Nodes accept data unless otherwise specified; rejection can be conditional
+		!noData || noData !== true && elem.getAttribute("classid") === noData;
+};
+
+
+var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
+	rmultiDash = /([A-Z])/g;
+
+function dataAttr( elem, key, data ) {
+	// If nothing was found internally, try to fetch any
+	// data from the HTML5 data-* attribute
+	if ( data === undefined && elem.nodeType === 1 ) {
+
+		var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
+
+		data = elem.getAttribute( name );
+
+		if ( typeof data === "string" ) {
+			try {
+				data = data === "true" ? true :
+					data === "false" ? false :
+					data === "null" ? null :
+					// Only convert to a number if it doesn't change the string
+					+data + "" === data ? +data :
+					rbrace.test( data ) ? jQuery.parseJSON( data ) :
+					data;
+			} catch( e ) {}
+
+			// Make sure we set the data so it isn't changed later
+			jQuery.data( elem, key, data );
+
+		} else {
+			data = undefined;
+		}
+	}
+
+	return data;
+}
+
+// checks a cache object for emptiness
+function isEmptyDataObject( obj ) {
+	var name;
+	for ( name in obj ) {
+
+		// if the public data object is empty, the private is still empty
+		if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
+			continue;
+		}
+		if ( name !== "toJSON" ) {
+			return false;
+		}
+	}
+
+	return true;
+}
+
+function internalData( elem, name, data, pvt /* Internal Use Only */ ) {
+	if ( !jQuery.acceptData( elem ) ) {
+		return;
+	}
+
+	var ret, thisCache,
+		internalKey = jQuery.expando,
+
+		// We have to handle DOM nodes and JS objects differently because IE6-7
+		// can't GC object references properly across the DOM-JS boundary
+		isNode = elem.nodeType,
+
+		// Only DOM nodes need the global jQuery cache; JS object data is
+		// attached directly to the object so GC can occur automatically
+		cache = isNode ? jQuery.cache : elem,
+
+		// Only defining an ID for JS objects if its cache already exists allows
+		// the code to shortcut on the same path as a DOM node with no cache
+		id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey;
+
+	// Avoid doing any more work than we need to when trying to get data on an
+	// object that has no data at all
+	if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && data === undefined && typeof name === "string" ) {
+		return;
+	}
+
+	if ( !id ) {
+		// Only DOM nodes need a new unique ID for each element since their data
+		// ends up in the global cache
+		if ( isNode ) {
+			id = elem[ internalKey ] = deletedIds.pop() || jQuery.guid++;
+		} else {
+			id = internalKey;
+		}
+	}
+
+	if ( !cache[ id ] ) {
+		// Avoid exposing jQuery metadata on plain JS objects when the object
+		// is serialized using JSON.stringify
+		cache[ id ] = isNode ? {} : { toJSON: jQuery.noop };
+	}
+
+	// An object can be passed to jQuery.data instead of a key/value pair; this gets
+	// shallow copied over onto the existing cache
+	if ( typeof name === "object" || typeof name === "function" ) {
+		if ( pvt ) {
+			cache[ id ] = jQuery.extend( cache[ id ], name );
+		} else {
+			cache[ id ].data = jQuery.extend( cache[ id ].data, name );
+		}
+	}
+
+	thisCache = cache[ id ];
+
+	// jQuery data() is stored in a separate object inside the object's internal data
+	// cache in order to avoid key collisions between internal data and user-defined
+	// data.
+	if ( !pvt ) {
+		if ( !thisCache.data ) {
+			thisCache.data = {};
+		}
+
+		thisCache = thisCache.data;
+	}
+
+	if ( data !== undefined ) {
+		thisCache[ jQuery.camelCase( name ) ] = data;
+	}
+
+	// Check for both converted-to-camel and non-converted data property names
+	// If a data property was specified
+	if ( typeof name === "string" ) {
+
+		// First Try to find as-is property data
+		ret = thisCache[ name ];
+
+		// Test for null|undefined property data
+		if ( ret == null ) {
+
+			// Try to find the camelCased property
+			ret = thisCache[ jQuery.camelCase( name ) ];
+		}
+	} else {
+		ret = thisCache;
+	}
+
+	return ret;
+}
+
+function internalRemoveData( elem, name, pvt ) {
+	if ( !jQuery.acceptData( elem ) ) {
+		return;
+	}
+
+	var thisCache, i,
+		isNode = elem.nodeType,
+
+		// See jQuery.data for more information
+		cache = isNode ? jQuery.cache : elem,
+		id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
+
+	// If there is already no cache entry for this object, there is no
+	// purpose in continuing
+	if ( !cache[ id ] ) {
+		return;
+	}
+
+	if ( name ) {
+
+		thisCache = pvt ? cache[ id ] : cache[ id ].data;
+
+		if ( thisCache ) {
+
+			// Support array or space separated string names for data keys
+			if ( !jQuery.isArray( name ) ) {
+
+				// try the string as a key before any manipulation
+				if ( name in thisCache ) {
+					name = [ name ];
+				} else {
+
+					// split the camel cased version by spaces unless a key with the spaces exists
+					name = jQuery.camelCase( name );
+					if ( name in thisCache ) {
+						name = [ name ];
+					} else {
+						name = name.split(" ");
+					}
+				}
+			} else {
+				// If "name" is an array of keys...
+				// When data is initially created, via ("key", "val") signature,
+				// keys will be converted to camelCase.
+				// Since there is no way to tell _how_ a key was added, remove
+				// both plain key and camelCase key. #12786
+				// This will only penalize the array argument path.
+				name = name.concat( jQuery.map( name, jQuery.camelCase ) );
+			}
+
+			i = name.length;
+			while ( i-- ) {
+				delete thisCache[ name[i] ];
+			}
+
+			// If there is no data left in the cache, we want to continue
+			// and let the cache object itself get destroyed
+			if ( pvt ? !isEmptyDataObject(thisCache) : !jQuery.isEmptyObject(thisCache) ) {
+				return;
+			}
+		}
+	}
+
+	// See jQuery.data for more information
+	if ( !pvt ) {
+		delete cache[ id ].data;
+
+		// Don't destroy the parent cache unless the internal data object
+		// had been the only thing left in it
+		if ( !isEmptyDataObject( cache[ id ] ) ) {
+			return;
+		}
+	}
+
+	// Destroy the cache
+	if ( isNode ) {
+		jQuery.cleanData( [ elem ], true );
+
+	// Use delete when supported for expandos or `cache` is not a window per isWindow (#10080)
+	/* jshint eqeqeq: false */
+	} else if ( support.deleteExpando || cache != cache.window ) {
+		/* jshint eqeqeq: true */
+		delete cache[ id ];
+
+	// When all else fails, null
+	} else {
+		cache[ id ] = null;
+	}
+}
+
+jQuery.extend({
+	cache: {},
+
+	// The following elements (space-suffixed to avoid Object.prototype collisions)
+	// throw uncatchable exceptions if you attempt to set expando properties
+	noData: {
+		"applet ": true,
+		"embed ": true,
+		// ...but Flash objects (which have this classid) *can* handle expandos
+		"object ": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
+	},
+
+	hasData: function( elem ) {
+		elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
+		return !!elem && !isEmptyDataObject( elem );
+	},
+
+	data: function( elem, name, data ) {
+		return internalData( elem, name, data );
+	},
+
+	removeData: function( elem, name ) {
+		return internalRemoveData( elem, name );
+	},
+
+	// For internal use only.
+	_data: function( elem, name, data ) {
+		return internalData( elem, name, data, true );
+	},
+
+	_removeData: function( elem, name ) {
+		return internalRemoveData( elem, name, true );
+	}
+});
+
+jQuery.fn.extend({
+	data: function( key, value ) {
+		var i, name, data,
+			elem = this[0],
+			attrs = elem && elem.attributes;
+
+		// Special expections of .data basically thwart jQuery.access,
+		// so implement the relevant behavior ourselves
+
+		// Gets all values
+		if ( key === undefined ) {
+			if ( this.length ) {
+				data = jQuery.data( elem );
+
+				if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
+					i = attrs.length;
+					while ( i-- ) {
+
+						// Support: IE11+
+						// The attrs elements can be null (#14894)
+						if ( attrs[ i ] ) {
+							name = attrs[ i ].name;
+							if ( name.indexOf( "data-" ) === 0 ) {
+								name = jQuery.camelCase( name.slice(5) );
+								dataAttr( elem, name, data[ name ] );
+							}
+						}
+					}
+					jQuery._data( elem, "parsedAttrs", true );
+				}
+			}
+
+			return data;
+		}
+
+		// Sets multiple values
+		if ( typeof key === "object" ) {
+			return this.each(function() {
+				jQuery.data( this, key );
+			});
+		}
+
+		return arguments.length > 1 ?
+
+			// Sets one value
+			this.each(function() {
+				jQuery.data( this, key, value );
+			}) :
+
+			// Gets one value
+			// Try to fetch any internally stored data first
+			elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : undefined;
+	},
+
+	removeData: function( key ) {
+		return this.each(function() {
+			jQuery.removeData( this, key );
+		});
+	}
+});
+
+
+jQuery.extend({
+	queue: function( elem, type, data ) {
+		var queue;
+
+		if ( elem ) {
+			type = ( type || "fx" ) + "queue";
+			queue = jQuery._data( elem, type );
+
+			// Speed up dequeue by getting out quickly if this is just a lookup
+			if ( data ) {
+				if ( !queue || jQuery.isArray(data) ) {
+					queue = jQuery._data( elem, type, jQuery.makeArray(data) );
+				} else {
+					queue.push( data );
+				}
+			}
+			return queue || [];
+		}
+	},
+
+	dequeue: function( elem, type ) {
+		type = type || "fx";
+
+		var queue = jQuery.queue( elem, type ),
+			startLength = queue.length,
+			fn = queue.shift(),
+			hooks = jQuery._queueHooks( elem, type ),
+			next = function() {
+				jQuery.dequeue( elem, type );
+			};
+
+		// If the fx queue is dequeued, always remove the progress sentinel
+		if ( fn === "inprogress" ) {
+			fn = queue.shift();
+			startLength--;
+		}
+
+		if ( fn ) {
+
+			// Add a progress sentinel to prevent the fx queue from being
+			// automatically dequeued
+			if ( type === "fx" ) {
+				queue.unshift( "inprogress" );
+			}
+
+			// clear up the last queue stop function
+			delete hooks.stop;
+			fn.call( elem, next, hooks );
+		}
+
+		if ( !startLength && hooks ) {
+			hooks.empty.fire();
+		}
+	},
+
+	// not intended for public consumption - generates a queueHooks object, or returns the current one
+	_queueHooks: function( elem, type ) {
+		var key = type + "queueHooks";
+		return jQuery._data( elem, key ) || jQuery._data( elem, key, {
+			empty: jQuery.Callbacks("once memory").add(function() {
+				jQuery._removeData( elem, type + "queue" );
+				jQuery._removeData( elem, key );
+			})
+		});
+	}
+});
+
+jQuery.fn.extend({
+	queue: function( type, data ) {
+		var setter = 2;
+
+		if ( typeof type !== "string" ) {
+			data = type;
+			type = "fx";
+			setter--;
+		}
+
+		if ( arguments.length < setter ) {
+			return jQuery.queue( this[0], type );
+		}
+
+		return data === undefined ?
+			this :
+			this.each(function() {
+				var queue = jQuery.queue( this, type, data );
+
+				// ensure a hooks for this queue
+				jQuery._queueHooks( this, type );
+
+				if ( type === "fx" && queue[0] !== "inprogress" ) {
+					jQuery.dequeue( this, type );
+				}
+			});
+	},
+	dequeue: function( type ) {
+		return this.each(function() {
+			jQuery.dequeue( this, type );
+		});
+	},
+	clearQueue: function( type ) {
+		return this.queue( type || "fx", [] );
+	},
+	// Get a promise resolved when queues of a certain type
+	// are emptied (fx is the type by default)
+	promise: function( type, obj ) {
+		var tmp,
+			count = 1,
+			defer = jQuery.Deferred(),
+			elements = this,
+			i = this.length,
+			resolve = function() {
+				if ( !( --count ) ) {
+					defer.resolveWith( elements, [ elements ] );
+				}
+			};
+
+		if ( typeof type !== "string" ) {
+			obj = type;
+			type = undefined;
+		}
+		type = type || "fx";
+
+		while ( i-- ) {
+			tmp = jQuery._data( elements[ i ], type + "queueHooks" );
+			if ( tmp && tmp.empty ) {
+				count++;
+				tmp.empty.add( resolve );
+			}
+		}
+		resolve();
+		return defer.promise( obj );
+	}
+});
+var pnum = (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source;
+
+var cssExpand = [ "Top", "Right", "Bottom", "Left" ];
+
+var isHidden = function( elem, el ) {
+		// isHidden might be called from jQuery#filter function;
+		// in that case, element will be second argument
+		elem = el || elem;
+		return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
+	};
+
+
+
+// Multifunctional method to get and set values of a collection
+// The value/s can optionally be executed if it's a function
+var access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
+	var i = 0,
+		length = elems.length,
+		bulk = key == null;
+
+	// Sets many values
+	if ( jQuery.type( key ) === "object" ) {
+		chainable = true;
+		for ( i in key ) {
+			jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
+		}
+
+	// Sets one value
+	} else if ( value !== undefined ) {
+		chainable = true;
+
+		if ( !jQuery.isFunction( value ) ) {
+			raw = true;
+		}
+
+		if ( bulk ) {
+			// Bulk operations run against the entire set
+			if ( raw ) {
+				fn.call( elems, value );
+				fn = null;
+
+			// ...except when executing function values
+			} else {
+				bulk = fn;
+				fn = function( elem, key, value ) {
+					return bulk.call( jQuery( elem ), value );
+				};
+			}
+		}
+
+		if ( fn ) {
+			for ( ; i < length; i++ ) {
+				fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
+			}
+		}
+	}
+
+	return chainable ?
+		elems :
+
+		// Gets
+		bulk ?
+			fn.call( elems ) :
+			length ? fn( elems[0], key ) : emptyGet;
+};
+var rcheckableType = (/^(?:checkbox|radio)$/i);
+
+
+
+(function() {
+	// Minified: var a,b,c
+	var input = document.createElement( "input" ),
+		div = document.createElement( "div" ),
+		fragment = document.createDocumentFragment();
+
+	// Setup
+	div.innerHTML = "  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
+
+	// IE strips leading whitespace when .innerHTML is used
+	support.leadingWhitespace = div.firstChild.nodeType === 3;
+
+	// Make sure that tbody elements aren't automatically inserted
+	// IE will insert them into empty tables
+	support.tbody = !div.getElementsByTagName( "tbody" ).length;
+
+	// Make sure that link elements get serialized correctly by innerHTML
+	// This requires a wrapper element in IE
+	support.htmlSerialize = !!div.getElementsByTagName( "link" ).length;
+
+	// Makes sure cloning an html5 element does not cause problems
+	// Where outerHTML is undefined, this still works
+	support.html5Clone =
+		document.createElement( "nav" ).cloneNode( true ).outerHTML !== "<:nav></:nav>";
+
+	// Check if a disconnected checkbox will retain its checked
+	// value of true after appended to the DOM (IE6/7)
+	input.type = "checkbox";
+	input.checked = true;
+	fragment.appendChild( input );
+	support.appendChecked = input.checked;
+
+	// Make sure textarea (and checkbox) defaultValue is properly cloned
+	// Support: IE6-IE11+
+	div.innerHTML = "<textarea>x</textarea>";
+	support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
+
+	// #11217 - WebKit loses check when the name is after the checked attribute
+	fragment.appendChild( div );
+	div.innerHTML = "<input type='radio' checked='checked' name='t'/>";
+
+	// Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3
+	// old WebKit doesn't clone checked state correctly in fragments
+	support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;
+
+	// Support: IE<9
+	// Opera does not clone events (and typeof div.attachEvent === undefined).
+	// IE9-10 clones events bound via attachEvent, but they don't trigger with .click()
+	support.noCloneEvent = true;
+	if ( div.attachEvent ) {
+		div.attachEvent( "onclick", function() {
+			support.noCloneEvent = false;
+		});
+
+		div.cloneNode( true ).click();
+	}
+
+	// Execute the test only if not already executed in another module.
+	if (support.deleteExpando == null) {
+		// Support: IE<9
+		support.deleteExpando = true;
+		try {
+			delete div.test;
+		} catch( e ) {
+			support.deleteExpando = false;
+		}
+	}
+})();
+
+
+(function() {
+	var i, eventName,
+		div = document.createElement( "div" );
+
+	// Support: IE<9 (lack submit/change bubble), Firefox 23+ (lack focusin event)
+	for ( i in { submit: true, change: true, focusin: true }) {
+		eventName = "on" + i;
+
+		if ( !(support[ i + "Bubbles" ] = eventName in window) ) {
+			// Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP)
+			div.setAttribute( eventName, "t" );
+			support[ i + "Bubbles" ] = div.attributes[ eventName ].expando === false;
+		}
+	}
+
+	// Null elements to avoid leaks in IE.
+	div = null;
+})();
+
+
+var rformElems = /^(?:input|select|textarea)$/i,
+	rkeyEvent = /^key/,
+	rmouseEvent = /^(?:mouse|pointer|contextmenu)|click/,
+	rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
+	rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
+
+function returnTrue() {
+	return true;
+}
+
+function returnFalse() {
+	return false;
+}
+
+function safeActiveElement() {
+	try {
+		return document.activeElement;
+	} catch ( err ) { }
+}
+
+/*
+ * Helper functions for managing events -- not part of the public interface.
+ * Props to Dean Edwards' addEvent library for many of the ideas.
+ */
+jQuery.event = {
+
+	global: {},
+
+	add: function( elem, types, handler, data, selector ) {
+		var tmp, events, t, handleObjIn,
+			special, eventHandle, handleObj,
+			handlers, type, namespaces, origType,
+			elemData = jQuery._data( elem );
+
+		// Don't attach events to noData or text/comment nodes (but allow plain objects)
+		if ( !elemData ) {
+			return;
+		}
+
+		// Caller can pass in an object of custom data in lieu of the handler
+		if ( handler.handler ) {
+			handleObjIn = handler;
+			handler = handleObjIn.handler;
+			selector = handleObjIn.selector;
+		}
+
+		// Make sure that the handler has a unique ID, used to find/remove it later
+		if ( !handler.guid ) {
+			handler.guid = jQuery.guid++;
+		}
+
+		// Init the element's event structure and main handler, if this is the first
+		if ( !(events = elemData.events) ) {
+			events = elemData.events = {};
+		}
+		if ( !(eventHandle = elemData.handle) ) {
+			eventHandle = elemData.handle = function( e ) {
+				// Discard the second event of a jQuery.event.trigger() and
+				// when an event is called after a page has unloaded
+				return typeof jQuery !== strundefined && (!e || jQuery.event.triggered !== e.type) ?
+					jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
+					undefined;
+			};
+			// Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
+			eventHandle.elem = elem;
+		}
+
+		// Handle multiple events separated by a space
+		types = ( types || "" ).match( rnotwhite ) || [ "" ];
+		t = types.length;
+		while ( t-- ) {
+			tmp = rtypenamespace.exec( types[t] ) || [];
+			type = origType = tmp[1];
+			namespaces = ( tmp[2] || "" ).split( "." ).sort();
+
+			// There *must* be a type, no attaching namespace-only handlers
+			if ( !type ) {
+				continue;
+			}
+
+			// If event changes its type, use the special event handlers for the changed type
+			special = jQuery.event.special[ type ] || {};
+
+			// If selector defined, determine special event api type, otherwise given type
+			type = ( selector ? special.delegateType : special.bindType ) || type;
+
+			// Update special based on newly reset type
+			special = jQuery.event.special[ type ] || {};
+
+			// handleObj is passed to all event handlers
+			handleObj = jQuery.extend({
+				type: type,
+				origType: origType,
+				data: data,
+				handler: handler,
+				guid: handler.guid,
+				selector: selector,
+				needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
+				namespace: namespaces.join(".")
+			}, handleObjIn );
+
+			// Init the event handler queue if we're the first
+			if ( !(handlers = events[ type ]) ) {
+				handlers = events[ type ] = [];
+				handlers.delegateCount = 0;
+
+				// Only use addEventListener/attachEvent if the special events handler returns false
+				if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
+					// Bind the global event handler to the element
+					if ( elem.addEventListener ) {
+						elem.addEventListener( type, eventHandle, false );
+
+					} else if ( elem.attachEvent ) {
+						elem.attachEvent( "on" + type, eventHandle );
+					}
+				}
+			}
+
+			if ( special.add ) {
+				special.add.call( elem, handleObj );
+
+				if ( !handleObj.handler.guid ) {
+					handleObj.handler.guid = handler.guid;
+				}
+			}
+
+			// Add to the element's handler list, delegates in front
+			if ( selector ) {
+				handlers.splice( handlers.delegateCount++, 0, handleObj );
+			} else {
+				handlers.push( handleObj );
+			}
+
+			// Keep track of which events have ever been used, for event optimization
+			jQuery.event.global[ type ] = true;
+		}
+
+		// Nullify elem to prevent memory leaks in IE
+		elem = null;
+	},
+
+	// Detach an event or set of events from an element
+	remove: function( elem, types, handler, selector, mappedTypes ) {
+		var j, handleObj, tmp,
+			origCount, t, events,
+			special, handlers, type,
+			namespaces, origType,
+			elemData = jQuery.hasData( elem ) && jQuery._data( elem );
+
+		if ( !elemData || !(events = elemData.events) ) {
+			return;
+		}
+
+		// Once for each type.namespace in types; type may be omitted
+		types = ( types || "" ).match( rnotwhite ) || [ "" ];
+		t = types.length;
+		while ( t-- ) {
+			tmp = rtypenamespace.exec( types[t] ) || [];
+			type = origType = tmp[1];
+			namespaces = ( tmp[2] || "" ).split( "." ).sort();
+
+			// Unbind all events (on this namespace, if provided) for the element
+			if ( !type ) {
+				for ( type in events ) {
+					jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
+				}
+				continue;
+			}
+
+			special = jQuery.event.special[ type ] || {};
+			type = ( selector ? special.delegateType : special.bindType ) || type;
+			handlers = events[ type ] || [];
+			tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" );
+
+			// Remove matching events
+			origCount = j = handlers.length;
+			while ( j-- ) {
+				handleObj = handlers[ j ];
+
+				if ( ( mappedTypes || origType === handleObj.origType ) &&
+					( !handler || handler.guid === handleObj.guid ) &&
+					( !tmp || tmp.test( handleObj.namespace ) ) &&
+					( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
+					handlers.splice( j, 1 );
+
+					if ( handleObj.selector ) {
+						handlers.delegateCount--;
+					}
+					if ( special.remove ) {
+						special.remove.call( elem, handleObj );
+					}
+				}
+			}
+
+			// Remove generic event handler if we removed something and no more handlers exist
+			// (avoids potential for endless recursion during removal of special event handlers)
+			if ( origCount && !handlers.length ) {
+				if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
+					jQuery.removeEvent( elem, type, elemData.handle );
+				}
+
+				delete events[ type ];
+			}
+		}
+
+		// Remove the expando if it's no longer used
+		if ( jQuery.isEmptyObject( events ) ) {
+			delete elemData.handle;
+
+			// removeData also checks for emptiness and clears the expando if empty
+			// so use it instead of delete
+			jQuery._removeData( elem, "events" );
+		}
+	},
+
+	trigger: function( event, data, elem, onlyHandlers ) {
+		var handle, ontype, cur,
+			bubbleType, special, tmp, i,
+			eventPath = [ elem || document ],
+			type = hasOwn.call( event, "type" ) ? event.type : event,
+			namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : [];
+
+		cur = tmp = elem = elem || document;
+
+		// Don't do events on text and comment nodes
+		if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+			return;
+		}
+
+		// focus/blur morphs to focusin/out; ensure we're not firing them right now
+		if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
+			return;
+		}
+
+		if ( type.indexOf(".") >= 0 ) {
+			// Namespaced trigger; create a regexp to match event type in handle()
+			namespaces = type.split(".");
+			type = namespaces.shift();
+			namespaces.sort();
+		}
+		ontype = type.indexOf(":") < 0 && "on" + type;
+
+		// Caller can pass in a jQuery.Event object, Object, or just an event type string
+		event = event[ jQuery.expando ] ?
+			event :
+			new jQuery.Event( type, typeof event === "object" && event );
+
+		// Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
+		event.isTrigger = onlyHandlers ? 2 : 3;
+		event.namespace = namespaces.join(".");
+		event.namespace_re = event.namespace ?
+			new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) :
+			null;
+
+		// Clean up the event in case it is being reused
+		event.result = undefined;
+		if ( !event.target ) {
+			event.target = elem;
+		}
+
+		// Clone any incoming data and prepend the event, creating the handler arg list
+		data = data == null ?
+			[ event ] :
+			jQuery.makeArray( data, [ event ] );
+
+		// Allow special events to draw outside the lines
+		special = jQuery.event.special[ type ] || {};
+		if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
+			return;
+		}
+
+		// Determine event propagation path in advance, per W3C events spec (#9951)
+		// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
+		if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
+
+			bubbleType = special.delegateType || type;
+			if ( !rfocusMorph.test( bubbleType + type ) ) {
+				cur = cur.parentNode;
+			}
+			for ( ; cur; cur = cur.parentNode ) {
+				eventPath.push( cur );
+				tmp = cur;
+			}
+
+			// Only add window if we got to document (e.g., not plain obj or detached DOM)
+			if ( tmp === (elem.ownerDocument || document) ) {
+				eventPath.push( tmp.defaultView || tmp.parentWindow || window );
+			}
+		}
+
+		// Fire handlers on the event path
+		i = 0;
+		while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {
+
+			event.type = i > 1 ?
+				bubbleType :
+				special.bindType || type;
+
+			// jQuery handler
+			handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
+			if ( handle ) {
+				handle.apply( cur, data );
+			}
+
+			// Native handler
+			handle = ontype && cur[ ontype ];
+			if ( handle && handle.apply && jQuery.acceptData( cur ) ) {
+				event.result = handle.apply( cur, data );
+				if ( event.result === false ) {
+					event.preventDefault();
+				}
+			}
+		}
+		event.type = type;
+
+		// If nobody prevented the default action, do it now
+		if ( !onlyHandlers && !event.isDefaultPrevented() ) {
+
+			if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) &&
+				jQuery.acceptData( elem ) ) {
+
+				// Call a native DOM method on the target with the same name name as the event.
+				// Can't use an .isFunction() check here because IE6/7 fails that test.
+				// Don't do default actions on window, that's where global variables be (#6170)
+				if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) {
+
+					// Don't re-trigger an onFOO event when we call its FOO() method
+					tmp = elem[ ontype ];
+
+					if ( tmp ) {
+						elem[ ontype ] = null;
+					}
+
+					// Prevent re-triggering of the same event, since we already bubbled it above
+					jQuery.event.triggered = type;
+					try {
+						elem[ type ]();
+					} catch ( e ) {
+						// IE<9 dies on focus/blur to hidden element (#1486,#12518)
+						// only reproducible on winXP IE8 native, not IE9 in IE8 mode
+					}
+					jQuery.event.triggered = undefined;
+
+					if ( tmp ) {
+						elem[ ontype ] = tmp;
+					}
+				}
+			}
+		}
+
+		return event.result;
+	},
+
+	dispatch: function( event ) {
+
+		// Make a writable jQuery.Event from the native event object
+		event = jQuery.event.fix( event );
+
+		var i, ret, handleObj, matched, j,
+			handlerQueue = [],
+			args = slice.call( arguments ),
+			handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [],
+			special = jQuery.event.special[ event.type ] || {};
+
+		// Use the fix-ed jQuery.Event rather than the (read-only) native event
+		args[0] = event;
+		event.delegateTarget = this;
+
+		// Call the preDispatch hook for the mapped type, and let it bail if desired
+		if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
+			return;
+		}
+
+		// Determine handlers
+		handlerQueue = jQuery.event.handlers.call( this, event, handlers );
+
+		// Run delegates first; they may want to stop propagation beneath us
+		i = 0;
+		while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {
+			event.currentTarget = matched.elem;
+
+			j = 0;
+			while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {
+
+				// Triggered event must either 1) have no namespace, or
+				// 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
+				if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {
+
+					event.handleObj = handleObj;
+					event.data = handleObj.data;
+
+					ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
+							.apply( matched.elem, args );
+
+					if ( ret !== undefined ) {
+						if ( (event.result = ret) === false ) {
+							event.preventDefault();
+							event.stopPropagation();
+						}
+					}
+				}
+			}
+		}
+
+		// Call the postDispatch hook for the mapped type
+		if ( special.postDispatch ) {
+			special.postDispatch.call( this, event );
+		}
+
+		return event.result;
+	},
+
+	handlers: function( event, handlers ) {
+		var sel, handleObj, matches, i,
+			handlerQueue = [],
+			delegateCount = handlers.delegateCount,
+			cur = event.target;
+
+		// Find delegate handlers
+		// Black-hole SVG <use> instance trees (#13180)
+		// Avoid non-left-click bubbling in Firefox (#3861)
+		if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) {
+
+			/* jshint eqeqeq: false */
+			for ( ; cur != this; cur = cur.parentNode || this ) {
+				/* jshint eqeqeq: true */
+
+				// Don't check non-elements (#13208)
+				// Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
+				if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) {
+					matches = [];
+					for ( i = 0; i < delegateCount; i++ ) {
+						handleObj = handlers[ i ];
+
+						// Don't conflict with Object.prototype properties (#13203)
+						sel = handleObj.selector + " ";
+
+						if ( matches[ sel ] === undefined ) {
+							matches[ sel ] = handleObj.needsContext ?
+								jQuery( sel, this ).index( cur ) >= 0 :
+								jQuery.find( sel, this, null, [ cur ] ).length;
+						}
+						if ( matches[ sel ] ) {
+							matches.push( handleObj );
+						}
+					}
+					if ( matches.length ) {
+						handlerQueue.push({ elem: cur, handlers: matches });
+					}
+				}
+			}
+		}
+
+		// Add the remaining (directly-bound) handlers
+		if ( delegateCount < handlers.length ) {
+			handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });
+		}
+
+		return handlerQueue;
+	},
+
+	fix: function( event ) {
+		if ( event[ jQuery.expando ] ) {
+			return event;
+		}
+
+		// Create a writable copy of the event object and normalize some properties
+		var i, prop, copy,
+			type = event.type,
+			originalEvent = event,
+			fixHook = this.fixHooks[ type ];
+
+		if ( !fixHook ) {
+			this.fixHooks[ type ] = fixHook =
+				rmouseEvent.test( type ) ? this.mouseHooks :
+				rkeyEvent.test( type ) ? this.keyHooks :
+				{};
+		}
+		copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
+
+		event = new jQuery.Event( originalEvent );
+
+		i = copy.length;
+		while ( i-- ) {
+			prop = copy[ i ];
+			event[ prop ] = originalEvent[ prop ];
+		}
+
+		// Support: IE<9
+		// Fix target property (#1925)
+		if ( !event.target ) {
+			event.target = originalEvent.srcElement || document;
+		}
+
+		// Support: Chrome 23+, Safari?
+		// Target should not be a text node (#504, #13143)
+		if ( event.target.nodeType === 3 ) {
+			event.target = event.target.parentNode;
+		}
+
+		// Support: IE<9
+		// For mouse/key events, metaKey==false if it's undefined (#3368, #11328)
+		event.metaKey = !!event.metaKey;
+
+		return fixHook.filter ? fixHook.filter( event, originalEvent ) : event;
+	},
+
+	// Includes some event props shared by KeyEvent and MouseEvent
+	props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
+
+	fixHooks: {},
+
+	keyHooks: {
+		props: "char charCode key keyCode".split(" "),
+		filter: function( event, original ) {
+
+			// Add which for key events
+			if ( event.which == null ) {
+				event.which = original.charCode != null ? original.charCode : original.keyCode;
+			}
+
+			return event;
+		}
+	},
+
+	mouseHooks: {
+		props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
+		filter: function( event, original ) {
+			var body, eventDoc, doc,
+				button = original.button,
+				fromElement = original.fromElement;
+
+			// Calculate pageX/Y if missing and clientX/Y available
+			if ( event.pageX == null && original.clientX != null ) {
+				eventDoc = event.target.ownerDocument || document;
+				doc = eventDoc.documentElement;
+				body = eventDoc.body;
+
+				event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
+				event.pageY = original.clientY + ( doc && doc.scrollTop  || body && body.scrollTop  || 0 ) - ( doc && doc.clientTop  || body && body.clientTop  || 0 );
+			}
+
+			// Add relatedTarget, if necessary
+			if ( !event.relatedTarget && fromElement ) {
+				event.relatedTarget = fromElement === event.target ? original.toElement : fromElement;
+			}
+
+			// Add which for click: 1 === left; 2 === middle; 3 === right
+			// Note: button is not normalized, so don't use it
+			if ( !event.which && button !== undefined ) {
+				event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
+			}
+
+			return event;
+		}
+	},
+
+	special: {
+		load: {
+			// Prevent triggered image.load events from bubbling to window.load
+			noBubble: true
+		},
+		focus: {
+			// Fire native event if possible so blur/focus sequence is correct
+			trigger: function() {
+				if ( this !== safeActiveElement() && this.focus ) {
+					try {
+						this.focus();
+						return false;
+					} catch ( e ) {
+						// Support: IE<9
+						// If we error on focus to hidden element (#1486, #12518),
+						// let .trigger() run the handlers
+					}
+				}
+			},
+			delegateType: "focusin"
+		},
+		blur: {
+			trigger: function() {
+				if ( this === safeActiveElement() && this.blur ) {
+					this.blur();
+					return false;
+				}
+			},
+			delegateType: "focusout"
+		},
+		click: {
+			// For checkbox, fire native event so checked state will be right
+			trigger: function() {
+				if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) {
+					this.click();
+					return false;
+				}
+			},
+
+			// For cross-browser consistency, don't fire native .click() on links
+			_default: function( event ) {
+				return jQuery.nodeName( event.target, "a" );
+			}
+		},
+
+		beforeunload: {
+			postDispatch: function( event ) {
+
+				// Support: Firefox 20+
+				// Firefox doesn't alert if the returnValue field is not set.
+				if ( event.result !== undefined && event.originalEvent ) {
+					event.originalEvent.returnValue = event.result;
+				}
+			}
+		}
+	},
+
+	simulate: function( type, elem, event, bubble ) {
+		// Piggyback on a donor event to simulate a different one.
+		// Fake originalEvent to avoid donor's stopPropagation, but if the
+		// simulated event prevents default then we do the same on the donor.
+		var e = jQuery.extend(
+			new jQuery.Event(),
+			event,
+			{
+				type: type,
+				isSimulated: true,
+				originalEvent: {}
+			}
+		);
+		if ( bubble ) {
+			jQuery.event.trigger( e, null, elem );
+		} else {
+			jQuery.event.dispatch.call( elem, e );
+		}
+		if ( e.isDefaultPrevented() ) {
+			event.preventDefault();
+		}
+	}
+};
+
+jQuery.removeEvent = document.removeEventListener ?
+	function( elem, type, handle ) {
+		if ( elem.removeEventListener ) {
+			elem.removeEventListener( type, handle, false );
+		}
+	} :
+	function( elem, type, handle ) {
+		var name = "on" + type;
+
+		if ( elem.detachEvent ) {
+
+			// #8545, #7054, preventing memory leaks for custom events in IE6-8
+			// detachEvent needed property on element, by name of that event, to properly expose it to GC
+			if ( typeof elem[ name ] === strundefined ) {
+				elem[ name ] = null;
+			}
+
+			elem.detachEvent( name, handle );
+		}
+	};
+
+jQuery.Event = function( src, props ) {
+	// Allow instantiation without the 'new' keyword
+	if ( !(this instanceof jQuery.Event) ) {
+		return new jQuery.Event( src, props );
+	}
+
+	// Event object
+	if ( src && src.type ) {
+		this.originalEvent = src;
+		this.type = src.type;
+
+		// Events bubbling up the document may have been marked as prevented
+		// by a handler lower down the tree; reflect the correct value.
+		this.isDefaultPrevented = src.defaultPrevented ||
+				src.defaultPrevented === undefined &&
+				// Support: IE < 9, Android < 4.0
+				src.returnValue === false ?
+			returnTrue :
+			returnFalse;
+
+	// Event type
+	} else {
+		this.type = src;
+	}
+
+	// Put explicitly provided properties onto the event object
+	if ( props ) {
+		jQuery.extend( this, props );
+	}
+
+	// Create a timestamp if incoming event doesn't have one
+	this.timeStamp = src && src.timeStamp || jQuery.now();
+
+	// Mark it as fixed
+	this[ jQuery.expando ] = true;
+};
+
+// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
+// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
+jQuery.Event.prototype = {
+	isDefaultPrevented: returnFalse,
+	isPropagationStopped: returnFalse,
+	isImmediatePropagationStopped: returnFalse,
+
+	preventDefault: function() {
+		var e = this.originalEvent;
+
+		this.isDefaultPrevented = returnTrue;
+		if ( !e ) {
+			return;
+		}
+
+		// If preventDefault exists, run it on the original event
+		if ( e.preventDefault ) {
+			e.preventDefault();
+
+		// Support: IE
+		// Otherwise set the returnValue property of the original event to false
+		} else {
+			e.returnValue = false;
+		}
+	},
+	stopPropagation: function() {
+		var e = this.originalEvent;
+
+		this.isPropagationStopped = returnTrue;
+		if ( !e ) {
+			return;
+		}
+		// If stopPropagation exists, run it on the original event
+		if ( e.stopPropagation ) {
+			e.stopPropagation();
+		}
+
+		// Support: IE
+		// Set the cancelBubble property of the original event to true
+		e.cancelBubble = true;
+	},
+	stopImmediatePropagation: function() {
+		var e = this.originalEvent;
+
+		this.isImmediatePropagationStopped = returnTrue;
+
+		if ( e && e.stopImmediatePropagation ) {
+			e.stopImmediatePropagation();
+		}
+
+		this.stopPropagation();
+	}
+};
+
+// Create mouseenter/leave events using mouseover/out and event-time checks
+jQuery.each({
+	mouseenter: "mouseover",
+	mouseleave: "mouseout",
+	pointerenter: "pointerover",
+	pointerleave: "pointerout"
+}, function( orig, fix ) {
+	jQuery.event.special[ orig ] = {
+		delegateType: fix,
+		bindType: fix,
+
+		handle: function( event ) {
+			var ret,
+				target = this,
+				related = event.relatedTarget,
+				handleObj = event.handleObj;
+
+			// For mousenter/leave call the handler if related is outside the target.
+			// NB: No relatedTarget if the mouse left/entered the browser window
+			if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
+				event.type = handleObj.origType;
+				ret = handleObj.handler.apply( this, arguments );
+				event.type = fix;
+			}
+			return ret;
+		}
+	};
+});
+
+// IE submit delegation
+if ( !support.submitBubbles ) {
+
+	jQuery.event.special.submit = {
+		setup: function() {
+			// Only need this for delegated form submit events
+			if ( jQuery.nodeName( this, "form" ) ) {
+				return false;
+			}
+
+			// Lazy-add a submit handler when a descendant form may potentially be submitted
+			jQuery.event.add( this, "click._submit keypress._submit", function( e ) {
+				// Node name check avoids a VML-related crash in IE (#9807)
+				var elem = e.target,
+					form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;
+				if ( form && !jQuery._data( form, "submitBubbles" ) ) {
+					jQuery.event.add( form, "submit._submit", function( event ) {
+						event._submit_bubble = true;
+					});
+					jQuery._data( form, "submitBubbles", true );
+				}
+			});
+			// return undefined since we don't need an event listener
+		},
+
+		postDispatch: function( event ) {
+			// If form was submitted by the user, bubble the event up the tree
+			if ( event._submit_bubble ) {
+				delete event._submit_bubble;
+				if ( this.parentNode && !event.isTrigger ) {
+					jQuery.event.simulate( "submit", this.parentNode, event, true );
+				}
+			}
+		},
+
+		teardown: function() {
+			// Only need this for delegated form submit events
+			if ( jQuery.nodeName( this, "form" ) ) {
+				return false;
+			}
+
+			// Remove delegated handlers; cleanData eventually reaps submit handlers attached above
+			jQuery.event.remove( this, "._submit" );
+		}
+	};
+}
+
+// IE change delegation and checkbox/radio fix
+if ( !support.changeBubbles ) {
+
+	jQuery.event.special.change = {
+
+		setup: function() {
+
+			if ( rformElems.test( this.nodeName ) ) {
+				// IE doesn't fire change on a check/radio until blur; trigger it on click
+				// after a propertychange. Eat the blur-change in special.change.handle.
+				// This still fires onchange a second time for check/radio after blur.
+				if ( this.type === "checkbox" || this.type === "radio" ) {
+					jQuery.event.add( this, "propertychange._change", function( event ) {
+						if ( event.originalEvent.propertyName === "checked" ) {
+							this._just_changed = true;
+						}
+					});
+					jQuery.event.add( this, "click._change", function( event ) {
+						if ( this._just_changed && !event.isTrigger ) {
+							this._just_changed = false;
+						}
+						// Allow triggered, simulated change events (#11500)
+						jQuery.event.simulate( "change", this, event, true );
+					});
+				}
+				return false;
+			}
+			// Delegated event; lazy-add a change handler on descendant inputs
+			jQuery.event.add( this, "beforeactivate._change", function( e ) {
+				var elem = e.target;
+
+				if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "changeBubbles" ) ) {
+					jQuery.event.add( elem, "change._change", function( event ) {
+						if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {
+							jQuery.event.simulate( "change", this.parentNode, event, true );
+						}
+					});
+					jQuery._data( elem, "changeBubbles", true );
+				}
+			});
+		},
+
+		handle: function( event ) {
+			var elem = event.target;
+
+			// Swallow native change events from checkbox/radio, we already triggered them above
+			if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) {
+				return event.handleObj.handler.apply( this, arguments );
+			}
+		},
+
+		teardown: function() {
+			jQuery.event.remove( this, "._change" );
+
+			return !rformElems.test( this.nodeName );
+		}
+	};
+}
+
+// Create "bubbling" focus and blur events
+if ( !support.focusinBubbles ) {
+	jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
+
+		// Attach a single capturing handler on the document while someone wants focusin/focusout
+		var handler = function( event ) {
+				jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
+			};
+
+		jQuery.event.special[ fix ] = {
+			setup: function() {
+				var doc = this.ownerDocument || this,
+					attaches = jQuery._data( doc, fix );
+
+				if ( !attaches ) {
+					doc.addEventListener( orig, handler, true );
+				}
+				jQuery._data( doc, fix, ( attaches || 0 ) + 1 );
+			},
+			teardown: function() {
+				var doc = this.ownerDocument || this,
+					attaches = jQuery._data( doc, fix ) - 1;
+
+				if ( !attaches ) {
+					doc.removeEventListener( orig, handler, true );
+					jQuery._removeData( doc, fix );
+				} else {
+					jQuery._data( doc, fix, attaches );
+				}
+			}
+		};
+	});
+}
+
+jQuery.fn.extend({
+
+	on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
+		var type, origFn;
+
+		// Types can be a map of types/handlers
+		if ( typeof types === "object" ) {
+			// ( types-Object, selector, data )
+			if ( typeof selector !== "string" ) {
+				// ( types-Object, data )
+				data = data || selector;
+				selector = undefined;
+			}
+			for ( type in types ) {
+				this.on( type, selector, data, types[ type ], one );
+			}
+			return this;
+		}
+
+		if ( data == null && fn == null ) {
+			// ( types, fn )
+			fn = selector;
+			data = selector = undefined;
+		} else if ( fn == null ) {
+			if ( typeof selector === "string" ) {
+				// ( types, selector, fn )
+				fn = data;
+				data = undefined;
+			} else {
+				// ( types, data, fn )
+				fn = data;
+				data = selector;
+				selector = undefined;
+			}
+		}
+		if ( fn === false ) {
+			fn = returnFalse;
+		} else if ( !fn ) {
+			return this;
+		}
+
+		if ( one === 1 ) {
+			origFn = fn;
+			fn = function( event ) {
+				// Can use an empty set, since event contains the info
+				jQuery().off( event );
+				return origFn.apply( this, arguments );
+			};
+			// Use same guid so caller can remove using origFn
+			fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
+		}
+		return this.each( function() {
+			jQuery.event.add( this, types, fn, data, selector );
+		});
+	},
+	one: function( types, selector, data, fn ) {
+		return this.on( types, selector, data, fn, 1 );
+	},
+	off: function( types, selector, fn ) {
+		var handleObj, type;
+		if ( types && types.preventDefault && types.handleObj ) {
+			// ( event )  dispatched jQuery.Event
+			handleObj = types.handleObj;
+			jQuery( types.delegateTarget ).off(
+				handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
+				handleObj.selector,
+				handleObj.handler
+			);
+			return this;
+		}
+		if ( typeof types === "object" ) {
+			// ( types-object [, selector] )
+			for ( type in types ) {
+				this.off( type, selector, types[ type ] );
+			}
+			return this;
+		}
+		if ( selector === false || typeof selector === "function" ) {
+			// ( types [, fn] )
+			fn = selector;
+			selector = undefined;
+		}
+		if ( fn === false ) {
+			fn = returnFalse;
+		}
+		return this.each(function() {
+			jQuery.event.remove( this, types, fn, selector );
+		});
+	},
+
+	trigger: function( type, data ) {
+		return this.each(function() {
+			jQuery.event.trigger( type, data, this );
+		});
+	},
+	triggerHandler: function( type, data ) {
+		var elem = this[0];
+		if ( elem ) {
+			return jQuery.event.trigger( type, data, elem, true );
+		}
+	}
+});
+
+
+function createSafeFragment( document ) {
+	var list = nodeNames.split( "|" ),
+		safeFrag = document.createDocumentFragment();
+
+	if ( safeFrag.createElement ) {
+		while ( list.length ) {
+			safeFrag.createElement(
+				list.pop()
+			);
+		}
+	}
+	return safeFrag;
+}
+
+var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" +
+		"header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
+	rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g,
+	rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"),
+	rleadingWhitespace = /^\s+/,
+	rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
+	rtagName = /<([\w:]+)/,
+	rtbody = /<tbody/i,
+	rhtml = /<|&#?\w+;/,
+	rnoInnerhtml = /<(?:script|style|link)/i,
+	// checked="checked" or checked
+	rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
+	rscriptType = /^$|\/(?:java|ecma)script/i,
+	rscriptTypeMasked = /^true\/(.*)/,
+	rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,
+
+	// We have to close these tags to support XHTML (#13200)
+	wrapMap = {
+		option: [ 1, "<select multiple='multiple'>", "</select>" ],
+		legend: [ 1, "<fieldset>", "</fieldset>" ],
+		area: [ 1, "<map>", "</map>" ],
+		param: [ 1, "<object>", "</object>" ],
+		thead: [ 1, "<table>", "</table>" ],
+		tr: [ 2, "<table><tbody>", "</tbody></table>" ],
+		col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
+		td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
+
+		// IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags,
+		// unless wrapped in a div with non-breaking characters in front of it.
+		_default: support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X<div>", "</div>"  ]
+	},
+	safeFragment = createSafeFragment( document ),
+	fragmentDiv = safeFragment.appendChild( document.createElement("div") );
+
+wrapMap.optgroup = wrapMap.option;
+wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
+wrapMap.th = wrapMap.td;
+
+function getAll( context, tag ) {
+	var elems, elem,
+		i = 0,
+		found = typeof context.getElementsByTagName !== strundefined ? context.getElementsByTagName( tag || "*" ) :
+			typeof context.querySelectorAll !== strundefined ? context.querySelectorAll( tag || "*" ) :
+			undefined;
+
+	if ( !found ) {
+		for ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) {
+			if ( !tag || jQuery.nodeName( elem, tag ) ) {
+				found.push( elem );
+			} else {
+				jQuery.merge( found, getAll( elem, tag ) );
+			}
+		}
+	}
+
+	return tag === undefined || tag && jQuery.nodeName( context, tag ) ?
+		jQuery.merge( [ context ], found ) :
+		found;
+}
+
+// Used in buildFragment, fixes the defaultChecked property
+function fixDefaultChecked( elem ) {
+	if ( rcheckableType.test( elem.type ) ) {
+		elem.defaultChecked = elem.checked;
+	}
+}
+
+// Support: IE<8
+// Manipulating tables requires a tbody
+function manipulationTarget( elem, content ) {
+	return jQuery.nodeName( elem, "table" ) &&
+		jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ?
+
+		elem.getElementsByTagName("tbody")[0] ||
+			elem.appendChild( elem.ownerDocument.createElement("tbody") ) :
+		elem;
+}
+
+// Replace/restore the type attribute of script elements for safe DOM manipulation
+function disableScript( elem ) {
+	elem.type = (jQuery.find.attr( elem, "type" ) !== null) + "/" + elem.type;
+	return elem;
+}
+function restoreScript( elem ) {
+	var match = rscriptTypeMasked.exec( elem.type );
+	if ( match ) {
+		elem.type = match[1];
+	} else {
+		elem.removeAttribute("type");
+	}
+	return elem;
+}
+
+// Mark scripts as having already been evaluated
+function setGlobalEval( elems, refElements ) {
+	var elem,
+		i = 0;
+	for ( ; (elem = elems[i]) != null; i++ ) {
+		jQuery._data( elem, "globalEval", !refElements || jQuery._data( refElements[i], "globalEval" ) );
+	}
+}
+
+function cloneCopyEvent( src, dest ) {
+
+	if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
+		return;
+	}
+
+	var type, i, l,
+		oldData = jQuery._data( src ),
+		curData = jQuery._data( dest, oldData ),
+		events = oldData.events;
+
+	if ( events ) {
+		delete curData.handle;
+		curData.events = {};
+
+		for ( type in events ) {
+			for ( i = 0, l = events[ type ].length; i < l; i++ ) {
+				jQuery.event.add( dest, type, events[ type ][ i ] );
+			}
+		}
+	}
+
+	// make the cloned public data object a copy from the original
+	if ( curData.data ) {
+		curData.data = jQuery.extend( {}, curData.data );
+	}
+}
+
+function fixCloneNodeIssues( src, dest ) {
+	var nodeName, e, data;
+
+	// We do not need to do anything for non-Elements
+	if ( dest.nodeType !== 1 ) {
+		return;
+	}
+
+	nodeName = dest.nodeName.toLowerCase();
+
+	// IE6-8 copies events bound via attachEvent when using cloneNode.
+	if ( !support.noCloneEvent && dest[ jQuery.expando ] ) {
+		data = jQuery._data( dest );
+
+		for ( e in data.events ) {
+			jQuery.removeEvent( dest, e, data.handle );
+		}
+
+		// Event data gets referenced instead of copied if the expando gets copied too
+		dest.removeAttribute( jQuery.expando );
+	}
+
+	// IE blanks contents when cloning scripts, and tries to evaluate newly-set text
+	if ( nodeName === "script" && dest.text !== src.text ) {
+		disableScript( dest ).text = src.text;
+		restoreScript( dest );
+
+	// IE6-10 improperly clones children of object elements using classid.
+	// IE10 throws NoModificationAllowedError if parent is null, #12132.
+	} else if ( nodeName === "object" ) {
+		if ( dest.parentNode ) {
+			dest.outerHTML = src.outerHTML;
+		}
+
+		// This path appears unavoidable for IE9. When cloning an object
+		// element in IE9, the outerHTML strategy above is not sufficient.
+		// If the src has innerHTML and the destination does not,
+		// copy the src.innerHTML into the dest.innerHTML. #10324
+		if ( support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) {
+			dest.innerHTML = src.innerHTML;
+		}
+
+	} else if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
+		// IE6-8 fails to persist the checked state of a cloned checkbox
+		// or radio button. Worse, IE6-7 fail to give the cloned element
+		// a checked appearance if the defaultChecked value isn't also set
+
+		dest.defaultChecked = dest.checked = src.checked;
+
+		// IE6-7 get confused and end up setting the value of a cloned
+		// checkbox/radio button to an empty string instead of "on"
+		if ( dest.value !== src.value ) {
+			dest.value = src.value;
+		}
+
+	// IE6-8 fails to return the selected option to the default selected
+	// state when cloning options
+	} else if ( nodeName === "option" ) {
+		dest.defaultSelected = dest.selected = src.defaultSelected;
+
+	// IE6-8 fails to set the defaultValue to the correct value when
+	// cloning other types of input fields
+	} else if ( nodeName === "input" || nodeName === "textarea" ) {
+		dest.defaultValue = src.defaultValue;
+	}
+}
+
+jQuery.extend({
+	clone: function( elem, dataAndEvents, deepDataAndEvents ) {
+		var destElements, node, clone, i, srcElements,
+			inPage = jQuery.contains( elem.ownerDocument, elem );
+
+		if ( support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) {
+			clone = elem.cloneNode( true );
+
+		// IE<=8 does not properly clone detached, unknown element nodes
+		} else {
+			fragmentDiv.innerHTML = elem.outerHTML;
+			fragmentDiv.removeChild( clone = fragmentDiv.firstChild );
+		}
+
+		if ( (!support.noCloneEvent || !support.noCloneChecked) &&
+				(elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
+
+			// We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2
+			destElements = getAll( clone );
+			srcElements = getAll( elem );
+
+			// Fix all IE cloning issues
+			for ( i = 0; (node = srcElements[i]) != null; ++i ) {
+				// Ensure that the destination node is not null; Fixes #9587
+				if ( destElements[i] ) {
+					fixCloneNodeIssues( node, destElements[i] );
+				}
+			}
+		}
+
+		// Copy the events from the original to the clone
+		if ( dataAndEvents ) {
+			if ( deepDataAndEvents ) {
+				srcElements = srcElements || getAll( elem );
+				destElements = destElements || getAll( clone );
+
+				for ( i = 0; (node = srcElements[i]) != null; i++ ) {
+					cloneCopyEvent( node, destElements[i] );
+				}
+			} else {
+				cloneCopyEvent( elem, clone );
+			}
+		}
+
+		// Preserve script evaluation history
+		destElements = getAll( clone, "script" );
+		if ( destElements.length > 0 ) {
+			setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
+		}
+
+		destElements = srcElements = node = null;
+
+		// Return the cloned set
+		return clone;
+	},
+
+	buildFragment: function( elems, context, scripts, selection ) {
+		var j, elem, contains,
+			tmp, tag, tbody, wrap,
+			l = elems.length,
+
+			// Ensure a safe fragment
+			safe = createSafeFragment( context ),
+
+			nodes = [],
+			i = 0;
+
+		for ( ; i < l; i++ ) {
+			elem = elems[ i ];
+
+			if ( elem || elem === 0 ) {
+
+				// Add nodes directly
+				if ( jQuery.type( elem ) === "object" ) {
+					jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
+
+				// Convert non-html into a text node
+				} else if ( !rhtml.test( elem ) ) {
+					nodes.push( context.createTextNode( elem ) );
+
+				// Convert html into DOM nodes
+				} else {
+					tmp = tmp || safe.appendChild( context.createElement("div") );
+
+					// Deserialize a standard representation
+					tag = (rtagName.exec( elem ) || [ "", "" ])[ 1 ].toLowerCase();
+					wrap = wrapMap[ tag ] || wrapMap._default;
+
+					tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1></$2>" ) + wrap[2];
+
+					// Descend through wrappers to the right content
+					j = wrap[0];
+					while ( j-- ) {
+						tmp = tmp.lastChild;
+					}
+
+					// Manually add leading whitespace removed by IE
+					if ( !support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
+						nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) );
+					}
+
+					// Remove IE's autoinserted <tbody> from table fragments
+					if ( !support.tbody ) {
+
+						// String was a <table>, *may* have spurious <tbody>
+						elem = tag === "table" && !rtbody.test( elem ) ?
+							tmp.firstChild :
+
+							// String was a bare <thead> or <tfoot>
+							wrap[1] === "<table>" && !rtbody.test( elem ) ?
+								tmp :
+								0;
+
+						j = elem && elem.childNodes.length;
+						while ( j-- ) {
+							if ( jQuery.nodeName( (tbody = elem.childNodes[j]), "tbody" ) && !tbody.childNodes.length ) {
+								elem.removeChild( tbody );
+							}
+						}
+					}
+
+					jQuery.merge( nodes, tmp.childNodes );
+
+					// Fix #12392 for WebKit and IE > 9
+					tmp.textContent = "";
+
+					// Fix #12392 for oldIE
+					while ( tmp.firstChild ) {
+						tmp.removeChild( tmp.firstChild );
+					}
+
+					// Remember the top-level container for proper cleanup
+					tmp = safe.lastChild;
+				}
+			}
+		}
+
+		// Fix #11356: Clear elements from fragment
+		if ( tmp ) {
+			safe.removeChild( tmp );
+		}
+
+		// Reset defaultChecked for any radios and checkboxes
+		// about to be appended to the DOM in IE 6/7 (#8060)
+		if ( !support.appendChecked ) {
+			jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked );
+		}
+
+		i = 0;
+		while ( (elem = nodes[ i++ ]) ) {
+
+			// #4087 - If origin and destination elements are the same, and this is
+			// that element, do not do anything
+			if ( selection && jQuery.inArray( elem, selection ) !== -1 ) {
+				continue;
+			}
+
+			contains = jQuery.contains( elem.ownerDocument, elem );
+
+			// Append to fragment
+			tmp = getAll( safe.appendChild( elem ), "script" );
+
+			// Preserve script evaluation history
+			if ( contains ) {
+				setGlobalEval( tmp );
+			}
+
+			// Capture executables
+			if ( scripts ) {
+				j = 0;
+				while ( (elem = tmp[ j++ ]) ) {
+					if ( rscriptType.test( elem.type || "" ) ) {
+						scripts.push( elem );
+					}
+				}
+			}
+		}
+
+		tmp = null;
+
+		return safe;
+	},
+
+	cleanData: function( elems, /* internal */ acceptData ) {
+		var elem, type, id, data,
+			i = 0,
+			internalKey = jQuery.expando,
+			cache = jQuery.cache,
+			deleteExpando = support.deleteExpando,
+			special = jQuery.event.special;
+
+		for ( ; (elem = elems[i]) != null; i++ ) {
+			if ( acceptData || jQuery.acceptData( elem ) ) {
+
+				id = elem[ internalKey ];
+				data = id && cache[ id ];
+
+				if ( data ) {
+					if ( data.events ) {
+						for ( type in data.events ) {
+							if ( special[ type ] ) {
+								jQuery.event.remove( elem, type );
+
+							// This is a shortcut to avoid jQuery.event.remove's overhead
+							} else {
+								jQuery.removeEvent( elem, type, data.handle );
+							}
+						}
+					}
+
+					// Remove cache only if it was not already removed by jQuery.event.remove
+					if ( cache[ id ] ) {
+
+						delete cache[ id ];
+
+						// IE does not allow us to delete expando properties from nodes,
+						// nor does it have a removeAttribute function on Document nodes;
+						// we must handle all of these cases
+						if ( deleteExpando ) {
+							delete elem[ internalKey ];
+
+						} else if ( typeof elem.removeAttribute !== strundefined ) {
+							elem.removeAttribute( internalKey );
+
+						} else {
+							elem[ internalKey ] = null;
+						}
+
+						deletedIds.push( id );
+					}
+				}
+			}
+		}
+	}
+});
+
+jQuery.fn.extend({
+	text: function( value ) {
+		return access( this, function( value ) {
+			return value === undefined ?
+				jQuery.text( this ) :
+				this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );
+		}, null, value, arguments.length );
+	},
+
+	append: function() {
+		return this.domManip( arguments, function( elem ) {
+			if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+				var target = manipulationTarget( this, elem );
+				target.appendChild( elem );
+			}
+		});
+	},
+
+	prepend: function() {
+		return this.domManip( arguments, function( elem ) {
+			if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+				var target = manipulationTarget( this, elem );
+				target.insertBefore( elem, target.firstChild );
+			}
+		});
+	},
+
+	before: function() {
+		return this.domManip( arguments, function( elem ) {
+			if ( this.parentNode ) {
+				this.parentNode.insertBefore( elem, this );
+			}
+		});
+	},
+
+	after: function() {
+		return this.domManip( arguments, function( elem ) {
+			if ( this.parentNode ) {
+				this.parentNode.insertBefore( elem, this.nextSibling );
+			}
+		});
+	},
+
+	remove: function( selector, keepData /* Internal Use Only */ ) {
+		var elem,
+			elems = selector ? jQuery.filter( selector, this ) : this,
+			i = 0;
+
+		for ( ; (elem = elems[i]) != null; i++ ) {
+
+			if ( !keepData && elem.nodeType === 1 ) {
+				jQuery.cleanData( getAll( elem ) );
+			}
+
+			if ( elem.parentNode ) {
+				if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) {
+					setGlobalEval( getAll( elem, "script" ) );
+				}
+				elem.parentNode.removeChild( elem );
+			}
+		}
+
+		return this;
+	},
+
+	empty: function() {
+		var elem,
+			i = 0;
+
+		for ( ; (elem = this[i]) != null; i++ ) {
+			// Remove element nodes and prevent memory leaks
+			if ( elem.nodeType === 1 ) {
+				jQuery.cleanData( getAll( elem, false ) );
+			}
+
+			// Remove any remaining nodes
+			while ( elem.firstChild ) {
+				elem.removeChild( elem.firstChild );
+			}
+
+			// If this is a select, ensure that it displays empty (#12336)
+			// Support: IE<9
+			if ( elem.options && jQuery.nodeName( elem, "select" ) ) {
+				elem.options.length = 0;
+			}
+		}
+
+		return this;
+	},
+
+	clone: function( dataAndEvents, deepDataAndEvents ) {
+		dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
+		deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
+
+		return this.map(function() {
+			return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
+		});
+	},
+
+	html: function( value ) {
+		return access( this, function( value ) {
+			var elem = this[ 0 ] || {},
+				i = 0,
+				l = this.length;
+
+			if ( value === undefined ) {
+				return elem.nodeType === 1 ?
+					elem.innerHTML.replace( rinlinejQuery, "" ) :
+					undefined;
+			}
+
+			// See if we can take a shortcut and just use innerHTML
+			if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
+				( support.htmlSerialize || !rnoshimcache.test( value )  ) &&
+				( support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
+				!wrapMap[ (rtagName.exec( value ) || [ "", "" ])[ 1 ].toLowerCase() ] ) {
+
+				value = value.replace( rxhtmlTag, "<$1></$2>" );
+
+				try {
+					for (; i < l; i++ ) {
+						// Remove element nodes and prevent memory leaks
+						elem = this[i] || {};
+						if ( elem.nodeType === 1 ) {
+							jQuery.cleanData( getAll( elem, false ) );
+							elem.innerHTML = value;
+						}
+					}
+
+					elem = 0;
+
+				// If using innerHTML throws an exception, use the fallback method
+				} catch(e) {}
+			}
+
+			if ( elem ) {
+				this.empty().append( value );
+			}
+		}, null, value, arguments.length );
+	},
+
+	replaceWith: function() {
+		var arg = arguments[ 0 ];
+
+		// Make the changes, replacing each context element with the new content
+		this.domManip( arguments, function( elem ) {
+			arg = this.parentNode;
+
+			jQuery.cleanData( getAll( this ) );
+
+			if ( arg ) {
+				arg.replaceChild( elem, this );
+			}
+		});
+
+		// Force removal if there was no new content (e.g., from empty arguments)
+		return arg && (arg.length || arg.nodeType) ? this : this.remove();
+	},
+
+	detach: function( selector ) {
+		return this.remove( selector, true );
+	},
+
+	domManip: function( args, callback ) {
+
+		// Flatten any nested arrays
+		args = concat.apply( [], args );
+
+		var first, node, hasScripts,
+			scripts, doc, fragment,
+			i = 0,
+			l = this.length,
+			set = this,
+			iNoClone = l - 1,
+			value = args[0],
+			isFunction = jQuery.isFunction( value );
+
+		// We can't cloneNode fragments that contain checked, in WebKit
+		if ( isFunction ||
+				( l > 1 && typeof value === "string" &&
+					!support.checkClone && rchecked.test( value ) ) ) {
+			return this.each(function( index ) {
+				var self = set.eq( index );
+				if ( isFunction ) {
+					args[0] = value.call( this, index, self.html() );
+				}
+				self.domManip( args, callback );
+			});
+		}
+
+		if ( l ) {
+			fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this );
+			first = fragment.firstChild;
+
+			if ( fragment.childNodes.length === 1 ) {
+				fragment = first;
+			}
+
+			if ( first ) {
+				scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
+				hasScripts = scripts.length;
+
+				// Use the original fragment for the last item instead of the first because it can end up
+				// being emptied incorrectly in certain situations (#8070).
+				for ( ; i < l; i++ ) {
+					node = fragment;
+
+					if ( i !== iNoClone ) {
+						node = jQuery.clone( node, true, true );
+
+						// Keep references to cloned scripts for later restoration
+						if ( hasScripts ) {
+							jQuery.merge( scripts, getAll( node, "script" ) );
+						}
+					}
+
+					callback.call( this[i], node, i );
+				}
+
+				if ( hasScripts ) {
+					doc = scripts[ scripts.length - 1 ].ownerDocument;
+
+					// Reenable scripts
+					jQuery.map( scripts, restoreScript );
+
+					// Evaluate executable scripts on first document insertion
+					for ( i = 0; i < hasScripts; i++ ) {
+						node = scripts[ i ];
+						if ( rscriptType.test( node.type || "" ) &&
+							!jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) {
+
+							if ( node.src ) {
+								// Optional AJAX dependency, but won't run scripts if not present
+								if ( jQuery._evalUrl ) {
+									jQuery._evalUrl( node.src );
+								}
+							} else {
+								jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) );
+							}
+						}
+					}
+				}
+
+				// Fix #11809: Avoid leaking memory
+				fragment = first = null;
+			}
+		}
+
+		return this;
+	}
+});
+
+jQuery.each({
+	appendTo: "append",
+	prependTo: "prepend",
+	insertBefore: "before",
+	insertAfter: "after",
+	replaceAll: "replaceWith"
+}, function( name, original ) {
+	jQuery.fn[ name ] = function( selector ) {
+		var elems,
+			i = 0,
+			ret = [],
+			insert = jQuery( selector ),
+			last = insert.length - 1;
+
+		for ( ; i <= last; i++ ) {
+			elems = i === last ? this : this.clone(true);
+			jQuery( insert[i] )[ original ]( elems );
+
+			// Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get()
+			push.apply( ret, elems.get() );
+		}
+
+		return this.pushStack( ret );
+	};
+});
+
+
+var iframe,
+	elemdisplay = {};
+
+/**
+ * Retrieve the actual display of a element
+ * @param {String} name nodeName of the element
+ * @param {Object} doc Document object
+ */
+// Called only from within defaultDisplay
+function actualDisplay( name, doc ) {
+	var style,
+		elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
+
+		// getDefaultComputedStyle might be reliably used only on attached element
+		display = window.getDefaultComputedStyle && ( style = window.getDefaultComputedStyle( elem[ 0 ] ) ) ?
+
+			// Use of this method is a temporary fix (more like optmization) until something better comes along,
+			// since it was removed from specification and supported only in FF
+			style.display : jQuery.css( elem[ 0 ], "display" );
+
+	// We don't have any data stored on the element,
+	// so use "detach" method as fast way to get rid of the element
+	elem.detach();
+
+	return display;
+}
+
+/**
+ * Try to determine the default display value of an element
+ * @param {String} nodeName
+ */
+function defaultDisplay( nodeName ) {
+	var doc = document,
+		display = elemdisplay[ nodeName ];
+
+	if ( !display ) {
+		display = actualDisplay( nodeName, doc );
+
+		// If the simple way fails, read from inside an iframe
+		if ( display === "none" || !display ) {
+
+			// Use the already-created iframe if possible
+			iframe = (iframe || jQuery( "<iframe frameborder='0' width='0' height='0'/>" )).appendTo( doc.documentElement );
+
+			// Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse
+			doc = ( iframe[ 0 ].contentWindow || iframe[ 0 ].contentDocument ).document;
+
+			// Support: IE
+			doc.write();
+			doc.close();
+
+			display = actualDisplay( nodeName, doc );
+			iframe.detach();
+		}
+
+		// Store the correct default display
+		elemdisplay[ nodeName ] = display;
+	}
+
+	return display;
+}
+
+
+(function() {
+	var shrinkWrapBlocksVal;
+
+	support.shrinkWrapBlocks = function() {
+		if ( shrinkWrapBlocksVal != null ) {
+			return shrinkWrapBlocksVal;
+		}
+
+		// Will be changed later if needed.
+		shrinkWrapBlocksVal = false;
+
+		// Minified: var b,c,d
+		var div, body, container;
+
+		body = document.getElementsByTagName( "body" )[ 0 ];
+		if ( !body || !body.style ) {
+			// Test fired too early or in an unsupported environment, exit.
+			return;
+		}
+
+		// Setup
+		div = document.createElement( "div" );
+		container = document.createElement( "div" );
+		container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px";
+		body.appendChild( container ).appendChild( div );
+
+		// Support: IE6
+		// Check if elements with layout shrink-wrap their children
+		if ( typeof div.style.zoom !== strundefined ) {
+			// Reset CSS: box-sizing; display; margin; border
+			div.style.cssText =
+				// Support: Firefox<29, Android 2.3
+				// Vendor-prefix box-sizing
+				"-webkit-box-sizing:content-box;-moz-box-sizing:content-box;" +
+				"box-sizing:content-box;display:block;margin:0;border:0;" +
+				"padding:1px;width:1px;zoom:1";
+			div.appendChild( document.createElement( "div" ) ).style.width = "5px";
+			shrinkWrapBlocksVal = div.offsetWidth !== 3;
+		}
+
+		body.removeChild( container );
+
+		return shrinkWrapBlocksVal;
+	};
+
+})();
+var rmargin = (/^margin/);
+
+var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" );
+
+
+
+var getStyles, curCSS,
+	rposition = /^(top|right|bottom|left)$/;
+
+if ( window.getComputedStyle ) {
+	getStyles = function( elem ) {
+		// Support: IE<=11+, Firefox<=30+ (#15098, #14150)
+		// IE throws on elements created in popups
+		// FF meanwhile throws on frame elements through "defaultView.getComputedStyle"
+		if ( elem.ownerDocument.defaultView.opener ) {
+			return elem.ownerDocument.defaultView.getComputedStyle( elem, null );
+		}
+
+		return window.getComputedStyle( elem, null );
+	};
+
+	curCSS = function( elem, name, computed ) {
+		var width, minWidth, maxWidth, ret,
+			style = elem.style;
+
+		computed = computed || getStyles( elem );
+
+		// getPropertyValue is only needed for .css('filter') in IE9, see #12537
+		ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined;
+
+		if ( computed ) {
+
+			if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
+				ret = jQuery.style( elem, name );
+			}
+
+			// A tribute to the "awesome hack by Dean Edwards"
+			// Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right
+			// Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
+			// this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
+			if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
+
+				// Remember the original values
+				width = style.width;
+				minWidth = style.minWidth;
+				maxWidth = style.maxWidth;
+
+				// Put in the new values to get a computed value out
+				style.minWidth = style.maxWidth = style.width = ret;
+				ret = computed.width;
+
+				// Revert the changed values
+				style.width = width;
+				style.minWidth = minWidth;
+				style.maxWidth = maxWidth;
+			}
+		}
+
+		// Support: IE
+		// IE returns zIndex value as an integer.
+		return ret === undefined ?
+			ret :
+			ret + "";
+	};
+} else if ( document.documentElement.currentStyle ) {
+	getStyles = function( elem ) {
+		return elem.currentStyle;
+	};
+
+	curCSS = function( elem, name, computed ) {
+		var left, rs, rsLeft, ret,
+			style = elem.style;
+
+		computed = computed || getStyles( elem );
+		ret = computed ? computed[ name ] : undefined;
+
+		// Avoid setting ret to empty string here
+		// so we don't default to auto
+		if ( ret == null && style && style[ name ] ) {
+			ret = style[ name ];
+		}
+
+		// From the awesome hack by Dean Edwards
+		// http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
+
+		// If we're not dealing with a regular pixel number
+		// but a number that has a weird ending, we need to convert it to pixels
+		// but not position css attributes, as those are proportional to the parent element instead
+		// and we can't measure the parent instead because it might trigger a "stacking dolls" problem
+		if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) {
+
+			// Remember the original values
+			left = style.left;
+			rs = elem.runtimeStyle;
+			rsLeft = rs && rs.left;
+
+			// Put in the new values to get a computed value out
+			if ( rsLeft ) {
+				rs.left = elem.currentStyle.left;
+			}
+			style.left = name === "fontSize" ? "1em" : ret;
+			ret = style.pixelLeft + "px";
+
+			// Revert the changed values
+			style.left = left;
+			if ( rsLeft ) {
+				rs.left = rsLeft;
+			}
+		}
+
+		// Support: IE
+		// IE returns zIndex value as an integer.
+		return ret === undefined ?
+			ret :
+			ret + "" || "auto";
+	};
+}
+
+
+
+
+function addGetHookIf( conditionFn, hookFn ) {
+	// Define the hook, we'll check on the first run if it's really needed.
+	return {
+		get: function() {
+			var condition = conditionFn();
+
+			if ( condition == null ) {
+				// The test was not ready at this point; screw the hook this time
+				// but check again when needed next time.
+				return;
+			}
+
+			if ( condition ) {
+				// Hook not needed (or it's not possible to use it due to missing dependency),
+				// remove it.
+				// Since there are no other hooks for marginRight, remove the whole object.
+				delete this.get;
+				return;
+			}
+
+			// Hook needed; redefine it so that the support test is not executed again.
+
+			return (this.get = hookFn).apply( this, arguments );
+		}
+	};
+}
+
+
+(function() {
+	// Minified: var b,c,d,e,f,g, h,i
+	var div, style, a, pixelPositionVal, boxSizingReliableVal,
+		reliableHiddenOffsetsVal, reliableMarginRightVal;
+
+	// Setup
+	div = document.createElement( "div" );
+	div.innerHTML = "  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
+	a = div.getElementsByTagName( "a" )[ 0 ];
+	style = a && a.style;
+
+	// Finish early in limited (non-browser) environments
+	if ( !style ) {
+		return;
+	}
+
+	style.cssText = "float:left;opacity:.5";
+
+	// Support: IE<9
+	// Make sure that element opacity exists (as opposed to filter)
+	support.opacity = style.opacity === "0.5";
+
+	// Verify style float existence
+	// (IE uses styleFloat instead of cssFloat)
+	support.cssFloat = !!style.cssFloat;
+
+	div.style.backgroundClip = "content-box";
+	div.cloneNode( true ).style.backgroundClip = "";
+	support.clearCloneStyle = div.style.backgroundClip === "content-box";
+
+	// Support: Firefox<29, Android 2.3
+	// Vendor-prefix box-sizing
+	support.boxSizing = style.boxSizing === "" || style.MozBoxSizing === "" ||
+		style.WebkitBoxSizing === "";
+
+	jQuery.extend(support, {
+		reliableHiddenOffsets: function() {
+			if ( reliableHiddenOffsetsVal == null ) {
+				computeStyleTests();
+			}
+			return reliableHiddenOffsetsVal;
+		},
+
+		boxSizingReliable: function() {
+			if ( boxSizingReliableVal == null ) {
+				computeStyleTests();
+			}
+			return boxSizingReliableVal;
+		},
+
+		pixelPosition: function() {
+			if ( pixelPositionVal == null ) {
+				computeStyleTests();
+			}
+			return pixelPositionVal;
+		},
+
+		// Support: Android 2.3
+		reliableMarginRight: function() {
+			if ( reliableMarginRightVal == null ) {
+				computeStyleTests();
+			}
+			return reliableMarginRightVal;
+		}
+	});
+
+	function computeStyleTests() {
+		// Minified: var b,c,d,j
+		var div, body, container, contents;
+
+		body = document.getElementsByTagName( "body" )[ 0 ];
+		if ( !body || !body.style ) {
+			// Test fired too early or in an unsupported environment, exit.
+			return;
+		}
+
+		// Setup
+		div = document.createElement( "div" );
+		container = document.createElement( "div" );
+		container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px";
+		body.appendChild( container ).appendChild( div );
+
+		div.style.cssText =
+			// Support: Firefox<29, Android 2.3
+			// Vendor-prefix box-sizing
+			"-webkit-box-sizing:border-box;-moz-box-sizing:border-box;" +
+			"box-sizing:border-box;display:block;margin-top:1%;top:1%;" +
+			"border:1px;padding:1px;width:4px;position:absolute";
+
+		// Support: IE<9
+		// Assume reasonable values in the absence of getComputedStyle
+		pixelPositionVal = boxSizingReliableVal = false;
+		reliableMarginRightVal = true;
+
+		// Check for getComputedStyle so that this code is not run in IE<9.
+		if ( window.getComputedStyle ) {
+			pixelPositionVal = ( window.getComputedStyle( div, null ) || {} ).top !== "1%";
+			boxSizingReliableVal =
+				( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px";
+
+			// Support: Android 2.3
+			// Div with explicit width and no margin-right incorrectly
+			// gets computed margin-right based on width of container (#3333)
+			// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+			contents = div.appendChild( document.createElement( "div" ) );
+
+			// Reset CSS: box-sizing; display; margin; border; padding
+			contents.style.cssText = div.style.cssText =
+				// Support: Firefox<29, Android 2.3
+				// Vendor-prefix box-sizing
+				"-webkit-box-sizing:content-box;-moz-box-sizing:content-box;" +
+				"box-sizing:content-box;display:block;margin:0;border:0;padding:0";
+			contents.style.marginRight = contents.style.width = "0";
+			div.style.width = "1px";
+
+			reliableMarginRightVal =
+				!parseFloat( ( window.getComputedStyle( contents, null ) || {} ).marginRight );
+
+			div.removeChild( contents );
+		}
+
+		// Support: IE8
+		// Check if table cells still have offsetWidth/Height when they are set
+		// to display:none and there are still other visible table cells in a
+		// table row; if so, offsetWidth/Height are not reliable for use when
+		// determining if an element has been hidden directly using
+		// display:none (it is still safe to use offsets if a parent element is
+		// hidden; don safety goggles and see bug #4512 for more information).
+		div.innerHTML = "<table><tr><td></td><td>t</td></tr></table>";
+		contents = div.getElementsByTagName( "td" );
+		contents[ 0 ].style.cssText = "margin:0;border:0;padding:0;display:none";
+		reliableHiddenOffsetsVal = contents[ 0 ].offsetHeight === 0;
+		if ( reliableHiddenOffsetsVal ) {
+			contents[ 0 ].style.display = "";
+			contents[ 1 ].style.display = "none";
+			reliableHiddenOffsetsVal = contents[ 0 ].offsetHeight === 0;
+		}
+
+		body.removeChild( container );
+	}
+
+})();
+
+
+// A method for quickly swapping in/out CSS properties to get correct calculations.
+jQuery.swap = function( elem, options, callback, args ) {
+	var ret, name,
+		old = {};
+
+	// Remember the old values, and insert the new ones
+	for ( name in options ) {
+		old[ name ] = elem.style[ name ];
+		elem.style[ name ] = options[ name ];
+	}
+
+	ret = callback.apply( elem, args || [] );
+
+	// Revert the old values
+	for ( name in options ) {
+		elem.style[ name ] = old[ name ];
+	}
+
+	return ret;
+};
+
+
+var
+		ralpha = /alpha\([^)]*\)/i,
+	ropacity = /opacity\s*=\s*([^)]*)/,
+
+	// swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
+	// see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
+	rdisplayswap = /^(none|table(?!-c[ea]).+)/,
+	rnumsplit = new RegExp( "^(" + pnum + ")(.*)$", "i" ),
+	rrelNum = new RegExp( "^([+-])=(" + pnum + ")", "i" ),
+
+	cssShow = { position: "absolute", visibility: "hidden", display: "block" },
+	cssNormalTransform = {
+		letterSpacing: "0",
+		fontWeight: "400"
+	},
+
+	cssPrefixes = [ "Webkit", "O", "Moz", "ms" ];
+
+
+// return a css property mapped to a potentially vendor prefixed property
+function vendorPropName( style, name ) {
+
+	// shortcut for names that are not vendor prefixed
+	if ( name in style ) {
+		return name;
+	}
+
+	// check for vendor prefixed names
+	var capName = name.charAt(0).toUpperCase() + name.slice(1),
+		origName = name,
+		i = cssPrefixes.length;
+
+	while ( i-- ) {
+		name = cssPrefixes[ i ] + capName;
+		if ( name in style ) {
+			return name;
+		}
+	}
+
+	return origName;
+}
+
+function showHide( elements, show ) {
+	var display, elem, hidden,
+		values = [],
+		index = 0,
+		length = elements.length;
+
+	for ( ; index < length; index++ ) {
+		elem = elements[ index ];
+		if ( !elem.style ) {
+			continue;
+		}
+
+		values[ index ] = jQuery._data( elem, "olddisplay" );
+		display = elem.style.display;
+		if ( show ) {
+			// Reset the inline display of this element to learn if it is
+			// being hidden by cascaded rules or not
+			if ( !values[ index ] && display === "none" ) {
+				elem.style.display = "";
+			}
+
+			// Set elements which have been overridden with display: none
+			// in a stylesheet to whatever the default browser style is
+			// for such an element
+			if ( elem.style.display === "" && isHidden( elem ) ) {
+				values[ index ] = jQuery._data( elem, "olddisplay", defaultDisplay(elem.nodeName) );
+			}
+		} else {
+			hidden = isHidden( elem );
+
+			if ( display && display !== "none" || !hidden ) {
+				jQuery._data( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) );
+			}
+		}
+	}
+
+	// Set the display of most of the elements in a second loop
+	// to avoid the constant reflow
+	for ( index = 0; index < length; index++ ) {
+		elem = elements[ index ];
+		if ( !elem.style ) {
+			continue;
+		}
+		if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
+			elem.style.display = show ? values[ index ] || "" : "none";
+		}
+	}
+
+	return elements;
+}
+
+function setPositiveNumber( elem, value, subtract ) {
+	var matches = rnumsplit.exec( value );
+	return matches ?
+		// Guard against undefined "subtract", e.g., when used as in cssHooks
+		Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
+		value;
+}
+
+function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
+	var i = extra === ( isBorderBox ? "border" : "content" ) ?
+		// If we already have the right measurement, avoid augmentation
+		4 :
+		// Otherwise initialize for horizontal or vertical properties
+		name === "width" ? 1 : 0,
+
+		val = 0;
+
+	for ( ; i < 4; i += 2 ) {
+		// both box models exclude margin, so add it if we want it
+		if ( extra === "margin" ) {
+			val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
+		}
+
+		if ( isBorderBox ) {
+			// border-box includes padding, so remove it if we want content
+			if ( extra === "content" ) {
+				val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
+			}
+
+			// at this point, extra isn't border nor margin, so remove border
+			if ( extra !== "margin" ) {
+				val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+			}
+		} else {
+			// at this point, extra isn't content, so add padding
+			val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
+
+			// at this point, extra isn't content nor padding, so add border
+			if ( extra !== "padding" ) {
+				val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+			}
+		}
+	}
+
+	return val;
+}
+
+function getWidthOrHeight( elem, name, extra ) {
+
+	// Start with offset property, which is equivalent to the border-box value
+	var valueIsBorderBox = true,
+		val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
+		styles = getStyles( elem ),
+		isBorderBox = support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
+
+	// some non-html elements return undefined for offsetWidth, so check for null/undefined
+	// svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
+	// MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
+	if ( val <= 0 || val == null ) {
+		// Fall back to computed then uncomputed css if necessary
+		val = curCSS( elem, name, styles );
+		if ( val < 0 || val == null ) {
+			val = elem.style[ name ];
+		}
+
+		// Computed unit is not pixels. Stop here and return.
+		if ( rnumnonpx.test(val) ) {
+			return val;
+		}
+
+		// we need the check for style in case a browser which returns unreliable values
+		// for getComputedStyle silently falls back to the reliable elem.style
+		valueIsBorderBox = isBorderBox && ( support.boxSizingReliable() || val === elem.style[ name ] );
+
+		// Normalize "", auto, and prepare for extra
+		val = parseFloat( val ) || 0;
+	}
+
+	// use the active box-sizing model to add/subtract irrelevant styles
+	return ( val +
+		augmentWidthOrHeight(
+			elem,
+			name,
+			extra || ( isBorderBox ? "border" : "content" ),
+			valueIsBorderBox,
+			styles
+		)
+	) + "px";
+}
+
+jQuery.extend({
+	// Add in style property hooks for overriding the default
+	// behavior of getting and setting a style property
+	cssHooks: {
+		opacity: {
+			get: function( elem, computed ) {
+				if ( computed ) {
+					// We should always get a number back from opacity
+					var ret = curCSS( elem, "opacity" );
+					return ret === "" ? "1" : ret;
+				}
+			}
+		}
+	},
+
+	// Don't automatically add "px" to these possibly-unitless properties
+	cssNumber: {
+		"columnCount": true,
+		"fillOpacity": true,
+		"flexGrow": true,
+		"flexShrink": true,
+		"fontWeight": true,
+		"lineHeight": true,
+		"opacity": true,
+		"order": true,
+		"orphans": true,
+		"widows": true,
+		"zIndex": true,
+		"zoom": true
+	},
+
+	// Add in properties whose names you wish to fix before
+	// setting or getting the value
+	cssProps: {
+		// normalize float css property
+		"float": support.cssFloat ? "cssFloat" : "styleFloat"
+	},
+
+	// Get and set the style property on a DOM Node
+	style: function( elem, name, value, extra ) {
+		// Don't set styles on text and comment nodes
+		if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
+			return;
+		}
+
+		// Make sure that we're working with the right name
+		var ret, type, hooks,
+			origName = jQuery.camelCase( name ),
+			style = elem.style;
+
+		name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
+
+		// gets hook for the prefixed version
+		// followed by the unprefixed version
+		hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+		// Check if we're setting a value
+		if ( value !== undefined ) {
+			type = typeof value;
+
+			// convert relative number strings (+= or -=) to relative numbers. #7345
+			if ( type === "string" && (ret = rrelNum.exec( value )) ) {
+				value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
+				// Fixes bug #9237
+				type = "number";
+			}
+
+			// Make sure that null and NaN values aren't set. See: #7116
+			if ( value == null || value !== value ) {
+				return;
+			}
+
+			// If a number was passed in, add 'px' to the (except for certain CSS properties)
+			if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
+				value += "px";
+			}
+
+			// Fixes #8908, it can be done more correctly by specifing setters in cssHooks,
+			// but it would mean to define eight (for every problematic property) identical functions
+			if ( !support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) {
+				style[ name ] = "inherit";
+			}
+
+			// If a hook was provided, use that value, otherwise just set the specified value
+			if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
+
+				// Support: IE
+				// Swallow errors from 'invalid' CSS values (#5509)
+				try {
+					style[ name ] = value;
+				} catch(e) {}
+			}
+
+		} else {
+			// If a hook was provided get the non-computed value from there
+			if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
+				return ret;
+			}
+
+			// Otherwise just get the value from the style object
+			return style[ name ];
+		}
+	},
+
+	css: function( elem, name, extra, styles ) {
+		var num, val, hooks,
+			origName = jQuery.camelCase( name );
+
+		// Make sure that we're working with the right name
+		name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
+
+		// gets hook for the prefixed version
+		// followed by the unprefixed version
+		hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+		// If a hook was provided get the computed value from there
+		if ( hooks && "get" in hooks ) {
+			val = hooks.get( elem, true, extra );
+		}
+
+		// Otherwise, if a way to get the computed value exists, use that
+		if ( val === undefined ) {
+			val = curCSS( elem, name, styles );
+		}
+
+		//convert "normal" to computed value
+		if ( val === "normal" && name in cssNormalTransform ) {
+			val = cssNormalTransform[ name ];
+		}
+
+		// Return, converting to number if forced or a qualifier was provided and val looks numeric
+		if ( extra === "" || extra ) {
+			num = parseFloat( val );
+			return extra === true || jQuery.isNumeric( num ) ? num || 0 : val;
+		}
+		return val;
+	}
+});
+
+jQuery.each([ "height", "width" ], function( i, name ) {
+	jQuery.cssHooks[ name ] = {
+		get: function( elem, computed, extra ) {
+			if ( computed ) {
+				// certain elements can have dimension info if we invisibly show them
+				// however, it must have a current display style that would benefit from this
+				return rdisplayswap.test( jQuery.css( elem, "display" ) ) && elem.offsetWidth === 0 ?
+					jQuery.swap( elem, cssShow, function() {
+						return getWidthOrHeight( elem, name, extra );
+					}) :
+					getWidthOrHeight( elem, name, extra );
+			}
+		},
+
+		set: function( elem, value, extra ) {
+			var styles = extra && getStyles( elem );
+			return setPositiveNumber( elem, value, extra ?
+				augmentWidthOrHeight(
+					elem,
+					name,
+					extra,
+					support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
+					styles
+				) : 0
+			);
+		}
+	};
+});
+
+if ( !support.opacity ) {
+	jQuery.cssHooks.opacity = {
+		get: function( elem, computed ) {
+			// IE uses filters for opacity
+			return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
+				( 0.01 * parseFloat( RegExp.$1 ) ) + "" :
+				computed ? "1" : "";
+		},
+
+		set: function( elem, value ) {
+			var style = elem.style,
+				currentStyle = elem.currentStyle,
+				opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",
+				filter = currentStyle && currentStyle.filter || style.filter || "";
+
+			// IE has trouble with opacity if it does not have layout
+			// Force it by setting the zoom level
+			style.zoom = 1;
+
+			// if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652
+			// if value === "", then remove inline opacity #12685
+			if ( ( value >= 1 || value === "" ) &&
+					jQuery.trim( filter.replace( ralpha, "" ) ) === "" &&
+					style.removeAttribute ) {
+
+				// Setting style.filter to null, "" & " " still leave "filter:" in the cssText
+				// if "filter:" is present at all, clearType is disabled, we want to avoid this
+				// style.removeAttribute is IE Only, but so apparently is this code path...
+				style.removeAttribute( "filter" );
+
+				// if there is no filter style applied in a css rule or unset inline opacity, we are done
+				if ( value === "" || currentStyle && !currentStyle.filter ) {
+					return;
+				}
+			}
+
+			// otherwise, set new filter values
+			style.filter = ralpha.test( filter ) ?
+				filter.replace( ralpha, opacity ) :
+				filter + " " + opacity;
+		}
+	};
+}
+
+jQuery.cssHooks.marginRight = addGetHookIf( support.reliableMarginRight,
+	function( elem, computed ) {
+		if ( computed ) {
+			// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+			// Work around by temporarily setting element display to inline-block
+			return jQuery.swap( elem, { "display": "inline-block" },
+				curCSS, [ elem, "marginRight" ] );
+		}
+	}
+);
+
+// These hooks are used by animate to expand properties
+jQuery.each({
+	margin: "",
+	padding: "",
+	border: "Width"
+}, function( prefix, suffix ) {
+	jQuery.cssHooks[ prefix + suffix ] = {
+		expand: function( value ) {
+			var i = 0,
+				expanded = {},
+
+				// assumes a single number if not a string
+				parts = typeof value === "string" ? value.split(" ") : [ value ];
+
+			for ( ; i < 4; i++ ) {
+				expanded[ prefix + cssExpand[ i ] + suffix ] =
+					parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
+			}
+
+			return expanded;
+		}
+	};
+
+	if ( !rmargin.test( prefix ) ) {
+		jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
+	}
+});
+
+jQuery.fn.extend({
+	css: function( name, value ) {
+		return access( this, function( elem, name, value ) {
+			var styles, len,
+				map = {},
+				i = 0;
+
+			if ( jQuery.isArray( name ) ) {
+				styles = getStyles( elem );
+				len = name.length;
+
+				for ( ; i < len; i++ ) {
+					map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
+				}
+
+				return map;
+			}
+
+			return value !== undefined ?
+				jQuery.style( elem, name, value ) :
+				jQuery.css( elem, name );
+		}, name, value, arguments.length > 1 );
+	},
+	show: function() {
+		return showHide( this, true );
+	},
+	hide: function() {
+		return showHide( this );
+	},
+	toggle: function( state ) {
+		if ( typeof state === "boolean" ) {
+			return state ? this.show() : this.hide();
+		}
+
+		return this.each(function() {
+			if ( isHidden( this ) ) {
+				jQuery( this ).show();
+			} else {
+				jQuery( this ).hide();
+			}
+		});
+	}
+});
+
+
+function Tween( elem, options, prop, end, easing ) {
+	return new Tween.prototype.init( elem, options, prop, end, easing );
+}
+jQuery.Tween = Tween;
+
+Tween.prototype = {
+	constructor: Tween,
+	init: function( elem, options, prop, end, easing, unit ) {
+		this.elem = elem;
+		this.prop = prop;
+		this.easing = easing || "swing";
+		this.options = options;
+		this.start = this.now = this.cur();
+		this.end = end;
+		this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
+	},
+	cur: function() {
+		var hooks = Tween.propHooks[ this.prop ];
+
+		return hooks && hooks.get ?
+			hooks.get( this ) :
+			Tween.propHooks._default.get( this );
+	},
+	run: function( percent ) {
+		var eased,
+			hooks = Tween.propHooks[ this.prop ];
+
+		if ( this.options.duration ) {
+			this.pos = eased = jQuery.easing[ this.easing ](
+				percent, this.options.duration * percent, 0, 1, this.options.duration
+			);
+		} else {
+			this.pos = eased = percent;
+		}
+		this.now = ( this.end - this.start ) * eased + this.start;
+
+		if ( this.options.step ) {
+			this.options.step.call( this.elem, this.now, this );
+		}
+
+		if ( hooks && hooks.set ) {
+			hooks.set( this );
+		} else {
+			Tween.propHooks._default.set( this );
+		}
+		return this;
+	}
+};
+
+Tween.prototype.init.prototype = Tween.prototype;
+
+Tween.propHooks = {
+	_default: {
+		get: function( tween ) {
+			var result;
+
+			if ( tween.elem[ tween.prop ] != null &&
+				(!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {
+				return tween.elem[ tween.prop ];
+			}
+
+			// passing an empty string as a 3rd parameter to .css will automatically
+			// attempt a parseFloat and fallback to a string if the parse fails
+			// so, simple values such as "10px" are parsed to Float.
+			// complex values such as "rotate(1rad)" are returned as is.
+			result = jQuery.css( tween.elem, tween.prop, "" );
+			// Empty strings, null, undefined and "auto" are converted to 0.
+			return !result || result === "auto" ? 0 : result;
+		},
+		set: function( tween ) {
+			// use step hook for back compat - use cssHook if its there - use .style if its
+			// available and use plain properties where available
+			if ( jQuery.fx.step[ tween.prop ] ) {
+				jQuery.fx.step[ tween.prop ]( tween );
+			} else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {
+				jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
+			} else {
+				tween.elem[ tween.prop ] = tween.now;
+			}
+		}
+	}
+};
+
+// Support: IE <=9
+// Panic based approach to setting things on disconnected nodes
+
+Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
+	set: function( tween ) {
+		if ( tween.elem.nodeType && tween.elem.parentNode ) {
+			tween.elem[ tween.prop ] = tween.now;
+		}
+	}
+};
+
+jQuery.easing = {
+	linear: function( p ) {
+		return p;
+	},
+	swing: function( p ) {
+		return 0.5 - Math.cos( p * Math.PI ) / 2;
+	}
+};
+
+jQuery.fx = Tween.prototype.init;
+
+// Back Compat <1.8 extension point
+jQuery.fx.step = {};
+
+
+
+
+var
+	fxNow, timerId,
+	rfxtypes = /^(?:toggle|show|hide)$/,
+	rfxnum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ),
+	rrun = /queueHooks$/,
+	animationPrefilters = [ defaultPrefilter ],
+	tweeners = {
+		"*": [ function( prop, value ) {
+			var tween = this.createTween( prop, value ),
+				target = tween.cur(),
+				parts = rfxnum.exec( value ),
+				unit = parts && parts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
+
+				// Starting value computation is required for potential unit mismatches
+				start = ( jQuery.cssNumber[ prop ] || unit !== "px" && +target ) &&
+					rfxnum.exec( jQuery.css( tween.elem, prop ) ),
+				scale = 1,
+				maxIterations = 20;
+
+			if ( start && start[ 3 ] !== unit ) {
+				// Trust units reported by jQuery.css
+				unit = unit || start[ 3 ];
+
+				// Make sure we update the tween properties later on
+				parts = parts || [];
+
+				// Iteratively approximate from a nonzero starting point
+				start = +target || 1;
+
+				do {
+					// If previous iteration zeroed out, double until we get *something*
+					// Use a string for doubling factor so we don't accidentally see scale as unchanged below
+					scale = scale || ".5";
+
+					// Adjust and apply
+					start = start / scale;
+					jQuery.style( tween.elem, prop, start + unit );
+
+				// Update scale, tolerating zero or NaN from tween.cur()
+				// And breaking the loop if scale is unchanged or perfect, or if we've just had enough
+				} while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
+			}
+
+			// Update tween properties
+			if ( parts ) {
+				start = tween.start = +start || +target || 0;
+				tween.unit = unit;
+				// If a +=/-= token was provided, we're doing a relative animation
+				tween.end = parts[ 1 ] ?
+					start + ( parts[ 1 ] + 1 ) * parts[ 2 ] :
+					+parts[ 2 ];
+			}
+
+			return tween;
+		} ]
+	};
+
+// Animations created synchronously will run synchronously
+function createFxNow() {
+	setTimeout(function() {
+		fxNow = undefined;
+	});
+	return ( fxNow = jQuery.now() );
+}
+
+// Generate parameters to create a standard animation
+function genFx( type, includeWidth ) {
+	var which,
+		attrs = { height: type },
+		i = 0;
+
+	// if we include width, step value is 1 to do all cssExpand values,
+	// if we don't include width, step value is 2 to skip over Left and Right
+	includeWidth = includeWidth ? 1 : 0;
+	for ( ; i < 4 ; i += 2 - includeWidth ) {
+		which = cssExpand[ i ];
+		attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
+	}
+
+	if ( includeWidth ) {
+		attrs.opacity = attrs.width = type;
+	}
+
+	return attrs;
+}
+
+function createTween( value, prop, animation ) {
+	var tween,
+		collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
+		index = 0,
+		length = collection.length;
+	for ( ; index < length; index++ ) {
+		if ( (tween = collection[ index ].call( animation, prop, value )) ) {
+
+			// we're done with this property
+			return tween;
+		}
+	}
+}
+
+function defaultPrefilter( elem, props, opts ) {
+	/* jshint validthis: true */
+	var prop, value, toggle, tween, hooks, oldfire, display, checkDisplay,
+		anim = this,
+		orig = {},
+		style = elem.style,
+		hidden = elem.nodeType && isHidden( elem ),
+		dataShow = jQuery._data( elem, "fxshow" );
+
+	// handle queue: false promises
+	if ( !opts.queue ) {
+		hooks = jQuery._queueHooks( elem, "fx" );
+		if ( hooks.unqueued == null ) {
+			hooks.unqueued = 0;
+			oldfire = hooks.empty.fire;
+			hooks.empty.fire = function() {
+				if ( !hooks.unqueued ) {
+					oldfire();
+				}
+			};
+		}
+		hooks.unqueued++;
+
+		anim.always(function() {
+			// doing this makes sure that the complete handler will be called
+			// before this completes
+			anim.always(function() {
+				hooks.unqueued--;
+				if ( !jQuery.queue( elem, "fx" ).length ) {
+					hooks.empty.fire();
+				}
+			});
+		});
+	}
+
+	// height/width overflow pass
+	if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
+		// Make sure that nothing sneaks out
+		// Record all 3 overflow attributes because IE does not
+		// change the overflow attribute when overflowX and
+		// overflowY are set to the same value
+		opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
+
+		// Set display property to inline-block for height/width
+		// animations on inline elements that are having width/height animated
+		display = jQuery.css( elem, "display" );
+
+		// Test default display if display is currently "none"
+		checkDisplay = display === "none" ?
+			jQuery._data( elem, "olddisplay" ) || defaultDisplay( elem.nodeName ) : display;
+
+		if ( checkDisplay === "inline" && jQuery.css( elem, "float" ) === "none" ) {
+
+			// inline-level elements accept inline-block;
+			// block-level elements need to be inline with layout
+			if ( !support.inlineBlockNeedsLayout || defaultDisplay( elem.nodeName ) === "inline" ) {
+				style.display = "inline-block";
+			} else {
+				style.zoom = 1;
+			}
+		}
+	}
+
+	if ( opts.overflow ) {
+		style.overflow = "hidden";
+		if ( !support.shrinkWrapBlocks() ) {
+			anim.always(function() {
+				style.overflow = opts.overflow[ 0 ];
+				style.overflowX = opts.overflow[ 1 ];
+				style.overflowY = opts.overflow[ 2 ];
+			});
+		}
+	}
+
+	// show/hide pass
+	for ( prop in props ) {
+		value = props[ prop ];
+		if ( rfxtypes.exec( value ) ) {
+			delete props[ prop ];
+			toggle = toggle || value === "toggle";
+			if ( value === ( hidden ? "hide" : "show" ) ) {
+
+				// If there is dataShow left over from a stopped hide or show and we are going to proceed with show, we should pretend to be hidden
+				if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
+					hidden = true;
+				} else {
+					continue;
+				}
+			}
+			orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
+
+		// Any non-fx value stops us from restoring the original display value
+		} else {
+			display = undefined;
+		}
+	}
+
+	if ( !jQuery.isEmptyObject( orig ) ) {
+		if ( dataShow ) {
+			if ( "hidden" in dataShow ) {
+				hidden = dataShow.hidden;
+			}
+		} else {
+			dataShow = jQuery._data( elem, "fxshow", {} );
+		}
+
+		// store state if its toggle - enables .stop().toggle() to "reverse"
+		if ( toggle ) {
+			dataShow.hidden = !hidden;
+		}
+		if ( hidden ) {
+			jQuery( elem ).show();
+		} else {
+			anim.done(function() {
+				jQuery( elem ).hide();
+			});
+		}
+		anim.done(function() {
+			var prop;
+			jQuery._removeData( elem, "fxshow" );
+			for ( prop in orig ) {
+				jQuery.style( elem, prop, orig[ prop ] );
+			}
+		});
+		for ( prop in orig ) {
+			tween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
+
+			if ( !( prop in dataShow ) ) {
+				dataShow[ prop ] = tween.start;
+				if ( hidden ) {
+					tween.end = tween.start;
+					tween.start = prop === "width" || prop === "height" ? 1 : 0;
+				}
+			}
+		}
+
+	// If this is a noop like .hide().hide(), restore an overwritten display value
+	} else if ( (display === "none" ? defaultDisplay( elem.nodeName ) : display) === "inline" ) {
+		style.display = display;
+	}
+}
+
+function propFilter( props, specialEasing ) {
+	var index, name, easing, value, hooks;
+
+	// camelCase, specialEasing and expand cssHook pass
+	for ( index in props ) {
+		name = jQuery.camelCase( index );
+		easing = specialEasing[ name ];
+		value = props[ index ];
+		if ( jQuery.isArray( value ) ) {
+			easing = value[ 1 ];
+			value = props[ index ] = value[ 0 ];
+		}
+
+		if ( index !== name ) {
+			props[ name ] = value;
+			delete props[ index ];
+		}
+
+		hooks = jQuery.cssHooks[ name ];
+		if ( hooks && "expand" in hooks ) {
+			value = hooks.expand( value );
+			delete props[ name ];
+
+			// not quite $.extend, this wont overwrite keys already present.
+			// also - reusing 'index' from above because we have the correct "name"
+			for ( index in value ) {
+				if ( !( index in props ) ) {
+					props[ index ] = value[ index ];
+					specialEasing[ index ] = easing;
+				}
+			}
+		} else {
+			specialEasing[ name ] = easing;
+		}
+	}
+}
+
+function Animation( elem, properties, options ) {
+	var result,
+		stopped,
+		index = 0,
+		length = animationPrefilters.length,
+		deferred = jQuery.Deferred().always( function() {
+			// don't match elem in the :animated selector
+			delete tick.elem;
+		}),
+		tick = function() {
+			if ( stopped ) {
+				return false;
+			}
+			var currentTime = fxNow || createFxNow(),
+				remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
+				// archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)
+				temp = remaining / animation.duration || 0,
+				percent = 1 - temp,
+				index = 0,
+				length = animation.tweens.length;
+
+			for ( ; index < length ; index++ ) {
+				animation.tweens[ index ].run( percent );
+			}
+
+			deferred.notifyWith( elem, [ animation, percent, remaining ]);
+
+			if ( percent < 1 && length ) {
+				return remaining;
+			} else {
+				deferred.resolveWith( elem, [ animation ] );
+				return false;
+			}
+		},
+		animation = deferred.promise({
+			elem: elem,
+			props: jQuery.extend( {}, properties ),
+			opts: jQuery.extend( true, { specialEasing: {} }, options ),
+			originalProperties: properties,
+			originalOptions: options,
+			startTime: fxNow || createFxNow(),
+			duration: options.duration,
+			tweens: [],
+			createTween: function( prop, end ) {
+				var tween = jQuery.Tween( elem, animation.opts, prop, end,
+						animation.opts.specialEasing[ prop ] || animation.opts.easing );
+				animation.tweens.push( tween );
+				return tween;
+			},
+			stop: function( gotoEnd ) {
+				var index = 0,
+					// if we are going to the end, we want to run all the tweens
+					// otherwise we skip this part
+					length = gotoEnd ? animation.tweens.length : 0;
+				if ( stopped ) {
+					return this;
+				}
+				stopped = true;
+				for ( ; index < length ; index++ ) {
+					animation.tweens[ index ].run( 1 );
+				}
+
+				// resolve when we played the last frame
+				// otherwise, reject
+				if ( gotoEnd ) {
+					deferred.resolveWith( elem, [ animation, gotoEnd ] );
+				} else {
+					deferred.rejectWith( elem, [ animation, gotoEnd ] );
+				}
+				return this;
+			}
+		}),
+		props = animation.props;
+
+	propFilter( props, animation.opts.specialEasing );
+
+	for ( ; index < length ; index++ ) {
+		result = animationPrefilters[ index ].call( animation, elem, props, animation.opts );
+		if ( result ) {
+			return result;
+		}
+	}
+
+	jQuery.map( props, createTween, animation );
+
+	if ( jQuery.isFunction( animation.opts.start ) ) {
+		animation.opts.start.call( elem, animation );
+	}
+
+	jQuery.fx.timer(
+		jQuery.extend( tick, {
+			elem: elem,
+			anim: animation,
+			queue: animation.opts.queue
+		})
+	);
+
+	// attach callbacks from options
+	return animation.progress( animation.opts.progress )
+		.done( animation.opts.done, animation.opts.complete )
+		.fail( animation.opts.fail )
+		.always( animation.opts.always );
+}
+
+jQuery.Animation = jQuery.extend( Animation, {
+	tweener: function( props, callback ) {
+		if ( jQuery.isFunction( props ) ) {
+			callback = props;
+			props = [ "*" ];
+		} else {
+			props = props.split(" ");
+		}
+
+		var prop,
+			index = 0,
+			length = props.length;
+
+		for ( ; index < length ; index++ ) {
+			prop = props[ index ];
+			tweeners[ prop ] = tweeners[ prop ] || [];
+			tweeners[ prop ].unshift( callback );
+		}
+	},
+
+	prefilter: function( callback, prepend ) {
+		if ( prepend ) {
+			animationPrefilters.unshift( callback );
+		} else {
+			animationPrefilters.push( callback );
+		}
+	}
+});
+
+jQuery.speed = function( speed, easing, fn ) {
+	var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
+		complete: fn || !fn && easing ||
+			jQuery.isFunction( speed ) && speed,
+		duration: speed,
+		easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
+	};
+
+	opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
+		opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
+
+	// normalize opt.queue - true/undefined/null -> "fx"
+	if ( opt.queue == null || opt.queue === true ) {
+		opt.queue = "fx";
+	}
+
+	// Queueing
+	opt.old = opt.complete;
+
+	opt.complete = function() {
+		if ( jQuery.isFunction( opt.old ) ) {
+			opt.old.call( this );
+		}
+
+		if ( opt.queue ) {
+			jQuery.dequeue( this, opt.queue );
+		}
+	};
+
+	return opt;
+};
+
+jQuery.fn.extend({
+	fadeTo: function( speed, to, easing, callback ) {
+
+		// show any hidden elements after setting opacity to 0
+		return this.filter( isHidden ).css( "opacity", 0 ).show()
+
+			// animate to the value specified
+			.end().animate({ opacity: to }, speed, easing, callback );
+	},
+	animate: function( prop, speed, easing, callback ) {
+		var empty = jQuery.isEmptyObject( prop ),
+			optall = jQuery.speed( speed, easing, callback ),
+			doAnimation = function() {
+				// Operate on a copy of prop so per-property easing won't be lost
+				var anim = Animation( this, jQuery.extend( {}, prop ), optall );
+
+				// Empty animations, or finishing resolves immediately
+				if ( empty || jQuery._data( this, "finish" ) ) {
+					anim.stop( true );
+				}
+			};
+			doAnimation.finish = doAnimation;
+
+		return empty || optall.queue === false ?
+			this.each( doAnimation ) :
+			this.queue( optall.queue, doAnimation );
+	},
+	stop: function( type, clearQueue, gotoEnd ) {
+		var stopQueue = function( hooks ) {
+			var stop = hooks.stop;
+			delete hooks.stop;
+			stop( gotoEnd );
+		};
+
+		if ( typeof type !== "string" ) {
+			gotoEnd = clearQueue;
+			clearQueue = type;
+			type = undefined;
+		}
+		if ( clearQueue && type !== false ) {
+			this.queue( type || "fx", [] );
+		}
+
+		return this.each(function() {
+			var dequeue = true,
+				index = type != null && type + "queueHooks",
+				timers = jQuery.timers,
+				data = jQuery._data( this );
+
+			if ( index ) {
+				if ( data[ index ] && data[ index ].stop ) {
+					stopQueue( data[ index ] );
+				}
+			} else {
+				for ( index in data ) {
+					if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
+						stopQueue( data[ index ] );
+					}
+				}
+			}
+
+			for ( index = timers.length; index--; ) {
+				if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
+					timers[ index ].anim.stop( gotoEnd );
+					dequeue = false;
+					timers.splice( index, 1 );
+				}
+			}
+
+			// start the next in the queue if the last step wasn't forced
+			// timers currently will call their complete callbacks, which will dequeue
+			// but only if they were gotoEnd
+			if ( dequeue || !gotoEnd ) {
+				jQuery.dequeue( this, type );
+			}
+		});
+	},
+	finish: function( type ) {
+		if ( type !== false ) {
+			type = type || "fx";
+		}
+		return this.each(function() {
+			var index,
+				data = jQuery._data( this ),
+				queue = data[ type + "queue" ],
+				hooks = data[ type + "queueHooks" ],
+				timers = jQuery.timers,
+				length = queue ? queue.length : 0;
+
+			// enable finishing flag on private data
+			data.finish = true;
+
+			// empty the queue first
+			jQuery.queue( this, type, [] );
+
+			if ( hooks && hooks.stop ) {
+				hooks.stop.call( this, true );
+			}
+
+			// look for any active animations, and finish them
+			for ( index = timers.length; index--; ) {
+				if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
+					timers[ index ].anim.stop( true );
+					timers.splice( index, 1 );
+				}
+			}
+
+			// look for any animations in the old queue and finish them
+			for ( index = 0; index < length; index++ ) {
+				if ( queue[ index ] && queue[ index ].finish ) {
+					queue[ index ].finish.call( this );
+				}
+			}
+
+			// turn off finishing flag
+			delete data.finish;
+		});
+	}
+});
+
+jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
+	var cssFn = jQuery.fn[ name ];
+	jQuery.fn[ name ] = function( speed, easing, callback ) {
+		return speed == null || typeof speed === "boolean" ?
+			cssFn.apply( this, arguments ) :
+			this.animate( genFx( name, true ), speed, easing, callback );
+	};
+});
+
+// Generate shortcuts for custom animations
+jQuery.each({
+	slideDown: genFx("show"),
+	slideUp: genFx("hide"),
+	slideToggle: genFx("toggle"),
+	fadeIn: { opacity: "show" },
+	fadeOut: { opacity: "hide" },
+	fadeToggle: { opacity: "toggle" }
+}, function( name, props ) {
+	jQuery.fn[ name ] = function( speed, easing, callback ) {
+		return this.animate( props, speed, easing, callback );
+	};
+});
+
+jQuery.timers = [];
+jQuery.fx.tick = function() {
+	var timer,
+		timers = jQuery.timers,
+		i = 0;
+
+	fxNow = jQuery.now();
+
+	for ( ; i < timers.length; i++ ) {
+		timer = timers[ i ];
+		// Checks the timer has not already been removed
+		if ( !timer() && timers[ i ] === timer ) {
+			timers.splice( i--, 1 );
+		}
+	}
+
+	if ( !timers.length ) {
+		jQuery.fx.stop();
+	}
+	fxNow = undefined;
+};
+
+jQuery.fx.timer = function( timer ) {
+	jQuery.timers.push( timer );
+	if ( timer() ) {
+		jQuery.fx.start();
+	} else {
+		jQuery.timers.pop();
+	}
+};
+
+jQuery.fx.interval = 13;
+
+jQuery.fx.start = function() {
+	if ( !timerId ) {
+		timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
+	}
+};
+
+jQuery.fx.stop = function() {
+	clearInterval( timerId );
+	timerId = null;
+};
+
+jQuery.fx.speeds = {
+	slow: 600,
+	fast: 200,
+	// Default speed
+	_default: 400
+};
+
+
+// Based off of the plugin by Clint Helfers, with permission.
+// http://blindsignals.com/index.php/2009/07/jquery-delay/
+jQuery.fn.delay = function( time, type ) {
+	time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
+	type = type || "fx";
+
+	return this.queue( type, function( next, hooks ) {
+		var timeout = setTimeout( next, time );
+		hooks.stop = function() {
+			clearTimeout( timeout );
+		};
+	});
+};
+
+
+(function() {
+	// Minified: var a,b,c,d,e
+	var input, div, select, a, opt;
+
+	// Setup
+	div = document.createElement( "div" );
+	div.setAttribute( "className", "t" );
+	div.innerHTML = "  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
+	a = div.getElementsByTagName("a")[ 0 ];
+
+	// First batch of tests.
+	select = document.createElement("select");
+	opt = select.appendChild( document.createElement("option") );
+	input = div.getElementsByTagName("input")[ 0 ];
+
+	a.style.cssText = "top:1px";
+
+	// Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
+	support.getSetAttribute = div.className !== "t";
+
+	// Get the style information from getAttribute
+	// (IE uses .cssText instead)
+	support.style = /top/.test( a.getAttribute("style") );
+
+	// Make sure that URLs aren't manipulated
+	// (IE normalizes it by default)
+	support.hrefNormalized = a.getAttribute("href") === "/a";
+
+	// Check the default checkbox/radio value ("" on WebKit; "on" elsewhere)
+	support.checkOn = !!input.value;
+
+	// Make sure that a selected-by-default option has a working selected property.
+	// (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
+	support.optSelected = opt.selected;
+
+	// Tests for enctype support on a form (#6743)
+	support.enctype = !!document.createElement("form").enctype;
+
+	// Make sure that the options inside disabled selects aren't marked as disabled
+	// (WebKit marks them as disabled)
+	select.disabled = true;
+	support.optDisabled = !opt.disabled;
+
+	// Support: IE8 only
+	// Check if we can trust getAttribute("value")
+	input = document.createElement( "input" );
+	input.setAttribute( "value", "" );
+	support.input = input.getAttribute( "value" ) === "";
+
+	// Check if an input maintains its value after becoming a radio
+	input.value = "t";
+	input.setAttribute( "type", "radio" );
+	support.radioValue = input.value === "t";
+})();
+
+
+var rreturn = /\r/g;
+
+jQuery.fn.extend({
+	val: function( value ) {
+		var hooks, ret, isFunction,
+			elem = this[0];
+
+		if ( !arguments.length ) {
+			if ( elem ) {
+				hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
+
+				if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
+					return ret;
+				}
+
+				ret = elem.value;
+
+				return typeof ret === "string" ?
+					// handle most common string cases
+					ret.replace(rreturn, "") :
+					// handle cases where value is null/undef or number
+					ret == null ? "" : ret;
+			}
+
+			return;
+		}
+
+		isFunction = jQuery.isFunction( value );
+
+		return this.each(function( i ) {
+			var val;
+
+			if ( this.nodeType !== 1 ) {
+				return;
+			}
+
+			if ( isFunction ) {
+				val = value.call( this, i, jQuery( this ).val() );
+			} else {
+				val = value;
+			}
+
+			// Treat null/undefined as ""; convert numbers to string
+			if ( val == null ) {
+				val = "";
+			} else if ( typeof val === "number" ) {
+				val += "";
+			} else if ( jQuery.isArray( val ) ) {
+				val = jQuery.map( val, function( value ) {
+					return value == null ? "" : value + "";
+				});
+			}
+
+			hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
+
+			// If set returns undefined, fall back to normal setting
+			if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
+				this.value = val;
+			}
+		});
+	}
+});
+
+jQuery.extend({
+	valHooks: {
+		option: {
+			get: function( elem ) {
+				var val = jQuery.find.attr( elem, "value" );
+				return val != null ?
+					val :
+					// Support: IE10-11+
+					// option.text throws exceptions (#14686, #14858)
+					jQuery.trim( jQuery.text( elem ) );
+			}
+		},
+		select: {
+			get: function( elem ) {
+				var value, option,
+					options = elem.options,
+					index = elem.selectedIndex,
+					one = elem.type === "select-one" || index < 0,
+					values = one ? null : [],
+					max = one ? index + 1 : options.length,
+					i = index < 0 ?
+						max :
+						one ? index : 0;
+
+				// Loop through all the selected options
+				for ( ; i < max; i++ ) {
+					option = options[ i ];
+
+					// oldIE doesn't update selected after form reset (#2551)
+					if ( ( option.selected || i === index ) &&
+							// Don't return options that are disabled or in a disabled optgroup
+							( support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) &&
+							( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
+
+						// Get the specific value for the option
+						value = jQuery( option ).val();
+
+						// We don't need an array for one selects
+						if ( one ) {
+							return value;
+						}
+
+						// Multi-Selects return an array
+						values.push( value );
+					}
+				}
+
+				return values;
+			},
+
+			set: function( elem, value ) {
+				var optionSet, option,
+					options = elem.options,
+					values = jQuery.makeArray( value ),
+					i = options.length;
+
+				while ( i-- ) {
+					option = options[ i ];
+
+					if ( jQuery.inArray( jQuery.valHooks.option.get( option ), values ) >= 0 ) {
+
+						// Support: IE6
+						// When new option element is added to select box we need to
+						// force reflow of newly added node in order to workaround delay
+						// of initialization properties
+						try {
+							option.selected = optionSet = true;
+
+						} catch ( _ ) {
+
+							// Will be executed only in IE6
+							option.scrollHeight;
+						}
+
+					} else {
+						option.selected = false;
+					}
+				}
+
+				// Force browsers to behave consistently when non-matching value is set
+				if ( !optionSet ) {
+					elem.selectedIndex = -1;
+				}
+
+				return options;
+			}
+		}
+	}
+});
+
+// Radios and checkboxes getter/setter
+jQuery.each([ "radio", "checkbox" ], function() {
+	jQuery.valHooks[ this ] = {
+		set: function( elem, value ) {
+			if ( jQuery.isArray( value ) ) {
+				return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
+			}
+		}
+	};
+	if ( !support.checkOn ) {
+		jQuery.valHooks[ this ].get = function( elem ) {
+			// Support: Webkit
+			// "" is returned instead of "on" if a value isn't specified
+			return elem.getAttribute("value") === null ? "on" : elem.value;
+		};
+	}
+});
+
+
+
+
+var nodeHook, boolHook,
+	attrHandle = jQuery.expr.attrHandle,
+	ruseDefault = /^(?:checked|selected)$/i,
+	getSetAttribute = support.getSetAttribute,
+	getSetInput = support.input;
+
+jQuery.fn.extend({
+	attr: function( name, value ) {
+		return access( this, jQuery.attr, name, value, arguments.length > 1 );
+	},
+
+	removeAttr: function( name ) {
+		return this.each(function() {
+			jQuery.removeAttr( this, name );
+		});
+	}
+});
+
+jQuery.extend({
+	attr: function( elem, name, value ) {
+		var hooks, ret,
+			nType = elem.nodeType;
+
+		// don't get/set attributes on text, comment and attribute nodes
+		if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+			return;
+		}
+
+		// Fallback to prop when attributes are not supported
+		if ( typeof elem.getAttribute === strundefined ) {
+			return jQuery.prop( elem, name, value );
+		}
+
+		// All attributes are lowercase
+		// Grab necessary hook if one is defined
+		if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
+			name = name.toLowerCase();
+			hooks = jQuery.attrHooks[ name ] ||
+				( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook );
+		}
+
+		if ( value !== undefined ) {
+
+			if ( value === null ) {
+				jQuery.removeAttr( elem, name );
+
+			} else if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
+				return ret;
+
+			} else {
+				elem.setAttribute( name, value + "" );
+				return value;
+			}
+
+		} else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
+			return ret;
+
+		} else {
+			ret = jQuery.find.attr( elem, name );
+
+			// Non-existent attributes return null, we normalize to undefined
+			return ret == null ?
+				undefined :
+				ret;
+		}
+	},
+
+	removeAttr: function( elem, value ) {
+		var name, propName,
+			i = 0,
+			attrNames = value && value.match( rnotwhite );
+
+		if ( attrNames && elem.nodeType === 1 ) {
+			while ( (name = attrNames[i++]) ) {
+				propName = jQuery.propFix[ name ] || name;
+
+				// Boolean attributes get special treatment (#10870)
+				if ( jQuery.expr.match.bool.test( name ) ) {
+					// Set corresponding property to false
+					if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
+						elem[ propName ] = false;
+					// Support: IE<9
+					// Also clear defaultChecked/defaultSelected (if appropriate)
+					} else {
+						elem[ jQuery.camelCase( "default-" + name ) ] =
+							elem[ propName ] = false;
+					}
+
+				// See #9699 for explanation of this approach (setting first, then removal)
+				} else {
+					jQuery.attr( elem, name, "" );
+				}
+
+				elem.removeAttribute( getSetAttribute ? name : propName );
+			}
+		}
+	},
+
+	attrHooks: {
+		type: {
+			set: function( elem, value ) {
+				if ( !support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
+					// Setting the type on a radio button after the value resets the value in IE6-9
+					// Reset value to default in case type is set after value during creation
+					var val = elem.value;
+					elem.setAttribute( "type", value );
+					if ( val ) {
+						elem.value = val;
+					}
+					return value;
+				}
+			}
+		}
+	}
+});
+
+// Hook for boolean attributes
+boolHook = {
+	set: function( elem, value, name ) {
+		if ( value === false ) {
+			// Remove boolean attributes when set to false
+			jQuery.removeAttr( elem, name );
+		} else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
+			// IE<8 needs the *property* name
+			elem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name );
+
+		// Use defaultChecked and defaultSelected for oldIE
+		} else {
+			elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true;
+		}
+
+		return name;
+	}
+};
+
+// Retrieve booleans specially
+jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) {
+
+	var getter = attrHandle[ name ] || jQuery.find.attr;
+
+	attrHandle[ name ] = getSetInput && getSetAttribute || !ruseDefault.test( name ) ?
+		function( elem, name, isXML ) {
+			var ret, handle;
+			if ( !isXML ) {
+				// Avoid an infinite loop by temporarily removing this function from the getter
+				handle = attrHandle[ name ];
+				attrHandle[ name ] = ret;
+				ret = getter( elem, name, isXML ) != null ?
+					name.toLowerCase() :
+					null;
+				attrHandle[ name ] = handle;
+			}
+			return ret;
+		} :
+		function( elem, name, isXML ) {
+			if ( !isXML ) {
+				return elem[ jQuery.camelCase( "default-" + name ) ] ?
+					name.toLowerCase() :
+					null;
+			}
+		};
+});
+
+// fix oldIE attroperties
+if ( !getSetInput || !getSetAttribute ) {
+	jQuery.attrHooks.value = {
+		set: function( elem, value, name ) {
+			if ( jQuery.nodeName( elem, "input" ) ) {
+				// Does not return so that setAttribute is also used
+				elem.defaultValue = value;
+			} else {
+				// Use nodeHook if defined (#1954); otherwise setAttribute is fine
+				return nodeHook && nodeHook.set( elem, value, name );
+			}
+		}
+	};
+}
+
+// IE6/7 do not support getting/setting some attributes with get/setAttribute
+if ( !getSetAttribute ) {
+
+	// Use this for any attribute in IE6/7
+	// This fixes almost every IE6/7 issue
+	nodeHook = {
+		set: function( elem, value, name ) {
+			// Set the existing or create a new attribute node
+			var ret = elem.getAttributeNode( name );
+			if ( !ret ) {
+				elem.setAttributeNode(
+					(ret = elem.ownerDocument.createAttribute( name ))
+				);
+			}
+
+			ret.value = value += "";
+
+			// Break association with cloned elements by also using setAttribute (#9646)
+			if ( name === "value" || value === elem.getAttribute( name ) ) {
+				return value;
+			}
+		}
+	};
+
+	// Some attributes are constructed with empty-string values when not defined
+	attrHandle.id = attrHandle.name = attrHandle.coords =
+		function( elem, name, isXML ) {
+			var ret;
+			if ( !isXML ) {
+				return (ret = elem.getAttributeNode( name )) && ret.value !== "" ?
+					ret.value :
+					null;
+			}
+		};
+
+	// Fixing value retrieval on a button requires this module
+	jQuery.valHooks.button = {
+		get: function( elem, name ) {
+			var ret = elem.getAttributeNode( name );
+			if ( ret && ret.specified ) {
+				return ret.value;
+			}
+		},
+		set: nodeHook.set
+	};
+
+	// Set contenteditable to false on removals(#10429)
+	// Setting to empty string throws an error as an invalid value
+	jQuery.attrHooks.contenteditable = {
+		set: function( elem, value, name ) {
+			nodeHook.set( elem, value === "" ? false : value, name );
+		}
+	};
+
+	// Set width and height to auto instead of 0 on empty string( Bug #8150 )
+	// This is for removals
+	jQuery.each([ "width", "height" ], function( i, name ) {
+		jQuery.attrHooks[ name ] = {
+			set: function( elem, value ) {
+				if ( value === "" ) {
+					elem.setAttribute( name, "auto" );
+					return value;
+				}
+			}
+		};
+	});
+}
+
+if ( !support.style ) {
+	jQuery.attrHooks.style = {
+		get: function( elem ) {
+			// Return undefined in the case of empty string
+			// Note: IE uppercases css property names, but if we were to .toLowerCase()
+			// .cssText, that would destroy case senstitivity in URL's, like in "background"
+			return elem.style.cssText || undefined;
+		},
+		set: function( elem, value ) {
+			return ( elem.style.cssText = value + "" );
+		}
+	};
+}
+
+
+
+
+var rfocusable = /^(?:input|select|textarea|button|object)$/i,
+	rclickable = /^(?:a|area)$/i;
+
+jQuery.fn.extend({
+	prop: function( name, value ) {
+		return access( this, jQuery.prop, name, value, arguments.length > 1 );
+	},
+
+	removeProp: function( name ) {
+		name = jQuery.propFix[ name ] || name;
+		return this.each(function() {
+			// try/catch handles cases where IE balks (such as removing a property on window)
+			try {
+				this[ name ] = undefined;
+				delete this[ name ];
+			} catch( e ) {}
+		});
+	}
+});
+
+jQuery.extend({
+	propFix: {
+		"for": "htmlFor",
+		"class": "className"
+	},
+
+	prop: function( elem, name, value ) {
+		var ret, hooks, notxml,
+			nType = elem.nodeType;
+
+		// don't get/set properties on text, comment and attribute nodes
+		if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+			return;
+		}
+
+		notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+
+		if ( notxml ) {
+			// Fix name and attach hooks
+			name = jQuery.propFix[ name ] || name;
+			hooks = jQuery.propHooks[ name ];
+		}
+
+		if ( value !== undefined ) {
+			return hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ?
+				ret :
+				( elem[ name ] = value );
+
+		} else {
+			return hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ?
+				ret :
+				elem[ name ];
+		}
+	},
+
+	propHooks: {
+		tabIndex: {
+			get: function( elem ) {
+				// elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
+				// http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
+				// Use proper attribute retrieval(#12072)
+				var tabindex = jQuery.find.attr( elem, "tabindex" );
+
+				return tabindex ?
+					parseInt( tabindex, 10 ) :
+					rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
+						0 :
+						-1;
+			}
+		}
+	}
+});
+
+// Some attributes require a special call on IE
+// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
+if ( !support.hrefNormalized ) {
+	// href/src property should get the full normalized URL (#10299/#12915)
+	jQuery.each([ "href", "src" ], function( i, name ) {
+		jQuery.propHooks[ name ] = {
+			get: function( elem ) {
+				return elem.getAttribute( name, 4 );
+			}
+		};
+	});
+}
+
+// Support: Safari, IE9+
+// mis-reports the default selected property of an option
+// Accessing the parent's selectedIndex property fixes it
+if ( !support.optSelected ) {
+	jQuery.propHooks.selected = {
+		get: function( elem ) {
+			var parent = elem.parentNode;
+
+			if ( parent ) {
+				parent.selectedIndex;
+
+				// Make sure that it also works with optgroups, see #5701
+				if ( parent.parentNode ) {
+					parent.parentNode.selectedIndex;
+				}
+			}
+			return null;
+		}
+	};
+}
+
+jQuery.each([
+	"tabIndex",
+	"readOnly",
+	"maxLength",
+	"cellSpacing",
+	"cellPadding",
+	"rowSpan",
+	"colSpan",
+	"useMap",
+	"frameBorder",
+	"contentEditable"
+], function() {
+	jQuery.propFix[ this.toLowerCase() ] = this;
+});
+
+// IE6/7 call enctype encoding
+if ( !support.enctype ) {
+	jQuery.propFix.enctype = "encoding";
+}
+
+
+
+
+var rclass = /[\t\r\n\f]/g;
+
+jQuery.fn.extend({
+	addClass: function( value ) {
+		var classes, elem, cur, clazz, j, finalValue,
+			i = 0,
+			len = this.length,
+			proceed = typeof value === "string" && value;
+
+		if ( jQuery.isFunction( value ) ) {
+			return this.each(function( j ) {
+				jQuery( this ).addClass( value.call( this, j, this.className ) );
+			});
+		}
+
+		if ( proceed ) {
+			// The disjunction here is for better compressibility (see removeClass)
+			classes = ( value || "" ).match( rnotwhite ) || [];
+
+			for ( ; i < len; i++ ) {
+				elem = this[ i ];
+				cur = elem.nodeType === 1 && ( elem.className ?
+					( " " + elem.className + " " ).replace( rclass, " " ) :
+					" "
+				);
+
+				if ( cur ) {
+					j = 0;
+					while ( (clazz = classes[j++]) ) {
+						if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
+							cur += clazz + " ";
+						}
+					}
+
+					// only assign if different to avoid unneeded rendering.
+					finalValue = jQuery.trim( cur );
+					if ( elem.className !== finalValue ) {
+						elem.className = finalValue;
+					}
+				}
+			}
+		}
+
+		return this;
+	},
+
+	removeClass: function( value ) {
+		var classes, elem, cur, clazz, j, finalValue,
+			i = 0,
+			len = this.length,
+			proceed = arguments.length === 0 || typeof value === "string" && value;
+
+		if ( jQuery.isFunction( value ) ) {
+			return this.each(function( j ) {
+				jQuery( this ).removeClass( value.call( this, j, this.className ) );
+			});
+		}
+		if ( proceed ) {
+			classes = ( value || "" ).match( rnotwhite ) || [];
+
+			for ( ; i < len; i++ ) {
+				elem = this[ i ];
+				// This expression is here for better compressibility (see addClass)
+				cur = elem.nodeType === 1 && ( elem.className ?
+					( " " + elem.className + " " ).replace( rclass, " " ) :
+					""
+				);
+
+				if ( cur ) {
+					j = 0;
+					while ( (clazz = classes[j++]) ) {
+						// Remove *all* instances
+						while ( cur.indexOf( " " + clazz + " " ) >= 0 ) {
+							cur = cur.replace( " " + clazz + " ", " " );
+						}
+					}
+
+					// only assign if different to avoid unneeded rendering.
+					finalValue = value ? jQuery.trim( cur ) : "";
+					if ( elem.className !== finalValue ) {
+						elem.className = finalValue;
+					}
+				}
+			}
+		}
+
+		return this;
+	},
+
+	toggleClass: function( value, stateVal ) {
+		var type = typeof value;
+
+		if ( typeof stateVal === "boolean" && type === "string" ) {
+			return stateVal ? this.addClass( value ) : this.removeClass( value );
+		}
+
+		if ( jQuery.isFunction( value ) ) {
+			return this.each(function( i ) {
+				jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
+			});
+		}
+
+		return this.each(function() {
+			if ( type === "string" ) {
+				// toggle individual class names
+				var className,
+					i = 0,
+					self = jQuery( this ),
+					classNames = value.match( rnotwhite ) || [];
+
+				while ( (className = classNames[ i++ ]) ) {
+					// check each className given, space separated list
+					if ( self.hasClass( className ) ) {
+						self.removeClass( className );
+					} else {
+						self.addClass( className );
+					}
+				}
+
+			// Toggle whole class name
+			} else if ( type === strundefined || type === "boolean" ) {
+				if ( this.className ) {
+					// store className if set
+					jQuery._data( this, "__className__", this.className );
+				}
+
+				// If the element has a class name or if we're passed "false",
+				// then remove the whole classname (if there was one, the above saved it).
+				// Otherwise bring back whatever was previously saved (if anything),
+				// falling back to the empty string if nothing was stored.
+				this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
+			}
+		});
+	},
+
+	hasClass: function( selector ) {
+		var className = " " + selector + " ",
+			i = 0,
+			l = this.length;
+		for ( ; i < l; i++ ) {
+			if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
+				return true;
+			}
+		}
+
+		return false;
+	}
+});
+
+
+
+
+// Return jQuery for attributes-only inclusion
+
+
+jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
+	"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
+	"change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
+
+	// Handle event binding
+	jQuery.fn[ name ] = function( data, fn ) {
+		return arguments.length > 0 ?
+			this.on( name, null, data, fn ) :
+			this.trigger( name );
+	};
+});
+
+jQuery.fn.extend({
+	hover: function( fnOver, fnOut ) {
+		return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
+	},
+
+	bind: function( types, data, fn ) {
+		return this.on( types, null, data, fn );
+	},
+	unbind: function( types, fn ) {
+		return this.off( types, null, fn );
+	},
+
+	delegate: function( selector, types, data, fn ) {
+		return this.on( types, selector, data, fn );
+	},
+	undelegate: function( selector, types, fn ) {
+		// ( namespace ) or ( selector, types [, fn] )
+		return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
+	}
+});
+
+
+var nonce = jQuery.now();
+
+var rquery = (/\?/);
+
+
+
+var rvalidtokens = /(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;
+
+jQuery.parseJSON = function( data ) {
+	// Attempt to parse using the native JSON parser first
+	if ( window.JSON && window.JSON.parse ) {
+		// Support: Android 2.3
+		// Workaround failure to string-cast null input
+		return window.JSON.parse( data + "" );
+	}
+
+	var requireNonComma,
+		depth = null,
+		str = jQuery.trim( data + "" );
+
+	// Guard against invalid (and possibly dangerous) input by ensuring that nothing remains
+	// after removing valid tokens
+	return str && !jQuery.trim( str.replace( rvalidtokens, function( token, comma, open, close ) {
+
+		// Force termination if we see a misplaced comma
+		if ( requireNonComma && comma ) {
+			depth = 0;
+		}
+
+		// Perform no more replacements after returning to outermost depth
+		if ( depth === 0 ) {
+			return token;
+		}
+
+		// Commas must not follow "[", "{", or ","
+		requireNonComma = open || comma;
+
+		// Determine new depth
+		// array/object open ("[" or "{"): depth += true - false (increment)
+		// array/object close ("]" or "}"): depth += false - true (decrement)
+		// other cases ("," or primitive): depth += true - true (numeric cast)
+		depth += !close - !open;
+
+		// Remove this token
+		return "";
+	}) ) ?
+		( Function( "return " + str ) )() :
+		jQuery.error( "Invalid JSON: " + data );
+};
+
+
+// Cross-browser xml parsing
+jQuery.parseXML = function( data ) {
+	var xml, tmp;
+	if ( !data || typeof data !== "string" ) {
+		return null;
+	}
+	try {
+		if ( window.DOMParser ) { // Standard
+			tmp = new DOMParser();
+			xml = tmp.parseFromString( data, "text/xml" );
+		} else { // IE
+			xml = new ActiveXObject( "Microsoft.XMLDOM" );
+			xml.async = "false";
+			xml.loadXML( data );
+		}
+	} catch( e ) {
+		xml = undefined;
+	}
+	if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
+		jQuery.error( "Invalid XML: " + data );
+	}
+	return xml;
+};
+
+
+var
+	// Document location
+	ajaxLocParts,
+	ajaxLocation,
+
+	rhash = /#.*$/,
+	rts = /([?&])_=[^&]*/,
+	rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
+	// #7653, #8125, #8152: local protocol detection
+	rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
+	rnoContent = /^(?:GET|HEAD)$/,
+	rprotocol = /^\/\//,
+	rurl = /^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,
+
+	/* Prefilters
+	 * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
+	 * 2) These are called:
+	 *    - BEFORE asking for a transport
+	 *    - AFTER param serialization (s.data is a string if s.processData is true)
+	 * 3) key is the dataType
+	 * 4) the catchall symbol "*" can be used
+	 * 5) execution will start with transport dataType and THEN continue down to "*" if needed
+	 */
+	prefilters = {},
+
+	/* Transports bindings
+	 * 1) key is the dataType
+	 * 2) the catchall symbol "*" can be used
+	 * 3) selection will start with transport dataType and THEN go to "*" if needed
+	 */
+	transports = {},
+
+	// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
+	allTypes = "*/".concat("*");
+
+// #8138, IE may throw an exception when accessing
+// a field from window.location if document.domain has been set
+try {
+	ajaxLocation = location.href;
+} catch( e ) {
+	// Use the href attribute of an A element
+	// since IE will modify it given document.location
+	ajaxLocation = document.createElement( "a" );
+	ajaxLocation.href = "";
+	ajaxLocation = ajaxLocation.href;
+}
+
+// Segment location into parts
+ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
+
+// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
+function addToPrefiltersOrTransports( structure ) {
+
+	// dataTypeExpression is optional and defaults to "*"
+	return function( dataTypeExpression, func ) {
+
+		if ( typeof dataTypeExpression !== "string" ) {
+			func = dataTypeExpression;
+			dataTypeExpression = "*";
+		}
+
+		var dataType,
+			i = 0,
+			dataTypes = dataTypeExpression.toLowerCase().match( rnotwhite ) || [];
+
+		if ( jQuery.isFunction( func ) ) {
+			// For each dataType in the dataTypeExpression
+			while ( (dataType = dataTypes[i++]) ) {
+				// Prepend if requested
+				if ( dataType.charAt( 0 ) === "+" ) {
+					dataType = dataType.slice( 1 ) || "*";
+					(structure[ dataType ] = structure[ dataType ] || []).unshift( func );
+
+				// Otherwise append
+				} else {
+					(structure[ dataType ] = structure[ dataType ] || []).push( func );
+				}
+			}
+		}
+	};
+}
+
+// Base inspection function for prefilters and transports
+function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
+
+	var inspected = {},
+		seekingTransport = ( structure === transports );
+
+	function inspect( dataType ) {
+		var selected;
+		inspected[ dataType ] = true;
+		jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
+			var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
+			if ( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {
+				options.dataTypes.unshift( dataTypeOrTransport );
+				inspect( dataTypeOrTransport );
+				return false;
+			} else if ( seekingTransport ) {
+				return !( selected = dataTypeOrTransport );
+			}
+		});
+		return selected;
+	}
+
+	return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
+}
+
+// A special extend for ajax options
+// that takes "flat" options (not to be deep extended)
+// Fixes #9887
+function ajaxExtend( target, src ) {
+	var deep, key,
+		flatOptions = jQuery.ajaxSettings.flatOptions || {};
+
+	for ( key in src ) {
+		if ( src[ key ] !== undefined ) {
+			( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ];
+		}
+	}
+	if ( deep ) {
+		jQuery.extend( true, target, deep );
+	}
+
+	return target;
+}
+
+/* Handles responses to an ajax request:
+ * - finds the right dataType (mediates between content-type and expected dataType)
+ * - returns the corresponding response
+ */
+function ajaxHandleResponses( s, jqXHR, responses ) {
+	var firstDataType, ct, finalDataType, type,
+		contents = s.contents,
+		dataTypes = s.dataTypes;
+
+	// Remove auto dataType and get content-type in the process
+	while ( dataTypes[ 0 ] === "*" ) {
+		dataTypes.shift();
+		if ( ct === undefined ) {
+			ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
+		}
+	}
+
+	// Check if we're dealing with a known content-type
+	if ( ct ) {
+		for ( type in contents ) {
+			if ( contents[ type ] && contents[ type ].test( ct ) ) {
+				dataTypes.unshift( type );
+				break;
+			}
+		}
+	}
+
+	// Check to see if we have a response for the expected dataType
+	if ( dataTypes[ 0 ] in responses ) {
+		finalDataType = dataTypes[ 0 ];
+	} else {
+		// Try convertible dataTypes
+		for ( type in responses ) {
+			if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
+				finalDataType = type;
+				break;
+			}
+			if ( !firstDataType ) {
+				firstDataType = type;
+			}
+		}
+		// Or just use first one
+		finalDataType = finalDataType || firstDataType;
+	}
+
+	// If we found a dataType
+	// We add the dataType to the list if needed
+	// and return the corresponding response
+	if ( finalDataType ) {
+		if ( finalDataType !== dataTypes[ 0 ] ) {
+			dataTypes.unshift( finalDataType );
+		}
+		return responses[ finalDataType ];
+	}
+}
+
+/* Chain conversions given the request and the original response
+ * Also sets the responseXXX fields on the jqXHR instance
+ */
+function ajaxConvert( s, response, jqXHR, isSuccess ) {
+	var conv2, current, conv, tmp, prev,
+		converters = {},
+		// Work with a copy of dataTypes in case we need to modify it for conversion
+		dataTypes = s.dataTypes.slice();
+
+	// Create converters map with lowercased keys
+	if ( dataTypes[ 1 ] ) {
+		for ( conv in s.converters ) {
+			converters[ conv.toLowerCase() ] = s.converters[ conv ];
+		}
+	}
+
+	current = dataTypes.shift();
+
+	// Convert to each sequential dataType
+	while ( current ) {
+
+		if ( s.responseFields[ current ] ) {
+			jqXHR[ s.responseFields[ current ] ] = response;
+		}
+
+		// Apply the dataFilter if provided
+		if ( !prev && isSuccess && s.dataFilter ) {
+			response = s.dataFilter( response, s.dataType );
+		}
+
+		prev = current;
+		current = dataTypes.shift();
+
+		if ( current ) {
+
+			// There's only work to do if current dataType is non-auto
+			if ( current === "*" ) {
+
+				current = prev;
+
+			// Convert response if prev dataType is non-auto and differs from current
+			} else if ( prev !== "*" && prev !== current ) {
+
+				// Seek a direct converter
+				conv = converters[ prev + " " + current ] || converters[ "* " + current ];
+
+				// If none found, seek a pair
+				if ( !conv ) {
+					for ( conv2 in converters ) {
+
+						// If conv2 outputs current
+						tmp = conv2.split( " " );
+						if ( tmp[ 1 ] === current ) {
+
+							// If prev can be converted to accepted input
+							conv = converters[ prev + " " + tmp[ 0 ] ] ||
+								converters[ "* " + tmp[ 0 ] ];
+							if ( conv ) {
+								// Condense equivalence converters
+								if ( conv === true ) {
+									conv = converters[ conv2 ];
+
+								// Otherwise, insert the intermediate dataType
+								} else if ( converters[ conv2 ] !== true ) {
+									current = tmp[ 0 ];
+									dataTypes.unshift( tmp[ 1 ] );
+								}
+								break;
+							}
+						}
+					}
+				}
+
+				// Apply converter (if not an equivalence)
+				if ( conv !== true ) {
+
+					// Unless errors are allowed to bubble, catch and return them
+					if ( conv && s[ "throws" ] ) {
+						response = conv( response );
+					} else {
+						try {
+							response = conv( response );
+						} catch ( e ) {
+							return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current };
+						}
+					}
+				}
+			}
+		}
+	}
+
+	return { state: "success", data: response };
+}
+
+jQuery.extend({
+
+	// Counter for holding the number of active queries
+	active: 0,
+
+	// Last-Modified header cache for next request
+	lastModified: {},
+	etag: {},
+
+	ajaxSettings: {
+		url: ajaxLocation,
+		type: "GET",
+		isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
+		global: true,
+		processData: true,
+		async: true,
+		contentType: "application/x-www-form-urlencoded; charset=UTF-8",
+		/*
+		timeout: 0,
+		data: null,
+		dataType: null,
+		username: null,
+		password: null,
+		cache: null,
+		throws: false,
+		traditional: false,
+		headers: {},
+		*/
+
+		accepts: {
+			"*": allTypes,
+			text: "text/plain",
+			html: "text/html",
+			xml: "application/xml, text/xml",
+			json: "application/json, text/javascript"
+		},
+
+		contents: {
+			xml: /xml/,
+			html: /html/,
+			json: /json/
+		},
+
+		responseFields: {
+			xml: "responseXML",
+			text: "responseText",
+			json: "responseJSON"
+		},
+
+		// Data converters
+		// Keys separate source (or catchall "*") and destination types with a single space
+		converters: {
+
+			// Convert anything to text
+			"* text": String,
+
+			// Text to html (true = no transformation)
+			"text html": true,
+
+			// Evaluate text as a json expression
+			"text json": jQuery.parseJSON,
+
+			// Parse text as xml
+			"text xml": jQuery.parseXML
+		},
+
+		// For options that shouldn't be deep extended:
+		// you can add your own custom options here if
+		// and when you create one that shouldn't be
+		// deep extended (see ajaxExtend)
+		flatOptions: {
+			url: true,
+			context: true
+		}
+	},
+
+	// Creates a full fledged settings object into target
+	// with both ajaxSettings and settings fields.
+	// If target is omitted, writes into ajaxSettings.
+	ajaxSetup: function( target, settings ) {
+		return settings ?
+
+			// Building a settings object
+			ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
+
+			// Extending ajaxSettings
+			ajaxExtend( jQuery.ajaxSettings, target );
+	},
+
+	ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
+	ajaxTransport: addToPrefiltersOrTransports( transports ),
+
+	// Main method
+	ajax: function( url, options ) {
+
+		// If url is an object, simulate pre-1.5 signature
+		if ( typeof url === "object" ) {
+			options = url;
+			url = undefined;
+		}
+
+		// Force options to be an object
+		options = options || {};
+
+		var // Cross-domain detection vars
+			parts,
+			// Loop variable
+			i,
+			// URL without anti-cache param
+			cacheURL,
+			// Response headers as string
+			responseHeadersString,
+			// timeout handle
+			timeoutTimer,
+
+			// To know if global events are to be dispatched
+			fireGlobals,
+
+			transport,
+			// Response headers
+			responseHeaders,
+			// Create the final options object
+			s = jQuery.ajaxSetup( {}, options ),
+			// Callbacks context
+			callbackContext = s.context || s,
+			// Context for global events is callbackContext if it is a DOM node or jQuery collection
+			globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?
+				jQuery( callbackContext ) :
+				jQuery.event,
+			// Deferreds
+			deferred = jQuery.Deferred(),
+			completeDeferred = jQuery.Callbacks("once memory"),
+			// Status-dependent callbacks
+			statusCode = s.statusCode || {},
+			// Headers (they are sent all at once)
+			requestHeaders = {},
+			requestHeadersNames = {},
+			// The jqXHR state
+			state = 0,
+			// Default abort message
+			strAbort = "canceled",
+			// Fake xhr
+			jqXHR = {
+				readyState: 0,
+
+				// Builds headers hashtable if needed
+				getResponseHeader: function( key ) {
+					var match;
+					if ( state === 2 ) {
+						if ( !responseHeaders ) {
+							responseHeaders = {};
+							while ( (match = rheaders.exec( responseHeadersString )) ) {
+								responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
+							}
+						}
+						match = responseHeaders[ key.toLowerCase() ];
+					}
+					return match == null ? null : match;
+				},
+
+				// Raw string
+				getAllResponseHeaders: function() {
+					return state === 2 ? responseHeadersString : null;
+				},
+
+				// Caches the header
+				setRequestHeader: function( name, value ) {
+					var lname = name.toLowerCase();
+					if ( !state ) {
+						name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
+						requestHeaders[ name ] = value;
+					}
+					return this;
+				},
+
+				// Overrides response content-type header
+				overrideMimeType: function( type ) {
+					if ( !state ) {
+						s.mimeType = type;
+					}
+					return this;
+				},
+
+				// Status-dependent callbacks
+				statusCode: function( map ) {
+					var code;
+					if ( map ) {
+						if ( state < 2 ) {
+							for ( code in map ) {
+								// Lazy-add the new callback in a way that preserves old ones
+								statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
+							}
+						} else {
+							// Execute the appropriate callbacks
+							jqXHR.always( map[ jqXHR.status ] );
+						}
+					}
+					return this;
+				},
+
+				// Cancel the request
+				abort: function( statusText ) {
+					var finalText = statusText || strAbort;
+					if ( transport ) {
+						transport.abort( finalText );
+					}
+					done( 0, finalText );
+					return this;
+				}
+			};
+
+		// Attach deferreds
+		deferred.promise( jqXHR ).complete = completeDeferred.add;
+		jqXHR.success = jqXHR.done;
+		jqXHR.error = jqXHR.fail;
+
+		// Remove hash character (#7531: and string promotion)
+		// Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
+		// Handle falsy url in the settings object (#10093: consistency with old signature)
+		// We also use the url parameter if available
+		s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
+
+		// Alias method option to type as per ticket #12004
+		s.type = options.method || options.type || s.method || s.type;
+
+		// Extract dataTypes list
+		s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( rnotwhite ) || [ "" ];
+
+		// A cross-domain request is in order when we have a protocol:host:port mismatch
+		if ( s.crossDomain == null ) {
+			parts = rurl.exec( s.url.toLowerCase() );
+			s.crossDomain = !!( parts &&
+				( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
+					( parts[ 3 ] || ( parts[ 1 ] === "http:" ? "80" : "443" ) ) !==
+						( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? "80" : "443" ) ) )
+			);
+		}
+
+		// Convert data if not already a string
+		if ( s.data && s.processData && typeof s.data !== "string" ) {
+			s.data = jQuery.param( s.data, s.traditional );
+		}
+
+		// Apply prefilters
+		inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
+
+		// If request was aborted inside a prefilter, stop there
+		if ( state === 2 ) {
+			return jqXHR;
+		}
+
+		// We can fire global events as of now if asked to
+		// Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)
+		fireGlobals = jQuery.event && s.global;
+
+		// Watch for a new set of requests
+		if ( fireGlobals && jQuery.active++ === 0 ) {
+			jQuery.event.trigger("ajaxStart");
+		}
+
+		// Uppercase the type
+		s.type = s.type.toUpperCase();
+
+		// Determine if request has content
+		s.hasContent = !rnoContent.test( s.type );
+
+		// Save the URL in case we're toying with the If-Modified-Since
+		// and/or If-None-Match header later on
+		cacheURL = s.url;
+
+		// More options handling for requests with no content
+		if ( !s.hasContent ) {
+
+			// If data is available, append data to url
+			if ( s.data ) {
+				cacheURL = ( s.url += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data );
+				// #9682: remove data so that it's not used in an eventual retry
+				delete s.data;
+			}
+
+			// Add anti-cache in url if needed
+			if ( s.cache === false ) {
+				s.url = rts.test( cacheURL ) ?
+
+					// If there is already a '_' parameter, set its value
+					cacheURL.replace( rts, "$1_=" + nonce++ ) :
+
+					// Otherwise add one to the end
+					cacheURL + ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + nonce++;
+			}
+		}
+
+		// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+		if ( s.ifModified ) {
+			if ( jQuery.lastModified[ cacheURL ] ) {
+				jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
+			}
+			if ( jQuery.etag[ cacheURL ] ) {
+				jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
+			}
+		}
+
+		// Set the correct header, if data is being sent
+		if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
+			jqXHR.setRequestHeader( "Content-Type", s.contentType );
+		}
+
+		// Set the Accepts header for the server, depending on the dataType
+		jqXHR.setRequestHeader(
+			"Accept",
+			s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
+				s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
+				s.accepts[ "*" ]
+		);
+
+		// Check for headers option
+		for ( i in s.headers ) {
+			jqXHR.setRequestHeader( i, s.headers[ i ] );
+		}
+
+		// Allow custom headers/mimetypes and early abort
+		if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
+			// Abort if not done already and return
+			return jqXHR.abort();
+		}
+
+		// aborting is no longer a cancellation
+		strAbort = "abort";
+
+		// Install callbacks on deferreds
+		for ( i in { success: 1, error: 1, complete: 1 } ) {
+			jqXHR[ i ]( s[ i ] );
+		}
+
+		// Get transport
+		transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
+
+		// If no transport, we auto-abort
+		if ( !transport ) {
+			done( -1, "No Transport" );
+		} else {
+			jqXHR.readyState = 1;
+
+			// Send global event
+			if ( fireGlobals ) {
+				globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
+			}
+			// Timeout
+			if ( s.async && s.timeout > 0 ) {
+				timeoutTimer = setTimeout(function() {
+					jqXHR.abort("timeout");
+				}, s.timeout );
+			}
+
+			try {
+				state = 1;
+				transport.send( requestHeaders, done );
+			} catch ( e ) {
+				// Propagate exception as error if not done
+				if ( state < 2 ) {
+					done( -1, e );
+				// Simply rethrow otherwise
+				} else {
+					throw e;
+				}
+			}
+		}
+
+		// Callback for when everything is done
+		function done( status, nativeStatusText, responses, headers ) {
+			var isSuccess, success, error, response, modified,
+				statusText = nativeStatusText;
+
+			// Called once
+			if ( state === 2 ) {
+				return;
+			}
+
+			// State is "done" now
+			state = 2;
+
+			// Clear timeout if it exists
+			if ( timeoutTimer ) {
+				clearTimeout( timeoutTimer );
+			}
+
+			// Dereference transport for early garbage collection
+			// (no matter how long the jqXHR object will be used)
+			transport = undefined;
+
+			// Cache response headers
+			responseHeadersString = headers || "";
+
+			// Set readyState
+			jqXHR.readyState = status > 0 ? 4 : 0;
+
+			// Determine if successful
+			isSuccess = status >= 200 && status < 300 || status === 304;
+
+			// Get response data
+			if ( responses ) {
+				response = ajaxHandleResponses( s, jqXHR, responses );
+			}
+
+			// Convert no matter what (that way responseXXX fields are always set)
+			response = ajaxConvert( s, response, jqXHR, isSuccess );
+
+			// If successful, handle type chaining
+			if ( isSuccess ) {
+
+				// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+				if ( s.ifModified ) {
+					modified = jqXHR.getResponseHeader("Last-Modified");
+					if ( modified ) {
+						jQuery.lastModified[ cacheURL ] = modified;
+					}
+					modified = jqXHR.getResponseHeader("etag");
+					if ( modified ) {
+						jQuery.etag[ cacheURL ] = modified;
+					}
+				}
+
+				// if no content
+				if ( status === 204 || s.type === "HEAD" ) {
+					statusText = "nocontent";
+
+				// if not modified
+				} else if ( status === 304 ) {
+					statusText = "notmodified";
+
+				// If we have data, let's convert it
+				} else {
+					statusText = response.state;
+					success = response.data;
+					error = response.error;
+					isSuccess = !error;
+				}
+			} else {
+				// We extract error from statusText
+				// then normalize statusText and status for non-aborts
+				error = statusText;
+				if ( status || !statusText ) {
+					statusText = "error";
+					if ( status < 0 ) {
+						status = 0;
+					}
+				}
+			}
+
+			// Set data for the fake xhr object
+			jqXHR.status = status;
+			jqXHR.statusText = ( nativeStatusText || statusText ) + "";
+
+			// Success/Error
+			if ( isSuccess ) {
+				deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
+			} else {
+				deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
+			}
+
+			// Status-dependent callbacks
+			jqXHR.statusCode( statusCode );
+			statusCode = undefined;
+
+			if ( fireGlobals ) {
+				globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
+					[ jqXHR, s, isSuccess ? success : error ] );
+			}
+
+			// Complete
+			completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
+
+			if ( fireGlobals ) {
+				globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
+				// Handle the global AJAX counter
+				if ( !( --jQuery.active ) ) {
+					jQuery.event.trigger("ajaxStop");
+				}
+			}
+		}
+
+		return jqXHR;
+	},
+
+	getJSON: function( url, data, callback ) {
+		return jQuery.get( url, data, callback, "json" );
+	},
+
+	getScript: function( url, callback ) {
+		return jQuery.get( url, undefined, callback, "script" );
+	}
+});
+
+jQuery.each( [ "get", "post" ], function( i, method ) {
+	jQuery[ method ] = function( url, data, callback, type ) {
+		// shift arguments if data argument was omitted
+		if ( jQuery.isFunction( data ) ) {
+			type = type || callback;
+			callback = data;
+			data = undefined;
+		}
+
+		return jQuery.ajax({
+			url: url,
+			type: method,
+			dataType: type,
+			data: data,
+			success: callback
+		});
+	};
+});
+
+
+jQuery._evalUrl = function( url ) {
+	return jQuery.ajax({
+		url: url,
+		type: "GET",
+		dataType: "script",
+		async: false,
+		global: false,
+		"throws": true
+	});
+};
+
+
+jQuery.fn.extend({
+	wrapAll: function( html ) {
+		if ( jQuery.isFunction( html ) ) {
+			return this.each(function(i) {
+				jQuery(this).wrapAll( html.call(this, i) );
+			});
+		}
+
+		if ( this[0] ) {
+			// The elements to wrap the target around
+			var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
+
+			if ( this[0].parentNode ) {
+				wrap.insertBefore( this[0] );
+			}
+
+			wrap.map(function() {
+				var elem = this;
+
+				while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
+					elem = elem.firstChild;
+				}
+
+				return elem;
+			}).append( this );
+		}
+
+		return this;
+	},
+
+	wrapInner: function( html ) {
+		if ( jQuery.isFunction( html ) ) {
+			return this.each(function(i) {
+				jQuery(this).wrapInner( html.call(this, i) );
+			});
+		}
+
+		return this.each(function() {
+			var self = jQuery( this ),
+				contents = self.contents();
+
+			if ( contents.length ) {
+				contents.wrapAll( html );
+
+			} else {
+				self.append( html );
+			}
+		});
+	},
+
+	wrap: function( html ) {
+		var isFunction = jQuery.isFunction( html );
+
+		return this.each(function(i) {
+			jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
+		});
+	},
+
+	unwrap: function() {
+		return this.parent().each(function() {
+			if ( !jQuery.nodeName( this, "body" ) ) {
+				jQuery( this ).replaceWith( this.childNodes );
+			}
+		}).end();
+	}
+});
+
+
+jQuery.expr.filters.hidden = function( elem ) {
+	// Support: Opera <= 12.12
+	// Opera reports offsetWidths and offsetHeights less than zero on some elements
+	return elem.offsetWidth <= 0 && elem.offsetHeight <= 0 ||
+		(!support.reliableHiddenOffsets() &&
+			((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none");
+};
+
+jQuery.expr.filters.visible = function( elem ) {
+	return !jQuery.expr.filters.hidden( elem );
+};
+
+
+
+
+var r20 = /%20/g,
+	rbracket = /\[\]$/,
+	rCRLF = /\r?\n/g,
+	rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
+	rsubmittable = /^(?:input|select|textarea|keygen)/i;
+
+function buildParams( prefix, obj, traditional, add ) {
+	var name;
+
+	if ( jQuery.isArray( obj ) ) {
+		// Serialize array item.
+		jQuery.each( obj, function( i, v ) {
+			if ( traditional || rbracket.test( prefix ) ) {
+				// Treat each array item as a scalar.
+				add( prefix, v );
+
+			} else {
+				// Item is non-scalar (array or object), encode its numeric index.
+				buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
+			}
+		});
+
+	} else if ( !traditional && jQuery.type( obj ) === "object" ) {
+		// Serialize object item.
+		for ( name in obj ) {
+			buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
+		}
+
+	} else {
+		// Serialize scalar item.
+		add( prefix, obj );
+	}
+}
+
+// Serialize an array of form elements or a set of
+// key/values into a query string
+jQuery.param = function( a, traditional ) {
+	var prefix,
+		s = [],
+		add = function( key, value ) {
+			// If value is a function, invoke it and return its value
+			value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
+			s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
+		};
+
+	// Set traditional to true for jQuery <= 1.3.2 behavior.
+	if ( traditional === undefined ) {
+		traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
+	}
+
+	// If an array was passed in, assume that it is an array of form elements.
+	if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
+		// Serialize the form elements
+		jQuery.each( a, function() {
+			add( this.name, this.value );
+		});
+
+	} else {
+		// If traditional, encode the "old" way (the way 1.3.2 or older
+		// did it), otherwise encode params recursively.
+		for ( prefix in a ) {
+			buildParams( prefix, a[ prefix ], traditional, add );
+		}
+	}
+
+	// Return the resulting serialization
+	return s.join( "&" ).replace( r20, "+" );
+};
+
+jQuery.fn.extend({
+	serialize: function() {
+		return jQuery.param( this.serializeArray() );
+	},
+	serializeArray: function() {
+		return this.map(function() {
+			// Can add propHook for "elements" to filter or add form elements
+			var elements = jQuery.prop( this, "elements" );
+			return elements ? jQuery.makeArray( elements ) : this;
+		})
+		.filter(function() {
+			var type = this.type;
+			// Use .is(":disabled") so that fieldset[disabled] works
+			return this.name && !jQuery( this ).is( ":disabled" ) &&
+				rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
+				( this.checked || !rcheckableType.test( type ) );
+		})
+		.map(function( i, elem ) {
+			var val = jQuery( this ).val();
+
+			return val == null ?
+				null :
+				jQuery.isArray( val ) ?
+					jQuery.map( val, function( val ) {
+						return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+					}) :
+					{ name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+		}).get();
+	}
+});
+
+
+// Create the request object
+// (This is still attached to ajaxSettings for backward compatibility)
+jQuery.ajaxSettings.xhr = window.ActiveXObject !== undefined ?
+	// Support: IE6+
+	function() {
+
+		// XHR cannot access local files, always use ActiveX for that case
+		return !this.isLocal &&
+
+			// Support: IE7-8
+			// oldIE XHR does not support non-RFC2616 methods (#13240)
+			// See http://msdn.microsoft.com/en-us/library/ie/ms536648(v=vs.85).aspx
+			// and http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9
+			// Although this check for six methods instead of eight
+			// since IE also does not support "trace" and "connect"
+			/^(get|post|head|put|delete|options)$/i.test( this.type ) &&
+
+			createStandardXHR() || createActiveXHR();
+	} :
+	// For all other browsers, use the standard XMLHttpRequest object
+	createStandardXHR;
+
+var xhrId = 0,
+	xhrCallbacks = {},
+	xhrSupported = jQuery.ajaxSettings.xhr();
+
+// Support: IE<10
+// Open requests must be manually aborted on unload (#5280)
+// See https://support.microsoft.com/kb/2856746 for more info
+if ( window.attachEvent ) {
+	window.attachEvent( "onunload", function() {
+		for ( var key in xhrCallbacks ) {
+			xhrCallbacks[ key ]( undefined, true );
+		}
+	});
+}
+
+// Determine support properties
+support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
+xhrSupported = support.ajax = !!xhrSupported;
+
+// Create transport if the browser can provide an xhr
+if ( xhrSupported ) {
+
+	jQuery.ajaxTransport(function( options ) {
+		// Cross domain only allowed if supported through XMLHttpRequest
+		if ( !options.crossDomain || support.cors ) {
+
+			var callback;
+
+			return {
+				send: function( headers, complete ) {
+					var i,
+						xhr = options.xhr(),
+						id = ++xhrId;
+
+					// Open the socket
+					xhr.open( options.type, options.url, options.async, options.username, options.password );
+
+					// Apply custom fields if provided
+					if ( options.xhrFields ) {
+						for ( i in options.xhrFields ) {
+							xhr[ i ] = options.xhrFields[ i ];
+						}
+					}
+
+					// Override mime type if needed
+					if ( options.mimeType && xhr.overrideMimeType ) {
+						xhr.overrideMimeType( options.mimeType );
+					}
+
+					// X-Requested-With header
+					// For cross-domain requests, seeing as conditions for a preflight are
+					// akin to a jigsaw puzzle, we simply never set it to be sure.
+					// (it can always be set on a per-request basis or even using ajaxSetup)
+					// For same-domain requests, won't change header if already provided.
+					if ( !options.crossDomain && !headers["X-Requested-With"] ) {
+						headers["X-Requested-With"] = "XMLHttpRequest";
+					}
+
+					// Set headers
+					for ( i in headers ) {
+						// Support: IE<9
+						// IE's ActiveXObject throws a 'Type Mismatch' exception when setting
+						// request header to a null-value.
+						//
+						// To keep consistent with other XHR implementations, cast the value
+						// to string and ignore `undefined`.
+						if ( headers[ i ] !== undefined ) {
+							xhr.setRequestHeader( i, headers[ i ] + "" );
+						}
+					}
+
+					// Do send the request
+					// This may raise an exception which is actually
+					// handled in jQuery.ajax (so no try/catch here)
+					xhr.send( ( options.hasContent && options.data ) || null );
+
+					// Listener
+					callback = function( _, isAbort ) {
+						var status, statusText, responses;
+
+						// Was never called and is aborted or complete
+						if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
+							// Clean up
+							delete xhrCallbacks[ id ];
+							callback = undefined;
+							xhr.onreadystatechange = jQuery.noop;
+
+							// Abort manually if needed
+							if ( isAbort ) {
+								if ( xhr.readyState !== 4 ) {
+									xhr.abort();
+								}
+							} else {
+								responses = {};
+								status = xhr.status;
+
+								// Support: IE<10
+								// Accessing binary-data responseText throws an exception
+								// (#11426)
+								if ( typeof xhr.responseText === "string" ) {
+									responses.text = xhr.responseText;
+								}
+
+								// Firefox throws an exception when accessing
+								// statusText for faulty cross-domain requests
+								try {
+									statusText = xhr.statusText;
+								} catch( e ) {
+									// We normalize with Webkit giving an empty statusText
+									statusText = "";
+								}
+
+								// Filter status for non standard behaviors
+
+								// If the request is local and we have data: assume a success
+								// (success with no data won't get notified, that's the best we
+								// can do given current implementations)
+								if ( !status && options.isLocal && !options.crossDomain ) {
+									status = responses.text ? 200 : 404;
+								// IE - #1450: sometimes returns 1223 when it should be 204
+								} else if ( status === 1223 ) {
+									status = 204;
+								}
+							}
+						}
+
+						// Call complete if needed
+						if ( responses ) {
+							complete( status, statusText, responses, xhr.getAllResponseHeaders() );
+						}
+					};
+
+					if ( !options.async ) {
+						// if we're in sync mode we fire the callback
+						callback();
+					} else if ( xhr.readyState === 4 ) {
+						// (IE6 & IE7) if it's in cache and has been
+						// retrieved directly we need to fire the callback
+						setTimeout( callback );
+					} else {
+						// Add to the list of active xhr callbacks
+						xhr.onreadystatechange = xhrCallbacks[ id ] = callback;
+					}
+				},
+
+				abort: function() {
+					if ( callback ) {
+						callback( undefined, true );
+					}
+				}
+			};
+		}
+	});
+}
+
+// Functions to create xhrs
+function createStandardXHR() {
+	try {
+		return new window.XMLHttpRequest();
+	} catch( e ) {}
+}
+
+function createActiveXHR() {
+	try {
+		return new window.ActiveXObject( "Microsoft.XMLHTTP" );
+	} catch( e ) {}
+}
+
+
+
+
+// Install script dataType
+jQuery.ajaxSetup({
+	accepts: {
+		script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
+	},
+	contents: {
+		script: /(?:java|ecma)script/
+	},
+	converters: {
+		"text script": function( text ) {
+			jQuery.globalEval( text );
+			return text;
+		}
+	}
+});
+
+// Handle cache's special case and global
+jQuery.ajaxPrefilter( "script", function( s ) {
+	if ( s.cache === undefined ) {
+		s.cache = false;
+	}
+	if ( s.crossDomain ) {
+		s.type = "GET";
+		s.global = false;
+	}
+});
+
+// Bind script tag hack transport
+jQuery.ajaxTransport( "script", function(s) {
+
+	// This transport only deals with cross domain requests
+	if ( s.crossDomain ) {
+
+		var script,
+			head = document.head || jQuery("head")[0] || document.documentElement;
+
+		return {
+
+			send: function( _, callback ) {
+
+				script = document.createElement("script");
+
+				script.async = true;
+
+				if ( s.scriptCharset ) {
+					script.charset = s.scriptCharset;
+				}
+
+				script.src = s.url;
+
+				// Attach handlers for all browsers
+				script.onload = script.onreadystatechange = function( _, isAbort ) {
+
+					if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
+
+						// Handle memory leak in IE
+						script.onload = script.onreadystatechange = null;
+
+						// Remove the script
+						if ( script.parentNode ) {
+							script.parentNode.removeChild( script );
+						}
+
+						// Dereference the script
+						script = null;
+
+						// Callback if not abort
+						if ( !isAbort ) {
+							callback( 200, "success" );
+						}
+					}
+				};
+
+				// Circumvent IE6 bugs with base elements (#2709 and #4378) by prepending
+				// Use native DOM manipulation to avoid our domManip AJAX trickery
+				head.insertBefore( script, head.firstChild );
+			},
+
+			abort: function() {
+				if ( script ) {
+					script.onload( undefined, true );
+				}
+			}
+		};
+	}
+});
+
+
+
+
+var oldCallbacks = [],
+	rjsonp = /(=)\?(?=&|$)|\?\?/;
+
+// Default jsonp settings
+jQuery.ajaxSetup({
+	jsonp: "callback",
+	jsonpCallback: function() {
+		var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) );
+		this[ callback ] = true;
+		return callback;
+	}
+});
+
+// Detect, normalize options and install callbacks for jsonp requests
+jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
+
+	var callbackName, overwritten, responseContainer,
+		jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
+			"url" :
+			typeof s.data === "string" && !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && rjsonp.test( s.data ) && "data"
+		);
+
+	// Handle iff the expected data type is "jsonp" or we have a parameter to set
+	if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
+
+		// Get callback name, remembering preexisting value associated with it
+		callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
+			s.jsonpCallback() :
+			s.jsonpCallback;
+
+		// Insert callback into url or form data
+		if ( jsonProp ) {
+			s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
+		} else if ( s.jsonp !== false ) {
+			s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
+		}
+
+		// Use data converter to retrieve json after script execution
+		s.converters["script json"] = function() {
+			if ( !responseContainer ) {
+				jQuery.error( callbackName + " was not called" );
+			}
+			return responseContainer[ 0 ];
+		};
+
+		// force json dataType
+		s.dataTypes[ 0 ] = "json";
+
+		// Install callback
+		overwritten = window[ callbackName ];
+		window[ callbackName ] = function() {
+			responseContainer = arguments;
+		};
+
+		// Clean-up function (fires after converters)
+		jqXHR.always(function() {
+			// Restore preexisting value
+			window[ callbackName ] = overwritten;
+
+			// Save back as free
+			if ( s[ callbackName ] ) {
+				// make sure that re-using the options doesn't screw things around
+				s.jsonpCallback = originalSettings.jsonpCallback;
+
+				// save the callback name for future use
+				oldCallbacks.push( callbackName );
+			}
+
+			// Call if it was a function and we have a response
+			if ( responseContainer && jQuery.isFunction( overwritten ) ) {
+				overwritten( responseContainer[ 0 ] );
+			}
+
+			responseContainer = overwritten = undefined;
+		});
+
+		// Delegate to script
+		return "script";
+	}
+});
+
+
+
+
+// data: string of html
+// context (optional): If specified, the fragment will be created in this context, defaults to document
+// keepScripts (optional): If true, will include scripts passed in the html string
+jQuery.parseHTML = function( data, context, keepScripts ) {
+	if ( !data || typeof data !== "string" ) {
+		return null;
+	}
+	if ( typeof context === "boolean" ) {
+		keepScripts = context;
+		context = false;
+	}
+	context = context || document;
+
+	var parsed = rsingleTag.exec( data ),
+		scripts = !keepScripts && [];
+
+	// Single tag
+	if ( parsed ) {
+		return [ context.createElement( parsed[1] ) ];
+	}
+
+	parsed = jQuery.buildFragment( [ data ], context, scripts );
+
+	if ( scripts && scripts.length ) {
+		jQuery( scripts ).remove();
+	}
+
+	return jQuery.merge( [], parsed.childNodes );
+};
+
+
+// Keep a copy of the old load method
+var _load = jQuery.fn.load;
+
+/**
+ * Load a url into a page
+ */
+jQuery.fn.load = function( url, params, callback ) {
+	if ( typeof url !== "string" && _load ) {
+		return _load.apply( this, arguments );
+	}
+
+	var selector, response, type,
+		self = this,
+		off = url.indexOf(" ");
+
+	if ( off >= 0 ) {
+		selector = jQuery.trim( url.slice( off, url.length ) );
+		url = url.slice( 0, off );
+	}
+
+	// If it's a function
+	if ( jQuery.isFunction( params ) ) {
+
+		// We assume that it's the callback
+		callback = params;
+		params = undefined;
+
+	// Otherwise, build a param string
+	} else if ( params && typeof params === "object" ) {
+		type = "POST";
+	}
+
+	// If we have elements to modify, make the request
+	if ( self.length > 0 ) {
+		jQuery.ajax({
+			url: url,
+
+			// if "type" variable is undefined, then "GET" method will be used
+			type: type,
+			dataType: "html",
+			data: params
+		}).done(function( responseText ) {
+
+			// Save response for use in complete callback
+			response = arguments;
+
+			self.html( selector ?
+
+				// If a selector was specified, locate the right elements in a dummy div
+				// Exclude scripts to avoid IE 'Permission Denied' errors
+				jQuery("<div>").append( jQuery.parseHTML( responseText ) ).find( selector ) :
+
+				// Otherwise use the full result
+				responseText );
+
+		}).complete( callback && function( jqXHR, status ) {
+			self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );
+		});
+	}
+
+	return this;
+};
+
+
+
+
+// Attach a bunch of functions for handling common AJAX events
+jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ) {
+	jQuery.fn[ type ] = function( fn ) {
+		return this.on( type, fn );
+	};
+});
+
+
+
+
+jQuery.expr.filters.animated = function( elem ) {
+	return jQuery.grep(jQuery.timers, function( fn ) {
+		return elem === fn.elem;
+	}).length;
+};
+
+
+
+
+
+var docElem = window.document.documentElement;
+
+/**
+ * Gets a window from an element
+ */
+function getWindow( elem ) {
+	return jQuery.isWindow( elem ) ?
+		elem :
+		elem.nodeType === 9 ?
+			elem.defaultView || elem.parentWindow :
+			false;
+}
+
+jQuery.offset = {
+	setOffset: function( elem, options, i ) {
+		var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,
+			position = jQuery.css( elem, "position" ),
+			curElem = jQuery( elem ),
+			props = {};
+
+		// set position first, in-case top/left are set even on static elem
+		if ( position === "static" ) {
+			elem.style.position = "relative";
+		}
+
+		curOffset = curElem.offset();
+		curCSSTop = jQuery.css( elem, "top" );
+		curCSSLeft = jQuery.css( elem, "left" );
+		calculatePosition = ( position === "absolute" || position === "fixed" ) &&
+			jQuery.inArray("auto", [ curCSSTop, curCSSLeft ] ) > -1;
+
+		// need to be able to calculate position if either top or left is auto and position is either absolute or fixed
+		if ( calculatePosition ) {
+			curPosition = curElem.position();
+			curTop = curPosition.top;
+			curLeft = curPosition.left;
+		} else {
+			curTop = parseFloat( curCSSTop ) || 0;
+			curLeft = parseFloat( curCSSLeft ) || 0;
+		}
+
+		if ( jQuery.isFunction( options ) ) {
+			options = options.call( elem, i, curOffset );
+		}
+
+		if ( options.top != null ) {
+			props.top = ( options.top - curOffset.top ) + curTop;
+		}
+		if ( options.left != null ) {
+			props.left = ( options.left - curOffset.left ) + curLeft;
+		}
+
+		if ( "using" in options ) {
+			options.using.call( elem, props );
+		} else {
+			curElem.css( props );
+		}
+	}
+};
+
+jQuery.fn.extend({
+	offset: function( options ) {
+		if ( arguments.length ) {
+			return options === undefined ?
+				this :
+				this.each(function( i ) {
+					jQuery.offset.setOffset( this, options, i );
+				});
+		}
+
+		var docElem, win,
+			box = { top: 0, left: 0 },
+			elem = this[ 0 ],
+			doc = elem && elem.ownerDocument;
+
+		if ( !doc ) {
+			return;
+		}
+
+		docElem = doc.documentElement;
+
+		// Make sure it's not a disconnected DOM node
+		if ( !jQuery.contains( docElem, elem ) ) {
+			return box;
+		}
+
+		// If we don't have gBCR, just use 0,0 rather than error
+		// BlackBerry 5, iOS 3 (original iPhone)
+		if ( typeof elem.getBoundingClientRect !== strundefined ) {
+			box = elem.getBoundingClientRect();
+		}
+		win = getWindow( doc );
+		return {
+			top: box.top  + ( win.pageYOffset || docElem.scrollTop )  - ( docElem.clientTop  || 0 ),
+			left: box.left + ( win.pageXOffset || docElem.scrollLeft ) - ( docElem.clientLeft || 0 )
+		};
+	},
+
+	position: function() {
+		if ( !this[ 0 ] ) {
+			return;
+		}
+
+		var offsetParent, offset,
+			parentOffset = { top: 0, left: 0 },
+			elem = this[ 0 ];
+
+		// fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is its only offset parent
+		if ( jQuery.css( elem, "position" ) === "fixed" ) {
+			// we assume that getBoundingClientRect is available when computed position is fixed
+			offset = elem.getBoundingClientRect();
+		} else {
+			// Get *real* offsetParent
+			offsetParent = this.offsetParent();
+
+			// Get correct offsets
+			offset = this.offset();
+			if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) {
+				parentOffset = offsetParent.offset();
+			}
+
+			// Add offsetParent borders
+			parentOffset.top  += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true );
+			parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true );
+		}
+
+		// Subtract parent offsets and element margins
+		// note: when an element has margin: auto the offsetLeft and marginLeft
+		// are the same in Safari causing offset.left to incorrectly be 0
+		return {
+			top:  offset.top  - parentOffset.top - jQuery.css( elem, "marginTop", true ),
+			left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true)
+		};
+	},
+
+	offsetParent: function() {
+		return this.map(function() {
+			var offsetParent = this.offsetParent || docElem;
+
+			while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && jQuery.css( offsetParent, "position" ) === "static" ) ) {
+				offsetParent = offsetParent.offsetParent;
+			}
+			return offsetParent || docElem;
+		});
+	}
+});
+
+// Create scrollLeft and scrollTop methods
+jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) {
+	var top = /Y/.test( prop );
+
+	jQuery.fn[ method ] = function( val ) {
+		return access( this, function( elem, method, val ) {
+			var win = getWindow( elem );
+
+			if ( val === undefined ) {
+				return win ? (prop in win) ? win[ prop ] :
+					win.document.documentElement[ method ] :
+					elem[ method ];
+			}
+
+			if ( win ) {
+				win.scrollTo(
+					!top ? val : jQuery( win ).scrollLeft(),
+					top ? val : jQuery( win ).scrollTop()
+				);
+
+			} else {
+				elem[ method ] = val;
+			}
+		}, method, val, arguments.length, null );
+	};
+});
+
+// Add the top/left cssHooks using jQuery.fn.position
+// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
+// getComputedStyle returns percent when specified for top/left/bottom/right
+// rather than make the css module depend on the offset module, we just check for it here
+jQuery.each( [ "top", "left" ], function( i, prop ) {
+	jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,
+		function( elem, computed ) {
+			if ( computed ) {
+				computed = curCSS( elem, prop );
+				// if curCSS returns percentage, fallback to offset
+				return rnumnonpx.test( computed ) ?
+					jQuery( elem ).position()[ prop ] + "px" :
+					computed;
+			}
+		}
+	);
+});
+
+
+// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
+jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
+	jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
+		// margin is only for outerHeight, outerWidth
+		jQuery.fn[ funcName ] = function( margin, value ) {
+			var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
+				extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
+
+			return access( this, function( elem, type, value ) {
+				var doc;
+
+				if ( jQuery.isWindow( elem ) ) {
+					// As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
+					// isn't a whole lot we can do. See pull request at this URL for discussion:
+					// https://github.com/jquery/jquery/pull/764
+					return elem.document.documentElement[ "client" + name ];
+				}
+
+				// Get document width or height
+				if ( elem.nodeType === 9 ) {
+					doc = elem.documentElement;
+
+					// Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest
+					// unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it.
+					return Math.max(
+						elem.body[ "scroll" + name ], doc[ "scroll" + name ],
+						elem.body[ "offset" + name ], doc[ "offset" + name ],
+						doc[ "client" + name ]
+					);
+				}
+
+				return value === undefined ?
+					// Get width or height on the element, requesting but not forcing parseFloat
+					jQuery.css( elem, type, extra ) :
+
+					// Set width or height on the element
+					jQuery.style( elem, type, value, extra );
+			}, type, chainable ? margin : undefined, chainable, null );
+		};
+	});
+});
+
+
+// The number of elements contained in the matched element set
+jQuery.fn.size = function() {
+	return this.length;
+};
+
+jQuery.fn.andSelf = jQuery.fn.addBack;
+
+
+
+
+// Register as a named AMD module, since jQuery can be concatenated with other
+// files that may use define, but not via a proper concatenation script that
+// understands anonymous AMD modules. A named AMD is safest and most robust
+// way to register. Lowercase jquery is used because AMD module names are
+// derived from file names, and jQuery is normally delivered in a lowercase
+// file name. Do this after creating the global so that if an AMD module wants
+// to call noConflict to hide this version of jQuery, it will work.
+
+// Note that for maximum portability, libraries that are not jQuery should
+// declare themselves as anonymous modules, and avoid setting a global if an
+// AMD loader is present. jQuery is a special case. For more information, see
+// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon
+
+if ( typeof define === "function" && define.amd ) {
+	define( "jquery", [], function() {
+		return jQuery;
+	});
+}
+
+
+
+
+var
+	// Map over jQuery in case of overwrite
+	_jQuery = window.jQuery,
+
+	// Map over the $ in case of overwrite
+	_$ = window.$;
+
+jQuery.noConflict = function( deep ) {
+	if ( window.$ === jQuery ) {
+		window.$ = _$;
+	}
+
+	if ( deep && window.jQuery === jQuery ) {
+		window.jQuery = _jQuery;
+	}
+
+	return jQuery;
+};
+
+// Expose jQuery and $ identifiers, even in
+// AMD (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
+// and CommonJS for browser emulators (#13566)
+if ( typeof noGlobal === strundefined ) {
+	window.jQuery = window.$ = jQuery;
+}
+
+
+
+
+return jQuery;
+
+}));
diff --git a/xos/core/xoslib/static/js/vendor/ngXosHelpers.js b/xos/core/xoslib/static/js/vendor/ngXosHelpers.js
new file mode 100644
index 0000000..eebc675
--- /dev/null
+++ b/xos/core/xoslib/static/js/vendor/ngXosHelpers.js
@@ -0,0 +1,2 @@
+"use strict";function _toConsumableArray(e){if(Array.isArray(e)){for(var n=0,o=Array(e.length);n<e.length;n++)o[n]=e[n];return o}return Array.from(e)}!function(){angular.module("xos.uiComponents",["chart.js","RecursionHelper"])}(),function(){function e(){var e=function(e){return e.split("_").join(" ").trim()},n=function(e){return e.split(/(?=[A-Z])/).map(function(e){return e.toLowerCase()}).join(" ")},o=function(e){return e.slice(0,1).toUpperCase()+e.slice(1)},i=function(i){return i=e(i),i=n(i),i=o(i).replace(/\s\s+/g," ")+":",i.replace("::",":")};return{_formatByUnderscore:e,_formatByUppercase:n,_capitalize:o,format:i}}angular.module("xos.uiComponents").factory("LabelFormatter",e)}();var _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol?"symbol":typeof e};!function(){angular.module("xos.uiComponents").service("XosFormHelpers",["_","LabelFormatter",function(e,n){var o=this;this._isEmail=function(e){var n=/(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))/;return n.test(e)},this._getFieldFormat=function(n){return angular.isArray(n)?"array":e.isDate(n)||!Number.isNaN(Date.parse(n))&&new Date(n).getTime()>6311808e5?"date":"boolean"==typeof n?"boolean":o._isEmail(n)?"email":angular.isString(n)||null===n?"text":"undefined"==typeof n?"undefined":_typeof(n)},this.buildFormStructure=function(i,t,r){return i=angular.extend(i,t),t=t||{},e.reduce(Object.keys(i),function(e,i){return e[i]={label:t[i]&&t[i].label?t[i].label+":":n.format(i),type:t[i]&&t[i].type?t[i].type:o._getFieldFormat(r[i]),validators:t[i]&&t[i].validators?t[i].validators:{},hint:t[i]&&t[i].hint?t[i].hint:""},t[i]&&t[i].options&&(e[i].options=t[i].options),t[i]&&t[i].properties&&(e[i].properties=t[i].properties),"date"===e[i].type&&(r[i]=new Date(r[i])),"number"===e[i].type&&(r[i]=parseInt(r[i],10)),e},{})},this.parseModelField=function(n){return e.reduce(n,function(e,n){return e[n]={},e},{})}}])}(),function(){function e(){return function(e,n){if(angular.isUndefined(e))return!1;if(null===e||null===n)return e===n;if(angular.isObject(n)||angular.isObject(e))return angular.equals(n,e);if(_.isBoolean(e)||_.isBoolean(n))return 0!==e&&1!==e||(e=!!e),angular.equals(n,e);if(!angular.isString(e)||!angular.isString(n)){if(!angular.isDefined(e.toString)||!angular.isDefined(n.toString))return e===n;e=e.toString(),n=n.toString()}return e=e.toLowerCase()+"",n=n.toLowerCase()+"",-1!==e.indexOf(n)}}angular.module("xos.uiComponents").factory("Comparator",e)}();var _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol?"symbol":typeof e};!function(){angular.module("xos.uiComponents").directive("xosSmartTable",function(){return{restrict:"E",scope:{config:"="},template:'\n        <div class="row" ng-show="vm.data.length > 0">\n          <div class="col-xs-12 text-right">\n            <a href="" class="btn btn-success" ng-click="vm.createItem()">\n              Add\n            </a>\n          </div>\n        </div>\n        <div class="row">\n          <div class="col-xs-12 table-responsive">\n            <xos-table config="vm.tableConfig" data="vm.data"></xos-table>\n          </div>\n        </div>\n        <div class="panel panel-default" ng-show="vm.detailedItem">\n          <div class="panel-heading">\n            <div class="row">\n              <div class="col-xs-11">\n                <h3 class="panel-title" ng-show="vm.detailedItem.id">Update {{vm.config.resource}} {{vm.detailedItem.id}}</h3>\n                <h3 class="panel-title" ng-show="!vm.detailedItem.id">Create {{vm.config.resource}} item</h3>\n              </div>\n              <div class="col-xs-1">\n                <a href="" ng-click="vm.cleanForm()">\n                  <i class="glyphicon glyphicon-remove pull-right"></i>\n                </a>\n              </div>\n            </div>\n          </div>\n          <div class="panel-body">\n            <xos-form config="vm.formConfig" ng-model="vm.detailedItem"></xos-form>\n          </div>\n        </div>\n        <xos-alert config="{type: \'success\', closeBtn: true}" show="vm.responseMsg">{{vm.responseMsg}}</xos-alert>\n        <xos-alert config="{type: \'danger\', closeBtn: true}" show="vm.responseErr">{{vm.responseErr}}</xos-alert>\n      ',bindToController:!0,controllerAs:"vm",controller:["$injector","LabelFormatter","_","XosFormHelpers",function(e,n,o,i){var t=this;this.responseMsg=!1,this.responseErr=!1,this.tableConfig={columns:[],actions:[{label:"delete",icon:"remove",cb:function(e){t.Resource["delete"]({id:e.id}).$promise.then(function(){o.remove(t.data,function(n){return n.id===e.id}),t.responseMsg=t.config.resource+" with id "+e.id+" successfully deleted"})["catch"](function(n){t.responseErr=n.data.detail||"Error while deleting "+t.config.resource+" with id "+e.id})},color:"red"},{label:"details",icon:"search",cb:function(e){t.detailedItem=e}}],classes:"table table-striped table-bordered table-responsive",filter:"field",order:!0,pagination:{pageSize:10}},this.formConfig={exclude:this.config.hiddenFields,fields:{},formName:this.config.resource+"Form",actions:[{label:"Save",icon:"ok",cb:function(e){var n=void 0,o=!0;e.id?(n=e.$update(),o=!1):n=e.$save(),n.then(function(n){o&&t.data.push(angular.copy(n)),delete t.detailedItem,t.responseMsg=t.config.resource+" with id "+e.id+" successfully saved"})["catch"](function(n){t.responseErr=n.data.detail||"Error while saving "+t.config.resource+" with id "+e.id})},"class":"success"}]},this.cleanForm=function(){delete t.detailedItem},this.createItem=function(){t.detailedItem=new t.Resource},this.Resource=e.get(this.config.resource);var r=function(){t.Resource.query().$promise.then(function(e){if(!e[0])return void(t.data=e);var r=e[0],a=Object.keys(r);o.remove(a,function(e){return"id"===e||"validators"===e}),angular.isArray(t.config.hiddenFields)&&(a=o.difference(a,t.config.hiddenFields));var s=a.map(function(e){return n.format(e)});a.forEach(function(e,n){var o={label:s[n],prop:e};angular.isString(r[e])&&"undefined"!=typeof r[e]&&(o.type=_typeof(r[e])),t.tableConfig.columns.push(o)}),a.forEach(function(e,o){t.formConfig.fields[e]={label:n.format(s[o]).replace(":",""),type:i._getFieldFormat(r[e])}}),t.data=e})};r()}]}})}(),function(){angular.module("xos.uiComponents").directive("xosSmartPie",function(){return{restrict:"E",scope:{config:"="},template:'\n        <canvas\n          class="chart chart-pie {{vm.config.classes}}"\n          chart-data="vm.data" chart-labels="vm.labels"\n          chart-legend="{{vm.config.legend}}">\n        </canvas>\n      ',bindToController:!0,controllerAs:"vm",controller:["$injector","$interval","$scope","$timeout","_",function(e,n,o,i,t){var r=this;if(!this.config.resource&&!this.config.data)throw new Error("[xosSmartPie] Please provide a resource or an array of data in the configuration");var a=function(e){return t.groupBy(e,r.config.groupBy)},s=function(e){return t.reduce(Object.keys(e),function(n,o){return n.concat(e[o].length)},[])},l=function(e){return angular.isFunction(r.config.labelFormatter)?r.config.labelFormatter(Object.keys(e)):Object.keys(e)},c=function(e){var n=a(e);r.data=s(n),r.labels=l(n)};this.config.resource?!function(){r.Resource=e.get(r.config.resource);var o=function(){r.Resource.query().$promise.then(function(e){e[0]&&c(e)})};o(),r.config.poll&&n(function(){o()},1e3*r.config.poll)}():o.$watch(function(){return r.config.data},function(e){e&&c(r.config.data)},!0),o.$on("create",function(e,n){console.log("create: "+n.id)}),o.$on("destroy",function(e,n){console.log("destroy: "+n.id)})}]}})}(),function(){angular.module("xos.uiComponents").directive("xosValidation",function(){return{restrict:"E",scope:{field:"=",form:"="},template:'\n        <div ng-cloak>\n          <xos-alert config="vm.config" show="vm.field.$error.required !== undefined && vm.field.$error.required !== false  && (vm.field.$touched || vm.form.$submitted)">\n            Field required\n          </xos-alert>\n          <xos-alert config="vm.config" show="vm.field.$error.email !== undefined && vm.field.$error.email !== false && (vm.field.$touched || vm.form.$submitted)">\n            This is not a valid email\n          </xos-alert>\n          <xos-alert config="vm.config" show="vm.field.$error.minlength !== undefined && vm.field.$error.minlength !== false && (vm.field.$touched || vm.form.$submitted)">\n            Too short\n          </xos-alert>\n          <xos-alert config="vm.config" show="vm.field.$error.maxlength !== undefined && vm.field.$error.maxlength !== false && (vm.field.$touched || vm.form.$submitted)">\n            Too long\n          </xos-alert>\n          <xos-alert config="vm.config" show="vm.field.$error.custom !== undefined && vm.field.$error.custom !== false && (vm.field.$touched || vm.form.$submitted)">\n            Field invalid\n          </xos-alert>\n        </div>\n      ',transclude:!0,bindToController:!0,controllerAs:"vm",controller:function(){this.config={type:"danger"}}}})}(),function(){angular.module("xos.uiComponents").directive("xosTable",function(){return{restrict:"E",scope:{data:"=",config:"="},template:'\n          <div ng-show="vm.data.length > 0 && vm.loader == false">\n            <div class="row" ng-if="vm.config.filter == \'fulltext\'">\n              <div class="col-xs-12">\n                <input\n                  class="form-control"\n                  placeholder="Type to search.."\n                  type="text"\n                  ng-model="vm.query"/>\n              </div>\n            </div>\n            <table ng-class="vm.classes" ng-hide="vm.data.length == 0">\n              <thead>\n                <tr>\n                  <th ng-repeat="col in vm.columns">\n                    {{col.label}}\n                    <span ng-if="vm.config.order">\n                      <a href="" ng-click="vm.orderBy = col.prop; vm.reverse = false">\n                        <i class="glyphicon glyphicon-chevron-up"></i>\n                      </a>\n                      <a href="" ng-click="vm.orderBy = col.prop; vm.reverse = true">\n                        <i class="glyphicon glyphicon-chevron-down"></i>\n                      </a>\n                    </span>\n                  </th>\n                  <th ng-if="vm.config.actions">Actions:</th>\n                </tr>\n              </thead>\n              <tbody ng-if="vm.config.filter == \'field\'">\n                <tr>\n                  <td ng-repeat="col in vm.columns">\n                    <input\n                      ng-if="col.type !== \'boolean\' && col.type !== \'array\' && col.type !== \'object\' && col.type !== \'custom\'"\n                      class="form-control"\n                      placeholder="Type to search by {{col.label}}"\n                      type="text"\n                      ng-model="vm.query[col.prop]"/>\n                    <select\n                      ng-if="col.type === \'boolean\'"\n                      class="form-control"\n                      ng-model="vm.query[col.prop]">\n                      <option value="">-</option>\n                      <option value="true">True</option>\n                      <option value="false">False</option>\n                    </select>\n                  </td>\n                  <td ng-if="vm.config.actions"></td>\n                </tr>\n              </tbody>\n              <tbody>\n                <tr ng-repeat="item in vm.data | filter:vm.query:vm.comparator | orderBy:vm.orderBy:vm.reverse | pagination:vm.currentPage * vm.config.pagination.pageSize | limitTo: (vm.config.pagination.pageSize || vm.data.length) track by $index">\n                  <td ng-repeat="col in vm.columns" xos-link-wrapper>\n                    <span ng-if="!col.type">{{item[col.prop]}}</span>\n                    <span ng-if="col.type === \'boolean\'">\n                      <i class="glyphicon"\n                        ng-class="{\'glyphicon-ok\': item[col.prop], \'glyphicon-remove\': !item[col.prop]}">\n                      </i>\n                    </span>\n                    <span ng-if="col.type === \'date\'">\n                      {{item[col.prop] | date:\'H:mm MMM d, yyyy\'}}\n                    </span>\n                    <span ng-if="col.type === \'array\'">\n                      {{item[col.prop] | arrayToList}}\n                    </span>\n                    <span ng-if="col.type === \'object\'">\n                      <dl class="dl-horizontal">\n                        <span ng-repeat="(k,v) in item[col.prop]">\n                          <dt>{{k}}</dt>\n                          <dd>{{v}}</dd>\n                        </span>\n                      </dl>\n                    </span>\n                    <span ng-if="col.type === \'custom\'">\n                      {{col.formatter(item)}}\n                    </span>\n                    <span ng-if="col.type === \'icon\'">\n                      <i class="glyphicon glyphicon-{{col.formatter(item)}}">\n                      </i>\n                    </span>\n                  </td>\n                  <td ng-if="vm.config.actions">\n                    <a href=""\n                      ng-repeat="action in vm.config.actions"\n                      ng-click="action.cb(item)"\n                      title="{{action.label}}">\n                      <i\n                        class="glyphicon glyphicon-{{action.icon}}"\n                        style="color: {{action.color}};"></i>\n                    </a>\n                  </td>\n                </tr>\n              </tbody>\n            </table>\n            <xos-pagination\n              ng-if="vm.config.pagination"\n              page-size="vm.config.pagination.pageSize"\n              total-elements="vm.data.length"\n              change="vm.goToPage">\n              </xos-pagination>\n          </div>\n          <div ng-show="(vm.data.length == 0 || !vm.data) && vm.loader == false">\n             <xos-alert config="{type: \'info\'}">\n              No data to show.\n            </xos-alert>\n          </div>\n          <div ng-show="vm.loader == true">\n            <div class="loader"></div>\n          </div>\n        ',bindToController:!0,controllerAs:"vm",controller:["_","$scope","Comparator",function(e,n,o){var i=this;if(this.comparator=o,this.loader=!0,n.$watch(function(){return i.data},function(e){angular.isDefined(e)&&(i.loader=!1)}),!this.config)throw new Error('[xosTable] Please provide a configuration via the "config" attribute');if(!this.config.columns)throw new Error("[xosTable] Please provide a columns list in the configuration");this.config.order&&angular.isObject(this.config.order)&&(this.reverse=this.config.order.reverse||!1,this.orderBy=this.config.order.field||"id");var t=e.filter(this.config.columns,{type:"custom"});angular.isArray(t)&&t.length>0&&e.forEach(t,function(e){if(!e.formatter||!angular.isFunction(e.formatter))throw new Error("[xosTable] You have provided a custom field type, a formatter function should provided too.")});var r=e.filter(this.config.columns,{type:"icon"});angular.isArray(r)&&r.length>0&&e.forEach(r,function(e){if(!e.formatter||!angular.isFunction(e.formatter))throw new Error("[xosTable] You have provided an icon field type, a formatter function should provided too.")});var a=e.filter(this.config.columns,function(e){return angular.isDefined(e.link)});angular.isArray(a)&&a.length>0&&e.forEach(a,function(e){if(!angular.isFunction(e.link))throw new Error("[xosTable] The link property should be a function.")}),this.columns=this.config.columns,this.classes=this.config.classes||"table table-striped table-bordered",this.config.actions,this.config.pagination&&(this.currentPage=0,this.goToPage=function(e){i.currentPage=e})}]}}).filter("arrayToList",function(){return function(e){return angular.isArray(e)?e.join(", "):e}}).directive("xosLinkWrapper",function(){return{restrict:"A",transclude:!0,template:'\n          <a ng-if="col.link" href="{{col.link(item)}}">\n            <div ng-transclude></div>\n          </a>\n          <div ng-transclude ng-if="!col.link"></div>\n        '}})}(),function(){angular.module("xos.uiComponents").directive("xosPagination",function(){return{restrict:"E",scope:{pageSize:"=",totalElements:"=",change:"="},template:'\n        <div class="row" ng-if="vm.pageList.length > 1">\n          <div class="col-xs-12 text-center">\n            <ul class="pagination">\n              <li\n                ng-click="vm.goToPage(vm.currentPage - 1)"\n                ng-class="{disabled: vm.currentPage == 0}">\n                <a href="" aria-label="Previous">\n                    <span aria-hidden="true">&laquo;</span>\n                </a>\n              </li>\n              <li ng-repeat="i in vm.pageList" ng-class="{active: i === vm.currentPage}">\n                <a href="" ng-click="vm.goToPage(i)">{{i + 1}}</a>\n              </li>\n              <li\n                ng-click="vm.goToPage(vm.currentPage + 1)"\n                ng-class="{disabled: vm.currentPage == vm.pages - 1}">\n                <a href="" aria-label="Next">\n                    <span aria-hidden="true">&raquo;</span>\n                </a>\n              </li>\n            </ul>\n          </div>\n        </div>\n      ',bindToController:!0,controllerAs:"vm",controller:["$scope",function(e){var n=this;this.currentPage=0,this.goToPage=function(e){0>e||e===n.pages||(n.currentPage=e,n.change(e))},this.createPages=function(e){for(var n=[],o=0;e>o;o++)n.push(o);return n},e.$watch(function(){return n.totalElements},function(){n.totalElements&&(n.pages=Math.ceil(n.totalElements/n.pageSize),n.pageList=n.createPages(n.pages))})}]}}).filter("pagination",function(){return function(e,n){return e&&angular.isArray(e)?(n=parseInt(n,10),e.slice(n)):e}})}(),function(){angular.module("xos.uiComponents").directive("xosForm",function(){return{restrict:"E",scope:{config:"=",ngModel:"="},template:'\n        <form name="vm.{{vm.config.formName || \'form\'}}" novalidate>\n          <div class="form-group" ng-repeat="(name, field) in vm.formField">\n            <xos-field name="name" field="field" ng-model="vm.ngModel[name]"></xos-field>\n            <xos-validation field="vm[vm.config.formName || \'form\'][name]" form = "vm[vm.config.formName || \'form\']"></xos-validation>\n            <div class="alert alert-info" ng-show="(field.hint).length >0" role="alert">{{field.hint}}</div>\n          </div>\n          <div class="form-group" ng-if="vm.config.actions">\n          <xos-alert config="vm.config.feedback" show="vm.config.feedback.show">{{vm.config.feedback.message}}</xos-alert>\n\n            <button role="button" href=""\n              ng-repeat="action in vm.config.actions"\n              ng-click="action.cb(vm.ngModel, vm[vm.config.formName || \'form\'])"\n              class="btn btn-{{action.class}}"\n              title="{{action.label}}">\n              <i class="glyphicon glyphicon-{{action.icon}}"></i>\n              {{action.label}}\n            </button>\n          </div>\n        </form>\n      ',bindToController:!0,controllerAs:"vm",controller:["$scope","$log","_","XosFormHelpers",function(e,n,o,i){var t=this;if(!this.config)throw new Error('[xosForm] Please provide a configuration via the "config" attribute');if(!this.config.actions)throw new Error("[xosForm] Please provide an action list in the configuration");this.config.feedback||(this.config.feedback={show:!1,message:"Form submitted successfully !!!",type:"success"}),this.excludedField=["id","validators","created","updated","deleted","backend_status"],this.config&&this.config.exclude&&(this.excludedField=this.excludedField.concat(this.config.exclude)),this.formField=[],e.$watch(function(){return t.config},function(){if(t.ngModel){var e=o.difference(Object.keys(t.ngModel),t.excludedField),n=i.parseModelField(e);t.formField=i.buildFormStructure(n,t.config.fields,t.ngModel)}},!0),e.$watch(function(){return t.ngModel},function(e){if(t.formField={},e){var n=o.difference(Object.keys(e),t.excludedField),r=i.parseModelField(n);t.formField=i.buildFormStructure(r,t.config.fields,e)}})}]}})}(),function(){angular.module("xos.uiComponents").directive("xosField",["RecursionHelper",function(e){return{restrict:"E",scope:{name:"=",field:"=",ngModel:"="},template:'\n        <label ng-if="vm.field.type !== \'object\'">{{vm.field.label}}</label>\n            <input\n              xos-custom-validator custom-validator="vm.field.validators.custom || null"\n              ng-if="vm.field.type !== \'boolean\' && vm.field.type !== \'object\' && vm.field.type !== \'select\'"\n              type="{{vm.field.type}}"\n              name="{{vm.name}}"\n              class="form-control"\n              ng-model="vm.ngModel"\n              ng-minlength="vm.field.validators.minlength || 0"\n              ng-maxlength="vm.field.validators.maxlength || 2000"\n              ng-required="vm.field.validators.required || false" />\n              <select class="form-control" ng-if ="vm.field.type === \'select\'"\n                name = "{{vm.name}}"\n                ng-options="item.id as item.label for item in vm.field.options"\n                ng-model="vm.ngModel"\n                ng-required="vm.field.validators.required || false">\n                </select>\n            <span class="boolean-field" ng-if="vm.field.type === \'boolean\'">\n              <a href="#"\n                class="btn btn-success"\n                ng-show="vm.ngModel"\n                ng-click="vm.ngModel = false">\n                <i class="glyphicon glyphicon-ok"></i>\n              </a>\n              <a href="#"\n                class="btn btn-danger"\n                ng-show="!vm.ngModel"\n                ng-click="vm.ngModel = true">\n                <i class="glyphicon glyphicon-remove"></i>\n              </a>\n            </span>\n            <div\n              class="panel panel-default object-field"\n              ng-if="vm.field.type == \'object\' && (!vm.isEmptyObject(vm.ngModel) || !vm.isEmptyObject(vm.field.properties))"\n              >\n              <div class="panel-heading">{{vm.field.label}}</div>\n              <div class="panel-body">\n                <div ng-if="!vm.field.properties" ng-repeat="(k, v) in vm.ngModel">\n                  <xos-field\n                    name="k"\n                    field="{label: vm.formatLabel(k), type: vm.getType(v)}"\n                    ng-model="v">\n                  </xos-field>\n                </div>\n                <div ng-if="vm.field.properties" ng-repeat="(k, v) in vm.field.properties">\n                  <xos-field\n                    name="k"\n                    field="{\n                      label: v.label || vm.formatLabel(k),\n                      type: v.type,\n                      validators: v.validators\n                    }"\n                    ng-model="vm.ngModel[k]">\n                  </xos-field>\n                </div>\n              </div>\n            </div>\n      ',bindToController:!0,controllerAs:"vm",compile:function(n){return e.compile(n)},controller:["$attrs","XosFormHelpers","LabelFormatter",function(e,n,o){if(!this.name)throw new Error("[xosField] Please provide a field name");if(!this.field)throw new Error("[xosField] Please provide a field definition");if(!this.field.type)throw new Error("[xosField] Please provide a type in the field definition");if(!e.ngModel)throw new Error("[xosField] Please provide an ng-model");this.getType=n._getFieldFormat,this.formatLabel=o.format,this.isEmptyObject=function(e){return e?0===Object.keys(e).length:!0}}]}}]).directive("xosCustomValidator",function(){return{restrict:"A",scope:{fn:"=customValidator"},require:"ngModel",link:function(e,n,o,i){function t(n){var o=e.fn(n);return angular.isArray(o)?i.$setValidity.apply(i,_toConsumableArray(o)):i.$setValidity("customValidation",o),n}angular.isFunction(e.fn)&&i.$parsers.push(t)}}})}(),function(){angular.module("xos.uiComponents").directive("xosAlert",function(){return{restrict:"E",scope:{config:"=",show:"=?"},template:'\n        <div ng-cloak class="alert alert-{{vm.config.type}}" ng-hide="!vm.show">\n          <button type="button" class="close" ng-if="vm.config.closeBtn" ng-click="vm.dismiss()">\n            <span aria-hidden="true">&times;</span>\n          </button>\n          <p ng-transclude></p>\n        </div>\n      ',transclude:!0,bindToController:!0,controllerAs:"vm",controller:["$timeout",function(e){var n=this;if(!this.config)throw new Error('[xosAlert] Please provide a configuration via the "config" attribute');this.show=this.show!==!1,this.dismiss=function(){n.show=!1},this.config.autoHide&&!function(){var o=e(function(){n.dismiss(),e.cancel(o)},n.config.autoHide)}()}]}})}(),function(){function e(e,n,o){e.interceptors.push("SetCSRFToken"),n.startSymbol("{$"),n.endSymbol("$}"),o.defaults.stripTrailingSlashes=!1}e.$inject=["$httpProvider","$interpolateProvider","$resourceProvider"],angular.module("bugSnag",[]).factory("$exceptionHandler",function(){return function(e,n){window.Bugsnag?Bugsnag.notifyException(e,{diagnostics:{cause:n}}):console.error(e,n,e.stack)}}),angular.module("xos.helpers",["ngCookies","ngResource","ngAnimate","bugSnag","xos.uiComponents"]).config(e).factory("_",["$window",function(e){return e._}])}(),function(){angular.module("xos.helpers").service("vSG-Collection",["$resource",function(e){return e("/api/service/vsg/")}])}(),function(){angular.module("xos.helpers").service("vOLT-Collection",["$resource",function(e){return e("/api/tenant/cord/volt/:volt_id/",{volt_id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Login",["$resource",function(e){return e("/api/utility/login/")}]).service("Logout",["$resource",function(e){return e("/api/utility/logout/")}])}(),function(){angular.module("xos.helpers").service("Users",["$resource",function(e){return e("/api/core/users/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Truckroll",["$resource",function(e){return e("/api/tenant/truckroll/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Tenants",["$resource",function(e){return e("/api/core/tenants/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Subscribers",["$resource",function(e){return e("/api/tenant/cord/subscriber/:id/",{id:"@id"},{update:{method:"PUT"},"View-a-Subscriber-Features-Detail":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/"},"Read-Subscriber-uplink_speed":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/uplink_speed/"},"Update-Subscriber-uplink_speed":{method:"PUT",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/uplink_speed/"},"Read-Subscriber-downlink_speed":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/downlink_speed/"},"Update-Subscriber-downlink_speed":{method:"PUT",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/downlink_speed/"},"Read-Subscriber-cdn":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/cdn/"},"Update-Subscriber-cdn":{method:"PUT",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/cdn/"},"Read-Subscriber-uverse":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/uverse/"},"Update-Subscriber-uverse":{method:"PUT",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/uverse/"},"Read-Subscriber-status":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/status/"},"Update-Subscriber-status":{method:"PUT",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/status/"}})}])}(),function(){angular.module("xos.helpers").service("SlicesPlus",["$http","$q",function(e,n){this.query=function(o){var i=n.defer();return e.get("/api/utility/slicesplus/",{params:o}).then(function(e){i.resolve(e.data)})["catch"](function(e){i.reject(e.data)}),{$promise:i.promise}},this.get=function(o,i){var t=n.defer();return e.get("/api/utility/slicesplus/"+o,{params:i}).then(function(e){t.resolve(e.data)})["catch"](function(e){t.reject(e.data)}),{$promise:t.promise}}}])}(),function(){angular.module("xos.helpers").service("Slices",["$resource",function(e){return e("/api/core/slices/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Sites",["$resource",function(e){return e("/api/core/sites/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Services",["$resource",function(e){return e("/api/core/services/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("ONOS-Services-Collection",["$resource",function(e){return e("/api/service/onos/")}])}(),function(){angular.module("xos.helpers").service("ONOS-App-Collection",["$resource",function(e){return e("/api/tenant/onos/app/")}])}(),function(){angular.module("xos.helpers").service("Nodes",["$resource",function(e){return e("/api/core/nodes/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Networks",["$resource",function(e){return e("/api/core/networks/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Instances",["$resource",function(e){return e("/api/core/instances/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Images",["$resource",function(e){return e("/api/core/images/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Flavors",["$resource",function(e){return e("/api/core/flavors/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Example-Services-Collection",["$resource",function(e){return e("/api/service/exampleservice/")}])}(),function(){angular.module("xos.helpers").service("Deployments",["$resource",function(e){return e("/api/core/deployments/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("XosUserPrefs",["$cookies",function(e){var n=this,o=e.get("xosUserPrefs")?angular.fromJson(e.get("xosUserPrefs")):{};this.getAll=function(){return o=e.get("xosUserPrefs")?angular.fromJson(e.get("xosUserPrefs")):{}},this.setAll=function(n){e.put("xosUserPrefs",angular.toJson(n))},this.getSynchronizerNotificationStatus=function(){var e=arguments.length<=0||void 0===arguments[0]?!1:arguments[0];return e?n.getAll().synchronizers.notification[e]:n.getAll().synchronizers.notification},this.setSynchronizerNotificationStatus=function(){var e=arguments.length<=0||void 0===arguments[0]?!1:arguments[0],o=arguments[1];if(!e)throw new Error("[XosUserPrefs] When updating a synchronizer is mandatory to provide a name.");var i=n.getAll();i.synchronizers||(i.synchronizers={notification:{}}),i.synchronizers.notification[e]=o,n.setAll(i)}}])}(),function(){angular.module("xos.helpers").service("GraphService",["$q","Tenants","Services",function(e,n,o){var i=this;this.loadCoarseData=function(){var i=void 0,t=e.defer();return o.query().$promise.then(function(e){return i=e,n.query({kind:"coarse"}).$promise}).then(function(e){t.resolve({tenants:e,services:i})}),t.promise},this.getCoarseGraph=function(){return i.loadCoarseData().then(function(e){console.log(e)}),"ciao"}}])}(),function(){angular.module("xos.helpers").factory("Notification",function(){return window.Notification}).service("xosNotification",["$q","$log","Notification",function(e,n,o){var i=this;this.checkPermission=function(){var n=e.defer();return o.requestPermission().then(function(e){"granted"===e?n.resolve(e):n.reject(e)}),n.promise},this.sendNotification=function(e,i){var t=new o(e,i);t.onerror=function(e){n.error(e)}},this.notify=function(e,t){
+"Notification"in window?"granted"!==o.permission?i.checkPermission().then(function(){return i.sendNotification(e,t)}):"granted"===o.permission&&i.sendNotification(e,t):n.info("This browser does not support desktop notification")}}])}(),function(){function e(){return{request:function(e){return-1===e.url.indexOf(".html")&&(e.url+="?no_hyperlinks=1"),e}}}angular.module("xos.helpers").factory("NoHyperlinks",e)}(),angular.module("xos.helpers").config(["$provide",function(e){e.decorator("$log",["$delegate",function(e){var n=function(){return window.location.href.indexOf("debug=true")>=0},o=e.log,i=e.info,t=e.warn,r=e.error,a=e.debug,s=function(o){return function(){if(n()){var i=[].slice.call(arguments),t=new Date;i[0]="["+t.getHours()+":"+t.getMinutes()+":"+t.getSeconds()+"] "+i[0],!angular.isFunction(e.reset)||e.debug.logs instanceof Array||e.reset(),o.apply(null,i)}}};return e.info=s(i),e.log=s(o),e.warn=s(t),e.error=s(r),e.debug=s(a),e}])}]),function(){function e(){var e=function(e){return e.split("_").join(" ").trim()},n=function(e){return e.split(/(?=[A-Z])/).map(function(e){return e.toLowerCase()}).join(" ")},o=function(e){return e.slice(0,1).toUpperCase()+e.slice(1)},i=function(i){return i=e(i),i=n(i),i=o(i).replace(/\s\s+/g," ")+":",i.replace("::",":")};return{_formatByUnderscore:e,_formatByUppercase:n,_capitalize:o,format:i}}angular.module("xos.uiComponents").factory("LabelFormatter",e)}(),function(){function e(e){return{request:function(n){return"GET"!==n.method&&(n.headers["X-CSRFToken"]=e.get("xoscsrftoken")),n}}}e.$inject=["$cookies"],angular.module("xos.helpers").factory("SetCSRFToken",e)}();
\ No newline at end of file
diff --git a/xos/core/xoslib/static/js/vendor/ngXosVendor.js b/xos/core/xoslib/static/js/vendor/ngXosVendor.js
new file mode 100644
index 0000000..78eee30
--- /dev/null
+++ b/xos/core/xoslib/static/js/vendor/ngXosVendor.js
@@ -0,0 +1,16 @@
+!function(t,n,e){"use strict";function r(t,n){return n=n||Error,function(){var e,r,i=2,o=arguments,a=o[0],u="["+(t?t+":":"")+a+"] ",s=o[1];for(u+=s.replace(/\{\d+\}/g,function(t){var n=+t.slice(1,-1),e=n+i;return e<o.length?$t(o[e]):t}),u+="\nhttp://errors.angularjs.org/1.4.7/"+(t?t+"/":"")+a,r=i,e="?";r<o.length;r++,e="&")u+=e+"p"+(r-i)+"="+encodeURIComponent($t(o[r]));return new n(u)}}function i(t){if(null==t||A(t))return!1;var n="length"in Object(t)&&t.length;return t.nodeType===Yr&&n?!0:C(t)||Fr(t)||0===n||"number"==typeof n&&n>0&&n-1 in t}function o(t,n,e){var r,a;if(t)if(M(t))for(r in t)"prototype"==r||"length"==r||"name"==r||t.hasOwnProperty&&!t.hasOwnProperty(r)||n.call(e,t[r],r,t);else if(Fr(t)||i(t)){var u="object"!=typeof t;for(r=0,a=t.length;a>r;r++)(u||r in t)&&n.call(e,t[r],r,t)}else if(t.forEach&&t.forEach!==o)t.forEach(n,e,t);else if(w(t))for(r in t)n.call(e,t[r],r,t);else if("function"==typeof t.hasOwnProperty)for(r in t)t.hasOwnProperty(r)&&n.call(e,t[r],r,t);else for(r in t)br.call(t,r)&&n.call(e,t[r],r,t);return t}function a(t,n,e){for(var r=Object.keys(t).sort(),i=0;i<r.length;i++)n.call(e,t[r[i]],r[i]);return r}function u(t){return function(n,e){t(e,n)}}function s(){return++Rr}function l(t,n){n?t.$$hashKey=n:delete t.$$hashKey}function c(t,n,e){for(var r=t.$$hashKey,i=0,o=n.length;o>i;++i){var a=n[i];if(b(a)||M(a))for(var u=Object.keys(a),s=0,f=u.length;f>s;s++){var h=u[s],p=a[h];e&&b(p)?_(p)?t[h]=new Date(p.valueOf()):k(p)?t[h]=new RegExp(p):(b(t[h])||(t[h]=Fr(p)?[]:{}),c(t[h],[p],!0)):t[h]=p}}return l(t,r),t}function f(t){return c(t,Er.call(arguments,1),!1)}function h(t){return c(t,Er.call(arguments,1),!0)}function p(t){return parseInt(t,10)}function d(t,n){return f(Object.create(t),n)}function v(){}function g(t){return t}function m(t){return function(){return t}}function y(t){return M(t.toString)&&t.toString!==Object.prototype.toString}function $(t){return"undefined"==typeof t}function x(t){return"undefined"!=typeof t}function b(t){return null!==t&&"object"==typeof t}function w(t){return null!==t&&"object"==typeof t&&!Lr(t)}function C(t){return"string"==typeof t}function S(t){return"number"==typeof t}function _(t){return"[object Date]"===Tr.call(t)}function M(t){return"function"==typeof t}function k(t){return"[object RegExp]"===Tr.call(t)}function A(t){return t&&t.window===t}function E(t){return t&&t.$evalAsync&&t.$watch}function P(t){return"[object File]"===Tr.call(t)}function O(t){return"[object FormData]"===Tr.call(t)}function T(t){return"[object Blob]"===Tr.call(t)}function L(t){return"boolean"==typeof t}function j(t){return t&&M(t.then)}function N(t){return Ir.test(Tr.call(t))}function R(t){return!(!t||!(t.nodeName||t.prop&&t.attr&&t.find))}function D(t){var n,e={},r=t.split(",");for(n=0;n<r.length;n++)e[r[n]]=!0;return e}function F(t){return xr(t.nodeName||t[0]&&t[0].nodeName)}function I(t,n){var e=t.indexOf(n);return e>=0&&t.splice(e,1),e}function z(t,n,e,r){if(A(t)||E(t))throw jr("cpws","Can't copy! Making copies of Window or Scope instances is not supported.");if(N(n))throw jr("cpta","Can't copy! TypedArray destination cannot be mutated.");if(n){if(t===n)throw jr("cpi","Can't copy! Source and destination are identical.");e=e||[],r=r||[],b(t)&&(e.push(t),r.push(n));var i;if(Fr(t)){n.length=0;for(var a=0;a<t.length;a++)n.push(z(t[a],null,e,r))}else{var u=n.$$hashKey;if(Fr(n)?n.length=0:o(n,function(t,e){delete n[e]}),w(t))for(i in t)n[i]=z(t[i],null,e,r);else if(t&&"function"==typeof t.hasOwnProperty)for(i in t)t.hasOwnProperty(i)&&(n[i]=z(t[i],null,e,r));else for(i in t)br.call(t,i)&&(n[i]=z(t[i],null,e,r));l(n,u)}}else if(n=t,b(t)){var s;if(e&&-1!==(s=e.indexOf(t)))return r[s];if(Fr(t))return z(t,[],e,r);if(N(t))n=new t.constructor(t);else if(_(t))n=new Date(t.getTime());else if(k(t))n=new RegExp(t.source,t.toString().match(/[^\/]*$/)[0]),n.lastIndex=t.lastIndex;else{if(!M(t.cloneNode)){var c=Object.create(Lr(t));return z(t,c,e,r)}n=t.cloneNode(!0)}r&&(e.push(t),r.push(n))}return n}function q(t,n){if(Fr(t)){n=n||[];for(var e=0,r=t.length;r>e;e++)n[e]=t[e]}else if(b(t)){n=n||{};for(var i in t)"$"===i.charAt(0)&&"$"===i.charAt(1)||(n[i]=t[i])}return n||t}function V(t,n){if(t===n)return!0;if(null===t||null===n)return!1;if(t!==t&&n!==n)return!0;var e,r,i,o=typeof t,a=typeof n;if(o==a&&"object"==o){if(!Fr(t)){if(_(t))return _(n)?V(t.getTime(),n.getTime()):!1;if(k(t))return k(n)?t.toString()==n.toString():!1;if(E(t)||E(n)||A(t)||A(n)||Fr(n)||_(n)||k(n))return!1;i=gt();for(r in t)if("$"!==r.charAt(0)&&!M(t[r])){if(!V(t[r],n[r]))return!1;i[r]=!0}for(r in n)if(!(r in i)&&"$"!==r.charAt(0)&&x(n[r])&&!M(n[r]))return!1;return!0}if(!Fr(n))return!1;if((e=t.length)==n.length){for(r=0;e>r;r++)if(!V(t[r],n[r]))return!1;return!0}}return!1}function B(t,n,e){return t.concat(Er.call(n,e))}function W(t,n){return Er.call(t,n||0)}function U(t,n){var e=arguments.length>2?W(arguments,2):[];return!M(n)||n instanceof RegExp?n:e.length?function(){return arguments.length?n.apply(t,B(e,arguments,0)):n.apply(t,e)}:function(){return arguments.length?n.apply(t,arguments):n.call(t)}}function H(t,r){var i=r;return"string"==typeof t&&"$"===t.charAt(0)&&"$"===t.charAt(1)?i=e:A(r)?i="$WINDOW":r&&n===r?i="$DOCUMENT":E(r)&&(i="$SCOPE"),i}function Y(t,n){return"undefined"==typeof t?e:(S(n)||(n=n?2:null),JSON.stringify(t,H,n))}function G(t){return C(t)?JSON.parse(t):t}function X(t,n){var e=Date.parse("Jan 01, 1970 00:00:00 "+t)/6e4;return isNaN(e)?n:e}function Z(t,n){return t=new Date(t.getTime()),t.setMinutes(t.getMinutes()+n),t}function J(t,n,e){e=e?-1:1;var r=X(n,t.getTimezoneOffset());return Z(t,e*(r-t.getTimezoneOffset()))}function K(t){t=Mr(t).clone();try{t.empty()}catch(n){}var e=Mr("<div>").append(t).html();try{return t[0].nodeType===Xr?xr(e):e.match(/^(<[^>]+>)/)[1].replace(/^<([\w\-]+)/,function(t,n){return"<"+xr(n)})}catch(n){return xr(e)}}function Q(t){try{return decodeURIComponent(t)}catch(n){}}function tt(t){var n={};return o((t||"").split("&"),function(t){var e,r,i;t&&(r=t=t.replace(/\+/g,"%20"),e=t.indexOf("="),-1!==e&&(r=t.substring(0,e),i=t.substring(e+1)),r=Q(r),x(r)&&(i=x(i)?Q(i):!0,br.call(n,r)?Fr(n[r])?n[r].push(i):n[r]=[n[r],i]:n[r]=i))}),n}function nt(t){var n=[];return o(t,function(t,e){Fr(t)?o(t,function(t){n.push(rt(e,!0)+(t===!0?"":"="+rt(t,!0)))}):n.push(rt(e,!0)+(t===!0?"":"="+rt(t,!0)))}),n.length?n.join("&"):""}function et(t){return rt(t,!0).replace(/%26/gi,"&").replace(/%3D/gi,"=").replace(/%2B/gi,"+")}function rt(t,n){return encodeURIComponent(t).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%3B/gi,";").replace(/%20/g,n?"%20":"+")}function it(t,n){var e,r,i=Wr.length;for(r=0;i>r;++r)if(e=Wr[r]+n,C(e=t.getAttribute(e)))return e;return null}function ot(t,n){var e,r,i={};o(Wr,function(n){var i=n+"app";!e&&t.hasAttribute&&t.hasAttribute(i)&&(e=t,r=t.getAttribute(i))}),o(Wr,function(n){var i,o=n+"app";!e&&(i=t.querySelector("["+o.replace(":","\\:")+"]"))&&(e=i,r=i.getAttribute(o))}),e&&(i.strictDi=null!==it(e,"strict-di"),n(e,r?[r]:[],i))}function at(e,r,i){b(i)||(i={});var a={strictDi:!1};i=f(a,i);var u=function(){if(e=Mr(e),e.injector()){var t=e[0]===n?"document":K(e);throw jr("btstrpd","App Already Bootstrapped with this Element '{0}'",t.replace(/</,"&lt;").replace(/>/,"&gt;"))}r=r||[],r.unshift(["$provide",function(t){t.value("$rootElement",e)}]),i.debugInfoEnabled&&r.push(["$compileProvider",function(t){t.debugInfoEnabled(!0)}]),r.unshift("ng");var o=Kt(r,i.strictDi);return o.invoke(["$rootScope","$rootElement","$compile","$injector",function(t,n,e,r){t.$apply(function(){n.data("$injector",r),e(n)(t)})}]),o},s=/^NG_ENABLE_DEBUG_INFO!/,l=/^NG_DEFER_BOOTSTRAP!/;return t&&s.test(t.name)&&(i.debugInfoEnabled=!0,t.name=t.name.replace(s,"")),t&&!l.test(t.name)?u():(t.name=t.name.replace(l,""),Nr.resumeBootstrap=function(t){return o(t,function(t){r.push(t)}),u()},void(M(Nr.resumeDeferredBootstrap)&&Nr.resumeDeferredBootstrap()))}function ut(){t.name="NG_ENABLE_DEBUG_INFO!"+t.name,t.location.reload()}function st(t){var n=Nr.element(t).injector();if(!n)throw jr("test","no injector found for element argument to getTestability");return n.get("$$testability")}function lt(t,n){return n=n||"_",t.replace(Ur,function(t,e){return(e?n:"")+t.toLowerCase()})}function ct(){var n;if(!Hr){var r=Br();kr=$(r)?t.jQuery:r?t[r]:e,kr&&kr.fn.on?(Mr=kr,f(kr.fn,{scope:pi.scope,isolateScope:pi.isolateScope,controller:pi.controller,injector:pi.injector,inheritedData:pi.inheritedData}),n=kr.cleanData,kr.cleanData=function(t){var e;if(Dr)Dr=!1;else for(var r,i=0;null!=(r=t[i]);i++)e=kr._data(r,"events"),e&&e.$destroy&&kr(r).triggerHandler("$destroy");n(t)}):Mr=At,Nr.element=Mr,Hr=!0}}function ft(t,n,e){if(!t)throw jr("areq","Argument '{0}' is {1}",n||"?",e||"required");return t}function ht(t,n,e){return e&&Fr(t)&&(t=t[t.length-1]),ft(M(t),n,"not a function, got "+(t&&"object"==typeof t?t.constructor.name||"Object":typeof t)),t}function pt(t,n){if("hasOwnProperty"===t)throw jr("badname","hasOwnProperty is not a valid {0} name",n)}function dt(t,n,e){if(!n)return t;for(var r,i=n.split("."),o=t,a=i.length,u=0;a>u;u++)r=i[u],t&&(t=(o=t)[r]);return!e&&M(t)?U(o,t):t}function vt(t){for(var n,e=t[0],r=t[t.length-1],i=1;e!==r&&(e=e.nextSibling);i++)(n||t[i]!==e)&&(n||(n=Mr(Er.call(t,0,i))),n.push(e));return n||t}function gt(){return Object.create(null)}function mt(t){function n(t,n,e){return t[n]||(t[n]=e())}var e=r("$injector"),i=r("ng"),o=n(t,"angular",Object);return o.$$minErr=o.$$minErr||r,n(o,"module",function(){var t={};return function(r,o,a){var u=function(t,n){if("hasOwnProperty"===t)throw i("badname","hasOwnProperty is not a valid {0} name",n)};return u(r,"module"),o&&t.hasOwnProperty(r)&&(t[r]=null),n(t,r,function(){function t(t,n,e,r){return r||(r=i),function(){return r[e||"push"]([t,n,arguments]),c}}function n(t,n){return function(e,o){return o&&M(o)&&(o.$$moduleName=r),i.push([t,n,arguments]),c}}if(!o)throw e("nomod","Module '{0}' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.",r);var i=[],u=[],s=[],l=t("$injector","invoke","push",u),c={_invokeQueue:i,_configBlocks:u,_runBlocks:s,requires:o,name:r,provider:n("$provide","provider"),factory:n("$provide","factory"),service:n("$provide","service"),value:t("$provide","value"),constant:t("$provide","constant","unshift"),decorator:n("$provide","decorator"),animation:n("$animateProvider","register"),filter:n("$filterProvider","register"),controller:n("$controllerProvider","register"),directive:n("$compileProvider","directive"),config:l,run:function(t){return s.push(t),this}};return a&&l(a),c})}})}function yt(t){var n=[];return JSON.stringify(t,function(t,e){if(e=H(t,e),b(e)){if(n.indexOf(e)>=0)return"...";n.push(e)}return e})}function $t(t){return"function"==typeof t?t.toString().replace(/ \{[\s\S]*$/,""):$(t)?"undefined":"string"!=typeof t?yt(t):t}function xt(n){f(n,{bootstrap:at,copy:z,extend:f,merge:h,equals:V,element:Mr,forEach:o,injector:Kt,noop:v,bind:U,toJson:Y,fromJson:G,identity:g,isUndefined:$,isDefined:x,isString:C,isFunction:M,isObject:b,isNumber:S,isElement:R,isArray:Fr,version:Qr,isDate:_,lowercase:xr,uppercase:wr,callbacks:{counter:0},getTestability:st,$$minErr:r,$$csp:Vr,reloadWithDebugInfo:ut}),(Ar=mt(t))("ng",["ngLocale"],["$provide",function(t){t.provider({$$sanitizeUri:me}),t.provider("$compile",ln).directive({a:po,input:Oo,textarea:Oo,form:$o,script:Ca,select:Ma,style:Aa,option:ka,ngBind:jo,ngBindHtml:Ro,ngBindTemplate:No,ngClass:Fo,ngClassEven:zo,ngClassOdd:Io,ngCloak:qo,ngController:Vo,ngForm:xo,ngHide:ma,ngIf:Uo,ngInclude:Ho,ngInit:Go,ngNonBindable:sa,ngPluralize:ha,ngRepeat:pa,ngShow:ga,ngStyle:ya,ngSwitch:$a,ngSwitchWhen:xa,ngSwitchDefault:ba,ngOptions:fa,ngTransclude:wa,ngModel:oa,ngList:Xo,ngChange:Do,pattern:Pa,ngPattern:Pa,required:Ea,ngRequired:Ea,minlength:Ta,ngMinlength:Ta,maxlength:Oa,ngMaxlength:Oa,ngValue:Lo,ngModelOptions:ua}).directive({ngInclude:Yo}).directive(vo).directive(Bo),t.provider({$anchorScroll:Qt,$animate:Ai,$animateCss:Ei,$$animateQueue:ki,$$AnimateRunner:Mi,$browser:an,$cacheFactory:un,$controller:dn,$document:vn,$exceptionHandler:gn,$filter:Oe,$$forceReflow:ji,$interpolate:Pn,$interval:On,$http:Mn,$httpParamSerializer:yn,$httpParamSerializerJQLike:$n,$httpBackend:An,$xhrFactory:kn,$location:Un,$log:Hn,$parse:fe,$rootScope:ge,$q:he,$$q:pe,$sce:be,$sceDelegate:xe,$sniffer:we,$templateCache:sn,$templateRequest:Ce,$$testability:Se,$timeout:_e,$window:Ae,$$rAF:ve,$$jqLite:Yt,$$HashMap:mi,$$cookieReader:Pe})}])}function bt(){return++ni}function wt(t){return t.replace(ii,function(t,n,e,r){return r?e.toUpperCase():e}).replace(oi,"Moz$1")}function Ct(t){return!li.test(t)}function St(t){var n=t.nodeType;return n===Yr||!n||n===Jr}function _t(t){for(var n in ti[t.ng339])return!0;return!1}function Mt(t,n){var e,r,i,a,u=n.createDocumentFragment(),s=[];if(Ct(t))s.push(n.createTextNode(t));else{for(e=e||u.appendChild(n.createElement("div")),r=(ci.exec(t)||["",""])[1].toLowerCase(),i=hi[r]||hi._default,e.innerHTML=i[1]+t.replace(fi,"<$1></$2>")+i[2],a=i[0];a--;)e=e.lastChild;s=B(s,e.childNodes),e=u.firstChild,e.textContent=""}return u.textContent="",u.innerHTML="",o(s,function(t){u.appendChild(t)}),u}function kt(t,e){e=e||n;var r;return(r=si.exec(t))?[e.createElement(r[1])]:(r=Mt(t,e))?r.childNodes:[]}function At(t){if(t instanceof At)return t;var n;if(C(t)&&(t=zr(t),n=!0),!(this instanceof At)){if(n&&"<"!=t.charAt(0))throw ui("nosel","Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element");return new At(t)}n?Ft(this,kt(t)):Ft(this,t)}function Et(t){return t.cloneNode(!0)}function Pt(t,n){if(n||Tt(t),t.querySelectorAll)for(var e=t.querySelectorAll("*"),r=0,i=e.length;i>r;r++)Tt(e[r])}function Ot(t,n,e,r){if(x(r))throw ui("offargs","jqLite#off() does not support the `selector` argument");var i=Lt(t),a=i&&i.events,u=i&&i.handle;if(u)if(n)o(n.split(" "),function(n){if(x(e)){var r=a[n];if(I(r||[],e),r&&r.length>0)return}ri(t,n,u),delete a[n]});else for(n in a)"$destroy"!==n&&ri(t,n,u),delete a[n]}function Tt(t,n){var r=t.ng339,i=r&&ti[r];if(i){if(n)return void delete i.data[n];i.handle&&(i.events.$destroy&&i.handle({},"$destroy"),Ot(t)),delete ti[r],t.ng339=e}}function Lt(t,n){var r=t.ng339,i=r&&ti[r];return n&&!i&&(t.ng339=r=bt(),i=ti[r]={events:{},data:{},handle:e}),i}function jt(t,n,e){if(St(t)){var r=x(e),i=!r&&n&&!b(n),o=!n,a=Lt(t,!i),u=a&&a.data;if(r)u[n]=e;else{if(o)return u;if(i)return u&&u[n];f(u,n)}}}function Nt(t,n){return t.getAttribute?(" "+(t.getAttribute("class")||"")+" ").replace(/[\n\t]/g," ").indexOf(" "+n+" ")>-1:!1}function Rt(t,n){n&&t.setAttribute&&o(n.split(" "),function(n){t.setAttribute("class",zr((" "+(t.getAttribute("class")||"")+" ").replace(/[\n\t]/g," ").replace(" "+zr(n)+" "," ")))})}function Dt(t,n){if(n&&t.setAttribute){var e=(" "+(t.getAttribute("class")||"")+" ").replace(/[\n\t]/g," ");o(n.split(" "),function(t){t=zr(t),-1===e.indexOf(" "+t+" ")&&(e+=t+" ")}),t.setAttribute("class",zr(e))}}function Ft(t,n){if(n)if(n.nodeType)t[t.length++]=n;else{var e=n.length;if("number"==typeof e&&n.window!==n){if(e)for(var r=0;e>r;r++)t[t.length++]=n[r]}else t[t.length++]=n}}function It(t,n){return zt(t,"$"+(n||"ngController")+"Controller")}function zt(t,n,e){t.nodeType==Jr&&(t=t.documentElement);for(var r=Fr(n)?n:[n];t;){for(var i=0,o=r.length;o>i;i++)if(x(e=Mr.data(t,r[i])))return e;t=t.parentNode||t.nodeType===Kr&&t.host}}function qt(t){for(Pt(t,!0);t.firstChild;)t.removeChild(t.firstChild)}function Vt(t,n){n||Pt(t);var e=t.parentNode;e&&e.removeChild(t)}function Bt(n,e){e=e||t,"complete"===e.document.readyState?e.setTimeout(n):Mr(e).on("load",n)}function Wt(t,n){var e=di[n.toLowerCase()];return e&&vi[F(t)]&&e}function Ut(t){return gi[t]}function Ht(t,n){var e=function(e,r){e.isDefaultPrevented=function(){return e.defaultPrevented};var i=n[r||e.type],o=i?i.length:0;if(o){if($(e.immediatePropagationStopped)){var a=e.stopImmediatePropagation;e.stopImmediatePropagation=function(){e.immediatePropagationStopped=!0,e.stopPropagation&&e.stopPropagation(),a&&a.call(e)}}e.isImmediatePropagationStopped=function(){return e.immediatePropagationStopped===!0},o>1&&(i=q(i));for(var u=0;o>u;u++)e.isImmediatePropagationStopped()||i[u].call(t,e)}};return e.elem=t,e}function Yt(){this.$get=function(){return f(At,{hasClass:function(t,n){return t.attr&&(t=t[0]),Nt(t,n)},addClass:function(t,n){return t.attr&&(t=t[0]),Dt(t,n)},removeClass:function(t,n){return t.attr&&(t=t[0]),Rt(t,n)}})}}function Gt(t,n){var e=t&&t.$$hashKey;if(e)return"function"==typeof e&&(e=t.$$hashKey()),e;var r=typeof t;return e="function"==r||"object"==r&&null!==t?t.$$hashKey=r+":"+(n||s)():r+":"+t}function Xt(t,n){if(n){var e=0;this.nextUid=function(){return++e}}o(t,this.put,this)}function Zt(t){var n=t.toString().replace(bi,""),e=n.match(yi);return e?"function("+(e[1]||"").replace(/[\s\r\n]+/," ")+")":"fn"}function Jt(t,n,e){var r,i,a,u;if("function"==typeof t){if(!(r=t.$inject)){if(r=[],t.length){if(n)throw C(e)&&e||(e=t.name||Zt(t)),wi("strictdi","{0} is not using explicit annotation and cannot be invoked in strict mode",e);i=t.toString().replace(bi,""),a=i.match(yi),o(a[1].split($i),function(t){t.replace(xi,function(t,n,e){r.push(e)})})}t.$inject=r}}else Fr(t)?(u=t.length-1,ht(t[u],"fn"),r=t.slice(0,u)):ht(t,"fn",!0);return r}function Kt(t,n){function r(t){return function(n,e){return b(n)?void o(n,u(t)):t(n,e)}}function i(t,n){if(pt(t,"service"),(M(n)||Fr(n))&&(n=S.instantiate(n)),!n.$get)throw wi("pget","Provider '{0}' must define $get factory method.",t);return w[t+g]=n}function a(t,n){return function(){var e=k.invoke(n,this);if($(e))throw wi("undef","Provider '{0}' must return a value from $get factory method.",t);return e}}function s(t,n,e){return i(t,{$get:e!==!1?a(t,n):n})}function l(t,n){return s(t,["$injector",function(t){return t.instantiate(n)}])}function c(t,n){return s(t,m(n),!1)}function f(t,n){pt(t,"constant"),w[t]=n,_[t]=n}function h(t,n){var e=S.get(t+g),r=e.$get;e.$get=function(){var t=k.invoke(r,e);return k.invoke(n,null,{$delegate:t})}}function p(t){ft($(t)||Fr(t),"modulesToLoad","not an array");var n,e=[];return o(t,function(t){function r(t){var n,e;for(n=0,e=t.length;e>n;n++){var r=t[n],i=S.get(r[0]);i[r[1]].apply(i,r[2])}}if(!x.get(t)){x.put(t,!0);try{C(t)?(n=Ar(t),e=e.concat(p(n.requires)).concat(n._runBlocks),r(n._invokeQueue),r(n._configBlocks)):M(t)?e.push(S.invoke(t)):Fr(t)?e.push(S.invoke(t)):ht(t,"module")}catch(i){throw Fr(t)&&(t=t[t.length-1]),i.message&&i.stack&&-1==i.stack.indexOf(i.message)&&(i=i.message+"\n"+i.stack),wi("modulerr","Failed to instantiate module {0} due to:\n{1}",t,i.stack||i.message||i)}}}),e}function d(t,e){function r(n,r){if(t.hasOwnProperty(n)){if(t[n]===v)throw wi("cdep","Circular dependency found: {0}",n+" <- "+y.join(" <- "));return t[n]}try{return y.unshift(n),t[n]=v,t[n]=e(n,r)}catch(i){throw t[n]===v&&delete t[n],i}finally{y.shift()}}function i(t,e,i,o){"string"==typeof i&&(o=i,i=null);var a,u,s,l=[],c=Kt.$$annotate(t,n,o);for(u=0,a=c.length;a>u;u++){if(s=c[u],"string"!=typeof s)throw wi("itkn","Incorrect injection token! Expected service name as string, got {0}",s);l.push(i&&i.hasOwnProperty(s)?i[s]:r(s,o))}return Fr(t)&&(t=t[a]),t.apply(e,l)}function o(t,n,e){var r=Object.create((Fr(t)?t[t.length-1]:t).prototype||null),o=i(t,r,n,e);return b(o)||M(o)?o:r}return{invoke:i,instantiate:o,get:r,annotate:Kt.$$annotate,has:function(n){return w.hasOwnProperty(n+g)||t.hasOwnProperty(n)}}}n=n===!0;var v={},g="Provider",y=[],x=new Xt([],!0),w={$provide:{provider:r(i),factory:r(s),service:r(l),value:r(c),constant:r(f),decorator:h}},S=w.$injector=d(w,function(t,n){throw Nr.isString(n)&&y.push(n),wi("unpr","Unknown provider: {0}",y.join(" <- "))}),_={},k=_.$injector=d(_,function(t,n){var r=S.get(t+g,n);return k.invoke(r.$get,r,e,t)});return o(p(t),function(t){t&&k.invoke(t)}),k}function Qt(){var t=!0;this.disableAutoScrolling=function(){t=!1},this.$get=["$window","$location","$rootScope",function(n,e,r){function i(t){var n=null;return Array.prototype.some.call(t,function(t){return"a"===F(t)?(n=t,!0):void 0}),n}function o(){var t=u.yOffset;if(M(t))t=t();else if(R(t)){var e=t[0],r=n.getComputedStyle(e);t="fixed"!==r.position?0:e.getBoundingClientRect().bottom}else S(t)||(t=0);return t}function a(t){if(t){t.scrollIntoView();var e=o();if(e){var r=t.getBoundingClientRect().top;n.scrollBy(0,r-e)}}else n.scrollTo(0,0)}function u(t){t=C(t)?t:e.hash();var n;t?(n=s.getElementById(t))?a(n):(n=i(s.getElementsByName(t)))?a(n):"top"===t&&a(null):a(null)}var s=n.document;return t&&r.$watch(function(){return e.hash()},function(t,n){t===n&&""===t||Bt(function(){r.$evalAsync(u)})}),u}]}function tn(t,n){return t||n?t?n?(Fr(t)&&(t=t.join(" ")),Fr(n)&&(n=n.join(" ")),t+" "+n):t:n:""}function nn(t){for(var n=0;n<t.length;n++){var e=t[n];if(e.nodeType===Si)return e}}function en(t){C(t)&&(t=t.split(" "));var n=gt();return o(t,function(t){t.length&&(n[t]=!0)}),n}function rn(t){return b(t)?t:{}}function on(t,n,e,r){function i(t){try{t.apply(null,W(arguments,1))}finally{if(y--,0===y)for(;x.length;)try{x.pop()()}catch(n){e.error(n)}}}function a(t){var n=t.indexOf("#");return-1===n?"":t.substr(n)}function u(){_=null,l(),c()}function s(){try{return p.state}catch(t){}}function l(){b=s(),b=$(b)?null:b,V(b,A)&&(b=A),A=b}function c(){C===f.url()&&w===b||(C=f.url(),w=b,o(M,function(t){t(f.url(),b)}))}var f=this,h=(n[0],t.location),p=t.history,d=t.setTimeout,g=t.clearTimeout,m={};f.isMock=!1;var y=0,x=[];f.$$completeOutstandingRequest=i,f.$$incOutstandingRequestCount=function(){y++},f.notifyWhenNoOutstandingRequests=function(t){0===y?t():x.push(t)};var b,w,C=h.href,S=n.find("base"),_=null;l(),w=b,f.url=function(n,e,i){if($(i)&&(i=null),h!==t.location&&(h=t.location),p!==t.history&&(p=t.history),n){var o=w===i;if(C===n&&(!r.history||o))return f;var u=C&&Rn(C)===Rn(n);return C=n,w=i,!r.history||u&&o?(u&&!_||(_=n),e?h.replace(n):u?h.hash=a(n):h.href=n,h.href!==n&&(_=n)):(p[e?"replaceState":"pushState"](i,"",n),l(),w=b),f}return _||h.href.replace(/%27/g,"'")},f.state=function(){return b};var M=[],k=!1,A=null;f.onUrlChange=function(n){return k||(r.history&&Mr(t).on("popstate",u),Mr(t).on("hashchange",u),k=!0),M.push(n),n},f.$$applicationDestroyed=function(){Mr(t).off("hashchange popstate",u)},f.$$checkUrlChange=c,f.baseHref=function(){var t=S.attr("href");return t?t.replace(/^(https?\:)?\/\/[^\/]*/,""):""},f.defer=function(t,n){var e;return y++,e=d(function(){delete m[e],i(t)},n||0),m[e]=!0,e},f.defer.cancel=function(t){return m[t]?(delete m[t],g(t),i(v),!0):!1}}function an(){this.$get=["$window","$log","$sniffer","$document",function(t,n,e,r){return new on(t,r,n,e)}]}function un(){this.$get=function(){function t(t,e){function i(t){t!=h&&(p?p==t&&(p=t.n):p=t,o(t.n,t.p),o(t,h),h=t,h.n=null)}function o(t,n){t!=n&&(t&&(t.p=n),n&&(n.n=t))}if(t in n)throw r("$cacheFactory")("iid","CacheId '{0}' is already taken!",t);var a=0,u=f({},e,{id:t}),s={},l=e&&e.capacity||Number.MAX_VALUE,c={},h=null,p=null;return n[t]={put:function(t,n){if(!$(n)){if(l<Number.MAX_VALUE){var e=c[t]||(c[t]={key:t});i(e)}return t in s||a++,s[t]=n,a>l&&this.remove(p.key),n}},get:function(t){if(l<Number.MAX_VALUE){var n=c[t];if(!n)return;i(n)}return s[t]},remove:function(t){if(l<Number.MAX_VALUE){var n=c[t];if(!n)return;n==h&&(h=n.p),n==p&&(p=n.n),o(n.n,n.p),delete c[t]}delete s[t],a--},removeAll:function(){s={},a=0,c={},h=p=null},destroy:function(){s=null,u=null,c=null,delete n[t]},info:function(){return f({},u,{size:a})}}}var n={};return t.info=function(){var t={};return o(n,function(n,e){t[e]=n.info()}),t},t.get=function(t){return n[t]},t}}function sn(){this.$get=["$cacheFactory",function(t){return t("templates")}]}function ln(t,r){function i(t,n,e){var r=/^\s*([@&]|=(\*?))(\??)\s*(\w*)\s*$/,i={};return o(t,function(t,o){var a=t.match(r);if(!a)throw Pi("iscp","Invalid {3} for directive '{0}'. Definition: {... {1}: '{2}' ...}",n,o,t,e?"controller bindings definition":"isolate scope definition");i[o]={mode:a[1][0],collection:"*"===a[2],optional:"?"===a[3],attrName:a[4]||o}}),i}function a(t,n){var e={isolateScope:null,bindToController:null};if(b(t.scope)&&(t.bindToController===!0?(e.bindToController=i(t.scope,n,!0),e.isolateScope={}):e.isolateScope=i(t.scope,n,!1)),b(t.bindToController)&&(e.bindToController=i(t.bindToController,n,!0)),b(e.bindToController)){var r=t.controller,o=t.controllerAs;if(!r)throw Pi("noctrl","Cannot bind to controller without directive '{0}'s controller.",n);if(!pn(r,o))throw Pi("noident","Cannot bind to controller without identifier for directive '{0}'.",n)}return e}function s(t){var n=t.charAt(0);if(!n||n!==xr(n))throw Pi("baddir","Directive name '{0}' is invalid. The first character must be a lowercase letter",t);if(t!==t.trim())throw Pi("baddir","Directive name '{0}' is invalid. The name should not contain leading or trailing whitespaces",t)}var l={},c="Directive",h=/^\s*directive\:\s*([\w\-]+)\s+(.*)$/,p=/(([\w\-]+)(?:\:([^;]+))?;?)/,y=D("ngSrc,ngSrcset,src,srcset"),w=/^(?:(\^\^?)?(\?)?(\^\^?)?)?/,S=/^(on[a-z]+|formaction)$/;this.directive=function k(n,e){return pt(n,"directive"),C(n)?(s(n),ft(e,"directiveFactory"),l.hasOwnProperty(n)||(l[n]=[],t.factory(n+c,["$injector","$exceptionHandler",function(t,e){var r=[];return o(l[n],function(i,o){try{var u=t.invoke(i);M(u)?u={compile:m(u)}:!u.compile&&u.link&&(u.compile=m(u.link)),u.priority=u.priority||0,u.index=o,u.name=u.name||n,u.require=u.require||u.controller&&u.name,u.restrict=u.restrict||"EA";var s=u.$$bindings=a(u,u.name);b(s.isolateScope)&&(u.$$isolateBindings=s.isolateScope),u.$$moduleName=i.$$moduleName,r.push(u)}catch(l){e(l)}}),r}])),l[n].push(e)):o(n,u(k)),this},this.aHrefSanitizationWhitelist=function(t){return x(t)?(r.aHrefSanitizationWhitelist(t),this):r.aHrefSanitizationWhitelist()},this.imgSrcSanitizationWhitelist=function(t){return x(t)?(r.imgSrcSanitizationWhitelist(t),this):r.imgSrcSanitizationWhitelist()};var _=!0;this.debugInfoEnabled=function(t){return x(t)?(_=t,this):_},this.$get=["$injector","$interpolate","$exceptionHandler","$templateRequest","$parse","$controller","$rootScope","$document","$sce","$animate","$$sanitizeUri",function(t,r,i,a,u,s,m,x,k,A,P){function O(t,n){try{t.addClass(n)}catch(e){}}function T(t,n,e,r,i){t instanceof Mr||(t=Mr(t)),o(t,function(n,e){n.nodeType==Xr&&n.nodeValue.match(/\S+/)&&(t[e]=Mr(n).wrap("<span></span>").parent()[0])});var a=j(t,n,t,e,r,i);T.$$addScopeClass(t);var u=null;return function(n,e,r){ft(n,"scope"),r=r||{};var i=r.parentBoundTranscludeFn,o=r.transcludeControllers,s=r.futureParentElement;i&&i.$$boundTransclude&&(i=i.$$boundTransclude),u||(u=L(s));var l;if(l="html"!==u?Mr(Q(u,Mr("<div>").append(t).html())):e?pi.clone.call(t):t,o)for(var c in o)l.data("$"+c+"Controller",o[c].instance);return T.$$addScopeInfo(l,n),e&&e(l,n),a&&a(n,l,l,i),l}}function L(t){var n=t&&t[0];return n&&"foreignobject"!==F(n)&&n.toString().match(/SVG/)?"svg":"html"}function j(t,n,r,i,o,a){function u(t,r,i,o){var a,u,s,l,c,f,h,p,g;if(d){var m=r.length;for(g=new Array(m),c=0;c<v.length;c+=3)h=v[c],g[h]=r[h]}else g=r;for(c=0,f=v.length;f>c;)if(s=g[v[c++]],a=v[c++],u=v[c++],a){if(a.scope){l=t.$new(),T.$$addScopeInfo(Mr(s),l);var y=a.$$destroyBindings;y&&(a.$$destroyBindings=null,l.$on("$destroyed",y))}else l=t;p=a.transcludeOnThisElement?N(t,a.transclude,o):!a.templateOnThisElement&&o?o:!o&&n?N(t,n):null,a(u,l,s,i,p,a)}else u&&u(t,s.childNodes,e,o)}for(var s,l,c,f,h,p,d,v=[],g=0;g<t.length;g++)s=new at,l=R(t[g],[],s,0===g?i:e,o),c=l.length?q(l,t[g],s,n,r,null,[],[],a):null,c&&c.scope&&T.$$addScopeClass(s.$$element),h=c&&c.terminal||!(f=t[g].childNodes)||!f.length?null:j(f,c?(c.transcludeOnThisElement||!c.templateOnThisElement)&&c.transclude:n),(c||h)&&(v.push(g,c,h),p=!0,d=d||c),a=null;return p?u:null}function N(t,n,e){var r=function(r,i,o,a,u){return r||(r=t.$new(!1,u),r.$$transcluded=!0),n(r,i,{parentBoundTranscludeFn:e,transcludeControllers:o,futureParentElement:a})};return r}function R(t,n,e,r,i){var o,a,u=t.nodeType,s=e.$attr;switch(u){case Yr:U(n,cn(F(t)),"E",r,i);for(var l,c,f,d,v,g,m=t.attributes,y=0,$=m&&m.length;$>y;y++){var x=!1,w=!1;l=m[y],c=l.name,v=zr(l.value),d=cn(c),(g=ht.test(d))&&(c=c.replace(Oi,"").substr(8).replace(/_(.)/g,function(t,n){return n.toUpperCase()}));var S=d.replace(/(Start|End)$/,"");H(S)&&d===S+"Start"&&(x=c,w=c.substr(0,c.length-5)+"end",c=c.substr(0,c.length-6)),f=cn(c.toLowerCase()),s[f]=c,!g&&e.hasOwnProperty(f)||(e[f]=v,Wt(t,f)&&(e[f]=!0)),nt(t,n,v,f,g),U(n,f,"A",r,i,x,w)}if(a=t.className,b(a)&&(a=a.animVal),C(a)&&""!==a)for(;o=p.exec(a);)f=cn(o[2]),U(n,f,"C",r,i)&&(e[f]=zr(o[3])),a=a.substr(o.index+o[0].length);break;case Xr:if(11===_r)for(;t.parentNode&&t.nextSibling&&t.nextSibling.nodeType===Xr;)t.nodeValue=t.nodeValue+t.nextSibling.nodeValue,t.parentNode.removeChild(t.nextSibling);J(n,t.nodeValue);break;case Zr:try{o=h.exec(t.nodeValue),o&&(f=cn(o[1]),U(n,f,"M",r,i)&&(e[f]=zr(o[2])))}catch(_){}}return n.sort(X),n}function D(t,n,e){var r=[],i=0;if(n&&t.hasAttribute&&t.hasAttribute(n)){do{if(!t)throw Pi("uterdir","Unterminated attribute, found '{0}' but no matching '{1}' found.",n,e);t.nodeType==Yr&&(t.hasAttribute(n)&&i++,t.hasAttribute(e)&&i--),r.push(t),t=t.nextSibling}while(i>0)}else r.push(t);return Mr(r)}function z(t,n,e){return function(r,i,o,a,u){return i=D(i[0],n,e),t(r,i,o,a,u)}}function q(t,r,o,a,u,l,c,f,h){function p(t,n,e,r){t&&(e&&(t=z(t,e,r)),t.require=m.require,t.directiveName=y,(P===m||m.$$isolateScope)&&(t=rt(t,{isolateScope:!0})),c.push(t)),n&&(e&&(n=z(n,e,r)),n.require=m.require,n.directiveName=y,(P===m||m.$$isolateScope)&&(n=rt(n,{isolateScope:!0})),f.push(n))}function d(t,n,e,r){var i;if(C(n)){var o=n.match(w),a=n.substring(o[0].length),u=o[1]||o[3],s="?"===o[2];if("^^"===u?e=e.parent():(i=r&&r[a],i=i&&i.instance),!i){var l="$"+a+"Controller";i=u?e.inheritedData(l):e.data(l)}if(!i&&!s)throw Pi("ctreq","Controller '{0}', required by directive '{1}', can't be found!",a,t)}else if(Fr(n)){i=[];for(var c=0,f=n.length;f>c;c++)i[c]=d(t,n[c],e,r)}return i||null}function v(t,n,e,r,i,o){var a=gt();for(var u in r){var l=r[u],c={$scope:l===P||l.$$isolateScope?i:o,$element:t,$attrs:n,$transclude:e},f=l.controller;"@"==f&&(f=n[l.name]);var h=s(f,c,!0,l.controllerAs);a[l.name]=h,F||t.data("$"+l.name+"Controller",h.instance)}return a}function g(t,n,i,a,u,s){function l(t,n,r){var i;return E(t)||(r=n,n=t,t=e),F&&(i=$),r||(r=F?b.parent():b),u(t,n,i,r,L)}var h,p,g,m,y,$,x,b,w;if(r===i?(w=o,b=o.$$element):(b=Mr(i),w=new at(b,o)),P&&(y=n.$new(!0)),u&&(x=l,x.$$boundTransclude=u),A&&($=v(b,w,x,A,y,n)),P&&(T.$$addScopeInfo(b,y,!0,!(O&&(O===P||O===P.$$originalDirective))),T.$$addScopeClass(b,!0),y.$$isolateBindings=P.$$isolateBindings,ot(n,w,y,y.$$isolateBindings,P,y)),$){var C,S,_=P||k;_&&$[_.name]&&(C=_.$$bindings.bindToController,m=$[_.name],m&&m.identifier&&C&&(S=m,s.$$destroyBindings=ot(n,w,m.instance,C,_)));for(h in $){m=$[h];var M=m();M!==m.instance&&(m.instance=M,b.data("$"+h+"Controller",M),m===S&&(s.$$destroyBindings(),s.$$destroyBindings=ot(n,w,M,C,_)))}}for(h=0,p=c.length;p>h;h++)g=c[h],it(g,g.isolateScope?y:n,b,w,g.require&&d(g.directiveName,g.require,b,$),x);var L=n;for(P&&(P.template||null===P.templateUrl)&&(L=y),t&&t(L,i.childNodes,e,u),h=f.length-1;h>=0;h--)g=f[h],it(g,g.isolateScope?y:n,b,w,g.require&&d(g.directiveName,g.require,b,$),x)}h=h||{};for(var m,y,$,x,S,_=-Number.MAX_VALUE,k=h.newScopeDirective,A=h.controllerDirectives,P=h.newIsolateScopeDirective,O=h.templateDirective,L=h.nonTlbTranscludeDirective,j=!1,N=!1,F=h.hasElementTranscludeDirective,I=o.$$element=Mr(r),q=l,V=a,U=0,H=t.length;H>U;U++){m=t[U];var X=m.$$start,J=m.$$end;if(X&&(I=D(r,X,J)),$=e,_>m.priority)break;if((S=m.scope)&&(m.templateUrl||(b(S)?(Z("new/isolated scope",P||k,m,I),P=m):Z("new/isolated scope",P,m,I)),k=k||m),y=m.name,!m.templateUrl&&m.controller&&(S=m.controller,A=A||gt(),Z("'"+y+"' controller",A[y],m,I),
+A[y]=m),(S=m.transclude)&&(j=!0,m.$$tlb||(Z("transclusion",L,m,I),L=m),"element"==S?(F=!0,_=m.priority,$=I,I=o.$$element=Mr(n.createComment(" "+y+": "+o[y]+" ")),r=I[0],et(u,W($),r),V=T($,a,_,q&&q.name,{nonTlbTranscludeDirective:L})):($=Mr(Et(r)).contents(),I.empty(),V=T($,a))),m.template)if(N=!0,Z("template",O,m,I),O=m,S=M(m.template)?m.template(I,o):m.template,S=ct(S),m.replace){if(q=m,$=Ct(S)?[]:hn(Q(m.templateNamespace,zr(S))),r=$[0],1!=$.length||r.nodeType!==Yr)throw Pi("tplrt","Template for directive '{0}' must have exactly one root element. {1}",y,"");et(u,I,r);var tt={$attr:{}},nt=R(r,[],tt),ut=t.splice(U+1,t.length-(U+1));P&&B(nt),t=t.concat(nt).concat(ut),Y(o,tt),H=t.length}else I.html(S);if(m.templateUrl)N=!0,Z("template",O,m,I),O=m,m.replace&&(q=m),g=G(t.splice(U,t.length-U),I,o,u,j&&V,c,f,{controllerDirectives:A,newScopeDirective:k!==m&&k,newIsolateScopeDirective:P,templateDirective:O,nonTlbTranscludeDirective:L}),H=t.length;else if(m.compile)try{x=m.compile(I,o,V),M(x)?p(null,x,X,J):x&&p(x.pre,x.post,X,J)}catch(st){i(st,K(I))}m.terminal&&(g.terminal=!0,_=Math.max(_,m.priority))}return g.scope=k&&k.scope===!0,g.transcludeOnThisElement=j,g.templateOnThisElement=N,g.transclude=V,h.hasElementTranscludeDirective=F,g}function B(t){for(var n=0,e=t.length;e>n;n++)t[n]=d(t[n],{$$isolateScope:!0})}function U(n,e,r,o,a,u,s){if(e===a)return null;var f=null;if(l.hasOwnProperty(e))for(var h,p=t.get(e+c),v=0,g=p.length;g>v;v++)try{h=p[v],($(o)||o>h.priority)&&-1!=h.restrict.indexOf(r)&&(u&&(h=d(h,{$$start:u,$$end:s})),n.push(h),f=h)}catch(m){i(m)}return f}function H(n){if(l.hasOwnProperty(n))for(var e,r=t.get(n+c),i=0,o=r.length;o>i;i++)if(e=r[i],e.multiElement)return!0;return!1}function Y(t,n){var e=n.$attr,r=t.$attr,i=t.$$element;o(t,function(r,i){"$"!=i.charAt(0)&&(n[i]&&n[i]!==r&&(r+=("style"===i?";":" ")+n[i]),t.$set(i,r,!0,e[i]))}),o(n,function(n,o){"class"==o?(O(i,n),t["class"]=(t["class"]?t["class"]+" ":"")+n):"style"==o?(i.attr("style",i.attr("style")+";"+n),t.style=(t.style?t.style+";":"")+n):"$"==o.charAt(0)||t.hasOwnProperty(o)||(t[o]=n,r[o]=e[o])})}function G(t,n,e,r,i,u,s,l){var c,f,h=[],p=n[0],v=t.shift(),g=d(v,{templateUrl:null,transclude:null,replace:null,$$originalDirective:v}),m=M(v.templateUrl)?v.templateUrl(n,e):v.templateUrl,y=v.templateNamespace;return n.empty(),a(m).then(function(a){var d,$,x,w;if(a=ct(a),v.replace){if(x=Ct(a)?[]:hn(Q(y,zr(a))),d=x[0],1!=x.length||d.nodeType!==Yr)throw Pi("tplrt","Template for directive '{0}' must have exactly one root element. {1}",v.name,m);$={$attr:{}},et(r,n,d);var C=R(d,[],$);b(v.scope)&&B(C),t=C.concat(t),Y(e,$)}else d=p,n.html(a);for(t.unshift(g),c=q(t,d,e,i,n,v,u,s,l),o(r,function(t,e){t==d&&(r[e]=n[0])}),f=j(n[0].childNodes,i);h.length;){var S=h.shift(),_=h.shift(),M=h.shift(),k=h.shift(),A=n[0];if(!S.$$destroyed){if(_!==p){var E=_.className;l.hasElementTranscludeDirective&&v.replace||(A=Et(d)),et(M,Mr(_),A),O(Mr(A),E)}w=c.transcludeOnThisElement?N(S,c.transclude,k):k,c(f,S,A,r,w,c)}}h=null}),function(t,n,e,r,i){var o=i;n.$$destroyed||(h?h.push(n,e,r,o):(c.transcludeOnThisElement&&(o=N(n,c.transclude,i)),c(f,n,e,r,o,c)))}}function X(t,n){var e=n.priority-t.priority;return 0!==e?e:t.name!==n.name?t.name<n.name?-1:1:t.index-n.index}function Z(t,n,e,r){function i(t){return t?" (module: "+t+")":""}if(n)throw Pi("multidir","Multiple directives [{0}{1}, {2}{3}] asking for {4} on: {5}",n.name,i(n.$$moduleName),e.name,i(e.$$moduleName),t,K(r))}function J(t,n){var e=r(n,!0);e&&t.push({priority:0,compile:function(t){var n=t.parent(),r=!!n.length;return r&&T.$$addBindingClass(n),function(t,n){var i=n.parent();r||T.$$addBindingClass(i),T.$$addBindingInfo(i,e.expressions),t.$watch(e,function(t){n[0].nodeValue=t})}}})}function Q(t,e){switch(t=xr(t||"html")){case"svg":case"math":var r=n.createElement("div");return r.innerHTML="<"+t+">"+e+"</"+t+">",r.childNodes[0].childNodes;default:return e}}function tt(t,n){if("srcdoc"==n)return k.HTML;var e=F(t);return"xlinkHref"==n||"form"==e&&"action"==n||"img"!=e&&("src"==n||"ngSrc"==n)?k.RESOURCE_URL:void 0}function nt(t,n,e,i,o){var a=tt(t,i);o=y[i]||o;var u=r(e,!0,a,o);if(u){if("multiple"===i&&"select"===F(t))throw Pi("selmulti","Binding to the 'multiple' attribute is not supported. Element: {0}",K(t));n.push({priority:100,compile:function(){return{pre:function(t,n,s){var l=s.$$observers||(s.$$observers=gt());if(S.test(i))throw Pi("nodomevents","Interpolations for HTML DOM event attributes are disallowed.  Please use the ng- versions (such as ng-click instead of onclick) instead.");var c=s[i];c!==e&&(u=c&&r(c,!0,a,o),e=c),u&&(s[i]=u(t),(l[i]||(l[i]=[])).$$inter=!0,(s.$$observers&&s.$$observers[i].$$scope||t).$watch(u,function(t,n){"class"===i&&t!=n?s.$updateClass(t,n):s.$set(i,t)}))}}}})}}function et(t,e,r){var i,o,a=e[0],u=e.length,s=a.parentNode;if(t)for(i=0,o=t.length;o>i;i++)if(t[i]==a){t[i++]=r;for(var l=i,c=l+u-1,f=t.length;f>l;l++,c++)f>c?t[l]=t[c]:delete t[l];t.length-=u-1,t.context===a&&(t.context=r);break}s&&s.replaceChild(r,a);var h=n.createDocumentFragment();h.appendChild(a),Mr.hasData(a)&&(Mr(r).data(Mr(a).data()),kr?(Dr=!0,kr.cleanData([a])):delete Mr.cache[a[Mr.expando]]);for(var p=1,d=e.length;d>p;p++){var v=e[p];Mr(v).remove(),h.appendChild(v),delete e[p]}e[0]=r,e.length=1}function rt(t,n){return f(function(){return t.apply(null,arguments)},t,n)}function it(t,n,e,r,o,a){try{t(n,e,r,o,a)}catch(u){i(u,K(e))}}function ot(t,n,e,i,a,s){var l;o(i,function(i,o){var s,c,f,h,p=i.attrName,d=i.optional,g=i.mode;switch(g){case"@":d||br.call(n,p)||(e[o]=n[p]=void 0),n.$observe(p,function(t){C(t)&&(e[o]=t)}),n.$$observers[p].$$scope=t,C(n[p])&&(e[o]=r(n[p])(t));break;case"=":if(!br.call(n,p)){if(d)break;n[p]=void 0}if(d&&!n[p])break;c=u(n[p]),h=c.literal?V:function(t,n){return t===n||t!==t&&n!==n},f=c.assign||function(){throw s=e[o]=c(t),Pi("nonassign","Expression '{0}' used with directive '{1}' is non-assignable!",n[p],a.name)},s=e[o]=c(t);var m=function(n){return h(n,e[o])||(h(n,s)?f(t,n=e[o]):e[o]=n),s=n};m.$stateful=!0;var y;y=i.collection?t.$watchCollection(n[p],m):t.$watch(u(n[p],m),null,c.literal),l=l||[],l.push(y);break;case"&":if(c=n.hasOwnProperty(p)?u(n[p]):v,c===v&&d)break;e[o]=function(n){return c(t,n)}}});var c=l?function(){for(var t=0,n=l.length;n>t;++t)l[t]()}:v;return s&&c!==v?(s.$on("$destroy",c),v):c}var at=function(t,n){if(n){var e,r,i,o=Object.keys(n);for(e=0,r=o.length;r>e;e++)i=o[e],this[i]=n[i]}else this.$attr={};this.$$element=t};at.prototype={$normalize:cn,$addClass:function(t){t&&t.length>0&&A.addClass(this.$$element,t)},$removeClass:function(t){t&&t.length>0&&A.removeClass(this.$$element,t)},$updateClass:function(t,n){var e=fn(t,n);e&&e.length&&A.addClass(this.$$element,e);var r=fn(n,t);r&&r.length&&A.removeClass(this.$$element,r)},$set:function(t,n,e,r){var a,u=this.$$element[0],s=Wt(u,t),l=Ut(t),c=t;if(s?(this.$$element.prop(t,n),r=s):l&&(this[l]=n,c=l),this[t]=n,r?this.$attr[t]=r:(r=this.$attr[t],r||(this.$attr[t]=r=lt(t,"-"))),a=F(this.$$element),"a"===a&&"href"===t||"img"===a&&"src"===t)this[t]=n=P(n,"src"===t);else if("img"===a&&"srcset"===t){for(var f="",h=zr(n),p=/(\s+\d+x\s*,|\s+\d+w\s*,|\s+,|,\s+)/,d=/\s/.test(h)?p:/(,)/,v=h.split(d),g=Math.floor(v.length/2),m=0;g>m;m++){var y=2*m;f+=P(zr(v[y]),!0),f+=" "+zr(v[y+1])}var x=zr(v[2*m]).split(/\s/);f+=P(zr(x[0]),!0),2===x.length&&(f+=" "+zr(x[1])),this[t]=n=f}e!==!1&&(null===n||$(n)?this.$$element.removeAttr(r):this.$$element.attr(r,n));var b=this.$$observers;b&&o(b[c],function(t){try{t(n)}catch(e){i(e)}})},$observe:function(t,n){var e=this,r=e.$$observers||(e.$$observers=gt()),i=r[t]||(r[t]=[]);return i.push(n),m.$evalAsync(function(){i.$$inter||!e.hasOwnProperty(t)||$(e[t])||n(e[t])}),function(){I(i,n)}}};var ut=r.startSymbol(),st=r.endSymbol(),ct="{{"==ut||"}}"==st?g:function(t){return t.replace(/\{\{/g,ut).replace(/}}/g,st)},ht=/^ngAttr[A-Z]/;return T.$$addBindingInfo=_?function(t,n){var e=t.data("$binding")||[];Fr(n)?e=e.concat(n):e.push(n),t.data("$binding",e)}:v,T.$$addBindingClass=_?function(t){O(t,"ng-binding")}:v,T.$$addScopeInfo=_?function(t,n,e,r){var i=e?r?"$isolateScopeNoTemplate":"$isolateScope":"$scope";t.data(i,n)}:v,T.$$addScopeClass=_?function(t,n){O(t,n?"ng-isolate-scope":"ng-scope")}:v,T}]}function cn(t){return wt(t.replace(Oi,""))}function fn(t,n){var e="",r=t.split(/\s+/),i=n.split(/\s+/);t:for(var o=0;o<r.length;o++){for(var a=r[o],u=0;u<i.length;u++)if(a==i[u])continue t;e+=(e.length>0?" ":"")+a}return e}function hn(t){t=Mr(t);var n=t.length;if(1>=n)return t;for(;n--;){var e=t[n];e.nodeType===Zr&&Pr.call(t,n,1)}return t}function pn(t,n){if(n&&C(n))return n;if(C(t)){var e=Li.exec(t);if(e)return e[3]}}function dn(){var t={},n=!1;this.register=function(n,e){pt(n,"controller"),b(n)?f(t,n):t[n]=e},this.allowGlobals=function(){n=!0},this.$get=["$injector","$window",function(i,o){function a(t,n,e,i){if(!t||!b(t.$scope))throw r("$controller")("noscp","Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.",i,n);t.$scope[n]=e}return function(r,u,s,l){var c,h,p,d;if(s=s===!0,l&&C(l)&&(d=l),C(r)){if(h=r.match(Li),!h)throw Ti("ctrlfmt","Badly formed controller string '{0}'. Must match `__name__ as __id__` or `__name__`.",r);p=h[1],d=d||h[3],r=t.hasOwnProperty(p)?t[p]:dt(u.$scope,p,!0)||(n?dt(o,p,!0):e),ht(r,p,!0)}if(s){var v=(Fr(r)?r[r.length-1]:r).prototype;c=Object.create(v||null),d&&a(u,d,c,p||r.name);var g;return g=f(function(){var t=i.invoke(r,c,u,p);return t!==c&&(b(t)||M(t))&&(c=t,d&&a(u,d,c,p||r.name)),c},{instance:c,identifier:d})}return c=i.instantiate(r,u,p),d&&a(u,d,c,p||r.name),c}}]}function vn(){this.$get=["$window",function(t){return Mr(t.document)}]}function gn(){this.$get=["$log",function(t){return function(n,e){t.error.apply(t,arguments)}}]}function mn(t){return b(t)?_(t)?t.toISOString():Y(t):t}function yn(){this.$get=function(){return function(t){if(!t)return"";var n=[];return a(t,function(t,e){null===t||$(t)||(Fr(t)?o(t,function(t,r){n.push(rt(e)+"="+rt(mn(t)))}):n.push(rt(e)+"="+rt(mn(t))))}),n.join("&")}}}function $n(){this.$get=function(){return function(t){function n(t,r,i){null===t||$(t)||(Fr(t)?o(t,function(t,e){n(t,r+"["+(b(t)?e:"")+"]")}):b(t)&&!_(t)?a(t,function(t,e){n(t,r+(i?"":"[")+e+(i?"":"]"))}):e.push(rt(r)+"="+rt(mn(t))))}if(!t)return"";var e=[];return n(t,"",!0),e.join("&")}}}function xn(t,n){if(C(t)){var e=t.replace(Ii,"").trim();if(e){var r=n("Content-Type");(r&&0===r.indexOf(Ni)||bn(e))&&(t=G(e))}}return t}function bn(t){var n=t.match(Di);return n&&Fi[n[0]].test(t)}function wn(t){function n(t,n){t&&(r[t]=r[t]?r[t]+", "+n:n)}var e,r=gt();return C(t)?o(t.split("\n"),function(t){e=t.indexOf(":"),n(xr(zr(t.substr(0,e))),zr(t.substr(e+1)))}):b(t)&&o(t,function(t,e){n(xr(e),zr(t))}),r}function Cn(t){var n;return function(e){if(n||(n=wn(t)),e){var r=n[xr(e)];return void 0===r&&(r=null),r}return n}}function Sn(t,n,e,r){return M(r)?r(t,n,e):(o(r,function(r){t=r(t,n,e)}),t)}function _n(t){return t>=200&&300>t}function Mn(){var t=this.defaults={transformResponse:[xn],transformRequest:[function(t){return!b(t)||P(t)||T(t)||O(t)?t:Y(t)}],headers:{common:{Accept:"application/json, text/plain, */*"},post:q(Ri),put:q(Ri),patch:q(Ri)},xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",paramSerializer:"$httpParamSerializer"},n=!1;this.useApplyAsync=function(t){return x(t)?(n=!!t,this):n};var i=!0;this.useLegacyPromiseExtensions=function(t){return x(t)?(i=!!t,this):i};var a=this.interceptors=[];this.$get=["$httpBackend","$$cookieReader","$cacheFactory","$rootScope","$q","$injector",function(u,s,l,c,h,p){function d(n){function a(t){var n=f({},t);return t.data?n.data=Sn(t.data,t.headers,t.status,l.transformResponse):n.data=t.data,_n(t.status)?n:h.reject(n)}function u(t,n){var e,r={};return o(t,function(t,i){M(t)?(e=t(n),null!=e&&(r[i]=e)):r[i]=t}),r}function s(n){var e,r,i,o=t.headers,a=f({},n.headers);o=f({},o.common,o[xr(n.method)]);t:for(e in o){r=xr(e);for(i in a)if(xr(i)===r)continue t;a[e]=o[e]}return u(a,q(n))}if(!Nr.isObject(n))throw r("$http")("badreq","Http request configuration must be an object.  Received: {0}",n);var l=f({method:"get",transformRequest:t.transformRequest,transformResponse:t.transformResponse,paramSerializer:t.paramSerializer},n);l.headers=s(n),l.method=wr(l.method),l.paramSerializer=C(l.paramSerializer)?p.get(l.paramSerializer):l.paramSerializer;var c=function(n){var r=n.headers,i=Sn(n.data,Cn(r),e,n.transformRequest);return $(i)&&o(r,function(t,n){"content-type"===xr(n)&&delete r[n]}),$(n.withCredentials)&&!$(t.withCredentials)&&(n.withCredentials=t.withCredentials),m(n,i).then(a,a)},d=[c,e],v=h.when(l);for(o(S,function(t){(t.request||t.requestError)&&d.unshift(t.request,t.requestError),(t.response||t.responseError)&&d.push(t.response,t.responseError)});d.length;){var g=d.shift(),y=d.shift();v=v.then(g,y)}return i?(v.success=function(t){return ht(t,"fn"),v.then(function(n){t(n.data,n.status,n.headers,l)}),v},v.error=function(t){return ht(t,"fn"),v.then(null,function(n){t(n.data,n.status,n.headers,l)}),v}):(v.success=qi("success"),v.error=qi("error")),v}function v(t){o(arguments,function(t){d[t]=function(n,e){return d(f({},e||{},{method:t,url:n}))}})}function g(t){o(arguments,function(t){d[t]=function(n,e,r){return d(f({},r||{},{method:t,url:n,data:e}))}})}function m(r,i){function o(t,e,r,i){function o(){a(e,t,r,i)}p&&(_n(t)?p.put(S,[t,e,wn(r),i]):p.remove(S)),n?c.$applyAsync(o):(o(),c.$$phase||c.$apply())}function a(t,n,e,i){n=n>=-1?n:0,(_n(n)?g.resolve:g.reject)({data:t,status:n,headers:Cn(e),config:r,statusText:i})}function l(t){a(t.data,t.status,q(t.headers()),t.statusText)}function f(){var t=d.pendingRequests.indexOf(r);-1!==t&&d.pendingRequests.splice(t,1)}var p,v,g=h.defer(),m=g.promise,C=r.headers,S=y(r.url,r.paramSerializer(r.params));if(d.pendingRequests.push(r),m.then(f,f),!r.cache&&!t.cache||r.cache===!1||"GET"!==r.method&&"JSONP"!==r.method||(p=b(r.cache)?r.cache:b(t.cache)?t.cache:w),p&&(v=p.get(S),x(v)?j(v)?v.then(l,l):Fr(v)?a(v[1],v[0],q(v[2]),v[3]):a(v,200,{},"OK"):p.put(S,m)),$(v)){var _=ke(r.url)?s()[r.xsrfCookieName||t.xsrfCookieName]:e;_&&(C[r.xsrfHeaderName||t.xsrfHeaderName]=_),u(r.method,S,i,o,C,r.timeout,r.withCredentials,r.responseType)}return m}function y(t,n){return n.length>0&&(t+=(-1==t.indexOf("?")?"?":"&")+n),t}var w=l("$http");t.paramSerializer=C(t.paramSerializer)?p.get(t.paramSerializer):t.paramSerializer;var S=[];return o(a,function(t){S.unshift(C(t)?p.get(t):p.invoke(t))}),d.pendingRequests=[],v("get","delete","head","jsonp"),g("post","put","patch"),d.defaults=t,d}]}function kn(){this.$get=function(){return function(){return new t.XMLHttpRequest}}}function An(){this.$get=["$browser","$window","$document","$xhrFactory",function(t,n,e,r){return En(t,r,t.defer,n.angular.callbacks,e[0])}]}function En(t,n,e,r,i){function a(t,n,e){var o=i.createElement("script"),a=null;return o.type="text/javascript",o.src=t,o.async=!0,a=function(t){ri(o,"load",a),ri(o,"error",a),i.body.removeChild(o),o=null;var u=-1,s="unknown";t&&("load"!==t.type||r[n].called||(t={type:"error"}),s=t.type,u="error"===t.type?404:200),e&&e(u,s)},ei(o,"load",a),ei(o,"error",a),i.body.appendChild(o),a}return function(i,u,s,l,c,f,h,p){function d(){y&&y(),b&&b.abort()}function g(n,r,i,o,a){x(S)&&e.cancel(S),y=b=null,n(r,i,o,a),t.$$completeOutstandingRequest(v)}if(t.$$incOutstandingRequestCount(),u=u||t.url(),"jsonp"==xr(i)){var m="_"+(r.counter++).toString(36);r[m]=function(t){r[m].data=t,r[m].called=!0};var y=a(u.replace("JSON_CALLBACK","angular.callbacks."+m),m,function(t,n){g(l,t,r[m].data,"",n),r[m]=v})}else{var b=n(i,u);b.open(i,u,!0),o(c,function(t,n){x(t)&&b.setRequestHeader(n,t)}),b.onload=function(){var t=b.statusText||"",n="response"in b?b.response:b.responseText,e=1223===b.status?204:b.status;0===e&&(e=n?200:"file"==Me(u).protocol?404:0),g(l,e,n,b.getAllResponseHeaders(),t)};var w=function(){g(l,-1,null,null,"")};if(b.onerror=w,b.onabort=w,h&&(b.withCredentials=!0),p)try{b.responseType=p}catch(C){if("json"!==p)throw C}b.send($(s)?null:s)}if(f>0)var S=e(d,f);else j(f)&&f.then(d)}}function Pn(){var t="{{",n="}}";this.startSymbol=function(n){return n?(t=n,this):t},this.endSymbol=function(t){return t?(n=t,this):n},this.$get=["$parse","$exceptionHandler","$sce",function(e,r,i){function o(t){return"\\\\\\"+t}function a(e){return e.replace(h,t).replace(p,n)}function u(t){if(null==t)return"";switch(typeof t){case"string":break;case"number":t=""+t;break;default:t=Y(t)}return t}function s(o,s,h,p){function d(t){try{return t=A(t),p&&!x(t)?t:u(t)}catch(n){r(Vi.interr(o,n))}}p=!!p;for(var v,g,m,y=0,b=[],w=[],C=o.length,S=[],_=[];C>y;){if(-1==(v=o.indexOf(t,y))||-1==(g=o.indexOf(n,v+l))){y!==C&&S.push(a(o.substring(y)));break}y!==v&&S.push(a(o.substring(y,v))),m=o.substring(v+l,g),b.push(m),w.push(e(m,d)),y=g+c,_.push(S.length),S.push("")}if(h&&S.length>1&&Vi.throwNoconcat(o),!s||b.length){var k=function(t){for(var n=0,e=b.length;e>n;n++){if(p&&$(t[n]))return;S[_[n]]=t[n]}return S.join("")},A=function(t){return h?i.getTrusted(h,t):i.valueOf(t)};return f(function(t){var n=0,e=b.length,i=new Array(e);try{for(;e>n;n++)i[n]=w[n](t);return k(i)}catch(a){r(Vi.interr(o,a))}},{exp:o,expressions:b,$$watchDelegate:function(t,n){var e;return t.$watchGroup(w,function(r,i){var o=k(r);M(n)&&n.call(this,o,r!==i?e:o,t),e=o})}})}}var l=t.length,c=n.length,h=new RegExp(t.replace(/./g,o),"g"),p=new RegExp(n.replace(/./g,o),"g");return s.startSymbol=function(){return t},s.endSymbol=function(){return n},s}]}function On(){this.$get=["$rootScope","$window","$q","$$q",function(t,n,e,r){function i(i,a,u,s){var l=arguments.length>4,c=l?W(arguments,4):[],f=n.setInterval,h=n.clearInterval,p=0,d=x(s)&&!s,v=(d?r:e).defer(),g=v.promise;return u=x(u)?u:0,g.then(null,null,l?function(){i.apply(null,c)}:i),g.$$intervalId=f(function(){v.notify(p++),u>0&&p>=u&&(v.resolve(p),h(g.$$intervalId),delete o[g.$$intervalId]),d||t.$apply()},a),o[g.$$intervalId]=v,g}var o={};return i.cancel=function(t){return t&&t.$$intervalId in o?(o[t.$$intervalId].reject("canceled"),n.clearInterval(t.$$intervalId),delete o[t.$$intervalId],!0):!1},i}]}function Tn(t){for(var n=t.split("/"),e=n.length;e--;)n[e]=et(n[e]);return n.join("/")}function Ln(t,n){var e=Me(t);n.$$protocol=e.protocol,n.$$host=e.hostname,n.$$port=p(e.port)||Wi[e.protocol]||null}function jn(t,n){var e="/"!==t.charAt(0);e&&(t="/"+t);var r=Me(t);n.$$path=decodeURIComponent(e&&"/"===r.pathname.charAt(0)?r.pathname.substring(1):r.pathname),n.$$search=tt(r.search),n.$$hash=decodeURIComponent(r.hash),n.$$path&&"/"!=n.$$path.charAt(0)&&(n.$$path="/"+n.$$path)}function Nn(t,n){return 0===n.indexOf(t)?n.substr(t.length):void 0}function Rn(t){var n=t.indexOf("#");return-1==n?t:t.substr(0,n)}function Dn(t){return t.replace(/(#.+)|#$/,"$1")}function Fn(t){return t.substr(0,Rn(t).lastIndexOf("/")+1)}function In(t){return t.substring(0,t.indexOf("/",t.indexOf("//")+2))}function zn(t,n,e){this.$$html5=!0,e=e||"",Ln(t,this),this.$$parse=function(t){var e=Nn(n,t);if(!C(e))throw Ui("ipthprfx",'Invalid url "{0}", missing path prefix "{1}".',t,n);jn(e,this),this.$$path||(this.$$path="/"),this.$$compose()},this.$$compose=function(){var t=nt(this.$$search),e=this.$$hash?"#"+et(this.$$hash):"";this.$$url=Tn(this.$$path)+(t?"?"+t:"")+e,this.$$absUrl=n+this.$$url.substr(1)},this.$$parseLinkUrl=function(r,i){if(i&&"#"===i[0])return this.hash(i.slice(1)),!0;var o,a,u;return x(o=Nn(t,r))?(a=o,u=x(o=Nn(e,o))?n+(Nn("/",o)||o):t+a):x(o=Nn(n,r))?u=n+o:n==r+"/"&&(u=n),u&&this.$$parse(u),!!u}}function qn(t,n,e){Ln(t,this),this.$$parse=function(r){function i(t,n,e){var r,i=/^\/[A-Z]:(\/.*)/;return 0===n.indexOf(e)&&(n=n.replace(e,"")),i.exec(n)?t:(r=i.exec(t),r?r[1]:t)}var o,a=Nn(t,r)||Nn(n,r);$(a)||"#"!==a.charAt(0)?this.$$html5?o=a:(o="",$(a)&&(t=r,this.replace())):(o=Nn(e,a),$(o)&&(o=a)),jn(o,this),this.$$path=i(this.$$path,o,t),this.$$compose()},this.$$compose=function(){var n=nt(this.$$search),r=this.$$hash?"#"+et(this.$$hash):"";this.$$url=Tn(this.$$path)+(n?"?"+n:"")+r,this.$$absUrl=t+(this.$$url?e+this.$$url:"")},this.$$parseLinkUrl=function(n,e){return Rn(t)==Rn(n)?(this.$$parse(n),!0):!1}}function Vn(t,n,e){this.$$html5=!0,qn.apply(this,arguments),this.$$parseLinkUrl=function(r,i){if(i&&"#"===i[0])return this.hash(i.slice(1)),!0;var o,a;return t==Rn(r)?o=r:(a=Nn(n,r))?o=t+e+a:n===r+"/"&&(o=n),o&&this.$$parse(o),!!o},this.$$compose=function(){var n=nt(this.$$search),r=this.$$hash?"#"+et(this.$$hash):"";this.$$url=Tn(this.$$path)+(n?"?"+n:"")+r,this.$$absUrl=t+e+this.$$url}}function Bn(t){return function(){return this[t]}}function Wn(t,n){return function(e){return $(e)?this[t]:(this[t]=n(e),this.$$compose(),this)}}function Un(){var t="",n={enabled:!1,requireBase:!0,rewriteLinks:!0};this.hashPrefix=function(n){return x(n)?(t=n,this):t},this.html5Mode=function(t){return L(t)?(n.enabled=t,this):b(t)?(L(t.enabled)&&(n.enabled=t.enabled),L(t.requireBase)&&(n.requireBase=t.requireBase),L(t.rewriteLinks)&&(n.rewriteLinks=t.rewriteLinks),this):n},this.$get=["$rootScope","$browser","$sniffer","$rootElement","$window",function(e,r,i,o,a){function u(t,n,e){var i=l.url(),o=l.$$state;try{r.url(t,n,e),l.$$state=r.state()}catch(a){throw l.url(i),l.$$state=o,a}}function s(t,n){e.$broadcast("$locationChangeSuccess",l.absUrl(),t,l.$$state,n)}var l,c,f,h=r.baseHref(),p=r.url();if(n.enabled){if(!h&&n.requireBase)throw Ui("nobase","$location in HTML5 mode requires a <base> tag to be present!");f=In(p)+(h||"/"),c=i.history?zn:Vn}else f=Rn(p),c=qn;var d=Fn(f);l=new c(f,d,"#"+t),l.$$parseLinkUrl(p,p),l.$$state=r.state();var v=/^\s*(javascript|mailto):/i;o.on("click",function(t){if(n.rewriteLinks&&!t.ctrlKey&&!t.metaKey&&!t.shiftKey&&2!=t.which&&2!=t.button){for(var i=Mr(t.target);"a"!==F(i[0]);)if(i[0]===o[0]||!(i=i.parent())[0])return;var u=i.prop("href"),s=i.attr("href")||i.attr("xlink:href");b(u)&&"[object SVGAnimatedString]"===u.toString()&&(u=Me(u.animVal).href),v.test(u)||!u||i.attr("target")||t.isDefaultPrevented()||l.$$parseLinkUrl(u,s)&&(t.preventDefault(),l.absUrl()!=r.url()&&(e.$apply(),a.angular["ff-684208-preventDefault"]=!0))}}),Dn(l.absUrl())!=Dn(p)&&r.url(l.absUrl(),!0);var g=!0;return r.onUrlChange(function(t,n){return $(Nn(d,t))?void(a.location.href=t):(e.$evalAsync(function(){var r,i=l.absUrl(),o=l.$$state;l.$$parse(t),l.$$state=n,r=e.$broadcast("$locationChangeStart",t,i,n,o).defaultPrevented,l.absUrl()===t&&(r?(l.$$parse(i),l.$$state=o,u(i,!1,o)):(g=!1,s(i,o)))}),void(e.$$phase||e.$digest()))}),e.$watch(function(){var t=Dn(r.url()),n=Dn(l.absUrl()),o=r.state(),a=l.$$replace,c=t!==n||l.$$html5&&i.history&&o!==l.$$state;(g||c)&&(g=!1,e.$evalAsync(function(){var n=l.absUrl(),r=e.$broadcast("$locationChangeStart",n,t,l.$$state,o).defaultPrevented;l.absUrl()===n&&(r?(l.$$parse(t),l.$$state=o):(c&&u(n,a,o===l.$$state?null:l.$$state),s(t,o)))})),l.$$replace=!1}),l}]}function Hn(){var t=!0,n=this;this.debugEnabled=function(n){return x(n)?(t=n,this):t},this.$get=["$window",function(e){function r(t){return t instanceof Error&&(t.stack?t=t.message&&-1===t.stack.indexOf(t.message)?"Error: "+t.message+"\n"+t.stack:t.stack:t.sourceURL&&(t=t.message+"\n"+t.sourceURL+":"+t.line)),t}function i(t){var n=e.console||{},i=n[t]||n.log||v,a=!1;try{a=!!i.apply}catch(u){}return a?function(){var t=[];return o(arguments,function(n){t.push(r(n))}),i.apply(n,t)}:function(t,n){i(t,null==n?"":n)}}return{log:i("log"),info:i("info"),warn:i("warn"),error:i("error"),debug:function(){var e=i("debug");return function(){t&&e.apply(n,arguments)}}()}}]}function Yn(t,n){if("__defineGetter__"===t||"__defineSetter__"===t||"__lookupGetter__"===t||"__lookupSetter__"===t||"__proto__"===t)throw Yi("isecfld","Attempting to access a disallowed field in Angular expressions! Expression: {0}",n);return t}function Gn(t,n){if(t+="",!C(t))throw Yi("iseccst","Cannot convert object to primitive value! Expression: {0}",n);return t}function Xn(t,n){if(t){if(t.constructor===t)throw Yi("isecfn","Referencing Function in Angular expressions is disallowed! Expression: {0}",n);if(t.window===t)throw Yi("isecwindow","Referencing the Window in Angular expressions is disallowed! Expression: {0}",n);if(t.children&&(t.nodeName||t.prop&&t.attr&&t.find))throw Yi("isecdom","Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}",n);if(t===Object)throw Yi("isecobj","Referencing Object in Angular expressions is disallowed! Expression: {0}",n)}return t}function Zn(t,n){if(t){if(t.constructor===t)throw Yi("isecfn","Referencing Function in Angular expressions is disallowed! Expression: {0}",n);if(t===Gi||t===Xi||t===Zi)throw Yi("isecff","Referencing call, apply or bind in Angular expressions is disallowed! Expression: {0}",n)}}function Jn(t,n){if(t&&(t===0..constructor||t===(!1).constructor||t==="".constructor||t==={}.constructor||t===[].constructor||t===Function.constructor))throw Yi("isecaf","Assigning to a constructor is disallowed! Expression: {0}",n)}function Kn(t,n){return"undefined"!=typeof t?t:n}function Qn(t,n){return"undefined"==typeof t?n:"undefined"==typeof n?t:t+n}function te(t,n){var e=t(n);return!e.$stateful}function ne(t,n){var e,r;switch(t.type){case to.Program:e=!0,o(t.body,function(t){ne(t.expression,n),e=e&&t.expression.constant}),t.constant=e;break;case to.Literal:t.constant=!0,t.toWatch=[];break;case to.UnaryExpression:ne(t.argument,n),t.constant=t.argument.constant,t.toWatch=t.argument.toWatch;break;case to.BinaryExpression:ne(t.left,n),ne(t.right,n),t.constant=t.left.constant&&t.right.constant,t.toWatch=t.left.toWatch.concat(t.right.toWatch);break;case to.LogicalExpression:ne(t.left,n),ne(t.right,n),t.constant=t.left.constant&&t.right.constant,t.toWatch=t.constant?[]:[t];break;case to.ConditionalExpression:ne(t.test,n),ne(t.alternate,n),ne(t.consequent,n),t.constant=t.test.constant&&t.alternate.constant&&t.consequent.constant,t.toWatch=t.constant?[]:[t];break;case to.Identifier:t.constant=!1,t.toWatch=[t];break;case to.MemberExpression:ne(t.object,n),t.computed&&ne(t.property,n),t.constant=t.object.constant&&(!t.computed||t.property.constant),t.toWatch=[t];break;case to.CallExpression:e=t.filter?te(n,t.callee.name):!1,r=[],o(t.arguments,function(t){ne(t,n),e=e&&t.constant,t.constant||r.push.apply(r,t.toWatch)}),t.constant=e,t.toWatch=t.filter&&te(n,t.callee.name)?r:[t];break;case to.AssignmentExpression:ne(t.left,n),ne(t.right,n),t.constant=t.left.constant&&t.right.constant,t.toWatch=[t];break;case to.ArrayExpression:e=!0,r=[],o(t.elements,function(t){ne(t,n),e=e&&t.constant,t.constant||r.push.apply(r,t.toWatch)}),t.constant=e,t.toWatch=r;break;case to.ObjectExpression:e=!0,r=[],o(t.properties,function(t){ne(t.value,n),e=e&&t.value.constant,t.value.constant||r.push.apply(r,t.value.toWatch)}),t.constant=e,t.toWatch=r;break;case to.ThisExpression:t.constant=!1,t.toWatch=[]}}function ee(t){if(1==t.length){var n=t[0].expression,r=n.toWatch;return 1!==r.length?r:r[0]!==n?r:e}}function re(t){return t.type===to.Identifier||t.type===to.MemberExpression}function ie(t){return 1===t.body.length&&re(t.body[0].expression)?{type:to.AssignmentExpression,left:t.body[0].expression,right:{type:to.NGValueParameter},operator:"="}:void 0}function oe(t){return 0===t.body.length||1===t.body.length&&(t.body[0].expression.type===to.Literal||t.body[0].expression.type===to.ArrayExpression||t.body[0].expression.type===to.ObjectExpression)}function ae(t){return t.constant}function ue(t,n){this.astBuilder=t,this.$filter=n}function se(t,n){this.astBuilder=t,this.$filter=n}function le(t){return"constructor"==t}function ce(t){return M(t.valueOf)?t.valueOf():eo.call(t)}function fe(){var t=gt(),n=gt();this.$get=["$filter",function(r){function i(t,n){return null==t||null==n?t===n:"object"==typeof t&&(t=ce(t),"object"==typeof t)?!1:t===n||t!==t&&n!==n}function a(t,n,r,o,a){var u,s=o.inputs;if(1===s.length){var l=i;return s=s[0],t.$watch(function(t){var n=s(t);return i(n,l)||(u=o(t,e,e,[n]),l=n&&ce(n)),u},n,r,a)}for(var c=[],f=[],h=0,p=s.length;p>h;h++)c[h]=i,f[h]=null;return t.$watch(function(t){for(var n=!1,r=0,a=s.length;a>r;r++){var l=s[r](t);(n||(n=!i(l,c[r])))&&(f[r]=l,c[r]=l&&ce(l))}return n&&(u=o(t,e,e,f)),u},n,r,a)}function u(t,n,e,r){var i,o;return i=t.$watch(function(t){return r(t)},function(t,e,r){o=t,M(n)&&n.apply(this,arguments),x(t)&&r.$$postDigest(function(){x(o)&&i()})},e)}function s(t,n,e,r){function i(t){var n=!0;return o(t,function(t){x(t)||(n=!1)}),n}var a,u;return a=t.$watch(function(t){return r(t)},function(t,e,r){u=t,M(n)&&n.call(this,t,e,r),i(t)&&r.$$postDigest(function(){i(u)&&a()})},e)}function l(t,n,e,r){var i;return i=t.$watch(function(t){return r(t)},function(t,e,r){M(n)&&n.apply(this,arguments),i()},e)}function c(t,n){if(!n)return t;var e=t.$$watchDelegate,r=e!==s&&e!==u,i=r?function(e,r,i,o){var a=t(e,r,i,o);return n(a,e,r)}:function(e,r,i,o){var a=t(e,r,i,o),u=n(a,e,r);return x(a)?u:a};return t.$$watchDelegate&&t.$$watchDelegate!==a?i.$$watchDelegate=t.$$watchDelegate:n.$stateful||(i.$$watchDelegate=a,i.inputs=t.inputs?t.inputs:[t]),i}var f=Vr().noUnsafeEval,h={csp:f,expensiveChecks:!1},p={csp:f,expensiveChecks:!0};return function(e,i,o){var f,d,g;switch(typeof e){case"string":e=e.trim(),g=e;var m=o?n:t;if(f=m[g],!f){":"===e.charAt(0)&&":"===e.charAt(1)&&(d=!0,e=e.substring(2));var y=o?p:h,$=new Qi(y),x=new no($,r,y);f=x.parse(e),f.constant?f.$$watchDelegate=l:d?f.$$watchDelegate=f.literal?s:u:f.inputs&&(f.$$watchDelegate=a),m[g]=f}return c(f,i);case"function":return c(e,i);default:return v}}}]}function he(){this.$get=["$rootScope","$exceptionHandler",function(t,n){return de(function(n){t.$evalAsync(n)},n)}]}function pe(){this.$get=["$browser","$exceptionHandler",function(t,n){return de(function(n){t.defer(n)},n)}]}function de(t,n){function i(t,n,e){function r(n){return function(e){i||(i=!0,n.call(t,e))}}var i=!1;return[r(n),r(e)]}function a(){this.$$state={status:0}}function u(t,n){return function(e){n.call(t,e)}}function s(t){var r,i,o;o=t.pending,t.processScheduled=!1,t.pending=e;for(var a=0,u=o.length;u>a;++a){i=o[a][0],r=o[a][t.status];try{M(r)?i.resolve(r(t.value)):1===t.status?i.resolve(t.value):i.reject(t.value)}catch(s){i.reject(s),n(s)}}}function l(n){!n.processScheduled&&n.pending&&(n.processScheduled=!0,t(function(){s(n)}))}function c(){this.promise=new a,this.resolve=u(this,this.resolve),this.reject=u(this,this.reject),this.notify=u(this,this.notify)}function h(t){var n=new c,e=0,r=Fr(t)?[]:{};return o(t,function(t,i){e++,y(t).then(function(t){r.hasOwnProperty(i)||(r[i]=t,--e||n.resolve(r))},function(t){r.hasOwnProperty(i)||n.reject(t)})}),0===e&&n.resolve(r),n.promise}var p=r("$q",TypeError),d=function(){return new c};f(a.prototype,{then:function(t,n,e){if($(t)&&$(n)&&$(e))return this;var r=new c;return this.$$state.pending=this.$$state.pending||[],this.$$state.pending.push([r,t,n,e]),this.$$state.status>0&&l(this.$$state),r.promise},"catch":function(t){return this.then(null,t)},"finally":function(t,n){return this.then(function(n){return m(n,!0,t)},function(n){return m(n,!1,t)},n)}}),f(c.prototype,{resolve:function(t){this.promise.$$state.status||(t===this.promise?this.$$reject(p("qcycle","Expected promise to be resolved with value other than itself '{0}'",t)):this.$$resolve(t))},$$resolve:function(t){var e,r;r=i(this,this.$$resolve,this.$$reject);try{(b(t)||M(t))&&(e=t&&t.then),M(e)?(this.promise.$$state.status=-1,e.call(t,r[0],r[1],this.notify)):(this.promise.$$state.value=t,this.promise.$$state.status=1,l(this.promise.$$state))}catch(o){r[1](o),n(o)}},reject:function(t){this.promise.$$state.status||this.$$reject(t)},$$reject:function(t){this.promise.$$state.value=t,this.promise.$$state.status=2,l(this.promise.$$state)},notify:function(e){var r=this.promise.$$state.pending;this.promise.$$state.status<=0&&r&&r.length&&t(function(){for(var t,i,o=0,a=r.length;a>o;o++){i=r[o][0],t=r[o][3];try{i.notify(M(t)?t(e):e)}catch(u){n(u)}}})}});var v=function(t){var n=new c;return n.reject(t),n.promise},g=function(t,n){var e=new c;return n?e.resolve(t):e.reject(t),e.promise},m=function(t,n,e){
+var r=null;try{M(e)&&(r=e())}catch(i){return g(i,!1)}return j(r)?r.then(function(){return g(t,n)},function(t){return g(t,!1)}):g(t,n)},y=function(t,n,e,r){var i=new c;return i.resolve(t),i.promise.then(n,e,r)},x=y,w=function C(t){function n(t){r.resolve(t)}function e(t){r.reject(t)}if(!M(t))throw p("norslvr","Expected resolverFn, got '{0}'",t);if(!(this instanceof C))return new C(t);var r=new c;return t(n,e),r.promise};return w.defer=d,w.reject=v,w.when=y,w.resolve=x,w.all=h,w}function ve(){this.$get=["$window","$timeout",function(t,n){var e=t.requestAnimationFrame||t.webkitRequestAnimationFrame,r=t.cancelAnimationFrame||t.webkitCancelAnimationFrame||t.webkitCancelRequestAnimationFrame,i=!!e,o=i?function(t){var n=e(t);return function(){r(n)}}:function(t){var e=n(t,16.66,!1);return function(){n.cancel(e)}};return o.supported=i,o}]}function ge(){function t(t){function n(){this.$$watchers=this.$$nextSibling=this.$$childHead=this.$$childTail=null,this.$$listeners={},this.$$listenerCount={},this.$$watchersCount=0,this.$id=s(),this.$$ChildScope=null}return n.prototype=t,n}var n=10,e=r("$rootScope"),a=null,u=null;this.digestTtl=function(t){return arguments.length&&(n=t),n},this.$get=["$injector","$exceptionHandler","$parse","$browser",function(r,l,c,f){function h(t){t.currentScope.$$destroyed=!0}function p(){this.$id=s(),this.$$phase=this.$parent=this.$$watchers=this.$$nextSibling=this.$$prevSibling=this.$$childHead=this.$$childTail=null,this.$root=this,this.$$destroyed=!1,this.$$listeners={},this.$$listenerCount={},this.$$watchersCount=0,this.$$isolateBindings=null}function d(t){if(S.$$phase)throw e("inprog","{0} already in progress",S.$$phase);S.$$phase=t}function g(){S.$$phase=null}function m(t,n){do t.$$watchersCount+=n;while(t=t.$parent)}function y(t,n,e){do t.$$listenerCount[e]-=n,0===t.$$listenerCount[e]&&delete t.$$listenerCount[e];while(t=t.$parent)}function x(){}function w(){for(;A.length;)try{A.shift()()}catch(t){l(t)}u=null}function C(){null===u&&(u=f.defer(function(){S.$apply(w)}))}p.prototype={constructor:p,$new:function(n,e){var r;return e=e||this,n?(r=new p,r.$root=this.$root):(this.$$ChildScope||(this.$$ChildScope=t(this)),r=new this.$$ChildScope),r.$parent=e,r.$$prevSibling=e.$$childTail,e.$$childHead?(e.$$childTail.$$nextSibling=r,e.$$childTail=r):e.$$childHead=e.$$childTail=r,(n||e!=this)&&r.$on("$destroy",h),r},$watch:function(t,n,e,r){var i=c(t);if(i.$$watchDelegate)return i.$$watchDelegate(this,n,e,i,t);var o=this,u=o.$$watchers,s={fn:n,last:x,get:i,exp:r||t,eq:!!e};return a=null,M(n)||(s.fn=v),u||(u=o.$$watchers=[]),u.unshift(s),m(this,1),function(){I(u,s)>=0&&m(o,-1),a=null}},$watchGroup:function(t,n){function e(){s=!1,l?(l=!1,n(i,i,u)):n(i,r,u)}var r=new Array(t.length),i=new Array(t.length),a=[],u=this,s=!1,l=!0;if(!t.length){var c=!0;return u.$evalAsync(function(){c&&n(i,i,u)}),function(){c=!1}}return 1===t.length?this.$watch(t[0],function(t,e,o){i[0]=t,r[0]=e,n(i,t===e?i:r,o)}):(o(t,function(t,n){var o=u.$watch(t,function(t,o){i[n]=t,r[n]=o,s||(s=!0,u.$evalAsync(e))});a.push(o)}),function(){for(;a.length;)a.shift()()})},$watchCollection:function(t,n){function e(t){o=t;var n,e,r,u,s;if(!$(o)){if(b(o))if(i(o)){a!==p&&(a=p,g=a.length=0,f++),n=o.length,g!==n&&(f++,a.length=g=n);for(var l=0;n>l;l++)s=a[l],u=o[l],r=s!==s&&u!==u,r||s===u||(f++,a[l]=u)}else{a!==d&&(a=d={},g=0,f++),n=0;for(e in o)br.call(o,e)&&(n++,u=o[e],s=a[e],e in a?(r=s!==s&&u!==u,r||s===u||(f++,a[e]=u)):(g++,a[e]=u,f++));if(g>n){f++;for(e in a)br.call(o,e)||(g--,delete a[e])}}else a!==o&&(a=o,f++);return f}}function r(){if(v?(v=!1,n(o,o,s)):n(o,u,s),l)if(b(o))if(i(o)){u=new Array(o.length);for(var t=0;t<o.length;t++)u[t]=o[t]}else{u={};for(var e in o)br.call(o,e)&&(u[e]=o[e])}else u=o}e.$stateful=!0;var o,a,u,s=this,l=n.length>1,f=0,h=c(t,e),p=[],d={},v=!0,g=0;return this.$watch(h,r)},$digest:function(){var t,r,i,o,s,c,h,p,v,m,y=n,$=this,b=[];d("$digest"),f.$$checkUrlChange(),this===S&&null!==u&&(f.defer.cancel(u),w()),a=null;do{for(c=!1,p=$;_.length;){try{m=_.shift(),m.scope.$eval(m.expression,m.locals)}catch(C){l(C)}a=null}t:do{if(o=p.$$watchers)for(s=o.length;s--;)try{if(t=o[s])if((r=t.get(p))===(i=t.last)||(t.eq?V(r,i):"number"==typeof r&&"number"==typeof i&&isNaN(r)&&isNaN(i))){if(t===a){c=!1;break t}}else c=!0,a=t,t.last=t.eq?z(r,null):r,t.fn(r,i===x?r:i,p),5>y&&(v=4-y,b[v]||(b[v]=[]),b[v].push({msg:M(t.exp)?"fn: "+(t.exp.name||t.exp.toString()):t.exp,newVal:r,oldVal:i}))}catch(C){l(C)}if(!(h=p.$$watchersCount&&p.$$childHead||p!==$&&p.$$nextSibling))for(;p!==$&&!(h=p.$$nextSibling);)p=p.$parent}while(p=h);if((c||_.length)&&!y--)throw g(),e("infdig","{0} $digest() iterations reached. Aborting!\nWatchers fired in the last 5 iterations: {1}",n,b)}while(c||_.length);for(g();k.length;)try{k.shift()()}catch(C){l(C)}},$destroy:function(){if(!this.$$destroyed){var t=this.$parent;this.$broadcast("$destroy"),this.$$destroyed=!0,this===S&&f.$$applicationDestroyed(),m(this,-this.$$watchersCount);for(var n in this.$$listenerCount)y(this,this.$$listenerCount[n],n);t&&t.$$childHead==this&&(t.$$childHead=this.$$nextSibling),t&&t.$$childTail==this&&(t.$$childTail=this.$$prevSibling),this.$$prevSibling&&(this.$$prevSibling.$$nextSibling=this.$$nextSibling),this.$$nextSibling&&(this.$$nextSibling.$$prevSibling=this.$$prevSibling),this.$destroy=this.$digest=this.$apply=this.$evalAsync=this.$applyAsync=v,this.$on=this.$watch=this.$watchGroup=function(){return v},this.$$listeners={},this.$parent=this.$$nextSibling=this.$$prevSibling=this.$$childHead=this.$$childTail=this.$root=this.$$watchers=null}},$eval:function(t,n){return c(t)(this,n)},$evalAsync:function(t,n){S.$$phase||_.length||f.defer(function(){_.length&&S.$digest()}),_.push({scope:this,expression:t,locals:n})},$$postDigest:function(t){k.push(t)},$apply:function(t){try{d("$apply");try{return this.$eval(t)}finally{g()}}catch(n){l(n)}finally{try{S.$digest()}catch(n){throw l(n),n}}},$applyAsync:function(t){function n(){e.$eval(t)}var e=this;t&&A.push(n),C()},$on:function(t,n){var e=this.$$listeners[t];e||(this.$$listeners[t]=e=[]),e.push(n);var r=this;do r.$$listenerCount[t]||(r.$$listenerCount[t]=0),r.$$listenerCount[t]++;while(r=r.$parent);var i=this;return function(){var r=e.indexOf(n);-1!==r&&(e[r]=null,y(i,1,t))}},$emit:function(t,n){var e,r,i,o=[],a=this,u=!1,s={name:t,targetScope:a,stopPropagation:function(){u=!0},preventDefault:function(){s.defaultPrevented=!0},defaultPrevented:!1},c=B([s],arguments,1);do{for(e=a.$$listeners[t]||o,s.currentScope=a,r=0,i=e.length;i>r;r++)if(e[r])try{e[r].apply(null,c)}catch(f){l(f)}else e.splice(r,1),r--,i--;if(u)return s.currentScope=null,s;a=a.$parent}while(a);return s.currentScope=null,s},$broadcast:function(t,n){var e=this,r=e,i=e,o={name:t,targetScope:e,preventDefault:function(){o.defaultPrevented=!0},defaultPrevented:!1};if(!e.$$listenerCount[t])return o;for(var a,u,s,c=B([o],arguments,1);r=i;){for(o.currentScope=r,a=r.$$listeners[t]||[],u=0,s=a.length;s>u;u++)if(a[u])try{a[u].apply(null,c)}catch(f){l(f)}else a.splice(u,1),u--,s--;if(!(i=r.$$listenerCount[t]&&r.$$childHead||r!==e&&r.$$nextSibling))for(;r!==e&&!(i=r.$$nextSibling);)r=r.$parent}return o.currentScope=null,o}};var S=new p,_=S.$$asyncQueue=[],k=S.$$postDigestQueue=[],A=S.$$applyAsyncQueue=[];return S}]}function me(){var t=/^\s*(https?|ftp|mailto|tel|file):/,n=/^\s*((https?|ftp|file|blob):|data:image\/)/;this.aHrefSanitizationWhitelist=function(n){return x(n)?(t=n,this):t},this.imgSrcSanitizationWhitelist=function(t){return x(t)?(n=t,this):n},this.$get=function(){return function(e,r){var i,o=r?n:t;return i=Me(e).href,""===i||i.match(o)?e:"unsafe:"+i}}}function ye(t){if("self"===t)return t;if(C(t)){if(t.indexOf("***")>-1)throw ro("iwcard","Illegal sequence *** in string matcher.  String: {0}",t);return t=qr(t).replace("\\*\\*",".*").replace("\\*","[^:/.?&;]*"),new RegExp("^"+t+"$")}if(k(t))return new RegExp("^"+t.source+"$");throw ro("imatcher",'Matchers may only be "self", string patterns or RegExp objects')}function $e(t){var n=[];return x(t)&&o(t,function(t){n.push(ye(t))}),n}function xe(){this.SCE_CONTEXTS=io;var t=["self"],n=[];this.resourceUrlWhitelist=function(n){return arguments.length&&(t=$e(n)),t},this.resourceUrlBlacklist=function(t){return arguments.length&&(n=$e(t)),n},this.$get=["$injector",function(e){function r(t,n){return"self"===t?ke(n):!!t.exec(n.href)}function i(e){var i,o,a=Me(e.toString()),u=!1;for(i=0,o=t.length;o>i;i++)if(r(t[i],a)){u=!0;break}if(u)for(i=0,o=n.length;o>i;i++)if(r(n[i],a)){u=!1;break}return u}function o(t){var n=function(t){this.$$unwrapTrustedValue=function(){return t}};return t&&(n.prototype=new t),n.prototype.valueOf=function(){return this.$$unwrapTrustedValue()},n.prototype.toString=function(){return this.$$unwrapTrustedValue().toString()},n}function a(t,n){var e=f.hasOwnProperty(t)?f[t]:null;if(!e)throw ro("icontext","Attempted to trust a value in invalid context. Context: {0}; Value: {1}",t,n);if(null===n||$(n)||""===n)return n;if("string"!=typeof n)throw ro("itype","Attempted to trust a non-string value in a content requiring a string: Context: {0}",t);return new e(n)}function u(t){return t instanceof c?t.$$unwrapTrustedValue():t}function s(t,n){if(null===n||$(n)||""===n)return n;var e=f.hasOwnProperty(t)?f[t]:null;if(e&&n instanceof e)return n.$$unwrapTrustedValue();if(t===io.RESOURCE_URL){if(i(n))return n;throw ro("insecurl","Blocked loading resource from url not allowed by $sceDelegate policy.  URL: {0}",n.toString())}if(t===io.HTML)return l(n);throw ro("unsafe","Attempting to use an unsafe value in a safe context.")}var l=function(t){throw ro("unsafe","Attempting to use an unsafe value in a safe context.")};e.has("$sanitize")&&(l=e.get("$sanitize"));var c=o(),f={};return f[io.HTML]=o(c),f[io.CSS]=o(c),f[io.URL]=o(c),f[io.JS]=o(c),f[io.RESOURCE_URL]=o(f[io.URL]),{trustAs:a,getTrusted:s,valueOf:u}}]}function be(){var t=!0;this.enabled=function(n){return arguments.length&&(t=!!n),t},this.$get=["$parse","$sceDelegate",function(n,e){if(t&&8>_r)throw ro("iequirks","Strict Contextual Escaping does not support Internet Explorer version < 11 in quirks mode.  You can fix this by adding the text <!doctype html> to the top of your HTML document.  See http://docs.angularjs.org/api/ng.$sce for more information.");var r=q(io);r.isEnabled=function(){return t},r.trustAs=e.trustAs,r.getTrusted=e.getTrusted,r.valueOf=e.valueOf,t||(r.trustAs=r.getTrusted=function(t,n){return n},r.valueOf=g),r.parseAs=function(t,e){var i=n(e);return i.literal&&i.constant?i:n(e,function(n){return r.getTrusted(t,n)})};var i=r.parseAs,a=r.getTrusted,u=r.trustAs;return o(io,function(t,n){var e=xr(n);r[wt("parse_as_"+e)]=function(n){return i(t,n)},r[wt("get_trusted_"+e)]=function(n){return a(t,n)},r[wt("trust_as_"+e)]=function(n){return u(t,n)}}),r}]}function we(){this.$get=["$window","$document",function(t,n){var e,r,i={},o=p((/android (\d+)/.exec(xr((t.navigator||{}).userAgent))||[])[1]),a=/Boxee/i.test((t.navigator||{}).userAgent),u=n[0]||{},s=/^(Moz|webkit|ms)(?=[A-Z])/,l=u.body&&u.body.style,c=!1,f=!1;if(l){for(var h in l)if(r=s.exec(h)){e=r[0],e=e.substr(0,1).toUpperCase()+e.substr(1);break}e||(e="WebkitOpacity"in l&&"webkit"),c=!!("transition"in l||e+"Transition"in l),f=!!("animation"in l||e+"Animation"in l),!o||c&&f||(c=C(l.webkitTransition),f=C(l.webkitAnimation))}return{history:!(!t.history||!t.history.pushState||4>o||a),hasEvent:function(t){if("input"===t&&11>=_r)return!1;if($(i[t])){var n=u.createElement("div");i[t]="on"+t in n}return i[t]},csp:Vr(),vendorPrefix:e,transitions:c,animations:f,android:o}}]}function Ce(){this.$get=["$templateCache","$http","$q","$sce",function(t,n,e,r){function i(o,a){function u(t){if(!a)throw Pi("tpload","Failed to load template: {0} (HTTP status: {1} {2})",o,t.status,t.statusText);return e.reject(t)}i.totalPendingRequests++,C(o)&&t.get(o)||(o=r.getTrustedResourceUrl(o));var s=n.defaults&&n.defaults.transformResponse;Fr(s)?s=s.filter(function(t){return t!==xn}):s===xn&&(s=null);var l={cache:t,transformResponse:s};return n.get(o,l)["finally"](function(){i.totalPendingRequests--}).then(function(n){return t.put(o,n.data),n.data},u)}return i.totalPendingRequests=0,i}]}function Se(){this.$get=["$rootScope","$browser","$location",function(t,n,e){var r={};return r.findBindings=function(t,n,e){var r=t.getElementsByClassName("ng-binding"),i=[];return o(r,function(t){var r=Nr.element(t).data("$binding");r&&o(r,function(r){if(e){var o=new RegExp("(^|\\s)"+qr(n)+"(\\s|\\||$)");o.test(r)&&i.push(t)}else-1!=r.indexOf(n)&&i.push(t)})}),i},r.findModels=function(t,n,e){for(var r=["ng-","data-ng-","ng\\:"],i=0;i<r.length;++i){var o=e?"=":"*=",a="["+r[i]+"model"+o+'"'+n+'"]',u=t.querySelectorAll(a);if(u.length)return u}},r.getLocation=function(){return e.url()},r.setLocation=function(n){n!==e.url()&&(e.url(n),t.$digest())},r.whenStable=function(t){n.notifyWhenNoOutstandingRequests(t)},r}]}function _e(){this.$get=["$rootScope","$browser","$q","$$q","$exceptionHandler",function(t,n,e,r,i){function o(o,u,s){M(o)||(s=u,u=o,o=v);var l,c=W(arguments,3),f=x(s)&&!s,h=(f?r:e).defer(),p=h.promise;return l=n.defer(function(){try{h.resolve(o.apply(null,c))}catch(n){h.reject(n),i(n)}finally{delete a[p.$$timeoutId]}f||t.$apply()},u),p.$$timeoutId=l,a[l]=h,p}var a={};return o.cancel=function(t){return t&&t.$$timeoutId in a?(a[t.$$timeoutId].reject("canceled"),delete a[t.$$timeoutId],n.defer.cancel(t.$$timeoutId)):!1},o}]}function Me(t){var n=t;return _r&&(oo.setAttribute("href",n),n=oo.href),oo.setAttribute("href",n),{href:oo.href,protocol:oo.protocol?oo.protocol.replace(/:$/,""):"",host:oo.host,search:oo.search?oo.search.replace(/^\?/,""):"",hash:oo.hash?oo.hash.replace(/^#/,""):"",hostname:oo.hostname,port:oo.port,pathname:"/"===oo.pathname.charAt(0)?oo.pathname:"/"+oo.pathname}}function ke(t){var n=C(t)?Me(t):t;return n.protocol===ao.protocol&&n.host===ao.host}function Ae(){this.$get=m(t)}function Ee(t){function n(t){try{return decodeURIComponent(t)}catch(n){return t}}var e=t[0]||{},r={},i="";return function(){var t,o,a,u,s,l=e.cookie||"";if(l!==i)for(i=l,t=i.split("; "),r={},a=0;a<t.length;a++)o=t[a],u=o.indexOf("="),u>0&&(s=n(o.substring(0,u)),$(r[s])&&(r[s]=n(o.substring(u+1))));return r}}function Pe(){this.$get=Ee}function Oe(t){function n(r,i){if(b(r)){var a={};return o(r,function(t,e){a[e]=n(e,t)}),a}return t.factory(r+e,i)}var e="Filter";this.register=n,this.$get=["$injector",function(t){return function(n){return t.get(n+e)}}],n("currency",Re),n("date",Xe),n("filter",Te),n("json",Ze),n("limitTo",Je),n("lowercase",fo),n("number",De),n("orderBy",Ke),n("uppercase",ho)}function Te(){return function(t,n,e){if(!i(t)){if(null==t)return t;throw r("filter")("notarray","Expected array but received: {0}",t)}var o,a,u=Ne(n);switch(u){case"function":o=n;break;case"boolean":case"null":case"number":case"string":a=!0;case"object":o=Le(n,e,a);break;default:return t}return Array.prototype.filter.call(t,o)}}function Le(t,n,e){var r,i=b(t)&&"$"in t;return n===!0?n=V:M(n)||(n=function(t,n){return $(t)?!1:null===t||null===n?t===n:b(n)||b(t)&&!y(t)?!1:(t=xr(""+t),n=xr(""+n),-1!==t.indexOf(n))}),r=function(r){return i&&!b(r)?je(r,t.$,n,!1):je(r,t,n,e)}}function je(t,n,e,r,i){var o=Ne(t),a=Ne(n);if("string"===a&&"!"===n.charAt(0))return!je(t,n.substring(1),e,r);if(Fr(t))return t.some(function(t){return je(t,n,e,r)});switch(o){case"object":var u;if(r){for(u in t)if("$"!==u.charAt(0)&&je(t[u],n,e,!0))return!0;return i?!1:je(t,n,e,!1)}if("object"===a){for(u in n){var s=n[u];if(!M(s)&&!$(s)){var l="$"===u,c=l?t:t[u];if(!je(c,s,e,l,l))return!1}}return!0}return e(t,n);case"function":return!1;default:return e(t,n)}}function Ne(t){return null===t?"null":typeof t}function Re(t){var n=t.NUMBER_FORMATS;return function(t,e,r){return $(e)&&(e=n.CURRENCY_SYM),$(r)&&(r=n.PATTERNS[1].maxFrac),null==t?t:Fe(t,n.PATTERNS[1],n.GROUP_SEP,n.DECIMAL_SEP,r).replace(/\u00A4/g,e)}}function De(t){var n=t.NUMBER_FORMATS;return function(t,e){return null==t?t:Fe(t,n.PATTERNS[0],n.GROUP_SEP,n.DECIMAL_SEP,e)}}function Fe(t,n,e,r,i){if(b(t))return"";var o=0>t;t=Math.abs(t);var a=t===1/0;if(!a&&!isFinite(t))return"";var u=t+"",s="",l=!1,c=[];if(a&&(s="∞"),!a&&-1!==u.indexOf("e")){var f=u.match(/([\d\.]+)e(-?)(\d+)/);f&&"-"==f[2]&&f[3]>i+1?t=0:(s=u,l=!0)}if(a||l)i>0&&1>t&&(s=t.toFixed(i),t=parseFloat(s),s=s.replace(uo,r));else{var h=(u.split(uo)[1]||"").length;$(i)&&(i=Math.min(Math.max(n.minFrac,h),n.maxFrac)),t=+(Math.round(+(t.toString()+"e"+i)).toString()+"e"+-i);var p=(""+t).split(uo),d=p[0];p=p[1]||"";var v,g=0,m=n.lgSize,y=n.gSize;if(d.length>=m+y)for(g=d.length-m,v=0;g>v;v++)(g-v)%y===0&&0!==v&&(s+=e),s+=d.charAt(v);for(v=g;v<d.length;v++)(d.length-v)%m===0&&0!==v&&(s+=e),s+=d.charAt(v);for(;p.length<i;)p+="0";i&&"0"!==i&&(s+=r+p.substr(0,i))}return 0===t&&(o=!1),c.push(o?n.negPre:n.posPre,s,o?n.negSuf:n.posSuf),c.join("")}function Ie(t,n,e){var r="";for(0>t&&(r="-",t=-t),t=""+t;t.length<n;)t="0"+t;return e&&(t=t.substr(t.length-n)),r+t}function ze(t,n,e,r){return e=e||0,function(i){var o=i["get"+t]();return(e>0||o>-e)&&(o+=e),0===o&&-12==e&&(o=12),Ie(o,n,r)}}function qe(t,n){return function(e,r){var i=e["get"+t](),o=wr(n?"SHORT"+t:t);return r[o][i]}}function Ve(t,n,e){var r=-1*e,i=r>=0?"+":"";return i+=Ie(Math[r>0?"floor":"ceil"](r/60),2)+Ie(Math.abs(r%60),2)}function Be(t){var n=new Date(t,0,1).getDay();return new Date(t,0,(4>=n?5:12)-n)}function We(t){return new Date(t.getFullYear(),t.getMonth(),t.getDate()+(4-t.getDay()))}function Ue(t){return function(n){var e=Be(n.getFullYear()),r=We(n),i=+r-+e,o=1+Math.round(i/6048e5);return Ie(o,t)}}function He(t,n){return t.getHours()<12?n.AMPMS[0]:n.AMPMS[1]}function Ye(t,n){return t.getFullYear()<=0?n.ERAS[0]:n.ERAS[1]}function Ge(t,n){return t.getFullYear()<=0?n.ERANAMES[0]:n.ERANAMES[1]}function Xe(t){function n(t){var n;if(n=t.match(e)){var r=new Date(0),i=0,o=0,a=n[8]?r.setUTCFullYear:r.setFullYear,u=n[8]?r.setUTCHours:r.setHours;n[9]&&(i=p(n[9]+n[10]),o=p(n[9]+n[11])),a.call(r,p(n[1]),p(n[2])-1,p(n[3]));var s=p(n[4]||0)-i,l=p(n[5]||0)-o,c=p(n[6]||0),f=Math.round(1e3*parseFloat("0."+(n[7]||0)));return u.call(r,s,l,c,f),r}return t}var e=/^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;return function(e,r,i){var a,u,s="",l=[];if(r=r||"mediumDate",r=t.DATETIME_FORMATS[r]||r,C(e)&&(e=co.test(e)?p(e):n(e)),S(e)&&(e=new Date(e)),!_(e)||!isFinite(e.getTime()))return e;for(;r;)u=lo.exec(r),u?(l=B(l,u,1),r=l.pop()):(l.push(r),r=null);var c=e.getTimezoneOffset();return i&&(c=X(i,e.getTimezoneOffset()),e=J(e,i,!0)),o(l,function(n){a=so[n],s+=a?a(e,t.DATETIME_FORMATS,c):n.replace(/(^'|'$)/g,"").replace(/''/g,"'")}),s}}function Ze(){return function(t,n){return $(n)&&(n=2),Y(t,n)}}function Je(){return function(t,n,e){return n=Math.abs(Number(n))===1/0?Number(n):p(n),isNaN(n)?t:(S(t)&&(t=t.toString()),Fr(t)||C(t)?(e=!e||isNaN(e)?0:p(e),e=0>e&&e>=-t.length?t.length+e:e,n>=0?t.slice(e,e+n):0===e?t.slice(n,t.length):t.slice(Math.max(0,e+n),e)):t)}}function Ke(t){function n(n,e){return e=e?-1:1,n.map(function(n){var r=1,i=g;if(M(n))i=n;else if(C(n)&&("+"!=n.charAt(0)&&"-"!=n.charAt(0)||(r="-"==n.charAt(0)?-1:1,n=n.substring(1)),""!==n&&(i=t(n),i.constant))){var o=i();i=function(t){return t[o]}}return{get:i,descending:r*e}})}function e(t){switch(typeof t){case"number":case"boolean":case"string":return!0;default:return!1}}function r(t,n){return"function"==typeof t.valueOf&&(t=t.valueOf(),e(t))?t:y(t)&&(t=t.toString(),e(t))?t:n}function o(t,n){var e=typeof t;return null===t?(e="string",t="null"):"string"===e?t=t.toLowerCase():"object"===e&&(t=r(t,n)),{value:t,type:e}}function a(t,n){var e=0;return t.type===n.type?t.value!==n.value&&(e=t.value<n.value?-1:1):e=t.type<n.type?-1:1,e}return function(t,e,r){function u(t,n){return{value:t,predicateValues:l.map(function(e){return o(e.get(t),n)})}}function s(t,n){for(var e=0,r=0,i=l.length;i>r&&!(e=a(t.predicateValues[r],n.predicateValues[r])*l[r].descending);++r);return e}if(!i(t))return t;Fr(e)||(e=[e]),0===e.length&&(e=["+"]);var l=n(e,r);l.push({get:function(){return{}},descending:r?-1:1});var c=Array.prototype.map.call(t,u);return c.sort(s),t=c.map(function(t){return t.value})}}function Qe(t){return M(t)&&(t={link:t}),t.restrict=t.restrict||"AC",m(t)}function tr(t,n){t.$name=n}function nr(t,n,r,i,a){var u=this,s=[];u.$error={},u.$$success={},u.$pending=e,u.$name=a(n.name||n.ngForm||"")(r),u.$dirty=!1,u.$pristine=!0,u.$valid=!0,u.$invalid=!1,u.$submitted=!1,u.$$parentForm=go,u.$rollbackViewValue=function(){o(s,function(t){t.$rollbackViewValue()})},u.$commitViewValue=function(){o(s,function(t){t.$commitViewValue()})},u.$addControl=function(t){pt(t.$name,"input"),s.push(t),t.$name&&(u[t.$name]=t),t.$$parentForm=u},u.$$renameControl=function(t,n){var e=t.$name;u[e]===t&&delete u[e],u[n]=t,t.$name=n},u.$removeControl=function(t){t.$name&&u[t.$name]===t&&delete u[t.$name],o(u.$pending,function(n,e){u.$setValidity(e,null,t)}),o(u.$error,function(n,e){u.$setValidity(e,null,t)}),o(u.$$success,function(n,e){u.$setValidity(e,null,t)}),I(s,t),t.$$parentForm=go},gr({ctrl:this,$element:t,set:function(t,n,e){var r=t[n];if(r){var i=r.indexOf(e);-1===i&&r.push(e)}else t[n]=[e]},unset:function(t,n,e){var r=t[n];r&&(I(r,e),0===r.length&&delete t[n])},$animate:i}),u.$setDirty=function(){i.removeClass(t,Ko),i.addClass(t,Qo),u.$dirty=!0,u.$pristine=!1,u.$$parentForm.$setDirty()},u.$setPristine=function(){i.setClass(t,Ko,Qo+" "+mo),u.$dirty=!1,u.$pristine=!0,u.$submitted=!1,o(s,function(t){t.$setPristine()})},u.$setUntouched=function(){o(s,function(t){t.$setUntouched()})},u.$setSubmitted=function(){i.addClass(t,mo),u.$submitted=!0,u.$$parentForm.$setSubmitted()}}function er(t){t.$formatters.push(function(n){return t.$isEmpty(n)?n:n.toString()})}function rr(t,n,e,r,i,o){ir(t,n,e,r,i,o),er(r)}function ir(t,n,e,r,i,o){var a=xr(n[0].type);if(!i.android){var u=!1;n.on("compositionstart",function(t){u=!0}),n.on("compositionend",function(){u=!1,s()})}var s=function(t){if(l&&(o.defer.cancel(l),l=null),!u){var i=n.val(),s=t&&t.type;"password"===a||e.ngTrim&&"false"===e.ngTrim||(i=zr(i)),(r.$viewValue!==i||""===i&&r.$$hasNativeValidators)&&r.$setViewValue(i,s)}};if(i.hasEvent("input"))n.on("input",s);else{var l,c=function(t,n,e){l||(l=o.defer(function(){l=null,n&&n.value===e||s(t)}))};n.on("keydown",function(t){var n=t.keyCode;91===n||n>15&&19>n||n>=37&&40>=n||c(t,this,this.value)}),i.hasEvent("paste")&&n.on("paste cut",c)}n.on("change",s),r.$render=function(){var t=r.$isEmpty(r.$viewValue)?"":r.$viewValue;n.val()!==t&&n.val(t)}}function or(t,n){if(_(t))return t;if(C(t)){ko.lastIndex=0;var e=ko.exec(t);if(e){var r=+e[1],i=+e[2],o=0,a=0,u=0,s=0,l=Be(r),c=7*(i-1);return n&&(o=n.getHours(),a=n.getMinutes(),u=n.getSeconds(),s=n.getMilliseconds()),new Date(r,0,l.getDate()+c,o,a,u,s)}}return NaN}function ar(t,n){return function(e,r){var i,a;if(_(e))return e;if(C(e)){if('"'==e.charAt(0)&&'"'==e.charAt(e.length-1)&&(e=e.substring(1,e.length-1)),bo.test(e))return new Date(e);if(t.lastIndex=0,i=t.exec(e))return i.shift(),a=r?{yyyy:r.getFullYear(),MM:r.getMonth()+1,dd:r.getDate(),HH:r.getHours(),mm:r.getMinutes(),ss:r.getSeconds(),sss:r.getMilliseconds()/1e3}:{yyyy:1970,MM:1,dd:1,HH:0,mm:0,ss:0,sss:0},o(i,function(t,e){e<n.length&&(a[n[e]]=+t)}),new Date(a.yyyy,a.MM-1,a.dd,a.HH,a.mm,a.ss||0,1e3*a.sss||0)}return NaN}}function ur(t,n,r,i){return function(o,a,u,s,l,c,f){function h(t){return t&&!(t.getTime&&t.getTime()!==t.getTime())}function p(t){return x(t)&&!_(t)?r(t)||e:t}sr(o,a,u,s),ir(o,a,u,s,l,c);var d,v=s&&s.$options&&s.$options.timezone;if(s.$$parserName=t,s.$parsers.push(function(t){if(s.$isEmpty(t))return null;if(n.test(t)){var i=r(t,d);return v&&(i=J(i,v)),i}return e}),s.$formatters.push(function(t){if(t&&!_(t))throw ra("datefmt","Expected `{0}` to be a date",t);return h(t)?(d=t,d&&v&&(d=J(d,v,!0)),f("date")(t,i,v)):(d=null,"")}),x(u.min)||u.ngMin){var g;s.$validators.min=function(t){return!h(t)||$(g)||r(t)>=g},u.$observe("min",function(t){g=p(t),s.$validate()})}if(x(u.max)||u.ngMax){var m;s.$validators.max=function(t){return!h(t)||$(m)||r(t)<=m},u.$observe("max",function(t){m=p(t),s.$validate()})}}}function sr(t,n,r,i){var o=n[0],a=i.$$hasNativeValidators=b(o.validity);a&&i.$parsers.push(function(t){var r=n.prop($r)||{};return r.badInput&&!r.typeMismatch?e:t})}function lr(t,n,r,i,o,a){if(sr(t,n,r,i),ir(t,n,r,i,o,a),i.$$parserName="number",i.$parsers.push(function(t){return i.$isEmpty(t)?null:So.test(t)?parseFloat(t):e}),i.$formatters.push(function(t){if(!i.$isEmpty(t)){if(!S(t))throw ra("numfmt","Expected `{0}` to be a number",t);t=t.toString()}return t}),x(r.min)||r.ngMin){var u;i.$validators.min=function(t){return i.$isEmpty(t)||$(u)||t>=u},r.$observe("min",function(t){x(t)&&!S(t)&&(t=parseFloat(t,10)),u=S(t)&&!isNaN(t)?t:e,i.$validate()})}if(x(r.max)||r.ngMax){var s;i.$validators.max=function(t){return i.$isEmpty(t)||$(s)||s>=t},r.$observe("max",function(t){x(t)&&!S(t)&&(t=parseFloat(t,10)),s=S(t)&&!isNaN(t)?t:e,i.$validate()})}}function cr(t,n,e,r,i,o){ir(t,n,e,r,i,o),er(r),r.$$parserName="url",r.$validators.url=function(t,n){var e=t||n;return r.$isEmpty(e)||wo.test(e)}}function fr(t,n,e,r,i,o){ir(t,n,e,r,i,o),er(r),r.$$parserName="email",r.$validators.email=function(t,n){var e=t||n;return r.$isEmpty(e)||Co.test(e)}}function hr(t,n,e,r){$(e.name)&&n.attr("name",s());var i=function(t){n[0].checked&&r.$setViewValue(e.value,t&&t.type)};n.on("click",i),r.$render=function(){var t=e.value;n[0].checked=t==r.$viewValue},e.$observe("value",r.$render)}function pr(t,n,e,r,i){var o;if(x(r)){if(o=t(r),!o.constant)throw ra("constexpr","Expected constant expression for `{0}`, but saw `{1}`.",e,r);return o(n)}return i}function dr(t,n,e,r,i,o,a,u){var s=pr(u,t,"ngTrueValue",e.ngTrueValue,!0),l=pr(u,t,"ngFalseValue",e.ngFalseValue,!1),c=function(t){r.$setViewValue(n[0].checked,t&&t.type)};n.on("click",c),r.$render=function(){n[0].checked=r.$viewValue},r.$isEmpty=function(t){return t===!1},r.$formatters.push(function(t){return V(t,s)}),r.$parsers.push(function(t){return t?s:l})}function vr(t,n){return t="ngClass"+t,["$animate",function(e){function r(t,n){var e=[];t:for(var r=0;r<t.length;r++){for(var i=t[r],o=0;o<n.length;o++)if(i==n[o])continue t;e.push(i)}return e}function i(t){var n=[];return Fr(t)?(o(t,function(t){n=n.concat(i(t))}),n):C(t)?t.split(" "):b(t)?(o(t,function(t,e){t&&(n=n.concat(e.split(" ")))}),n):t}return{restrict:"AC",link:function(a,u,s){function l(t){var n=f(t,1);s.$addClass(n)}function c(t){var n=f(t,-1);s.$removeClass(n)}function f(t,n){var e=u.data("$classCounts")||gt(),r=[];return o(t,function(t){(n>0||e[t])&&(e[t]=(e[t]||0)+n,e[t]===+(n>0)&&r.push(t))}),u.data("$classCounts",e),r.join(" ")}function h(t,n){var i=r(n,t),o=r(t,n);i=f(i,1),o=f(o,-1),i&&i.length&&e.addClass(u,i),o&&o.length&&e.removeClass(u,o)}function p(t){if(n===!0||a.$index%2===n){var e=i(t||[]);if(d){if(!V(t,d)){var r=i(d);h(r,e)}}else l(e)}d=q(t)}var d;a.$watch(s[t],p,!0),s.$observe("class",function(n){p(a.$eval(s[t]))}),"ngClass"!==t&&a.$watch("$index",function(e,r){var o=1&e;if(o!==(1&r)){var u=i(a.$eval(s[t]));o===n?l(u):c(u)}})}}}]}function gr(t){function n(t,n,s){$(n)?r("$pending",t,s):i("$pending",t,s),L(n)?n?(f(u.$error,t,s),c(u.$$success,t,s)):(c(u.$error,t,s),f(u.$$success,t,s)):(f(u.$error,t,s),f(u.$$success,t,s)),u.$pending?(o(ea,!0),u.$valid=u.$invalid=e,a("",null)):(o(ea,!1),u.$valid=mr(u.$error),u.$invalid=!u.$valid,a("",u.$valid));var l;l=u.$pending&&u.$pending[t]?e:u.$error[t]?!1:u.$$success[t]?!0:null,a(t,l),u.$$parentForm.$setValidity(t,l,u)}function r(t,n,e){u[t]||(u[t]={}),c(u[t],n,e)}function i(t,n,r){u[t]&&f(u[t],n,r),mr(u[t])&&(u[t]=e)}function o(t,n){n&&!l[t]?(h.addClass(s,t),l[t]=!0):!n&&l[t]&&(h.removeClass(s,t),l[t]=!1)}function a(t,n){t=t?"-"+lt(t,"-"):"",o(Zo+t,n===!0),o(Jo+t,n===!1)}var u=t.ctrl,s=t.$element,l={},c=t.set,f=t.unset,h=t.$animate;l[Jo]=!(l[Zo]=s.hasClass(Zo)),u.$setValidity=n}function mr(t){if(t)for(var n in t)if(t.hasOwnProperty(n))return!1;return!0}var yr=/^\/(.+)\/([a-z]*)$/,$r="validity",xr=function(t){return C(t)?t.toLowerCase():t},br=Object.prototype.hasOwnProperty,wr=function(t){return C(t)?t.toUpperCase():t},Cr=function(t){return C(t)?t.replace(/[A-Z]/g,function(t){return String.fromCharCode(32|t.charCodeAt(0))}):t},Sr=function(t){return C(t)?t.replace(/[a-z]/g,function(t){return String.fromCharCode(-33&t.charCodeAt(0))}):t};"i"!=="I".toLowerCase()&&(xr=Cr,wr=Sr);var _r,Mr,kr,Ar,Er=[].slice,Pr=[].splice,Or=[].push,Tr=Object.prototype.toString,Lr=Object.getPrototypeOf,jr=r("ng"),Nr=t.angular||(t.angular={}),Rr=0;_r=n.documentMode,v.$inject=[],g.$inject=[];var Dr,Fr=Array.isArray,Ir=/^\[object (Uint8(Clamped)?)|(Uint16)|(Uint32)|(Int8)|(Int16)|(Int32)|(Float(32)|(64))Array\]$/,zr=function(t){return C(t)?t.trim():t},qr=function(t){return t.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g,"\\$1").replace(/\x08/g,"\\x08")},Vr=function(){function t(){try{return new Function(""),!1}catch(t){return!0}}if(!x(Vr.rules)){var e=n.querySelector("[ng-csp]")||n.querySelector("[data-ng-csp]");if(e){var r=e.getAttribute("ng-csp")||e.getAttribute("data-ng-csp");Vr.rules={noUnsafeEval:!r||-1!==r.indexOf("no-unsafe-eval"),noInlineStyle:!r||-1!==r.indexOf("no-inline-style")}}else Vr.rules={noUnsafeEval:t(),noInlineStyle:!1}}return Vr.rules},Br=function(){if(x(Br.name_))return Br.name_;var t,e,r,i,o=Wr.length;for(e=0;o>e;++e)if(r=Wr[e],t=n.querySelector("["+r.replace(":","\\:")+"jq]")){i=t.getAttribute(r+"jq");break}return Br.name_=i},Wr=["ng-","data-ng-","ng:","x-ng-"],Ur=/[A-Z]/g,Hr=!1,Yr=1,Gr=2,Xr=3,Zr=8,Jr=9,Kr=11,Qr={full:"1.4.7",major:1,minor:4,dot:7,codeName:"dark-luminescence"};At.expando="ng339";var ti=At.cache={},ni=1,ei=function(t,n,e){t.addEventListener(n,e,!1)},ri=function(t,n,e){t.removeEventListener(n,e,!1)};At._data=function(t){return this.cache[t[this.expando]]||{}};var ii=/([\:\-\_]+(.))/g,oi=/^moz([A-Z])/,ai={mouseleave:"mouseout",mouseenter:"mouseover"},ui=r("jqLite"),si=/^<([\w-]+)\s*\/?>(?:<\/\1>|)$/,li=/<|&#?\w+;/,ci=/<([\w:-]+)/,fi=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi,hi={option:[1,'<select multiple="multiple">',"</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};hi.optgroup=hi.option,hi.tbody=hi.tfoot=hi.colgroup=hi.caption=hi.thead,hi.th=hi.td;var pi=At.prototype={ready:function(e){function r(){i||(i=!0,e())}var i=!1;"complete"===n.readyState?setTimeout(r):(this.on("DOMContentLoaded",r),At(t).on("load",r))},toString:function(){var t=[];return o(this,function(n){t.push(""+n)}),"["+t.join(", ")+"]"},eq:function(t){return Mr(t>=0?this[t]:this[this.length+t])},length:0,push:Or,sort:[].sort,splice:[].splice},di={};o("multiple,selected,checked,disabled,readOnly,required,open".split(","),function(t){di[xr(t)]=t});var vi={};o("input,select,option,textarea,button,form,details".split(","),function(t){vi[t]=!0});var gi={ngMinlength:"minlength",ngMaxlength:"maxlength",ngMin:"min",ngMax:"max",ngPattern:"pattern"};o({data:jt,removeData:Tt,hasData:_t},function(t,n){At[n]=t}),o({data:jt,inheritedData:zt,scope:function(t){return Mr.data(t,"$scope")||zt(t.parentNode||t,["$isolateScope","$scope"])},isolateScope:function(t){return Mr.data(t,"$isolateScope")||Mr.data(t,"$isolateScopeNoTemplate")},controller:It,injector:function(t){return zt(t,"$injector")},removeAttr:function(t,n){t.removeAttribute(n)},hasClass:Nt,css:function(t,n,e){return n=wt(n),x(e)?void(t.style[n]=e):t.style[n]},attr:function(t,n,r){var i=t.nodeType;if(i!==Xr&&i!==Gr&&i!==Zr){var o=xr(n);if(di[o]){if(!x(r))return t[n]||(t.attributes.getNamedItem(n)||v).specified?o:e;r?(t[n]=!0,t.setAttribute(n,o)):(t[n]=!1,t.removeAttribute(o))}else if(x(r))t.setAttribute(n,r);else if(t.getAttribute){var a=t.getAttribute(n,2);return null===a?e:a}}},prop:function(t,n,e){return x(e)?void(t[n]=e):t[n]},text:function(){function t(t,n){
+if($(n)){var e=t.nodeType;return e===Yr||e===Xr?t.textContent:""}t.textContent=n}return t.$dv="",t}(),val:function(t,n){if($(n)){if(t.multiple&&"select"===F(t)){var e=[];return o(t.options,function(t){t.selected&&e.push(t.value||t.text)}),0===e.length?null:e}return t.value}t.value=n},html:function(t,n){return $(n)?t.innerHTML:(Pt(t,!0),void(t.innerHTML=n))},empty:qt},function(t,n){At.prototype[n]=function(n,e){var r,i,o=this.length;if(t!==qt&&$(2==t.length&&t!==Nt&&t!==It?n:e)){if(b(n)){for(r=0;o>r;r++)if(t===jt)t(this[r],n);else for(i in n)t(this[r],i,n[i]);return this}for(var a=t.$dv,u=$(a)?Math.min(o,1):o,s=0;u>s;s++){var l=t(this[s],n,e);a=a?a+l:l}return a}for(r=0;o>r;r++)t(this[r],n,e);return this}}),o({removeData:Tt,on:function La(t,n,e,r){if(x(r))throw ui("onargs","jqLite#on() does not support the `selector` or `eventData` parameters");if(St(t)){var i=Lt(t,!0),o=i.events,a=i.handle;a||(a=i.handle=Ht(t,o));for(var u=n.indexOf(" ")>=0?n.split(" "):[n],s=u.length;s--;){n=u[s];var l=o[n];l||(o[n]=[],"mouseenter"===n||"mouseleave"===n?La(t,ai[n],function(t){var e=this,r=t.relatedTarget;r&&(r===e||e.contains(r))||a(t,n)}):"$destroy"!==n&&ei(t,n,a),l=o[n]),l.push(e)}}},off:Ot,one:function(t,n,e){t=Mr(t),t.on(n,function r(){t.off(n,e),t.off(n,r)}),t.on(n,e)},replaceWith:function(t,n){var e,r=t.parentNode;Pt(t),o(new At(n),function(n){e?r.insertBefore(n,e.nextSibling):r.replaceChild(n,t),e=n})},children:function(t){var n=[];return o(t.childNodes,function(t){t.nodeType===Yr&&n.push(t)}),n},contents:function(t){return t.contentDocument||t.childNodes||[]},append:function(t,n){var e=t.nodeType;if(e===Yr||e===Kr){n=new At(n);for(var r=0,i=n.length;i>r;r++){var o=n[r];t.appendChild(o)}}},prepend:function(t,n){if(t.nodeType===Yr){var e=t.firstChild;o(new At(n),function(n){t.insertBefore(n,e)})}},wrap:function(t,n){n=Mr(n).eq(0).clone()[0];var e=t.parentNode;e&&e.replaceChild(n,t),n.appendChild(t)},remove:Vt,detach:function(t){Vt(t,!0)},after:function(t,n){var e=t,r=t.parentNode;n=new At(n);for(var i=0,o=n.length;o>i;i++){var a=n[i];r.insertBefore(a,e.nextSibling),e=a}},addClass:Dt,removeClass:Rt,toggleClass:function(t,n,e){n&&o(n.split(" "),function(n){var r=e;$(r)&&(r=!Nt(t,n)),(r?Dt:Rt)(t,n)})},parent:function(t){var n=t.parentNode;return n&&n.nodeType!==Kr?n:null},next:function(t){return t.nextElementSibling},find:function(t,n){return t.getElementsByTagName?t.getElementsByTagName(n):[]},clone:Et,triggerHandler:function(t,n,e){var r,i,a,u=n.type||n,s=Lt(t),l=s&&s.events,c=l&&l[u];c&&(r={preventDefault:function(){this.defaultPrevented=!0},isDefaultPrevented:function(){return this.defaultPrevented===!0},stopImmediatePropagation:function(){this.immediatePropagationStopped=!0},isImmediatePropagationStopped:function(){return this.immediatePropagationStopped===!0},stopPropagation:v,type:u,target:t},n.type&&(r=f(r,n)),i=q(c),a=e?[r].concat(e):[r],o(i,function(n){r.isImmediatePropagationStopped()||n.apply(t,a)}))}},function(t,n){At.prototype[n]=function(n,e,r){for(var i,o=0,a=this.length;a>o;o++)$(i)?(i=t(this[o],n,e,r),x(i)&&(i=Mr(i))):Ft(i,t(this[o],n,e,r));return x(i)?i:this},At.prototype.bind=At.prototype.on,At.prototype.unbind=At.prototype.off}),Xt.prototype={put:function(t,n){this[Gt(t,this.nextUid)]=n},get:function(t){return this[Gt(t,this.nextUid)]},remove:function(t){var n=this[t=Gt(t,this.nextUid)];return delete this[t],n}};var mi=[function(){this.$get=[function(){return Xt}]}],yi=/^[^\(]*\(\s*([^\)]*)\)/m,$i=/,/,xi=/^\s*(_?)(\S+?)\1\s*$/,bi=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm,wi=r("$injector");Kt.$$annotate=Jt;var Ci=r("$animate"),Si=1,_i="ng-animate",Mi=function(){this.$get=["$q","$$rAF",function(t,n){function e(){}return e.all=v,e.chain=v,e.prototype={end:v,cancel:v,resume:v,pause:v,complete:v,then:function(e,r){return t(function(t){n(function(){t()})}).then(e,r)}},e}]},ki=function(){var t=new Xt,n=[];this.$get=["$$AnimateRunner","$rootScope",function(e,r){function i(t,n,e){var r=!1;return n&&(n=C(n)?n.split(" "):Fr(n)?n:[],o(n,function(n){n&&(r=!0,t[n]=e)})),r}function a(){o(n,function(n){var e=t.get(n);if(e){var r=en(n.attr("class")),i="",a="";o(e,function(t,n){var e=!!r[n];t!==e&&(t?i+=(i.length?" ":"")+n:a+=(a.length?" ":"")+n)}),o(n,function(t){i&&Dt(t,i),a&&Rt(t,a)}),t.remove(n)}}),n.length=0}function u(e,o,u){var s=t.get(e)||{},l=i(s,o,!0),c=i(s,u,!1);(l||c)&&(t.put(e,s),n.push(e),1===n.length&&r.$$postDigest(a))}return{enabled:v,on:v,off:v,pin:v,push:function(t,n,r,i){return i&&i(),r=r||{},r.from&&t.css(r.from),r.to&&t.css(r.to),(r.addClass||r.removeClass)&&u(t,r.addClass,r.removeClass),new e}}}]},Ai=["$provide",function(t){var n=this;this.$$registeredAnimations=Object.create(null),this.register=function(e,r){if(e&&"."!==e.charAt(0))throw Ci("notcsel","Expecting class selector starting with '.' got '{0}'.",e);var i=e+"-animation";n.$$registeredAnimations[e.substr(1)]=i,t.factory(i,r)},this.classNameFilter=function(t){if(1===arguments.length&&(this.$$classNameFilter=t instanceof RegExp?t:null,this.$$classNameFilter)){var n=new RegExp("(\\s+|\\/)"+_i+"(\\s+|\\/)");if(n.test(this.$$classNameFilter.toString()))throw Ci("nongcls",'$animateProvider.classNameFilter(regex) prohibits accepting a regex value which matches/contains the "{0}" CSS class.',_i)}return this.$$classNameFilter},this.$get=["$$animateQueue",function(t){function n(t,n,e){if(e){var r=nn(e);!r||r.parentNode||r.previousElementSibling||(e=null)}e?e.after(t):n.prepend(t)}return{on:t.on,off:t.off,pin:t.pin,enabled:t.enabled,cancel:function(t){t.end&&t.end()},enter:function(e,r,i,o){return r=r&&Mr(r),i=i&&Mr(i),r=r||i.parent(),n(e,r,i),t.push(e,"enter",rn(o))},move:function(e,r,i,o){return r=r&&Mr(r),i=i&&Mr(i),r=r||i.parent(),n(e,r,i),t.push(e,"move",rn(o))},leave:function(n,e){return t.push(n,"leave",rn(e),function(){n.remove()})},addClass:function(n,e,r){return r=rn(r),r.addClass=tn(r.addclass,e),t.push(n,"addClass",r)},removeClass:function(n,e,r){return r=rn(r),r.removeClass=tn(r.removeClass,e),t.push(n,"removeClass",r)},setClass:function(n,e,r,i){return i=rn(i),i.addClass=tn(i.addClass,e),i.removeClass=tn(i.removeClass,r),t.push(n,"setClass",i)},animate:function(n,e,r,i,o){return o=rn(o),o.from=o.from?f(o.from,e):e,o.to=o.to?f(o.to,r):r,i=i||"ng-inline-animate",o.tempClasses=tn(o.tempClasses,i),t.push(n,"animate",o)}}}]}],Ei=function(){this.$get=["$$rAF","$q",function(t,n){var e=function(){};return e.prototype={done:function(t){this.defer&&this.defer[t===!0?"reject":"resolve"]()},end:function(){this.done()},cancel:function(){this.done(!0)},getPromise:function(){return this.defer||(this.defer=n.defer()),this.defer.promise},then:function(t,n){return this.getPromise().then(t,n)},"catch":function(t){return this.getPromise()["catch"](t)},"finally":function(t){return this.getPromise()["finally"](t)}},function(n,r){function i(){return t(function(){o(),a||u.done(),a=!0}),u}function o(){r.addClass&&(n.addClass(r.addClass),r.addClass=null),r.removeClass&&(n.removeClass(r.removeClass),r.removeClass=null),r.to&&(n.css(r.to),r.to=null)}r.cleanupStyles&&(r.from=r.to=null),r.from&&(n.css(r.from),r.from=null);var a,u=new e;return{start:i,end:i}}}]},Pi=r("$compile");ln.$inject=["$provide","$$sanitizeUriProvider"];var Oi=/^((?:x|data)[\:\-_])/i,Ti=r("$controller"),Li=/^(\S+)(\s+as\s+(\w+))?$/,ji=function(){this.$get=["$document",function(t){return function(n){return n?!n.nodeType&&n instanceof Mr&&(n=n[0]):n=t[0].body,n.offsetWidth+1}}]},Ni="application/json",Ri={"Content-Type":Ni+";charset=utf-8"},Di=/^\[|^\{(?!\{)/,Fi={"[":/]$/,"{":/}$/},Ii=/^\)\]\}',?\n/,zi=r("$http"),qi=function(t){return function(){throw zi("legacy","The method `{0}` on the promise returned from `$http` has been disabled.",t)}},Vi=Nr.$interpolateMinErr=r("$interpolate");Vi.throwNoconcat=function(t){throw Vi("noconcat","Error while interpolating: {0}\nStrict Contextual Escaping disallows interpolations that concatenate multiple expressions when a trusted value is required.  See http://docs.angularjs.org/api/ng.$sce",t)},Vi.interr=function(t,n){return Vi("interr","Can't interpolate: {0}\n{1}",t,n.toString())};var Bi=/^([^\?#]*)(\?([^#]*))?(#(.*))?$/,Wi={http:80,https:443,ftp:21},Ui=r("$location"),Hi={$$html5:!1,$$replace:!1,absUrl:Bn("$$absUrl"),url:function(t){if($(t))return this.$$url;var n=Bi.exec(t);return(n[1]||""===t)&&this.path(decodeURIComponent(n[1])),(n[2]||n[1]||""===t)&&this.search(n[3]||""),this.hash(n[5]||""),this},protocol:Bn("$$protocol"),host:Bn("$$host"),port:Bn("$$port"),path:Wn("$$path",function(t){return t=null!==t?t.toString():"","/"==t.charAt(0)?t:"/"+t}),search:function(t,n){switch(arguments.length){case 0:return this.$$search;case 1:if(C(t)||S(t))t=t.toString(),this.$$search=tt(t);else{if(!b(t))throw Ui("isrcharg","The first argument of the `$location#search()` call must be a string or an object.");t=z(t,{}),o(t,function(n,e){null==n&&delete t[e]}),this.$$search=t}break;default:$(n)||null===n?delete this.$$search[t]:this.$$search[t]=n}return this.$$compose(),this},hash:Wn("$$hash",function(t){return null!==t?t.toString():""}),replace:function(){return this.$$replace=!0,this}};o([Vn,qn,zn],function(t){t.prototype=Object.create(Hi),t.prototype.state=function(n){if(!arguments.length)return this.$$state;if(t!==zn||!this.$$html5)throw Ui("nostate","History API state support is available only in HTML5 mode and only in browsers supporting HTML5 History API");return this.$$state=$(n)?null:n,this}});var Yi=r("$parse"),Gi=Function.prototype.call,Xi=Function.prototype.apply,Zi=Function.prototype.bind,Ji=gt();o("+ - * / % === !== == != < > <= >= && || ! = |".split(" "),function(t){Ji[t]=!0});var Ki={n:"\n",f:"\f",r:"\r",t:"	",v:"\x0B","'":"'",'"':'"'},Qi=function(t){this.options=t};Qi.prototype={constructor:Qi,lex:function(t){for(this.text=t,this.index=0,this.tokens=[];this.index<this.text.length;){var n=this.text.charAt(this.index);if('"'===n||"'"===n)this.readString(n);else if(this.isNumber(n)||"."===n&&this.isNumber(this.peek()))this.readNumber();else if(this.isIdent(n))this.readIdent();else if(this.is(n,"(){}[].,;:?"))this.tokens.push({index:this.index,text:n}),this.index++;else if(this.isWhitespace(n))this.index++;else{var e=n+this.peek(),r=e+this.peek(2),i=Ji[n],o=Ji[e],a=Ji[r];if(i||o||a){var u=a?r:o?e:n;this.tokens.push({index:this.index,text:u,operator:!0}),this.index+=u.length}else this.throwError("Unexpected next character ",this.index,this.index+1)}}return this.tokens},is:function(t,n){return-1!==n.indexOf(t)},peek:function(t){var n=t||1;return this.index+n<this.text.length?this.text.charAt(this.index+n):!1},isNumber:function(t){return t>="0"&&"9">=t&&"string"==typeof t},isWhitespace:function(t){return" "===t||"\r"===t||"	"===t||"\n"===t||"\x0B"===t||" "===t},isIdent:function(t){return t>="a"&&"z">=t||t>="A"&&"Z">=t||"_"===t||"$"===t},isExpOperator:function(t){return"-"===t||"+"===t||this.isNumber(t)},throwError:function(t,n,e){e=e||this.index;var r=x(n)?"s "+n+"-"+this.index+" ["+this.text.substring(n,e)+"]":" "+e;throw Yi("lexerr","Lexer Error: {0} at column{1} in expression [{2}].",t,r,this.text)},readNumber:function(){for(var t="",n=this.index;this.index<this.text.length;){var e=xr(this.text.charAt(this.index));if("."==e||this.isNumber(e))t+=e;else{var r=this.peek();if("e"==e&&this.isExpOperator(r))t+=e;else if(this.isExpOperator(e)&&r&&this.isNumber(r)&&"e"==t.charAt(t.length-1))t+=e;else{if(!this.isExpOperator(e)||r&&this.isNumber(r)||"e"!=t.charAt(t.length-1))break;this.throwError("Invalid exponent")}}this.index++}this.tokens.push({index:n,text:t,constant:!0,value:Number(t)})},readIdent:function(){for(var t=this.index;this.index<this.text.length;){var n=this.text.charAt(this.index);if(!this.isIdent(n)&&!this.isNumber(n))break;this.index++}this.tokens.push({index:t,text:this.text.slice(t,this.index),identifier:!0})},readString:function(t){var n=this.index;this.index++;for(var e="",r=t,i=!1;this.index<this.text.length;){var o=this.text.charAt(this.index);if(r+=o,i){if("u"===o){var a=this.text.substring(this.index+1,this.index+5);a.match(/[\da-f]{4}/i)||this.throwError("Invalid unicode escape [\\u"+a+"]"),this.index+=4,e+=String.fromCharCode(parseInt(a,16))}else{var u=Ki[o];e+=u||o}i=!1}else if("\\"===o)i=!0;else{if(o===t)return this.index++,void this.tokens.push({index:n,text:r,constant:!0,value:e});e+=o}this.index++}this.throwError("Unterminated quote",n)}};var to=function(t,n){this.lexer=t,this.options=n};to.Program="Program",to.ExpressionStatement="ExpressionStatement",to.AssignmentExpression="AssignmentExpression",to.ConditionalExpression="ConditionalExpression",to.LogicalExpression="LogicalExpression",to.BinaryExpression="BinaryExpression",to.UnaryExpression="UnaryExpression",to.CallExpression="CallExpression",to.MemberExpression="MemberExpression",to.Identifier="Identifier",to.Literal="Literal",to.ArrayExpression="ArrayExpression",to.Property="Property",to.ObjectExpression="ObjectExpression",to.ThisExpression="ThisExpression",to.NGValueParameter="NGValueParameter",to.prototype={ast:function(t){this.text=t,this.tokens=this.lexer.lex(t);var n=this.program();return 0!==this.tokens.length&&this.throwError("is an unexpected token",this.tokens[0]),n},program:function(){for(var t=[];;)if(this.tokens.length>0&&!this.peek("}",")",";","]")&&t.push(this.expressionStatement()),!this.expect(";"))return{type:to.Program,body:t}},expressionStatement:function(){return{type:to.ExpressionStatement,expression:this.filterChain()}},filterChain:function(){for(var t,n=this.expression();t=this.expect("|");)n=this.filter(n);return n},expression:function(){return this.assignment()},assignment:function(){var t=this.ternary();return this.expect("=")&&(t={type:to.AssignmentExpression,left:t,right:this.assignment(),operator:"="}),t},ternary:function(){var t,n,e=this.logicalOR();return this.expect("?")&&(t=this.expression(),this.consume(":"))?(n=this.expression(),{type:to.ConditionalExpression,test:e,alternate:t,consequent:n}):e},logicalOR:function(){for(var t=this.logicalAND();this.expect("||");)t={type:to.LogicalExpression,operator:"||",left:t,right:this.logicalAND()};return t},logicalAND:function(){for(var t=this.equality();this.expect("&&");)t={type:to.LogicalExpression,operator:"&&",left:t,right:this.equality()};return t},equality:function(){for(var t,n=this.relational();t=this.expect("==","!=","===","!==");)n={type:to.BinaryExpression,operator:t.text,left:n,right:this.relational()};return n},relational:function(){for(var t,n=this.additive();t=this.expect("<",">","<=",">=");)n={type:to.BinaryExpression,operator:t.text,left:n,right:this.additive()};return n},additive:function(){for(var t,n=this.multiplicative();t=this.expect("+","-");)n={type:to.BinaryExpression,operator:t.text,left:n,right:this.multiplicative()};return n},multiplicative:function(){for(var t,n=this.unary();t=this.expect("*","/","%");)n={type:to.BinaryExpression,operator:t.text,left:n,right:this.unary()};return n},unary:function(){var t;return(t=this.expect("+","-","!"))?{type:to.UnaryExpression,operator:t.text,prefix:!0,argument:this.unary()}:this.primary()},primary:function(){var t;this.expect("(")?(t=this.filterChain(),this.consume(")")):this.expect("[")?t=this.arrayDeclaration():this.expect("{")?t=this.object():this.constants.hasOwnProperty(this.peek().text)?t=z(this.constants[this.consume().text]):this.peek().identifier?t=this.identifier():this.peek().constant?t=this.constant():this.throwError("not a primary expression",this.peek());for(var n;n=this.expect("(","[",".");)"("===n.text?(t={type:to.CallExpression,callee:t,arguments:this.parseArguments()},this.consume(")")):"["===n.text?(t={type:to.MemberExpression,object:t,property:this.expression(),computed:!0},this.consume("]")):"."===n.text?t={type:to.MemberExpression,object:t,property:this.identifier(),computed:!1}:this.throwError("IMPOSSIBLE");return t},filter:function(t){for(var n=[t],e={type:to.CallExpression,callee:this.identifier(),arguments:n,filter:!0};this.expect(":");)n.push(this.expression());return e},parseArguments:function(){var t=[];if(")"!==this.peekToken().text)do t.push(this.expression());while(this.expect(","));return t},identifier:function(){var t=this.consume();return t.identifier||this.throwError("is not a valid identifier",t),{type:to.Identifier,name:t.text}},constant:function(){return{type:to.Literal,value:this.consume().value}},arrayDeclaration:function(){var t=[];if("]"!==this.peekToken().text)do{if(this.peek("]"))break;t.push(this.expression())}while(this.expect(","));return this.consume("]"),{type:to.ArrayExpression,elements:t}},object:function(){var t,n=[];if("}"!==this.peekToken().text)do{if(this.peek("}"))break;t={type:to.Property,kind:"init"},this.peek().constant?t.key=this.constant():this.peek().identifier?t.key=this.identifier():this.throwError("invalid key",this.peek()),this.consume(":"),t.value=this.expression(),n.push(t)}while(this.expect(","));return this.consume("}"),{type:to.ObjectExpression,properties:n}},throwError:function(t,n){throw Yi("syntax","Syntax Error: Token '{0}' {1} at column {2} of the expression [{3}] starting at [{4}].",n.text,t,n.index+1,this.text,this.text.substring(n.index))},consume:function(t){if(0===this.tokens.length)throw Yi("ueoe","Unexpected end of expression: {0}",this.text);var n=this.expect(t);return n||this.throwError("is unexpected, expecting ["+t+"]",this.peek()),n},peekToken:function(){if(0===this.tokens.length)throw Yi("ueoe","Unexpected end of expression: {0}",this.text);return this.tokens[0]},peek:function(t,n,e,r){return this.peekAhead(0,t,n,e,r)},peekAhead:function(t,n,e,r,i){if(this.tokens.length>t){var o=this.tokens[t],a=o.text;if(a===n||a===e||a===r||a===i||!n&&!e&&!r&&!i)return o}return!1},expect:function(t,n,e,r){var i=this.peek(t,n,e,r);return i?(this.tokens.shift(),i):!1},constants:{"true":{type:to.Literal,value:!0},"false":{type:to.Literal,value:!1},"null":{type:to.Literal,value:null},undefined:{type:to.Literal,value:e},"this":{type:to.ThisExpression}}},ue.prototype={compile:function(t,n){var r=this,i=this.astBuilder.ast(t);this.state={nextId:0,filters:{},expensiveChecks:n,fn:{vars:[],body:[],own:{}},assign:{vars:[],body:[],own:{}},inputs:[]},ne(i,r.$filter);var a,u="";if(this.stage="assign",a=ie(i)){this.state.computing="assign";var s=this.nextId();this.recurse(a,s),this.return_(s),u="fn.assign="+this.generateFunction("assign","s,v,l")}var l=ee(i.body);r.stage="inputs",o(l,function(t,n){var e="fn"+n;r.state[e]={vars:[],body:[],own:{}},r.state.computing=e;var i=r.nextId();r.recurse(t,i),r.return_(i),r.state.inputs.push(e),t.watchId=n}),this.state.computing="fn",this.stage="main",this.recurse(i);var c='"'+this.USE+" "+this.STRICT+'";\n'+this.filterPrefix()+"var fn="+this.generateFunction("fn","s,l,a,i")+u+this.watchFns()+"return fn;",f=new Function("$filter","ensureSafeMemberName","ensureSafeObject","ensureSafeFunction","getStringValue","ensureSafeAssignContext","ifDefined","plus","text",c)(this.$filter,Yn,Xn,Zn,Gn,Jn,Kn,Qn,t);return this.state=this.stage=e,f.literal=oe(i),f.constant=ae(i),f},USE:"use",STRICT:"strict",watchFns:function(){var t=[],n=this.state.inputs,e=this;return o(n,function(n){t.push("var "+n+"="+e.generateFunction(n,"s"))}),n.length&&t.push("fn.inputs=["+n.join(",")+"];"),t.join("")},generateFunction:function(t,n){return"function("+n+"){"+this.varsPrefix(t)+this.body(t)+"};"},filterPrefix:function(){var t=[],n=this;return o(this.state.filters,function(e,r){t.push(e+"=$filter("+n.escape(r)+")")}),t.length?"var "+t.join(",")+";":""},varsPrefix:function(t){return this.state[t].vars.length?"var "+this.state[t].vars.join(",")+";":""},body:function(t){return this.state[t].body.join("")},recurse:function(t,n,r,i,a,u){var s,l,c,f,h=this;if(i=i||v,!u&&x(t.watchId))return n=n||this.nextId(),void this.if_("i",this.lazyAssign(n,this.computedMember("i",t.watchId)),this.lazyRecurse(t,n,r,i,a,!0));switch(t.type){case to.Program:o(t.body,function(n,r){h.recurse(n.expression,e,e,function(t){l=t}),r!==t.body.length-1?h.current().body.push(l,";"):h.return_(l)});break;case to.Literal:f=this.escape(t.value),this.assign(n,f),i(f);break;case to.UnaryExpression:this.recurse(t.argument,e,e,function(t){l=t}),f=t.operator+"("+this.ifDefined(l,0)+")",this.assign(n,f),i(f);break;case to.BinaryExpression:this.recurse(t.left,e,e,function(t){s=t}),this.recurse(t.right,e,e,function(t){l=t}),f="+"===t.operator?this.plus(s,l):"-"===t.operator?this.ifDefined(s,0)+t.operator+this.ifDefined(l,0):"("+s+")"+t.operator+"("+l+")",this.assign(n,f),i(f);break;case to.LogicalExpression:n=n||this.nextId(),h.recurse(t.left,n),h.if_("&&"===t.operator?n:h.not(n),h.lazyRecurse(t.right,n)),i(n);break;case to.ConditionalExpression:n=n||this.nextId(),h.recurse(t.test,n),h.if_(n,h.lazyRecurse(t.alternate,n),h.lazyRecurse(t.consequent,n)),i(n);break;case to.Identifier:n=n||this.nextId(),r&&(r.context="inputs"===h.stage?"s":this.assign(this.nextId(),this.getHasOwnProperty("l",t.name)+"?l:s"),r.computed=!1,r.name=t.name),Yn(t.name),h.if_("inputs"===h.stage||h.not(h.getHasOwnProperty("l",t.name)),function(){h.if_("inputs"===h.stage||"s",function(){a&&1!==a&&h.if_(h.not(h.nonComputedMember("s",t.name)),h.lazyAssign(h.nonComputedMember("s",t.name),"{}")),h.assign(n,h.nonComputedMember("s",t.name))})},n&&h.lazyAssign(n,h.nonComputedMember("l",t.name))),(h.state.expensiveChecks||le(t.name))&&h.addEnsureSafeObject(n),i(n);break;case to.MemberExpression:s=r&&(r.context=this.nextId())||this.nextId(),n=n||this.nextId(),h.recurse(t.object,s,e,function(){h.if_(h.notNull(s),function(){t.computed?(l=h.nextId(),h.recurse(t.property,l),h.getStringValue(l),h.addEnsureSafeMemberName(l),a&&1!==a&&h.if_(h.not(h.computedMember(s,l)),h.lazyAssign(h.computedMember(s,l),"{}")),f=h.ensureSafeObject(h.computedMember(s,l)),h.assign(n,f),r&&(r.computed=!0,r.name=l)):(Yn(t.property.name),a&&1!==a&&h.if_(h.not(h.nonComputedMember(s,t.property.name)),h.lazyAssign(h.nonComputedMember(s,t.property.name),"{}")),f=h.nonComputedMember(s,t.property.name),(h.state.expensiveChecks||le(t.property.name))&&(f=h.ensureSafeObject(f)),h.assign(n,f),r&&(r.computed=!1,r.name=t.property.name))},function(){h.assign(n,"undefined")}),i(n)},!!a);break;case to.CallExpression:n=n||this.nextId(),t.filter?(l=h.filter(t.callee.name),c=[],o(t.arguments,function(t){var n=h.nextId();h.recurse(t,n),c.push(n)}),f=l+"("+c.join(",")+")",h.assign(n,f),i(n)):(l=h.nextId(),s={},c=[],h.recurse(t.callee,l,s,function(){h.if_(h.notNull(l),function(){h.addEnsureSafeFunction(l),o(t.arguments,function(t){h.recurse(t,h.nextId(),e,function(t){c.push(h.ensureSafeObject(t))})}),s.name?(h.state.expensiveChecks||h.addEnsureSafeObject(s.context),f=h.member(s.context,s.name,s.computed)+"("+c.join(",")+")"):f=l+"("+c.join(",")+")",f=h.ensureSafeObject(f),h.assign(n,f)},function(){h.assign(n,"undefined")}),i(n)}));break;case to.AssignmentExpression:if(l=this.nextId(),s={},!re(t.left))throw Yi("lval","Trying to assing a value to a non l-value");this.recurse(t.left,e,s,function(){h.if_(h.notNull(s.context),function(){h.recurse(t.right,l),h.addEnsureSafeObject(h.member(s.context,s.name,s.computed)),h.addEnsureSafeAssignContext(s.context),f=h.member(s.context,s.name,s.computed)+t.operator+l,h.assign(n,f),i(n||f)})},1);break;case to.ArrayExpression:c=[],o(t.elements,function(t){h.recurse(t,h.nextId(),e,function(t){c.push(t)})}),f="["+c.join(",")+"]",this.assign(n,f),i(f);break;case to.ObjectExpression:c=[],o(t.properties,function(t){h.recurse(t.value,h.nextId(),e,function(n){c.push(h.escape(t.key.type===to.Identifier?t.key.name:""+t.key.value)+":"+n)})}),f="{"+c.join(",")+"}",this.assign(n,f),i(f);break;case to.ThisExpression:this.assign(n,"s"),i("s");break;case to.NGValueParameter:this.assign(n,"v"),i("v")}},getHasOwnProperty:function(t,n){var e=t+"."+n,r=this.current().own;return r.hasOwnProperty(e)||(r[e]=this.nextId(!1,t+"&&("+this.escape(n)+" in "+t+")")),r[e]},assign:function(t,n){return t?(this.current().body.push(t,"=",n,";"),t):void 0},filter:function(t){return this.state.filters.hasOwnProperty(t)||(this.state.filters[t]=this.nextId(!0)),this.state.filters[t]},ifDefined:function(t,n){return"ifDefined("+t+","+this.escape(n)+")"},plus:function(t,n){return"plus("+t+","+n+")"},return_:function(t){this.current().body.push("return ",t,";")},if_:function(t,n,e){if(t===!0)n();else{var r=this.current().body;r.push("if(",t,"){"),n(),r.push("}"),e&&(r.push("else{"),e(),r.push("}"))}},not:function(t){return"!("+t+")"},notNull:function(t){return t+"!=null"},nonComputedMember:function(t,n){return t+"."+n},computedMember:function(t,n){return t+"["+n+"]"},member:function(t,n,e){return e?this.computedMember(t,n):this.nonComputedMember(t,n)},addEnsureSafeObject:function(t){this.current().body.push(this.ensureSafeObject(t),";")},addEnsureSafeMemberName:function(t){this.current().body.push(this.ensureSafeMemberName(t),";")},addEnsureSafeFunction:function(t){this.current().body.push(this.ensureSafeFunction(t),";")},addEnsureSafeAssignContext:function(t){this.current().body.push(this.ensureSafeAssignContext(t),";")},ensureSafeObject:function(t){return"ensureSafeObject("+t+",text)"},ensureSafeMemberName:function(t){return"ensureSafeMemberName("+t+",text)"},ensureSafeFunction:function(t){return"ensureSafeFunction("+t+",text)"},getStringValue:function(t){this.assign(t,"getStringValue("+t+",text)")},ensureSafeAssignContext:function(t){return"ensureSafeAssignContext("+t+",text)"},lazyRecurse:function(t,n,e,r,i,o){var a=this;return function(){a.recurse(t,n,e,r,i,o)}},lazyAssign:function(t,n){var e=this;return function(){e.assign(t,n)}},stringEscapeRegex:/[^ a-zA-Z0-9]/g,stringEscapeFn:function(t){return"\\u"+("0000"+t.charCodeAt(0).toString(16)).slice(-4)},escape:function(t){if(C(t))return"'"+t.replace(this.stringEscapeRegex,this.stringEscapeFn)+"'";if(S(t))return t.toString();if(t===!0)return"true";if(t===!1)return"false";if(null===t)return"null";if("undefined"==typeof t)return"undefined";throw Yi("esc","IMPOSSIBLE")},nextId:function(t,n){var e="v"+this.state.nextId++;return t||this.current().vars.push(e+(n?"="+n:"")),e},current:function(){return this.state[this.state.computing]}},se.prototype={compile:function(t,n){var e=this,r=this.astBuilder.ast(t);this.expression=t,this.expensiveChecks=n,ne(r,e.$filter);var i,a;(i=ie(r))&&(a=this.recurse(i));var u,s=ee(r.body);s&&(u=[],o(s,function(t,n){var r=e.recurse(t);t.input=r,u.push(r),t.watchId=n}));var l=[];o(r.body,function(t){l.push(e.recurse(t.expression))});var c=0===r.body.length?function(){}:1===r.body.length?l[0]:function(t,n){var e;return o(l,function(r){e=r(t,n)}),e};return a&&(c.assign=function(t,n,e){return a(t,e,n)}),u&&(c.inputs=u),c.literal=oe(r),c.constant=ae(r),c},recurse:function(t,n,r){var i,a,u,s=this;if(t.input)return this.inputs(t.input,t.watchId);switch(t.type){case to.Literal:return this.value(t.value,n);case to.UnaryExpression:return a=this.recurse(t.argument),this["unary"+t.operator](a,n);case to.BinaryExpression:return i=this.recurse(t.left),a=this.recurse(t.right),this["binary"+t.operator](i,a,n);case to.LogicalExpression:return i=this.recurse(t.left),a=this.recurse(t.right),this["binary"+t.operator](i,a,n);case to.ConditionalExpression:return this["ternary?:"](this.recurse(t.test),this.recurse(t.alternate),this.recurse(t.consequent),n);case to.Identifier:return Yn(t.name,s.expression),s.identifier(t.name,s.expensiveChecks||le(t.name),n,r,s.expression);case to.MemberExpression:return i=this.recurse(t.object,!1,!!r),t.computed||(Yn(t.property.name,s.expression),a=t.property.name),t.computed&&(a=this.recurse(t.property)),t.computed?this.computedMember(i,a,n,r,s.expression):this.nonComputedMember(i,a,s.expensiveChecks,n,r,s.expression);case to.CallExpression:return u=[],o(t.arguments,function(t){u.push(s.recurse(t))}),t.filter&&(a=this.$filter(t.callee.name)),t.filter||(a=this.recurse(t.callee,!0)),t.filter?function(t,r,i,o){for(var s=[],l=0;l<u.length;++l)s.push(u[l](t,r,i,o));var c=a.apply(e,s,o);return n?{context:e,name:e,value:c}:c}:function(t,e,r,i){var o,l=a(t,e,r,i);if(null!=l.value){Xn(l.context,s.expression),Zn(l.value,s.expression);for(var c=[],f=0;f<u.length;++f)c.push(Xn(u[f](t,e,r,i),s.expression));o=Xn(l.value.apply(l.context,c),s.expression)}return n?{value:o}:o};case to.AssignmentExpression:return i=this.recurse(t.left,!0,1),a=this.recurse(t.right),function(t,e,r,o){var u=i(t,e,r,o),l=a(t,e,r,o);return Xn(u.value,s.expression),Jn(u.context),u.context[u.name]=l,n?{value:l}:l};case to.ArrayExpression:return u=[],o(t.elements,function(t){u.push(s.recurse(t))}),function(t,e,r,i){for(var o=[],a=0;a<u.length;++a)o.push(u[a](t,e,r,i));return n?{value:o}:o};case to.ObjectExpression:return u=[],o(t.properties,function(t){u.push({key:t.key.type===to.Identifier?t.key.name:""+t.key.value,value:s.recurse(t.value)})}),function(t,e,r,i){for(var o={},a=0;a<u.length;++a)o[u[a].key]=u[a].value(t,e,r,i);return n?{value:o}:o};case to.ThisExpression:return function(t){return n?{value:t}:t};case to.NGValueParameter:return function(t,e,r,i){return n?{value:r}:r}}},"unary+":function(t,n){return function(e,r,i,o){var a=t(e,r,i,o);return a=x(a)?+a:0,n?{value:a}:a}},"unary-":function(t,n){return function(e,r,i,o){var a=t(e,r,i,o);return a=x(a)?-a:0,n?{value:a}:a}},"unary!":function(t,n){return function(e,r,i,o){var a=!t(e,r,i,o);return n?{value:a}:a}},"binary+":function(t,n,e){return function(r,i,o,a){var u=t(r,i,o,a),s=n(r,i,o,a),l=Qn(u,s);return e?{value:l}:l}},"binary-":function(t,n,e){return function(r,i,o,a){var u=t(r,i,o,a),s=n(r,i,o,a),l=(x(u)?u:0)-(x(s)?s:0);return e?{value:l}:l}},"binary*":function(t,n,e){return function(r,i,o,a){var u=t(r,i,o,a)*n(r,i,o,a);return e?{value:u}:u}},"binary/":function(t,n,e){return function(r,i,o,a){var u=t(r,i,o,a)/n(r,i,o,a);return e?{value:u}:u}},"binary%":function(t,n,e){return function(r,i,o,a){var u=t(r,i,o,a)%n(r,i,o,a);return e?{value:u}:u}},"binary===":function(t,n,e){return function(r,i,o,a){var u=t(r,i,o,a)===n(r,i,o,a);return e?{value:u}:u}},"binary!==":function(t,n,e){return function(r,i,o,a){var u=t(r,i,o,a)!==n(r,i,o,a);return e?{value:u}:u}},"binary==":function(t,n,e){return function(r,i,o,a){var u=t(r,i,o,a)==n(r,i,o,a);return e?{value:u}:u}},"binary!=":function(t,n,e){return function(r,i,o,a){var u=t(r,i,o,a)!=n(r,i,o,a);return e?{value:u}:u}},"binary<":function(t,n,e){return function(r,i,o,a){var u=t(r,i,o,a)<n(r,i,o,a);return e?{value:u}:u}},"binary>":function(t,n,e){return function(r,i,o,a){var u=t(r,i,o,a)>n(r,i,o,a);return e?{value:u}:u}},"binary<=":function(t,n,e){return function(r,i,o,a){var u=t(r,i,o,a)<=n(r,i,o,a);return e?{value:u}:u}},"binary>=":function(t,n,e){return function(r,i,o,a){var u=t(r,i,o,a)>=n(r,i,o,a);return e?{value:u}:u}},"binary&&":function(t,n,e){return function(r,i,o,a){var u=t(r,i,o,a)&&n(r,i,o,a);return e?{value:u}:u}},"binary||":function(t,n,e){return function(r,i,o,a){var u=t(r,i,o,a)||n(r,i,o,a);return e?{value:u}:u}},"ternary?:":function(t,n,e,r){return function(i,o,a,u){var s=t(i,o,a,u)?n(i,o,a,u):e(i,o,a,u);return r?{value:s}:s}},value:function(t,n){return function(){return n?{context:e,name:e,value:t}:t}},identifier:function(t,n,r,i,o){return function(a,u,s,l){var c=u&&t in u?u:a;i&&1!==i&&c&&!c[t]&&(c[t]={});var f=c?c[t]:e;return n&&Xn(f,o),r?{context:c,name:t,value:f}:f}},computedMember:function(t,n,e,r,i){return function(o,a,u,s){var l,c,f=t(o,a,u,s);return null!=f&&(l=n(o,a,u,s),l=Gn(l),Yn(l,i),r&&1!==r&&f&&!f[l]&&(f[l]={}),c=f[l],Xn(c,i)),e?{context:f,name:l,value:c}:c}},nonComputedMember:function(t,n,r,i,o,a){return function(u,s,l,c){var f=t(u,s,l,c);o&&1!==o&&f&&!f[n]&&(f[n]={});var h=null!=f?f[n]:e;return(r||le(n))&&Xn(h,a),i?{context:f,name:n,value:h}:h}},inputs:function(t,n){return function(e,r,i,o){return o?o[n]:t(e,r,i)}}};var no=function(t,n,e){this.lexer=t,this.$filter=n,this.options=e,this.ast=new to(this.lexer),this.astCompiler=e.csp?new se(this.ast,n):new ue(this.ast,n)};no.prototype={constructor:no,parse:function(t){return this.astCompiler.compile(t,this.options.expensiveChecks)}};var eo=(gt(),gt(),Object.prototype.valueOf),ro=r("$sce"),io={
+HTML:"html",CSS:"css",URL:"url",RESOURCE_URL:"resourceUrl",JS:"js"},Pi=r("$compile"),oo=n.createElement("a"),ao=Me(t.location.href);Ee.$inject=["$document"],Oe.$inject=["$provide"],Re.$inject=["$locale"],De.$inject=["$locale"];var uo=".",so={yyyy:ze("FullYear",4),yy:ze("FullYear",2,0,!0),y:ze("FullYear",1),MMMM:qe("Month"),MMM:qe("Month",!0),MM:ze("Month",2,1),M:ze("Month",1,1),dd:ze("Date",2),d:ze("Date",1),HH:ze("Hours",2),H:ze("Hours",1),hh:ze("Hours",2,-12),h:ze("Hours",1,-12),mm:ze("Minutes",2),m:ze("Minutes",1),ss:ze("Seconds",2),s:ze("Seconds",1),sss:ze("Milliseconds",3),EEEE:qe("Day"),EEE:qe("Day",!0),a:He,Z:Ve,ww:Ue(2),w:Ue(1),G:Ye,GG:Ye,GGG:Ye,GGGG:Ge},lo=/((?:[^yMdHhmsaZEwG']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z|G+|w+))(.*)/,co=/^\-?\d+$/;Xe.$inject=["$locale"];var fo=m(xr),ho=m(wr);Ke.$inject=["$parse"];var po=m({restrict:"E",compile:function(t,n){return n.href||n.xlinkHref?void 0:function(t,n){if("a"===n[0].nodeName.toLowerCase()){var e="[object SVGAnimatedString]"===Tr.call(n.prop("href"))?"xlink:href":"href";n.on("click",function(t){n.attr(e)||t.preventDefault()})}}}}),vo={};o(di,function(t,n){function e(t,e,i){t.$watch(i[r],function(t){i.$set(n,!!t)})}if("multiple"!=t){var r=cn("ng-"+n),i=e;"checked"===t&&(i=function(t,n,i){i.ngModel!==i[r]&&e(t,n,i)}),vo[r]=function(){return{restrict:"A",priority:100,link:i}}}}),o(gi,function(t,n){vo[n]=function(){return{priority:100,link:function(t,e,r){if("ngPattern"===n&&"/"==r.ngPattern.charAt(0)){var i=r.ngPattern.match(yr);if(i)return void r.$set("ngPattern",new RegExp(i[1],i[2]))}t.$watch(r[n],function(t){r.$set(n,t)})}}}}),o(["src","srcset","href"],function(t){var n=cn("ng-"+t);vo[n]=function(){return{priority:99,link:function(e,r,i){var o=t,a=t;"href"===t&&"[object SVGAnimatedString]"===Tr.call(r.prop("href"))&&(a="xlinkHref",i.$attr[a]="xlink:href",o=null),i.$observe(n,function(n){return n?(i.$set(a,n),void(_r&&o&&r.prop(o,i[a]))):void("href"===t&&i.$set(a,null))})}}}});var go={$addControl:v,$$renameControl:tr,$removeControl:v,$setValidity:v,$setDirty:v,$setPristine:v,$setSubmitted:v},mo="ng-submitted";nr.$inject=["$element","$attrs","$scope","$animate","$interpolate"];var yo=function(t){return["$timeout","$parse",function(n,r){function i(t){return""===t?r('this[""]').assign:r(t).assign||v}var o={name:"form",restrict:t?"EAC":"E",require:["form","^^?form"],controller:nr,compile:function(r,o){r.addClass(Ko).addClass(Zo);var a=o.name?"name":t&&o.ngForm?"ngForm":!1;return{pre:function(t,r,o,u){var s=u[0];if(!("action"in o)){var l=function(n){t.$apply(function(){s.$commitViewValue(),s.$setSubmitted()}),n.preventDefault()};ei(r[0],"submit",l),r.on("$destroy",function(){n(function(){ri(r[0],"submit",l)},0,!1)})}var c=u[1]||s.$$parentForm;c.$addControl(s);var h=a?i(s.$name):v;a&&(h(t,s),o.$observe(a,function(n){s.$name!==n&&(h(t,e),s.$$parentForm.$$renameControl(s,n),(h=i(s.$name))(t,s))})),r.on("$destroy",function(){s.$$parentForm.$removeControl(s),h(t,e),f(s,go)})}}}};return o}]},$o=yo(),xo=yo(!0),bo=/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/,wo=/^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/,Co=/^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i,So=/^\s*(\-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/,_o=/^(\d{4})-(\d{2})-(\d{2})$/,Mo=/^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/,ko=/^(\d{4})-W(\d\d)$/,Ao=/^(\d{4})-(\d\d)$/,Eo=/^(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/,Po={text:rr,date:ur("date",_o,ar(_o,["yyyy","MM","dd"]),"yyyy-MM-dd"),"datetime-local":ur("datetimelocal",Mo,ar(Mo,["yyyy","MM","dd","HH","mm","ss","sss"]),"yyyy-MM-ddTHH:mm:ss.sss"),time:ur("time",Eo,ar(Eo,["HH","mm","ss","sss"]),"HH:mm:ss.sss"),week:ur("week",ko,or,"yyyy-Www"),month:ur("month",Ao,ar(Ao,["yyyy","MM"]),"yyyy-MM"),number:lr,url:cr,email:fr,radio:hr,checkbox:dr,hidden:v,button:v,submit:v,reset:v,file:v},Oo=["$browser","$sniffer","$filter","$parse",function(t,n,e,r){return{restrict:"E",require:["?ngModel"],link:{pre:function(i,o,a,u){u[0]&&(Po[xr(a.type)]||Po.text)(i,o,a,u[0],n,t,e,r)}}}}],To=/^(true|false|\d+)$/,Lo=function(){return{restrict:"A",priority:100,compile:function(t,n){return To.test(n.ngValue)?function(t,n,e){e.$set("value",t.$eval(e.ngValue))}:function(t,n,e){t.$watch(e.ngValue,function(t){e.$set("value",t)})}}}},jo=["$compile",function(t){return{restrict:"AC",compile:function(n){return t.$$addBindingClass(n),function(n,e,r){t.$$addBindingInfo(e,r.ngBind),e=e[0],n.$watch(r.ngBind,function(t){e.textContent=$(t)?"":t})}}}}],No=["$interpolate","$compile",function(t,n){return{compile:function(e){return n.$$addBindingClass(e),function(e,r,i){var o=t(r.attr(i.$attr.ngBindTemplate));n.$$addBindingInfo(r,o.expressions),r=r[0],i.$observe("ngBindTemplate",function(t){r.textContent=$(t)?"":t})}}}}],Ro=["$sce","$parse","$compile",function(t,n,e){return{restrict:"A",compile:function(r,i){var o=n(i.ngBindHtml),a=n(i.ngBindHtml,function(t){return(t||"").toString()});return e.$$addBindingClass(r),function(n,r,i){e.$$addBindingInfo(r,i.ngBindHtml),n.$watch(a,function(){r.html(t.getTrustedHtml(o(n))||"")})}}}}],Do=m({restrict:"A",require:"ngModel",link:function(t,n,e,r){r.$viewChangeListeners.push(function(){t.$eval(e.ngChange)})}}),Fo=vr("",!0),Io=vr("Odd",0),zo=vr("Even",1),qo=Qe({compile:function(t,n){n.$set("ngCloak",e),t.removeClass("ng-cloak")}}),Vo=[function(){return{restrict:"A",scope:!0,controller:"@",priority:500}}],Bo={},Wo={blur:!0,focus:!0};o("click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste".split(" "),function(t){var n=cn("ng-"+t);Bo[n]=["$parse","$rootScope",function(e,r){return{restrict:"A",compile:function(i,o){var a=e(o[n],null,!0);return function(n,e){e.on(t,function(e){var i=function(){a(n,{$event:e})};Wo[t]&&r.$$phase?n.$evalAsync(i):n.$apply(i)})}}}}]});var Uo=["$animate",function(t){return{multiElement:!0,transclude:"element",priority:600,terminal:!0,restrict:"A",$$tlb:!0,link:function(e,r,i,o,a){var u,s,l;e.$watch(i.ngIf,function(e){e?s||a(function(e,o){s=o,e[e.length++]=n.createComment(" end ngIf: "+i.ngIf+" "),u={clone:e},t.enter(e,r.parent(),r)}):(l&&(l.remove(),l=null),s&&(s.$destroy(),s=null),u&&(l=vt(u.clone),t.leave(l).then(function(){l=null}),u=null))})}}}],Ho=["$templateRequest","$anchorScroll","$animate",function(t,n,e){return{restrict:"ECA",priority:400,terminal:!0,transclude:"element",controller:Nr.noop,compile:function(r,i){var o=i.ngInclude||i.src,a=i.onload||"",u=i.autoscroll;return function(r,i,s,l,c){var f,h,p,d=0,v=function(){h&&(h.remove(),h=null),f&&(f.$destroy(),f=null),p&&(e.leave(p).then(function(){h=null}),h=p,p=null)};r.$watch(o,function(o){var s=function(){!x(u)||u&&!r.$eval(u)||n()},h=++d;o?(t(o,!0).then(function(t){if(h===d){var n=r.$new();l.template=t;var u=c(n,function(t){v(),e.enter(t,null,i).then(s)});f=n,p=u,f.$emit("$includeContentLoaded",o),r.$eval(a)}},function(){h===d&&(v(),r.$emit("$includeContentError",o))}),r.$emit("$includeContentRequested",o)):(v(),l.template=null)})}}}}],Yo=["$compile",function(t){return{restrict:"ECA",priority:-400,require:"ngInclude",link:function(e,r,i,o){return/SVG/.test(r[0].toString())?(r.empty(),void t(Mt(o.template,n).childNodes)(e,function(t){r.append(t)},{futureParentElement:r})):(r.html(o.template),void t(r.contents())(e))}}}],Go=Qe({priority:450,compile:function(){return{pre:function(t,n,e){t.$eval(e.ngInit)}}}}),Xo=function(){return{restrict:"A",priority:100,require:"ngModel",link:function(t,n,r,i){var a=n.attr(r.$attr.ngList)||", ",u="false"!==r.ngTrim,s=u?zr(a):a,l=function(t){if(!$(t)){var n=[];return t&&o(t.split(s),function(t){t&&n.push(u?zr(t):t)}),n}};i.$parsers.push(l),i.$formatters.push(function(t){return Fr(t)?t.join(a):e}),i.$isEmpty=function(t){return!t||!t.length}}}},Zo="ng-valid",Jo="ng-invalid",Ko="ng-pristine",Qo="ng-dirty",ta="ng-untouched",na="ng-touched",ea="ng-pending",ra=r("ngModel"),ia=["$scope","$exceptionHandler","$attrs","$element","$parse","$animate","$timeout","$rootScope","$q","$interpolate",function(t,n,r,i,a,u,s,l,c,f){this.$viewValue=Number.NaN,this.$modelValue=Number.NaN,this.$$rawModelValue=e,this.$validators={},this.$asyncValidators={},this.$parsers=[],this.$formatters=[],this.$viewChangeListeners=[],this.$untouched=!0,this.$touched=!1,this.$pristine=!0,this.$dirty=!1,this.$valid=!0,this.$invalid=!1,this.$error={},this.$$success={},this.$pending=e,this.$name=f(r.name||"",!1)(t),this.$$parentForm=go;var h,p=a(r.ngModel),d=p.assign,g=p,m=d,y=null,b=this;this.$$setOptions=function(t){if(b.$options=t,t&&t.getterSetter){var n=a(r.ngModel+"()"),e=a(r.ngModel+"($$$p)");g=function(t){var e=p(t);return M(e)&&(e=n(t)),e},m=function(t,n){M(p(t))?e(t,{$$$p:b.$modelValue}):d(t,b.$modelValue)}}else if(!p.assign)throw ra("nonassign","Expression '{0}' is non-assignable. Element: {1}",r.ngModel,K(i))},this.$render=v,this.$isEmpty=function(t){return $(t)||""===t||null===t||t!==t};var w=0;gr({ctrl:this,$element:i,set:function(t,n){t[n]=!0},unset:function(t,n){delete t[n]},$animate:u}),this.$setPristine=function(){b.$dirty=!1,b.$pristine=!0,u.removeClass(i,Qo),u.addClass(i,Ko)},this.$setDirty=function(){b.$dirty=!0,b.$pristine=!1,u.removeClass(i,Ko),u.addClass(i,Qo),b.$$parentForm.$setDirty()},this.$setUntouched=function(){b.$touched=!1,b.$untouched=!0,u.setClass(i,ta,na)},this.$setTouched=function(){b.$touched=!0,b.$untouched=!1,u.setClass(i,na,ta)},this.$rollbackViewValue=function(){s.cancel(y),b.$viewValue=b.$$lastCommittedViewValue,b.$render()},this.$validate=function(){if(!S(b.$modelValue)||!isNaN(b.$modelValue)){var t=b.$$lastCommittedViewValue,n=b.$$rawModelValue,r=b.$valid,i=b.$modelValue,o=b.$options&&b.$options.allowInvalid;b.$$runValidators(n,t,function(t){o||r===t||(b.$modelValue=t?n:e,b.$modelValue!==i&&b.$$writeModelToScope())})}},this.$$runValidators=function(t,n,r){function i(){var t=b.$$parserName||"parse";return $(h)?(s(t,null),!0):(h||(o(b.$validators,function(t,n){s(n,null)}),o(b.$asyncValidators,function(t,n){s(n,null)})),s(t,h),h)}function a(){var e=!0;return o(b.$validators,function(r,i){var o=r(t,n);e=e&&o,s(i,o)}),e?!0:(o(b.$asyncValidators,function(t,n){s(n,null)}),!1)}function u(){var r=[],i=!0;o(b.$asyncValidators,function(o,a){var u=o(t,n);if(!j(u))throw ra("$asyncValidators","Expected asynchronous validator to return a promise but got '{0}' instead.",u);s(a,e),r.push(u.then(function(){s(a,!0)},function(t){i=!1,s(a,!1)}))}),r.length?c.all(r).then(function(){l(i)},v):l(!0)}function s(t,n){f===w&&b.$setValidity(t,n)}function l(t){f===w&&r(t)}w++;var f=w;return i()&&a()?void u():void l(!1)},this.$commitViewValue=function(){var t=b.$viewValue;s.cancel(y),(b.$$lastCommittedViewValue!==t||""===t&&b.$$hasNativeValidators)&&(b.$$lastCommittedViewValue=t,b.$pristine&&this.$setDirty(),this.$$parseAndValidate())},this.$$parseAndValidate=function(){function n(){b.$modelValue!==a&&b.$$writeModelToScope()}var r=b.$$lastCommittedViewValue,i=r;if(h=$(i)?e:!0)for(var o=0;o<b.$parsers.length;o++)if(i=b.$parsers[o](i),$(i)){h=!1;break}S(b.$modelValue)&&isNaN(b.$modelValue)&&(b.$modelValue=g(t));var a=b.$modelValue,u=b.$options&&b.$options.allowInvalid;b.$$rawModelValue=i,u&&(b.$modelValue=i,n()),b.$$runValidators(i,b.$$lastCommittedViewValue,function(t){u||(b.$modelValue=t?i:e,n())})},this.$$writeModelToScope=function(){m(t,b.$modelValue),o(b.$viewChangeListeners,function(t){try{t()}catch(e){n(e)}})},this.$setViewValue=function(t,n){b.$viewValue=t,b.$options&&!b.$options.updateOnDefault||b.$$debounceViewValueCommit(n)},this.$$debounceViewValueCommit=function(n){var e,r=0,i=b.$options;i&&x(i.debounce)&&(e=i.debounce,S(e)?r=e:S(e[n])?r=e[n]:S(e["default"])&&(r=e["default"])),s.cancel(y),r?y=s(function(){b.$commitViewValue()},r):l.$$phase?b.$commitViewValue():t.$apply(function(){b.$commitViewValue()})},t.$watch(function(){var n=g(t);if(n!==b.$modelValue&&(b.$modelValue===b.$modelValue||n===n)){b.$modelValue=b.$$rawModelValue=n,h=e;for(var r=b.$formatters,i=r.length,o=n;i--;)o=r[i](o);b.$viewValue!==o&&(b.$viewValue=b.$$lastCommittedViewValue=o,b.$render(),b.$$runValidators(n,o,v))}return n})}],oa=["$rootScope",function(t){return{restrict:"A",require:["ngModel","^?form","^?ngModelOptions"],controller:ia,priority:1,compile:function(n){return n.addClass(Ko).addClass(ta).addClass(Zo),{pre:function(t,n,e,r){var i=r[0],o=r[1]||i.$$parentForm;i.$$setOptions(r[2]&&r[2].$options),o.$addControl(i),e.$observe("name",function(t){i.$name!==t&&i.$$parentForm.$$renameControl(i,t)}),t.$on("$destroy",function(){i.$$parentForm.$removeControl(i)})},post:function(n,e,r,i){var o=i[0];o.$options&&o.$options.updateOn&&e.on(o.$options.updateOn,function(t){o.$$debounceViewValueCommit(t&&t.type)}),e.on("blur",function(e){o.$touched||(t.$$phase?n.$evalAsync(o.$setTouched):n.$apply(o.$setTouched))})}}}}}],aa=/(\s+|^)default(\s+|$)/,ua=function(){return{restrict:"A",controller:["$scope","$attrs",function(t,n){var e=this;this.$options=z(t.$eval(n.ngModelOptions)),x(this.$options.updateOn)?(this.$options.updateOnDefault=!1,this.$options.updateOn=zr(this.$options.updateOn.replace(aa,function(){return e.$options.updateOnDefault=!0," "}))):this.$options.updateOnDefault=!0}]}},sa=Qe({terminal:!0,priority:1e3}),la=r("ngOptions"),ca=/^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s+([\s\S]+?))?(?:\s+disable\s+when\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?$/,fa=["$compile","$parse",function(t,e){function r(t,n,r){function o(t,n,e,r,i){this.selectValue=t,this.viewValue=n,this.label=e,this.group=r,this.disabled=i}function a(t){var n;if(!l&&i(t))n=t;else{n=[];for(var e in t)t.hasOwnProperty(e)&&"$"!==e.charAt(0)&&n.push(e)}return n}var u=t.match(ca);if(!u)throw la("iexp","Expected expression in form of '_select_ (as _label_)? for (_key_,)?_value_ in _collection_' but got '{0}'. Element: {1}",t,K(n));var s=u[5]||u[7],l=u[6],c=/ as /.test(u[0])&&u[1],f=u[9],h=e(u[2]?u[1]:s),p=c&&e(c),d=p||h,v=f&&e(f),g=f?function(t,n){return v(r,n)}:function(t){return Gt(t)},m=function(t,n){return g(t,C(t,n))},y=e(u[2]||u[1]),$=e(u[3]||""),x=e(u[4]||""),b=e(u[8]),w={},C=l?function(t,n){return w[l]=n,w[s]=t,w}:function(t){return w[s]=t,w};return{trackBy:f,getTrackByValue:m,getWatchables:e(b,function(t){var n=[];t=t||[];for(var e=a(t),i=e.length,o=0;i>o;o++){var s=t===e?o:e[o],l=(t[s],C(t[s],s)),c=g(t[s],l);if(n.push(c),u[2]||u[1]){var f=y(r,l);n.push(f)}if(u[4]){var h=x(r,l);n.push(h)}}return n}),getOptions:function(){for(var t=[],n={},e=b(r)||[],i=a(e),u=i.length,s=0;u>s;s++){var l=e===i?s:i[s],c=e[l],h=C(c,l),p=d(r,h),v=g(p,h),w=y(r,h),S=$(r,h),_=x(r,h),M=new o(v,p,w,S,_);t.push(M),n[v]=M}return{items:t,selectValueMap:n,getOptionFromViewValue:function(t){return n[m(t)]},getViewValueFromOption:function(t){return f?Nr.copy(t.viewValue):t.viewValue}}}}}var a=n.createElement("option"),u=n.createElement("optgroup");return{restrict:"A",terminal:!0,require:["select","?ngModel"],link:function(n,e,i,s){function l(t,n){t.element=n,n.disabled=t.disabled,t.label!==n.label&&(n.label=t.label,n.textContent=t.label),t.value!==n.value&&(n.value=t.selectValue)}function c(t,n,e,r){var i;return n&&xr(n.nodeName)===e?i=n:(i=r.cloneNode(!1),n?t.insertBefore(i,n):t.appendChild(i)),i}function f(t){for(var n;t;)n=t.nextSibling,Vt(t),t=n}function h(t){var n=v&&v[0],e=w&&w[0];if(n||e)for(;t&&(t===n||t===e||n&&n.nodeType===Zr);)t=t.nextSibling;return t}function p(){var t=C&&g.readValue();C=S.getOptions();var n={},r=e[0].firstChild;if(b&&e.prepend(v),r=h(r),C.items.forEach(function(t){var i,o,s;t.group?(i=n[t.group],i||(o=c(e[0],r,"optgroup",u),r=o.nextSibling,o.label=t.group,i=n[t.group]={groupElement:o,currentOptionElement:o.firstChild}),s=c(i.groupElement,i.currentOptionElement,"option",a),l(t,s),i.currentOptionElement=s.nextSibling):(s=c(e[0],r,"option",a),l(t,s),r=s.nextSibling)}),Object.keys(n).forEach(function(t){f(n[t].currentOptionElement)}),f(r),d.$render(),!d.$isEmpty(t)){var i=g.readValue();(S.trackBy?V(t,i):t===i)||(d.$setViewValue(i),d.$render())}}var d=s[1];if(d){for(var v,g=s[0],m=i.multiple,y=0,$=e.children(),x=$.length;x>y;y++)if(""===$[y].value){v=$.eq(y);break}var b=!!v,w=Mr(a.cloneNode(!1));w.val("?");var C,S=r(i.ngOptions,e,n),_=function(){b||e.prepend(v),e.val(""),v.prop("selected",!0),v.attr("selected",!0)},M=function(){b||v.remove()},k=function(){e.prepend(w),e.val("?"),w.prop("selected",!0),w.attr("selected",!0)},A=function(){w.remove()};m?(d.$isEmpty=function(t){return!t||0===t.length},g.writeValue=function(t){C.items.forEach(function(t){t.element.selected=!1}),t&&t.forEach(function(t){var n=C.getOptionFromViewValue(t);n&&!n.disabled&&(n.element.selected=!0)})},g.readValue=function(){var t=e.val()||[],n=[];return o(t,function(t){var e=C.selectValueMap[t];e&&!e.disabled&&n.push(C.getViewValueFromOption(e))}),n},S.trackBy&&n.$watchCollection(function(){return Fr(d.$viewValue)?d.$viewValue.map(function(t){return S.getTrackByValue(t)}):void 0},function(){d.$render()})):(g.writeValue=function(t){var n=C.getOptionFromViewValue(t);n&&!n.disabled?e[0].value!==n.selectValue&&(A(),M(),e[0].value=n.selectValue,n.element.selected=!0,n.element.setAttribute("selected","selected")):null===t||b?(A(),_()):(M(),k())},g.readValue=function(){var t=C.selectValueMap[e.val()];return t&&!t.disabled?(M(),A(),C.getViewValueFromOption(t)):null},S.trackBy&&n.$watch(function(){return S.getTrackByValue(d.$viewValue)},function(){d.$render()})),b?(v.remove(),t(v)(n),v.removeClass("ng-scope")):v=Mr(a.cloneNode(!1)),p(),n.$watchCollection(S.getWatchables,p)}}}}],ha=["$locale","$interpolate","$log",function(t,n,e){var r=/{}/g,i=/^when(Minus)?(.+)$/;return{link:function(a,u,s){function l(t){u.text(t||"")}var c,f=s.count,h=s.$attr.when&&u.attr(s.$attr.when),p=s.offset||0,d=a.$eval(h)||{},g={},m=n.startSymbol(),y=n.endSymbol(),x=m+f+"-"+p+y,b=Nr.noop;o(s,function(t,n){var e=i.exec(n);if(e){var r=(e[1]?"-":"")+xr(e[2]);d[r]=u.attr(s.$attr[n])}}),o(d,function(t,e){g[e]=n(t.replace(r,x))}),a.$watch(f,function(n){var r=parseFloat(n),i=isNaN(r);if(i||r in d||(r=t.pluralCat(r-p)),r!==c&&!(i&&S(c)&&isNaN(c))){b();var o=g[r];$(o)?(null!=n&&e.debug("ngPluralize: no rule defined for '"+r+"' in "+h),b=v,l()):b=a.$watch(o,l),c=r}})}}}],pa=["$parse","$animate",function(t,a){var u="$$NG_REMOVED",s=r("ngRepeat"),l=function(t,n,e,r,i,o,a){t[e]=r,i&&(t[i]=o),t.$index=n,t.$first=0===n,t.$last=n===a-1,t.$middle=!(t.$first||t.$last),t.$odd=!(t.$even=0===(1&n))},c=function(t){return t.clone[0]},f=function(t){return t.clone[t.clone.length-1]};return{restrict:"A",multiElement:!0,transclude:"element",priority:1e3,terminal:!0,$$tlb:!0,compile:function(r,h){var p=h.ngRepeat,d=n.createComment(" end ngRepeat: "+p+" "),v=p.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+track\s+by\s+([\s\S]+?))?\s*$/);if(!v)throw s("iexp","Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.",p);var g=v[1],m=v[2],y=v[3],$=v[4];if(v=g.match(/^(?:(\s*[\$\w]+)|\(\s*([\$\w]+)\s*,\s*([\$\w]+)\s*\))$/),!v)throw s("iidexp","'_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.",g);var x=v[3]||v[1],b=v[2];if(y&&(!/^[$a-zA-Z_][$a-zA-Z0-9_]*$/.test(y)||/^(null|undefined|this|\$index|\$first|\$middle|\$last|\$even|\$odd|\$parent|\$root|\$id)$/.test(y)))throw s("badident","alias '{0}' is invalid --- must be a valid JS identifier which is not a reserved name.",y);var w,C,S,_,M={$id:Gt};return $?w=t($):(S=function(t,n){return Gt(n)},_=function(t){return t}),function(t,n,r,h,v){w&&(C=function(n,e,r){return b&&(M[b]=n),M[x]=e,M.$index=r,w(t,M)});var g=gt();t.$watchCollection(m,function(r){var h,m,$,w,M,k,A,E,P,O,T,L,j=n[0],N=gt();if(y&&(t[y]=r),i(r))P=r,E=C||S;else{E=C||_,P=[];for(var R in r)br.call(r,R)&&"$"!==R.charAt(0)&&P.push(R)}for(w=P.length,T=new Array(w),h=0;w>h;h++)if(M=r===P?h:P[h],k=r[M],A=E(M,k,h),g[A])O=g[A],delete g[A],N[A]=O,T[h]=O;else{if(N[A])throw o(T,function(t){t&&t.scope&&(g[t.id]=t)}),s("dupes","Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}, Duplicate value: {2}",p,A,k);T[h]={id:A,scope:e,clone:e},N[A]=!0}for(var D in g){if(O=g[D],L=vt(O.clone),a.leave(L),L[0].parentNode)for(h=0,m=L.length;m>h;h++)L[h][u]=!0;O.scope.$destroy()}for(h=0;w>h;h++)if(M=r===P?h:P[h],k=r[M],O=T[h],O.scope){$=j;do $=$.nextSibling;while($&&$[u]);c(O)!=$&&a.move(vt(O.clone),null,Mr(j)),j=f(O),l(O.scope,h,x,k,b,M,w)}else v(function(t,n){O.scope=n;var e=d.cloneNode(!1);t[t.length++]=e,a.enter(t,null,Mr(j)),j=e,O.clone=t,N[O.id]=O,l(O.scope,h,x,k,b,M,w)});g=N})}}}}],da="ng-hide",va="ng-hide-animate",ga=["$animate",function(t){return{restrict:"A",multiElement:!0,link:function(n,e,r){n.$watch(r.ngShow,function(n){t[n?"removeClass":"addClass"](e,da,{tempClasses:va})})}}}],ma=["$animate",function(t){return{restrict:"A",multiElement:!0,link:function(n,e,r){n.$watch(r.ngHide,function(n){t[n?"addClass":"removeClass"](e,da,{tempClasses:va})})}}}],ya=Qe(function(t,n,e){t.$watch(e.ngStyle,function(t,e){e&&t!==e&&o(e,function(t,e){n.css(e,"")}),t&&n.css(t)},!0)}),$a=["$animate",function(t){return{require:"ngSwitch",controller:["$scope",function(){this.cases={}}],link:function(e,r,i,a){var u=i.ngSwitch||i.on,s=[],l=[],c=[],f=[],h=function(t,n){return function(){t.splice(n,1)}};e.$watch(u,function(e){var r,i;for(r=0,i=c.length;i>r;++r)t.cancel(c[r]);for(c.length=0,r=0,i=f.length;i>r;++r){var u=vt(l[r].clone);f[r].$destroy();var p=c[r]=t.leave(u);p.then(h(c,r))}l.length=0,f.length=0,(s=a.cases["!"+e]||a.cases["?"])&&o(s,function(e){e.transclude(function(r,i){f.push(i);var o=e.element;r[r.length++]=n.createComment(" end ngSwitchWhen: ");var a={clone:r};l.push(a),t.enter(r,o.parent(),o)})})})}}}],xa=Qe({transclude:"element",priority:1200,require:"^ngSwitch",multiElement:!0,link:function(t,n,e,r,i){r.cases["!"+e.ngSwitchWhen]=r.cases["!"+e.ngSwitchWhen]||[],r.cases["!"+e.ngSwitchWhen].push({transclude:i,element:n})}}),ba=Qe({transclude:"element",priority:1200,require:"^ngSwitch",multiElement:!0,link:function(t,n,e,r,i){r.cases["?"]=r.cases["?"]||[],r.cases["?"].push({transclude:i,element:n})}}),wa=Qe({restrict:"EAC",link:function(t,n,e,i,o){if(!o)throw r("ngTransclude")("orphan","Illegal use of ngTransclude directive in the template! No parent directive that requires a transclusion found. Element: {0}",K(n));o(function(t){n.empty(),n.append(t)})}}),Ca=["$templateCache",function(t){return{restrict:"E",terminal:!0,compile:function(n,e){if("text/ng-template"==e.type){var r=e.id,i=n[0].text;t.put(r,i)}}}}],Sa={$setViewValue:v,$render:v},_a=["$element","$scope","$attrs",function(t,r,i){var o=this,a=new Xt;o.ngModelCtrl=Sa,o.unknownOption=Mr(n.createElement("option")),o.renderUnknownOption=function(n){var e="? "+Gt(n)+" ?";o.unknownOption.val(e),t.prepend(o.unknownOption),t.val(e)},r.$on("$destroy",function(){o.renderUnknownOption=v}),o.removeUnknownOption=function(){o.unknownOption.parent()&&o.unknownOption.remove()},o.readValue=function(){return o.removeUnknownOption(),t.val()},o.writeValue=function(n){o.hasOption(n)?(o.removeUnknownOption(),t.val(n),""===n&&o.emptyOption.prop("selected",!0)):null==n&&o.emptyOption?(o.removeUnknownOption(),t.val("")):o.renderUnknownOption(n)},o.addOption=function(t,n){pt(t,'"option value"'),""===t&&(o.emptyOption=n);var e=a.get(t)||0;a.put(t,e+1)},o.removeOption=function(t){var n=a.get(t);n&&(1===n?(a.remove(t),""===t&&(o.emptyOption=e)):a.put(t,n-1))},o.hasOption=function(t){return!!a.get(t)}}],Ma=function(){return{restrict:"E",require:["select","?ngModel"],controller:_a,link:function(t,n,e,r){var i=r[1];if(i){var a=r[0];if(a.ngModelCtrl=i,i.$render=function(){a.writeValue(i.$viewValue)},n.on("change",function(){t.$apply(function(){i.$setViewValue(a.readValue())})}),e.multiple){a.readValue=function(){var t=[];return o(n.find("option"),function(n){n.selected&&t.push(n.value)}),t},a.writeValue=function(t){var e=new Xt(t);o(n.find("option"),function(t){t.selected=x(e.get(t.value))})};var u,s=NaN;t.$watch(function(){s!==i.$viewValue||V(u,i.$viewValue)||(u=q(i.$viewValue),i.$render()),s=i.$viewValue}),i.$isEmpty=function(t){return!t||0===t.length}}}}}},ka=["$interpolate",function(t){function n(t){t[0].hasAttribute("selected")&&(t[0].selected=!0)}return{restrict:"E",priority:100,compile:function(e,r){if(x(r.value))var i=t(r.value,!0);else{var o=t(e.text(),!0);o||r.$set("value",e.text())}return function(t,e,r){function a(t){l.addOption(t,e),l.ngModelCtrl.$render(),n(e)}var u="$selectController",s=e.parent(),l=s.data(u)||s.parent().data(u);if(l&&l.ngModelCtrl){if(i){var c;r.$observe("value",function(t){x(c)&&l.removeOption(c),c=t,a(t)})}else o?t.$watch(o,function(t,n){r.$set("value",t),n!==t&&l.removeOption(n),a(t)}):a(r.value);e.on("$destroy",function(){l.removeOption(r.value),l.ngModelCtrl.$render()})}}}}}],Aa=m({restrict:"E",terminal:!1}),Ea=function(){return{restrict:"A",require:"?ngModel",link:function(t,n,e,r){r&&(e.required=!0,r.$validators.required=function(t,n){return!e.required||!r.$isEmpty(n)},e.$observe("required",function(){r.$validate()}))}}},Pa=function(){return{restrict:"A",require:"?ngModel",link:function(t,n,i,o){if(o){var a,u=i.ngPattern||i.pattern;i.$observe("pattern",function(t){if(C(t)&&t.length>0&&(t=new RegExp("^"+t+"$")),t&&!t.test)throw r("ngPattern")("noregexp","Expected {0} to be a RegExp but was {1}. Element: {2}",u,t,K(n));a=t||e,o.$validate()}),o.$validators.pattern=function(t,n){return o.$isEmpty(n)||$(a)||a.test(n)}}}}},Oa=function(){return{restrict:"A",require:"?ngModel",link:function(t,n,e,r){if(r){var i=-1;e.$observe("maxlength",function(t){var n=p(t);i=isNaN(n)?-1:n,r.$validate()}),r.$validators.maxlength=function(t,n){return 0>i||r.$isEmpty(n)||n.length<=i}}}}},Ta=function(){return{restrict:"A",require:"?ngModel",link:function(t,n,e,r){if(r){var i=0;e.$observe("minlength",function(t){i=p(t)||0,r.$validate()}),r.$validators.minlength=function(t,n){return r.$isEmpty(n)||n.length>=i}}}}};return t.angular.bootstrap?void console.log("WARNING: Tried to load angular more than once."):(ct(),xt(Nr),Nr.module("ngLocale",[],["$provide",function(t){function n(t){t+="";var n=t.indexOf(".");return-1==n?0:t.length-n-1}function r(t,r){var i=r;e===i&&(i=Math.min(n(t),3));var o=Math.pow(10,i),a=(t*o|0)%o;return{v:i,f:a}}var i={ZERO:"zero",ONE:"one",TWO:"two",FEW:"few",MANY:"many",OTHER:"other"};t.value("$locale",{DATETIME_FORMATS:{AMPMS:["AM","PM"],DAY:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],ERANAMES:["Before Christ","Anno Domini"],ERAS:["BC","AD"],FIRSTDAYOFWEEK:6,MONTH:["January","February","March","April","May","June","July","August","September","October","November","December"],SHORTDAY:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],SHORTMONTH:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],WEEKENDRANGE:[5,6],fullDate:"EEEE, MMMM d, y",longDate:"MMMM d, y",medium:"MMM d, y h:mm:ss a",mediumDate:"MMM d, y",mediumTime:"h:mm:ss a","short":"M/d/yy h:mm a",shortDate:"M/d/yy",shortTime:"h:mm a"},NUMBER_FORMATS:{CURRENCY_SYM:"$",DECIMAL_SEP:".",GROUP_SEP:",",PATTERNS:[{gSize:3,lgSize:3,maxFrac:3,minFrac:0,minInt:1,negPre:"-",negSuf:"",posPre:"",posSuf:""},{gSize:3,lgSize:3,maxFrac:2,minFrac:2,minInt:1,negPre:"-¤",negSuf:"",posPre:"¤",posSuf:""}]},id:"en-us",pluralCat:function(t,n){var e=0|t,o=r(t,n);return 1==e&&0==o.v?i.ONE:i.OTHER}})}]),void Mr(n).ready(function(){ot(n,at)}))}(window,document),!window.angular.$$csp().noInlineStyle&&window.angular.element(document.head).prepend('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide:not(.ng-hide-animate){display:none !important;}ng\\:form{display:block;}.ng-animate-shim{visibility:hidden;}.ng-anchor{position:absolute;}</style>'),"undefined"!=typeof module&&"undefined"!=typeof exports&&module.exports===exports&&(module.exports="ui.router"),function(t,n,e){"use strict";function r(t,n){return I(new(I(function(){},{prototype:t})),n)}function i(t){return F(arguments,function(n){n!==t&&F(n,function(n,e){t.hasOwnProperty(e)||(t[e]=n)})}),t}function o(t,n){var e=[];for(var r in t.path){if(t.path[r]!==n.path[r])break;e.push(t.path[r])}return e}function a(t){if(Object.keys)return Object.keys(t);var n=[];return F(t,function(t,e){n.push(e)}),n}function u(t,n){if(Array.prototype.indexOf)return t.indexOf(n,Number(arguments[2])||0);var e=t.length>>>0,r=Number(arguments[2])||0;for(r=0>r?Math.ceil(r):Math.floor(r),0>r&&(r+=e);e>r;r++)if(r in t&&t[r]===n)return r;return-1}function s(t,n,e,r){var i,s=o(e,r),l={},c=[];for(var f in s)if(s[f].params&&(i=a(s[f].params),i.length))for(var h in i)u(c,i[h])>=0||(c.push(i[h]),l[i[h]]=t[i[h]]);return I({},l,n)}function l(t,n,e){if(!e){e=[];for(var r in t)e.push(r)}for(var i=0;i<e.length;i++){var o=e[i];if(t[o]!=n[o])return!1}return!0}function c(t,n){var e={};return F(t,function(t){e[t]=n[t]}),e}function f(t){var n={},e=Array.prototype.concat.apply(Array.prototype,Array.prototype.slice.call(arguments,1));return F(e,function(e){e in t&&(n[e]=t[e])}),n}function h(t){var n={},e=Array.prototype.concat.apply(Array.prototype,Array.prototype.slice.call(arguments,1));for(var r in t)-1==u(e,r)&&(n[r]=t[r]);return n}function p(t,n){var e=D(t),r=e?[]:{};return F(t,function(t,i){n(t,i)&&(r[e?r.length:i]=t)}),r}function d(t,n){var e=D(t)?[]:{};return F(t,function(t,r){e[r]=n(t,r)}),e}function v(t,n){var r=1,o=2,s={},l=[],c=s,f=I(t.when(s),{$$promises:s,$$values:s});this.study=function(s){function p(t,e){if(y[e]!==o){if(m.push(e),y[e]===r)throw m.splice(0,u(m,e)),new Error("Cyclic dependency: "+m.join(" -> "));if(y[e]=r,N(t))g.push(e,[function(){return n.get(t)}],l);else{var i=n.annotate(t);F(i,function(t){t!==e&&s.hasOwnProperty(t)&&p(s[t],t)}),g.push(e,t,i)}m.pop(),y[e]=o}}function d(t){return R(t)&&t.then&&t.$$promises}if(!R(s))throw new Error("'invocables' must be an object");var v=a(s||{}),g=[],m=[],y={};return F(s,p),s=m=y=null,function(r,o,a){function u(){--x||(b||i($,o.$$values),m.$$values=$,m.$$promises=m.$$promises||!0,delete m.$$inheritedValues,p.resolve($))}function s(t){m.$$failure=t,p.reject(t)}function l(e,i,o){function l(t){f.reject(t),s(t)}function c(){if(!L(m.$$failure))try{f.resolve(n.invoke(i,a,$)),f.promise.then(function(t){$[e]=t,u()},l)}catch(t){l(t)}}var f=t.defer(),h=0;F(o,function(t){y.hasOwnProperty(t)&&!r.hasOwnProperty(t)&&(h++,y[t].then(function(n){$[t]=n,--h||c()},l))}),h||c(),y[e]=f.promise}if(d(r)&&a===e&&(a=o,o=r,r=null),r){if(!R(r))throw new Error("'locals' must be an object")}else r=c;if(o){if(!d(o))throw new Error("'parent' must be a promise returned by $resolve.resolve()")}else o=f;var p=t.defer(),m=p.promise,y=m.$$promises={},$=I({},r),x=1+g.length/3,b=!1;if(L(o.$$failure))return s(o.$$failure),m;o.$$inheritedValues&&i($,h(o.$$inheritedValues,v)),I(y,o.$$promises),o.$$values?(b=i($,h(o.$$values,v)),m.$$inheritedValues=h(o.$$values,v),u()):(o.$$inheritedValues&&(m.$$inheritedValues=h(o.$$inheritedValues,v)),o.then(u,s));for(var w=0,C=g.length;C>w;w+=3)r.hasOwnProperty(g[w])?u():l(g[w],g[w+1],g[w+2]);return m}},this.resolve=function(t,n,e,r){return this.study(t)(n,e,r)}}function g(t,n,e){this.fromConfig=function(t,n,e){return L(t.template)?this.fromString(t.template,n):L(t.templateUrl)?this.fromUrl(t.templateUrl,n):L(t.templateProvider)?this.fromProvider(t.templateProvider,n,e):null},this.fromString=function(t,n){return j(t)?t(n):t},this.fromUrl=function(e,r){return j(e)&&(e=e(r)),null==e?null:t.get(e,{cache:n,headers:{Accept:"text/html"}}).then(function(t){return t.data})},this.fromProvider=function(t,n,r){return e.invoke(t,null,r||{params:n})}}function m(t,n,i){function o(n,e,r,i){if(g.push(n),d[n])return d[n];if(!/^\w+(-+\w+)*(?:\[\])?$/.test(n))throw new Error("Invalid parameter name '"+n+"' in pattern '"+t+"'");if(v[n])throw new Error("Duplicate parameter name '"+n+"' in pattern '"+t+"'");
+return v[n]=new q.Param(n,e,r,i),v[n]}function a(t,n,e,r){var i=["",""],o=t.replace(/[\\\[\]\^$*+?.()|{}]/g,"\\$&");if(!n)return o;switch(e){case!1:i=["(",")"+(r?"?":"")];break;case!0:i=["?(",")?"];break;default:i=["("+e+"|",")?"]}return o+i[0]+n+i[1]}function u(i,o){var a,u,s,l,c;return a=i[2]||i[3],c=n.params[a],s=t.substring(h,i.index),u=o?i[4]:i[4]||("*"==i[1]?".*":null),l=q.type(u||"string")||r(q.type("string"),{pattern:new RegExp(u,n.caseInsensitive?"i":e)}),{id:a,regexp:u,segment:s,type:l,cfg:c}}n=I({params:{}},R(n)?n:{});var s,l=/([:*])([\w\[\]]+)|\{([\w\[\]]+)(?:\:((?:[^{}\\]+|\\.|\{(?:[^{}\\]+|\\.)*\})+))?\}/g,c=/([:]?)([\w\[\]-]+)|\{([\w\[\]-]+)(?:\:((?:[^{}\\]+|\\.|\{(?:[^{}\\]+|\\.)*\})+))?\}/g,f="^",h=0,p=this.segments=[],d=i?i.params:{},v=this.params=i?i.params.$$new():new q.ParamSet,g=[];this.source=t;for(var m,y,$;(s=l.exec(t))&&(m=u(s,!1),!(m.segment.indexOf("?")>=0));)y=o(m.id,m.type,m.cfg,"path"),f+=a(m.segment,y.type.pattern.source,y.squash,y.isOptional),p.push(m.segment),h=l.lastIndex;$=t.substring(h);var x=$.indexOf("?");if(x>=0){var b=this.sourceSearch=$.substring(x);if($=$.substring(0,x),this.sourcePath=t.substring(0,h+x),b.length>0)for(h=0;s=c.exec(b);)m=u(s,!0),y=o(m.id,m.type,m.cfg,"search"),h=l.lastIndex}else this.sourcePath=t,this.sourceSearch="";f+=a($)+(n.strict===!1?"/?":"")+"$",p.push($),this.regexp=new RegExp(f,n.caseInsensitive?"i":e),this.prefix=p[0],this.$$paramNames=g}function y(t){I(this,t)}function $(){function t(t){return null!=t?t.toString().replace(/\//g,"%2F"):t}function i(t){return null!=t?t.toString().replace(/%2F/g,"/"):t}function o(){return{strict:v,caseInsensitive:h}}function s(t){return j(t)||D(t)&&j(t[t.length-1])}function l(){for(;w.length;){var t=w.shift();if(t.pattern)throw new Error("You cannot override a type's .pattern at runtime.");n.extend(x[t.name],f.invoke(t.def))}}function c(t){I(this,t||{})}q=this;var f,h=!1,v=!0,g=!1,x={},b=!0,w=[],C={string:{encode:t,decode:i,is:function(t){return null==t||!L(t)||"string"==typeof t},pattern:/[^\/]*/},"int":{encode:t,decode:function(t){return parseInt(t,10)},is:function(t){return L(t)&&this.decode(t.toString())===t},pattern:/\d+/},bool:{encode:function(t){return t?1:0},decode:function(t){return 0!==parseInt(t,10)},is:function(t){return t===!0||t===!1},pattern:/0|1/},date:{encode:function(t){return this.is(t)?[t.getFullYear(),("0"+(t.getMonth()+1)).slice(-2),("0"+t.getDate()).slice(-2)].join("-"):e},decode:function(t){if(this.is(t))return t;var n=this.capture.exec(t);return n?new Date(n[1],n[2]-1,n[3]):e},is:function(t){return t instanceof Date&&!isNaN(t.valueOf())},equals:function(t,n){return this.is(t)&&this.is(n)&&t.toISOString()===n.toISOString()},pattern:/[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[1-2][0-9]|3[0-1])/,capture:/([0-9]{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])/},json:{encode:n.toJson,decode:n.fromJson,is:n.isObject,equals:n.equals,pattern:/[^\/]*/},any:{encode:n.identity,decode:n.identity,equals:n.equals,pattern:/.*/}};$.$$getDefaultValue=function(t){if(!s(t.value))return t.value;if(!f)throw new Error("Injectable functions cannot be called at configuration time");return f.invoke(t.value)},this.caseInsensitive=function(t){return L(t)&&(h=t),h},this.strictMode=function(t){return L(t)&&(v=t),v},this.defaultSquashPolicy=function(t){if(!L(t))return g;if(t!==!0&&t!==!1&&!N(t))throw new Error("Invalid squash policy: "+t+". Valid policies: false, true, arbitrary-string");return g=t,t},this.compile=function(t,n){return new m(t,I(o(),n))},this.isMatcher=function(t){if(!R(t))return!1;var n=!0;return F(m.prototype,function(e,r){j(e)&&(n=n&&L(t[r])&&j(t[r]))}),n},this.type=function(t,n,e){if(!L(n))return x[t];if(x.hasOwnProperty(t))throw new Error("A type named '"+t+"' has already been defined.");return x[t]=new y(I({name:t},n)),e&&(w.push({name:t,def:e}),b||l()),this},F(C,function(t,n){x[n]=new y(I({name:n},t))}),x=r(x,{}),this.$get=["$injector",function(t){return f=t,b=!1,l(),F(C,function(t,n){x[n]||(x[n]=new y(t))}),this}],this.Param=function(t,n,r,i){function o(t){var n=R(t)?a(t):[],e=-1===u(n,"value")&&-1===u(n,"type")&&-1===u(n,"squash")&&-1===u(n,"array");return e&&(t={value:t}),t.$$fn=s(t.value)?t.value:function(){return t.value},t}function l(n,e,r){if(n.type&&e)throw new Error("Param '"+t+"' has two type configurations.");return e?e:n.type?n.type instanceof y?n.type:new y(n.type):"config"===r?x.any:x.string}function c(){var n={array:"search"===i?"auto":!1},e=t.match(/\[\]$/)?{array:!0}:{};return I(n,e,r).array}function h(t,n){var e=t.squash;if(!n||e===!1)return!1;if(!L(e)||null==e)return g;if(e===!0||N(e))return e;throw new Error("Invalid squash policy: '"+e+"'. Valid policies: false, true, or arbitrary string")}function v(t,n,r,i){var o,a,s=[{from:"",to:r||n?e:""},{from:null,to:r||n?e:""}];return o=D(t.replace)?t.replace:[],N(i)&&o.push({from:i,to:e}),a=d(o,function(t){return t.from}),p(s,function(t){return-1===u(a,t.from)}).concat(o)}function m(){if(!f)throw new Error("Injectable functions cannot be called at configuration time");var t=f.invoke(r.$$fn);if(null!==t&&t!==e&&!w.type.is(t))throw new Error("Default value ("+t+") for parameter '"+w.id+"' is not an instance of Type ("+w.type.name+")");return t}function $(t){function n(t){return function(n){return n.from===t}}function e(t){var e=d(p(w.replace,n(t)),function(t){return t.to});return e.length?e[0]:t}return t=e(t),L(t)?w.type.$normalize(t):m()}function b(){return"{Param:"+t+" "+n+" squash: '"+_+"' optional: "+S+"}"}var w=this;r=o(r),n=l(r,n,i);var C=c();n=C?n.$asArray(C,"search"===i):n,"string"!==n.name||C||"path"!==i||r.value!==e||(r.value="");var S=r.value!==e,_=h(r,S),M=v(r,C,S,_);I(this,{id:t,type:n,location:i,array:C,squash:_,replace:M,isOptional:S,value:$,dynamic:e,config:r,toString:b})},c.prototype={$$new:function(){return r(this,I(new c,{$$parent:this}))},$$keys:function(){for(var t=[],n=[],e=this,r=a(c.prototype);e;)n.push(e),e=e.$$parent;return n.reverse(),F(n,function(n){F(a(n),function(n){-1===u(t,n)&&-1===u(r,n)&&t.push(n)})}),t},$$values:function(t){var n={},e=this;return F(e.$$keys(),function(r){n[r]=e[r].value(t&&t[r])}),n},$$equals:function(t,n){var e=!0,r=this;return F(r.$$keys(),function(i){var o=t&&t[i],a=n&&n[i];r[i].type.equals(o,a)||(e=!1)}),e},$$validates:function(t){var r,i,o,a,u,s=this.$$keys();for(r=0;r<s.length&&(i=this[s[r]],o=t[s[r]],o!==e&&null!==o||!i.isOptional);r++){if(a=i.type.$normalize(o),!i.type.is(a))return!1;if(u=i.type.encode(a),n.isString(u)&&!i.type.pattern.exec(u))return!1}return!0},$$parent:e},this.ParamSet=c}function x(t,r){function i(t){var n=/^\^((?:\\[^a-zA-Z0-9]|[^\\\[\]\^$*+?.()|{}]+)*)/.exec(t.source);return null!=n?n[1].replace(/\\(.)/g,"$1"):""}function o(t,n){return t.replace(/\$(\$|\d{1,2})/,function(t,e){return n["$"===e?0:Number(e)]})}function a(t,n,e){if(!e)return!1;var r=t.invoke(n,n,{$match:e});return L(r)?r:!0}function u(r,i,o,a){function u(t,n,e){return"/"===v?t:n?v.slice(0,-1)+t:e?v.slice(1)+t:t}function h(t){function n(t){var n=t(o,r);return n?(N(n)&&r.replace().url(n),!0):!1}if(!t||!t.defaultPrevented){d&&r.url()===d;d=e;var i,a=l.length;for(i=0;a>i;i++)if(n(l[i]))return;c&&n(c)}}function p(){return s=s||i.$on("$locationChangeSuccess",h)}var d,v=a.baseHref(),g=r.url();return f||p(),{sync:function(){h()},listen:function(){return p()},update:function(t){return t?void(g=r.url()):void(r.url()!==g&&(r.url(g),r.replace()))},push:function(t,n,i){var o=t.format(n||{});null!==o&&n&&n["#"]&&(o+="#"+n["#"]),r.url(o),d=i&&i.$$avoidResync?r.url():e,i&&i.replace&&r.replace()},href:function(e,i,o){if(!e.validates(i))return null;var a=t.html5Mode();n.isObject(a)&&(a=a.enabled);var s=e.format(i);if(o=o||{},a||null===s||(s="#"+t.hashPrefix()+s),null!==s&&i&&i["#"]&&(s+="#"+i["#"]),s=u(s,a,o.absolute),!o.absolute||!s)return s;var l=!a&&s?"/":"",c=r.port();return c=80===c||443===c?"":":"+c,[r.protocol(),"://",r.host(),c,l,s].join("")}}}var s,l=[],c=null,f=!1;this.rule=function(t){if(!j(t))throw new Error("'rule' must be a function");return l.push(t),this},this.otherwise=function(t){if(N(t)){var n=t;t=function(){return n}}else if(!j(t))throw new Error("'rule' must be a function");return c=t,this},this.when=function(t,n){var e,u=N(n);if(N(t)&&(t=r.compile(t)),!u&&!j(n)&&!D(n))throw new Error("invalid 'handler' in when()");var s={matcher:function(t,n){return u&&(e=r.compile(n),n=["$match",function(t){return e.format(t)}]),I(function(e,r){return a(e,n,t.exec(r.path(),r.search()))},{prefix:N(t.prefix)?t.prefix:""})},regex:function(t,n){if(t.global||t.sticky)throw new Error("when() RegExp must not be global or sticky");return u&&(e=n,n=["$match",function(t){return o(e,t)}]),I(function(e,r){return a(e,n,t.exec(r.path()))},{prefix:i(t)})}},l={matcher:r.isMatcher(t),regex:t instanceof RegExp};for(var c in l)if(l[c])return this.rule(s[c](t,n));throw new Error("invalid 'what' in when()")},this.deferIntercept=function(t){t===e&&(t=!0),f=t},this.$get=u,u.$inject=["$location","$rootScope","$injector","$browser"]}function b(t,i){function o(t){return 0===t.indexOf(".")||0===t.indexOf("^")}function h(t,n){if(!t)return e;var r=N(t),i=r?t:t.name,a=o(i);if(a){if(!n)throw new Error("No reference point given for path '"+i+"'");n=h(n);for(var u=i.split("."),s=0,l=u.length,c=n;l>s;s++)if(""!==u[s]||0!==s){if("^"!==u[s])break;if(!c.parent)throw new Error("Path '"+i+"' not valid for state '"+n.name+"'");c=c.parent}else c=n;u=u.slice(s).join("."),i=c.name+(c.name&&u?".":"")+u}var f=_[i];return!f||!r&&(r||f!==t&&f.self!==t)?e:f}function p(t,n){M[t]||(M[t]=[]),M[t].push(n)}function v(t){for(var n=M[t]||[];n.length;)g(n.shift())}function g(n){n=r(n,{self:n,resolve:n.resolve||{},toString:function(){return this.name}});var e=n.name;if(!N(e)||e.indexOf("@")>=0)throw new Error("State must have a valid name");if(_.hasOwnProperty(e))throw new Error("State '"+e+"'' is already defined");var i=-1!==e.indexOf(".")?e.substring(0,e.lastIndexOf(".")):N(n.parent)?n.parent:R(n.parent)&&N(n.parent.name)?n.parent.name:"";if(i&&!_[i])return p(i,n.self);for(var o in A)j(A[o])&&(n[o]=A[o](n,A.$delegates[o]));return _[e]=n,!n[k]&&n.url&&t.when(n.url,["$match","$stateParams",function(t,e){S.$current.navigable==n&&l(t,e)||S.transitionTo(n,t,{inherit:!0,location:!1})}]),v(e),n}function m(t){return t.indexOf("*")>-1}function y(t){for(var n=t.split("."),e=S.$current.name.split("."),r=0,i=n.length;i>r;r++)"*"===n[r]&&(e[r]="*");return"**"===n[0]&&(e=e.slice(u(e,n[1])),e.unshift("**")),"**"===n[n.length-1]&&(e.splice(u(e,n[n.length-2])+1,Number.MAX_VALUE),e.push("**")),n.length!=e.length?!1:e.join("")===n.join("")}function $(t,n){return N(t)&&!L(n)?A[t]:j(n)&&N(t)?(A[t]&&!A.$delegates[t]&&(A.$delegates[t]=A[t]),A[t]=n,this):this}function x(t,n){return R(t)?n=t:n.name=t,g(n),this}function b(t,i,o,u,f,p,v,g,$){function x(n,e,r,o){var a=t.$broadcast("$stateNotFound",n,e,r);if(a.defaultPrevented)return v.update(),E;if(!a.retry)return null;if(o.$retry)return v.update(),P;var u=S.transition=i.when(a.retry);return u.then(function(){return u!==S.transition?M:(n.options.$retry=!0,S.transitionTo(n.to,n.toParams,n.options))},function(){return E}),v.update(),u}function b(t,e,r,a,s,l){function h(){var e=[];return F(t.views,function(r,i){var a=r.resolve&&r.resolve!==t.resolve?r.resolve:{};a.$template=[function(){return o.load(i,{view:r,locals:s.globals,params:p,notify:l.notify})||""}],e.push(f.resolve(a,s.globals,s.resolve,t).then(function(e){if(j(r.controllerProvider)||D(r.controllerProvider)){var o=n.extend({},a,s.globals);e.$$controller=u.invoke(r.controllerProvider,null,o)}else e.$$controller=r.controller;e.$$state=t,e.$$controllerAs=r.controllerAs,s[i]=e}))}),i.all(e).then(function(){return s.globals})}var p=r?e:c(t.params.$$keys(),e),d={$stateParams:p};s.resolve=f.resolve(t.resolve,d,s.resolve,t);var v=[s.resolve.then(function(t){s.globals=t})];return a&&v.push(a),i.all(v).then(h).then(function(t){return s})}var M=i.reject(new Error("transition superseded")),A=i.reject(new Error("transition prevented")),E=i.reject(new Error("transition aborted")),P=i.reject(new Error("transition failed"));return C.locals={resolve:null,globals:{$stateParams:{}}},S={params:{},current:C.self,$current:C,transition:null},S.reload=function(t){return S.transitionTo(S.current,p,{reload:t||!0,inherit:!1,notify:!0})},S.go=function(t,n,e){return S.transitionTo(t,n,I({inherit:!0,relative:S.$current},e))},S.transitionTo=function(n,e,o){e=e||{},o=I({location:!0,inherit:!1,relative:null,notify:!0,reload:!1,$retry:!1},o||{});var a,l=S.$current,f=S.params,d=l.path,g=h(n,o.relative),m=e["#"];if(!L(g)){var y={to:n,toParams:e,options:o},$=x(y,l.self,f,o);if($)return $;if(n=y.to,e=y.toParams,o=y.options,g=h(n,o.relative),!L(g)){if(!o.relative)throw new Error("No such state '"+n+"'");throw new Error("Could not resolve '"+n+"' from state '"+o.relative+"'")}}if(g[k])throw new Error("Cannot transition to abstract state '"+n+"'");if(o.inherit&&(e=s(p,e||{},S.$current,g)),!g.params.$$validates(e))return P;e=g.params.$$values(e),n=g;var _=n.path,E=0,O=_[E],T=C.locals,j=[];if(o.reload){if(N(o.reload)||R(o.reload)){if(R(o.reload)&&!o.reload.name)throw new Error("Invalid reload state object");var D=o.reload===!0?d[0]:h(o.reload);if(o.reload&&!D)throw new Error("No such reload state '"+(N(o.reload)?o.reload:o.reload.name)+"'");for(;O&&O===d[E]&&O!==D;)T=j[E]=O.locals,E++,O=_[E]}}else for(;O&&O===d[E]&&O.ownParams.$$equals(e,f);)T=j[E]=O.locals,E++,O=_[E];if(w(n,e,l,f,T,o))return m&&(e["#"]=m),S.params=e,z(S.params,p),o.location&&n.navigable&&n.navigable.url&&(v.push(n.navigable.url,e,{$$avoidResync:!0,replace:"replace"===o.location}),v.update(!0)),S.transition=null,i.when(S.current);if(e=c(n.params.$$keys(),e||{}),o.notify&&t.$broadcast("$stateChangeStart",n.self,e,l.self,f).defaultPrevented)return t.$broadcast("$stateChangeCancel",n.self,e,l.self,f),v.update(),A;for(var F=i.when(T),q=E;q<_.length;q++,O=_[q])T=j[q]=r(T),F=b(O,e,O===n,F,T,o);var V=S.transition=F.then(function(){var r,i,a;if(S.transition!==V)return M;for(r=d.length-1;r>=E;r--)a=d[r],a.self.onExit&&u.invoke(a.self.onExit,a.self,a.locals.globals),a.locals=null;for(r=E;r<_.length;r++)i=_[r],i.locals=j[r],i.self.onEnter&&u.invoke(i.self.onEnter,i.self,i.locals.globals);return m&&(e["#"]=m),S.transition!==V?M:(S.$current=n,S.current=n.self,S.params=e,z(S.params,p),S.transition=null,o.location&&n.navigable&&v.push(n.navigable.url,n.navigable.locals.globals.$stateParams,{$$avoidResync:!0,replace:"replace"===o.location}),o.notify&&t.$broadcast("$stateChangeSuccess",n.self,e,l.self,f),v.update(!0),S.current)},function(r){return S.transition!==V?M:(S.transition=null,a=t.$broadcast("$stateChangeError",n.self,e,l.self,f,r),a.defaultPrevented||v.update(),i.reject(r))});return V},S.is=function(t,n,r){r=I({relative:S.$current},r||{});var i=h(t,r.relative);return L(i)?S.$current!==i?!1:n?l(i.params.$$values(n),p):!0:e},S.includes=function(t,n,r){if(r=I({relative:S.$current},r||{}),N(t)&&m(t)){if(!y(t))return!1;t=S.$current.name}var i=h(t,r.relative);return L(i)?L(S.$current.includes[i.name])?n?l(i.params.$$values(n),p,a(n)):!0:!1:e},S.href=function(t,n,r){r=I({lossy:!0,inherit:!0,absolute:!1,relative:S.$current},r||{});var i=h(t,r.relative);if(!L(i))return null;r.inherit&&(n=s(p,n||{},S.$current,i));var o=i&&r.lossy?i.navigable:i;return o&&o.url!==e&&null!==o.url?v.href(o.url,c(i.params.$$keys().concat("#"),n||{}),{absolute:r.absolute}):null},S.get=function(t,n){if(0===arguments.length)return d(a(_),function(t){return _[t].self});var e=h(t,n||S.$current);return e&&e.self?e.self:null},S}function w(t,n,e,r,i,o){function a(t,n,e){function r(n){return"search"!=t.params[n].location}var i=t.params.$$keys().filter(r),o=f.apply({},[t.params].concat(i)),a=new q.ParamSet(o);return a.$$equals(n,e)}return!o.reload&&t===e&&(i===e.locals||t.self.reloadOnSearch===!1&&a(e,r,n))?!0:void 0}var C,S,_={},M={},k="abstract",A={parent:function(t){if(L(t.parent)&&t.parent)return h(t.parent);var n=/^(.+)\.[^.]+$/.exec(t.name);return n?h(n[1]):C},data:function(t){return t.parent&&t.parent.data&&(t.data=t.self.data=I({},t.parent.data,t.data)),t.data},url:function(t){var n=t.url,e={params:t.params||{}};if(N(n))return"^"==n.charAt(0)?i.compile(n.substring(1),e):(t.parent.navigable||C).url.concat(n,e);if(!n||i.isMatcher(n))return n;throw new Error("Invalid url '"+n+"' in state '"+t+"'")},navigable:function(t){return t.url?t:t.parent?t.parent.navigable:null},ownParams:function(t){var n=t.url&&t.url.params||new q.ParamSet;return F(t.params||{},function(t,e){n[e]||(n[e]=new q.Param(e,null,t,"config"))}),n},params:function(t){return t.parent&&t.parent.params?I(t.parent.params.$$new(),t.ownParams):new q.ParamSet},views:function(t){var n={};return F(L(t.views)?t.views:{"":t},function(e,r){r.indexOf("@")<0&&(r+="@"+t.parent.name),n[r]=e}),n},path:function(t){return t.parent?t.parent.path.concat(t):[]},includes:function(t){var n=t.parent?I({},t.parent.includes):{};return n[t.name]=!0,n},$delegates:{}};C=g({name:"",url:"^",views:null,"abstract":!0}),C.navigable=null,this.decorator=$,this.state=x,this.$get=b,b.$inject=["$rootScope","$q","$view","$injector","$resolve","$stateParams","$urlRouter","$location","$urlMatcherFactory"]}function w(){function t(t,n){return{load:function(e,r){var i,o={template:null,controller:null,view:null,locals:null,notify:!0,async:!0,params:{}};return r=I(o,r),r.view&&(i=n.fromConfig(r.view,r.params,r.locals)),i&&r.notify&&t.$broadcast("$viewContentLoading",r),i}}}this.$get=t,t.$inject=["$rootScope","$templateFactory"]}function C(){var t=!1;this.useAnchorScroll=function(){t=!0},this.$get=["$anchorScroll","$timeout",function(n,e){return t?n:function(t){return e(function(){t[0].scrollIntoView()},0,!1)}}]}function S(t,e,r,i){function o(){return e.has?function(t){return e.has(t)?e.get(t):null}:function(t){try{return e.get(t)}catch(n){return null}}}function a(t,n){var e=function(){return{enter:function(t,n,e){n.after(t),e()},leave:function(t,n){t.remove(),n()}}};if(l)return{enter:function(t,n,e){var r=l.enter(t,null,n,e);r&&r.then&&r.then(e)},leave:function(t,n){var e=l.leave(t,n);e&&e.then&&e.then(n)}};if(s){var r=s&&s(n,t);return{enter:function(t,n,e){r.enter(t,null,n),e()},leave:function(t,n){r.leave(t),n()}}}return e()}var u=o(),s=u("$animator"),l=u("$animate"),c={restrict:"ECA",terminal:!0,priority:400,transclude:"element",compile:function(e,o,u){return function(e,o,s){function l(){f&&(f.remove(),f=null),p&&(p.$destroy(),p=null),h&&(m.leave(h,function(){f=null}),f=h,h=null)}function c(a){var c,f=M(e,s,o,i),y=f&&t.$current&&t.$current.locals[f];if(a||y!==d){c=e.$new(),d=t.$current.locals[f];var $=u(c,function(t){m.enter(t,o,function(){p&&p.$emit("$viewContentAnimationEnded"),(n.isDefined(g)&&!g||e.$eval(g))&&r(t)}),l()});h=$,p=c,p.$emit("$viewContentLoaded"),p.$eval(v)}}var f,h,p,d,v=s.onload||"",g=s.autoscroll,m=a(s,e);e.$on("$stateChangeSuccess",function(){c(!1)}),e.$on("$viewContentLoading",function(){c(!1)}),c(!0)}}};return c}function _(t,n,e,r){return{restrict:"ECA",priority:-400,compile:function(i){var o=i.html();return function(i,a,u){var s=e.$current,l=M(i,u,a,r),c=s&&s.locals[l];if(c){a.data("$uiView",{name:l,state:c.$$state}),a.html(c.$template?c.$template:o);var f=t(a.contents());if(c.$$controller){c.$scope=i,c.$element=a;var h=n(c.$$controller,c);c.$$controllerAs&&(i[c.$$controllerAs]=h),a.data("$ngControllerController",h),a.children().data("$ngControllerController",h)}f(i)}}}}}function M(t,n,e,r){var i=r(n.uiView||n.name||"")(t),o=e.inheritedData("$uiView");return i.indexOf("@")>=0?i:i+"@"+(o?o.state.name:"")}function k(t,n){var e,r=t.match(/^\s*({[^}]*})\s*$/);if(r&&(t=n+"("+r[1]+")"),e=t.replace(/\n/g," ").match(/^([^(]+?)\s*(\((.*)\))?$/),!e||4!==e.length)throw new Error("Invalid state ref '"+t+"'");return{state:e[1],paramExpr:e[3]||null}}function A(t){var n=t.parent().inheritedData("$uiView");return n&&n.state&&n.state.name?n.state:void 0}function E(t,e){var r=["location","inherit","reload","absolute"];return{restrict:"A",require:["?^uiSrefActive","?^uiSrefActiveEq"],link:function(i,o,a,u){var s=k(a.uiSref,t.current.name),l=null,c=A(o)||t.$current,f="[object SVGAnimatedString]"===Object.prototype.toString.call(o.prop("href"))?"xlink:href":"href",h=null,p="A"===o.prop("tagName").toUpperCase(),d="FORM"===o[0].nodeName,v=d?"action":f,g=!0,m={relative:c,inherit:!0},y=i.$eval(a.uiSrefOpts)||{};n.forEach(r,function(t){t in y&&(m[t]=y[t])});var $=function(e){if(e&&(l=n.copy(e)),g){h=t.href(s.state,l,m);var r=u[1]||u[0];return r&&r.$$addStateInfo(s.state,l),null===h?(g=!1,!1):void a.$set(v,h)}};s.paramExpr&&(i.$watch(s.paramExpr,function(t,n){t!==l&&$(t)},!0),l=n.copy(i.$eval(s.paramExpr))),$(),d||o.bind("click",function(n){var r=n.which||n.button;if(!(r>1||n.ctrlKey||n.metaKey||n.shiftKey||o.attr("target"))){var i=e(function(){t.go(s.state,l,m)});n.preventDefault();var a=p&&!h?1:0;n.preventDefault=function(){a--<=0&&e.cancel(i)}}})}}}function P(t,n,e){return{restrict:"A",controller:["$scope","$element","$attrs",function(n,r,i){function o(){a()?r.addClass(s):r.removeClass(s)}function a(){for(var t=0;t<l.length;t++)if(u(l[t].state,l[t].params))return!0;return!1}function u(n,e){return"undefined"!=typeof i.uiSrefActiveEq?t.is(n.name,e):t.includes(n.name,e)}var s,l=[];s=e(i.uiSrefActiveEq||i.uiSrefActive||"",!1)(n),this.$$addStateInfo=function(n,e){var i=t.get(n,A(r));l.push({state:i||{name:n},params:e}),o()},n.$on("$stateChangeSuccess",o)}]}}function O(t){var n=function(n){return t.is(n)};return n.$stateful=!0,n}function T(t){var n=function(n){return t.includes(n)};return n.$stateful=!0,n}var L=n.isDefined,j=n.isFunction,N=n.isString,R=n.isObject,D=n.isArray,F=n.forEach,I=n.extend,z=n.copy;n.module("ui.router.util",["ng"]),n.module("ui.router.router",["ui.router.util"]),n.module("ui.router.state",["ui.router.router","ui.router.util"]),n.module("ui.router",["ui.router.state"]),n.module("ui.router.compat",["ui.router"]),v.$inject=["$q","$injector"],n.module("ui.router.util").service("$resolve",v),g.$inject=["$http","$templateCache","$injector"],n.module("ui.router.util").service("$templateFactory",g);var q;m.prototype.concat=function(t,n){var e={caseInsensitive:q.caseInsensitive(),strict:q.strictMode(),squash:q.defaultSquashPolicy()};return new m(this.sourcePath+t+this.sourceSearch,I(e,n),this)},m.prototype.toString=function(){return this.source},m.prototype.exec=function(t,n){function e(t){function n(t){return t.split("").reverse().join("")}function e(t){return t.replace(/\\-/g,"-")}var r=n(t).split(/-(?!\\)/),i=d(r,n);return d(i,e).reverse()}var r=this.regexp.exec(t);if(!r)return null;n=n||{};var i,o,a,u=this.parameters(),s=u.length,l=this.segments.length-1,c={};if(l!==r.length-1)throw new Error("Unbalanced capture group in route '"+this.source+"'");for(i=0;l>i;i++){a=u[i];var f=this.params[a],h=r[i+1];for(o=0;o<f.replace;o++)f.replace[o].from===h&&(h=f.replace[o].to);h&&f.array===!0&&(h=e(h)),c[a]=f.value(h)}for(;s>i;i++)a=u[i],c[a]=this.params[a].value(n[a]);return c},m.prototype.parameters=function(t){return L(t)?this.params[t]||null:this.$$paramNames},m.prototype.validates=function(t){return this.params.$$validates(t)},m.prototype.format=function(t){function n(t){return encodeURIComponent(t).replace(/-/g,function(t){return"%5C%"+t.charCodeAt(0).toString(16).toUpperCase()})}t=t||{};var e=this.segments,r=this.parameters(),i=this.params;if(!this.validates(t))return null;var o,a=!1,u=e.length-1,s=r.length,l=e[0];for(o=0;s>o;o++){var c=u>o,f=r[o],h=i[f],p=h.value(t[f]),v=h.isOptional&&h.type.equals(h.value(),p),g=v?h.squash:!1,m=h.type.encode(p);if(c){var y=e[o+1];if(g===!1)null!=m&&(l+=D(m)?d(m,n).join("-"):encodeURIComponent(m)),l+=y;else if(g===!0){var $=l.match(/\/$/)?/\/?(.*)/:/(.*)/;l+=y.match($)[1]}else N(g)&&(l+=g+y)}else{if(null==m||v&&g!==!1)continue;D(m)||(m=[m]),m=d(m,encodeURIComponent).join("&"+f+"="),l+=(a?"&":"?")+(f+"="+m),a=!0}}return l},y.prototype.is=function(t,n){return!0},y.prototype.encode=function(t,n){return t},y.prototype.decode=function(t,n){return t},y.prototype.equals=function(t,n){return t==n},y.prototype.$subPattern=function(){var t=this.pattern.toString();return t.substr(1,t.length-2)},y.prototype.pattern=/.*/,y.prototype.toString=function(){return"{Type:"+this.name+"}"},y.prototype.$normalize=function(t){return this.is(t)?t:this.decode(t)},y.prototype.$asArray=function(t,n){function r(t,n){function r(t,n){return function(){return t[n].apply(t,arguments)}}function i(t){return D(t)?t:L(t)?[t]:[]}function o(t){switch(t.length){case 0:return e;case 1:return"auto"===n?t[0]:t;default:return t}}function a(t){return!t}function u(t,n){return function(e){e=i(e);var r=d(e,t);return n===!0?0===p(r,a).length:o(r)}}function s(t){return function(n,e){var r=i(n),o=i(e);if(r.length!==o.length)return!1;for(var a=0;a<r.length;a++)if(!t(r[a],o[a]))return!1;return!0}}this.encode=u(r(t,"encode")),this.decode=u(r(t,"decode")),this.is=u(r(t,"is"),!0),this.equals=s(r(t,"equals")),this.pattern=t.pattern,this.$normalize=u(r(t,"$normalize")),this.name=t.name,this.$arrayMode=n}if(!t)return this;if("auto"===t&&!n)throw new Error("'auto' array mode is for query parameters only");return new r(this,t)},n.module("ui.router.util").provider("$urlMatcherFactory",$),n.module("ui.router.util").run(["$urlMatcherFactory",function(t){}]),x.$inject=["$locationProvider","$urlMatcherFactoryProvider"],n.module("ui.router.router").provider("$urlRouter",x),b.$inject=["$urlRouterProvider","$urlMatcherFactoryProvider"],n.module("ui.router.state").value("$stateParams",{}).provider("$state",b),w.$inject=[],n.module("ui.router.state").provider("$view",w),n.module("ui.router.state").provider("$uiViewScroll",C),S.$inject=["$state","$injector","$uiViewScroll","$interpolate"],_.$inject=["$compile","$controller","$state","$interpolate"],n.module("ui.router.state").directive("uiView",S),n.module("ui.router.state").directive("uiView",_),E.$inject=["$state","$timeout"],P.$inject=["$state","$stateParams","$interpolate"],n.module("ui.router.state").directive("uiSref",E).directive("uiSrefActive",P).directive("uiSrefActiveEq",P),O.$inject=["$state"],T.$inject=["$state"],n.module("ui.router.state").filter("isState",O).filter("includedByState",T)}(window,window.angular),function(t,n,e){"use strict";function r(t){return null!=t&&""!==t&&"hasOwnProperty"!==t&&u.test("."+t)}function i(t,i){if(!r(i))throw a("badmember",'Dotted member path "@{0}" is invalid.',i);for(var o=i.split("."),u=0,s=o.length;s>u&&n.isDefined(t);u++){var l=o[u];t=null!==t?t[l]:e}return t}function o(t,e){e=e||{},n.forEach(e,function(t,n){delete e[n]});for(var r in t)!t.hasOwnProperty(r)||"$"===r.charAt(0)&&"$"===r.charAt(1)||(e[r]=t[r]);return e}var a=n.$$minErr("$resource"),u=/^(\.[a-zA-Z_$@][0-9a-zA-Z_$@]*)+$/;n.module("ngResource",["ng"]).provider("$resource",function(){var t=/^https?:\/\/[^\/]*/,r=this;this.defaults={stripTrailingSlashes:!0,actions:{get:{method:"GET"},save:{method:"POST"},query:{method:"GET",isArray:!0},remove:{method:"DELETE"},"delete":{method:"DELETE"}}},this.$get=["$http","$q",function(u,s){function l(t){return c(t,!0).replace(/%26/gi,"&").replace(/%3D/gi,"=").replace(/%2B/gi,"+")}function c(t,n){return encodeURIComponent(t).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,n?"%20":"+")}function f(t,n){this.template=t,this.defaults=v({},r.defaults,n),this.urlParams={}}function h(t,l,c,y){function $(t,n){var e={};return n=v({},l,n),d(n,function(n,r){m(n)&&(n=n()),e[r]=n&&n.charAt&&"@"==n.charAt(0)?i(t,n.substr(1)):n}),e}function x(t){return t.resource}function b(t){o(t||{},this)}var w=new f(t,y);return c=v({},r.defaults.actions,c),b.prototype.toJSON=function(){var t=v({},this);return delete t.$promise,delete t.$resolved,t},d(c,function(t,r){var i=/^(POST|PUT|PATCH)$/i.test(t.method);b[r]=function(l,c,f,h){var y,C,S,_={};switch(arguments.length){case 4:S=h,C=f;case 3:case 2:if(!m(c)){_=l,y=c,C=f;break}if(m(l)){C=l,S=c;break}C=c,S=f;case 1:m(l)?C=l:i?y=l:_=l;break;case 0:break;default:throw a("badargs","Expected up to 4 arguments [params, data, success, error], got {0} arguments",arguments.length)}var M=this instanceof b,k=M?y:t.isArray?[]:new b(y),A={},E=t.interceptor&&t.interceptor.response||x,P=t.interceptor&&t.interceptor.responseError||e;d(t,function(t,n){"params"!=n&&"isArray"!=n&&"interceptor"!=n&&(A[n]=g(t))}),i&&(A.data=y),w.setUrlParams(A,v({},$(y,t.params||{}),_),t.url);var O=u(A).then(function(e){var i=e.data,u=k.$promise;if(i){if(n.isArray(i)!==!!t.isArray)throw a("badcfg","Error in resource configuration for action `{0}`. Expected response to contain an {1} but got an {2} (Request: {3} {4})",r,t.isArray?"array":"object",n.isArray(i)?"array":"object",A.method,A.url);t.isArray?(k.length=0,d(i,function(t){"object"==typeof t?k.push(new b(t)):k.push(t)})):(o(i,k),k.$promise=u)}return k.$resolved=!0,e.resource=k,e},function(t){return k.$resolved=!0,(S||p)(t),s.reject(t)});return O=O.then(function(t){var n=E(t);return(C||p)(n,t.headers),n},P),M?O:(k.$promise=O,k.$resolved=!1,k)},b.prototype["$"+r]=function(t,n,e){m(t)&&(e=n,n=t,t={});var i=b[r].call(this,t,this,n,e);return i.$promise||i}}),b.bind=function(n){return h(t,v({},l,n),c)},b}var p=n.noop,d=n.forEach,v=n.extend,g=n.copy,m=n.isFunction;return f.prototype={setUrlParams:function(e,r,i){var o,u,s=this,c=i||s.template,f="",h=s.urlParams={};d(c.split(/\W/),function(t){if("hasOwnProperty"===t)throw a("badname","hasOwnProperty is not a valid parameter name.");!new RegExp("^\\d+$").test(t)&&t&&new RegExp("(^|[^\\\\]):"+t+"(\\W|$)").test(c)&&(h[t]=!0)}),c=c.replace(/\\:/g,":"),c=c.replace(t,function(t){return f=t,""}),r=r||{},d(s.urlParams,function(t,e){o=r.hasOwnProperty(e)?r[e]:s.defaults[e],n.isDefined(o)&&null!==o?(u=l(o),c=c.replace(new RegExp(":"+e+"(\\W|$)","g"),function(t,n){return u+n})):c=c.replace(new RegExp("(/?):"+e+"(\\W|$)","g"),function(t,n,e){return"/"==e.charAt(0)?e:n+e})}),s.defaults.stripTrailingSlashes&&(c=c.replace(/\/+$/,"")||"/"),c=c.replace(/\/\.(?=\w+($|\?))/,"."),e.url=f+c.replace(/\/\\\./,"/."),d(r,function(t,n){s.urlParams[n]||(e.params=e.params||{},e.params[n]=t)})}},h}]})}(window,window.angular),function(t,n,e){"use strict";function r(t,e,r){function i(t,r,i){var a,u;i=i||{},u=i.expires,a=n.isDefined(i.path)?i.path:o,n.isUndefined(r)&&(u="Thu, 01 Jan 1970 00:00:00 GMT",r=""),n.isString(u)&&(u=new Date(u));var s=encodeURIComponent(t)+"="+encodeURIComponent(r);s+=a?";path="+a:"",s+=i.domain?";domain="+i.domain:"",s+=u?";expires="+u.toUTCString():"",s+=i.secure?";secure":"";var l=s.length+1;return l>4096&&e.warn("Cookie '"+t+"' possibly not set or overflowed because it was too large ("+l+" > 4096 bytes)!"),s}var o=r.baseHref(),a=t[0];return function(t,n,e){a.cookie=i(t,n,e)}}n.module("ngCookies",["ng"]).provider("$cookies",[function(){function t(t){return t?n.extend({},r,t):r}var r=this.defaults={};this.$get=["$$cookieReader","$$cookieWriter",function(r,i){return{get:function(t){return r()[t]},getObject:function(t){var e=this.get(t);return e?n.fromJson(e):e},getAll:function(){return r()},put:function(n,e,r){i(n,e,t(r))},putObject:function(t,e,r){this.put(t,n.toJson(e),r)},remove:function(n,r){i(n,e,t(r))}}}]}]),n.module("ngCookies").factory("$cookieStore",["$cookies",function(t){return{get:function(n){return t.getObject(n)},put:function(n,e){t.putObject(n,e)},remove:function(n){t.remove(n)}}}]),r.$inject=["$document","$log","$browser"],n.module("ngCookies").provider("$$cookieWriter",function(){this.$get=r})}(window,window.angular),function(t,n,e){"use strict";function r(t,n,e){if(!t)throw ngMinErr("areq","Argument '{0}' is {1}",n||"?",e||"required");return t}function i(t,n){return t||n?t?n?(V(t)&&(t=t.join(" ")),V(n)&&(n=n.join(" ")),t+" "+n):t:n:""}function o(t){var n={};return t&&(t.to||t.from)&&(n.to=t.to,n.from=t.from),n}function a(t,n,e){var r="";return t=V(t)?t:t&&B(t)&&t.length?t.split(/\s+/):[],q(t,function(t,i){t&&t.length>0&&(r+=i>0?" ":"",r+=e?n+t:t+n)}),r}function u(t,n){var e=t.indexOf(n);n>=0&&t.splice(e,1)}function s(t){if(t instanceof z)switch(t.length){
+case 0:return[];case 1:if(t[0].nodeType===X)return t;break;default:return z(l(t))}return t.nodeType===X?z(t):void 0}function l(t){if(!t[0])return t;for(var n=0;n<t.length;n++){var e=t[n];if(e.nodeType==X)return e}}function c(t,n,e){q(n,function(n){t.addClass(n,e)})}function f(t,n,e){q(n,function(n){t.removeClass(n,e)})}function h(t){return function(n,e){e.addClass&&(c(t,n,e.addClass),e.addClass=null),e.removeClass&&(f(t,n,e.removeClass),e.removeClass=null)}}function p(t){if(t=t||{},!t.$$prepared){var n=t.domOperation||F;t.domOperation=function(){t.$$domOperationFired=!0,n(),n=F},t.$$prepared=!0}return t}function d(t,n){v(t,n),g(t,n)}function v(t,n){n.from&&(t.css(n.from),n.from=null)}function g(t,n){n.to&&(t.css(n.to),n.to=null)}function m(t,n,e){var r=(n.addClass||"")+" "+(e.addClass||""),i=(n.removeClass||"")+" "+(e.removeClass||""),o=y(t.attr("class"),r,i);e.preparationClasses&&(n.preparationClasses=_(e.preparationClasses,n.preparationClasses),delete e.preparationClasses);var a=n.domOperation!==F?n.domOperation:null;return I(n,e),a&&(n.domOperation=a),o.addClass?n.addClass=o.addClass:n.addClass=null,o.removeClass?n.removeClass=o.removeClass:n.removeClass=null,n}function y(t,n,e){function r(t){B(t)&&(t=t.split(" "));var n={};return q(t,function(t){t.length&&(n[t]=!0)}),n}var i=1,o=-1,a={};t=r(t),n=r(n),q(n,function(t,n){a[n]=i}),e=r(e),q(e,function(t,n){a[n]=a[n]===i?null:o});var u={addClass:"",removeClass:""};return q(a,function(n,e){var r,a;n===i?(r="addClass",a=!t[e]):n===o&&(r="removeClass",a=t[e]),a&&(u[r].length&&(u[r]+=" "),u[r]+=e)}),u}function $(t){return t instanceof n.element?t[0]:t}function x(t,n,e){var r="";n&&(r=a(n,K,!0)),e.addClass&&(r=_(r,a(e.addClass,Z))),e.removeClass&&(r=_(r,a(e.removeClass,J))),r.length&&(e.preparationClasses=r,t.addClass(r))}function b(t,n){n.preparationClasses&&(t.removeClass(n.preparationClasses),n.preparationClasses=null),n.activeClasses&&(t.removeClass(n.activeClasses),n.activeClasses=null)}function w(t,n){var e=n?"-"+n+"s":"";return S(t,[ht,e]),[ht,e]}function C(t,n){var e=n?"paused":"",r=R+st;return S(t,[r,e]),[r,e]}function S(t,n){var e=n[0],r=n[1];t.style[e]=r}function _(t,n){return t?n?t+" "+n:t:n}function M(t){return[ft,t+"s"]}function k(t,n){var e=n?ct:ht;return[e,t+"s"]}function A(t,n,e){var r=Object.create(null),i=t.getComputedStyle(n)||{};return q(e,function(t,n){var e=i[t];if(e){var o=e.charAt(0);("-"===o||"+"===o||o>=0)&&(e=E(e)),0===e&&(e=null),r[n]=e}}),r}function E(t){var n=0,e=t.split(/\s*,\s*/);return q(e,function(t){"s"==t.charAt(t.length-1)&&(t=t.substring(0,t.length-1)),t=parseFloat(t)||0,n=n?Math.max(t,n):t}),n}function P(t){return 0===t||null!=t}function O(t,n){var e=j,r=t+"s";return n?e+=rt:r+=" linear all",[e,r]}function T(){var t=Object.create(null);return{flush:function(){t=Object.create(null)},count:function(n){var e=t[n];return e?e.total:0},get:function(n){var e=t[n];return e&&e.value},put:function(n,e){t[n]?t[n].total++:t[n]={total:1,value:e}}}}function L(t,n,e){q(e,function(e){t[e]=H(t[e])?t[e]:n.style.getPropertyValue(e)})}var j,N,R,D,F=n.noop,I=n.extend,z=n.element,q=n.forEach,V=n.isArray,B=n.isString,W=n.isObject,U=n.isUndefined,H=n.isDefined,Y=n.isFunction,G=n.isElement,X=1,Z="-add",J="-remove",K="ng-",Q="-active",tt="ng-animate",nt="$$ngAnimateChildren",et="";U(t.ontransitionend)&&H(t.onwebkittransitionend)?(et="-webkit-",j="WebkitTransition",N="webkitTransitionEnd transitionend"):(j="transition",N="transitionend"),U(t.onanimationend)&&H(t.onwebkitanimationend)?(et="-webkit-",R="WebkitAnimation",D="webkitAnimationEnd animationend"):(R="animation",D="animationend");var rt="Duration",it="Property",ot="Delay",at="TimingFunction",ut="IterationCount",st="PlayState",lt=9999,ct=R+ot,ft=R+rt,ht=j+ot,pt=j+rt,dt=["$$rAF",function(t){function n(t){r=r.concat(t),e()}function e(){if(r.length){for(var n=r.shift(),o=0;o<n.length;o++)n[o]();i||t(function(){i||e()})}}var r,i;return r=n.queue=[],n.waitUntilQuiet=function(n){i&&i(),i=t(function(){i=null,n(),e()})},n}],vt=[function(){return function(t,e,r){var i=r.ngAnimateChildren;n.isString(i)&&0===i.length?e.data(nt,!0):r.$observe("ngAnimateChildren",function(t){t="on"===t||"true"===t,e.data(nt,t)})}}],gt="$$animateCss",mt=1e3,yt=3,$t=1.5,xt={transitionDuration:pt,transitionDelay:ht,transitionProperty:j+it,animationDuration:ft,animationDelay:ct,animationIterationCount:R+ut},bt={transitionDuration:pt,transitionDelay:ht,animationDuration:ft,animationDelay:ct},wt=["$animateProvider",function(t){var n=T(),e=T();this.$get=["$window","$$jqLite","$$AnimateRunner","$timeout","$$forceReflow","$sniffer","$$rAFScheduler","$animate",function(t,r,i,s,l,c,f,m){function y(t,n){var e="$$ngAnimateParentKey",r=t.parentNode,i=r[e]||(r[e]=++I);return i+"-"+t.getAttribute("class")+"-"+n}function x(e,r,i,o){var a=n.get(i);return a||(a=A(t,e,o),"infinite"===a.animationIterationCount&&(a.animationIterationCount=1)),n.put(i,a),a}function b(i,o,u,s){var l;if(n.count(u)>0&&(l=e.get(u),!l)){var c=a(o,"-stagger");r.addClass(i,c),l=A(t,i,s),l.animationDuration=Math.max(l.animationDuration,0),l.transitionDuration=Math.max(l.transitionDuration,0),r.removeClass(i,c),e.put(u,l)}return l||{}}function _(t){z.push(t),f.waitUntilQuiet(function(){n.flush(),e.flush();for(var t=l(),r=0;r<z.length;r++)z[r](t);z.length=0})}function E(t,n,e){var r=x(t,n,e,xt),i=r.animationDelay,o=r.transitionDelay;return r.maxDelay=i&&o?Math.max(i,o):i||o,r.maxDuration=Math.max(r.animationDuration*r.animationIterationCount,r.transitionDuration),r}var T=h(r),I=0,z=[];return function(t,e){function l(){h()}function f(){h(!0)}function h(n){W||H&&U||(W=!0,U=!1,e.$$skipPreparationClasses||r.removeClass(t,pt),r.removeClass(t,vt),C(B,!1),w(B,!1),q(rt,function(t){B.style[t[0]]=""}),T(t,e),d(t,e),Object.keys(z).length&&q(z,function(t,n){t?B.style.setProperty(n,t):B.style.removeProperty(n)}),e.onDone&&e.onDone(),Y&&Y.complete(!n))}function x(t){jt.blockTransition&&w(B,t),jt.blockKeyframeAnimation&&C(B,!!t)}function A(){return Y=new i({end:l,cancel:f}),_(F),h(),{$$willAnimate:!1,start:function(){return Y},end:l}}function I(){function n(){if(!W){if(x(!1),q(rt,function(t){var n=t[0],e=t[1];B.style[n]=e}),T(t,e),r.addClass(t,vt),jt.recalculateTimingStyles){if(dt=B.className+" "+pt,Ct=y(B,dt),Tt=E(B,dt,Ct),Lt=Tt.maxDelay,X=Math.max(Lt,0),nt=Tt.maxDuration,0===nt)return void h();jt.hasTransitions=Tt.transitionDuration>0,jt.hasAnimations=Tt.animationDuration>0}if(jt.applyAnimationDelay&&(Lt="boolean"!=typeof e.delay&&P(e.delay)?parseFloat(e.delay):Lt,X=Math.max(Lt,0),Tt.animationDelay=Lt,Nt=k(Lt,!0),rt.push(Nt),B.style[Nt[0]]=Nt[1]),tt=X*mt,et=nt*mt,e.easing){var n,u=e.easing;jt.hasTransitions&&(n=j+at,rt.push([n,u]),B.style[n]=u),jt.hasAnimations&&(n=R+at,rt.push([n,u]),B.style[n]=u)}Tt.transitionDuration&&l.push(N),Tt.animationDuration&&l.push(D),a=Date.now();var c=tt+$t*et,f=a+c,p=t.data(gt)||[],d=!0;if(p.length){var v=p[0];d=f>v.expectedEndTime,d?s.cancel(v.timer):p.push(h)}if(d){var m=s(i,c,!1);p[0]={timer:m,expectedEndTime:f},p.push(h),t.data(gt,p)}t.on(l.join(" "),o),e.to&&(e.cleanupStyles&&L(z,B,Object.keys(e.to)),g(t,e))}}function i(){var n=t.data(gt);if(n){for(var e=1;e<n.length;e++)n[e]();t.removeData(gt)}}function o(t){t.stopPropagation();var n=t.originalEvent||t,e=n.$manualTimeStamp||n.timeStamp||Date.now(),r=parseFloat(n.elapsedTime.toFixed(yt));Math.max(e-a,0)>=tt&&r>=nt&&(H=!0,h())}if(!W){if(!B.parentNode)return void h();var a,l=[],c=function(t){if(H)U&&t&&(U=!1,h());else if(U=!t,Tt.animationDuration){var n=C(B,U);U?rt.push(n):u(rt,n)}},f=Pt>0&&(Tt.transitionDuration&&0===St.transitionDuration||Tt.animationDuration&&0===St.animationDuration)&&Math.max(St.animationDelay,St.transitionDelay);f?s(n,Math.floor(f*Pt*mt),!1):n(),G.resume=function(){c(!0)},G.pause=function(){c(!1)}}}var z={},B=$(t);if(!B||!B.parentNode||!m.enabled())return A();e=p(e);var W,U,H,Y,G,X,tt,nt,et,rt=[],ot=t.attr("class"),ut=o(e);if(0===e.duration||!c.animations&&!c.transitions)return A();var st=e.event&&V(e.event)?e.event.join(" "):e.event,ct=st&&e.structural,ft="",ht="";ct?ft=a(st,K,!0):st&&(ft=st),e.addClass&&(ht+=a(e.addClass,Z)),e.removeClass&&(ht.length&&(ht+=" "),ht+=a(e.removeClass,J)),e.applyClassesEarly&&ht.length&&T(t,e);var pt=[ft,ht].join(" ").trim(),dt=ot+" "+pt,vt=a(pt,Q),xt=ut.to&&Object.keys(ut.to).length>0,wt=(e.keyframeStyle||"").length>0;if(!wt&&!xt&&!pt)return A();var Ct,St;if(e.stagger>0){var _t=parseFloat(e.stagger);St={transitionDelay:_t,animationDelay:_t,transitionDuration:0,animationDuration:0}}else Ct=y(B,dt),St=b(B,pt,Ct,bt);e.$$skipPreparationClasses||r.addClass(t,pt);var Mt;if(e.transitionStyle){var kt=[j,e.transitionStyle];S(B,kt),rt.push(kt)}if(e.duration>=0){Mt=B.style[j].length>0;var At=O(e.duration,Mt);S(B,At),rt.push(At)}if(e.keyframeStyle){var Et=[R,e.keyframeStyle];S(B,Et),rt.push(Et)}var Pt=St?e.staggerIndex>=0?e.staggerIndex:n.count(Ct):0,Ot=0===Pt;Ot&&!e.skipBlocking&&w(B,lt);var Tt=E(B,dt,Ct),Lt=Tt.maxDelay;X=Math.max(Lt,0),nt=Tt.maxDuration;var jt={};if(jt.hasTransitions=Tt.transitionDuration>0,jt.hasAnimations=Tt.animationDuration>0,jt.hasTransitionAll=jt.hasTransitions&&"all"==Tt.transitionProperty,jt.applyTransitionDuration=xt&&(jt.hasTransitions&&!jt.hasTransitionAll||jt.hasAnimations&&!jt.hasTransitions),jt.applyAnimationDuration=e.duration&&jt.hasAnimations,jt.applyTransitionDelay=P(e.delay)&&(jt.applyTransitionDuration||jt.hasTransitions),jt.applyAnimationDelay=P(e.delay)&&jt.hasAnimations,jt.recalculateTimingStyles=ht.length>0,(jt.applyTransitionDuration||jt.applyAnimationDuration)&&(nt=e.duration?parseFloat(e.duration):nt,jt.applyTransitionDuration&&(jt.hasTransitions=!0,Tt.transitionDuration=nt,Mt=B.style[j+it].length>0,rt.push(O(nt,Mt))),jt.applyAnimationDuration&&(jt.hasAnimations=!0,Tt.animationDuration=nt,rt.push(M(nt)))),0===nt&&!jt.recalculateTimingStyles)return A();if(null!=e.delay){var Nt=parseFloat(e.delay);jt.applyTransitionDelay&&rt.push(k(Nt)),jt.applyAnimationDelay&&rt.push(k(Nt,!0))}return null==e.duration&&Tt.transitionDuration>0&&(jt.recalculateTimingStyles=jt.recalculateTimingStyles||Ot),tt=X*mt,et=nt*mt,e.skipBlocking||(jt.blockTransition=Tt.transitionDuration>0,jt.blockKeyframeAnimation=Tt.animationDuration>0&&St.animationDelay>0&&0===St.animationDuration),e.from&&(e.cleanupStyles&&L(z,B,Object.keys(e.from)),v(t,e)),jt.blockTransition||jt.blockKeyframeAnimation?x(nt):e.skipBlocking||w(B,!1),{$$willAnimate:!0,end:l,start:function(){return W?void 0:(G={end:l,cancel:f,resume:null,pause:null},Y=new i(G),_(I),Y)}}}}]}],Ct=["$$animationProvider",function(t){function n(t){return t.parentNode&&11===t.parentNode.nodeType}t.drivers.push("$$animateCssDriver");var e="ng-animate-shim",r="ng-anchor",i="ng-anchor-out",o="ng-anchor-in";this.$get=["$animateCss","$rootScope","$$AnimateRunner","$rootElement","$sniffer","$$jqLite","$document",function(t,a,u,s,l,c,f){function p(t){return t.replace(/\bng-\S+\b/g,"")}function d(t,n){return B(t)&&(t=t.split(" ")),B(n)&&(n=n.split(" ")),t.filter(function(t){return-1===n.indexOf(t)}).join(" ")}function v(n,a,s){function l(t){var n={},e=$(t).getBoundingClientRect();return q(["width","height","top","left"],function(t){var r=e[t];switch(t){case"top":r+=y.scrollTop;break;case"left":r+=y.scrollLeft}n[t]=Math.floor(r)+"px"}),n}function c(){var n=t(g,{addClass:i,delay:!0,from:l(a)});return n.$$willAnimate?n:null}function f(t){return t.attr("class")||""}function h(){var n=p(f(s)),e=d(n,m),r=d(m,n),a=t(g,{to:l(s),addClass:o+" "+e,removeClass:i+" "+r,delay:!0});return a.$$willAnimate?a:null}function v(){g.remove(),a.removeClass(e),s.removeClass(e)}var g=z($(a).cloneNode(!0)),m=p(f(g));a.addClass(e),s.addClass(e),g.addClass(r),b.append(g);var x,w=c();if(!w&&(x=h(),!x))return v();var C=w||x;return{start:function(){function t(){e&&e.end()}var n,e=C.start();return e.done(function(){return e=null,!x&&(x=h())?(e=x.start(),e.done(function(){e=null,v(),n.complete()}),e):(v(),void n.complete())}),n=new u({end:t,cancel:t})}}}function g(t,n,e,r){var i=m(t,F),o=m(n,F),a=[];return q(r,function(t){var n=t.out,r=t["in"],i=v(e,n,r);i&&a.push(i)}),i||o||0!==a.length?{start:function(){function t(){q(n,function(t){t.end()})}var n=[];i&&n.push(i.start()),o&&n.push(o.start()),q(a,function(t){n.push(t.start())});var e=new u({end:t,cancel:t});return u.all(n,function(t){e.complete(t)}),e}}:void 0}function m(n){var e=n.element,r=n.options||{};n.structural&&(r.event=n.event,r.structural=!0,r.applyClassesEarly=!0,"leave"===n.event&&(r.onDone=r.domOperation)),r.preparationClasses&&(r.event=_(r.event,r.preparationClasses));var i=t(e,r);return i.$$willAnimate?i:null}if(!l.animations&&!l.transitions)return F;var y=f[0].body,x=$(s),b=z(n(x)||y.contains(x)?x:y);h(c);return function(t){return t.from&&t.to?g(t.from,t.to,t.classes,t.anchors):m(t)}}]}],St=["$animateProvider",function(t){this.$get=["$injector","$$AnimateRunner","$$jqLite",function(n,e,r){function i(e){e=V(e)?e:e.split(" ");for(var r=[],i={},o=0;o<e.length;o++){var a=e[o],u=t.$$registeredAnimations[a];u&&!i[a]&&(r.push(n.get(u)),i[a]=!0)}return r}var o=h(r);return function(t,n,r,a){function u(){a.domOperation(),o(t,a)}function s(t,n,r,i,o){var a;switch(r){case"animate":a=[n,i.from,i.to,o];break;case"setClass":a=[n,v,g,o];break;case"addClass":a=[n,v,o];break;case"removeClass":a=[n,g,o];break;default:a=[n,o]}a.push(i);var u=t.apply(t,a);if(u)if(Y(u.start)&&(u=u.start()),u instanceof e)u.done(o);else if(Y(u))return u;return F}function l(t,n,r,i,o){var a=[];return q(i,function(i){var u=i[o];u&&a.push(function(){var i,o,a=!1,l=function(t){a||(a=!0,(o||F)(t),i.complete(!t))};return i=new e({end:function(){l()},cancel:function(){l(!0)}}),o=s(u,t,n,r,function(t){var n=t===!1;l(n)}),i})}),a}function c(t,n,r,i,o){var a=l(t,n,r,i,o);if(0===a.length){var u,s;"beforeSetClass"===o?(u=l(t,"removeClass",r,i,"beforeRemoveClass"),s=l(t,"addClass",r,i,"beforeAddClass")):"setClass"===o&&(u=l(t,"removeClass",r,i,"removeClass"),s=l(t,"addClass",r,i,"addClass")),u&&(a=a.concat(u)),s&&(a=a.concat(s))}if(0!==a.length)return function(t){var n=[];return a.length&&q(a,function(t){n.push(t())}),n.length?e.all(n,t):t(),function(t){q(n,function(n){t?n.cancel():n.end()})}}}3===arguments.length&&W(r)&&(a=r,r=null),a=p(a),r||(r=t.attr("class")||"",a.addClass&&(r+=" "+a.addClass),a.removeClass&&(r+=" "+a.removeClass));var f,h,v=a.addClass,g=a.removeClass,m=i(r);if(m.length){var y,$;"leave"==n?($="leave",y="afterLeave"):($="before"+n.charAt(0).toUpperCase()+n.substr(1),y=n),"enter"!==n&&"move"!==n&&(f=c(t,n,a,m,$)),h=c(t,n,a,m,y)}return f||h?{start:function(){function n(n){s=!0,u(),d(t,a),l.complete(n)}function r(t){s||((i||F)(t),n(t))}var i,o=[];f&&o.push(function(t){i=f(t)}),o.length?o.push(function(t){u(),t(!0)}):u(),h&&o.push(function(t){i=h(t)});var s=!1,l=new e({end:function(){r()},cancel:function(){r(!0)}});return e.chain(o,n),l}}:void 0}}]}],_t=["$$animationProvider",function(t){t.drivers.push("$$animateJsDriver"),this.$get=["$$animateJs","$$AnimateRunner",function(t,n){function e(n){var e=n.element,r=n.event,i=n.options,o=n.classes;return t(e,r,o,i)}return function(t){if(t.from&&t.to){var r=e(t.from),i=e(t.to);if(!r&&!i)return;return{start:function(){function t(){return function(){q(o,function(t){t.end()})}}function e(t){a.complete(t)}var o=[];r&&o.push(r.start()),i&&o.push(i.start()),n.all(o,e);var a=new n({end:t(),cancel:t()});return a}}}return e(t)}}]}],Mt="data-ng-animate",kt="$ngAnimatePin",At=["$animateProvider",function(t){function n(t,n,e,r){return a[t].some(function(t){return t(n,e,r)})}function e(t,n){t=t||{};var e=(t.addClass||"").length>0,r=(t.removeClass||"").length>0;return n?e&&r:e||r}var i=1,o=2,a=this.rules={skip:[],cancel:[],join:[]};a.join.push(function(t,n,r){return!n.structural&&e(n.options)}),a.skip.push(function(t,n,r){return!n.structural&&!e(n.options)}),a.skip.push(function(t,n,e){return"leave"==e.event&&n.structural}),a.skip.push(function(t,n,e){return e.structural&&e.state===o&&!n.structural}),a.cancel.push(function(t,n,e){return e.structural&&n.structural}),a.cancel.push(function(t,n,e){return e.state===o&&n.structural}),a.cancel.push(function(t,n,e){var r=n.options,i=e.options;return r.addClass&&r.addClass===i.removeClass||r.removeClass&&r.removeClass===i.addClass}),this.$get=["$$rAF","$rootScope","$rootElement","$document","$$HashMap","$$animation","$$AnimateRunner","$templateRequest","$$jqLite","$$forceReflow",function(a,u,c,f,v,g,y,w,C,S){function _(){var t=!1;return function(n){t?n():u.$$postDigest(function(){t=!0,n()})}}function M(t,n){return m(t,n,{})}function k(t,n){var e=$(t),r=[],i=F[n];return i&&q(i,function(t){t.node.contains(e)&&r.push(t.callback)}),r}function A(t,r,l){function c(n,e,r,i){C(function(){var n=k(t,e);n.length&&a(function(){q(n,function(n){n(t,r,i)})})}),n.progress(e,r,i)}function f(n){b(t,l),J(t,l),d(t,l),l.domOperation(),w.complete(!n)}var h,v;t=s(t),t&&(h=$(t),v=t.parent()),l=p(l);var w=new y,C=_();if(V(l.addClass)&&(l.addClass=l.addClass.join(" ")),l.addClass&&!B(l.addClass)&&(l.addClass=null),V(l.removeClass)&&(l.removeClass=l.removeClass.join(" ")),l.removeClass&&!B(l.removeClass)&&(l.removeClass=null),l.from&&!W(l.from)&&(l.from=null),l.to&&!W(l.to)&&(l.to=null),!h)return f(),w;var S=[h.className,l.addClass,l.removeClass].join(" ");if(!Z(S))return f(),w;var A=["enter","move","leave"].indexOf(r)>=0,O=!R||N.get(h),D=!O&&j.get(h)||{},F=!!D.state;if(O||F&&D.state==i||(O=!T(t,v,r)),O)return f(),w;A&&E(t);var I={structural:A,element:t,event:r,close:f,options:l,runner:w};if(F){var z=n("skip",t,I,D);if(z)return D.state===o?(f(),w):(m(t,D.options,l),D.runner);var U=n("cancel",t,I,D);if(U)if(D.state===o)D.runner.end();else{if(!D.structural)return m(t,D.options,I.options),D.runner;D.close()}else{var H=n("join",t,I,D);if(H){if(D.state!==o)return x(t,A?r:null,l),r=I.event=D.event,l=m(t,D.options,I.options),D.runner;M(t,l)}}}else M(t,l);var Y=I.structural;if(Y||(Y="animate"===I.event&&Object.keys(I.options.to||{}).length>0||e(I.options)),!Y)return f(),P(t),w;var G=(D.counter||0)+1;return I.counter=G,L(t,i,I),u.$$postDigest(function(){var n=j.get(h),i=!n;n=n||{};var a=t.parent()||[],u=a.length>0&&("animate"===n.event||n.structural||e(n.options));if(i||n.counter!==G||!u)return i&&(J(t,l),d(t,l)),(i||A&&n.event!==r)&&(l.domOperation(),w.end()),void(u||P(t));r=!n.structural&&e(n.options,!0)?"setClass":n.event,L(t,o);var s=g(t,r,n.options);s.done(function(n){f(!n);var e=j.get(h);e&&e.counter===G&&P($(t)),c(w,r,"close",{})}),w.setHost(s),c(w,r,"start",{})}),w}function E(t){var n=$(t),e=n.querySelectorAll("["+Mt+"]");q(e,function(t){var n=parseInt(t.getAttribute(Mt)),e=j.get(t);switch(n){case o:e.runner.end();case i:e&&j.remove(t)}})}function P(t){var n=$(t);n.removeAttribute(Mt),j.remove(n)}function O(t,n){return $(t)===$(n)}function T(t,n,e){var r,i=z(f[0].body),o=O(t,i)||"HTML"===t[0].nodeName,a=O(t,c),u=!1,s=t.data(kt);for(s&&(n=s);n&&n.length;){a||(a=O(n,c));var l=n[0];if(l.nodeType!==X)break;var h=j.get(l)||{};if(u||(u=h.structural||N.get(l)),U(r)||r===!0){var p=n.data(nt);H(p)&&(r=p)}if(u&&r===!1)break;a||(a=O(n,c),a||(s=n.data(kt),s&&(n=s))),o||(o=O(n,i)),n=n.parent()}var d=!u||r;return d&&a&&o}function L(t,n,e){e=e||{},e.state=n;var r=$(t);r.setAttribute(Mt,n);var i=j.get(r),o=i?I(i,e):e;j.put(r,o)}var j=new v,N=new v,R=null,D=u.$watch(function(){return 0===w.totalPendingRequests},function(t){t&&(D(),u.$$postDigest(function(){u.$$postDigest(function(){null===R&&(R=!0)})}))}),F={},Y=t.classNameFilter(),Z=Y?function(t){return Y.test(t)}:function(){return!0},J=h(C);return{on:function(t,n,e){var r=l(n);F[t]=F[t]||[],F[t].push({node:r,callback:e})},off:function(t,n,e){function r(t,n,e){var r=l(n);return t.filter(function(t){var n=t.node===r&&(!e||t.callback===e);return!n})}var i=F[t];i&&(F[t]=1===arguments.length?null:r(i,n,e))},pin:function(t,n){r(G(t),"element","not an element"),r(G(n),"parentElement","not an element"),t.data(kt,n)},push:function(t,n,e,r){return e=e||{},e.domOperation=r,A(t,n,e)},enabled:function(t,n){var e=arguments.length;if(0===e)n=!!R;else{var r=G(t);if(r){var i=$(t),o=N.get(i);1===e?n=!o:(n=!!n,n?o&&N.remove(i):N.put(i,!0))}else n=R=!!t}return n}}}]}],Et=["$$rAF",function(t){function n(n){e.push(n),e.length>1||t(function(){for(var t=0;t<e.length;t++)e[t]();e=[]})}var e=[];return function(){var t=!1;return n(function(){t=!0}),function(e){t?e():n(e)}}}],Pt=["$q","$sniffer","$$animateAsyncRun",function(t,n,e){function r(t){this.setHost(t),this._doneCallbacks=[],this._runInAnimationFrame=e(),this._state=0}var i=0,o=1,a=2;return r.chain=function(t,n){function e(){return r===t.length?void n(!0):void t[r](function(t){return t===!1?void n(!1):(r++,void e())})}var r=0;e()},r.all=function(t,n){function e(e){i=i&&e,++r===t.length&&n(i)}var r=0,i=!0;q(t,function(t){t.done(e)})},r.prototype={setHost:function(t){this.host=t||{}},done:function(t){this._state===a?t():this._doneCallbacks.push(t)},progress:F,getPromise:function(){if(!this.promise){var n=this;this.promise=t(function(t,e){n.done(function(n){n===!1?e():t()})})}return this.promise},then:function(t,n){return this.getPromise().then(t,n)},"catch":function(t){return this.getPromise()["catch"](t)},"finally":function(t){return this.getPromise()["finally"](t)},pause:function(){this.host.pause&&this.host.pause()},resume:function(){this.host.resume&&this.host.resume()},end:function(){this.host.end&&this.host.end(),this._resolve(!0)},cancel:function(){this.host.cancel&&this.host.cancel(),this._resolve(!1)},complete:function(t){var n=this;n._state===i&&(n._state=o,n._runInAnimationFrame(function(){n._resolve(t)}))},_resolve:function(t){this._state!==a&&(q(this._doneCallbacks,function(n){n(t)}),this._doneCallbacks.length=0,this._state=a)}},r}],Ot=["$animateProvider",function(t){function n(t,n){t.data(u,n)}function e(t){t.removeData(u)}function r(t){return t.data(u)}var o="ng-animate-ref",a=this.drivers=[],u="$$animationRunner";this.$get=["$$jqLite","$rootScope","$injector","$$AnimateRunner","$$HashMap","$$rAFScheduler",function(t,u,s,l,c,f){function v(t){function n(t){if(t.processed)return t;t.processed=!0;var e=t.domNode,r=e.parentNode;o.put(e,t);for(var a;r;){if(a=o.get(r)){a.processed||(a=n(a));break}r=r.parentNode}return(a||i).children.push(t),t}function e(t){var n,e=[],r=[];for(n=0;n<t.children.length;n++)r.push(t.children[n]);var i=r.length,o=0,a=[];for(n=0;n<r.length;n++){var u=r[n];0>=i&&(i=o,o=0,e.push(a),a=[]),a.push(u.fn),u.children.forEach(function(t){o++,r.push(t)}),i--}return a.length&&e.push(a),e}var r,i={children:[]},o=new c;for(r=0;r<t.length;r++){var a=t[r];o.put(a.domNode,t[r]={domNode:a.domNode,fn:a.fn,children:[]})}for(r=0;r<t.length;r++)n(t[r]);return e(i)}var g=[],m=h(t);return function(c,h,y){function x(t){var n="["+o+"]",e=t.hasAttribute(o)?[t]:t.querySelectorAll(n),r=[];return q(e,function(t){var n=t.getAttribute(o);n&&n.length&&r.push(t)}),r}function b(t){var n=[],e={};q(t,function(t,r){var i=t.element,a=$(i),u=t.event,s=["enter","move"].indexOf(u)>=0,l=t.structural?x(a):[];if(l.length){var c=s?"to":"from";q(l,function(t){var n=t.getAttribute(o);e[n]=e[n]||{},e[n][c]={animationID:r,element:z(t)}})}else n.push(t)});var r={},i={};return q(e,function(e,o){var a=e.from,u=e.to;if(!a||!u){var s=a?a.animationID:u.animationID,l=s.toString();return void(r[l]||(r[l]=!0,n.push(t[s])))}var c=t[a.animationID],f=t[u.animationID],h=a.animationID.toString();if(!i[h]){var p=i[h]={structural:!0,beforeStart:function(){c.beforeStart(),f.beforeStart()},close:function(){c.close(),f.close()},classes:w(c.classes,f.classes),from:c,to:f,anchors:[]};p.classes.length?n.push(p):(n.push(c),n.push(f))}i[h].anchors.push({out:a.element,"in":u.element})}),n}function w(t,n){t=t.split(" "),n=n.split(" ");for(var e=[],r=0;r<t.length;r++){var i=t[r];if("ng-"!==i.substring(0,3))for(var o=0;o<n.length;o++)if(i===n[o]){e.push(i);break}}return e.join(" ")}function C(t){for(var n=a.length-1;n>=0;n--){var e=a[n];if(s.has(e)){var r=s.get(e),i=r(t);if(i)return i}}}function S(){c.addClass(tt),O&&t.addClass(c,O)}function _(t,n){function e(t){r(t).setHost(n)}t.from&&t.to?(e(t.from.element),e(t.to.element)):e(t.element)}function M(){var t=r(c);!t||"leave"===h&&y.$$domOperationFired||t.end()}function k(n){c.off("$destroy",M),e(c),m(c,y),d(c,y),y.domOperation(),O&&t.removeClass(c,O),c.removeClass(tt),E.complete(!n)}y=p(y);var A=["enter","move","leave"].indexOf(h)>=0,E=new l({end:function(){k()},cancel:function(){k(!0)}});if(!a.length)return k(),E;n(c,E);var P=i(c.attr("class"),i(y.addClass,y.removeClass)),O=y.tempClasses;return O&&(P+=" "+O,y.tempClasses=null),g.push({element:c,classes:P,event:h,structural:A,options:y,beforeStart:S,close:k}),c.on("$destroy",M),g.length>1?E:(u.$$postDigest(function(){var t=[];q(g,function(n){r(n.element)?t.push(n):n.close()}),g.length=0;var n=b(t),e=[];q(n,function(t){e.push({domNode:$(t.from?t.from.element:t.element),fn:function(){t.beforeStart();var n,e=t.close,i=t.anchors?t.from.element||t.to.element:t.element;if(r(i)){var o=C(t);o&&(n=o.start)}if(n){var a=n();a.done(function(t){e(!t)}),_(t,a)}else e()}})}),f(v(e))}),E)}}]}];n.module("ngAnimate",[]).directive("ngAnimateChildren",vt).factory("$$rAFScheduler",dt).factory("$$AnimateRunner",Pt).factory("$$animateAsyncRun",Et).provider("$$animateQueue",At).provider("$$animation",Ot).provider("$animateCss",wt).provider("$$animateCssDriver",Ct).provider("$$animateJs",St).provider("$$animateJsDriver",_t)}(window,window.angular),function(){function t(t,n){return t.set(n[0],n[1]),t}function n(t,n){return t.add(n),t}function e(t,n,e){var r=e.length;switch(r){case 0:return t.call(n);case 1:return t.call(n,e[0]);case 2:return t.call(n,e[0],e[1]);case 3:return t.call(n,e[0],e[1],e[2])}return t.apply(n,e)}function r(t,n,e,r){for(var i=-1,o=t.length;++i<o;){var a=t[i];n(r,a,e(a),t)}return r}function i(t,n){for(var e=-1,r=t.length,i=-1,o=n.length,a=Array(r+o);++e<r;)a[e]=t[e];for(;++i<o;)a[e++]=n[i];return a}function o(t,n){for(var e=-1,r=t.length;++e<r&&n(t[e],e,t)!==!1;);return t}function a(t,n){for(var e=t.length;e--&&n(t[e],e,t)!==!1;);return t}function u(t,n){for(var e=-1,r=t.length;++e<r;)if(!n(t[e],e,t))return!1;return!0}function s(t,n){for(var e=-1,r=t.length,i=0,o=[];++e<r;){var a=t[e];n(a,e,t)&&(o[i++]=a)}return o}function l(t,n){return!!t.length&&y(t,n,0)>-1}function c(t,n,e){for(var r=-1,i=t.length;++r<i;)if(e(n,t[r]))return!0;return!1}function f(t,n){for(var e=-1,r=t.length,i=Array(r);++e<r;)i[e]=n(t[e],e,t);return i}function h(t,n){for(var e=-1,r=n.length,i=t.length;++e<r;)t[i+e]=n[e];return t}function p(t,n,e,r){var i=-1,o=t.length;for(r&&o&&(e=t[++i]);++i<o;)e=n(e,t[i],i,t);return e}function d(t,n,e,r){var i=t.length;for(r&&i&&(e=t[--i]);i--;)e=n(e,t[i],i,t);return e}function v(t,n){for(var e=-1,r=t.length;++e<r;)if(n(t[e],e,t))return!0;return!1}function g(t,n,e,r){var i;return e(t,function(t,e,o){return n(t,e,o)?(i=r?e:t,!1):void 0}),i}function m(t,n,e){for(var r=t.length,i=e?r:-1;e?i--:++i<r;)if(n(t[i],i,t))return i;return-1}function y(t,n,e){if(n!==n)return N(t,e);for(var r=e-1,i=t.length;++r<i;)if(t[r]===n)return r;return-1}function $(t,n,e,r){for(var i=e-1,o=t.length;++i<o;)if(r(t[i],n))return i;return-1}function x(t,n){var e=t?t.length:0;return e?C(t,n)/e:$t}function b(t,n,e,r,i){return i(t,function(t,i,o){e=r?(r=!1,t):n(e,t,i,o)}),e}function w(t,n){var e=t.length;for(t.sort(n);e--;)t[e]=t[e].value;return t}function C(t,n){for(var e,r=-1,i=t.length;++r<i;){var o=n(t[r]);o!==U&&(e=e===U?o:e+o)}return e}function S(t,n){for(var e=-1,r=Array(t);++e<t;)r[e]=n(e);return r}function _(t,n){return f(n,function(n){return[n,t[n]]})}function M(t){return function(n){return t(n)}}function k(t,n){return f(n,function(n){return t[n]})}function A(t,n){for(var e=-1,r=t.length;++e<r&&y(n,t[e],0)>-1;);return e}function E(t,n){for(var e=t.length;e--&&y(n,t[e],0)>-1;);return e}function P(t){return t&&t.Object===Object?t:null}function O(t,n){for(var e=t.length,r=0;e--;)t[e]===n&&r++;return r}function T(t){return we[t]}function L(t){return Ce[t]}function j(t){return"\\"+Me[t]}function N(t,n,e){for(var r=t.length,i=n+(e?0:-1);e?i--:++i<r;){var o=t[i];if(o!==o)return i}return-1}function R(t){var n=!1;if(null!=t&&"function"!=typeof t.toString)try{n=!!(t+"")}catch(e){}return n}function D(t){for(var n,e=[];!(n=t.next()).done;)e.push(n.value);return e}function F(t){var n=-1,e=Array(t.size);return t.forEach(function(t,r){e[++n]=[r,t]}),e}function I(t,n){for(var e=-1,r=t.length,i=0,o=[];++e<r;){var a=t[e];a!==n&&a!==Z||(t[e]=Z,o[i++]=e)}return o}function z(t){var n=-1,e=Array(t.size);return t.forEach(function(t){e[++n]=t}),e}function q(t){if(!t||!ge.test(t))return t.length;for(var n=de.lastIndex=0;de.test(t);)n++;return n}function V(t){return t.match(de)}function B(t){return Se[t]}function W(P){function En(t){if(lu(t)&&!tf(t)&&!(t instanceof Tn)){if(t instanceof On)return t;if(dl.call(t,"__wrapped__"))return no(t)}return new On(t)}function Pn(){}function On(t,n){this.__wrapped__=t,this.__actions__=[],this.__chain__=!!n,this.__index__=0,this.__values__=U}function Tn(t){this.__wrapped__=t,this.__actions__=[],this.__dir__=1,this.__filtered__=!1,this.__iteratees__=[],this.__takeCount__=xt,this.__views__=[]}function Ln(){var t=new Tn(this.__wrapped__);return t.__actions__=Zr(this.__actions__),t.__dir__=this.__dir__,t.__filtered__=this.__filtered__,t.__iteratees__=Zr(this.__iteratees__),t.__takeCount__=this.__takeCount__,t.__views__=Zr(this.__views__),t}function jn(){if(this.__filtered__){var t=new Tn(this);t.__dir__=-1,t.__filtered__=!0}else t=this.clone(),t.__dir__*=-1;return t}function Nn(){var t=this.__wrapped__.value(),n=this.__dir__,e=tf(t),r=0>n,i=e?t.length:0,o=Li(0,i,this.__views__),a=o.start,u=o.end,s=u-a,l=r?u:a-1,c=this.__iteratees__,f=c.length,h=0,p=Il(s,this.__takeCount__);if(!e||Y>i||i==s&&p==s)return Or(t,this.__actions__);var d=[];t:for(;s--&&p>h;){l+=n;for(var v=-1,g=t[l];++v<f;){var m=c[v],y=m.iteratee,$=m.type,x=y(g);if($==dt)g=x;else if(!x){if($==pt)continue t;break t}}d[h++]=g}return d}function Rn(){}function Dn(t,n){return In(t,n)&&delete t[n]}function Fn(t,n){if(Zl){var e=t[n];return e===X?U:e}return dl.call(t,n)?t[n]:U}function In(t,n){return Zl?t[n]!==U:dl.call(t,n)}function zn(t,n,e){t[n]=Zl&&e===U?X:e}function qn(t){var n=-1,e=t?t.length:0;for(this.clear();++n<e;){var r=t[n];this.set(r[0],r[1])}}function Vn(){this.__data__={hash:new Rn,map:Hl?new Hl:[],string:new Rn}}function Bn(t){var n=this.__data__;return Wi(t)?Dn("string"==typeof t?n.string:n.hash,t):Hl?n.map["delete"](t):ee(n.map,t)}function Wn(t){var n=this.__data__;return Wi(t)?Fn("string"==typeof t?n.string:n.hash,t):Hl?n.map.get(t):re(n.map,t)}function Un(t){var n=this.__data__;return Wi(t)?In("string"==typeof t?n.string:n.hash,t):Hl?n.map.has(t):ie(n.map,t)}function Hn(t,n){var e=this.__data__;return Wi(t)?zn("string"==typeof t?e.string:e.hash,t,n):Hl?e.map.set(t,n):ae(e.map,t,n),this}function Yn(t){var n=-1,e=t?t.length:0;for(this.__data__=new qn;++n<e;)this.push(t[n])}function Gn(t,n){var e=t.__data__;if(Wi(n)){var r=e.__data__,i="string"==typeof n?r.string:r.hash;return i[n]===X}return e.has(n)}function Xn(t){var n=this.__data__;if(Wi(t)){var e=n.__data__,r="string"==typeof t?e.string:e.hash;r[t]=X}else n.set(t,X)}function Zn(t){var n=-1,e=t?t.length:0;for(this.clear();++n<e;){var r=t[n];this.set(r[0],r[1])}}function Jn(){this.__data__={array:[],map:null}}function Kn(t){var n=this.__data__,e=n.array;return e?ee(e,t):n.map["delete"](t)}function Qn(t){var n=this.__data__,e=n.array;return e?re(e,t):n.map.get(t)}function te(t){var n=this.__data__,e=n.array;return e?ie(e,t):n.map.has(t)}function ne(t,n){var e=this.__data__,r=e.array;r&&(r.length<Y-1?ae(r,t,n):(e.array=null,e.map=new qn(r)));var i=e.map;return i&&i.set(t,n),this}function ee(t,n){var e=oe(t,n);if(0>e)return!1;var r=t.length-1;return e==r?t.pop():Ol.call(t,e,1),!0}function re(t,n){var e=oe(t,n);return 0>e?U:t[e][1]}function ie(t,n){return oe(t,n)>-1}function oe(t,n){for(var e=t.length;e--;)if(Ha(t[e][0],n))return e;return-1}function ae(t,n,e){var r=oe(t,n);0>r?t.push([n,e]):t[r][1]=e}function ue(t,n,e,r){
+return t===U||Ha(t,fl[e])&&!dl.call(r,e)?n:t}function se(t,n,e){(e===U||Ha(t[n],e))&&("number"!=typeof n||e!==U||n in t)||(t[n]=e)}function le(t,n,e){var r=t[n];dl.call(t,n)&&Ha(r,e)&&(e!==U||n in t)||(t[n]=e)}function ce(t,n,e,r){return sc(t,function(t,i,o){n(r,t,e(t),o)}),r}function fe(t,n){return t&&Jr(n,Yu(n),t)}function de(t,n){for(var e=-1,r=null==t,i=n.length,o=Array(i);++e<i;)o[e]=r?U:Wu(t,n[e]);return o}function we(t,n,e){return t===t&&(e!==U&&(t=e>=t?t:e),n!==U&&(t=t>=n?t:n)),t}function Ce(t,n,e,r,i,a,u){var s;if(r&&(s=a?r(t,i,a,u):r(t)),s!==U)return s;if(!su(t))return t;var l=tf(t);if(l){if(s=Ni(t),!n)return Zr(t,s)}else{var c=Ti(t),f=c==At||c==Et;if(nf(t))return Fr(t,n);if(c==Tt||c==Ct||f&&!a){if(R(t))return a?t:{};if(s=Ri(f?{}:t),!n)return Kr(t,fe(s,t))}else{if(!be[c])return a?t:{};s=Di(t,c,Ce,n)}}u||(u=new Zn);var h=u.get(t);if(h)return h;if(u.set(t,s),!l)var p=e?Ci(t):Yu(t);return o(p||t,function(i,o){p&&(o=i,i=t[o]),le(s,o,Ce(i,n,e,r,o,t,u))}),s}function Se(t){var n=Yu(t),e=n.length;return function(r){if(null==r)return!e;for(var i=e;i--;){var o=n[i],a=t[o],u=r[o];if(u===U&&!(o in Object(r))||!a(u))return!1}return!0}}function _e(t){return su(t)?Al(t):{}}function Me(t,n,e){if("function"!=typeof t)throw new ll(G);return Pl(function(){t.apply(U,e)},n)}function Ee(t,n,e,r){var i=-1,o=l,a=!0,u=t.length,s=[],h=n.length;if(!u)return s;e&&(n=f(n,M(e))),r?(o=c,a=!1):n.length>=Y&&(o=Gn,a=!1,n=new Yn(n));t:for(;++i<u;){var p=t[i],d=e?e(p):p;if(p=r||0!==p?p:0,a&&d===d){for(var v=h;v--;)if(n[v]===d)continue t;s.push(p)}else o(n,d,r)||s.push(p)}return s}function Pe(t,n){var e=!0;return sc(t,function(t,r,i){return e=!!n(t,r,i)}),e}function Te(t,n,e){for(var r=-1,i=t.length;++r<i;){var o=t[r],a=n(o);if(null!=a&&(u===U?a===a&&!Cu(a):e(a,u)))var u=a,s=o}return s}function Le(t,n,e,r){var i=t.length;for(e=Eu(e),0>e&&(e=-e>i?0:i+e),r=r===U||r>i?i:Eu(r),0>r&&(r+=i),r=e>r?0:Pu(r);r>e;)t[e++]=n;return t}function je(t,n){var e=[];return sc(t,function(t,r,i){n(t,r,i)&&e.push(t)}),e}function Ne(t,n,e,r,i){var o=-1,a=t.length;for(e||(e=Ii),i||(i=[]);++o<a;){var u=t[o];n>0&&e(u)?n>1?Ne(u,n-1,e,r,i):h(i,u):r||(i[i.length]=u)}return i}function Fe(t,n){return t&&cc(t,n,Yu)}function Ie(t,n){return t&&fc(t,n,Yu)}function ze(t,n){return s(n,function(n){return ou(t[n])})}function qe(t,n){n=Bi(n,t)?[n]:Rr(n);for(var e=0,r=n.length;null!=t&&r>e;)t=t[Qi(n[e++])];return e&&e==r?t:U}function Ve(t,n,e){var r=n(t);return tf(t)?r:h(r,e(t))}function Be(t,n){return t>n}function We(t,n){return dl.call(t,n)||"object"==typeof t&&n in t&&null===Pi(t)}function Ue(t,n){return n in Object(t)}function He(t,n,e){return t>=Il(n,e)&&t<Fl(n,e)}function Ye(t,n,e){for(var r=e?c:l,i=t[0].length,o=t.length,a=o,u=Array(o),s=1/0,h=[];a--;){var p=t[a];a&&n&&(p=f(p,M(n))),s=Il(p.length,s),u[a]=!e&&(n||i>=120&&p.length>=120)?new Yn(a&&p):U}p=t[0];var d=-1,v=u[0];t:for(;++d<i&&h.length<s;){var g=p[d],m=n?n(g):g;if(g=e||0!==g?g:0,!(v?Gn(v,m):r(h,m,e))){for(a=o;--a;){var y=u[a];if(!(y?Gn(y,m):r(t[a],m,e)))continue t}v&&v.push(m),h.push(g)}}return h}function Ge(t,n,e,r){return Fe(t,function(t,i,o){n(r,e(t),i,o)}),r}function Xe(t,n,r){Bi(n,t)||(n=Rr(n),t=Ji(t,n),n=bo(n));var i=null==t?t:t[Qi(n)];return null==i?U:e(i,t,r)}function Ze(t,n,e,r,i){return t===n?!0:null==t||null==n||!su(t)&&!lu(n)?t!==t&&n!==n:Je(t,n,Ze,e,r,i)}function Je(t,n,e,r,i,o){var a=tf(t),u=tf(n),s=St,l=St;a||(s=Ti(t),s=s==Ct?Tt:s),u||(l=Ti(n),l=l==Ct?Tt:l);var c=s==Tt&&!R(t),f=l==Tt&&!R(n),h=s==l;if(h&&!c)return o||(o=new Zn),a||Su(t)?xi(t,n,e,r,i,o):bi(t,n,s,e,r,i,o);if(!(i&st)){var p=c&&dl.call(t,"__wrapped__"),d=f&&dl.call(n,"__wrapped__");if(p||d){var v=p?t.value():t,g=d?n.value():n;return o||(o=new Zn),e(v,g,r,i,o)}}return h?(o||(o=new Zn),wi(t,n,e,r,i,o)):!1}function Ke(t,n,e,r){var i=e.length,o=i,a=!r;if(null==t)return!o;for(t=Object(t);i--;){var u=e[i];if(a&&u[2]?u[1]!==t[u[0]]:!(u[0]in t))return!1}for(;++i<o;){u=e[i];var s=u[0],l=t[s],c=u[1];if(a&&u[2]){if(l===U&&!(s in t))return!1}else{var f=new Zn;if(r)var h=r(l,c,s,t,n,f);if(!(h===U?Ze(c,l,r,ut|st,f):h))return!1}}return!0}function Qe(t){return"function"==typeof t?t:null==t?Fs:"object"==typeof t?tf(t)?or(t[0],t[1]):ir(t):Hs(t)}function tr(t){return Dl(Object(t))}function nr(t){t=null==t?t:Object(t);var n=[];for(var e in t)n.push(e);return n}function er(t,n){return n>t}function rr(t,n){var e=-1,r=Xa(t)?Array(t.length):[];return sc(t,function(t,i,o){r[++e]=n(t,i,o)}),r}function ir(t){var n=ki(t);return 1==n.length&&n[0][2]?Gi(n[0][0],n[0][1]):function(e){return e===t||Ke(e,t,n)}}function or(t,n){return Bi(t)&&Yi(n)?Gi(Qi(t),n):function(e){var r=Wu(e,t);return r===U&&r===n?Hu(e,t):Ze(n,r,U,ut|st)}}function ar(t,n,e,r,i){if(t!==n){if(!tf(n)&&!Su(n))var a=Gu(n);o(a||n,function(o,u){if(a&&(u=o,o=n[u]),su(o))i||(i=new Zn),ur(t,n,u,e,ar,r,i);else{var s=r?r(t[u],o,u+"",t,n,i):U;s===U&&(s=o),se(t,u,s)}})}}function ur(t,n,e,r,i,o,a){var u=t[e],s=n[e],l=a.get(s);if(l)return void se(t,e,l);var c=o?o(u,s,e+"",t,n,a):U,f=c===U;f&&(c=s,tf(s)||Su(s)?tf(u)?c=u:Za(u)?c=Zr(u):(f=!1,c=Ce(s,!0)):yu(s)||Ya(s)?Ya(u)?c=Tu(u):!su(u)||r&&ou(u)?(f=!1,c=Ce(s,!0)):c=u:f=!1),a.set(s,c),f&&i(c,s,r,o,a),a["delete"](s),se(t,e,c)}function sr(t,n){var e=t.length;if(e)return n+=0>n?e:0,qi(n,e)?t[n]:U}function lr(t,n,e){var r=-1;n=f(n.length?n:[Fs],M(Mi()));var i=rr(t,function(t,e,i){var o=f(n,function(n){return n(t)});return{criteria:o,index:++r,value:t}});return w(i,function(t,n){return Yr(t,n,e)})}function cr(t,n){return t=Object(t),p(n,function(n,e){return e in t&&(n[e]=t[e]),n},{})}function fr(t,n){for(var e=-1,r=Si(t),i=r.length,o={};++e<i;){var a=r[e],u=t[a];n(u,a)&&(o[a]=u)}return o}function hr(t){return function(n){return null==n?U:n[t]}}function pr(t){return function(n){return qe(n,t)}}function dr(t,n,e,r){var i=r?$:y,o=-1,a=n.length,u=t;for(e&&(u=f(t,M(e)));++o<a;)for(var s=0,l=n[o],c=e?e(l):l;(s=i(u,c,s,r))>-1;)u!==t&&Ol.call(u,s,1),Ol.call(t,s,1);return t}function vr(t,n){for(var e=t?n.length:0,r=e-1;e--;){var i=n[e];if(e==r||i!==o){var o=i;if(qi(i))Ol.call(t,i,1);else if(Bi(i,t))delete t[Qi(i)];else{var a=Rr(i),u=Ji(t,a);null!=u&&delete u[Qi(bo(a))]}}}return t}function gr(t,n){return t+Ll(ql()*(n-t+1))}function mr(t,n,e,r){for(var i=-1,o=Fl(Tl((n-t)/(e||1)),0),a=Array(o);o--;)a[r?o:++i]=t,t+=e;return a}function yr(t,n){var e="";if(!t||1>n||n>mt)return e;do n%2&&(e+=t),n=Ll(n/2),n&&(t+=t);while(n);return e}function $r(t,n,e,r){n=Bi(n,t)?[n]:Rr(n);for(var i=-1,o=n.length,a=o-1,u=t;null!=u&&++i<o;){var s=Qi(n[i]);if(su(u)){var l=e;if(i!=a){var c=u[s];l=r?r(c,s,u):U,l===U&&(l=null==c?qi(n[i+1])?[]:{}:c)}le(u,s,l)}u=u[s]}return t}function xr(t,n,e){var r=-1,i=t.length;0>n&&(n=-n>i?0:i+n),e=e>i?i:e,0>e&&(e+=i),i=n>e?0:e-n>>>0,n>>>=0;for(var o=Array(i);++r<i;)o[r]=t[r+n];return o}function br(t,n){var e;return sc(t,function(t,r,i){return e=n(t,r,i),!e}),!!e}function wr(t,n,e){var r=0,i=t?t.length:r;if("number"==typeof n&&n===n&&wt>=i){for(;i>r;){var o=r+i>>>1,a=t[o];null!==a&&!Cu(a)&&(e?n>=a:n>a)?r=o+1:i=o}return i}return Cr(t,n,Fs,e)}function Cr(t,n,e,r){n=e(n);for(var i=0,o=t?t.length:0,a=n!==n,u=null===n,s=Cu(n),l=n===U;o>i;){var c=Ll((i+o)/2),f=e(t[c]),h=f!==U,p=null===f,d=f===f,v=Cu(f);if(a)var g=r||d;else g=l?d&&(r||h):u?d&&h&&(r||!p):s?d&&h&&!p&&(r||!v):p||v?!1:r?n>=f:n>f;g?i=c+1:o=c}return Il(o,bt)}function Sr(t,n){for(var e=-1,r=t.length,i=0,o=[];++e<r;){var a=t[e],u=n?n(a):a;if(!e||!Ha(u,s)){var s=u;o[i++]=0===a?0:a}}return o}function _r(t){return"number"==typeof t?t:Cu(t)?$t:+t}function Mr(t){if("string"==typeof t)return t;if(Cu(t))return uc?uc.call(t):"";var n=t+"";return"0"==n&&1/t==-gt?"-0":n}function kr(t,n,e){var r=-1,i=l,o=t.length,a=!0,u=[],s=u;if(e)a=!1,i=c;else if(o>=Y){var f=n?null:pc(t);if(f)return z(f);a=!1,i=Gn,s=new Yn}else s=n?[]:u;t:for(;++r<o;){var h=t[r],p=n?n(h):h;if(h=e||0!==h?h:0,a&&p===p){for(var d=s.length;d--;)if(s[d]===p)continue t;n&&s.push(p),u.push(h)}else i(s,p,e)||(s!==u&&s.push(p),u.push(h))}return u}function Ar(t,n){n=Bi(n,t)?[n]:Rr(n),t=Ji(t,n);var e=Qi(bo(n));return!(null!=t&&We(t,e))||delete t[e]}function Er(t,n,e,r){return $r(t,n,e(qe(t,n)),r)}function Pr(t,n,e,r){for(var i=t.length,o=r?i:-1;(r?o--:++o<i)&&n(t[o],o,t););return e?xr(t,r?0:o,r?o+1:i):xr(t,r?o+1:0,r?i:o)}function Or(t,n){var e=t;return e instanceof Tn&&(e=e.value()),p(n,function(t,n){return n.func.apply(n.thisArg,h([t],n.args))},e)}function Tr(t,n,e){for(var r=-1,i=t.length;++r<i;)var o=o?h(Ee(o,t[r],n,e),Ee(t[r],o,n,e)):t[r];return o&&o.length?kr(o,n,e):[]}function Lr(t,n,e){for(var r=-1,i=t.length,o=n.length,a={};++r<i;){var u=o>r?n[r]:U;e(a,t[r],u)}return a}function jr(t){return Za(t)?t:[]}function Nr(t){return"function"==typeof t?t:Fs}function Rr(t){return tf(t)?t:yc(t)}function Dr(t,n,e){var r=t.length;return e=e===U?r:e,!n&&e>=r?t:xr(t,n,e)}function Fr(t,n){if(n)return t.slice();var e=new t.constructor(t.length);return t.copy(e),e}function Ir(t){var n=new t.constructor(t.byteLength);return new Cl(n).set(new Cl(t)),n}function zr(t,n){var e=n?Ir(t.buffer):t.buffer;return new t.constructor(e,t.byteOffset,t.byteLength)}function qr(n,e,r){var i=e?r(F(n),!0):F(n);return p(i,t,new n.constructor)}function Vr(t){var n=new t.constructor(t.source,$n.exec(t));return n.lastIndex=t.lastIndex,n}function Br(t,e,r){var i=e?r(z(t),!0):z(t);return p(i,n,new t.constructor)}function Wr(t){return ac?Object(ac.call(t)):{}}function Ur(t,n){var e=n?Ir(t.buffer):t.buffer;return new t.constructor(e,t.byteOffset,t.length)}function Hr(t,n){if(t!==n){var e=t!==U,r=null===t,i=t===t,o=Cu(t),a=n!==U,u=null===n,s=n===n,l=Cu(n);if(!u&&!l&&!o&&t>n||o&&a&&s&&!u&&!l||r&&a&&s||!e&&s||!i)return 1;if(!r&&!o&&!l&&n>t||l&&e&&i&&!r&&!o||u&&e&&i||!a&&i||!s)return-1}return 0}function Yr(t,n,e){for(var r=-1,i=t.criteria,o=n.criteria,a=i.length,u=e.length;++r<a;){var s=Hr(i[r],o[r]);if(s){if(r>=u)return s;var l=e[r];return s*("desc"==l?-1:1)}}return t.index-n.index}function Gr(t,n,e,r){for(var i=-1,o=t.length,a=e.length,u=-1,s=n.length,l=Fl(o-a,0),c=Array(s+l),f=!r;++u<s;)c[u]=n[u];for(;++i<a;)(f||o>i)&&(c[e[i]]=t[i]);for(;l--;)c[u++]=t[i++];return c}function Xr(t,n,e,r){for(var i=-1,o=t.length,a=-1,u=e.length,s=-1,l=n.length,c=Fl(o-u,0),f=Array(c+l),h=!r;++i<c;)f[i]=t[i];for(var p=i;++s<l;)f[p+s]=n[s];for(;++a<u;)(h||o>i)&&(f[p+e[a]]=t[i++]);return f}function Zr(t,n){var e=-1,r=t.length;for(n||(n=Array(r));++e<r;)n[e]=t[e];return n}function Jr(t,n,e,r){e||(e={});for(var i=-1,o=n.length;++i<o;){var a=n[i],u=r?r(e[a],t[a],a,e,t):t[a];le(e,a,u)}return e}function Kr(t,n){return Jr(t,Oi(t),n)}function Qr(t,n){return function(e,i){var o=tf(e)?r:ce,a=n?n():{};return o(e,t,Mi(i),a)}}function ti(t){return Ra(function(n,e){var r=-1,i=e.length,o=i>1?e[i-1]:U,a=i>2?e[2]:U;for(o="function"==typeof o?(i--,o):U,a&&Vi(e[0],e[1],a)&&(o=3>i?U:o,i=1),n=Object(n);++r<i;){var u=e[r];u&&t(n,u,r,o)}return n})}function ni(t,n){return function(e,r){if(null==e)return e;if(!Xa(e))return t(e,r);for(var i=e.length,o=n?i:-1,a=Object(e);(n?o--:++o<i)&&r(a[o],o,a)!==!1;);return e}}function ei(t){return function(n,e,r){for(var i=-1,o=Object(n),a=r(n),u=a.length;u--;){var s=a[t?u:++i];if(e(o[s],s,o)===!1)break}return n}}function ri(t,n,e){function r(){var n=this&&this!==Re&&this instanceof r?o:t;return n.apply(i?e:this,arguments)}var i=n&J,o=ai(t);return r}function ii(t){return function(n){n=ju(n);var e=ge.test(n)?V(n):U,r=e?e[0]:n.charAt(0),i=e?Dr(e,1).join(""):n.slice(1);return r[t]()+i}}function oi(t){return function(n){return p(js(ds(n).replace(he,"")),t,"")}}function ai(t){return function(){var n=arguments;switch(n.length){case 0:return new t;case 1:return new t(n[0]);case 2:return new t(n[0],n[1]);case 3:return new t(n[0],n[1],n[2]);case 4:return new t(n[0],n[1],n[2],n[3]);case 5:return new t(n[0],n[1],n[2],n[3],n[4]);case 6:return new t(n[0],n[1],n[2],n[3],n[4],n[5]);case 7:return new t(n[0],n[1],n[2],n[3],n[4],n[5],n[6])}var e=_e(t.prototype),r=t.apply(e,n);return su(r)?r:e}}function ui(t,n,r){function i(){for(var a=arguments.length,u=Array(a),s=a,l=Ei(i);s--;)u[s]=arguments[s];var c=3>a&&u[0]!==l&&u[a-1]!==l?[]:I(u,l);if(a-=c.length,r>a)return mi(t,n,li,i.placeholder,U,u,c,U,U,r-a);var f=this&&this!==Re&&this instanceof i?o:t;return e(f,this,u)}var o=ai(t);return i}function si(t){return Ra(function(n){n=Ne(n,1);var e=n.length,r=e,i=On.prototype.thru;for(t&&n.reverse();r--;){var o=n[r];if("function"!=typeof o)throw new ll(G);if(i&&!a&&"wrapper"==_i(o))var a=new On([],!0)}for(r=a?r:e;++r<e;){o=n[r];var u=_i(o),s="wrapper"==u?dc(o):U;a=s&&Ui(s[0])&&s[1]==(it|tt|et|ot)&&!s[4].length&&1==s[9]?a[_i(s[0])].apply(a,s[3]):1==o.length&&Ui(o)?a[u]():a.thru(o)}return function(){var t=arguments,r=t[0];if(a&&1==t.length&&tf(r)&&r.length>=Y)return a.plant(r).value();for(var i=0,o=e?n[i].apply(this,t):r;++i<e;)o=n[i].call(this,o);return o}})}function li(t,n,e,r,i,o,a,u,s,l){function c(){for(var m=arguments.length,y=m,$=Array(m);y--;)$[y]=arguments[y];if(d)var x=Ei(c),b=O($,x);if(r&&($=Gr($,r,i,d)),o&&($=Xr($,o,a,d)),m-=b,d&&l>m){var w=I($,x);return mi(t,n,li,c.placeholder,e,$,w,u,s,l-m)}var C=h?e:this,S=p?C[t]:t;return m=$.length,u?$=Ki($,u):v&&m>1&&$.reverse(),f&&m>s&&($.length=s),this&&this!==Re&&this instanceof c&&(S=g||ai(S)),S.apply(C,$)}var f=n&it,h=n&J,p=n&K,d=n&(tt|nt),v=n&at,g=p?U:ai(t);return c}function ci(t,n){return function(e,r){return Ge(e,t,n(r),{})}}function fi(t){return function(n,e){var r;if(n===U&&e===U)return 0;if(n!==U&&(r=n),e!==U){if(r===U)return e;"string"==typeof n||"string"==typeof e?(n=Mr(n),e=Mr(e)):(n=_r(n),e=_r(e)),r=t(n,e)}return r}}function hi(t){return Ra(function(n){return n=1==n.length&&tf(n[0])?f(n[0],M(Mi())):f(Ne(n,1,zi),M(Mi())),Ra(function(r){var i=this;return t(n,function(t){return e(t,i,r)})})})}function pi(t,n){n=n===U?" ":Mr(n);var e=n.length;if(2>e)return e?yr(n,t):n;var r=yr(n,Tl(t/q(n)));return ge.test(n)?Dr(V(r),0,t).join(""):r.slice(0,t)}function di(t,n,r,i){function o(){for(var n=-1,s=arguments.length,l=-1,c=i.length,f=Array(c+s),h=this&&this!==Re&&this instanceof o?u:t;++l<c;)f[l]=i[l];for(;s--;)f[l++]=arguments[++n];return e(h,a?r:this,f)}var a=n&J,u=ai(t);return o}function vi(t){return function(n,e,r){return r&&"number"!=typeof r&&Vi(n,e,r)&&(e=r=U),n=Ou(n),n=n===n?n:0,e===U?(e=n,n=0):e=Ou(e)||0,r=r===U?e>n?1:-1:Ou(r)||0,mr(n,e,r,t)}}function gi(t){return function(n,e){return"string"==typeof n&&"string"==typeof e||(n=Ou(n),e=Ou(e)),t(n,e)}}function mi(t,n,e,r,i,o,a,u,s,l){var c=n&tt,f=c?a:U,h=c?U:a,p=c?o:U,d=c?U:o;n|=c?et:rt,n&=~(c?rt:et),n&Q||(n&=~(J|K));var v=[t,n,i,p,f,d,h,u,s,l],g=e.apply(U,v);return Ui(t)&&mc(g,v),g.placeholder=r,g}function yi(t){var n=ul[t];return function(t,e){if(t=Ou(t),e=Eu(e)){var r=(ju(t)+"e").split("e"),i=n(r[0]+"e"+(+r[1]+e));return r=(ju(i)+"e").split("e"),+(r[0]+"e"+(+r[1]-e))}return n(t)}}function $i(t,n,e,r,i,o,a,u){var s=n&K;if(!s&&"function"!=typeof t)throw new ll(G);var l=r?r.length:0;if(l||(n&=~(et|rt),r=i=U),a=a===U?a:Fl(Eu(a),0),u=u===U?u:Eu(u),l-=i?i.length:0,n&rt){var c=r,f=i;r=i=U}var h=s?U:dc(t),p=[t,n,e,r,i,c,f,o,a,u];if(h&&Xi(p,h),t=p[0],n=p[1],e=p[2],r=p[3],i=p[4],u=p[9]=null==p[9]?s?0:t.length:Fl(p[9]-l,0),!u&&n&(tt|nt)&&(n&=~(tt|nt)),n&&n!=J)d=n==tt||n==nt?ui(t,n,u):n!=et&&n!=(J|et)||i.length?li.apply(U,p):di(t,n,e,r);else var d=ri(t,n,e);var v=h?hc:mc;return v(d,p)}function xi(t,n,e,r,i,o){var a=-1,u=i&st,s=i&ut,l=t.length,c=n.length;if(l!=c&&!(u&&c>l))return!1;var f=o.get(t);if(f)return f==n;var h=!0;for(o.set(t,n);++a<l;){var p=t[a],d=n[a];if(r)var g=u?r(d,p,a,n,t,o):r(p,d,a,t,n,o);if(g!==U){if(g)continue;h=!1;break}if(s){if(!v(n,function(t){return p===t||e(p,t,r,i,o)})){h=!1;break}}else if(p!==d&&!e(p,d,r,i,o)){h=!1;break}}return o["delete"](t),h}function bi(t,n,e,r,i,o,a){switch(e){case qt:if(t.byteLength!=n.byteLength||t.byteOffset!=n.byteOffset)return!1;t=t.buffer,n=n.buffer;case zt:return!(t.byteLength!=n.byteLength||!r(new Cl(t),new Cl(n)));case _t:case Mt:return+t==+n;case kt:return t.name==n.name&&t.message==n.message;case Ot:return t!=+t?n!=+n:t==+n;case jt:case Rt:return t==n+"";case Pt:var u=F;case Nt:var s=o&st;if(u||(u=z),t.size!=n.size&&!s)return!1;var l=a.get(t);return l?l==n:(o|=ut,a.set(t,n),xi(u(t),u(n),r,i,o,a));case Dt:if(ac)return ac.call(t)==ac.call(n)}return!1}function wi(t,n,e,r,i,o){var a=i&st,u=Yu(t),s=u.length,l=Yu(n),c=l.length;if(s!=c&&!a)return!1;for(var f=s;f--;){var h=u[f];if(!(a?h in n:We(n,h)))return!1}var p=o.get(t);if(p)return p==n;var d=!0;o.set(t,n);for(var v=a;++f<s;){h=u[f];var g=t[h],m=n[h];if(r)var y=a?r(m,g,h,n,t,o):r(g,m,h,t,n,o);if(!(y===U?g===m||e(g,m,r,i,o):y)){d=!1;break}v||(v="constructor"==h)}if(d&&!v){var $=t.constructor,x=n.constructor;$!=x&&"constructor"in t&&"constructor"in n&&!("function"==typeof $&&$ instanceof $&&"function"==typeof x&&x instanceof x)&&(d=!1)}return o["delete"](t),d}function Ci(t){return Ve(t,Yu,Oi)}function Si(t){return Ve(t,Gu,gc)}function _i(t){for(var n=t.name+"",e=Ql[n],r=dl.call(Ql,n)?e.length:0;r--;){var i=e[r],o=i.func;if(null==o||o==t)return i.name}return n}function Mi(){var t=En.iteratee||Is;return t=t===Is?Qe:t,arguments.length?t(arguments[0],arguments[1]):t}function ki(t){for(var n=es(t),e=n.length;e--;)n[e][2]=Yi(n[e][1]);return n}function Ai(t,n){var e=t[n];return du(e)?e:U}function Ei(t){var n=dl.call(En,"placeholder")?En:t;return n.placeholder}function Pi(t){return jl(Object(t))}function Oi(t){return Ml(Object(t))}function Ti(t){return ml.call(t)}function Li(t,n,e){for(var r=-1,i=e.length;++r<i;){var o=e[r],a=o.size;switch(o.type){case"drop":t+=a;break;case"dropRight":n-=a;break;case"take":n=Il(n,t+a);break;case"takeRight":t=Fl(t,n-a)}}return{start:t,end:n}}function ji(t,n,e){n=Bi(n,t)?[n]:Rr(n);for(var r,i=-1,o=n.length;++i<o;){var a=Qi(n[i]);if(!(r=null!=t&&e(t,a)))break;t=t[a]}if(r)return r;var o=t?t.length:0;return!!o&&uu(o)&&qi(a,o)&&(tf(t)||wu(t)||Ya(t))}function Ni(t){var n=t.length,e=t.constructor(n);return n&&"string"==typeof t[0]&&dl.call(t,"index")&&(e.index=t.index,e.input=t.input),e}function Ri(t){return"function"!=typeof t.constructor||Hi(t)?{}:_e(Pi(t))}function Di(t,n,e,r){var i=t.constructor;switch(n){case zt:return Ir(t);case _t:case Mt:return new i(+t);case qt:return zr(t,r);case Vt:case Bt:case Wt:case Ut:case Ht:case Yt:case Gt:case Xt:case Zt:return Ur(t,r);case Pt:return qr(t,r,e);case Ot:case Rt:return new i(t);case jt:return Vr(t);case Nt:return Br(t,r,e);case Dt:return Wr(t)}}function Fi(t){var n=t?t.length:U;return uu(n)&&(tf(t)||wu(t)||Ya(t))?S(n,String):null}function Ii(t){return Za(t)&&(tf(t)||Ya(t))}function zi(t){return tf(t)&&!(2==t.length&&!ou(t[0]))}function qi(t,n){return n=null==n?mt:n,!!n&&("number"==typeof t||_n.test(t))&&t>-1&&t%1==0&&n>t}function Vi(t,n,e){if(!su(e))return!1;var r=typeof n;return("number"==r?Xa(e)&&qi(n,e.length):"string"==r&&n in e)?Ha(e[n],t):!1}function Bi(t,n){if(tf(t))return!1;var e=typeof t;return"number"==e||"symbol"==e||"boolean"==e||null==t||Cu(t)?!0:ln.test(t)||!sn.test(t)||null!=n&&t in Object(n)}function Wi(t){var n=typeof t;return"string"==n||"number"==n||"symbol"==n||"boolean"==n?"__proto__"!==t:null===t}function Ui(t){var n=_i(t),e=En[n];if("function"!=typeof e||!(n in Tn.prototype))return!1;if(t===e)return!0;var r=dc(e);return!!r&&t===r[0]}function Hi(t){var n=t&&t.constructor,e="function"==typeof n&&n.prototype||fl;return t===e}function Yi(t){return t===t&&!su(t)}function Gi(t,n){return function(e){return null==e?!1:e[t]===n&&(n!==U||t in Object(e))}}function Xi(t,n){var e=t[1],r=n[1],i=e|r,o=(J|K|it)>i,a=r==it&&e==tt||r==it&&e==ot&&t[7].length<=n[8]||r==(it|ot)&&n[7].length<=n[8]&&e==tt;if(!o&&!a)return t;r&J&&(t[2]=n[2],i|=e&J?0:Q);var u=n[3];if(u){var s=t[3];t[3]=s?Gr(s,u,n[4]):u,t[4]=s?I(t[3],Z):n[4]}return u=n[5],u&&(s=t[5],t[5]=s?Xr(s,u,n[6]):u,t[6]=s?I(t[5],Z):n[6]),u=n[7],u&&(t[7]=u),r&it&&(t[8]=null==t[8]?n[8]:Il(t[8],n[8])),null==t[9]&&(t[9]=n[9]),t[0]=n[0],t[1]=i,t}function Zi(t,n,e,r,i,o){return su(t)&&su(n)&&ar(t,n,U,Zi,o.set(n,t)),t}function Ji(t,n){return 1==n.length?t:qe(t,xr(n,0,-1))}function Ki(t,n){for(var e=t.length,r=Il(n.length,e),i=Zr(t);r--;){var o=n[r];t[r]=qi(o,e)?i[o]:U}return t}function Qi(t){if("string"==typeof t||Cu(t))return t;var n=t+"";return"0"==n&&1/t==-gt?"-0":n}function to(t){if(null!=t){try{return pl.call(t)}catch(n){}try{return t+""}catch(n){}}return""}function no(t){if(t instanceof Tn)return t.clone();var n=new On(t.__wrapped__,t.__chain__);return n.__actions__=Zr(t.__actions__),n.__index__=t.__index__,n.__values__=t.__values__,n}function eo(t,n,e){n=(e?Vi(t,n,e):n===U)?1:Fl(Eu(n),0);var r=t?t.length:0;if(!r||1>n)return[];for(var i=0,o=0,a=Array(Tl(r/n));r>i;)a[o++]=xr(t,i,i+=n);return a}function ro(t){for(var n=-1,e=t?t.length:0,r=0,i=[];++n<e;){var o=t[n];o&&(i[r++]=o)}return i}function io(){var t=arguments.length,n=qa(arguments[0]);if(2>t)return t?Zr(n):[];for(var e=Array(t-1);t--;)e[t-1]=arguments[t];return i(n,Ne(e,1))}function oo(t,n,e){var r=t?t.length:0;return r?(n=e||n===U?1:Eu(n),xr(t,0>n?0:n,r)):[]}function ao(t,n,e){var r=t?t.length:0;return r?(n=e||n===U?1:Eu(n),n=r-n,xr(t,0,0>n?0:n)):[]}function uo(t,n){return t&&t.length?Pr(t,Mi(n,3),!0,!0):[]}function so(t,n){return t&&t.length?Pr(t,Mi(n,3),!0):[]}function lo(t,n,e,r){var i=t?t.length:0;return i?(e&&"number"!=typeof e&&Vi(t,n,e)&&(e=0,r=i),Le(t,n,e,r)):[]}function co(t,n){return t&&t.length?m(t,Mi(n,3)):-1}function fo(t,n){return t&&t.length?m(t,Mi(n,3),!0):-1}function ho(t){var n=t?t.length:0;return n?Ne(t,1):[]}function po(t){var n=t?t.length:0;return n?Ne(t,gt):[]}function vo(t,n){var e=t?t.length:0;return e?(n=n===U?1:Eu(n),Ne(t,n)):[]}function go(t){for(var n=-1,e=t?t.length:0,r={};++n<e;){var i=t[n];r[i[0]]=i[1]}return r}function mo(t){return t&&t.length?t[0]:U}function yo(t,n,e){var r=t?t.length:0;return r?(e=Eu(e),0>e&&(e=Fl(r+e,0)),y(t,n,e)):-1}function $o(t){return ao(t,1)}function xo(t,n){return t?Rl.call(t,n):""}function bo(t){var n=t?t.length:0;return n?t[n-1]:U}function wo(t,n,e){var r=t?t.length:0;if(!r)return-1;var i=r;if(e!==U&&(i=Eu(e),i=(0>i?Fl(r+i,0):Il(i,r-1))+1),n!==n)return N(t,i,!0);for(;i--;)if(t[i]===n)return i;return-1}function Co(t,n){return t&&t.length?sr(t,Eu(n)):U}function So(t,n){return t&&t.length&&n&&n.length?dr(t,n):t}function _o(t,n,e){return t&&t.length&&n&&n.length?dr(t,n,Mi(e)):t}function Mo(t,n,e){return t&&t.length&&n&&n.length?dr(t,n,U,e):t}function ko(t,n){var e=[];if(!t||!t.length)return e;var r=-1,i=[],o=t.length;for(n=Mi(n,3);++r<o;){var a=t[r];n(a,r,t)&&(e.push(a),i.push(r))}return vr(t,i),e}function Ao(t){return t?Bl.call(t):t}function Eo(t,n,e){var r=t?t.length:0;return r?(e&&"number"!=typeof e&&Vi(t,n,e)?(n=0,e=r):(n=null==n?0:Eu(n),e=e===U?r:Eu(e)),xr(t,n,e)):[]}function Po(t,n){return wr(t,n)}function Oo(t,n,e){return Cr(t,n,Mi(e))}function To(t,n){var e=t?t.length:0;if(e){var r=wr(t,n);if(e>r&&Ha(t[r],n))return r}return-1}function Lo(t,n){return wr(t,n,!0)}function jo(t,n,e){return Cr(t,n,Mi(e),!0)}function No(t,n){var e=t?t.length:0;if(e){var r=wr(t,n,!0)-1;if(Ha(t[r],n))return r}return-1}function Ro(t){return t&&t.length?Sr(t):[]}function Do(t,n){return t&&t.length?Sr(t,Mi(n)):[]}function Fo(t){return oo(t,1)}function Io(t,n,e){return t&&t.length?(n=e||n===U?1:Eu(n),xr(t,0,0>n?0:n)):[]}function zo(t,n,e){var r=t?t.length:0;return r?(n=e||n===U?1:Eu(n),n=r-n,xr(t,0>n?0:n,r)):[]}function qo(t,n){return t&&t.length?Pr(t,Mi(n,3),!1,!0):[]}function Vo(t,n){return t&&t.length?Pr(t,Mi(n,3)):[]}function Bo(t){return t&&t.length?kr(t):[]}function Wo(t,n){return t&&t.length?kr(t,Mi(n)):[]}function Uo(t,n){return t&&t.length?kr(t,U,n):[]}function Ho(t){if(!t||!t.length)return[];var n=0;return t=s(t,function(t){return Za(t)?(n=Fl(t.length,n),!0):void 0}),S(n,function(n){return f(t,hr(n))})}function Yo(t,n){if(!t||!t.length)return[];var r=Ho(t);return null==n?r:f(r,function(t){return e(n,U,t)})}function Go(t,n){return Lr(t||[],n||[],le)}function Xo(t,n){return Lr(t||[],n||[],$r)}function Zo(t){var n=En(t);return n.__chain__=!0,n}function Jo(t,n){return n(t),t}function Ko(t,n){return n(t)}function Qo(){return Zo(this)}function ta(){return new On(this.value(),this.__chain__)}function na(){this.__values__===U&&(this.__values__=Au(this.value()));var t=this.__index__>=this.__values__.length,n=t?U:this.__values__[this.__index__++];return{done:t,value:n}}function ea(){return this}function ra(t){for(var n,e=this;e instanceof Pn;){var r=no(e);r.__index__=0,r.__values__=U,n?i.__wrapped__=r:n=r;var i=r;e=e.__wrapped__}return i.__wrapped__=t,n}function ia(){var t=this.__wrapped__;if(t instanceof Tn){var n=t;return this.__actions__.length&&(n=new Tn(this)),n=n.reverse(),n.__actions__.push({func:Ko,args:[Ao],thisArg:U}),new On(n,this.__chain__)}return this.thru(Ao)}function oa(){return Or(this.__wrapped__,this.__actions__)}function aa(t,n,e){var r=tf(t)?u:Pe;return e&&Vi(t,n,e)&&(n=U),r(t,Mi(n,3))}function ua(t,n){var e=tf(t)?s:je;return e(t,Mi(n,3))}function sa(t,n){if(n=Mi(n,3),tf(t)){var e=m(t,n);return e>-1?t[e]:U}return g(t,n,sc)}function la(t,n){if(n=Mi(n,3),tf(t)){var e=m(t,n,!0);return e>-1?t[e]:U}return g(t,n,lc)}function ca(t,n){return Ne(ga(t,n),1)}function fa(t,n){return Ne(ga(t,n),gt)}function ha(t,n,e){return e=e===U?1:Eu(e),Ne(ga(t,n),e)}function pa(t,n){return"function"==typeof n&&tf(t)?o(t,n):sc(t,Mi(n))}function da(t,n){return"function"==typeof n&&tf(t)?a(t,n):lc(t,Mi(n))}function va(t,n,e,r){t=Xa(t)?t:ss(t),e=e&&!r?Eu(e):0;var i=t.length;return 0>e&&(e=Fl(i+e,0)),wu(t)?i>=e&&t.indexOf(n,e)>-1:!!i&&y(t,n,e)>-1}function ga(t,n){var e=tf(t)?f:rr;return e(t,Mi(n,3))}function ma(t,n,e,r){return null==t?[]:(tf(n)||(n=null==n?[]:[n]),e=r?U:e,tf(e)||(e=null==e?[]:[e]),lr(t,n,e))}function ya(t,n,e){var r=tf(t)?p:b,i=arguments.length<3;return r(t,Mi(n,4),e,i,sc)}function $a(t,n,e){var r=tf(t)?d:b,i=arguments.length<3;return r(t,Mi(n,4),e,i,lc)}function xa(t,n){var e=tf(t)?s:je;return n=Mi(n,3),e(t,function(t,e,r){return!n(t,e,r)})}function ba(t){var n=Xa(t)?t:ss(t),e=n.length;return e>0?n[gr(0,e-1)]:U}function wa(t,n,e){var r=-1,i=Au(t),o=i.length,a=o-1;for(n=(e?Vi(t,n,e):n===U)?1:we(Eu(n),0,o);++r<n;){var u=gr(r,a),s=i[u];i[u]=i[r],i[r]=s}return i.length=n,i}function Ca(t){return wa(t,xt)}function Sa(t){if(null==t)return 0;if(Xa(t)){var n=t.length;return n&&wu(t)?q(t):n}if(lu(t)){var e=Ti(t);if(e==Pt||e==Nt)return t.size}return Yu(t).length}function _a(t,n,e){var r=tf(t)?v:br;return e&&Vi(t,n,e)&&(n=U),r(t,Mi(n,3))}function Ma(t,n){if("function"!=typeof n)throw new ll(G);return t=Eu(t),function(){return--t<1?n.apply(this,arguments):void 0}}function ka(t,n,e){return n=e?U:n,n=t&&null==n?t.length:n,$i(t,it,U,U,U,U,n)}function Aa(t,n){var e;if("function"!=typeof n)throw new ll(G);return t=Eu(t),function(){return--t>0&&(e=n.apply(this,arguments)),1>=t&&(n=U),e}}function Ea(t,n,e){n=e?U:n;var r=$i(t,tt,U,U,U,U,U,n);return r.placeholder=Ea.placeholder,r}function Pa(t,n,e){n=e?U:n;var r=$i(t,nt,U,U,U,U,U,n);return r.placeholder=Pa.placeholder,r}function Oa(t,n,e){function r(n){var e=h,r=p;return h=p=U,y=n,v=t.apply(r,e)}function i(t){return y=t,g=Pl(u,n),$?r(t):v}function o(t){var e=t-m,r=t-y,i=n-e;return x?Il(i,d-r):i}function a(t){var e=t-m,r=t-y;return!m||e>=n||0>e||x&&r>=d}function u(){var t=Bc();return a(t)?s(t):void(g=Pl(u,o(t)))}function s(t){return Sl(g),g=U,b&&h?r(t):(h=p=U,v)}function l(){g!==U&&Sl(g),m=y=0,h=p=g=U}function c(){return g===U?v:s(Bc())}function f(){var t=Bc(),e=a(t);if(h=arguments,p=this,m=t,e){if(g===U)return i(m);if(x)return Sl(g),g=Pl(u,n),r(m)}return g===U&&(g=Pl(u,n)),v}var h,p,d,v,g,m=0,y=0,$=!1,x=!1,b=!0;if("function"!=typeof t)throw new ll(G);return n=Ou(n)||0,su(e)&&($=!!e.leading,x="maxWait"in e,d=x?Fl(Ou(e.maxWait)||0,n):d,b="trailing"in e?!!e.trailing:b),f.cancel=l,f.flush=c,f}function Ta(t){return $i(t,at)}function La(t,n){if("function"!=typeof t||n&&"function"!=typeof n)throw new ll(G);var e=function(){var r=arguments,i=n?n.apply(this,r):r[0],o=e.cache;if(o.has(i))return o.get(i);var a=t.apply(this,r);return e.cache=o.set(i,a),a};return e.cache=new(La.Cache||qn),e}function ja(t){if("function"!=typeof t)throw new ll(G);return function(){return!t.apply(this,arguments)}}function Na(t){return Aa(2,t)}function Ra(t,n){if("function"!=typeof t)throw new ll(G);return n=Fl(n===U?t.length-1:Eu(n),0),function(){for(var r=arguments,i=-1,o=Fl(r.length-n,0),a=Array(o);++i<o;)a[i]=r[n+i];switch(n){case 0:return t.call(this,a);case 1:return t.call(this,r[0],a);case 2:return t.call(this,r[0],r[1],a)}var u=Array(n+1);for(i=-1;++i<n;)u[i]=r[i];return u[n]=a,e(t,this,u)}}function Da(t,n){if("function"!=typeof t)throw new ll(G);return n=n===U?0:Fl(Eu(n),0),Ra(function(r){var i=r[n],o=Dr(r,0,n);return i&&h(o,i),e(t,this,o)})}function Fa(t,n,e){var r=!0,i=!0;if("function"!=typeof t)throw new ll(G);return su(e)&&(r="leading"in e?!!e.leading:r,i="trailing"in e?!!e.trailing:i),Oa(t,n,{leading:r,maxWait:n,trailing:i})}function Ia(t){return ka(t,1)}function za(t,n){return n=null==n?Fs:n,Xc(n,t)}function qa(){if(!arguments.length)return[];var t=arguments[0];return tf(t)?t:[t]}function Va(t){return Ce(t,!1,!0)}function Ba(t,n){return Ce(t,!1,!0,n)}function Wa(t){return Ce(t,!0,!0)}function Ua(t,n){return Ce(t,!0,!0,n)}function Ha(t,n){return t===n||t!==t&&n!==n}function Ya(t){return Za(t)&&dl.call(t,"callee")&&(!El.call(t,"callee")||ml.call(t)==Ct)}function Ga(t){return lu(t)&&ml.call(t)==zt}function Xa(t){return null!=t&&uu(vc(t))&&!ou(t)}function Za(t){return lu(t)&&Xa(t)}function Ja(t){return t===!0||t===!1||lu(t)&&ml.call(t)==_t}function Ka(t){return lu(t)&&ml.call(t)==Mt}function Qa(t){return!!t&&1===t.nodeType&&lu(t)&&!yu(t)}function tu(t){if(Xa(t)&&(tf(t)||wu(t)||ou(t.splice)||Ya(t)||nf(t)))return!t.length;if(lu(t)){var n=Ti(t);if(n==Pt||n==Nt)return!t.size}for(var e in t)if(dl.call(t,e))return!1;return!(Kl&&Yu(t).length)}function nu(t,n){return Ze(t,n)}function eu(t,n,e){e="function"==typeof e?e:U;var r=e?e(t,n):U;return r===U?Ze(t,n,e):!!r}function ru(t){return lu(t)?ml.call(t)==kt||"string"==typeof t.message&&"string"==typeof t.name:!1}function iu(t){return"number"==typeof t&&Nl(t)}function ou(t){var n=su(t)?ml.call(t):"";return n==At||n==Et}function au(t){return"number"==typeof t&&t==Eu(t)}function uu(t){return"number"==typeof t&&t>-1&&t%1==0&&mt>=t}function su(t){var n=typeof t;return!!t&&("object"==n||"function"==n)}function lu(t){return!!t&&"object"==typeof t}function cu(t){return lu(t)&&Ti(t)==Pt}function fu(t,n){return t===n||Ke(t,n,ki(n))}function hu(t,n,e){return e="function"==typeof e?e:U,Ke(t,n,ki(n),e)}function pu(t){return mu(t)&&t!=+t}function du(t){if(!su(t))return!1;var n=ou(t)||R(t)?$l:Cn;return n.test(to(t))}function vu(t){return null===t}function gu(t){return null==t}function mu(t){return"number"==typeof t||lu(t)&&ml.call(t)==Ot}function yu(t){if(!lu(t)||ml.call(t)!=Tt||R(t))return!1;var n=Pi(t);if(null===n)return!0;var e=dl.call(n,"constructor")&&n.constructor;return"function"==typeof e&&e instanceof e&&pl.call(e)==gl}function $u(t){return su(t)&&ml.call(t)==jt}function xu(t){return au(t)&&t>=-mt&&mt>=t}function bu(t){return lu(t)&&Ti(t)==Nt}function wu(t){return"string"==typeof t||!tf(t)&&lu(t)&&ml.call(t)==Rt}function Cu(t){return"symbol"==typeof t||lu(t)&&ml.call(t)==Dt}function Su(t){return lu(t)&&uu(t.length)&&!!xe[ml.call(t)]}function _u(t){return t===U}function Mu(t){return lu(t)&&Ti(t)==Ft}function ku(t){return lu(t)&&ml.call(t)==It}function Au(t){if(!t)return[];if(Xa(t))return wu(t)?V(t):Zr(t);if(kl&&t[kl])return D(t[kl]());var n=Ti(t),e=n==Pt?F:n==Nt?z:ss;return e(t)}function Eu(t){if(!t)return 0===t?t:0;if(t=Ou(t),t===gt||t===-gt){var n=0>t?-1:1;return n*yt}var e=t%1;return t===t?e?t-e:t:0}function Pu(t){return t?we(Eu(t),0,xt):0}function Ou(t){if("number"==typeof t)return t;if(Cu(t))return $t;if(su(t)){var n=ou(t.valueOf)?t.valueOf():t;t=su(n)?n+"":n}if("string"!=typeof t)return 0===t?t:+t;t=t.replace(pn,"");var e=wn.test(t);return e||Sn.test(t)?Ae(t.slice(2),e?2:8):bn.test(t)?$t:+t}function Tu(t){return Jr(t,Gu(t))}function Lu(t){return we(Eu(t),-mt,mt)}function ju(t){return null==t?"":Mr(t)}function Nu(t,n){var e=_e(t);return n?fe(e,n):e}function Ru(t,n){return g(t,Mi(n,3),Fe,!0);
+}function Du(t,n){return g(t,Mi(n,3),Ie,!0)}function Fu(t,n){return null==t?t:cc(t,Mi(n),Gu)}function Iu(t,n){return null==t?t:fc(t,Mi(n),Gu)}function zu(t,n){return t&&Fe(t,Mi(n))}function qu(t,n){return t&&Ie(t,Mi(n))}function Vu(t){return null==t?[]:ze(t,Yu(t))}function Bu(t){return null==t?[]:ze(t,Gu(t))}function Wu(t,n,e){var r=null==t?U:qe(t,n);return r===U?e:r}function Uu(t,n){return null!=t&&ji(t,n,We)}function Hu(t,n){return null!=t&&ji(t,n,Ue)}function Yu(t){var n=Hi(t);if(!n&&!Xa(t))return tr(t);var e=Fi(t),r=!!e,i=e||[],o=i.length;for(var a in t)!We(t,a)||r&&("length"==a||qi(a,o))||n&&"constructor"==a||i.push(a);return i}function Gu(t){for(var n=-1,e=Hi(t),r=nr(t),i=r.length,o=Fi(t),a=!!o,u=o||[],s=u.length;++n<i;){var l=r[n];a&&("length"==l||qi(l,s))||"constructor"==l&&(e||!dl.call(t,l))||u.push(l)}return u}function Xu(t,n){var e={};return n=Mi(n,3),Fe(t,function(t,r,i){e[n(t,r,i)]=t}),e}function Zu(t,n){var e={};return n=Mi(n,3),Fe(t,function(t,r,i){e[r]=n(t,r,i)}),e}function Ju(t,n){return n=Mi(n),fr(t,function(t,e){return!n(t,e)})}function Ku(t,n){return null==t?{}:fr(t,Mi(n))}function Qu(t,n,e){n=Bi(n,t)?[n]:Rr(n);var r=-1,i=n.length;for(i||(t=U,i=1);++r<i;){var o=null==t?U:t[Qi(n[r])];o===U&&(r=i,o=e),t=ou(o)?o.call(t):o}return t}function ts(t,n,e){return null==t?t:$r(t,n,e)}function ns(t,n,e,r){return r="function"==typeof r?r:U,null==t?t:$r(t,n,e,r)}function es(t){return _(t,Yu(t))}function rs(t){return _(t,Gu(t))}function is(t,n,e){var r=tf(t)||Su(t);if(n=Mi(n,4),null==e)if(r||su(t)){var i=t.constructor;e=r?tf(t)?new i:[]:ou(i)?_e(Pi(t)):{}}else e={};return(r?o:Fe)(t,function(t,r,i){return n(e,t,r,i)}),e}function os(t,n){return null==t?!0:Ar(t,n)}function as(t,n,e){return null==t?t:Er(t,n,Nr(e))}function us(t,n,e,r){return r="function"==typeof r?r:U,null==t?t:Er(t,n,Nr(e),r)}function ss(t){return t?k(t,Yu(t)):[]}function ls(t){return null==t?[]:k(t,Gu(t))}function cs(t,n,e){return e===U&&(e=n,n=U),e!==U&&(e=Ou(e),e=e===e?e:0),n!==U&&(n=Ou(n),n=n===n?n:0),we(Ou(t),n,e)}function fs(t,n,e){return n=Ou(n)||0,e===U?(e=n,n=0):e=Ou(e)||0,t=Ou(t),He(t,n,e)}function hs(t,n,e){if(e&&"boolean"!=typeof e&&Vi(t,n,e)&&(n=e=U),e===U&&("boolean"==typeof n?(e=n,n=U):"boolean"==typeof t&&(e=t,t=U)),t===U&&n===U?(t=0,n=1):(t=Ou(t)||0,n===U?(n=t,t=0):n=Ou(n)||0),t>n){var r=t;t=n,n=r}if(e||t%1||n%1){var i=ql();return Il(t+i*(n-t+ke("1e-"+((i+"").length-1))),n)}return gr(t,n)}function ps(t){return Mf(ju(t).toLowerCase())}function ds(t){return t=ju(t),t&&t.replace(Mn,T).replace(pe,"")}function vs(t,n,e){t=ju(t),n=Mr(n);var r=t.length;return e=e===U?r:we(Eu(e),0,r),e-=n.length,e>=0&&t.indexOf(n,e)==e}function gs(t){return t=ju(t),t&&rn.test(t)?t.replace(nn,L):t}function ms(t){return t=ju(t),t&&hn.test(t)?t.replace(fn,"\\$&"):t}function ys(t,n,e){t=ju(t),n=Eu(n);var r=n?q(t):0;if(!n||r>=n)return t;var i=(n-r)/2;return pi(Ll(i),e)+t+pi(Tl(i),e)}function $s(t,n,e){t=ju(t),n=Eu(n);var r=n?q(t):0;return n&&n>r?t+pi(n-r,e):t}function xs(t,n,e){t=ju(t),n=Eu(n);var r=n?q(t):0;return n&&n>r?pi(n-r,e)+t:t}function bs(t,n,e){return e||null==n?n=0:n&&(n=+n),t=ju(t).replace(pn,""),zl(t,n||(xn.test(t)?16:10))}function ws(t,n,e){return n=(e?Vi(t,n,e):n===U)?1:Eu(n),yr(ju(t),n)}function Cs(){var t=arguments,n=ju(t[0]);return t.length<3?n:Vl.call(n,t[1],t[2])}function Ss(t,n,e){return e&&"number"!=typeof e&&Vi(t,n,e)&&(n=e=U),(e=e===U?xt:e>>>0)?(t=ju(t),t&&("string"==typeof n||null!=n&&!$u(n))&&(n=Mr(n),""==n&&ge.test(t))?Dr(V(t),0,e):Wl.call(t,n,e)):[]}function _s(t,n,e){return t=ju(t),e=we(Eu(e),0,t.length),t.lastIndexOf(Mr(n),e)==e}function Ms(t,n,e){var r=En.templateSettings;e&&Vi(t,n,e)&&(n=U),t=ju(t),n=uf({},n,r,ue);var i,o,a=uf({},n.imports,r.imports,ue),u=Yu(a),s=k(a,u),l=0,c=n.interpolate||kn,f="__p += '",h=sl((n.escape||kn).source+"|"+c.source+"|"+(c===un?yn:kn).source+"|"+(n.evaluate||kn).source+"|$","g"),p="//# sourceURL="+("sourceURL"in n?n.sourceURL:"lodash.templateSources["+ ++$e+"]")+"\n";t.replace(h,function(n,e,r,a,u,s){return r||(r=a),f+=t.slice(l,s).replace(An,j),e&&(i=!0,f+="' +\n__e("+e+") +\n'"),u&&(o=!0,f+="';\n"+u+";\n__p += '"),r&&(f+="' +\n((__t = ("+r+")) == null ? '' : __t) +\n'"),l=s+n.length,n}),f+="';\n";var d=n.variable;d||(f="with (obj) {\n"+f+"\n}\n"),f=(o?f.replace(Jt,""):f).replace(Kt,"$1").replace(Qt,"$1;"),f="function("+(d||"obj")+") {\n"+(d?"":"obj || (obj = {});\n")+"var __t, __p = ''"+(i?", __e = _.escape":"")+(o?", __j = Array.prototype.join;\nfunction print() { __p += __j.call(arguments, '') }\n":";\n")+f+"return __p\n}";var v=kf(function(){return Function(u,p+"return "+f).apply(U,s)});if(v.source=f,ru(v))throw v;return v}function ks(t){return ju(t).toLowerCase()}function As(t){return ju(t).toUpperCase()}function Es(t,n,e){if(t=ju(t),t&&(e||n===U))return t.replace(pn,"");if(!t||!(n=Mr(n)))return t;var r=V(t),i=V(n),o=A(r,i),a=E(r,i)+1;return Dr(r,o,a).join("")}function Ps(t,n,e){if(t=ju(t),t&&(e||n===U))return t.replace(vn,"");if(!t||!(n=Mr(n)))return t;var r=V(t),i=E(r,V(n))+1;return Dr(r,0,i).join("")}function Os(t,n,e){if(t=ju(t),t&&(e||n===U))return t.replace(dn,"");if(!t||!(n=Mr(n)))return t;var r=V(t),i=A(r,V(n));return Dr(r,i).join("")}function Ts(t,n){var e=lt,r=ct;if(su(n)){var i="separator"in n?n.separator:i;e="length"in n?Eu(n.length):e,r="omission"in n?Mr(n.omission):r}t=ju(t);var o=t.length;if(ge.test(t)){var a=V(t);o=a.length}if(e>=o)return t;var u=e-q(r);if(1>u)return r;var s=a?Dr(a,0,u).join(""):t.slice(0,u);if(i===U)return s+r;if(a&&(u+=s.length-u),$u(i)){if(t.slice(u).search(i)){var l,c=s;for(i.global||(i=sl(i.source,ju($n.exec(i))+"g")),i.lastIndex=0;l=i.exec(c);)var f=l.index;s=s.slice(0,f===U?u:f)}}else if(t.indexOf(Mr(i),u)!=u){var h=s.lastIndexOf(i);h>-1&&(s=s.slice(0,h))}return s+r}function Ls(t){return t=ju(t),t&&en.test(t)?t.replace(tn,B):t}function js(t,n,e){return t=ju(t),n=e?U:n,n===U&&(n=me.test(t)?ve:gn),t.match(n)||[]}function Ns(t){var n=t?t.length:0,r=Mi();return t=n?f(t,function(t){if("function"!=typeof t[1])throw new ll(G);return[r(t[0]),t[1]]}):[],Ra(function(r){for(var i=-1;++i<n;){var o=t[i];if(e(o[0],this,r))return e(o[1],this,r)}})}function Rs(t){return Se(Ce(t,!0))}function Ds(t){return function(){return t}}function Fs(t){return t}function Is(t){return Qe("function"==typeof t?t:Ce(t,!0))}function zs(t){return ir(Ce(t,!0))}function qs(t,n){return or(t,Ce(n,!0))}function Vs(t,n,e){var r=Yu(n),i=ze(n,r);null!=e||su(n)&&(i.length||!r.length)||(e=n,n=t,t=this,i=ze(n,Yu(n)));var a=!(su(e)&&"chain"in e&&!e.chain),u=ou(t);return o(i,function(e){var r=n[e];t[e]=r,u&&(t.prototype[e]=function(){var n=this.__chain__;if(a||n){var e=t(this.__wrapped__),i=e.__actions__=Zr(this.__actions__);return i.push({func:r,args:arguments,thisArg:t}),e.__chain__=n,e}return r.apply(t,h([this.value()],arguments))})}),t}function Bs(){return Re._===this&&(Re._=yl),this}function Ws(){}function Us(t){return t=Eu(t),Ra(function(n){return sr(n,t)})}function Hs(t){return Bi(t)?hr(Qi(t)):pr(t)}function Ys(t){return function(n){return null==t?U:qe(t,n)}}function Gs(t,n){if(t=Eu(t),1>t||t>mt)return[];var e=xt,r=Il(t,xt);n=Mi(n),t-=xt;for(var i=S(r,n);++e<t;)n(e);return i}function Xs(t){return tf(t)?f(t,Qi):Cu(t)?[t]:Zr(yc(t))}function Zs(t){var n=++vl;return ju(t)+n}function Js(t){return t&&t.length?Te(t,Fs,Be):U}function Ks(t,n){return t&&t.length?Te(t,Mi(n),Be):U}function Qs(t){return x(t,Fs)}function tl(t,n){return x(t,Mi(n))}function nl(t){return t&&t.length?Te(t,Fs,er):U}function el(t,n){return t&&t.length?Te(t,Mi(n),er):U}function rl(t){return t&&t.length?C(t,Fs):0}function il(t,n){return t&&t.length?C(t,Mi(n)):0}P=P?De.defaults({},P,De.pick(Re,ye)):Re;var ol=P.Date,al=P.Error,ul=P.Math,sl=P.RegExp,ll=P.TypeError,cl=P.Array.prototype,fl=P.Object.prototype,hl=P.String.prototype,pl=P.Function.prototype.toString,dl=fl.hasOwnProperty,vl=0,gl=pl.call(Object),ml=fl.toString,yl=Re._,$l=sl("^"+pl.call(dl).replace(fn,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),xl=Oe?P.Buffer:U,bl=P.Reflect,wl=P.Symbol,Cl=P.Uint8Array,Sl=P.clearTimeout,_l=bl?bl.enumerate:U,Ml=Object.getOwnPropertySymbols,kl="symbol"==typeof(kl=wl&&wl.iterator)?kl:U,Al=Object.create,El=fl.propertyIsEnumerable,Pl=P.setTimeout,Ol=cl.splice,Tl=ul.ceil,Ll=ul.floor,jl=Object.getPrototypeOf,Nl=P.isFinite,Rl=cl.join,Dl=Object.keys,Fl=ul.max,Il=ul.min,zl=P.parseInt,ql=ul.random,Vl=hl.replace,Bl=cl.reverse,Wl=hl.split,Ul=Ai(P,"DataView"),Hl=Ai(P,"Map"),Yl=Ai(P,"Promise"),Gl=Ai(P,"Set"),Xl=Ai(P,"WeakMap"),Zl=Ai(Object,"create"),Jl=Xl&&new Xl,Kl=!El.call({valueOf:1},"valueOf"),Ql={},tc=to(Ul),nc=to(Hl),ec=to(Yl),rc=to(Gl),ic=to(Xl),oc=wl?wl.prototype:U,ac=oc?oc.valueOf:U,uc=oc?oc.toString:U;En.templateSettings={escape:on,evaluate:an,interpolate:un,variable:"",imports:{_:En}},En.prototype=Pn.prototype,En.prototype.constructor=En,On.prototype=_e(Pn.prototype),On.prototype.constructor=On,Tn.prototype=_e(Pn.prototype),Tn.prototype.constructor=Tn,Rn.prototype=Zl?Zl(null):fl,qn.prototype.clear=Vn,qn.prototype["delete"]=Bn,qn.prototype.get=Wn,qn.prototype.has=Un,qn.prototype.set=Hn,Yn.prototype.push=Xn,Zn.prototype.clear=Jn,Zn.prototype["delete"]=Kn,Zn.prototype.get=Qn,Zn.prototype.has=te,Zn.prototype.set=ne;var sc=ni(Fe),lc=ni(Ie,!0),cc=ei(),fc=ei(!0);_l&&!El.call({valueOf:1},"valueOf")&&(nr=function(t){return D(_l(t))});var hc=Jl?function(t,n){return Jl.set(t,n),t}:Fs,pc=Gl&&1/z(new Gl([,-0]))[1]==gt?function(t){return new Gl(t)}:Ws,dc=Jl?function(t){return Jl.get(t)}:Ws,vc=hr("length");Ml||(Oi=function(){return[]});var gc=Ml?function(t){for(var n=[];t;)h(n,Oi(t)),t=Pi(t);return n}:Oi;(Ul&&Ti(new Ul(new ArrayBuffer(1)))!=qt||Hl&&Ti(new Hl)!=Pt||Yl&&Ti(Yl.resolve())!=Lt||Gl&&Ti(new Gl)!=Nt||Xl&&Ti(new Xl)!=Ft)&&(Ti=function(t){var n=ml.call(t),e=n==Tt?t.constructor:U,r=e?to(e):U;if(r)switch(r){case tc:return qt;case nc:return Pt;case ec:return Lt;case rc:return Nt;case ic:return Ft}return n});var mc=function(){var t=0,n=0;return function(e,r){var i=Bc(),o=ht-(i-n);if(n=i,o>0){if(++t>=ft)return e}else t=0;return hc(e,r)}}(),yc=La(function(t){var n=[];return ju(t).replace(cn,function(t,e,r,i){n.push(r?i.replace(mn,"$1"):e||t)}),n}),$c=Ra(function(t,n){return Za(t)?Ee(t,Ne(n,1,Za,!0)):[]}),xc=Ra(function(t,n){var e=bo(n);return Za(e)&&(e=U),Za(t)?Ee(t,Ne(n,1,Za,!0),Mi(e)):[]}),bc=Ra(function(t,n){var e=bo(n);return Za(e)&&(e=U),Za(t)?Ee(t,Ne(n,1,Za,!0),U,e):[]}),wc=Ra(function(t){var n=f(t,jr);return n.length&&n[0]===t[0]?Ye(n):[]}),Cc=Ra(function(t){var n=bo(t),e=f(t,jr);return n===bo(e)?n=U:e.pop(),e.length&&e[0]===t[0]?Ye(e,Mi(n)):[]}),Sc=Ra(function(t){var n=bo(t),e=f(t,jr);return n===bo(e)?n=U:e.pop(),e.length&&e[0]===t[0]?Ye(e,U,n):[]}),_c=Ra(So),Mc=Ra(function(t,n){n=Ne(n,1);var e=t?t.length:0,r=de(t,n);return vr(t,f(n,function(t){return qi(t,e)?+t:t}).sort(Hr)),r}),kc=Ra(function(t){return kr(Ne(t,1,Za,!0))}),Ac=Ra(function(t){var n=bo(t);return Za(n)&&(n=U),kr(Ne(t,1,Za,!0),Mi(n))}),Ec=Ra(function(t){var n=bo(t);return Za(n)&&(n=U),kr(Ne(t,1,Za,!0),U,n)}),Pc=Ra(function(t,n){return Za(t)?Ee(t,n):[]}),Oc=Ra(function(t){return Tr(s(t,Za))}),Tc=Ra(function(t){var n=bo(t);return Za(n)&&(n=U),Tr(s(t,Za),Mi(n))}),Lc=Ra(function(t){var n=bo(t);return Za(n)&&(n=U),Tr(s(t,Za),U,n)}),jc=Ra(Ho),Nc=Ra(function(t){var n=t.length,e=n>1?t[n-1]:U;return e="function"==typeof e?(t.pop(),e):U,Yo(t,e)}),Rc=Ra(function(t){t=Ne(t,1);var n=t.length,e=n?t[0]:0,r=this.__wrapped__,i=function(n){return de(n,t)};return!(n>1||this.__actions__.length)&&r instanceof Tn&&qi(e)?(r=r.slice(e,+e+(n?1:0)),r.__actions__.push({func:Ko,args:[i],thisArg:U}),new On(r,this.__chain__).thru(function(t){return n&&!t.length&&t.push(U),t})):this.thru(i)}),Dc=Qr(function(t,n,e){dl.call(t,e)?++t[e]:t[e]=1}),Fc=Qr(function(t,n,e){dl.call(t,e)?t[e].push(n):t[e]=[n]}),Ic=Ra(function(t,n,r){var i=-1,o="function"==typeof n,a=Bi(n),u=Xa(t)?Array(t.length):[];return sc(t,function(t){var s=o?n:a&&null!=t?t[n]:U;u[++i]=s?e(s,t,r):Xe(t,n,r)}),u}),zc=Qr(function(t,n,e){t[e]=n}),qc=Qr(function(t,n,e){t[e?0:1].push(n)},function(){return[[],[]]}),Vc=Ra(function(t,n){if(null==t)return[];var e=n.length;return e>1&&Vi(t,n[0],n[1])?n=[]:e>2&&Vi(n[0],n[1],n[2])&&(n=[n[0]]),n=1==n.length&&tf(n[0])?n[0]:Ne(n,1,zi),lr(t,n,[])}),Bc=ol.now,Wc=Ra(function(t,n,e){var r=J;if(e.length){var i=I(e,Ei(Wc));r|=et}return $i(t,r,n,e,i)}),Uc=Ra(function(t,n,e){var r=J|K;if(e.length){var i=I(e,Ei(Uc));r|=et}return $i(n,r,t,e,i)}),Hc=Ra(function(t,n){return Me(t,1,n)}),Yc=Ra(function(t,n,e){return Me(t,Ou(n)||0,e)});La.Cache=qn;var Gc=Ra(function(t,n){n=1==n.length&&tf(n[0])?f(n[0],M(Mi())):f(Ne(n,1,zi),M(Mi()));var r=n.length;return Ra(function(i){for(var o=-1,a=Il(i.length,r);++o<a;)i[o]=n[o].call(this,i[o]);return e(t,this,i)})}),Xc=Ra(function(t,n){var e=I(n,Ei(Xc));return $i(t,et,U,n,e)}),Zc=Ra(function(t,n){var e=I(n,Ei(Zc));return $i(t,rt,U,n,e)}),Jc=Ra(function(t,n){return $i(t,ot,U,U,U,Ne(n,1))}),Kc=gi(Be),Qc=gi(function(t,n){return t>=n}),tf=Array.isArray,nf=xl?function(t){return t instanceof xl}:Ds(!1),ef=gi(er),rf=gi(function(t,n){return n>=t}),of=ti(function(t,n){if(Kl||Hi(n)||Xa(n))return void Jr(n,Yu(n),t);for(var e in n)dl.call(n,e)&&le(t,e,n[e])}),af=ti(function(t,n){if(Kl||Hi(n)||Xa(n))return void Jr(n,Gu(n),t);for(var e in n)le(t,e,n[e])}),uf=ti(function(t,n,e,r){Jr(n,Gu(n),t,r)}),sf=ti(function(t,n,e,r){Jr(n,Yu(n),t,r)}),lf=Ra(function(t,n){return de(t,Ne(n,1))}),cf=Ra(function(t){return t.push(U,ue),e(uf,U,t)}),ff=Ra(function(t){return t.push(U,Zi),e(gf,U,t)}),hf=ci(function(t,n,e){t[n]=e},Ds(Fs)),pf=ci(function(t,n,e){dl.call(t,n)?t[n].push(e):t[n]=[e]},Mi),df=Ra(Xe),vf=ti(function(t,n,e){ar(t,n,e)}),gf=ti(function(t,n,e,r){ar(t,n,e,r)}),mf=Ra(function(t,n){return null==t?{}:(n=f(Ne(n,1),Qi),cr(t,Ee(Si(t),n)))}),yf=Ra(function(t,n){return null==t?{}:cr(t,f(Ne(n,1),Qi))}),$f=oi(function(t,n,e){return n=n.toLowerCase(),t+(e?ps(n):n)}),xf=oi(function(t,n,e){return t+(e?"-":"")+n.toLowerCase()}),bf=oi(function(t,n,e){return t+(e?" ":"")+n.toLowerCase()}),wf=ii("toLowerCase"),Cf=oi(function(t,n,e){return t+(e?"_":"")+n.toLowerCase()}),Sf=oi(function(t,n,e){return t+(e?" ":"")+Mf(n)}),_f=oi(function(t,n,e){return t+(e?" ":"")+n.toUpperCase()}),Mf=ii("toUpperCase"),kf=Ra(function(t,n){try{return e(t,U,n)}catch(r){return ru(r)?r:new al(r)}}),Af=Ra(function(t,n){return o(Ne(n,1),function(n){n=Qi(n),t[n]=Wc(t[n],t)}),t}),Ef=si(),Pf=si(!0),Of=Ra(function(t,n){return function(e){return Xe(e,t,n)}}),Tf=Ra(function(t,n){return function(e){return Xe(t,e,n)}}),Lf=hi(f),jf=hi(u),Nf=hi(v),Rf=vi(),Df=vi(!0),Ff=fi(function(t,n){return t+n}),If=yi("ceil"),zf=fi(function(t,n){return t/n}),qf=yi("floor"),Vf=fi(function(t,n){return t*n}),Bf=yi("round"),Wf=fi(function(t,n){return t-n});return En.after=Ma,En.ary=ka,En.assign=of,En.assignIn=af,En.assignInWith=uf,En.assignWith=sf,En.at=lf,En.before=Aa,En.bind=Wc,En.bindAll=Af,En.bindKey=Uc,En.castArray=qa,En.chain=Zo,En.chunk=eo,En.compact=ro,En.concat=io,En.cond=Ns,En.conforms=Rs,En.constant=Ds,En.countBy=Dc,En.create=Nu,En.curry=Ea,En.curryRight=Pa,En.debounce=Oa,En.defaults=cf,En.defaultsDeep=ff,En.defer=Hc,En.delay=Yc,En.difference=$c,En.differenceBy=xc,En.differenceWith=bc,En.drop=oo,En.dropRight=ao,En.dropRightWhile=uo,En.dropWhile=so,En.fill=lo,En.filter=ua,En.flatMap=ca,En.flatMapDeep=fa,En.flatMapDepth=ha,En.flatten=ho,En.flattenDeep=po,En.flattenDepth=vo,En.flip=Ta,En.flow=Ef,En.flowRight=Pf,En.fromPairs=go,En.functions=Vu,En.functionsIn=Bu,En.groupBy=Fc,En.initial=$o,En.intersection=wc,En.intersectionBy=Cc,En.intersectionWith=Sc,En.invert=hf,En.invertBy=pf,En.invokeMap=Ic,En.iteratee=Is,En.keyBy=zc,En.keys=Yu,En.keysIn=Gu,En.map=ga,En.mapKeys=Xu,En.mapValues=Zu,En.matches=zs,En.matchesProperty=qs,En.memoize=La,En.merge=vf,En.mergeWith=gf,En.method=Of,En.methodOf=Tf,En.mixin=Vs,En.negate=ja,En.nthArg=Us,En.omit=mf,En.omitBy=Ju,En.once=Na,En.orderBy=ma,En.over=Lf,En.overArgs=Gc,En.overEvery=jf,En.overSome=Nf,En.partial=Xc,En.partialRight=Zc,En.partition=qc,En.pick=yf,En.pickBy=Ku,En.property=Hs,En.propertyOf=Ys,En.pull=_c,En.pullAll=So,En.pullAllBy=_o,En.pullAllWith=Mo,En.pullAt=Mc,En.range=Rf,En.rangeRight=Df,En.rearg=Jc,En.reject=xa,En.remove=ko,En.rest=Ra,En.reverse=Ao,En.sampleSize=wa,En.set=ts,En.setWith=ns,En.shuffle=Ca,En.slice=Eo,En.sortBy=Vc,En.sortedUniq=Ro,En.sortedUniqBy=Do,En.split=Ss,En.spread=Da,En.tail=Fo,En.take=Io,En.takeRight=zo,En.takeRightWhile=qo,En.takeWhile=Vo,En.tap=Jo,En.throttle=Fa,En.thru=Ko,En.toArray=Au,En.toPairs=es,En.toPairsIn=rs,En.toPath=Xs,En.toPlainObject=Tu,En.transform=is,En.unary=Ia,En.union=kc,En.unionBy=Ac,En.unionWith=Ec,En.uniq=Bo,En.uniqBy=Wo,En.uniqWith=Uo,En.unset=os,En.unzip=Ho,En.unzipWith=Yo,En.update=as,En.updateWith=us,En.values=ss,En.valuesIn=ls,En.without=Pc,En.words=js,En.wrap=za,En.xor=Oc,En.xorBy=Tc,En.xorWith=Lc,En.zip=jc,En.zipObject=Go,En.zipObjectDeep=Xo,En.zipWith=Nc,En.entries=es,En.entriesIn=rs,En.extend=af,En.extendWith=uf,Vs(En,En),En.add=Ff,En.attempt=kf,En.camelCase=$f,En.capitalize=ps,En.ceil=If,En.clamp=cs,En.clone=Va,En.cloneDeep=Wa,En.cloneDeepWith=Ua,En.cloneWith=Ba,En.deburr=ds,En.divide=zf,En.endsWith=vs,En.eq=Ha,En.escape=gs,En.escapeRegExp=ms,En.every=aa,En.find=sa,En.findIndex=co,En.findKey=Ru,En.findLast=la,En.findLastIndex=fo,En.findLastKey=Du,En.floor=qf,En.forEach=pa,En.forEachRight=da,En.forIn=Fu,En.forInRight=Iu,En.forOwn=zu,En.forOwnRight=qu,En.get=Wu,En.gt=Kc,En.gte=Qc,En.has=Uu,En.hasIn=Hu,En.head=mo,En.identity=Fs,En.includes=va,En.indexOf=yo,En.inRange=fs,En.invoke=df,En.isArguments=Ya,En.isArray=tf,En.isArrayBuffer=Ga,En.isArrayLike=Xa,En.isArrayLikeObject=Za,En.isBoolean=Ja,En.isBuffer=nf,En.isDate=Ka,En.isElement=Qa,En.isEmpty=tu,En.isEqual=nu,En.isEqualWith=eu,En.isError=ru,En.isFinite=iu,En.isFunction=ou,En.isInteger=au,En.isLength=uu,En.isMap=cu,En.isMatch=fu,En.isMatchWith=hu,En.isNaN=pu,En.isNative=du,En.isNil=gu,En.isNull=vu,En.isNumber=mu,En.isObject=su,En.isObjectLike=lu,En.isPlainObject=yu,En.isRegExp=$u,En.isSafeInteger=xu,En.isSet=bu,En.isString=wu,En.isSymbol=Cu,En.isTypedArray=Su,En.isUndefined=_u,En.isWeakMap=Mu,En.isWeakSet=ku,En.join=xo,En.kebabCase=xf,En.last=bo,En.lastIndexOf=wo,En.lowerCase=bf,En.lowerFirst=wf,En.lt=ef,En.lte=rf,En.max=Js,En.maxBy=Ks,En.mean=Qs,En.meanBy=tl,En.min=nl,En.minBy=el,En.multiply=Vf,En.nth=Co,En.noConflict=Bs,En.noop=Ws,En.now=Bc,En.pad=ys,En.padEnd=$s,En.padStart=xs,En.parseInt=bs,En.random=hs,En.reduce=ya,En.reduceRight=$a,En.repeat=ws,En.replace=Cs,En.result=Qu,En.round=Bf,En.runInContext=W,En.sample=ba,En.size=Sa,En.snakeCase=Cf,En.some=_a,En.sortedIndex=Po,En.sortedIndexBy=Oo,En.sortedIndexOf=To,En.sortedLastIndex=Lo,En.sortedLastIndexBy=jo,En.sortedLastIndexOf=No,En.startCase=Sf,En.startsWith=_s,En.subtract=Wf,En.sum=rl,En.sumBy=il,En.template=Ms,En.times=Gs,En.toInteger=Eu,En.toLength=Pu,En.toLower=ks,En.toNumber=Ou,En.toSafeInteger=Lu,En.toString=ju,En.toUpper=As,En.trim=Es,En.trimEnd=Ps,En.trimStart=Os,En.truncate=Ts,En.unescape=Ls,En.uniqueId=Zs,En.upperCase=_f,En.upperFirst=Mf,En.each=pa,En.eachRight=da,En.first=mo,Vs(En,function(){var t={};return Fe(En,function(n,e){dl.call(En.prototype,e)||(t[e]=n)}),t}(),{chain:!1}),En.VERSION=H,o(["bind","bindKey","curry","curryRight","partial","partialRight"],function(t){En[t].placeholder=En}),o(["drop","take"],function(t,n){Tn.prototype[t]=function(e){var r=this.__filtered__;if(r&&!n)return new Tn(this);e=e===U?1:Fl(Eu(e),0);var i=this.clone();return r?i.__takeCount__=Il(e,i.__takeCount__):i.__views__.push({size:Il(e,xt),type:t+(i.__dir__<0?"Right":"")}),i},Tn.prototype[t+"Right"]=function(n){return this.reverse()[t](n).reverse()}}),o(["filter","map","takeWhile"],function(t,n){var e=n+1,r=e==pt||e==vt;Tn.prototype[t]=function(t){var n=this.clone();return n.__iteratees__.push({iteratee:Mi(t,3),type:e}),n.__filtered__=n.__filtered__||r,n}}),o(["head","last"],function(t,n){var e="take"+(n?"Right":"");Tn.prototype[t]=function(){return this[e](1).value()[0]}}),o(["initial","tail"],function(t,n){var e="drop"+(n?"":"Right");Tn.prototype[t]=function(){return this.__filtered__?new Tn(this):this[e](1)}}),Tn.prototype.compact=function(){return this.filter(Fs)},Tn.prototype.find=function(t){return this.filter(t).head()},Tn.prototype.findLast=function(t){return this.reverse().find(t)},Tn.prototype.invokeMap=Ra(function(t,n){return"function"==typeof t?new Tn(this):this.map(function(e){return Xe(e,t,n)})}),Tn.prototype.reject=function(t){return t=Mi(t,3),this.filter(function(n){return!t(n)})},Tn.prototype.slice=function(t,n){t=Eu(t);var e=this;return e.__filtered__&&(t>0||0>n)?new Tn(e):(0>t?e=e.takeRight(-t):t&&(e=e.drop(t)),n!==U&&(n=Eu(n),e=0>n?e.dropRight(-n):e.take(n-t)),e)},Tn.prototype.takeRightWhile=function(t){return this.reverse().takeWhile(t).reverse()},Tn.prototype.toArray=function(){return this.take(xt)},Fe(Tn.prototype,function(t,n){var e=/^(?:filter|find|map|reject)|While$/.test(n),r=/^(?:head|last)$/.test(n),i=En[r?"take"+("last"==n?"Right":""):n],o=r||/^find/.test(n);i&&(En.prototype[n]=function(){var n=this.__wrapped__,a=r?[1]:arguments,u=n instanceof Tn,s=a[0],l=u||tf(n),c=function(t){var n=i.apply(En,h([t],a));return r&&f?n[0]:n};l&&e&&"function"==typeof s&&1!=s.length&&(u=l=!1);var f=this.__chain__,p=!!this.__actions__.length,d=o&&!f,v=u&&!p;if(!o&&l){n=v?n:new Tn(this);var g=t.apply(n,a);return g.__actions__.push({func:Ko,args:[c],thisArg:U}),new On(g,f)}return d&&v?t.apply(this,a):(g=this.thru(c),d?r?g.value()[0]:g.value():g)})}),o(["pop","push","shift","sort","splice","unshift"],function(t){var n=cl[t],e=/^(?:push|sort|unshift)$/.test(t)?"tap":"thru",r=/^(?:pop|shift)$/.test(t);En.prototype[t]=function(){var t=arguments;if(r&&!this.__chain__){var i=this.value();return n.apply(tf(i)?i:[],t)}return this[e](function(e){return n.apply(tf(e)?e:[],t)})}}),Fe(Tn.prototype,function(t,n){var e=En[n];if(e){var r=e.name+"",i=Ql[r]||(Ql[r]=[]);i.push({name:n,func:e})}}),Ql[li(U,K).name]=[{name:"wrapper",func:U}],Tn.prototype.clone=Ln,Tn.prototype.reverse=jn,Tn.prototype.value=Nn,En.prototype.at=Rc,En.prototype.chain=Qo,En.prototype.commit=ta,En.prototype.next=na,En.prototype.plant=ra,En.prototype.reverse=ia,En.prototype.toJSON=En.prototype.valueOf=En.prototype.value=oa,kl&&(En.prototype[kl]=ea),En}var U,H="4.11.2",Y=200,G="Expected a function",X="__lodash_hash_undefined__",Z="__lodash_placeholder__",J=1,K=2,Q=4,tt=8,nt=16,et=32,rt=64,it=128,ot=256,at=512,ut=1,st=2,lt=30,ct="...",ft=150,ht=16,pt=1,dt=2,vt=3,gt=1/0,mt=9007199254740991,yt=1.7976931348623157e308,$t=NaN,xt=4294967295,bt=xt-1,wt=xt>>>1,Ct="[object Arguments]",St="[object Array]",_t="[object Boolean]",Mt="[object Date]",kt="[object Error]",At="[object Function]",Et="[object GeneratorFunction]",Pt="[object Map]",Ot="[object Number]",Tt="[object Object]",Lt="[object Promise]",jt="[object RegExp]",Nt="[object Set]",Rt="[object String]",Dt="[object Symbol]",Ft="[object WeakMap]",It="[object WeakSet]",zt="[object ArrayBuffer]",qt="[object DataView]",Vt="[object Float32Array]",Bt="[object Float64Array]",Wt="[object Int8Array]",Ut="[object Int16Array]",Ht="[object Int32Array]",Yt="[object Uint8Array]",Gt="[object Uint8ClampedArray]",Xt="[object Uint16Array]",Zt="[object Uint32Array]",Jt=/\b__p \+= '';/g,Kt=/\b(__p \+=) '' \+/g,Qt=/(__e\(.*?\)|\b__t\)) \+\n'';/g,tn=/&(?:amp|lt|gt|quot|#39|#96);/g,nn=/[&<>"'`]/g,en=RegExp(tn.source),rn=RegExp(nn.source),on=/<%-([\s\S]+?)%>/g,an=/<%([\s\S]+?)%>/g,un=/<%=([\s\S]+?)%>/g,sn=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,ln=/^\w*$/,cn=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]/g,fn=/[\\^$.*+?()[\]{}|]/g,hn=RegExp(fn.source),pn=/^\s+|\s+$/g,dn=/^\s+/,vn=/\s+$/,gn=/[a-zA-Z0-9]+/g,mn=/\\(\\)?/g,yn=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,$n=/\w*$/,xn=/^0x/i,bn=/^[-+]0x[0-9a-f]+$/i,wn=/^0b[01]+$/i,Cn=/^\[object .+?Constructor\]$/,Sn=/^0o[0-7]+$/i,_n=/^(?:0|[1-9]\d*)$/,Mn=/[\xc0-\xd6\xd8-\xde\xdf-\xf6\xf8-\xff]/g,kn=/($^)/,An=/['\n\r\u2028\u2029\\]/g,En="\\ud800-\\udfff",Pn="\\u0300-\\u036f\\ufe20-\\ufe23",On="\\u20d0-\\u20f0",Tn="\\u2700-\\u27bf",Ln="a-z\\xdf-\\xf6\\xf8-\\xff",jn="\\xac\\xb1\\xd7\\xf7",Nn="\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf",Rn="\\u2000-\\u206f",Dn=" \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000",Fn="A-Z\\xc0-\\xd6\\xd8-\\xde",In="\\ufe0e\\ufe0f",zn=jn+Nn+Rn+Dn,qn="['’]",Vn="["+En+"]",Bn="["+zn+"]",Wn="["+Pn+On+"]",Un="\\d+",Hn="["+Tn+"]",Yn="["+Ln+"]",Gn="[^"+En+zn+Un+Tn+Ln+Fn+"]",Xn="\\ud83c[\\udffb-\\udfff]",Zn="(?:"+Wn+"|"+Xn+")",Jn="[^"+En+"]",Kn="(?:\\ud83c[\\udde6-\\uddff]){2}",Qn="[\\ud800-\\udbff][\\udc00-\\udfff]",te="["+Fn+"]",ne="\\u200d",ee="(?:"+Yn+"|"+Gn+")",re="(?:"+te+"|"+Gn+")",ie="(?:"+qn+"(?:d|ll|m|re|s|t|ve))?",oe="(?:"+qn+"(?:D|LL|M|RE|S|T|VE))?",ae=Zn+"?",ue="["+In+"]?",se="(?:"+ne+"(?:"+[Jn,Kn,Qn].join("|")+")"+ue+ae+")*",le=ue+ae+se,ce="(?:"+[Hn,Kn,Qn].join("|")+")"+le,fe="(?:"+[Jn+Wn+"?",Wn,Kn,Qn,Vn].join("|")+")",he=RegExp(qn,"g"),pe=RegExp(Wn,"g"),de=RegExp(Xn+"(?="+Xn+")|"+fe+le,"g"),ve=RegExp([te+"?"+Yn+"+"+ie+"(?="+[Bn,te,"$"].join("|")+")",re+"+"+oe+"(?="+[Bn,te+ee,"$"].join("|")+")",te+"?"+ee+"+"+ie,te+"+"+oe,Un,ce].join("|"),"g"),ge=RegExp("["+ne+En+Pn+On+In+"]"),me=/[a-z][A-Z]|[A-Z]{2,}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,ye=["Array","Buffer","DataView","Date","Error","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Math","Object","Promise","Reflect","RegExp","Set","String","Symbol","TypeError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","_","clearTimeout","isFinite","parseInt","setTimeout"],$e=-1,xe={};xe[Vt]=xe[Bt]=xe[Wt]=xe[Ut]=xe[Ht]=xe[Yt]=xe[Gt]=xe[Xt]=xe[Zt]=!0,xe[Ct]=xe[St]=xe[zt]=xe[_t]=xe[qt]=xe[Mt]=xe[kt]=xe[At]=xe[Pt]=xe[Ot]=xe[Tt]=xe[jt]=xe[Nt]=xe[Rt]=xe[Ft]=!1;var be={};be[Ct]=be[St]=be[zt]=be[qt]=be[_t]=be[Mt]=be[Vt]=be[Bt]=be[Wt]=be[Ut]=be[Ht]=be[Pt]=be[Ot]=be[Tt]=be[jt]=be[Nt]=be[Rt]=be[Dt]=be[Yt]=be[Gt]=be[Xt]=be[Zt]=!0,be[kt]=be[At]=be[Ft]=!1;var we={"À":"A","Á":"A","Â":"A","Ã":"A","Ä":"A","Å":"A","à":"a","á":"a","â":"a","ã":"a","ä":"a","å":"a","Ç":"C","ç":"c","Ð":"D","ð":"d","È":"E","É":"E","Ê":"E","Ë":"E","è":"e","é":"e","ê":"e","ë":"e","Ì":"I","Í":"I","Î":"I","Ï":"I","ì":"i","í":"i","î":"i","ï":"i","Ñ":"N","ñ":"n","Ò":"O","Ó":"O","Ô":"O","Õ":"O","Ö":"O","Ø":"O","ò":"o","ó":"o","ô":"o","õ":"o","ö":"o","ø":"o","Ù":"U","Ú":"U","Û":"U","Ü":"U","ù":"u","ú":"u","û":"u","ü":"u","Ý":"Y","ý":"y","ÿ":"y","Æ":"Ae","æ":"ae","Þ":"Th","þ":"th","ß":"ss"},Ce={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","`":"&#96;"},Se={"&amp;":"&","&lt;":"<","&gt;":">","&quot;":'"',"&#39;":"'","&#96;":"`"},_e={"function":!0,object:!0},Me={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},ke=parseFloat,Ae=parseInt,Ee=_e[typeof exports]&&exports&&!exports.nodeType?exports:U,Pe=_e[typeof module]&&module&&!module.nodeType?module:U,Oe=Pe&&Pe.exports===Ee?Ee:U,Te=P(Ee&&Pe&&"object"==typeof global&&global),Le=P(_e[typeof self]&&self),je=P(_e[typeof window]&&window),Ne=P(_e[typeof this]&&this),Re=Te||je!==(Ne&&Ne.window)&&je||Le||Ne||Function("return this")(),De=W();(je||Le||{})._=De,"function"==typeof define&&"object"==typeof define.amd&&define.amd?define(function(){return De}):Ee&&Pe?(Oe&&((Pe.exports=De)._=De),Ee._=De):Re._=De}.call(this),function(){"use strict";var t=this,n=t.Chart,e=function(t){this.canvas=t.canvas,this.ctx=t;var n=function(t,n){return t["offset"+n]?t["offset"+n]:document.defaultView.getComputedStyle(t).getPropertyValue(n)};this.width=n(t.canvas,"Width")||t.canvas.width,this.height=n(t.canvas,"Height")||t.canvas.height;return this.aspectRatio=this.width/this.height,r.retinaScale(this),this};e.defaults={global:{animation:!0,animationSteps:60,animationEasing:"easeOutQuart",showScale:!0,scaleOverride:!1,scaleSteps:null,scaleStepWidth:null,scaleStartValue:null,scaleLineColor:"rgba(0,0,0,.1)",scaleLineWidth:1,scaleShowLabels:!0,scaleLabel:"<%=value%>",scaleIntegersOnly:!0,scaleBeginAtZero:!1,scaleFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",scaleFontSize:12,scaleFontStyle:"normal",scaleFontColor:"#666",responsive:!1,maintainAspectRatio:!0,showTooltips:!0,customTooltips:!1,tooltipEvents:["mousemove","touchstart","touchmove","mouseout"],tooltipFillColor:"rgba(0,0,0,0.8)",tooltipFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",tooltipFontSize:14,tooltipFontStyle:"normal",tooltipFontColor:"#fff",tooltipTitleFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",tooltipTitleFontSize:14,tooltipTitleFontStyle:"bold",tooltipTitleFontColor:"#fff",tooltipTitleTemplate:"<%= label%>",tooltipYPadding:6,tooltipXPadding:6,tooltipCaretSize:8,tooltipCornerRadius:6,tooltipXOffset:10,tooltipTemplate:"<%if (label){%><%=label%>: <%}%><%= value %>",multiTooltipTemplate:"<%= datasetLabel %>: <%= value %>",multiTooltipKeyBackground:"#fff",segmentColorDefault:["#A6CEE3","#1F78B4","#B2DF8A","#33A02C","#FB9A99","#E31A1C","#FDBF6F","#FF7F00","#CAB2D6","#6A3D9A","#B4B482","#B15928"],segmentHighlightColorDefaults:["#CEF6FF","#47A0DC","#DAFFB2","#5BC854","#FFC2C1","#FF4244","#FFE797","#FFA728","#F2DAFE","#9265C2","#DCDCAA","#D98150"],onAnimationProgress:function(){},onAnimationComplete:function(){}}},e.types={};var r=e.helpers={},i=r.each=function(t,n,e){var r=Array.prototype.slice.call(arguments,3);if(t)if(t.length===+t.length){var i;for(i=0;i<t.length;i++)n.apply(e,[t[i],i].concat(r))}else for(var o in t)n.apply(e,[t[o],o].concat(r))},o=r.clone=function(t){var n={};return i(t,function(e,r){t.hasOwnProperty(r)&&(n[r]=e)}),n},a=r.extend=function(t){return i(Array.prototype.slice.call(arguments,1),function(n){i(n,function(e,r){n.hasOwnProperty(r)&&(t[r]=e)})}),t},u=r.merge=function(t,n){var e=Array.prototype.slice.call(arguments,0);return e.unshift({}),a.apply(null,e)},s=r.indexOf=function(t,n){if(Array.prototype.indexOf)return t.indexOf(n);for(var e=0;e<t.length;e++)if(t[e]===n)return e;return-1},l=(r.where=function(t,n){var e=[];return r.each(t,function(t){n(t)&&e.push(t)}),e},r.findNextWhere=function(t,n,e){e||(e=-1);for(var r=e+1;r<t.length;r++){var i=t[r];if(n(i))return i}},r.findPreviousWhere=function(t,n,e){e||(e=t.length);for(var r=e-1;r>=0;r--){var i=t[r];if(n(i))return i}},r.inherits=function(t){var n=this,e=t&&t.hasOwnProperty("constructor")?t.constructor:function(){return n.apply(this,arguments)},r=function(){this.constructor=e};return r.prototype=n.prototype,e.prototype=new r,e.extend=l,t&&a(e.prototype,t),e.__super__=n.prototype,e}),c=r.noop=function(){},f=r.uid=function(){var t=0;return function(){return"chart-"+t++}}(),h=r.warn=function(t){window.console&&"function"==typeof window.console.warn&&console.warn(t)},p=r.amd="function"==typeof define&&define.amd,d=r.isNumber=function(t){return!isNaN(parseFloat(t))&&isFinite(t)},v=r.max=function(t){return Math.max.apply(Math,t)},g=r.min=function(t){return Math.min.apply(Math,t)},m=(r.cap=function(t,n,e){if(d(n)){if(t>n)return n}else if(d(e)&&e>t)return e;return t},r.getDecimalPlaces=function(t){if(t%1!==0&&d(t)){var n=t.toString();if(n.indexOf("e-")<0)return n.split(".")[1].length;if(n.indexOf(".")<0)return parseInt(n.split("e-")[1]);var e=n.split(".")[1].split("e-");return e[0].length+parseInt(e[1])}return 0}),y=r.radians=function(t){return t*(Math.PI/180)},$=(r.getAngleFromPoint=function(t,n){var e=n.x-t.x,r=n.y-t.y,i=Math.sqrt(e*e+r*r),o=2*Math.PI+Math.atan2(r,e);return 0>e&&0>r&&(o+=2*Math.PI),{angle:o,distance:i}},r.aliasPixel=function(t){return t%2===0?0:.5}),x=(r.splineCurve=function(t,n,e,r){var i=Math.sqrt(Math.pow(n.x-t.x,2)+Math.pow(n.y-t.y,2)),o=Math.sqrt(Math.pow(e.x-n.x,2)+Math.pow(e.y-n.y,2)),a=r*i/(i+o),u=r*o/(i+o);return{inner:{x:n.x-a*(e.x-t.x),y:n.y-a*(e.y-t.y)},outer:{x:n.x+u*(e.x-t.x),y:n.y+u*(e.y-t.y)}}},r.calculateOrderOfMagnitude=function(t){return Math.floor(Math.log(t)/Math.LN10)}),b=(r.calculateScaleRange=function(t,n,e,r,o){var a=2,u=Math.floor(n/(1.5*e)),s=a>=u,l=[];i(t,function(t){null==t||l.push(t)});var c=g(l),f=v(l);f===c&&(f+=.5,
+c>=.5&&!r?c-=.5:f+=.5);for(var h=Math.abs(f-c),p=x(h),d=Math.ceil(f/(1*Math.pow(10,p)))*Math.pow(10,p),m=r?0:Math.floor(c/(1*Math.pow(10,p)))*Math.pow(10,p),y=d-m,$=Math.pow(10,p),b=Math.round(y/$);(b>u||u>2*b)&&!s;)if(b>u)$*=2,b=Math.round(y/$),b%1!==0&&(s=!0);else if(o&&p>=0){if($/2%1!==0)break;$/=2,b=Math.round(y/$)}else $/=2,b=Math.round(y/$);return s&&(b=a,$=y/b),{steps:b,stepValue:$,min:m,max:m+b*$}},r.template=function(t,n){function e(t,n){var e=/\W/.test(t)?new Function("obj","var p=[],print=function(){p.push.apply(p,arguments);};with(obj){p.push('"+t.replace(/[\r\t\n]/g," ").split("<%").join("	").replace(/((^|%>)[^\t]*)'/g,"$1\r").replace(/\t=(.*?)%>/g,"',$1,'").split("	").join("');").split("%>").join("p.push('").split("\r").join("\\'")+"');}return p.join('');"):r[t]=r[t];return n?e(n):e}if(t instanceof Function)return t(n);var r={};return e(t,n)}),w=(r.generateLabels=function(t,n,e,r){var o=new Array(n);return t&&i(o,function(n,i){o[i]=b(t,{value:e+r*(i+1)})}),o},r.easingEffects={linear:function(t){return t},easeInQuad:function(t){return t*t},easeOutQuad:function(t){return-1*t*(t-2)},easeInOutQuad:function(t){return(t/=.5)<1?.5*t*t:-0.5*(--t*(t-2)-1)},easeInCubic:function(t){return t*t*t},easeOutCubic:function(t){return 1*((t=t/1-1)*t*t+1)},easeInOutCubic:function(t){return(t/=.5)<1?.5*t*t*t:.5*((t-=2)*t*t+2)},easeInQuart:function(t){return t*t*t*t},easeOutQuart:function(t){return-1*((t=t/1-1)*t*t*t-1)},easeInOutQuart:function(t){return(t/=.5)<1?.5*t*t*t*t:-0.5*((t-=2)*t*t*t-2)},easeInQuint:function(t){return 1*(t/=1)*t*t*t*t},easeOutQuint:function(t){return 1*((t=t/1-1)*t*t*t*t+1)},easeInOutQuint:function(t){return(t/=.5)<1?.5*t*t*t*t*t:.5*((t-=2)*t*t*t*t+2)},easeInSine:function(t){return-1*Math.cos(t/1*(Math.PI/2))+1},easeOutSine:function(t){return 1*Math.sin(t/1*(Math.PI/2))},easeInOutSine:function(t){return-0.5*(Math.cos(Math.PI*t/1)-1)},easeInExpo:function(t){return 0===t?1:1*Math.pow(2,10*(t/1-1))},easeOutExpo:function(t){return 1===t?1:1*(-Math.pow(2,-10*t/1)+1)},easeInOutExpo:function(t){return 0===t?0:1===t?1:(t/=.5)<1?.5*Math.pow(2,10*(t-1)):.5*(-Math.pow(2,-10*--t)+2)},easeInCirc:function(t){return t>=1?t:-1*(Math.sqrt(1-(t/=1)*t)-1)},easeOutCirc:function(t){return 1*Math.sqrt(1-(t=t/1-1)*t)},easeInOutCirc:function(t){return(t/=.5)<1?-0.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1)},easeInElastic:function(t){var n=1.70158,e=0,r=1;return 0===t?0:1==(t/=1)?1:(e||(e=.3),r<Math.abs(1)?(r=1,n=e/4):n=e/(2*Math.PI)*Math.asin(1/r),-(r*Math.pow(2,10*(t-=1))*Math.sin((1*t-n)*(2*Math.PI)/e)))},easeOutElastic:function(t){var n=1.70158,e=0,r=1;return 0===t?0:1==(t/=1)?1:(e||(e=.3),r<Math.abs(1)?(r=1,n=e/4):n=e/(2*Math.PI)*Math.asin(1/r),r*Math.pow(2,-10*t)*Math.sin((1*t-n)*(2*Math.PI)/e)+1)},easeInOutElastic:function(t){var n=1.70158,e=0,r=1;return 0===t?0:2==(t/=.5)?1:(e||(e=1*(.3*1.5)),r<Math.abs(1)?(r=1,n=e/4):n=e/(2*Math.PI)*Math.asin(1/r),1>t?-.5*(r*Math.pow(2,10*(t-=1))*Math.sin((1*t-n)*(2*Math.PI)/e)):r*Math.pow(2,-10*(t-=1))*Math.sin((1*t-n)*(2*Math.PI)/e)*.5+1)},easeInBack:function(t){var n=1.70158;return 1*(t/=1)*t*((n+1)*t-n)},easeOutBack:function(t){var n=1.70158;return 1*((t=t/1-1)*t*((n+1)*t+n)+1)},easeInOutBack:function(t){var n=1.70158;return(t/=.5)<1?.5*(t*t*(((n*=1.525)+1)*t-n)):.5*((t-=2)*t*(((n*=1.525)+1)*t+n)+2)},easeInBounce:function(t){return 1-w.easeOutBounce(1-t)},easeOutBounce:function(t){return(t/=1)<1/2.75?1*(7.5625*t*t):2/2.75>t?1*(7.5625*(t-=1.5/2.75)*t+.75):2.5/2.75>t?1*(7.5625*(t-=2.25/2.75)*t+.9375):1*(7.5625*(t-=2.625/2.75)*t+.984375)},easeInOutBounce:function(t){return.5>t?.5*w.easeInBounce(2*t):.5*w.easeOutBounce(2*t-1)+.5}}),C=r.requestAnimFrame=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(t){return window.setTimeout(t,1e3/60)}}(),S=(r.cancelAnimFrame=function(){return window.cancelAnimationFrame||window.webkitCancelAnimationFrame||window.mozCancelAnimationFrame||window.oCancelAnimationFrame||window.msCancelAnimationFrame||function(t){return window.clearTimeout(t,1e3/60)}}(),r.animationLoop=function(t,n,e,r,i,o){var a=0,u=w[e]||w.linear,s=function(){a++;var e=a/n,l=u(e);t.call(o,l,e,a),r.call(o,l,e),n>a?o.animationFrame=C(s):i.apply(o)};C(s)},r.getRelativePosition=function(t){var n,e,r=t.originalEvent||t,i=t.currentTarget||t.srcElement,o=i.getBoundingClientRect();return r.touches?(n=r.touches[0].clientX-o.left,e=r.touches[0].clientY-o.top):(n=r.clientX-o.left,e=r.clientY-o.top),{x:n,y:e}},r.addEvent=function(t,n,e){t.addEventListener?t.addEventListener(n,e):t.attachEvent?t.attachEvent("on"+n,e):t["on"+n]=e}),_=r.removeEvent=function(t,n,e){t.removeEventListener?t.removeEventListener(n,e,!1):t.detachEvent?t.detachEvent("on"+n,e):t["on"+n]=c},M=(r.bindEvents=function(t,n,e){t.events||(t.events={}),i(n,function(n){t.events[n]=function(){e.apply(t,arguments)},S(t.chart.canvas,n,t.events[n])})},r.unbindEvents=function(t,n){i(n,function(n,e){_(t.chart.canvas,e,n)})}),k=r.getMaximumWidth=function(t){var n=t.parentNode,e=parseInt(E(n,"padding-left"))+parseInt(E(n,"padding-right"));return n?n.clientWidth-e:0},A=r.getMaximumHeight=function(t){var n=t.parentNode,e=parseInt(E(n,"padding-bottom"))+parseInt(E(n,"padding-top"));return n?n.clientHeight-e:0},E=r.getStyle=function(t,n){return t.currentStyle?t.currentStyle[n]:document.defaultView.getComputedStyle(t,null).getPropertyValue(n)},P=(r.getMaximumSize=r.getMaximumWidth,r.retinaScale=function(t){var n=t.ctx,e=t.canvas.width,r=t.canvas.height;window.devicePixelRatio&&(n.canvas.style.width=e+"px",n.canvas.style.height=r+"px",n.canvas.height=r*window.devicePixelRatio,n.canvas.width=e*window.devicePixelRatio,n.scale(window.devicePixelRatio,window.devicePixelRatio))}),O=r.clear=function(t){t.ctx.clearRect(0,0,t.width,t.height)},T=r.fontString=function(t,n,e){return n+" "+t+"px "+e},L=r.longestText=function(t,n,e){t.font=n;var r=0;return i(e,function(n){var e=t.measureText(n).width;r=e>r?e:r}),r},j=r.drawRoundedRectangle=function(t,n,e,r,i,o){t.beginPath(),t.moveTo(n+o,e),t.lineTo(n+r-o,e),t.quadraticCurveTo(n+r,e,n+r,e+o),t.lineTo(n+r,e+i-o),t.quadraticCurveTo(n+r,e+i,n+r-o,e+i),t.lineTo(n+o,e+i),t.quadraticCurveTo(n,e+i,n,e+i-o),t.lineTo(n,e+o),t.quadraticCurveTo(n,e,n+o,e),t.closePath()};e.instances={},e.Type=function(t,n,r){this.options=n,this.chart=r,this.id=f(),e.instances[this.id]=this,n.responsive&&this.resize(),this.initialize.call(this,t)},a(e.Type.prototype,{initialize:function(){return this},clear:function(){return O(this.chart),this},stop:function(){return e.animationService.cancelAnimation(this),this},resize:function(t){this.stop();var n=this.chart.canvas,e=k(this.chart.canvas),r=this.options.maintainAspectRatio?e/this.chart.aspectRatio:A(this.chart.canvas);return n.width=this.chart.width=e,n.height=this.chart.height=r,P(this.chart),"function"==typeof t&&t.apply(this,Array.prototype.slice.call(arguments,1)),this},reflow:c,render:function(t){if(t&&this.reflow(),this.options.animation&&!t){var n=new e.Animation;n.numSteps=this.options.animationSteps,n.easing=this.options.animationEasing,n.render=function(t,n){var e=r.easingEffects[n.easing],i=n.currentStep/n.numSteps,o=e(i);t.draw(o,i,n.currentStep)},n.onAnimationProgress=this.options.onAnimationProgress,n.onAnimationComplete=this.options.onAnimationComplete,e.animationService.addAnimation(this,n)}else this.draw(),this.options.onAnimationComplete.call(this);return this},generateLegend:function(){return r.template(this.options.legendTemplate,this)},destroy:function(){this.stop(),this.clear(),M(this,this.events);var t=this.chart.canvas;t.width=this.chart.width,t.height=this.chart.height,t.style.removeProperty?(t.style.removeProperty("width"),t.style.removeProperty("height")):(t.style.removeAttribute("width"),t.style.removeAttribute("height")),delete e.instances[this.id]},showTooltip:function(t,n){"undefined"==typeof this.activeElements&&(this.activeElements=[]);var o=function(t){var n=!1;return t.length!==this.activeElements.length?n=!0:(i(t,function(t,e){t!==this.activeElements[e]&&(n=!0)},this),n)}.call(this,t);if(o||n){if(this.activeElements=t,this.draw(),this.options.customTooltips&&this.options.customTooltips(!1),t.length>0)if(this.datasets&&this.datasets.length>1){for(var a,u,l=this.datasets.length-1;l>=0&&(a=this.datasets[l].points||this.datasets[l].bars||this.datasets[l].segments,u=s(a,t[0]),-1===u);l--);var c=[],f=[],h=function(t){var n,e,i,o,a,s=[],l=[],h=[];return r.each(this.datasets,function(t){n=t.points||t.bars||t.segments,n[u]&&n[u].hasValue()&&s.push(n[u])}),r.each(s,function(t){l.push(t.x),h.push(t.y),c.push(r.template(this.options.multiTooltipTemplate,t)),f.push({fill:t._saved.fillColor||t.fillColor,stroke:t._saved.strokeColor||t.strokeColor})},this),a=g(h),i=v(h),o=g(l),e=v(l),{x:o>this.chart.width/2?o:e,y:(a+i)/2}}.call(this,u);new e.MultiTooltip({x:h.x,y:h.y,xPadding:this.options.tooltipXPadding,yPadding:this.options.tooltipYPadding,xOffset:this.options.tooltipXOffset,fillColor:this.options.tooltipFillColor,textColor:this.options.tooltipFontColor,fontFamily:this.options.tooltipFontFamily,fontStyle:this.options.tooltipFontStyle,fontSize:this.options.tooltipFontSize,titleTextColor:this.options.tooltipTitleFontColor,titleFontFamily:this.options.tooltipTitleFontFamily,titleFontStyle:this.options.tooltipTitleFontStyle,titleFontSize:this.options.tooltipTitleFontSize,cornerRadius:this.options.tooltipCornerRadius,labels:c,legendColors:f,legendColorBackground:this.options.multiTooltipKeyBackground,title:b(this.options.tooltipTitleTemplate,t[0]),chart:this.chart,ctx:this.chart.ctx,custom:this.options.customTooltips}).draw()}else i(t,function(t){var n=t.tooltipPosition();new e.Tooltip({x:Math.round(n.x),y:Math.round(n.y),xPadding:this.options.tooltipXPadding,yPadding:this.options.tooltipYPadding,fillColor:this.options.tooltipFillColor,textColor:this.options.tooltipFontColor,fontFamily:this.options.tooltipFontFamily,fontStyle:this.options.tooltipFontStyle,fontSize:this.options.tooltipFontSize,caretHeight:this.options.tooltipCaretSize,cornerRadius:this.options.tooltipCornerRadius,text:b(this.options.tooltipTemplate,t),chart:this.chart,custom:this.options.customTooltips}).draw()},this);return this}},toBase64Image:function(){return this.chart.canvas.toDataURL.apply(this.chart.canvas,arguments)}}),e.Type.extend=function(t){var n=this,r=function(){return n.apply(this,arguments)};if(r.prototype=o(n.prototype),a(r.prototype,t),r.extend=e.Type.extend,t.name||n.prototype.name){var i=t.name||n.prototype.name,s=e.defaults[n.prototype.name]?o(e.defaults[n.prototype.name]):{};e.defaults[i]=a(s,t.defaults),e.types[i]=r,e.prototype[i]=function(t,n){var o=u(e.defaults.global,e.defaults[i],n||{});return new r(t,o,this)}}else h("Name not provided for this chart, so it hasn't been registered");return n},e.Element=function(t){a(this,t),this.initialize.apply(this,arguments),this.save()},a(e.Element.prototype,{initialize:function(){},restore:function(t){return t?i(t,function(t){this[t]=this._saved[t]},this):a(this,this._saved),this},save:function(){return this._saved=o(this),delete this._saved._saved,this},update:function(t){return i(t,function(t,n){this._saved[n]=this[n],this[n]=t},this),this},transition:function(t,n){return i(t,function(t,e){this[e]=(t-this._saved[e])*n+this._saved[e]},this),this},tooltipPosition:function(){return{x:this.x,y:this.y}},hasValue:function(){return d(this.value)}}),e.Element.extend=l,e.Point=e.Element.extend({display:!0,inRange:function(t,n){var e=this.hitDetectionRadius+this.radius;return Math.pow(t-this.x,2)+Math.pow(n-this.y,2)<Math.pow(e,2)},draw:function(){if(this.display){var t=this.ctx;t.beginPath(),t.arc(this.x,this.y,this.radius,0,2*Math.PI),t.closePath(),t.strokeStyle=this.strokeColor,t.lineWidth=this.strokeWidth,t.fillStyle=this.fillColor,t.fill(),t.stroke()}}}),e.Arc=e.Element.extend({inRange:function(t,n){var e=r.getAngleFromPoint(this,{x:t,y:n}),i=e.angle%(2*Math.PI),o=(2*Math.PI+this.startAngle)%(2*Math.PI),a=(2*Math.PI+this.endAngle)%(2*Math.PI)||360,u=o>a?a>=i||i>=o:i>=o&&a>=i,s=e.distance>=this.innerRadius&&e.distance<=this.outerRadius;return u&&s},tooltipPosition:function(){var t=this.startAngle+(this.endAngle-this.startAngle)/2,n=(this.outerRadius-this.innerRadius)/2+this.innerRadius;return{x:this.x+Math.cos(t)*n,y:this.y+Math.sin(t)*n}},draw:function(t){var n=this.ctx;n.beginPath(),n.arc(this.x,this.y,this.outerRadius<0?0:this.outerRadius,this.startAngle,this.endAngle),n.arc(this.x,this.y,this.innerRadius<0?0:this.innerRadius,this.endAngle,this.startAngle,!0),n.closePath(),n.strokeStyle=this.strokeColor,n.lineWidth=this.strokeWidth,n.fillStyle=this.fillColor,n.fill(),n.lineJoin="bevel",this.showStroke&&n.stroke()}}),e.Rectangle=e.Element.extend({draw:function(){var t=this.ctx,n=this.width/2,e=this.x-n,r=this.x+n,i=this.base-(this.base-this.y),o=this.strokeWidth/2;this.showStroke&&(e+=o,r-=o,i+=o),t.beginPath(),t.fillStyle=this.fillColor,t.strokeStyle=this.strokeColor,t.lineWidth=this.strokeWidth,t.moveTo(e,this.base),t.lineTo(e,i),t.lineTo(r,i),t.lineTo(r,this.base),t.fill(),this.showStroke&&t.stroke()},height:function(){return this.base-this.y},inRange:function(t,n){return t>=this.x-this.width/2&&t<=this.x+this.width/2&&n>=this.y&&n<=this.base}}),e.Animation=e.Element.extend({currentStep:null,numSteps:60,easing:"",render:null,onAnimationProgress:null,onAnimationComplete:null}),e.Tooltip=e.Element.extend({draw:function(){var t=this.chart.ctx;t.font=T(this.fontSize,this.fontStyle,this.fontFamily),this.xAlign="center",this.yAlign="above";var n=this.caretPadding=2,e=t.measureText(this.text).width+2*this.xPadding,r=this.fontSize+2*this.yPadding,i=r+this.caretHeight+n;this.x+e/2>this.chart.width?this.xAlign="left":this.x-e/2<0&&(this.xAlign="right"),this.y-i<0&&(this.yAlign="below");var o=this.x-e/2,a=this.y-i;if(t.fillStyle=this.fillColor,this.custom)this.custom(this);else{switch(this.yAlign){case"above":t.beginPath(),t.moveTo(this.x,this.y-n),t.lineTo(this.x+this.caretHeight,this.y-(n+this.caretHeight)),t.lineTo(this.x-this.caretHeight,this.y-(n+this.caretHeight)),t.closePath(),t.fill();break;case"below":a=this.y+n+this.caretHeight,t.beginPath(),t.moveTo(this.x,this.y+n),t.lineTo(this.x+this.caretHeight,this.y+n+this.caretHeight),t.lineTo(this.x-this.caretHeight,this.y+n+this.caretHeight),t.closePath(),t.fill()}switch(this.xAlign){case"left":o=this.x-e+(this.cornerRadius+this.caretHeight);break;case"right":o=this.x-(this.cornerRadius+this.caretHeight)}j(t,o,a,e,r,this.cornerRadius),t.fill(),t.fillStyle=this.textColor,t.textAlign="center",t.textBaseline="middle",t.fillText(this.text,o+e/2,a+r/2)}}}),e.MultiTooltip=e.Element.extend({initialize:function(){this.font=T(this.fontSize,this.fontStyle,this.fontFamily),this.titleFont=T(this.titleFontSize,this.titleFontStyle,this.titleFontFamily),this.titleHeight=this.title?1.5*this.titleFontSize:0,this.height=this.labels.length*this.fontSize+(this.labels.length-1)*(this.fontSize/2)+2*this.yPadding+this.titleHeight,this.ctx.font=this.titleFont;var t=this.ctx.measureText(this.title).width,n=L(this.ctx,this.font,this.labels)+this.fontSize+3,e=v([n,t]);this.width=e+2*this.xPadding;var r=this.height/2;this.y-r<0?this.y=r:this.y+r>this.chart.height&&(this.y=this.chart.height-r),this.x>this.chart.width/2?this.x-=this.xOffset+this.width:this.x+=this.xOffset},getLineHeight:function(t){var n=this.y-this.height/2+this.yPadding,e=t-1;return 0===t?n+this.titleHeight/3:n+(1.5*this.fontSize*e+this.fontSize/2)+this.titleHeight},draw:function(){if(this.custom)this.custom(this);else{j(this.ctx,this.x,this.y-this.height/2,this.width,this.height,this.cornerRadius);var t=this.ctx;t.fillStyle=this.fillColor,t.fill(),t.closePath(),t.textAlign="left",t.textBaseline="middle",t.fillStyle=this.titleTextColor,t.font=this.titleFont,t.fillText(this.title,this.x+this.xPadding,this.getLineHeight(0)),t.font=this.font,r.each(this.labels,function(n,e){t.fillStyle=this.textColor,t.fillText(n,this.x+this.xPadding+this.fontSize+3,this.getLineHeight(e+1)),t.fillStyle=this.legendColorBackground,t.fillRect(this.x+this.xPadding,this.getLineHeight(e+1)-this.fontSize/2,this.fontSize,this.fontSize),t.fillStyle=this.legendColors[e].fill,t.fillRect(this.x+this.xPadding,this.getLineHeight(e+1)-this.fontSize/2,this.fontSize,this.fontSize)},this)}}}),e.Scale=e.Element.extend({initialize:function(){this.fit()},buildYLabels:function(){this.yLabels=[];for(var t=m(this.stepValue),n=0;n<=this.steps;n++)this.yLabels.push(b(this.templateString,{value:(this.min+n*this.stepValue).toFixed(t)}));this.yLabelWidth=this.display&&this.showLabels?L(this.ctx,this.font,this.yLabels)+10:0},addXLabel:function(t){this.xLabels.push(t),this.valuesCount++,this.fit()},removeXLabel:function(){this.xLabels.shift(),this.valuesCount--,this.fit()},fit:function(){this.startPoint=this.display?this.fontSize:0,this.endPoint=this.display?this.height-1.5*this.fontSize-5:this.height,this.startPoint+=this.padding,this.endPoint-=this.padding;var t,n=this.endPoint,e=this.endPoint-this.startPoint;for(this.calculateYRange(e),this.buildYLabels(),this.calculateXLabelRotation();e>this.endPoint-this.startPoint;)e=this.endPoint-this.startPoint,t=this.yLabelWidth,this.calculateYRange(e),this.buildYLabels(),t<this.yLabelWidth&&(this.endPoint=n,this.calculateXLabelRotation())},calculateXLabelRotation:function(){this.ctx.font=this.font;var t,n,e=this.ctx.measureText(this.xLabels[0]).width,r=this.ctx.measureText(this.xLabels[this.xLabels.length-1]).width;if(this.xScalePaddingRight=r/2+3,this.xScalePaddingLeft=e/2>this.yLabelWidth?e/2:this.yLabelWidth,this.xLabelRotation=0,this.display){var i,o=L(this.ctx,this.font,this.xLabels);this.xLabelWidth=o;for(var a=Math.floor(this.calculateX(1)-this.calculateX(0))-6;this.xLabelWidth>a&&0===this.xLabelRotation||this.xLabelWidth>a&&this.xLabelRotation<=90&&this.xLabelRotation>0;)i=Math.cos(y(this.xLabelRotation)),t=i*e,n=i*r,t+this.fontSize/2>this.yLabelWidth&&(this.xScalePaddingLeft=t+this.fontSize/2),this.xScalePaddingRight=this.fontSize/2,this.xLabelRotation++,this.xLabelWidth=i*o;this.xLabelRotation>0&&(this.endPoint-=Math.sin(y(this.xLabelRotation))*o+3)}else this.xLabelWidth=0,this.xScalePaddingRight=this.padding,this.xScalePaddingLeft=this.padding},calculateYRange:c,drawingArea:function(){return this.startPoint-this.endPoint},calculateY:function(t){var n=this.drawingArea()/(this.min-this.max);return this.endPoint-n*(t-this.min)},calculateX:function(t){var n=(this.xLabelRotation>0,this.width-(this.xScalePaddingLeft+this.xScalePaddingRight)),e=n/Math.max(this.valuesCount-(this.offsetGridLines?0:1),1),r=e*t+this.xScalePaddingLeft;return this.offsetGridLines&&(r+=e/2),Math.round(r)},update:function(t){r.extend(this,t),this.fit()},draw:function(){var t=this.ctx,n=(this.endPoint-this.startPoint)/this.steps,e=Math.round(this.xScalePaddingLeft);this.display&&(t.fillStyle=this.textColor,t.font=this.font,i(this.yLabels,function(i,o){var a=this.endPoint-n*o,u=Math.round(a),s=this.showHorizontalLines;t.textAlign="right",t.textBaseline="middle",this.showLabels&&t.fillText(i,e-10,a),0!==o||s||(s=!0),s&&t.beginPath(),o>0?(t.lineWidth=this.gridLineWidth,t.strokeStyle=this.gridLineColor):(t.lineWidth=this.lineWidth,t.strokeStyle=this.lineColor),u+=r.aliasPixel(t.lineWidth),s&&(t.moveTo(e,u),t.lineTo(this.width,u),t.stroke(),t.closePath()),t.lineWidth=this.lineWidth,t.strokeStyle=this.lineColor,t.beginPath(),t.moveTo(e-5,u),t.lineTo(e,u),t.stroke(),t.closePath()},this),i(this.xLabels,function(n,e){var r=this.calculateX(e)+$(this.lineWidth),i=this.calculateX(e-(this.offsetGridLines?.5:0))+$(this.lineWidth),o=this.xLabelRotation>0,a=this.showVerticalLines;0!==e||a||(a=!0),a&&t.beginPath(),e>0?(t.lineWidth=this.gridLineWidth,t.strokeStyle=this.gridLineColor):(t.lineWidth=this.lineWidth,t.strokeStyle=this.lineColor),a&&(t.moveTo(i,this.endPoint),t.lineTo(i,this.startPoint-3),t.stroke(),t.closePath()),t.lineWidth=this.lineWidth,t.strokeStyle=this.lineColor,t.beginPath(),t.moveTo(i,this.endPoint),t.lineTo(i,this.endPoint+5),t.stroke(),t.closePath(),t.save(),t.translate(r,o?this.endPoint+12:this.endPoint+8),t.rotate(-1*y(this.xLabelRotation)),t.font=this.font,t.textAlign=o?"right":"center",t.textBaseline=o?"middle":"top",t.fillText(n,0,0),t.restore()},this))}}),e.RadialScale=e.Element.extend({initialize:function(){this.size=g([this.height,this.width]),this.drawingArea=this.display?this.size/2-(this.fontSize/2+this.backdropPaddingY):this.size/2},calculateCenterOffset:function(t){var n=this.drawingArea/(this.max-this.min);return(t-this.min)*n},update:function(){this.lineArc?this.drawingArea=this.display?this.size/2-(this.fontSize/2+this.backdropPaddingY):this.size/2:this.setScaleSize(),this.buildYLabels()},buildYLabels:function(){this.yLabels=[];for(var t=m(this.stepValue),n=0;n<=this.steps;n++)this.yLabels.push(b(this.templateString,{value:(this.min+n*this.stepValue).toFixed(t)}))},getCircumference:function(){return 2*Math.PI/this.valuesCount},setScaleSize:function(){var t,n,e,r,i,o,a,u,s,l,c,f,h=g([this.height/2-this.pointLabelFontSize-5,this.width/2]),p=this.width,v=0;for(this.ctx.font=T(this.pointLabelFontSize,this.pointLabelFontStyle,this.pointLabelFontFamily),n=0;n<this.valuesCount;n++)t=this.getPointPosition(n,h),e=this.ctx.measureText(b(this.templateString,{value:this.labels[n]})).width+5,0===n||n===this.valuesCount/2?(r=e/2,t.x+r>p&&(p=t.x+r,i=n),t.x-r<v&&(v=t.x-r,a=n)):n<this.valuesCount/2?t.x+e>p&&(p=t.x+e,i=n):n>this.valuesCount/2&&t.x-e<v&&(v=t.x-e,a=n);s=v,l=Math.ceil(p-this.width),o=this.getIndexAngle(i),u=this.getIndexAngle(a),c=l/Math.sin(o+Math.PI/2),f=s/Math.sin(u+Math.PI/2),c=d(c)?c:0,f=d(f)?f:0,this.drawingArea=h-(f+c)/2,this.setCenterPoint(f,c)},setCenterPoint:function(t,n){var e=this.width-n-this.drawingArea,r=t+this.drawingArea;this.xCenter=(r+e)/2,this.yCenter=this.height/2},getIndexAngle:function(t){var n=2*Math.PI/this.valuesCount;return t*n-Math.PI/2},getPointPosition:function(t,n){var e=this.getIndexAngle(t);return{x:Math.cos(e)*n+this.xCenter,y:Math.sin(e)*n+this.yCenter}},draw:function(){if(this.display){var t=this.ctx;if(i(this.yLabels,function(n,e){if(e>0){var r,i=e*(this.drawingArea/this.steps),o=this.yCenter-i;if(this.lineWidth>0)if(t.strokeStyle=this.lineColor,t.lineWidth=this.lineWidth,this.lineArc)t.beginPath(),t.arc(this.xCenter,this.yCenter,i,0,2*Math.PI),t.closePath(),t.stroke();else{t.beginPath();for(var a=0;a<this.valuesCount;a++)r=this.getPointPosition(a,this.calculateCenterOffset(this.min+e*this.stepValue)),0===a?t.moveTo(r.x,r.y):t.lineTo(r.x,r.y);t.closePath(),t.stroke()}if(this.showLabels){if(t.font=T(this.fontSize,this.fontStyle,this.fontFamily),this.showLabelBackdrop){var u=t.measureText(n).width;t.fillStyle=this.backdropColor,t.fillRect(this.xCenter-u/2-this.backdropPaddingX,o-this.fontSize/2-this.backdropPaddingY,u+2*this.backdropPaddingX,this.fontSize+2*this.backdropPaddingY)}t.textAlign="center",t.textBaseline="middle",t.fillStyle=this.fontColor,t.fillText(n,this.xCenter,o)}}},this),!this.lineArc){t.lineWidth=this.angleLineWidth,t.strokeStyle=this.angleLineColor;for(var n=this.valuesCount-1;n>=0;n--){var e=null,r=null;if(this.angleLineWidth>0&&n%this.angleLineInterval===0&&(e=this.calculateCenterOffset(this.max),r=this.getPointPosition(n,e),t.beginPath(),t.moveTo(this.xCenter,this.yCenter),t.lineTo(r.x,r.y),t.stroke(),t.closePath()),this.backgroundColors&&this.backgroundColors.length==this.valuesCount){null==e&&(e=this.calculateCenterOffset(this.max)),null==r&&(r=this.getPointPosition(n,e));var o=this.getPointPosition(0===n?this.valuesCount-1:n-1,e),a=this.getPointPosition(n===this.valuesCount-1?0:n+1,e),u={x:(o.x+r.x)/2,y:(o.y+r.y)/2},s={x:(r.x+a.x)/2,y:(r.y+a.y)/2};t.beginPath(),t.moveTo(this.xCenter,this.yCenter),t.lineTo(u.x,u.y),t.lineTo(r.x,r.y),t.lineTo(s.x,s.y),t.fillStyle=this.backgroundColors[n],t.fill(),t.closePath()}var l=this.getPointPosition(n,this.calculateCenterOffset(this.max)+5);t.font=T(this.pointLabelFontSize,this.pointLabelFontStyle,this.pointLabelFontFamily),t.fillStyle=this.pointLabelFontColor;var c=this.labels.length,f=this.labels.length/2,h=f/2,p=h>n||n>c-h,d=n===h||n===c-h;0===n?t.textAlign="center":n===f?t.textAlign="center":f>n?t.textAlign="left":t.textAlign="right",d?t.textBaseline="middle":p?t.textBaseline="bottom":t.textBaseline="top",t.fillText(this.labels[n],l.x,l.y)}}}}}),e.animationService={frameDuration:17,animations:[],dropFrames:0,addAnimation:function(t,n){for(var e=0;e<this.animations.length;++e)if(this.animations[e].chartInstance===t)return void(this.animations[e].animationObject=n);this.animations.push({chartInstance:t,animationObject:n}),1==this.animations.length&&r.requestAnimFrame.call(window,this.digestWrapper)},cancelAnimation:function(t){var n=r.findNextWhere(this.animations,function(n){return n.chartInstance===t});n&&this.animations.splice(n,1)},digestWrapper:function(){e.animationService.startDigest.call(e.animationService)},startDigest:function(){var t=Date.now(),n=0;this.dropFrames>1&&(n=Math.floor(this.dropFrames),this.dropFrames-=n);for(var e=0;e<this.animations.length;e++)null===this.animations[e].animationObject.currentStep&&(this.animations[e].animationObject.currentStep=0),this.animations[e].animationObject.currentStep+=1+n,this.animations[e].animationObject.currentStep>this.animations[e].animationObject.numSteps&&(this.animations[e].animationObject.currentStep=this.animations[e].animationObject.numSteps),this.animations[e].animationObject.render(this.animations[e].chartInstance,this.animations[e].animationObject),this.animations[e].animationObject.currentStep==this.animations[e].animationObject.numSteps&&(this.animations[e].animationObject.onAnimationComplete.call(this.animations[e].chartInstance),this.animations.splice(e,1),e--);var i=Date.now(),o=i-t-this.frameDuration,a=o/this.frameDuration;a>1&&(this.dropFrames+=a),this.animations.length>0&&r.requestAnimFrame.call(window,this.digestWrapper)}},r.addEvent(window,"resize",function(){var t;return function(){clearTimeout(t),t=setTimeout(function(){i(e.instances,function(t){t.options.responsive&&t.resize(t.render,!0)})},50)}}()),p?define("Chart",[],function(){return e}):"object"==typeof module&&module.exports&&(module.exports=e),t.Chart=e,e.noConflict=function(){return t.Chart=n,e}}.call(this),function(){"use strict";var t=this,n=t.Chart,e=n.helpers,r={scaleBeginAtZero:!0,scaleShowGridLines:!0,scaleGridLineColor:"rgba(0,0,0,.05)",scaleGridLineWidth:1,scaleShowHorizontalLines:!0,scaleShowVerticalLines:!0,barShowStroke:!0,barStrokeWidth:2,barValueSpacing:5,barDatasetSpacing:1,legendTemplate:'<ul class="<%=name.toLowerCase()%>-legend"><% for (var i=0; i<datasets.length; i++){%><li><span class="<%=name.toLowerCase()%>-legend-icon" style="background-color:<%=datasets[i].fillColor%>"></span><span class="<%=name.toLowerCase()%>-legend-text"><%if(datasets[i].label){%><%=datasets[i].label%><%}%></span></li><%}%></ul>'};n.Type.extend({name:"Bar",defaults:r,initialize:function(t){var r=this.options;this.ScaleClass=n.Scale.extend({offsetGridLines:!0,calculateBarX:function(t,n,e){var i=this.calculateBaseWidth(),o=this.calculateX(e)-i/2,a=this.calculateBarWidth(t);return o+a*n+n*r.barDatasetSpacing+a/2},calculateBaseWidth:function(){return this.calculateX(1)-this.calculateX(0)-2*r.barValueSpacing},calculateBarWidth:function(t){var n=this.calculateBaseWidth()-(t-1)*r.barDatasetSpacing;return n/t}}),this.datasets=[],this.options.showTooltips&&e.bindEvents(this,this.options.tooltipEvents,function(t){var n="mouseout"!==t.type?this.getBarsAtEvent(t):[];this.eachBars(function(t){t.restore(["fillColor","strokeColor"])}),e.each(n,function(t){t&&(t.fillColor=t.highlightFill,t.strokeColor=t.highlightStroke)}),this.showTooltip(n)}),this.BarClass=n.Rectangle.extend({strokeWidth:this.options.barStrokeWidth,showStroke:this.options.barShowStroke,ctx:this.chart.ctx}),e.each(t.datasets,function(n,r){var i={label:n.label||null,fillColor:n.fillColor,strokeColor:n.strokeColor,bars:[]};this.datasets.push(i),e.each(n.data,function(e,r){i.bars.push(new this.BarClass({value:e,label:t.labels[r],datasetLabel:n.label,strokeColor:"object"==typeof n.strokeColor?n.strokeColor[r]:n.strokeColor,fillColor:"object"==typeof n.fillColor?n.fillColor[r]:n.fillColor,highlightFill:n.highlightFill?"object"==typeof n.highlightFill?n.highlightFill[r]:n.highlightFill:"object"==typeof n.fillColor?n.fillColor[r]:n.fillColor,highlightStroke:n.highlightStroke?"object"==typeof n.highlightStroke?n.highlightStroke[r]:n.highlightStroke:"object"==typeof n.strokeColor?n.strokeColor[r]:n.strokeColor}))},this)},this),this.buildScale(t.labels),this.BarClass.prototype.base=this.scale.endPoint,this.eachBars(function(t,n,r){e.extend(t,{width:this.scale.calculateBarWidth(this.datasets.length),x:this.scale.calculateBarX(this.datasets.length,r,n),y:this.scale.endPoint}),t.save()},this),this.render()},update:function(){this.scale.update(),e.each(this.activeElements,function(t){t.restore(["fillColor","strokeColor"])}),this.eachBars(function(t){t.save()}),this.render()},eachBars:function(t){e.each(this.datasets,function(n,r){e.each(n.bars,t,this,r)},this)},getBarsAtEvent:function(t){for(var n,r=[],i=e.getRelativePosition(t),o=function(t){r.push(t.bars[n])},a=0;a<this.datasets.length;a++)for(n=0;n<this.datasets[a].bars.length;n++)if(this.datasets[a].bars[n].inRange(i.x,i.y))return e.each(this.datasets,o),r;return r},buildScale:function(t){var n=this,r=function(){var t=[];return n.eachBars(function(n){t.push(n.value)}),t},i={templateString:this.options.scaleLabel,height:this.chart.height,width:this.chart.width,ctx:this.chart.ctx,textColor:this.options.scaleFontColor,fontSize:this.options.scaleFontSize,fontStyle:this.options.scaleFontStyle,fontFamily:this.options.scaleFontFamily,valuesCount:t.length,beginAtZero:this.options.scaleBeginAtZero,integersOnly:this.options.scaleIntegersOnly,calculateYRange:function(t){var n=e.calculateScaleRange(r(),t,this.fontSize,this.beginAtZero,this.integersOnly);e.extend(this,n)},xLabels:t,font:e.fontString(this.options.scaleFontSize,this.options.scaleFontStyle,this.options.scaleFontFamily),lineWidth:this.options.scaleLineWidth,lineColor:this.options.scaleLineColor,showHorizontalLines:this.options.scaleShowHorizontalLines,showVerticalLines:this.options.scaleShowVerticalLines,gridLineWidth:this.options.scaleShowGridLines?this.options.scaleGridLineWidth:0,gridLineColor:this.options.scaleShowGridLines?this.options.scaleGridLineColor:"rgba(0,0,0,0)",padding:this.options.showScale?0:this.options.barShowStroke?this.options.barStrokeWidth:0,showLabels:this.options.scaleShowLabels,display:this.options.showScale};this.options.scaleOverride&&e.extend(i,{calculateYRange:e.noop,steps:this.options.scaleSteps,stepValue:this.options.scaleStepWidth,min:this.options.scaleStartValue,max:this.options.scaleStartValue+this.options.scaleSteps*this.options.scaleStepWidth}),this.scale=new this.ScaleClass(i)},addData:function(t,n){e.each(t,function(t,e){this.datasets[e].bars.push(new this.BarClass({value:t,label:n,datasetLabel:this.datasets[e].label,x:this.scale.calculateBarX(this.datasets.length,e,this.scale.valuesCount+1),y:this.scale.endPoint,width:this.scale.calculateBarWidth(this.datasets.length),base:this.scale.endPoint,strokeColor:this.datasets[e].strokeColor,fillColor:this.datasets[e].fillColor}))},this),this.scale.addXLabel(n),this.update()},removeData:function(){this.scale.removeXLabel(),e.each(this.datasets,function(t){t.bars.shift()},this),this.update()},reflow:function(){e.extend(this.BarClass.prototype,{y:this.scale.endPoint,base:this.scale.endPoint});var t=e.extend({height:this.chart.height,width:this.chart.width});this.scale.update(t)},draw:function(t){var n=t||1;this.clear();this.chart.ctx;this.scale.draw(n),e.each(this.datasets,function(t,r){e.each(t.bars,function(t,e){t.hasValue()&&(t.base=this.scale.endPoint,t.transition({x:this.scale.calculateBarX(this.datasets.length,r,e),y:this.scale.calculateY(t.value),
+width:this.scale.calculateBarWidth(this.datasets.length)},n).draw())},this)},this)}})}.call(this),function(){"use strict";var t=this,n=t.Chart,e=n.helpers,r={segmentShowStroke:!0,segmentStrokeColor:"#fff",segmentStrokeWidth:2,percentageInnerCutout:50,animationSteps:100,animationEasing:"easeOutBounce",animateRotate:!0,animateScale:!1,legendTemplate:'<ul class="<%=name.toLowerCase()%>-legend"><% for (var i=0; i<segments.length; i++){%><li><span class="<%=name.toLowerCase()%>-legend-icon" style="background-color:<%=segments[i].fillColor%>"></span><span class="<%=name.toLowerCase()%>-legend-text"><%if(segments[i].label){%><%=segments[i].label%><%}%></span></li><%}%></ul>'};n.Type.extend({name:"Doughnut",defaults:r,initialize:function(t){this.segments=[],this.outerRadius=(e.min([this.chart.width,this.chart.height])-this.options.segmentStrokeWidth/2)/2,this.SegmentArc=n.Arc.extend({ctx:this.chart.ctx,x:this.chart.width/2,y:this.chart.height/2}),this.options.showTooltips&&e.bindEvents(this,this.options.tooltipEvents,function(t){var n="mouseout"!==t.type?this.getSegmentsAtEvent(t):[];e.each(this.segments,function(t){t.restore(["fillColor"])}),e.each(n,function(t){t.fillColor=t.highlightColor}),this.showTooltip(n)}),this.calculateTotal(t),e.each(t,function(n,e){n.color||(n.color="hsl("+360*e/t.length+", 100%, 50%)"),this.addData(n,e,!0)},this),this.render()},getSegmentsAtEvent:function(t){var n=[],r=e.getRelativePosition(t);return e.each(this.segments,function(t){t.inRange(r.x,r.y)&&n.push(t)},this),n},addData:function(t,e,r){var i=void 0!==e?e:this.segments.length;"undefined"==typeof t.color&&(t.color=n.defaults.global.segmentColorDefault[i%n.defaults.global.segmentColorDefault.length],t.highlight=n.defaults.global.segmentHighlightColorDefaults[i%n.defaults.global.segmentHighlightColorDefaults.length]),this.segments.splice(i,0,new this.SegmentArc({value:t.value,outerRadius:this.options.animateScale?0:this.outerRadius,innerRadius:this.options.animateScale?0:this.outerRadius/100*this.options.percentageInnerCutout,fillColor:t.color,highlightColor:t.highlight||t.color,showStroke:this.options.segmentShowStroke,strokeWidth:this.options.segmentStrokeWidth,strokeColor:this.options.segmentStrokeColor,startAngle:1.5*Math.PI,circumference:this.options.animateRotate?0:this.calculateCircumference(t.value),label:t.label})),r||(this.reflow(),this.update())},calculateCircumference:function(t){return this.total>0?2*Math.PI*(t/this.total):0},calculateTotal:function(t){this.total=0,e.each(t,function(t){this.total+=Math.abs(t.value)},this)},update:function(){this.calculateTotal(this.segments),e.each(this.activeElements,function(t){t.restore(["fillColor"])}),e.each(this.segments,function(t){t.save()}),this.render()},removeData:function(t){var n=e.isNumber(t)?t:this.segments.length-1;this.segments.splice(n,1),this.reflow(),this.update()},reflow:function(){e.extend(this.SegmentArc.prototype,{x:this.chart.width/2,y:this.chart.height/2}),this.outerRadius=(e.min([this.chart.width,this.chart.height])-this.options.segmentStrokeWidth/2)/2,e.each(this.segments,function(t){t.update({outerRadius:this.outerRadius,innerRadius:this.outerRadius/100*this.options.percentageInnerCutout})},this)},draw:function(t){var n=t?t:1;this.clear(),e.each(this.segments,function(t,e){t.transition({circumference:this.calculateCircumference(t.value),outerRadius:this.outerRadius,innerRadius:this.outerRadius/100*this.options.percentageInnerCutout},n),t.endAngle=t.startAngle+t.circumference,t.draw(),0===e&&(t.startAngle=1.5*Math.PI),e<this.segments.length-1&&(this.segments[e+1].startAngle=t.endAngle)},this)}}),n.types.Doughnut.extend({name:"Pie",defaults:e.merge(r,{percentageInnerCutout:0})})}.call(this),function(){"use strict";var t=this,n=t.Chart,e=n.helpers,r={scaleShowGridLines:!0,scaleGridLineColor:"rgba(0,0,0,.05)",scaleGridLineWidth:1,scaleShowHorizontalLines:!0,scaleShowVerticalLines:!0,bezierCurve:!0,bezierCurveTension:.4,pointDot:!0,pointDotRadius:4,pointDotStrokeWidth:1,pointHitDetectionRadius:20,datasetStroke:!0,datasetStrokeWidth:2,datasetFill:!0,legendTemplate:'<ul class="<%=name.toLowerCase()%>-legend"><% for (var i=0; i<datasets.length; i++){%><li><span class="<%=name.toLowerCase()%>-legend-icon" style="background-color:<%=datasets[i].strokeColor%>"></span><span class="<%=name.toLowerCase()%>-legend-text"><%if(datasets[i].label){%><%=datasets[i].label%><%}%></span></li><%}%></ul>',offsetGridLines:!1};n.Type.extend({name:"Line",defaults:r,initialize:function(t){this.PointClass=n.Point.extend({offsetGridLines:this.options.offsetGridLines,strokeWidth:this.options.pointDotStrokeWidth,radius:this.options.pointDotRadius,display:this.options.pointDot,hitDetectionRadius:this.options.pointHitDetectionRadius,ctx:this.chart.ctx,inRange:function(t){return Math.pow(t-this.x,2)<Math.pow(this.radius+this.hitDetectionRadius,2)}}),this.datasets=[],this.options.showTooltips&&e.bindEvents(this,this.options.tooltipEvents,function(t){var n="mouseout"!==t.type?this.getPointsAtEvent(t):[];this.eachPoints(function(t){t.restore(["fillColor","strokeColor"])}),e.each(n,function(t){t.fillColor=t.highlightFill,t.strokeColor=t.highlightStroke}),this.showTooltip(n)}),e.each(t.datasets,function(n){var r={label:n.label||null,fillColor:n.fillColor,strokeColor:n.strokeColor,pointColor:n.pointColor,pointStrokeColor:n.pointStrokeColor,points:[]};this.datasets.push(r),e.each(n.data,function(e,i){r.points.push(new this.PointClass({value:e,label:t.labels[i],datasetLabel:n.label,strokeColor:n.pointStrokeColor,fillColor:n.pointColor,highlightFill:n.pointHighlightFill||n.pointColor,highlightStroke:n.pointHighlightStroke||n.pointStrokeColor}))},this),this.buildScale(t.labels),this.eachPoints(function(t,n){e.extend(t,{x:this.scale.calculateX(n),y:this.scale.endPoint}),t.save()},this)},this),this.render()},update:function(){this.scale.update(),e.each(this.activeElements,function(t){t.restore(["fillColor","strokeColor"])}),this.eachPoints(function(t){t.save()}),this.render()},eachPoints:function(t){e.each(this.datasets,function(n){e.each(n.points,t,this)},this)},getPointsAtEvent:function(t){var n=[],r=e.getRelativePosition(t);return e.each(this.datasets,function(t){e.each(t.points,function(t){t.inRange(r.x,r.y)&&n.push(t)})},this),n},buildScale:function(t){var r=this,i=function(){var t=[];return r.eachPoints(function(n){t.push(n.value)}),t},o={templateString:this.options.scaleLabel,height:this.chart.height,width:this.chart.width,ctx:this.chart.ctx,textColor:this.options.scaleFontColor,offsetGridLines:this.options.offsetGridLines,fontSize:this.options.scaleFontSize,fontStyle:this.options.scaleFontStyle,fontFamily:this.options.scaleFontFamily,valuesCount:t.length,beginAtZero:this.options.scaleBeginAtZero,integersOnly:this.options.scaleIntegersOnly,calculateYRange:function(t){var n=e.calculateScaleRange(i(),t,this.fontSize,this.beginAtZero,this.integersOnly);e.extend(this,n)},xLabels:t,font:e.fontString(this.options.scaleFontSize,this.options.scaleFontStyle,this.options.scaleFontFamily),lineWidth:this.options.scaleLineWidth,lineColor:this.options.scaleLineColor,showHorizontalLines:this.options.scaleShowHorizontalLines,showVerticalLines:this.options.scaleShowVerticalLines,gridLineWidth:this.options.scaleShowGridLines?this.options.scaleGridLineWidth:0,gridLineColor:this.options.scaleShowGridLines?this.options.scaleGridLineColor:"rgba(0,0,0,0)",padding:this.options.showScale?0:this.options.pointDotRadius+this.options.pointDotStrokeWidth,showLabels:this.options.scaleShowLabels,display:this.options.showScale};this.options.scaleOverride&&e.extend(o,{calculateYRange:e.noop,steps:this.options.scaleSteps,stepValue:this.options.scaleStepWidth,min:this.options.scaleStartValue,max:this.options.scaleStartValue+this.options.scaleSteps*this.options.scaleStepWidth}),this.scale=new n.Scale(o)},addData:function(t,n){e.each(t,function(t,e){this.datasets[e].points.push(new this.PointClass({value:t,label:n,datasetLabel:this.datasets[e].label,x:this.scale.calculateX(this.scale.valuesCount+1),y:this.scale.endPoint,strokeColor:this.datasets[e].pointStrokeColor,fillColor:this.datasets[e].pointColor}))},this),this.scale.addXLabel(n),this.update()},removeData:function(){this.scale.removeXLabel(),e.each(this.datasets,function(t){t.points.shift()},this),this.update()},reflow:function(){var t=e.extend({height:this.chart.height,width:this.chart.width});this.scale.update(t)},draw:function(t){var n=t||1;this.clear();var r=this.chart.ctx,i=function(t){return null!==t.value},o=function(t,n,r){return e.findNextWhere(n,i,r)||t},a=function(t,n,r){return e.findPreviousWhere(n,i,r)||t};this.scale&&(this.scale.draw(n),e.each(this.datasets,function(t){var u=e.where(t.points,i);e.each(t.points,function(t,e){t.hasValue()&&t.transition({y:this.scale.calculateY(t.value),x:this.scale.calculateX(e)},n)},this),this.options.bezierCurve&&e.each(u,function(t,n){var r=n>0&&n<u.length-1?this.options.bezierCurveTension:0;t.controlPoints=e.splineCurve(a(t,u,n),t,o(t,u,n),r),t.controlPoints.outer.y>this.scale.endPoint?t.controlPoints.outer.y=this.scale.endPoint:t.controlPoints.outer.y<this.scale.startPoint&&(t.controlPoints.outer.y=this.scale.startPoint),t.controlPoints.inner.y>this.scale.endPoint?t.controlPoints.inner.y=this.scale.endPoint:t.controlPoints.inner.y<this.scale.startPoint&&(t.controlPoints.inner.y=this.scale.startPoint)},this),r.lineWidth=this.options.datasetStrokeWidth,r.strokeStyle=t.strokeColor,r.beginPath(),e.each(u,function(t,n){if(0===n)r.moveTo(t.x,t.y);else if(this.options.bezierCurve){var e=a(t,u,n);r.bezierCurveTo(e.controlPoints.outer.x,e.controlPoints.outer.y,t.controlPoints.inner.x,t.controlPoints.inner.y,t.x,t.y)}else r.lineTo(t.x,t.y)},this),this.options.datasetStroke&&r.stroke(),this.options.datasetFill&&u.length>0&&(r.lineTo(u[u.length-1].x,this.scale.endPoint),r.lineTo(u[0].x,this.scale.endPoint),r.fillStyle=t.fillColor,r.closePath(),r.fill()),e.each(u,function(t){t.draw()})},this))}})}.call(this),function(){"use strict";var t=this,n=t.Chart,e=n.helpers,r={scaleShowLabelBackdrop:!0,scaleBackdropColor:"rgba(255,255,255,0.75)",scaleBeginAtZero:!0,scaleBackdropPaddingY:2,scaleBackdropPaddingX:2,scaleShowLine:!0,segmentShowStroke:!0,segmentStrokeColor:"#fff",segmentStrokeWidth:2,animationSteps:100,animationEasing:"easeOutBounce",animateRotate:!0,animateScale:!1,legendTemplate:'<ul class="<%=name.toLowerCase()%>-legend"><% for (var i=0; i<segments.length; i++){%><li><span class="<%=name.toLowerCase()%>-legend-icon" style="background-color:<%=segments[i].fillColor%>"></span><span class="<%=name.toLowerCase()%>-legend-text"><%if(segments[i].label){%><%=segments[i].label%><%}%></span></li><%}%></ul>'};n.Type.extend({name:"PolarArea",defaults:r,initialize:function(t){this.segments=[],this.SegmentArc=n.Arc.extend({showStroke:this.options.segmentShowStroke,strokeWidth:this.options.segmentStrokeWidth,strokeColor:this.options.segmentStrokeColor,ctx:this.chart.ctx,innerRadius:0,x:this.chart.width/2,y:this.chart.height/2}),this.scale=new n.RadialScale({display:this.options.showScale,fontStyle:this.options.scaleFontStyle,fontSize:this.options.scaleFontSize,fontFamily:this.options.scaleFontFamily,fontColor:this.options.scaleFontColor,showLabels:this.options.scaleShowLabels,showLabelBackdrop:this.options.scaleShowLabelBackdrop,backdropColor:this.options.scaleBackdropColor,backdropPaddingY:this.options.scaleBackdropPaddingY,backdropPaddingX:this.options.scaleBackdropPaddingX,lineWidth:this.options.scaleShowLine?this.options.scaleLineWidth:0,lineColor:this.options.scaleLineColor,lineArc:!0,width:this.chart.width,height:this.chart.height,xCenter:this.chart.width/2,yCenter:this.chart.height/2,ctx:this.chart.ctx,templateString:this.options.scaleLabel,valuesCount:t.length}),this.updateScaleRange(t),this.scale.update(),e.each(t,function(t,n){this.addData(t,n,!0)},this),this.options.showTooltips&&e.bindEvents(this,this.options.tooltipEvents,function(t){var n="mouseout"!==t.type?this.getSegmentsAtEvent(t):[];e.each(this.segments,function(t){t.restore(["fillColor"])}),e.each(n,function(t){t.fillColor=t.highlightColor}),this.showTooltip(n)}),this.render()},getSegmentsAtEvent:function(t){var n=[],r=e.getRelativePosition(t);return e.each(this.segments,function(t){t.inRange(r.x,r.y)&&n.push(t)},this),n},addData:function(t,n,e){var r=n||this.segments.length;this.segments.splice(r,0,new this.SegmentArc({fillColor:t.color,highlightColor:t.highlight||t.color,label:t.label,value:t.value,outerRadius:this.options.animateScale?0:this.scale.calculateCenterOffset(t.value),circumference:this.options.animateRotate?0:this.scale.getCircumference(),startAngle:1.5*Math.PI})),e||(this.reflow(),this.update())},removeData:function(t){var n=e.isNumber(t)?t:this.segments.length-1;this.segments.splice(n,1),this.reflow(),this.update()},calculateTotal:function(t){this.total=0,e.each(t,function(t){this.total+=t.value},this),this.scale.valuesCount=this.segments.length},updateScaleRange:function(t){var n=[];e.each(t,function(t){n.push(t.value)});var r=this.options.scaleOverride?{steps:this.options.scaleSteps,stepValue:this.options.scaleStepWidth,min:this.options.scaleStartValue,max:this.options.scaleStartValue+this.options.scaleSteps*this.options.scaleStepWidth}:e.calculateScaleRange(n,e.min([this.chart.width,this.chart.height])/2,this.options.scaleFontSize,this.options.scaleBeginAtZero,this.options.scaleIntegersOnly);e.extend(this.scale,r,{size:e.min([this.chart.width,this.chart.height]),xCenter:this.chart.width/2,yCenter:this.chart.height/2})},update:function(){this.calculateTotal(this.segments),e.each(this.segments,function(t){t.save()}),this.reflow(),this.render()},reflow:function(){e.extend(this.SegmentArc.prototype,{x:this.chart.width/2,y:this.chart.height/2}),this.updateScaleRange(this.segments),this.scale.update(),e.extend(this.scale,{xCenter:this.chart.width/2,yCenter:this.chart.height/2}),e.each(this.segments,function(t){t.update({outerRadius:this.scale.calculateCenterOffset(t.value)})},this)},draw:function(t){var n=t||1;this.clear(),e.each(this.segments,function(t,e){t.transition({circumference:this.scale.getCircumference(),outerRadius:this.scale.calculateCenterOffset(t.value)},n),t.endAngle=t.startAngle+t.circumference,0===e&&(t.startAngle=1.5*Math.PI),e<this.segments.length-1&&(this.segments[e+1].startAngle=t.endAngle),t.draw()},this),this.scale.draw()}})}.call(this),function(){"use strict";var t=this,n=t.Chart,e=n.helpers;n.Type.extend({name:"Radar",defaults:{scaleShowLine:!0,angleShowLineOut:!0,scaleShowLabels:!1,scaleBeginAtZero:!0,angleLineColor:"rgba(0,0,0,.1)",angleLineWidth:1,angleLineInterval:1,pointLabelFontFamily:"'Arial'",pointLabelFontStyle:"normal",pointLabelFontSize:10,pointLabelFontColor:"#666",pointDot:!0,pointDotRadius:3,pointDotStrokeWidth:1,pointHitDetectionRadius:20,datasetStroke:!0,datasetStrokeWidth:2,datasetFill:!0,legendTemplate:'<ul class="<%=name.toLowerCase()%>-legend"><% for (var i=0; i<datasets.length; i++){%><li><span class="<%=name.toLowerCase()%>-legend-icon" style="background-color:<%=datasets[i].strokeColor%>"></span><span class="<%=name.toLowerCase()%>-legend-text"><%if(datasets[i].label){%><%=datasets[i].label%><%}%></span></li><%}%></ul>'},initialize:function(t){this.PointClass=n.Point.extend({strokeWidth:this.options.pointDotStrokeWidth,radius:this.options.pointDotRadius,display:this.options.pointDot,hitDetectionRadius:this.options.pointHitDetectionRadius,ctx:this.chart.ctx}),this.datasets=[],this.buildScale(t),this.options.showTooltips&&e.bindEvents(this,this.options.tooltipEvents,function(t){var n="mouseout"!==t.type?this.getPointsAtEvent(t):[];this.eachPoints(function(t){t.restore(["fillColor","strokeColor"])}),e.each(n,function(t){t.fillColor=t.highlightFill,t.strokeColor=t.highlightStroke}),this.showTooltip(n)}),e.each(t.datasets,function(n){var r={label:n.label||null,fillColor:n.fillColor,strokeColor:n.strokeColor,pointColor:n.pointColor,pointStrokeColor:n.pointStrokeColor,points:[]};this.datasets.push(r),e.each(n.data,function(e,i){var o;this.scale.animation||(o=this.scale.getPointPosition(i,this.scale.calculateCenterOffset(e))),r.points.push(new this.PointClass({value:e,label:t.labels[i],datasetLabel:n.label,x:this.options.animation?this.scale.xCenter:o.x,y:this.options.animation?this.scale.yCenter:o.y,strokeColor:n.pointStrokeColor,fillColor:n.pointColor,highlightFill:n.pointHighlightFill||n.pointColor,highlightStroke:n.pointHighlightStroke||n.pointStrokeColor}))},this)},this),this.render()},eachPoints:function(t){e.each(this.datasets,function(n){e.each(n.points,t,this)},this)},getPointsAtEvent:function(t){var n=e.getRelativePosition(t),r=e.getAngleFromPoint({x:this.scale.xCenter,y:this.scale.yCenter},n),i=2*Math.PI/this.scale.valuesCount,o=Math.round((r.angle-1.5*Math.PI)/i),a=[];return(o>=this.scale.valuesCount||0>o)&&(o=0),r.distance<=this.scale.drawingArea&&e.each(this.datasets,function(t){a.push(t.points[o])}),a},buildScale:function(t){this.scale=new n.RadialScale({display:this.options.showScale,fontStyle:this.options.scaleFontStyle,fontSize:this.options.scaleFontSize,fontFamily:this.options.scaleFontFamily,fontColor:this.options.scaleFontColor,showLabels:this.options.scaleShowLabels,showLabelBackdrop:this.options.scaleShowLabelBackdrop,backdropColor:this.options.scaleBackdropColor,backgroundColors:this.options.scaleBackgroundColors,backdropPaddingY:this.options.scaleBackdropPaddingY,backdropPaddingX:this.options.scaleBackdropPaddingX,lineWidth:this.options.scaleShowLine?this.options.scaleLineWidth:0,lineColor:this.options.scaleLineColor,angleLineColor:this.options.angleLineColor,angleLineWidth:this.options.angleShowLineOut?this.options.angleLineWidth:0,angleLineInterval:this.options.angleLineInterval?this.options.angleLineInterval:1,pointLabelFontColor:this.options.pointLabelFontColor,pointLabelFontSize:this.options.pointLabelFontSize,pointLabelFontFamily:this.options.pointLabelFontFamily,pointLabelFontStyle:this.options.pointLabelFontStyle,height:this.chart.height,width:this.chart.width,xCenter:this.chart.width/2,yCenter:this.chart.height/2,ctx:this.chart.ctx,templateString:this.options.scaleLabel,labels:t.labels,valuesCount:t.datasets[0].data.length}),this.scale.setScaleSize(),this.updateScaleRange(t.datasets),this.scale.buildYLabels()},updateScaleRange:function(t){var n=function(){var n=[];return e.each(t,function(t){t.data?n=n.concat(t.data):e.each(t.points,function(t){n.push(t.value)})}),n}(),r=this.options.scaleOverride?{steps:this.options.scaleSteps,stepValue:this.options.scaleStepWidth,min:this.options.scaleStartValue,max:this.options.scaleStartValue+this.options.scaleSteps*this.options.scaleStepWidth}:e.calculateScaleRange(n,e.min([this.chart.width,this.chart.height])/2,this.options.scaleFontSize,this.options.scaleBeginAtZero,this.options.scaleIntegersOnly);e.extend(this.scale,r)},addData:function(t,n){this.scale.valuesCount++,e.each(t,function(t,e){var r=this.scale.getPointPosition(this.scale.valuesCount,this.scale.calculateCenterOffset(t));this.datasets[e].points.push(new this.PointClass({value:t,label:n,datasetLabel:this.datasets[e].label,x:r.x,y:r.y,strokeColor:this.datasets[e].pointStrokeColor,fillColor:this.datasets[e].pointColor}))},this),this.scale.labels.push(n),this.reflow(),this.update()},removeData:function(){this.scale.valuesCount--,this.scale.labels.shift(),e.each(this.datasets,function(t){t.points.shift()},this),this.reflow(),this.update()},update:function(){this.eachPoints(function(t){t.save()}),this.reflow(),this.render()},reflow:function(){e.extend(this.scale,{width:this.chart.width,height:this.chart.height,size:e.min([this.chart.width,this.chart.height]),xCenter:this.chart.width/2,yCenter:this.chart.height/2}),this.updateScaleRange(this.datasets),this.scale.setScaleSize(),this.scale.buildYLabels()},draw:function(t){var n=t||1,r=this.chart.ctx;this.clear(),this.scale.draw(),e.each(this.datasets,function(t){e.each(t.points,function(t,e){t.hasValue()&&t.transition(this.scale.getPointPosition(e,this.scale.calculateCenterOffset(t.value)),n)},this),r.lineWidth=this.options.datasetStrokeWidth,r.strokeStyle=t.strokeColor,r.beginPath(),e.each(t.points,function(t,n){0===n?r.moveTo(t.x,t.y):r.lineTo(t.x,t.y)},this),r.closePath(),r.stroke(),r.fillStyle=t.fillColor,this.options.datasetFill&&r.fill(),e.each(t.points,function(t){t.hasValue()&&t.draw()})},this)}})}.call(this),function(t){"use strict";"object"==typeof exports?module.exports=t("undefined"!=typeof angular?angular:require("angular"),"undefined"!=typeof Chart?Chart:require("chart.js")):"function"==typeof define&&define.amd?define(["angular","chart"],t):t(angular,Chart)}(function(t,n){"use strict";function e(){var e={},r={Chart:n,getOptions:function(n){var r=n&&e[n]||{};return t.extend({},e,r)}};this.setOptions=function(n,r){return r?void(e[n]=t.extend(e[n]||{},r)):(r=n,void(e=t.extend(e,r)))},this.$get=function(){return r}}function r(e,r){function o(t,n){return t&&n&&t.length&&n.length?Array.isArray(t[0])?t.length===n.length&&t.every(function(t,e){return t.length===n[e].length}):n.reduce(a,0)>0?t.length===n.length:!1:!1}function a(t,n){return t+n}function u(n,e,r,i){var o=null;return function(a){var u=e.getPointsAtEvent||e.getBarsAtEvent||e.getSegmentsAtEvent;if(u){var s=u.call(e,a);i!==!1&&t.equals(o,s)!==!1||(o=s,n[r](s,a),n.$apply())}}}function s(r,i){for(var o=!1,a=t.copy(i.colours||e.getOptions(r).colours||n.defaults.global.colours);a.length<i.data.length;)a.push(i.getColour()),o=!0;return o&&(i.colours=a),a.map(l)}function l(t){return"object"==typeof t&&null!==t?t:"string"==typeof t&&"#"===t[0]?f(d(t.substr(1))):c()}function c(){var t=[h(0,255),h(0,255),h(0,255)];return f(t)}function f(t){return{fillColor:p(t,.2),strokeColor:p(t,1),pointColor:p(t,1),pointStrokeColor:"#fff",pointHighlightFill:"#fff",pointHighlightStroke:p(t,.8)}}function h(t,n){return Math.floor(Math.random()*(n-t+1))+t}function p(t,n){return i?"rgb("+t.join(",")+")":"rgba("+t.concat(n).join(",")+")"}function d(t){var n=parseInt(t,16),e=n>>16&255,r=n>>8&255,i=255&n;return[e,r,i]}function v(n,e,r,i){return{labels:n,datasets:e.map(function(n,e){return t.extend({},i[e],{label:r[e],data:n})})}}function g(n,e,r){return n.map(function(n,i){return t.extend({},r[i],{label:n,value:e[i],color:r[i].strokeColor,highlight:r[i].pointHighlightStroke})})}function m(t,n){var e=t.parent(),r=e.find("chart-legend"),i="<chart-legend>"+n.generateLegend()+"</chart-legend>";r.length?r.replaceWith(i):e.append(i)}function y(t,n,e,r){Array.isArray(e.data[0])?t.datasets.forEach(function(t,e){(t.points||t.bars).forEach(function(t,r){t.value=n[e][r]})}):t.segments.forEach(function(t,e){t.value=n[e]}),t.update(),e.$emit("update",t),e.legend&&"false"!==e.legend&&m(r,t)}function $(t){return!t||Array.isArray(t)&&!t.length||"object"==typeof t&&!Object.keys(t).length}function x(r,i){var o=t.extend({},n.defaults.global,e.getOptions(r),i.options);return o.responsive}function b(t,n){t&&(t.destroy(),n.$emit("destroy",t))}return function(n){return{restrict:"CA",scope:{data:"=?",labels:"=?",options:"=?",series:"=?",colours:"=?",getColour:"=?",chartType:"=",legend:"@",click:"=?",hover:"=?",chartData:"=?",chartLabels:"=?",chartOptions:"=?",chartSeries:"=?",chartColours:"=?",chartLegend:"@",chartClick:"=?",chartHover:"=?"},link:function(a,l){function f(t,n){a.$watch(t,function(t){"undefined"!=typeof t&&(a[n]=t)})}function h(e,r){if(!$(e)&&!t.equals(e,r)){var i=n||a.chartType;i&&p(i)}}function p(n){if(x(n,a)&&0===l[0].clientHeight&&0===C.clientHeight)return r(function(){p(n)},50,!1);if(a.data&&a.data.length){a.getColour="function"==typeof a.getColour?a.getColour:c;var i=s(n,a),o=l[0],f=o.getContext("2d"),h=Array.isArray(a.data[0])?v(a.labels,a.data,a.series||[],i):g(a.labels,a.data,i),d=t.extend({},e.getOptions(n),a.options);b(w,a),w=new e.Chart(f)[n](h,d),a.$emit("create",w),o.onclick=a.click?u(a,w,"click",!1):t.noop,o.onmousemove=a.hover?u(a,w,"hover",!0):t.noop,a.legend&&"false"!==a.legend&&m(l,w)}}function d(t){if("undefined"!=typeof console&&"test"!==e.getOptions().env){var n="function"==typeof console.warn?console.warn:console.log;a[t]&&n.call(console,'"%s" is deprecated and will be removed in a future version. Please use "chart-%s" instead.',t,t)}}var w,C=document.createElement("div");C.className="chart-container",l.replaceWith(C),C.appendChild(l[0]),i&&window.G_vmlCanvasManager.initElement(l[0]),["data","labels","options","series","colours","legend","click","hover"].forEach(d),f("chartData","data"),f("chartLabels","labels"),f("chartOptions","options"),f("chartSeries","series"),f("chartColours","colours"),f("chartLegend","legend"),f("chartClick","click"),f("chartHover","hover"),a.$watch("data",function(t,e){if(!t||!t.length||Array.isArray(t[0])&&!t[0].length)return void b(w,a);var r=n||a.chartType;if(r)return w&&o(t,e)?y(w,t,a,l):void p(r)},!0),a.$watch("series",h,!0),a.$watch("labels",h,!0),a.$watch("options",h,!0),a.$watch("colours",h,!0),a.$watch("chartType",function(n,e){$(n)||t.equals(n,e)||p(n)}),a.$on("$destroy",function(){b(w,a)})}}}}n.defaults.global.responsive=!0,n.defaults.global.multiTooltipTemplate="<%if (datasetLabel){%><%=datasetLabel%>: <%}%><%= value %>",n.defaults.global.colours=["#97BBCD","#DCDCDC","#F7464A","#46BFBD","#FDB45C","#949FB1","#4D5360"];var i="object"==typeof window.G_vmlCanvasManager&&null!==window.G_vmlCanvasManager&&"function"==typeof window.G_vmlCanvasManager.initElement;return i&&(n.defaults.global.animation=!1),t.module("chart.js",[]).provider("ChartJs",e).factory("ChartJsFactory",["ChartJs","$timeout",r]).directive("chartBase",["ChartJsFactory",function(t){return new t}]).directive("chartLine",["ChartJsFactory",function(t){return new t("Line")}]).directive("chartBar",["ChartJsFactory",function(t){return new t("Bar")}]).directive("chartRadar",["ChartJsFactory",function(t){return new t("Radar")}]).directive("chartDoughnut",["ChartJsFactory",function(t){return new t("Doughnut")}]).directive("chartPie",["ChartJsFactory",function(t){return new t("Pie")}]).directive("chartPolarArea",["ChartJsFactory",function(t){return new t("PolarArea")}])}),!function(){function t(t){return t&&(t.ownerDocument||t.document||t).documentElement}function n(t){return t&&(t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView)}function e(t,n){return n>t?-1:t>n?1:t>=n?0:NaN}function r(t){return null===t?NaN:+t}function i(t){return!isNaN(t)}function o(t){return{left:function(n,e,r,i){for(arguments.length<3&&(r=0),arguments.length<4&&(i=n.length);i>r;){var o=r+i>>>1;t(n[o],e)<0?r=o+1:i=o}return r},right:function(n,e,r,i){for(arguments.length<3&&(r=0),arguments.length<4&&(i=n.length);i>r;){var o=r+i>>>1;t(n[o],e)>0?i=o:r=o+1}return r}}}function a(t){return t.length}function u(t){for(var n=1;t*n%1;)n*=10;return n}function s(t,n){for(var e in n)Object.defineProperty(t.prototype,e,{value:n[e],enumerable:!1})}function l(){this._=Object.create(null)}function c(t){return(t+="")===ba||t[0]===wa?wa+t:t}function f(t){return(t+="")[0]===wa?t.slice(1):t}function h(t){return c(t)in this._}function p(t){return(t=c(t))in this._&&delete this._[t]}function d(){var t=[];for(var n in this._)t.push(f(n));return t}function v(){var t=0;for(var n in this._)++t;return t}function g(){for(var t in this._)return!1;return!0}function m(){this._=Object.create(null)}function y(t){return t}function $(t,n,e){return function(){var r=e.apply(n,arguments);return r===n?t:r}}function x(t,n){if(n in t)return n;n=n.charAt(0).toUpperCase()+n.slice(1);for(var e=0,r=Ca.length;r>e;++e){var i=Ca[e]+n;if(i in t)return i}}function b(){}function w(){}function C(t){function n(){for(var n,r=e,i=-1,o=r.length;++i<o;)(n=r[i].on)&&n.apply(this,arguments);return t}var e=[],r=new l;return n.on=function(n,i){var o,a=r.get(n);return arguments.length<2?a&&a.on:(a&&(a.on=null,e=e.slice(0,o=e.indexOf(a)).concat(e.slice(o+1)),r.remove(n)),i&&e.push(r.set(n,{on:i})),t)},n}function S(){sa.event.preventDefault()}function _(){for(var t,n=sa.event;t=n.sourceEvent;)n=t;return n}function M(t){for(var n=new w,e=0,r=arguments.length;++e<r;)n[arguments[e]]=C(n);return n.of=function(e,r){return function(i){try{var o=i.sourceEvent=sa.event;i.target=t,sa.event=i,n[i.type].apply(e,r)}finally{sa.event=o}}},n}function k(t){return _a(t,Ea),t}function A(t){return"function"==typeof t?t:function(){return Ma(t,this)}}function E(t){return"function"==typeof t?t:function(){return ka(t,this)}}function P(t,n){function e(){this.removeAttribute(t)}function r(){this.removeAttributeNS(t.space,t.local)}function i(){this.setAttribute(t,n)}function o(){this.setAttributeNS(t.space,t.local,n)}function a(){var e=n.apply(this,arguments);null==e?this.removeAttribute(t):this.setAttribute(t,e)}function u(){var e=n.apply(this,arguments);null==e?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,e)}return t=sa.ns.qualify(t),null==n?t.local?r:e:"function"==typeof n?t.local?u:a:t.local?o:i}function O(t){return t.trim().replace(/\s+/g," ")}function T(t){return new RegExp("(?:^|\\s+)"+sa.requote(t)+"(?:\\s+|$)","g")}function L(t){return(t+"").trim().split(/^|\s+/)}function j(t,n){function e(){for(var e=-1;++e<i;)t[e](this,n)}function r(){for(var e=-1,r=n.apply(this,arguments);++e<i;)t[e](this,r)}t=L(t).map(N);var i=t.length;return"function"==typeof n?r:e}function N(t){var n=T(t);return function(e,r){if(i=e.classList)return r?i.add(t):i.remove(t);var i=e.getAttribute("class")||"";r?(n.lastIndex=0,n.test(i)||e.setAttribute("class",O(i+" "+t))):e.setAttribute("class",O(i.replace(n," ")))}}function R(t,n,e){function r(){this.style.removeProperty(t)}function i(){this.style.setProperty(t,n,e)}function o(){var r=n.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,e)}return null==n?r:"function"==typeof n?o:i}function D(t,n){function e(){delete this[t]}function r(){this[t]=n}function i(){var e=n.apply(this,arguments);null==e?delete this[t]:this[t]=e}return null==n?e:"function"==typeof n?i:r}function F(t){function n(){var n=this.ownerDocument,e=this.namespaceURI;return e===Pa&&n.documentElement.namespaceURI===Pa?n.createElement(t):n.createElementNS(e,t)}function e(){return this.ownerDocument.createElementNS(t.space,t.local)}return"function"==typeof t?t:(t=sa.ns.qualify(t)).local?e:n}function I(){var t=this.parentNode;t&&t.removeChild(this)}function z(t){return{__data__:t}}function q(t){return function(){return Aa(this,t)}}function V(t){return arguments.length||(t=e),function(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e}}function B(t,n){for(var e=0,r=t.length;r>e;e++)for(var i,o=t[e],a=0,u=o.length;u>a;a++)(i=o[a])&&n(i,a,e);return t}function W(t){return _a(t,Ta),t}function U(t){var n,e;return function(r,i,o){var a,u=t[o].update,s=u.length;for(o!=e&&(e=o,n=0),i>=n&&(n=i+1);!(a=u[n])&&++n<s;);return a}}function H(t,n,e){function r(){var n=this[a];n&&(this.removeEventListener(t,n,n.$),delete this[a])}function i(){var i=s(n,ca(arguments));r.call(this),this.addEventListener(t,this[a]=i,i.$=e),i._=n}function o(){var n,e=new RegExp("^__on([^.]+)"+sa.requote(t)+"$");for(var r in this)if(n=r.match(e)){var i=this[r];this.removeEventListener(n[1],i,i.$),delete this[r]}}var a="__on"+t,u=t.indexOf("."),s=Y;u>0&&(t=t.slice(0,u));var l=La.get(t);return l&&(t=l,s=G),u?n?i:r:n?b:o}function Y(t,n){return function(e){var r=sa.event;sa.event=e,n[0]=this.__data__;try{t.apply(this,n)}finally{sa.event=r}}}function G(t,n){var e=Y(t,n);return function(t){var n=this,r=t.relatedTarget;r&&(r===n||8&r.compareDocumentPosition(n))||e.call(n,t)}}function X(e){var r=".dragsuppress-"+ ++Na,i="click"+r,o=sa.select(n(e)).on("touchmove"+r,S).on("dragstart"+r,S).on("selectstart"+r,S);if(null==ja&&(ja="onselectstart"in e?!1:x(e.style,"userSelect")),ja){var a=t(e).style,u=a[ja];a[ja]="none"}return function(t){if(o.on(r,null),ja&&(a[ja]=u),t){var n=function(){o.on(i,null)};o.on(i,function(){S(),n()},!0),setTimeout(n,0)}}}function Z(t,e){e.changedTouches&&(e=e.changedTouches[0]);var r=t.ownerSVGElement||t;if(r.createSVGPoint){var i=r.createSVGPoint();if(0>Ra){
+var o=n(t);if(o.scrollX||o.scrollY){r=sa.select("body").append("svg").style({position:"absolute",top:0,left:0,margin:0,padding:0,border:"none"},"important");var a=r[0][0].getScreenCTM();Ra=!(a.f||a.e),r.remove()}}return Ra?(i.x=e.pageX,i.y=e.pageY):(i.x=e.clientX,i.y=e.clientY),i=i.matrixTransform(t.getScreenCTM().inverse()),[i.x,i.y]}var u=t.getBoundingClientRect();return[e.clientX-u.left-t.clientLeft,e.clientY-u.top-t.clientTop]}function J(){return sa.event.changedTouches[0].identifier}function K(t){return t>0?1:0>t?-1:0}function Q(t,n,e){return(n[0]-t[0])*(e[1]-t[1])-(n[1]-t[1])*(e[0]-t[0])}function tt(t){return t>1?0:-1>t?Ia:Math.acos(t)}function nt(t){return t>1?Va:-1>t?-Va:Math.asin(t)}function et(t){return((t=Math.exp(t))-1/t)/2}function rt(t){return((t=Math.exp(t))+1/t)/2}function it(t){return((t=Math.exp(2*t))-1)/(t+1)}function ot(t){return(t=Math.sin(t/2))*t}function at(){}function ut(t,n,e){return this instanceof ut?(this.h=+t,this.s=+n,void(this.l=+e)):arguments.length<2?t instanceof ut?new ut(t.h,t.s,t.l):bt(""+t,wt,ut):new ut(t,n,e)}function st(t,n,e){function r(t){return t>360?t-=360:0>t&&(t+=360),60>t?o+(a-o)*t/60:180>t?a:240>t?o+(a-o)*(240-t)/60:o}function i(t){return Math.round(255*r(t))}var o,a;return t=isNaN(t)?0:(t%=360)<0?t+360:t,n=isNaN(n)?0:0>n?0:n>1?1:n,e=0>e?0:e>1?1:e,a=.5>=e?e*(1+n):e+n-e*n,o=2*e-a,new mt(i(t+120),i(t),i(t-120))}function lt(t,n,e){return this instanceof lt?(this.h=+t,this.c=+n,void(this.l=+e)):arguments.length<2?t instanceof lt?new lt(t.h,t.c,t.l):t instanceof ft?pt(t.l,t.a,t.b):pt((t=Ct((t=sa.rgb(t)).r,t.g,t.b)).l,t.a,t.b):new lt(t,n,e)}function ct(t,n,e){return isNaN(t)&&(t=0),isNaN(n)&&(n=0),new ft(e,Math.cos(t*=Ba)*n,Math.sin(t)*n)}function ft(t,n,e){return this instanceof ft?(this.l=+t,this.a=+n,void(this.b=+e)):arguments.length<2?t instanceof ft?new ft(t.l,t.a,t.b):t instanceof lt?ct(t.h,t.c,t.l):Ct((t=mt(t)).r,t.g,t.b):new ft(t,n,e)}function ht(t,n,e){var r=(t+16)/116,i=r+n/500,o=r-e/200;return i=dt(i)*tu,r=dt(r)*nu,o=dt(o)*eu,new mt(gt(3.2404542*i-1.5371385*r-.4985314*o),gt(-.969266*i+1.8760108*r+.041556*o),gt(.0556434*i-.2040259*r+1.0572252*o))}function pt(t,n,e){return t>0?new lt(Math.atan2(e,n)*Wa,Math.sqrt(n*n+e*e),t):new lt(NaN,NaN,t)}function dt(t){return t>.206893034?t*t*t:(t-4/29)/7.787037}function vt(t){return t>.008856?Math.pow(t,1/3):7.787037*t+4/29}function gt(t){return Math.round(255*(.00304>=t?12.92*t:1.055*Math.pow(t,1/2.4)-.055))}function mt(t,n,e){return this instanceof mt?(this.r=~~t,this.g=~~n,void(this.b=~~e)):arguments.length<2?t instanceof mt?new mt(t.r,t.g,t.b):bt(""+t,mt,st):new mt(t,n,e)}function yt(t){return new mt(t>>16,t>>8&255,255&t)}function $t(t){return yt(t)+""}function xt(t){return 16>t?"0"+Math.max(0,t).toString(16):Math.min(255,t).toString(16)}function bt(t,n,e){var r,i,o,a=0,u=0,s=0;if(r=/([a-z]+)\((.*)\)/.exec(t=t.toLowerCase()))switch(i=r[2].split(","),r[1]){case"hsl":return e(parseFloat(i[0]),parseFloat(i[1])/100,parseFloat(i[2])/100);case"rgb":return n(_t(i[0]),_t(i[1]),_t(i[2]))}return(o=ou.get(t))?n(o.r,o.g,o.b):(null==t||"#"!==t.charAt(0)||isNaN(o=parseInt(t.slice(1),16))||(4===t.length?(a=(3840&o)>>4,a=a>>4|a,u=240&o,u=u>>4|u,s=15&o,s=s<<4|s):7===t.length&&(a=(16711680&o)>>16,u=(65280&o)>>8,s=255&o)),n(a,u,s))}function wt(t,n,e){var r,i,o=Math.min(t/=255,n/=255,e/=255),a=Math.max(t,n,e),u=a-o,s=(a+o)/2;return u?(i=.5>s?u/(a+o):u/(2-a-o),r=t==a?(n-e)/u+(e>n?6:0):n==a?(e-t)/u+2:(t-n)/u+4,r*=60):(r=NaN,i=s>0&&1>s?0:r),new ut(r,i,s)}function Ct(t,n,e){t=St(t),n=St(n),e=St(e);var r=vt((.4124564*t+.3575761*n+.1804375*e)/tu),i=vt((.2126729*t+.7151522*n+.072175*e)/nu),o=vt((.0193339*t+.119192*n+.9503041*e)/eu);return ft(116*i-16,500*(r-i),200*(i-o))}function St(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function _t(t){var n=parseFloat(t);return"%"===t.charAt(t.length-1)?Math.round(2.55*n):n}function Mt(t){return"function"==typeof t?t:function(){return t}}function kt(t){return function(n,e,r){return 2===arguments.length&&"function"==typeof e&&(r=e,e=null),At(n,e,t,r)}}function At(t,n,e,r){function i(){var t,n=s.status;if(!n&&Pt(s)||n>=200&&300>n||304===n){try{t=e.call(o,s)}catch(r){return void a.error.call(o,r)}a.load.call(o,t)}else a.error.call(o,s)}var o={},a=sa.dispatch("beforesend","progress","load","error"),u={},s=new XMLHttpRequest,l=null;return!this.XDomainRequest||"withCredentials"in s||!/^(http(s)?:)?\/\//.test(t)||(s=new XDomainRequest),"onload"in s?s.onload=s.onerror=i:s.onreadystatechange=function(){s.readyState>3&&i()},s.onprogress=function(t){var n=sa.event;sa.event=t;try{a.progress.call(o,s)}finally{sa.event=n}},o.header=function(t,n){return t=(t+"").toLowerCase(),arguments.length<2?u[t]:(null==n?delete u[t]:u[t]=n+"",o)},o.mimeType=function(t){return arguments.length?(n=null==t?null:t+"",o):n},o.responseType=function(t){return arguments.length?(l=t,o):l},o.response=function(t){return e=t,o},["get","post"].forEach(function(t){o[t]=function(){return o.send.apply(o,[t].concat(ca(arguments)))}}),o.send=function(e,r,i){if(2===arguments.length&&"function"==typeof r&&(i=r,r=null),s.open(e,t,!0),null==n||"accept"in u||(u.accept=n+",*/*"),s.setRequestHeader)for(var c in u)s.setRequestHeader(c,u[c]);return null!=n&&s.overrideMimeType&&s.overrideMimeType(n),null!=l&&(s.responseType=l),null!=i&&o.on("error",i).on("load",function(t){i(null,t)}),a.beforesend.call(o,s),s.send(null==r?null:r),o},o.abort=function(){return s.abort(),o},sa.rebind(o,a,"on"),null==r?o:o.get(Et(r))}function Et(t){return 1===t.length?function(n,e){t(null==n?e:null)}:t}function Pt(t){var n=t.responseType;return n&&"text"!==n?t.response:t.responseText}function Ot(t,n,e){var r=arguments.length;2>r&&(n=0),3>r&&(e=Date.now());var i=e+n,o={c:t,t:i,n:null};return uu?uu.n=o:au=o,uu=o,su||(lu=clearTimeout(lu),su=1,cu(Tt)),o}function Tt(){var t=Lt(),n=jt()-t;n>24?(isFinite(n)&&(clearTimeout(lu),lu=setTimeout(Tt,n)),su=0):(su=1,cu(Tt))}function Lt(){for(var t=Date.now(),n=au;n;)t>=n.t&&n.c(t-n.t)&&(n.c=null),n=n.n;return t}function jt(){for(var t,n=au,e=1/0;n;)n.c?(n.t<e&&(e=n.t),n=(t=n).n):n=t?t.n=n.n:au=n.n;return uu=t,e}function Nt(t,n){return n-(t?Math.ceil(Math.log(t)/Math.LN10):1)}function Rt(t,n){var e=Math.pow(10,3*xa(8-n));return{scale:n>8?function(t){return t/e}:function(t){return t*e},symbol:t}}function Dt(t){var n=t.decimal,e=t.thousands,r=t.grouping,i=t.currency,o=r&&e?function(t,n){for(var i=t.length,o=[],a=0,u=r[0],s=0;i>0&&u>0&&(s+u+1>n&&(u=Math.max(1,n-s)),o.push(t.substring(i-=u,i+u)),!((s+=u+1)>n));)u=r[a=(a+1)%r.length];return o.reverse().join(e)}:y;return function(t){var e=hu.exec(t),r=e[1]||" ",a=e[2]||">",u=e[3]||"-",s=e[4]||"",l=e[5],c=+e[6],f=e[7],h=e[8],p=e[9],d=1,v="",g="",m=!1,y=!0;switch(h&&(h=+h.substring(1)),(l||"0"===r&&"="===a)&&(l=r="0",a="="),p){case"n":f=!0,p="g";break;case"%":d=100,g="%",p="f";break;case"p":d=100,g="%",p="r";break;case"b":case"o":case"x":case"X":"#"===s&&(v="0"+p.toLowerCase());case"c":y=!1;case"d":m=!0,h=0;break;case"s":d=-1,p="r"}"$"===s&&(v=i[0],g=i[1]),"r"!=p||h||(p="g"),null!=h&&("g"==p?h=Math.max(1,Math.min(21,h)):"e"!=p&&"f"!=p||(h=Math.max(0,Math.min(20,h)))),p=pu.get(p)||Ft;var $=l&&f;return function(t){var e=g;if(m&&t%1)return"";var i=0>t||0===t&&0>1/t?(t=-t,"-"):"-"===u?"":u;if(0>d){var s=sa.formatPrefix(t,h);t=s.scale(t),e=s.symbol+g}else t*=d;t=p(t,h);var x,b,w=t.lastIndexOf(".");if(0>w){var C=y?t.lastIndexOf("e"):-1;0>C?(x=t,b=""):(x=t.substring(0,C),b=t.substring(C))}else x=t.substring(0,w),b=n+t.substring(w+1);!l&&f&&(x=o(x,1/0));var S=v.length+x.length+b.length+($?0:i.length),_=c>S?new Array(S=c-S+1).join(r):"";return $&&(x=o(_+x,_.length?c-b.length:1/0)),i+=v,t=x+b,("<"===a?i+t+_:">"===a?_+i+t:"^"===a?_.substring(0,S>>=1)+i+t+_.substring(S):i+($?t:_+t))+e}}}function Ft(t){return t+""}function It(){this._=new Date(arguments.length>1?Date.UTC.apply(this,arguments):arguments[0])}function zt(t,n,e){function r(n){var e=t(n),r=o(e,1);return r-n>n-e?e:r}function i(e){return n(e=t(new vu(e-1)),1),e}function o(t,e){return n(t=new vu(+t),e),t}function a(t,r,o){var a=i(t),u=[];if(o>1)for(;r>a;)e(a)%o||u.push(new Date(+a)),n(a,1);else for(;r>a;)u.push(new Date(+a)),n(a,1);return u}function u(t,n,e){try{vu=It;var r=new It;return r._=t,a(r,n,e)}finally{vu=Date}}t.floor=t,t.round=r,t.ceil=i,t.offset=o,t.range=a;var s=t.utc=qt(t);return s.floor=s,s.round=qt(r),s.ceil=qt(i),s.offset=qt(o),s.range=u,t}function qt(t){return function(n,e){try{vu=It;var r=new It;return r._=n,t(r,e)._}finally{vu=Date}}}function Vt(t){function n(t){function n(n){for(var e,i,o,a=[],u=-1,s=0;++u<r;)37===t.charCodeAt(u)&&(a.push(t.slice(s,u)),null!=(i=mu[e=t.charAt(++u)])&&(e=t.charAt(++u)),(o=A[e])&&(e=o(n,null==i?"e"===e?" ":"0":i)),a.push(e),s=u+1);return a.push(t.slice(s,u)),a.join("")}var r=t.length;return n.parse=function(n){var r={y:1900,m:0,d:1,H:0,M:0,S:0,L:0,Z:null},i=e(r,t,n,0);if(i!=n.length)return null;"p"in r&&(r.H=r.H%12+12*r.p);var o=null!=r.Z&&vu!==It,a=new(o?It:vu);return"j"in r?a.setFullYear(r.y,0,r.j):"W"in r||"U"in r?("w"in r||(r.w="W"in r?1:0),a.setFullYear(r.y,0,1),a.setFullYear(r.y,0,"W"in r?(r.w+6)%7+7*r.W-(a.getDay()+5)%7:r.w+7*r.U-(a.getDay()+6)%7)):a.setFullYear(r.y,r.m,r.d),a.setHours(r.H+(r.Z/100|0),r.M+r.Z%100,r.S,r.L),o?a._:a},n.toString=function(){return t},n}function e(t,n,e,r){for(var i,o,a,u=0,s=n.length,l=e.length;s>u;){if(r>=l)return-1;if(i=n.charCodeAt(u++),37===i){if(a=n.charAt(u++),o=E[a in mu?n.charAt(u++):a],!o||(r=o(t,e,r))<0)return-1}else if(i!=e.charCodeAt(r++))return-1}return r}function r(t,n,e){w.lastIndex=0;var r=w.exec(n.slice(e));return r?(t.w=C.get(r[0].toLowerCase()),e+r[0].length):-1}function i(t,n,e){x.lastIndex=0;var r=x.exec(n.slice(e));return r?(t.w=b.get(r[0].toLowerCase()),e+r[0].length):-1}function o(t,n,e){M.lastIndex=0;var r=M.exec(n.slice(e));return r?(t.m=k.get(r[0].toLowerCase()),e+r[0].length):-1}function a(t,n,e){S.lastIndex=0;var r=S.exec(n.slice(e));return r?(t.m=_.get(r[0].toLowerCase()),e+r[0].length):-1}function u(t,n,r){return e(t,A.c.toString(),n,r)}function s(t,n,r){return e(t,A.x.toString(),n,r)}function l(t,n,r){return e(t,A.X.toString(),n,r)}function c(t,n,e){var r=$.get(n.slice(e,e+=2).toLowerCase());return null==r?-1:(t.p=r,e)}var f=t.dateTime,h=t.date,p=t.time,d=t.periods,v=t.days,g=t.shortDays,m=t.months,y=t.shortMonths;n.utc=function(t){function e(t){try{vu=It;var n=new vu;return n._=t,r(n)}finally{vu=Date}}var r=n(t);return e.parse=function(t){try{vu=It;var n=r.parse(t);return n&&n._}finally{vu=Date}},e.toString=r.toString,e},n.multi=n.utc.multi=ln;var $=sa.map(),x=Wt(v),b=Ut(v),w=Wt(g),C=Ut(g),S=Wt(m),_=Ut(m),M=Wt(y),k=Ut(y);d.forEach(function(t,n){$.set(t.toLowerCase(),n)});var A={a:function(t){return g[t.getDay()]},A:function(t){return v[t.getDay()]},b:function(t){return y[t.getMonth()]},B:function(t){return m[t.getMonth()]},c:n(f),d:function(t,n){return Bt(t.getDate(),n,2)},e:function(t,n){return Bt(t.getDate(),n,2)},H:function(t,n){return Bt(t.getHours(),n,2)},I:function(t,n){return Bt(t.getHours()%12||12,n,2)},j:function(t,n){return Bt(1+du.dayOfYear(t),n,3)},L:function(t,n){return Bt(t.getMilliseconds(),n,3)},m:function(t,n){return Bt(t.getMonth()+1,n,2)},M:function(t,n){return Bt(t.getMinutes(),n,2)},p:function(t){return d[+(t.getHours()>=12)]},S:function(t,n){return Bt(t.getSeconds(),n,2)},U:function(t,n){return Bt(du.sundayOfYear(t),n,2)},w:function(t){return t.getDay()},W:function(t,n){return Bt(du.mondayOfYear(t),n,2)},x:n(h),X:n(p),y:function(t,n){return Bt(t.getFullYear()%100,n,2)},Y:function(t,n){return Bt(t.getFullYear()%1e4,n,4)},Z:un,"%":function(){return"%"}},E={a:r,A:i,b:o,B:a,c:u,d:tn,e:tn,H:en,I:en,j:nn,L:an,m:Qt,M:rn,p:c,S:on,U:Yt,w:Ht,W:Gt,x:s,X:l,y:Zt,Y:Xt,Z:Jt,"%":sn};return n}function Bt(t,n,e){var r=0>t?"-":"",i=(r?-t:t)+"",o=i.length;return r+(e>o?new Array(e-o+1).join(n)+i:i)}function Wt(t){return new RegExp("^(?:"+t.map(sa.requote).join("|")+")","i")}function Ut(t){for(var n=new l,e=-1,r=t.length;++e<r;)n.set(t[e].toLowerCase(),e);return n}function Ht(t,n,e){yu.lastIndex=0;var r=yu.exec(n.slice(e,e+1));return r?(t.w=+r[0],e+r[0].length):-1}function Yt(t,n,e){yu.lastIndex=0;var r=yu.exec(n.slice(e));return r?(t.U=+r[0],e+r[0].length):-1}function Gt(t,n,e){yu.lastIndex=0;var r=yu.exec(n.slice(e));return r?(t.W=+r[0],e+r[0].length):-1}function Xt(t,n,e){yu.lastIndex=0;var r=yu.exec(n.slice(e,e+4));return r?(t.y=+r[0],e+r[0].length):-1}function Zt(t,n,e){yu.lastIndex=0;var r=yu.exec(n.slice(e,e+2));return r?(t.y=Kt(+r[0]),e+r[0].length):-1}function Jt(t,n,e){return/^[+-]\d{4}$/.test(n=n.slice(e,e+5))?(t.Z=-n,e+5):-1}function Kt(t){return t+(t>68?1900:2e3)}function Qt(t,n,e){yu.lastIndex=0;var r=yu.exec(n.slice(e,e+2));return r?(t.m=r[0]-1,e+r[0].length):-1}function tn(t,n,e){yu.lastIndex=0;var r=yu.exec(n.slice(e,e+2));return r?(t.d=+r[0],e+r[0].length):-1}function nn(t,n,e){yu.lastIndex=0;var r=yu.exec(n.slice(e,e+3));return r?(t.j=+r[0],e+r[0].length):-1}function en(t,n,e){yu.lastIndex=0;var r=yu.exec(n.slice(e,e+2));return r?(t.H=+r[0],e+r[0].length):-1}function rn(t,n,e){yu.lastIndex=0;var r=yu.exec(n.slice(e,e+2));return r?(t.M=+r[0],e+r[0].length):-1}function on(t,n,e){yu.lastIndex=0;var r=yu.exec(n.slice(e,e+2));return r?(t.S=+r[0],e+r[0].length):-1}function an(t,n,e){yu.lastIndex=0;var r=yu.exec(n.slice(e,e+3));return r?(t.L=+r[0],e+r[0].length):-1}function un(t){var n=t.getTimezoneOffset(),e=n>0?"-":"+",r=xa(n)/60|0,i=xa(n)%60;return e+Bt(r,"0",2)+Bt(i,"0",2)}function sn(t,n,e){$u.lastIndex=0;var r=$u.exec(n.slice(e,e+1));return r?e+r[0].length:-1}function ln(t){for(var n=t.length,e=-1;++e<n;)t[e][0]=this(t[e][0]);return function(n){for(var e=0,r=t[e];!r[1](n);)r=t[++e];return r[0](n)}}function cn(){}function fn(t,n,e){var r=e.s=t+n,i=r-t,o=r-i;e.t=t-o+(n-i)}function hn(t,n){t&&Cu.hasOwnProperty(t.type)&&Cu[t.type](t,n)}function pn(t,n,e){var r,i=-1,o=t.length-e;for(n.lineStart();++i<o;)r=t[i],n.point(r[0],r[1],r[2]);n.lineEnd()}function dn(t,n){var e=-1,r=t.length;for(n.polygonStart();++e<r;)pn(t[e],n,1);n.polygonEnd()}function vn(){function t(t,n){t*=Ba,n=n*Ba/2+Ia/4;var e=t-r,a=e>=0?1:-1,u=a*e,s=Math.cos(n),l=Math.sin(n),c=o*l,f=i*s+c*Math.cos(u),h=c*a*Math.sin(u);_u.add(Math.atan2(h,f)),r=t,i=s,o=l}var n,e,r,i,o;Mu.point=function(a,u){Mu.point=t,r=(n=a)*Ba,i=Math.cos(u=(e=u)*Ba/2+Ia/4),o=Math.sin(u)},Mu.lineEnd=function(){t(n,e)}}function gn(t){var n=t[0],e=t[1],r=Math.cos(e);return[r*Math.cos(n),r*Math.sin(n),Math.sin(e)]}function mn(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]}function yn(t,n){return[t[1]*n[2]-t[2]*n[1],t[2]*n[0]-t[0]*n[2],t[0]*n[1]-t[1]*n[0]]}function $n(t,n){t[0]+=n[0],t[1]+=n[1],t[2]+=n[2]}function xn(t,n){return[t[0]*n,t[1]*n,t[2]*n]}function bn(t){var n=Math.sqrt(t[0]*t[0]+t[1]*t[1]+t[2]*t[2]);t[0]/=n,t[1]/=n,t[2]/=n}function wn(t){return[Math.atan2(t[1],t[0]),nt(t[2])]}function Cn(t,n){return xa(t[0]-n[0])<Da&&xa(t[1]-n[1])<Da}function Sn(t,n){t*=Ba;var e=Math.cos(n*=Ba);_n(e*Math.cos(t),e*Math.sin(t),Math.sin(n))}function _n(t,n,e){++ku,Eu+=(t-Eu)/ku,Pu+=(n-Pu)/ku,Ou+=(e-Ou)/ku}function Mn(){function t(t,i){t*=Ba;var o=Math.cos(i*=Ba),a=o*Math.cos(t),u=o*Math.sin(t),s=Math.sin(i),l=Math.atan2(Math.sqrt((l=e*s-r*u)*l+(l=r*a-n*s)*l+(l=n*u-e*a)*l),n*a+e*u+r*s);Au+=l,Tu+=l*(n+(n=a)),Lu+=l*(e+(e=u)),ju+=l*(r+(r=s)),_n(n,e,r)}var n,e,r;Fu.point=function(i,o){i*=Ba;var a=Math.cos(o*=Ba);n=a*Math.cos(i),e=a*Math.sin(i),r=Math.sin(o),Fu.point=t,_n(n,e,r)}}function kn(){Fu.point=Sn}function An(){function t(t,n){t*=Ba;var e=Math.cos(n*=Ba),a=e*Math.cos(t),u=e*Math.sin(t),s=Math.sin(n),l=i*s-o*u,c=o*a-r*s,f=r*u-i*a,h=Math.sqrt(l*l+c*c+f*f),p=r*a+i*u+o*s,d=h&&-tt(p)/h,v=Math.atan2(h,p);Nu+=d*l,Ru+=d*c,Du+=d*f,Au+=v,Tu+=v*(r+(r=a)),Lu+=v*(i+(i=u)),ju+=v*(o+(o=s)),_n(r,i,o)}var n,e,r,i,o;Fu.point=function(a,u){n=a,e=u,Fu.point=t,a*=Ba;var s=Math.cos(u*=Ba);r=s*Math.cos(a),i=s*Math.sin(a),o=Math.sin(u),_n(r,i,o)},Fu.lineEnd=function(){t(n,e),Fu.lineEnd=kn,Fu.point=Sn}}function En(t,n){function e(e,r){return e=t(e,r),n(e[0],e[1])}return t.invert&&n.invert&&(e.invert=function(e,r){return e=n.invert(e,r),e&&t.invert(e[0],e[1])}),e}function Pn(){return!0}function On(t,n,e,r,i){var o=[],a=[];if(t.forEach(function(t){if(!((n=t.length-1)<=0)){var n,e=t[0],r=t[n];if(Cn(e,r)){i.lineStart();for(var u=0;n>u;++u)i.point((e=t[u])[0],e[1]);return void i.lineEnd()}var s=new Ln(e,t,null,!0),l=new Ln(e,null,s,!1);s.o=l,o.push(s),a.push(l),s=new Ln(r,t,null,!1),l=new Ln(r,null,s,!0),s.o=l,o.push(s),a.push(l)}}),a.sort(n),Tn(o),Tn(a),o.length){for(var u=0,s=e,l=a.length;l>u;++u)a[u].e=s=!s;for(var c,f,h=o[0];;){for(var p=h,d=!0;p.v;)if((p=p.n)===h)return;c=p.z,i.lineStart();do{if(p.v=p.o.v=!0,p.e){if(d)for(var u=0,l=c.length;l>u;++u)i.point((f=c[u])[0],f[1]);else r(p.x,p.n.x,1,i);p=p.n}else{if(d){c=p.p.z;for(var u=c.length-1;u>=0;--u)i.point((f=c[u])[0],f[1])}else r(p.x,p.p.x,-1,i);p=p.p}p=p.o,c=p.z,d=!d}while(!p.v);i.lineEnd()}}}function Tn(t){if(n=t.length){for(var n,e,r=0,i=t[0];++r<n;)i.n=e=t[r],e.p=i,i=e;i.n=e=t[0],e.p=i}}function Ln(t,n,e,r){this.x=t,this.z=n,this.o=e,this.e=r,this.v=!1,this.n=this.p=null}function jn(t,n,e,r){return function(i,o){function a(n,e){var r=i(n,e);t(n=r[0],e=r[1])&&o.point(n,e)}function u(t,n){var e=i(t,n);g.point(e[0],e[1])}function s(){y.point=u,g.lineStart()}function l(){y.point=a,g.lineEnd()}function c(t,n){v.push([t,n]);var e=i(t,n);x.point(e[0],e[1])}function f(){x.lineStart(),v=[]}function h(){c(v[0][0],v[0][1]),x.lineEnd();var t,n=x.clean(),e=$.buffer(),r=e.length;if(v.pop(),d.push(v),v=null,r)if(1&n){t=e[0];var i,r=t.length-1,a=-1;if(r>0){for(b||(o.polygonStart(),b=!0),o.lineStart();++a<r;)o.point((i=t[a])[0],i[1]);o.lineEnd()}}else r>1&&2&n&&e.push(e.pop().concat(e.shift())),p.push(e.filter(Nn))}var p,d,v,g=n(o),m=i.invert(r[0],r[1]),y={point:a,lineStart:s,lineEnd:l,polygonStart:function(){y.point=c,y.lineStart=f,y.lineEnd=h,p=[],d=[]},polygonEnd:function(){y.point=a,y.lineStart=s,y.lineEnd=l,p=sa.merge(p);var t=qn(m,d);p.length?(b||(o.polygonStart(),b=!0),On(p,Dn,t,e,o)):t&&(b||(o.polygonStart(),b=!0),o.lineStart(),e(null,null,1,o),o.lineEnd()),b&&(o.polygonEnd(),b=!1),p=d=null},sphere:function(){o.polygonStart(),o.lineStart(),e(null,null,1,o),o.lineEnd(),o.polygonEnd()}},$=Rn(),x=n($),b=!1;return y}}function Nn(t){return t.length>1}function Rn(){var t,n=[];return{lineStart:function(){n.push(t=[])},point:function(n,e){t.push([n,e])},lineEnd:b,buffer:function(){var e=n;return n=[],t=null,e},rejoin:function(){n.length>1&&n.push(n.pop().concat(n.shift()))}}}function Dn(t,n){return((t=t.x)[0]<0?t[1]-Va-Da:Va-t[1])-((n=n.x)[0]<0?n[1]-Va-Da:Va-n[1])}function Fn(t){var n,e=NaN,r=NaN,i=NaN;return{lineStart:function(){t.lineStart(),n=1},point:function(o,a){var u=o>0?Ia:-Ia,s=xa(o-e);xa(s-Ia)<Da?(t.point(e,r=(r+a)/2>0?Va:-Va),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(u,r),t.point(o,r),n=0):i!==u&&s>=Ia&&(xa(e-i)<Da&&(e-=i*Da),xa(o-u)<Da&&(o-=u*Da),r=In(e,r,o,a),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(u,r),n=0),t.point(e=o,r=a),i=u},lineEnd:function(){t.lineEnd(),e=r=NaN},clean:function(){return 2-n}}}function In(t,n,e,r){var i,o,a=Math.sin(t-e);return xa(a)>Da?Math.atan((Math.sin(n)*(o=Math.cos(r))*Math.sin(e)-Math.sin(r)*(i=Math.cos(n))*Math.sin(t))/(i*o*a)):(n+r)/2}function zn(t,n,e,r){var i;if(null==t)i=e*Va,r.point(-Ia,i),r.point(0,i),r.point(Ia,i),r.point(Ia,0),r.point(Ia,-i),r.point(0,-i),r.point(-Ia,-i),r.point(-Ia,0),r.point(-Ia,i);else if(xa(t[0]-n[0])>Da){var o=t[0]<n[0]?Ia:-Ia;i=e*o/2,r.point(-o,i),r.point(0,i),r.point(o,i)}else r.point(n[0],n[1])}function qn(t,n){var e=t[0],r=t[1],i=[Math.sin(e),-Math.cos(e),0],o=0,a=0;_u.reset();for(var u=0,s=n.length;s>u;++u){var l=n[u],c=l.length;if(c)for(var f=l[0],h=f[0],p=f[1]/2+Ia/4,d=Math.sin(p),v=Math.cos(p),g=1;;){g===c&&(g=0),t=l[g];var m=t[0],y=t[1]/2+Ia/4,$=Math.sin(y),x=Math.cos(y),b=m-h,w=b>=0?1:-1,C=w*b,S=C>Ia,_=d*$;if(_u.add(Math.atan2(_*w*Math.sin(C),v*x+_*Math.cos(C))),o+=S?b+w*za:b,S^h>=e^m>=e){var M=yn(gn(f),gn(t));bn(M);var k=yn(i,M);bn(k);var A=(S^b>=0?-1:1)*nt(k[2]);(r>A||r===A&&(M[0]||M[1]))&&(a+=S^b>=0?1:-1)}if(!g++)break;h=m,d=$,v=x,f=t}}return(-Da>o||Da>o&&-Da>_u)^1&a}function Vn(t){function n(t,n){return Math.cos(t)*Math.cos(n)>o}function e(t){var e,o,s,l,c;return{lineStart:function(){l=s=!1,c=1},point:function(f,h){var p,d=[f,h],v=n(f,h),g=a?v?0:i(f,h):v?i(f+(0>f?Ia:-Ia),h):0;if(!e&&(l=s=v)&&t.lineStart(),v!==s&&(p=r(e,d),(Cn(e,p)||Cn(d,p))&&(d[0]+=Da,d[1]+=Da,v=n(d[0],d[1]))),v!==s)c=0,v?(t.lineStart(),p=r(d,e),t.point(p[0],p[1])):(p=r(e,d),t.point(p[0],p[1]),t.lineEnd()),e=p;else if(u&&e&&a^v){var m;g&o||!(m=r(d,e,!0))||(c=0,a?(t.lineStart(),t.point(m[0][0],m[0][1]),t.point(m[1][0],m[1][1]),t.lineEnd()):(t.point(m[1][0],m[1][1]),t.lineEnd(),t.lineStart(),t.point(m[0][0],m[0][1])))}!v||e&&Cn(e,d)||t.point(d[0],d[1]),e=d,s=v,o=g},lineEnd:function(){s&&t.lineEnd(),e=null},clean:function(){return c|(l&&s)<<1}}}function r(t,n,e){var r=gn(t),i=gn(n),a=[1,0,0],u=yn(r,i),s=mn(u,u),l=u[0],c=s-l*l;if(!c)return!e&&t;var f=o*s/c,h=-o*l/c,p=yn(a,u),d=xn(a,f),v=xn(u,h);$n(d,v);var g=p,m=mn(d,g),y=mn(g,g),$=m*m-y*(mn(d,d)-1);if(!(0>$)){var x=Math.sqrt($),b=xn(g,(-m-x)/y);if($n(b,d),b=wn(b),!e)return b;var w,C=t[0],S=n[0],_=t[1],M=n[1];C>S&&(w=C,C=S,S=w);var k=S-C,A=xa(k-Ia)<Da,E=A||Da>k;if(!A&&_>M&&(w=_,_=M,M=w),E?A?_+M>0^b[1]<(xa(b[0]-C)<Da?_:M):_<=b[1]&&b[1]<=M:k>Ia^(C<=b[0]&&b[0]<=S)){var P=xn(g,(-m+x)/y);return $n(P,d),[b,wn(P)]}}}function i(n,e){var r=a?t:Ia-t,i=0;return-r>n?i|=1:n>r&&(i|=2),-r>e?i|=4:e>r&&(i|=8),i}var o=Math.cos(t),a=o>0,u=xa(o)>Da,s=ve(t,6*Ba);return jn(n,e,s,a?[0,-t]:[-Ia,t-Ia])}function Bn(t,n,e,r){return function(i){var o,a=i.a,u=i.b,s=a.x,l=a.y,c=u.x,f=u.y,h=0,p=1,d=c-s,v=f-l;if(o=t-s,d||!(o>0)){if(o/=d,0>d){if(h>o)return;p>o&&(p=o)}else if(d>0){if(o>p)return;o>h&&(h=o)}if(o=e-s,d||!(0>o)){if(o/=d,0>d){if(o>p)return;o>h&&(h=o)}else if(d>0){if(h>o)return;p>o&&(p=o)}if(o=n-l,v||!(o>0)){if(o/=v,0>v){if(h>o)return;p>o&&(p=o)}else if(v>0){if(o>p)return;o>h&&(h=o)}if(o=r-l,v||!(0>o)){if(o/=v,0>v){if(o>p)return;o>h&&(h=o)}else if(v>0){if(h>o)return;p>o&&(p=o)}return h>0&&(i.a={x:s+h*d,y:l+h*v}),1>p&&(i.b={x:s+p*d,y:l+p*v}),i}}}}}}function Wn(t,n,e,r){function i(r,i){return xa(r[0]-t)<Da?i>0?0:3:xa(r[0]-e)<Da?i>0?2:1:xa(r[1]-n)<Da?i>0?1:0:i>0?3:2}function o(t,n){return a(t.x,n.x)}function a(t,n){var e=i(t,1),r=i(n,1);return e!==r?e-r:0===e?n[1]-t[1]:1===e?t[0]-n[0]:2===e?t[1]-n[1]:n[0]-t[0]}return function(u){function s(t){for(var n=0,e=g.length,r=t[1],i=0;e>i;++i)for(var o,a=1,u=g[i],s=u.length,l=u[0];s>a;++a)o=u[a],l[1]<=r?o[1]>r&&Q(l,o,t)>0&&++n:o[1]<=r&&Q(l,o,t)<0&&--n,l=o;return 0!==n}function l(o,u,s,l){var c=0,f=0;if(null==o||(c=i(o,s))!==(f=i(u,s))||a(o,u)<0^s>0){do l.point(0===c||3===c?t:e,c>1?r:n);while((c=(c+s+4)%4)!==f)}else l.point(u[0],u[1])}function c(i,o){return i>=t&&e>=i&&o>=n&&r>=o}function f(t,n){c(t,n)&&u.point(t,n)}function h(){E.point=d,g&&g.push(m=[]),S=!0,C=!1,b=w=NaN}function p(){v&&(d(y,$),x&&C&&k.rejoin(),v.push(k.buffer())),E.point=f,C&&u.lineEnd()}function d(t,n){t=Math.max(-zu,Math.min(zu,t)),n=Math.max(-zu,Math.min(zu,n));var e=c(t,n);if(g&&m.push([t,n]),S)y=t,$=n,x=e,S=!1,e&&(u.lineStart(),u.point(t,n));else if(e&&C)u.point(t,n);else{var r={a:{x:b,y:w},b:{x:t,y:n}};A(r)?(C||(u.lineStart(),u.point(r.a.x,r.a.y)),u.point(r.b.x,r.b.y),e||u.lineEnd(),_=!1):e&&(u.lineStart(),u.point(t,n),_=!1)}b=t,w=n,C=e}var v,g,m,y,$,x,b,w,C,S,_,M=u,k=Rn(),A=Bn(t,n,e,r),E={point:f,lineStart:h,lineEnd:p,polygonStart:function(){u=k,v=[],g=[],_=!0},polygonEnd:function(){u=M,v=sa.merge(v);var n=s([t,r]),e=_&&n,i=v.length;(e||i)&&(u.polygonStart(),e&&(u.lineStart(),l(null,null,1,u),u.lineEnd()),i&&On(v,o,n,l,u),u.polygonEnd()),v=g=m=null}};return E}}function Un(t){var n=0,e=Ia/3,r=ue(t),i=r(n,e);return i.parallels=function(t){return arguments.length?r(n=t[0]*Ia/180,e=t[1]*Ia/180):[n/Ia*180,e/Ia*180]},i}function Hn(t,n){function e(t,n){var e=Math.sqrt(o-2*i*Math.sin(n))/i;return[e*Math.sin(t*=i),a-e*Math.cos(t)]}var r=Math.sin(t),i=(r+Math.sin(n))/2,o=1+r*(2*i-r),a=Math.sqrt(o)/i;return e.invert=function(t,n){var e=a-n;return[Math.atan2(t,e)/i,nt((o-(t*t+e*e)*i*i)/(2*i))]},e}function Yn(){function t(t,n){Vu+=i*t-r*n,r=t,i=n}var n,e,r,i;Yu.point=function(o,a){Yu.point=t,n=r=o,e=i=a},Yu.lineEnd=function(){t(n,e)}}function Gn(t,n){Bu>t&&(Bu=t),t>Uu&&(Uu=t),Wu>n&&(Wu=n),n>Hu&&(Hu=n)}function Xn(){function t(t,n){a.push("M",t,",",n,o)}function n(t,n){a.push("M",t,",",n),u.point=e}function e(t,n){a.push("L",t,",",n)}function r(){u.point=t}function i(){a.push("Z")}var o=Zn(4.5),a=[],u={point:t,lineStart:function(){u.point=n},lineEnd:r,polygonStart:function(){u.lineEnd=i},polygonEnd:function(){u.lineEnd=r,u.point=t},pointRadius:function(t){return o=Zn(t),u},result:function(){if(a.length){var t=a.join("");return a=[],t}}};return u}function Zn(t){return"m0,"+t+"a"+t+","+t+" 0 1,1 0,"+-2*t+"a"+t+","+t+" 0 1,1 0,"+2*t+"z"}function Jn(t,n){Eu+=t,Pu+=n,++Ou}function Kn(){function t(t,r){var i=t-n,o=r-e,a=Math.sqrt(i*i+o*o);Tu+=a*(n+t)/2,Lu+=a*(e+r)/2,ju+=a,Jn(n=t,e=r)}var n,e;Xu.point=function(r,i){Xu.point=t,Jn(n=r,e=i)}}function Qn(){Xu.point=Jn}function te(){function t(t,n){var e=t-r,o=n-i,a=Math.sqrt(e*e+o*o);Tu+=a*(r+t)/2,Lu+=a*(i+n)/2,ju+=a,a=i*t-r*n,Nu+=a*(r+t),Ru+=a*(i+n),Du+=3*a,Jn(r=t,i=n)}var n,e,r,i;Xu.point=function(o,a){Xu.point=t,Jn(n=r=o,e=i=a)},Xu.lineEnd=function(){t(n,e)}}function ne(t){function n(n,e){t.moveTo(n+a,e),t.arc(n,e,a,0,za)}function e(n,e){t.moveTo(n,e),u.point=r}function r(n,e){t.lineTo(n,e)}function i(){u.point=n}function o(){t.closePath()}var a=4.5,u={point:n,lineStart:function(){u.point=e},lineEnd:i,polygonStart:function(){u.lineEnd=o},polygonEnd:function(){u.lineEnd=i,u.point=n},pointRadius:function(t){return a=t,u},result:b};return u}function ee(t){function n(t){return(u?r:e)(t)}function e(n){return oe(n,function(e,r){e=t(e,r),n.point(e[0],e[1])})}function r(n){function e(e,r){e=t(e,r),n.point(e[0],e[1])}function r(){$=NaN,S.point=o,n.lineStart()}function o(e,r){var o=gn([e,r]),a=t(e,r);i($,x,y,b,w,C,$=a[0],x=a[1],y=e,b=o[0],w=o[1],C=o[2],u,n),n.point($,x)}function a(){S.point=e,n.lineEnd()}function s(){r(),S.point=l,S.lineEnd=c}function l(t,n){o(f=t,h=n),p=$,d=x,v=b,g=w,m=C,S.point=o}function c(){i($,x,y,b,w,C,p,d,f,v,g,m,u,n),S.lineEnd=a,a()}var f,h,p,d,v,g,m,y,$,x,b,w,C,S={point:e,lineStart:r,lineEnd:a,polygonStart:function(){n.polygonStart(),S.lineStart=s},polygonEnd:function(){n.polygonEnd(),S.lineStart=r}};return S}function i(n,e,r,u,s,l,c,f,h,p,d,v,g,m){var y=c-n,$=f-e,x=y*y+$*$;if(x>4*o&&g--){var b=u+p,w=s+d,C=l+v,S=Math.sqrt(b*b+w*w+C*C),_=Math.asin(C/=S),M=xa(xa(C)-1)<Da||xa(r-h)<Da?(r+h)/2:Math.atan2(w,b),k=t(M,_),A=k[0],E=k[1],P=A-n,O=E-e,T=$*P-y*O;(T*T/x>o||xa((y*P+$*O)/x-.5)>.3||a>u*p+s*d+l*v)&&(i(n,e,r,u,s,l,A,E,M,b/=S,w/=S,C,g,m),m.point(A,E),i(A,E,M,b,w,C,c,f,h,p,d,v,g,m))}}var o=.5,a=Math.cos(30*Ba),u=16;return n.precision=function(t){return arguments.length?(u=(o=t*t)>0&&16,n):Math.sqrt(o)},n}function re(t){var n=ee(function(n,e){return t([n*Wa,e*Wa])});return function(t){return se(n(t))}}function ie(t){this.stream=t}function oe(t,n){return{point:n,sphere:function(){t.sphere()},lineStart:function(){t.lineStart()},lineEnd:function(){t.lineEnd()},polygonStart:function(){t.polygonStart()},polygonEnd:function(){t.polygonEnd()}}}function ae(t){return ue(function(){return t})()}function ue(t){function n(t){return t=u(t[0]*Ba,t[1]*Ba),[t[0]*h+s,l-t[1]*h]}function e(t){return t=u.invert((t[0]-s)/h,(l-t[1])/h),t&&[t[0]*Wa,t[1]*Wa]}function r(){u=En(a=fe(m,$,x),o);var t=o(v,g);return s=p-t[0]*h,l=d+t[1]*h,i()}function i(){return c&&(c.valid=!1,c=null),n}var o,a,u,s,l,c,f=ee(function(t,n){return t=o(t,n),[t[0]*h+s,l-t[1]*h]}),h=150,p=480,d=250,v=0,g=0,m=0,$=0,x=0,b=Iu,w=y,C=null,S=null;return n.stream=function(t){return c&&(c.valid=!1),c=se(b(a,f(w(t)))),c.valid=!0,c},n.clipAngle=function(t){return arguments.length?(b=null==t?(C=t,Iu):Vn((C=+t)*Ba),i()):C},n.clipExtent=function(t){return arguments.length?(S=t,w=t?Wn(t[0][0],t[0][1],t[1][0],t[1][1]):y,i()):S},n.scale=function(t){return arguments.length?(h=+t,r()):h},n.translate=function(t){return arguments.length?(p=+t[0],d=+t[1],r()):[p,d]},n.center=function(t){return arguments.length?(v=t[0]%360*Ba,g=t[1]%360*Ba,r()):[v*Wa,g*Wa]},n.rotate=function(t){return arguments.length?(m=t[0]%360*Ba,$=t[1]%360*Ba,x=t.length>2?t[2]%360*Ba:0,r()):[m*Wa,$*Wa,x*Wa]},sa.rebind(n,f,"precision"),function(){return o=t.apply(this,arguments),n.invert=o.invert&&e,r()}}function se(t){return oe(t,function(n,e){t.point(n*Ba,e*Ba)})}function le(t,n){return[t,n]}function ce(t,n){return[t>Ia?t-za:-Ia>t?t+za:t,n]}function fe(t,n,e){return t?n||e?En(pe(t),de(n,e)):pe(t):n||e?de(n,e):ce}function he(t){return function(n,e){return n+=t,[n>Ia?n-za:-Ia>n?n+za:n,e]}}function pe(t){var n=he(t);return n.invert=he(-t),n}function de(t,n){function e(t,n){var e=Math.cos(n),u=Math.cos(t)*e,s=Math.sin(t)*e,l=Math.sin(n),c=l*r+u*i;return[Math.atan2(s*o-c*a,u*r-l*i),nt(c*o+s*a)]}var r=Math.cos(t),i=Math.sin(t),o=Math.cos(n),a=Math.sin(n);return e.invert=function(t,n){var e=Math.cos(n),u=Math.cos(t)*e,s=Math.sin(t)*e,l=Math.sin(n),c=l*o-s*a;return[Math.atan2(s*o+l*a,u*r+c*i),nt(c*r-u*i)]},e}function ve(t,n){var e=Math.cos(t),r=Math.sin(t);return function(i,o,a,u){var s=a*n;null!=i?(i=ge(e,i),o=ge(e,o),(a>0?o>i:i>o)&&(i+=a*za)):(i=t+a*za,o=t-.5*s);for(var l,c=i;a>0?c>o:o>c;c-=s)u.point((l=wn([e,-r*Math.cos(c),-r*Math.sin(c)]))[0],l[1])}}function ge(t,n){var e=gn(n);e[0]-=t,bn(e);var r=tt(-e[1]);return((-e[2]<0?-r:r)+2*Math.PI-Da)%(2*Math.PI)}function me(t,n,e){var r=sa.range(t,n-Da,e).concat(n);return function(t){return r.map(function(n){return[t,n]})}}function ye(t,n,e){var r=sa.range(t,n-Da,e).concat(n);return function(t){return r.map(function(n){return[n,t]})}}function $e(t){return t.source}function xe(t){return t.target}function be(t,n,e,r){var i=Math.cos(n),o=Math.sin(n),a=Math.cos(r),u=Math.sin(r),s=i*Math.cos(t),l=i*Math.sin(t),c=a*Math.cos(e),f=a*Math.sin(e),h=2*Math.asin(Math.sqrt(ot(r-n)+i*a*ot(e-t))),p=1/Math.sin(h),d=h?function(t){var n=Math.sin(t*=h)*p,e=Math.sin(h-t)*p,r=e*s+n*c,i=e*l+n*f,a=e*o+n*u;return[Math.atan2(i,r)*Wa,Math.atan2(a,Math.sqrt(r*r+i*i))*Wa]}:function(){return[t*Wa,n*Wa]};return d.distance=h,d}function we(){function t(t,i){var o=Math.sin(i*=Ba),a=Math.cos(i),u=xa((t*=Ba)-n),s=Math.cos(u);Zu+=Math.atan2(Math.sqrt((u=a*Math.sin(u))*u+(u=r*o-e*a*s)*u),e*o+r*a*s),n=t,e=o,r=a}var n,e,r;Ju.point=function(i,o){n=i*Ba,e=Math.sin(o*=Ba),r=Math.cos(o),Ju.point=t},Ju.lineEnd=function(){Ju.point=Ju.lineEnd=b}}function Ce(t,n){function e(n,e){var r=Math.cos(n),i=Math.cos(e),o=t(r*i);return[o*i*Math.sin(n),o*Math.sin(e)]}return e.invert=function(t,e){var r=Math.sqrt(t*t+e*e),i=n(r),o=Math.sin(i),a=Math.cos(i);return[Math.atan2(t*o,r*a),Math.asin(r&&e*o/r)]},e}function Se(t,n){function e(t,n){a>0?-Va+Da>n&&(n=-Va+Da):n>Va-Da&&(n=Va-Da);var e=a/Math.pow(i(n),o);return[e*Math.sin(o*t),a-e*Math.cos(o*t)]}var r=Math.cos(t),i=function(t){return Math.tan(Ia/4+t/2)},o=t===n?Math.sin(t):Math.log(r/Math.cos(n))/Math.log(i(n)/i(t)),a=r*Math.pow(i(t),o)/o;return o?(e.invert=function(t,n){var e=a-n,r=K(o)*Math.sqrt(t*t+e*e);return[Math.atan2(t,e)/o,2*Math.atan(Math.pow(a/r,1/o))-Va]},e):Me}function _e(t,n){function e(t,n){var e=o-n;return[e*Math.sin(i*t),o-e*Math.cos(i*t)]}var r=Math.cos(t),i=t===n?Math.sin(t):(r-Math.cos(n))/(n-t),o=r/i+t;return xa(i)<Da?le:(e.invert=function(t,n){var e=o-n;return[Math.atan2(t,e)/i,o-K(i)*Math.sqrt(t*t+e*e)]},e)}function Me(t,n){return[t,Math.log(Math.tan(Ia/4+n/2))]}function ke(t){var n,e=ae(t),r=e.scale,i=e.translate,o=e.clipExtent;return e.scale=function(){var t=r.apply(e,arguments);return t===e?n?e.clipExtent(null):e:t},e.translate=function(){var t=i.apply(e,arguments);return t===e?n?e.clipExtent(null):e:t},e.clipExtent=function(t){var a=o.apply(e,arguments);if(a===e){if(n=null==t){var u=Ia*r(),s=i();o([[s[0]-u,s[1]-u],[s[0]+u,s[1]+u]])}}else n&&(a=null);return a},e.clipExtent(null)}function Ae(t,n){return[Math.log(Math.tan(Ia/4+n/2)),-t]}function Ee(t){return t[0];
+}function Pe(t){return t[1]}function Oe(t){for(var n=t.length,e=[0,1],r=2,i=2;n>i;i++){for(;r>1&&Q(t[e[r-2]],t[e[r-1]],t[i])<=0;)--r;e[r++]=i}return e.slice(0,r)}function Te(t,n){return t[0]-n[0]||t[1]-n[1]}function Le(t,n,e){return(e[0]-n[0])*(t[1]-n[1])<(e[1]-n[1])*(t[0]-n[0])}function je(t,n,e,r){var i=t[0],o=e[0],a=n[0]-i,u=r[0]-o,s=t[1],l=e[1],c=n[1]-s,f=r[1]-l,h=(u*(s-l)-f*(i-o))/(f*a-u*c);return[i+h*a,s+h*c]}function Ne(t){var n=t[0],e=t[t.length-1];return!(n[0]-e[0]||n[1]-e[1])}function Re(){rr(this),this.edge=this.site=this.circle=null}function De(t){var n=ls.pop()||new Re;return n.site=t,n}function Fe(t){Ge(t),as.remove(t),ls.push(t),rr(t)}function Ie(t){var n=t.circle,e=n.x,r=n.cy,i={x:e,y:r},o=t.P,a=t.N,u=[t];Fe(t);for(var s=o;s.circle&&xa(e-s.circle.x)<Da&&xa(r-s.circle.cy)<Da;)o=s.P,u.unshift(s),Fe(s),s=o;u.unshift(s),Ge(s);for(var l=a;l.circle&&xa(e-l.circle.x)<Da&&xa(r-l.circle.cy)<Da;)a=l.N,u.push(l),Fe(l),l=a;u.push(l),Ge(l);var c,f=u.length;for(c=1;f>c;++c)l=u[c],s=u[c-1],tr(l.edge,s.site,l.site,i);s=u[0],l=u[f-1],l.edge=Ke(s.site,l.site,null,i),Ye(s),Ye(l)}function ze(t){for(var n,e,r,i,o=t.x,a=t.y,u=as._;u;)if(r=qe(u,a)-o,r>Da)u=u.L;else{if(i=o-Ve(u,a),!(i>Da)){r>-Da?(n=u.P,e=u):i>-Da?(n=u,e=u.N):n=e=u;break}if(!u.R){n=u;break}u=u.R}var s=De(t);if(as.insert(n,s),n||e){if(n===e)return Ge(n),e=De(n.site),as.insert(s,e),s.edge=e.edge=Ke(n.site,s.site),Ye(n),void Ye(e);if(!e)return void(s.edge=Ke(n.site,s.site));Ge(n),Ge(e);var l=n.site,c=l.x,f=l.y,h=t.x-c,p=t.y-f,d=e.site,v=d.x-c,g=d.y-f,m=2*(h*g-p*v),y=h*h+p*p,$=v*v+g*g,x={x:(g*y-p*$)/m+c,y:(h*$-v*y)/m+f};tr(e.edge,l,d,x),s.edge=Ke(l,t,null,x),e.edge=Ke(t,d,null,x),Ye(n),Ye(e)}}function qe(t,n){var e=t.site,r=e.x,i=e.y,o=i-n;if(!o)return r;var a=t.P;if(!a)return-(1/0);e=a.site;var u=e.x,s=e.y,l=s-n;if(!l)return u;var c=u-r,f=1/o-1/l,h=c/l;return f?(-h+Math.sqrt(h*h-2*f*(c*c/(-2*l)-s+l/2+i-o/2)))/f+r:(r+u)/2}function Ve(t,n){var e=t.N;if(e)return qe(e,n);var r=t.site;return r.y===n?r.x:1/0}function Be(t){this.site=t,this.edges=[]}function We(t){for(var n,e,r,i,o,a,u,s,l,c,f=t[0][0],h=t[1][0],p=t[0][1],d=t[1][1],v=os,g=v.length;g--;)if(o=v[g],o&&o.prepare())for(u=o.edges,s=u.length,a=0;s>a;)c=u[a].end(),r=c.x,i=c.y,l=u[++a%s].start(),n=l.x,e=l.y,(xa(r-n)>Da||xa(i-e)>Da)&&(u.splice(a,0,new nr(Qe(o.site,c,xa(r-f)<Da&&d-i>Da?{x:f,y:xa(n-f)<Da?e:d}:xa(i-d)<Da&&h-r>Da?{x:xa(e-d)<Da?n:h,y:d}:xa(r-h)<Da&&i-p>Da?{x:h,y:xa(n-h)<Da?e:p}:xa(i-p)<Da&&r-f>Da?{x:xa(e-p)<Da?n:f,y:p}:null),o.site,null)),++s)}function Ue(t,n){return n.angle-t.angle}function He(){rr(this),this.x=this.y=this.arc=this.site=this.cy=null}function Ye(t){var n=t.P,e=t.N;if(n&&e){var r=n.site,i=t.site,o=e.site;if(r!==o){var a=i.x,u=i.y,s=r.x-a,l=r.y-u,c=o.x-a,f=o.y-u,h=2*(s*f-l*c);if(!(h>=-Fa)){var p=s*s+l*l,d=c*c+f*f,v=(f*p-l*d)/h,g=(s*d-c*p)/h,f=g+u,m=cs.pop()||new He;m.arc=t,m.site=i,m.x=v+a,m.y=f+Math.sqrt(v*v+g*g),m.cy=f,t.circle=m;for(var y=null,$=ss._;$;)if(m.y<$.y||m.y===$.y&&m.x<=$.x){if(!$.L){y=$.P;break}$=$.L}else{if(!$.R){y=$;break}$=$.R}ss.insert(y,m),y||(us=m)}}}}function Ge(t){var n=t.circle;n&&(n.P||(us=n.N),ss.remove(n),cs.push(n),rr(n),t.circle=null)}function Xe(t){for(var n,e=is,r=Bn(t[0][0],t[0][1],t[1][0],t[1][1]),i=e.length;i--;)n=e[i],(!Ze(n,t)||!r(n)||xa(n.a.x-n.b.x)<Da&&xa(n.a.y-n.b.y)<Da)&&(n.a=n.b=null,e.splice(i,1))}function Ze(t,n){var e=t.b;if(e)return!0;var r,i,o=t.a,a=n[0][0],u=n[1][0],s=n[0][1],l=n[1][1],c=t.l,f=t.r,h=c.x,p=c.y,d=f.x,v=f.y,g=(h+d)/2,m=(p+v)/2;if(v===p){if(a>g||g>=u)return;if(h>d){if(o){if(o.y>=l)return}else o={x:g,y:s};e={x:g,y:l}}else{if(o){if(o.y<s)return}else o={x:g,y:l};e={x:g,y:s}}}else if(r=(h-d)/(v-p),i=m-r*g,-1>r||r>1)if(h>d){if(o){if(o.y>=l)return}else o={x:(s-i)/r,y:s};e={x:(l-i)/r,y:l}}else{if(o){if(o.y<s)return}else o={x:(l-i)/r,y:l};e={x:(s-i)/r,y:s}}else if(v>p){if(o){if(o.x>=u)return}else o={x:a,y:r*a+i};e={x:u,y:r*u+i}}else{if(o){if(o.x<a)return}else o={x:u,y:r*u+i};e={x:a,y:r*a+i}}return t.a=o,t.b=e,!0}function Je(t,n){this.l=t,this.r=n,this.a=this.b=null}function Ke(t,n,e,r){var i=new Je(t,n);return is.push(i),e&&tr(i,t,n,e),r&&tr(i,n,t,r),os[t.i].edges.push(new nr(i,t,n)),os[n.i].edges.push(new nr(i,n,t)),i}function Qe(t,n,e){var r=new Je(t,null);return r.a=n,r.b=e,is.push(r),r}function tr(t,n,e,r){t.a||t.b?t.l===e?t.b=r:t.a=r:(t.a=r,t.l=n,t.r=e)}function nr(t,n,e){var r=t.a,i=t.b;this.edge=t,this.site=n,this.angle=e?Math.atan2(e.y-n.y,e.x-n.x):t.l===n?Math.atan2(i.x-r.x,r.y-i.y):Math.atan2(r.x-i.x,i.y-r.y)}function er(){this._=null}function rr(t){t.U=t.C=t.L=t.R=t.P=t.N=null}function ir(t,n){var e=n,r=n.R,i=e.U;i?i.L===e?i.L=r:i.R=r:t._=r,r.U=i,e.U=r,e.R=r.L,e.R&&(e.R.U=e),r.L=e}function or(t,n){var e=n,r=n.L,i=e.U;i?i.L===e?i.L=r:i.R=r:t._=r,r.U=i,e.U=r,e.L=r.R,e.L&&(e.L.U=e),r.R=e}function ar(t){for(;t.L;)t=t.L;return t}function ur(t,n){var e,r,i,o=t.sort(sr).pop();for(is=[],os=new Array(t.length),as=new er,ss=new er;;)if(i=us,o&&(!i||o.y<i.y||o.y===i.y&&o.x<i.x))o.x===e&&o.y===r||(os[o.i]=new Be(o),ze(o),e=o.x,r=o.y),o=t.pop();else{if(!i)break;Ie(i.arc)}n&&(Xe(n),We(n));var a={cells:os,edges:is};return as=ss=is=os=null,a}function sr(t,n){return n.y-t.y||n.x-t.x}function lr(t,n,e){return(t.x-e.x)*(n.y-t.y)-(t.x-n.x)*(e.y-t.y)}function cr(t){return t.x}function fr(t){return t.y}function hr(){return{leaf:!0,nodes:[],point:null,x:null,y:null}}function pr(t,n,e,r,i,o){if(!t(n,e,r,i,o)){var a=.5*(e+i),u=.5*(r+o),s=n.nodes;s[0]&&pr(t,s[0],e,r,a,u),s[1]&&pr(t,s[1],a,r,i,u),s[2]&&pr(t,s[2],e,u,a,o),s[3]&&pr(t,s[3],a,u,i,o)}}function dr(t,n,e,r,i,o,a){var u,s=1/0;return function l(t,c,f,h,p){if(!(c>o||f>a||r>h||i>p)){if(d=t.point){var d,v=n-t.x,g=e-t.y,m=v*v+g*g;if(s>m){var y=Math.sqrt(s=m);r=n-y,i=e-y,o=n+y,a=e+y,u=d}}for(var $=t.nodes,x=.5*(c+h),b=.5*(f+p),w=n>=x,C=e>=b,S=C<<1|w,_=S+4;_>S;++S)if(t=$[3&S])switch(3&S){case 0:l(t,c,f,x,b);break;case 1:l(t,x,f,h,b);break;case 2:l(t,c,b,x,p);break;case 3:l(t,x,b,h,p)}}}(t,r,i,o,a),u}function vr(t,n){t=sa.rgb(t),n=sa.rgb(n);var e=t.r,r=t.g,i=t.b,o=n.r-e,a=n.g-r,u=n.b-i;return function(t){return"#"+xt(Math.round(e+o*t))+xt(Math.round(r+a*t))+xt(Math.round(i+u*t))}}function gr(t,n){var e,r={},i={};for(e in t)e in n?r[e]=$r(t[e],n[e]):i[e]=t[e];for(e in n)e in t||(i[e]=n[e]);return function(t){for(e in r)i[e]=r[e](t);return i}}function mr(t,n){return t=+t,n=+n,function(e){return t*(1-e)+n*e}}function yr(t,n){var e,r,i,o=hs.lastIndex=ps.lastIndex=0,a=-1,u=[],s=[];for(t+="",n+="";(e=hs.exec(t))&&(r=ps.exec(n));)(i=r.index)>o&&(i=n.slice(o,i),u[a]?u[a]+=i:u[++a]=i),(e=e[0])===(r=r[0])?u[a]?u[a]+=r:u[++a]=r:(u[++a]=null,s.push({i:a,x:mr(e,r)})),o=ps.lastIndex;return o<n.length&&(i=n.slice(o),u[a]?u[a]+=i:u[++a]=i),u.length<2?s[0]?(n=s[0].x,function(t){return n(t)+""}):function(){return n}:(n=s.length,function(t){for(var e,r=0;n>r;++r)u[(e=s[r]).i]=e.x(t);return u.join("")})}function $r(t,n){for(var e,r=sa.interpolators.length;--r>=0&&!(e=sa.interpolators[r](t,n)););return e}function xr(t,n){var e,r=[],i=[],o=t.length,a=n.length,u=Math.min(t.length,n.length);for(e=0;u>e;++e)r.push($r(t[e],n[e]));for(;o>e;++e)i[e]=t[e];for(;a>e;++e)i[e]=n[e];return function(t){for(e=0;u>e;++e)i[e]=r[e](t);return i}}function br(t){return function(n){return 0>=n?0:n>=1?1:t(n)}}function wr(t){return function(n){return 1-t(1-n)}}function Cr(t){return function(n){return.5*(.5>n?t(2*n):2-t(2-2*n))}}function Sr(t){return t*t}function _r(t){return t*t*t}function Mr(t){if(0>=t)return 0;if(t>=1)return 1;var n=t*t,e=n*t;return 4*(.5>t?e:3*(t-n)+e-.75)}function kr(t){return function(n){return Math.pow(n,t)}}function Ar(t){return 1-Math.cos(t*Va)}function Er(t){return Math.pow(2,10*(t-1))}function Pr(t){return 1-Math.sqrt(1-t*t)}function Or(t,n){var e;return arguments.length<2&&(n=.45),arguments.length?e=n/za*Math.asin(1/t):(t=1,e=n/4),function(r){return 1+t*Math.pow(2,-10*r)*Math.sin((r-e)*za/n)}}function Tr(t){return t||(t=1.70158),function(n){return n*n*((t+1)*n-t)}}function Lr(t){return 1/2.75>t?7.5625*t*t:2/2.75>t?7.5625*(t-=1.5/2.75)*t+.75:2.5/2.75>t?7.5625*(t-=2.25/2.75)*t+.9375:7.5625*(t-=2.625/2.75)*t+.984375}function jr(t,n){t=sa.hcl(t),n=sa.hcl(n);var e=t.h,r=t.c,i=t.l,o=n.h-e,a=n.c-r,u=n.l-i;return isNaN(a)&&(a=0,r=isNaN(r)?n.c:r),isNaN(o)?(o=0,e=isNaN(e)?n.h:e):o>180?o-=360:-180>o&&(o+=360),function(t){return ct(e+o*t,r+a*t,i+u*t)+""}}function Nr(t,n){t=sa.hsl(t),n=sa.hsl(n);var e=t.h,r=t.s,i=t.l,o=n.h-e,a=n.s-r,u=n.l-i;return isNaN(a)&&(a=0,r=isNaN(r)?n.s:r),isNaN(o)?(o=0,e=isNaN(e)?n.h:e):o>180?o-=360:-180>o&&(o+=360),function(t){return st(e+o*t,r+a*t,i+u*t)+""}}function Rr(t,n){t=sa.lab(t),n=sa.lab(n);var e=t.l,r=t.a,i=t.b,o=n.l-e,a=n.a-r,u=n.b-i;return function(t){return ht(e+o*t,r+a*t,i+u*t)+""}}function Dr(t,n){return n-=t,function(e){return Math.round(t+n*e)}}function Fr(t){var n=[t.a,t.b],e=[t.c,t.d],r=zr(n),i=Ir(n,e),o=zr(qr(e,n,-i))||0;n[0]*e[1]<e[0]*n[1]&&(n[0]*=-1,n[1]*=-1,r*=-1,i*=-1),this.rotate=(r?Math.atan2(n[1],n[0]):Math.atan2(-e[0],e[1]))*Wa,this.translate=[t.e,t.f],this.scale=[r,o],this.skew=o?Math.atan2(i,o)*Wa:0}function Ir(t,n){return t[0]*n[0]+t[1]*n[1]}function zr(t){var n=Math.sqrt(Ir(t,t));return n&&(t[0]/=n,t[1]/=n),n}function qr(t,n,e){return t[0]+=e*n[0],t[1]+=e*n[1],t}function Vr(t){return t.length?t.pop()+",":""}function Br(t,n,e,r){if(t[0]!==n[0]||t[1]!==n[1]){var i=e.push("translate(",null,",",null,")");r.push({i:i-4,x:mr(t[0],n[0])},{i:i-2,x:mr(t[1],n[1])})}else(n[0]||n[1])&&e.push("translate("+n+")")}function Wr(t,n,e,r){t!==n?(t-n>180?n+=360:n-t>180&&(t+=360),r.push({i:e.push(Vr(e)+"rotate(",null,")")-2,x:mr(t,n)})):n&&e.push(Vr(e)+"rotate("+n+")")}function Ur(t,n,e,r){t!==n?r.push({i:e.push(Vr(e)+"skewX(",null,")")-2,x:mr(t,n)}):n&&e.push(Vr(e)+"skewX("+n+")")}function Hr(t,n,e,r){if(t[0]!==n[0]||t[1]!==n[1]){var i=e.push(Vr(e)+"scale(",null,",",null,")");r.push({i:i-4,x:mr(t[0],n[0])},{i:i-2,x:mr(t[1],n[1])})}else 1===n[0]&&1===n[1]||e.push(Vr(e)+"scale("+n+")")}function Yr(t,n){var e=[],r=[];return t=sa.transform(t),n=sa.transform(n),Br(t.translate,n.translate,e,r),Wr(t.rotate,n.rotate,e,r),Ur(t.skew,n.skew,e,r),Hr(t.scale,n.scale,e,r),t=n=null,function(t){for(var n,i=-1,o=r.length;++i<o;)e[(n=r[i]).i]=n.x(t);return e.join("")}}function Gr(t,n){return n=(n-=t=+t)||1/n,function(e){return(e-t)/n}}function Xr(t,n){return n=(n-=t=+t)||1/n,function(e){return Math.max(0,Math.min(1,(e-t)/n))}}function Zr(t){for(var n=t.source,e=t.target,r=Kr(n,e),i=[n];n!==r;)n=n.parent,i.push(n);for(var o=i.length;e!==r;)i.splice(o,0,e),e=e.parent;return i}function Jr(t){for(var n=[],e=t.parent;null!=e;)n.push(t),t=e,e=e.parent;return n.push(t),n}function Kr(t,n){if(t===n)return t;for(var e=Jr(t),r=Jr(n),i=e.pop(),o=r.pop(),a=null;i===o;)a=i,i=e.pop(),o=r.pop();return a}function Qr(t){t.fixed|=2}function ti(t){t.fixed&=-7}function ni(t){t.fixed|=4,t.px=t.x,t.py=t.y}function ei(t){t.fixed&=-5}function ri(t,n,e){var r=0,i=0;if(t.charge=0,!t.leaf)for(var o,a=t.nodes,u=a.length,s=-1;++s<u;)o=a[s],null!=o&&(ri(o,n,e),t.charge+=o.charge,r+=o.charge*o.cx,i+=o.charge*o.cy);if(t.point){t.leaf||(t.point.x+=Math.random()-.5,t.point.y+=Math.random()-.5);var l=n*e[t.point.index];t.charge+=t.pointCharge=l,r+=l*t.point.x,i+=l*t.point.y}t.cx=r/t.charge,t.cy=i/t.charge}function ii(t,n){return sa.rebind(t,n,"sort","children","value"),t.nodes=t,t.links=ci,t}function oi(t,n){for(var e=[t];null!=(t=e.pop());)if(n(t),(i=t.children)&&(r=i.length))for(var r,i;--r>=0;)e.push(i[r])}function ai(t,n){for(var e=[t],r=[];null!=(t=e.pop());)if(r.push(t),(o=t.children)&&(i=o.length))for(var i,o,a=-1;++a<i;)e.push(o[a]);for(;null!=(t=r.pop());)n(t)}function ui(t){return t.children}function si(t){return t.value}function li(t,n){return n.value-t.value}function ci(t){return sa.merge(t.map(function(t){return(t.children||[]).map(function(n){return{source:t,target:n}})}))}function fi(t){return t.x}function hi(t){return t.y}function pi(t,n,e){t.y0=n,t.y=e}function di(t){return sa.range(t.length)}function vi(t){for(var n=-1,e=t[0].length,r=[];++n<e;)r[n]=0;return r}function gi(t){for(var n,e=1,r=0,i=t[0][1],o=t.length;o>e;++e)(n=t[e][1])>i&&(r=e,i=n);return r}function mi(t){return t.reduce(yi,0)}function yi(t,n){return t+n[1]}function $i(t,n){return xi(t,Math.ceil(Math.log(n.length)/Math.LN2+1))}function xi(t,n){for(var e=-1,r=+t[0],i=(t[1]-r)/n,o=[];++e<=n;)o[e]=i*e+r;return o}function bi(t){return[sa.min(t),sa.max(t)]}function wi(t,n){return t.value-n.value}function Ci(t,n){var e=t._pack_next;t._pack_next=n,n._pack_prev=t,n._pack_next=e,e._pack_prev=n}function Si(t,n){t._pack_next=n,n._pack_prev=t}function _i(t,n){var e=n.x-t.x,r=n.y-t.y,i=t.r+n.r;return.999*i*i>e*e+r*r}function Mi(t){function n(t){c=Math.min(t.x-t.r,c),f=Math.max(t.x+t.r,f),h=Math.min(t.y-t.r,h),p=Math.max(t.y+t.r,p)}if((e=t.children)&&(l=e.length)){var e,r,i,o,a,u,s,l,c=1/0,f=-(1/0),h=1/0,p=-(1/0);if(e.forEach(ki),r=e[0],r.x=-r.r,r.y=0,n(r),l>1&&(i=e[1],i.x=i.r,i.y=0,n(i),l>2))for(o=e[2],Pi(r,i,o),n(o),Ci(r,o),r._pack_prev=o,Ci(o,i),i=r._pack_next,a=3;l>a;a++){Pi(r,i,o=e[a]);var d=0,v=1,g=1;for(u=i._pack_next;u!==i;u=u._pack_next,v++)if(_i(u,o)){d=1;break}if(1==d)for(s=r._pack_prev;s!==u._pack_prev&&!_i(s,o);s=s._pack_prev,g++);d?(g>v||v==g&&i.r<r.r?Si(r,i=u):Si(r=s,i),a--):(Ci(r,o),i=o,n(o))}var m=(c+f)/2,y=(h+p)/2,$=0;for(a=0;l>a;a++)o=e[a],o.x-=m,o.y-=y,$=Math.max($,o.r+Math.sqrt(o.x*o.x+o.y*o.y));t.r=$,e.forEach(Ai)}}function ki(t){t._pack_next=t._pack_prev=t}function Ai(t){delete t._pack_next,delete t._pack_prev}function Ei(t,n,e,r){var i=t.children;if(t.x=n+=r*t.x,t.y=e+=r*t.y,t.r*=r,i)for(var o=-1,a=i.length;++o<a;)Ei(i[o],n,e,r)}function Pi(t,n,e){var r=t.r+e.r,i=n.x-t.x,o=n.y-t.y;if(r&&(i||o)){var a=n.r+e.r,u=i*i+o*o;a*=a,r*=r;var s=.5+(r-a)/(2*u),l=Math.sqrt(Math.max(0,2*a*(r+u)-(r-=u)*r-a*a))/(2*u);e.x=t.x+s*i+l*o,e.y=t.y+s*o-l*i}else e.x=t.x+r,e.y=t.y}function Oi(t,n){return t.parent==n.parent?1:2}function Ti(t){var n=t.children;return n.length?n[0]:t.t}function Li(t){var n,e=t.children;return(n=e.length)?e[n-1]:t.t}function ji(t,n,e){var r=e/(n.i-t.i);n.c-=r,n.s+=e,t.c+=r,n.z+=e,n.m+=e}function Ni(t){for(var n,e=0,r=0,i=t.children,o=i.length;--o>=0;)n=i[o],n.z+=e,n.m+=e,e+=n.s+(r+=n.c)}function Ri(t,n,e){return t.a.parent===n.parent?t.a:e}function Di(t){return 1+sa.max(t,function(t){return t.y})}function Fi(t){return t.reduce(function(t,n){return t+n.x},0)/t.length}function Ii(t){var n=t.children;return n&&n.length?Ii(n[0]):t}function zi(t){var n,e=t.children;return e&&(n=e.length)?zi(e[n-1]):t}function qi(t){return{x:t.x,y:t.y,dx:t.dx,dy:t.dy}}function Vi(t,n){var e=t.x+n[3],r=t.y+n[0],i=t.dx-n[1]-n[3],o=t.dy-n[0]-n[2];return 0>i&&(e+=i/2,i=0),0>o&&(r+=o/2,o=0),{x:e,y:r,dx:i,dy:o}}function Bi(t){var n=t[0],e=t[t.length-1];return e>n?[n,e]:[e,n]}function Wi(t){return t.rangeExtent?t.rangeExtent():Bi(t.range())}function Ui(t,n,e,r){var i=e(t[0],t[1]),o=r(n[0],n[1]);return function(t){return o(i(t))}}function Hi(t,n){var e,r=0,i=t.length-1,o=t[r],a=t[i];return o>a&&(e=r,r=i,i=e,e=o,o=a,a=e),t[r]=n.floor(o),t[i]=n.ceil(a),t}function Yi(t){return t?{floor:function(n){return Math.floor(n/t)*t},ceil:function(n){return Math.ceil(n/t)*t}}:Ss}function Gi(t,n,e,r){var i=[],o=[],a=0,u=Math.min(t.length,n.length)-1;for(t[u]<t[0]&&(t=t.slice().reverse(),n=n.slice().reverse());++a<=u;)i.push(e(t[a-1],t[a])),o.push(r(n[a-1],n[a]));return function(n){var e=sa.bisect(t,n,1,u)-1;return o[e](i[e](n))}}function Xi(t,n,e,r){function i(){var i=Math.min(t.length,n.length)>2?Gi:Ui,s=r?Xr:Gr;return a=i(t,n,s,e),u=i(n,t,s,$r),o}function o(t){return a(t)}var a,u;return o.invert=function(t){return u(t)},o.domain=function(n){return arguments.length?(t=n.map(Number),i()):t},o.range=function(t){return arguments.length?(n=t,i()):n},o.rangeRound=function(t){return o.range(t).interpolate(Dr)},o.clamp=function(t){return arguments.length?(r=t,i()):r},o.interpolate=function(t){return arguments.length?(e=t,i()):e},o.ticks=function(n){return Qi(t,n)},o.tickFormat=function(n,e){return to(t,n,e)},o.nice=function(n){return Ji(t,n),i()},o.copy=function(){return Xi(t,n,e,r)},i()}function Zi(t,n){return sa.rebind(t,n,"range","rangeRound","interpolate","clamp")}function Ji(t,n){return Hi(t,Yi(Ki(t,n)[2])),Hi(t,Yi(Ki(t,n)[2])),t}function Ki(t,n){null==n&&(n=10);var e=Bi(t),r=e[1]-e[0],i=Math.pow(10,Math.floor(Math.log(r/n)/Math.LN10)),o=n/r*i;return.15>=o?i*=10:.35>=o?i*=5:.75>=o&&(i*=2),e[0]=Math.ceil(e[0]/i)*i,e[1]=Math.floor(e[1]/i)*i+.5*i,e[2]=i,e}function Qi(t,n){return sa.range.apply(sa,Ki(t,n))}function to(t,n,e){var r=Ki(t,n);if(e){var i=hu.exec(e);if(i.shift(),"s"===i[8]){var o=sa.formatPrefix(Math.max(xa(r[0]),xa(r[1])));return i[7]||(i[7]="."+no(o.scale(r[2]))),i[8]="f",e=sa.format(i.join("")),function(t){return e(o.scale(t))+o.symbol}}i[7]||(i[7]="."+eo(i[8],r)),e=i.join("")}else e=",."+no(r[2])+"f";return sa.format(e)}function no(t){return-Math.floor(Math.log(t)/Math.LN10+.01)}function eo(t,n){var e=no(n[2]);return t in _s?Math.abs(e-no(Math.max(xa(n[0]),xa(n[1]))))+ +("e"!==t):e-2*("%"===t)}function ro(t,n,e,r){function i(t){return(e?Math.log(0>t?0:t):-Math.log(t>0?0:-t))/Math.log(n)}function o(t){return e?Math.pow(n,t):-Math.pow(n,-t)}function a(n){return t(i(n))}return a.invert=function(n){return o(t.invert(n))},a.domain=function(n){return arguments.length?(e=n[0]>=0,t.domain((r=n.map(Number)).map(i)),a):r},a.base=function(e){return arguments.length?(n=+e,t.domain(r.map(i)),a):n},a.nice=function(){var n=Hi(r.map(i),e?Math:ks);return t.domain(n),r=n.map(o),a},a.ticks=function(){var t=Bi(r),a=[],u=t[0],s=t[1],l=Math.floor(i(u)),c=Math.ceil(i(s)),f=n%1?2:n;if(isFinite(c-l)){if(e){for(;c>l;l++)for(var h=1;f>h;h++)a.push(o(l)*h);a.push(o(l))}else for(a.push(o(l));l++<c;)for(var h=f-1;h>0;h--)a.push(o(l)*h);for(l=0;a[l]<u;l++);for(c=a.length;a[c-1]>s;c--);a=a.slice(l,c)}return a},a.tickFormat=function(t,e){if(!arguments.length)return Ms;arguments.length<2?e=Ms:"function"!=typeof e&&(e=sa.format(e));var r=Math.max(1,n*t/a.ticks().length);return function(t){var a=t/o(Math.round(i(t)));return n-.5>a*n&&(a*=n),r>=a?e(t):""}},a.copy=function(){return ro(t.copy(),n,e,r)},Zi(a,t)}function io(t,n,e){function r(n){return t(i(n))}var i=oo(n),o=oo(1/n);return r.invert=function(n){return o(t.invert(n))},r.domain=function(n){return arguments.length?(t.domain((e=n.map(Number)).map(i)),r):e},r.ticks=function(t){return Qi(e,t)},r.tickFormat=function(t,n){return to(e,t,n)},r.nice=function(t){return r.domain(Ji(e,t))},r.exponent=function(a){return arguments.length?(i=oo(n=a),o=oo(1/n),t.domain(e.map(i)),r):n},r.copy=function(){return io(t.copy(),n,e)},Zi(r,t)}function oo(t){return function(n){return 0>n?-Math.pow(-n,t):Math.pow(n,t)}}function ao(t,n){function e(e){return o[((i.get(e)||("range"===n.t?i.set(e,t.push(e)):NaN))-1)%o.length]}function r(n,e){return sa.range(t.length).map(function(t){return n+e*t})}var i,o,a;return e.domain=function(r){if(!arguments.length)return t;t=[],i=new l;for(var o,a=-1,u=r.length;++a<u;)i.has(o=r[a])||i.set(o,t.push(o));return e[n.t].apply(e,n.a)},e.range=function(t){return arguments.length?(o=t,a=0,n={t:"range",a:arguments},e):o},e.rangePoints=function(i,u){arguments.length<2&&(u=0);var s=i[0],l=i[1],c=t.length<2?(s=(s+l)/2,0):(l-s)/(t.length-1+u);return o=r(s+c*u/2,c),a=0,n={t:"rangePoints",a:arguments},e},e.rangeRoundPoints=function(i,u){arguments.length<2&&(u=0);var s=i[0],l=i[1],c=t.length<2?(s=l=Math.round((s+l)/2),0):(l-s)/(t.length-1+u)|0;return o=r(s+Math.round(c*u/2+(l-s-(t.length-1+u)*c)/2),c),a=0,n={t:"rangeRoundPoints",a:arguments},e},e.rangeBands=function(i,u,s){arguments.length<2&&(u=0),arguments.length<3&&(s=u);var l=i[1]<i[0],c=i[l-0],f=i[1-l],h=(f-c)/(t.length-u+2*s);return o=r(c+h*s,h),l&&o.reverse(),a=h*(1-u),n={t:"rangeBands",a:arguments},e},e.rangeRoundBands=function(i,u,s){arguments.length<2&&(u=0),arguments.length<3&&(s=u);var l=i[1]<i[0],c=i[l-0],f=i[1-l],h=Math.floor((f-c)/(t.length-u+2*s));return o=r(c+Math.round((f-c-(t.length-u)*h)/2),h),l&&o.reverse(),a=Math.round(h*(1-u)),n={t:"rangeRoundBands",a:arguments},e},e.rangeBand=function(){return a},e.rangeExtent=function(){return Bi(n.a[0])},e.copy=function(){return ao(t,n)},e.domain(t)}function uo(t,n){function o(){var e=0,r=n.length;for(u=[];++e<r;)u[e-1]=sa.quantile(t,e/r);return a}function a(t){return isNaN(t=+t)?void 0:n[sa.bisect(u,t)]}var u;return a.domain=function(n){return arguments.length?(t=n.map(r).filter(i).sort(e),o()):t},a.range=function(t){return arguments.length?(n=t,o()):n},a.quantiles=function(){return u},a.invertExtent=function(e){return e=n.indexOf(e),0>e?[NaN,NaN]:[e>0?u[e-1]:t[0],e<u.length?u[e]:t[t.length-1]]},a.copy=function(){return uo(t,n)},o()}function so(t,n,e){function r(n){return e[Math.max(0,Math.min(a,Math.floor(o*(n-t))))]}function i(){return o=e.length/(n-t),a=e.length-1,r}var o,a;return r.domain=function(e){return arguments.length?(t=+e[0],n=+e[e.length-1],i()):[t,n]},r.range=function(t){return arguments.length?(e=t,i()):e},r.invertExtent=function(n){return n=e.indexOf(n),n=0>n?NaN:n/o+t,[n,n+1/o]},r.copy=function(){return so(t,n,e)},i()}function lo(t,n){function e(e){return e>=e?n[sa.bisect(t,e)]:void 0}return e.domain=function(n){return arguments.length?(t=n,e):t},e.range=function(t){return arguments.length?(n=t,e):n},e.invertExtent=function(e){return e=n.indexOf(e),[t[e-1],t[e]]},e.copy=function(){return lo(t,n)},e}function co(t){function n(t){return+t}return n.invert=n,n.domain=n.range=function(e){return arguments.length?(t=e.map(n),n):t},n.ticks=function(n){return Qi(t,n)},n.tickFormat=function(n,e){return to(t,n,e)},n.copy=function(){return co(t)},n}function fo(){return 0}function ho(t){return t.innerRadius}function po(t){return t.outerRadius}function vo(t){return t.startAngle}function go(t){return t.endAngle}function mo(t){return t&&t.padAngle}function yo(t,n,e,r){return(t-e)*n-(n-r)*t>0?0:1}function $o(t,n,e,r,i){var o=t[0]-n[0],a=t[1]-n[1],u=(i?r:-r)/Math.sqrt(o*o+a*a),s=u*a,l=-u*o,c=t[0]+s,f=t[1]+l,h=n[0]+s,p=n[1]+l,d=(c+h)/2,v=(f+p)/2,g=h-c,m=p-f,y=g*g+m*m,$=e-r,x=c*p-h*f,b=(0>m?-1:1)*Math.sqrt(Math.max(0,$*$*y-x*x)),w=(x*m-g*b)/y,C=(-x*g-m*b)/y,S=(x*m+g*b)/y,_=(-x*g+m*b)/y,M=w-d,k=C-v,A=S-d,E=_-v;return M*M+k*k>A*A+E*E&&(w=S,C=_),[[w-s,C-l],[w*e/$,C*e/$]]}function xo(t){function n(n){function a(){l.push("M",o(t(c),u))}for(var s,l=[],c=[],f=-1,h=n.length,p=Mt(e),d=Mt(r);++f<h;)i.call(this,s=n[f],f)?c.push([+p.call(this,s,f),+d.call(this,s,f)]):c.length&&(a(),c=[]);return c.length&&a(),l.length?l.join(""):null}var e=Ee,r=Pe,i=Pn,o=bo,a=o.key,u=.7;return n.x=function(t){return arguments.length?(e=t,n):e},n.y=function(t){return arguments.length?(r=t,n):r},n.defined=function(t){return arguments.length?(i=t,n):i},n.interpolate=function(t){return arguments.length?(a="function"==typeof t?o=t:(o=Ls.get(t)||bo).key,n):a},n.tension=function(t){return arguments.length?(u=t,n):u},n}function bo(t){return t.length>1?t.join("L"):t+"Z"}function wo(t){return t.join("L")+"Z"}function Co(t){for(var n=0,e=t.length,r=t[0],i=[r[0],",",r[1]];++n<e;)i.push("H",(r[0]+(r=t[n])[0])/2,"V",r[1]);return e>1&&i.push("H",r[0]),i.join("")}function So(t){for(var n=0,e=t.length,r=t[0],i=[r[0],",",r[1]];++n<e;)i.push("V",(r=t[n])[1],"H",r[0]);return i.join("")}function _o(t){for(var n=0,e=t.length,r=t[0],i=[r[0],",",r[1]];++n<e;)i.push("H",(r=t[n])[0],"V",r[1]);return i.join("")}function Mo(t,n){return t.length<4?bo(t):t[1]+Eo(t.slice(1,-1),Po(t,n))}function ko(t,n){return t.length<3?wo(t):t[0]+Eo((t.push(t[0]),t),Po([t[t.length-2]].concat(t,[t[1]]),n))}function Ao(t,n){return t.length<3?bo(t):t[0]+Eo(t,Po(t,n))}function Eo(t,n){if(n.length<1||t.length!=n.length&&t.length!=n.length+2)return bo(t);var e=t.length!=n.length,r="",i=t[0],o=t[1],a=n[0],u=a,s=1;if(e&&(r+="Q"+(o[0]-2*a[0]/3)+","+(o[1]-2*a[1]/3)+","+o[0]+","+o[1],i=t[1],s=2),n.length>1){u=n[1],o=t[s],s++,r+="C"+(i[0]+a[0])+","+(i[1]+a[1])+","+(o[0]-u[0])+","+(o[1]-u[1])+","+o[0]+","+o[1];for(var l=2;l<n.length;l++,s++)o=t[s],u=n[l],r+="S"+(o[0]-u[0])+","+(o[1]-u[1])+","+o[0]+","+o[1]}if(e){var c=t[s];r+="Q"+(o[0]+2*u[0]/3)+","+(o[1]+2*u[1]/3)+","+c[0]+","+c[1]}return r}function Po(t,n){for(var e,r=[],i=(1-n)/2,o=t[0],a=t[1],u=1,s=t.length;++u<s;)e=o,o=a,a=t[u],r.push([i*(a[0]-e[0]),i*(a[1]-e[1])]);return r}function Oo(t){if(t.length<3)return bo(t);var n=1,e=t.length,r=t[0],i=r[0],o=r[1],a=[i,i,i,(r=t[1])[0]],u=[o,o,o,r[1]],s=[i,",",o,"L",No(Rs,a),",",No(Rs,u)];for(t.push(t[e-1]);++n<=e;)r=t[n],a.shift(),a.push(r[0]),u.shift(),u.push(r[1]),Ro(s,a,u);return t.pop(),s.push("L",r),s.join("")}function To(t){if(t.length<4)return bo(t);for(var n,e=[],r=-1,i=t.length,o=[0],a=[0];++r<3;)n=t[r],o.push(n[0]),a.push(n[1]);for(e.push(No(Rs,o)+","+No(Rs,a)),--r;++r<i;)n=t[r],o.shift(),o.push(n[0]),a.shift(),a.push(n[1]),Ro(e,o,a);return e.join("")}function Lo(t){for(var n,e,r=-1,i=t.length,o=i+4,a=[],u=[];++r<4;)e=t[r%i],a.push(e[0]),u.push(e[1]);for(n=[No(Rs,a),",",No(Rs,u)],--r;++r<o;)e=t[r%i],a.shift(),a.push(e[0]),u.shift(),u.push(e[1]),Ro(n,a,u);return n.join("")}function jo(t,n){var e=t.length-1;if(e)for(var r,i,o=t[0][0],a=t[0][1],u=t[e][0]-o,s=t[e][1]-a,l=-1;++l<=e;)r=t[l],i=l/e,r[0]=n*r[0]+(1-n)*(o+i*u),r[1]=n*r[1]+(1-n)*(a+i*s);return Oo(t)}function No(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]+t[3]*n[3]}function Ro(t,n,e){t.push("C",No(js,n),",",No(js,e),",",No(Ns,n),",",No(Ns,e),",",No(Rs,n),",",No(Rs,e))}function Do(t,n){return(n[1]-t[1])/(n[0]-t[0])}function Fo(t){for(var n=0,e=t.length-1,r=[],i=t[0],o=t[1],a=r[0]=Do(i,o);++n<e;)r[n]=(a+(a=Do(i=o,o=t[n+1])))/2;return r[n]=a,r}function Io(t){for(var n,e,r,i,o=[],a=Fo(t),u=-1,s=t.length-1;++u<s;)n=Do(t[u],t[u+1]),xa(n)<Da?a[u]=a[u+1]=0:(e=a[u]/n,r=a[u+1]/n,i=e*e+r*r,i>9&&(i=3*n/Math.sqrt(i),a[u]=i*e,a[u+1]=i*r));for(u=-1;++u<=s;)i=(t[Math.min(s,u+1)][0]-t[Math.max(0,u-1)][0])/(6*(1+a[u]*a[u])),o.push([i||0,a[u]*i||0]);return o}function zo(t){return t.length<3?bo(t):t[0]+Eo(t,Io(t))}function qo(t){for(var n,e,r,i=-1,o=t.length;++i<o;)n=t[i],e=n[0],r=n[1]-Va,n[0]=e*Math.cos(r),n[1]=e*Math.sin(r);return t}function Vo(t){function n(n){function s(){v.push("M",u(t(m),f),c,l(t(g.reverse()),f),"Z")}for(var h,p,d,v=[],g=[],m=[],y=-1,$=n.length,x=Mt(e),b=Mt(i),w=e===r?function(){return p}:Mt(r),C=i===o?function(){return d}:Mt(o);++y<$;)a.call(this,h=n[y],y)?(g.push([p=+x.call(this,h,y),d=+b.call(this,h,y)]),m.push([+w.call(this,h,y),+C.call(this,h,y)])):g.length&&(s(),g=[],m=[]);return g.length&&s(),v.length?v.join(""):null}var e=Ee,r=Ee,i=0,o=Pe,a=Pn,u=bo,s=u.key,l=u,c="L",f=.7;return n.x=function(t){return arguments.length?(e=r=t,n):r},n.x0=function(t){return arguments.length?(e=t,n):e},n.x1=function(t){return arguments.length?(r=t,n):r},n.y=function(t){return arguments.length?(i=o=t,n):o},n.y0=function(t){return arguments.length?(i=t,n):i},n.y1=function(t){return arguments.length?(o=t,n):o},n.defined=function(t){return arguments.length?(a=t,n):a},n.interpolate=function(t){return arguments.length?(s="function"==typeof t?u=t:(u=Ls.get(t)||bo).key,l=u.reverse||u,c=u.closed?"M":"L",n):s},n.tension=function(t){return arguments.length?(f=t,n):f},n}function Bo(t){return t.radius}function Wo(t){return[t.x,t.y]}function Uo(t){return function(){var n=t.apply(this,arguments),e=n[0],r=n[1]-Va;return[e*Math.cos(r),e*Math.sin(r)]}}function Ho(){return 64}function Yo(){return"circle"}function Go(t){var n=Math.sqrt(t/Ia);return"M0,"+n+"A"+n+","+n+" 0 1,1 0,"+-n+"A"+n+","+n+" 0 1,1 0,"+n+"Z"}function Xo(t){return function(){var n,e,r;(n=this[t])&&(r=n[e=n.active])&&(r.timer.c=null,r.timer.t=NaN,--n.count?delete n[e]:delete this[t],n.active+=.5,r.event&&r.event.interrupt.call(this,this.__data__,r.index))}}function Zo(t,n,e){return _a(t,Bs),t.namespace=n,t.id=e,t}function Jo(t,n,e,r){var i=t.id,o=t.namespace;return B(t,"function"==typeof e?function(t,a,u){t[o][i].tween.set(n,r(e.call(t,t.__data__,a,u)))}:(e=r(e),function(t){t[o][i].tween.set(n,e)}))}function Ko(t){return null==t&&(t=""),function(){this.textContent=t}}function Qo(t){return null==t?"__transition__":"__transition_"+t+"__"}function ta(t,n,e,r,i){function o(t){var n=v.delay;return c.t=n+s,t>=n?a(t-n):void(c.c=a)}function a(e){var i=d.active,o=d[i];o&&(o.timer.c=null,o.timer.t=NaN,--d.count,delete d[i],o.event&&o.event.interrupt.call(t,t.__data__,o.index));for(var a in d)if(r>+a){var l=d[a];l.timer.c=null,l.timer.t=NaN,--d.count,delete d[a]}c.c=u,Ot(function(){return c.c&&u(e||1)&&(c.c=null,c.t=NaN),1},0,s),d.active=r,v.event&&v.event.start.call(t,t.__data__,n),p=[],v.tween.forEach(function(e,r){(r=r.call(t,t.__data__,n))&&p.push(r)}),h=v.ease,f=v.duration}function u(i){for(var o=i/f,a=h(o),u=p.length;u>0;)p[--u].call(t,a);return o>=1?(v.event&&v.event.end.call(t,t.__data__,n),--d.count?delete d[r]:delete t[e],1):void 0}var s,c,f,h,p,d=t[e]||(t[e]={active:0,count:0}),v=d[r];v||(s=i.time,c=Ot(o,0,s),v=d[r]={tween:new l,time:s,timer:c,delay:i.delay,duration:i.duration,ease:i.ease,index:n},i=null,++d.count)}function na(t,n,e){t.attr("transform",function(t){var r=n(t);return"translate("+(isFinite(r)?r:e(t))+",0)"})}function ea(t,n,e){t.attr("transform",function(t){var r=n(t);return"translate(0,"+(isFinite(r)?r:e(t))+")"})}function ra(t){return t.toISOString()}function ia(t,n,e){function r(n){return t(n)}function i(t,e){var r=t[1]-t[0],i=r/e,o=sa.bisect(Ks,i);return o==Ks.length?[n.year,Ki(t.map(function(t){return t/31536e6}),e)[2]]:o?n[i/Ks[o-1]<Ks[o]/i?o-1:o]:[nl,Ki(t,e)[2]]}return r.invert=function(n){return oa(t.invert(n))},r.domain=function(n){return arguments.length?(t.domain(n),r):t.domain().map(oa)},r.nice=function(t,n){function e(e){return!isNaN(e)&&!t.range(e,oa(+e+1),n).length}var o=r.domain(),a=Bi(o),u=null==t?i(a,10):"number"==typeof t&&i(a,t);return u&&(t=u[0],n=u[1]),r.domain(Hi(o,n>1?{floor:function(n){for(;e(n=t.floor(n));)n=oa(n-1);return n},ceil:function(n){for(;e(n=t.ceil(n));)n=oa(+n+1);return n}}:t))},r.ticks=function(t,n){var e=Bi(r.domain()),o=null==t?i(e,10):"number"==typeof t?i(e,t):!t.range&&[{range:t},n];return o&&(t=o[0],n=o[1]),t.range(e[0],oa(+e[1]+1),1>n?1:n)},r.tickFormat=function(){return e},r.copy=function(){return ia(t.copy(),n,e)},Zi(r,t)}function oa(t){return new Date(t)}function aa(t){return JSON.parse(t.responseText)}function ua(t){var n=fa.createRange();return n.selectNode(fa.body),n.createContextualFragment(t.responseText)}var sa={version:"3.5.17"},la=[].slice,ca=function(t){return la.call(t)},fa=this.document;if(fa)try{ca(fa.documentElement.childNodes)[0].nodeType}catch(ha){ca=function(t){for(var n=t.length,e=new Array(n);n--;)e[n]=t[n];return e}}if(Date.now||(Date.now=function(){return+new Date}),fa)try{fa.createElement("DIV").style.setProperty("opacity",0,"")}catch(pa){var da=this.Element.prototype,va=da.setAttribute,ga=da.setAttributeNS,ma=this.CSSStyleDeclaration.prototype,ya=ma.setProperty;da.setAttribute=function(t,n){va.call(this,t,n+"")},da.setAttributeNS=function(t,n,e){ga.call(this,t,n,e+"")},ma.setProperty=function(t,n,e){ya.call(this,t,n+"",e)}}sa.ascending=e,sa.descending=function(t,n){return t>n?-1:n>t?1:n>=t?0:NaN},sa.min=function(t,n){var e,r,i=-1,o=t.length;if(1===arguments.length){for(;++i<o;)if(null!=(r=t[i])&&r>=r){e=r;break}for(;++i<o;)null!=(r=t[i])&&e>r&&(e=r)}else{for(;++i<o;)if(null!=(r=n.call(t,t[i],i))&&r>=r){e=r;break}for(;++i<o;)null!=(r=n.call(t,t[i],i))&&e>r&&(e=r)}return e},sa.max=function(t,n){var e,r,i=-1,o=t.length;if(1===arguments.length){for(;++i<o;)if(null!=(r=t[i])&&r>=r){e=r;break}for(;++i<o;)null!=(r=t[i])&&r>e&&(e=r)}else{for(;++i<o;)if(null!=(r=n.call(t,t[i],i))&&r>=r){e=r;break}for(;++i<o;)null!=(r=n.call(t,t[i],i))&&r>e&&(e=r)}return e},sa.extent=function(t,n){var e,r,i,o=-1,a=t.length;if(1===arguments.length){for(;++o<a;)if(null!=(r=t[o])&&r>=r){e=i=r;break}for(;++o<a;)null!=(r=t[o])&&(e>r&&(e=r),r>i&&(i=r))}else{for(;++o<a;)if(null!=(r=n.call(t,t[o],o))&&r>=r){e=i=r;break}for(;++o<a;)null!=(r=n.call(t,t[o],o))&&(e>r&&(e=r),r>i&&(i=r))}return[e,i]},sa.sum=function(t,n){var e,r=0,o=t.length,a=-1;if(1===arguments.length)for(;++a<o;)i(e=+t[a])&&(r+=e);else for(;++a<o;)i(e=+n.call(t,t[a],a))&&(r+=e);return r},sa.mean=function(t,n){
+var e,o=0,a=t.length,u=-1,s=a;if(1===arguments.length)for(;++u<a;)i(e=r(t[u]))?o+=e:--s;else for(;++u<a;)i(e=r(n.call(t,t[u],u)))?o+=e:--s;return s?o/s:void 0},sa.quantile=function(t,n){var e=(t.length-1)*n+1,r=Math.floor(e),i=+t[r-1],o=e-r;return o?i+o*(t[r]-i):i},sa.median=function(t,n){var o,a=[],u=t.length,s=-1;if(1===arguments.length)for(;++s<u;)i(o=r(t[s]))&&a.push(o);else for(;++s<u;)i(o=r(n.call(t,t[s],s)))&&a.push(o);return a.length?sa.quantile(a.sort(e),.5):void 0},sa.variance=function(t,n){var e,o,a=t.length,u=0,s=0,l=-1,c=0;if(1===arguments.length)for(;++l<a;)i(e=r(t[l]))&&(o=e-u,u+=o/++c,s+=o*(e-u));else for(;++l<a;)i(e=r(n.call(t,t[l],l)))&&(o=e-u,u+=o/++c,s+=o*(e-u));return c>1?s/(c-1):void 0},sa.deviation=function(){var t=sa.variance.apply(this,arguments);return t?Math.sqrt(t):t};var $a=o(e);sa.bisectLeft=$a.left,sa.bisect=sa.bisectRight=$a.right,sa.bisector=function(t){return o(1===t.length?function(n,r){return e(t(n),r)}:t)},sa.shuffle=function(t,n,e){(o=arguments.length)<3&&(e=t.length,2>o&&(n=0));for(var r,i,o=e-n;o;)i=Math.random()*o--|0,r=t[o+n],t[o+n]=t[i+n],t[i+n]=r;return t},sa.permute=function(t,n){for(var e=n.length,r=new Array(e);e--;)r[e]=t[n[e]];return r},sa.pairs=function(t){for(var n,e=0,r=t.length-1,i=t[0],o=new Array(0>r?0:r);r>e;)o[e]=[n=i,i=t[++e]];return o},sa.transpose=function(t){if(!(i=t.length))return[];for(var n=-1,e=sa.min(t,a),r=new Array(e);++n<e;)for(var i,o=-1,u=r[n]=new Array(i);++o<i;)u[o]=t[o][n];return r},sa.zip=function(){return sa.transpose(arguments)},sa.keys=function(t){var n=[];for(var e in t)n.push(e);return n},sa.values=function(t){var n=[];for(var e in t)n.push(t[e]);return n},sa.entries=function(t){var n=[];for(var e in t)n.push({key:e,value:t[e]});return n},sa.merge=function(t){for(var n,e,r,i=t.length,o=-1,a=0;++o<i;)a+=t[o].length;for(e=new Array(a);--i>=0;)for(r=t[i],n=r.length;--n>=0;)e[--a]=r[n];return e};var xa=Math.abs;sa.range=function(t,n,e){if(arguments.length<3&&(e=1,arguments.length<2&&(n=t,t=0)),(n-t)/e===1/0)throw new Error("infinite range");var r,i=[],o=u(xa(e)),a=-1;if(t*=o,n*=o,e*=o,0>e)for(;(r=t+e*++a)>n;)i.push(r/o);else for(;(r=t+e*++a)<n;)i.push(r/o);return i},sa.map=function(t,n){var e=new l;if(t instanceof l)t.forEach(function(t,n){e.set(t,n)});else if(Array.isArray(t)){var r,i=-1,o=t.length;if(1===arguments.length)for(;++i<o;)e.set(i,t[i]);else for(;++i<o;)e.set(n.call(t,r=t[i],i),r)}else for(var a in t)e.set(a,t[a]);return e};var ba="__proto__",wa="\x00";s(l,{has:h,get:function(t){return this._[c(t)]},set:function(t,n){return this._[c(t)]=n},remove:p,keys:d,values:function(){var t=[];for(var n in this._)t.push(this._[n]);return t},entries:function(){var t=[];for(var n in this._)t.push({key:f(n),value:this._[n]});return t},size:v,empty:g,forEach:function(t){for(var n in this._)t.call(this,f(n),this._[n])}}),sa.nest=function(){function t(n,a,u){if(u>=o.length)return r?r.call(i,a):e?a.sort(e):a;for(var s,c,f,h,p=-1,d=a.length,v=o[u++],g=new l;++p<d;)(h=g.get(s=v(c=a[p])))?h.push(c):g.set(s,[c]);return n?(c=n(),f=function(e,r){c.set(e,t(n,r,u))}):(c={},f=function(e,r){c[e]=t(n,r,u)}),g.forEach(f),c}function n(t,e){if(e>=o.length)return t;var r=[],i=a[e++];return t.forEach(function(t,i){r.push({key:t,values:n(i,e)})}),i?r.sort(function(t,n){return i(t.key,n.key)}):r}var e,r,i={},o=[],a=[];return i.map=function(n,e){return t(e,n,0)},i.entries=function(e){return n(t(sa.map,e,0),0)},i.key=function(t){return o.push(t),i},i.sortKeys=function(t){return a[o.length-1]=t,i},i.sortValues=function(t){return e=t,i},i.rollup=function(t){return r=t,i},i},sa.set=function(t){var n=new m;if(t)for(var e=0,r=t.length;r>e;++e)n.add(t[e]);return n},s(m,{has:h,add:function(t){return this._[c(t+="")]=!0,t},remove:p,values:d,size:v,empty:g,forEach:function(t){for(var n in this._)t.call(this,f(n))}}),sa.behavior={},sa.rebind=function(t,n){for(var e,r=1,i=arguments.length;++r<i;)t[e=arguments[r]]=$(t,n,n[e]);return t};var Ca=["webkit","ms","moz","Moz","o","O"];sa.dispatch=function(){for(var t=new w,n=-1,e=arguments.length;++n<e;)t[arguments[n]]=C(t);return t},w.prototype.on=function(t,n){var e=t.indexOf("."),r="";if(e>=0&&(r=t.slice(e+1),t=t.slice(0,e)),t)return arguments.length<2?this[t].on(r):this[t].on(r,n);if(2===arguments.length){if(null==n)for(t in this)this.hasOwnProperty(t)&&this[t].on(r,null);return this}},sa.event=null,sa.requote=function(t){return t.replace(Sa,"\\$&")};var Sa=/[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g,_a={}.__proto__?function(t,n){t.__proto__=n}:function(t,n){for(var e in n)t[e]=n[e]},Ma=function(t,n){return n.querySelector(t)},ka=function(t,n){return n.querySelectorAll(t)},Aa=function(t,n){var e=t.matches||t[x(t,"matchesSelector")];return(Aa=function(t,n){return e.call(t,n)})(t,n)};"function"==typeof Sizzle&&(Ma=function(t,n){return Sizzle(t,n)[0]||null},ka=Sizzle,Aa=Sizzle.matchesSelector),sa.selection=function(){return sa.select(fa.documentElement)};var Ea=sa.selection.prototype=[];Ea.select=function(t){var n,e,r,i,o=[];t=A(t);for(var a=-1,u=this.length;++a<u;){o.push(n=[]),n.parentNode=(r=this[a]).parentNode;for(var s=-1,l=r.length;++s<l;)(i=r[s])?(n.push(e=t.call(i,i.__data__,s,a)),e&&"__data__"in i&&(e.__data__=i.__data__)):n.push(null)}return k(o)},Ea.selectAll=function(t){var n,e,r=[];t=E(t);for(var i=-1,o=this.length;++i<o;)for(var a=this[i],u=-1,s=a.length;++u<s;)(e=a[u])&&(r.push(n=ca(t.call(e,e.__data__,u,i))),n.parentNode=e);return k(r)};var Pa="http://www.w3.org/1999/xhtml",Oa={svg:"http://www.w3.org/2000/svg",xhtml:Pa,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};sa.ns={prefix:Oa,qualify:function(t){var n=t.indexOf(":"),e=t;return n>=0&&"xmlns"!==(e=t.slice(0,n))&&(t=t.slice(n+1)),Oa.hasOwnProperty(e)?{space:Oa[e],local:t}:t}},Ea.attr=function(t,n){if(arguments.length<2){if("string"==typeof t){var e=this.node();return t=sa.ns.qualify(t),t.local?e.getAttributeNS(t.space,t.local):e.getAttribute(t)}for(n in t)this.each(P(n,t[n]));return this}return this.each(P(t,n))},Ea.classed=function(t,n){if(arguments.length<2){if("string"==typeof t){var e=this.node(),r=(t=L(t)).length,i=-1;if(n=e.classList){for(;++i<r;)if(!n.contains(t[i]))return!1}else for(n=e.getAttribute("class");++i<r;)if(!T(t[i]).test(n))return!1;return!0}for(n in t)this.each(j(n,t[n]));return this}return this.each(j(t,n))},Ea.style=function(t,e,r){var i=arguments.length;if(3>i){if("string"!=typeof t){2>i&&(e="");for(r in t)this.each(R(r,t[r],e));return this}if(2>i){var o=this.node();return n(o).getComputedStyle(o,null).getPropertyValue(t)}r=""}return this.each(R(t,e,r))},Ea.property=function(t,n){if(arguments.length<2){if("string"==typeof t)return this.node()[t];for(n in t)this.each(D(n,t[n]));return this}return this.each(D(t,n))},Ea.text=function(t){return arguments.length?this.each("function"==typeof t?function(){var n=t.apply(this,arguments);this.textContent=null==n?"":n}:null==t?function(){this.textContent=""}:function(){this.textContent=t}):this.node().textContent},Ea.html=function(t){return arguments.length?this.each("function"==typeof t?function(){var n=t.apply(this,arguments);this.innerHTML=null==n?"":n}:null==t?function(){this.innerHTML=""}:function(){this.innerHTML=t}):this.node().innerHTML},Ea.append=function(t){return t=F(t),this.select(function(){return this.appendChild(t.apply(this,arguments))})},Ea.insert=function(t,n){return t=F(t),n=A(n),this.select(function(){return this.insertBefore(t.apply(this,arguments),n.apply(this,arguments)||null)})},Ea.remove=function(){return this.each(I)},Ea.data=function(t,n){function e(t,e){var r,i,o,a=t.length,f=e.length,h=Math.min(a,f),p=new Array(f),d=new Array(f),v=new Array(a);if(n){var g,m=new l,y=new Array(a);for(r=-1;++r<a;)(i=t[r])&&(m.has(g=n.call(i,i.__data__,r))?v[r]=i:m.set(g,i),y[r]=g);for(r=-1;++r<f;)(i=m.get(g=n.call(e,o=e[r],r)))?i!==!0&&(p[r]=i,i.__data__=o):d[r]=z(o),m.set(g,!0);for(r=-1;++r<a;)r in y&&m.get(y[r])!==!0&&(v[r]=t[r])}else{for(r=-1;++r<h;)i=t[r],o=e[r],i?(i.__data__=o,p[r]=i):d[r]=z(o);for(;f>r;++r)d[r]=z(e[r]);for(;a>r;++r)v[r]=t[r]}d.update=p,d.parentNode=p.parentNode=v.parentNode=t.parentNode,u.push(d),s.push(p),c.push(v)}var r,i,o=-1,a=this.length;if(!arguments.length){for(t=new Array(a=(r=this[0]).length);++o<a;)(i=r[o])&&(t[o]=i.__data__);return t}var u=W([]),s=k([]),c=k([]);if("function"==typeof t)for(;++o<a;)e(r=this[o],t.call(r,r.parentNode.__data__,o));else for(;++o<a;)e(r=this[o],t);return s.enter=function(){return u},s.exit=function(){return c},s},Ea.datum=function(t){return arguments.length?this.property("__data__",t):this.property("__data__")},Ea.filter=function(t){var n,e,r,i=[];"function"!=typeof t&&(t=q(t));for(var o=0,a=this.length;a>o;o++){i.push(n=[]),n.parentNode=(e=this[o]).parentNode;for(var u=0,s=e.length;s>u;u++)(r=e[u])&&t.call(r,r.__data__,u,o)&&n.push(r)}return k(i)},Ea.order=function(){for(var t=-1,n=this.length;++t<n;)for(var e,r=this[t],i=r.length-1,o=r[i];--i>=0;)(e=r[i])&&(o&&o!==e.nextSibling&&o.parentNode.insertBefore(e,o),o=e);return this},Ea.sort=function(t){t=V.apply(this,arguments);for(var n=-1,e=this.length;++n<e;)this[n].sort(t);return this.order()},Ea.each=function(t){return B(this,function(n,e,r){t.call(n,n.__data__,e,r)})},Ea.call=function(t){var n=ca(arguments);return t.apply(n[0]=this,n),this},Ea.empty=function(){return!this.node()},Ea.node=function(){for(var t=0,n=this.length;n>t;t++)for(var e=this[t],r=0,i=e.length;i>r;r++){var o=e[r];if(o)return o}return null},Ea.size=function(){var t=0;return B(this,function(){++t}),t};var Ta=[];sa.selection.enter=W,sa.selection.enter.prototype=Ta,Ta.append=Ea.append,Ta.empty=Ea.empty,Ta.node=Ea.node,Ta.call=Ea.call,Ta.size=Ea.size,Ta.select=function(t){for(var n,e,r,i,o,a=[],u=-1,s=this.length;++u<s;){r=(i=this[u]).update,a.push(n=[]),n.parentNode=i.parentNode;for(var l=-1,c=i.length;++l<c;)(o=i[l])?(n.push(r[l]=e=t.call(i.parentNode,o.__data__,l,u)),e.__data__=o.__data__):n.push(null)}return k(a)},Ta.insert=function(t,n){return arguments.length<2&&(n=U(this)),Ea.insert.call(this,t,n)},sa.select=function(n){var e;return"string"==typeof n?(e=[Ma(n,fa)],e.parentNode=fa.documentElement):(e=[n],e.parentNode=t(n)),k([e])},sa.selectAll=function(t){var n;return"string"==typeof t?(n=ca(ka(t,fa)),n.parentNode=fa.documentElement):(n=ca(t),n.parentNode=null),k([n])},Ea.on=function(t,n,e){var r=arguments.length;if(3>r){if("string"!=typeof t){2>r&&(n=!1);for(e in t)this.each(H(e,t[e],n));return this}if(2>r)return(r=this.node()["__on"+t])&&r._;e=!1}return this.each(H(t,n,e))};var La=sa.map({mouseenter:"mouseover",mouseleave:"mouseout"});fa&&La.forEach(function(t){"on"+t in fa&&La.remove(t)});var ja,Na=0;sa.mouse=function(t){return Z(t,_())};var Ra=this.navigator&&/WebKit/.test(this.navigator.userAgent)?-1:0;sa.touch=function(t,n,e){if(arguments.length<3&&(e=n,n=_().changedTouches),n)for(var r,i=0,o=n.length;o>i;++i)if((r=n[i]).identifier===e)return Z(t,r)},sa.behavior.drag=function(){function t(){this.on("mousedown.drag",o).on("touchstart.drag",a)}function e(t,n,e,o,a){return function(){function u(){var t,e,r=n(h,v);r&&(t=r[0]-$[0],e=r[1]-$[1],d|=t|e,$=r,p({type:"drag",x:r[0]+l[0],y:r[1]+l[1],dx:t,dy:e}))}function s(){n(h,v)&&(m.on(o+g,null).on(a+g,null),y(d),p({type:"dragend"}))}var l,c=this,f=sa.event.target.correspondingElement||sa.event.target,h=c.parentNode,p=r.of(c,arguments),d=0,v=t(),g=".drag"+(null==v?"":"-"+v),m=sa.select(e(f)).on(o+g,u).on(a+g,s),y=X(f),$=n(h,v);i?(l=i.apply(c,arguments),l=[l.x-$[0],l.y-$[1]]):l=[0,0],p({type:"dragstart"})}}var r=M(t,"drag","dragstart","dragend"),i=null,o=e(b,sa.mouse,n,"mousemove","mouseup"),a=e(J,sa.touch,y,"touchmove","touchend");return t.origin=function(n){return arguments.length?(i=n,t):i},sa.rebind(t,r,"on")},sa.touches=function(t,n){return arguments.length<2&&(n=_().touches),n?ca(n).map(function(n){var e=Z(t,n);return e.identifier=n.identifier,e}):[]};var Da=1e-6,Fa=Da*Da,Ia=Math.PI,za=2*Ia,qa=za-Da,Va=Ia/2,Ba=Ia/180,Wa=180/Ia,Ua=Math.SQRT2,Ha=2,Ya=4;sa.interpolateZoom=function(t,n){var e,r,i=t[0],o=t[1],a=t[2],u=n[0],s=n[1],l=n[2],c=u-i,f=s-o,h=c*c+f*f;if(Fa>h)r=Math.log(l/a)/Ua,e=function(t){return[i+t*c,o+t*f,a*Math.exp(Ua*t*r)]};else{var p=Math.sqrt(h),d=(l*l-a*a+Ya*h)/(2*a*Ha*p),v=(l*l-a*a-Ya*h)/(2*l*Ha*p),g=Math.log(Math.sqrt(d*d+1)-d),m=Math.log(Math.sqrt(v*v+1)-v);r=(m-g)/Ua,e=function(t){var n=t*r,e=rt(g),u=a/(Ha*p)*(e*it(Ua*n+g)-et(g));return[i+u*c,o+u*f,a*e/rt(Ua*n+g)]}}return e.duration=1e3*r,e},sa.behavior.zoom=function(){function t(t){t.on(O,f).on(Xa+".zoom",p).on("dblclick.zoom",d).on(j,h)}function e(t){return[(t[0]-_.x)/_.k,(t[1]-_.y)/_.k]}function r(t){return[t[0]*_.k+_.x,t[1]*_.k+_.y]}function i(t){_.k=Math.max(A[0],Math.min(A[1],t))}function o(t,n){n=r(n),_.x+=t[0]-n[0],_.y+=t[1]-n[1]}function a(n,e,r,a){n.__chart__={x:_.x,y:_.y,k:_.k},i(Math.pow(2,a)),o(g=e,r),n=sa.select(n),E>0&&(n=n.transition().duration(E)),n.call(t.event)}function u(){b&&b.domain(x.range().map(function(t){return(t-_.x)/_.k}).map(x.invert)),C&&C.domain(w.range().map(function(t){return(t-_.y)/_.k}).map(w.invert))}function s(t){P++||t({type:"zoomstart"})}function l(t){u(),t({type:"zoom",scale:_.k,translate:[_.x,_.y]})}function c(t){--P||(t({type:"zoomend"}),g=null)}function f(){function t(){u=1,o(sa.mouse(i),h),l(a)}function r(){f.on(T,null).on(L,null),p(u),c(a)}var i=this,a=N.of(i,arguments),u=0,f=sa.select(n(i)).on(T,t).on(L,r),h=e(sa.mouse(i)),p=X(i);Vs.call(i),s(a)}function h(){function t(){var t=sa.touches(d);return p=_.k,t.forEach(function(t){t.identifier in g&&(g[t.identifier]=e(t))}),t}function n(){var n=sa.event.target;sa.select(n).on(x,r).on(b,u),w.push(n);for(var e=sa.event.changedTouches,i=0,o=e.length;o>i;++i)g[e[i].identifier]=null;var s=t(),l=Date.now();if(1===s.length){if(500>l-$){var c=s[0];a(d,c,g[c.identifier],Math.floor(Math.log(_.k)/Math.LN2)+1),S()}$=l}else if(s.length>1){var c=s[0],f=s[1],h=c[0]-f[0],p=c[1]-f[1];m=h*h+p*p}}function r(){var t,n,e,r,a=sa.touches(d);Vs.call(d);for(var u=0,s=a.length;s>u;++u,r=null)if(e=a[u],r=g[e.identifier]){if(n)break;t=e,n=r}if(r){var c=(c=e[0]-t[0])*c+(c=e[1]-t[1])*c,f=m&&Math.sqrt(c/m);t=[(t[0]+e[0])/2,(t[1]+e[1])/2],n=[(n[0]+r[0])/2,(n[1]+r[1])/2],i(f*p)}$=null,o(t,n),l(v)}function u(){if(sa.event.touches.length){for(var n=sa.event.changedTouches,e=0,r=n.length;r>e;++e)delete g[n[e].identifier];for(var i in g)return void t()}sa.selectAll(w).on(y,null),C.on(O,f).on(j,h),M(),c(v)}var p,d=this,v=N.of(d,arguments),g={},m=0,y=".zoom-"+sa.event.changedTouches[0].identifier,x="touchmove"+y,b="touchend"+y,w=[],C=sa.select(d),M=X(d);n(),s(v),C.on(O,null).on(j,n)}function p(){var t=N.of(this,arguments);y?clearTimeout(y):(Vs.call(this),v=e(g=m||sa.mouse(this)),s(t)),y=setTimeout(function(){y=null,c(t)},50),S(),i(Math.pow(2,.002*Ga())*_.k),o(g,v),l(t)}function d(){var t=sa.mouse(this),n=Math.log(_.k)/Math.LN2;a(this,t,e(t),sa.event.shiftKey?Math.ceil(n)-1:Math.floor(n)+1)}var v,g,m,y,$,x,b,w,C,_={x:0,y:0,k:1},k=[960,500],A=Za,E=250,P=0,O="mousedown.zoom",T="mousemove.zoom",L="mouseup.zoom",j="touchstart.zoom",N=M(t,"zoomstart","zoom","zoomend");return Xa||(Xa="onwheel"in fa?(Ga=function(){return-sa.event.deltaY*(sa.event.deltaMode?120:1)},"wheel"):"onmousewheel"in fa?(Ga=function(){return sa.event.wheelDelta},"mousewheel"):(Ga=function(){return-sa.event.detail},"MozMousePixelScroll")),t.event=function(t){t.each(function(){var t=N.of(this,arguments),n=_;zs?sa.select(this).transition().each("start.zoom",function(){_=this.__chart__||{x:0,y:0,k:1},s(t)}).tween("zoom:zoom",function(){var e=k[0],r=k[1],i=g?g[0]:e/2,o=g?g[1]:r/2,a=sa.interpolateZoom([(i-_.x)/_.k,(o-_.y)/_.k,e/_.k],[(i-n.x)/n.k,(o-n.y)/n.k,e/n.k]);return function(n){var r=a(n),u=e/r[2];this.__chart__=_={x:i-r[0]*u,y:o-r[1]*u,k:u},l(t)}}).each("interrupt.zoom",function(){c(t)}).each("end.zoom",function(){c(t)}):(this.__chart__=_,s(t),l(t),c(t))})},t.translate=function(n){return arguments.length?(_={x:+n[0],y:+n[1],k:_.k},u(),t):[_.x,_.y]},t.scale=function(n){return arguments.length?(_={x:_.x,y:_.y,k:null},i(+n),u(),t):_.k},t.scaleExtent=function(n){return arguments.length?(A=null==n?Za:[+n[0],+n[1]],t):A},t.center=function(n){return arguments.length?(m=n&&[+n[0],+n[1]],t):m},t.size=function(n){return arguments.length?(k=n&&[+n[0],+n[1]],t):k},t.duration=function(n){return arguments.length?(E=+n,t):E},t.x=function(n){return arguments.length?(b=n,x=n.copy(),_={x:0,y:0,k:1},t):b},t.y=function(n){return arguments.length?(C=n,w=n.copy(),_={x:0,y:0,k:1},t):C},sa.rebind(t,N,"on")};var Ga,Xa,Za=[0,1/0];sa.color=at,at.prototype.toString=function(){return this.rgb()+""},sa.hsl=ut;var Ja=ut.prototype=new at;Ja.brighter=function(t){return t=Math.pow(.7,arguments.length?t:1),new ut(this.h,this.s,this.l/t)},Ja.darker=function(t){return t=Math.pow(.7,arguments.length?t:1),new ut(this.h,this.s,t*this.l)},Ja.rgb=function(){return st(this.h,this.s,this.l)},sa.hcl=lt;var Ka=lt.prototype=new at;Ka.brighter=function(t){return new lt(this.h,this.c,Math.min(100,this.l+Qa*(arguments.length?t:1)))},Ka.darker=function(t){return new lt(this.h,this.c,Math.max(0,this.l-Qa*(arguments.length?t:1)))},Ka.rgb=function(){return ct(this.h,this.c,this.l).rgb()},sa.lab=ft;var Qa=18,tu=.95047,nu=1,eu=1.08883,ru=ft.prototype=new at;ru.brighter=function(t){return new ft(Math.min(100,this.l+Qa*(arguments.length?t:1)),this.a,this.b)},ru.darker=function(t){return new ft(Math.max(0,this.l-Qa*(arguments.length?t:1)),this.a,this.b)},ru.rgb=function(){return ht(this.l,this.a,this.b)},sa.rgb=mt;var iu=mt.prototype=new at;iu.brighter=function(t){t=Math.pow(.7,arguments.length?t:1);var n=this.r,e=this.g,r=this.b,i=30;return n||e||r?(n&&i>n&&(n=i),e&&i>e&&(e=i),r&&i>r&&(r=i),new mt(Math.min(255,n/t),Math.min(255,e/t),Math.min(255,r/t))):new mt(i,i,i)},iu.darker=function(t){return t=Math.pow(.7,arguments.length?t:1),new mt(t*this.r,t*this.g,t*this.b)},iu.hsl=function(){return wt(this.r,this.g,this.b)},iu.toString=function(){return"#"+xt(this.r)+xt(this.g)+xt(this.b)};var ou=sa.map({aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074});ou.forEach(function(t,n){ou.set(t,yt(n))}),sa.functor=Mt,sa.xhr=kt(y),sa.dsv=function(t,n){function e(t,e,o){arguments.length<3&&(o=e,e=null);var a=At(t,n,null==e?r:i(e),o);return a.row=function(t){return arguments.length?a.response(null==(e=t)?r:i(t)):e},a}function r(t){return e.parse(t.responseText)}function i(t){return function(n){return e.parse(n.responseText,t)}}function o(n){return n.map(a).join(t)}function a(t){return u.test(t)?'"'+t.replace(/\"/g,'""')+'"':t}var u=new RegExp('["'+t+"\n]"),s=t.charCodeAt(0);return e.parse=function(t,n){var r;return e.parseRows(t,function(t,e){if(r)return r(t,e-1);var i=new Function("d","return {"+t.map(function(t,n){return JSON.stringify(t)+": d["+n+"]"}).join(",")+"}");r=n?function(t,e){return n(i(t),e)}:i})},e.parseRows=function(t,n){function e(){if(c>=l)return a;if(i)return i=!1,o;var n=c;if(34===t.charCodeAt(n)){for(var e=n;e++<l;)if(34===t.charCodeAt(e)){if(34!==t.charCodeAt(e+1))break;++e}c=e+2;var r=t.charCodeAt(e+1);return 13===r?(i=!0,10===t.charCodeAt(e+2)&&++c):10===r&&(i=!0),t.slice(n+1,e).replace(/""/g,'"')}for(;l>c;){var r=t.charCodeAt(c++),u=1;if(10===r)i=!0;else if(13===r)i=!0,10===t.charCodeAt(c)&&(++c,++u);else if(r!==s)continue;return t.slice(n,c-u)}return t.slice(n)}for(var r,i,o={},a={},u=[],l=t.length,c=0,f=0;(r=e())!==a;){for(var h=[];r!==o&&r!==a;)h.push(r),r=e();n&&null==(h=n(h,f++))||u.push(h)}return u},e.format=function(n){if(Array.isArray(n[0]))return e.formatRows(n);var r=new m,i=[];return n.forEach(function(t){for(var n in t)r.has(n)||i.push(r.add(n))}),[i.map(a).join(t)].concat(n.map(function(n){return i.map(function(t){return a(n[t])}).join(t)})).join("\n")},e.formatRows=function(t){return t.map(o).join("\n")},e},sa.csv=sa.dsv(",","text/csv"),sa.tsv=sa.dsv("	","text/tab-separated-values");var au,uu,su,lu,cu=this[x(this,"requestAnimationFrame")]||function(t){setTimeout(t,17)};sa.timer=function(){Ot.apply(this,arguments)},sa.timer.flush=function(){Lt(),jt()},sa.round=function(t,n){return n?Math.round(t*(n=Math.pow(10,n)))/n:Math.round(t)};var fu=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"].map(Rt);sa.formatPrefix=function(t,n){var e=0;return(t=+t)&&(0>t&&(t*=-1),n&&(t=sa.round(t,Nt(t,n))),e=1+Math.floor(1e-12+Math.log(t)/Math.LN10),e=Math.max(-24,Math.min(24,3*Math.floor((e-1)/3)))),fu[8+e/3]};var hu=/(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i,pu=sa.map({b:function(t){return t.toString(2)},c:function(t){return String.fromCharCode(t)},o:function(t){return t.toString(8)},x:function(t){return t.toString(16)},X:function(t){return t.toString(16).toUpperCase()},g:function(t,n){return t.toPrecision(n)},e:function(t,n){return t.toExponential(n)},f:function(t,n){return t.toFixed(n)},r:function(t,n){return(t=sa.round(t,Nt(t,n))).toFixed(Math.max(0,Math.min(20,Nt(t*(1+1e-15),n))))}}),du=sa.time={},vu=Date;It.prototype={getDate:function(){return this._.getUTCDate()},getDay:function(){return this._.getUTCDay()},getFullYear:function(){return this._.getUTCFullYear()},getHours:function(){return this._.getUTCHours()},getMilliseconds:function(){return this._.getUTCMilliseconds()},getMinutes:function(){return this._.getUTCMinutes()},getMonth:function(){return this._.getUTCMonth()},getSeconds:function(){return this._.getUTCSeconds()},getTime:function(){return this._.getTime()},getTimezoneOffset:function(){return 0},valueOf:function(){return this._.valueOf()},setDate:function(){gu.setUTCDate.apply(this._,arguments)},setDay:function(){gu.setUTCDay.apply(this._,arguments)},setFullYear:function(){gu.setUTCFullYear.apply(this._,arguments)},setHours:function(){gu.setUTCHours.apply(this._,arguments)},setMilliseconds:function(){gu.setUTCMilliseconds.apply(this._,arguments)},setMinutes:function(){gu.setUTCMinutes.apply(this._,arguments)},setMonth:function(){gu.setUTCMonth.apply(this._,arguments)},setSeconds:function(){gu.setUTCSeconds.apply(this._,arguments)},setTime:function(){gu.setTime.apply(this._,arguments)}};var gu=Date.prototype;du.year=zt(function(t){return t=du.day(t),t.setMonth(0,1),t},function(t,n){t.setFullYear(t.getFullYear()+n)},function(t){return t.getFullYear()}),du.years=du.year.range,du.years.utc=du.year.utc.range,du.day=zt(function(t){var n=new vu(2e3,0);return n.setFullYear(t.getFullYear(),t.getMonth(),t.getDate()),n},function(t,n){t.setDate(t.getDate()+n)},function(t){return t.getDate()-1}),du.days=du.day.range,du.days.utc=du.day.utc.range,du.dayOfYear=function(t){var n=du.year(t);return Math.floor((t-n-6e4*(t.getTimezoneOffset()-n.getTimezoneOffset()))/864e5)},["sunday","monday","tuesday","wednesday","thursday","friday","saturday"].forEach(function(t,n){n=7-n;var e=du[t]=zt(function(t){return(t=du.day(t)).setDate(t.getDate()-(t.getDay()+n)%7),t},function(t,n){t.setDate(t.getDate()+7*Math.floor(n))},function(t){var e=du.year(t).getDay();return Math.floor((du.dayOfYear(t)+(e+n)%7)/7)-(e!==n)});du[t+"s"]=e.range,du[t+"s"].utc=e.utc.range,du[t+"OfYear"]=function(t){var e=du.year(t).getDay();return Math.floor((du.dayOfYear(t)+(e+n)%7)/7)}}),du.week=du.sunday,du.weeks=du.sunday.range,du.weeks.utc=du.sunday.utc.range,du.weekOfYear=du.sundayOfYear;var mu={"-":"",_:" ",0:"0"},yu=/^\s*\d+/,$u=/^%/;sa.locale=function(t){return{numberFormat:Dt(t),timeFormat:Vt(t)}};var xu=sa.locale({decimal:".",thousands:",",grouping:[3],currency:["$",""],dateTime:"%a %b %e %X %Y",date:"%m/%d/%Y",time:"%H:%M:%S",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});sa.format=xu.numberFormat,sa.geo={},cn.prototype={s:0,t:0,add:function(t){fn(t,this.t,bu),fn(bu.s,this.s,this),this.s?this.t+=bu.t:this.s=bu.t},reset:function(){this.s=this.t=0},valueOf:function(){return this.s}};var bu=new cn;sa.geo.stream=function(t,n){t&&wu.hasOwnProperty(t.type)?wu[t.type](t,n):hn(t,n)};var wu={Feature:function(t,n){hn(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++r<i;)hn(e[r].geometry,n)}},Cu={Sphere:function(t,n){n.sphere()},Point:function(t,n){t=t.coordinates,n.point(t[0],t[1],t[2])},MultiPoint:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)t=e[r],n.point(t[0],t[1],t[2])},LineString:function(t,n){pn(t.coordinates,n,0)},MultiLineString:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)pn(e[r],n,0)},Polygon:function(t,n){dn(t.coordinates,n)},MultiPolygon:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)dn(e[r],n)},GeometryCollection:function(t,n){for(var e=t.geometries,r=-1,i=e.length;++r<i;)hn(e[r],n)}};sa.geo.area=function(t){return Su=0,sa.geo.stream(t,Mu),Su};var Su,_u=new cn,Mu={sphere:function(){Su+=4*Ia},point:b,lineStart:b,lineEnd:b,polygonStart:function(){_u.reset(),Mu.lineStart=vn},polygonEnd:function(){var t=2*_u;Su+=0>t?4*Ia+t:t,Mu.lineStart=Mu.lineEnd=Mu.point=b}};sa.geo.bounds=function(){function t(t,n){$.push(x=[c=t,h=t]),f>n&&(f=n),n>p&&(p=n)}function n(n,e){var r=gn([n*Ba,e*Ba]);if(m){var i=yn(m,r),o=[i[1],-i[0],0],a=yn(o,i);bn(a),a=wn(a);var s=n-d,l=s>0?1:-1,v=a[0]*Wa*l,g=xa(s)>180;if(g^(v>l*d&&l*n>v)){var y=a[1]*Wa;y>p&&(p=y)}else if(v=(v+360)%360-180,g^(v>l*d&&l*n>v)){var y=-a[1]*Wa;f>y&&(f=y)}else f>e&&(f=e),e>p&&(p=e);g?d>n?u(c,n)>u(c,h)&&(h=n):u(n,h)>u(c,h)&&(c=n):h>=c?(c>n&&(c=n),n>h&&(h=n)):n>d?u(c,n)>u(c,h)&&(h=n):u(n,h)>u(c,h)&&(c=n)}else t(n,e);m=r,d=n}function e(){b.point=n}function r(){x[0]=c,x[1]=h,b.point=t,m=null}function i(t,e){if(m){var r=t-d;y+=xa(r)>180?r+(r>0?360:-360):r}else v=t,g=e;Mu.point(t,e),n(t,e)}function o(){Mu.lineStart()}function a(){i(v,g),Mu.lineEnd(),xa(y)>Da&&(c=-(h=180)),x[0]=c,x[1]=h,m=null}function u(t,n){return(n-=t)<0?n+360:n}function s(t,n){return t[0]-n[0]}function l(t,n){return n[0]<=n[1]?n[0]<=t&&t<=n[1]:t<n[0]||n[1]<t}var c,f,h,p,d,v,g,m,y,$,x,b={point:t,lineStart:e,lineEnd:r,polygonStart:function(){b.point=i,b.lineStart=o,b.lineEnd=a,y=0,Mu.polygonStart()},polygonEnd:function(){Mu.polygonEnd(),b.point=t,b.lineStart=e,b.lineEnd=r,0>_u?(c=-(h=180),f=-(p=90)):y>Da?p=90:-Da>y&&(f=-90),x[0]=c,x[1]=h}};return function(t){p=h=-(c=f=1/0),$=[],sa.geo.stream(t,b);var n=$.length;if(n){$.sort(s);for(var e,r=1,i=$[0],o=[i];n>r;++r)e=$[r],l(e[0],i)||l(e[1],i)?(u(i[0],e[1])>u(i[0],i[1])&&(i[1]=e[1]),u(e[0],i[1])>u(i[0],i[1])&&(i[0]=e[0])):o.push(i=e);for(var a,e,d=-(1/0),n=o.length-1,r=0,i=o[n];n>=r;i=e,++r)e=o[r],(a=u(i[1],e[0]))>d&&(d=a,c=e[0],h=i[1])}return $=x=null,c===1/0||f===1/0?[[NaN,NaN],[NaN,NaN]]:[[c,f],[h,p]]}}(),sa.geo.centroid=function(t){ku=Au=Eu=Pu=Ou=Tu=Lu=ju=Nu=Ru=Du=0,sa.geo.stream(t,Fu);var n=Nu,e=Ru,r=Du,i=n*n+e*e+r*r;return Fa>i&&(n=Tu,e=Lu,r=ju,Da>Au&&(n=Eu,e=Pu,r=Ou),i=n*n+e*e+r*r,Fa>i)?[NaN,NaN]:[Math.atan2(e,n)*Wa,nt(r/Math.sqrt(i))*Wa]};var ku,Au,Eu,Pu,Ou,Tu,Lu,ju,Nu,Ru,Du,Fu={sphere:b,point:Sn,lineStart:Mn,lineEnd:kn,polygonStart:function(){Fu.lineStart=An},polygonEnd:function(){Fu.lineStart=Mn}},Iu=jn(Pn,Fn,zn,[-Ia,-Ia/2]),zu=1e9;sa.geo.clipExtent=function(){var t,n,e,r,i,o,a={stream:function(t){return i&&(i.valid=!1),i=o(t),i.valid=!0,i},extent:function(u){return arguments.length?(o=Wn(t=+u[0][0],n=+u[0][1],e=+u[1][0],r=+u[1][1]),i&&(i.valid=!1,i=null),a):[[t,n],[e,r]]}};return a.extent([[0,0],[960,500]])},(sa.geo.conicEqualArea=function(){return Un(Hn)}).raw=Hn,sa.geo.albers=function(){return sa.geo.conicEqualArea().rotate([96,0]).center([-.6,38.7]).parallels([29.5,45.5]).scale(1070)},sa.geo.albersUsa=function(){function t(t){var o=t[0],a=t[1];return n=null,e(o,a),n||(r(o,a),n)||i(o,a),n}var n,e,r,i,o=sa.geo.albers(),a=sa.geo.conicEqualArea().rotate([154,0]).center([-2,58.5]).parallels([55,65]),u=sa.geo.conicEqualArea().rotate([157,0]).center([-3,19.9]).parallels([8,18]),s={point:function(t,e){n=[t,e]}};return t.invert=function(t){var n=o.scale(),e=o.translate(),r=(t[0]-e[0])/n,i=(t[1]-e[1])/n;return(i>=.12&&.234>i&&r>=-.425&&-.214>r?a:i>=.166&&.234>i&&r>=-.214&&-.115>r?u:o).invert(t)},t.stream=function(t){var n=o.stream(t),e=a.stream(t),r=u.stream(t);return{point:function(t,i){n.point(t,i),e.point(t,i),r.point(t,i)},sphere:function(){n.sphere(),e.sphere(),r.sphere()},lineStart:function(){n.lineStart(),e.lineStart(),r.lineStart()},lineEnd:function(){n.lineEnd(),e.lineEnd(),r.lineEnd()},polygonStart:function(){n.polygonStart(),e.polygonStart(),r.polygonStart()},polygonEnd:function(){n.polygonEnd(),e.polygonEnd(),r.polygonEnd()}}},t.precision=function(n){return arguments.length?(o.precision(n),a.precision(n),u.precision(n),t):o.precision()},t.scale=function(n){return arguments.length?(o.scale(n),a.scale(.35*n),u.scale(n),t.translate(o.translate())):o.scale()},t.translate=function(n){if(!arguments.length)return o.translate();var l=o.scale(),c=+n[0],f=+n[1];return e=o.translate(n).clipExtent([[c-.455*l,f-.238*l],[c+.455*l,f+.238*l]]).stream(s).point,r=a.translate([c-.307*l,f+.201*l]).clipExtent([[c-.425*l+Da,f+.12*l+Da],[c-.214*l-Da,f+.234*l-Da]]).stream(s).point,i=u.translate([c-.205*l,f+.212*l]).clipExtent([[c-.214*l+Da,f+.166*l+Da],[c-.115*l-Da,f+.234*l-Da]]).stream(s).point,t},t.scale(1070)};var qu,Vu,Bu,Wu,Uu,Hu,Yu={point:b,lineStart:b,lineEnd:b,polygonStart:function(){Vu=0,Yu.lineStart=Yn;
+},polygonEnd:function(){Yu.lineStart=Yu.lineEnd=Yu.point=b,qu+=xa(Vu/2)}},Gu={point:Gn,lineStart:b,lineEnd:b,polygonStart:b,polygonEnd:b},Xu={point:Jn,lineStart:Kn,lineEnd:Qn,polygonStart:function(){Xu.lineStart=te},polygonEnd:function(){Xu.point=Jn,Xu.lineStart=Kn,Xu.lineEnd=Qn}};sa.geo.path=function(){function t(t){return t&&("function"==typeof u&&o.pointRadius(+u.apply(this,arguments)),a&&a.valid||(a=i(o)),sa.geo.stream(t,a)),o.result()}function n(){return a=null,t}var e,r,i,o,a,u=4.5;return t.area=function(t){return qu=0,sa.geo.stream(t,i(Yu)),qu},t.centroid=function(t){return Eu=Pu=Ou=Tu=Lu=ju=Nu=Ru=Du=0,sa.geo.stream(t,i(Xu)),Du?[Nu/Du,Ru/Du]:ju?[Tu/ju,Lu/ju]:Ou?[Eu/Ou,Pu/Ou]:[NaN,NaN]},t.bounds=function(t){return Uu=Hu=-(Bu=Wu=1/0),sa.geo.stream(t,i(Gu)),[[Bu,Wu],[Uu,Hu]]},t.projection=function(t){return arguments.length?(i=(e=t)?t.stream||re(t):y,n()):e},t.context=function(t){return arguments.length?(o=null==(r=t)?new Xn:new ne(t),"function"!=typeof u&&o.pointRadius(u),n()):r},t.pointRadius=function(n){return arguments.length?(u="function"==typeof n?n:(o.pointRadius(+n),+n),t):u},t.projection(sa.geo.albersUsa()).context(null)},sa.geo.transform=function(t){return{stream:function(n){var e=new ie(n);for(var r in t)e[r]=t[r];return e}}},ie.prototype={point:function(t,n){this.stream.point(t,n)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}},sa.geo.projection=ae,sa.geo.projectionMutator=ue,(sa.geo.equirectangular=function(){return ae(le)}).raw=le.invert=le,sa.geo.rotation=function(t){function n(n){return n=t(n[0]*Ba,n[1]*Ba),n[0]*=Wa,n[1]*=Wa,n}return t=fe(t[0]%360*Ba,t[1]*Ba,t.length>2?t[2]*Ba:0),n.invert=function(n){return n=t.invert(n[0]*Ba,n[1]*Ba),n[0]*=Wa,n[1]*=Wa,n},n},ce.invert=le,sa.geo.circle=function(){function t(){var t="function"==typeof r?r.apply(this,arguments):r,n=fe(-t[0]*Ba,-t[1]*Ba,0).invert,i=[];return e(null,null,1,{point:function(t,e){i.push(t=n(t,e)),t[0]*=Wa,t[1]*=Wa}}),{type:"Polygon",coordinates:[i]}}var n,e,r=[0,0],i=6;return t.origin=function(n){return arguments.length?(r=n,t):r},t.angle=function(r){return arguments.length?(e=ve((n=+r)*Ba,i*Ba),t):n},t.precision=function(r){return arguments.length?(e=ve(n*Ba,(i=+r)*Ba),t):i},t.angle(90)},sa.geo.distance=function(t,n){var e,r=(n[0]-t[0])*Ba,i=t[1]*Ba,o=n[1]*Ba,a=Math.sin(r),u=Math.cos(r),s=Math.sin(i),l=Math.cos(i),c=Math.sin(o),f=Math.cos(o);return Math.atan2(Math.sqrt((e=f*a)*e+(e=l*c-s*f*u)*e),s*c+l*f*u)},sa.geo.graticule=function(){function t(){return{type:"MultiLineString",coordinates:n()}}function n(){return sa.range(Math.ceil(o/g)*g,i,g).map(h).concat(sa.range(Math.ceil(l/m)*m,s,m).map(p)).concat(sa.range(Math.ceil(r/d)*d,e,d).filter(function(t){return xa(t%g)>Da}).map(c)).concat(sa.range(Math.ceil(u/v)*v,a,v).filter(function(t){return xa(t%m)>Da}).map(f))}var e,r,i,o,a,u,s,l,c,f,h,p,d=10,v=d,g=90,m=360,y=2.5;return t.lines=function(){return n().map(function(t){return{type:"LineString",coordinates:t}})},t.outline=function(){return{type:"Polygon",coordinates:[h(o).concat(p(s).slice(1),h(i).reverse().slice(1),p(l).reverse().slice(1))]}},t.extent=function(n){return arguments.length?t.majorExtent(n).minorExtent(n):t.minorExtent()},t.majorExtent=function(n){return arguments.length?(o=+n[0][0],i=+n[1][0],l=+n[0][1],s=+n[1][1],o>i&&(n=o,o=i,i=n),l>s&&(n=l,l=s,s=n),t.precision(y)):[[o,l],[i,s]]},t.minorExtent=function(n){return arguments.length?(r=+n[0][0],e=+n[1][0],u=+n[0][1],a=+n[1][1],r>e&&(n=r,r=e,e=n),u>a&&(n=u,u=a,a=n),t.precision(y)):[[r,u],[e,a]]},t.step=function(n){return arguments.length?t.majorStep(n).minorStep(n):t.minorStep()},t.majorStep=function(n){return arguments.length?(g=+n[0],m=+n[1],t):[g,m]},t.minorStep=function(n){return arguments.length?(d=+n[0],v=+n[1],t):[d,v]},t.precision=function(n){return arguments.length?(y=+n,c=me(u,a,90),f=ye(r,e,y),h=me(l,s,90),p=ye(o,i,y),t):y},t.majorExtent([[-180,-90+Da],[180,90-Da]]).minorExtent([[-180,-80-Da],[180,80+Da]])},sa.geo.greatArc=function(){function t(){return{type:"LineString",coordinates:[n||r.apply(this,arguments),e||i.apply(this,arguments)]}}var n,e,r=$e,i=xe;return t.distance=function(){return sa.geo.distance(n||r.apply(this,arguments),e||i.apply(this,arguments))},t.source=function(e){return arguments.length?(r=e,n="function"==typeof e?null:e,t):r},t.target=function(n){return arguments.length?(i=n,e="function"==typeof n?null:n,t):i},t.precision=function(){return arguments.length?t:0},t},sa.geo.interpolate=function(t,n){return be(t[0]*Ba,t[1]*Ba,n[0]*Ba,n[1]*Ba)},sa.geo.length=function(t){return Zu=0,sa.geo.stream(t,Ju),Zu};var Zu,Ju={sphere:b,point:b,lineStart:we,lineEnd:b,polygonStart:b,polygonEnd:b},Ku=Ce(function(t){return Math.sqrt(2/(1+t))},function(t){return 2*Math.asin(t/2)});(sa.geo.azimuthalEqualArea=function(){return ae(Ku)}).raw=Ku;var Qu=Ce(function(t){var n=Math.acos(t);return n&&n/Math.sin(n)},y);(sa.geo.azimuthalEquidistant=function(){return ae(Qu)}).raw=Qu,(sa.geo.conicConformal=function(){return Un(Se)}).raw=Se,(sa.geo.conicEquidistant=function(){return Un(_e)}).raw=_e;var ts=Ce(function(t){return 1/t},Math.atan);(sa.geo.gnomonic=function(){return ae(ts)}).raw=ts,Me.invert=function(t,n){return[t,2*Math.atan(Math.exp(n))-Va]},(sa.geo.mercator=function(){return ke(Me)}).raw=Me;var ns=Ce(function(){return 1},Math.asin);(sa.geo.orthographic=function(){return ae(ns)}).raw=ns;var es=Ce(function(t){return 1/(1+t)},function(t){return 2*Math.atan(t)});(sa.geo.stereographic=function(){return ae(es)}).raw=es,Ae.invert=function(t,n){return[-n,2*Math.atan(Math.exp(t))-Va]},(sa.geo.transverseMercator=function(){var t=ke(Ae),n=t.center,e=t.rotate;return t.center=function(t){return t?n([-t[1],t[0]]):(t=n(),[t[1],-t[0]])},t.rotate=function(t){return t?e([t[0],t[1],t.length>2?t[2]+90:90]):(t=e(),[t[0],t[1],t[2]-90])},e([0,0,90])}).raw=Ae,sa.geom={},sa.geom.hull=function(t){function n(t){if(t.length<3)return[];var n,i=Mt(e),o=Mt(r),a=t.length,u=[],s=[];for(n=0;a>n;n++)u.push([+i.call(this,t[n],n),+o.call(this,t[n],n),n]);for(u.sort(Te),n=0;a>n;n++)s.push([u[n][0],-u[n][1]]);var l=Oe(u),c=Oe(s),f=c[0]===l[0],h=c[c.length-1]===l[l.length-1],p=[];for(n=l.length-1;n>=0;--n)p.push(t[u[l[n]][2]]);for(n=+f;n<c.length-h;++n)p.push(t[u[c[n]][2]]);return p}var e=Ee,r=Pe;return arguments.length?n(t):(n.x=function(t){return arguments.length?(e=t,n):e},n.y=function(t){return arguments.length?(r=t,n):r},n)},sa.geom.polygon=function(t){return _a(t,rs),t};var rs=sa.geom.polygon.prototype=[];rs.area=function(){for(var t,n=-1,e=this.length,r=this[e-1],i=0;++n<e;)t=r,r=this[n],i+=t[1]*r[0]-t[0]*r[1];return.5*i},rs.centroid=function(t){var n,e,r=-1,i=this.length,o=0,a=0,u=this[i-1];for(arguments.length||(t=-1/(6*this.area()));++r<i;)n=u,u=this[r],e=n[0]*u[1]-u[0]*n[1],o+=(n[0]+u[0])*e,a+=(n[1]+u[1])*e;return[o*t,a*t]},rs.clip=function(t){for(var n,e,r,i,o,a,u=Ne(t),s=-1,l=this.length-Ne(this),c=this[l-1];++s<l;){for(n=t.slice(),t.length=0,i=this[s],o=n[(r=n.length-u)-1],e=-1;++e<r;)a=n[e],Le(a,c,i)?(Le(o,c,i)||t.push(je(o,a,c,i)),t.push(a)):Le(o,c,i)&&t.push(je(o,a,c,i)),o=a;u&&t.push(t[0]),c=i}return t};var is,os,as,us,ss,ls=[],cs=[];Be.prototype.prepare=function(){for(var t,n=this.edges,e=n.length;e--;)t=n[e].edge,t.b&&t.a||n.splice(e,1);return n.sort(Ue),n.length},nr.prototype={start:function(){return this.edge.l===this.site?this.edge.a:this.edge.b},end:function(){return this.edge.l===this.site?this.edge.b:this.edge.a}},er.prototype={insert:function(t,n){var e,r,i;if(t){if(n.P=t,n.N=t.N,t.N&&(t.N.P=n),t.N=n,t.R){for(t=t.R;t.L;)t=t.L;t.L=n}else t.R=n;e=t}else this._?(t=ar(this._),n.P=null,n.N=t,t.P=t.L=n,e=t):(n.P=n.N=null,this._=n,e=null);for(n.L=n.R=null,n.U=e,n.C=!0,t=n;e&&e.C;)r=e.U,e===r.L?(i=r.R,i&&i.C?(e.C=i.C=!1,r.C=!0,t=r):(t===e.R&&(ir(this,e),t=e,e=t.U),e.C=!1,r.C=!0,or(this,r))):(i=r.L,i&&i.C?(e.C=i.C=!1,r.C=!0,t=r):(t===e.L&&(or(this,e),t=e,e=t.U),e.C=!1,r.C=!0,ir(this,r))),e=t.U;this._.C=!1},remove:function(t){t.N&&(t.N.P=t.P),t.P&&(t.P.N=t.N),t.N=t.P=null;var n,e,r,i=t.U,o=t.L,a=t.R;if(e=o?a?ar(a):o:a,i?i.L===t?i.L=e:i.R=e:this._=e,o&&a?(r=e.C,e.C=t.C,e.L=o,o.U=e,e!==a?(i=e.U,e.U=t.U,t=e.R,i.L=t,e.R=a,a.U=e):(e.U=i,i=e,t=e.R)):(r=t.C,t=e),t&&(t.U=i),!r){if(t&&t.C)return void(t.C=!1);do{if(t===this._)break;if(t===i.L){if(n=i.R,n.C&&(n.C=!1,i.C=!0,ir(this,i),n=i.R),n.L&&n.L.C||n.R&&n.R.C){n.R&&n.R.C||(n.L.C=!1,n.C=!0,or(this,n),n=i.R),n.C=i.C,i.C=n.R.C=!1,ir(this,i),t=this._;break}}else if(n=i.L,n.C&&(n.C=!1,i.C=!0,or(this,i),n=i.L),n.L&&n.L.C||n.R&&n.R.C){n.L&&n.L.C||(n.R.C=!1,n.C=!0,ir(this,n),n=i.L),n.C=i.C,i.C=n.L.C=!1,or(this,i),t=this._;break}n.C=!0,t=i,i=i.U}while(!t.C);t&&(t.C=!1)}}},sa.geom.voronoi=function(t){function n(t){var n=new Array(t.length),r=u[0][0],i=u[0][1],o=u[1][0],a=u[1][1];return ur(e(t),u).cells.forEach(function(e,u){var s=e.edges,l=e.site,c=n[u]=s.length?s.map(function(t){var n=t.start();return[n.x,n.y]}):l.x>=r&&l.x<=o&&l.y>=i&&l.y<=a?[[r,a],[o,a],[o,i],[r,i]]:[];c.point=t[u]}),n}function e(t){return t.map(function(t,n){return{x:Math.round(o(t,n)/Da)*Da,y:Math.round(a(t,n)/Da)*Da,i:n}})}var r=Ee,i=Pe,o=r,a=i,u=fs;return t?n(t):(n.links=function(t){return ur(e(t)).edges.filter(function(t){return t.l&&t.r}).map(function(n){return{source:t[n.l.i],target:t[n.r.i]}})},n.triangles=function(t){var n=[];return ur(e(t)).cells.forEach(function(e,r){for(var i,o,a=e.site,u=e.edges.sort(Ue),s=-1,l=u.length,c=u[l-1].edge,f=c.l===a?c.r:c.l;++s<l;)i=c,o=f,c=u[s].edge,f=c.l===a?c.r:c.l,r<o.i&&r<f.i&&lr(a,o,f)<0&&n.push([t[r],t[o.i],t[f.i]])}),n},n.x=function(t){return arguments.length?(o=Mt(r=t),n):r},n.y=function(t){return arguments.length?(a=Mt(i=t),n):i},n.clipExtent=function(t){return arguments.length?(u=null==t?fs:t,n):u===fs?null:u},n.size=function(t){return arguments.length?n.clipExtent(t&&[[0,0],t]):u===fs?null:u&&u[1]},n)};var fs=[[-1e6,-1e6],[1e6,1e6]];sa.geom.delaunay=function(t){return sa.geom.voronoi().triangles(t)},sa.geom.quadtree=function(t,n,e,r,i){function o(t){function o(t,n,e,r,i,o,a,u){if(!isNaN(e)&&!isNaN(r))if(t.leaf){var s=t.x,c=t.y;if(null!=s)if(xa(s-e)+xa(c-r)<.01)l(t,n,e,r,i,o,a,u);else{var f=t.point;t.x=t.y=t.point=null,l(t,f,s,c,i,o,a,u),l(t,n,e,r,i,o,a,u)}else t.x=e,t.y=r,t.point=n}else l(t,n,e,r,i,o,a,u)}function l(t,n,e,r,i,a,u,s){var l=.5*(i+u),c=.5*(a+s),f=e>=l,h=r>=c,p=h<<1|f;t.leaf=!1,t=t.nodes[p]||(t.nodes[p]=hr()),f?i=l:u=l,h?a=c:s=c,o(t,n,e,r,i,a,u,s)}var c,f,h,p,d,v,g,m,y,$=Mt(u),x=Mt(s);if(null!=n)v=n,g=e,m=r,y=i;else if(m=y=-(v=g=1/0),f=[],h=[],d=t.length,a)for(p=0;d>p;++p)c=t[p],c.x<v&&(v=c.x),c.y<g&&(g=c.y),c.x>m&&(m=c.x),c.y>y&&(y=c.y),f.push(c.x),h.push(c.y);else for(p=0;d>p;++p){var b=+$(c=t[p],p),w=+x(c,p);v>b&&(v=b),g>w&&(g=w),b>m&&(m=b),w>y&&(y=w),f.push(b),h.push(w)}var C=m-v,S=y-g;C>S?y=g+C:m=v+S;var _=hr();if(_.add=function(t){o(_,t,+$(t,++p),+x(t,p),v,g,m,y)},_.visit=function(t){pr(t,_,v,g,m,y)},_.find=function(t){return dr(_,t[0],t[1],v,g,m,y)},p=-1,null==n){for(;++p<d;)o(_,t[p],f[p],h[p],v,g,m,y);--p}else t.forEach(_.add);return f=h=t=c=null,_}var a,u=Ee,s=Pe;return(a=arguments.length)?(u=cr,s=fr,3===a&&(i=e,r=n,e=n=0),o(t)):(o.x=function(t){return arguments.length?(u=t,o):u},o.y=function(t){return arguments.length?(s=t,o):s},o.extent=function(t){return arguments.length?(null==t?n=e=r=i=null:(n=+t[0][0],e=+t[0][1],r=+t[1][0],i=+t[1][1]),o):null==n?null:[[n,e],[r,i]]},o.size=function(t){return arguments.length?(null==t?n=e=r=i=null:(n=e=0,r=+t[0],i=+t[1]),o):null==n?null:[r-n,i-e]},o)},sa.interpolateRgb=vr,sa.interpolateObject=gr,sa.interpolateNumber=mr,sa.interpolateString=yr;var hs=/[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,ps=new RegExp(hs.source,"g");sa.interpolate=$r,sa.interpolators=[function(t,n){var e=typeof n;return("string"===e?ou.has(n.toLowerCase())||/^(#|rgb\(|hsl\()/i.test(n)?vr:yr:n instanceof at?vr:Array.isArray(n)?xr:"object"===e&&isNaN(n)?gr:mr)(t,n)}],sa.interpolateArray=xr;var ds=function(){return y},vs=sa.map({linear:ds,poly:kr,quad:function(){return Sr},cubic:function(){return _r},sin:function(){return Ar},exp:function(){return Er},circle:function(){return Pr},elastic:Or,back:Tr,bounce:function(){return Lr}}),gs=sa.map({"in":y,out:wr,"in-out":Cr,"out-in":function(t){return Cr(wr(t))}});sa.ease=function(t){var n=t.indexOf("-"),e=n>=0?t.slice(0,n):t,r=n>=0?t.slice(n+1):"in";return e=vs.get(e)||ds,r=gs.get(r)||y,br(r(e.apply(null,la.call(arguments,1))))},sa.interpolateHcl=jr,sa.interpolateHsl=Nr,sa.interpolateLab=Rr,sa.interpolateRound=Dr,sa.transform=function(t){var n=fa.createElementNS(sa.ns.prefix.svg,"g");return(sa.transform=function(t){if(null!=t){n.setAttribute("transform",t);var e=n.transform.baseVal.consolidate()}return new Fr(e?e.matrix:ms)})(t)},Fr.prototype.toString=function(){return"translate("+this.translate+")rotate("+this.rotate+")skewX("+this.skew+")scale("+this.scale+")"};var ms={a:1,b:0,c:0,d:1,e:0,f:0};sa.interpolateTransform=Yr,sa.layout={},sa.layout.bundle=function(){return function(t){for(var n=[],e=-1,r=t.length;++e<r;)n.push(Zr(t[e]));return n}},sa.layout.chord=function(){function t(){var t,l,f,h,p,d={},v=[],g=sa.range(o),m=[];for(e=[],r=[],t=0,h=-1;++h<o;){for(l=0,p=-1;++p<o;)l+=i[h][p];v.push(l),m.push(sa.range(o)),t+=l}for(a&&g.sort(function(t,n){return a(v[t],v[n])}),u&&m.forEach(function(t,n){t.sort(function(t,e){return u(i[n][t],i[n][e])})}),t=(za-c*o)/t,l=0,h=-1;++h<o;){for(f=l,p=-1;++p<o;){var y=g[h],$=m[y][p],x=i[y][$],b=l,w=l+=x*t;d[y+"-"+$]={index:y,subindex:$,startAngle:b,endAngle:w,value:x}}r[y]={index:y,startAngle:f,endAngle:l,value:v[y]},l+=c}for(h=-1;++h<o;)for(p=h-1;++p<o;){var C=d[h+"-"+p],S=d[p+"-"+h];(C.value||S.value)&&e.push(C.value<S.value?{source:S,target:C}:{source:C,target:S})}s&&n()}function n(){e.sort(function(t,n){return s((t.source.value+t.target.value)/2,(n.source.value+n.target.value)/2)})}var e,r,i,o,a,u,s,l={},c=0;return l.matrix=function(t){return arguments.length?(o=(i=t)&&i.length,e=r=null,l):i},l.padding=function(t){return arguments.length?(c=t,e=r=null,l):c},l.sortGroups=function(t){return arguments.length?(a=t,e=r=null,l):a},l.sortSubgroups=function(t){return arguments.length?(u=t,e=null,l):u},l.sortChords=function(t){return arguments.length?(s=t,e&&n(),l):s},l.chords=function(){return e||t(),e},l.groups=function(){return r||t(),r},l},sa.layout.force=function(){function t(t){return function(n,e,r,i){if(n.point!==t){var o=n.cx-t.x,a=n.cy-t.y,u=i-e,s=o*o+a*a;if(s>u*u/m){if(v>s){var l=n.charge/s;t.px-=o*l,t.py-=a*l}return!0}if(n.point&&s&&v>s){var l=n.pointCharge/s;t.px-=o*l,t.py-=a*l}}return!n.charge}}function n(t){t.px=sa.event.x,t.py=sa.event.y,s.resume()}var e,r,i,o,a,u,s={},l=sa.dispatch("start","tick","end"),c=[1,1],f=.9,h=ys,p=$s,d=-30,v=xs,g=.1,m=.64,$=[],x=[];return s.tick=function(){if((i*=.99)<.005)return e=null,l.end({type:"end",alpha:i=0}),!0;var n,r,s,h,p,v,m,y,b,w=$.length,C=x.length;for(r=0;C>r;++r)s=x[r],h=s.source,p=s.target,y=p.x-h.x,b=p.y-h.y,(v=y*y+b*b)&&(v=i*a[r]*((v=Math.sqrt(v))-o[r])/v,y*=v,b*=v,p.x-=y*(m=h.weight+p.weight?h.weight/(h.weight+p.weight):.5),p.y-=b*m,h.x+=y*(m=1-m),h.y+=b*m);if((m=i*g)&&(y=c[0]/2,b=c[1]/2,r=-1,m))for(;++r<w;)s=$[r],s.x+=(y-s.x)*m,s.y+=(b-s.y)*m;if(d)for(ri(n=sa.geom.quadtree($),i,u),r=-1;++r<w;)(s=$[r]).fixed||n.visit(t(s));for(r=-1;++r<w;)s=$[r],s.fixed?(s.x=s.px,s.y=s.py):(s.x-=(s.px-(s.px=s.x))*f,s.y-=(s.py-(s.py=s.y))*f);l.tick({type:"tick",alpha:i})},s.nodes=function(t){return arguments.length?($=t,s):$},s.links=function(t){return arguments.length?(x=t,s):x},s.size=function(t){return arguments.length?(c=t,s):c},s.linkDistance=function(t){return arguments.length?(h="function"==typeof t?t:+t,s):h},s.distance=s.linkDistance,s.linkStrength=function(t){return arguments.length?(p="function"==typeof t?t:+t,s):p},s.friction=function(t){return arguments.length?(f=+t,s):f},s.charge=function(t){return arguments.length?(d="function"==typeof t?t:+t,s):d},s.chargeDistance=function(t){return arguments.length?(v=t*t,s):Math.sqrt(v)},s.gravity=function(t){return arguments.length?(g=+t,s):g},s.theta=function(t){return arguments.length?(m=t*t,s):Math.sqrt(m)},s.alpha=function(t){return arguments.length?(t=+t,i?t>0?i=t:(e.c=null,e.t=NaN,e=null,l.end({type:"end",alpha:i=0})):t>0&&(l.start({type:"start",alpha:i=t}),e=Ot(s.tick)),s):i},s.start=function(){function t(t,r){if(!e){for(e=new Array(i),s=0;i>s;++s)e[s]=[];for(s=0;l>s;++s){var o=x[s];e[o.source.index].push(o.target),e[o.target.index].push(o.source)}}for(var a,u=e[n],s=-1,c=u.length;++s<c;)if(!isNaN(a=u[s][t]))return a;return Math.random()*r}var n,e,r,i=$.length,l=x.length,f=c[0],v=c[1];for(n=0;i>n;++n)(r=$[n]).index=n,r.weight=0;for(n=0;l>n;++n)r=x[n],"number"==typeof r.source&&(r.source=$[r.source]),"number"==typeof r.target&&(r.target=$[r.target]),++r.source.weight,++r.target.weight;for(n=0;i>n;++n)r=$[n],isNaN(r.x)&&(r.x=t("x",f)),isNaN(r.y)&&(r.y=t("y",v)),isNaN(r.px)&&(r.px=r.x),isNaN(r.py)&&(r.py=r.y);if(o=[],"function"==typeof h)for(n=0;l>n;++n)o[n]=+h.call(this,x[n],n);else for(n=0;l>n;++n)o[n]=h;if(a=[],"function"==typeof p)for(n=0;l>n;++n)a[n]=+p.call(this,x[n],n);else for(n=0;l>n;++n)a[n]=p;if(u=[],"function"==typeof d)for(n=0;i>n;++n)u[n]=+d.call(this,$[n],n);else for(n=0;i>n;++n)u[n]=d;return s.resume()},s.resume=function(){return s.alpha(.1)},s.stop=function(){return s.alpha(0)},s.drag=function(){return r||(r=sa.behavior.drag().origin(y).on("dragstart.force",Qr).on("drag.force",n).on("dragend.force",ti)),arguments.length?void this.on("mouseover.force",ni).on("mouseout.force",ei).call(r):r},sa.rebind(s,l,"on")};var ys=20,$s=1,xs=1/0;sa.layout.hierarchy=function(){function t(i){var o,a=[i],u=[];for(i.depth=0;null!=(o=a.pop());)if(u.push(o),(l=e.call(t,o,o.depth))&&(s=l.length)){for(var s,l,c;--s>=0;)a.push(c=l[s]),c.parent=o,c.depth=o.depth+1;r&&(o.value=0),o.children=l}else r&&(o.value=+r.call(t,o,o.depth)||0),delete o.children;return ai(i,function(t){var e,i;n&&(e=t.children)&&e.sort(n),r&&(i=t.parent)&&(i.value+=t.value)}),u}var n=li,e=ui,r=si;return t.sort=function(e){return arguments.length?(n=e,t):n},t.children=function(n){return arguments.length?(e=n,t):e},t.value=function(n){return arguments.length?(r=n,t):r},t.revalue=function(n){return r&&(oi(n,function(t){t.children&&(t.value=0)}),ai(n,function(n){var e;n.children||(n.value=+r.call(t,n,n.depth)||0),(e=n.parent)&&(e.value+=n.value)})),n},t},sa.layout.partition=function(){function t(n,e,r,i){var o=n.children;if(n.x=e,n.y=n.depth*i,n.dx=r,n.dy=i,o&&(a=o.length)){var a,u,s,l=-1;for(r=n.value?r/n.value:0;++l<a;)t(u=o[l],e,s=u.value*r,i),e+=s}}function n(t){var e=t.children,r=0;if(e&&(i=e.length))for(var i,o=-1;++o<i;)r=Math.max(r,n(e[o]));return 1+r}function e(e,o){var a=r.call(this,e,o);return t(a[0],0,i[0],i[1]/n(a[0])),a}var r=sa.layout.hierarchy(),i=[1,1];return e.size=function(t){return arguments.length?(i=t,e):i},ii(e,r)},sa.layout.pie=function(){function t(a){var u,s=a.length,l=a.map(function(e,r){return+n.call(t,e,r)}),c=+("function"==typeof r?r.apply(this,arguments):r),f=("function"==typeof i?i.apply(this,arguments):i)-c,h=Math.min(Math.abs(f)/s,+("function"==typeof o?o.apply(this,arguments):o)),p=h*(0>f?-1:1),d=sa.sum(l),v=d?(f-s*p)/d:0,g=sa.range(s),m=[];return null!=e&&g.sort(e===bs?function(t,n){return l[n]-l[t]}:function(t,n){return e(a[t],a[n])}),g.forEach(function(t){m[t]={data:a[t],value:u=l[t],startAngle:c,endAngle:c+=u*v+p,padAngle:h}}),m}var n=Number,e=bs,r=0,i=za,o=0;return t.value=function(e){return arguments.length?(n=e,t):n},t.sort=function(n){return arguments.length?(e=n,t):e},t.startAngle=function(n){return arguments.length?(r=n,t):r},t.endAngle=function(n){return arguments.length?(i=n,t):i},t.padAngle=function(n){return arguments.length?(o=n,t):o},t};var bs={};sa.layout.stack=function(){function t(u,s){if(!(h=u.length))return u;var l=u.map(function(e,r){return n.call(t,e,r)}),c=l.map(function(n){return n.map(function(n,e){return[o.call(t,n,e),a.call(t,n,e)]})}),f=e.call(t,c,s);l=sa.permute(l,f),c=sa.permute(c,f);var h,p,d,v,g=r.call(t,c,s),m=l[0].length;for(d=0;m>d;++d)for(i.call(t,l[0][d],v=g[d],c[0][d][1]),p=1;h>p;++p)i.call(t,l[p][d],v+=c[p-1][d][1],c[p][d][1]);return u}var n=y,e=di,r=vi,i=pi,o=fi,a=hi;return t.values=function(e){return arguments.length?(n=e,t):n},t.order=function(n){return arguments.length?(e="function"==typeof n?n:ws.get(n)||di,t):e},t.offset=function(n){return arguments.length?(r="function"==typeof n?n:Cs.get(n)||vi,t):r},t.x=function(n){return arguments.length?(o=n,t):o},t.y=function(n){return arguments.length?(a=n,t):a},t.out=function(n){return arguments.length?(i=n,t):i},t};var ws=sa.map({"inside-out":function(t){var n,e,r=t.length,i=t.map(gi),o=t.map(mi),a=sa.range(r).sort(function(t,n){return i[t]-i[n]}),u=0,s=0,l=[],c=[];for(n=0;r>n;++n)e=a[n],s>u?(u+=o[e],l.push(e)):(s+=o[e],c.push(e));return c.reverse().concat(l)},reverse:function(t){return sa.range(t.length).reverse()},"default":di}),Cs=sa.map({silhouette:function(t){var n,e,r,i=t.length,o=t[0].length,a=[],u=0,s=[];for(e=0;o>e;++e){for(n=0,r=0;i>n;n++)r+=t[n][e][1];r>u&&(u=r),a.push(r)}for(e=0;o>e;++e)s[e]=(u-a[e])/2;return s},wiggle:function(t){var n,e,r,i,o,a,u,s,l,c=t.length,f=t[0],h=f.length,p=[];for(p[0]=s=l=0,e=1;h>e;++e){for(n=0,i=0;c>n;++n)i+=t[n][e][1];for(n=0,o=0,u=f[e][0]-f[e-1][0];c>n;++n){for(r=0,a=(t[n][e][1]-t[n][e-1][1])/(2*u);n>r;++r)a+=(t[r][e][1]-t[r][e-1][1])/u;o+=a*t[n][e][1]}p[e]=s-=i?o/i*u:0,l>s&&(l=s)}for(e=0;h>e;++e)p[e]-=l;return p},expand:function(t){var n,e,r,i=t.length,o=t[0].length,a=1/i,u=[];for(e=0;o>e;++e){for(n=0,r=0;i>n;n++)r+=t[n][e][1];if(r)for(n=0;i>n;n++)t[n][e][1]/=r;else for(n=0;i>n;n++)t[n][e][1]=a}for(e=0;o>e;++e)u[e]=0;return u},zero:vi});sa.layout.histogram=function(){function t(t,o){for(var a,u,s=[],l=t.map(e,this),c=r.call(this,l,o),f=i.call(this,c,l,o),o=-1,h=l.length,p=f.length-1,d=n?1:1/h;++o<p;)a=s[o]=[],a.dx=f[o+1]-(a.x=f[o]),a.y=0;if(p>0)for(o=-1;++o<h;)u=l[o],u>=c[0]&&u<=c[1]&&(a=s[sa.bisect(f,u,1,p)-1],a.y+=d,a.push(t[o]));return s}var n=!0,e=Number,r=bi,i=$i;return t.value=function(n){return arguments.length?(e=n,t):e},t.range=function(n){return arguments.length?(r=Mt(n),t):r},t.bins=function(n){return arguments.length?(i="number"==typeof n?function(t){return xi(t,n)}:Mt(n),t):i},t.frequency=function(e){return arguments.length?(n=!!e,t):n},t},sa.layout.pack=function(){function t(t,o){var a=e.call(this,t,o),u=a[0],s=i[0],l=i[1],c=null==n?Math.sqrt:"function"==typeof n?n:function(){return n};if(u.x=u.y=0,ai(u,function(t){t.r=+c(t.value)}),ai(u,Mi),r){var f=r*(n?1:Math.max(2*u.r/s,2*u.r/l))/2;ai(u,function(t){t.r+=f}),ai(u,Mi),ai(u,function(t){t.r-=f})}return Ei(u,s/2,l/2,n?1:1/Math.max(2*u.r/s,2*u.r/l)),a}var n,e=sa.layout.hierarchy().sort(wi),r=0,i=[1,1];return t.size=function(n){return arguments.length?(i=n,t):i},t.radius=function(e){return arguments.length?(n=null==e||"function"==typeof e?e:+e,t):n},t.padding=function(n){return arguments.length?(r=+n,t):r},ii(t,e)},sa.layout.tree=function(){function t(t,i){var c=a.call(this,t,i),f=c[0],h=n(f);if(ai(h,e),h.parent.m=-h.z,oi(h,r),l)oi(f,o);else{var p=f,d=f,v=f;oi(f,function(t){t.x<p.x&&(p=t),t.x>d.x&&(d=t),t.depth>v.depth&&(v=t)});var g=u(p,d)/2-p.x,m=s[0]/(d.x+u(d,p)/2+g),y=s[1]/(v.depth||1);oi(f,function(t){t.x=(t.x+g)*m,t.y=t.depth*y})}return c}function n(t){for(var n,e={A:null,children:[t]},r=[e];null!=(n=r.pop());)for(var i,o=n.children,a=0,u=o.length;u>a;++a)r.push((o[a]=i={_:o[a],parent:n,children:(i=o[a].children)&&i.slice()||[],A:null,a:null,z:0,m:0,c:0,s:0,t:null,i:a}).a=i);return e.children[0]}function e(t){var n=t.children,e=t.parent.children,r=t.i?e[t.i-1]:null;if(n.length){Ni(t);var o=(n[0].z+n[n.length-1].z)/2;r?(t.z=r.z+u(t._,r._),t.m=t.z-o):t.z=o}else r&&(t.z=r.z+u(t._,r._));t.parent.A=i(t,r,t.parent.A||e[0])}function r(t){t._.x=t.z+t.parent.m,t.m+=t.parent.m}function i(t,n,e){if(n){for(var r,i=t,o=t,a=n,s=i.parent.children[0],l=i.m,c=o.m,f=a.m,h=s.m;a=Li(a),i=Ti(i),a&&i;)s=Ti(s),o=Li(o),o.a=t,r=a.z+f-i.z-l+u(a._,i._),r>0&&(ji(Ri(a,t,e),t,r),l+=r,c+=r),f+=a.m,l+=i.m,h+=s.m,c+=o.m;a&&!Li(o)&&(o.t=a,o.m+=f-c),i&&!Ti(s)&&(s.t=i,s.m+=l-h,e=t)}return e}function o(t){t.x*=s[0],t.y=t.depth*s[1]}var a=sa.layout.hierarchy().sort(null).value(null),u=Oi,s=[1,1],l=null;return t.separation=function(n){return arguments.length?(u=n,t):u},t.size=function(n){return arguments.length?(l=null==(s=n)?o:null,t):l?null:s},t.nodeSize=function(n){return arguments.length?(l=null==(s=n)?null:o,t):l?s:null},ii(t,a)},sa.layout.cluster=function(){function t(t,o){var a,u=n.call(this,t,o),s=u[0],l=0;ai(s,function(t){var n=t.children;n&&n.length?(t.x=Fi(n),t.y=Di(n)):(t.x=a?l+=e(t,a):0,t.y=0,a=t)});var c=Ii(s),f=zi(s),h=c.x-e(c,f)/2,p=f.x+e(f,c)/2;return ai(s,i?function(t){t.x=(t.x-s.x)*r[0],t.y=(s.y-t.y)*r[1]}:function(t){t.x=(t.x-h)/(p-h)*r[0],t.y=(1-(s.y?t.y/s.y:1))*r[1]}),u}var n=sa.layout.hierarchy().sort(null).value(null),e=Oi,r=[1,1],i=!1;return t.separation=function(n){return arguments.length?(e=n,t):e},t.size=function(n){return arguments.length?(i=null==(r=n),t):i?null:r},t.nodeSize=function(n){return arguments.length?(i=null!=(r=n),t):i?r:null},ii(t,n)},sa.layout.treemap=function(){function t(t,n){for(var e,r,i=-1,o=t.length;++i<o;)r=(e=t[i]).value*(0>n?0:n),e.area=isNaN(r)||0>=r?0:r}function n(e){var o=e.children;if(o&&o.length){var a,u,s,l=f(e),c=[],h=o.slice(),d=1/0,v="slice"===p?l.dx:"dice"===p?l.dy:"slice-dice"===p?1&e.depth?l.dy:l.dx:Math.min(l.dx,l.dy);for(t(h,l.dx*l.dy/e.value),c.area=0;(s=h.length)>0;)c.push(a=h[s-1]),c.area+=a.area,"squarify"!==p||(u=r(c,v))<=d?(h.pop(),d=u):(c.area-=c.pop().area,i(c,v,l,!1),v=Math.min(l.dx,l.dy),c.length=c.area=0,d=1/0);c.length&&(i(c,v,l,!0),c.length=c.area=0),o.forEach(n)}}function e(n){var r=n.children;if(r&&r.length){var o,a=f(n),u=r.slice(),s=[];for(t(u,a.dx*a.dy/n.value),s.area=0;o=u.pop();)s.push(o),s.area+=o.area,null!=o.z&&(i(s,o.z?a.dx:a.dy,a,!u.length),s.length=s.area=0);r.forEach(e)}}function r(t,n){for(var e,r=t.area,i=0,o=1/0,a=-1,u=t.length;++a<u;)(e=t[a].area)&&(o>e&&(o=e),e>i&&(i=e));return r*=r,n*=n,r?Math.max(n*i*d/r,r/(n*o*d)):1/0}function i(t,n,e,r){var i,o=-1,a=t.length,u=e.x,l=e.y,c=n?s(t.area/n):0;if(n==e.dx){for((r||c>e.dy)&&(c=e.dy);++o<a;)i=t[o],i.x=u,i.y=l,i.dy=c,u+=i.dx=Math.min(e.x+e.dx-u,c?s(i.area/c):0);i.z=!0,i.dx+=e.x+e.dx-u,e.y+=c,e.dy-=c}else{for((r||c>e.dx)&&(c=e.dx);++o<a;)i=t[o],i.x=u,i.y=l,i.dx=c,l+=i.dy=Math.min(e.y+e.dy-l,c?s(i.area/c):0);i.z=!1,i.dy+=e.y+e.dy-l,e.x+=c,e.dx-=c}}function o(r){var i=a||u(r),o=i[0];return o.x=o.y=0,o.value?(o.dx=l[0],o.dy=l[1]):o.dx=o.dy=0,a&&u.revalue(o),t([o],o.dx*o.dy/o.value),(a?e:n)(o),h&&(a=i),i}var a,u=sa.layout.hierarchy(),s=Math.round,l=[1,1],c=null,f=qi,h=!1,p="squarify",d=.5*(1+Math.sqrt(5));return o.size=function(t){return arguments.length?(l=t,o):l},o.padding=function(t){function n(n){var e=t.call(o,n,n.depth);return null==e?qi(n):Vi(n,"number"==typeof e?[e,e,e,e]:e)}function e(n){return Vi(n,t)}if(!arguments.length)return c;var r;return f=null==(c=t)?qi:"function"==(r=typeof t)?n:"number"===r?(t=[t,t,t,t],e):e,o},o.round=function(t){return arguments.length?(s=t?Math.round:Number,o):s!=Number},o.sticky=function(t){return arguments.length?(h=t,a=null,o):h},o.ratio=function(t){return arguments.length?(d=t,o):d},o.mode=function(t){return arguments.length?(p=t+"",o):p},ii(o,u)},sa.random={normal:function(t,n){var e=arguments.length;return 2>e&&(n=1),1>e&&(t=0),function(){var e,r,i;do e=2*Math.random()-1,r=2*Math.random()-1,i=e*e+r*r;while(!i||i>1);return t+n*e*Math.sqrt(-2*Math.log(i)/i)}},logNormal:function(){var t=sa.random.normal.apply(sa,arguments);return function(){return Math.exp(t())}},bates:function(t){var n=sa.random.irwinHall(t);return function(){return n()/t}},irwinHall:function(t){return function(){for(var n=0,e=0;t>e;e++)n+=Math.random();return n}}},sa.scale={};var Ss={floor:y,ceil:y};sa.scale.linear=function(){return Xi([0,1],[0,1],$r,!1)};var _s={s:1,g:1,p:1,r:1,e:1};sa.scale.log=function(){return ro(sa.scale.linear().domain([0,1]),10,!0,[1,10])};var Ms=sa.format(".0e"),ks={floor:function(t){return-Math.ceil(-t)},ceil:function(t){return-Math.floor(-t)}};sa.scale.pow=function(){return io(sa.scale.linear(),1,[0,1])},sa.scale.sqrt=function(){return sa.scale.pow().exponent(.5)},sa.scale.ordinal=function(){return ao([],{t:"range",a:[[]]})},sa.scale.category10=function(){return sa.scale.ordinal().range(As)},sa.scale.category20=function(){return sa.scale.ordinal().range(Es)},sa.scale.category20b=function(){return sa.scale.ordinal().range(Ps)},sa.scale.category20c=function(){return sa.scale.ordinal().range(Os)};var As=[2062260,16744206,2924588,14034728,9725885,9197131,14907330,8355711,12369186,1556175].map($t),Es=[2062260,11454440,16744206,16759672,2924588,10018698,14034728,16750742,9725885,12955861,9197131,12885140,14907330,16234194,8355711,13092807,12369186,14408589,1556175,10410725].map($t),Ps=[3750777,5395619,7040719,10264286,6519097,9216594,11915115,13556636,9202993,12426809,15186514,15190932,8666169,11356490,14049643,15177372,8077683,10834324,13528509,14589654].map($t),Os=[3244733,7057110,10406625,13032431,15095053,16616764,16625259,16634018,3253076,7652470,10607003,13101504,7695281,10394312,12369372,14342891,6513507,9868950,12434877,14277081].map($t);sa.scale.quantile=function(){return uo([],[])},sa.scale.quantize=function(){return so(0,1,[0,1])},sa.scale.threshold=function(){return lo([.5],[0,1])},sa.scale.identity=function(){return co([0,1])},sa.svg={},sa.svg.arc=function(){function t(){var t=Math.max(0,+e.apply(this,arguments)),l=Math.max(0,+r.apply(this,arguments)),c=a.apply(this,arguments)-Va,f=u.apply(this,arguments)-Va,h=Math.abs(f-c),p=c>f?0:1;if(t>l&&(d=l,l=t,t=d),h>=qa)return n(l,p)+(t?n(t,1-p):"")+"Z";var d,v,g,m,y,$,x,b,w,C,S,_,M=0,k=0,A=[];if((m=(+s.apply(this,arguments)||0)/2)&&(g=o===Ts?Math.sqrt(t*t+l*l):+o.apply(this,arguments),p||(k*=-1),l&&(k=nt(g/l*Math.sin(m))),t&&(M=nt(g/t*Math.sin(m)))),l){y=l*Math.cos(c+k),$=l*Math.sin(c+k),x=l*Math.cos(f-k),b=l*Math.sin(f-k);var E=Math.abs(f-c-2*k)<=Ia?0:1;if(k&&yo(y,$,x,b)===p^E){var P=(c+f)/2;y=l*Math.cos(P),$=l*Math.sin(P),x=b=null}}else y=$=0;if(t){w=t*Math.cos(f-M),C=t*Math.sin(f-M),S=t*Math.cos(c+M),_=t*Math.sin(c+M);var O=Math.abs(c-f+2*M)<=Ia?0:1;if(M&&yo(w,C,S,_)===1-p^O){var T=(c+f)/2;w=t*Math.cos(T),C=t*Math.sin(T),S=_=null}}else w=C=0;if(h>Da&&(d=Math.min(Math.abs(l-t)/2,+i.apply(this,arguments)))>.001){v=l>t^p?0:1;var L=d,j=d;if(Ia>h){var N=null==S?[w,C]:null==x?[y,$]:je([y,$],[S,_],[x,b],[w,C]),R=y-N[0],D=$-N[1],F=x-N[0],I=b-N[1],z=1/Math.sin(Math.acos((R*F+D*I)/(Math.sqrt(R*R+D*D)*Math.sqrt(F*F+I*I)))/2),q=Math.sqrt(N[0]*N[0]+N[1]*N[1]);j=Math.min(d,(t-q)/(z-1)),L=Math.min(d,(l-q)/(z+1))}if(null!=x){var V=$o(null==S?[w,C]:[S,_],[y,$],l,L,p),B=$o([x,b],[w,C],l,L,p);d===L?A.push("M",V[0],"A",L,",",L," 0 0,",v," ",V[1],"A",l,",",l," 0 ",1-p^yo(V[1][0],V[1][1],B[1][0],B[1][1]),",",p," ",B[1],"A",L,",",L," 0 0,",v," ",B[0]):A.push("M",V[0],"A",L,",",L," 0 1,",v," ",B[0])}else A.push("M",y,",",$);if(null!=S){var W=$o([y,$],[S,_],t,-j,p),U=$o([w,C],null==x?[y,$]:[x,b],t,-j,p);d===j?A.push("L",U[0],"A",j,",",j," 0 0,",v," ",U[1],"A",t,",",t," 0 ",p^yo(U[1][0],U[1][1],W[1][0],W[1][1]),",",1-p," ",W[1],"A",j,",",j," 0 0,",v," ",W[0]):A.push("L",U[0],"A",j,",",j," 0 0,",v," ",W[0])}else A.push("L",w,",",C)}else A.push("M",y,",",$),null!=x&&A.push("A",l,",",l," 0 ",E,",",p," ",x,",",b),A.push("L",w,",",C),null!=S&&A.push("A",t,",",t," 0 ",O,",",1-p," ",S,",",_);return A.push("Z"),A.join("")}function n(t,n){return"M0,"+t+"A"+t+","+t+" 0 1,"+n+" 0,"+-t+"A"+t+","+t+" 0 1,"+n+" 0,"+t}var e=ho,r=po,i=fo,o=Ts,a=vo,u=go,s=mo;return t.innerRadius=function(n){return arguments.length?(e=Mt(n),t):e},t.outerRadius=function(n){return arguments.length?(r=Mt(n),t):r},t.cornerRadius=function(n){return arguments.length?(i=Mt(n),t):i},t.padRadius=function(n){return arguments.length?(o=n==Ts?Ts:Mt(n),t):o},t.startAngle=function(n){return arguments.length?(a=Mt(n),t):a;
+},t.endAngle=function(n){return arguments.length?(u=Mt(n),t):u},t.padAngle=function(n){return arguments.length?(s=Mt(n),t):s},t.centroid=function(){var t=(+e.apply(this,arguments)+ +r.apply(this,arguments))/2,n=(+a.apply(this,arguments)+ +u.apply(this,arguments))/2-Va;return[Math.cos(n)*t,Math.sin(n)*t]},t};var Ts="auto";sa.svg.line=function(){return xo(y)};var Ls=sa.map({linear:bo,"linear-closed":wo,step:Co,"step-before":So,"step-after":_o,basis:Oo,"basis-open":To,"basis-closed":Lo,bundle:jo,cardinal:Ao,"cardinal-open":Mo,"cardinal-closed":ko,monotone:zo});Ls.forEach(function(t,n){n.key=t,n.closed=/-closed$/.test(t)});var js=[0,2/3,1/3,0],Ns=[0,1/3,2/3,0],Rs=[0,1/6,2/3,1/6];sa.svg.line.radial=function(){var t=xo(qo);return t.radius=t.x,delete t.x,t.angle=t.y,delete t.y,t},So.reverse=_o,_o.reverse=So,sa.svg.area=function(){return Vo(y)},sa.svg.area.radial=function(){var t=Vo(qo);return t.radius=t.x,delete t.x,t.innerRadius=t.x0,delete t.x0,t.outerRadius=t.x1,delete t.x1,t.angle=t.y,delete t.y,t.startAngle=t.y0,delete t.y0,t.endAngle=t.y1,delete t.y1,t},sa.svg.chord=function(){function t(t,u){var s=n(this,o,t,u),l=n(this,a,t,u);return"M"+s.p0+r(s.r,s.p1,s.a1-s.a0)+(e(s,l)?i(s.r,s.p1,s.r,s.p0):i(s.r,s.p1,l.r,l.p0)+r(l.r,l.p1,l.a1-l.a0)+i(l.r,l.p1,s.r,s.p0))+"Z"}function n(t,n,e,r){var i=n.call(t,e,r),o=u.call(t,i,r),a=s.call(t,i,r)-Va,c=l.call(t,i,r)-Va;return{r:o,a0:a,a1:c,p0:[o*Math.cos(a),o*Math.sin(a)],p1:[o*Math.cos(c),o*Math.sin(c)]}}function e(t,n){return t.a0==n.a0&&t.a1==n.a1}function r(t,n,e){return"A"+t+","+t+" 0 "+ +(e>Ia)+",1 "+n}function i(t,n,e,r){return"Q 0,0 "+r}var o=$e,a=xe,u=Bo,s=vo,l=go;return t.radius=function(n){return arguments.length?(u=Mt(n),t):u},t.source=function(n){return arguments.length?(o=Mt(n),t):o},t.target=function(n){return arguments.length?(a=Mt(n),t):a},t.startAngle=function(n){return arguments.length?(s=Mt(n),t):s},t.endAngle=function(n){return arguments.length?(l=Mt(n),t):l},t},sa.svg.diagonal=function(){function t(t,i){var o=n.call(this,t,i),a=e.call(this,t,i),u=(o.y+a.y)/2,s=[o,{x:o.x,y:u},{x:a.x,y:u},a];return s=s.map(r),"M"+s[0]+"C"+s[1]+" "+s[2]+" "+s[3]}var n=$e,e=xe,r=Wo;return t.source=function(e){return arguments.length?(n=Mt(e),t):n},t.target=function(n){return arguments.length?(e=Mt(n),t):e},t.projection=function(n){return arguments.length?(r=n,t):r},t},sa.svg.diagonal.radial=function(){var t=sa.svg.diagonal(),n=Wo,e=t.projection;return t.projection=function(t){return arguments.length?e(Uo(n=t)):n},t},sa.svg.symbol=function(){function t(t,r){return(Ds.get(n.call(this,t,r))||Go)(e.call(this,t,r))}var n=Yo,e=Ho;return t.type=function(e){return arguments.length?(n=Mt(e),t):n},t.size=function(n){return arguments.length?(e=Mt(n),t):e},t};var Ds=sa.map({circle:Go,cross:function(t){var n=Math.sqrt(t/5)/2;return"M"+-3*n+","+-n+"H"+-n+"V"+-3*n+"H"+n+"V"+-n+"H"+3*n+"V"+n+"H"+n+"V"+3*n+"H"+-n+"V"+n+"H"+-3*n+"Z"},diamond:function(t){var n=Math.sqrt(t/(2*Is)),e=n*Is;return"M0,"+-n+"L"+e+",0 0,"+n+" "+-e+",0Z"},square:function(t){var n=Math.sqrt(t)/2;return"M"+-n+","+-n+"L"+n+","+-n+" "+n+","+n+" "+-n+","+n+"Z"},"triangle-down":function(t){var n=Math.sqrt(t/Fs),e=n*Fs/2;return"M0,"+e+"L"+n+","+-e+" "+-n+","+-e+"Z"},"triangle-up":function(t){var n=Math.sqrt(t/Fs),e=n*Fs/2;return"M0,"+-e+"L"+n+","+e+" "+-n+","+e+"Z"}});sa.svg.symbolTypes=Ds.keys();var Fs=Math.sqrt(3),Is=Math.tan(30*Ba);Ea.transition=function(t){for(var n,e,r=zs||++Ws,i=Qo(t),o=[],a=qs||{time:Date.now(),ease:Mr,delay:0,duration:250},u=-1,s=this.length;++u<s;){o.push(n=[]);for(var l=this[u],c=-1,f=l.length;++c<f;)(e=l[c])&&ta(e,c,i,r,a),n.push(e)}return Zo(o,i,r)},Ea.interrupt=function(t){return this.each(null==t?Vs:Xo(Qo(t)))};var zs,qs,Vs=Xo(Qo()),Bs=[],Ws=0;Bs.call=Ea.call,Bs.empty=Ea.empty,Bs.node=Ea.node,Bs.size=Ea.size,sa.transition=function(t,n){return t&&t.transition?zs?t.transition(n):t:sa.selection().transition(t)},sa.transition.prototype=Bs,Bs.select=function(t){var n,e,r,i=this.id,o=this.namespace,a=[];t=A(t);for(var u=-1,s=this.length;++u<s;){a.push(n=[]);for(var l=this[u],c=-1,f=l.length;++c<f;)(r=l[c])&&(e=t.call(r,r.__data__,c,u))?("__data__"in r&&(e.__data__=r.__data__),ta(e,c,o,i,r[o][i]),n.push(e)):n.push(null)}return Zo(a,o,i)},Bs.selectAll=function(t){var n,e,r,i,o,a=this.id,u=this.namespace,s=[];t=E(t);for(var l=-1,c=this.length;++l<c;)for(var f=this[l],h=-1,p=f.length;++h<p;)if(r=f[h]){o=r[u][a],e=t.call(r,r.__data__,h,l),s.push(n=[]);for(var d=-1,v=e.length;++d<v;)(i=e[d])&&ta(i,d,u,a,o),n.push(i)}return Zo(s,u,a)},Bs.filter=function(t){var n,e,r,i=[];"function"!=typeof t&&(t=q(t));for(var o=0,a=this.length;a>o;o++){i.push(n=[]);for(var e=this[o],u=0,s=e.length;s>u;u++)(r=e[u])&&t.call(r,r.__data__,u,o)&&n.push(r)}return Zo(i,this.namespace,this.id)},Bs.tween=function(t,n){var e=this.id,r=this.namespace;return arguments.length<2?this.node()[r][e].tween.get(t):B(this,null==n?function(n){n[r][e].tween.remove(t)}:function(i){i[r][e].tween.set(t,n)})},Bs.attr=function(t,n){function e(){this.removeAttribute(u)}function r(){this.removeAttributeNS(u.space,u.local)}function i(t){return null==t?e:(t+="",function(){var n,e=this.getAttribute(u);return e!==t&&(n=a(e,t),function(t){this.setAttribute(u,n(t))})})}function o(t){return null==t?r:(t+="",function(){var n,e=this.getAttributeNS(u.space,u.local);return e!==t&&(n=a(e,t),function(t){this.setAttributeNS(u.space,u.local,n(t))})})}if(arguments.length<2){for(n in t)this.attr(n,t[n]);return this}var a="transform"==t?Yr:$r,u=sa.ns.qualify(t);return Jo(this,"attr."+t,n,u.local?o:i)},Bs.attrTween=function(t,n){function e(t,e){var r=n.call(this,t,e,this.getAttribute(i));return r&&function(t){this.setAttribute(i,r(t))}}function r(t,e){var r=n.call(this,t,e,this.getAttributeNS(i.space,i.local));return r&&function(t){this.setAttributeNS(i.space,i.local,r(t))}}var i=sa.ns.qualify(t);return this.tween("attr."+t,i.local?r:e)},Bs.style=function(t,e,r){function i(){this.style.removeProperty(t)}function o(e){return null==e?i:(e+="",function(){var i,o=n(this).getComputedStyle(this,null).getPropertyValue(t);return o!==e&&(i=$r(o,e),function(n){this.style.setProperty(t,i(n),r)})})}var a=arguments.length;if(3>a){if("string"!=typeof t){2>a&&(e="");for(r in t)this.style(r,t[r],e);return this}r=""}return Jo(this,"style."+t,e,o)},Bs.styleTween=function(t,e,r){function i(i,o){var a=e.call(this,i,o,n(this).getComputedStyle(this,null).getPropertyValue(t));return a&&function(n){this.style.setProperty(t,a(n),r)}}return arguments.length<3&&(r=""),this.tween("style."+t,i)},Bs.text=function(t){return Jo(this,"text",t,Ko)},Bs.remove=function(){var t=this.namespace;return this.each("end.transition",function(){var n;this[t].count<2&&(n=this.parentNode)&&n.removeChild(this)})},Bs.ease=function(t){var n=this.id,e=this.namespace;return arguments.length<1?this.node()[e][n].ease:("function"!=typeof t&&(t=sa.ease.apply(sa,arguments)),B(this,function(r){r[e][n].ease=t}))},Bs.delay=function(t){var n=this.id,e=this.namespace;return arguments.length<1?this.node()[e][n].delay:B(this,"function"==typeof t?function(r,i,o){r[e][n].delay=+t.call(r,r.__data__,i,o)}:(t=+t,function(r){r[e][n].delay=t}))},Bs.duration=function(t){var n=this.id,e=this.namespace;return arguments.length<1?this.node()[e][n].duration:B(this,"function"==typeof t?function(r,i,o){r[e][n].duration=Math.max(1,t.call(r,r.__data__,i,o))}:(t=Math.max(1,t),function(r){r[e][n].duration=t}))},Bs.each=function(t,n){var e=this.id,r=this.namespace;if(arguments.length<2){var i=qs,o=zs;try{zs=e,B(this,function(n,i,o){qs=n[r][e],t.call(n,n.__data__,i,o)})}finally{qs=i,zs=o}}else B(this,function(i){var o=i[r][e];(o.event||(o.event=sa.dispatch("start","end","interrupt"))).on(t,n)});return this},Bs.transition=function(){for(var t,n,e,r,i=this.id,o=++Ws,a=this.namespace,u=[],s=0,l=this.length;l>s;s++){u.push(t=[]);for(var n=this[s],c=0,f=n.length;f>c;c++)(e=n[c])&&(r=e[a][i],ta(e,c,a,o,{time:r.time,ease:r.ease,delay:r.delay+r.duration,duration:r.duration})),t.push(e)}return Zo(u,a,o)},sa.svg.axis=function(){function t(t){t.each(function(){var t,l=sa.select(this),c=this.__chart__||e,f=this.__chart__=e.copy(),h=null==s?f.ticks?f.ticks.apply(f,u):f.domain():s,p=null==n?f.tickFormat?f.tickFormat.apply(f,u):y:n,d=l.selectAll(".tick").data(h,f),v=d.enter().insert("g",".domain").attr("class","tick").style("opacity",Da),g=sa.transition(d.exit()).style("opacity",Da).remove(),m=sa.transition(d.order()).style("opacity",1),$=Math.max(i,0)+a,x=Wi(f),b=l.selectAll(".domain").data([0]),w=(b.enter().append("path").attr("class","domain"),sa.transition(b));v.append("line"),v.append("text");var C,S,_,M,k=v.select("line"),A=m.select("line"),E=d.select("text").text(p),P=v.select("text"),O=m.select("text"),T="top"===r||"left"===r?-1:1;if("bottom"===r||"top"===r?(t=na,C="x",_="y",S="x2",M="y2",E.attr("dy",0>T?"0em":".71em").style("text-anchor","middle"),w.attr("d","M"+x[0]+","+T*o+"V0H"+x[1]+"V"+T*o)):(t=ea,C="y",_="x",S="y2",M="x2",E.attr("dy",".32em").style("text-anchor",0>T?"end":"start"),w.attr("d","M"+T*o+","+x[0]+"H0V"+x[1]+"H"+T*o)),k.attr(M,T*i),P.attr(_,T*$),A.attr(S,0).attr(M,T*i),O.attr(C,0).attr(_,T*$),f.rangeBand){var L=f,j=L.rangeBand()/2;c=f=function(t){return L(t)+j}}else c.rangeBand?c=f:g.call(t,f,c);v.call(t,c,f),m.call(t,f,f)})}var n,e=sa.scale.linear(),r=Us,i=6,o=6,a=3,u=[10],s=null;return t.scale=function(n){return arguments.length?(e=n,t):e},t.orient=function(n){return arguments.length?(r=n in Hs?n+"":Us,t):r},t.ticks=function(){return arguments.length?(u=ca(arguments),t):u},t.tickValues=function(n){return arguments.length?(s=n,t):s},t.tickFormat=function(e){return arguments.length?(n=e,t):n},t.tickSize=function(n){var e=arguments.length;return e?(i=+n,o=+arguments[e-1],t):i},t.innerTickSize=function(n){return arguments.length?(i=+n,t):i},t.outerTickSize=function(n){return arguments.length?(o=+n,t):o},t.tickPadding=function(n){return arguments.length?(a=+n,t):a},t.tickSubdivide=function(){return arguments.length&&t},t};var Us="bottom",Hs={top:1,right:1,bottom:1,left:1};sa.svg.brush=function(){function t(n){n.each(function(){var n=sa.select(this).style("pointer-events","all").style("-webkit-tap-highlight-color","rgba(0,0,0,0)").on("mousedown.brush",o).on("touchstart.brush",o),a=n.selectAll(".background").data([0]);a.enter().append("rect").attr("class","background").style("visibility","hidden").style("cursor","crosshair"),n.selectAll(".extent").data([0]).enter().append("rect").attr("class","extent").style("cursor","move");var u=n.selectAll(".resize").data(v,y);u.exit().remove(),u.enter().append("g").attr("class",function(t){return"resize "+t}).style("cursor",function(t){return Ys[t]}).append("rect").attr("x",function(t){return/[ew]$/.test(t)?-3:null}).attr("y",function(t){return/^[ns]/.test(t)?-3:null}).attr("width",6).attr("height",6).style("visibility","hidden"),u.style("display",t.empty()?"none":null);var s,f=sa.transition(n),h=sa.transition(a);l&&(s=Wi(l),h.attr("x",s[0]).attr("width",s[1]-s[0]),r(f)),c&&(s=Wi(c),h.attr("y",s[0]).attr("height",s[1]-s[0]),i(f)),e(f)})}function e(t){t.selectAll(".resize").attr("transform",function(t){return"translate("+f[+/e$/.test(t)]+","+h[+/^s/.test(t)]+")"})}function r(t){t.select(".extent").attr("x",f[0]),t.selectAll(".extent,.n>rect,.s>rect").attr("width",f[1]-f[0])}function i(t){t.select(".extent").attr("y",h[0]),t.selectAll(".extent,.e>rect,.w>rect").attr("height",h[1]-h[0])}function o(){function o(){32==sa.event.keyCode&&(E||($=null,O[0]-=f[1],O[1]-=h[1],E=2),S())}function v(){32==sa.event.keyCode&&2==E&&(O[0]+=f[1],O[1]+=h[1],E=0,S())}function g(){var t=sa.mouse(b),n=!1;x&&(t[0]+=x[0],t[1]+=x[1]),E||(sa.event.altKey?($||($=[(f[0]+f[1])/2,(h[0]+h[1])/2]),O[0]=f[+(t[0]<$[0])],O[1]=h[+(t[1]<$[1])]):$=null),k&&m(t,l,0)&&(r(_),n=!0),A&&m(t,c,1)&&(i(_),n=!0),n&&(e(_),C({type:"brush",mode:E?"move":"resize"}))}function m(t,n,e){var r,i,o=Wi(n),s=o[0],l=o[1],c=O[e],v=e?h:f,g=v[1]-v[0];return E&&(s-=c,l-=g+c),r=(e?d:p)?Math.max(s,Math.min(l,t[e])):t[e],E?i=(r+=c)+g:($&&(c=Math.max(s,Math.min(l,2*$[e]-r))),r>c?(i=r,r=c):i=c),v[0]!=r||v[1]!=i?(e?u=null:a=null,v[0]=r,v[1]=i,!0):void 0}function y(){g(),_.style("pointer-events","all").selectAll(".resize").style("display",t.empty()?"none":null),sa.select("body").style("cursor",null),T.on("mousemove.brush",null).on("mouseup.brush",null).on("touchmove.brush",null).on("touchend.brush",null).on("keydown.brush",null).on("keyup.brush",null),P(),C({type:"brushend"})}var $,x,b=this,w=sa.select(sa.event.target),C=s.of(b,arguments),_=sa.select(b),M=w.datum(),k=!/^(n|s)$/.test(M)&&l,A=!/^(e|w)$/.test(M)&&c,E=w.classed("extent"),P=X(b),O=sa.mouse(b),T=sa.select(n(b)).on("keydown.brush",o).on("keyup.brush",v);if(sa.event.changedTouches?T.on("touchmove.brush",g).on("touchend.brush",y):T.on("mousemove.brush",g).on("mouseup.brush",y),_.interrupt().selectAll("*").interrupt(),E)O[0]=f[0]-O[0],O[1]=h[0]-O[1];else if(M){var L=+/w$/.test(M),j=+/^n/.test(M);x=[f[1-L]-O[0],h[1-j]-O[1]],O[0]=f[L],O[1]=h[j]}else sa.event.altKey&&($=O.slice());_.style("pointer-events","none").selectAll(".resize").style("display",null),sa.select("body").style("cursor",w.style("cursor")),C({type:"brushstart"}),g()}var a,u,s=M(t,"brushstart","brush","brushend"),l=null,c=null,f=[0,0],h=[0,0],p=!0,d=!0,v=Gs[0];return t.event=function(t){t.each(function(){var t=s.of(this,arguments),n={x:f,y:h,i:a,j:u},e=this.__chart__||n;this.__chart__=n,zs?sa.select(this).transition().each("start.brush",function(){a=e.i,u=e.j,f=e.x,h=e.y,t({type:"brushstart"})}).tween("brush:brush",function(){var e=xr(f,n.x),r=xr(h,n.y);return a=u=null,function(i){f=n.x=e(i),h=n.y=r(i),t({type:"brush",mode:"resize"})}}).each("end.brush",function(){a=n.i,u=n.j,t({type:"brush",mode:"resize"}),t({type:"brushend"})}):(t({type:"brushstart"}),t({type:"brush",mode:"resize"}),t({type:"brushend"}))})},t.x=function(n){return arguments.length?(l=n,v=Gs[!l<<1|!c],t):l},t.y=function(n){return arguments.length?(c=n,v=Gs[!l<<1|!c],t):c},t.clamp=function(n){return arguments.length?(l&&c?(p=!!n[0],d=!!n[1]):l?p=!!n:c&&(d=!!n),t):l&&c?[p,d]:l?p:c?d:null},t.extent=function(n){var e,r,i,o,s;return arguments.length?(l&&(e=n[0],r=n[1],c&&(e=e[0],r=r[0]),a=[e,r],l.invert&&(e=l(e),r=l(r)),e>r&&(s=e,e=r,r=s),e==f[0]&&r==f[1]||(f=[e,r])),c&&(i=n[0],o=n[1],l&&(i=i[1],o=o[1]),u=[i,o],c.invert&&(i=c(i),o=c(o)),i>o&&(s=i,i=o,o=s),i==h[0]&&o==h[1]||(h=[i,o])),t):(l&&(a?(e=a[0],r=a[1]):(e=f[0],r=f[1],l.invert&&(e=l.invert(e),r=l.invert(r)),e>r&&(s=e,e=r,r=s))),c&&(u?(i=u[0],o=u[1]):(i=h[0],o=h[1],c.invert&&(i=c.invert(i),o=c.invert(o)),i>o&&(s=i,i=o,o=s))),l&&c?[[e,i],[r,o]]:l?[e,r]:c&&[i,o])},t.clear=function(){return t.empty()||(f=[0,0],h=[0,0],a=u=null),t},t.empty=function(){return!!l&&f[0]==f[1]||!!c&&h[0]==h[1]},sa.rebind(t,s,"on")};var Ys={n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},Gs=[["n","e","s","w","nw","ne","se","sw"],["e","w"],["n","s"],[]],Xs=du.format=xu.timeFormat,Zs=Xs.utc,Js=Zs("%Y-%m-%dT%H:%M:%S.%LZ");Xs.iso=Date.prototype.toISOString&&+new Date("2000-01-01T00:00:00.000Z")?ra:Js,ra.parse=function(t){var n=new Date(t);return isNaN(n)?null:n},ra.toString=Js.toString,du.second=zt(function(t){return new vu(1e3*Math.floor(t/1e3))},function(t,n){t.setTime(t.getTime()+1e3*Math.floor(n))},function(t){return t.getSeconds()}),du.seconds=du.second.range,du.seconds.utc=du.second.utc.range,du.minute=zt(function(t){return new vu(6e4*Math.floor(t/6e4))},function(t,n){t.setTime(t.getTime()+6e4*Math.floor(n))},function(t){return t.getMinutes()}),du.minutes=du.minute.range,du.minutes.utc=du.minute.utc.range,du.hour=zt(function(t){var n=t.getTimezoneOffset()/60;return new vu(36e5*(Math.floor(t/36e5-n)+n))},function(t,n){t.setTime(t.getTime()+36e5*Math.floor(n))},function(t){return t.getHours()}),du.hours=du.hour.range,du.hours.utc=du.hour.utc.range,du.month=zt(function(t){return t=du.day(t),t.setDate(1),t},function(t,n){t.setMonth(t.getMonth()+n)},function(t){return t.getMonth()}),du.months=du.month.range,du.months.utc=du.month.utc.range;var Ks=[1e3,5e3,15e3,3e4,6e4,3e5,9e5,18e5,36e5,108e5,216e5,432e5,864e5,1728e5,6048e5,2592e6,7776e6,31536e6],Qs=[[du.second,1],[du.second,5],[du.second,15],[du.second,30],[du.minute,1],[du.minute,5],[du.minute,15],[du.minute,30],[du.hour,1],[du.hour,3],[du.hour,6],[du.hour,12],[du.day,1],[du.day,2],[du.week,1],[du.month,1],[du.month,3],[du.year,1]],tl=Xs.multi([[".%L",function(t){return t.getMilliseconds()}],[":%S",function(t){return t.getSeconds()}],["%I:%M",function(t){return t.getMinutes()}],["%I %p",function(t){return t.getHours()}],["%a %d",function(t){return t.getDay()&&1!=t.getDate()}],["%b %d",function(t){return 1!=t.getDate()}],["%B",function(t){return t.getMonth()}],["%Y",Pn]]),nl={range:function(t,n,e){return sa.range(Math.ceil(t/e)*e,+n,e).map(oa)},floor:y,ceil:y};Qs.year=du.year,du.scale=function(){return ia(sa.scale.linear(),Qs,tl)};var el=Qs.map(function(t){return[t[0].utc,t[1]]}),rl=Zs.multi([[".%L",function(t){return t.getUTCMilliseconds()}],[":%S",function(t){return t.getUTCSeconds()}],["%I:%M",function(t){return t.getUTCMinutes()}],["%I %p",function(t){return t.getUTCHours()}],["%a %d",function(t){return t.getUTCDay()&&1!=t.getUTCDate()}],["%b %d",function(t){return 1!=t.getUTCDate()}],["%B",function(t){return t.getUTCMonth()}],["%Y",Pn]]);el.year=du.year.utc,du.scale.utc=function(){return ia(sa.scale.linear(),el,rl)},sa.text=kt(function(t){return t.responseText}),sa.json=function(t,n){return At(t,"application/json",aa,n)},sa.html=function(t,n){return At(t,"text/html",ua,n)},sa.xml=kt(function(t){return t.responseXML}),"function"==typeof define&&define.amd?(this.d3=sa,define(sa)):"object"==typeof module&&module.exports?module.exports=sa:this.d3=sa}(),angular.module("RecursionHelper",[]).factory("RecursionHelper",["$compile",function(t){return{compile:function(n,e){angular.isFunction(e)&&(e={post:e});var r,i=n.contents().remove();return{pre:e&&e.pre?e.pre:null,post:function(n,o){r||(r=t(i)),r(n,function(t){o.append(t)}),e&&e.post&&e.post.apply(null,arguments)}}}}}]);
\ No newline at end of file
diff --git a/xos/core/xoslib/static/js/vendor/underscore-min.js b/xos/core/xoslib/static/js/vendor/underscore-min.js
new file mode 100644
index 0000000..3434d6c
--- /dev/null
+++ b/xos/core/xoslib/static/js/vendor/underscore-min.js
@@ -0,0 +1,6 @@
+//     Underscore.js 1.6.0
+//     http://underscorejs.org
+//     (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+//     Underscore may be freely distributed under the MIT license.
+(function(){var n=this,t=n._,r={},e=Array.prototype,u=Object.prototype,i=Function.prototype,a=e.push,o=e.slice,c=e.concat,l=u.toString,f=u.hasOwnProperty,s=e.forEach,p=e.map,h=e.reduce,v=e.reduceRight,g=e.filter,d=e.every,m=e.some,y=e.indexOf,b=e.lastIndexOf,x=Array.isArray,w=Object.keys,_=i.bind,j=function(n){return n instanceof j?n:this instanceof j?void(this._wrapped=n):new j(n)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=j),exports._=j):n._=j,j.VERSION="1.6.0";var A=j.each=j.forEach=function(n,t,e){if(null==n)return n;if(s&&n.forEach===s)n.forEach(t,e);else if(n.length===+n.length){for(var u=0,i=n.length;i>u;u++)if(t.call(e,n[u],u,n)===r)return}else for(var a=j.keys(n),u=0,i=a.length;i>u;u++)if(t.call(e,n[a[u]],a[u],n)===r)return;return n};j.map=j.collect=function(n,t,r){var e=[];return null==n?e:p&&n.map===p?n.map(t,r):(A(n,function(n,u,i){e.push(t.call(r,n,u,i))}),e)};var O="Reduce of empty array with no initial value";j.reduce=j.foldl=j.inject=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),h&&n.reduce===h)return e&&(t=j.bind(t,e)),u?n.reduce(t,r):n.reduce(t);if(A(n,function(n,i,a){u?r=t.call(e,r,n,i,a):(r=n,u=!0)}),!u)throw new TypeError(O);return r},j.reduceRight=j.foldr=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),v&&n.reduceRight===v)return e&&(t=j.bind(t,e)),u?n.reduceRight(t,r):n.reduceRight(t);var i=n.length;if(i!==+i){var a=j.keys(n);i=a.length}if(A(n,function(o,c,l){c=a?a[--i]:--i,u?r=t.call(e,r,n[c],c,l):(r=n[c],u=!0)}),!u)throw new TypeError(O);return r},j.find=j.detect=function(n,t,r){var e;return k(n,function(n,u,i){return t.call(r,n,u,i)?(e=n,!0):void 0}),e},j.filter=j.select=function(n,t,r){var e=[];return null==n?e:g&&n.filter===g?n.filter(t,r):(A(n,function(n,u,i){t.call(r,n,u,i)&&e.push(n)}),e)},j.reject=function(n,t,r){return j.filter(n,function(n,e,u){return!t.call(r,n,e,u)},r)},j.every=j.all=function(n,t,e){t||(t=j.identity);var u=!0;return null==n?u:d&&n.every===d?n.every(t,e):(A(n,function(n,i,a){return(u=u&&t.call(e,n,i,a))?void 0:r}),!!u)};var k=j.some=j.any=function(n,t,e){t||(t=j.identity);var u=!1;return null==n?u:m&&n.some===m?n.some(t,e):(A(n,function(n,i,a){return u||(u=t.call(e,n,i,a))?r:void 0}),!!u)};j.contains=j.include=function(n,t){return null==n?!1:y&&n.indexOf===y?n.indexOf(t)!=-1:k(n,function(n){return n===t})},j.invoke=function(n,t){var r=o.call(arguments,2),e=j.isFunction(t);return j.map(n,function(n){return(e?t:n[t]).apply(n,r)})},j.pluck=function(n,t){return j.map(n,j.property(t))},j.where=function(n,t){return j.filter(n,j.matches(t))},j.findWhere=function(n,t){return j.find(n,j.matches(t))},j.max=function(n,t,r){if(!t&&j.isArray(n)&&n[0]===+n[0]&&n.length<65535)return Math.max.apply(Math,n);var e=-1/0,u=-1/0;return A(n,function(n,i,a){var o=t?t.call(r,n,i,a):n;o>u&&(e=n,u=o)}),e},j.min=function(n,t,r){if(!t&&j.isArray(n)&&n[0]===+n[0]&&n.length<65535)return Math.min.apply(Math,n);var e=1/0,u=1/0;return A(n,function(n,i,a){var o=t?t.call(r,n,i,a):n;u>o&&(e=n,u=o)}),e},j.shuffle=function(n){var t,r=0,e=[];return A(n,function(n){t=j.random(r++),e[r-1]=e[t],e[t]=n}),e},j.sample=function(n,t,r){return null==t||r?(n.length!==+n.length&&(n=j.values(n)),n[j.random(n.length-1)]):j.shuffle(n).slice(0,Math.max(0,t))};var E=function(n){return null==n?j.identity:j.isFunction(n)?n:j.property(n)};j.sortBy=function(n,t,r){return t=E(t),j.pluck(j.map(n,function(n,e,u){return{value:n,index:e,criteria:t.call(r,n,e,u)}}).sort(function(n,t){var r=n.criteria,e=t.criteria;if(r!==e){if(r>e||r===void 0)return 1;if(e>r||e===void 0)return-1}return n.index-t.index}),"value")};var F=function(n){return function(t,r,e){var u={};return r=E(r),A(t,function(i,a){var o=r.call(e,i,a,t);n(u,o,i)}),u}};j.groupBy=F(function(n,t,r){j.has(n,t)?n[t].push(r):n[t]=[r]}),j.indexBy=F(function(n,t,r){n[t]=r}),j.countBy=F(function(n,t){j.has(n,t)?n[t]++:n[t]=1}),j.sortedIndex=function(n,t,r,e){r=E(r);for(var u=r.call(e,t),i=0,a=n.length;a>i;){var o=i+a>>>1;r.call(e,n[o])<u?i=o+1:a=o}return i},j.toArray=function(n){return n?j.isArray(n)?o.call(n):n.length===+n.length?j.map(n,j.identity):j.values(n):[]},j.size=function(n){return null==n?0:n.length===+n.length?n.length:j.keys(n).length},j.first=j.head=j.take=function(n,t,r){return null==n?void 0:null==t||r?n[0]:0>t?[]:o.call(n,0,t)},j.initial=function(n,t,r){return o.call(n,0,n.length-(null==t||r?1:t))},j.last=function(n,t,r){return null==n?void 0:null==t||r?n[n.length-1]:o.call(n,Math.max(n.length-t,0))},j.rest=j.tail=j.drop=function(n,t,r){return o.call(n,null==t||r?1:t)},j.compact=function(n){return j.filter(n,j.identity)};var M=function(n,t,r){return t&&j.every(n,j.isArray)?c.apply(r,n):(A(n,function(n){j.isArray(n)||j.isArguments(n)?t?a.apply(r,n):M(n,t,r):r.push(n)}),r)};j.flatten=function(n,t){return M(n,t,[])},j.without=function(n){return j.difference(n,o.call(arguments,1))},j.partition=function(n,t){var r=[],e=[];return A(n,function(n){(t(n)?r:e).push(n)}),[r,e]},j.uniq=j.unique=function(n,t,r,e){j.isFunction(t)&&(e=r,r=t,t=!1);var u=r?j.map(n,r,e):n,i=[],a=[];return A(u,function(r,e){(t?e&&a[a.length-1]===r:j.contains(a,r))||(a.push(r),i.push(n[e]))}),i},j.union=function(){return j.uniq(j.flatten(arguments,!0))},j.intersection=function(n){var t=o.call(arguments,1);return j.filter(j.uniq(n),function(n){return j.every(t,function(t){return j.contains(t,n)})})},j.difference=function(n){var t=c.apply(e,o.call(arguments,1));return j.filter(n,function(n){return!j.contains(t,n)})},j.zip=function(){for(var n=j.max(j.pluck(arguments,"length").concat(0)),t=new Array(n),r=0;n>r;r++)t[r]=j.pluck(arguments,""+r);return t},j.object=function(n,t){if(null==n)return{};for(var r={},e=0,u=n.length;u>e;e++)t?r[n[e]]=t[e]:r[n[e][0]]=n[e][1];return r},j.indexOf=function(n,t,r){if(null==n)return-1;var e=0,u=n.length;if(r){if("number"!=typeof r)return e=j.sortedIndex(n,t),n[e]===t?e:-1;e=0>r?Math.max(0,u+r):r}if(y&&n.indexOf===y)return n.indexOf(t,r);for(;u>e;e++)if(n[e]===t)return e;return-1},j.lastIndexOf=function(n,t,r){if(null==n)return-1;var e=null!=r;if(b&&n.lastIndexOf===b)return e?n.lastIndexOf(t,r):n.lastIndexOf(t);for(var u=e?r:n.length;u--;)if(n[u]===t)return u;return-1},j.range=function(n,t,r){arguments.length<=1&&(t=n||0,n=0),r=arguments[2]||1;for(var e=Math.max(Math.ceil((t-n)/r),0),u=0,i=new Array(e);e>u;)i[u++]=n,n+=r;return i};var R=function(){};j.bind=function(n,t){var r,e;if(_&&n.bind===_)return _.apply(n,o.call(arguments,1));if(!j.isFunction(n))throw new TypeError;return r=o.call(arguments,2),e=function(){if(!(this instanceof e))return n.apply(t,r.concat(o.call(arguments)));R.prototype=n.prototype;var u=new R;R.prototype=null;var i=n.apply(u,r.concat(o.call(arguments)));return Object(i)===i?i:u}},j.partial=function(n){var t=o.call(arguments,1);return function(){for(var r=0,e=t.slice(),u=0,i=e.length;i>u;u++)e[u]===j&&(e[u]=arguments[r++]);for(;r<arguments.length;)e.push(arguments[r++]);return n.apply(this,e)}},j.bindAll=function(n){var t=o.call(arguments,1);if(0===t.length)throw new Error("bindAll must be passed function names");return A(t,function(t){n[t]=j.bind(n[t],n)}),n},j.memoize=function(n,t){var r={};return t||(t=j.identity),function(){var e=t.apply(this,arguments);return j.has(r,e)?r[e]:r[e]=n.apply(this,arguments)}},j.delay=function(n,t){var r=o.call(arguments,2);return setTimeout(function(){return n.apply(null,r)},t)},j.defer=function(n){return j.delay.apply(j,[n,1].concat(o.call(arguments,1)))},j.throttle=function(n,t,r){var e,u,i,a=null,o=0;r||(r={});var c=function(){o=r.leading===!1?0:j.now(),a=null,i=n.apply(e,u),e=u=null};return function(){var l=j.now();o||r.leading!==!1||(o=l);var f=t-(l-o);return e=this,u=arguments,0>=f?(clearTimeout(a),a=null,o=l,i=n.apply(e,u),e=u=null):a||r.trailing===!1||(a=setTimeout(c,f)),i}},j.debounce=function(n,t,r){var e,u,i,a,o,c=function(){var l=j.now()-a;t>l?e=setTimeout(c,t-l):(e=null,r||(o=n.apply(i,u),i=u=null))};return function(){i=this,u=arguments,a=j.now();var l=r&&!e;return e||(e=setTimeout(c,t)),l&&(o=n.apply(i,u),i=u=null),o}},j.once=function(n){var t,r=!1;return function(){return r?t:(r=!0,t=n.apply(this,arguments),n=null,t)}},j.wrap=function(n,t){return j.partial(t,n)},j.compose=function(){var n=arguments;return function(){for(var t=arguments,r=n.length-1;r>=0;r--)t=[n[r].apply(this,t)];return t[0]}},j.after=function(n,t){return function(){return--n<1?t.apply(this,arguments):void 0}},j.keys=function(n){if(!j.isObject(n))return[];if(w)return w(n);var t=[];for(var r in n)j.has(n,r)&&t.push(r);return t},j.values=function(n){for(var t=j.keys(n),r=t.length,e=new Array(r),u=0;r>u;u++)e[u]=n[t[u]];return e},j.pairs=function(n){for(var t=j.keys(n),r=t.length,e=new Array(r),u=0;r>u;u++)e[u]=[t[u],n[t[u]]];return e},j.invert=function(n){for(var t={},r=j.keys(n),e=0,u=r.length;u>e;e++)t[n[r[e]]]=r[e];return t},j.functions=j.methods=function(n){var t=[];for(var r in n)j.isFunction(n[r])&&t.push(r);return t.sort()},j.extend=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)n[r]=t[r]}),n},j.pick=function(n){var t={},r=c.apply(e,o.call(arguments,1));return A(r,function(r){r in n&&(t[r]=n[r])}),t},j.omit=function(n){var t={},r=c.apply(e,o.call(arguments,1));for(var u in n)j.contains(r,u)||(t[u]=n[u]);return t},j.defaults=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)n[r]===void 0&&(n[r]=t[r])}),n},j.clone=function(n){return j.isObject(n)?j.isArray(n)?n.slice():j.extend({},n):n},j.tap=function(n,t){return t(n),n};var S=function(n,t,r,e){if(n===t)return 0!==n||1/n==1/t;if(null==n||null==t)return n===t;n instanceof j&&(n=n._wrapped),t instanceof j&&(t=t._wrapped);var u=l.call(n);if(u!=l.call(t))return!1;switch(u){case"[object String]":return n==String(t);case"[object Number]":return n!=+n?t!=+t:0==n?1/n==1/t:n==+t;case"[object Date]":case"[object Boolean]":return+n==+t;case"[object RegExp]":return n.source==t.source&&n.global==t.global&&n.multiline==t.multiline&&n.ignoreCase==t.ignoreCase}if("object"!=typeof n||"object"!=typeof t)return!1;for(var i=r.length;i--;)if(r[i]==n)return e[i]==t;var a=n.constructor,o=t.constructor;if(a!==o&&!(j.isFunction(a)&&a instanceof a&&j.isFunction(o)&&o instanceof o)&&"constructor"in n&&"constructor"in t)return!1;r.push(n),e.push(t);var c=0,f=!0;if("[object Array]"==u){if(c=n.length,f=c==t.length)for(;c--&&(f=S(n[c],t[c],r,e)););}else{for(var s in n)if(j.has(n,s)&&(c++,!(f=j.has(t,s)&&S(n[s],t[s],r,e))))break;if(f){for(s in t)if(j.has(t,s)&&!c--)break;f=!c}}return r.pop(),e.pop(),f};j.isEqual=function(n,t){return S(n,t,[],[])},j.isEmpty=function(n){if(null==n)return!0;if(j.isArray(n)||j.isString(n))return 0===n.length;for(var t in n)if(j.has(n,t))return!1;return!0},j.isElement=function(n){return!(!n||1!==n.nodeType)},j.isArray=x||function(n){return"[object Array]"==l.call(n)},j.isObject=function(n){return n===Object(n)},A(["Arguments","Function","String","Number","Date","RegExp"],function(n){j["is"+n]=function(t){return l.call(t)=="[object "+n+"]"}}),j.isArguments(arguments)||(j.isArguments=function(n){return!(!n||!j.has(n,"callee"))}),"function"!=typeof/./&&(j.isFunction=function(n){return"function"==typeof n}),j.isFinite=function(n){return isFinite(n)&&!isNaN(parseFloat(n))},j.isNaN=function(n){return j.isNumber(n)&&n!=+n},j.isBoolean=function(n){return n===!0||n===!1||"[object Boolean]"==l.call(n)},j.isNull=function(n){return null===n},j.isUndefined=function(n){return n===void 0},j.has=function(n,t){return f.call(n,t)},j.noConflict=function(){return n._=t,this},j.identity=function(n){return n},j.constant=function(n){return function(){return n}},j.property=function(n){return function(t){return t[n]}},j.matches=function(n){return function(t){if(t===n)return!0;for(var r in n)if(n[r]!==t[r])return!1;return!0}},j.times=function(n,t,r){for(var e=Array(Math.max(0,n)),u=0;n>u;u++)e[u]=t.call(r,u);return e},j.random=function(n,t){return null==t&&(t=n,n=0),n+Math.floor(Math.random()*(t-n+1))},j.now=Date.now||function(){return(new Date).getTime()};var T={escape:{"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#x27;"}};T.unescape=j.invert(T.escape);var I={escape:new RegExp("["+j.keys(T.escape).join("")+"]","g"),unescape:new RegExp("("+j.keys(T.unescape).join("|")+")","g")};j.each(["escape","unescape"],function(n){j[n]=function(t){return null==t?"":(""+t).replace(I[n],function(t){return T[n][t]})}}),j.result=function(n,t){if(null==n)return void 0;var r=n[t];return j.isFunction(r)?r.call(n):r},j.mixin=function(n){A(j.functions(n),function(t){var r=j[t]=n[t];j.prototype[t]=function(){var n=[this._wrapped];return a.apply(n,arguments),z.call(this,r.apply(j,n))}})};var N=0;j.uniqueId=function(n){var t=++N+"";return n?n+t:t},j.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var q=/(.)^/,B={"'":"'","\\":"\\","\r":"r","\n":"n","	":"t","\u2028":"u2028","\u2029":"u2029"},D=/\\|'|\r|\n|\t|\u2028|\u2029/g;j.template=function(n,t,r){var e;r=j.defaults({},r,j.templateSettings);var u=new RegExp([(r.escape||q).source,(r.interpolate||q).source,(r.evaluate||q).source].join("|")+"|$","g"),i=0,a="__p+='";n.replace(u,function(t,r,e,u,o){return a+=n.slice(i,o).replace(D,function(n){return"\\"+B[n]}),r&&(a+="'+\n((__t=("+r+"))==null?'':_.escape(__t))+\n'"),e&&(a+="'+\n((__t=("+e+"))==null?'':__t)+\n'"),u&&(a+="';\n"+u+"\n__p+='"),i=o+t.length,t}),a+="';\n",r.variable||(a="with(obj||{}){\n"+a+"}\n"),a="var __t,__p='',__j=Array.prototype.join,"+"print=function(){__p+=__j.call(arguments,'');};\n"+a+"return __p;\n";try{e=new Function(r.variable||"obj","_",a)}catch(o){throw o.source=a,o}if(t)return e(t,j);var c=function(n){return e.call(this,n,j)};return c.source="function("+(r.variable||"obj")+"){\n"+a+"}",c},j.chain=function(n){return j(n).chain()};var z=function(n){return this._chain?j(n).chain():n};j.mixin(j),A(["pop","push","reverse","shift","sort","splice","unshift"],function(n){var t=e[n];j.prototype[n]=function(){var r=this._wrapped;return t.apply(r,arguments),"shift"!=n&&"splice"!=n||0!==r.length||delete r[0],z.call(this,r)}}),A(["concat","join","slice"],function(n){var t=e[n];j.prototype[n]=function(){return z.call(this,t.apply(this._wrapped,arguments))}}),j.extend(j.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}}),"function"==typeof define&&define.amd&&define("underscore",[],function(){return j})}).call(this);
+//# sourceMappingURL=underscore-min.map
\ No newline at end of file
diff --git a/xos/core/xoslib/static/js/vendor/xosCeilometerDashboardVendor.js b/xos/core/xoslib/static/js/vendor/xosCeilometerDashboardVendor.js
new file mode 100644
index 0000000..8beb09e
--- /dev/null
+++ b/xos/core/xoslib/static/js/vendor/xosCeilometerDashboardVendor.js
@@ -0,0 +1,3 @@
+(function(){"use strict";var t=this,e=t.Chart,i=function(t){this.canvas=t.canvas,this.ctx=t;var e=function(t,e){return t["offset"+e]?t["offset"+e]:document.defaultView.getComputedStyle(t).getPropertyValue(e)},i=this.width=e(t.canvas,"Width"),s=this.height=e(t.canvas,"Height");t.canvas.width=i,t.canvas.height=s;var i=this.width=t.canvas.width,s=this.height=t.canvas.height;return this.aspectRatio=this.width/this.height,n.retinaScale(this),this};i.defaults={global:{animation:!0,animationSteps:60,animationEasing:"easeOutQuart",showScale:!0,scaleOverride:!1,scaleSteps:null,scaleStepWidth:null,scaleStartValue:null,scaleLineColor:"rgba(0,0,0,.1)",scaleLineWidth:1,scaleShowLabels:!0,scaleLabel:"<%=value%>",scaleIntegersOnly:!0,scaleBeginAtZero:!1,scaleFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",scaleFontSize:12,scaleFontStyle:"normal",scaleFontColor:"#666",responsive:!1,maintainAspectRatio:!0,showTooltips:!0,customTooltips:!1,tooltipEvents:["mousemove","touchstart","touchmove","mouseout"],tooltipFillColor:"rgba(0,0,0,0.8)",tooltipFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",tooltipFontSize:14,tooltipFontStyle:"normal",tooltipFontColor:"#fff",tooltipTitleFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",tooltipTitleFontSize:14,tooltipTitleFontStyle:"bold",tooltipTitleFontColor:"#fff",tooltipYPadding:6,tooltipXPadding:6,tooltipCaretSize:8,tooltipCornerRadius:6,tooltipXOffset:10,tooltipTemplate:"<%if (label){%><%=label%>: <%}%><%= value %>",multiTooltipTemplate:"<%= value %>",multiTooltipKeyBackground:"#fff",onAnimationProgress:function(){},onAnimationComplete:function(){}}},i.types={};var n=i.helpers={},s=n.each=function(t,e,i){var n=Array.prototype.slice.call(arguments,3);if(t)if(t.length===+t.length){var s;for(s=0;s<t.length;s++)e.apply(i,[t[s],s].concat(n))}else for(var o in t)e.apply(i,[t[o],o].concat(n))},o=n.clone=function(t){var e={};return s(t,function(i,n){t.hasOwnProperty(n)&&(e[n]=i)}),e},a=n.extend=function(t){return s(Array.prototype.slice.call(arguments,1),function(e){s(e,function(i,n){e.hasOwnProperty(n)&&(t[n]=i)})}),t},r=n.merge=function(t,e){var i=Array.prototype.slice.call(arguments,0);return i.unshift({}),a.apply(null,i)},l=n.indexOf=function(t,e){if(Array.prototype.indexOf)return t.indexOf(e);for(var i=0;i<t.length;i++)if(t[i]===e)return i;return-1},h=(n.where=function(t,e){var i=[];return n.each(t,function(t){e(t)&&i.push(t)}),i},n.findNextWhere=function(t,e,i){i||(i=-1);for(var n=i+1;n<t.length;n++){var s=t[n];if(e(s))return s}},n.findPreviousWhere=function(t,e,i){i||(i=t.length);for(var n=i-1;n>=0;n--){var s=t[n];if(e(s))return s}},n.inherits=function(t){var e=this,i=t&&t.hasOwnProperty("constructor")?t.constructor:function(){return e.apply(this,arguments)},n=function(){this.constructor=i};return n.prototype=e.prototype,i.prototype=new n,i.extend=h,t&&a(i.prototype,t),i.__super__=e.prototype,i}),c=n.noop=function(){},u=n.uid=function(){var t=0;return function(){return"chart-"+t++}}(),d=n.warn=function(t){window.console&&"function"==typeof window.console.warn&&console.warn(t)},f=n.amd="function"==typeof define&&define.amd,p=n.isNumber=function(t){return!isNaN(parseFloat(t))&&isFinite(t)},g=n.max=function(t){return Math.max.apply(Math,t)},v=n.min=function(t){return Math.min.apply(Math,t)},m=(n.cap=function(t,e,i){if(p(e)){if(t>e)return e}else if(p(i)&&i>t)return i;return t},n.getDecimalPlaces=function(t){return t%1!==0&&p(t)?t.toString().split(".")[1].length:0}),C=n.radians=function(t){return t*(Math.PI/180)},y=(n.getAngleFromPoint=function(t,e){var i=e.x-t.x,n=e.y-t.y,s=Math.sqrt(i*i+n*n),o=2*Math.PI+Math.atan2(n,i);return 0>i&&0>n&&(o+=2*Math.PI),{angle:o,distance:s}},n.aliasPixel=function(t){return t%2===0?0:.5}),b=(n.splineCurve=function(t,e,i,n){var s=Math.sqrt(Math.pow(e.x-t.x,2)+Math.pow(e.y-t.y,2)),o=Math.sqrt(Math.pow(i.x-e.x,2)+Math.pow(i.y-e.y,2)),a=n*s/(s+o),r=n*o/(s+o);return{inner:{x:e.x-a*(i.x-t.x),y:e.y-a*(i.y-t.y)},outer:{x:e.x+r*(i.x-t.x),y:e.y+r*(i.y-t.y)}}},n.calculateOrderOfMagnitude=function(t){return Math.floor(Math.log(t)/Math.LN10)}),w=(n.calculateScaleRange=function(t,e,i,n,s){var o=2,a=Math.floor(e/(1.5*i)),r=o>=a,l=g(t),h=v(t);l===h&&(l+=.5,h>=.5&&!n?h-=.5:l+=.5);for(var c=Math.abs(l-h),u=b(c),d=Math.ceil(l/(1*Math.pow(10,u)))*Math.pow(10,u),f=n?0:Math.floor(h/(1*Math.pow(10,u)))*Math.pow(10,u),p=d-f,m=Math.pow(10,u),C=Math.round(p/m);(C>a||a>2*C)&&!r;)if(C>a)m*=2,C=Math.round(p/m),C%1!==0&&(r=!0);else if(s&&u>=0){if(m/2%1!==0)break;m/=2,C=Math.round(p/m)}else m/=2,C=Math.round(p/m);return r&&(C=o,m=p/C),{steps:C,stepValue:m,min:f,max:f+C*m}},n.template=function(t,e){function i(t,e){var i=/\W/.test(t)?new Function("obj","var p=[],print=function(){p.push.apply(p,arguments);};with(obj){p.push('"+t.replace(/[\r\t\n]/g," ").split("<%").join("	").replace(/((^|%>)[^\t]*)'/g,"$1\r").replace(/\t=(.*?)%>/g,"',$1,'").split("	").join("');").split("%>").join("p.push('").split("\r").join("\\'")+"');}return p.join('');"):n[t]=n[t];return e?i(e):i}if(t instanceof Function)return t(e);var n={};return i(t,e)}),x=(n.generateLabels=function(t,e,i,n){var o=new Array(e);return labelTemplateString&&s(o,function(e,s){o[s]=w(t,{value:i+n*(s+1)})}),o},n.easingEffects={linear:function(t){return t},easeInQuad:function(t){return t*t},easeOutQuad:function(t){return-1*t*(t-2)},easeInOutQuad:function(t){return(t/=.5)<1?.5*t*t:-0.5*(--t*(t-2)-1)},easeInCubic:function(t){return t*t*t},easeOutCubic:function(t){return 1*((t=t/1-1)*t*t+1)},easeInOutCubic:function(t){return(t/=.5)<1?.5*t*t*t:.5*((t-=2)*t*t+2)},easeInQuart:function(t){return t*t*t*t},easeOutQuart:function(t){return-1*((t=t/1-1)*t*t*t-1)},easeInOutQuart:function(t){return(t/=.5)<1?.5*t*t*t*t:-0.5*((t-=2)*t*t*t-2)},easeInQuint:function(t){return 1*(t/=1)*t*t*t*t},easeOutQuint:function(t){return 1*((t=t/1-1)*t*t*t*t+1)},easeInOutQuint:function(t){return(t/=.5)<1?.5*t*t*t*t*t:.5*((t-=2)*t*t*t*t+2)},easeInSine:function(t){return-1*Math.cos(t/1*(Math.PI/2))+1},easeOutSine:function(t){return 1*Math.sin(t/1*(Math.PI/2))},easeInOutSine:function(t){return-0.5*(Math.cos(Math.PI*t/1)-1)},easeInExpo:function(t){return 0===t?1:1*Math.pow(2,10*(t/1-1))},easeOutExpo:function(t){return 1===t?1:1*(-Math.pow(2,-10*t/1)+1)},easeInOutExpo:function(t){return 0===t?0:1===t?1:(t/=.5)<1?.5*Math.pow(2,10*(t-1)):.5*(-Math.pow(2,-10*--t)+2)},easeInCirc:function(t){return t>=1?t:-1*(Math.sqrt(1-(t/=1)*t)-1)},easeOutCirc:function(t){return 1*Math.sqrt(1-(t=t/1-1)*t)},easeInOutCirc:function(t){return(t/=.5)<1?-0.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1)},easeInElastic:function(t){var e=1.70158,i=0,n=1;return 0===t?0:1==(t/=1)?1:(i||(i=.3),n<Math.abs(1)?(n=1,e=i/4):e=i/(2*Math.PI)*Math.asin(1/n),-(n*Math.pow(2,10*(t-=1))*Math.sin((1*t-e)*(2*Math.PI)/i)))},easeOutElastic:function(t){var e=1.70158,i=0,n=1;return 0===t?0:1==(t/=1)?1:(i||(i=.3),n<Math.abs(1)?(n=1,e=i/4):e=i/(2*Math.PI)*Math.asin(1/n),n*Math.pow(2,-10*t)*Math.sin((1*t-e)*(2*Math.PI)/i)+1)},easeInOutElastic:function(t){var e=1.70158,i=0,n=1;return 0===t?0:2==(t/=.5)?1:(i||(i=1*(.3*1.5)),n<Math.abs(1)?(n=1,e=i/4):e=i/(2*Math.PI)*Math.asin(1/n),1>t?-.5*(n*Math.pow(2,10*(t-=1))*Math.sin((1*t-e)*(2*Math.PI)/i)):n*Math.pow(2,-10*(t-=1))*Math.sin((1*t-e)*(2*Math.PI)/i)*.5+1)},easeInBack:function(t){var e=1.70158;return 1*(t/=1)*t*((e+1)*t-e)},easeOutBack:function(t){var e=1.70158;return 1*((t=t/1-1)*t*((e+1)*t+e)+1)},easeInOutBack:function(t){var e=1.70158;return(t/=.5)<1?.5*(t*t*(((e*=1.525)+1)*t-e)):.5*((t-=2)*t*(((e*=1.525)+1)*t+e)+2)},easeInBounce:function(t){return 1-x.easeOutBounce(1-t)},easeOutBounce:function(t){return(t/=1)<1/2.75?1*(7.5625*t*t):2/2.75>t?1*(7.5625*(t-=1.5/2.75)*t+.75):2.5/2.75>t?1*(7.5625*(t-=2.25/2.75)*t+.9375):1*(7.5625*(t-=2.625/2.75)*t+.984375)},easeInOutBounce:function(t){return.5>t?.5*x.easeInBounce(2*t):.5*x.easeOutBounce(2*t-1)+.5}}),S=n.requestAnimFrame=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(t){return window.setTimeout(t,1e3/60)}}(),P=n.cancelAnimFrame=function(){return window.cancelAnimationFrame||window.webkitCancelAnimationFrame||window.mozCancelAnimationFrame||window.oCancelAnimationFrame||window.msCancelAnimationFrame||function(t){return window.clearTimeout(t,1e3/60)}}(),k=(n.animationLoop=function(t,e,i,n,s,o){var a=0,r=x[i]||x.linear,l=function(){a++;var i=a/e,h=r(i);t.call(o,h,i,a),n.call(o,h,i),e>a?o.animationFrame=S(l):s.apply(o)};S(l)},n.getRelativePosition=function(t){var e,i,n=t.originalEvent||t,s=t.currentTarget||t.srcElement,o=s.getBoundingClientRect();return n.touches?(e=n.touches[0].clientX-o.left,i=n.touches[0].clientY-o.top):(e=n.clientX-o.left,i=n.clientY-o.top),{x:e,y:i}},n.addEvent=function(t,e,i){t.addEventListener?t.addEventListener(e,i):t.attachEvent?t.attachEvent("on"+e,i):t["on"+e]=i}),A=n.removeEvent=function(t,e,i){t.removeEventListener?t.removeEventListener(e,i,!1):t.detachEvent?t.detachEvent("on"+e,i):t["on"+e]=c},L=(n.bindEvents=function(t,e,i){t.events||(t.events={}),s(e,function(e){t.events[e]=function(){i.apply(t,arguments)},k(t.chart.canvas,e,t.events[e])})},n.unbindEvents=function(t,e){s(e,function(e,i){A(t.chart.canvas,i,e)})}),$=n.getMaximumWidth=function(t){var e=t.parentNode;return e.clientWidth},F=n.getMaximumHeight=function(t){var e=t.parentNode;return e.clientHeight},T=(n.getMaximumSize=n.getMaximumWidth,n.retinaScale=function(t){var e=t.ctx,i=t.canvas.width,n=t.canvas.height;window.devicePixelRatio&&(e.canvas.style.width=i+"px",e.canvas.style.height=n+"px",e.canvas.height=n*window.devicePixelRatio,e.canvas.width=i*window.devicePixelRatio,e.scale(window.devicePixelRatio,window.devicePixelRatio))}),R=n.clear=function(t){t.ctx.clearRect(0,0,t.width,t.height)},D=n.fontString=function(t,e,i){return e+" "+t+"px "+i},M=n.longestText=function(t,e,i){t.font=e;var n=0;return s(i,function(e){var i=t.measureText(e).width;n=i>n?i:n}),n},W=n.drawRoundedRectangle=function(t,e,i,n,s,o){t.beginPath(),t.moveTo(e+o,i),t.lineTo(e+n-o,i),t.quadraticCurveTo(e+n,i,e+n,i+o),t.lineTo(e+n,i+s-o),t.quadraticCurveTo(e+n,i+s,e+n-o,i+s),t.lineTo(e+o,i+s),t.quadraticCurveTo(e,i+s,e,i+s-o),t.lineTo(e,i+o),t.quadraticCurveTo(e,i,e+o,i),t.closePath()};i.instances={},i.Type=function(t,e,n){this.options=e,this.chart=n,this.id=u(),i.instances[this.id]=this,e.responsive&&this.resize(),this.initialize.call(this,t)},a(i.Type.prototype,{initialize:function(){return this},clear:function(){return R(this.chart),this},stop:function(){return P(this.animationFrame),this},resize:function(t){this.stop();var e=this.chart.canvas,i=$(this.chart.canvas),n=this.options.maintainAspectRatio?i/this.chart.aspectRatio:F(this.chart.canvas);return e.width=this.chart.width=i,e.height=this.chart.height=n,T(this.chart),"function"==typeof t&&t.apply(this,Array.prototype.slice.call(arguments,1)),this},reflow:c,render:function(t){return t&&this.reflow(),this.options.animation&&!t?n.animationLoop(this.draw,this.options.animationSteps,this.options.animationEasing,this.options.onAnimationProgress,this.options.onAnimationComplete,this):(this.draw(),this.options.onAnimationComplete.call(this)),this},generateLegend:function(){return w(this.options.legendTemplate,this)},destroy:function(){this.clear(),L(this,this.events);var t=this.chart.canvas;t.width=this.chart.width,t.height=this.chart.height,t.style.removeProperty?(t.style.removeProperty("width"),t.style.removeProperty("height")):(t.style.removeAttribute("width"),t.style.removeAttribute("height")),delete i.instances[this.id]},showTooltip:function(t,e){"undefined"==typeof this.activeElements&&(this.activeElements=[]);var o=function(t){var e=!1;return t.length!==this.activeElements.length?e=!0:(s(t,function(t,i){t!==this.activeElements[i]&&(e=!0)},this),e)}.call(this,t);if(o||e){if(this.activeElements=t,this.draw(),this.options.customTooltips&&this.options.customTooltips(!1),t.length>0)if(this.datasets&&this.datasets.length>1){for(var a,r,h=this.datasets.length-1;h>=0&&(a=this.datasets[h].points||this.datasets[h].bars||this.datasets[h].segments,r=l(a,t[0]),-1===r);h--);var c=[],u=[],d=function(t){var e,i,s,o,a,l=[],h=[],d=[];return n.each(this.datasets,function(t){e=t.points||t.bars||t.segments,e[r]&&e[r].hasValue()&&l.push(e[r])}),n.each(l,function(t){h.push(t.x),d.push(t.y),c.push(n.template(this.options.multiTooltipTemplate,t)),u.push({fill:t._saved.fillColor||t.fillColor,stroke:t._saved.strokeColor||t.strokeColor})},this),a=v(d),s=g(d),o=v(h),i=g(h),{x:o>this.chart.width/2?o:i,y:(a+s)/2}}.call(this,r);new i.MultiTooltip({x:d.x,y:d.y,xPadding:this.options.tooltipXPadding,yPadding:this.options.tooltipYPadding,xOffset:this.options.tooltipXOffset,fillColor:this.options.tooltipFillColor,textColor:this.options.tooltipFontColor,fontFamily:this.options.tooltipFontFamily,fontStyle:this.options.tooltipFontStyle,fontSize:this.options.tooltipFontSize,titleTextColor:this.options.tooltipTitleFontColor,titleFontFamily:this.options.tooltipTitleFontFamily,titleFontStyle:this.options.tooltipTitleFontStyle,titleFontSize:this.options.tooltipTitleFontSize,cornerRadius:this.options.tooltipCornerRadius,labels:c,legendColors:u,legendColorBackground:this.options.multiTooltipKeyBackground,title:t[0].label,chart:this.chart,ctx:this.chart.ctx,custom:this.options.customTooltips}).draw()}else s(t,function(t){var e=t.tooltipPosition();new i.Tooltip({x:Math.round(e.x),y:Math.round(e.y),xPadding:this.options.tooltipXPadding,yPadding:this.options.tooltipYPadding,fillColor:this.options.tooltipFillColor,textColor:this.options.tooltipFontColor,fontFamily:this.options.tooltipFontFamily,fontStyle:this.options.tooltipFontStyle,fontSize:this.options.tooltipFontSize,caretHeight:this.options.tooltipCaretSize,cornerRadius:this.options.tooltipCornerRadius,text:w(this.options.tooltipTemplate,t),chart:this.chart,custom:this.options.customTooltips}).draw()},this);return this}},toBase64Image:function(){return this.chart.canvas.toDataURL.apply(this.chart.canvas,arguments)}}),i.Type.extend=function(t){var e=this,n=function(){return e.apply(this,arguments)};if(n.prototype=o(e.prototype),a(n.prototype,t),n.extend=i.Type.extend,t.name||e.prototype.name){var s=t.name||e.prototype.name,l=i.defaults[e.prototype.name]?o(i.defaults[e.prototype.name]):{};i.defaults[s]=a(l,t.defaults),i.types[s]=n,i.prototype[s]=function(t,e){var o=r(i.defaults.global,i.defaults[s],e||{});return new n(t,o,this)}}else d("Name not provided for this chart, so it hasn't been registered");return e},i.Element=function(t){a(this,t),this.initialize.apply(this,arguments),this.save()},a(i.Element.prototype,{initialize:function(){},restore:function(t){return t?s(t,function(t){this[t]=this._saved[t]},this):a(this,this._saved),this},save:function(){return this._saved=o(this),delete this._saved._saved,this},update:function(t){return s(t,function(t,e){this._saved[e]=this[e],this[e]=t},this),this},transition:function(t,e){return s(t,function(t,i){this[i]=(t-this._saved[i])*e+this._saved[i]},this),this},tooltipPosition:function(){return{x:this.x,y:this.y}},hasValue:function(){return p(this.value)}}),i.Element.extend=h,i.Point=i.Element.extend({display:!0,inRange:function(t,e){var i=this.hitDetectionRadius+this.radius;return Math.pow(t-this.x,2)+Math.pow(e-this.y,2)<Math.pow(i,2)},draw:function(){if(this.display){var t=this.ctx;t.beginPath(),t.arc(this.x,this.y,this.radius,0,2*Math.PI),t.closePath(),t.strokeStyle=this.strokeColor,t.lineWidth=this.strokeWidth,t.fillStyle=this.fillColor,t.fill(),t.stroke()}}}),i.Arc=i.Element.extend({inRange:function(t,e){var i=n.getAngleFromPoint(this,{x:t,y:e}),s=i.angle>=this.startAngle&&i.angle<=this.endAngle,o=i.distance>=this.innerRadius&&i.distance<=this.outerRadius;return s&&o},tooltipPosition:function(){var t=this.startAngle+(this.endAngle-this.startAngle)/2,e=(this.outerRadius-this.innerRadius)/2+this.innerRadius;return{x:this.x+Math.cos(t)*e,y:this.y+Math.sin(t)*e}},draw:function(t){var e=this.ctx;e.beginPath(),e.arc(this.x,this.y,this.outerRadius,this.startAngle,this.endAngle),e.arc(this.x,this.y,this.innerRadius,this.endAngle,this.startAngle,!0),e.closePath(),e.strokeStyle=this.strokeColor,e.lineWidth=this.strokeWidth,e.fillStyle=this.fillColor,e.fill(),e.lineJoin="bevel",this.showStroke&&e.stroke()}}),i.Rectangle=i.Element.extend({draw:function(){var t=this.ctx,e=this.width/2,i=this.x-e,n=this.x+e,s=this.base-(this.base-this.y),o=this.strokeWidth/2;this.showStroke&&(i+=o,n-=o,s+=o),t.beginPath(),t.fillStyle=this.fillColor,t.strokeStyle=this.strokeColor,t.lineWidth=this.strokeWidth,t.moveTo(i,this.base),t.lineTo(i,s),t.lineTo(n,s),t.lineTo(n,this.base),t.fill(),this.showStroke&&t.stroke()},height:function(){return this.base-this.y},inRange:function(t,e){return t>=this.x-this.width/2&&t<=this.x+this.width/2&&e>=this.y&&e<=this.base}}),i.Tooltip=i.Element.extend({draw:function(){var t=this.chart.ctx;t.font=D(this.fontSize,this.fontStyle,this.fontFamily),this.xAlign="center",this.yAlign="above";var e=this.caretPadding=2,i=t.measureText(this.text).width+2*this.xPadding,n=this.fontSize+2*this.yPadding,s=n+this.caretHeight+e;this.x+i/2>this.chart.width?this.xAlign="left":this.x-i/2<0&&(this.xAlign="right"),this.y-s<0&&(this.yAlign="below");var o=this.x-i/2,a=this.y-s;if(t.fillStyle=this.fillColor,this.custom)this.custom(this);else{switch(this.yAlign){case"above":t.beginPath(),t.moveTo(this.x,this.y-e),t.lineTo(this.x+this.caretHeight,this.y-(e+this.caretHeight)),t.lineTo(this.x-this.caretHeight,this.y-(e+this.caretHeight)),t.closePath(),t.fill();break;case"below":a=this.y+e+this.caretHeight,t.beginPath(),t.moveTo(this.x,this.y+e),t.lineTo(this.x+this.caretHeight,this.y+e+this.caretHeight),t.lineTo(this.x-this.caretHeight,this.y+e+this.caretHeight),t.closePath(),t.fill()}switch(this.xAlign){case"left":o=this.x-i+(this.cornerRadius+this.caretHeight);break;case"right":o=this.x-(this.cornerRadius+this.caretHeight)}W(t,o,a,i,n,this.cornerRadius),t.fill(),t.fillStyle=this.textColor,t.textAlign="center",t.textBaseline="middle",t.fillText(this.text,o+i/2,a+n/2)}}}),i.MultiTooltip=i.Element.extend({initialize:function(){this.font=D(this.fontSize,this.fontStyle,this.fontFamily),this.titleFont=D(this.titleFontSize,this.titleFontStyle,this.titleFontFamily),this.height=this.labels.length*this.fontSize+(this.labels.length-1)*(this.fontSize/2)+2*this.yPadding+1.5*this.titleFontSize,this.ctx.font=this.titleFont;var t=this.ctx.measureText(this.title).width,e=M(this.ctx,this.font,this.labels)+this.fontSize+3,i=g([e,t]);this.width=i+2*this.xPadding;var n=this.height/2;this.y-n<0?this.y=n:this.y+n>this.chart.height&&(this.y=this.chart.height-n),this.x>this.chart.width/2?this.x-=this.xOffset+this.width:this.x+=this.xOffset},getLineHeight:function(t){var e=this.y-this.height/2+this.yPadding,i=t-1;return 0===t?e+this.titleFontSize/2:e+(1.5*this.fontSize*i+this.fontSize/2)+1.5*this.titleFontSize},draw:function(){if(this.custom)this.custom(this);else{W(this.ctx,this.x,this.y-this.height/2,this.width,this.height,this.cornerRadius);var t=this.ctx;t.fillStyle=this.fillColor,t.fill(),t.closePath(),t.textAlign="left",t.textBaseline="middle",t.fillStyle=this.titleTextColor,t.font=this.titleFont,t.fillText(this.title,this.x+this.xPadding,this.getLineHeight(0)),t.font=this.font,n.each(this.labels,function(e,i){t.fillStyle=this.textColor,t.fillText(e,this.x+this.xPadding+this.fontSize+3,this.getLineHeight(i+1)),t.fillStyle=this.legendColorBackground,t.fillRect(this.x+this.xPadding,this.getLineHeight(i+1)-this.fontSize/2,this.fontSize,this.fontSize),t.fillStyle=this.legendColors[i].fill,t.fillRect(this.x+this.xPadding,this.getLineHeight(i+1)-this.fontSize/2,this.fontSize,this.fontSize)},this)}}}),i.Scale=i.Element.extend({initialize:function(){this.fit()},buildYLabels:function(){this.yLabels=[];for(var t=m(this.stepValue),e=0;e<=this.steps;e++)this.yLabels.push(w(this.templateString,{value:(this.min+e*this.stepValue).toFixed(t)}));this.yLabelWidth=this.display&&this.showLabels?M(this.ctx,this.font,this.yLabels):0},addXLabel:function(t){this.xLabels.push(t),this.valuesCount++,this.fit()},removeXLabel:function(){this.xLabels.shift(),this.valuesCount--,this.fit()},fit:function(){this.startPoint=this.display?this.fontSize:0,this.endPoint=this.display?this.height-1.5*this.fontSize-5:this.height,this.startPoint+=this.padding,this.endPoint-=this.padding;var t,e=this.endPoint-this.startPoint;for(this.calculateYRange(e),this.buildYLabels(),this.calculateXLabelRotation();e>this.endPoint-this.startPoint;)e=this.endPoint-this.startPoint,t=this.yLabelWidth,this.calculateYRange(e),this.buildYLabels(),t<this.yLabelWidth&&this.calculateXLabelRotation()},calculateXLabelRotation:function(){this.ctx.font=this.font;var t,e,i=this.ctx.measureText(this.xLabels[0]).width,n=this.ctx.measureText(this.xLabels[this.xLabels.length-1]).width;if(this.xScalePaddingRight=n/2+3,this.xScalePaddingLeft=i/2>this.yLabelWidth+10?i/2:this.yLabelWidth+10,this.xLabelRotation=0,this.display){var s,o=M(this.ctx,this.font,this.xLabels);this.xLabelWidth=o;for(var a=Math.floor(this.calculateX(1)-this.calculateX(0))-6;this.xLabelWidth>a&&0===this.xLabelRotation||this.xLabelWidth>a&&this.xLabelRotation<=90&&this.xLabelRotation>0;)s=Math.cos(C(this.xLabelRotation)),t=s*i,e=s*n,t+this.fontSize/2>this.yLabelWidth+8&&(this.xScalePaddingLeft=t+this.fontSize/2),this.xScalePaddingRight=this.fontSize/2,this.xLabelRotation++,this.xLabelWidth=s*o;this.xLabelRotation>0&&(this.endPoint-=Math.sin(C(this.xLabelRotation))*o+3)}else this.xLabelWidth=0,this.xScalePaddingRight=this.padding,this.xScalePaddingLeft=this.padding},calculateYRange:c,drawingArea:function(){return this.startPoint-this.endPoint},calculateY:function(t){var e=this.drawingArea()/(this.min-this.max);return this.endPoint-e*(t-this.min)},calculateX:function(t){var e=(this.xLabelRotation>0,this.width-(this.xScalePaddingLeft+this.xScalePaddingRight)),i=e/Math.max(this.valuesCount-(this.offsetGridLines?0:1),1),n=i*t+this.xScalePaddingLeft;return this.offsetGridLines&&(n+=i/2),Math.round(n)},update:function(t){n.extend(this,t),this.fit()},draw:function(){var t=this.ctx,e=(this.endPoint-this.startPoint)/this.steps,i=Math.round(this.xScalePaddingLeft);this.display&&(t.fillStyle=this.textColor,t.font=this.font,s(this.yLabels,function(s,o){var a=this.endPoint-e*o,r=Math.round(a),l=this.showHorizontalLines;t.textAlign="right",t.textBaseline="middle",this.showLabels&&t.fillText(s,i-10,a),0!==o||l||(l=!0),l&&t.beginPath(),o>0?(t.lineWidth=this.gridLineWidth,t.strokeStyle=this.gridLineColor):(t.lineWidth=this.lineWidth,t.strokeStyle=this.lineColor),r+=n.aliasPixel(t.lineWidth),l&&(t.moveTo(i,r),t.lineTo(this.width,r),t.stroke(),t.closePath()),t.lineWidth=this.lineWidth,t.strokeStyle=this.lineColor,t.beginPath(),t.moveTo(i-5,r),t.lineTo(i,r),t.stroke(),t.closePath()},this),s(this.xLabels,function(e,i){var n=this.calculateX(i)+y(this.lineWidth),s=this.calculateX(i-(this.offsetGridLines?.5:0))+y(this.lineWidth),o=this.xLabelRotation>0,a=this.showVerticalLines;0!==i||a||(a=!0),a&&t.beginPath(),i>0?(t.lineWidth=this.gridLineWidth,t.strokeStyle=this.gridLineColor):(t.lineWidth=this.lineWidth,t.strokeStyle=this.lineColor),a&&(t.moveTo(s,this.endPoint),t.lineTo(s,this.startPoint-3),t.stroke(),t.closePath()),t.lineWidth=this.lineWidth,t.strokeStyle=this.lineColor,t.beginPath(),t.moveTo(s,this.endPoint),t.lineTo(s,this.endPoint+5),t.stroke(),t.closePath(),t.save(),t.translate(n,o?this.endPoint+12:this.endPoint+8),t.rotate(-1*C(this.xLabelRotation)),t.font=this.font,t.textAlign=o?"right":"center",t.textBaseline=o?"middle":"top",t.fillText(e,0,0),t.restore()},this))}}),i.RadialScale=i.Element.extend({initialize:function(){this.size=v([this.height,this.width]),this.drawingArea=this.display?this.size/2-(this.fontSize/2+this.backdropPaddingY):this.size/2},calculateCenterOffset:function(t){var e=this.drawingArea/(this.max-this.min);return(t-this.min)*e},update:function(){this.lineArc?this.drawingArea=this.display?this.size/2-(this.fontSize/2+this.backdropPaddingY):this.size/2:this.setScaleSize(),this.buildYLabels()},buildYLabels:function(){this.yLabels=[];for(var t=m(this.stepValue),e=0;e<=this.steps;e++)this.yLabels.push(w(this.templateString,{value:(this.min+e*this.stepValue).toFixed(t)}))},getCircumference:function(){return 2*Math.PI/this.valuesCount},setScaleSize:function(){var t,e,i,n,s,o,a,r,l,h,c,u,d=v([this.height/2-this.pointLabelFontSize-5,this.width/2]),f=this.width,g=0;for(this.ctx.font=D(this.pointLabelFontSize,this.pointLabelFontStyle,this.pointLabelFontFamily),e=0;e<this.valuesCount;e++)t=this.getPointPosition(e,d),i=this.ctx.measureText(w(this.templateString,{value:this.labels[e]})).width+5,0===e||e===this.valuesCount/2?(n=i/2,t.x+n>f&&(f=t.x+n,s=e),t.x-n<g&&(g=t.x-n,a=e)):e<this.valuesCount/2?t.x+i>f&&(f=t.x+i,s=e):e>this.valuesCount/2&&t.x-i<g&&(g=t.x-i,a=e);l=g,h=Math.ceil(f-this.width),o=this.getIndexAngle(s),r=this.getIndexAngle(a),c=h/Math.sin(o+Math.PI/2),u=l/Math.sin(r+Math.PI/2),c=p(c)?c:0,u=p(u)?u:0,this.drawingArea=d-(u+c)/2,this.setCenterPoint(u,c)},setCenterPoint:function(t,e){var i=this.width-e-this.drawingArea,n=t+this.drawingArea;this.xCenter=(n+i)/2,this.yCenter=this.height/2},getIndexAngle:function(t){var e=2*Math.PI/this.valuesCount;return t*e-Math.PI/2},getPointPosition:function(t,e){var i=this.getIndexAngle(t);return{x:Math.cos(i)*e+this.xCenter,y:Math.sin(i)*e+this.yCenter}},draw:function(){if(this.display){var t=this.ctx;if(s(this.yLabels,function(e,i){if(i>0){var n,s=i*(this.drawingArea/this.steps),o=this.yCenter-s;if(this.lineWidth>0)if(t.strokeStyle=this.lineColor,t.lineWidth=this.lineWidth,this.lineArc)t.beginPath(),t.arc(this.xCenter,this.yCenter,s,0,2*Math.PI),t.closePath(),t.stroke();else{t.beginPath();for(var a=0;a<this.valuesCount;a++)n=this.getPointPosition(a,this.calculateCenterOffset(this.min+i*this.stepValue)),0===a?t.moveTo(n.x,n.y):t.lineTo(n.x,n.y);t.closePath(),t.stroke()}if(this.showLabels){if(t.font=D(this.fontSize,this.fontStyle,this.fontFamily),this.showLabelBackdrop){var r=t.measureText(e).width;t.fillStyle=this.backdropColor,t.fillRect(this.xCenter-r/2-this.backdropPaddingX,o-this.fontSize/2-this.backdropPaddingY,r+2*this.backdropPaddingX,this.fontSize+2*this.backdropPaddingY)}t.textAlign="center",t.textBaseline="middle",t.fillStyle=this.fontColor,t.fillText(e,this.xCenter,o)}}},this),!this.lineArc){t.lineWidth=this.angleLineWidth,t.strokeStyle=this.angleLineColor;for(var e=this.valuesCount-1;e>=0;e--){if(this.angleLineWidth>0){var i=this.getPointPosition(e,this.calculateCenterOffset(this.max));t.beginPath(),t.moveTo(this.xCenter,this.yCenter),t.lineTo(i.x,i.y),t.stroke(),t.closePath()}var n=this.getPointPosition(e,this.calculateCenterOffset(this.max)+5);t.font=D(this.pointLabelFontSize,this.pointLabelFontStyle,this.pointLabelFontFamily),t.fillStyle=this.pointLabelFontColor;var o=this.labels.length,a=this.labels.length/2,r=a/2,l=r>e||e>o-r,h=e===r||e===o-r;0===e?t.textAlign="center":e===a?t.textAlign="center":a>e?t.textAlign="left":t.textAlign="right",h?t.textBaseline="middle":l?t.textBaseline="bottom":t.textBaseline="top",t.fillText(this.labels[e],n.x,n.y)}}}}}),n.addEvent(window,"resize",function(){var t;return function(){clearTimeout(t),t=setTimeout(function(){s(i.instances,function(t){t.options.responsive&&t.resize(t.render,!0)})},50)}}()),f?define(function(){return i}):"object"==typeof module&&module.exports&&(module.exports=i),t.Chart=i,i.noConflict=function(){return t.Chart=e,i}}).call(this),function(){"use strict";var t=this,e=t.Chart,i=e.helpers,n={scaleBeginAtZero:!0,scaleShowGridLines:!0,scaleGridLineColor:"rgba(0,0,0,.05)",scaleGridLineWidth:1,scaleShowHorizontalLines:!0,scaleShowVerticalLines:!0,barShowStroke:!0,barStrokeWidth:2,barValueSpacing:5,barDatasetSpacing:1,legendTemplate:'<ul class="<%=name.toLowerCase()%>-legend"><% for (var i=0; i<datasets.length; i++){%><li><span style="background-color:<%=datasets[i].fillColor%>"></span><%if(datasets[i].label){%><%=datasets[i].label%><%}%></li><%}%></ul>'};e.Type.extend({name:"Bar",defaults:n,initialize:function(t){var n=this.options;this.ScaleClass=e.Scale.extend({offsetGridLines:!0,calculateBarX:function(t,e,i){var s=this.calculateBaseWidth(),o=this.calculateX(i)-s/2,a=this.calculateBarWidth(t);return o+a*e+e*n.barDatasetSpacing+a/2},calculateBaseWidth:function(){return this.calculateX(1)-this.calculateX(0)-2*n.barValueSpacing},calculateBarWidth:function(t){var e=this.calculateBaseWidth()-(t-1)*n.barDatasetSpacing;return e/t}}),this.datasets=[],this.options.showTooltips&&i.bindEvents(this,this.options.tooltipEvents,function(t){var e="mouseout"!==t.type?this.getBarsAtEvent(t):[];this.eachBars(function(t){t.restore(["fillColor","strokeColor"])}),i.each(e,function(t){t.fillColor=t.highlightFill,t.strokeColor=t.highlightStroke}),this.showTooltip(e)}),this.BarClass=e.Rectangle.extend({strokeWidth:this.options.barStrokeWidth,showStroke:this.options.barShowStroke,ctx:this.chart.ctx}),i.each(t.datasets,function(e,n){var s={label:e.label||null,fillColor:e.fillColor,strokeColor:e.strokeColor,bars:[]};this.datasets.push(s),i.each(e.data,function(i,n){s.bars.push(new this.BarClass({value:i,label:t.labels[n],datasetLabel:e.label,strokeColor:e.strokeColor,fillColor:e.fillColor,highlightFill:e.highlightFill||e.fillColor,highlightStroke:e.highlightStroke||e.strokeColor}))},this)},this),this.buildScale(t.labels),this.BarClass.prototype.base=this.scale.endPoint,this.eachBars(function(t,e,n){i.extend(t,{width:this.scale.calculateBarWidth(this.datasets.length),x:this.scale.calculateBarX(this.datasets.length,n,e),y:this.scale.endPoint}),t.save()},this),this.render()},update:function(){this.scale.update(),i.each(this.activeElements,function(t){t.restore(["fillColor","strokeColor"])}),this.eachBars(function(t){t.save()}),this.render()},eachBars:function(t){i.each(this.datasets,function(e,n){i.each(e.bars,t,this,n)},this)},getBarsAtEvent:function(t){for(var e,n=[],s=i.getRelativePosition(t),o=function(t){n.push(t.bars[e])},a=0;a<this.datasets.length;a++)for(e=0;e<this.datasets[a].bars.length;e++)if(this.datasets[a].bars[e].inRange(s.x,s.y))return i.each(this.datasets,o),n;return n},buildScale:function(t){var e=this,n=function(){var t=[];return e.eachBars(function(e){t.push(e.value)}),t},s={templateString:this.options.scaleLabel,height:this.chart.height,width:this.chart.width,ctx:this.chart.ctx,textColor:this.options.scaleFontColor,fontSize:this.options.scaleFontSize,fontStyle:this.options.scaleFontStyle,fontFamily:this.options.scaleFontFamily,valuesCount:t.length,beginAtZero:this.options.scaleBeginAtZero,integersOnly:this.options.scaleIntegersOnly,calculateYRange:function(t){var e=i.calculateScaleRange(n(),t,this.fontSize,this.beginAtZero,this.integersOnly);i.extend(this,e)},xLabels:t,font:i.fontString(this.options.scaleFontSize,this.options.scaleFontStyle,this.options.scaleFontFamily),lineWidth:this.options.scaleLineWidth,lineColor:this.options.scaleLineColor,showHorizontalLines:this.options.scaleShowHorizontalLines,showVerticalLines:this.options.scaleShowVerticalLines,gridLineWidth:this.options.scaleShowGridLines?this.options.scaleGridLineWidth:0,gridLineColor:this.options.scaleShowGridLines?this.options.scaleGridLineColor:"rgba(0,0,0,0)",padding:this.options.showScale?0:this.options.barShowStroke?this.options.barStrokeWidth:0,showLabels:this.options.scaleShowLabels,display:this.options.showScale};this.options.scaleOverride&&i.extend(s,{calculateYRange:i.noop,steps:this.options.scaleSteps,stepValue:this.options.scaleStepWidth,min:this.options.scaleStartValue,max:this.options.scaleStartValue+this.options.scaleSteps*this.options.scaleStepWidth}),this.scale=new this.ScaleClass(s)},addData:function(t,e){i.each(t,function(t,i){this.datasets[i].bars.push(new this.BarClass({value:t,label:e,x:this.scale.calculateBarX(this.datasets.length,i,this.scale.valuesCount+1),y:this.scale.endPoint,width:this.scale.calculateBarWidth(this.datasets.length),
+base:this.scale.endPoint,strokeColor:this.datasets[i].strokeColor,fillColor:this.datasets[i].fillColor}))},this),this.scale.addXLabel(e),this.update()},removeData:function(){this.scale.removeXLabel(),i.each(this.datasets,function(t){t.bars.shift()},this),this.update()},reflow:function(){i.extend(this.BarClass.prototype,{y:this.scale.endPoint,base:this.scale.endPoint});var t=i.extend({height:this.chart.height,width:this.chart.width});this.scale.update(t)},draw:function(t){var e=t||1;this.clear();this.chart.ctx;this.scale.draw(e),i.each(this.datasets,function(t,n){i.each(t.bars,function(t,i){t.hasValue()&&(t.base=this.scale.endPoint,t.transition({x:this.scale.calculateBarX(this.datasets.length,n,i),y:this.scale.calculateY(t.value),width:this.scale.calculateBarWidth(this.datasets.length)},e).draw())},this)},this)}})}.call(this),function(){"use strict";var t=this,e=t.Chart,i=e.helpers,n={segmentShowStroke:!0,segmentStrokeColor:"#fff",segmentStrokeWidth:2,percentageInnerCutout:50,animationSteps:100,animationEasing:"easeOutBounce",animateRotate:!0,animateScale:!1,legendTemplate:'<ul class="<%=name.toLowerCase()%>-legend"><% for (var i=0; i<segments.length; i++){%><li><span style="background-color:<%=segments[i].fillColor%>"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>'};e.Type.extend({name:"Doughnut",defaults:n,initialize:function(t){this.segments=[],this.outerRadius=(i.min([this.chart.width,this.chart.height])-this.options.segmentStrokeWidth/2)/2,this.SegmentArc=e.Arc.extend({ctx:this.chart.ctx,x:this.chart.width/2,y:this.chart.height/2}),this.options.showTooltips&&i.bindEvents(this,this.options.tooltipEvents,function(t){var e="mouseout"!==t.type?this.getSegmentsAtEvent(t):[];i.each(this.segments,function(t){t.restore(["fillColor"])}),i.each(e,function(t){t.fillColor=t.highlightColor}),this.showTooltip(e)}),this.calculateTotal(t),i.each(t,function(t,e){this.addData(t,e,!0)},this),this.render()},getSegmentsAtEvent:function(t){var e=[],n=i.getRelativePosition(t);return i.each(this.segments,function(t){t.inRange(n.x,n.y)&&e.push(t)},this),e},addData:function(t,e,i){var n=e||this.segments.length;this.segments.splice(n,0,new this.SegmentArc({value:t.value,outerRadius:this.options.animateScale?0:this.outerRadius,innerRadius:this.options.animateScale?0:this.outerRadius/100*this.options.percentageInnerCutout,fillColor:t.color,highlightColor:t.highlight||t.color,showStroke:this.options.segmentShowStroke,strokeWidth:this.options.segmentStrokeWidth,strokeColor:this.options.segmentStrokeColor,startAngle:1.5*Math.PI,circumference:this.options.animateRotate?0:this.calculateCircumference(t.value),label:t.label})),i||(this.reflow(),this.update())},calculateCircumference:function(t){return 2*Math.PI*(Math.abs(t)/this.total)},calculateTotal:function(t){this.total=0,i.each(t,function(t){this.total+=Math.abs(t.value)},this)},update:function(){this.calculateTotal(this.segments),i.each(this.activeElements,function(t){t.restore(["fillColor"])}),i.each(this.segments,function(t){t.save()}),this.render()},removeData:function(t){var e=i.isNumber(t)?t:this.segments.length-1;this.segments.splice(e,1),this.reflow(),this.update()},reflow:function(){i.extend(this.SegmentArc.prototype,{x:this.chart.width/2,y:this.chart.height/2}),this.outerRadius=(i.min([this.chart.width,this.chart.height])-this.options.segmentStrokeWidth/2)/2,i.each(this.segments,function(t){t.update({outerRadius:this.outerRadius,innerRadius:this.outerRadius/100*this.options.percentageInnerCutout})},this)},draw:function(t){var e=t?t:1;this.clear(),i.each(this.segments,function(t,i){t.transition({circumference:this.calculateCircumference(t.value),outerRadius:this.outerRadius,innerRadius:this.outerRadius/100*this.options.percentageInnerCutout},e),t.endAngle=t.startAngle+t.circumference,t.draw(),0===i&&(t.startAngle=1.5*Math.PI),i<this.segments.length-1&&(this.segments[i+1].startAngle=t.endAngle)},this)}}),e.types.Doughnut.extend({name:"Pie",defaults:i.merge(n,{percentageInnerCutout:0})})}.call(this),function(){"use strict";var t=this,e=t.Chart,i=e.helpers,n={scaleShowGridLines:!0,scaleGridLineColor:"rgba(0,0,0,.05)",scaleGridLineWidth:1,scaleShowHorizontalLines:!0,scaleShowVerticalLines:!0,bezierCurve:!0,bezierCurveTension:.4,pointDot:!0,pointDotRadius:4,pointDotStrokeWidth:1,pointHitDetectionRadius:20,datasetStroke:!0,datasetStrokeWidth:2,datasetFill:!0,legendTemplate:'<ul class="<%=name.toLowerCase()%>-legend"><% for (var i=0; i<datasets.length; i++){%><li><span style="background-color:<%=datasets[i].strokeColor%>"></span><%if(datasets[i].label){%><%=datasets[i].label%><%}%></li><%}%></ul>'};e.Type.extend({name:"Line",defaults:n,initialize:function(t){this.PointClass=e.Point.extend({strokeWidth:this.options.pointDotStrokeWidth,radius:this.options.pointDotRadius,display:this.options.pointDot,hitDetectionRadius:this.options.pointHitDetectionRadius,ctx:this.chart.ctx,inRange:function(t){return Math.pow(t-this.x,2)<Math.pow(this.radius+this.hitDetectionRadius,2)}}),this.datasets=[],this.options.showTooltips&&i.bindEvents(this,this.options.tooltipEvents,function(t){var e="mouseout"!==t.type?this.getPointsAtEvent(t):[];this.eachPoints(function(t){t.restore(["fillColor","strokeColor"])}),i.each(e,function(t){t.fillColor=t.highlightFill,t.strokeColor=t.highlightStroke}),this.showTooltip(e)}),i.each(t.datasets,function(e){var n={label:e.label||null,fillColor:e.fillColor,strokeColor:e.strokeColor,pointColor:e.pointColor,pointStrokeColor:e.pointStrokeColor,points:[]};this.datasets.push(n),i.each(e.data,function(i,s){n.points.push(new this.PointClass({value:i,label:t.labels[s],datasetLabel:e.label,strokeColor:e.pointStrokeColor,fillColor:e.pointColor,highlightFill:e.pointHighlightFill||e.pointColor,highlightStroke:e.pointHighlightStroke||e.pointStrokeColor}))},this),this.buildScale(t.labels),this.eachPoints(function(t,e){i.extend(t,{x:this.scale.calculateX(e),y:this.scale.endPoint}),t.save()},this)},this),this.render()},update:function(){this.scale.update(),i.each(this.activeElements,function(t){t.restore(["fillColor","strokeColor"])}),this.eachPoints(function(t){t.save()}),this.render()},eachPoints:function(t){i.each(this.datasets,function(e){i.each(e.points,t,this)},this)},getPointsAtEvent:function(t){var e=[],n=i.getRelativePosition(t);return i.each(this.datasets,function(t){i.each(t.points,function(t){t.inRange(n.x,n.y)&&e.push(t)})},this),e},buildScale:function(t){var n=this,s=function(){var t=[];return n.eachPoints(function(e){t.push(e.value)}),t},o={templateString:this.options.scaleLabel,height:this.chart.height,width:this.chart.width,ctx:this.chart.ctx,textColor:this.options.scaleFontColor,fontSize:this.options.scaleFontSize,fontStyle:this.options.scaleFontStyle,fontFamily:this.options.scaleFontFamily,valuesCount:t.length,beginAtZero:this.options.scaleBeginAtZero,integersOnly:this.options.scaleIntegersOnly,calculateYRange:function(t){var e=i.calculateScaleRange(s(),t,this.fontSize,this.beginAtZero,this.integersOnly);i.extend(this,e)},xLabels:t,font:i.fontString(this.options.scaleFontSize,this.options.scaleFontStyle,this.options.scaleFontFamily),lineWidth:this.options.scaleLineWidth,lineColor:this.options.scaleLineColor,showHorizontalLines:this.options.scaleShowHorizontalLines,showVerticalLines:this.options.scaleShowVerticalLines,gridLineWidth:this.options.scaleShowGridLines?this.options.scaleGridLineWidth:0,gridLineColor:this.options.scaleShowGridLines?this.options.scaleGridLineColor:"rgba(0,0,0,0)",padding:this.options.showScale?0:this.options.pointDotRadius+this.options.pointDotStrokeWidth,showLabels:this.options.scaleShowLabels,display:this.options.showScale};this.options.scaleOverride&&i.extend(o,{calculateYRange:i.noop,steps:this.options.scaleSteps,stepValue:this.options.scaleStepWidth,min:this.options.scaleStartValue,max:this.options.scaleStartValue+this.options.scaleSteps*this.options.scaleStepWidth}),this.scale=new e.Scale(o)},addData:function(t,e){i.each(t,function(t,i){this.datasets[i].points.push(new this.PointClass({value:t,label:e,x:this.scale.calculateX(this.scale.valuesCount+1),y:this.scale.endPoint,strokeColor:this.datasets[i].pointStrokeColor,fillColor:this.datasets[i].pointColor}))},this),this.scale.addXLabel(e),this.update()},removeData:function(){this.scale.removeXLabel(),i.each(this.datasets,function(t){t.points.shift()},this),this.update()},reflow:function(){var t=i.extend({height:this.chart.height,width:this.chart.width});this.scale.update(t)},draw:function(t){var e=t||1;this.clear();var n=this.chart.ctx,s=function(t){return null!==t.value},o=function(t,e,n){return i.findNextWhere(e,s,n)||t},a=function(t,e,n){return i.findPreviousWhere(e,s,n)||t};this.scale.draw(e),i.each(this.datasets,function(t){var r=i.where(t.points,s);i.each(t.points,function(t,i){t.hasValue()&&t.transition({y:this.scale.calculateY(t.value),x:this.scale.calculateX(i)},e)},this),this.options.bezierCurve&&i.each(r,function(t,e){var n=e>0&&e<r.length-1?this.options.bezierCurveTension:0;t.controlPoints=i.splineCurve(a(t,r,e),t,o(t,r,e),n),t.controlPoints.outer.y>this.scale.endPoint?t.controlPoints.outer.y=this.scale.endPoint:t.controlPoints.outer.y<this.scale.startPoint&&(t.controlPoints.outer.y=this.scale.startPoint),t.controlPoints.inner.y>this.scale.endPoint?t.controlPoints.inner.y=this.scale.endPoint:t.controlPoints.inner.y<this.scale.startPoint&&(t.controlPoints.inner.y=this.scale.startPoint)},this),n.lineWidth=this.options.datasetStrokeWidth,n.strokeStyle=t.strokeColor,n.beginPath(),i.each(r,function(t,e){if(0===e)n.moveTo(t.x,t.y);else if(this.options.bezierCurve){var i=a(t,r,e);n.bezierCurveTo(i.controlPoints.outer.x,i.controlPoints.outer.y,t.controlPoints.inner.x,t.controlPoints.inner.y,t.x,t.y)}else n.lineTo(t.x,t.y)},this),n.stroke(),this.options.datasetFill&&r.length>0&&(n.lineTo(r[r.length-1].x,this.scale.endPoint),n.lineTo(r[0].x,this.scale.endPoint),n.fillStyle=t.fillColor,n.closePath(),n.fill()),i.each(r,function(t){t.draw()})},this)}})}.call(this),function(){"use strict";var t=this,e=t.Chart,i=e.helpers,n={scaleShowLabelBackdrop:!0,scaleBackdropColor:"rgba(255,255,255,0.75)",scaleBeginAtZero:!0,scaleBackdropPaddingY:2,scaleBackdropPaddingX:2,scaleShowLine:!0,segmentShowStroke:!0,segmentStrokeColor:"#fff",segmentStrokeWidth:2,animationSteps:100,animationEasing:"easeOutBounce",animateRotate:!0,animateScale:!1,legendTemplate:'<ul class="<%=name.toLowerCase()%>-legend"><% for (var i=0; i<segments.length; i++){%><li><span style="background-color:<%=segments[i].fillColor%>"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>'};e.Type.extend({name:"PolarArea",defaults:n,initialize:function(t){this.segments=[],this.SegmentArc=e.Arc.extend({showStroke:this.options.segmentShowStroke,strokeWidth:this.options.segmentStrokeWidth,strokeColor:this.options.segmentStrokeColor,ctx:this.chart.ctx,innerRadius:0,x:this.chart.width/2,y:this.chart.height/2}),this.scale=new e.RadialScale({display:this.options.showScale,fontStyle:this.options.scaleFontStyle,fontSize:this.options.scaleFontSize,fontFamily:this.options.scaleFontFamily,fontColor:this.options.scaleFontColor,showLabels:this.options.scaleShowLabels,showLabelBackdrop:this.options.scaleShowLabelBackdrop,backdropColor:this.options.scaleBackdropColor,backdropPaddingY:this.options.scaleBackdropPaddingY,backdropPaddingX:this.options.scaleBackdropPaddingX,lineWidth:this.options.scaleShowLine?this.options.scaleLineWidth:0,lineColor:this.options.scaleLineColor,lineArc:!0,width:this.chart.width,height:this.chart.height,xCenter:this.chart.width/2,yCenter:this.chart.height/2,ctx:this.chart.ctx,templateString:this.options.scaleLabel,valuesCount:t.length}),this.updateScaleRange(t),this.scale.update(),i.each(t,function(t,e){this.addData(t,e,!0)},this),this.options.showTooltips&&i.bindEvents(this,this.options.tooltipEvents,function(t){var e="mouseout"!==t.type?this.getSegmentsAtEvent(t):[];i.each(this.segments,function(t){t.restore(["fillColor"])}),i.each(e,function(t){t.fillColor=t.highlightColor}),this.showTooltip(e)}),this.render()},getSegmentsAtEvent:function(t){var e=[],n=i.getRelativePosition(t);return i.each(this.segments,function(t){t.inRange(n.x,n.y)&&e.push(t)},this),e},addData:function(t,e,i){var n=e||this.segments.length;this.segments.splice(n,0,new this.SegmentArc({fillColor:t.color,highlightColor:t.highlight||t.color,label:t.label,value:t.value,outerRadius:this.options.animateScale?0:this.scale.calculateCenterOffset(t.value),circumference:this.options.animateRotate?0:this.scale.getCircumference(),startAngle:1.5*Math.PI})),i||(this.reflow(),this.update())},removeData:function(t){var e=i.isNumber(t)?t:this.segments.length-1;this.segments.splice(e,1),this.reflow(),this.update()},calculateTotal:function(t){this.total=0,i.each(t,function(t){this.total+=t.value},this),this.scale.valuesCount=this.segments.length},updateScaleRange:function(t){var e=[];i.each(t,function(t){e.push(t.value)});var n=this.options.scaleOverride?{steps:this.options.scaleSteps,stepValue:this.options.scaleStepWidth,min:this.options.scaleStartValue,max:this.options.scaleStartValue+this.options.scaleSteps*this.options.scaleStepWidth}:i.calculateScaleRange(e,i.min([this.chart.width,this.chart.height])/2,this.options.scaleFontSize,this.options.scaleBeginAtZero,this.options.scaleIntegersOnly);i.extend(this.scale,n,{size:i.min([this.chart.width,this.chart.height]),xCenter:this.chart.width/2,yCenter:this.chart.height/2})},update:function(){this.calculateTotal(this.segments),i.each(this.segments,function(t){t.save()}),this.reflow(),this.render()},reflow:function(){i.extend(this.SegmentArc.prototype,{x:this.chart.width/2,y:this.chart.height/2}),this.updateScaleRange(this.segments),this.scale.update(),i.extend(this.scale,{xCenter:this.chart.width/2,yCenter:this.chart.height/2}),i.each(this.segments,function(t){t.update({outerRadius:this.scale.calculateCenterOffset(t.value)})},this)},draw:function(t){var e=t||1;this.clear(),i.each(this.segments,function(t,i){t.transition({circumference:this.scale.getCircumference(),outerRadius:this.scale.calculateCenterOffset(t.value)},e),t.endAngle=t.startAngle+t.circumference,0===i&&(t.startAngle=1.5*Math.PI),i<this.segments.length-1&&(this.segments[i+1].startAngle=t.endAngle),t.draw()},this),this.scale.draw()}})}.call(this),function(){"use strict";var t=this,e=t.Chart,i=e.helpers;e.Type.extend({name:"Radar",defaults:{scaleShowLine:!0,angleShowLineOut:!0,scaleShowLabels:!1,scaleBeginAtZero:!0,angleLineColor:"rgba(0,0,0,.1)",angleLineWidth:1,pointLabelFontFamily:"'Arial'",pointLabelFontStyle:"normal",pointLabelFontSize:10,pointLabelFontColor:"#666",pointDot:!0,pointDotRadius:3,pointDotStrokeWidth:1,pointHitDetectionRadius:20,datasetStroke:!0,datasetStrokeWidth:2,datasetFill:!0,legendTemplate:'<ul class="<%=name.toLowerCase()%>-legend"><% for (var i=0; i<datasets.length; i++){%><li><span style="background-color:<%=datasets[i].strokeColor%>"></span><%if(datasets[i].label){%><%=datasets[i].label%><%}%></li><%}%></ul>'},initialize:function(t){this.PointClass=e.Point.extend({strokeWidth:this.options.pointDotStrokeWidth,radius:this.options.pointDotRadius,display:this.options.pointDot,hitDetectionRadius:this.options.pointHitDetectionRadius,ctx:this.chart.ctx}),this.datasets=[],this.buildScale(t),this.options.showTooltips&&i.bindEvents(this,this.options.tooltipEvents,function(t){var e="mouseout"!==t.type?this.getPointsAtEvent(t):[];this.eachPoints(function(t){t.restore(["fillColor","strokeColor"])}),i.each(e,function(t){t.fillColor=t.highlightFill,t.strokeColor=t.highlightStroke}),this.showTooltip(e)}),i.each(t.datasets,function(e){var n={label:e.label||null,fillColor:e.fillColor,strokeColor:e.strokeColor,pointColor:e.pointColor,pointStrokeColor:e.pointStrokeColor,points:[]};this.datasets.push(n),i.each(e.data,function(i,s){var o;this.scale.animation||(o=this.scale.getPointPosition(s,this.scale.calculateCenterOffset(i))),n.points.push(new this.PointClass({value:i,label:t.labels[s],datasetLabel:e.label,x:this.options.animation?this.scale.xCenter:o.x,y:this.options.animation?this.scale.yCenter:o.y,strokeColor:e.pointStrokeColor,fillColor:e.pointColor,highlightFill:e.pointHighlightFill||e.pointColor,highlightStroke:e.pointHighlightStroke||e.pointStrokeColor}))},this)},this),this.render()},eachPoints:function(t){i.each(this.datasets,function(e){i.each(e.points,t,this)},this)},getPointsAtEvent:function(t){var e=i.getRelativePosition(t),n=i.getAngleFromPoint({x:this.scale.xCenter,y:this.scale.yCenter},e),s=2*Math.PI/this.scale.valuesCount,o=Math.round((n.angle-1.5*Math.PI)/s),a=[];return(o>=this.scale.valuesCount||0>o)&&(o=0),n.distance<=this.scale.drawingArea&&i.each(this.datasets,function(t){a.push(t.points[o])}),a},buildScale:function(t){this.scale=new e.RadialScale({display:this.options.showScale,fontStyle:this.options.scaleFontStyle,fontSize:this.options.scaleFontSize,fontFamily:this.options.scaleFontFamily,fontColor:this.options.scaleFontColor,showLabels:this.options.scaleShowLabels,showLabelBackdrop:this.options.scaleShowLabelBackdrop,backdropColor:this.options.scaleBackdropColor,backdropPaddingY:this.options.scaleBackdropPaddingY,backdropPaddingX:this.options.scaleBackdropPaddingX,lineWidth:this.options.scaleShowLine?this.options.scaleLineWidth:0,lineColor:this.options.scaleLineColor,angleLineColor:this.options.angleLineColor,angleLineWidth:this.options.angleShowLineOut?this.options.angleLineWidth:0,pointLabelFontColor:this.options.pointLabelFontColor,pointLabelFontSize:this.options.pointLabelFontSize,pointLabelFontFamily:this.options.pointLabelFontFamily,pointLabelFontStyle:this.options.pointLabelFontStyle,height:this.chart.height,width:this.chart.width,xCenter:this.chart.width/2,yCenter:this.chart.height/2,ctx:this.chart.ctx,templateString:this.options.scaleLabel,labels:t.labels,valuesCount:t.datasets[0].data.length}),this.scale.setScaleSize(),this.updateScaleRange(t.datasets),this.scale.buildYLabels()},updateScaleRange:function(t){var e=function(){var e=[];return i.each(t,function(t){t.data?e=e.concat(t.data):i.each(t.points,function(t){e.push(t.value)})}),e}(),n=this.options.scaleOverride?{steps:this.options.scaleSteps,stepValue:this.options.scaleStepWidth,min:this.options.scaleStartValue,max:this.options.scaleStartValue+this.options.scaleSteps*this.options.scaleStepWidth}:i.calculateScaleRange(e,i.min([this.chart.width,this.chart.height])/2,this.options.scaleFontSize,this.options.scaleBeginAtZero,this.options.scaleIntegersOnly);i.extend(this.scale,n)},addData:function(t,e){this.scale.valuesCount++,i.each(t,function(t,i){var n=this.scale.getPointPosition(this.scale.valuesCount,this.scale.calculateCenterOffset(t));this.datasets[i].points.push(new this.PointClass({value:t,label:e,x:n.x,y:n.y,strokeColor:this.datasets[i].pointStrokeColor,fillColor:this.datasets[i].pointColor}))},this),this.scale.labels.push(e),this.reflow(),this.update()},removeData:function(){this.scale.valuesCount--,this.scale.labels.shift(),i.each(this.datasets,function(t){t.points.shift()},this),this.reflow(),this.update()},update:function(){this.eachPoints(function(t){t.save()}),this.reflow(),this.render()},reflow:function(){i.extend(this.scale,{width:this.chart.width,height:this.chart.height,size:i.min([this.chart.width,this.chart.height]),xCenter:this.chart.width/2,yCenter:this.chart.height/2}),this.updateScaleRange(this.datasets),this.scale.setScaleSize(),this.scale.buildYLabels()},draw:function(t){var e=t||1,n=this.chart.ctx;this.clear(),this.scale.draw(),i.each(this.datasets,function(t){i.each(t.points,function(t,i){t.hasValue()&&t.transition(this.scale.getPointPosition(i,this.scale.calculateCenterOffset(t.value)),e)},this),n.lineWidth=this.options.datasetStrokeWidth,n.strokeStyle=t.strokeColor,n.beginPath(),i.each(t.points,function(t,e){0===e?n.moveTo(t.x,t.y):n.lineTo(t.x,t.y)},this),n.closePath(),n.stroke(),n.fillStyle=t.fillColor,n.fill(),i.each(t.points,function(t){t.hasValue()&&t.draw()})},this)}})}.call(this),function(t){"use strict";"object"==typeof exports?module.exports=t(angular,Chart):"function"==typeof define&&define.amd?define(["angular","chart"],t):t(angular,Chart)}(function(t,e){"use strict";function i(){var i={},n={Chart:e,getOptions:function(e){var n=e&&i[e]||{};return t.extend({},i,n)}};this.setOptions=function(e,n){return n?void(i[e]=t.extend(i[e]||{},n)):(n=e,void(i=t.extend(i,n)))},this.$get=function(){return n}}function n(i,n){function o(t,e){return t&&e&&t.length&&e.length?Array.isArray(t[0])?t.length===e.length&&t.every(function(t,i){return t.length===e[i].length}):e.reduce(a,0)>0?t.length===e.length:!1:!1}function a(t,e){return t+e}function r(e,i,n,s){var o=null;return function(a){var r=i.getPointsAtEvent||i.getBarsAtEvent||i.getSegmentsAtEvent;if(r){var l=r.call(i,a);s!==!1&&t.equals(o,l)!==!1||(o=l,e[n](l,a),e.$apply())}}}function l(n,s){for(var o=t.copy(s.colours||i.getOptions(n).colours||e.defaults.global.colours);o.length<s.data.length;)o.push(s.getColour());return o.map(h)}function h(t){return"object"==typeof t&&null!==t?t:"string"==typeof t&&"#"===t[0]?u(p(t.substr(1))):c()}function c(){var t=[d(0,255),d(0,255),d(0,255)];return u(t)}function u(t){return{fillColor:f(t,.2),strokeColor:f(t,1),pointColor:f(t,1),pointStrokeColor:"#fff",pointHighlightFill:"#fff",pointHighlightStroke:f(t,.8)}}function d(t,e){return Math.floor(Math.random()*(e-t+1))+t}function f(t,e){return s?"rgb("+t.join(",")+")":"rgba("+t.concat(e).join(",")+")"}function p(t){var e=parseInt(t,16),i=e>>16&255,n=e>>8&255,s=255&e;return[i,n,s]}function g(e,i,n,s){return{labels:e,datasets:i.map(function(e,i){return t.extend({},s[i],{label:n[i],data:e})})}}function v(e,i,n){return e.map(function(e,s){return t.extend({},n[s],{label:e,value:i[s],color:n[s].strokeColor,highlight:n[s].pointHighlightStroke})})}function m(t,e){var i=t.parent(),n=i.find("chart-legend"),s="<chart-legend>"+e.generateLegend()+"</chart-legend>";n.length?n.replaceWith(s):i.append(s)}function C(t,e,i,n){Array.isArray(i.data[0])?t.datasets.forEach(function(t,i){(t.points||t.bars).forEach(function(t,n){t.value=e[i][n]})}):t.segments.forEach(function(t,i){t.value=e[i]}),t.update(),i.$emit("update",t),i.legend&&"false"!==i.legend&&m(n,t)}function y(t){return!t||Array.isArray(t)&&!t.length||"object"==typeof t&&!Object.keys(t).length}function b(n,s){var o=t.extend({},e.defaults.global,i.getOptions(n),s.options);return o.responsive}return function(e){return{restrict:"CA",scope:{data:"=?",labels:"=?",options:"=?",series:"=?",colours:"=?",getColour:"=?",chartType:"=",legend:"@",click:"=?",hover:"=?",chartData:"=?",chartLabels:"=?",chartOptions:"=?",chartSeries:"=?",chartColours:"=?",chartLegend:"@",chartClick:"=?",chartHover:"=?"},link:function(a,h){function u(t,e){a.$watch(t,function(t){"undefined"!=typeof t&&(a[e]=t)})}function d(i,n){if(!y(i)&&!t.equals(i,n)){var s=e||a.chartType;s&&(w&&w.destroy(),f(s))}}function f(e){if(b(e,a)&&0===h[0].clientHeight&&0===x.clientHeight)return n(function(){f(e)},50,!1);if(a.data&&a.data.length){a.getColour="function"==typeof a.getColour?a.getColour:c,a.colours=l(e,a);var s=h[0],o=s.getContext("2d"),u=Array.isArray(a.data[0])?g(a.labels,a.data,a.series||[],a.colours):v(a.labels,a.data,a.colours),d=t.extend({},i.getOptions(e),a.options);w=new i.Chart(o)[e](u,d),a.$emit("create",w),s.onclick=a.click?r(a,w,"click",!1):t.noop,s.onmousemove=a.hover?r(a,w,"hover",!0):t.noop,a.legend&&"false"!==a.legend&&m(h,w)}}function p(t){if("undefined"!=typeof console&&"test"!==i.getOptions().env){var e="function"==typeof console.warn?console.warn:console.log;a[t]&&e.call(console,'"%s" is deprecated and will be removed in a future version. Please use "chart-%s" instead.',t,t)}}var w,x=document.createElement("div");x.className="chart-container",h.replaceWith(x),x.appendChild(h[0]),s&&window.G_vmlCanvasManager.initElement(h[0]),["data","labels","options","series","colours","legend","click","hover"].forEach(p),u("chartData","data"),u("chartLabels","labels"),u("chartOptions","options"),u("chartSeries","series"),u("chartColours","colours"),u("chartLegend","legend"),u("chartClick","click"),u("chartHover","hover"),a.$watch("data",function(t,i){if(t&&t.length&&(!Array.isArray(t[0])||t[0].length)){var n=e||a.chartType;if(n){if(w){if(o(t,i))return C(w,t,a,h);w.destroy()}f(n)}}},!0),a.$watch("series",d,!0),a.$watch("labels",d,!0),a.$watch("options",d,!0),a.$watch("colours",d,!0),a.$watch("chartType",function(e,i){y(e)||t.equals(e,i)||(w&&w.destroy(),f(e))}),a.$on("$destroy",function(){w&&w.destroy()})}}}}e.defaults.global.responsive=!0,e.defaults.global.multiTooltipTemplate="<%if (datasetLabel){%><%=datasetLabel%>: <%}%><%= value %>",e.defaults.global.colours=["#97BBCD","#DCDCDC","#F7464A","#46BFBD","#FDB45C","#949FB1","#4D5360"];var s="object"==typeof window.G_vmlCanvasManager&&null!==window.G_vmlCanvasManager&&"function"==typeof window.G_vmlCanvasManager.initElement;return s&&(e.defaults.global.animation=!1),t.module("chart.js",[]).provider("ChartJs",i).factory("ChartJsFactory",["ChartJs","$timeout",n]).directive("chartBase",["ChartJsFactory",function(t){return new t}]).directive("chartLine",["ChartJsFactory",function(t){return new t("Line")}]).directive("chartBar",["ChartJsFactory",function(t){return new t("Bar")}]).directive("chartRadar",["ChartJsFactory",function(t){return new t("Radar")}]).directive("chartDoughnut",["ChartJsFactory",function(t){return new t("Doughnut")}]).directive("chartPie",["ChartJsFactory",function(t){return new t("Pie")}]).directive("chartPolarArea",["ChartJsFactory",function(t){return new t("PolarArea")}])}),function(t,e,i){"use strict";function n(t,e,i){if(!t)throw ngMinErr("areq","Argument '{0}' is {1}",e||"?",i||"required");return t}function s(t,e){return t||e?t?e?(q(t)&&(t=t.join(" ")),q(e)&&(e=e.join(" ")),t+" "+e):t:e:""}function o(t){var e={};return t&&(t.to||t.from)&&(e.to=t.to,e.from=t.from),e}function a(t,e,i){var n="";return t=q(t)?t:t&&X(t)&&t.length?t.split(/\s+/):[],j(t,function(t,s){t&&t.length>0&&(n+=s>0?" ":"",n+=i?e+t:t+e)}),n}function r(t,e){var i=t.indexOf(e);e>=0&&t.splice(i,1)}function l(t){if(t instanceof H)switch(t.length){case 0:return[];case 1:if(t[0].nodeType===U)return t;break;default:return H(h(t))}return t.nodeType===U?H(t):void 0}function h(t){if(!t[0])return t;for(var e=0;e<t.length;e++){var i=t[e];if(i.nodeType==U)return i}}function c(t,e,i){j(e,function(e){t.addClass(e,i)})}function u(t,e,i){j(e,function(e){t.removeClass(e,i)})}function d(t){return function(e,i){i.addClass&&(c(t,e,i.addClass),i.addClass=null),i.removeClass&&(u(t,e,i.removeClass),i.removeClass=null)}}function f(t){if(t=t||{},!t.$$prepared){var e=t.domOperation||B;t.domOperation=function(){t.$$domOperationFired=!0,e(),e=B},t.$$prepared=!0}return t}function p(t,e){g(t,e),v(t,e)}function g(t,e){e.from&&(t.css(e.from),e.from=null)}function v(t,e){e.to&&(t.css(e.to),e.to=null)}function m(t,e,i){var n=(e.addClass||"")+" "+(i.addClass||""),s=(e.removeClass||"")+" "+(i.removeClass||""),o=C(t.attr("class"),n,s);i.preparationClasses&&(e.preparationClasses=k(i.preparationClasses,e.preparationClasses),delete i.preparationClasses);var a=e.domOperation!==B?e.domOperation:null;return I(e,i),a&&(e.domOperation=a),o.addClass?e.addClass=o.addClass:e.addClass=null,o.removeClass?e.removeClass=o.removeClass:e.removeClass=null,e}function C(t,e,i){function n(t){X(t)&&(t=t.split(" "));var e={};return j(t,function(t){t.length&&(e[t]=!0)}),e}var s=1,o=-1,a={};t=n(t),e=n(e),j(e,function(t,e){a[e]=s}),i=n(i),j(i,function(t,e){a[e]=a[e]===s?null:o});var r={addClass:"",removeClass:""};return j(a,function(e,i){var n,a;e===s?(n="addClass",a=!t[i]):e===o&&(n="removeClass",a=t[i]),a&&(r[n].length&&(r[n]+=" "),r[n]+=i)}),r}function y(t){return t instanceof e.element?t[0]:t}function b(t,e,i){var n="";e&&(n=a(e,Z,!0)),i.addClass&&(n=k(n,a(i.addClass,J))),i.removeClass&&(n=k(n,a(i.removeClass,Q))),n.length&&(i.preparationClasses=n,t.addClass(n))}function w(t,e){e.preparationClasses&&(t.removeClass(e.preparationClasses),e.preparationClasses=null),e.activeClasses&&(t.removeClass(e.activeClasses),e.activeClasses=null)}function x(t,e){var i=e?"-"+e+"s":"";return P(t,[dt,i]),[dt,i]}function S(t,e){var i=e?"paused":"",n=z+lt;return P(t,[n,i]),[n,i]}function P(t,e){var i=e[0],n=e[1];t.style[i]=n}function k(t,e){return t?e?t+" "+e:t:e}function A(t){return[ut,t+"s"]}function L(t,e){var i=e?ct:dt;return[i,t+"s"]}function $(t,e,i){var n=Object.create(null),s=t.getComputedStyle(e)||{};return j(i,function(t,e){var i=s[t];if(i){var o=i.charAt(0);("-"===o||"+"===o||o>=0)&&(i=F(i)),0===i&&(i=null),n[e]=i}}),n}function F(t){var e=0,i=t.split(/\s*,\s*/);return j(i,function(t){"s"==t.charAt(t.length-1)&&(t=t.substring(0,t.length-1)),t=parseFloat(t)||0,e=e?Math.max(t,e):t}),e}function T(t){return 0===t||null!=t}function R(t,e){var i=W,n=t+"s";return e?i+=nt:n+=" linear all",[i,n]}function D(){var t=Object.create(null);return{flush:function(){t=Object.create(null)},count:function(e){var i=t[e];return i?i.total:0},get:function(e){var i=t[e];return i&&i.value},put:function(e,i){t[e]?t[e].total++:t[e]={total:1,value:i}}}}function M(t,e,i){j(i,function(i){t[i]=_(t[i])?t[i]:e.style.getPropertyValue(i)})}var W,O,z,E,B=e.noop,I=e.extend,H=e.element,j=e.forEach,q=e.isArray,X=e.isString,V=e.isObject,G=e.isUndefined,_=e.isDefined,N=e.isFunction,Y=e.isElement,U=1,J="-add",Q="-remove",Z="ng-",K="-active",tt="ng-animate",et="$$ngAnimateChildren",it="";G(t.ontransitionend)&&_(t.onwebkittransitionend)?(it="-webkit-",W="WebkitTransition",O="webkitTransitionEnd transitionend"):(W="transition",O="transitionend"),G(t.onanimationend)&&_(t.onwebkitanimationend)?(it="-webkit-",z="WebkitAnimation",E="webkitAnimationEnd animationend"):(z="animation",E="animationend");var nt="Duration",st="Property",ot="Delay",at="TimingFunction",rt="IterationCount",lt="PlayState",ht=9999,ct=z+ot,ut=z+nt,dt=W+ot,ft=W+nt,pt=["$$rAF",function(t){function e(t){n=n.concat(t),i()}function i(){if(n.length){for(var e=n.shift(),o=0;o<e.length;o++)e[o]();s||t(function(){s||i()})}}var n,s;return n=e.queue=[],e.waitUntilQuiet=function(e){s&&s(),s=t(function(){s=null,e(),i()})},e}],gt=[function(){return function(t,i,n){var s=n.ngAnimateChildren;e.isString(s)&&0===s.length?i.data(et,!0):n.$observe("ngAnimateChildren",function(t){t="on"===t||"true"===t,i.data(et,t)})}}],vt="$$animateCss",mt=1e3,Ct=3,yt=1.5,bt={transitionDuration:ft,transitionDelay:dt,transitionProperty:W+st,animationDuration:ut,animationDelay:ct,animationIterationCount:z+rt},wt={transitionDuration:ft,transitionDelay:dt,animationDuration:ut,animationDelay:ct},xt=["$animateProvider",function(t){var e=D(),i=D();this.$get=["$window","$$jqLite","$$AnimateRunner","$timeout","$$forceReflow","$sniffer","$$rAFScheduler","$animate",function(t,n,s,l,h,c,u,m){function C(t,e){var i="$$ngAnimateParentKey",n=t.parentNode,s=n[i]||(n[i]=++I);return s+"-"+t.getAttribute("class")+"-"+e}function b(i,n,s,o){var a=e.get(s);return a||(a=$(t,i,o),"infinite"===a.animationIterationCount&&(a.animationIterationCount=1)),e.put(s,a),a}function w(s,o,r,l){var h;if(e.count(r)>0&&(h=i.get(r),!h)){var c=a(o,"-stagger");n.addClass(s,c),h=$(t,s,l),h.animationDuration=Math.max(h.animationDuration,0),h.transitionDuration=Math.max(h.transitionDuration,0),n.removeClass(s,c),i.put(r,h)}return h||{}}function k(t){H.push(t),u.waitUntilQuiet(function(){e.flush(),i.flush();for(var t=h(),n=0;n<H.length;n++)H[n](t);H.length=0})}function F(t,e,i){var n=b(t,e,i,bt),s=n.animationDelay,o=n.transitionDelay;return n.maxDelay=s&&o?Math.max(s,o):s||o,n.maxDuration=Math.max(n.animationDuration*n.animationIterationCount,n.transitionDuration),n}var D=d(n),I=0,H=[];return function(t,i){function h(){d()}function u(){d(!0)}function d(e){V||_&&G||(V=!0,G=!1,i.$$skipPreparationClasses||n.removeClass(t,ft),n.removeClass(t,gt),S(X,!1),x(X,!1),j(nt,function(t){X.style[t[0]]=""}),D(t,i),p(t,i),Object.keys(H).length&&j(H,function(t,e){t?X.style.setProperty(e,t):X.style.removeProperty(e)}),i.onDone&&i.onDone(),N&&N.complete(!e));
+}function b(t){Wt.blockTransition&&x(X,t),Wt.blockKeyframeAnimation&&S(X,!!t)}function $(){return N=new s({end:h,cancel:u}),k(B),d(),{$$willAnimate:!1,start:function(){return N},end:h}}function I(){function e(){if(!V){if(b(!1),j(nt,function(t){var e=t[0],i=t[1];X.style[e]=i}),D(t,i),n.addClass(t,gt),Wt.recalculateTimingStyles){if(pt=X.className+" "+ft,St=C(X,pt),Dt=F(X,pt,St),Mt=Dt.maxDelay,U=Math.max(Mt,0),et=Dt.maxDuration,0===et)return void d();Wt.hasTransitions=Dt.transitionDuration>0,Wt.hasAnimations=Dt.animationDuration>0}if(Wt.applyAnimationDelay&&(Mt="boolean"!=typeof i.delay&&T(i.delay)?parseFloat(i.delay):Mt,U=Math.max(Mt,0),Dt.animationDelay=Mt,Ot=L(Mt,!0),nt.push(Ot),X.style[Ot[0]]=Ot[1]),tt=U*mt,it=et*mt,i.easing){var e,r=i.easing;Wt.hasTransitions&&(e=W+at,nt.push([e,r]),X.style[e]=r),Wt.hasAnimations&&(e=z+at,nt.push([e,r]),X.style[e]=r)}Dt.transitionDuration&&h.push(O),Dt.animationDuration&&h.push(E),a=Date.now();var c=tt+yt*it,u=a+c,f=t.data(vt)||[],p=!0;if(f.length){var g=f[0];p=u>g.expectedEndTime,p?l.cancel(g.timer):f.push(d)}if(p){var m=l(s,c,!1);f[0]={timer:m,expectedEndTime:u},f.push(d),t.data(vt,f)}t.on(h.join(" "),o),i.to&&(i.cleanupStyles&&M(H,X,Object.keys(i.to)),v(t,i))}}function s(){var e=t.data(vt);if(e){for(var i=1;i<e.length;i++)e[i]();t.removeData(vt)}}function o(t){t.stopPropagation();var e=t.originalEvent||t,i=e.$manualTimeStamp||e.timeStamp||Date.now(),n=parseFloat(e.elapsedTime.toFixed(Ct));Math.max(i-a,0)>=tt&&n>=et&&(_=!0,d())}if(!V){if(!X.parentNode)return void d();var a,h=[],c=function(t){if(_)G&&t&&(G=!1,d());else if(G=!t,Dt.animationDuration){var e=S(X,G);G?nt.push(e):r(nt,e)}},u=Tt>0&&(Dt.transitionDuration&&0===Pt.transitionDuration||Dt.animationDuration&&0===Pt.animationDuration)&&Math.max(Pt.animationDelay,Pt.transitionDelay);u?l(e,Math.floor(u*Tt*mt),!1):e(),Y.resume=function(){c(!0)},Y.pause=function(){c(!1)}}}var H={},X=y(t);if(!X||!X.parentNode||!m.enabled())return $();i=f(i);var V,G,_,N,Y,U,tt,et,it,nt=[],ot=t.attr("class"),rt=o(i);if(0===i.duration||!c.animations&&!c.transitions)return $();var lt=i.event&&q(i.event)?i.event.join(" "):i.event,ct=lt&&i.structural,ut="",dt="";ct?ut=a(lt,Z,!0):lt&&(ut=lt),i.addClass&&(dt+=a(i.addClass,J)),i.removeClass&&(dt.length&&(dt+=" "),dt+=a(i.removeClass,Q)),i.applyClassesEarly&&dt.length&&D(t,i);var ft=[ut,dt].join(" ").trim(),pt=ot+" "+ft,gt=a(ft,K),bt=rt.to&&Object.keys(rt.to).length>0,xt=(i.keyframeStyle||"").length>0;if(!xt&&!bt&&!ft)return $();var St,Pt;if(i.stagger>0){var kt=parseFloat(i.stagger);Pt={transitionDelay:kt,animationDelay:kt,transitionDuration:0,animationDuration:0}}else St=C(X,pt),Pt=w(X,ft,St,wt);i.$$skipPreparationClasses||n.addClass(t,ft);var At;if(i.transitionStyle){var Lt=[W,i.transitionStyle];P(X,Lt),nt.push(Lt)}if(i.duration>=0){At=X.style[W].length>0;var $t=R(i.duration,At);P(X,$t),nt.push($t)}if(i.keyframeStyle){var Ft=[z,i.keyframeStyle];P(X,Ft),nt.push(Ft)}var Tt=Pt?i.staggerIndex>=0?i.staggerIndex:e.count(St):0,Rt=0===Tt;Rt&&!i.skipBlocking&&x(X,ht);var Dt=F(X,pt,St),Mt=Dt.maxDelay;U=Math.max(Mt,0),et=Dt.maxDuration;var Wt={};if(Wt.hasTransitions=Dt.transitionDuration>0,Wt.hasAnimations=Dt.animationDuration>0,Wt.hasTransitionAll=Wt.hasTransitions&&"all"==Dt.transitionProperty,Wt.applyTransitionDuration=bt&&(Wt.hasTransitions&&!Wt.hasTransitionAll||Wt.hasAnimations&&!Wt.hasTransitions),Wt.applyAnimationDuration=i.duration&&Wt.hasAnimations,Wt.applyTransitionDelay=T(i.delay)&&(Wt.applyTransitionDuration||Wt.hasTransitions),Wt.applyAnimationDelay=T(i.delay)&&Wt.hasAnimations,Wt.recalculateTimingStyles=dt.length>0,(Wt.applyTransitionDuration||Wt.applyAnimationDuration)&&(et=i.duration?parseFloat(i.duration):et,Wt.applyTransitionDuration&&(Wt.hasTransitions=!0,Dt.transitionDuration=et,At=X.style[W+st].length>0,nt.push(R(et,At))),Wt.applyAnimationDuration&&(Wt.hasAnimations=!0,Dt.animationDuration=et,nt.push(A(et)))),0===et&&!Wt.recalculateTimingStyles)return $();if(null!=i.delay){var Ot=parseFloat(i.delay);Wt.applyTransitionDelay&&nt.push(L(Ot)),Wt.applyAnimationDelay&&nt.push(L(Ot,!0))}return null==i.duration&&Dt.transitionDuration>0&&(Wt.recalculateTimingStyles=Wt.recalculateTimingStyles||Rt),tt=U*mt,it=et*mt,i.skipBlocking||(Wt.blockTransition=Dt.transitionDuration>0,Wt.blockKeyframeAnimation=Dt.animationDuration>0&&Pt.animationDelay>0&&0===Pt.animationDuration),i.from&&(i.cleanupStyles&&M(H,X,Object.keys(i.from)),g(t,i)),Wt.blockTransition||Wt.blockKeyframeAnimation?b(et):i.skipBlocking||x(X,!1),{$$willAnimate:!0,end:h,start:function(){return V?void 0:(Y={end:h,cancel:u,resume:null,pause:null},N=new s(Y),k(I),N)}}}}]}],St=["$$animationProvider",function(t){function e(t){return t.parentNode&&11===t.parentNode.nodeType}t.drivers.push("$$animateCssDriver");var i="ng-animate-shim",n="ng-anchor",s="ng-anchor-out",o="ng-anchor-in";this.$get=["$animateCss","$rootScope","$$AnimateRunner","$rootElement","$sniffer","$$jqLite","$document",function(t,a,r,l,h,c,u){function f(t){return t.replace(/\bng-\S+\b/g,"")}function p(t,e){return X(t)&&(t=t.split(" ")),X(e)&&(e=e.split(" ")),t.filter(function(t){return-1===e.indexOf(t)}).join(" ")}function g(e,a,l){function h(t){var e={},i=y(t).getBoundingClientRect();return j(["width","height","top","left"],function(t){var n=i[t];switch(t){case"top":n+=C.scrollTop;break;case"left":n+=C.scrollLeft}e[t]=Math.floor(n)+"px"}),e}function c(){var e=t(v,{addClass:s,delay:!0,from:h(a)});return e.$$willAnimate?e:null}function u(t){return t.attr("class")||""}function d(){var e=f(u(l)),i=p(e,m),n=p(m,e),a=t(v,{to:h(l),addClass:o+" "+i,removeClass:s+" "+n,delay:!0});return a.$$willAnimate?a:null}function g(){v.remove(),a.removeClass(i),l.removeClass(i)}var v=H(y(a).cloneNode(!0)),m=f(u(v));a.addClass(i),l.addClass(i),v.addClass(n),w.append(v);var b,x=c();if(!x&&(b=d(),!b))return g();var S=x||b;return{start:function(){function t(){i&&i.end()}var e,i=S.start();return i.done(function(){return i=null,!b&&(b=d())?(i=b.start(),i.done(function(){i=null,g(),e.complete()}),i):(g(),void e.complete())}),e=new r({end:t,cancel:t})}}}function v(t,e,i,n){var s=m(t,B),o=m(e,B),a=[];return j(n,function(t){var e=t.out,n=t["in"],s=g(i,e,n);s&&a.push(s)}),s||o||0!==a.length?{start:function(){function t(){j(e,function(t){t.end()})}var e=[];s&&e.push(s.start()),o&&e.push(o.start()),j(a,function(t){e.push(t.start())});var i=new r({end:t,cancel:t});return r.all(e,function(t){i.complete(t)}),i}}:void 0}function m(e){var i=e.element,n=e.options||{};e.structural&&(n.event=e.event,n.structural=!0,n.applyClassesEarly=!0,"leave"===e.event&&(n.onDone=n.domOperation)),n.preparationClasses&&(n.event=k(n.event,n.preparationClasses));var s=t(i,n);return s.$$willAnimate?s:null}if(!h.animations&&!h.transitions)return B;var C=u[0].body,b=y(l),w=H(e(b)||C.contains(b)?b:C);d(c);return function(t){return t.from&&t.to?v(t.from,t.to,t.classes,t.anchors):m(t)}}]}],Pt=["$animateProvider",function(t){this.$get=["$injector","$$AnimateRunner","$$jqLite",function(e,i,n){function s(i){i=q(i)?i:i.split(" ");for(var n=[],s={},o=0;o<i.length;o++){var a=i[o],r=t.$$registeredAnimations[a];r&&!s[a]&&(n.push(e.get(r)),s[a]=!0)}return n}var o=d(n);return function(t,e,n,a){function r(){a.domOperation(),o(t,a)}function l(t,e,n,s,o){var a;switch(n){case"animate":a=[e,s.from,s.to,o];break;case"setClass":a=[e,g,v,o];break;case"addClass":a=[e,g,o];break;case"removeClass":a=[e,v,o];break;default:a=[e,o]}a.push(s);var r=t.apply(t,a);if(r)if(N(r.start)&&(r=r.start()),r instanceof i)r.done(o);else if(N(r))return r;return B}function h(t,e,n,s,o){var a=[];return j(s,function(s){var r=s[o];r&&a.push(function(){var s,o,a=!1,h=function(t){a||(a=!0,(o||B)(t),s.complete(!t))};return s=new i({end:function(){h()},cancel:function(){h(!0)}}),o=l(r,t,e,n,function(t){var e=t===!1;h(e)}),s})}),a}function c(t,e,n,s,o){var a=h(t,e,n,s,o);if(0===a.length){var r,l;"beforeSetClass"===o?(r=h(t,"removeClass",n,s,"beforeRemoveClass"),l=h(t,"addClass",n,s,"beforeAddClass")):"setClass"===o&&(r=h(t,"removeClass",n,s,"removeClass"),l=h(t,"addClass",n,s,"addClass")),r&&(a=a.concat(r)),l&&(a=a.concat(l))}if(0!==a.length)return function(t){var e=[];return a.length&&j(a,function(t){e.push(t())}),e.length?i.all(e,t):t(),function(t){j(e,function(e){t?e.cancel():e.end()})}}}3===arguments.length&&V(n)&&(a=n,n=null),a=f(a),n||(n=t.attr("class")||"",a.addClass&&(n+=" "+a.addClass),a.removeClass&&(n+=" "+a.removeClass));var u,d,g=a.addClass,v=a.removeClass,m=s(n);if(m.length){var C,y;"leave"==e?(y="leave",C="afterLeave"):(y="before"+e.charAt(0).toUpperCase()+e.substr(1),C=e),"enter"!==e&&"move"!==e&&(u=c(t,e,a,m,y)),d=c(t,e,a,m,C)}return u||d?{start:function(){function e(e){l=!0,r(),p(t,a),h.complete(e)}function n(t){l||((s||B)(t),e(t))}var s,o=[];u&&o.push(function(t){s=u(t)}),o.length?o.push(function(t){r(),t(!0)}):r(),d&&o.push(function(t){s=d(t)});var l=!1,h=new i({end:function(){n()},cancel:function(){n(!0)}});return i.chain(o,e),h}}:void 0}}]}],kt=["$$animationProvider",function(t){t.drivers.push("$$animateJsDriver"),this.$get=["$$animateJs","$$AnimateRunner",function(t,e){function i(e){var i=e.element,n=e.event,s=e.options,o=e.classes;return t(i,n,o,s)}return function(t){if(t.from&&t.to){var n=i(t.from),s=i(t.to);if(!n&&!s)return;return{start:function(){function t(){return function(){j(o,function(t){t.end()})}}function i(t){a.complete(t)}var o=[];n&&o.push(n.start()),s&&o.push(s.start()),e.all(o,i);var a=new e({end:t(),cancel:t()});return a}}}return i(t)}}]}],At="data-ng-animate",Lt="$ngAnimatePin",$t=["$animateProvider",function(t){function e(t,e,i,n){return a[t].some(function(t){return t(e,i,n)})}function i(t,e){t=t||{};var i=(t.addClass||"").length>0,n=(t.removeClass||"").length>0;return e?i&&n:i||n}var s=1,o=2,a=this.rules={skip:[],cancel:[],join:[]};a.join.push(function(t,e,n){return!e.structural&&i(e.options)}),a.skip.push(function(t,e,n){return!e.structural&&!i(e.options)}),a.skip.push(function(t,e,i){return"leave"==i.event&&e.structural}),a.skip.push(function(t,e,i){return i.structural&&i.state===o&&!e.structural}),a.cancel.push(function(t,e,i){return i.structural&&e.structural}),a.cancel.push(function(t,e,i){return i.state===o&&e.structural}),a.cancel.push(function(t,e,i){var n=e.options,s=i.options;return n.addClass&&n.addClass===s.removeClass||n.removeClass&&n.removeClass===s.addClass}),this.$get=["$$rAF","$rootScope","$rootElement","$document","$$HashMap","$$animation","$$AnimateRunner","$templateRequest","$$jqLite","$$forceReflow",function(a,r,c,u,g,v,C,x,S,P){function k(){var t=!1;return function(e){t?e():r.$$postDigest(function(){t=!0,e()})}}function A(t,e){return m(t,e,{})}function L(t,e){var i=y(t),n=[],s=B[e];return s&&j(s,function(t){t.node.contains(i)&&n.push(t.callback)}),n}function $(t,n,h){function c(e,i,n,s){S(function(){var e=L(t,i);e.length&&a(function(){j(e,function(e){e(t,n,s)})})}),e.progress(i,n,s)}function u(e){w(t,h),Q(t,h),p(t,h),h.domOperation(),x.complete(!e)}var d,g;t=l(t),t&&(d=y(t),g=t.parent()),h=f(h);var x=new C,S=k();if(q(h.addClass)&&(h.addClass=h.addClass.join(" ")),h.addClass&&!X(h.addClass)&&(h.addClass=null),q(h.removeClass)&&(h.removeClass=h.removeClass.join(" ")),h.removeClass&&!X(h.removeClass)&&(h.removeClass=null),h.from&&!V(h.from)&&(h.from=null),h.to&&!V(h.to)&&(h.to=null),!d)return u(),x;var P=[d.className,h.addClass,h.removeClass].join(" ");if(!J(P))return u(),x;var $=["enter","move","leave"].indexOf(n)>=0,R=!z||O.get(d),E=!R&&W.get(d)||{},B=!!E.state;if(R||B&&E.state==s||(R=!D(t,g,n)),R)return u(),x;$&&F(t);var I={structural:$,element:t,event:n,close:u,options:h,runner:x};if(B){var H=e("skip",t,I,E);if(H)return E.state===o?(u(),x):(m(t,E.options,h),E.runner);var G=e("cancel",t,I,E);if(G)if(E.state===o)E.runner.end();else{if(!E.structural)return m(t,E.options,I.options),E.runner;E.close()}else{var _=e("join",t,I,E);if(_){if(E.state!==o)return b(t,$?n:null,h),n=I.event=E.event,h=m(t,E.options,I.options),E.runner;A(t,h)}}}else A(t,h);var N=I.structural;if(N||(N="animate"===I.event&&Object.keys(I.options.to||{}).length>0||i(I.options)),!N)return u(),T(t),x;var Y=(E.counter||0)+1;return I.counter=Y,M(t,s,I),r.$$postDigest(function(){var e=W.get(d),s=!e;e=e||{};var a=t.parent()||[],r=a.length>0&&("animate"===e.event||e.structural||i(e.options));if(s||e.counter!==Y||!r)return s&&(Q(t,h),p(t,h)),(s||$&&e.event!==n)&&(h.domOperation(),x.end()),void(r||T(t));n=!e.structural&&i(e.options,!0)?"setClass":e.event,M(t,o);var l=v(t,n,e.options);l.done(function(e){u(!e);var i=W.get(d);i&&i.counter===Y&&T(y(t)),c(x,n,"close",{})}),x.setHost(l),c(x,n,"start",{})}),x}function F(t){var e=y(t),i=e.querySelectorAll("["+At+"]");j(i,function(t){var e=parseInt(t.getAttribute(At)),i=W.get(t);switch(e){case o:i.runner.end();case s:i&&W.remove(t)}})}function T(t){var e=y(t);e.removeAttribute(At),W.remove(e)}function R(t,e){return y(t)===y(e)}function D(t,e,i){var n,s=H(u[0].body),o=R(t,s)||"HTML"===t[0].nodeName,a=R(t,c),r=!1,l=t.data(Lt);for(l&&(e=l);e&&e.length;){a||(a=R(e,c));var h=e[0];if(h.nodeType!==U)break;var d=W.get(h)||{};if(r||(r=d.structural||O.get(h)),G(n)||n===!0){var f=e.data(et);_(f)&&(n=f)}if(r&&n===!1)break;a||(a=R(e,c),a||(l=e.data(Lt),l&&(e=l))),o||(o=R(e,s)),e=e.parent()}var p=!r||n;return p&&a&&o}function M(t,e,i){i=i||{},i.state=e;var n=y(t);n.setAttribute(At,e);var s=W.get(n),o=s?I(s,i):i;W.put(n,o)}var W=new g,O=new g,z=null,E=r.$watch(function(){return 0===x.totalPendingRequests},function(t){t&&(E(),r.$$postDigest(function(){r.$$postDigest(function(){null===z&&(z=!0)})}))}),B={},N=t.classNameFilter(),J=N?function(t){return N.test(t)}:function(){return!0},Q=d(S);return{on:function(t,e,i){var n=h(e);B[t]=B[t]||[],B[t].push({node:n,callback:i})},off:function(t,e,i){function n(t,e,i){var n=h(e);return t.filter(function(t){var e=t.node===n&&(!i||t.callback===i);return!e})}var s=B[t];s&&(B[t]=1===arguments.length?null:n(s,e,i))},pin:function(t,e){n(Y(t),"element","not an element"),n(Y(e),"parentElement","not an element"),t.data(Lt,e)},push:function(t,e,i,n){return i=i||{},i.domOperation=n,$(t,e,i)},enabled:function(t,e){var i=arguments.length;if(0===i)e=!!z;else{var n=Y(t);if(n){var s=y(t),o=O.get(s);1===i?e=!o:(e=!!e,e?o&&O.remove(s):O.put(s,!0))}else e=z=!!t}return e}}}]}],Ft=["$$rAF",function(t){function e(e){i.push(e),i.length>1||t(function(){for(var t=0;t<i.length;t++)i[t]();i=[]})}var i=[];return function(){var t=!1;return e(function(){t=!0}),function(i){t?i():e(i)}}}],Tt=["$q","$sniffer","$$animateAsyncRun",function(t,e,i){function n(t){this.setHost(t),this._doneCallbacks=[],this._runInAnimationFrame=i(),this._state=0}var s=0,o=1,a=2;return n.chain=function(t,e){function i(){return n===t.length?void e(!0):void t[n](function(t){return t===!1?void e(!1):(n++,void i())})}var n=0;i()},n.all=function(t,e){function i(i){s=s&&i,++n===t.length&&e(s)}var n=0,s=!0;j(t,function(t){t.done(i)})},n.prototype={setHost:function(t){this.host=t||{}},done:function(t){this._state===a?t():this._doneCallbacks.push(t)},progress:B,getPromise:function(){if(!this.promise){var e=this;this.promise=t(function(t,i){e.done(function(e){e===!1?i():t()})})}return this.promise},then:function(t,e){return this.getPromise().then(t,e)},"catch":function(t){return this.getPromise()["catch"](t)},"finally":function(t){return this.getPromise()["finally"](t)},pause:function(){this.host.pause&&this.host.pause()},resume:function(){this.host.resume&&this.host.resume()},end:function(){this.host.end&&this.host.end(),this._resolve(!0)},cancel:function(){this.host.cancel&&this.host.cancel(),this._resolve(!1)},complete:function(t){var e=this;e._state===s&&(e._state=o,e._runInAnimationFrame(function(){e._resolve(t)}))},_resolve:function(t){this._state!==a&&(j(this._doneCallbacks,function(e){e(t)}),this._doneCallbacks.length=0,this._state=a)}},n}],Rt=["$animateProvider",function(t){function e(t,e){t.data(r,e)}function i(t){t.removeData(r)}function n(t){return t.data(r)}var o="ng-animate-ref",a=this.drivers=[],r="$$animationRunner";this.$get=["$$jqLite","$rootScope","$injector","$$AnimateRunner","$$HashMap","$$rAFScheduler",function(t,r,l,h,c,u){function g(t){function e(t){if(t.processed)return t;t.processed=!0;var i=t.domNode,n=i.parentNode;o.put(i,t);for(var a;n;){if(a=o.get(n)){a.processed||(a=e(a));break}n=n.parentNode}return(a||s).children.push(t),t}function i(t){var e,i=[],n=[];for(e=0;e<t.children.length;e++)n.push(t.children[e]);var s=n.length,o=0,a=[];for(e=0;e<n.length;e++){var r=n[e];0>=s&&(s=o,o=0,i.push(a),a=[]),a.push(r.fn),r.children.forEach(function(t){o++,n.push(t)}),s--}return a.length&&i.push(a),i}var n,s={children:[]},o=new c;for(n=0;n<t.length;n++){var a=t[n];o.put(a.domNode,t[n]={domNode:a.domNode,fn:a.fn,children:[]})}for(n=0;n<t.length;n++)e(t[n]);return i(s)}var v=[],m=d(t);return function(c,d,C){function b(t){var e="["+o+"]",i=t.hasAttribute(o)?[t]:t.querySelectorAll(e),n=[];return j(i,function(t){var e=t.getAttribute(o);e&&e.length&&n.push(t)}),n}function w(t){var e=[],i={};j(t,function(t,n){var s=t.element,a=y(s),r=t.event,l=["enter","move"].indexOf(r)>=0,h=t.structural?b(a):[];if(h.length){var c=l?"to":"from";j(h,function(t){var e=t.getAttribute(o);i[e]=i[e]||{},i[e][c]={animationID:n,element:H(t)}})}else e.push(t)});var n={},s={};return j(i,function(i,o){var a=i.from,r=i.to;if(!a||!r){var l=a?a.animationID:r.animationID,h=l.toString();return void(n[h]||(n[h]=!0,e.push(t[l])))}var c=t[a.animationID],u=t[r.animationID],d=a.animationID.toString();if(!s[d]){var f=s[d]={structural:!0,beforeStart:function(){c.beforeStart(),u.beforeStart()},close:function(){c.close(),u.close()},classes:x(c.classes,u.classes),from:c,to:u,anchors:[]};f.classes.length?e.push(f):(e.push(c),e.push(u))}s[d].anchors.push({out:a.element,"in":r.element})}),e}function x(t,e){t=t.split(" "),e=e.split(" ");for(var i=[],n=0;n<t.length;n++){var s=t[n];if("ng-"!==s.substring(0,3))for(var o=0;o<e.length;o++)if(s===e[o]){i.push(s);break}}return i.join(" ")}function S(t){for(var e=a.length-1;e>=0;e--){var i=a[e];if(l.has(i)){var n=l.get(i),s=n(t);if(s)return s}}}function P(){c.addClass(tt),R&&t.addClass(c,R)}function k(t,e){function i(t){n(t).setHost(e)}t.from&&t.to?(i(t.from.element),i(t.to.element)):i(t.element)}function A(){var t=n(c);!t||"leave"===d&&C.$$domOperationFired||t.end()}function L(e){c.off("$destroy",A),i(c),m(c,C),p(c,C),C.domOperation(),R&&t.removeClass(c,R),c.removeClass(tt),F.complete(!e)}C=f(C);var $=["enter","move","leave"].indexOf(d)>=0,F=new h({end:function(){L()},cancel:function(){L(!0)}});if(!a.length)return L(),F;e(c,F);var T=s(c.attr("class"),s(C.addClass,C.removeClass)),R=C.tempClasses;return R&&(T+=" "+R,C.tempClasses=null),v.push({element:c,classes:T,event:d,structural:$,options:C,beforeStart:P,close:L}),c.on("$destroy",A),v.length>1?F:(r.$$postDigest(function(){var t=[];j(v,function(e){n(e.element)?t.push(e):e.close()}),v.length=0;var e=w(t),i=[];j(e,function(t){i.push({domNode:y(t.from?t.from.element:t.element),fn:function(){t.beforeStart();var e,i=t.close,s=t.anchors?t.from.element||t.to.element:t.element;if(n(s)){var o=S(t);o&&(e=o.start)}if(e){var a=e();a.done(function(t){i(!t)}),k(t,a)}else i()}})}),u(g(i))}),F)}}]}];e.module("ngAnimate",[]).directive("ngAnimateChildren",gt).factory("$$rAFScheduler",pt).factory("$$AnimateRunner",Tt).factory("$$animateAsyncRun",Ft).provider("$$animateQueue",$t).provider("$$animation",Rt).provider("$animateCss",xt).provider("$$animateCssDriver",St).provider("$$animateJs",Pt).provider("$$animateJsDriver",kt)}(window,window.angular),angular.module("ui.bootstrap.accordion",["ui.bootstrap.collapse"]).constant("uibAccordionConfig",{closeOthers:!0}).controller("UibAccordionController",["$scope","$attrs","uibAccordionConfig",function(t,e,i){this.groups=[],this.closeOthers=function(n){var s=angular.isDefined(e.closeOthers)?t.$eval(e.closeOthers):i.closeOthers;s&&angular.forEach(this.groups,function(t){t!==n&&(t.isOpen=!1)})},this.addGroup=function(t){var e=this;this.groups.push(t),t.$on("$destroy",function(i){e.removeGroup(t)})},this.removeGroup=function(t){var e=this.groups.indexOf(t);-1!==e&&this.groups.splice(e,1)}}]).directive("uibAccordion",function(){return{controller:"UibAccordionController",controllerAs:"accordion",transclude:!0,templateUrl:function(t,e){return e.templateUrl||"template/accordion/accordion.html"}}}).directive("uibAccordionGroup",function(){return{require:"^uibAccordion",transclude:!0,replace:!0,templateUrl:function(t,e){return e.templateUrl||"template/accordion/accordion-group.html"},scope:{heading:"@",isOpen:"=?",isDisabled:"=?"},controller:function(){this.setHeading=function(t){this.heading=t}},link:function(t,e,i,n){n.addGroup(t),t.openClass=i.openClass||"panel-open",t.panelClass=i.panelClass,t.$watch("isOpen",function(i){e.toggleClass(t.openClass,!!i),i&&n.closeOthers(t)}),t.toggleOpen=function(e){t.isDisabled||e&&32!==e.which||(t.isOpen=!t.isOpen)}}}}).directive("uibAccordionHeading",function(){return{transclude:!0,template:"",replace:!0,require:"^uibAccordionGroup",link:function(t,e,i,n,s){n.setHeading(s(t,angular.noop))}}}).directive("uibAccordionTransclude",function(){return{require:["?^uibAccordionGroup","?^accordionGroup"],link:function(t,e,i,n){n=n[0]?n[0]:n[1],t.$watch(function(){return n[i.uibAccordionTransclude]},function(t){t&&(e.find("span").html(""),e.find("span").append(t))})}}}),angular.module("ui.bootstrap.accordion").value("$accordionSuppressWarning",!1).controller("AccordionController",["$scope","$attrs","$controller","$log","$accordionSuppressWarning",function(t,e,i,n,s){s||n.warn("AccordionController is now deprecated. Use UibAccordionController instead."),angular.extend(this,i("UibAccordionController",{$scope:t,$attrs:e}))}]).directive("accordion",["$log","$accordionSuppressWarning",function(t,e){return{restrict:"EA",controller:"AccordionController",controllerAs:"accordion",transclude:!0,replace:!1,templateUrl:function(t,e){return e.templateUrl||"template/accordion/accordion.html"},link:function(){e||t.warn("accordion is now deprecated. Use uib-accordion instead.")}}}]).directive("accordionGroup",["$log","$accordionSuppressWarning",function(t,e){return{require:"^accordion",restrict:"EA",transclude:!0,replace:!0,templateUrl:function(t,e){return e.templateUrl||"template/accordion/accordion-group.html"},scope:{heading:"@",isOpen:"=?",isDisabled:"=?"},controller:function(){this.setHeading=function(t){this.heading=t}},link:function(i,n,s,o){e||t.warn("accordion-group is now deprecated. Use uib-accordion-group instead."),o.addGroup(i),i.openClass=s.openClass||"panel-open",i.panelClass=s.panelClass,i.$watch("isOpen",function(t){n.toggleClass(i.openClass,!!t),t&&o.closeOthers(i)}),i.toggleOpen=function(t){i.isDisabled||t&&32!==t.which||(i.isOpen=!i.isOpen)}}}}]).directive("accordionHeading",["$log","$accordionSuppressWarning",function(t,e){return{restrict:"EA",transclude:!0,template:"",replace:!0,require:"^accordionGroup",link:function(i,n,s,o,a){e||t.warn("accordion-heading is now deprecated. Use uib-accordion-heading instead."),o.setHeading(a(i,angular.noop))}}}]).directive("accordionTransclude",["$log","$accordionSuppressWarning",function(t,e){return{require:"^accordionGroup",link:function(i,n,s,o){e||t.warn("accordion-transclude is now deprecated. Use uib-accordion-transclude instead."),i.$watch(function(){return o[s.accordionTransclude]},function(t){t&&(n.find("span").html(""),n.find("span").append(t))})}}}]),angular.module("ui.bootstrap.collapse",[]).directive("uibCollapse",["$animate","$injector",function(t,e){var i=e.has("$animateCss")?e.get("$animateCss"):null;return{link:function(e,n,s){function o(){n.removeClass("collapse").addClass("collapsing").attr("aria-expanded",!0).attr("aria-hidden",!1),i?i(n,{addClass:"in",easing:"ease",to:{height:n[0].scrollHeight+"px"}}).start()["finally"](a):t.addClass(n,"in",{to:{height:n[0].scrollHeight+"px"}}).then(a)}function a(){n.removeClass("collapsing").addClass("collapse").css({height:"auto"})}function r(){return n.hasClass("collapse")||n.hasClass("in")?(n.css({height:n[0].scrollHeight+"px"}).removeClass("collapse").addClass("collapsing").attr("aria-expanded",!1).attr("aria-hidden",!0),void(i?i(n,{removeClass:"in",to:{height:"0"}}).start()["finally"](l):t.removeClass(n,"in",{to:{height:"0"}}).then(l))):l()}function l(){n.css({height:"0"}),n.removeClass("collapsing").addClass("collapse")}e.$watch(s.uibCollapse,function(t){t?r():o()})}}}]),angular.module("ui.bootstrap.collapse").value("$collapseSuppressWarning",!1).directive("collapse",["$animate","$injector","$log","$collapseSuppressWarning",function(t,e,i,n){var s=e.has("$animateCss")?e.get("$animateCss"):null;return{link:function(e,o,a){function r(){o.removeClass("collapse").addClass("collapsing").attr("aria-expanded",!0).attr("aria-hidden",!1),s?s(o,{easing:"ease",to:{height:o[0].scrollHeight+"px"}}).start().done(l):t.animate(o,{},{height:o[0].scrollHeight+"px"}).then(l)}function l(){o.removeClass("collapsing").addClass("collapse in").css({height:"auto"})}function h(){return o.hasClass("collapse")||o.hasClass("in")?(o.css({height:o[0].scrollHeight+"px"}).removeClass("collapse in").addClass("collapsing").attr("aria-expanded",!1).attr("aria-hidden",!0),void(s?s(o,{to:{height:"0"}}).start().done(c):t.animate(o,{},{height:"0"}).then(c))):c()}function c(){o.css({height:"0"}),o.removeClass("collapsing").addClass("collapse")}n||i.warn("collapse is now deprecated. Use uib-collapse instead."),e.$watch(a.collapse,function(t){t?h():r()})}}}]);
\ No newline at end of file
diff --git a/xos/core/xoslib/static/js/vendor/xosDiagnosticVendor.js b/xos/core/xoslib/static/js/vendor/xosDiagnosticVendor.js
new file mode 100644
index 0000000..9ef6d6d
--- /dev/null
+++ b/xos/core/xoslib/static/js/vendor/xosDiagnosticVendor.js
@@ -0,0 +1,8 @@
+!function(){function n(n){return n&&(n.ownerDocument||n.document||n).documentElement}function t(n){return n&&(n.ownerDocument&&n.ownerDocument.defaultView||n.document&&n||n.defaultView)}function r(n,t){return t>n?-1:n>t?1:n>=t?0:NaN}function e(n){return null===n?NaN:+n}function i(n){return!isNaN(n)}function u(n){return{left:function(t,r,e,i){for(arguments.length<3&&(e=0),arguments.length<4&&(i=t.length);i>e;){var u=e+i>>>1;n(t[u],r)<0?e=u+1:i=u}return e},right:function(t,r,e,i){for(arguments.length<3&&(e=0),arguments.length<4&&(i=t.length);i>e;){var u=e+i>>>1;n(t[u],r)>0?i=u:e=u+1}return e}}}function o(n){return n.length}function a(n){for(var t=1;n*t%1;)t*=10;return t}function c(n,t){for(var r in t)Object.defineProperty(n.prototype,r,{value:t[r],enumerable:!1})}function l(){this._=Object.create(null)}function f(n){return(n+="")===Mo||n[0]===bo?bo+n:n}function s(n){return(n+="")[0]===bo?n.slice(1):n}function h(n){return f(n)in this._}function p(n){return(n=f(n))in this._&&delete this._[n]}function v(){var n=[];for(var t in this._)n.push(s(t));return n}function g(){var n=0;for(var t in this._)++n;return n}function d(){for(var n in this._)return!1;return!0}function y(){this._=Object.create(null)}function m(n){return n}function _(n,t,r){return function(){var e=r.apply(t,arguments);return e===t?n:e}}function x(n,t){if(t in n)return t;t=t.charAt(0).toUpperCase()+t.slice(1);for(var r=0,e=wo.length;e>r;++r){var i=wo[r]+t;if(i in n)return i}}function M(){}function b(){}function w(n){function t(){for(var t,e=r,i=-1,u=e.length;++i<u;)(t=e[i].on)&&t.apply(this,arguments);return n}var r=[],e=new l;return t.on=function(t,i){var u,o=e.get(t);return arguments.length<2?o&&o.on:(o&&(o.on=null,r=r.slice(0,u=r.indexOf(o)).concat(r.slice(u+1)),e.remove(t)),i&&r.push(e.set(t,{on:i})),n)},t}function k(){ao.event.preventDefault()}function C(){for(var n,t=ao.event;n=t.sourceEvent;)t=n;return t}function A(n){for(var t=new b,r=0,e=arguments.length;++r<e;)t[arguments[r]]=w(t);return t.of=function(r,e){return function(i){try{var u=i.sourceEvent=ao.event;i.target=n,ao.event=i,t[i.type].apply(r,e)}finally{ao.event=u}}},t}function S(n){return Co(n,No),n}function E(n){return"function"==typeof n?n:function(){return Ao(n,this)}}function N(n){return"function"==typeof n?n:function(){return So(n,this)}}function $(n,t){function r(){this.removeAttribute(n)}function e(){this.removeAttributeNS(n.space,n.local)}function i(){this.setAttribute(n,t)}function u(){this.setAttributeNS(n.space,n.local,t)}function o(){var r=t.apply(this,arguments);null==r?this.removeAttribute(n):this.setAttribute(n,r)}function a(){var r=t.apply(this,arguments);null==r?this.removeAttributeNS(n.space,n.local):this.setAttributeNS(n.space,n.local,r)}return n=ao.ns.qualify(n),null==t?n.local?e:r:"function"==typeof t?n.local?a:o:n.local?u:i}function j(n){return n.trim().replace(/\s+/g," ")}function D(n){return new RegExp("(?:^|\\s+)"+ao.requote(n)+"(?:\\s+|$)","g")}function T(n){return(n+"").trim().split(/^|\s+/)}function L(n,t){function r(){for(var r=-1;++r<i;)n[r](this,t)}function e(){for(var r=-1,e=t.apply(this,arguments);++r<i;)n[r](this,e)}n=T(n).map(R);var i=n.length;return"function"==typeof t?e:r}function R(n){var t=D(n);return function(r,e){if(i=r.classList)return e?i.add(n):i.remove(n);var i=r.getAttribute("class")||"";e?(t.lastIndex=0,t.test(i)||r.setAttribute("class",j(i+" "+n))):r.setAttribute("class",j(i.replace(t," ")))}}function O(n,t,r){function e(){this.style.removeProperty(n)}function i(){this.style.setProperty(n,t,r)}function u(){var e=t.apply(this,arguments);null==e?this.style.removeProperty(n):this.style.setProperty(n,e,r)}return null==t?e:"function"==typeof t?u:i}function z(n,t){function r(){delete this[n]}function e(){this[n]=t}function i(){var r=t.apply(this,arguments);null==r?delete this[n]:this[n]=r}return null==t?r:"function"==typeof t?i:e}function q(n){function t(){var t=this.ownerDocument,r=this.namespaceURI;return r&&r!==t.documentElement.namespaceURI?t.createElementNS(r,n):t.createElement(n)}function r(){return this.ownerDocument.createElementNS(n.space,n.local)}return"function"==typeof n?n:(n=ao.ns.qualify(n)).local?r:t}function I(){var n=this.parentNode;n&&n.removeChild(this)}function P(n){return{__data__:n}}function U(n){return function(){return Eo(this,n)}}function F(n){return arguments.length||(n=r),function(t,r){return t&&r?n(t.__data__,r.__data__):!t-!r}}function H(n,t){for(var r=0,e=n.length;e>r;r++)for(var i,u=n[r],o=0,a=u.length;a>o;o++)(i=u[o])&&t(i,o,r);return n}function W(n){return Co(n,jo),n}function B(n){var t,r;return function(e,i,u){var o,a=n[u].update,c=a.length;for(u!=r&&(r=u,t=0),i>=t&&(t=i+1);!(o=a[t])&&++t<c;);return o}}function Y(n,t,r){function e(){var t=this[o];t&&(this.removeEventListener(n,t,t.$),delete this[o])}function i(){var i=c(t,lo(arguments));e.call(this),this.addEventListener(n,this[o]=i,i.$=r),i._=t}function u(){var t,r=new RegExp("^__on([^.]+)"+ao.requote(n)+"$");for(var e in this)if(t=e.match(r)){var i=this[e];this.removeEventListener(t[1],i,i.$),delete this[e]}}var o="__on"+n,a=n.indexOf("."),c=Z;a>0&&(n=n.slice(0,a));var l=Do.get(n);return l&&(n=l,c=V),a?t?i:e:t?M:u}function Z(n,t){return function(r){var e=ao.event;ao.event=r,t[0]=this.__data__;try{n.apply(this,t)}finally{ao.event=e}}}function V(n,t){var r=Z(n,t);return function(n){var t=this,e=n.relatedTarget;e&&(e===t||8&e.compareDocumentPosition(t))||r.call(t,n)}}function X(r){var e=".dragsuppress-"+ ++Lo,i="click"+e,u=ao.select(t(r)).on("touchmove"+e,k).on("dragstart"+e,k).on("selectstart"+e,k);if(null==To&&(To="onselectstart"in r?!1:x(r.style,"userSelect")),To){var o=n(r).style,a=o[To];o[To]="none"}return function(n){if(u.on(e,null),To&&(o[To]=a),n){var t=function(){u.on(i,null)};u.on(i,function(){k(),t()},!0),setTimeout(t,0)}}}function K(n,r){r.changedTouches&&(r=r.changedTouches[0]);var e=n.ownerSVGElement||n;if(e.createSVGPoint){var i=e.createSVGPoint();if(0>Ro){var u=t(n);if(u.scrollX||u.scrollY){e=ao.select("body").append("svg").style({position:"absolute",top:0,left:0,margin:0,padding:0,border:"none"},"important");var o=e[0][0].getScreenCTM();Ro=!(o.f||o.e),e.remove()}}return Ro?(i.x=r.pageX,i.y=r.pageY):(i.x=r.clientX,i.y=r.clientY),i=i.matrixTransform(n.getScreenCTM().inverse()),[i.x,i.y]}var a=n.getBoundingClientRect();return[r.clientX-a.left-n.clientLeft,r.clientY-a.top-n.clientTop]}function J(){return ao.event.changedTouches[0].identifier}function Q(n){return n>0?1:0>n?-1:0}function G(n,t,r){return(t[0]-n[0])*(r[1]-n[1])-(t[1]-n[1])*(r[0]-n[0])}function nn(n){return n>1?0:-1>n?qo:Math.acos(n)}function tn(n){return n>1?Uo:-1>n?-Uo:Math.asin(n)}function rn(n){return((n=Math.exp(n))-1/n)/2}function en(n){return((n=Math.exp(n))+1/n)/2}function un(n){return((n=Math.exp(2*n))-1)/(n+1)}function on(n){return(n=Math.sin(n/2))*n}function an(){}function cn(n,t,r){return this instanceof cn?(this.h=+n,this.s=+t,void(this.l=+r)):arguments.length<2?n instanceof cn?new cn(n.h,n.s,n.l):bn(""+n,wn,cn):new cn(n,t,r)}function ln(n,t,r){function e(n){return n>360?n-=360:0>n&&(n+=360),60>n?u+(o-u)*n/60:180>n?o:240>n?u+(o-u)*(240-n)/60:u}function i(n){return Math.round(255*e(n))}var u,o;return n=isNaN(n)?0:(n%=360)<0?n+360:n,t=isNaN(t)?0:0>t?0:t>1?1:t,r=0>r?0:r>1?1:r,o=.5>=r?r*(1+t):r+t-r*t,u=2*r-o,new mn(i(n+120),i(n),i(n-120))}function fn(n,t,r){return this instanceof fn?(this.h=+n,this.c=+t,void(this.l=+r)):arguments.length<2?n instanceof fn?new fn(n.h,n.c,n.l):n instanceof hn?vn(n.l,n.a,n.b):vn((n=kn((n=ao.rgb(n)).r,n.g,n.b)).l,n.a,n.b):new fn(n,t,r)}function sn(n,t,r){return isNaN(n)&&(n=0),isNaN(t)&&(t=0),new hn(r,Math.cos(n*=Fo)*t,Math.sin(n)*t)}function hn(n,t,r){return this instanceof hn?(this.l=+n,this.a=+t,void(this.b=+r)):arguments.length<2?n instanceof hn?new hn(n.l,n.a,n.b):n instanceof fn?sn(n.h,n.c,n.l):kn((n=mn(n)).r,n.g,n.b):new hn(n,t,r)}function pn(n,t,r){var e=(n+16)/116,i=e+t/500,u=e-r/200;return i=gn(i)*Go,e=gn(e)*na,u=gn(u)*ta,new mn(yn(3.2404542*i-1.5371385*e-.4985314*u),yn(-.969266*i+1.8760108*e+.041556*u),yn(.0556434*i-.2040259*e+1.0572252*u))}function vn(n,t,r){return n>0?new fn(Math.atan2(r,t)*Ho,Math.sqrt(t*t+r*r),n):new fn(NaN,NaN,n)}function gn(n){return n>.206893034?n*n*n:(n-4/29)/7.787037}function dn(n){return n>.008856?Math.pow(n,1/3):7.787037*n+4/29}function yn(n){return Math.round(255*(.00304>=n?12.92*n:1.055*Math.pow(n,1/2.4)-.055))}function mn(n,t,r){return this instanceof mn?(this.r=~~n,this.g=~~t,void(this.b=~~r)):arguments.length<2?n instanceof mn?new mn(n.r,n.g,n.b):bn(""+n,mn,ln):new mn(n,t,r)}function _n(n){return new mn(n>>16,n>>8&255,255&n)}function xn(n){return _n(n)+""}function Mn(n){return 16>n?"0"+Math.max(0,n).toString(16):Math.min(255,n).toString(16)}function bn(n,t,r){var e,i,u,o=0,a=0,c=0;if(e=/([a-z]+)\((.*)\)/.exec(n=n.toLowerCase()))switch(i=e[2].split(","),e[1]){case"hsl":return r(parseFloat(i[0]),parseFloat(i[1])/100,parseFloat(i[2])/100);case"rgb":return t(An(i[0]),An(i[1]),An(i[2]))}return(u=ia.get(n))?t(u.r,u.g,u.b):(null==n||"#"!==n.charAt(0)||isNaN(u=parseInt(n.slice(1),16))||(4===n.length?(o=(3840&u)>>4,o=o>>4|o,a=240&u,a=a>>4|a,c=15&u,c=c<<4|c):7===n.length&&(o=(16711680&u)>>16,a=(65280&u)>>8,c=255&u)),t(o,a,c))}function wn(n,t,r){var e,i,u=Math.min(n/=255,t/=255,r/=255),o=Math.max(n,t,r),a=o-u,c=(o+u)/2;return a?(i=.5>c?a/(o+u):a/(2-o-u),e=n==o?(t-r)/a+(r>t?6:0):t==o?(r-n)/a+2:(n-t)/a+4,e*=60):(e=NaN,i=c>0&&1>c?0:e),new cn(e,i,c)}function kn(n,t,r){n=Cn(n),t=Cn(t),r=Cn(r);var e=dn((.4124564*n+.3575761*t+.1804375*r)/Go),i=dn((.2126729*n+.7151522*t+.072175*r)/na),u=dn((.0193339*n+.119192*t+.9503041*r)/ta);return hn(116*i-16,500*(e-i),200*(i-u))}function Cn(n){return(n/=255)<=.04045?n/12.92:Math.pow((n+.055)/1.055,2.4)}function An(n){var t=parseFloat(n);return"%"===n.charAt(n.length-1)?Math.round(2.55*t):t}function Sn(n){return"function"==typeof n?n:function(){return n}}function En(n){return function(t,r,e){return 2===arguments.length&&"function"==typeof r&&(e=r,r=null),Nn(t,r,n,e)}}function Nn(n,t,r,e){function i(){var n,t=c.status;if(!t&&jn(c)||t>=200&&300>t||304===t){try{n=r.call(u,c)}catch(e){return void o.error.call(u,e)}o.load.call(u,n)}else o.error.call(u,c)}var u={},o=ao.dispatch("beforesend","progress","load","error"),a={},c=new XMLHttpRequest,l=null;return!this.XDomainRequest||"withCredentials"in c||!/^(http(s)?:)?\/\//.test(n)||(c=new XDomainRequest),"onload"in c?c.onload=c.onerror=i:c.onreadystatechange=function(){c.readyState>3&&i()},c.onprogress=function(n){var t=ao.event;ao.event=n;try{o.progress.call(u,c)}finally{ao.event=t}},u.header=function(n,t){return n=(n+"").toLowerCase(),arguments.length<2?a[n]:(null==t?delete a[n]:a[n]=t+"",u)},u.mimeType=function(n){return arguments.length?(t=null==n?null:n+"",u):t},u.responseType=function(n){return arguments.length?(l=n,u):l},u.response=function(n){return r=n,u},["get","post"].forEach(function(n){u[n]=function(){return u.send.apply(u,[n].concat(lo(arguments)))}}),u.send=function(r,e,i){if(2===arguments.length&&"function"==typeof e&&(i=e,e=null),c.open(r,n,!0),null==t||"accept"in a||(a.accept=t+",*/*"),c.setRequestHeader)for(var f in a)c.setRequestHeader(f,a[f]);return null!=t&&c.overrideMimeType&&c.overrideMimeType(t),null!=l&&(c.responseType=l),null!=i&&u.on("error",i).on("load",function(n){i(null,n)}),o.beforesend.call(u,c),c.send(null==e?null:e),u},u.abort=function(){return c.abort(),u},ao.rebind(u,o,"on"),null==e?u:u.get($n(e))}function $n(n){return 1===n.length?function(t,r){n(null==t?r:null)}:n}function jn(n){var t=n.responseType;return t&&"text"!==t?n.response:n.responseText}function Dn(n,t,r){var e=arguments.length;2>e&&(t=0),3>e&&(r=Date.now());var i=r+t,u={c:n,t:i,n:null};return oa?oa.n=u:ua=u,oa=u,aa||(ca=clearTimeout(ca),aa=1,la(Tn)),u}function Tn(){var n=Ln(),t=Rn()-n;t>24?(isFinite(t)&&(clearTimeout(ca),ca=setTimeout(Tn,t)),aa=0):(aa=1,la(Tn))}function Ln(){for(var n=Date.now(),t=ua;t;)n>=t.t&&t.c(n-t.t)&&(t.c=null),t=t.n;return n}function Rn(){for(var n,t=ua,r=1/0;t;)t.c?(t.t<r&&(r=t.t),t=(n=t).n):t=n?n.n=t.n:ua=t.n;return oa=n,r}function On(n,t){return t-(n?Math.ceil(Math.log(n)/Math.LN10):1)}function zn(n,t){var r=Math.pow(10,3*xo(8-t));return{scale:t>8?function(n){return n/r}:function(n){return n*r},symbol:n}}function qn(n){var t=n.decimal,r=n.thousands,e=n.grouping,i=n.currency,u=e&&r?function(n,t){for(var i=n.length,u=[],o=0,a=e[0],c=0;i>0&&a>0&&(c+a+1>t&&(a=Math.max(1,t-c)),u.push(n.substring(i-=a,i+a)),!((c+=a+1)>t));)a=e[o=(o+1)%e.length];return u.reverse().join(r)}:m;return function(n){var r=sa.exec(n),e=r[1]||" ",o=r[2]||">",a=r[3]||"-",c=r[4]||"",l=r[5],f=+r[6],s=r[7],h=r[8],p=r[9],v=1,g="",d="",y=!1,m=!0;switch(h&&(h=+h.substring(1)),(l||"0"===e&&"="===o)&&(l=e="0",o="="),p){case"n":s=!0,p="g";break;case"%":v=100,d="%",p="f";break;case"p":v=100,d="%",p="r";break;case"b":case"o":case"x":case"X":"#"===c&&(g="0"+p.toLowerCase());case"c":m=!1;case"d":y=!0,h=0;break;case"s":v=-1,p="r"}"$"===c&&(g=i[0],d=i[1]),"r"!=p||h||(p="g"),null!=h&&("g"==p?h=Math.max(1,Math.min(21,h)):"e"!=p&&"f"!=p||(h=Math.max(0,Math.min(20,h)))),p=ha.get(p)||In;var _=l&&s;return function(n){var r=d;if(y&&n%1)return"";var i=0>n||0===n&&0>1/n?(n=-n,"-"):"-"===a?"":a;if(0>v){var c=ao.formatPrefix(n,h);n=c.scale(n),r=c.symbol+d}else n*=v;n=p(n,h);var x,M,b=n.lastIndexOf(".");if(0>b){var w=m?n.lastIndexOf("e"):-1;0>w?(x=n,M=""):(x=n.substring(0,w),M=n.substring(w))}else x=n.substring(0,b),M=t+n.substring(b+1);!l&&s&&(x=u(x,1/0));var k=g.length+x.length+M.length+(_?0:i.length),C=f>k?new Array(k=f-k+1).join(e):"";return _&&(x=u(C+x,C.length?f-M.length:1/0)),i+=g,n=x+M,("<"===o?i+n+C:">"===o?C+i+n:"^"===o?C.substring(0,k>>=1)+i+n+C.substring(k):i+(_?n:C+n))+r}}}function In(n){return n+""}function Pn(){this._=new Date(arguments.length>1?Date.UTC.apply(this,arguments):arguments[0])}function Un(n,t,r){function e(t){var r=n(t),e=u(r,1);return e-t>t-r?r:e}function i(r){return t(r=n(new va(r-1)),1),r}function u(n,r){return t(n=new va(+n),r),n}function o(n,e,u){var o=i(n),a=[];if(u>1)for(;e>o;)r(o)%u||a.push(new Date(+o)),t(o,1);else for(;e>o;)a.push(new Date(+o)),t(o,1);return a}function a(n,t,r){try{va=Pn;var e=new Pn;return e._=n,o(e,t,r)}finally{va=Date}}n.floor=n,n.round=e,n.ceil=i,n.offset=u,n.range=o;var c=n.utc=Fn(n);return c.floor=c,c.round=Fn(e),c.ceil=Fn(i),c.offset=Fn(u),c.range=a,n}function Fn(n){return function(t,r){try{va=Pn;var e=new Pn;return e._=t,n(e,r)._}finally{va=Date}}}function Hn(n){function t(n){function t(t){for(var r,i,u,o=[],a=-1,c=0;++a<e;)37===n.charCodeAt(a)&&(o.push(n.slice(c,a)),null!=(i=da[r=n.charAt(++a)])&&(r=n.charAt(++a)),(u=E[r])&&(r=u(t,null==i?"e"===r?" ":"0":i)),o.push(r),c=a+1);return o.push(n.slice(c,a)),o.join("")}var e=n.length;return t.parse=function(t){var e={y:1900,m:0,d:1,H:0,M:0,S:0,L:0,Z:null},i=r(e,n,t,0);if(i!=t.length)return null;"p"in e&&(e.H=e.H%12+12*e.p);var u=null!=e.Z&&va!==Pn,o=new(u?Pn:va);return"j"in e?o.setFullYear(e.y,0,e.j):"W"in e||"U"in e?("w"in e||(e.w="W"in e?1:0),o.setFullYear(e.y,0,1),o.setFullYear(e.y,0,"W"in e?(e.w+6)%7+7*e.W-(o.getDay()+5)%7:e.w+7*e.U-(o.getDay()+6)%7)):o.setFullYear(e.y,e.m,e.d),o.setHours(e.H+(e.Z/100|0),e.M+e.Z%100,e.S,e.L),u?o._:o},t.toString=function(){return n},t}function r(n,t,r,e){for(var i,u,o,a=0,c=t.length,l=r.length;c>a;){if(e>=l)return-1;if(i=t.charCodeAt(a++),37===i){if(o=t.charAt(a++),u=N[o in da?t.charAt(a++):o],!u||(e=u(n,r,e))<0)return-1}else if(i!=r.charCodeAt(e++))return-1}return e}function e(n,t,r){b.lastIndex=0;var e=b.exec(t.slice(r));return e?(n.w=w.get(e[0].toLowerCase()),r+e[0].length):-1}function i(n,t,r){x.lastIndex=0;var e=x.exec(t.slice(r));return e?(n.w=M.get(e[0].toLowerCase()),r+e[0].length):-1}function u(n,t,r){A.lastIndex=0;var e=A.exec(t.slice(r));return e?(n.m=S.get(e[0].toLowerCase()),r+e[0].length):-1}function o(n,t,r){k.lastIndex=0;var e=k.exec(t.slice(r));return e?(n.m=C.get(e[0].toLowerCase()),r+e[0].length):-1}function a(n,t,e){return r(n,E.c.toString(),t,e)}function c(n,t,e){return r(n,E.x.toString(),t,e)}function l(n,t,e){return r(n,E.X.toString(),t,e)}function f(n,t,r){var e=_.get(t.slice(r,r+=2).toLowerCase());return null==e?-1:(n.p=e,r)}var s=n.dateTime,h=n.date,p=n.time,v=n.periods,g=n.days,d=n.shortDays,y=n.months,m=n.shortMonths;t.utc=function(n){function r(n){try{va=Pn;var t=new va;return t._=n,e(t)}finally{va=Date}}var e=t(n);return r.parse=function(n){try{va=Pn;var t=e.parse(n);return t&&t._}finally{va=Date}},r.toString=e.toString,r},t.multi=t.utc.multi=lt;var _=ao.map(),x=Bn(g),M=Yn(g),b=Bn(d),w=Yn(d),k=Bn(y),C=Yn(y),A=Bn(m),S=Yn(m);v.forEach(function(n,t){_.set(n.toLowerCase(),t)});var E={a:function(n){return d[n.getDay()]},A:function(n){return g[n.getDay()]},b:function(n){return m[n.getMonth()]},B:function(n){return y[n.getMonth()]},c:t(s),d:function(n,t){return Wn(n.getDate(),t,2)},e:function(n,t){return Wn(n.getDate(),t,2)},H:function(n,t){return Wn(n.getHours(),t,2)},I:function(n,t){return Wn(n.getHours()%12||12,t,2)},j:function(n,t){return Wn(1+pa.dayOfYear(n),t,3)},L:function(n,t){return Wn(n.getMilliseconds(),t,3)},m:function(n,t){return Wn(n.getMonth()+1,t,2)},M:function(n,t){return Wn(n.getMinutes(),t,2)},p:function(n){return v[+(n.getHours()>=12)]},S:function(n,t){return Wn(n.getSeconds(),t,2)},U:function(n,t){return Wn(pa.sundayOfYear(n),t,2)},w:function(n){return n.getDay()},W:function(n,t){return Wn(pa.mondayOfYear(n),t,2)},x:t(h),X:t(p),y:function(n,t){return Wn(n.getFullYear()%100,t,2)},Y:function(n,t){return Wn(n.getFullYear()%1e4,t,4)},Z:at,"%":function(){return"%"}},N={a:e,A:i,b:u,B:o,c:a,d:tt,e:tt,H:et,I:et,j:rt,L:ot,m:nt,M:it,p:f,S:ut,U:Vn,w:Zn,W:Xn,x:c,X:l,y:Jn,Y:Kn,Z:Qn,"%":ct};return t}function Wn(n,t,r){var e=0>n?"-":"",i=(e?-n:n)+"",u=i.length;return e+(r>u?new Array(r-u+1).join(t)+i:i)}function Bn(n){return new RegExp("^(?:"+n.map(ao.requote).join("|")+")","i")}function Yn(n){for(var t=new l,r=-1,e=n.length;++r<e;)t.set(n[r].toLowerCase(),r);return t}function Zn(n,t,r){ya.lastIndex=0;var e=ya.exec(t.slice(r,r+1));return e?(n.w=+e[0],r+e[0].length):-1}function Vn(n,t,r){ya.lastIndex=0;var e=ya.exec(t.slice(r));return e?(n.U=+e[0],r+e[0].length):-1}function Xn(n,t,r){ya.lastIndex=0;var e=ya.exec(t.slice(r));return e?(n.W=+e[0],r+e[0].length):-1}function Kn(n,t,r){ya.lastIndex=0;var e=ya.exec(t.slice(r,r+4));return e?(n.y=+e[0],r+e[0].length):-1}function Jn(n,t,r){ya.lastIndex=0;var e=ya.exec(t.slice(r,r+2));return e?(n.y=Gn(+e[0]),r+e[0].length):-1}function Qn(n,t,r){return/^[+-]\d{4}$/.test(t=t.slice(r,r+5))?(n.Z=-t,r+5):-1}function Gn(n){return n+(n>68?1900:2e3)}function nt(n,t,r){ya.lastIndex=0;var e=ya.exec(t.slice(r,r+2));return e?(n.m=e[0]-1,r+e[0].length):-1}function tt(n,t,r){ya.lastIndex=0;var e=ya.exec(t.slice(r,r+2));return e?(n.d=+e[0],r+e[0].length):-1}function rt(n,t,r){ya.lastIndex=0;var e=ya.exec(t.slice(r,r+3));return e?(n.j=+e[0],r+e[0].length):-1}function et(n,t,r){ya.lastIndex=0;var e=ya.exec(t.slice(r,r+2));return e?(n.H=+e[0],r+e[0].length):-1}function it(n,t,r){ya.lastIndex=0;var e=ya.exec(t.slice(r,r+2));return e?(n.M=+e[0],r+e[0].length):-1}function ut(n,t,r){ya.lastIndex=0;var e=ya.exec(t.slice(r,r+2));return e?(n.S=+e[0],r+e[0].length):-1}function ot(n,t,r){ya.lastIndex=0;var e=ya.exec(t.slice(r,r+3));return e?(n.L=+e[0],r+e[0].length):-1}function at(n){var t=n.getTimezoneOffset(),r=t>0?"-":"+",e=xo(t)/60|0,i=xo(t)%60;return r+Wn(e,"0",2)+Wn(i,"0",2)}function ct(n,t,r){ma.lastIndex=0;var e=ma.exec(t.slice(r,r+1));return e?r+e[0].length:-1}function lt(n){for(var t=n.length,r=-1;++r<t;)n[r][0]=this(n[r][0]);return function(t){for(var r=0,e=n[r];!e[1](t);)e=n[++r];return e[0](t)}}function ft(){}function st(n,t,r){var e=r.s=n+t,i=e-n,u=e-i;r.t=n-u+(t-i)}function ht(n,t){n&&ba.hasOwnProperty(n.type)&&ba[n.type](n,t)}function pt(n,t,r){var e,i=-1,u=n.length-r;for(t.lineStart();++i<u;)e=n[i],t.point(e[0],e[1],e[2]);t.lineEnd()}function vt(n,t){var r=-1,e=n.length;for(t.polygonStart();++r<e;)pt(n[r],t,1);t.polygonEnd()}function gt(){function n(n,t){n*=Fo,t=t*Fo/2+qo/4;var r=n-e,o=r>=0?1:-1,a=o*r,c=Math.cos(t),l=Math.sin(t),f=u*l,s=i*c+f*Math.cos(a),h=f*o*Math.sin(a);ka.add(Math.atan2(h,s)),e=n,i=c,u=l}var t,r,e,i,u;Ca.point=function(o,a){Ca.point=n,e=(t=o)*Fo,i=Math.cos(a=(r=a)*Fo/2+qo/4),u=Math.sin(a)},Ca.lineEnd=function(){n(t,r)}}function dt(n){var t=n[0],r=n[1],e=Math.cos(r);return[e*Math.cos(t),e*Math.sin(t),Math.sin(r)]}function yt(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]}function mt(n,t){return[n[1]*t[2]-n[2]*t[1],n[2]*t[0]-n[0]*t[2],n[0]*t[1]-n[1]*t[0]]}function _t(n,t){n[0]+=t[0],n[1]+=t[1],n[2]+=t[2]}function xt(n,t){return[n[0]*t,n[1]*t,n[2]*t]}function Mt(n){var t=Math.sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]);n[0]/=t,n[1]/=t,n[2]/=t}function bt(n){return[Math.atan2(n[1],n[0]),tn(n[2])]}function wt(n,t){return xo(n[0]-t[0])<Oo&&xo(n[1]-t[1])<Oo}function kt(n,t){n*=Fo;var r=Math.cos(t*=Fo);Ct(r*Math.cos(n),r*Math.sin(n),Math.sin(t))}function Ct(n,t,r){++Aa,Ea+=(n-Ea)/Aa,Na+=(t-Na)/Aa,$a+=(r-$a)/Aa}function At(){function n(n,i){n*=Fo;var u=Math.cos(i*=Fo),o=u*Math.cos(n),a=u*Math.sin(n),c=Math.sin(i),l=Math.atan2(Math.sqrt((l=r*c-e*a)*l+(l=e*o-t*c)*l+(l=t*a-r*o)*l),t*o+r*a+e*c);Sa+=l,ja+=l*(t+(t=o)),Da+=l*(r+(r=a)),Ta+=l*(e+(e=c)),Ct(t,r,e)}var t,r,e;za.point=function(i,u){i*=Fo;var o=Math.cos(u*=Fo);t=o*Math.cos(i),r=o*Math.sin(i),e=Math.sin(u),za.point=n,Ct(t,r,e)}}function St(){za.point=kt}function Et(){function n(n,t){n*=Fo;var r=Math.cos(t*=Fo),o=r*Math.cos(n),a=r*Math.sin(n),c=Math.sin(t),l=i*c-u*a,f=u*o-e*c,s=e*a-i*o,h=Math.sqrt(l*l+f*f+s*s),p=e*o+i*a+u*c,v=h&&-nn(p)/h,g=Math.atan2(h,p);La+=v*l,Ra+=v*f,Oa+=v*s,Sa+=g,ja+=g*(e+(e=o)),Da+=g*(i+(i=a)),Ta+=g*(u+(u=c)),Ct(e,i,u)}var t,r,e,i,u;za.point=function(o,a){t=o,r=a,za.point=n,o*=Fo;var c=Math.cos(a*=Fo);e=c*Math.cos(o),i=c*Math.sin(o),u=Math.sin(a),Ct(e,i,u)},za.lineEnd=function(){n(t,r),za.lineEnd=St,za.point=kt}}function Nt(n,t){function r(r,e){return r=n(r,e),t(r[0],r[1])}return n.invert&&t.invert&&(r.invert=function(r,e){return r=t.invert(r,e),r&&n.invert(r[0],r[1])}),r}function $t(){return!0}function jt(n,t,r,e,i){var u=[],o=[];if(n.forEach(function(n){if(!((t=n.length-1)<=0)){var t,r=n[0],e=n[t];if(wt(r,e)){i.lineStart();for(var a=0;t>a;++a)i.point((r=n[a])[0],r[1]);return void i.lineEnd()}var c=new Tt(r,n,null,!0),l=new Tt(r,null,c,!1);c.o=l,u.push(c),o.push(l),c=new Tt(e,n,null,!1),l=new Tt(e,null,c,!0),c.o=l,u.push(c),o.push(l)}}),o.sort(t),Dt(u),Dt(o),u.length){for(var a=0,c=r,l=o.length;l>a;++a)o[a].e=c=!c;for(var f,s,h=u[0];;){for(var p=h,v=!0;p.v;)if((p=p.n)===h)return;f=p.z,i.lineStart();do{if(p.v=p.o.v=!0,p.e){if(v)for(var a=0,l=f.length;l>a;++a)i.point((s=f[a])[0],s[1]);else e(p.x,p.n.x,1,i);p=p.n}else{if(v){f=p.p.z;for(var a=f.length-1;a>=0;--a)i.point((s=f[a])[0],s[1])}else e(p.x,p.p.x,-1,i);p=p.p}p=p.o,f=p.z,v=!v}while(!p.v);i.lineEnd()}}}function Dt(n){if(t=n.length){for(var t,r,e=0,i=n[0];++e<t;)i.n=r=n[e],r.p=i,i=r;i.n=r=n[0],r.p=i}}function Tt(n,t,r,e){this.x=n,this.z=t,this.o=r,this.e=e,this.v=!1,this.n=this.p=null}function Lt(n,t,r,e){return function(i,u){function o(t,r){var e=i(t,r);n(t=e[0],r=e[1])&&u.point(t,r)}function a(n,t){var r=i(n,t);d.point(r[0],r[1])}function c(){m.point=a,d.lineStart()}function l(){m.point=o,d.lineEnd()}function f(n,t){g.push([n,t]);var r=i(n,t);x.point(r[0],r[1])}function s(){x.lineStart(),g=[]}function h(){f(g[0][0],g[0][1]),x.lineEnd();var n,t=x.clean(),r=_.buffer(),e=r.length;if(g.pop(),v.push(g),g=null,e)if(1&t){n=r[0];var i,e=n.length-1,o=-1;if(e>0){for(M||(u.polygonStart(),M=!0),u.lineStart();++o<e;)u.point((i=n[o])[0],i[1]);u.lineEnd()}}else e>1&&2&t&&r.push(r.pop().concat(r.shift())),p.push(r.filter(Rt))}var p,v,g,d=t(u),y=i.invert(e[0],e[1]),m={point:o,lineStart:c,lineEnd:l,polygonStart:function(){m.point=f,m.lineStart=s,m.lineEnd=h,p=[],v=[]},polygonEnd:function(){m.point=o,m.lineStart=c,m.lineEnd=l,p=ao.merge(p);var n=Ut(y,v);p.length?(M||(u.polygonStart(),M=!0),jt(p,zt,n,r,u)):n&&(M||(u.polygonStart(),M=!0),u.lineStart(),r(null,null,1,u),u.lineEnd()),M&&(u.polygonEnd(),M=!1),p=v=null},sphere:function(){u.polygonStart(),u.lineStart(),r(null,null,1,u),u.lineEnd(),u.polygonEnd()}},_=Ot(),x=t(_),M=!1;return m}}function Rt(n){return n.length>1}function Ot(){var n,t=[];return{lineStart:function(){t.push(n=[])},point:function(t,r){n.push([t,r])},lineEnd:M,buffer:function(){var r=t;return t=[],n=null,r},rejoin:function(){t.length>1&&t.push(t.pop().concat(t.shift()))}}}function zt(n,t){return((n=n.x)[0]<0?n[1]-Uo-Oo:Uo-n[1])-((t=t.x)[0]<0?t[1]-Uo-Oo:Uo-t[1])}function qt(n){var t,r=NaN,e=NaN,i=NaN;return{lineStart:function(){n.lineStart(),t=1},point:function(u,o){var a=u>0?qo:-qo,c=xo(u-r);xo(c-qo)<Oo?(n.point(r,e=(e+o)/2>0?Uo:-Uo),n.point(i,e),n.lineEnd(),n.lineStart(),n.point(a,e),n.point(u,e),t=0):i!==a&&c>=qo&&(xo(r-i)<Oo&&(r-=i*Oo),xo(u-a)<Oo&&(u-=a*Oo),e=It(r,e,u,o),n.point(i,e),n.lineEnd(),n.lineStart(),n.point(a,e),t=0),n.point(r=u,e=o),i=a},lineEnd:function(){n.lineEnd(),r=e=NaN},clean:function(){return 2-t}}}function It(n,t,r,e){var i,u,o=Math.sin(n-r);return xo(o)>Oo?Math.atan((Math.sin(t)*(u=Math.cos(e))*Math.sin(r)-Math.sin(e)*(i=Math.cos(t))*Math.sin(n))/(i*u*o)):(t+e)/2}function Pt(n,t,r,e){var i;if(null==n)i=r*Uo,e.point(-qo,i),e.point(0,i),e.point(qo,i),e.point(qo,0),e.point(qo,-i),e.point(0,-i),e.point(-qo,-i),e.point(-qo,0),e.point(-qo,i);else if(xo(n[0]-t[0])>Oo){var u=n[0]<t[0]?qo:-qo;i=r*u/2,e.point(-u,i),e.point(0,i),e.point(u,i)}else e.point(t[0],t[1])}function Ut(n,t){var r=n[0],e=n[1],i=[Math.sin(r),-Math.cos(r),0],u=0,o=0;ka.reset();for(var a=0,c=t.length;c>a;++a){var l=t[a],f=l.length;if(f)for(var s=l[0],h=s[0],p=s[1]/2+qo/4,v=Math.sin(p),g=Math.cos(p),d=1;;){d===f&&(d=0),n=l[d];var y=n[0],m=n[1]/2+qo/4,_=Math.sin(m),x=Math.cos(m),M=y-h,b=M>=0?1:-1,w=b*M,k=w>qo,C=v*_;if(ka.add(Math.atan2(C*b*Math.sin(w),g*x+C*Math.cos(w))),u+=k?M+b*Io:M,k^h>=r^y>=r){var A=mt(dt(s),dt(n));Mt(A);var S=mt(i,A);Mt(S);var E=(k^M>=0?-1:1)*tn(S[2]);(e>E||e===E&&(A[0]||A[1]))&&(o+=k^M>=0?1:-1)}if(!d++)break;h=y,v=_,g=x,s=n}}return(-Oo>u||Oo>u&&0>ka)^1&o}function Ft(n){function t(n,t){return Math.cos(n)*Math.cos(t)>u}function r(n){var r,u,c,l,f;return{lineStart:function(){l=c=!1,f=1},point:function(s,h){var p,v=[s,h],g=t(s,h),d=o?g?0:i(s,h):g?i(s+(0>s?qo:-qo),h):0;if(!r&&(l=c=g)&&n.lineStart(),g!==c&&(p=e(r,v),(wt(r,p)||wt(v,p))&&(v[0]+=Oo,v[1]+=Oo,g=t(v[0],v[1]))),g!==c)f=0,g?(n.lineStart(),p=e(v,r),n.point(p[0],p[1])):(p=e(r,v),n.point(p[0],p[1]),n.lineEnd()),r=p;else if(a&&r&&o^g){var y;d&u||!(y=e(v,r,!0))||(f=0,o?(n.lineStart(),n.point(y[0][0],y[0][1]),n.point(y[1][0],y[1][1]),n.lineEnd()):(n.point(y[1][0],y[1][1]),n.lineEnd(),n.lineStart(),n.point(y[0][0],y[0][1])))}!g||r&&wt(r,v)||n.point(v[0],v[1]),r=v,c=g,u=d},lineEnd:function(){c&&n.lineEnd(),r=null},clean:function(){return f|(l&&c)<<1}}}function e(n,t,r){var e=dt(n),i=dt(t),o=[1,0,0],a=mt(e,i),c=yt(a,a),l=a[0],f=c-l*l;if(!f)return!r&&n;var s=u*c/f,h=-u*l/f,p=mt(o,a),v=xt(o,s),g=xt(a,h);_t(v,g);var d=p,y=yt(v,d),m=yt(d,d),_=y*y-m*(yt(v,v)-1);if(!(0>_)){var x=Math.sqrt(_),M=xt(d,(-y-x)/m);if(_t(M,v),M=bt(M),!r)return M;var b,w=n[0],k=t[0],C=n[1],A=t[1];w>k&&(b=w,w=k,k=b);var S=k-w,E=xo(S-qo)<Oo,N=E||Oo>S;if(!E&&C>A&&(b=C,C=A,A=b),N?E?C+A>0^M[1]<(xo(M[0]-w)<Oo?C:A):C<=M[1]&&M[1]<=A:S>qo^(w<=M[0]&&M[0]<=k)){var $=xt(d,(-y+x)/m);return _t($,v),[M,bt($)]}}}function i(t,r){var e=o?n:qo-n,i=0;return-e>t?i|=1:t>e&&(i|=2),-e>r?i|=4:r>e&&(i|=8),i}var u=Math.cos(n),o=u>0,a=xo(u)>Oo,c=gr(n,6*Fo);return Lt(t,r,c,o?[0,-n]:[-qo,n-qo])}function Ht(n,t,r,e){return function(i){var u,o=i.a,a=i.b,c=o.x,l=o.y,f=a.x,s=a.y,h=0,p=1,v=f-c,g=s-l;if(u=n-c,v||!(u>0)){if(u/=v,0>v){if(h>u)return;p>u&&(p=u)}else if(v>0){if(u>p)return;u>h&&(h=u)}if(u=r-c,v||!(0>u)){if(u/=v,0>v){if(u>p)return;u>h&&(h=u)}else if(v>0){if(h>u)return;p>u&&(p=u)}if(u=t-l,g||!(u>0)){if(u/=g,0>g){if(h>u)return;p>u&&(p=u)}else if(g>0){if(u>p)return;u>h&&(h=u)}if(u=e-l,g||!(0>u)){if(u/=g,0>g){if(u>p)return;u>h&&(h=u)}else if(g>0){if(h>u)return;p>u&&(p=u)}return h>0&&(i.a={x:c+h*v,y:l+h*g}),1>p&&(i.b={x:c+p*v,y:l+p*g}),i}}}}}}function Wt(n,t,r,e){function i(e,i){return xo(e[0]-n)<Oo?i>0?0:3:xo(e[0]-r)<Oo?i>0?2:1:xo(e[1]-t)<Oo?i>0?1:0:i>0?3:2}function u(n,t){return o(n.x,t.x)}function o(n,t){var r=i(n,1),e=i(t,1);return r!==e?r-e:0===r?t[1]-n[1]:1===r?n[0]-t[0]:2===r?n[1]-t[1]:t[0]-n[0]}return function(a){function c(n){for(var t=0,r=d.length,e=n[1],i=0;r>i;++i)for(var u,o=1,a=d[i],c=a.length,l=a[0];c>o;++o)u=a[o],l[1]<=e?u[1]>e&&G(l,u,n)>0&&++t:u[1]<=e&&G(l,u,n)<0&&--t,l=u;return 0!==t}function l(u,a,c,l){var f=0,s=0;if(null==u||(f=i(u,c))!==(s=i(a,c))||o(u,a)<0^c>0){do l.point(0===f||3===f?n:r,f>1?e:t);while((f=(f+c+4)%4)!==s)}else l.point(a[0],a[1])}function f(i,u){return i>=n&&r>=i&&u>=t&&e>=u}function s(n,t){f(n,t)&&a.point(n,t)}function h(){N.point=v,d&&d.push(y=[]),k=!0,w=!1,M=b=NaN}function p(){g&&(v(m,_),x&&w&&S.rejoin(),g.push(S.buffer())),N.point=s,w&&a.lineEnd()}function v(n,t){n=Math.max(-Ia,Math.min(Ia,n)),t=Math.max(-Ia,Math.min(Ia,t));var r=f(n,t);if(d&&y.push([n,t]),k)m=n,_=t,x=r,k=!1,r&&(a.lineStart(),a.point(n,t));else if(r&&w)a.point(n,t);else{var e={a:{x:M,y:b},b:{x:n,y:t}};E(e)?(w||(a.lineStart(),a.point(e.a.x,e.a.y)),a.point(e.b.x,e.b.y),r||a.lineEnd(),C=!1):r&&(a.lineStart(),a.point(n,t),C=!1)}M=n,b=t,w=r}var g,d,y,m,_,x,M,b,w,k,C,A=a,S=Ot(),E=Ht(n,t,r,e),N={point:s,lineStart:h,lineEnd:p,polygonStart:function(){a=S,g=[],d=[],C=!0},polygonEnd:function(){a=A,g=ao.merge(g);var t=c([n,e]),r=C&&t,i=g.length;(r||i)&&(a.polygonStart(),r&&(a.lineStart(),l(null,null,1,a),a.lineEnd()),i&&jt(g,u,t,l,a),a.polygonEnd()),g=d=y=null}};return N}}function Bt(n){var t=0,r=qo/3,e=ar(n),i=e(t,r);return i.parallels=function(n){return arguments.length?e(t=n[0]*qo/180,r=n[1]*qo/180):[t/qo*180,r/qo*180]},i}function Yt(n,t){function r(n,t){var r=Math.sqrt(u-2*i*Math.sin(t))/i;return[r*Math.sin(n*=i),o-r*Math.cos(n)]}var e=Math.sin(n),i=(e+Math.sin(t))/2,u=1+e*(2*i-e),o=Math.sqrt(u)/i;return r.invert=function(n,t){var r=o-t;return[Math.atan2(n,r)/i,tn((u-(n*n+r*r)*i*i)/(2*i))]},r}function Zt(){function n(n,t){Ua+=i*n-e*t,e=n,i=t}var t,r,e,i;Ya.point=function(u,o){Ya.point=n,t=e=u,r=i=o},Ya.lineEnd=function(){n(t,r)}}function Vt(n,t){Fa>n&&(Fa=n),n>Wa&&(Wa=n),Ha>t&&(Ha=t),t>Ba&&(Ba=t)}function Xt(){function n(n,t){o.push("M",n,",",t,u)}function t(n,t){o.push("M",n,",",t),a.point=r}function r(n,t){o.push("L",n,",",t)}function e(){a.point=n}function i(){o.push("Z")}var u=Kt(4.5),o=[],a={point:n,lineStart:function(){a.point=t},lineEnd:e,polygonStart:function(){a.lineEnd=i},polygonEnd:function(){a.lineEnd=e,a.point=n},pointRadius:function(n){return u=Kt(n),a},result:function(){if(o.length){var n=o.join("");return o=[],n}}};return a}function Kt(n){return"m0,"+n+"a"+n+","+n+" 0 1,1 0,"+-2*n+"a"+n+","+n+" 0 1,1 0,"+2*n+"z"}function Jt(n,t){Ea+=n,Na+=t,++$a}function Qt(){function n(n,e){var i=n-t,u=e-r,o=Math.sqrt(i*i+u*u);ja+=o*(t+n)/2,Da+=o*(r+e)/2,Ta+=o,Jt(t=n,r=e)}var t,r;Va.point=function(e,i){Va.point=n,Jt(t=e,r=i)}}function Gt(){Va.point=Jt}function nr(){function n(n,t){var r=n-e,u=t-i,o=Math.sqrt(r*r+u*u);ja+=o*(e+n)/2,Da+=o*(i+t)/2,Ta+=o,o=i*n-e*t,La+=o*(e+n),Ra+=o*(i+t),Oa+=3*o,Jt(e=n,i=t)}var t,r,e,i;Va.point=function(u,o){Va.point=n,Jt(t=e=u,r=i=o)},Va.lineEnd=function(){n(t,r)}}function tr(n){function t(t,r){n.moveTo(t+o,r),n.arc(t,r,o,0,Io)}function r(t,r){n.moveTo(t,r),a.point=e}function e(t,r){n.lineTo(t,r)}function i(){a.point=t}function u(){n.closePath()}var o=4.5,a={point:t,lineStart:function(){a.point=r},lineEnd:i,polygonStart:function(){a.lineEnd=u},polygonEnd:function(){a.lineEnd=i,a.point=t},pointRadius:function(n){return o=n,a},result:M};return a}function rr(n){function t(n){return(a?e:r)(n)}function r(t){return ur(t,function(r,e){r=n(r,e),t.point(r[0],r[1])})}function e(t){function r(r,e){r=n(r,e),t.point(r[0],r[1])}function e(){_=NaN,k.point=u,t.lineStart()}function u(r,e){var u=dt([r,e]),o=n(r,e);i(_,x,m,M,b,w,_=o[0],x=o[1],m=r,M=u[0],b=u[1],w=u[2],a,t),t.point(_,x)}function o(){k.point=r,t.lineEnd()}function c(){
+e(),k.point=l,k.lineEnd=f}function l(n,t){u(s=n,h=t),p=_,v=x,g=M,d=b,y=w,k.point=u}function f(){i(_,x,m,M,b,w,p,v,s,g,d,y,a,t),k.lineEnd=o,o()}var s,h,p,v,g,d,y,m,_,x,M,b,w,k={point:r,lineStart:e,lineEnd:o,polygonStart:function(){t.polygonStart(),k.lineStart=c},polygonEnd:function(){t.polygonEnd(),k.lineStart=e}};return k}function i(t,r,e,a,c,l,f,s,h,p,v,g,d,y){var m=f-t,_=s-r,x=m*m+_*_;if(x>4*u&&d--){var M=a+p,b=c+v,w=l+g,k=Math.sqrt(M*M+b*b+w*w),C=Math.asin(w/=k),A=xo(xo(w)-1)<Oo||xo(e-h)<Oo?(e+h)/2:Math.atan2(b,M),S=n(A,C),E=S[0],N=S[1],$=E-t,j=N-r,D=_*$-m*j;(D*D/x>u||xo((m*$+_*j)/x-.5)>.3||o>a*p+c*v+l*g)&&(i(t,r,e,a,c,l,E,N,A,M/=k,b/=k,w,d,y),y.point(E,N),i(E,N,A,M,b,w,f,s,h,p,v,g,d,y))}}var u=.5,o=Math.cos(30*Fo),a=16;return t.precision=function(n){return arguments.length?(a=(u=n*n)>0&&16,t):Math.sqrt(u)},t}function er(n){var t=rr(function(t,r){return n([t*Ho,r*Ho])});return function(n){return cr(t(n))}}function ir(n){this.stream=n}function ur(n,t){return{point:t,sphere:function(){n.sphere()},lineStart:function(){n.lineStart()},lineEnd:function(){n.lineEnd()},polygonStart:function(){n.polygonStart()},polygonEnd:function(){n.polygonEnd()}}}function or(n){return ar(function(){return n})()}function ar(n){function t(n){return n=a(n[0]*Fo,n[1]*Fo),[n[0]*h+c,l-n[1]*h]}function r(n){return n=a.invert((n[0]-c)/h,(l-n[1])/h),n&&[n[0]*Ho,n[1]*Ho]}function e(){a=Nt(o=sr(y,_,x),u);var n=u(g,d);return c=p-n[0]*h,l=v+n[1]*h,i()}function i(){return f&&(f.valid=!1,f=null),t}var u,o,a,c,l,f,s=rr(function(n,t){return n=u(n,t),[n[0]*h+c,l-n[1]*h]}),h=150,p=480,v=250,g=0,d=0,y=0,_=0,x=0,M=qa,b=m,w=null,k=null;return t.stream=function(n){return f&&(f.valid=!1),f=cr(M(o,s(b(n)))),f.valid=!0,f},t.clipAngle=function(n){return arguments.length?(M=null==n?(w=n,qa):Ft((w=+n)*Fo),i()):w},t.clipExtent=function(n){return arguments.length?(k=n,b=n?Wt(n[0][0],n[0][1],n[1][0],n[1][1]):m,i()):k},t.scale=function(n){return arguments.length?(h=+n,e()):h},t.translate=function(n){return arguments.length?(p=+n[0],v=+n[1],e()):[p,v]},t.center=function(n){return arguments.length?(g=n[0]%360*Fo,d=n[1]%360*Fo,e()):[g*Ho,d*Ho]},t.rotate=function(n){return arguments.length?(y=n[0]%360*Fo,_=n[1]%360*Fo,x=n.length>2?n[2]%360*Fo:0,e()):[y*Ho,_*Ho,x*Ho]},ao.rebind(t,s,"precision"),function(){return u=n.apply(this,arguments),t.invert=u.invert&&r,e()}}function cr(n){return ur(n,function(t,r){n.point(t*Fo,r*Fo)})}function lr(n,t){return[n,t]}function fr(n,t){return[n>qo?n-Io:-qo>n?n+Io:n,t]}function sr(n,t,r){return n?t||r?Nt(pr(n),vr(t,r)):pr(n):t||r?vr(t,r):fr}function hr(n){return function(t,r){return t+=n,[t>qo?t-Io:-qo>t?t+Io:t,r]}}function pr(n){var t=hr(n);return t.invert=hr(-n),t}function vr(n,t){function r(n,t){var r=Math.cos(t),a=Math.cos(n)*r,c=Math.sin(n)*r,l=Math.sin(t),f=l*e+a*i;return[Math.atan2(c*u-f*o,a*e-l*i),tn(f*u+c*o)]}var e=Math.cos(n),i=Math.sin(n),u=Math.cos(t),o=Math.sin(t);return r.invert=function(n,t){var r=Math.cos(t),a=Math.cos(n)*r,c=Math.sin(n)*r,l=Math.sin(t),f=l*u-c*o;return[Math.atan2(c*u+l*o,a*e+f*i),tn(f*e-a*i)]},r}function gr(n,t){var r=Math.cos(n),e=Math.sin(n);return function(i,u,o,a){var c=o*t;null!=i?(i=dr(r,i),u=dr(r,u),(o>0?u>i:i>u)&&(i+=o*Io)):(i=n+o*Io,u=n-.5*c);for(var l,f=i;o>0?f>u:u>f;f-=c)a.point((l=bt([r,-e*Math.cos(f),-e*Math.sin(f)]))[0],l[1])}}function dr(n,t){var r=dt(t);r[0]-=n,Mt(r);var e=nn(-r[1]);return((-r[2]<0?-e:e)+2*Math.PI-Oo)%(2*Math.PI)}function yr(n,t,r){var e=ao.range(n,t-Oo,r).concat(t);return function(n){return e.map(function(t){return[n,t]})}}function mr(n,t,r){var e=ao.range(n,t-Oo,r).concat(t);return function(n){return e.map(function(t){return[t,n]})}}function _r(n){return n.source}function xr(n){return n.target}function Mr(n,t,r,e){var i=Math.cos(t),u=Math.sin(t),o=Math.cos(e),a=Math.sin(e),c=i*Math.cos(n),l=i*Math.sin(n),f=o*Math.cos(r),s=o*Math.sin(r),h=2*Math.asin(Math.sqrt(on(e-t)+i*o*on(r-n))),p=1/Math.sin(h),v=h?function(n){var t=Math.sin(n*=h)*p,r=Math.sin(h-n)*p,e=r*c+t*f,i=r*l+t*s,o=r*u+t*a;return[Math.atan2(i,e)*Ho,Math.atan2(o,Math.sqrt(e*e+i*i))*Ho]}:function(){return[n*Ho,t*Ho]};return v.distance=h,v}function br(){function n(n,i){var u=Math.sin(i*=Fo),o=Math.cos(i),a=xo((n*=Fo)-t),c=Math.cos(a);Xa+=Math.atan2(Math.sqrt((a=o*Math.sin(a))*a+(a=e*u-r*o*c)*a),r*u+e*o*c),t=n,r=u,e=o}var t,r,e;Ka.point=function(i,u){t=i*Fo,r=Math.sin(u*=Fo),e=Math.cos(u),Ka.point=n},Ka.lineEnd=function(){Ka.point=Ka.lineEnd=M}}function wr(n,t){function r(t,r){var e=Math.cos(t),i=Math.cos(r),u=n(e*i);return[u*i*Math.sin(t),u*Math.sin(r)]}return r.invert=function(n,r){var e=Math.sqrt(n*n+r*r),i=t(e),u=Math.sin(i),o=Math.cos(i);return[Math.atan2(n*u,e*o),Math.asin(e&&r*u/e)]},r}function kr(n,t){function r(n,t){o>0?-Uo+Oo>t&&(t=-Uo+Oo):t>Uo-Oo&&(t=Uo-Oo);var r=o/Math.pow(i(t),u);return[r*Math.sin(u*n),o-r*Math.cos(u*n)]}var e=Math.cos(n),i=function(n){return Math.tan(qo/4+n/2)},u=n===t?Math.sin(n):Math.log(e/Math.cos(t))/Math.log(i(t)/i(n)),o=e*Math.pow(i(n),u)/u;return u?(r.invert=function(n,t){var r=o-t,e=Q(u)*Math.sqrt(n*n+r*r);return[Math.atan2(n,r)/u,2*Math.atan(Math.pow(o/e,1/u))-Uo]},r):Ar}function Cr(n,t){function r(n,t){var r=u-t;return[r*Math.sin(i*n),u-r*Math.cos(i*n)]}var e=Math.cos(n),i=n===t?Math.sin(n):(e-Math.cos(t))/(t-n),u=e/i+n;return xo(i)<Oo?lr:(r.invert=function(n,t){var r=u-t;return[Math.atan2(n,r)/i,u-Q(i)*Math.sqrt(n*n+r*r)]},r)}function Ar(n,t){return[n,Math.log(Math.tan(qo/4+t/2))]}function Sr(n){var t,r=or(n),e=r.scale,i=r.translate,u=r.clipExtent;return r.scale=function(){var n=e.apply(r,arguments);return n===r?t?r.clipExtent(null):r:n},r.translate=function(){var n=i.apply(r,arguments);return n===r?t?r.clipExtent(null):r:n},r.clipExtent=function(n){var o=u.apply(r,arguments);if(o===r){if(t=null==n){var a=qo*e(),c=i();u([[c[0]-a,c[1]-a],[c[0]+a,c[1]+a]])}}else t&&(o=null);return o},r.clipExtent(null)}function Er(n,t){return[Math.log(Math.tan(qo/4+t/2)),-n]}function Nr(n){return n[0]}function $r(n){return n[1]}function jr(n){for(var t=n.length,r=[0,1],e=2,i=2;t>i;i++){for(;e>1&&G(n[r[e-2]],n[r[e-1]],n[i])<=0;)--e;r[e++]=i}return r.slice(0,e)}function Dr(n,t){return n[0]-t[0]||n[1]-t[1]}function Tr(n,t,r){return(r[0]-t[0])*(n[1]-t[1])<(r[1]-t[1])*(n[0]-t[0])}function Lr(n,t,r,e){var i=n[0],u=r[0],o=t[0]-i,a=e[0]-u,c=n[1],l=r[1],f=t[1]-c,s=e[1]-l,h=(a*(c-l)-s*(i-u))/(s*o-a*f);return[i+h*o,c+h*f]}function Rr(n){var t=n[0],r=n[n.length-1];return!(t[0]-r[0]||t[1]-r[1])}function Or(){ee(this),this.edge=this.site=this.circle=null}function zr(n){var t=cc.pop()||new Or;return t.site=n,t}function qr(n){Vr(n),uc.remove(n),cc.push(n),ee(n)}function Ir(n){var t=n.circle,r=t.x,e=t.cy,i={x:r,y:e},u=n.P,o=n.N,a=[n];qr(n);for(var c=u;c.circle&&xo(r-c.circle.x)<Oo&&xo(e-c.circle.cy)<Oo;)u=c.P,a.unshift(c),qr(c),c=u;a.unshift(c),Vr(c);for(var l=o;l.circle&&xo(r-l.circle.x)<Oo&&xo(e-l.circle.cy)<Oo;)o=l.N,a.push(l),qr(l),l=o;a.push(l),Vr(l);var f,s=a.length;for(f=1;s>f;++f)l=a[f],c=a[f-1],ne(l.edge,c.site,l.site,i);c=a[0],l=a[s-1],l.edge=Qr(c.site,l.site,null,i),Zr(c),Zr(l)}function Pr(n){for(var t,r,e,i,u=n.x,o=n.y,a=uc._;a;)if(e=Ur(a,o)-u,e>Oo)a=a.L;else{if(i=u-Fr(a,o),!(i>Oo)){e>-Oo?(t=a.P,r=a):i>-Oo?(t=a,r=a.N):t=r=a;break}if(!a.R){t=a;break}a=a.R}var c=zr(n);if(uc.insert(t,c),t||r){if(t===r)return Vr(t),r=zr(t.site),uc.insert(c,r),c.edge=r.edge=Qr(t.site,c.site),Zr(t),void Zr(r);if(!r)return void(c.edge=Qr(t.site,c.site));Vr(t),Vr(r);var l=t.site,f=l.x,s=l.y,h=n.x-f,p=n.y-s,v=r.site,g=v.x-f,d=v.y-s,y=2*(h*d-p*g),m=h*h+p*p,_=g*g+d*d,x={x:(d*m-p*_)/y+f,y:(h*_-g*m)/y+s};ne(r.edge,l,v,x),c.edge=Qr(l,n,null,x),r.edge=Qr(n,v,null,x),Zr(t),Zr(r)}}function Ur(n,t){var r=n.site,e=r.x,i=r.y,u=i-t;if(!u)return e;var o=n.P;if(!o)return-(1/0);r=o.site;var a=r.x,c=r.y,l=c-t;if(!l)return a;var f=a-e,s=1/u-1/l,h=f/l;return s?(-h+Math.sqrt(h*h-2*s*(f*f/(-2*l)-c+l/2+i-u/2)))/s+e:(e+a)/2}function Fr(n,t){var r=n.N;if(r)return Ur(r,t);var e=n.site;return e.y===t?e.x:1/0}function Hr(n){this.site=n,this.edges=[]}function Wr(n){for(var t,r,e,i,u,o,a,c,l,f,s=n[0][0],h=n[1][0],p=n[0][1],v=n[1][1],g=ic,d=g.length;d--;)if(u=g[d],u&&u.prepare())for(a=u.edges,c=a.length,o=0;c>o;)f=a[o].end(),e=f.x,i=f.y,l=a[++o%c].start(),t=l.x,r=l.y,(xo(e-t)>Oo||xo(i-r)>Oo)&&(a.splice(o,0,new te(Gr(u.site,f,xo(e-s)<Oo&&v-i>Oo?{x:s,y:xo(t-s)<Oo?r:v}:xo(i-v)<Oo&&h-e>Oo?{x:xo(r-v)<Oo?t:h,y:v}:xo(e-h)<Oo&&i-p>Oo?{x:h,y:xo(t-h)<Oo?r:p}:xo(i-p)<Oo&&e-s>Oo?{x:xo(r-p)<Oo?t:s,y:p}:null),u.site,null)),++c)}function Br(n,t){return t.angle-n.angle}function Yr(){ee(this),this.x=this.y=this.arc=this.site=this.cy=null}function Zr(n){var t=n.P,r=n.N;if(t&&r){var e=t.site,i=n.site,u=r.site;if(e!==u){var o=i.x,a=i.y,c=e.x-o,l=e.y-a,f=u.x-o,s=u.y-a,h=2*(c*s-l*f);if(!(h>=-zo)){var p=c*c+l*l,v=f*f+s*s,g=(s*p-l*v)/h,d=(c*v-f*p)/h,s=d+a,y=lc.pop()||new Yr;y.arc=n,y.site=i,y.x=g+o,y.y=s+Math.sqrt(g*g+d*d),y.cy=s,n.circle=y;for(var m=null,_=ac._;_;)if(y.y<_.y||y.y===_.y&&y.x<=_.x){if(!_.L){m=_.P;break}_=_.L}else{if(!_.R){m=_;break}_=_.R}ac.insert(m,y),m||(oc=y)}}}}function Vr(n){var t=n.circle;t&&(t.P||(oc=t.N),ac.remove(t),lc.push(t),ee(t),n.circle=null)}function Xr(n){for(var t,r=ec,e=Ht(n[0][0],n[0][1],n[1][0],n[1][1]),i=r.length;i--;)t=r[i],(!Kr(t,n)||!e(t)||xo(t.a.x-t.b.x)<Oo&&xo(t.a.y-t.b.y)<Oo)&&(t.a=t.b=null,r.splice(i,1))}function Kr(n,t){var r=n.b;if(r)return!0;var e,i,u=n.a,o=t[0][0],a=t[1][0],c=t[0][1],l=t[1][1],f=n.l,s=n.r,h=f.x,p=f.y,v=s.x,g=s.y,d=(h+v)/2,y=(p+g)/2;if(g===p){if(o>d||d>=a)return;if(h>v){if(u){if(u.y>=l)return}else u={x:d,y:c};r={x:d,y:l}}else{if(u){if(u.y<c)return}else u={x:d,y:l};r={x:d,y:c}}}else if(e=(h-v)/(g-p),i=y-e*d,-1>e||e>1)if(h>v){if(u){if(u.y>=l)return}else u={x:(c-i)/e,y:c};r={x:(l-i)/e,y:l}}else{if(u){if(u.y<c)return}else u={x:(l-i)/e,y:l};r={x:(c-i)/e,y:c}}else if(g>p){if(u){if(u.x>=a)return}else u={x:o,y:e*o+i};r={x:a,y:e*a+i}}else{if(u){if(u.x<o)return}else u={x:a,y:e*a+i};r={x:o,y:e*o+i}}return n.a=u,n.b=r,!0}function Jr(n,t){this.l=n,this.r=t,this.a=this.b=null}function Qr(n,t,r,e){var i=new Jr(n,t);return ec.push(i),r&&ne(i,n,t,r),e&&ne(i,t,n,e),ic[n.i].edges.push(new te(i,n,t)),ic[t.i].edges.push(new te(i,t,n)),i}function Gr(n,t,r){var e=new Jr(n,null);return e.a=t,e.b=r,ec.push(e),e}function ne(n,t,r,e){n.a||n.b?n.l===r?n.b=e:n.a=e:(n.a=e,n.l=t,n.r=r)}function te(n,t,r){var e=n.a,i=n.b;this.edge=n,this.site=t,this.angle=r?Math.atan2(r.y-t.y,r.x-t.x):n.l===t?Math.atan2(i.x-e.x,e.y-i.y):Math.atan2(e.x-i.x,i.y-e.y)}function re(){this._=null}function ee(n){n.U=n.C=n.L=n.R=n.P=n.N=null}function ie(n,t){var r=t,e=t.R,i=r.U;i?i.L===r?i.L=e:i.R=e:n._=e,e.U=i,r.U=e,r.R=e.L,r.R&&(r.R.U=r),e.L=r}function ue(n,t){var r=t,e=t.L,i=r.U;i?i.L===r?i.L=e:i.R=e:n._=e,e.U=i,r.U=e,r.L=e.R,r.L&&(r.L.U=r),e.R=r}function oe(n){for(;n.L;)n=n.L;return n}function ae(n,t){var r,e,i,u=n.sort(ce).pop();for(ec=[],ic=new Array(n.length),uc=new re,ac=new re;;)if(i=oc,u&&(!i||u.y<i.y||u.y===i.y&&u.x<i.x))u.x===r&&u.y===e||(ic[u.i]=new Hr(u),Pr(u),r=u.x,e=u.y),u=n.pop();else{if(!i)break;Ir(i.arc)}t&&(Xr(t),Wr(t));var o={cells:ic,edges:ec};return uc=ac=ec=ic=null,o}function ce(n,t){return t.y-n.y||t.x-n.x}function le(n,t,r){return(n.x-r.x)*(t.y-n.y)-(n.x-t.x)*(r.y-n.y)}function fe(n){return n.x}function se(n){return n.y}function he(){return{leaf:!0,nodes:[],point:null,x:null,y:null}}function pe(n,t,r,e,i,u){if(!n(t,r,e,i,u)){var o=.5*(r+i),a=.5*(e+u),c=t.nodes;c[0]&&pe(n,c[0],r,e,o,a),c[1]&&pe(n,c[1],o,e,i,a),c[2]&&pe(n,c[2],r,a,o,u),c[3]&&pe(n,c[3],o,a,i,u)}}function ve(n,t,r,e,i,u,o){var a,c=1/0;return function l(n,f,s,h,p){if(!(f>u||s>o||e>h||i>p)){if(v=n.point){var v,g=t-n.x,d=r-n.y,y=g*g+d*d;if(c>y){var m=Math.sqrt(c=y);e=t-m,i=r-m,u=t+m,o=r+m,a=v}}for(var _=n.nodes,x=.5*(f+h),M=.5*(s+p),b=t>=x,w=r>=M,k=w<<1|b,C=k+4;C>k;++k)if(n=_[3&k])switch(3&k){case 0:l(n,f,s,x,M);break;case 1:l(n,x,s,h,M);break;case 2:l(n,f,M,x,p);break;case 3:l(n,x,M,h,p)}}}(n,e,i,u,o),a}function ge(n,t){n=ao.rgb(n),t=ao.rgb(t);var r=n.r,e=n.g,i=n.b,u=t.r-r,o=t.g-e,a=t.b-i;return function(n){return"#"+Mn(Math.round(r+u*n))+Mn(Math.round(e+o*n))+Mn(Math.round(i+a*n))}}function de(n,t){var r,e={},i={};for(r in n)r in t?e[r]=_e(n[r],t[r]):i[r]=n[r];for(r in t)r in n||(i[r]=t[r]);return function(n){for(r in e)i[r]=e[r](n);return i}}function ye(n,t){return n=+n,t=+t,function(r){return n*(1-r)+t*r}}function me(n,t){var r,e,i,u=sc.lastIndex=hc.lastIndex=0,o=-1,a=[],c=[];for(n+="",t+="";(r=sc.exec(n))&&(e=hc.exec(t));)(i=e.index)>u&&(i=t.slice(u,i),a[o]?a[o]+=i:a[++o]=i),(r=r[0])===(e=e[0])?a[o]?a[o]+=e:a[++o]=e:(a[++o]=null,c.push({i:o,x:ye(r,e)})),u=hc.lastIndex;return u<t.length&&(i=t.slice(u),a[o]?a[o]+=i:a[++o]=i),a.length<2?c[0]?(t=c[0].x,function(n){return t(n)+""}):function(){return t}:(t=c.length,function(n){for(var r,e=0;t>e;++e)a[(r=c[e]).i]=r.x(n);return a.join("")})}function _e(n,t){for(var r,e=ao.interpolators.length;--e>=0&&!(r=ao.interpolators[e](n,t)););return r}function xe(n,t){var r,e=[],i=[],u=n.length,o=t.length,a=Math.min(n.length,t.length);for(r=0;a>r;++r)e.push(_e(n[r],t[r]));for(;u>r;++r)i[r]=n[r];for(;o>r;++r)i[r]=t[r];return function(n){for(r=0;a>r;++r)i[r]=e[r](n);return i}}function Me(n){return function(t){return 0>=t?0:t>=1?1:n(t)}}function be(n){return function(t){return 1-n(1-t)}}function we(n){return function(t){return.5*(.5>t?n(2*t):2-n(2-2*t))}}function ke(n){return n*n}function Ce(n){return n*n*n}function Ae(n){if(0>=n)return 0;if(n>=1)return 1;var t=n*n,r=t*n;return 4*(.5>n?r:3*(n-t)+r-.75)}function Se(n){return function(t){return Math.pow(t,n)}}function Ee(n){return 1-Math.cos(n*Uo)}function Ne(n){return Math.pow(2,10*(n-1))}function $e(n){return 1-Math.sqrt(1-n*n)}function je(n,t){var r;return arguments.length<2&&(t=.45),arguments.length?r=t/Io*Math.asin(1/n):(n=1,r=t/4),function(e){return 1+n*Math.pow(2,-10*e)*Math.sin((e-r)*Io/t)}}function De(n){return n||(n=1.70158),function(t){return t*t*((n+1)*t-n)}}function Te(n){return 1/2.75>n?7.5625*n*n:2/2.75>n?7.5625*(n-=1.5/2.75)*n+.75:2.5/2.75>n?7.5625*(n-=2.25/2.75)*n+.9375:7.5625*(n-=2.625/2.75)*n+.984375}function Le(n,t){n=ao.hcl(n),t=ao.hcl(t);var r=n.h,e=n.c,i=n.l,u=t.h-r,o=t.c-e,a=t.l-i;return isNaN(o)&&(o=0,e=isNaN(e)?t.c:e),isNaN(u)?(u=0,r=isNaN(r)?t.h:r):u>180?u-=360:-180>u&&(u+=360),function(n){return sn(r+u*n,e+o*n,i+a*n)+""}}function Re(n,t){n=ao.hsl(n),t=ao.hsl(t);var r=n.h,e=n.s,i=n.l,u=t.h-r,o=t.s-e,a=t.l-i;return isNaN(o)&&(o=0,e=isNaN(e)?t.s:e),isNaN(u)?(u=0,r=isNaN(r)?t.h:r):u>180?u-=360:-180>u&&(u+=360),function(n){return ln(r+u*n,e+o*n,i+a*n)+""}}function Oe(n,t){n=ao.lab(n),t=ao.lab(t);var r=n.l,e=n.a,i=n.b,u=t.l-r,o=t.a-e,a=t.b-i;return function(n){return pn(r+u*n,e+o*n,i+a*n)+""}}function ze(n,t){return t-=n,function(r){return Math.round(n+t*r)}}function qe(n){var t=[n.a,n.b],r=[n.c,n.d],e=Pe(t),i=Ie(t,r),u=Pe(Ue(r,t,-i))||0;t[0]*r[1]<r[0]*t[1]&&(t[0]*=-1,t[1]*=-1,e*=-1,i*=-1),this.rotate=(e?Math.atan2(t[1],t[0]):Math.atan2(-r[0],r[1]))*Ho,this.translate=[n.e,n.f],this.scale=[e,u],this.skew=u?Math.atan2(i,u)*Ho:0}function Ie(n,t){return n[0]*t[0]+n[1]*t[1]}function Pe(n){var t=Math.sqrt(Ie(n,n));return t&&(n[0]/=t,n[1]/=t),t}function Ue(n,t,r){return n[0]+=r*t[0],n[1]+=r*t[1],n}function Fe(n){return n.length?n.pop()+",":""}function He(n,t,r,e){if(n[0]!==t[0]||n[1]!==t[1]){var i=r.push("translate(",null,",",null,")");e.push({i:i-4,x:ye(n[0],t[0])},{i:i-2,x:ye(n[1],t[1])})}else(t[0]||t[1])&&r.push("translate("+t+")")}function We(n,t,r,e){n!==t?(n-t>180?t+=360:t-n>180&&(n+=360),e.push({i:r.push(Fe(r)+"rotate(",null,")")-2,x:ye(n,t)})):t&&r.push(Fe(r)+"rotate("+t+")")}function Be(n,t,r,e){n!==t?e.push({i:r.push(Fe(r)+"skewX(",null,")")-2,x:ye(n,t)}):t&&r.push(Fe(r)+"skewX("+t+")")}function Ye(n,t,r,e){if(n[0]!==t[0]||n[1]!==t[1]){var i=r.push(Fe(r)+"scale(",null,",",null,")");e.push({i:i-4,x:ye(n[0],t[0])},{i:i-2,x:ye(n[1],t[1])})}else 1===t[0]&&1===t[1]||r.push(Fe(r)+"scale("+t+")")}function Ze(n,t){var r=[],e=[];return n=ao.transform(n),t=ao.transform(t),He(n.translate,t.translate,r,e),We(n.rotate,t.rotate,r,e),Be(n.skew,t.skew,r,e),Ye(n.scale,t.scale,r,e),n=t=null,function(n){for(var t,i=-1,u=e.length;++i<u;)r[(t=e[i]).i]=t.x(n);return r.join("")}}function Ve(n,t){return t=(t-=n=+n)||1/t,function(r){return(r-n)/t}}function Xe(n,t){return t=(t-=n=+n)||1/t,function(r){return Math.max(0,Math.min(1,(r-n)/t))}}function Ke(n){for(var t=n.source,r=n.target,e=Qe(t,r),i=[t];t!==e;)t=t.parent,i.push(t);for(var u=i.length;r!==e;)i.splice(u,0,r),r=r.parent;return i}function Je(n){for(var t=[],r=n.parent;null!=r;)t.push(n),n=r,r=r.parent;return t.push(n),t}function Qe(n,t){if(n===t)return n;for(var r=Je(n),e=Je(t),i=r.pop(),u=e.pop(),o=null;i===u;)o=i,i=r.pop(),u=e.pop();return o}function Ge(n){n.fixed|=2}function ni(n){n.fixed&=-7}function ti(n){n.fixed|=4,n.px=n.x,n.py=n.y}function ri(n){n.fixed&=-5}function ei(n,t,r){var e=0,i=0;if(n.charge=0,!n.leaf)for(var u,o=n.nodes,a=o.length,c=-1;++c<a;)u=o[c],null!=u&&(ei(u,t,r),n.charge+=u.charge,e+=u.charge*u.cx,i+=u.charge*u.cy);if(n.point){n.leaf||(n.point.x+=Math.random()-.5,n.point.y+=Math.random()-.5);var l=t*r[n.point.index];n.charge+=n.pointCharge=l,e+=l*n.point.x,i+=l*n.point.y}n.cx=e/n.charge,n.cy=i/n.charge}function ii(n,t){return ao.rebind(n,t,"sort","children","value"),n.nodes=n,n.links=fi,n}function ui(n,t){for(var r=[n];null!=(n=r.pop());)if(t(n),(i=n.children)&&(e=i.length))for(var e,i;--e>=0;)r.push(i[e])}function oi(n,t){for(var r=[n],e=[];null!=(n=r.pop());)if(e.push(n),(u=n.children)&&(i=u.length))for(var i,u,o=-1;++o<i;)r.push(u[o]);for(;null!=(n=e.pop());)t(n)}function ai(n){return n.children}function ci(n){return n.value}function li(n,t){return t.value-n.value}function fi(n){return ao.merge(n.map(function(n){return(n.children||[]).map(function(t){return{source:n,target:t}})}))}function si(n){return n.x}function hi(n){return n.y}function pi(n,t,r){n.y0=t,n.y=r}function vi(n){return ao.range(n.length)}function gi(n){for(var t=-1,r=n[0].length,e=[];++t<r;)e[t]=0;return e}function di(n){for(var t,r=1,e=0,i=n[0][1],u=n.length;u>r;++r)(t=n[r][1])>i&&(e=r,i=t);return e}function yi(n){return n.reduce(mi,0)}function mi(n,t){return n+t[1]}function _i(n,t){return xi(n,Math.ceil(Math.log(t.length)/Math.LN2+1))}function xi(n,t){for(var r=-1,e=+n[0],i=(n[1]-e)/t,u=[];++r<=t;)u[r]=i*r+e;return u}function Mi(n){return[ao.min(n),ao.max(n)]}function bi(n,t){return n.value-t.value}function wi(n,t){var r=n._pack_next;n._pack_next=t,t._pack_prev=n,t._pack_next=r,r._pack_prev=t}function ki(n,t){n._pack_next=t,t._pack_prev=n}function Ci(n,t){var r=t.x-n.x,e=t.y-n.y,i=n.r+t.r;return.999*i*i>r*r+e*e}function Ai(n){function t(n){f=Math.min(n.x-n.r,f),s=Math.max(n.x+n.r,s),h=Math.min(n.y-n.r,h),p=Math.max(n.y+n.r,p)}if((r=n.children)&&(l=r.length)){var r,e,i,u,o,a,c,l,f=1/0,s=-(1/0),h=1/0,p=-(1/0);if(r.forEach(Si),e=r[0],e.x=-e.r,e.y=0,t(e),l>1&&(i=r[1],i.x=i.r,i.y=0,t(i),l>2))for(u=r[2],$i(e,i,u),t(u),wi(e,u),e._pack_prev=u,wi(u,i),i=e._pack_next,o=3;l>o;o++){$i(e,i,u=r[o]);var v=0,g=1,d=1;for(a=i._pack_next;a!==i;a=a._pack_next,g++)if(Ci(a,u)){v=1;break}if(1==v)for(c=e._pack_prev;c!==a._pack_prev&&!Ci(c,u);c=c._pack_prev,d++);v?(d>g||g==d&&i.r<e.r?ki(e,i=a):ki(e=c,i),o--):(wi(e,u),i=u,t(u))}var y=(f+s)/2,m=(h+p)/2,_=0;for(o=0;l>o;o++)u=r[o],u.x-=y,u.y-=m,_=Math.max(_,u.r+Math.sqrt(u.x*u.x+u.y*u.y));n.r=_,r.forEach(Ei)}}function Si(n){n._pack_next=n._pack_prev=n}function Ei(n){delete n._pack_next,delete n._pack_prev}function Ni(n,t,r,e){var i=n.children;if(n.x=t+=e*n.x,n.y=r+=e*n.y,n.r*=e,i)for(var u=-1,o=i.length;++u<o;)Ni(i[u],t,r,e)}function $i(n,t,r){var e=n.r+r.r,i=t.x-n.x,u=t.y-n.y;if(e&&(i||u)){var o=t.r+r.r,a=i*i+u*u;o*=o,e*=e;var c=.5+(e-o)/(2*a),l=Math.sqrt(Math.max(0,2*o*(e+a)-(e-=a)*e-o*o))/(2*a);r.x=n.x+c*i+l*u,r.y=n.y+c*u-l*i}else r.x=n.x+e,r.y=n.y}function ji(n,t){return n.parent==t.parent?1:2}function Di(n){var t=n.children;return t.length?t[0]:n.t}function Ti(n){var t,r=n.children;return(t=r.length)?r[t-1]:n.t}function Li(n,t,r){var e=r/(t.i-n.i);t.c-=e,t.s+=r,n.c+=e,t.z+=r,t.m+=r}function Ri(n){for(var t,r=0,e=0,i=n.children,u=i.length;--u>=0;)t=i[u],t.z+=r,t.m+=r,r+=t.s+(e+=t.c)}function Oi(n,t,r){return n.a.parent===t.parent?n.a:r}function zi(n){return 1+ao.max(n,function(n){return n.y})}function qi(n){return n.reduce(function(n,t){return n+t.x},0)/n.length}function Ii(n){var t=n.children;return t&&t.length?Ii(t[0]):n}function Pi(n){var t,r=n.children;return r&&(t=r.length)?Pi(r[t-1]):n}function Ui(n){return{x:n.x,y:n.y,dx:n.dx,dy:n.dy}}function Fi(n,t){var r=n.x+t[3],e=n.y+t[0],i=n.dx-t[1]-t[3],u=n.dy-t[0]-t[2];return 0>i&&(r+=i/2,i=0),0>u&&(e+=u/2,u=0),{x:r,y:e,dx:i,dy:u}}function Hi(n){var t=n[0],r=n[n.length-1];return r>t?[t,r]:[r,t]}function Wi(n){return n.rangeExtent?n.rangeExtent():Hi(n.range())}function Bi(n,t,r,e){var i=r(n[0],n[1]),u=e(t[0],t[1]);return function(n){return u(i(n))}}function Yi(n,t){var r,e=0,i=n.length-1,u=n[e],o=n[i];return u>o&&(r=e,e=i,i=r,r=u,u=o,o=r),n[e]=t.floor(u),n[i]=t.ceil(o),n}function Zi(n){return n?{floor:function(t){return Math.floor(t/n)*n},ceil:function(t){return Math.ceil(t/n)*n}}:wc}function Vi(n,t,r,e){var i=[],u=[],o=0,a=Math.min(n.length,t.length)-1;for(n[a]<n[0]&&(n=n.slice().reverse(),t=t.slice().reverse());++o<=a;)i.push(r(n[o-1],n[o])),u.push(e(t[o-1],t[o]));return function(t){var r=ao.bisect(n,t,1,a)-1;return u[r](i[r](t))}}function Xi(n,t,r,e){function i(){var i=Math.min(n.length,t.length)>2?Vi:Bi,c=e?Xe:Ve;return o=i(n,t,c,r),a=i(t,n,c,_e),u}function u(n){return o(n)}var o,a;return u.invert=function(n){return a(n)},u.domain=function(t){return arguments.length?(n=t.map(Number),i()):n},u.range=function(n){return arguments.length?(t=n,i()):t},u.rangeRound=function(n){return u.range(n).interpolate(ze)},u.clamp=function(n){return arguments.length?(e=n,i()):e},u.interpolate=function(n){return arguments.length?(r=n,i()):r},u.ticks=function(t){return Gi(n,t)},u.tickFormat=function(t,r){return nu(n,t,r)},u.nice=function(t){return Ji(n,t),i()},u.copy=function(){return Xi(n,t,r,e)},i()}function Ki(n,t){return ao.rebind(n,t,"range","rangeRound","interpolate","clamp")}function Ji(n,t){return Yi(n,Zi(Qi(n,t)[2])),Yi(n,Zi(Qi(n,t)[2])),n}function Qi(n,t){null==t&&(t=10);var r=Hi(n),e=r[1]-r[0],i=Math.pow(10,Math.floor(Math.log(e/t)/Math.LN10)),u=t/e*i;return.15>=u?i*=10:.35>=u?i*=5:.75>=u&&(i*=2),r[0]=Math.ceil(r[0]/i)*i,r[1]=Math.floor(r[1]/i)*i+.5*i,r[2]=i,r}function Gi(n,t){return ao.range.apply(ao,Qi(n,t))}function nu(n,t,r){var e=Qi(n,t);if(r){var i=sa.exec(r);if(i.shift(),"s"===i[8]){var u=ao.formatPrefix(Math.max(xo(e[0]),xo(e[1])));return i[7]||(i[7]="."+tu(u.scale(e[2]))),i[8]="f",r=ao.format(i.join("")),function(n){return r(u.scale(n))+u.symbol}}i[7]||(i[7]="."+ru(i[8],e)),r=i.join("")}else r=",."+tu(e[2])+"f";return ao.format(r)}function tu(n){return-Math.floor(Math.log(n)/Math.LN10+.01)}function ru(n,t){var r=tu(t[2]);return n in kc?Math.abs(r-tu(Math.max(xo(t[0]),xo(t[1]))))+ +("e"!==n):r-2*("%"===n)}function eu(n,t,r,e){function i(n){return(r?Math.log(0>n?0:n):-Math.log(n>0?0:-n))/Math.log(t)}function u(n){return r?Math.pow(t,n):-Math.pow(t,-n)}function o(t){return n(i(t))}return o.invert=function(t){return u(n.invert(t))},o.domain=function(t){return arguments.length?(r=t[0]>=0,n.domain((e=t.map(Number)).map(i)),o):e},o.base=function(r){return arguments.length?(t=+r,n.domain(e.map(i)),o):t},o.nice=function(){var t=Yi(e.map(i),r?Math:Ac);return n.domain(t),e=t.map(u),o},o.ticks=function(){var n=Hi(e),o=[],a=n[0],c=n[1],l=Math.floor(i(a)),f=Math.ceil(i(c)),s=t%1?2:t;if(isFinite(f-l)){if(r){for(;f>l;l++)for(var h=1;s>h;h++)o.push(u(l)*h);o.push(u(l))}else for(o.push(u(l));l++<f;)for(var h=s-1;h>0;h--)o.push(u(l)*h);for(l=0;o[l]<a;l++);for(f=o.length;o[f-1]>c;f--);o=o.slice(l,f)}return o},o.tickFormat=function(n,r){if(!arguments.length)return Cc;arguments.length<2?r=Cc:"function"!=typeof r&&(r=ao.format(r));var e=Math.max(1,t*n/o.ticks().length);return function(n){var o=n/u(Math.round(i(n)));return t-.5>o*t&&(o*=t),e>=o?r(n):""}},o.copy=function(){return eu(n.copy(),t,r,e)},Ki(o,n)}function iu(n,t,r){function e(t){return n(i(t))}var i=uu(t),u=uu(1/t);return e.invert=function(t){return u(n.invert(t))},e.domain=function(t){return arguments.length?(n.domain((r=t.map(Number)).map(i)),e):r},e.ticks=function(n){return Gi(r,n)},e.tickFormat=function(n,t){return nu(r,n,t)},e.nice=function(n){return e.domain(Ji(r,n))},e.exponent=function(o){return arguments.length?(i=uu(t=o),u=uu(1/t),n.domain(r.map(i)),e):t},e.copy=function(){return iu(n.copy(),t,r)},Ki(e,n)}function uu(n){return function(t){return 0>t?-Math.pow(-t,n):Math.pow(t,n)}}function ou(n,t){function r(r){return u[((i.get(r)||("range"===t.t?i.set(r,n.push(r)):NaN))-1)%u.length]}function e(t,r){return ao.range(n.length).map(function(n){return t+r*n})}var i,u,o;return r.domain=function(e){if(!arguments.length)return n;n=[],i=new l;for(var u,o=-1,a=e.length;++o<a;)i.has(u=e[o])||i.set(u,n.push(u));return r[t.t].apply(r,t.a)},r.range=function(n){return arguments.length?(u=n,o=0,t={t:"range",a:arguments},r):u},r.rangePoints=function(i,a){arguments.length<2&&(a=0);var c=i[0],l=i[1],f=n.length<2?(c=(c+l)/2,0):(l-c)/(n.length-1+a);return u=e(c+f*a/2,f),o=0,t={t:"rangePoints",a:arguments},r},r.rangeRoundPoints=function(i,a){arguments.length<2&&(a=0);var c=i[0],l=i[1],f=n.length<2?(c=l=Math.round((c+l)/2),0):(l-c)/(n.length-1+a)|0;return u=e(c+Math.round(f*a/2+(l-c-(n.length-1+a)*f)/2),f),o=0,t={t:"rangeRoundPoints",a:arguments},r},r.rangeBands=function(i,a,c){arguments.length<2&&(a=0),arguments.length<3&&(c=a);var l=i[1]<i[0],f=i[l-0],s=i[1-l],h=(s-f)/(n.length-a+2*c);return u=e(f+h*c,h),l&&u.reverse(),o=h*(1-a),t={t:"rangeBands",a:arguments},r},r.rangeRoundBands=function(i,a,c){arguments.length<2&&(a=0),arguments.length<3&&(c=a);var l=i[1]<i[0],f=i[l-0],s=i[1-l],h=Math.floor((s-f)/(n.length-a+2*c));return u=e(f+Math.round((s-f-(n.length-a)*h)/2),h),l&&u.reverse(),o=Math.round(h*(1-a)),t={t:"rangeRoundBands",a:arguments},r},r.rangeBand=function(){return o},r.rangeExtent=function(){return Hi(t.a[0])},r.copy=function(){return ou(n,t)},r.domain(n)}function au(n,t){function u(){var r=0,e=t.length;for(a=[];++r<e;)a[r-1]=ao.quantile(n,r/e);return o}function o(n){return isNaN(n=+n)?void 0:t[ao.bisect(a,n)]}var a;return o.domain=function(t){return arguments.length?(n=t.map(e).filter(i).sort(r),u()):n},o.range=function(n){return arguments.length?(t=n,u()):t},o.quantiles=function(){return a},o.invertExtent=function(r){return r=t.indexOf(r),0>r?[NaN,NaN]:[r>0?a[r-1]:n[0],r<a.length?a[r]:n[n.length-1]]},o.copy=function(){return au(n,t)},u()}function cu(n,t,r){function e(t){return r[Math.max(0,Math.min(o,Math.floor(u*(t-n))))]}function i(){return u=r.length/(t-n),o=r.length-1,e}var u,o;return e.domain=function(r){return arguments.length?(n=+r[0],t=+r[r.length-1],i()):[n,t]},e.range=function(n){return arguments.length?(r=n,i()):r},e.invertExtent=function(t){return t=r.indexOf(t),t=0>t?NaN:t/u+n,[t,t+1/u]},e.copy=function(){return cu(n,t,r)},i()}function lu(n,t){function r(r){return r>=r?t[ao.bisect(n,r)]:void 0}return r.domain=function(t){return arguments.length?(n=t,r):n},r.range=function(n){return arguments.length?(t=n,r):t},r.invertExtent=function(r){return r=t.indexOf(r),[n[r-1],n[r]]},r.copy=function(){return lu(n,t)},r}function fu(n){function t(n){return+n}return t.invert=t,t.domain=t.range=function(r){return arguments.length?(n=r.map(t),t):n},t.ticks=function(t){return Gi(n,t)},t.tickFormat=function(t,r){return nu(n,t,r)},t.copy=function(){return fu(n)},t}function su(){return 0}function hu(n){return n.innerRadius}function pu(n){return n.outerRadius}function vu(n){return n.startAngle}function gu(n){return n.endAngle}function du(n){return n&&n.padAngle}function yu(n,t,r,e){return(n-r)*t-(t-e)*n>0?0:1}function mu(n,t,r,e,i){var u=n[0]-t[0],o=n[1]-t[1],a=(i?e:-e)/Math.sqrt(u*u+o*o),c=a*o,l=-a*u,f=n[0]+c,s=n[1]+l,h=t[0]+c,p=t[1]+l,v=(f+h)/2,g=(s+p)/2,d=h-f,y=p-s,m=d*d+y*y,_=r-e,x=f*p-h*s,M=(0>y?-1:1)*Math.sqrt(Math.max(0,_*_*m-x*x)),b=(x*y-d*M)/m,w=(-x*d-y*M)/m,k=(x*y+d*M)/m,C=(-x*d+y*M)/m,A=b-v,S=w-g,E=k-v,N=C-g;return A*A+S*S>E*E+N*N&&(b=k,w=C),[[b-c,w-l],[b*r/_,w*r/_]]}function _u(n){function t(t){function o(){l.push("M",u(n(f),a))}for(var c,l=[],f=[],s=-1,h=t.length,p=Sn(r),v=Sn(e);++s<h;)i.call(this,c=t[s],s)?f.push([+p.call(this,c,s),+v.call(this,c,s)]):f.length&&(o(),f=[]);return f.length&&o(),l.length?l.join(""):null}var r=Nr,e=$r,i=$t,u=xu,o=u.key,a=.7;return t.x=function(n){return arguments.length?(r=n,t):r},t.y=function(n){return arguments.length?(e=n,t):e},t.defined=function(n){return arguments.length?(i=n,t):i},t.interpolate=function(n){return arguments.length?(o="function"==typeof n?u=n:(u=Dc.get(n)||xu).key,t):o},t.tension=function(n){return arguments.length?(a=n,t):a},t}function xu(n){return n.length>1?n.join("L"):n+"Z"}function Mu(n){return n.join("L")+"Z"}function bu(n){for(var t=0,r=n.length,e=n[0],i=[e[0],",",e[1]];++t<r;)i.push("H",(e[0]+(e=n[t])[0])/2,"V",e[1]);return r>1&&i.push("H",e[0]),i.join("")}function wu(n){for(var t=0,r=n.length,e=n[0],i=[e[0],",",e[1]];++t<r;)i.push("V",(e=n[t])[1],"H",e[0]);return i.join("")}function ku(n){for(var t=0,r=n.length,e=n[0],i=[e[0],",",e[1]];++t<r;)i.push("H",(e=n[t])[0],"V",e[1]);return i.join("")}function Cu(n,t){return n.length<4?xu(n):n[1]+Eu(n.slice(1,-1),Nu(n,t))}function Au(n,t){return n.length<3?Mu(n):n[0]+Eu((n.push(n[0]),n),Nu([n[n.length-2]].concat(n,[n[1]]),t))}function Su(n,t){return n.length<3?xu(n):n[0]+Eu(n,Nu(n,t))}function Eu(n,t){if(t.length<1||n.length!=t.length&&n.length!=t.length+2)return xu(n);var r=n.length!=t.length,e="",i=n[0],u=n[1],o=t[0],a=o,c=1;if(r&&(e+="Q"+(u[0]-2*o[0]/3)+","+(u[1]-2*o[1]/3)+","+u[0]+","+u[1],i=n[1],c=2),t.length>1){a=t[1],u=n[c],c++,e+="C"+(i[0]+o[0])+","+(i[1]+o[1])+","+(u[0]-a[0])+","+(u[1]-a[1])+","+u[0]+","+u[1];for(var l=2;l<t.length;l++,c++)u=n[c],a=t[l],e+="S"+(u[0]-a[0])+","+(u[1]-a[1])+","+u[0]+","+u[1]}if(r){var f=n[c];e+="Q"+(u[0]+2*a[0]/3)+","+(u[1]+2*a[1]/3)+","+f[0]+","+f[1]}return e}function Nu(n,t){for(var r,e=[],i=(1-t)/2,u=n[0],o=n[1],a=1,c=n.length;++a<c;)r=u,u=o,o=n[a],e.push([i*(o[0]-r[0]),i*(o[1]-r[1])]);return e}function $u(n){if(n.length<3)return xu(n);var t=1,r=n.length,e=n[0],i=e[0],u=e[1],o=[i,i,i,(e=n[1])[0]],a=[u,u,u,e[1]],c=[i,",",u,"L",Lu(Rc,o),",",Lu(Rc,a)];for(n.push(n[r-1]);++t<=r;)e=n[t],o.shift(),o.push(e[0]),a.shift(),a.push(e[1]),Ru(c,o,a);return n.pop(),c.push("L",e),c.join("")}function ju(n){if(n.length<4)return xu(n);for(var t,r=[],e=-1,i=n.length,u=[0],o=[0];++e<3;)t=n[e],u.push(t[0]),o.push(t[1]);for(r.push(Lu(Rc,u)+","+Lu(Rc,o)),--e;++e<i;)t=n[e],u.shift(),u.push(t[0]),o.shift(),o.push(t[1]),Ru(r,u,o);return r.join("")}function Du(n){for(var t,r,e=-1,i=n.length,u=i+4,o=[],a=[];++e<4;)r=n[e%i],o.push(r[0]),a.push(r[1]);for(t=[Lu(Rc,o),",",Lu(Rc,a)],--e;++e<u;)r=n[e%i],o.shift(),o.push(r[0]),a.shift(),a.push(r[1]),Ru(t,o,a);return t.join("")}function Tu(n,t){var r=n.length-1;if(r)for(var e,i,u=n[0][0],o=n[0][1],a=n[r][0]-u,c=n[r][1]-o,l=-1;++l<=r;)e=n[l],i=l/r,e[0]=t*e[0]+(1-t)*(u+i*a),e[1]=t*e[1]+(1-t)*(o+i*c);return $u(n)}function Lu(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]+n[3]*t[3]}function Ru(n,t,r){n.push("C",Lu(Tc,t),",",Lu(Tc,r),",",Lu(Lc,t),",",Lu(Lc,r),",",Lu(Rc,t),",",Lu(Rc,r))}function Ou(n,t){return(t[1]-n[1])/(t[0]-n[0])}function zu(n){for(var t=0,r=n.length-1,e=[],i=n[0],u=n[1],o=e[0]=Ou(i,u);++t<r;)e[t]=(o+(o=Ou(i=u,u=n[t+1])))/2;return e[t]=o,e}function qu(n){for(var t,r,e,i,u=[],o=zu(n),a=-1,c=n.length-1;++a<c;)t=Ou(n[a],n[a+1]),xo(t)<Oo?o[a]=o[a+1]=0:(r=o[a]/t,e=o[a+1]/t,i=r*r+e*e,i>9&&(i=3*t/Math.sqrt(i),o[a]=i*r,o[a+1]=i*e));for(a=-1;++a<=c;)i=(n[Math.min(c,a+1)][0]-n[Math.max(0,a-1)][0])/(6*(1+o[a]*o[a])),u.push([i||0,o[a]*i||0]);return u}function Iu(n){return n.length<3?xu(n):n[0]+Eu(n,qu(n))}function Pu(n){for(var t,r,e,i=-1,u=n.length;++i<u;)t=n[i],r=t[0],e=t[1]-Uo,t[0]=r*Math.cos(e),t[1]=r*Math.sin(e);return n}function Uu(n){function t(t){function c(){g.push("M",a(n(y),s),f,l(n(d.reverse()),s),"Z")}for(var h,p,v,g=[],d=[],y=[],m=-1,_=t.length,x=Sn(r),M=Sn(i),b=r===e?function(){
+return p}:Sn(e),w=i===u?function(){return v}:Sn(u);++m<_;)o.call(this,h=t[m],m)?(d.push([p=+x.call(this,h,m),v=+M.call(this,h,m)]),y.push([+b.call(this,h,m),+w.call(this,h,m)])):d.length&&(c(),d=[],y=[]);return d.length&&c(),g.length?g.join(""):null}var r=Nr,e=Nr,i=0,u=$r,o=$t,a=xu,c=a.key,l=a,f="L",s=.7;return t.x=function(n){return arguments.length?(r=e=n,t):e},t.x0=function(n){return arguments.length?(r=n,t):r},t.x1=function(n){return arguments.length?(e=n,t):e},t.y=function(n){return arguments.length?(i=u=n,t):u},t.y0=function(n){return arguments.length?(i=n,t):i},t.y1=function(n){return arguments.length?(u=n,t):u},t.defined=function(n){return arguments.length?(o=n,t):o},t.interpolate=function(n){return arguments.length?(c="function"==typeof n?a=n:(a=Dc.get(n)||xu).key,l=a.reverse||a,f=a.closed?"M":"L",t):c},t.tension=function(n){return arguments.length?(s=n,t):s},t}function Fu(n){return n.radius}function Hu(n){return[n.x,n.y]}function Wu(n){return function(){var t=n.apply(this,arguments),r=t[0],e=t[1]-Uo;return[r*Math.cos(e),r*Math.sin(e)]}}function Bu(){return 64}function Yu(){return"circle"}function Zu(n){var t=Math.sqrt(n/qo);return"M0,"+t+"A"+t+","+t+" 0 1,1 0,"+-t+"A"+t+","+t+" 0 1,1 0,"+t+"Z"}function Vu(n){return function(){var t,r,e;(t=this[n])&&(e=t[r=t.active])&&(e.timer.c=null,e.timer.t=NaN,--t.count?delete t[r]:delete this[n],t.active+=.5,e.event&&e.event.interrupt.call(this,this.__data__,e.index))}}function Xu(n,t,r){return Co(n,Fc),n.namespace=t,n.id=r,n}function Ku(n,t,r,e){var i=n.id,u=n.namespace;return H(n,"function"==typeof r?function(n,o,a){n[u][i].tween.set(t,e(r.call(n,n.__data__,o,a)))}:(r=e(r),function(n){n[u][i].tween.set(t,r)}))}function Ju(n){return null==n&&(n=""),function(){this.textContent=n}}function Qu(n){return null==n?"__transition__":"__transition_"+n+"__"}function Gu(n,t,r,e,i){function u(n){var t=g.delay;return f.t=t+c,n>=t?o(n-t):void(f.c=o)}function o(r){var i=v.active,u=v[i];u&&(u.timer.c=null,u.timer.t=NaN,--v.count,delete v[i],u.event&&u.event.interrupt.call(n,n.__data__,u.index));for(var o in v)if(e>+o){var l=v[o];l.timer.c=null,l.timer.t=NaN,--v.count,delete v[o]}f.c=a,Dn(function(){return f.c&&a(r||1)&&(f.c=null,f.t=NaN),1},0,c),v.active=e,g.event&&g.event.start.call(n,n.__data__,t),p=[],g.tween.forEach(function(r,e){(e=e.call(n,n.__data__,t))&&p.push(e)}),h=g.ease,s=g.duration}function a(i){for(var u=i/s,o=h(u),a=p.length;a>0;)p[--a].call(n,o);return u>=1?(g.event&&g.event.end.call(n,n.__data__,t),--v.count?delete v[e]:delete n[r],1):void 0}var c,f,s,h,p,v=n[r]||(n[r]={active:0,count:0}),g=v[e];g||(c=i.time,f=Dn(u,0,c),g=v[e]={tween:new l,time:c,timer:f,delay:i.delay,duration:i.duration,ease:i.ease,index:t},i=null,++v.count)}function no(n,t,r){n.attr("transform",function(n){var e=t(n);return"translate("+(isFinite(e)?e:r(n))+",0)"})}function to(n,t,r){n.attr("transform",function(n){var e=t(n);return"translate(0,"+(isFinite(e)?e:r(n))+")"})}function ro(n){return n.toISOString()}function eo(n,t,r){function e(t){return n(t)}function i(n,r){var e=n[1]-n[0],i=e/r,u=ao.bisect(Jc,i);return u==Jc.length?[t.year,Qi(n.map(function(n){return n/31536e6}),r)[2]]:u?t[i/Jc[u-1]<Jc[u]/i?u-1:u]:[nl,Qi(n,r)[2]]}return e.invert=function(t){return io(n.invert(t))},e.domain=function(t){return arguments.length?(n.domain(t),e):n.domain().map(io)},e.nice=function(n,t){function r(r){return!isNaN(r)&&!n.range(r,io(+r+1),t).length}var u=e.domain(),o=Hi(u),a=null==n?i(o,10):"number"==typeof n&&i(o,n);return a&&(n=a[0],t=a[1]),e.domain(Yi(u,t>1?{floor:function(t){for(;r(t=n.floor(t));)t=io(t-1);return t},ceil:function(t){for(;r(t=n.ceil(t));)t=io(+t+1);return t}}:n))},e.ticks=function(n,t){var r=Hi(e.domain()),u=null==n?i(r,10):"number"==typeof n?i(r,n):!n.range&&[{range:n},t];return u&&(n=u[0],t=u[1]),n.range(r[0],io(+r[1]+1),1>t?1:t)},e.tickFormat=function(){return r},e.copy=function(){return eo(n.copy(),t,r)},Ki(e,n)}function io(n){return new Date(n)}function uo(n){return JSON.parse(n.responseText)}function oo(n){var t=fo.createRange();return t.selectNode(fo.body),t.createContextualFragment(n.responseText)}var ao={version:"3.5.15"},co=[].slice,lo=function(n){return co.call(n)},fo=this.document;if(fo)try{lo(fo.documentElement.childNodes)[0].nodeType}catch(so){lo=function(n){for(var t=n.length,r=new Array(t);t--;)r[t]=n[t];return r}}if(Date.now||(Date.now=function(){return+new Date}),fo)try{fo.createElement("DIV").style.setProperty("opacity",0,"")}catch(ho){var po=this.Element.prototype,vo=po.setAttribute,go=po.setAttributeNS,yo=this.CSSStyleDeclaration.prototype,mo=yo.setProperty;po.setAttribute=function(n,t){vo.call(this,n,t+"")},po.setAttributeNS=function(n,t,r){go.call(this,n,t,r+"")},yo.setProperty=function(n,t,r){mo.call(this,n,t+"",r)}}ao.ascending=r,ao.descending=function(n,t){return n>t?-1:t>n?1:t>=n?0:NaN},ao.min=function(n,t){var r,e,i=-1,u=n.length;if(1===arguments.length){for(;++i<u;)if(null!=(e=n[i])&&e>=e){r=e;break}for(;++i<u;)null!=(e=n[i])&&r>e&&(r=e)}else{for(;++i<u;)if(null!=(e=t.call(n,n[i],i))&&e>=e){r=e;break}for(;++i<u;)null!=(e=t.call(n,n[i],i))&&r>e&&(r=e)}return r},ao.max=function(n,t){var r,e,i=-1,u=n.length;if(1===arguments.length){for(;++i<u;)if(null!=(e=n[i])&&e>=e){r=e;break}for(;++i<u;)null!=(e=n[i])&&e>r&&(r=e)}else{for(;++i<u;)if(null!=(e=t.call(n,n[i],i))&&e>=e){r=e;break}for(;++i<u;)null!=(e=t.call(n,n[i],i))&&e>r&&(r=e)}return r},ao.extent=function(n,t){var r,e,i,u=-1,o=n.length;if(1===arguments.length){for(;++u<o;)if(null!=(e=n[u])&&e>=e){r=i=e;break}for(;++u<o;)null!=(e=n[u])&&(r>e&&(r=e),e>i&&(i=e))}else{for(;++u<o;)if(null!=(e=t.call(n,n[u],u))&&e>=e){r=i=e;break}for(;++u<o;)null!=(e=t.call(n,n[u],u))&&(r>e&&(r=e),e>i&&(i=e))}return[r,i]},ao.sum=function(n,t){var r,e=0,u=n.length,o=-1;if(1===arguments.length)for(;++o<u;)i(r=+n[o])&&(e+=r);else for(;++o<u;)i(r=+t.call(n,n[o],o))&&(e+=r);return e},ao.mean=function(n,t){var r,u=0,o=n.length,a=-1,c=o;if(1===arguments.length)for(;++a<o;)i(r=e(n[a]))?u+=r:--c;else for(;++a<o;)i(r=e(t.call(n,n[a],a)))?u+=r:--c;return c?u/c:void 0},ao.quantile=function(n,t){var r=(n.length-1)*t+1,e=Math.floor(r),i=+n[e-1],u=r-e;return u?i+u*(n[e]-i):i},ao.median=function(n,t){var u,o=[],a=n.length,c=-1;if(1===arguments.length)for(;++c<a;)i(u=e(n[c]))&&o.push(u);else for(;++c<a;)i(u=e(t.call(n,n[c],c)))&&o.push(u);return o.length?ao.quantile(o.sort(r),.5):void 0},ao.variance=function(n,t){var r,u,o=n.length,a=0,c=0,l=-1,f=0;if(1===arguments.length)for(;++l<o;)i(r=e(n[l]))&&(u=r-a,a+=u/++f,c+=u*(r-a));else for(;++l<o;)i(r=e(t.call(n,n[l],l)))&&(u=r-a,a+=u/++f,c+=u*(r-a));return f>1?c/(f-1):void 0},ao.deviation=function(){var n=ao.variance.apply(this,arguments);return n?Math.sqrt(n):n};var _o=u(r);ao.bisectLeft=_o.left,ao.bisect=ao.bisectRight=_o.right,ao.bisector=function(n){return u(1===n.length?function(t,e){return r(n(t),e)}:n)},ao.shuffle=function(n,t,r){(u=arguments.length)<3&&(r=n.length,2>u&&(t=0));for(var e,i,u=r-t;u;)i=Math.random()*u--|0,e=n[u+t],n[u+t]=n[i+t],n[i+t]=e;return n},ao.permute=function(n,t){for(var r=t.length,e=new Array(r);r--;)e[r]=n[t[r]];return e},ao.pairs=function(n){for(var t,r=0,e=n.length-1,i=n[0],u=new Array(0>e?0:e);e>r;)u[r]=[t=i,i=n[++r]];return u},ao.transpose=function(n){if(!(i=n.length))return[];for(var t=-1,r=ao.min(n,o),e=new Array(r);++t<r;)for(var i,u=-1,a=e[t]=new Array(i);++u<i;)a[u]=n[u][t];return e},ao.zip=function(){return ao.transpose(arguments)},ao.keys=function(n){var t=[];for(var r in n)t.push(r);return t},ao.values=function(n){var t=[];for(var r in n)t.push(n[r]);return t},ao.entries=function(n){var t=[];for(var r in n)t.push({key:r,value:n[r]});return t},ao.merge=function(n){for(var t,r,e,i=n.length,u=-1,o=0;++u<i;)o+=n[u].length;for(r=new Array(o);--i>=0;)for(e=n[i],t=e.length;--t>=0;)r[--o]=e[t];return r};var xo=Math.abs;ao.range=function(n,t,r){if(arguments.length<3&&(r=1,arguments.length<2&&(t=n,n=0)),(t-n)/r===1/0)throw new Error("infinite range");var e,i=[],u=a(xo(r)),o=-1;if(n*=u,t*=u,r*=u,0>r)for(;(e=n+r*++o)>t;)i.push(e/u);else for(;(e=n+r*++o)<t;)i.push(e/u);return i},ao.map=function(n,t){var r=new l;if(n instanceof l)n.forEach(function(n,t){r.set(n,t)});else if(Array.isArray(n)){var e,i=-1,u=n.length;if(1===arguments.length)for(;++i<u;)r.set(i,n[i]);else for(;++i<u;)r.set(t.call(n,e=n[i],i),e)}else for(var o in n)r.set(o,n[o]);return r};var Mo="__proto__",bo="\x00";c(l,{has:h,get:function(n){return this._[f(n)]},set:function(n,t){return this._[f(n)]=t},remove:p,keys:v,values:function(){var n=[];for(var t in this._)n.push(this._[t]);return n},entries:function(){var n=[];for(var t in this._)n.push({key:s(t),value:this._[t]});return n},size:g,empty:d,forEach:function(n){for(var t in this._)n.call(this,s(t),this._[t])}}),ao.nest=function(){function n(t,o,a){if(a>=u.length)return e?e.call(i,o):r?o.sort(r):o;for(var c,f,s,h,p=-1,v=o.length,g=u[a++],d=new l;++p<v;)(h=d.get(c=g(f=o[p])))?h.push(f):d.set(c,[f]);return t?(f=t(),s=function(r,e){f.set(r,n(t,e,a))}):(f={},s=function(r,e){f[r]=n(t,e,a)}),d.forEach(s),f}function t(n,r){if(r>=u.length)return n;var e=[],i=o[r++];return n.forEach(function(n,i){e.push({key:n,values:t(i,r)})}),i?e.sort(function(n,t){return i(n.key,t.key)}):e}var r,e,i={},u=[],o=[];return i.map=function(t,r){return n(r,t,0)},i.entries=function(r){return t(n(ao.map,r,0),0)},i.key=function(n){return u.push(n),i},i.sortKeys=function(n){return o[u.length-1]=n,i},i.sortValues=function(n){return r=n,i},i.rollup=function(n){return e=n,i},i},ao.set=function(n){var t=new y;if(n)for(var r=0,e=n.length;e>r;++r)t.add(n[r]);return t},c(y,{has:h,add:function(n){return this._[f(n+="")]=!0,n},remove:p,values:v,size:g,empty:d,forEach:function(n){for(var t in this._)n.call(this,s(t))}}),ao.behavior={},ao.rebind=function(n,t){for(var r,e=1,i=arguments.length;++e<i;)n[r=arguments[e]]=_(n,t,t[r]);return n};var wo=["webkit","ms","moz","Moz","o","O"];ao.dispatch=function(){for(var n=new b,t=-1,r=arguments.length;++t<r;)n[arguments[t]]=w(n);return n},b.prototype.on=function(n,t){var r=n.indexOf("."),e="";if(r>=0&&(e=n.slice(r+1),n=n.slice(0,r)),n)return arguments.length<2?this[n].on(e):this[n].on(e,t);if(2===arguments.length){if(null==t)for(n in this)this.hasOwnProperty(n)&&this[n].on(e,null);return this}},ao.event=null,ao.requote=function(n){return n.replace(ko,"\\$&")};var ko=/[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g,Co={}.__proto__?function(n,t){n.__proto__=t}:function(n,t){for(var r in t)n[r]=t[r]},Ao=function(n,t){return t.querySelector(n)},So=function(n,t){return t.querySelectorAll(n)},Eo=function(n,t){var r=n.matches||n[x(n,"matchesSelector")];return(Eo=function(n,t){return r.call(n,t)})(n,t)};"function"==typeof Sizzle&&(Ao=function(n,t){return Sizzle(n,t)[0]||null},So=Sizzle,Eo=Sizzle.matchesSelector),ao.selection=function(){return ao.select(fo.documentElement)};var No=ao.selection.prototype=[];No.select=function(n){var t,r,e,i,u=[];n=E(n);for(var o=-1,a=this.length;++o<a;){u.push(t=[]),t.parentNode=(e=this[o]).parentNode;for(var c=-1,l=e.length;++c<l;)(i=e[c])?(t.push(r=n.call(i,i.__data__,c,o)),r&&"__data__"in i&&(r.__data__=i.__data__)):t.push(null)}return S(u)},No.selectAll=function(n){var t,r,e=[];n=N(n);for(var i=-1,u=this.length;++i<u;)for(var o=this[i],a=-1,c=o.length;++a<c;)(r=o[a])&&(e.push(t=lo(n.call(r,r.__data__,a,i))),t.parentNode=r);return S(e)};var $o={svg:"http://www.w3.org/2000/svg",xhtml:"http://www.w3.org/1999/xhtml",xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};ao.ns={prefix:$o,qualify:function(n){var t=n.indexOf(":"),r=n;return t>=0&&"xmlns"!==(r=n.slice(0,t))&&(n=n.slice(t+1)),$o.hasOwnProperty(r)?{space:$o[r],local:n}:n}},No.attr=function(n,t){if(arguments.length<2){if("string"==typeof n){var r=this.node();return n=ao.ns.qualify(n),n.local?r.getAttributeNS(n.space,n.local):r.getAttribute(n)}for(t in n)this.each($(t,n[t]));return this}return this.each($(n,t))},No.classed=function(n,t){if(arguments.length<2){if("string"==typeof n){var r=this.node(),e=(n=T(n)).length,i=-1;if(t=r.classList){for(;++i<e;)if(!t.contains(n[i]))return!1}else for(t=r.getAttribute("class");++i<e;)if(!D(n[i]).test(t))return!1;return!0}for(t in n)this.each(L(t,n[t]));return this}return this.each(L(n,t))},No.style=function(n,r,e){var i=arguments.length;if(3>i){if("string"!=typeof n){2>i&&(r="");for(e in n)this.each(O(e,n[e],r));return this}if(2>i){var u=this.node();return t(u).getComputedStyle(u,null).getPropertyValue(n)}e=""}return this.each(O(n,r,e))},No.property=function(n,t){if(arguments.length<2){if("string"==typeof n)return this.node()[n];for(t in n)this.each(z(t,n[t]));return this}return this.each(z(n,t))},No.text=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.textContent=null==t?"":t}:null==n?function(){this.textContent=""}:function(){this.textContent=n}):this.node().textContent},No.html=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.innerHTML=null==t?"":t}:null==n?function(){this.innerHTML=""}:function(){this.innerHTML=n}):this.node().innerHTML},No.append=function(n){return n=q(n),this.select(function(){return this.appendChild(n.apply(this,arguments))})},No.insert=function(n,t){return n=q(n),t=E(t),this.select(function(){return this.insertBefore(n.apply(this,arguments),t.apply(this,arguments)||null)})},No.remove=function(){return this.each(I)},No.data=function(n,t){function r(n,r){var e,i,u,o=n.length,s=r.length,h=Math.min(o,s),p=new Array(s),v=new Array(s),g=new Array(o);if(t){var d,y=new l,m=new Array(o);for(e=-1;++e<o;)(i=n[e])&&(y.has(d=t.call(i,i.__data__,e))?g[e]=i:y.set(d,i),m[e]=d);for(e=-1;++e<s;)(i=y.get(d=t.call(r,u=r[e],e)))?i!==!0&&(p[e]=i,i.__data__=u):v[e]=P(u),y.set(d,!0);for(e=-1;++e<o;)e in m&&y.get(m[e])!==!0&&(g[e]=n[e])}else{for(e=-1;++e<h;)i=n[e],u=r[e],i?(i.__data__=u,p[e]=i):v[e]=P(u);for(;s>e;++e)v[e]=P(r[e]);for(;o>e;++e)g[e]=n[e]}v.update=p,v.parentNode=p.parentNode=g.parentNode=n.parentNode,a.push(v),c.push(p),f.push(g)}var e,i,u=-1,o=this.length;if(!arguments.length){for(n=new Array(o=(e=this[0]).length);++u<o;)(i=e[u])&&(n[u]=i.__data__);return n}var a=W([]),c=S([]),f=S([]);if("function"==typeof n)for(;++u<o;)r(e=this[u],n.call(e,e.parentNode.__data__,u));else for(;++u<o;)r(e=this[u],n);return c.enter=function(){return a},c.exit=function(){return f},c},No.datum=function(n){return arguments.length?this.property("__data__",n):this.property("__data__")},No.filter=function(n){var t,r,e,i=[];"function"!=typeof n&&(n=U(n));for(var u=0,o=this.length;o>u;u++){i.push(t=[]),t.parentNode=(r=this[u]).parentNode;for(var a=0,c=r.length;c>a;a++)(e=r[a])&&n.call(e,e.__data__,a,u)&&t.push(e)}return S(i)},No.order=function(){for(var n=-1,t=this.length;++n<t;)for(var r,e=this[n],i=e.length-1,u=e[i];--i>=0;)(r=e[i])&&(u&&u!==r.nextSibling&&u.parentNode.insertBefore(r,u),u=r);return this},No.sort=function(n){n=F.apply(this,arguments);for(var t=-1,r=this.length;++t<r;)this[t].sort(n);return this.order()},No.each=function(n){return H(this,function(t,r,e){n.call(t,t.__data__,r,e)})},No.call=function(n){var t=lo(arguments);return n.apply(t[0]=this,t),this},No.empty=function(){return!this.node()},No.node=function(){for(var n=0,t=this.length;t>n;n++)for(var r=this[n],e=0,i=r.length;i>e;e++){var u=r[e];if(u)return u}return null},No.size=function(){var n=0;return H(this,function(){++n}),n};var jo=[];ao.selection.enter=W,ao.selection.enter.prototype=jo,jo.append=No.append,jo.empty=No.empty,jo.node=No.node,jo.call=No.call,jo.size=No.size,jo.select=function(n){for(var t,r,e,i,u,o=[],a=-1,c=this.length;++a<c;){e=(i=this[a]).update,o.push(t=[]),t.parentNode=i.parentNode;for(var l=-1,f=i.length;++l<f;)(u=i[l])?(t.push(e[l]=r=n.call(i.parentNode,u.__data__,l,a)),r.__data__=u.__data__):t.push(null)}return S(o)},jo.insert=function(n,t){return arguments.length<2&&(t=B(this)),No.insert.call(this,n,t)},ao.select=function(t){var r;return"string"==typeof t?(r=[Ao(t,fo)],r.parentNode=fo.documentElement):(r=[t],r.parentNode=n(t)),S([r])},ao.selectAll=function(n){var t;return"string"==typeof n?(t=lo(So(n,fo)),t.parentNode=fo.documentElement):(t=lo(n),t.parentNode=null),S([t])},No.on=function(n,t,r){var e=arguments.length;if(3>e){if("string"!=typeof n){2>e&&(t=!1);for(r in n)this.each(Y(r,n[r],t));return this}if(2>e)return(e=this.node()["__on"+n])&&e._;r=!1}return this.each(Y(n,t,r))};var Do=ao.map({mouseenter:"mouseover",mouseleave:"mouseout"});fo&&Do.forEach(function(n){"on"+n in fo&&Do.remove(n)});var To,Lo=0;ao.mouse=function(n){return K(n,C())};var Ro=this.navigator&&/WebKit/.test(this.navigator.userAgent)?-1:0;ao.touch=function(n,t,r){if(arguments.length<3&&(r=t,t=C().changedTouches),t)for(var e,i=0,u=t.length;u>i;++i)if((e=t[i]).identifier===r)return K(n,e)},ao.behavior.drag=function(){function n(){this.on("mousedown.drag",u).on("touchstart.drag",o)}function r(n,t,r,u,o){return function(){function a(){var n,r,e=t(h,g);e&&(n=e[0]-_[0],r=e[1]-_[1],v|=n|r,_=e,p({type:"drag",x:e[0]+l[0],y:e[1]+l[1],dx:n,dy:r}))}function c(){t(h,g)&&(y.on(u+d,null).on(o+d,null),m(v),p({type:"dragend"}))}var l,f=this,s=ao.event.target.correspondingElement||ao.event.target,h=f.parentNode,p=e.of(f,arguments),v=0,g=n(),d=".drag"+(null==g?"":"-"+g),y=ao.select(r(s)).on(u+d,a).on(o+d,c),m=X(s),_=t(h,g);i?(l=i.apply(f,arguments),l=[l.x-_[0],l.y-_[1]]):l=[0,0],p({type:"dragstart"})}}var e=A(n,"drag","dragstart","dragend"),i=null,u=r(M,ao.mouse,t,"mousemove","mouseup"),o=r(J,ao.touch,m,"touchmove","touchend");return n.origin=function(t){return arguments.length?(i=t,n):i},ao.rebind(n,e,"on")},ao.touches=function(n,t){return arguments.length<2&&(t=C().touches),t?lo(t).map(function(t){var r=K(n,t);return r.identifier=t.identifier,r}):[]};var Oo=1e-6,zo=Oo*Oo,qo=Math.PI,Io=2*qo,Po=Io-Oo,Uo=qo/2,Fo=qo/180,Ho=180/qo,Wo=Math.SQRT2,Bo=2,Yo=4;ao.interpolateZoom=function(n,t){var r,e,i=n[0],u=n[1],o=n[2],a=t[0],c=t[1],l=t[2],f=a-i,s=c-u,h=f*f+s*s;if(zo>h)e=Math.log(l/o)/Wo,r=function(n){return[i+n*f,u+n*s,o*Math.exp(Wo*n*e)]};else{var p=Math.sqrt(h),v=(l*l-o*o+Yo*h)/(2*o*Bo*p),g=(l*l-o*o-Yo*h)/(2*l*Bo*p),d=Math.log(Math.sqrt(v*v+1)-v),y=Math.log(Math.sqrt(g*g+1)-g);e=(y-d)/Wo,r=function(n){var t=n*e,r=en(d),a=o/(Bo*p)*(r*un(Wo*t+d)-rn(d));return[i+a*f,u+a*s,o*r/en(Wo*t+d)]}}return r.duration=1e3*e,r},ao.behavior.zoom=function(){function n(n){n.on(j,s).on(Vo+".zoom",p).on("dblclick.zoom",v).on(L,h)}function r(n){return[(n[0]-C.x)/C.k,(n[1]-C.y)/C.k]}function e(n){return[n[0]*C.k+C.x,n[1]*C.k+C.y]}function i(n){C.k=Math.max(E[0],Math.min(E[1],n))}function u(n,t){t=e(t),C.x+=n[0]-t[0],C.y+=n[1]-t[1]}function o(t,r,e,o){t.__chart__={x:C.x,y:C.y,k:C.k},i(Math.pow(2,o)),u(d=r,e),t=ao.select(t),N>0&&(t=t.transition().duration(N)),t.call(n.event)}function a(){M&&M.domain(x.range().map(function(n){return(n-C.x)/C.k}).map(x.invert)),w&&w.domain(b.range().map(function(n){return(n-C.y)/C.k}).map(b.invert))}function c(n){$++||n({type:"zoomstart"})}function l(n){a(),n({type:"zoom",scale:C.k,translate:[C.x,C.y]})}function f(n){--$||(n({type:"zoomend"}),d=null)}function s(){function n(){a=1,u(ao.mouse(i),h),l(o)}function e(){s.on(D,null).on(T,null),p(a),f(o)}var i=this,o=R.of(i,arguments),a=0,s=ao.select(t(i)).on(D,n).on(T,e),h=r(ao.mouse(i)),p=X(i);Uc.call(i),c(o)}function h(){function n(){var n=ao.touches(v);return p=C.k,n.forEach(function(n){n.identifier in d&&(d[n.identifier]=r(n))}),n}function t(){var t=ao.event.target;ao.select(t).on(x,e).on(M,a),b.push(t);for(var r=ao.event.changedTouches,i=0,u=r.length;u>i;++i)d[r[i].identifier]=null;var c=n(),l=Date.now();if(1===c.length){if(500>l-_){var f=c[0];o(v,f,d[f.identifier],Math.floor(Math.log(C.k)/Math.LN2)+1),k()}_=l}else if(c.length>1){var f=c[0],s=c[1],h=f[0]-s[0],p=f[1]-s[1];y=h*h+p*p}}function e(){var n,t,r,e,o=ao.touches(v);Uc.call(v);for(var a=0,c=o.length;c>a;++a,e=null)if(r=o[a],e=d[r.identifier]){if(t)break;n=r,t=e}if(e){var f=(f=r[0]-n[0])*f+(f=r[1]-n[1])*f,s=y&&Math.sqrt(f/y);n=[(n[0]+r[0])/2,(n[1]+r[1])/2],t=[(t[0]+e[0])/2,(t[1]+e[1])/2],i(s*p)}_=null,u(n,t),l(g)}function a(){if(ao.event.touches.length){for(var t=ao.event.changedTouches,r=0,e=t.length;e>r;++r)delete d[t[r].identifier];for(var i in d)return void n()}ao.selectAll(b).on(m,null),w.on(j,s).on(L,h),A(),f(g)}var p,v=this,g=R.of(v,arguments),d={},y=0,m=".zoom-"+ao.event.changedTouches[0].identifier,x="touchmove"+m,M="touchend"+m,b=[],w=ao.select(v),A=X(v);t(),c(g),w.on(j,null).on(L,t)}function p(){var n=R.of(this,arguments);m?clearTimeout(m):(Uc.call(this),g=r(d=y||ao.mouse(this)),c(n)),m=setTimeout(function(){m=null,f(n)},50),k(),i(Math.pow(2,.002*Zo())*C.k),u(d,g),l(n)}function v(){var n=ao.mouse(this),t=Math.log(C.k)/Math.LN2;o(this,n,r(n),ao.event.shiftKey?Math.ceil(t)-1:Math.floor(t)+1)}var g,d,y,m,_,x,M,b,w,C={x:0,y:0,k:1},S=[960,500],E=Xo,N=250,$=0,j="mousedown.zoom",D="mousemove.zoom",T="mouseup.zoom",L="touchstart.zoom",R=A(n,"zoomstart","zoom","zoomend");return Vo||(Vo="onwheel"in fo?(Zo=function(){return-ao.event.deltaY*(ao.event.deltaMode?120:1)},"wheel"):"onmousewheel"in fo?(Zo=function(){return ao.event.wheelDelta},"mousewheel"):(Zo=function(){return-ao.event.detail},"MozMousePixelScroll")),n.event=function(n){n.each(function(){var n=R.of(this,arguments),t=C;Ic?ao.select(this).transition().each("start.zoom",function(){C=this.__chart__||{x:0,y:0,k:1},c(n)}).tween("zoom:zoom",function(){var r=S[0],e=S[1],i=d?d[0]:r/2,u=d?d[1]:e/2,o=ao.interpolateZoom([(i-C.x)/C.k,(u-C.y)/C.k,r/C.k],[(i-t.x)/t.k,(u-t.y)/t.k,r/t.k]);return function(t){var e=o(t),a=r/e[2];this.__chart__=C={x:i-e[0]*a,y:u-e[1]*a,k:a},l(n)}}).each("interrupt.zoom",function(){f(n)}).each("end.zoom",function(){f(n)}):(this.__chart__=C,c(n),l(n),f(n))})},n.translate=function(t){return arguments.length?(C={x:+t[0],y:+t[1],k:C.k},a(),n):[C.x,C.y]},n.scale=function(t){return arguments.length?(C={x:C.x,y:C.y,k:null},i(+t),a(),n):C.k},n.scaleExtent=function(t){return arguments.length?(E=null==t?Xo:[+t[0],+t[1]],n):E},n.center=function(t){return arguments.length?(y=t&&[+t[0],+t[1]],n):y},n.size=function(t){return arguments.length?(S=t&&[+t[0],+t[1]],n):S},n.duration=function(t){return arguments.length?(N=+t,n):N},n.x=function(t){return arguments.length?(M=t,x=t.copy(),C={x:0,y:0,k:1},n):M},n.y=function(t){return arguments.length?(w=t,b=t.copy(),C={x:0,y:0,k:1},n):w},ao.rebind(n,R,"on")};var Zo,Vo,Xo=[0,1/0];ao.color=an,an.prototype.toString=function(){return this.rgb()+""},ao.hsl=cn;var Ko=cn.prototype=new an;Ko.brighter=function(n){return n=Math.pow(.7,arguments.length?n:1),new cn(this.h,this.s,this.l/n)},Ko.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),new cn(this.h,this.s,n*this.l)},Ko.rgb=function(){return ln(this.h,this.s,this.l)},ao.hcl=fn;var Jo=fn.prototype=new an;Jo.brighter=function(n){return new fn(this.h,this.c,Math.min(100,this.l+Qo*(arguments.length?n:1)))},Jo.darker=function(n){return new fn(this.h,this.c,Math.max(0,this.l-Qo*(arguments.length?n:1)))},Jo.rgb=function(){return sn(this.h,this.c,this.l).rgb()},ao.lab=hn;var Qo=18,Go=.95047,na=1,ta=1.08883,ra=hn.prototype=new an;ra.brighter=function(n){return new hn(Math.min(100,this.l+Qo*(arguments.length?n:1)),this.a,this.b)},ra.darker=function(n){return new hn(Math.max(0,this.l-Qo*(arguments.length?n:1)),this.a,this.b)},ra.rgb=function(){return pn(this.l,this.a,this.b)},ao.rgb=mn;var ea=mn.prototype=new an;ea.brighter=function(n){n=Math.pow(.7,arguments.length?n:1);var t=this.r,r=this.g,e=this.b,i=30;return t||r||e?(t&&i>t&&(t=i),r&&i>r&&(r=i),e&&i>e&&(e=i),new mn(Math.min(255,t/n),Math.min(255,r/n),Math.min(255,e/n))):new mn(i,i,i)},ea.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),new mn(n*this.r,n*this.g,n*this.b)},ea.hsl=function(){return wn(this.r,this.g,this.b)},ea.toString=function(){return"#"+Mn(this.r)+Mn(this.g)+Mn(this.b)};var ia=ao.map({aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074});ia.forEach(function(n,t){ia.set(n,_n(t))}),ao.functor=Sn,ao.xhr=En(m),ao.dsv=function(n,t){function r(n,r,u){arguments.length<3&&(u=r,r=null);var o=Nn(n,t,null==r?e:i(r),u);return o.row=function(n){return arguments.length?o.response(null==(r=n)?e:i(n)):r},o}function e(n){return r.parse(n.responseText)}function i(n){return function(t){return r.parse(t.responseText,n)}}function u(t){return t.map(o).join(n)}function o(n){return a.test(n)?'"'+n.replace(/\"/g,'""')+'"':n}var a=new RegExp('["'+n+"\n]"),c=n.charCodeAt(0);return r.parse=function(n,t){var e;return r.parseRows(n,function(n,r){if(e)return e(n,r-1);var i=new Function("d","return {"+n.map(function(n,t){return JSON.stringify(n)+": d["+t+"]"}).join(",")+"}");e=t?function(n,r){return t(i(n),r)}:i})},r.parseRows=function(n,t){function r(){if(f>=l)return o;if(i)return i=!1,u;var t=f;if(34===n.charCodeAt(t)){for(var r=t;r++<l;)if(34===n.charCodeAt(r)){if(34!==n.charCodeAt(r+1))break;++r}f=r+2;var e=n.charCodeAt(r+1);return 13===e?(i=!0,10===n.charCodeAt(r+2)&&++f):10===e&&(i=!0),n.slice(t+1,r).replace(/""/g,'"')}for(;l>f;){var e=n.charCodeAt(f++),a=1;if(10===e)i=!0;else if(13===e)i=!0,10===n.charCodeAt(f)&&(++f,++a);else if(e!==c)continue;return n.slice(t,f-a)}return n.slice(t)}for(var e,i,u={},o={},a=[],l=n.length,f=0,s=0;(e=r())!==o;){for(var h=[];e!==u&&e!==o;)h.push(e),e=r();t&&null==(h=t(h,s++))||a.push(h)}return a},r.format=function(t){if(Array.isArray(t[0]))return r.formatRows(t);var e=new y,i=[];return t.forEach(function(n){for(var t in n)e.has(t)||i.push(e.add(t))}),[i.map(o).join(n)].concat(t.map(function(t){return i.map(function(n){return o(t[n])}).join(n)})).join("\n")},r.formatRows=function(n){return n.map(u).join("\n")},r},ao.csv=ao.dsv(",","text/csv"),ao.tsv=ao.dsv("	","text/tab-separated-values");var ua,oa,aa,ca,la=this[x(this,"requestAnimationFrame")]||function(n){setTimeout(n,17)};ao.timer=function(){Dn.apply(this,arguments)},ao.timer.flush=function(){Ln(),Rn()},ao.round=function(n,t){return t?Math.round(n*(t=Math.pow(10,t)))/t:Math.round(n)};var fa=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"].map(zn);ao.formatPrefix=function(n,t){var r=0;return(n=+n)&&(0>n&&(n*=-1),t&&(n=ao.round(n,On(n,t))),r=1+Math.floor(1e-12+Math.log(n)/Math.LN10),r=Math.max(-24,Math.min(24,3*Math.floor((r-1)/3)))),fa[8+r/3]};var sa=/(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i,ha=ao.map({b:function(n){return n.toString(2)},c:function(n){return String.fromCharCode(n)},o:function(n){return n.toString(8)},x:function(n){return n.toString(16)},X:function(n){return n.toString(16).toUpperCase()},g:function(n,t){return n.toPrecision(t)},e:function(n,t){return n.toExponential(t)},f:function(n,t){return n.toFixed(t)},r:function(n,t){return(n=ao.round(n,On(n,t))).toFixed(Math.max(0,Math.min(20,On(n*(1+1e-15),t))))}}),pa=ao.time={},va=Date;Pn.prototype={getDate:function(){return this._.getUTCDate()},getDay:function(){return this._.getUTCDay()},getFullYear:function(){return this._.getUTCFullYear()},getHours:function(){return this._.getUTCHours()},getMilliseconds:function(){return this._.getUTCMilliseconds()},getMinutes:function(){return this._.getUTCMinutes()},getMonth:function(){return this._.getUTCMonth()},getSeconds:function(){return this._.getUTCSeconds()},getTime:function(){return this._.getTime()},getTimezoneOffset:function(){return 0},valueOf:function(){return this._.valueOf()},setDate:function(){ga.setUTCDate.apply(this._,arguments)},setDay:function(){ga.setUTCDay.apply(this._,arguments)},setFullYear:function(){ga.setUTCFullYear.apply(this._,arguments)},setHours:function(){ga.setUTCHours.apply(this._,arguments)},setMilliseconds:function(){ga.setUTCMilliseconds.apply(this._,arguments)},setMinutes:function(){ga.setUTCMinutes.apply(this._,arguments)},setMonth:function(){ga.setUTCMonth.apply(this._,arguments)},setSeconds:function(){ga.setUTCSeconds.apply(this._,arguments)},setTime:function(){ga.setTime.apply(this._,arguments)}};var ga=Date.prototype;pa.year=Un(function(n){return n=pa.day(n),n.setMonth(0,1),n},function(n,t){n.setFullYear(n.getFullYear()+t)},function(n){return n.getFullYear()}),pa.years=pa.year.range,pa.years.utc=pa.year.utc.range,pa.day=Un(function(n){var t=new va(2e3,0);return t.setFullYear(n.getFullYear(),n.getMonth(),n.getDate()),t},function(n,t){n.setDate(n.getDate()+t)},function(n){return n.getDate()-1}),pa.days=pa.day.range,pa.days.utc=pa.day.utc.range,pa.dayOfYear=function(n){var t=pa.year(n);return Math.floor((n-t-6e4*(n.getTimezoneOffset()-t.getTimezoneOffset()))/864e5)},["sunday","monday","tuesday","wednesday","thursday","friday","saturday"].forEach(function(n,t){t=7-t;var r=pa[n]=Un(function(n){return(n=pa.day(n)).setDate(n.getDate()-(n.getDay()+t)%7),n},function(n,t){n.setDate(n.getDate()+7*Math.floor(t))},function(n){var r=pa.year(n).getDay();return Math.floor((pa.dayOfYear(n)+(r+t)%7)/7)-(r!==t)});pa[n+"s"]=r.range,pa[n+"s"].utc=r.utc.range,pa[n+"OfYear"]=function(n){var r=pa.year(n).getDay();return Math.floor((pa.dayOfYear(n)+(r+t)%7)/7)}}),pa.week=pa.sunday,pa.weeks=pa.sunday.range,pa.weeks.utc=pa.sunday.utc.range,pa.weekOfYear=pa.sundayOfYear;var da={"-":"",_:" ",0:"0"},ya=/^\s*\d+/,ma=/^%/;ao.locale=function(n){return{numberFormat:qn(n),timeFormat:Hn(n)}};var _a=ao.locale({decimal:".",thousands:",",grouping:[3],currency:["$",""],dateTime:"%a %b %e %X %Y",date:"%m/%d/%Y",time:"%H:%M:%S",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],
+shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});ao.format=_a.numberFormat,ao.geo={},ft.prototype={s:0,t:0,add:function(n){st(n,this.t,xa),st(xa.s,this.s,this),this.s?this.t+=xa.t:this.s=xa.t},reset:function(){this.s=this.t=0},valueOf:function(){return this.s}};var xa=new ft;ao.geo.stream=function(n,t){n&&Ma.hasOwnProperty(n.type)?Ma[n.type](n,t):ht(n,t)};var Ma={Feature:function(n,t){ht(n.geometry,t)},FeatureCollection:function(n,t){for(var r=n.features,e=-1,i=r.length;++e<i;)ht(r[e].geometry,t)}},ba={Sphere:function(n,t){t.sphere()},Point:function(n,t){n=n.coordinates,t.point(n[0],n[1],n[2])},MultiPoint:function(n,t){for(var r=n.coordinates,e=-1,i=r.length;++e<i;)n=r[e],t.point(n[0],n[1],n[2])},LineString:function(n,t){pt(n.coordinates,t,0)},MultiLineString:function(n,t){for(var r=n.coordinates,e=-1,i=r.length;++e<i;)pt(r[e],t,0)},Polygon:function(n,t){vt(n.coordinates,t)},MultiPolygon:function(n,t){for(var r=n.coordinates,e=-1,i=r.length;++e<i;)vt(r[e],t)},GeometryCollection:function(n,t){for(var r=n.geometries,e=-1,i=r.length;++e<i;)ht(r[e],t)}};ao.geo.area=function(n){return wa=0,ao.geo.stream(n,Ca),wa};var wa,ka=new ft,Ca={sphere:function(){wa+=4*qo},point:M,lineStart:M,lineEnd:M,polygonStart:function(){ka.reset(),Ca.lineStart=gt},polygonEnd:function(){var n=2*ka;wa+=0>n?4*qo+n:n,Ca.lineStart=Ca.lineEnd=Ca.point=M}};ao.geo.bounds=function(){function n(n,t){_.push(x=[f=n,h=n]),s>t&&(s=t),t>p&&(p=t)}function t(t,r){var e=dt([t*Fo,r*Fo]);if(y){var i=mt(y,e),u=[i[1],-i[0],0],o=mt(u,i);Mt(o),o=bt(o);var c=t-v,l=c>0?1:-1,g=o[0]*Ho*l,d=xo(c)>180;if(d^(g>l*v&&l*t>g)){var m=o[1]*Ho;m>p&&(p=m)}else if(g=(g+360)%360-180,d^(g>l*v&&l*t>g)){var m=-o[1]*Ho;s>m&&(s=m)}else s>r&&(s=r),r>p&&(p=r);d?v>t?a(f,t)>a(f,h)&&(h=t):a(t,h)>a(f,h)&&(f=t):h>=f?(f>t&&(f=t),t>h&&(h=t)):t>v?a(f,t)>a(f,h)&&(h=t):a(t,h)>a(f,h)&&(f=t)}else n(t,r);y=e,v=t}function r(){M.point=t}function e(){x[0]=f,x[1]=h,M.point=n,y=null}function i(n,r){if(y){var e=n-v;m+=xo(e)>180?e+(e>0?360:-360):e}else g=n,d=r;Ca.point(n,r),t(n,r)}function u(){Ca.lineStart()}function o(){i(g,d),Ca.lineEnd(),xo(m)>Oo&&(f=-(h=180)),x[0]=f,x[1]=h,y=null}function a(n,t){return(t-=n)<0?t+360:t}function c(n,t){return n[0]-t[0]}function l(n,t){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:n<t[0]||t[1]<n}var f,s,h,p,v,g,d,y,m,_,x,M={point:n,lineStart:r,lineEnd:e,polygonStart:function(){M.point=i,M.lineStart=u,M.lineEnd=o,m=0,Ca.polygonStart()},polygonEnd:function(){Ca.polygonEnd(),M.point=n,M.lineStart=r,M.lineEnd=e,0>ka?(f=-(h=180),s=-(p=90)):m>Oo?p=90:-Oo>m&&(s=-90),x[0]=f,x[1]=h}};return function(n){p=h=-(f=s=1/0),_=[],ao.geo.stream(n,M);var t=_.length;if(t){_.sort(c);for(var r,e=1,i=_[0],u=[i];t>e;++e)r=_[e],l(r[0],i)||l(r[1],i)?(a(i[0],r[1])>a(i[0],i[1])&&(i[1]=r[1]),a(r[0],i[1])>a(i[0],i[1])&&(i[0]=r[0])):u.push(i=r);for(var o,r,v=-(1/0),t=u.length-1,e=0,i=u[t];t>=e;i=r,++e)r=u[e],(o=a(i[1],r[0]))>v&&(v=o,f=r[0],h=i[1])}return _=x=null,f===1/0||s===1/0?[[NaN,NaN],[NaN,NaN]]:[[f,s],[h,p]]}}(),ao.geo.centroid=function(n){Aa=Sa=Ea=Na=$a=ja=Da=Ta=La=Ra=Oa=0,ao.geo.stream(n,za);var t=La,r=Ra,e=Oa,i=t*t+r*r+e*e;return zo>i&&(t=ja,r=Da,e=Ta,Oo>Sa&&(t=Ea,r=Na,e=$a),i=t*t+r*r+e*e,zo>i)?[NaN,NaN]:[Math.atan2(r,t)*Ho,tn(e/Math.sqrt(i))*Ho]};var Aa,Sa,Ea,Na,$a,ja,Da,Ta,La,Ra,Oa,za={sphere:M,point:kt,lineStart:At,lineEnd:St,polygonStart:function(){za.lineStart=Et},polygonEnd:function(){za.lineStart=At}},qa=Lt($t,qt,Pt,[-qo,-qo/2]),Ia=1e9;ao.geo.clipExtent=function(){var n,t,r,e,i,u,o={stream:function(n){return i&&(i.valid=!1),i=u(n),i.valid=!0,i},extent:function(a){return arguments.length?(u=Wt(n=+a[0][0],t=+a[0][1],r=+a[1][0],e=+a[1][1]),i&&(i.valid=!1,i=null),o):[[n,t],[r,e]]}};return o.extent([[0,0],[960,500]])},(ao.geo.conicEqualArea=function(){return Bt(Yt)}).raw=Yt,ao.geo.albers=function(){return ao.geo.conicEqualArea().rotate([96,0]).center([-.6,38.7]).parallels([29.5,45.5]).scale(1070)},ao.geo.albersUsa=function(){function n(n){var u=n[0],o=n[1];return t=null,r(u,o),t||(e(u,o),t)||i(u,o),t}var t,r,e,i,u=ao.geo.albers(),o=ao.geo.conicEqualArea().rotate([154,0]).center([-2,58.5]).parallels([55,65]),a=ao.geo.conicEqualArea().rotate([157,0]).center([-3,19.9]).parallels([8,18]),c={point:function(n,r){t=[n,r]}};return n.invert=function(n){var t=u.scale(),r=u.translate(),e=(n[0]-r[0])/t,i=(n[1]-r[1])/t;return(i>=.12&&.234>i&&e>=-.425&&-.214>e?o:i>=.166&&.234>i&&e>=-.214&&-.115>e?a:u).invert(n)},n.stream=function(n){var t=u.stream(n),r=o.stream(n),e=a.stream(n);return{point:function(n,i){t.point(n,i),r.point(n,i),e.point(n,i)},sphere:function(){t.sphere(),r.sphere(),e.sphere()},lineStart:function(){t.lineStart(),r.lineStart(),e.lineStart()},lineEnd:function(){t.lineEnd(),r.lineEnd(),e.lineEnd()},polygonStart:function(){t.polygonStart(),r.polygonStart(),e.polygonStart()},polygonEnd:function(){t.polygonEnd(),r.polygonEnd(),e.polygonEnd()}}},n.precision=function(t){return arguments.length?(u.precision(t),o.precision(t),a.precision(t),n):u.precision()},n.scale=function(t){return arguments.length?(u.scale(t),o.scale(.35*t),a.scale(t),n.translate(u.translate())):u.scale()},n.translate=function(t){if(!arguments.length)return u.translate();var l=u.scale(),f=+t[0],s=+t[1];return r=u.translate(t).clipExtent([[f-.455*l,s-.238*l],[f+.455*l,s+.238*l]]).stream(c).point,e=o.translate([f-.307*l,s+.201*l]).clipExtent([[f-.425*l+Oo,s+.12*l+Oo],[f-.214*l-Oo,s+.234*l-Oo]]).stream(c).point,i=a.translate([f-.205*l,s+.212*l]).clipExtent([[f-.214*l+Oo,s+.166*l+Oo],[f-.115*l-Oo,s+.234*l-Oo]]).stream(c).point,n},n.scale(1070)};var Pa,Ua,Fa,Ha,Wa,Ba,Ya={point:M,lineStart:M,lineEnd:M,polygonStart:function(){Ua=0,Ya.lineStart=Zt},polygonEnd:function(){Ya.lineStart=Ya.lineEnd=Ya.point=M,Pa+=xo(Ua/2)}},Za={point:Vt,lineStart:M,lineEnd:M,polygonStart:M,polygonEnd:M},Va={point:Jt,lineStart:Qt,lineEnd:Gt,polygonStart:function(){Va.lineStart=nr},polygonEnd:function(){Va.point=Jt,Va.lineStart=Qt,Va.lineEnd=Gt}};ao.geo.path=function(){function n(n){return n&&("function"==typeof a&&u.pointRadius(+a.apply(this,arguments)),o&&o.valid||(o=i(u)),ao.geo.stream(n,o)),u.result()}function t(){return o=null,n}var r,e,i,u,o,a=4.5;return n.area=function(n){return Pa=0,ao.geo.stream(n,i(Ya)),Pa},n.centroid=function(n){return Ea=Na=$a=ja=Da=Ta=La=Ra=Oa=0,ao.geo.stream(n,i(Va)),Oa?[La/Oa,Ra/Oa]:Ta?[ja/Ta,Da/Ta]:$a?[Ea/$a,Na/$a]:[NaN,NaN]},n.bounds=function(n){return Wa=Ba=-(Fa=Ha=1/0),ao.geo.stream(n,i(Za)),[[Fa,Ha],[Wa,Ba]]},n.projection=function(n){return arguments.length?(i=(r=n)?n.stream||er(n):m,t()):r},n.context=function(n){return arguments.length?(u=null==(e=n)?new Xt:new tr(n),"function"!=typeof a&&u.pointRadius(a),t()):e},n.pointRadius=function(t){return arguments.length?(a="function"==typeof t?t:(u.pointRadius(+t),+t),n):a},n.projection(ao.geo.albersUsa()).context(null)},ao.geo.transform=function(n){return{stream:function(t){var r=new ir(t);for(var e in n)r[e]=n[e];return r}}},ir.prototype={point:function(n,t){this.stream.point(n,t)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}},ao.geo.projection=or,ao.geo.projectionMutator=ar,(ao.geo.equirectangular=function(){return or(lr)}).raw=lr.invert=lr,ao.geo.rotation=function(n){function t(t){return t=n(t[0]*Fo,t[1]*Fo),t[0]*=Ho,t[1]*=Ho,t}return n=sr(n[0]%360*Fo,n[1]*Fo,n.length>2?n[2]*Fo:0),t.invert=function(t){return t=n.invert(t[0]*Fo,t[1]*Fo),t[0]*=Ho,t[1]*=Ho,t},t},fr.invert=lr,ao.geo.circle=function(){function n(){var n="function"==typeof e?e.apply(this,arguments):e,t=sr(-n[0]*Fo,-n[1]*Fo,0).invert,i=[];return r(null,null,1,{point:function(n,r){i.push(n=t(n,r)),n[0]*=Ho,n[1]*=Ho}}),{type:"Polygon",coordinates:[i]}}var t,r,e=[0,0],i=6;return n.origin=function(t){return arguments.length?(e=t,n):e},n.angle=function(e){return arguments.length?(r=gr((t=+e)*Fo,i*Fo),n):t},n.precision=function(e){return arguments.length?(r=gr(t*Fo,(i=+e)*Fo),n):i},n.angle(90)},ao.geo.distance=function(n,t){var r,e=(t[0]-n[0])*Fo,i=n[1]*Fo,u=t[1]*Fo,o=Math.sin(e),a=Math.cos(e),c=Math.sin(i),l=Math.cos(i),f=Math.sin(u),s=Math.cos(u);return Math.atan2(Math.sqrt((r=s*o)*r+(r=l*f-c*s*a)*r),c*f+l*s*a)},ao.geo.graticule=function(){function n(){return{type:"MultiLineString",coordinates:t()}}function t(){return ao.range(Math.ceil(u/d)*d,i,d).map(h).concat(ao.range(Math.ceil(l/y)*y,c,y).map(p)).concat(ao.range(Math.ceil(e/v)*v,r,v).filter(function(n){return xo(n%d)>Oo}).map(f)).concat(ao.range(Math.ceil(a/g)*g,o,g).filter(function(n){return xo(n%y)>Oo}).map(s))}var r,e,i,u,o,a,c,l,f,s,h,p,v=10,g=v,d=90,y=360,m=2.5;return n.lines=function(){return t().map(function(n){return{type:"LineString",coordinates:n}})},n.outline=function(){return{type:"Polygon",coordinates:[h(u).concat(p(c).slice(1),h(i).reverse().slice(1),p(l).reverse().slice(1))]}},n.extent=function(t){return arguments.length?n.majorExtent(t).minorExtent(t):n.minorExtent()},n.majorExtent=function(t){return arguments.length?(u=+t[0][0],i=+t[1][0],l=+t[0][1],c=+t[1][1],u>i&&(t=u,u=i,i=t),l>c&&(t=l,l=c,c=t),n.precision(m)):[[u,l],[i,c]]},n.minorExtent=function(t){return arguments.length?(e=+t[0][0],r=+t[1][0],a=+t[0][1],o=+t[1][1],e>r&&(t=e,e=r,r=t),a>o&&(t=a,a=o,o=t),n.precision(m)):[[e,a],[r,o]]},n.step=function(t){return arguments.length?n.majorStep(t).minorStep(t):n.minorStep()},n.majorStep=function(t){return arguments.length?(d=+t[0],y=+t[1],n):[d,y]},n.minorStep=function(t){return arguments.length?(v=+t[0],g=+t[1],n):[v,g]},n.precision=function(t){return arguments.length?(m=+t,f=yr(a,o,90),s=mr(e,r,m),h=yr(l,c,90),p=mr(u,i,m),n):m},n.majorExtent([[-180,-90+Oo],[180,90-Oo]]).minorExtent([[-180,-80-Oo],[180,80+Oo]])},ao.geo.greatArc=function(){function n(){return{type:"LineString",coordinates:[t||e.apply(this,arguments),r||i.apply(this,arguments)]}}var t,r,e=_r,i=xr;return n.distance=function(){return ao.geo.distance(t||e.apply(this,arguments),r||i.apply(this,arguments))},n.source=function(r){return arguments.length?(e=r,t="function"==typeof r?null:r,n):e},n.target=function(t){return arguments.length?(i=t,r="function"==typeof t?null:t,n):i},n.precision=function(){return arguments.length?n:0},n},ao.geo.interpolate=function(n,t){return Mr(n[0]*Fo,n[1]*Fo,t[0]*Fo,t[1]*Fo)},ao.geo.length=function(n){return Xa=0,ao.geo.stream(n,Ka),Xa};var Xa,Ka={sphere:M,point:M,lineStart:br,lineEnd:M,polygonStart:M,polygonEnd:M},Ja=wr(function(n){return Math.sqrt(2/(1+n))},function(n){return 2*Math.asin(n/2)});(ao.geo.azimuthalEqualArea=function(){return or(Ja)}).raw=Ja;var Qa=wr(function(n){var t=Math.acos(n);return t&&t/Math.sin(t)},m);(ao.geo.azimuthalEquidistant=function(){return or(Qa)}).raw=Qa,(ao.geo.conicConformal=function(){return Bt(kr)}).raw=kr,(ao.geo.conicEquidistant=function(){return Bt(Cr)}).raw=Cr;var Ga=wr(function(n){return 1/n},Math.atan);(ao.geo.gnomonic=function(){return or(Ga)}).raw=Ga,Ar.invert=function(n,t){return[n,2*Math.atan(Math.exp(t))-Uo]},(ao.geo.mercator=function(){return Sr(Ar)}).raw=Ar;var nc=wr(function(){return 1},Math.asin);(ao.geo.orthographic=function(){return or(nc)}).raw=nc;var tc=wr(function(n){return 1/(1+n)},function(n){return 2*Math.atan(n)});(ao.geo.stereographic=function(){return or(tc)}).raw=tc,Er.invert=function(n,t){return[-t,2*Math.atan(Math.exp(n))-Uo]},(ao.geo.transverseMercator=function(){var n=Sr(Er),t=n.center,r=n.rotate;return n.center=function(n){return n?t([-n[1],n[0]]):(n=t(),[n[1],-n[0]])},n.rotate=function(n){return n?r([n[0],n[1],n.length>2?n[2]+90:90]):(n=r(),[n[0],n[1],n[2]-90])},r([0,0,90])}).raw=Er,ao.geom={},ao.geom.hull=function(n){function t(n){if(n.length<3)return[];var t,i=Sn(r),u=Sn(e),o=n.length,a=[],c=[];for(t=0;o>t;t++)a.push([+i.call(this,n[t],t),+u.call(this,n[t],t),t]);for(a.sort(Dr),t=0;o>t;t++)c.push([a[t][0],-a[t][1]]);var l=jr(a),f=jr(c),s=f[0]===l[0],h=f[f.length-1]===l[l.length-1],p=[];for(t=l.length-1;t>=0;--t)p.push(n[a[l[t]][2]]);for(t=+s;t<f.length-h;++t)p.push(n[a[f[t]][2]]);return p}var r=Nr,e=$r;return arguments.length?t(n):(t.x=function(n){return arguments.length?(r=n,t):r},t.y=function(n){return arguments.length?(e=n,t):e},t)},ao.geom.polygon=function(n){return Co(n,rc),n};var rc=ao.geom.polygon.prototype=[];rc.area=function(){for(var n,t=-1,r=this.length,e=this[r-1],i=0;++t<r;)n=e,e=this[t],i+=n[1]*e[0]-n[0]*e[1];return.5*i},rc.centroid=function(n){var t,r,e=-1,i=this.length,u=0,o=0,a=this[i-1];for(arguments.length||(n=-1/(6*this.area()));++e<i;)t=a,a=this[e],r=t[0]*a[1]-a[0]*t[1],u+=(t[0]+a[0])*r,o+=(t[1]+a[1])*r;return[u*n,o*n]},rc.clip=function(n){for(var t,r,e,i,u,o,a=Rr(n),c=-1,l=this.length-Rr(this),f=this[l-1];++c<l;){for(t=n.slice(),n.length=0,i=this[c],u=t[(e=t.length-a)-1],r=-1;++r<e;)o=t[r],Tr(o,f,i)?(Tr(u,f,i)||n.push(Lr(u,o,f,i)),n.push(o)):Tr(u,f,i)&&n.push(Lr(u,o,f,i)),u=o;a&&n.push(n[0]),f=i}return n};var ec,ic,uc,oc,ac,cc=[],lc=[];Hr.prototype.prepare=function(){for(var n,t=this.edges,r=t.length;r--;)n=t[r].edge,n.b&&n.a||t.splice(r,1);return t.sort(Br),t.length},te.prototype={start:function(){return this.edge.l===this.site?this.edge.a:this.edge.b},end:function(){return this.edge.l===this.site?this.edge.b:this.edge.a}},re.prototype={insert:function(n,t){var r,e,i;if(n){if(t.P=n,t.N=n.N,n.N&&(n.N.P=t),n.N=t,n.R){for(n=n.R;n.L;)n=n.L;n.L=t}else n.R=t;r=n}else this._?(n=oe(this._),t.P=null,t.N=n,n.P=n.L=t,r=n):(t.P=t.N=null,this._=t,r=null);for(t.L=t.R=null,t.U=r,t.C=!0,n=t;r&&r.C;)e=r.U,r===e.L?(i=e.R,i&&i.C?(r.C=i.C=!1,e.C=!0,n=e):(n===r.R&&(ie(this,r),n=r,r=n.U),r.C=!1,e.C=!0,ue(this,e))):(i=e.L,i&&i.C?(r.C=i.C=!1,e.C=!0,n=e):(n===r.L&&(ue(this,r),n=r,r=n.U),r.C=!1,e.C=!0,ie(this,e))),r=n.U;this._.C=!1},remove:function(n){n.N&&(n.N.P=n.P),n.P&&(n.P.N=n.N),n.N=n.P=null;var t,r,e,i=n.U,u=n.L,o=n.R;if(r=u?o?oe(o):u:o,i?i.L===n?i.L=r:i.R=r:this._=r,u&&o?(e=r.C,r.C=n.C,r.L=u,u.U=r,r!==o?(i=r.U,r.U=n.U,n=r.R,i.L=n,r.R=o,o.U=r):(r.U=i,i=r,n=r.R)):(e=n.C,n=r),n&&(n.U=i),!e){if(n&&n.C)return void(n.C=!1);do{if(n===this._)break;if(n===i.L){if(t=i.R,t.C&&(t.C=!1,i.C=!0,ie(this,i),t=i.R),t.L&&t.L.C||t.R&&t.R.C){t.R&&t.R.C||(t.L.C=!1,t.C=!0,ue(this,t),t=i.R),t.C=i.C,i.C=t.R.C=!1,ie(this,i),n=this._;break}}else if(t=i.L,t.C&&(t.C=!1,i.C=!0,ue(this,i),t=i.L),t.L&&t.L.C||t.R&&t.R.C){t.L&&t.L.C||(t.R.C=!1,t.C=!0,ie(this,t),t=i.L),t.C=i.C,i.C=t.L.C=!1,ue(this,i),n=this._;break}t.C=!0,n=i,i=i.U}while(!n.C);n&&(n.C=!1)}}},ao.geom.voronoi=function(n){function t(n){var t=new Array(n.length),e=a[0][0],i=a[0][1],u=a[1][0],o=a[1][1];return ae(r(n),a).cells.forEach(function(r,a){var c=r.edges,l=r.site,f=t[a]=c.length?c.map(function(n){var t=n.start();return[t.x,t.y]}):l.x>=e&&l.x<=u&&l.y>=i&&l.y<=o?[[e,o],[u,o],[u,i],[e,i]]:[];f.point=n[a]}),t}function r(n){return n.map(function(n,t){return{x:Math.round(u(n,t)/Oo)*Oo,y:Math.round(o(n,t)/Oo)*Oo,i:t}})}var e=Nr,i=$r,u=e,o=i,a=fc;return n?t(n):(t.links=function(n){return ae(r(n)).edges.filter(function(n){return n.l&&n.r}).map(function(t){return{source:n[t.l.i],target:n[t.r.i]}})},t.triangles=function(n){var t=[];return ae(r(n)).cells.forEach(function(r,e){for(var i,u,o=r.site,a=r.edges.sort(Br),c=-1,l=a.length,f=a[l-1].edge,s=f.l===o?f.r:f.l;++c<l;)i=f,u=s,f=a[c].edge,s=f.l===o?f.r:f.l,e<u.i&&e<s.i&&le(o,u,s)<0&&t.push([n[e],n[u.i],n[s.i]])}),t},t.x=function(n){return arguments.length?(u=Sn(e=n),t):e},t.y=function(n){return arguments.length?(o=Sn(i=n),t):i},t.clipExtent=function(n){return arguments.length?(a=null==n?fc:n,t):a===fc?null:a},t.size=function(n){return arguments.length?t.clipExtent(n&&[[0,0],n]):a===fc?null:a&&a[1]},t)};var fc=[[-1e6,-1e6],[1e6,1e6]];ao.geom.delaunay=function(n){return ao.geom.voronoi().triangles(n)},ao.geom.quadtree=function(n,t,r,e,i){function u(n){function u(n,t,r,e,i,u,o,a){if(!isNaN(r)&&!isNaN(e))if(n.leaf){var c=n.x,f=n.y;if(null!=c)if(xo(c-r)+xo(f-e)<.01)l(n,t,r,e,i,u,o,a);else{var s=n.point;n.x=n.y=n.point=null,l(n,s,c,f,i,u,o,a),l(n,t,r,e,i,u,o,a)}else n.x=r,n.y=e,n.point=t}else l(n,t,r,e,i,u,o,a)}function l(n,t,r,e,i,o,a,c){var l=.5*(i+a),f=.5*(o+c),s=r>=l,h=e>=f,p=h<<1|s;n.leaf=!1,n=n.nodes[p]||(n.nodes[p]=he()),s?i=l:a=l,h?o=f:c=f,u(n,t,r,e,i,o,a,c)}var f,s,h,p,v,g,d,y,m,_=Sn(a),x=Sn(c);if(null!=t)g=t,d=r,y=e,m=i;else if(y=m=-(g=d=1/0),s=[],h=[],v=n.length,o)for(p=0;v>p;++p)f=n[p],f.x<g&&(g=f.x),f.y<d&&(d=f.y),f.x>y&&(y=f.x),f.y>m&&(m=f.y),s.push(f.x),h.push(f.y);else for(p=0;v>p;++p){var M=+_(f=n[p],p),b=+x(f,p);g>M&&(g=M),d>b&&(d=b),M>y&&(y=M),b>m&&(m=b),s.push(M),h.push(b)}var w=y-g,k=m-d;w>k?m=d+w:y=g+k;var C=he();if(C.add=function(n){u(C,n,+_(n,++p),+x(n,p),g,d,y,m)},C.visit=function(n){pe(n,C,g,d,y,m)},C.find=function(n){return ve(C,n[0],n[1],g,d,y,m)},p=-1,null==t){for(;++p<v;)u(C,n[p],s[p],h[p],g,d,y,m);--p}else n.forEach(C.add);return s=h=n=f=null,C}var o,a=Nr,c=$r;return(o=arguments.length)?(a=fe,c=se,3===o&&(i=r,e=t,r=t=0),u(n)):(u.x=function(n){return arguments.length?(a=n,u):a},u.y=function(n){return arguments.length?(c=n,u):c},u.extent=function(n){return arguments.length?(null==n?t=r=e=i=null:(t=+n[0][0],r=+n[0][1],e=+n[1][0],i=+n[1][1]),u):null==t?null:[[t,r],[e,i]]},u.size=function(n){return arguments.length?(null==n?t=r=e=i=null:(t=r=0,e=+n[0],i=+n[1]),u):null==t?null:[e-t,i-r]},u)},ao.interpolateRgb=ge,ao.interpolateObject=de,ao.interpolateNumber=ye,ao.interpolateString=me;var sc=/[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,hc=new RegExp(sc.source,"g");ao.interpolate=_e,ao.interpolators=[function(n,t){var r=typeof t;return("string"===r?ia.has(t.toLowerCase())||/^(#|rgb\(|hsl\()/i.test(t)?ge:me:t instanceof an?ge:Array.isArray(t)?xe:"object"===r&&isNaN(t)?de:ye)(n,t)}],ao.interpolateArray=xe;var pc=function(){return m},vc=ao.map({linear:pc,poly:Se,quad:function(){return ke},cubic:function(){return Ce},sin:function(){return Ee},exp:function(){return Ne},circle:function(){return $e},elastic:je,back:De,bounce:function(){return Te}}),gc=ao.map({"in":m,out:be,"in-out":we,"out-in":function(n){return we(be(n))}});ao.ease=function(n){var t=n.indexOf("-"),r=t>=0?n.slice(0,t):n,e=t>=0?n.slice(t+1):"in";return r=vc.get(r)||pc,e=gc.get(e)||m,Me(e(r.apply(null,co.call(arguments,1))))},ao.interpolateHcl=Le,ao.interpolateHsl=Re,ao.interpolateLab=Oe,ao.interpolateRound=ze,ao.transform=function(n){var t=fo.createElementNS(ao.ns.prefix.svg,"g");return(ao.transform=function(n){if(null!=n){t.setAttribute("transform",n);var r=t.transform.baseVal.consolidate()}return new qe(r?r.matrix:dc)})(n)},qe.prototype.toString=function(){return"translate("+this.translate+")rotate("+this.rotate+")skewX("+this.skew+")scale("+this.scale+")"};var dc={a:1,b:0,c:0,d:1,e:0,f:0};ao.interpolateTransform=Ze,ao.layout={},ao.layout.bundle=function(){return function(n){for(var t=[],r=-1,e=n.length;++r<e;)t.push(Ke(n[r]));return t}},ao.layout.chord=function(){function n(){var n,l,s,h,p,v={},g=[],d=ao.range(u),y=[];for(r=[],e=[],n=0,h=-1;++h<u;){for(l=0,p=-1;++p<u;)l+=i[h][p];g.push(l),y.push(ao.range(u)),n+=l}for(o&&d.sort(function(n,t){return o(g[n],g[t])}),a&&y.forEach(function(n,t){n.sort(function(n,r){return a(i[t][n],i[t][r])})}),n=(Io-f*u)/n,l=0,h=-1;++h<u;){for(s=l,p=-1;++p<u;){var m=d[h],_=y[m][p],x=i[m][_],M=l,b=l+=x*n;v[m+"-"+_]={index:m,subindex:_,startAngle:M,endAngle:b,value:x}}e[m]={index:m,startAngle:s,endAngle:l,value:g[m]},l+=f}for(h=-1;++h<u;)for(p=h-1;++p<u;){var w=v[h+"-"+p],k=v[p+"-"+h];(w.value||k.value)&&r.push(w.value<k.value?{source:k,target:w}:{source:w,target:k})}c&&t()}function t(){r.sort(function(n,t){return c((n.source.value+n.target.value)/2,(t.source.value+t.target.value)/2)})}var r,e,i,u,o,a,c,l={},f=0;return l.matrix=function(n){return arguments.length?(u=(i=n)&&i.length,r=e=null,l):i},l.padding=function(n){return arguments.length?(f=n,r=e=null,l):f},l.sortGroups=function(n){return arguments.length?(o=n,r=e=null,l):o},l.sortSubgroups=function(n){return arguments.length?(a=n,r=null,l):a},l.sortChords=function(n){return arguments.length?(c=n,r&&t(),l):c},l.chords=function(){return r||n(),r},l.groups=function(){return e||n(),e},l},ao.layout.force=function(){function n(n){return function(t,r,e,i){if(t.point!==n){var u=t.cx-n.x,o=t.cy-n.y,a=i-r,c=u*u+o*o;if(c>a*a/y){if(g>c){var l=t.charge/c;n.px-=u*l,n.py-=o*l}return!0}if(t.point&&c&&g>c){var l=t.pointCharge/c;n.px-=u*l,n.py-=o*l}}return!t.charge}}function t(n){n.px=ao.event.x,n.py=ao.event.y,c.resume()}var r,e,i,u,o,a,c={},l=ao.dispatch("start","tick","end"),f=[1,1],s=.9,h=yc,p=mc,v=-30,g=_c,d=.1,y=.64,_=[],x=[];return c.tick=function(){if((i*=.99)<.005)return r=null,l.end({type:"end",alpha:i=0}),!0;var t,e,c,h,p,g,y,m,M,b=_.length,w=x.length;for(e=0;w>e;++e)c=x[e],h=c.source,p=c.target,m=p.x-h.x,M=p.y-h.y,(g=m*m+M*M)&&(g=i*o[e]*((g=Math.sqrt(g))-u[e])/g,m*=g,M*=g,p.x-=m*(y=h.weight+p.weight?h.weight/(h.weight+p.weight):.5),p.y-=M*y,h.x+=m*(y=1-y),h.y+=M*y);if((y=i*d)&&(m=f[0]/2,M=f[1]/2,e=-1,y))for(;++e<b;)c=_[e],c.x+=(m-c.x)*y,c.y+=(M-c.y)*y;if(v)for(ei(t=ao.geom.quadtree(_),i,a),e=-1;++e<b;)(c=_[e]).fixed||t.visit(n(c));for(e=-1;++e<b;)c=_[e],c.fixed?(c.x=c.px,c.y=c.py):(c.x-=(c.px-(c.px=c.x))*s,c.y-=(c.py-(c.py=c.y))*s);l.tick({type:"tick",alpha:i})},c.nodes=function(n){return arguments.length?(_=n,c):_},c.links=function(n){return arguments.length?(x=n,c):x},c.size=function(n){return arguments.length?(f=n,c):f},c.linkDistance=function(n){return arguments.length?(h="function"==typeof n?n:+n,c):h},c.distance=c.linkDistance,c.linkStrength=function(n){return arguments.length?(p="function"==typeof n?n:+n,c):p},c.friction=function(n){return arguments.length?(s=+n,c):s},c.charge=function(n){return arguments.length?(v="function"==typeof n?n:+n,c):v},c.chargeDistance=function(n){return arguments.length?(g=n*n,c):Math.sqrt(g)},c.gravity=function(n){return arguments.length?(d=+n,c):d},c.theta=function(n){return arguments.length?(y=n*n,c):Math.sqrt(y)},c.alpha=function(n){return arguments.length?(n=+n,i?n>0?i=n:(r.c=null,r.t=NaN,r=null,l.end({type:"end",alpha:i=0})):n>0&&(l.start({type:"start",alpha:i=n}),r=Dn(c.tick)),c):i},c.start=function(){function n(n,e){if(!r){for(r=new Array(i),c=0;i>c;++c)r[c]=[];for(c=0;l>c;++c){var u=x[c];r[u.source.index].push(u.target),r[u.target.index].push(u.source)}}for(var o,a=r[t],c=-1,f=a.length;++c<f;)if(!isNaN(o=a[c][n]))return o;return Math.random()*e}var t,r,e,i=_.length,l=x.length,s=f[0],g=f[1];for(t=0;i>t;++t)(e=_[t]).index=t,e.weight=0;for(t=0;l>t;++t)e=x[t],"number"==typeof e.source&&(e.source=_[e.source]),"number"==typeof e.target&&(e.target=_[e.target]),++e.source.weight,++e.target.weight;for(t=0;i>t;++t)e=_[t],isNaN(e.x)&&(e.x=n("x",s)),isNaN(e.y)&&(e.y=n("y",g)),isNaN(e.px)&&(e.px=e.x),isNaN(e.py)&&(e.py=e.y);if(u=[],"function"==typeof h)for(t=0;l>t;++t)u[t]=+h.call(this,x[t],t);else for(t=0;l>t;++t)u[t]=h;if(o=[],"function"==typeof p)for(t=0;l>t;++t)o[t]=+p.call(this,x[t],t);else for(t=0;l>t;++t)o[t]=p;if(a=[],"function"==typeof v)for(t=0;i>t;++t)a[t]=+v.call(this,_[t],t);else for(t=0;i>t;++t)a[t]=v;return c.resume()},c.resume=function(){return c.alpha(.1)},c.stop=function(){return c.alpha(0)},c.drag=function(){return e||(e=ao.behavior.drag().origin(m).on("dragstart.force",Ge).on("drag.force",t).on("dragend.force",ni)),arguments.length?void this.on("mouseover.force",ti).on("mouseout.force",ri).call(e):e},ao.rebind(c,l,"on")};var yc=20,mc=1,_c=1/0;ao.layout.hierarchy=function(){function n(i){var u,o=[i],a=[];for(i.depth=0;null!=(u=o.pop());)if(a.push(u),(l=r.call(n,u,u.depth))&&(c=l.length)){for(var c,l,f;--c>=0;)o.push(f=l[c]),f.parent=u,f.depth=u.depth+1;e&&(u.value=0),u.children=l}else e&&(u.value=+e.call(n,u,u.depth)||0),delete u.children;return oi(i,function(n){var r,i;t&&(r=n.children)&&r.sort(t),e&&(i=n.parent)&&(i.value+=n.value)}),a}var t=li,r=ai,e=ci;return n.sort=function(r){return arguments.length?(t=r,n):t},n.children=function(t){return arguments.length?(r=t,n):r},n.value=function(t){return arguments.length?(e=t,n):e},n.revalue=function(t){return e&&(ui(t,function(n){n.children&&(n.value=0)}),oi(t,function(t){var r;t.children||(t.value=+e.call(n,t,t.depth)||0),(r=t.parent)&&(r.value+=t.value)})),t},n},ao.layout.partition=function(){function n(t,r,e,i){var u=t.children;if(t.x=r,t.y=t.depth*i,t.dx=e,t.dy=i,u&&(o=u.length)){var o,a,c,l=-1;for(e=t.value?e/t.value:0;++l<o;)n(a=u[l],r,c=a.value*e,i),r+=c}}function t(n){var r=n.children,e=0;if(r&&(i=r.length))for(var i,u=-1;++u<i;)e=Math.max(e,t(r[u]));return 1+e}function r(r,u){var o=e.call(this,r,u);return n(o[0],0,i[0],i[1]/t(o[0])),o}var e=ao.layout.hierarchy(),i=[1,1];return r.size=function(n){return arguments.length?(i=n,r):i},ii(r,e)},ao.layout.pie=function(){function n(o){var a,c=o.length,l=o.map(function(r,e){return+t.call(n,r,e)}),f=+("function"==typeof e?e.apply(this,arguments):e),s=("function"==typeof i?i.apply(this,arguments):i)-f,h=Math.min(Math.abs(s)/c,+("function"==typeof u?u.apply(this,arguments):u)),p=h*(0>s?-1:1),v=ao.sum(l),g=v?(s-c*p)/v:0,d=ao.range(c),y=[];return null!=r&&d.sort(r===xc?function(n,t){return l[t]-l[n]}:function(n,t){return r(o[n],o[t])}),d.forEach(function(n){y[n]={data:o[n],value:a=l[n],startAngle:f,endAngle:f+=a*g+p,padAngle:h}}),y}var t=Number,r=xc,e=0,i=Io,u=0;return n.value=function(r){return arguments.length?(t=r,n):t},n.sort=function(t){return arguments.length?(r=t,n):r},n.startAngle=function(t){return arguments.length?(e=t,n):e},n.endAngle=function(t){return arguments.length?(i=t,n):i},n.padAngle=function(t){return arguments.length?(u=t,n):u},n};var xc={};ao.layout.stack=function(){function n(a,c){if(!(h=a.length))return a;var l=a.map(function(r,e){return t.call(n,r,e)}),f=l.map(function(t){return t.map(function(t,r){return[u.call(n,t,r),o.call(n,t,r)]})}),s=r.call(n,f,c);l=ao.permute(l,s),f=ao.permute(f,s);var h,p,v,g,d=e.call(n,f,c),y=l[0].length;for(v=0;y>v;++v)for(i.call(n,l[0][v],g=d[v],f[0][v][1]),p=1;h>p;++p)i.call(n,l[p][v],g+=f[p-1][v][1],f[p][v][1]);return a}var t=m,r=vi,e=gi,i=pi,u=si,o=hi;return n.values=function(r){return arguments.length?(t=r,n):t},n.order=function(t){return arguments.length?(r="function"==typeof t?t:Mc.get(t)||vi,n):r},n.offset=function(t){return arguments.length?(e="function"==typeof t?t:bc.get(t)||gi,n):e},n.x=function(t){return arguments.length?(u=t,n):u},n.y=function(t){return arguments.length?(o=t,n):o},n.out=function(t){return arguments.length?(i=t,n):i},n};var Mc=ao.map({"inside-out":function(n){var t,r,e=n.length,i=n.map(di),u=n.map(yi),o=ao.range(e).sort(function(n,t){return i[n]-i[t]}),a=0,c=0,l=[],f=[];for(t=0;e>t;++t)r=o[t],c>a?(a+=u[r],l.push(r)):(c+=u[r],f.push(r));return f.reverse().concat(l)},reverse:function(n){return ao.range(n.length).reverse()},"default":vi}),bc=ao.map({silhouette:function(n){var t,r,e,i=n.length,u=n[0].length,o=[],a=0,c=[];for(r=0;u>r;++r){for(t=0,e=0;i>t;t++)e+=n[t][r][1];e>a&&(a=e),o.push(e)}for(r=0;u>r;++r)c[r]=(a-o[r])/2;return c},wiggle:function(n){var t,r,e,i,u,o,a,c,l,f=n.length,s=n[0],h=s.length,p=[];for(p[0]=c=l=0,r=1;h>r;++r){for(t=0,i=0;f>t;++t)i+=n[t][r][1];for(t=0,u=0,a=s[r][0]-s[r-1][0];f>t;++t){for(e=0,o=(n[t][r][1]-n[t][r-1][1])/(2*a);t>e;++e)o+=(n[e][r][1]-n[e][r-1][1])/a;u+=o*n[t][r][1]}p[r]=c-=i?u/i*a:0,l>c&&(l=c)}for(r=0;h>r;++r)p[r]-=l;return p},expand:function(n){var t,r,e,i=n.length,u=n[0].length,o=1/i,a=[];for(r=0;u>r;++r){for(t=0,e=0;i>t;t++)e+=n[t][r][1];if(e)for(t=0;i>t;t++)n[t][r][1]/=e;else for(t=0;i>t;t++)n[t][r][1]=o}for(r=0;u>r;++r)a[r]=0;return a},zero:gi});ao.layout.histogram=function(){function n(n,u){for(var o,a,c=[],l=n.map(r,this),f=e.call(this,l,u),s=i.call(this,f,l,u),u=-1,h=l.length,p=s.length-1,v=t?1:1/h;++u<p;)o=c[u]=[],o.dx=s[u+1]-(o.x=s[u]),o.y=0;if(p>0)for(u=-1;++u<h;)a=l[u],a>=f[0]&&a<=f[1]&&(o=c[ao.bisect(s,a,1,p)-1],o.y+=v,o.push(n[u]));return c}var t=!0,r=Number,e=Mi,i=_i;return n.value=function(t){return arguments.length?(r=t,n):r},n.range=function(t){return arguments.length?(e=Sn(t),n):e},n.bins=function(t){return arguments.length?(i="number"==typeof t?function(n){return xi(n,t)}:Sn(t),n):i},n.frequency=function(r){return arguments.length?(t=!!r,n):t},n},ao.layout.pack=function(){function n(n,u){var o=r.call(this,n,u),a=o[0],c=i[0],l=i[1],f=null==t?Math.sqrt:"function"==typeof t?t:function(){return t};if(a.x=a.y=0,oi(a,function(n){n.r=+f(n.value)}),oi(a,Ai),e){var s=e*(t?1:Math.max(2*a.r/c,2*a.r/l))/2;oi(a,function(n){n.r+=s}),oi(a,Ai),oi(a,function(n){n.r-=s})}return Ni(a,c/2,l/2,t?1:1/Math.max(2*a.r/c,2*a.r/l)),o}var t,r=ao.layout.hierarchy().sort(bi),e=0,i=[1,1];return n.size=function(t){return arguments.length?(i=t,n):i},n.radius=function(r){return arguments.length?(t=null==r||"function"==typeof r?r:+r,n):t},n.padding=function(t){return arguments.length?(e=+t,n):e},ii(n,r)},ao.layout.tree=function(){function n(n,i){var f=o.call(this,n,i),s=f[0],h=t(s);if(oi(h,r),h.parent.m=-h.z,ui(h,e),l)ui(s,u);else{var p=s,v=s,g=s;ui(s,function(n){n.x<p.x&&(p=n),n.x>v.x&&(v=n),n.depth>g.depth&&(g=n)});var d=a(p,v)/2-p.x,y=c[0]/(v.x+a(v,p)/2+d),m=c[1]/(g.depth||1);ui(s,function(n){n.x=(n.x+d)*y,n.y=n.depth*m})}return f}function t(n){for(var t,r={A:null,children:[n]},e=[r];null!=(t=e.pop());)for(var i,u=t.children,o=0,a=u.length;a>o;++o)e.push((u[o]=i={_:u[o],parent:t,children:(i=u[o].children)&&i.slice()||[],A:null,a:null,z:0,m:0,c:0,s:0,t:null,i:o}).a=i);return r.children[0]}function r(n){var t=n.children,r=n.parent.children,e=n.i?r[n.i-1]:null;if(t.length){Ri(n);var u=(t[0].z+t[t.length-1].z)/2;e?(n.z=e.z+a(n._,e._),n.m=n.z-u):n.z=u}else e&&(n.z=e.z+a(n._,e._));n.parent.A=i(n,e,n.parent.A||r[0])}function e(n){n._.x=n.z+n.parent.m,n.m+=n.parent.m}function i(n,t,r){if(t){for(var e,i=n,u=n,o=t,c=i.parent.children[0],l=i.m,f=u.m,s=o.m,h=c.m;o=Ti(o),i=Di(i),o&&i;)c=Di(c),u=Ti(u),u.a=n,e=o.z+s-i.z-l+a(o._,i._),e>0&&(Li(Oi(o,n,r),n,e),l+=e,f+=e),s+=o.m,l+=i.m,h+=c.m,f+=u.m;o&&!Ti(u)&&(u.t=o,u.m+=s-f),i&&!Di(c)&&(c.t=i,c.m+=l-h,r=n)}return r}function u(n){n.x*=c[0],n.y=n.depth*c[1]}var o=ao.layout.hierarchy().sort(null).value(null),a=ji,c=[1,1],l=null;return n.separation=function(t){return arguments.length?(a=t,n):a},n.size=function(t){return arguments.length?(l=null==(c=t)?u:null,n):l?null:c},n.nodeSize=function(t){return arguments.length?(l=null==(c=t)?null:u,n):l?c:null},ii(n,o)},ao.layout.cluster=function(){function n(n,u){var o,a=t.call(this,n,u),c=a[0],l=0;oi(c,function(n){var t=n.children;t&&t.length?(n.x=qi(t),n.y=zi(t)):(n.x=o?l+=r(n,o):0,n.y=0,o=n)});var f=Ii(c),s=Pi(c),h=f.x-r(f,s)/2,p=s.x+r(s,f)/2;return oi(c,i?function(n){n.x=(n.x-c.x)*e[0],n.y=(c.y-n.y)*e[1]}:function(n){n.x=(n.x-h)/(p-h)*e[0],n.y=(1-(c.y?n.y/c.y:1))*e[1]}),a}var t=ao.layout.hierarchy().sort(null).value(null),r=ji,e=[1,1],i=!1;return n.separation=function(t){return arguments.length?(r=t,n):r},n.size=function(t){return arguments.length?(i=null==(e=t),n):i?null:e},n.nodeSize=function(t){return arguments.length?(i=null!=(e=t),n):i?e:null},ii(n,t)},ao.layout.treemap=function(){function n(n,t){for(var r,e,i=-1,u=n.length;++i<u;)e=(r=n[i]).value*(0>t?0:t),r.area=isNaN(e)||0>=e?0:e}function t(r){var u=r.children;if(u&&u.length){var o,a,c,l=s(r),f=[],h=u.slice(),v=1/0,g="slice"===p?l.dx:"dice"===p?l.dy:"slice-dice"===p?1&r.depth?l.dy:l.dx:Math.min(l.dx,l.dy);for(n(h,l.dx*l.dy/r.value),f.area=0;(c=h.length)>0;)f.push(o=h[c-1]),f.area+=o.area,"squarify"!==p||(a=e(f,g))<=v?(h.pop(),v=a):(f.area-=f.pop().area,i(f,g,l,!1),g=Math.min(l.dx,l.dy),f.length=f.area=0,v=1/0);f.length&&(i(f,g,l,!0),f.length=f.area=0),u.forEach(t)}}function r(t){var e=t.children;if(e&&e.length){var u,o=s(t),a=e.slice(),c=[];for(n(a,o.dx*o.dy/t.value),c.area=0;u=a.pop();)c.push(u),c.area+=u.area,null!=u.z&&(i(c,u.z?o.dx:o.dy,o,!a.length),c.length=c.area=0);e.forEach(r)}}function e(n,t){for(var r,e=n.area,i=0,u=1/0,o=-1,a=n.length;++o<a;)(r=n[o].area)&&(u>r&&(u=r),r>i&&(i=r));return e*=e,t*=t,e?Math.max(t*i*v/e,e/(t*u*v)):1/0}function i(n,t,r,e){var i,u=-1,o=n.length,a=r.x,l=r.y,f=t?c(n.area/t):0;
+if(t==r.dx){for((e||f>r.dy)&&(f=r.dy);++u<o;)i=n[u],i.x=a,i.y=l,i.dy=f,a+=i.dx=Math.min(r.x+r.dx-a,f?c(i.area/f):0);i.z=!0,i.dx+=r.x+r.dx-a,r.y+=f,r.dy-=f}else{for((e||f>r.dx)&&(f=r.dx);++u<o;)i=n[u],i.x=a,i.y=l,i.dx=f,l+=i.dy=Math.min(r.y+r.dy-l,f?c(i.area/f):0);i.z=!1,i.dy+=r.y+r.dy-l,r.x+=f,r.dx-=f}}function u(e){var i=o||a(e),u=i[0];return u.x=u.y=0,u.value?(u.dx=l[0],u.dy=l[1]):u.dx=u.dy=0,o&&a.revalue(u),n([u],u.dx*u.dy/u.value),(o?r:t)(u),h&&(o=i),i}var o,a=ao.layout.hierarchy(),c=Math.round,l=[1,1],f=null,s=Ui,h=!1,p="squarify",v=.5*(1+Math.sqrt(5));return u.size=function(n){return arguments.length?(l=n,u):l},u.padding=function(n){function t(t){var r=n.call(u,t,t.depth);return null==r?Ui(t):Fi(t,"number"==typeof r?[r,r,r,r]:r)}function r(t){return Fi(t,n)}if(!arguments.length)return f;var e;return s=null==(f=n)?Ui:"function"==(e=typeof n)?t:"number"===e?(n=[n,n,n,n],r):r,u},u.round=function(n){return arguments.length?(c=n?Math.round:Number,u):c!=Number},u.sticky=function(n){return arguments.length?(h=n,o=null,u):h},u.ratio=function(n){return arguments.length?(v=n,u):v},u.mode=function(n){return arguments.length?(p=n+"",u):p},ii(u,a)},ao.random={normal:function(n,t){var r=arguments.length;return 2>r&&(t=1),1>r&&(n=0),function(){var r,e,i;do r=2*Math.random()-1,e=2*Math.random()-1,i=r*r+e*e;while(!i||i>1);return n+t*r*Math.sqrt(-2*Math.log(i)/i)}},logNormal:function(){var n=ao.random.normal.apply(ao,arguments);return function(){return Math.exp(n())}},bates:function(n){var t=ao.random.irwinHall(n);return function(){return t()/n}},irwinHall:function(n){return function(){for(var t=0,r=0;n>r;r++)t+=Math.random();return t}}},ao.scale={};var wc={floor:m,ceil:m};ao.scale.linear=function(){return Xi([0,1],[0,1],_e,!1)};var kc={s:1,g:1,p:1,r:1,e:1};ao.scale.log=function(){return eu(ao.scale.linear().domain([0,1]),10,!0,[1,10])};var Cc=ao.format(".0e"),Ac={floor:function(n){return-Math.ceil(-n)},ceil:function(n){return-Math.floor(-n)}};ao.scale.pow=function(){return iu(ao.scale.linear(),1,[0,1])},ao.scale.sqrt=function(){return ao.scale.pow().exponent(.5)},ao.scale.ordinal=function(){return ou([],{t:"range",a:[[]]})},ao.scale.category10=function(){return ao.scale.ordinal().range(Sc)},ao.scale.category20=function(){return ao.scale.ordinal().range(Ec)},ao.scale.category20b=function(){return ao.scale.ordinal().range(Nc)},ao.scale.category20c=function(){return ao.scale.ordinal().range($c)};var Sc=[2062260,16744206,2924588,14034728,9725885,9197131,14907330,8355711,12369186,1556175].map(xn),Ec=[2062260,11454440,16744206,16759672,2924588,10018698,14034728,16750742,9725885,12955861,9197131,12885140,14907330,16234194,8355711,13092807,12369186,14408589,1556175,10410725].map(xn),Nc=[3750777,5395619,7040719,10264286,6519097,9216594,11915115,13556636,9202993,12426809,15186514,15190932,8666169,11356490,14049643,15177372,8077683,10834324,13528509,14589654].map(xn),$c=[3244733,7057110,10406625,13032431,15095053,16616764,16625259,16634018,3253076,7652470,10607003,13101504,7695281,10394312,12369372,14342891,6513507,9868950,12434877,14277081].map(xn);ao.scale.quantile=function(){return au([],[])},ao.scale.quantize=function(){return cu(0,1,[0,1])},ao.scale.threshold=function(){return lu([.5],[0,1])},ao.scale.identity=function(){return fu([0,1])},ao.svg={},ao.svg.arc=function(){function n(){var n=Math.max(0,+r.apply(this,arguments)),l=Math.max(0,+e.apply(this,arguments)),f=o.apply(this,arguments)-Uo,s=a.apply(this,arguments)-Uo,h=Math.abs(s-f),p=f>s?0:1;if(n>l&&(v=l,l=n,n=v),h>=Po)return t(l,p)+(n?t(n,1-p):"")+"Z";var v,g,d,y,m,_,x,M,b,w,k,C,A=0,S=0,E=[];if((y=(+c.apply(this,arguments)||0)/2)&&(d=u===jc?Math.sqrt(n*n+l*l):+u.apply(this,arguments),p||(S*=-1),l&&(S=tn(d/l*Math.sin(y))),n&&(A=tn(d/n*Math.sin(y)))),l){m=l*Math.cos(f+S),_=l*Math.sin(f+S),x=l*Math.cos(s-S),M=l*Math.sin(s-S);var N=Math.abs(s-f-2*S)<=qo?0:1;if(S&&yu(m,_,x,M)===p^N){var $=(f+s)/2;m=l*Math.cos($),_=l*Math.sin($),x=M=null}}else m=_=0;if(n){b=n*Math.cos(s-A),w=n*Math.sin(s-A),k=n*Math.cos(f+A),C=n*Math.sin(f+A);var j=Math.abs(f-s+2*A)<=qo?0:1;if(A&&yu(b,w,k,C)===1-p^j){var D=(f+s)/2;b=n*Math.cos(D),w=n*Math.sin(D),k=C=null}}else b=w=0;if(h>Oo&&(v=Math.min(Math.abs(l-n)/2,+i.apply(this,arguments)))>.001){g=l>n^p?0:1;var T=v,L=v;if(qo>h){var R=null==k?[b,w]:null==x?[m,_]:Lr([m,_],[k,C],[x,M],[b,w]),O=m-R[0],z=_-R[1],q=x-R[0],I=M-R[1],P=1/Math.sin(Math.acos((O*q+z*I)/(Math.sqrt(O*O+z*z)*Math.sqrt(q*q+I*I)))/2),U=Math.sqrt(R[0]*R[0]+R[1]*R[1]);L=Math.min(v,(n-U)/(P-1)),T=Math.min(v,(l-U)/(P+1))}if(null!=x){var F=mu(null==k?[b,w]:[k,C],[m,_],l,T,p),H=mu([x,M],[b,w],l,T,p);v===T?E.push("M",F[0],"A",T,",",T," 0 0,",g," ",F[1],"A",l,",",l," 0 ",1-p^yu(F[1][0],F[1][1],H[1][0],H[1][1]),",",p," ",H[1],"A",T,",",T," 0 0,",g," ",H[0]):E.push("M",F[0],"A",T,",",T," 0 1,",g," ",H[0])}else E.push("M",m,",",_);if(null!=k){var W=mu([m,_],[k,C],n,-L,p),B=mu([b,w],null==x?[m,_]:[x,M],n,-L,p);v===L?E.push("L",B[0],"A",L,",",L," 0 0,",g," ",B[1],"A",n,",",n," 0 ",p^yu(B[1][0],B[1][1],W[1][0],W[1][1]),",",1-p," ",W[1],"A",L,",",L," 0 0,",g," ",W[0]):E.push("L",B[0],"A",L,",",L," 0 0,",g," ",W[0])}else E.push("L",b,",",w)}else E.push("M",m,",",_),null!=x&&E.push("A",l,",",l," 0 ",N,",",p," ",x,",",M),E.push("L",b,",",w),null!=k&&E.push("A",n,",",n," 0 ",j,",",1-p," ",k,",",C);return E.push("Z"),E.join("")}function t(n,t){return"M0,"+n+"A"+n+","+n+" 0 1,"+t+" 0,"+-n+"A"+n+","+n+" 0 1,"+t+" 0,"+n}var r=hu,e=pu,i=su,u=jc,o=vu,a=gu,c=du;return n.innerRadius=function(t){return arguments.length?(r=Sn(t),n):r},n.outerRadius=function(t){return arguments.length?(e=Sn(t),n):e},n.cornerRadius=function(t){return arguments.length?(i=Sn(t),n):i},n.padRadius=function(t){return arguments.length?(u=t==jc?jc:Sn(t),n):u},n.startAngle=function(t){return arguments.length?(o=Sn(t),n):o},n.endAngle=function(t){return arguments.length?(a=Sn(t),n):a},n.padAngle=function(t){return arguments.length?(c=Sn(t),n):c},n.centroid=function(){var n=(+r.apply(this,arguments)+ +e.apply(this,arguments))/2,t=(+o.apply(this,arguments)+ +a.apply(this,arguments))/2-Uo;return[Math.cos(t)*n,Math.sin(t)*n]},n};var jc="auto";ao.svg.line=function(){return _u(m)};var Dc=ao.map({linear:xu,"linear-closed":Mu,step:bu,"step-before":wu,"step-after":ku,basis:$u,"basis-open":ju,"basis-closed":Du,bundle:Tu,cardinal:Su,"cardinal-open":Cu,"cardinal-closed":Au,monotone:Iu});Dc.forEach(function(n,t){t.key=n,t.closed=/-closed$/.test(n)});var Tc=[0,2/3,1/3,0],Lc=[0,1/3,2/3,0],Rc=[0,1/6,2/3,1/6];ao.svg.line.radial=function(){var n=_u(Pu);return n.radius=n.x,delete n.x,n.angle=n.y,delete n.y,n},wu.reverse=ku,ku.reverse=wu,ao.svg.area=function(){return Uu(m)},ao.svg.area.radial=function(){var n=Uu(Pu);return n.radius=n.x,delete n.x,n.innerRadius=n.x0,delete n.x0,n.outerRadius=n.x1,delete n.x1,n.angle=n.y,delete n.y,n.startAngle=n.y0,delete n.y0,n.endAngle=n.y1,delete n.y1,n},ao.svg.chord=function(){function n(n,a){var c=t(this,u,n,a),l=t(this,o,n,a);return"M"+c.p0+e(c.r,c.p1,c.a1-c.a0)+(r(c,l)?i(c.r,c.p1,c.r,c.p0):i(c.r,c.p1,l.r,l.p0)+e(l.r,l.p1,l.a1-l.a0)+i(l.r,l.p1,c.r,c.p0))+"Z"}function t(n,t,r,e){var i=t.call(n,r,e),u=a.call(n,i,e),o=c.call(n,i,e)-Uo,f=l.call(n,i,e)-Uo;return{r:u,a0:o,a1:f,p0:[u*Math.cos(o),u*Math.sin(o)],p1:[u*Math.cos(f),u*Math.sin(f)]}}function r(n,t){return n.a0==t.a0&&n.a1==t.a1}function e(n,t,r){return"A"+n+","+n+" 0 "+ +(r>qo)+",1 "+t}function i(n,t,r,e){return"Q 0,0 "+e}var u=_r,o=xr,a=Fu,c=vu,l=gu;return n.radius=function(t){return arguments.length?(a=Sn(t),n):a},n.source=function(t){return arguments.length?(u=Sn(t),n):u},n.target=function(t){return arguments.length?(o=Sn(t),n):o},n.startAngle=function(t){return arguments.length?(c=Sn(t),n):c},n.endAngle=function(t){return arguments.length?(l=Sn(t),n):l},n},ao.svg.diagonal=function(){function n(n,i){var u=t.call(this,n,i),o=r.call(this,n,i),a=(u.y+o.y)/2,c=[u,{x:u.x,y:a},{x:o.x,y:a},o];return c=c.map(e),"M"+c[0]+"C"+c[1]+" "+c[2]+" "+c[3]}var t=_r,r=xr,e=Hu;return n.source=function(r){return arguments.length?(t=Sn(r),n):t},n.target=function(t){return arguments.length?(r=Sn(t),n):r},n.projection=function(t){return arguments.length?(e=t,n):e},n},ao.svg.diagonal.radial=function(){var n=ao.svg.diagonal(),t=Hu,r=n.projection;return n.projection=function(n){return arguments.length?r(Wu(t=n)):t},n},ao.svg.symbol=function(){function n(n,e){return(Oc.get(t.call(this,n,e))||Zu)(r.call(this,n,e))}var t=Yu,r=Bu;return n.type=function(r){return arguments.length?(t=Sn(r),n):t},n.size=function(t){return arguments.length?(r=Sn(t),n):r},n};var Oc=ao.map({circle:Zu,cross:function(n){var t=Math.sqrt(n/5)/2;return"M"+-3*t+","+-t+"H"+-t+"V"+-3*t+"H"+t+"V"+-t+"H"+3*t+"V"+t+"H"+t+"V"+3*t+"H"+-t+"V"+t+"H"+-3*t+"Z"},diamond:function(n){var t=Math.sqrt(n/(2*qc)),r=t*qc;return"M0,"+-t+"L"+r+",0 0,"+t+" "+-r+",0Z"},square:function(n){var t=Math.sqrt(n)/2;return"M"+-t+","+-t+"L"+t+","+-t+" "+t+","+t+" "+-t+","+t+"Z"},"triangle-down":function(n){var t=Math.sqrt(n/zc),r=t*zc/2;return"M0,"+r+"L"+t+","+-r+" "+-t+","+-r+"Z"},"triangle-up":function(n){var t=Math.sqrt(n/zc),r=t*zc/2;return"M0,"+-r+"L"+t+","+r+" "+-t+","+r+"Z"}});ao.svg.symbolTypes=Oc.keys();var zc=Math.sqrt(3),qc=Math.tan(30*Fo);No.transition=function(n){for(var t,r,e=Ic||++Hc,i=Qu(n),u=[],o=Pc||{time:Date.now(),ease:Ae,delay:0,duration:250},a=-1,c=this.length;++a<c;){u.push(t=[]);for(var l=this[a],f=-1,s=l.length;++f<s;)(r=l[f])&&Gu(r,f,i,e,o),t.push(r)}return Xu(u,i,e)},No.interrupt=function(n){return this.each(null==n?Uc:Vu(Qu(n)))};var Ic,Pc,Uc=Vu(Qu()),Fc=[],Hc=0;Fc.call=No.call,Fc.empty=No.empty,Fc.node=No.node,Fc.size=No.size,ao.transition=function(n,t){return n&&n.transition?Ic?n.transition(t):n:ao.selection().transition(n)},ao.transition.prototype=Fc,Fc.select=function(n){var t,r,e,i=this.id,u=this.namespace,o=[];n=E(n);for(var a=-1,c=this.length;++a<c;){o.push(t=[]);for(var l=this[a],f=-1,s=l.length;++f<s;)(e=l[f])&&(r=n.call(e,e.__data__,f,a))?("__data__"in e&&(r.__data__=e.__data__),Gu(r,f,u,i,e[u][i]),t.push(r)):t.push(null)}return Xu(o,u,i)},Fc.selectAll=function(n){var t,r,e,i,u,o=this.id,a=this.namespace,c=[];n=N(n);for(var l=-1,f=this.length;++l<f;)for(var s=this[l],h=-1,p=s.length;++h<p;)if(e=s[h]){u=e[a][o],r=n.call(e,e.__data__,h,l),c.push(t=[]);for(var v=-1,g=r.length;++v<g;)(i=r[v])&&Gu(i,v,a,o,u),t.push(i)}return Xu(c,a,o)},Fc.filter=function(n){var t,r,e,i=[];"function"!=typeof n&&(n=U(n));for(var u=0,o=this.length;o>u;u++){i.push(t=[]);for(var r=this[u],a=0,c=r.length;c>a;a++)(e=r[a])&&n.call(e,e.__data__,a,u)&&t.push(e)}return Xu(i,this.namespace,this.id)},Fc.tween=function(n,t){var r=this.id,e=this.namespace;return arguments.length<2?this.node()[e][r].tween.get(n):H(this,null==t?function(t){t[e][r].tween.remove(n)}:function(i){i[e][r].tween.set(n,t)})},Fc.attr=function(n,t){function r(){this.removeAttribute(a)}function e(){this.removeAttributeNS(a.space,a.local)}function i(n){return null==n?r:(n+="",function(){var t,r=this.getAttribute(a);return r!==n&&(t=o(r,n),function(n){this.setAttribute(a,t(n))})})}function u(n){return null==n?e:(n+="",function(){var t,r=this.getAttributeNS(a.space,a.local);return r!==n&&(t=o(r,n),function(n){this.setAttributeNS(a.space,a.local,t(n))})})}if(arguments.length<2){for(t in n)this.attr(t,n[t]);return this}var o="transform"==n?Ze:_e,a=ao.ns.qualify(n);return Ku(this,"attr."+n,t,a.local?u:i)},Fc.attrTween=function(n,t){function r(n,r){var e=t.call(this,n,r,this.getAttribute(i));return e&&function(n){this.setAttribute(i,e(n))}}function e(n,r){var e=t.call(this,n,r,this.getAttributeNS(i.space,i.local));return e&&function(n){this.setAttributeNS(i.space,i.local,e(n))}}var i=ao.ns.qualify(n);return this.tween("attr."+n,i.local?e:r)},Fc.style=function(n,r,e){function i(){this.style.removeProperty(n)}function u(r){return null==r?i:(r+="",function(){var i,u=t(this).getComputedStyle(this,null).getPropertyValue(n);return u!==r&&(i=_e(u,r),function(t){this.style.setProperty(n,i(t),e)})})}var o=arguments.length;if(3>o){if("string"!=typeof n){2>o&&(r="");for(e in n)this.style(e,n[e],r);return this}e=""}return Ku(this,"style."+n,r,u)},Fc.styleTween=function(n,r,e){function i(i,u){var o=r.call(this,i,u,t(this).getComputedStyle(this,null).getPropertyValue(n));return o&&function(t){this.style.setProperty(n,o(t),e)}}return arguments.length<3&&(e=""),this.tween("style."+n,i)},Fc.text=function(n){return Ku(this,"text",n,Ju)},Fc.remove=function(){var n=this.namespace;return this.each("end.transition",function(){var t;this[n].count<2&&(t=this.parentNode)&&t.removeChild(this)})},Fc.ease=function(n){var t=this.id,r=this.namespace;return arguments.length<1?this.node()[r][t].ease:("function"!=typeof n&&(n=ao.ease.apply(ao,arguments)),H(this,function(e){e[r][t].ease=n}))},Fc.delay=function(n){var t=this.id,r=this.namespace;return arguments.length<1?this.node()[r][t].delay:H(this,"function"==typeof n?function(e,i,u){e[r][t].delay=+n.call(e,e.__data__,i,u)}:(n=+n,function(e){e[r][t].delay=n}))},Fc.duration=function(n){var t=this.id,r=this.namespace;return arguments.length<1?this.node()[r][t].duration:H(this,"function"==typeof n?function(e,i,u){e[r][t].duration=Math.max(1,n.call(e,e.__data__,i,u))}:(n=Math.max(1,n),function(e){e[r][t].duration=n}))},Fc.each=function(n,t){var r=this.id,e=this.namespace;if(arguments.length<2){var i=Pc,u=Ic;try{Ic=r,H(this,function(t,i,u){Pc=t[e][r],n.call(t,t.__data__,i,u)})}finally{Pc=i,Ic=u}}else H(this,function(i){var u=i[e][r];(u.event||(u.event=ao.dispatch("start","end","interrupt"))).on(n,t)});return this},Fc.transition=function(){for(var n,t,r,e,i=this.id,u=++Hc,o=this.namespace,a=[],c=0,l=this.length;l>c;c++){a.push(n=[]);for(var t=this[c],f=0,s=t.length;s>f;f++)(r=t[f])&&(e=r[o][i],Gu(r,f,o,u,{time:e.time,ease:e.ease,delay:e.delay+e.duration,duration:e.duration})),n.push(r)}return Xu(a,o,u)},ao.svg.axis=function(){function n(n){n.each(function(){var n,l=ao.select(this),f=this.__chart__||r,s=this.__chart__=r.copy(),h=null==c?s.ticks?s.ticks.apply(s,a):s.domain():c,p=null==t?s.tickFormat?s.tickFormat.apply(s,a):m:t,v=l.selectAll(".tick").data(h,s),g=v.enter().insert("g",".domain").attr("class","tick").style("opacity",Oo),d=ao.transition(v.exit()).style("opacity",Oo).remove(),y=ao.transition(v.order()).style("opacity",1),_=Math.max(i,0)+o,x=Wi(s),M=l.selectAll(".domain").data([0]),b=(M.enter().append("path").attr("class","domain"),ao.transition(M));g.append("line"),g.append("text");var w,k,C,A,S=g.select("line"),E=y.select("line"),N=v.select("text").text(p),$=g.select("text"),j=y.select("text"),D="top"===e||"left"===e?-1:1;if("bottom"===e||"top"===e?(n=no,w="x",C="y",k="x2",A="y2",N.attr("dy",0>D?"0em":".71em").style("text-anchor","middle"),b.attr("d","M"+x[0]+","+D*u+"V0H"+x[1]+"V"+D*u)):(n=to,w="y",C="x",k="y2",A="x2",N.attr("dy",".32em").style("text-anchor",0>D?"end":"start"),b.attr("d","M"+D*u+","+x[0]+"H0V"+x[1]+"H"+D*u)),S.attr(A,D*i),$.attr(C,D*_),E.attr(k,0).attr(A,D*i),j.attr(w,0).attr(C,D*_),s.rangeBand){var T=s,L=T.rangeBand()/2;f=s=function(n){return T(n)+L}}else f.rangeBand?f=s:d.call(n,s,f);g.call(n,f,s),y.call(n,s,s)})}var t,r=ao.scale.linear(),e=Wc,i=6,u=6,o=3,a=[10],c=null;return n.scale=function(t){return arguments.length?(r=t,n):r},n.orient=function(t){return arguments.length?(e=t in Bc?t+"":Wc,n):e},n.ticks=function(){return arguments.length?(a=lo(arguments),n):a},n.tickValues=function(t){return arguments.length?(c=t,n):c},n.tickFormat=function(r){return arguments.length?(t=r,n):t},n.tickSize=function(t){var r=arguments.length;return r?(i=+t,u=+arguments[r-1],n):i},n.innerTickSize=function(t){return arguments.length?(i=+t,n):i},n.outerTickSize=function(t){return arguments.length?(u=+t,n):u},n.tickPadding=function(t){return arguments.length?(o=+t,n):o},n.tickSubdivide=function(){return arguments.length&&n},n};var Wc="bottom",Bc={top:1,right:1,bottom:1,left:1};ao.svg.brush=function(){function n(t){t.each(function(){var t=ao.select(this).style("pointer-events","all").style("-webkit-tap-highlight-color","rgba(0,0,0,0)").on("mousedown.brush",u).on("touchstart.brush",u),o=t.selectAll(".background").data([0]);o.enter().append("rect").attr("class","background").style("visibility","hidden").style("cursor","crosshair"),t.selectAll(".extent").data([0]).enter().append("rect").attr("class","extent").style("cursor","move");var a=t.selectAll(".resize").data(g,m);a.exit().remove(),a.enter().append("g").attr("class",function(n){return"resize "+n}).style("cursor",function(n){return Yc[n]}).append("rect").attr("x",function(n){return/[ew]$/.test(n)?-3:null}).attr("y",function(n){return/^[ns]/.test(n)?-3:null}).attr("width",6).attr("height",6).style("visibility","hidden"),a.style("display",n.empty()?"none":null);var c,s=ao.transition(t),h=ao.transition(o);l&&(c=Wi(l),h.attr("x",c[0]).attr("width",c[1]-c[0]),e(s)),f&&(c=Wi(f),h.attr("y",c[0]).attr("height",c[1]-c[0]),i(s)),r(s)})}function r(n){n.selectAll(".resize").attr("transform",function(n){return"translate("+s[+/e$/.test(n)]+","+h[+/^s/.test(n)]+")"})}function e(n){n.select(".extent").attr("x",s[0]),n.selectAll(".extent,.n>rect,.s>rect").attr("width",s[1]-s[0])}function i(n){n.select(".extent").attr("y",h[0]),n.selectAll(".extent,.e>rect,.w>rect").attr("height",h[1]-h[0])}function u(){function u(){32==ao.event.keyCode&&(N||(_=null,j[0]-=s[1],j[1]-=h[1],N=2),k())}function g(){32==ao.event.keyCode&&2==N&&(j[0]+=s[1],j[1]+=h[1],N=0,k())}function d(){var n=ao.mouse(M),t=!1;x&&(n[0]+=x[0],n[1]+=x[1]),N||(ao.event.altKey?(_||(_=[(s[0]+s[1])/2,(h[0]+h[1])/2]),j[0]=s[+(n[0]<_[0])],j[1]=h[+(n[1]<_[1])]):_=null),S&&y(n,l,0)&&(e(C),t=!0),E&&y(n,f,1)&&(i(C),t=!0),t&&(r(C),w({type:"brush",mode:N?"move":"resize"}))}function y(n,t,r){var e,i,u=Wi(t),c=u[0],l=u[1],f=j[r],g=r?h:s,d=g[1]-g[0];return N&&(c-=f,l-=d+f),e=(r?v:p)?Math.max(c,Math.min(l,n[r])):n[r],N?i=(e+=f)+d:(_&&(f=Math.max(c,Math.min(l,2*_[r]-e))),e>f?(i=e,e=f):i=f),g[0]!=e||g[1]!=i?(r?a=null:o=null,g[0]=e,g[1]=i,!0):void 0}function m(){d(),C.style("pointer-events","all").selectAll(".resize").style("display",n.empty()?"none":null),ao.select("body").style("cursor",null),D.on("mousemove.brush",null).on("mouseup.brush",null).on("touchmove.brush",null).on("touchend.brush",null).on("keydown.brush",null).on("keyup.brush",null),$(),w({type:"brushend"})}var _,x,M=this,b=ao.select(ao.event.target),w=c.of(M,arguments),C=ao.select(M),A=b.datum(),S=!/^(n|s)$/.test(A)&&l,E=!/^(e|w)$/.test(A)&&f,N=b.classed("extent"),$=X(M),j=ao.mouse(M),D=ao.select(t(M)).on("keydown.brush",u).on("keyup.brush",g);if(ao.event.changedTouches?D.on("touchmove.brush",d).on("touchend.brush",m):D.on("mousemove.brush",d).on("mouseup.brush",m),C.interrupt().selectAll("*").interrupt(),N)j[0]=s[0]-j[0],j[1]=h[0]-j[1];else if(A){var T=+/w$/.test(A),L=+/^n/.test(A);x=[s[1-T]-j[0],h[1-L]-j[1]],j[0]=s[T],j[1]=h[L]}else ao.event.altKey&&(_=j.slice());C.style("pointer-events","none").selectAll(".resize").style("display",null),ao.select("body").style("cursor",b.style("cursor")),w({type:"brushstart"}),d()}var o,a,c=A(n,"brushstart","brush","brushend"),l=null,f=null,s=[0,0],h=[0,0],p=!0,v=!0,g=Zc[0];return n.event=function(n){n.each(function(){var n=c.of(this,arguments),t={x:s,y:h,i:o,j:a},r=this.__chart__||t;this.__chart__=t,Ic?ao.select(this).transition().each("start.brush",function(){o=r.i,a=r.j,s=r.x,h=r.y,n({type:"brushstart"})}).tween("brush:brush",function(){var r=xe(s,t.x),e=xe(h,t.y);return o=a=null,function(i){s=t.x=r(i),h=t.y=e(i),n({type:"brush",mode:"resize"})}}).each("end.brush",function(){o=t.i,a=t.j,n({type:"brush",mode:"resize"}),n({type:"brushend"})}):(n({type:"brushstart"}),n({type:"brush",mode:"resize"}),n({type:"brushend"}))})},n.x=function(t){return arguments.length?(l=t,g=Zc[!l<<1|!f],n):l},n.y=function(t){return arguments.length?(f=t,g=Zc[!l<<1|!f],n):f},n.clamp=function(t){return arguments.length?(l&&f?(p=!!t[0],v=!!t[1]):l?p=!!t:f&&(v=!!t),n):l&&f?[p,v]:l?p:f?v:null},n.extent=function(t){var r,e,i,u,c;return arguments.length?(l&&(r=t[0],e=t[1],f&&(r=r[0],e=e[0]),o=[r,e],l.invert&&(r=l(r),e=l(e)),r>e&&(c=r,r=e,e=c),r==s[0]&&e==s[1]||(s=[r,e])),f&&(i=t[0],u=t[1],l&&(i=i[1],u=u[1]),a=[i,u],f.invert&&(i=f(i),u=f(u)),i>u&&(c=i,i=u,u=c),i==h[0]&&u==h[1]||(h=[i,u])),n):(l&&(o?(r=o[0],e=o[1]):(r=s[0],e=s[1],l.invert&&(r=l.invert(r),e=l.invert(e)),r>e&&(c=r,r=e,e=c))),f&&(a?(i=a[0],u=a[1]):(i=h[0],u=h[1],f.invert&&(i=f.invert(i),u=f.invert(u)),i>u&&(c=i,i=u,u=c))),l&&f?[[r,i],[e,u]]:l?[r,e]:f&&[i,u])},n.clear=function(){return n.empty()||(s=[0,0],h=[0,0],o=a=null),n},n.empty=function(){return!!l&&s[0]==s[1]||!!f&&h[0]==h[1]},ao.rebind(n,c,"on")};var Yc={n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},Zc=[["n","e","s","w","nw","ne","se","sw"],["e","w"],["n","s"],[]],Vc=pa.format=_a.timeFormat,Xc=Vc.utc,Kc=Xc("%Y-%m-%dT%H:%M:%S.%LZ");Vc.iso=Date.prototype.toISOString&&+new Date("2000-01-01T00:00:00.000Z")?ro:Kc,ro.parse=function(n){var t=new Date(n);return isNaN(t)?null:t},ro.toString=Kc.toString,pa.second=Un(function(n){return new va(1e3*Math.floor(n/1e3))},function(n,t){n.setTime(n.getTime()+1e3*Math.floor(t))},function(n){return n.getSeconds()}),pa.seconds=pa.second.range,pa.seconds.utc=pa.second.utc.range,pa.minute=Un(function(n){return new va(6e4*Math.floor(n/6e4))},function(n,t){n.setTime(n.getTime()+6e4*Math.floor(t))},function(n){return n.getMinutes()}),pa.minutes=pa.minute.range,pa.minutes.utc=pa.minute.utc.range,pa.hour=Un(function(n){var t=n.getTimezoneOffset()/60;return new va(36e5*(Math.floor(n/36e5-t)+t))},function(n,t){n.setTime(n.getTime()+36e5*Math.floor(t))},function(n){return n.getHours()}),pa.hours=pa.hour.range,pa.hours.utc=pa.hour.utc.range,pa.month=Un(function(n){return n=pa.day(n),n.setDate(1),n},function(n,t){n.setMonth(n.getMonth()+t)},function(n){return n.getMonth()}),pa.months=pa.month.range,pa.months.utc=pa.month.utc.range;var Jc=[1e3,5e3,15e3,3e4,6e4,3e5,9e5,18e5,36e5,108e5,216e5,432e5,864e5,1728e5,6048e5,2592e6,7776e6,31536e6],Qc=[[pa.second,1],[pa.second,5],[pa.second,15],[pa.second,30],[pa.minute,1],[pa.minute,5],[pa.minute,15],[pa.minute,30],[pa.hour,1],[pa.hour,3],[pa.hour,6],[pa.hour,12],[pa.day,1],[pa.day,2],[pa.week,1],[pa.month,1],[pa.month,3],[pa.year,1]],Gc=Vc.multi([[".%L",function(n){return n.getMilliseconds()}],[":%S",function(n){return n.getSeconds()}],["%I:%M",function(n){return n.getMinutes()}],["%I %p",function(n){return n.getHours()}],["%a %d",function(n){return n.getDay()&&1!=n.getDate()}],["%b %d",function(n){return 1!=n.getDate()}],["%B",function(n){return n.getMonth()}],["%Y",$t]]),nl={range:function(n,t,r){return ao.range(Math.ceil(n/r)*r,+t,r).map(io)},floor:m,ceil:m};Qc.year=pa.year,pa.scale=function(){return eo(ao.scale.linear(),Qc,Gc)};var tl=Qc.map(function(n){return[n[0].utc,n[1]]}),rl=Xc.multi([[".%L",function(n){return n.getUTCMilliseconds()}],[":%S",function(n){return n.getUTCSeconds()}],["%I:%M",function(n){return n.getUTCMinutes()}],["%I %p",function(n){return n.getUTCHours()}],["%a %d",function(n){return n.getUTCDay()&&1!=n.getUTCDate()}],["%b %d",function(n){return 1!=n.getUTCDate()}],["%B",function(n){return n.getUTCMonth()}],["%Y",$t]]);tl.year=pa.year.utc,pa.scale.utc=function(){return eo(ao.scale.linear(),tl,rl)},ao.text=En(function(n){return n.responseText}),ao.json=function(n,t){return Nn(n,"application/json",uo,t)},ao.html=function(n,t){return Nn(n,"text/html",oo,t)},ao.xml=En(function(n){return n.responseXML}),"function"==typeof define&&define.amd?(this.d3=ao,define(ao)):"object"==typeof module&&module.exports?module.exports=ao:this.d3=ao}(),function(){function n(n,t){return n.set(t[0],t[1]),n}function t(n,t){return n.add(t),n}function r(n,t,r){var e=r?r.length:0;switch(e){case 0:return n.call(t);case 1:return n.call(t,r[0]);case 2:return n.call(t,r[0],r[1]);case 3:return n.call(t,r[0],r[1],r[2])}return n.apply(t,r)}function e(n,t){for(var r=-1,e=n.length,i=-1,u=t.length,o=Array(e+u);++r<e;)o[r]=n[r];for(;++i<u;)o[r++]=t[i];return o}function i(n,t){for(var r=-1,e=n.length;++r<e&&t(n[r],r,n)!==!1;);return n}function u(n,t){for(var r=n.length;r--&&t(n[r],r,n)!==!1;);return n}function o(n,t){for(var r=-1,e=n.length;++r<e;)if(!t(n[r],r,n))return!1;return!0}function a(n,t){for(var r=-1,e=n.length,i=-1,u=[];++r<e;){var o=n[r];t(o,r,n)&&(u[++i]=o)}return u}function c(n,t){return!!n.length&&m(n,t,0)>-1}function l(n,t,r){for(var e=-1,i=n.length;++e<i;)if(r(t,n[e]))return!0;return!1}function f(n,t){for(var r=-1,e=n.length,i=Array(e);++r<e;)i[r]=t(n[r],r,n);return i}function s(n,t){for(var r=-1,e=t.length,i=n.length;++r<e;)n[i+r]=t[r];return n}function h(n,t,r,e){var i=-1,u=n.length;for(e&&u&&(r=n[++i]);++i<u;)r=t(r,n[i],i,n);return r}function p(n,t,r,e){var i=n.length;for(e&&i&&(r=n[--i]);i--;)r=t(r,n[i],i,n);return r}function v(n,t){for(var r=-1,e=n.length;++r<e;)if(t(n[r],r,n))return!0;return!1}function g(n,t,r){for(var e=-1,i=n.length;++e<i;){var u=n[e],o=t(u);if(null!=o&&(a===B?o===o:r(o,a)))var a=o,c=u}return c}function d(n,t,r,e){var i;return r(n,function(n,r,u){return t(n,r,u)?(i=e?r:n,!1):void 0}),i}function y(n,t,r){for(var e=n.length,i=r?e:-1;r?i--:++i<e;)if(t(n[i],i,n))return i;return-1}function m(n,t,r){if(t!==t)return L(n,r);for(var e=r-1,i=n.length;++e<i;)if(n[e]===t)return e;return-1}function _(n,t,r,e,i){return i(n,function(n,i,u){r=e?(e=!1,n):t(r,n,i,u)}),r}function x(n,t){var r=n.length;for(n.sort(t);r--;)n[r]=n[r].value;return n}function M(n,t){for(var r,e=-1,i=n.length;++e<i;){var u=t(n[e]);u!==B&&(r=r===B?u:r+u)}return r}function b(n,t){for(var r=-1,e=Array(n);++r<n;)e[r]=t(r);return e}function w(n,t){return f(t,function(t){return[t,n[t]]})}function k(n){return function(t){return n(t)}}function C(n,t){return f(t,function(t){return n[t]})}function A(n,t){for(var r=-1,e=n.length;++r<e&&m(t,n[r],0)>-1;);return r}function S(n,t){for(var r=n.length;r--&&m(t,n[r],0)>-1;);return r}function E(n){return n&&n.Object===Object?n:null}function N(n,t){if(n!==t){var r=null===n,e=n===B,i=n===n,u=null===t,o=t===B,a=t===t;if(n>t&&!u||!i||r&&!o&&a||e&&a)return 1;if(t>n&&!r||!a||u&&!e&&i||o&&i)return-1}return 0}function $(n,t,r){for(var e=-1,i=n.criteria,u=t.criteria,o=i.length,a=r.length;++e<o;){var c=N(i[e],u[e]);if(c){if(e>=a)return c;var l=r[e];return c*("desc"==l?-1:1)}}return n.index-t.index}function j(n){return gr[n]}function D(n){return dr[n]}function T(n){return"\\"+_r[n]}function L(n,t,r){for(var e=n.length,i=t+(r?0:-1);r?i--:++i<e;){var u=n[i];if(u!==u)return i}return-1}function R(n){var t=!1;if(null!=n&&"function"!=typeof n.toString)try{t=!!(n+"")}catch(r){}return t}function O(n,t){return n="number"==typeof n||Mt.test(n)?+n:-1,t=null==t?yn:t,n>-1&&n%1==0&&t>n}function z(n){for(var t,r=[];!(t=n.next()).done;)r.push(t.value);return r}function q(n){var t=-1,r=Array(n.size);return n.forEach(function(n,e){r[++t]=[e,n]}),r}function I(n,t){for(var r=-1,e=n.length,i=-1,u=[];++r<e;)n[r]===t&&(n[r]=wn,u[++i]=r);return u}function P(n){var t=-1,r=Array(n.size);return n.forEach(function(n){r[++t]=n}),r}function U(n){if(!n||!ar.test(n))return n.length;for(var t=or.lastIndex=0;or.test(n);)t++;return t}function F(n){return n.match(or)}function H(n){return yr[n]}function W(E){function qn(n){if(wo(n)&&!nf(n)&&!(n instanceof At)){if(n instanceof Ct)return n;if(Cc.call(n,"__wrapped__"))return Mi(n)}return new Ct(n)}function Mt(){}function Ct(n,t){this.__wrapped__=n,this.__actions__=[],this.__chain__=!!t,this.__index__=0,this.__values__=B}function At(n){this.__wrapped__=n,this.__actions__=[],this.__dir__=1,this.__filtered__=!1,this.__iteratees__=[],this.__takeCount__=xn,this.__views__=[]}function St(){var n=new At(this.__wrapped__);return n.__actions__=Ae(this.__actions__),n.__dir__=this.__dir__,n.__filtered__=this.__filtered__,n.__iteratees__=Ae(this.__iteratees__),n.__takeCount__=this.__takeCount__,n.__views__=Ae(this.__views__),n}function Et(){if(this.__filtered__){var n=new At(this);n.__dir__=-1,n.__filtered__=!0}else n=this.clone(),n.__dir__*=-1;return n}function Nt(){var n=this.__wrapped__.value(),t=this.__dir__,r=nf(n),e=0>t,i=r?n.length:0,u=ri(0,i,this.__views__),o=u.start,a=u.end,c=a-o,l=e?a:o-1,f=this.__iteratees__,s=f.length,h=0,p=Vc(c,this.__takeCount__);if(!r||fn>i||i==c&&p==c)return de(n,this.__actions__);var v=[];n:for(;c--&&p>h;){l+=t;for(var g=-1,d=n[l];++g<s;){var y=f[g],m=y.iteratee,_=y.type,x=m(d);if(_==hn)d=x;else if(!x){if(_==sn)continue n;break n}}v[h++]=d}return v}function $t(){}function jt(n,t){return Tt(n,t)&&delete n[t]}function Dt(n,t){if(tl){var r=n[t];return r===gn?B:r}return Cc.call(n,t)?n[t]:B}function Tt(n,t){return tl?n[t]!==B:Cc.call(n,t)}function Lt(n,t,r){n[t]=tl&&r===B?gn:r}function Rt(n){var t=-1,r=n?n.length:0;for(this.clear();++t<r;){var e=n[t];this.set(e[0],e[1])}}function Ot(){this.__data__={hash:new $t,map:Qc?new Qc:[],string:new $t}}function zt(n){var t=this.__data__;return fi(n)?jt("string"==typeof n?t.string:t.hash,n):Qc?t.map["delete"](n):Kt(t.map,n)}function qt(n){var t=this.__data__;return fi(n)?Dt("string"==typeof n?t.string:t.hash,n):Qc?t.map.get(n):Jt(t.map,n)}function It(n){var t=this.__data__;return fi(n)?Tt("string"==typeof n?t.string:t.hash,n):Qc?t.map.has(n):Qt(t.map,n)}function Pt(n,t){var r=this.__data__;return fi(n)?Lt("string"==typeof n?r.string:r.hash,n,t):Qc?r.map.set(n,t):nr(r.map,n,t),this}function Ut(n){var t=-1,r=n?n.length:0;for(this.__data__=new Rt;++t<r;)this.push(n[t])}function Ft(n,t){var r=n.__data__;if(fi(t)){var e=r.__data__,i="string"==typeof t?e.string:e.hash;return i[t]===gn}return r.has(t)}function Ht(n){var t=this.__data__;if(fi(n)){var r=t.__data__,e="string"==typeof n?r.string:r.hash;e[n]=gn}else t.set(n,gn)}function Wt(n){var t=-1,r=n?n.length:0;for(this.clear();++t<r;){var e=n[t];this.set(e[0],e[1])}}function Bt(){this.__data__={array:[],map:null}}function Yt(n){var t=this.__data__,r=t.array;return r?Kt(r,n):t.map["delete"](n)}function Zt(n){var t=this.__data__,r=t.array;return r?Jt(r,n):t.map.get(n)}function Vt(n){var t=this.__data__,r=t.array;return r?Qt(r,n):t.map.has(n)}function Xt(n,t){var r=this.__data__,e=r.array;e&&(e.length<fn-1?nr(e,n,t):(r.array=null,r.map=new Rt(e)));var i=r.map;return i&&i.set(n,t),this}function Kt(n,t){var r=Gt(n,t);if(0>r)return!1;var e=n.length-1;return r==e?n.pop():Uc.call(n,r,1),!0}function Jt(n,t){var r=Gt(n,t);return 0>r?B:n[r][1]}function Qt(n,t){return Gt(n,t)>-1}function Gt(n,t){for(var r=n.length;r--;)if(io(n[r][0],t))return r;return-1}function nr(n,t,r){var e=Gt(n,t);0>e?n.push([t,r]):n[e][1]=r}function tr(n,t,r,e){return n===B||io(n,wc[r])&&!Cc.call(e,r)?t:n}function rr(n,t,r){(r===B||io(n[t],r))&&("number"!=typeof t||r!==B||t in n)||(n[t]=r)}function er(n,t,r){var e=n[t];io(e,r)&&(!io(e,wc[t])||Cc.call(n,t))&&(r!==B||t in n)||(n[t]=r)}function ir(n,t){return n&&Se(t,oa(t),n)}function or(n,t){for(var r=-1,e=null==n,i=t.length,u=Array(i);++r<i;)u[r]=e?B:ra(n,t[r]);return u}function gr(n,t,r){return n===n&&(r!==B&&(n=r>=n?n:r),t!==B&&(n=n>=t?n:t)),n}function dr(n,t,r,e,u,o){var a;if(r&&(a=u?r(n,e,u,o):r(n)),a!==B)return a;if(!bo(n))return n;var c=nf(n);if(c){if(a=ii(n),!t)return Ae(n,a)}else{var l=ti(n),f=l==Nn||l==$n;if(l!=Tn&&l!=kn&&(!f||u))return vr[l]?oi(n,l,t):u?n:{};if(R(n))return u?n:{};if(a=ui(f?{}:n),!t)return Ne(n,ir(a,n))}o||(o=new Wt);var s=o.get(n);return s?s:(o.set(n,a),(c?i:Sr)(n,function(e,i){er(a,i,dr(e,t,r,i,n,o))}),c?a:Ne(n,a))}function yr(n){var t=oa(n),r=t.length;return function(e){if(null==e)return!r;for(var i=r;i--;){var u=t[i],o=n[u],a=e[u];if(a===B&&!(u in Object(e))||!o(a))return!1}return!0}}function mr(n,t,r){if("function"!=typeof n)throw new Mc(vn);return Pc(function(){n.apply(B,r)},t)}function _r(n,t,r,e){var i=-1,u=c,o=!0,a=n.length,s=[],h=t.length;if(!a)return s;r&&(t=f(t,k(r))),e?(u=l,o=!1):t.length>=fn&&(u=Ft,o=!1,t=new Ut(t));n:for(;++i<a;){var p=n[i],v=r?r(p):p;if(o&&v===v){for(var g=h;g--;)if(t[g]===v)continue n;s.push(p)}else u(t,v,e)||s.push(p)}return s}function br(n,t){var r=!0;return fl(n,function(n,e,i){return r=!!t(n,e,i)}),r}function wr(n,t,r,e){var i=n.length;for(r=Uo(r),0>r&&(r=-r>i?0:i+r),
+e=e===B||e>i?i:Uo(e),0>e&&(e+=i),e=r>e?0:Fo(e);e>r;)n[r++]=t;return n}function kr(n,t){var r=[];return fl(n,function(n,e,i){t(n,e,i)&&r.push(n)}),r}function Cr(n,t,r,e){e||(e=[]);for(var i=-1,u=n.length;++i<u;){var o=n[i];lo(o)&&(r||nf(o)||ao(o))?t?Cr(o,t,r,e):s(e,o):r||(e[e.length]=o)}return e}function Ar(n,t){return null==n?n:hl(n,t,aa)}function Sr(n,t){return n&&hl(n,t,oa)}function Er(n,t){return n&&pl(n,t,oa)}function jr(n,t){return a(t,function(t){return _o(n[t])})}function Dr(n,t){t=li(t,n)?[t+""]:he(t);for(var r=0,e=t.length;null!=n&&e>r;)n=n[t[r++]];return r&&r==e?n:B}function Tr(n,t){return Cc.call(n,t)||"object"==typeof n&&t in n&&null===Oc(n)}function Lr(n,t){return t in Object(n)}function Rr(n,t,r){return n>=Vc(t,r)&&n<Zc(t,r)}function Or(n,t,r){for(var e=r?l:c,i=n.length,u=i,o=Array(i),a=[];u--;){var s=n[u];u&&t&&(s=f(s,k(t))),o[u]=!r&&(t||s.length>=120)?new Ut(u&&s):B}s=n[0];var h=-1,p=s.length,v=o[0];n:for(;++h<p;){var g=s[h],d=t?t(g):g;if(!(v?Ft(v,d):e(a,d,r))){for(var u=i;--u;){var y=o[u];if(!(y?Ft(y,d):e(n[u],d,r)))continue n}v&&v.push(d),a.push(g)}}return a}function zr(n,t,e){li(t,n)||(t=he(t),n=di(n,t),t=Ii(t));var i=null==n?n:n[t];return null==i?B:r(i,n,e)}function qr(n,t,r,e,i){return n===t?!0:null==n||null==t||!bo(n)&&!wo(t)?n!==n&&t!==t:Ir(n,t,qr,r,e,i)}function Ir(n,t,r,e,i,u){var o=nf(n),a=nf(t),c=Cn,l=Cn;o||(c=ti(n),c==kn?c=Tn:c!=Tn&&(o=Oo(n))),a||(l=ti(t),l==kn?l=Tn:l!=Tn&&(a=Oo(t)));var f=c==Tn&&!R(n),s=l==Tn&&!R(t),h=c==l;if(h&&!o&&!f)return Xe(n,t,c,r,e,i);var p=i&un;if(!p){var v=f&&Cc.call(n,"__wrapped__"),g=s&&Cc.call(t,"__wrapped__");if(v||g)return r(v?n.value():n,g?t.value():t,e,i,u)}return h?(u||(u=new Wt),(o?Ve:Ke)(n,t,r,e,i,u)):!1}function Pr(n,t,r,e){var i=r.length,u=i,o=!e;if(null==n)return!u;for(n=Object(n);i--;){var a=r[i];if(o&&a[2]?a[1]!==n[a[0]]:!(a[0]in n))return!1}for(;++i<u;){a=r[i];var c=a[0],l=n[c],f=a[1];if(o&&a[2]){if(l===B&&!(c in n))return!1}else{var s=new Wt,h=e?e(l,f,c,n,t,s):B;if(!(h===B?qr(f,l,e,en|un,s):h))return!1}}return!0}function Ur(n){var t=typeof n;return"function"==t?n:null==n?Xa:"object"==t?nf(n)?Yr(n[0],n[1]):Br(n):ec(n)}function Fr(n){return Yc(Object(n))}function Hr(n){n=null==n?n:Object(n);var t=[];for(var r in n)t.push(r);return t}function Wr(n,t){var r=-1,e=co(n)?Array(n.length):[];return fl(n,function(n,i,u){e[++r]=t(n,i,u)}),e}function Br(n){var t=Ge(n);if(1==t.length&&t[0][2]){var r=t[0][0],e=t[0][1];return function(n){return null==n?!1:n[r]===e&&(e!==B||r in Object(n))}}return function(r){return r===n||Pr(r,n,t)}}function Yr(n,t){return function(r){var e=ra(r,n);return e===B&&e===t?ia(r,n):qr(t,e,B,en|un)}}function Zr(n,t,r,e,u){if(n!==t){var o=nf(t)||Oo(t)?B:aa(t);i(o||t,function(i,a){if(o&&(a=i,i=t[a]),bo(i))u||(u=new Wt),Vr(n,t,a,r,Zr,e,u);else{var c=e?e(n[a],i,a+"",n,t,u):B;c===B&&(c=i),rr(n,a,c)}})}}function Vr(n,t,r,e,i,u,o){var a=n[r],c=t[r],l=o.get(c)||o.get(a);if(l)return void rr(n,r,l);var f=u?u(a,c,r+"",n,t,o):B,s=f===B;s&&(f=c,nf(c)||Oo(c)?f=nf(a)?e?Ae(a):a:lo(a)?Ae(a):dr(c):jo(c)||ao(c)?f=ao(a)?Wo(a):!bo(a)||e&&_o(a)?dr(c):e?dr(a):a:s=!1),o.set(c,f),s&&i(f,c,e,u,o),rr(n,r,f)}function Xr(n,t,r){var e=-1,i=Qe();t=f(t.length?t:Array(1),function(n){return i(n)});var u=Wr(n,function(n,r,i){var u=f(t,function(t){return t(n)});return{criteria:u,index:++e,value:n}});return x(u,function(n,t){return $(n,t,r)})}function Kr(n,t){return n=Object(n),h(t,function(t,r){return r in n&&(t[r]=n[r]),t},{})}function Jr(n,t){var r={};return Ar(n,function(n,e){t(n,e)&&(r[e]=n)}),r}function Qr(n){return function(t){return null==t?B:t[n]}}function Gr(n){return function(t){return Dr(t,n)}}function ne(n,t){return te(n,t)}function te(n,t,r){var e=-1,i=t.length,u=n;for(r&&(u=f(n,function(n){return r(n)}));++e<i;)for(var o=0,a=t[e],c=r?r(a):a;(o=m(u,c,o))>-1;)u!==n&&Uc.call(u,o,1),Uc.call(n,o,1);return n}function re(n,t){for(var r=n?t.length:0,e=r-1;r--;){var i=t[r];if(e==r||i!=u){var u=i;if(O(i))Uc.call(n,i,1);else if(li(i,n))delete n[i];else{var o=he(i),a=di(n,o);null!=a&&delete a[Ii(o)]}}}return n}function ee(n,t){return n+Hc(Kc()*(t-n+1))}function ie(n,t,r,e){for(var i=-1,u=Zc(Fc((t-n)/(r||1)),0),o=Array(u);u--;)o[e?u:++i]=n,n+=r;return o}function ue(n,t,r,e){t=li(t,n)?[t+""]:he(t);for(var i=-1,u=t.length,o=u-1,a=n;null!=a&&++i<u;){var c=t[i];if(bo(a)){var l=r;if(i!=o){var f=a[c];l=e?e(f,c,a):B,l===B&&(l=null==f?O(t[i+1])?[]:{}:f)}er(a,c,l)}a=a[c]}return n}function oe(n,t,r){var e=-1,i=n.length;0>t&&(t=-t>i?0:i+t),r=r>i?i:r,0>r&&(r+=i),i=t>r?0:r-t>>>0,t>>>=0;for(var u=Array(i);++e<i;)u[e]=n[e+t];return u}function ae(n,t){var r;return fl(n,function(n,e,i){return r=t(n,e,i),!r}),!!r}function ce(n,t,r){var e=0,i=n?n.length:e;if("number"==typeof t&&t===t&&bn>=i){for(;i>e;){var u=e+i>>>1,o=n[u];(r?t>=o:t>o)&&null!==o?e=u+1:i=u}return i}return le(n,t,Xa,r)}function le(n,t,r,e){t=r(t);for(var i=0,u=n?n.length:0,o=t!==t,a=null===t,c=t===B;u>i;){var l=Hc((i+u)/2),f=r(n[l]),s=f!==B,h=f===f;if(o)var p=h||e;else p=a?h&&s&&(e||null!=f):c?h&&(e||s):null==f?!1:e?t>=f:t>f;p?i=l+1:u=l}return Vc(u,Mn)}function fe(n){return se(n)}function se(n,t){for(var r=0,e=n.length,i=n[0],u=t?t(i):i,o=u,a=0,c=[i];++r<e;)i=n[r],u=t?t(i):i,io(u,o)||(o=u,c[++a]=i);return c}function he(n){return nf(n)?n:mi(n)}function pe(n,t,r){var e=-1,i=c,u=n.length,o=!0,a=[],f=a;if(r)o=!1,i=l;else if(u>=fn){var s=t?null:gl(n);if(s)return P(s);o=!1,i=Ft,f=new Ut}else f=t?[]:a;n:for(;++e<u;){var h=n[e],p=t?t(h):h;if(o&&p===p){for(var v=f.length;v--;)if(f[v]===p)continue n;t&&f.push(p),a.push(h)}else i(f,p,r)||(f!==a&&f.push(p),a.push(h))}return a}function ve(n,t){t=li(t,n)?[t+""]:he(t),n=di(n,t);var r=Ii(t);return null!=n&&ea(n,r)?delete n[r]:!0}function ge(n,t,r,e){for(var i=n.length,u=e?i:-1;(e?u--:++u<i)&&t(n[u],u,n););return r?oe(n,e?0:u,e?u+1:i):oe(n,e?u+1:0,e?i:u)}function de(n,t){var r=n;return r instanceof At&&(r=r.value()),h(t,function(n,t){return t.func.apply(t.thisArg,s([n],t.args))},r)}function ye(n,t,r){for(var e=-1,i=n.length;++e<i;)var u=u?s(_r(u,n[e],t,r),_r(n[e],u,t,r)):n[e];return u&&u.length?pe(u,t,r):[]}function me(n){var t=n.constructor,r=new t(n.byteLength),e=new Tc(r);return e.set(new Tc(n)),r}function _e(t){var r=t.constructor;return h(q(t),n,new r)}function xe(n){var t=n.constructor,r=new t(n.source,gt.exec(n));return r.lastIndex=n.lastIndex,r}function Me(n){var r=n.constructor;return h(P(n),t,new r)}function be(n){return Dc?Object(ol.call(n)):{}}function we(n,t){var r=n.buffer,e=n.constructor;return new e(t?me(r):r,n.byteOffset,n.length)}function ke(n,t,r){for(var e=r.length,i=-1,u=Zc(n.length-e,0),o=-1,a=t.length,c=Array(a+u);++o<a;)c[o]=t[o];for(;++i<e;)c[r[i]]=n[i];for(;u--;)c[o++]=n[i++];return c}function Ce(n,t,r){for(var e=-1,i=r.length,u=-1,o=Zc(n.length-i,0),a=-1,c=t.length,l=Array(o+c);++u<o;)l[u]=n[u];for(var f=u;++a<c;)l[f+a]=t[a];for(;++e<i;)l[f+r[e]]=n[u++];return l}function Ae(n,t){var r=-1,e=n.length;for(t||(t=Array(e));++r<e;)t[r]=n[r];return t}function Se(n,t,r){return Ee(n,t,r)}function Ee(n,t,r,e){r||(r={});for(var i=-1,u=t.length;++i<u;){var o=t[i],a=e?e(r[o],n[o],o,r,n):n[o];er(r,o,a)}return r}function Ne(n,t){return Se(n,ml(n),t)}function $e(n,t){return function(r,e){var i=t?t():{};if(e=Qe(e),nf(r))for(var u=-1,o=r.length;++u<o;){var a=r[u];n(i,a,e(a),r)}else fl(r,function(t,r,u){n(i,t,e(t),u)});return i}}function je(n){return Xu(function(t,r){var e=-1,i=r.length,u=i>1?r[i-1]:B,o=i>2?r[2]:B;for(u="function"==typeof u?(i--,u):B,o&&ci(r[0],r[1],o)&&(u=3>i?B:u,i=1),t=Object(t);++e<i;){var a=r[e];a&&n(t,a,e,u)}return t})}function De(n,t){return function(r,e){if(null==r)return r;if(!co(r))return n(r,e);for(var i=r.length,u=t?i:-1,o=Object(r);(t?u--:++u<i)&&e(o[u],u,o)!==!1;);return r}}function Te(n){return function(t,r,e){for(var i=-1,u=Object(t),o=e(t),a=o.length;a--;){var c=o[n?a:++i];if(r(u[c],c,u)===!1)break}return t}}function Le(n,t,r){function e(){var t=this&&this!==Nr&&this instanceof e?u:n;return t.apply(i?r:this,arguments)}var i=t&Z,u=ze(n);return e}function Re(n){return function(t){t=Yo(t);var r=ar.test(t)?F(t):B,e=r?r[0]:t.charAt(0),i=r?r.slice(1).join(""):t.slice(1);return e[n]()+i}}function Oe(n){return function(t){return h(Ba(Ca(t)),n,"")}}function ze(n){return function(){var t=arguments;switch(t.length){case 0:return new n;case 1:return new n(t[0]);case 2:return new n(t[0],t[1]);case 3:return new n(t[0],t[1],t[2]);case 4:return new n(t[0],t[1],t[2],t[3]);case 5:return new n(t[0],t[1],t[2],t[3],t[4]);case 6:return new n(t[0],t[1],t[2],t[3],t[4],t[5]);case 7:return new n(t[0],t[1],t[2],t[3],t[4],t[5],t[6])}var r=ll(n.prototype),e=n.apply(r,t);return bo(e)?e:r}}function qe(n,t,e){function i(){for(var o=arguments.length,a=o,c=Array(o),l=this&&this!==Nr&&this instanceof i?u:n,f=i.placeholder;a--;)c[a]=arguments[a];var s=3>o&&c[0]!==f&&c[o-1]!==f?[]:I(c,f);return o-=s.length,e>o?Be(n,t,Pe,f,B,c,s,B,B,e-o):r(l,this,c)}var u=ze(n);return i}function Ie(n){return Xu(function(t){t=Cr(t);var r=t.length,e=r,i=Ct.prototype.thru;for(n&&t.reverse();e--;){var u=t[e];if("function"!=typeof u)throw new Mc(vn);if(i&&!o&&"wrapper"==Je(u))var o=new Ct([],!0)}for(e=o?e:r;++e<r;){u=t[e];var a=Je(u),c="wrapper"==a?dl(u):B;o=c&&si(c[0])&&c[1]==(nn|K|Q|tn)&&!c[4].length&&1==c[9]?o[Je(c[0])].apply(o,c[3]):1==u.length&&si(u)?o[a]():o.thru(u)}return function(){var n=arguments,e=n[0];if(o&&1==n.length&&nf(e)&&e.length>=fn)return o.plant(e).value();for(var i=0,u=r?t[i].apply(this,n):e;++i<r;)u=t[i].call(this,u);return u}})}function Pe(n,t,r,e,i,u,o,a,c,l){function f(){for(var m=arguments.length,_=m,x=Array(m);_--;)x[_]=arguments[_];if(e&&(x=ke(x,e,i)),u&&(x=Ce(x,u,o)),v||g){var M=f.placeholder,b=I(x,M);if(m-=b.length,l>m)return Be(n,t,Pe,M,r,x,b,a,c,l-m)}var w=h?r:this,k=p?w[n]:n;return a?x=yi(x,a):d&&x.length>1&&x.reverse(),s&&c<x.length&&(x.length=c),this&&this!==Nr&&this instanceof f&&(k=y||ze(k)),k.apply(w,x)}var s=t&nn,h=t&Z,p=t&V,v=t&K,g=t&J,d=t&rn,y=p?B:ze(n);return f}function Ue(n){return Xu(function(t){return t=f(Cr(t),Qe()),Xu(function(e){var i=this;return n(t,function(n){return r(n,i,e)})})})}function Fe(n,t,r){t=Uo(t);var e=U(n);if(!t||e>=t)return"";var i=t-e;r=r===B?" ":r+"";var u=Ta(r,Fc(i/U(r)));return ar.test(r)?F(u).slice(0,i).join(""):u.slice(0,i)}function He(n,t,e,i){function u(){for(var t=-1,c=arguments.length,l=-1,f=i.length,s=Array(f+c),h=this&&this!==Nr&&this instanceof u?a:n;++l<f;)s[l]=i[l];for(;c--;)s[l++]=arguments[++t];return r(h,o?e:this,s)}var o=t&Z,a=ze(n);return u}function We(n){return function(t,r,e){return e&&"number"!=typeof e&&ci(t,r,e)&&(r=e=B),t=Ho(t),t=t===t?t:0,r===B?(r=t,t=0):r=Ho(r)||0,e=e===B?r>t?1:-1:Ho(e)||0,ie(t,r,e,n)}}function Be(n,t,r,e,i,u,o,a,c,l){var f=t&K,s=a?Ae(a):B,h=f?o:B,p=f?B:o,v=f?u:B,g=f?B:u;t|=f?Q:G,t&=~(f?G:Q),t&X||(t&=~(Z|V));var d=[n,t,i,v,h,g,p,s,c,l],y=r.apply(B,d);return si(n)&&_l(y,d),y.placeholder=e,y}function Ye(n){var t=_c[n];return function(n,r){if(n=Ho(n),r=Uo(r)){var e=(Yo(n)+"e").split("e"),i=t(e[0]+"e"+(+e[1]+r));return e=(Yo(i)+"e").split("e"),+(e[0]+"e"+(+e[1]-r))}return t(n)}}function Ze(n,t,r,e,i,u,o,a){var c=t&V;if(!c&&"function"!=typeof n)throw new Mc(vn);var l=e?e.length:0;if(l||(t&=~(Q|G),e=i=B),o=o===B?o:Zc(Uo(o),0),a=a===B?a:Uo(a),l-=i?i.length:0,t&G){var f=e,s=i;e=i=B}var h=c?B:dl(n),p=[n,t,r,e,i,f,s,u,o,a];if(h&&vi(p,h),n=p[0],t=p[1],r=p[2],e=p[3],i=p[4],a=p[9]=null==p[9]?c?0:n.length:Zc(p[9]-l,0),!a&&t&(K|J)&&(t&=~(K|J)),t&&t!=Z)v=t==K||t==J?qe(n,t,a):t!=Q&&t!=(Z|Q)||i.length?Pe.apply(B,p):He(n,t,r,e);else var v=Le(n,t,r);var g=h?vl:_l;return g(v,p)}function Ve(n,t,r,e,i,u){var o=-1,a=i&un,c=i&en,l=n.length,f=t.length;if(l!=f&&!(a&&f>l))return!1;var s=u.get(n);if(s)return s==t;var h=!0;for(u.set(n,t);++o<l;){var p=n[o],g=t[o];if(e)var d=a?e(g,p,o,t,n,u):e(p,g,o,n,t,u);if(d!==B){if(d)continue;h=!1;break}if(c){if(!v(t,function(n){return p===n||r(p,n,e,i,u)})){h=!1;break}}else if(p!==g&&!r(p,g,e,i,u)){h=!1;break}}return u["delete"](n),h}function Xe(n,t,r,e,i,u){switch(r){case In:return!(n.byteLength!=t.byteLength||!e(new Tc(n),new Tc(t)));case An:case Sn:return+n==+t;case En:return n.name==t.name&&n.message==t.message;case Dn:return n!=+n?t!=+t:n==+t;case Ln:case On:return n==t+"";case jn:var o=q;case Rn:var a=u&un;return o||(o=P),(a||n.size==t.size)&&e(o(n),o(t),i,u|en);case zn:return!!Dc&&ol.call(n)==ol.call(t)}return!1}function Ke(n,t,r,e,i,u){var o=i&un,a=oa(n),c=a.length,l=oa(t),f=l.length;if(c!=f&&!o)return!1;for(var s=c;s--;){var h=a[s];if(!(o?h in t:Tr(t,h)))return!1}var p=u.get(n);if(p)return p==t;var v=!0;u.set(n,t);for(var g=o;++s<c;){h=a[s];var d=n[h],y=t[h];if(e)var m=o?e(y,d,h,t,n,u):e(d,y,h,n,t,u);if(!(m===B?d===y||r(d,y,e,i,u):m)){v=!1;break}g||(g="constructor"==h)}if(v&&!g){var _=n.constructor,x=t.constructor;_!=x&&"constructor"in n&&"constructor"in t&&!("function"==typeof _&&_ instanceof _&&"function"==typeof x&&x instanceof x)&&(v=!1)}return u["delete"](n),v}function Je(n){for(var t=n.name+"",r=cl[t],e=Cc.call(cl,t)?r.length:0;e--;){var i=r[e],u=i.func;if(null==u||u==n)return i.name}return t}function Qe(){var n=qn.iteratee||Ka;return n=n===Ka?Ur:n,arguments.length?n(arguments[0],arguments[1]):n}function Ge(n){for(var t=ga(n),r=t.length;r--;)t[r][2]=pi(t[r][1]);return t}function ni(n,t){var r=null==n?B:n[t];return So(r)?r:B}function ti(n){return Ec.call(n)}function ri(n,t,r){for(var e=-1,i=r.length;++e<i;){var u=r[e],o=u.size;switch(u.type){case"drop":n+=o;break;case"dropRight":t-=o;break;case"take":t=Vc(t,n+o);break;case"takeRight":n=Zc(n,t-o)}}return{start:n,end:t}}function ei(n,t,r){if(null==n)return!1;var e=r(n,t);return e||li(t)||(t=he(t),n=di(n,t),null!=n&&(t=Ii(t),e=r(n,t))),e||Mo(n&&n.length)&&O(t,n.length)&&(nf(n)||Lo(n)||ao(n))}function ii(n){var t=n.length,r=n.constructor(t);return t&&"string"==typeof n[0]&&Cc.call(n,"index")&&(r.index=n.index,r.input=n.input),r}function ui(n){var t=n.constructor;return ll(_o(t)?t.prototype:B)}function oi(n,t,r){var e=n.constructor;switch(t){case In:return me(n);case An:case Sn:return new e(+n);case Pn:case Un:case Fn:case Hn:case Wn:case Bn:case Yn:case Zn:case Vn:return we(n,r);case jn:return _e(n);case Dn:case On:return new e(n);case Ln:return xe(n);case Rn:return Me(n);case zn:return be(n)}}function ai(n){var t=n?n.length:B;return Mo(t)&&(nf(n)||Lo(n)||ao(n))?b(t,String):null}function ci(n,t,r){if(!bo(r))return!1;var e=typeof t;return("number"==e?co(r)&&O(t,r.length):"string"==e&&t in r)?io(r[t],n):!1}function li(n,t){return"number"==typeof n?!0:!nf(n)&&(ot.test(n)||!ut.test(n)||null!=t&&n in Object(t))}function fi(n){var t=typeof n;return"number"==t||"boolean"==t||"string"==t&&"__proto__"!==n||null==n}function si(n){var t=Je(n),r=qn[t];if("function"!=typeof r||!(t in At.prototype))return!1;if(n===r)return!0;var e=dl(r);return!!e&&n===e[0]}function hi(n){var t=n&&n.constructor,r="function"==typeof t&&t.prototype||wc;return n===r}function pi(n){return n===n&&!bo(n)}function vi(n,t){var r=n[1],e=t[1],i=r|e,u=(Z|V|nn)>i,o=e==nn&&r==K||e==nn&&r==tn&&n[7].length<=t[8]||e==(nn|tn)&&t[7].length<=t[8]&&r==K;if(!u&&!o)return n;e&Z&&(n[2]=t[2],i|=r&Z?0:X);var a=t[3];if(a){var c=n[3];n[3]=c?ke(c,a,t[4]):Ae(a),n[4]=c?I(n[3],wn):Ae(t[4])}return a=t[5],a&&(c=n[5],n[5]=c?Ce(c,a,t[6]):Ae(a),n[6]=c?I(n[5],wn):Ae(t[6])),a=t[7],a&&(n[7]=Ae(a)),e&nn&&(n[8]=null==n[8]?t[8]:Vc(n[8],t[8])),null==n[9]&&(n[9]=t[9]),n[0]=t[0],n[1]=i,n}function gi(n,t,r,e,i,u){return bo(n)&&bo(t)&&(u.set(t,n),Zr(n,t,B,gi,u)),n}function di(n,t){return 1==t.length?n:ra(n,oe(t,0,-1))}function yi(n,t){for(var r=n.length,e=Vc(t.length,r),i=Ae(n);e--;){var u=t[e];n[e]=O(u,r)?i[u]:B}return n}function mi(n){var t=[];return Yo(n).replace(at,function(n,r,e,i){t.push(e?i.replace(pt,"$1"):r||n)}),t}function _i(n){return lo(n)?n:[]}function xi(n){return"function"==typeof n?n:Xa}function Mi(n){if(n instanceof At)return n.clone();var t=new Ct(n.__wrapped__,n.__chain__);return t.__actions__=Ae(n.__actions__),t.__index__=n.__index__,t.__values__=n.__values__,t}function bi(n,t){t=Zc(Uo(t),0);var r=n?n.length:0;if(!r||1>t)return[];for(var e=0,i=-1,u=Array(Fc(r/t));r>e;)u[++i]=oe(n,e,e+=t);return u}function wi(n){for(var t=-1,r=n?n.length:0,e=-1,i=[];++t<r;){var u=n[t];u&&(i[++e]=u)}return i}function ki(n,t,r){var e=n?n.length:0;return e?(t=r||t===B?1:Uo(t),oe(n,0>t?0:t,e)):[]}function Ci(n,t,r){var e=n?n.length:0;return e?(t=r||t===B?1:Uo(t),t=e-t,oe(n,0,0>t?0:t)):[]}function Ai(n,t){return n&&n.length?ge(n,Qe(t,3),!0,!0):[]}function Si(n,t){return n&&n.length?ge(n,Qe(t,3),!0):[]}function Ei(n,t,r,e){var i=n?n.length:0;return i?(r&&"number"!=typeof r&&ci(n,t,r)&&(r=0,e=i),wr(n,t,r,e)):[]}function Ni(n,t){return n&&n.length?y(n,Qe(t,3)):-1}function $i(n,t){return n&&n.length?y(n,Qe(t,3),!0):-1}function ji(n,t){var r=n?n.length:0;return r?Cr(f(n,Qe(t,3))):[]}function Di(n){var t=n?n.length:0;return t?Cr(n):[]}function Ti(n){var t=n?n.length:0;return t?Cr(n,!0):[]}function Li(n){for(var t=-1,r=n?n.length:0,e={};++t<r;){var i=n[t];e[i[0]]=i[1]}return e}function Ri(n){return n?n[0]:B}function Oi(n,t,r){var e=n?n.length:0;return e?(r=Uo(r),0>r&&(r=Zc(e+r,0)),m(n,t,r)):-1}function zi(n){return Ci(n,1)}function qi(n,t){return n?Bc.call(n,t):""}function Ii(n){var t=n?n.length:0;return t?n[t-1]:B}function Pi(n,t,r){var e=n?n.length:0;if(!e)return-1;var i=e;if(r!==B&&(i=Uo(r),i=(0>i?Zc(e+i,0):Vc(i,e-1))+1),t!==t)return L(n,i,!0);for(;i--;)if(n[i]===t)return i;return-1}function Ui(n,t){return n&&n.length&&t&&t.length?ne(n,t):n}function Fi(n,t,r){return n&&n.length&&t&&t.length?te(n,t,Qe(r)):n}function Hi(n,t){var r=[];if(!n||!n.length)return r;var e=-1,i=[],u=n.length;for(t=Qe(t,3);++e<u;){var o=n[e];t(o,e,n)&&(r.push(o),i.push(e))}return re(n,i),r}function Wi(n){return n?Jc.call(n):n}function Bi(n,t,r){var e=n?n.length:0;return e?(r&&"number"!=typeof r&&ci(n,t,r)?(t=0,r=e):(t=null==t?0:Uo(t),r=r===B?e:Uo(r)),oe(n,t,r)):[]}function Yi(n,t){return ce(n,t)}function Zi(n,t,r){return le(n,t,Qe(r))}function Vi(n,t){var r=n?n.length:0;if(r){var e=ce(n,t);if(r>e&&io(n[e],t))return e}return-1}function Xi(n,t){return ce(n,t,!0)}function Ki(n,t,r){return le(n,t,Qe(r),!0)}function Ji(n,t){var r=n?n.length:0;if(r){var e=ce(n,t,!0)-1;if(io(n[e],t))return e}return-1}function Qi(n){return n&&n.length?fe(n):[]}function Gi(n,t){return n&&n.length?se(n,Qe(t)):[]}function nu(n){return ki(n,1)}function tu(n,t,r){return n&&n.length?(t=r||t===B?1:Uo(t),oe(n,0,0>t?0:t)):[]}function ru(n,t,r){var e=n?n.length:0;return e?(t=r||t===B?1:Uo(t),t=e-t,oe(n,0>t?0:t,e)):[]}function eu(n,t){return n&&n.length?ge(n,Qe(t,3),!1,!0):[]}function iu(n,t){return n&&n.length?ge(n,Qe(t,3)):[]}function uu(n){return n&&n.length?pe(n):[]}function ou(n,t){return n&&n.length?pe(n,Qe(t)):[]}function au(n,t){return n&&n.length?pe(n,B,t):[]}function cu(n){if(!n||!n.length)return[];var t=0;return n=a(n,function(n){return lo(n)?(t=Zc(n.length,t),!0):void 0}),b(t,function(t){return f(n,Qr(t))})}function lu(n,t){if(!n||!n.length)return[];var e=cu(n);return null==t?e:f(e,function(n){return r(t,B,n)})}function fu(n,t){for(var r=-1,e=n?n.length:0,i=t?t.length:0,u={};++r<e;)ue(u,n[r],i>r?t[r]:B);return u}function su(n){var t=qn(n);return t.__chain__=!0,t}function hu(n,t){return t(n),n}function pu(n,t){return t(n)}function vu(){return su(this)}function gu(){return new Ct(this.value(),this.__chain__)}function du(n){return this.map(n).flatten()}function yu(){this.__values__===B&&(this.__values__=Po(this.value()));var n=this.__index__>=this.__values__.length,t=n?B:this.__values__[this.__index__++];return{done:n,value:t}}function mu(){return this}function _u(n){for(var t,r=this;r instanceof Mt;){var e=Mi(r);e.__index__=0,e.__values__=B,t?i.__wrapped__=e:t=e;var i=e;r=r.__wrapped__}return i.__wrapped__=n,t}function xu(){var n=this.__wrapped__;if(n instanceof At){var t=n;return this.__actions__.length&&(t=new At(this)),t=t.reverse(),t.__actions__.push({func:pu,args:[Wi],thisArg:B}),new Ct(t,this.__chain__)}return this.thru(Wi)}function Mu(){return de(this.__wrapped__,this.__actions__)}function bu(n,t,r){var e=nf(n)?o:br;return r&&ci(n,t,r)&&(t=B),e(n,Qe(t,3))}function wu(n,t){var r=nf(n)?a:kr;return r(n,Qe(t,3))}function ku(n,t){if(t=Qe(t,3),nf(n)){var r=y(n,t);return r>-1?n[r]:B}return d(n,t,fl)}function Cu(n,t){if(t=Qe(t,3),nf(n)){var r=y(n,t,!0);return r>-1?n[r]:B}return d(n,t,sl)}function Au(n,t){return"function"==typeof t&&nf(n)?i(n,t):fl(n,xi(t))}function Su(n,t){return"function"==typeof t&&nf(n)?u(n,t):sl(n,xi(t))}function Eu(n,t,r,e){n=co(n)?n:_a(n),r=r&&!e?Uo(r):0;var i=n.length;return 0>r&&(r=Zc(i+r,0)),Lo(n)?i>=r&&n.indexOf(t,r)>-1:!!i&&m(n,t,r)>-1}function Nu(n,t){var r=nf(n)?f:Wr;return r(n,Qe(t,3))}function $u(n,t,r,e){return null==n?[]:(nf(t)||(t=null==t?[]:[t]),r=e?B:r,nf(r)||(r=null==r?[]:[r]),Xr(n,t,r))}function ju(n,t,r){var e=nf(n)?h:_,i=arguments.length<3;return e(n,Qe(t,4),r,i,fl)}function Du(n,t,r){var e=nf(n)?p:_,i=arguments.length<3;return e(n,Qe(t,4),r,i,sl)}function Tu(n,t){var r=nf(n)?a:kr;return t=Qe(t,3),r(n,function(n,r,e){return!t(n,r,e)})}function Lu(n){var t=co(n)?n:_a(n),r=t.length;return r>0?t[ee(0,r-1)]:B}function Ru(n,t){var r=-1,e=Po(n),i=e.length,u=i-1;for(t=gr(Uo(t),0,i);++r<t;){var o=ee(r,u),a=e[o];e[o]=e[r],e[r]=a}return e.length=t,e}function Ou(n){return Ru(n,xn)}function zu(n){if(null==n)return 0;if(co(n)){var t=n.length;return t&&Lo(n)?U(n):t}return oa(n).length}function qu(n,t,r){var e=nf(n)?v:ae;return r&&ci(n,t,r)&&(t=B),e(n,Qe(t,3))}function Iu(n,t){if("function"!=typeof t)throw new Mc(vn);return n=Uo(n),function(){return--n<1?t.apply(this,arguments):void 0}}function Pu(n,t,r){return t=r?B:t,t=n&&null==t?n.length:t,Ze(n,nn,B,B,B,B,t)}function Uu(n,t){var r;if("function"!=typeof t)throw new Mc(vn);return n=Uo(n),function(){return--n>0&&(r=t.apply(this,arguments)),1>=n&&(t=B),r}}function Fu(n,t,r){t=r?B:t;var e=Ze(n,K,B,B,B,B,B,t);return e.placeholder=Fu.placeholder,e}function Hu(n,t,r){t=r?B:t;var e=Ze(n,J,B,B,B,B,B,t);return e.placeholder=Hu.placeholder,e}function Wu(n,t,r){function e(){v&&Lc(v),f&&Lc(f),d=0,l=f=p=v=g=B}function i(t,r){r&&Lc(r),f=v=g=B,t&&(d=Bl(),s=n.apply(p,l),v||f||(l=p=B))}function u(){var n=t-(Bl()-h);0>=n||n>t?i(g,f):v=Pc(u,n)}function o(){return(v&&g||f&&_)&&(s=n.apply(p,l)),e(),s}function a(){i(_,v)}function c(){if(l=arguments,h=Bl(),p=this,g=_&&(v||!y),m===!1)var r=y&&!v;else{f||y||(d=h);var e=m-(h-d),i=0>=e||e>m;i?(f&&(f=Lc(f)),d=h,s=n.apply(p,l)):f||(f=Pc(a,e))}return i&&v?v=Lc(v):v||t===m||(v=Pc(u,t)),r&&(i=!0,s=n.apply(p,l)),!i||v||f||(l=p=B),s}var l,f,s,h,p,v,g,d=0,y=!1,m=!1,_=!0;if("function"!=typeof n)throw new Mc(vn);return t=Ho(t)||0,bo(r)&&(y=!!r.leading,m="maxWait"in r&&Zc(Ho(r.maxWait)||0,t),_="trailing"in r?!!r.trailing:_),c.cancel=e,c.flush=o,c}function Bu(n){return Ze(n,rn)}function Yu(n,t){if("function"!=typeof n||t&&"function"!=typeof t)throw new Mc(vn);var r=function(){var e=arguments,i=t?t.apply(this,e):e[0],u=r.cache;if(u.has(i))return u.get(i);var o=n.apply(this,e);return r.cache=u.set(i,o),o};return r.cache=new Yu.Cache,r}function Zu(n){if("function"!=typeof n)throw new Mc(vn);return function(){return!n.apply(this,arguments)}}function Vu(n){return Uu(2,n)}function Xu(n,t){if("function"!=typeof n)throw new Mc(vn);return t=Zc(t===B?n.length-1:Uo(t),0),function(){for(var e=arguments,i=-1,u=Zc(e.length-t,0),o=Array(u);++i<u;)o[i]=e[t+i];switch(t){case 0:return n.call(this,o);case 1:return n.call(this,e[0],o);case 2:return n.call(this,e[0],e[1],o)}var a=Array(t+1);for(i=-1;++i<t;)a[i]=e[i];return a[t]=o,r(n,this,a)}}function Ku(n){if("function"!=typeof n)throw new Mc(vn);return function(t){return r(n,this,t)}}function Ju(n,t,r){var e=!0,i=!0;if("function"!=typeof n)throw new Mc(vn);return bo(r)&&(e="leading"in r?!!r.leading:e,i="trailing"in r?!!r.trailing:i),Wu(n,t,{leading:e,maxWait:t,trailing:i})}function Qu(n){return Pu(n,1)}function Gu(n,t){return t=null==t?Xa:t,Jl(t,n)}function no(n){return dr(n)}function to(n,t){return dr(n,!1,t)}function ro(n){return dr(n,!0)}function eo(n,t){return dr(n,!0,t)}function io(n,t){return n===t||n!==n&&t!==t}function uo(n,t){return n>t}function oo(n,t){return n>=t}function ao(n){return lo(n)&&Cc.call(n,"callee")&&(!Ic.call(n,"callee")||Ec.call(n)==kn)}function co(n){return null!=n&&!("function"==typeof n&&_o(n))&&Mo(yl(n))}function lo(n){return wo(n)&&co(n)}function fo(n){return n===!0||n===!1||wo(n)&&Ec.call(n)==An}function so(n){return wo(n)&&Ec.call(n)==Sn}function ho(n){return!!n&&1===n.nodeType&&wo(n)&&!jo(n)}function po(n){return!wo(n)||_o(n.splice)?!zu(n):!oa(n).length}function vo(n,t){return qr(n,t)}function go(n,t,r){r="function"==typeof r?r:B;var e=r?r(n,t):B;return e===B?qr(n,t,r):!!e}function yo(n){return wo(n)&&"string"==typeof n.message&&Ec.call(n)==En}function mo(n){return"number"==typeof n&&Wc(n)}function _o(n){var t=bo(n)?Ec.call(n):"";return t==Nn||t==$n}function xo(n){return"number"==typeof n&&n==Uo(n)}function Mo(n){return"number"==typeof n&&n>-1&&n%1==0&&yn>=n}function bo(n){var t=typeof n;return!!n&&("object"==t||"function"==t)}function wo(n){return!!n&&"object"==typeof n}function ko(n,t){return n===t||Pr(n,t,Ge(t))}function Co(n,t,r){return r="function"==typeof r?r:B,Pr(n,t,Ge(t),r)}function Ao(n){return $o(n)&&n!=+n}function So(n){return null==n?!1:_o(n)?$c.test(kc.call(n)):wo(n)&&(R(n)?$c:_t).test(n)}function Eo(n){return null===n}function No(n){return null==n}function $o(n){return"number"==typeof n||wo(n)&&Ec.call(n)==Dn}function jo(n){if(!wo(n)||Ec.call(n)!=Tn||R(n))return!1;var t=wc;if("function"==typeof n.constructor&&(t=Oc(n)),null===t)return!0;var r=t.constructor;return"function"==typeof r&&r instanceof r&&kc.call(r)==Sc}function Do(n){return bo(n)&&Ec.call(n)==Ln}function To(n){return xo(n)&&n>=-yn&&yn>=n}function Lo(n){return"string"==typeof n||!nf(n)&&wo(n)&&Ec.call(n)==On}function Ro(n){return"symbol"==typeof n||wo(n)&&Ec.call(n)==zn}function Oo(n){return wo(n)&&Mo(n.length)&&!!pr[Ec.call(n)]}function zo(n){return n===B}function qo(n,t){return t>n}function Io(n,t){return t>=n}function Po(n){if(!n)return[];if(co(n))return Lo(n)?F(n):Ae(n);if(qc&&n[qc])return z(n[qc]());var t=ti(n),r=t==jn?q:t==Rn?P:_a;return r(n)}function Uo(n){if(!n)return 0===n?n:0;if(n=Ho(n),n===dn||n===-dn){var t=0>n?-1:1;return t*mn}var r=n%1;return n===n?r?n-r:n:0}function Fo(n){return n?gr(Uo(n),0,xn):0}function Ho(n){if(bo(n)){var t=_o(n.valueOf)?n.valueOf():n;n=bo(t)?t+"":t}if("string"!=typeof n)return 0===n?n:+n;n=n.replace(ft,"");var r=mt.test(n);return r||xt.test(n)?Mr(n.slice(2),r?2:8):yt.test(n)?_n:+n}function Wo(n){return Se(n,aa(n))}function Bo(n){return gr(Uo(n),-yn,yn)}function Yo(n){if("string"==typeof n)return n;if(null==n)return"";if(Ro(n))return Dc?al.call(n):"";var t=n+"";return"0"==t&&1/n==-dn?"-0":t}function Zo(n,t){var r=ll(n);return t?ir(r,t):r}function Vo(n,t){return d(n,Qe(t,3),Sr,!0)}function Xo(n,t){return d(n,Qe(t,3),Er,!0)}function Ko(n,t){return null==n?n:hl(n,xi(t),aa)}function Jo(n,t){return null==n?n:pl(n,xi(t),aa)}function Qo(n,t){return n&&Sr(n,xi(t))}function Go(n,t){return n&&Er(n,xi(t))}function na(n){return null==n?[]:jr(n,oa(n))}function ta(n){return null==n?[]:jr(n,aa(n))}function ra(n,t,r){var e=null==n?B:Dr(n,t);return e===B?r:e}function ea(n,t){return ei(n,t,Tr)}function ia(n,t){return ei(n,t,Lr)}function ua(n,t,r){return h(oa(n),function(e,i){var u=n[i];return t&&!r?Cc.call(e,u)?e[u].push(i):e[u]=[i]:e[u]=i,e},{})}function oa(n){var t=hi(n);if(!t&&!co(n))return Fr(n);var r=ai(n),e=!!r,i=r||[],u=i.length;for(var o in n)!Tr(n,o)||e&&("length"==o||O(o,u))||t&&"constructor"==o||i.push(o);return i}function aa(n){for(var t=-1,r=hi(n),e=Hr(n),i=e.length,u=ai(n),o=!!u,a=u||[],c=a.length;++t<i;){var l=e[t];o&&("length"==l||O(l,c))||"constructor"==l&&(r||!Cc.call(n,l))||a.push(l)}return a}function ca(n,t){var r={};return t=Qe(t,3),Sr(n,function(n,e,i){r[t(n,e,i)]=n}),r}function la(n,t){var r={};return t=Qe(t,3),Sr(n,function(n,e,i){r[e]=t(n,e,i)}),r}function fa(n,t){return t=Qe(t,2),Jr(n,function(n,r){return!t(n,r)})}function sa(n,t){return null==n?{}:Jr(n,Qe(t,2))}function ha(n,t,r){if(li(t,n))e=null==n?B:n[t];else{t=he(t);var e=ra(n,t);n=di(n,t)}return e===B&&(e=r),_o(e)?e.call(n):e}function pa(n,t,r){return null==n?n:ue(n,t,r)}function va(n,t,r,e){return e="function"==typeof e?e:B,null==n?n:ue(n,t,r,e)}function ga(n){return w(n,oa(n))}function da(n){return w(n,aa(n))}function ya(n,t,r){var e=nf(n)||Oo(n);if(t=Qe(t,4),null==r)if(e||bo(n)){var u=n.constructor;r=e?nf(n)?new u:[]:ll(_o(u)?u.prototype:B)}else r={};return(e?i:Sr)(n,function(n,e,i){return t(r,n,e,i)}),r}function ma(n,t){return null==n?!0:ve(n,t)}function _a(n){return n?C(n,oa(n)):[]}function xa(n){return null==n?C(n,aa(n)):[]}function Ma(n,t,r){return r===B&&(r=t,t=B),r!==B&&(r=Ho(r),r=r===r?r:0),t!==B&&(t=Ho(t),t=t===t?t:0),gr(Ho(n),t,r)}function ba(n,t,r){return t=Ho(t)||0,r===B?(r=t,t=0):r=Ho(r)||0,n=Ho(n),Rr(n,t,r)}function wa(n,t,r){if(r&&"boolean"!=typeof r&&ci(n,t,r)&&(t=r=B),r===B&&("boolean"==typeof t?(r=t,t=B):"boolean"==typeof n&&(r=n,n=B)),n===B&&t===B?(n=0,t=1):(n=Ho(n)||0,t===B?(t=n,n=0):t=Ho(t)||0),n>t){var e=n;n=t,t=e}if(r||n%1||t%1){var i=Kc();return Vc(n+i*(t-n+xr("1e-"+((i+"").length-1))),t)}return ee(n,t)}function ka(n){return mf(Yo(n).toLowerCase())}function Ca(n){return n=Yo(n),n&&n.replace(bt,j).replace(ur,"")}function Aa(n,t,r){n=Yo(n),t="string"==typeof t?t:t+"";var e=n.length;return r=r===B?e:gr(Uo(r),0,e),r-=t.length,r>=0&&n.indexOf(t,r)==r}function Sa(n){return n=Yo(n),n&&tt.test(n)?n.replace(Gn,D):n}function Ea(n){return n=Yo(n),n&&lt.test(n)?n.replace(ct,"\\$&"):n}function Na(n,t,r){n=Yo(n),t=Uo(t);var e=U(n);if(!t||e>=t)return n;var i=(t-e)/2,u=Hc(i),o=Fc(i);return Fe("",u,r)+n+Fe("",o,r)}function $a(n,t,r){return n=Yo(n),n+Fe(n,t,r)}function ja(n,t,r){return n=Yo(n),Fe(n,t,r)+n}function Da(n,t,r){return r||null==t?t=0:t&&(t=+t),n=Yo(n).replace(ft,""),Xc(n,t||(dt.test(n)?16:10))}function Ta(n,t){n=Yo(n),t=Uo(t);var r="";if(!n||1>t||t>yn)return r;do t%2&&(r+=n),t=Hc(t/2),n+=n;while(t);return r}function La(){var n=arguments,t=Yo(n[0]);return n.length<3?t:t.replace(n[1],n[2])}function Ra(n,t,r){return Yo(n).split(t,r)}function Oa(n,t,r){return n=Yo(n),r=gr(Uo(r),0,n.length),n.lastIndexOf(t,r)==r}function za(n,t,r){var e=qn.templateSettings;r&&ci(n,t,r)&&(t=B),n=Yo(n),t=ef({},t,e,tr);var i,u,o=ef({},t.imports,e.imports,tr),a=oa(o),c=C(o,a),l=0,f=t.interpolate||wt,s="__p += '",h=xc((t.escape||wt).source+"|"+f.source+"|"+(f===it?vt:wt).source+"|"+(t.evaluate||wt).source+"|$","g"),p="//# sourceURL="+("sourceURL"in t?t.sourceURL:"lodash.templateSources["+ ++hr+"]")+"\n";n.replace(h,function(t,r,e,o,a,c){return e||(e=o),s+=n.slice(l,c).replace(kt,T),r&&(i=!0,s+="' +\n__e("+r+") +\n'"),a&&(u=!0,s+="';\n"+a+";\n__p += '"),e&&(s+="' +\n((__t = ("+e+")) == null ? '' : __t) +\n'"),l=c+t.length,t}),s+="';\n";var v=t.variable;v||(s="with (obj) {\n"+s+"\n}\n"),s=(u?s.replace(Xn,""):s).replace(Kn,"$1").replace(Jn,"$1;"),s="function("+(v||"obj")+") {\n"+(v?"":"obj || (obj = {});\n")+"var __t, __p = ''"+(i?", __e = _.escape":"")+(u?", __j = Array.prototype.join;\nfunction print() { __p += __j.call(arguments, '') }\n":";\n")+s+"return __p\n}";var g=bf(function(){return Function(a,p+"return "+s).apply(B,c)});if(g.source=s,yo(g))throw g;return g}function qa(n){return Yo(n).toLowerCase()}function Ia(n){return Yo(n).toUpperCase()}function Pa(n,t,r){if(n=Yo(n),!n)return n;if(r||t===B)return n.replace(ft,"");if(t+="",!t)return n;var e=F(n),i=F(t);return e.slice(A(e,i),S(e,i)+1).join("")}function Ua(n,t,r){if(n=Yo(n),!n)return n;if(r||t===B)return n.replace(ht,"");if(t+="",!t)return n;var e=F(n);return e.slice(0,S(e,F(t))+1).join("")}function Fa(n,t,r){if(n=Yo(n),!n)return n;if(r||t===B)return n.replace(st,"");if(t+="",!t)return n;var e=F(n);return e.slice(A(e,F(t))).join("")}function Ha(n,t){var r=on,e=an;if(bo(t)){var i="separator"in t?t.separator:i;r="length"in t?Uo(t.length):r,e="omission"in t?Yo(t.omission):e}n=Yo(n);var u=n.length;if(ar.test(n)){var o=F(n);u=o.length}if(r>=u)return n;var a=r-U(e);if(1>a)return e;var c=o?o.slice(0,a).join(""):n.slice(0,a);if(i===B)return c+e;if(o&&(a+=c.length-a),
+Do(i)){if(n.slice(a).search(i)){var l,f=c;for(i.global||(i=xc(i.source,Yo(gt.exec(i))+"g")),i.lastIndex=0;l=i.exec(f);)var s=l.index;c=c.slice(0,s===B?a:s)}}else if(n.indexOf(i,a)!=a){var h=c.lastIndexOf(i);h>-1&&(c=c.slice(0,h))}return c+e}function Wa(n){return n=Yo(n),n&&nt.test(n)?n.replace(Qn,H):n}function Ba(n,t,r){return n=Yo(n),t=r?B:t,t===B&&(t=fr.test(n)?lr:cr),n.match(t)||[]}function Ya(n){var t=n?n.length:0,e=Qe();return n=t?f(n,function(n){if("function"!=typeof n[1])throw new Mc(vn);return[e(n[0]),n[1]]}):[],Xu(function(e){for(var i=-1;++i<t;){var u=n[i];if(r(u[0],this,e))return r(u[1],this,e)}})}function Za(n){return yr(dr(n,!0))}function Va(n){return function(){return n}}function Xa(n){return n}function Ka(n){return wo(n)&&!nf(n)?Ja(n):Ur(n)}function Ja(n){return Br(dr(n,!0))}function Qa(n,t){return Yr(n,dr(t,!0))}function Ga(n,t,r){var e=oa(t),u=jr(t,e);null!=r||bo(t)&&(u.length||!e.length)||(r=t,t=n,n=this,u=jr(t,oa(t)));var o=bo(r)&&"chain"in r?r.chain:!0,a=_o(n);return i(u,function(r){var e=t[r];n[r]=e,a&&(n.prototype[r]=function(){var t=this.__chain__;if(o||t){var r=n(this.__wrapped__),i=r.__actions__=Ae(this.__actions__);return i.push({func:e,args:arguments,thisArg:n}),r.__chain__=t,r}return e.apply(n,s([this.value()],arguments))})}),n}function nc(){return Nr._===this&&(Nr._=Nc),this}function tc(){}function rc(n){return n=Uo(n),function(){return arguments[n]}}function ec(n){return li(n)?Qr(n):Gr(n)}function ic(n){return function(t){return null==n?B:Dr(n,t)}}function uc(n,t){if(n=Uo(n),1>n||n>yn)return[];var r=xn,e=Vc(n,xn);t=xi(t),n-=xn;for(var i=b(e,t);++r<n;)t(r);return i}function oc(n){return nf(n)?f(n,String):mi(n)}function ac(n){var t=++Ac;return Yo(n)+t}function cc(n,t){var r;return n!==B&&(r=n),t!==B&&(r=r===B?t:r+t),r}function lc(n){return n&&n.length?g(n,Xa,uo):B}function fc(n,t){return n&&n.length?g(n,Qe(t),uo):B}function sc(n){return gc(n)/(n?n.length:0)}function hc(n){return n&&n.length?g(n,Xa,qo):B}function pc(n,t){return n&&n.length?g(n,Qe(t),qo):B}function vc(n,t){var r;return n!==B&&(r=n),t!==B&&(r=r===B?t:r-t),r}function gc(n){return n&&n.length?M(n,Xa):B}function dc(n,t){return n&&n.length?M(n,Qe(t)):B}E=E?$r.defaults({},E,$r.pick(Nr,sr)):Nr;var yc=E.Date,mc=E.Error,_c=E.Math,xc=E.RegExp,Mc=E.TypeError,bc=E.Array.prototype,wc=E.Object.prototype,kc=E.Function.prototype.toString,Cc=wc.hasOwnProperty,Ac=0,Sc=kc.call(Object),Ec=wc.toString,Nc=Nr._,$c=xc("^"+kc.call(Cc).replace(ct,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),jc=E.Reflect,Dc=E.Symbol,Tc=E.Uint8Array,Lc=E.clearTimeout,Rc=jc?jc.enumerate:B,Oc=Object.getPrototypeOf,zc=Object.getOwnPropertySymbols,qc="symbol"==typeof(qc=Dc&&Dc.iterator)?qc:B,Ic=wc.propertyIsEnumerable,Pc=E.setTimeout,Uc=bc.splice,Fc=_c.ceil,Hc=_c.floor,Wc=E.isFinite,Bc=bc.join,Yc=Object.keys,Zc=_c.max,Vc=_c.min,Xc=E.parseInt,Kc=_c.random,Jc=bc.reverse,Qc=ni(E,"Map"),Gc=ni(E,"Set"),nl=ni(E,"WeakMap"),tl=ni(Object,"create"),rl=nl&&new nl,el=Qc?kc.call(Qc):"",il=Gc?kc.call(Gc):"",ul=Dc?Dc.prototype:B,ol=Dc?ul.valueOf:B,al=Dc?ul.toString:B,cl={};qn.templateSettings={escape:rt,evaluate:et,interpolate:it,variable:"",imports:{_:qn}};var ll=function(){function n(){}return function(t){if(bo(t)){n.prototype=t;var r=new n;n.prototype=B}return r||{}}}(),fl=De(Sr),sl=De(Er,!0),hl=Te(),pl=Te(!0);Rc&&!Ic.call({valueOf:1},"valueOf")&&(Hr=function(n){return z(Rc(n))});var vl=rl?function(n,t){return rl.set(n,t),n}:Xa,gl=Gc&&2===new Gc([1,2]).size?function(n){return new Gc(n)}:tc,dl=rl?function(n){return rl.get(n)}:tc,yl=Qr("length"),ml=zc||function(){return[]};(Qc&&ti(new Qc)!=jn||Gc&&ti(new Gc)!=Rn)&&(ti=function(n){var t=Ec.call(n),r=t==Tn?n.constructor:null,e="function"==typeof r?kc.call(r):"";if(e){if(e==el)return jn;if(e==il)return Rn}return t});var _l=function(){var n=0,t=0;return function(r,e){var i=Bl(),u=ln-(i-t);if(t=i,u>0){if(++n>=cn)return r}else n=0;return vl(r,e)}}(),xl=Xu(function(n,t){return nf(n)||(n=null==n?[]:[Object(n)]),t=Cr(t),e(n,t)}),Ml=Xu(function(n,t){return lo(n)?_r(n,Cr(t,!1,!0)):[]}),bl=Xu(function(n,t){var r=Ii(t);return lo(r)&&(r=B),lo(n)?_r(n,Cr(t,!1,!0),Qe(r)):[]}),wl=Xu(function(n,t){var r=Ii(t);return lo(r)&&(r=B),lo(n)?_r(n,Cr(t,!1,!0),B,r):[]}),kl=Xu(function(n){var t=f(n,_i);return t.length&&t[0]===n[0]?Or(t):[]}),Cl=Xu(function(n){var t=Ii(n),r=f(n,_i);return t===Ii(r)?t=B:r.pop(),r.length&&r[0]===n[0]?Or(r,Qe(t)):[]}),Al=Xu(function(n){var t=Ii(n),r=f(n,_i);return t===Ii(r)?t=B:r.pop(),r.length&&r[0]===n[0]?Or(r,B,t):[]}),Sl=Xu(Ui),El=Xu(function(n,t){t=f(Cr(t),String);var r=or(n,t);return re(n,t.sort(N)),r}),Nl=Xu(function(n){return pe(Cr(n,!1,!0))}),$l=Xu(function(n){var t=Ii(n);return lo(t)&&(t=B),pe(Cr(n,!1,!0),Qe(t))}),jl=Xu(function(n){var t=Ii(n);return lo(t)&&(t=B),pe(Cr(n,!1,!0),B,t)}),Dl=Xu(function(n,t){return lo(n)?_r(n,t):[]}),Tl=Xu(function(n){return ye(a(n,lo))}),Ll=Xu(function(n){var t=Ii(n);return lo(t)&&(t=B),ye(a(n,lo),Qe(t))}),Rl=Xu(function(n){var t=Ii(n);return lo(t)&&(t=B),ye(a(n,lo),B,t)}),Ol=Xu(cu),zl=Xu(function(n){var t=n.length,r=t>1?n[t-1]:B;return r="function"==typeof r?(n.pop(),r):B,lu(n,r)}),ql=Xu(function(n){n=Cr(n);var t=n.length,r=t?n[0]:0,e=this.__wrapped__,i=function(t){return or(t,n)};return!(t>1||this.__actions__.length)&&e instanceof At&&O(r)?(e=e.slice(r,+r+(t?1:0)),e.__actions__.push({func:pu,args:[i],thisArg:B}),new Ct(e,this.__chain__).thru(function(n){return t&&!n.length&&n.push(B),n})):this.thru(i)}),Il=$e(function(n,t,r){Cc.call(n,r)?++n[r]:n[r]=1}),Pl=$e(function(n,t,r){Cc.call(n,r)?n[r].push(t):n[r]=[t]}),Ul=Xu(function(n,t,e){var i=-1,u="function"==typeof t,o=li(t),a=co(n)?Array(n.length):[];return fl(n,function(n){var c=u?t:o&&null!=n?n[t]:B;a[++i]=c?r(c,n,e):zr(n,t,e)}),a}),Fl=$e(function(n,t,r){n[r]=t}),Hl=$e(function(n,t,r){n[r?0:1].push(t)},function(){return[[],[]]}),Wl=Xu(function(n,t){if(null==n)return[];var r=t.length;return r>1&&ci(n,t[0],t[1])?t=[]:r>2&&ci(t[0],t[1],t[2])&&(t.length=1),Xr(n,Cr(t),[])}),Bl=yc.now,Yl=Xu(function(n,t,r){var e=Z;if(r.length){var i=I(r,Yl.placeholder);e|=Q}return Ze(n,e,t,r,i)}),Zl=Xu(function(n,t,r){var e=Z|V;if(r.length){var i=I(r,Zl.placeholder);e|=Q}return Ze(t,e,n,r,i)}),Vl=Xu(function(n,t){return mr(n,1,t)}),Xl=Xu(function(n,t,r){return mr(n,Ho(t)||0,r)}),Kl=Xu(function(n,t){t=f(Cr(t),Qe());var e=t.length;return Xu(function(i){for(var u=-1,o=Vc(i.length,e);++u<o;)i[u]=t[u].call(this,i[u]);return r(n,this,i)})}),Jl=Xu(function(n,t){var r=I(t,Jl.placeholder);return Ze(n,Q,B,t,r)}),Ql=Xu(function(n,t){var r=I(t,Ql.placeholder);return Ze(n,G,B,t,r)}),Gl=Xu(function(n,t){return Ze(n,tn,B,B,B,Cr(t))}),nf=Array.isArray,tf=je(function(n,t){Se(t,oa(t),n)}),rf=je(function(n,t){Se(t,aa(t),n)}),ef=je(function(n,t,r,e){Ee(t,aa(t),n,e)}),uf=je(function(n,t,r,e){Ee(t,oa(t),n,e)}),of=Xu(function(n,t){return or(n,Cr(t))}),af=Xu(function(n){return n.push(B,tr),r(ef,B,n)}),cf=Xu(function(n){return n.push(B,gi),r(sf,B,n)}),lf=Xu(zr),ff=je(function(n,t,r){Zr(n,t,r)}),sf=je(function(n,t,r,e){Zr(n,t,r,e)}),hf=Xu(function(n,t){return null==n?{}:(t=f(Cr(t),String),Kr(n,_r(aa(n),t)))}),pf=Xu(function(n,t){return null==n?{}:Kr(n,Cr(t))}),vf=Oe(function(n,t,r){return t=t.toLowerCase(),n+(r?ka(t):t)}),gf=Oe(function(n,t,r){return n+(r?"-":"")+t.toLowerCase()}),df=Oe(function(n,t,r){return n+(r?" ":"")+t.toLowerCase()}),yf=Re("toLowerCase"),mf=Re("toUpperCase"),_f=Oe(function(n,t,r){return n+(r?"_":"")+t.toLowerCase()}),xf=Oe(function(n,t,r){return n+(r?" ":"")+ka(t)}),Mf=Oe(function(n,t,r){return n+(r?" ":"")+t.toUpperCase()}),bf=Xu(function(n,t){try{return r(n,B,t)}catch(e){return yo(e)?e:new mc(e)}}),wf=Xu(function(n,t){return i(Cr(t),function(t){n[t]=Yl(n[t],n)}),n}),kf=Ie(),Cf=Ie(!0),Af=Xu(function(n,t){return function(r){return zr(r,n,t)}}),Sf=Xu(function(n,t){return function(r){return zr(n,r,t)}}),Ef=Ue(f),Nf=Ue(o),$f=Ue(v),jf=We(),Df=We(!0),Tf=Ye("ceil"),Lf=Ye("floor"),Rf=Ye("round");return qn.prototype=Mt.prototype,Ct.prototype=ll(Mt.prototype),Ct.prototype.constructor=Ct,At.prototype=ll(Mt.prototype),At.prototype.constructor=At,$t.prototype=tl?tl(null):wc,Rt.prototype.clear=Ot,Rt.prototype["delete"]=zt,Rt.prototype.get=qt,Rt.prototype.has=It,Rt.prototype.set=Pt,Ut.prototype.push=Ht,Wt.prototype.clear=Bt,Wt.prototype["delete"]=Yt,Wt.prototype.get=Zt,Wt.prototype.has=Vt,Wt.prototype.set=Xt,Yu.Cache=Rt,qn.after=Iu,qn.ary=Pu,qn.assign=tf,qn.assignIn=rf,qn.assignInWith=ef,qn.assignWith=uf,qn.at=of,qn.before=Uu,qn.bind=Yl,qn.bindAll=wf,qn.bindKey=Zl,qn.chain=su,qn.chunk=bi,qn.compact=wi,qn.concat=xl,qn.cond=Ya,qn.conforms=Za,qn.constant=Va,qn.countBy=Il,qn.create=Zo,qn.curry=Fu,qn.curryRight=Hu,qn.debounce=Wu,qn.defaults=af,qn.defaultsDeep=cf,qn.defer=Vl,qn.delay=Xl,qn.difference=Ml,qn.differenceBy=bl,qn.differenceWith=wl,qn.drop=ki,qn.dropRight=Ci,qn.dropRightWhile=Ai,qn.dropWhile=Si,qn.fill=Ei,qn.filter=wu,qn.flatMap=ji,qn.flatten=Di,qn.flattenDeep=Ti,qn.flip=Bu,qn.flow=kf,qn.flowRight=Cf,qn.fromPairs=Li,qn.functions=na,qn.functionsIn=ta,qn.groupBy=Pl,qn.initial=zi,qn.intersection=kl,qn.intersectionBy=Cl,qn.intersectionWith=Al,qn.invert=ua,qn.invokeMap=Ul,qn.iteratee=Ka,qn.keyBy=Fl,qn.keys=oa,qn.keysIn=aa,qn.map=Nu,qn.mapKeys=ca,qn.mapValues=la,qn.matches=Ja,qn.matchesProperty=Qa,qn.memoize=Yu,qn.merge=ff,qn.mergeWith=sf,qn.method=Af,qn.methodOf=Sf,qn.mixin=Ga,qn.negate=Zu,qn.nthArg=rc,qn.omit=hf,qn.omitBy=fa,qn.once=Vu,qn.orderBy=$u,qn.over=Ef,qn.overArgs=Kl,qn.overEvery=Nf,qn.overSome=$f,qn.partial=Jl,qn.partialRight=Ql,qn.partition=Hl,qn.pick=pf,qn.pickBy=sa,qn.property=ec,qn.propertyOf=ic,qn.pull=Sl,qn.pullAll=Ui,qn.pullAllBy=Fi,qn.pullAt=El,qn.range=jf,qn.rangeRight=Df,qn.rearg=Gl,qn.reject=Tu,qn.remove=Hi,qn.rest=Xu,qn.reverse=Wi,qn.sampleSize=Ru,qn.set=pa,qn.setWith=va,qn.shuffle=Ou,qn.slice=Bi,qn.sortBy=Wl,qn.sortedUniq=Qi,qn.sortedUniqBy=Gi,qn.split=Ra,qn.spread=Ku,qn.tail=nu,qn.take=tu,qn.takeRight=ru,qn.takeRightWhile=eu,qn.takeWhile=iu,qn.tap=hu,qn.throttle=Ju,qn.thru=pu,qn.toArray=Po,qn.toPairs=ga,qn.toPairsIn=da,qn.toPath=oc,qn.toPlainObject=Wo,qn.transform=ya,qn.unary=Qu,qn.union=Nl,qn.unionBy=$l,qn.unionWith=jl,qn.uniq=uu,qn.uniqBy=ou,qn.uniqWith=au,qn.unset=ma,qn.unzip=cu,qn.unzipWith=lu,qn.values=_a,qn.valuesIn=xa,qn.without=Dl,qn.words=Ba,qn.wrap=Gu,qn.xor=Tl,qn.xorBy=Ll,qn.xorWith=Rl,qn.zip=Ol,qn.zipObject=fu,qn.zipWith=zl,qn.extend=rf,qn.extendWith=ef,Ga(qn,qn),qn.add=cc,qn.attempt=bf,qn.camelCase=vf,qn.capitalize=ka,qn.ceil=Tf,qn.clamp=Ma,qn.clone=no,qn.cloneDeep=ro,qn.cloneDeepWith=eo,qn.cloneWith=to,qn.deburr=Ca,qn.endsWith=Aa,qn.eq=io,qn.escape=Sa,qn.escapeRegExp=Ea,qn.every=bu,qn.find=ku,qn.findIndex=Ni,qn.findKey=Vo,qn.findLast=Cu,qn.findLastIndex=$i,qn.findLastKey=Xo,qn.floor=Lf,qn.forEach=Au,qn.forEachRight=Su,qn.forIn=Ko,qn.forInRight=Jo,qn.forOwn=Qo,qn.forOwnRight=Go,qn.get=ra,qn.gt=uo,qn.gte=oo,qn.has=ea,qn.hasIn=ia,qn.head=Ri,qn.identity=Xa,qn.includes=Eu,qn.indexOf=Oi,qn.inRange=ba,qn.invoke=lf,qn.isArguments=ao,qn.isArray=nf,qn.isArrayLike=co,qn.isArrayLikeObject=lo,qn.isBoolean=fo,qn.isDate=so,qn.isElement=ho,qn.isEmpty=po,qn.isEqual=vo,qn.isEqualWith=go,qn.isError=yo,qn.isFinite=mo,qn.isFunction=_o,qn.isInteger=xo,qn.isLength=Mo,qn.isMatch=ko,qn.isMatchWith=Co,qn.isNaN=Ao,qn.isNative=So,qn.isNil=No,qn.isNull=Eo,qn.isNumber=$o,qn.isObject=bo,qn.isObjectLike=wo,qn.isPlainObject=jo,qn.isRegExp=Do,qn.isSafeInteger=To,qn.isString=Lo,qn.isSymbol=Ro,qn.isTypedArray=Oo,qn.isUndefined=zo,qn.join=qi,qn.kebabCase=gf,qn.last=Ii,qn.lastIndexOf=Pi,qn.lowerCase=df,qn.lowerFirst=yf,qn.lt=qo,qn.lte=Io,qn.max=lc,qn.maxBy=fc,qn.mean=sc,qn.min=hc,qn.minBy=pc,qn.noConflict=nc,qn.noop=tc,qn.now=Bl,qn.pad=Na,qn.padEnd=$a,qn.padStart=ja,qn.parseInt=Da,qn.random=wa,qn.reduce=ju,qn.reduceRight=Du,qn.repeat=Ta,qn.replace=La,qn.result=ha,qn.round=Rf,qn.runInContext=W,qn.sample=Lu,qn.size=zu,qn.snakeCase=_f,qn.some=qu,qn.sortedIndex=Yi,qn.sortedIndexBy=Zi,qn.sortedIndexOf=Vi,qn.sortedLastIndex=Xi,qn.sortedLastIndexBy=Ki,qn.sortedLastIndexOf=Ji,qn.startCase=xf,qn.startsWith=Oa,qn.subtract=vc,qn.sum=gc,qn.sumBy=dc,qn.template=za,qn.times=uc,qn.toInteger=Uo,qn.toLength=Fo,qn.toLower=qa,qn.toNumber=Ho,qn.toSafeInteger=Bo,qn.toString=Yo,qn.toUpper=Ia,qn.trim=Pa,qn.trimEnd=Ua,qn.trimStart=Fa,qn.truncate=Ha,qn.unescape=Wa,qn.uniqueId=ac,qn.upperCase=Mf,qn.upperFirst=mf,qn.each=Au,qn.eachRight=Su,qn.first=Ri,Ga(qn,function(){var n={};return Sr(qn,function(t,r){Cc.call(qn.prototype,r)||(n[r]=t)}),n}(),{chain:!1}),qn.VERSION=Y,i(["bind","bindKey","curry","curryRight","partial","partialRight"],function(n){qn[n].placeholder=qn}),i(["drop","take"],function(n,t){At.prototype[n]=function(r){var e=this.__filtered__;if(e&&!t)return new At(this);r=r===B?1:Zc(Uo(r),0);var i=this.clone();return e?i.__takeCount__=Vc(r,i.__takeCount__):i.__views__.push({size:Vc(r,xn),type:n+(i.__dir__<0?"Right":"")}),i},At.prototype[n+"Right"]=function(t){return this.reverse()[n](t).reverse()}}),i(["filter","map","takeWhile"],function(n,t){var r=t+1,e=r==sn||r==pn;At.prototype[n]=function(n){var t=this.clone();return t.__iteratees__.push({iteratee:Qe(n,3),type:r}),t.__filtered__=t.__filtered__||e,t}}),i(["head","last"],function(n,t){var r="take"+(t?"Right":"");At.prototype[n]=function(){return this[r](1).value()[0]}}),i(["initial","tail"],function(n,t){var r="drop"+(t?"":"Right");At.prototype[n]=function(){return this.__filtered__?new At(this):this[r](1)}}),At.prototype.compact=function(){return this.filter(Xa)},At.prototype.find=function(n){return this.filter(n).head()},At.prototype.findLast=function(n){return this.reverse().find(n)},At.prototype.invokeMap=Xu(function(n,t){return"function"==typeof n?new At(this):this.map(function(r){return zr(r,n,t)})}),At.prototype.reject=function(n){return n=Qe(n,3),this.filter(function(t){return!n(t)})},At.prototype.slice=function(n,t){n=Uo(n);var r=this;return r.__filtered__&&(n>0||0>t)?new At(r):(0>n?r=r.takeRight(-n):n&&(r=r.drop(n)),t!==B&&(t=Uo(t),r=0>t?r.dropRight(-t):r.take(t-n)),r)},At.prototype.takeRightWhile=function(n){return this.reverse().takeWhile(n).reverse()},At.prototype.toArray=function(){return this.take(xn)},Sr(At.prototype,function(n,t){var r=/^(?:filter|find|map|reject)|While$/.test(t),e=/^(?:head|last)$/.test(t),i=qn[e?"take"+("last"==t?"Right":""):t],u=e||/^find/.test(t);i&&(qn.prototype[t]=function(){var t=this.__wrapped__,o=e?[1]:arguments,a=t instanceof At,c=o[0],l=a||nf(t),f=function(n){var t=i.apply(qn,s([n],o));return e&&h?t[0]:t};l&&r&&"function"==typeof c&&1!=c.length&&(a=l=!1);var h=this.__chain__,p=!!this.__actions__.length,v=u&&!h,g=a&&!p;if(!u&&l){t=g?t:new At(this);var d=n.apply(t,o);return d.__actions__.push({func:pu,args:[f],thisArg:B}),new Ct(d,h)}return v&&g?n.apply(this,o):(d=this.thru(f),v?e?d.value()[0]:d.value():d)})}),i(["pop","push","shift","sort","splice","unshift"],function(n){var t=bc[n],r=/^(?:push|sort|unshift)$/.test(n)?"tap":"thru",e=/^(?:pop|shift)$/.test(n);qn.prototype[n]=function(){var n=arguments;return e&&!this.__chain__?t.apply(this.value(),n):this[r](function(r){return t.apply(r,n)})}}),Sr(At.prototype,function(n,t){var r=qn[t];if(r){var e=r.name+"",i=cl[e]||(cl[e]=[]);i.push({name:t,func:r})}}),cl[Pe(B,V).name]=[{name:"wrapper",func:B}],At.prototype.clone=St,At.prototype.reverse=Et,At.prototype.value=Nt,qn.prototype.at=ql,qn.prototype.chain=vu,qn.prototype.commit=gu,qn.prototype.flatMap=du,qn.prototype.next=yu,qn.prototype.plant=_u,qn.prototype.reverse=xu,qn.prototype.toJSON=qn.prototype.valueOf=qn.prototype.value=Mu,qc&&(qn.prototype[qc]=mu),qn}var B,Y="4.0.1",Z=1,V=2,X=4,K=8,J=16,Q=32,G=64,nn=128,tn=256,rn=512,en=1,un=2,on=30,an="...",cn=150,ln=16,fn=200,sn=1,hn=2,pn=3,vn="Expected a function",gn="__lodash_hash_undefined__",dn=1/0,yn=9007199254740991,mn=1.7976931348623157e308,_n=NaN,xn=4294967295,Mn=xn-1,bn=xn>>>1,wn="__lodash_placeholder__",kn="[object Arguments]",Cn="[object Array]",An="[object Boolean]",Sn="[object Date]",En="[object Error]",Nn="[object Function]",$n="[object GeneratorFunction]",jn="[object Map]",Dn="[object Number]",Tn="[object Object]",Ln="[object RegExp]",Rn="[object Set]",On="[object String]",zn="[object Symbol]",qn="[object WeakMap]",In="[object ArrayBuffer]",Pn="[object Float32Array]",Un="[object Float64Array]",Fn="[object Int8Array]",Hn="[object Int16Array]",Wn="[object Int32Array]",Bn="[object Uint8Array]",Yn="[object Uint8ClampedArray]",Zn="[object Uint16Array]",Vn="[object Uint32Array]",Xn=/\b__p \+= '';/g,Kn=/\b(__p \+=) '' \+/g,Jn=/(__e\(.*?\)|\b__t\)) \+\n'';/g,Qn=/&(?:amp|lt|gt|quot|#39|#96);/g,Gn=/[&<>"'`]/g,nt=RegExp(Qn.source),tt=RegExp(Gn.source),rt=/<%-([\s\S]+?)%>/g,et=/<%([\s\S]+?)%>/g,it=/<%=([\s\S]+?)%>/g,ut=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,ot=/^\w*$/,at=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]/g,ct=/[\\^$.*+?()[\]{}|]/g,lt=RegExp(ct.source),ft=/^\s+|\s+$/g,st=/^\s+/,ht=/\s+$/,pt=/\\(\\)?/g,vt=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,gt=/\w*$/,dt=/^0x/i,yt=/^[-+]0x[0-9a-f]+$/i,mt=/^0b[01]+$/i,_t=/^\[object .+?Constructor\]$/,xt=/^0o[0-7]+$/i,Mt=/^(?:0|[1-9]\d*)$/,bt=/[\xc0-\xd6\xd8-\xde\xdf-\xf6\xf8-\xff]/g,wt=/($^)/,kt=/['\n\r\u2028\u2029\\]/g,Ct="\\ud800-\\udfff",At="\\u0300-\\u036f\\ufe20-\\ufe23",St="\\u20d0-\\u20f0",Et="\\u2700-\\u27bf",Nt="a-z\\xdf-\\xf6\\xf8-\\xff",$t="\\xac\\xb1\\xd7\\xf7",jt="\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf",Dt="\\u2018\\u2019\\u201c\\u201d",Tt=" \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000",Lt="A-Z\\xc0-\\xd6\\xd8-\\xde",Rt="\\ufe0e\\ufe0f",Ot=$t+jt+Dt+Tt,zt="["+Ct+"]",qt="["+Ot+"]",It="["+At+St+"]",Pt="\\d+",Ut="["+Et+"]",Ft="["+Nt+"]",Ht="[^"+Ct+Ot+Pt+Et+Nt+Lt+"]",Wt="\\ud83c[\\udffb-\\udfff]",Bt="(?:"+It+"|"+Wt+")",Yt="[^"+Ct+"]",Zt="(?:\\ud83c[\\udde6-\\uddff]){2}",Vt="[\\ud800-\\udbff][\\udc00-\\udfff]",Xt="["+Lt+"]",Kt="\\u200d",Jt="(?:"+Ft+"|"+Ht+")",Qt="(?:"+Xt+"|"+Ht+")",Gt=Bt+"?",nr="["+Rt+"]?",tr="(?:"+Kt+"(?:"+[Yt,Zt,Vt].join("|")+")"+nr+Gt+")*",rr=nr+Gt+tr,er="(?:"+[Ut,Zt,Vt].join("|")+")"+rr,ir="(?:"+[Yt+It+"?",It,Zt,Vt,zt].join("|")+")",ur=RegExp(It,"g"),or=RegExp(Wt+"(?="+Wt+")|"+ir+rr,"g"),ar=RegExp("["+Kt+Ct+At+St+Rt+"]"),cr=/[a-zA-Z0-9]+/g,lr=RegExp([Xt+"?"+Ft+"+(?="+[qt,Xt,"$"].join("|")+")",Qt+"+(?="+[qt,Xt+Jt,"$"].join("|")+")",Xt+"?"+Jt+"+",Xt+"+",Pt,er].join("|"),"g"),fr=/[a-z][A-Z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,sr=["Array","Date","Error","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Math","Object","Reflect","RegExp","Set","String","Symbol","TypeError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","_","clearTimeout","isFinite","parseInt","setTimeout"],hr=-1,pr={};pr[Pn]=pr[Un]=pr[Fn]=pr[Hn]=pr[Wn]=pr[Bn]=pr[Yn]=pr[Zn]=pr[Vn]=!0,pr[kn]=pr[Cn]=pr[In]=pr[An]=pr[Sn]=pr[En]=pr[Nn]=pr[jn]=pr[Dn]=pr[Tn]=pr[Ln]=pr[Rn]=pr[On]=pr[qn]=!1;var vr={};vr[kn]=vr[Cn]=vr[In]=vr[An]=vr[Sn]=vr[Pn]=vr[Un]=vr[Fn]=vr[Hn]=vr[Wn]=vr[jn]=vr[Dn]=vr[Tn]=vr[Ln]=vr[Rn]=vr[On]=vr[zn]=vr[Bn]=vr[Yn]=vr[Zn]=vr[Vn]=!0,vr[En]=vr[Nn]=vr[qn]=!1;var gr={"À":"A","Á":"A","Â":"A","Ã":"A","Ä":"A","Å":"A","à":"a","á":"a","â":"a","ã":"a","ä":"a","å":"a","Ç":"C","ç":"c","Ð":"D","ð":"d","È":"E","É":"E","Ê":"E","Ë":"E","è":"e","é":"e","ê":"e","ë":"e","Ì":"I","Í":"I","Î":"I","Ï":"I","ì":"i","í":"i","î":"i","ï":"i","Ñ":"N","ñ":"n","Ò":"O","Ó":"O","Ô":"O","Õ":"O","Ö":"O","Ø":"O","ò":"o","ó":"o","ô":"o","õ":"o","ö":"o","ø":"o","Ù":"U","Ú":"U","Û":"U","Ü":"U","ù":"u","ú":"u","û":"u","ü":"u","Ý":"Y","ý":"y","ÿ":"y","Æ":"Ae","æ":"ae","Þ":"Th","þ":"th","ß":"ss"},dr={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","`":"&#96;"},yr={"&amp;":"&","&lt;":"<","&gt;":">","&quot;":'"',"&#39;":"'","&#96;":"`"},mr={"function":!0,object:!0},_r={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},xr=parseFloat,Mr=parseInt,br=mr[typeof exports]&&exports&&!exports.nodeType?exports:null,wr=mr[typeof module]&&module&&!module.nodeType?module:null,kr=E(br&&wr&&"object"==typeof global&&global),Cr=E(mr[typeof self]&&self),Ar=E(mr[typeof window]&&window),Sr=wr&&wr.exports===br?br:null,Er=E(mr[typeof this]&&this),Nr=kr||Ar!==(Er&&Er.window)&&Ar||Cr||Er||Function("return this")(),$r=W();(Ar||Cr||{})._=$r,"function"==typeof define&&"object"==typeof define.amd&&define.amd?define(function(){return $r}):br&&wr?(Sr&&((wr.exports=$r)._=$r),br._=$r):Nr._=$r}.call(this),function(n,t,r){"use strict";function e(n,t,r){if(!n)throw dn("areq","Argument '{0}' is {1}",t||"?",r||"required");return n}function i(n,t){return n||t?n?t?(H(n)&&(n=n.join(" ")),H(t)&&(t=t.join(" ")),n+" "+t):n:t:""}function u(n){var t={};return n&&(n.to||n.from)&&(t.to=n.to,t.from=n.from),t}function o(n,t,r){var e="";return n=H(n)?n:n&&W(n)&&n.length?n.split(/\s+/):[],F(n,function(n,i){n&&n.length>0&&(e+=i>0?" ":"",e+=r?t+n:n+t)}),e}function a(n,t){var r=n.indexOf(t);t>=0&&n.splice(r,1)}function c(n){if(n instanceof U)switch(n.length){case 0:return[];case 1:if(n[0].nodeType===K)return n;break;default:return U(l(n))}return n.nodeType===K?U(n):void 0}function l(n){if(!n[0])return n;for(var t=0;t<n.length;t++){var r=n[t];if(r.nodeType==K)return r}}function f(n,t,r){F(t,function(t){n.addClass(t,r)})}function s(n,t,r){F(t,function(t){n.removeClass(t,r)})}function h(n){return function(t,r){r.addClass&&(f(n,t,r.addClass),r.addClass=null),r.removeClass&&(s(n,t,r.removeClass),r.removeClass=null)}}function p(n){if(n=n||{},!n.$$prepared){var t=n.domOperation||q;n.domOperation=function(){n.$$domOperationFired=!0,t(),t=q},n.$$prepared=!0}return n}function v(n,t){g(n,t),d(n,t)}function g(n,t){t.from&&(n.css(t.from),t.from=null)}function d(n,t){t.to&&(n.css(t.to),t.to=null)}function y(n,t,r){var e=(t.addClass||"")+" "+(r.addClass||""),i=(t.removeClass||"")+" "+(r.removeClass||""),u=m(n.attr("class"),e,i);r.preparationClasses&&(t.preparationClasses=C(r.preparationClasses,t.preparationClasses),delete r.preparationClasses);var o=t.domOperation!==q?t.domOperation:null;return P(t,r),o&&(t.domOperation=o),u.addClass?t.addClass=u.addClass:t.addClass=null,u.removeClass?t.removeClass=u.removeClass:t.removeClass=null,t}function m(n,t,r){function e(n){W(n)&&(n=n.split(" "));var t={};return F(n,function(n){n.length&&(t[n]=!0)}),t}var i=1,u=-1,o={};n=e(n),t=e(t),F(t,function(n,t){o[t]=i}),r=e(r),F(r,function(n,t){o[t]=o[t]===i?null:u});var a={addClass:"",removeClass:""};return F(o,function(t,r){var e,o;t===i?(e="addClass",o=!n[r]):t===u&&(e="removeClass",o=n[r]),o&&(a[e].length&&(a[e]+=" "),a[e]+=r)}),a}function _(n){return n instanceof t.element?n[0]:n}function x(n,t,r){var e="";t&&(e=o(t,G,!0)),r.addClass&&(e=C(e,o(r.addClass,J))),r.removeClass&&(e=C(e,o(r.removeClass,Q))),e.length&&(r.preparationClasses=e,n.addClass(e))}function M(n,t){t.preparationClasses&&(n.removeClass(t.preparationClasses),t.preparationClasses=null),t.activeClasses&&(n.removeClass(t.activeClasses),t.activeClasses=null)}function b(n,t){var r=t?"-"+t+"s":"";return k(n,[vn,r]),[vn,r]}function w(n,t){var r=t?"paused":"",e=O+fn;return k(n,[e,r]),[e,r]}function k(n,t){var r=t[0],e=t[1];n.style[r]=e}function C(n,t){return n?t?n+" "+t:n:t}function A(n){return[pn,n+"s"]}function S(n,t){var r=t?hn:vn;return[r,n+"s"]}function E(n,t,r){var e=Object.create(null),i=n.getComputedStyle(t)||{};return F(r,function(n,t){var r=i[n];if(r){var u=r.charAt(0);("-"===u||"+"===u||u>=0)&&(r=N(r)),0===r&&(r=null),e[t]=r}}),e}function N(n){var t=0,r=n.split(/\s*,\s*/);return F(r,function(n){"s"==n.charAt(n.length-1)&&(n=n.substring(0,n.length-1)),n=parseFloat(n)||0,t=t?Math.max(n,t):n}),t}function $(n){return 0===n||null!=n}function j(n,t){var r=L,e=n+"s";return t?r+=un:e+=" linear all",[r,e]}function D(){var n=Object.create(null);return{flush:function(){n=Object.create(null)},count:function(t){var r=n[t];return r?r.total:0},get:function(t){var r=n[t];return r&&r.value},put:function(t,r){n[t]?n[t].total++:n[t]={total:1,value:r}}}}function T(n,t,r){F(r,function(r){n[r]=Z(n[r])?n[r]:t.style.getPropertyValue(r)})}var L,R,O,z,q=t.noop,I=t.copy,P=t.extend,U=t.element,F=t.forEach,H=t.isArray,W=t.isString,B=t.isObject,Y=t.isUndefined,Z=t.isDefined,V=t.isFunction,X=t.isElement,K=1,J="-add",Q="-remove",G="ng-",nn="-active",tn="ng-animate",rn="$$ngAnimateChildren",en="";Y(n.ontransitionend)&&Z(n.onwebkittransitionend)?(en="-webkit-",L="WebkitTransition",R="webkitTransitionEnd transitionend"):(L="transition",R="transitionend"),Y(n.onanimationend)&&Z(n.onwebkitanimationend)?(en="-webkit-",O="WebkitAnimation",z="webkitAnimationEnd animationend"):(O="animation",z="animationend");var un="Duration",on="Property",an="Delay",cn="TimingFunction",ln="IterationCount",fn="PlayState",sn=9999,hn=O+an,pn=O+un,vn=L+an,gn=L+un,dn=t.$$minErr("ng"),yn=["$$rAF",function(n){function t(n){e=e.concat(n),r()}function r(){if(e.length){for(var t=e.shift(),u=0;u<t.length;u++)t[u]();i||n(function(){i||r()})}}var e,i;return e=t.queue=[],t.waitUntilQuiet=function(t){i&&i(),i=n(function(){i=null,t(),r()})},t}],mn=[function(){return function(n,r,e){var i=e.ngAnimateChildren;t.isString(i)&&0===i.length?r.data(rn,!0):e.$observe("ngAnimateChildren",function(n){n="on"===n||"true"===n,r.data(rn,n)})}}],_n="$$animateCss",xn=1e3,Mn=3,bn=1.5,wn={transitionDuration:gn,transitionDelay:vn,transitionProperty:L+on,animationDuration:pn,animationDelay:hn,animationIterationCount:O+ln},kn={transitionDuration:gn,transitionDelay:vn,animationDuration:pn,animationDelay:hn},Cn=["$animateProvider",function(n){var t=D(),r=D();this.$get=["$window","$$jqLite","$$AnimateRunner","$timeout","$$forceReflow","$sniffer","$$rAFScheduler","$$animateQueue",function(n,e,i,c,l,f,s,y){function m(n,t){var r="$$ngAnimateParentKey",e=n.parentNode,i=e[r]||(e[r]=++P);return i+"-"+n.getAttribute("class")+"-"+t}function x(r,e,i,u){var o=t.get(i);return o||(o=E(n,r,u),"infinite"===o.animationIterationCount&&(o.animationIterationCount=1)),t.put(i,o),o}function M(i,u,a,c){var l;if(t.count(a)>0&&(l=r.get(a),!l)){var f=o(u,"-stagger");e.addClass(i,f),l=E(n,i,c),l.animationDuration=Math.max(l.animationDuration,0),l.transitionDuration=Math.max(l.transitionDuration,0),e.removeClass(i,f),r.put(a,l)}return l||{}}function C(n){U.push(n),s.waitUntilQuiet(function(){t.flush(),r.flush();for(var n=l(),e=0;e<U.length;e++)U[e](n);U.length=0})}function N(n,t,r){var e=x(n,t,r,wn),i=e.animationDelay,u=e.transitionDelay;return e.maxDelay=i&&u?Math.max(i,u):i||u,e.maxDuration=Math.max(e.animationDuration*e.animationIterationCount,e.transitionDuration),e}var D=h(e),P=0,U=[];return function(n,r){function l(){h()}function s(){h(!0)}function h(t){Z||X&&V||(Z=!0,V=!1,W.$$skipPreparationClasses||e.removeClass(n,wn),e.removeClass(n,An),w(Y,!1),b(Y,!1),F(fn,function(n){Y.style[n[0]]=""}),D(n,W),v(n,W),Object.keys(B).length&&F(B,function(n,t){n?Y.style.setProperty(t,n):Y.style.removeProperty(t)}),W.onDone&&W.onDone(),vn&&vn.length&&n.off(vn.join(" "),P),K&&K.complete(!t))}function x(n){Pn.blockTransition&&b(Y,n),Pn.blockKeyframeAnimation&&w(Y,!!n)}function E(){return K=new i({end:l,cancel:s}),C(q),h(),{$$willAnimate:!1,start:function(){return K},end:l}}function P(n){n.stopPropagation();var t=n.originalEvent||n,r=t.$manualTimeStamp||Date.now(),e=parseFloat(t.elapsedTime.toFixed(Mn));Math.max(r-ln,0)>=en&&e>=un&&(X=!0,h())}function U(){function t(){if(!Z){if(x(!1),F(fn,function(n){var t=n[0],r=n[1];Y.style[t]=r}),D(n,W),e.addClass(n,An),Pn.recalculateTimingStyles){if(Cn=Y.className+" "+wn,Nn=m(Y,Cn),qn=N(Y,Cn,Nn),In=qn.maxDelay,rn=Math.max(In,0),un=qn.maxDuration,0===un)return void h();Pn.hasTransitions=qn.transitionDuration>0,Pn.hasAnimations=qn.animationDuration>0}if(Pn.applyAnimationDelay&&(In="boolean"!=typeof W.delay&&$(W.delay)?parseFloat(W.delay):In,rn=Math.max(In,0),qn.animationDelay=In,Un=S(In,!0),fn.push(Un),Y.style[Un[0]]=Un[1]),en=rn*xn,an=un*xn,W.easing){var t,i=W.easing;Pn.hasTransitions&&(t=L+cn,fn.push([t,i]),Y.style[t]=i),Pn.hasAnimations&&(t=O+cn,fn.push([t,i]),Y.style[t]=i)}qn.transitionDuration&&vn.push(R),qn.animationDuration&&vn.push(z),ln=Date.now();var u=en+bn*an,o=ln+u,a=n.data(_n)||[],l=!0;if(a.length){var f=a[0];l=o>f.expectedEndTime,l?c.cancel(f.timer):a.push(h)}if(l){var s=c(r,u,!1);a[0]={timer:s,expectedEndTime:o},a.push(h),n.data(_n,a)}vn.length&&n.on(vn.join(" "),P),W.to&&(W.cleanupStyles&&T(B,Y,Object.keys(W.to)),d(n,W))}}function r(){var t=n.data(_n);if(t){for(var r=1;r<t.length;r++)t[r]();n.removeData(_n)}}if(!Z){if(!Y.parentNode)return void h();var i=function(n){if(X)V&&n&&(V=!1,h());else if(V=!n,qn.animationDuration){var t=w(Y,V);V?fn.push(t):a(fn,t)}},u=On>0&&(qn.transitionDuration&&0===$n.transitionDuration||qn.animationDuration&&0===$n.animationDuration)&&Math.max($n.animationDelay,$n.transitionDelay);u?c(t,Math.floor(u*On*xn),!1):t(),tn.resume=function(){i(!0)},tn.pause=function(){i(!1)}}}var W=r||{};W.$$prepared||(W=p(I(W)));var B={},Y=_(n);if(!Y||!Y.parentNode||!y.enabled())return E();var Z,V,X,K,tn,rn,en,un,an,ln,fn=[],hn=n.attr("class"),pn=u(W),vn=[];if(0===W.duration||!f.animations&&!f.transitions)return E();var gn=W.event&&H(W.event)?W.event.join(" "):W.event,dn=gn&&W.structural,yn="",mn="";dn?yn=o(gn,G,!0):gn&&(yn=gn),W.addClass&&(mn+=o(W.addClass,J)),W.removeClass&&(mn.length&&(mn+=" "),mn+=o(W.removeClass,Q)),W.applyClassesEarly&&mn.length&&D(n,W);var wn=[yn,mn].join(" ").trim(),Cn=hn+" "+wn,An=o(wn,nn),Sn=pn.to&&Object.keys(pn.to).length>0,En=(W.keyframeStyle||"").length>0;if(!En&&!Sn&&!wn)return E();var Nn,$n;if(W.stagger>0){var jn=parseFloat(W.stagger);$n={transitionDelay:jn,animationDelay:jn,transitionDuration:0,animationDuration:0}}else Nn=m(Y,Cn),$n=M(Y,wn,Nn,kn);W.$$skipPreparationClasses||e.addClass(n,wn);var Dn;if(W.transitionStyle){var Tn=[L,W.transitionStyle];k(Y,Tn),fn.push(Tn)}if(W.duration>=0){Dn=Y.style[L].length>0;var Ln=j(W.duration,Dn);k(Y,Ln),fn.push(Ln)}if(W.keyframeStyle){var Rn=[O,W.keyframeStyle];k(Y,Rn),fn.push(Rn)}var On=$n?W.staggerIndex>=0?W.staggerIndex:t.count(Nn):0,zn=0===On;zn&&!W.skipBlocking&&b(Y,sn);var qn=N(Y,Cn,Nn),In=qn.maxDelay;rn=Math.max(In,0),un=qn.maxDuration;var Pn={};if(Pn.hasTransitions=qn.transitionDuration>0,Pn.hasAnimations=qn.animationDuration>0,Pn.hasTransitionAll=Pn.hasTransitions&&"all"==qn.transitionProperty,Pn.applyTransitionDuration=Sn&&(Pn.hasTransitions&&!Pn.hasTransitionAll||Pn.hasAnimations&&!Pn.hasTransitions),Pn.applyAnimationDuration=W.duration&&Pn.hasAnimations,Pn.applyTransitionDelay=$(W.delay)&&(Pn.applyTransitionDuration||Pn.hasTransitions),Pn.applyAnimationDelay=$(W.delay)&&Pn.hasAnimations,Pn.recalculateTimingStyles=mn.length>0,(Pn.applyTransitionDuration||Pn.applyAnimationDuration)&&(un=W.duration?parseFloat(W.duration):un,Pn.applyTransitionDuration&&(Pn.hasTransitions=!0,qn.transitionDuration=un,Dn=Y.style[L+on].length>0,fn.push(j(un,Dn))),Pn.applyAnimationDuration&&(Pn.hasAnimations=!0,qn.animationDuration=un,fn.push(A(un)))),0===un&&!Pn.recalculateTimingStyles)return E();if(null!=W.delay){var Un;"boolean"!=typeof W.delay&&(Un=parseFloat(W.delay),rn=Math.max(Un,0)),Pn.applyTransitionDelay&&fn.push(S(Un)),Pn.applyAnimationDelay&&fn.push(S(Un,!0))}return null==W.duration&&qn.transitionDuration>0&&(Pn.recalculateTimingStyles=Pn.recalculateTimingStyles||zn),en=rn*xn,an=un*xn,W.skipBlocking||(Pn.blockTransition=qn.transitionDuration>0,Pn.blockKeyframeAnimation=qn.animationDuration>0&&$n.animationDelay>0&&0===$n.animationDuration),W.from&&(W.cleanupStyles&&T(B,Y,Object.keys(W.from)),g(n,W)),Pn.blockTransition||Pn.blockKeyframeAnimation?x(un):W.skipBlocking||b(Y,!1),{$$willAnimate:!0,end:l,start:function(){return Z?void 0:(tn={end:l,cancel:s,resume:null,pause:null},K=new i(tn),C(U),K)}}}}]}],An=["$$animationProvider",function(n){function t(n){return n.parentNode&&11===n.parentNode.nodeType}n.drivers.push("$$animateCssDriver");var r="ng-animate-shim",e="ng-anchor",i="ng-anchor-out",u="ng-anchor-in";this.$get=["$animateCss","$rootScope","$$AnimateRunner","$rootElement","$sniffer","$$jqLite","$document",function(n,o,a,c,l,f,s){function p(n){return n.replace(/\bng-\S+\b/g,"");
+}function v(n,t){return W(n)&&(n=n.split(" ")),W(t)&&(t=t.split(" ")),n.filter(function(n){return-1===t.indexOf(n)}).join(" ")}function g(t,o,c){function l(n){var t={},r=_(n).getBoundingClientRect();return F(["width","height","top","left"],function(n){var e=r[n];switch(n){case"top":e+=m.scrollTop;break;case"left":e+=m.scrollLeft}t[n]=Math.floor(e)+"px"}),t}function f(){var t=n(d,{addClass:i,delay:!0,from:l(o)});return t.$$willAnimate?t:null}function s(n){return n.attr("class")||""}function h(){var t=p(s(c)),r=v(t,y),e=v(y,t),o=n(d,{to:l(c),addClass:u+" "+r,removeClass:i+" "+e,delay:!0});return o.$$willAnimate?o:null}function g(){d.remove(),o.removeClass(r),c.removeClass(r)}var d=U(_(o).cloneNode(!0)),y=p(s(d));o.addClass(r),c.addClass(r),d.addClass(e),M.append(d);var x,b=f();if(!b&&(x=h(),!x))return g();var w=b||x;return{start:function(){function n(){r&&r.end()}var t,r=w.start();return r.done(function(){return r=null,!x&&(x=h())?(r=x.start(),r.done(function(){r=null,g(),t.complete()}),r):(g(),void t.complete())}),t=new a({end:n,cancel:n})}}}function d(n,t,r,e){var i=y(n,q),u=y(t,q),o=[];return F(e,function(n){var t=n.out,e=n["in"],i=g(r,t,e);i&&o.push(i)}),i||u||0!==o.length?{start:function(){function n(){F(t,function(n){n.end()})}var t=[];i&&t.push(i.start()),u&&t.push(u.start()),F(o,function(n){t.push(n.start())});var r=new a({end:n,cancel:n});return a.all(t,function(n){r.complete(n)}),r}}:void 0}function y(t){var r=t.element,e=t.options||{};t.structural&&(e.event=t.event,e.structural=!0,e.applyClassesEarly=!0,"leave"===t.event&&(e.onDone=e.domOperation)),e.preparationClasses&&(e.event=C(e.event,e.preparationClasses));var i=n(r,e);return i.$$willAnimate?i:null}if(!l.animations&&!l.transitions)return q;var m=s[0].body,x=_(c),M=U(t(x)||m.contains(x)?x:m);h(f);return function(n){return n.from&&n.to?d(n.from,n.to,n.classes,n.anchors):y(n)}}]}],Sn=["$animateProvider",function(n){this.$get=["$injector","$$AnimateRunner","$$jqLite",function(t,r,e){function i(r){r=H(r)?r:r.split(" ");for(var e=[],i={},u=0;u<r.length;u++){var o=r[u],a=n.$$registeredAnimations[o];a&&!i[o]&&(e.push(t.get(a)),i[o]=!0)}return e}var u=h(e);return function(n,t,e,o){function a(){o.domOperation(),u(n,o)}function c(){h=!0,a(),v(n,o)}function l(n,t,e,i,u){var o;switch(e){case"animate":o=[t,i.from,i.to,u];break;case"setClass":o=[t,y,m,u];break;case"addClass":o=[t,y,u];break;case"removeClass":o=[t,m,u];break;default:o=[t,u]}o.push(i);var a=n.apply(n,o);if(a)if(V(a.start)&&(a=a.start()),a instanceof r)a.done(u);else if(V(a))return a;return q}function f(n,t,e,i,u){var o=[];return F(i,function(i){var a=i[u];a&&o.push(function(){var i,u,o=!1,c=function(n){o||(o=!0,(u||q)(n),i.complete(!n))};return i=new r({end:function(){c()},cancel:function(){c(!0)}}),u=l(a,n,t,e,function(n){var t=n===!1;c(t)}),i})}),o}function s(n,t,e,i,u){var o=f(n,t,e,i,u);if(0===o.length){var a,c;"beforeSetClass"===u?(a=f(n,"removeClass",e,i,"beforeRemoveClass"),c=f(n,"addClass",e,i,"beforeAddClass")):"setClass"===u&&(a=f(n,"removeClass",e,i,"removeClass"),c=f(n,"addClass",e,i,"addClass")),a&&(o=o.concat(a)),c&&(o=o.concat(c))}if(0!==o.length)return function(n){var t=[];return o.length&&F(o,function(n){t.push(n())}),t.length?r.all(t,n):n(),function(n){F(t,function(t){n?t.cancel():t.end()})}}}var h=!1;3===arguments.length&&B(e)&&(o=e,e=null),o=p(o),e||(e=n.attr("class")||"",o.addClass&&(e+=" "+o.addClass),o.removeClass&&(e+=" "+o.removeClass));var g,d,y=o.addClass,m=o.removeClass,_=i(e);if(_.length){var x,M;"leave"==t?(M="leave",x="afterLeave"):(M="before"+t.charAt(0).toUpperCase()+t.substr(1),x=t),"enter"!==t&&"move"!==t&&(g=s(n,t,o,_,M)),d=s(n,t,o,_,x)}if(g||d){var b;return{$$willAnimate:!0,end:function(){return b?b.end():(c(),b=new r,b.complete(!0)),b},start:function(){function n(n){c(n),b.complete(n)}function t(t){h||((e||q)(t),n(t))}if(b)return b;b=new r;var e,i=[];return g&&i.push(function(n){e=g(n)}),i.length?i.push(function(n){a(),n(!0)}):a(),d&&i.push(function(n){e=d(n)}),b.setHost({end:function(){t()},cancel:function(){t(!0)}}),r.chain(i,n),b}}}}}]}],En=["$$animationProvider",function(n){n.drivers.push("$$animateJsDriver"),this.$get=["$$animateJs","$$AnimateRunner",function(n,t){function r(t){var r=t.element,e=t.event,i=t.options,u=t.classes;return n(r,e,u,i)}return function(n){if(n.from&&n.to){var e=r(n.from),i=r(n.to);if(!e&&!i)return;return{start:function(){function n(){return function(){F(u,function(n){n.end()})}}function r(n){o.complete(n)}var u=[];e&&u.push(e.start()),i&&u.push(i.start()),t.all(u,r);var o=new t({end:n(),cancel:n()});return o}}}return r(n)}}]}],Nn="data-ng-animate",$n="$ngAnimatePin",jn=["$animateProvider",function(n){function t(n){if(!n)return null;var t=n.split(f),r=Object.create(null);return F(t,function(n){r[n]=!0}),r}function r(n,r){if(n&&r){var e=t(r);return n.split(f).some(function(n){return e[n]})}}function i(n,t,r,e){return s[n].some(function(n){return n(t,r,e)})}function u(n,t){n=n||{};var r=(n.addClass||"").length>0,e=(n.removeClass||"").length>0;return t?r&&e:r||e}var o=1,a=2,f=" ",s=this.rules={skip:[],cancel:[],join:[]};s.join.push(function(n,t,r){return!t.structural&&u(t.options)}),s.skip.push(function(n,t,r){return!t.structural&&!u(t.options)}),s.skip.push(function(n,t,r){return"leave"==r.event&&t.structural}),s.skip.push(function(n,t,r){return r.structural&&r.state===a&&!t.structural}),s.cancel.push(function(n,t,r){return r.structural&&t.structural}),s.cancel.push(function(n,t,r){return r.state===a&&t.structural}),s.cancel.push(function(n,t,e){var i=t.options.addClass,u=t.options.removeClass,o=e.options.addClass,a=e.options.removeClass;return Y(i)&&Y(u)||Y(o)&&Y(a)?!1:r(i,a)||r(u,o)}),this.$get=["$$rAF","$rootScope","$rootElement","$document","$$HashMap","$$animation","$$AnimateRunner","$templateRequest","$$jqLite","$$forceReflow",function(t,r,f,s,g,d,m,b,w,k){function C(){var n=!1;return function(t){n?t():r.$$postDigest(function(){n=!0,t()})}}function A(n,t){return y(n,t,{})}function S(n,t,r){var e=_(t),i=_(n),u=[],o=q[r];return o&&F(o,function(n){G.call(n.node,e)?u.push(n.callback):"leave"===r&&G.call(n.node,i)&&u.push(n.callback)}),u}function E(n,e,l){function f(r,e,i,u){E(function(){var r=S(b,n,e);r.length&&t(function(){F(r,function(t){t(n,i,u)})})}),r.progress(e,i,u)}function h(t){M(n,w),Q(n,w),v(n,w),w.domOperation(),k.complete(!t)}var g,b,w=I(l);n=c(n),n&&(g=_(n),b=n.parent()),w=p(w);var k=new m,E=C();if(H(w.addClass)&&(w.addClass=w.addClass.join(" ")),w.addClass&&!W(w.addClass)&&(w.addClass=null),H(w.removeClass)&&(w.removeClass=w.removeClass.join(" ")),w.removeClass&&!W(w.removeClass)&&(w.removeClass=null),w.from&&!B(w.from)&&(w.from=null),w.to&&!B(w.to)&&(w.to=null),!g)return h(),k;var j=[g.className,w.addClass,w.removeClass].join(" ");if(!J(j))return h(),k;var z=["enter","move","leave"].indexOf(e)>=0,q=!O||s[0].hidden||R.get(g),P=!q&&L.get(g)||{},U=!!P.state;if(q||U&&P.state==o||(q=!D(n,b,e)),q)return h(),k;z&&N(n);var Y={structural:z,element:n,event:e,close:h,options:w,runner:k};if(U){var Z=i("skip",n,Y,P);if(Z)return P.state===a?(h(),k):(y(n,P.options,w),P.runner);var V=i("cancel",n,Y,P);if(V)if(P.state===a)P.runner.end();else{if(!P.structural)return y(n,P.options,Y.options),P.runner;P.close()}else{var X=i("join",n,Y,P);if(X){if(P.state!==a)return x(n,z?e:null,w),e=Y.event=P.event,w=y(n,P.options,Y.options),P.runner;A(n,w)}}}else A(n,w);var K=Y.structural;if(K||(K="animate"===Y.event&&Object.keys(Y.options.to||{}).length>0||u(Y.options)),!K)return h(),$(n),k;var G=(P.counter||0)+1;return Y.counter=G,T(n,o,Y),r.$$postDigest(function(){var t=L.get(g),r=!t;t=t||{};var i=n.parent()||[],o=i.length>0&&("animate"===t.event||t.structural||u(t.options));if(r||t.counter!==G||!o)return r&&(Q(n,w),v(n,w)),(r||z&&t.event!==e)&&(w.domOperation(),k.end()),void(o||$(n));e=!t.structural&&u(t.options,!0)?"setClass":t.event,T(n,a);var c=d(n,e,t.options);c.done(function(t){h(!t);var r=L.get(g);r&&r.counter===G&&$(_(n)),f(k,e,"close",{})}),k.setHost(c),f(k,e,"start",{})}),k}function N(n){var t=_(n),r=t.querySelectorAll("["+Nn+"]");F(r,function(n){var t=parseInt(n.getAttribute(Nn)),r=L.get(n);if(r)switch(t){case a:r.runner.end();case o:L.remove(n)}})}function $(n){var t=_(n);t.removeAttribute(Nn),L.remove(t)}function j(n,t){return _(n)===_(t)}function D(n,t,r){var e,i=U(s[0].body),u=j(n,i)||"HTML"===n[0].nodeName,o=j(n,f),a=!1,c=R.get(_(n)),l=n.data($n);for(l&&(t=l);t&&t.length;){o||(o=j(t,f));var h=t[0];if(h.nodeType!==K)break;var p=L.get(h)||{};if(!a){var v=R.get(h);if(v===!0&&c!==!1){c=!0;break}v===!1&&(c=!1),a=p.structural}if(Y(e)||e===!0){var g=t.data(rn);Z(g)&&(e=g)}if(a&&e===!1)break;if(u||(u=j(t,i)),u&&o)break;t=o||!(l=t.data($n))?t.parent():l}var d=(!a||e)&&c!==!0;return d&&o&&u}function T(n,t,r){r=r||{},r.state=t;var e=_(n);e.setAttribute(Nn,t);var i=L.get(e),u=i?P(i,r):r;L.put(e,u)}var L=new g,R=new g,O=null,z=r.$watch(function(){return 0===b.totalPendingRequests},function(n){n&&(z(),r.$$postDigest(function(){r.$$postDigest(function(){null===O&&(O=!0)})}))}),q={},V=n.classNameFilter(),J=V?function(n){return V.test(n)}:function(){return!0},Q=h(w),G=Node.prototype.contains||function(n){return this===n||!!(16&this.compareDocumentPosition(n))};return{on:function(n,t,r){var e=l(t);q[n]=q[n]||[],q[n].push({node:e,callback:r})},off:function(n,t,r){function e(n,t,r){var e=l(t);return n.filter(function(n){var t=n.node===e&&(!r||n.callback===r);return!t})}var i=q[n];i&&(q[n]=1===arguments.length?null:e(i,t,r))},pin:function(n,t){e(X(n),"element","not an element"),e(X(t),"parentElement","not an element"),n.data($n,t)},push:function(n,t,r,e){return r=r||{},r.domOperation=e,E(n,t,r)},enabled:function(n,t){var r=arguments.length;if(0===r)t=!!O;else{var e=X(n);if(e){var i=_(n),u=R.get(i);1===r?t=!u:R.put(i,!t)}else t=O=!!n}return t}}}]}],Dn=["$animateProvider",function(n){function t(n,t){n.data(a,t)}function r(n){n.removeData(a)}function e(n){return n.data(a)}var u="ng-animate-ref",o=this.drivers=[],a="$$animationRunner";this.$get=["$$jqLite","$rootScope","$injector","$$AnimateRunner","$$HashMap","$$rAFScheduler",function(n,a,c,l,f,s){function g(n){function t(n){if(n.processed)return n;n.processed=!0;var r=n.domNode,e=r.parentNode;u.put(r,n);for(var o;e;){if(o=u.get(e)){o.processed||(o=t(o));break}e=e.parentNode}return(o||i).children.push(n),n}function r(n){var t,r=[],e=[];for(t=0;t<n.children.length;t++)e.push(n.children[t]);var i=e.length,u=0,o=[];for(t=0;t<e.length;t++){var a=e[t];0>=i&&(i=u,u=0,r.push(o),o=[]),o.push(a.fn),a.children.forEach(function(n){u++,e.push(n)}),i--}return o.length&&r.push(o),r}var e,i={children:[]},u=new f;for(e=0;e<n.length;e++){var o=n[e];u.put(o.domNode,n[e]={domNode:o.domNode,fn:o.fn,children:[]})}for(e=0;e<n.length;e++)t(n[e]);return r(i)}var d=[],y=h(n);return function(f,h,m){function x(n){var t="["+u+"]",r=n.hasAttribute(u)?[n]:n.querySelectorAll(t),e=[];return F(r,function(n){var t=n.getAttribute(u);t&&t.length&&e.push(n)}),e}function M(n){var t=[],r={};F(n,function(n,e){var i=n.element,o=_(i),a=n.event,c=["enter","move"].indexOf(a)>=0,l=n.structural?x(o):[];if(l.length){var f=c?"to":"from";F(l,function(n){var t=n.getAttribute(u);r[t]=r[t]||{},r[t][f]={animationID:e,element:U(n)}})}else t.push(n)});var e={},i={};return F(r,function(r,u){var o=r.from,a=r.to;if(!o||!a){var c=o?o.animationID:a.animationID,l=c.toString();return void(e[l]||(e[l]=!0,t.push(n[c])))}var f=n[o.animationID],s=n[a.animationID],h=o.animationID.toString();if(!i[h]){var p=i[h]={structural:!0,beforeStart:function(){f.beforeStart(),s.beforeStart()},close:function(){f.close(),s.close()},classes:b(f.classes,s.classes),from:f,to:s,anchors:[]};p.classes.length?t.push(p):(t.push(f),t.push(s))}i[h].anchors.push({out:o.element,"in":a.element})}),t}function b(n,t){n=n.split(" "),t=t.split(" ");for(var r=[],e=0;e<n.length;e++){var i=n[e];if("ng-"!==i.substring(0,3))for(var u=0;u<t.length;u++)if(i===t[u]){r.push(i);break}}return r.join(" ")}function w(n){for(var t=o.length-1;t>=0;t--){var r=o[t];if(c.has(r)){var e=c.get(r),i=e(n);if(i)return i}}}function k(){f.addClass(tn),j&&n.addClass(f,j)}function C(n,t){function r(n){e(n).setHost(t)}n.from&&n.to?(r(n.from.element),r(n.to.element)):r(n.element)}function A(){var n=e(f);!n||"leave"===h&&m.$$domOperationFired||n.end()}function S(t){f.off("$destroy",A),r(f),y(f,m),v(f,m),m.domOperation(),j&&n.removeClass(f,j),f.removeClass(tn),N.complete(!t)}m=p(m);var E=["enter","move","leave"].indexOf(h)>=0,N=new l({end:function(){S()},cancel:function(){S(!0)}});if(!o.length)return S(),N;t(f,N);var $=i(f.attr("class"),i(m.addClass,m.removeClass)),j=m.tempClasses;return j&&($+=" "+j,m.tempClasses=null),d.push({element:f,classes:$,event:h,structural:E,options:m,beforeStart:k,close:S}),f.on("$destroy",A),d.length>1?N:(a.$$postDigest(function(){var n=[];F(d,function(t){e(t.element)?n.push(t):t.close()}),d.length=0;var t=M(n),r=[];F(t,function(n){r.push({domNode:_(n.from?n.from.element:n.element),fn:function(){n.beforeStart();var t,r=n.close,i=n.anchors?n.from.element||n.to.element:n.element;if(e(i)){var u=w(n);u&&(t=u.start)}if(t){var o=t();o.done(function(n){r(!n)}),C(n,o)}else r()}})}),s(g(r))}),N)}}]}];t.module("ngAnimate",[]).directive("ngAnimateChildren",mn).factory("$$rAFScheduler",yn).provider("$$animateQueue",jn).provider("$$animation",Dn).provider("$animateCss",Cn).provider("$$animateCssDriver",An).provider("$$animateJs",Sn).provider("$$animateJsDriver",En)}(window,window.angular);
\ No newline at end of file
diff --git a/xos/core/xoslib/static/js/vendor/xosMcordTopologyVendor.js b/xos/core/xoslib/static/js/vendor/xosMcordTopologyVendor.js
new file mode 100644
index 0000000..103c7e8
--- /dev/null
+++ b/xos/core/xoslib/static/js/vendor/xosMcordTopologyVendor.js
@@ -0,0 +1,5 @@
+!function(){function n(n){return n&&(n.ownerDocument||n.document||n).documentElement}function t(n){return n&&(n.ownerDocument&&n.ownerDocument.defaultView||n.document&&n||n.defaultView)}function e(n,t){return t>n?-1:n>t?1:n>=t?0:NaN}function r(n){return null===n?NaN:+n}function i(n){return!isNaN(n)}function u(n){return{left:function(t,e,r,i){for(arguments.length<3&&(r=0),arguments.length<4&&(i=t.length);i>r;){var u=r+i>>>1;n(t[u],e)<0?r=u+1:i=u}return r},right:function(t,e,r,i){for(arguments.length<3&&(r=0),arguments.length<4&&(i=t.length);i>r;){var u=r+i>>>1;n(t[u],e)>0?i=u:r=u+1}return r}}}function o(n){return n.length}function a(n){for(var t=1;n*t%1;)t*=10;return t}function l(n,t){for(var e in t)Object.defineProperty(n.prototype,e,{value:t[e],enumerable:!1})}function c(){this._=Object.create(null)}function f(n){return(n+="")===bo||n[0]===_o?_o+n:n}function s(n){return(n+="")[0]===_o?n.slice(1):n}function h(n){return f(n)in this._}function p(n){return(n=f(n))in this._&&delete this._[n]}function g(){var n=[];for(var t in this._)n.push(s(t));return n}function v(){var n=0;for(var t in this._)++n;return n}function d(){for(var n in this._)return!1;return!0}function y(){this._=Object.create(null)}function m(n){return n}function M(n,t,e){return function(){var r=e.apply(t,arguments);return r===t?n:r}}function x(n,t){if(t in n)return t;t=t.charAt(0).toUpperCase()+t.slice(1);for(var e=0,r=wo.length;r>e;++e){var i=wo[e]+t;if(i in n)return i}}function b(){}function _(){}function w(n){function t(){for(var t,r=e,i=-1,u=r.length;++i<u;)(t=r[i].on)&&t.apply(this,arguments);return n}var e=[],r=new c;return t.on=function(t,i){var u,o=r.get(t);return arguments.length<2?o&&o.on:(o&&(o.on=null,e=e.slice(0,u=e.indexOf(o)).concat(e.slice(u+1)),r.remove(t)),i&&e.push(r.set(t,{on:i})),n)},t}function S(){ao.event.preventDefault()}function k(){for(var n,t=ao.event;n=t.sourceEvent;)t=n;return t}function N(n){for(var t=new _,e=0,r=arguments.length;++e<r;)t[arguments[e]]=w(t);return t.of=function(e,r){return function(i){try{var u=i.sourceEvent=ao.event;i.target=n,ao.event=i,t[i.type].apply(e,r)}finally{ao.event=u}}},t}function E(n){return ko(n,Co),n}function A(n){return"function"==typeof n?n:function(){return No(n,this)}}function C(n){return"function"==typeof n?n:function(){return Eo(n,this)}}function z(n,t){function e(){this.removeAttribute(n)}function r(){this.removeAttributeNS(n.space,n.local)}function i(){this.setAttribute(n,t)}function u(){this.setAttributeNS(n.space,n.local,t)}function o(){var e=t.apply(this,arguments);null==e?this.removeAttribute(n):this.setAttribute(n,e)}function a(){var e=t.apply(this,arguments);null==e?this.removeAttributeNS(n.space,n.local):this.setAttributeNS(n.space,n.local,e)}return n=ao.ns.qualify(n),null==t?n.local?r:e:"function"==typeof t?n.local?a:o:n.local?u:i}function L(n){return n.trim().replace(/\s+/g," ")}function q(n){return new RegExp("(?:^|\\s+)"+ao.requote(n)+"(?:\\s+|$)","g")}function T(n){return(n+"").trim().split(/^|\s+/)}function R(n,t){function e(){for(var e=-1;++e<i;)n[e](this,t)}function r(){for(var e=-1,r=t.apply(this,arguments);++e<i;)n[e](this,r)}n=T(n).map(D);var i=n.length;return"function"==typeof t?r:e}function D(n){var t=q(n);return function(e,r){if(i=e.classList)return r?i.add(n):i.remove(n);var i=e.getAttribute("class")||"";r?(t.lastIndex=0,t.test(i)||e.setAttribute("class",L(i+" "+n))):e.setAttribute("class",L(i.replace(t," ")))}}function P(n,t,e){function r(){this.style.removeProperty(n)}function i(){this.style.setProperty(n,t,e)}function u(){var r=t.apply(this,arguments);null==r?this.style.removeProperty(n):this.style.setProperty(n,r,e)}return null==t?r:"function"==typeof t?u:i}function U(n,t){function e(){delete this[n]}function r(){this[n]=t}function i(){var e=t.apply(this,arguments);null==e?delete this[n]:this[n]=e}return null==t?e:"function"==typeof t?i:r}function j(n){function t(){var t=this.ownerDocument,e=this.namespaceURI;return e===zo&&t.documentElement.namespaceURI===zo?t.createElement(n):t.createElementNS(e,n)}function e(){return this.ownerDocument.createElementNS(n.space,n.local)}return"function"==typeof n?n:(n=ao.ns.qualify(n)).local?e:t}function F(){var n=this.parentNode;n&&n.removeChild(this)}function H(n){return{__data__:n}}function O(n){return function(){return Ao(this,n)}}function I(n){return arguments.length||(n=e),function(t,e){return t&&e?n(t.__data__,e.__data__):!t-!e}}function Y(n,t){for(var e=0,r=n.length;r>e;e++)for(var i,u=n[e],o=0,a=u.length;a>o;o++)(i=u[o])&&t(i,o,e);return n}function Z(n){return ko(n,qo),n}function V(n){var t,e;return function(r,i,u){var o,a=n[u].update,l=a.length;for(u!=e&&(e=u,t=0),i>=t&&(t=i+1);!(o=a[t])&&++t<l;);return o}}function X(n,t,e){function r(){var t=this[o];t&&(this.removeEventListener(n,t,t.$),delete this[o])}function i(){var i=l(t,co(arguments));r.call(this),this.addEventListener(n,this[o]=i,i.$=e),i._=t}function u(){var t,e=new RegExp("^__on([^.]+)"+ao.requote(n)+"$");for(var r in this)if(t=r.match(e)){var i=this[r];this.removeEventListener(t[1],i,i.$),delete this[r]}}var o="__on"+n,a=n.indexOf("."),l=$;a>0&&(n=n.slice(0,a));var c=To.get(n);return c&&(n=c,l=B),a?t?i:r:t?b:u}function $(n,t){return function(e){var r=ao.event;ao.event=e,t[0]=this.__data__;try{n.apply(this,t)}finally{ao.event=r}}}function B(n,t){var e=$(n,t);return function(n){var t=this,r=n.relatedTarget;r&&(r===t||8&r.compareDocumentPosition(t))||e.call(t,n)}}function W(e){var r=".dragsuppress-"+ ++Do,i="click"+r,u=ao.select(t(e)).on("touchmove"+r,S).on("dragstart"+r,S).on("selectstart"+r,S);if(null==Ro&&(Ro="onselectstart"in e?!1:x(e.style,"userSelect")),Ro){var o=n(e).style,a=o[Ro];o[Ro]="none"}return function(n){if(u.on(r,null),Ro&&(o[Ro]=a),n){var t=function(){u.on(i,null)};u.on(i,function(){S(),t()},!0),setTimeout(t,0)}}}function J(n,e){e.changedTouches&&(e=e.changedTouches[0]);var r=n.ownerSVGElement||n;if(r.createSVGPoint){var i=r.createSVGPoint();if(0>Po){var u=t(n);if(u.scrollX||u.scrollY){r=ao.select("body").append("svg").style({position:"absolute",top:0,left:0,margin:0,padding:0,border:"none"},"important");var o=r[0][0].getScreenCTM();Po=!(o.f||o.e),r.remove()}}return Po?(i.x=e.pageX,i.y=e.pageY):(i.x=e.clientX,i.y=e.clientY),i=i.matrixTransform(n.getScreenCTM().inverse()),[i.x,i.y]}var a=n.getBoundingClientRect();return[e.clientX-a.left-n.clientLeft,e.clientY-a.top-n.clientTop]}function G(){return ao.event.changedTouches[0].identifier}function K(n){return n>0?1:0>n?-1:0}function Q(n,t,e){return(t[0]-n[0])*(e[1]-n[1])-(t[1]-n[1])*(e[0]-n[0])}function nn(n){return n>1?0:-1>n?Fo:Math.acos(n)}function tn(n){return n>1?Io:-1>n?-Io:Math.asin(n)}function en(n){return((n=Math.exp(n))-1/n)/2}function rn(n){return((n=Math.exp(n))+1/n)/2}function un(n){return((n=Math.exp(2*n))-1)/(n+1)}function on(n){return(n=Math.sin(n/2))*n}function an(){}function ln(n,t,e){return this instanceof ln?(this.h=+n,this.s=+t,void(this.l=+e)):arguments.length<2?n instanceof ln?new ln(n.h,n.s,n.l):_n(""+n,wn,ln):new ln(n,t,e)}function cn(n,t,e){function r(n){return n>360?n-=360:0>n&&(n+=360),60>n?u+(o-u)*n/60:180>n?o:240>n?u+(o-u)*(240-n)/60:u}function i(n){return Math.round(255*r(n))}var u,o;return n=isNaN(n)?0:(n%=360)<0?n+360:n,t=isNaN(t)?0:0>t?0:t>1?1:t,e=0>e?0:e>1?1:e,o=.5>=e?e*(1+t):e+t-e*t,u=2*e-o,new mn(i(n+120),i(n),i(n-120))}function fn(n,t,e){return this instanceof fn?(this.h=+n,this.c=+t,void(this.l=+e)):arguments.length<2?n instanceof fn?new fn(n.h,n.c,n.l):n instanceof hn?gn(n.l,n.a,n.b):gn((n=Sn((n=ao.rgb(n)).r,n.g,n.b)).l,n.a,n.b):new fn(n,t,e)}function sn(n,t,e){return isNaN(n)&&(n=0),isNaN(t)&&(t=0),new hn(e,Math.cos(n*=Yo)*t,Math.sin(n)*t)}function hn(n,t,e){return this instanceof hn?(this.l=+n,this.a=+t,void(this.b=+e)):arguments.length<2?n instanceof hn?new hn(n.l,n.a,n.b):n instanceof fn?sn(n.h,n.c,n.l):Sn((n=mn(n)).r,n.g,n.b):new hn(n,t,e)}function pn(n,t,e){var r=(n+16)/116,i=r+t/500,u=r-e/200;return i=vn(i)*na,r=vn(r)*ta,u=vn(u)*ea,new mn(yn(3.2404542*i-1.5371385*r-.4985314*u),yn(-.969266*i+1.8760108*r+.041556*u),yn(.0556434*i-.2040259*r+1.0572252*u))}function gn(n,t,e){return n>0?new fn(Math.atan2(e,t)*Zo,Math.sqrt(t*t+e*e),n):new fn(NaN,NaN,n)}function vn(n){return n>.206893034?n*n*n:(n-4/29)/7.787037}function dn(n){return n>.008856?Math.pow(n,1/3):7.787037*n+4/29}function yn(n){return Math.round(255*(.00304>=n?12.92*n:1.055*Math.pow(n,1/2.4)-.055))}function mn(n,t,e){return this instanceof mn?(this.r=~~n,this.g=~~t,void(this.b=~~e)):arguments.length<2?n instanceof mn?new mn(n.r,n.g,n.b):_n(""+n,mn,cn):new mn(n,t,e)}function Mn(n){return new mn(n>>16,n>>8&255,255&n)}function xn(n){return Mn(n)+""}function bn(n){return 16>n?"0"+Math.max(0,n).toString(16):Math.min(255,n).toString(16)}function _n(n,t,e){var r,i,u,o=0,a=0,l=0;if(r=/([a-z]+)\((.*)\)/.exec(n=n.toLowerCase()))switch(i=r[2].split(","),r[1]){case"hsl":return e(parseFloat(i[0]),parseFloat(i[1])/100,parseFloat(i[2])/100);case"rgb":return t(Nn(i[0]),Nn(i[1]),Nn(i[2]))}return(u=ua.get(n))?t(u.r,u.g,u.b):(null==n||"#"!==n.charAt(0)||isNaN(u=parseInt(n.slice(1),16))||(4===n.length?(o=(3840&u)>>4,o=o>>4|o,a=240&u,a=a>>4|a,l=15&u,l=l<<4|l):7===n.length&&(o=(16711680&u)>>16,a=(65280&u)>>8,l=255&u)),t(o,a,l))}function wn(n,t,e){var r,i,u=Math.min(n/=255,t/=255,e/=255),o=Math.max(n,t,e),a=o-u,l=(o+u)/2;return a?(i=.5>l?a/(o+u):a/(2-o-u),r=n==o?(t-e)/a+(e>t?6:0):t==o?(e-n)/a+2:(n-t)/a+4,r*=60):(r=NaN,i=l>0&&1>l?0:r),new ln(r,i,l)}function Sn(n,t,e){n=kn(n),t=kn(t),e=kn(e);var r=dn((.4124564*n+.3575761*t+.1804375*e)/na),i=dn((.2126729*n+.7151522*t+.072175*e)/ta),u=dn((.0193339*n+.119192*t+.9503041*e)/ea);return hn(116*i-16,500*(r-i),200*(i-u))}function kn(n){return(n/=255)<=.04045?n/12.92:Math.pow((n+.055)/1.055,2.4)}function Nn(n){var t=parseFloat(n);return"%"===n.charAt(n.length-1)?Math.round(2.55*t):t}function En(n){return"function"==typeof n?n:function(){return n}}function An(n){return function(t,e,r){return 2===arguments.length&&"function"==typeof e&&(r=e,e=null),Cn(t,e,n,r)}}function Cn(n,t,e,r){function i(){var n,t=l.status;if(!t&&Ln(l)||t>=200&&300>t||304===t){try{n=e.call(u,l)}catch(r){return void o.error.call(u,r)}o.load.call(u,n)}else o.error.call(u,l)}var u={},o=ao.dispatch("beforesend","progress","load","error"),a={},l=new XMLHttpRequest,c=null;return!this.XDomainRequest||"withCredentials"in l||!/^(http(s)?:)?\/\//.test(n)||(l=new XDomainRequest),"onload"in l?l.onload=l.onerror=i:l.onreadystatechange=function(){l.readyState>3&&i()},l.onprogress=function(n){var t=ao.event;ao.event=n;try{o.progress.call(u,l)}finally{ao.event=t}},u.header=function(n,t){return n=(n+"").toLowerCase(),arguments.length<2?a[n]:(null==t?delete a[n]:a[n]=t+"",u)},u.mimeType=function(n){return arguments.length?(t=null==n?null:n+"",u):t},u.responseType=function(n){return arguments.length?(c=n,u):c},u.response=function(n){return e=n,u},["get","post"].forEach(function(n){u[n]=function(){return u.send.apply(u,[n].concat(co(arguments)))}}),u.send=function(e,r,i){if(2===arguments.length&&"function"==typeof r&&(i=r,r=null),l.open(e,n,!0),null==t||"accept"in a||(a.accept=t+",*/*"),l.setRequestHeader)for(var f in a)l.setRequestHeader(f,a[f]);return null!=t&&l.overrideMimeType&&l.overrideMimeType(t),null!=c&&(l.responseType=c),null!=i&&u.on("error",i).on("load",function(n){i(null,n)}),o.beforesend.call(u,l),l.send(null==r?null:r),u},u.abort=function(){return l.abort(),u},ao.rebind(u,o,"on"),null==r?u:u.get(zn(r))}function zn(n){return 1===n.length?function(t,e){n(null==t?e:null)}:n}function Ln(n){var t=n.responseType;return t&&"text"!==t?n.response:n.responseText}function qn(n,t,e){var r=arguments.length;2>r&&(t=0),3>r&&(e=Date.now());var i=e+t,u={c:n,t:i,n:null};return aa?aa.n=u:oa=u,aa=u,la||(ca=clearTimeout(ca),la=1,fa(Tn)),u}function Tn(){var n=Rn(),t=Dn()-n;t>24?(isFinite(t)&&(clearTimeout(ca),ca=setTimeout(Tn,t)),la=0):(la=1,fa(Tn))}function Rn(){for(var n=Date.now(),t=oa;t;)n>=t.t&&t.c(n-t.t)&&(t.c=null),t=t.n;return n}function Dn(){for(var n,t=oa,e=1/0;t;)t.c?(t.t<e&&(e=t.t),t=(n=t).n):t=n?n.n=t.n:oa=t.n;return aa=n,e}function Pn(n,t){return t-(n?Math.ceil(Math.log(n)/Math.LN10):1)}function Un(n,t){var e=Math.pow(10,3*xo(8-t));return{scale:t>8?function(n){return n/e}:function(n){return n*e},symbol:n}}function jn(n){var t=n.decimal,e=n.thousands,r=n.grouping,i=n.currency,u=r&&e?function(n,t){for(var i=n.length,u=[],o=0,a=r[0],l=0;i>0&&a>0&&(l+a+1>t&&(a=Math.max(1,t-l)),u.push(n.substring(i-=a,i+a)),!((l+=a+1)>t));)a=r[o=(o+1)%r.length];return u.reverse().join(e)}:m;return function(n){var e=ha.exec(n),r=e[1]||" ",o=e[2]||">",a=e[3]||"-",l=e[4]||"",c=e[5],f=+e[6],s=e[7],h=e[8],p=e[9],g=1,v="",d="",y=!1,m=!0;switch(h&&(h=+h.substring(1)),(c||"0"===r&&"="===o)&&(c=r="0",o="="),p){case"n":s=!0,p="g";break;case"%":g=100,d="%",p="f";break;case"p":g=100,d="%",p="r";break;case"b":case"o":case"x":case"X":"#"===l&&(v="0"+p.toLowerCase());case"c":m=!1;case"d":y=!0,h=0;break;case"s":g=-1,p="r"}"$"===l&&(v=i[0],d=i[1]),"r"!=p||h||(p="g"),null!=h&&("g"==p?h=Math.max(1,Math.min(21,h)):"e"!=p&&"f"!=p||(h=Math.max(0,Math.min(20,h)))),p=pa.get(p)||Fn;var M=c&&s;return function(n){var e=d;if(y&&n%1)return"";var i=0>n||0===n&&0>1/n?(n=-n,"-"):"-"===a?"":a;if(0>g){var l=ao.formatPrefix(n,h);n=l.scale(n),e=l.symbol+d}else n*=g;n=p(n,h);var x,b,_=n.lastIndexOf(".");if(0>_){var w=m?n.lastIndexOf("e"):-1;0>w?(x=n,b=""):(x=n.substring(0,w),b=n.substring(w))}else x=n.substring(0,_),b=t+n.substring(_+1);!c&&s&&(x=u(x,1/0));var S=v.length+x.length+b.length+(M?0:i.length),k=f>S?new Array(S=f-S+1).join(r):"";return M&&(x=u(k+x,k.length?f-b.length:1/0)),i+=v,n=x+b,("<"===o?i+n+k:">"===o?k+i+n:"^"===o?k.substring(0,S>>=1)+i+n+k.substring(S):i+(M?n:k+n))+e}}}function Fn(n){return n+""}function Hn(){this._=new Date(arguments.length>1?Date.UTC.apply(this,arguments):arguments[0])}function On(n,t,e){function r(t){var e=n(t),r=u(e,1);return r-t>t-e?e:r}function i(e){return t(e=n(new va(e-1)),1),e}function u(n,e){return t(n=new va(+n),e),n}function o(n,r,u){var o=i(n),a=[];if(u>1)for(;r>o;)e(o)%u||a.push(new Date(+o)),t(o,1);else for(;r>o;)a.push(new Date(+o)),t(o,1);return a}function a(n,t,e){try{va=Hn;var r=new Hn;return r._=n,o(r,t,e)}finally{va=Date}}n.floor=n,n.round=r,n.ceil=i,n.offset=u,n.range=o;var l=n.utc=In(n);return l.floor=l,l.round=In(r),l.ceil=In(i),l.offset=In(u),l.range=a,n}function In(n){return function(t,e){try{va=Hn;var r=new Hn;return r._=t,n(r,e)._}finally{va=Date}}}function Yn(n){function t(n){function t(t){for(var e,i,u,o=[],a=-1,l=0;++a<r;)37===n.charCodeAt(a)&&(o.push(n.slice(l,a)),null!=(i=ya[e=n.charAt(++a)])&&(e=n.charAt(++a)),(u=A[e])&&(e=u(t,null==i?"e"===e?" ":"0":i)),o.push(e),l=a+1);return o.push(n.slice(l,a)),o.join("")}var r=n.length;return t.parse=function(t){var r={y:1900,m:0,d:1,H:0,M:0,S:0,L:0,Z:null},i=e(r,n,t,0);if(i!=t.length)return null;"p"in r&&(r.H=r.H%12+12*r.p);var u=null!=r.Z&&va!==Hn,o=new(u?Hn:va);return"j"in r?o.setFullYear(r.y,0,r.j):"W"in r||"U"in r?("w"in r||(r.w="W"in r?1:0),o.setFullYear(r.y,0,1),o.setFullYear(r.y,0,"W"in r?(r.w+6)%7+7*r.W-(o.getDay()+5)%7:r.w+7*r.U-(o.getDay()+6)%7)):o.setFullYear(r.y,r.m,r.d),o.setHours(r.H+(r.Z/100|0),r.M+r.Z%100,r.S,r.L),u?o._:o},t.toString=function(){return n},t}function e(n,t,e,r){for(var i,u,o,a=0,l=t.length,c=e.length;l>a;){if(r>=c)return-1;if(i=t.charCodeAt(a++),37===i){if(o=t.charAt(a++),u=C[o in ya?t.charAt(a++):o],!u||(r=u(n,e,r))<0)return-1}else if(i!=e.charCodeAt(r++))return-1}return r}function r(n,t,e){_.lastIndex=0;var r=_.exec(t.slice(e));return r?(n.w=w.get(r[0].toLowerCase()),e+r[0].length):-1}function i(n,t,e){x.lastIndex=0;var r=x.exec(t.slice(e));return r?(n.w=b.get(r[0].toLowerCase()),e+r[0].length):-1}function u(n,t,e){N.lastIndex=0;var r=N.exec(t.slice(e));return r?(n.m=E.get(r[0].toLowerCase()),e+r[0].length):-1}function o(n,t,e){S.lastIndex=0;var r=S.exec(t.slice(e));return r?(n.m=k.get(r[0].toLowerCase()),e+r[0].length):-1}function a(n,t,r){return e(n,A.c.toString(),t,r)}function l(n,t,r){return e(n,A.x.toString(),t,r)}function c(n,t,r){return e(n,A.X.toString(),t,r)}function f(n,t,e){var r=M.get(t.slice(e,e+=2).toLowerCase());return null==r?-1:(n.p=r,e)}var s=n.dateTime,h=n.date,p=n.time,g=n.periods,v=n.days,d=n.shortDays,y=n.months,m=n.shortMonths;t.utc=function(n){function e(n){try{va=Hn;var t=new va;return t._=n,r(t)}finally{va=Date}}var r=t(n);return e.parse=function(n){try{va=Hn;var t=r.parse(n);return t&&t._}finally{va=Date}},e.toString=r.toString,e},t.multi=t.utc.multi=ct;var M=ao.map(),x=Vn(v),b=Xn(v),_=Vn(d),w=Xn(d),S=Vn(y),k=Xn(y),N=Vn(m),E=Xn(m);g.forEach(function(n,t){M.set(n.toLowerCase(),t)});var A={a:function(n){return d[n.getDay()]},A:function(n){return v[n.getDay()]},b:function(n){return m[n.getMonth()]},B:function(n){return y[n.getMonth()]},c:t(s),d:function(n,t){return Zn(n.getDate(),t,2)},e:function(n,t){return Zn(n.getDate(),t,2)},H:function(n,t){return Zn(n.getHours(),t,2)},I:function(n,t){return Zn(n.getHours()%12||12,t,2)},j:function(n,t){return Zn(1+ga.dayOfYear(n),t,3)},L:function(n,t){return Zn(n.getMilliseconds(),t,3)},m:function(n,t){return Zn(n.getMonth()+1,t,2)},M:function(n,t){return Zn(n.getMinutes(),t,2)},p:function(n){return g[+(n.getHours()>=12)]},S:function(n,t){return Zn(n.getSeconds(),t,2)},U:function(n,t){return Zn(ga.sundayOfYear(n),t,2)},w:function(n){return n.getDay()},W:function(n,t){return Zn(ga.mondayOfYear(n),t,2)},x:t(h),X:t(p),y:function(n,t){return Zn(n.getFullYear()%100,t,2)},Y:function(n,t){return Zn(n.getFullYear()%1e4,t,4)},Z:at,"%":function(){return"%"}},C={a:r,A:i,b:u,B:o,c:a,d:tt,e:tt,H:rt,I:rt,j:et,L:ot,m:nt,M:it,p:f,S:ut,U:Bn,w:$n,W:Wn,x:l,X:c,y:Gn,Y:Jn,Z:Kn,"%":lt};return t}function Zn(n,t,e){var r=0>n?"-":"",i=(r?-n:n)+"",u=i.length;return r+(e>u?new Array(e-u+1).join(t)+i:i)}function Vn(n){return new RegExp("^(?:"+n.map(ao.requote).join("|")+")","i")}function Xn(n){for(var t=new c,e=-1,r=n.length;++e<r;)t.set(n[e].toLowerCase(),e);return t}function $n(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+1));return r?(n.w=+r[0],e+r[0].length):-1}function Bn(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e));return r?(n.U=+r[0],e+r[0].length):-1}function Wn(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e));return r?(n.W=+r[0],e+r[0].length):-1}function Jn(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+4));return r?(n.y=+r[0],e+r[0].length):-1}function Gn(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+2));return r?(n.y=Qn(+r[0]),e+r[0].length):-1}function Kn(n,t,e){return/^[+-]\d{4}$/.test(t=t.slice(e,e+5))?(n.Z=-t,e+5):-1}function Qn(n){return n+(n>68?1900:2e3)}function nt(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+2));return r?(n.m=r[0]-1,e+r[0].length):-1}function tt(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+2));return r?(n.d=+r[0],e+r[0].length):-1}function et(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+3));return r?(n.j=+r[0],e+r[0].length):-1}function rt(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+2));return r?(n.H=+r[0],e+r[0].length):-1}function it(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+2));return r?(n.M=+r[0],e+r[0].length):-1}function ut(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+2));return r?(n.S=+r[0],e+r[0].length):-1}function ot(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+3));return r?(n.L=+r[0],e+r[0].length):-1}function at(n){var t=n.getTimezoneOffset(),e=t>0?"-":"+",r=xo(t)/60|0,i=xo(t)%60;return e+Zn(r,"0",2)+Zn(i,"0",2)}function lt(n,t,e){Ma.lastIndex=0;var r=Ma.exec(t.slice(e,e+1));return r?e+r[0].length:-1}function ct(n){for(var t=n.length,e=-1;++e<t;)n[e][0]=this(n[e][0]);return function(t){for(var e=0,r=n[e];!r[1](t);)r=n[++e];return r[0](t)}}function ft(){}function st(n,t,e){var r=e.s=n+t,i=r-n,u=r-i;e.t=n-u+(t-i)}function ht(n,t){n&&wa.hasOwnProperty(n.type)&&wa[n.type](n,t)}function pt(n,t,e){var r,i=-1,u=n.length-e;for(t.lineStart();++i<u;)r=n[i],t.point(r[0],r[1],r[2]);t.lineEnd()}function gt(n,t){var e=-1,r=n.length;for(t.polygonStart();++e<r;)pt(n[e],t,1);t.polygonEnd()}function vt(){function n(n,t){n*=Yo,t=t*Yo/2+Fo/4;var e=n-r,o=e>=0?1:-1,a=o*e,l=Math.cos(t),c=Math.sin(t),f=u*c,s=i*l+f*Math.cos(a),h=f*o*Math.sin(a);ka.add(Math.atan2(h,s)),r=n,i=l,u=c}var t,e,r,i,u;Na.point=function(o,a){Na.point=n,r=(t=o)*Yo,i=Math.cos(a=(e=a)*Yo/2+Fo/4),u=Math.sin(a)},Na.lineEnd=function(){n(t,e)}}function dt(n){var t=n[0],e=n[1],r=Math.cos(e);return[r*Math.cos(t),r*Math.sin(t),Math.sin(e)]}function yt(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]}function mt(n,t){return[n[1]*t[2]-n[2]*t[1],n[2]*t[0]-n[0]*t[2],n[0]*t[1]-n[1]*t[0]]}function Mt(n,t){n[0]+=t[0],n[1]+=t[1],n[2]+=t[2]}function xt(n,t){return[n[0]*t,n[1]*t,n[2]*t]}function bt(n){var t=Math.sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]);n[0]/=t,n[1]/=t,n[2]/=t}function _t(n){return[Math.atan2(n[1],n[0]),tn(n[2])]}function wt(n,t){return xo(n[0]-t[0])<Uo&&xo(n[1]-t[1])<Uo}function St(n,t){n*=Yo;var e=Math.cos(t*=Yo);kt(e*Math.cos(n),e*Math.sin(n),Math.sin(t))}function kt(n,t,e){++Ea,Ca+=(n-Ca)/Ea,za+=(t-za)/Ea,La+=(e-La)/Ea}function Nt(){function n(n,i){n*=Yo;var u=Math.cos(i*=Yo),o=u*Math.cos(n),a=u*Math.sin(n),l=Math.sin(i),c=Math.atan2(Math.sqrt((c=e*l-r*a)*c+(c=r*o-t*l)*c+(c=t*a-e*o)*c),t*o+e*a+r*l);Aa+=c,qa+=c*(t+(t=o)),Ta+=c*(e+(e=a)),Ra+=c*(r+(r=l)),kt(t,e,r)}var t,e,r;ja.point=function(i,u){i*=Yo;var o=Math.cos(u*=Yo);t=o*Math.cos(i),e=o*Math.sin(i),r=Math.sin(u),ja.point=n,kt(t,e,r)}}function Et(){ja.point=St}function At(){function n(n,t){n*=Yo;var e=Math.cos(t*=Yo),o=e*Math.cos(n),a=e*Math.sin(n),l=Math.sin(t),c=i*l-u*a,f=u*o-r*l,s=r*a-i*o,h=Math.sqrt(c*c+f*f+s*s),p=r*o+i*a+u*l,g=h&&-nn(p)/h,v=Math.atan2(h,p);Da+=g*c,Pa+=g*f,Ua+=g*s,Aa+=v,qa+=v*(r+(r=o)),Ta+=v*(i+(i=a)),Ra+=v*(u+(u=l)),kt(r,i,u)}var t,e,r,i,u;ja.point=function(o,a){t=o,e=a,ja.point=n,o*=Yo;var l=Math.cos(a*=Yo);r=l*Math.cos(o),i=l*Math.sin(o),u=Math.sin(a),kt(r,i,u)},ja.lineEnd=function(){n(t,e),ja.lineEnd=Et,ja.point=St}}function Ct(n,t){function e(e,r){return e=n(e,r),t(e[0],e[1])}return n.invert&&t.invert&&(e.invert=function(e,r){return e=t.invert(e,r),e&&n.invert(e[0],e[1])}),e}function zt(){return!0}function Lt(n,t,e,r,i){var u=[],o=[];if(n.forEach(function(n){if(!((t=n.length-1)<=0)){var t,e=n[0],r=n[t];if(wt(e,r)){i.lineStart();for(var a=0;t>a;++a)i.point((e=n[a])[0],e[1]);return void i.lineEnd()}var l=new Tt(e,n,null,!0),c=new Tt(e,null,l,!1);l.o=c,u.push(l),o.push(c),l=new Tt(r,n,null,!1),c=new Tt(r,null,l,!0),l.o=c,u.push(l),o.push(c)}}),o.sort(t),qt(u),qt(o),u.length){for(var a=0,l=e,c=o.length;c>a;++a)o[a].e=l=!l;for(var f,s,h=u[0];;){for(var p=h,g=!0;p.v;)if((p=p.n)===h)return;f=p.z,i.lineStart();do{if(p.v=p.o.v=!0,p.e){if(g)for(var a=0,c=f.length;c>a;++a)i.point((s=f[a])[0],s[1]);else r(p.x,p.n.x,1,i);p=p.n}else{if(g){f=p.p.z;for(var a=f.length-1;a>=0;--a)i.point((s=f[a])[0],s[1])}else r(p.x,p.p.x,-1,i);p=p.p}p=p.o,f=p.z,g=!g}while(!p.v);i.lineEnd()}}}function qt(n){if(t=n.length){for(var t,e,r=0,i=n[0];++r<t;)i.n=e=n[r],e.p=i,i=e;i.n=e=n[0],e.p=i}}function Tt(n,t,e,r){this.x=n,this.z=t,this.o=e,this.e=r,this.v=!1,this.n=this.p=null}function Rt(n,t,e,r){return function(i,u){function o(t,e){var r=i(t,e);n(t=r[0],e=r[1])&&u.point(t,e)}function a(n,t){var e=i(n,t);d.point(e[0],e[1])}function l(){m.point=a,d.lineStart()}function c(){m.point=o,d.lineEnd()}function f(n,t){v.push([n,t]);var e=i(n,t);x.point(e[0],e[1])}function s(){x.lineStart(),v=[]}function h(){f(v[0][0],v[0][1]),x.lineEnd();var n,t=x.clean(),e=M.buffer(),r=e.length;if(v.pop(),g.push(v),v=null,r)if(1&t){n=e[0];var i,r=n.length-1,o=-1;if(r>0){for(b||(u.polygonStart(),b=!0),u.lineStart();++o<r;)u.point((i=n[o])[0],i[1]);u.lineEnd()}}else r>1&&2&t&&e.push(e.pop().concat(e.shift())),p.push(e.filter(Dt))}var p,g,v,d=t(u),y=i.invert(r[0],r[1]),m={point:o,lineStart:l,lineEnd:c,polygonStart:function(){m.point=f,m.lineStart=s,m.lineEnd=h,p=[],g=[]},polygonEnd:function(){m.point=o,m.lineStart=l,m.lineEnd=c,p=ao.merge(p);var n=Ot(y,g);p.length?(b||(u.polygonStart(),b=!0),Lt(p,Ut,n,e,u)):n&&(b||(u.polygonStart(),b=!0),u.lineStart(),e(null,null,1,u),u.lineEnd()),b&&(u.polygonEnd(),b=!1),p=g=null},sphere:function(){u.polygonStart(),u.lineStart(),e(null,null,1,u),u.lineEnd(),u.polygonEnd()}},M=Pt(),x=t(M),b=!1;return m}}function Dt(n){return n.length>1}function Pt(){var n,t=[];return{lineStart:function(){t.push(n=[])},point:function(t,e){n.push([t,e])},lineEnd:b,buffer:function(){var e=t;return t=[],n=null,e},rejoin:function(){t.length>1&&t.push(t.pop().concat(t.shift()))}}}function Ut(n,t){return((n=n.x)[0]<0?n[1]-Io-Uo:Io-n[1])-((t=t.x)[0]<0?t[1]-Io-Uo:Io-t[1])}function jt(n){var t,e=NaN,r=NaN,i=NaN;return{lineStart:function(){n.lineStart(),t=1},point:function(u,o){var a=u>0?Fo:-Fo,l=xo(u-e);xo(l-Fo)<Uo?(n.point(e,r=(r+o)/2>0?Io:-Io),n.point(i,r),n.lineEnd(),n.lineStart(),n.point(a,r),n.point(u,r),t=0):i!==a&&l>=Fo&&(xo(e-i)<Uo&&(e-=i*Uo),xo(u-a)<Uo&&(u-=a*Uo),r=Ft(e,r,u,o),n.point(i,r),n.lineEnd(),n.lineStart(),n.point(a,r),t=0),n.point(e=u,r=o),i=a},lineEnd:function(){n.lineEnd(),e=r=NaN},clean:function(){return 2-t}}}function Ft(n,t,e,r){var i,u,o=Math.sin(n-e);return xo(o)>Uo?Math.atan((Math.sin(t)*(u=Math.cos(r))*Math.sin(e)-Math.sin(r)*(i=Math.cos(t))*Math.sin(n))/(i*u*o)):(t+r)/2}function Ht(n,t,e,r){var i;if(null==n)i=e*Io,r.point(-Fo,i),r.point(0,i),r.point(Fo,i),r.point(Fo,0),r.point(Fo,-i),r.point(0,-i),r.point(-Fo,-i),r.point(-Fo,0),r.point(-Fo,i);else if(xo(n[0]-t[0])>Uo){var u=n[0]<t[0]?Fo:-Fo;i=e*u/2,r.point(-u,i),r.point(0,i),r.point(u,i)}else r.point(t[0],t[1])}function Ot(n,t){var e=n[0],r=n[1],i=[Math.sin(e),-Math.cos(e),0],u=0,o=0;ka.reset();for(var a=0,l=t.length;l>a;++a){var c=t[a],f=c.length;if(f)for(var s=c[0],h=s[0],p=s[1]/2+Fo/4,g=Math.sin(p),v=Math.cos(p),d=1;;){d===f&&(d=0),n=c[d];var y=n[0],m=n[1]/2+Fo/4,M=Math.sin(m),x=Math.cos(m),b=y-h,_=b>=0?1:-1,w=_*b,S=w>Fo,k=g*M;if(ka.add(Math.atan2(k*_*Math.sin(w),v*x+k*Math.cos(w))),u+=S?b+_*Ho:b,S^h>=e^y>=e){var N=mt(dt(s),dt(n));bt(N);var E=mt(i,N);bt(E);var A=(S^b>=0?-1:1)*tn(E[2]);(r>A||r===A&&(N[0]||N[1]))&&(o+=S^b>=0?1:-1)}if(!d++)break;h=y,g=M,v=x,s=n}}return(-Uo>u||Uo>u&&0>ka)^1&o}function It(n){function t(n,t){return Math.cos(n)*Math.cos(t)>u}function e(n){var e,u,l,c,f;return{lineStart:function(){c=l=!1,f=1},point:function(s,h){var p,g=[s,h],v=t(s,h),d=o?v?0:i(s,h):v?i(s+(0>s?Fo:-Fo),h):0;if(!e&&(c=l=v)&&n.lineStart(),v!==l&&(p=r(e,g),(wt(e,p)||wt(g,p))&&(g[0]+=Uo,g[1]+=Uo,v=t(g[0],g[1]))),v!==l)f=0,v?(n.lineStart(),p=r(g,e),n.point(p[0],p[1])):(p=r(e,g),n.point(p[0],p[1]),n.lineEnd()),e=p;else if(a&&e&&o^v){var y;d&u||!(y=r(g,e,!0))||(f=0,o?(n.lineStart(),n.point(y[0][0],y[0][1]),n.point(y[1][0],y[1][1]),n.lineEnd()):(n.point(y[1][0],y[1][1]),n.lineEnd(),n.lineStart(),n.point(y[0][0],y[0][1])))}!v||e&&wt(e,g)||n.point(g[0],g[1]),e=g,l=v,u=d},lineEnd:function(){l&&n.lineEnd(),e=null},clean:function(){return f|(c&&l)<<1}}}function r(n,t,e){var r=dt(n),i=dt(t),o=[1,0,0],a=mt(r,i),l=yt(a,a),c=a[0],f=l-c*c;if(!f)return!e&&n;var s=u*l/f,h=-u*c/f,p=mt(o,a),g=xt(o,s),v=xt(a,h);Mt(g,v);var d=p,y=yt(g,d),m=yt(d,d),M=y*y-m*(yt(g,g)-1);if(!(0>M)){var x=Math.sqrt(M),b=xt(d,(-y-x)/m);if(Mt(b,g),b=_t(b),!e)return b;var _,w=n[0],S=t[0],k=n[1],N=t[1];w>S&&(_=w,w=S,S=_);var E=S-w,A=xo(E-Fo)<Uo,C=A||Uo>E;if(!A&&k>N&&(_=k,k=N,N=_),C?A?k+N>0^b[1]<(xo(b[0]-w)<Uo?k:N):k<=b[1]&&b[1]<=N:E>Fo^(w<=b[0]&&b[0]<=S)){var z=xt(d,(-y+x)/m);return Mt(z,g),[b,_t(z)]}}}function i(t,e){var r=o?n:Fo-n,i=0;return-r>t?i|=1:t>r&&(i|=2),-r>e?i|=4:e>r&&(i|=8),i}var u=Math.cos(n),o=u>0,a=xo(u)>Uo,l=ve(n,6*Yo);return Rt(t,e,l,o?[0,-n]:[-Fo,n-Fo])}function Yt(n,t,e,r){return function(i){var u,o=i.a,a=i.b,l=o.x,c=o.y,f=a.x,s=a.y,h=0,p=1,g=f-l,v=s-c;if(u=n-l,g||!(u>0)){if(u/=g,0>g){if(h>u)return;p>u&&(p=u)}else if(g>0){if(u>p)return;u>h&&(h=u)}if(u=e-l,g||!(0>u)){if(u/=g,0>g){if(u>p)return;u>h&&(h=u)}else if(g>0){if(h>u)return;p>u&&(p=u)}if(u=t-c,v||!(u>0)){if(u/=v,0>v){if(h>u)return;p>u&&(p=u)}else if(v>0){if(u>p)return;u>h&&(h=u)}if(u=r-c,v||!(0>u)){if(u/=v,0>v){if(u>p)return;u>h&&(h=u)}else if(v>0){if(h>u)return;p>u&&(p=u)}return h>0&&(i.a={x:l+h*g,y:c+h*v}),1>p&&(i.b={x:l+p*g,y:c+p*v}),i}}}}}}function Zt(n,t,e,r){function i(r,i){return xo(r[0]-n)<Uo?i>0?0:3:xo(r[0]-e)<Uo?i>0?2:1:xo(r[1]-t)<Uo?i>0?1:0:i>0?3:2}function u(n,t){return o(n.x,t.x)}function o(n,t){var e=i(n,1),r=i(t,1);return e!==r?e-r:0===e?t[1]-n[1]:1===e?n[0]-t[0]:2===e?n[1]-t[1]:t[0]-n[0]}return function(a){function l(n){for(var t=0,e=d.length,r=n[1],i=0;e>i;++i)for(var u,o=1,a=d[i],l=a.length,c=a[0];l>o;++o)u=a[o],c[1]<=r?u[1]>r&&Q(c,u,n)>0&&++t:u[1]<=r&&Q(c,u,n)<0&&--t,c=u;return 0!==t}function c(u,a,l,c){var f=0,s=0;if(null==u||(f=i(u,l))!==(s=i(a,l))||o(u,a)<0^l>0){do c.point(0===f||3===f?n:e,f>1?r:t);while((f=(f+l+4)%4)!==s)}else c.point(a[0],a[1])}function f(i,u){return i>=n&&e>=i&&u>=t&&r>=u}function s(n,t){f(n,t)&&a.point(n,t)}function h(){C.point=g,d&&d.push(y=[]),S=!0,w=!1,b=_=NaN}function p(){v&&(g(m,M),x&&w&&E.rejoin(),v.push(E.buffer())),C.point=s,w&&a.lineEnd()}function g(n,t){n=Math.max(-Ha,Math.min(Ha,n)),t=Math.max(-Ha,Math.min(Ha,t));var e=f(n,t);if(d&&y.push([n,t]),S)m=n,M=t,x=e,S=!1,e&&(a.lineStart(),a.point(n,t));else if(e&&w)a.point(n,t);else{var r={a:{x:b,y:_},b:{x:n,y:t}};A(r)?(w||(a.lineStart(),a.point(r.a.x,r.a.y)),a.point(r.b.x,r.b.y),e||a.lineEnd(),k=!1):e&&(a.lineStart(),a.point(n,t),k=!1)}b=n,_=t,w=e}var v,d,y,m,M,x,b,_,w,S,k,N=a,E=Pt(),A=Yt(n,t,e,r),C={point:s,lineStart:h,lineEnd:p,polygonStart:function(){a=E,v=[],d=[],k=!0},polygonEnd:function(){a=N,v=ao.merge(v);var t=l([n,r]),e=k&&t,i=v.length;(e||i)&&(a.polygonStart(),e&&(a.lineStart(),c(null,null,1,a),a.lineEnd()),i&&Lt(v,u,t,c,a),a.polygonEnd()),v=d=y=null}};return C}}function Vt(n){var t=0,e=Fo/3,r=ae(n),i=r(t,e);return i.parallels=function(n){return arguments.length?r(t=n[0]*Fo/180,e=n[1]*Fo/180):[t/Fo*180,e/Fo*180]},i}function Xt(n,t){function e(n,t){var e=Math.sqrt(u-2*i*Math.sin(t))/i;return[e*Math.sin(n*=i),o-e*Math.cos(n)]}var r=Math.sin(n),i=(r+Math.sin(t))/2,u=1+r*(2*i-r),o=Math.sqrt(u)/i;return e.invert=function(n,t){var e=o-t;return[Math.atan2(n,e)/i,tn((u-(n*n+e*e)*i*i)/(2*i))]},e}function $t(){function n(n,t){Ia+=i*n-r*t,r=n,i=t}var t,e,r,i;$a.point=function(u,o){$a.point=n,t=r=u,e=i=o},$a.lineEnd=function(){n(t,e)}}function Bt(n,t){Ya>n&&(Ya=n),n>Va&&(Va=n),Za>t&&(Za=t),t>Xa&&(Xa=t)}function Wt(){function n(n,t){o.push("M",n,",",t,u)}function t(n,t){o.push("M",n,",",t),a.point=e}function e(n,t){o.push("L",n,",",t)}function r(){a.point=n}function i(){o.push("Z")}var u=Jt(4.5),o=[],a={point:n,lineStart:function(){a.point=t},lineEnd:r,polygonStart:function(){a.lineEnd=i},polygonEnd:function(){a.lineEnd=r,a.point=n},pointRadius:function(n){return u=Jt(n),a},result:function(){if(o.length){var n=o.join("");return o=[],n}}};return a}function Jt(n){return"m0,"+n+"a"+n+","+n+" 0 1,1 0,"+-2*n+"a"+n+","+n+" 0 1,1 0,"+2*n+"z"}function Gt(n,t){Ca+=n,za+=t,++La}function Kt(){function n(n,r){var i=n-t,u=r-e,o=Math.sqrt(i*i+u*u);qa+=o*(t+n)/2,Ta+=o*(e+r)/2,Ra+=o,Gt(t=n,e=r)}var t,e;Wa.point=function(r,i){Wa.point=n,Gt(t=r,e=i)}}function Qt(){Wa.point=Gt}function ne(){function n(n,t){var e=n-r,u=t-i,o=Math.sqrt(e*e+u*u);qa+=o*(r+n)/2,Ta+=o*(i+t)/2,Ra+=o,o=i*n-r*t,Da+=o*(r+n),Pa+=o*(i+t),Ua+=3*o,Gt(r=n,i=t)}var t,e,r,i;Wa.point=function(u,o){Wa.point=n,Gt(t=r=u,e=i=o)},Wa.lineEnd=function(){n(t,e)}}function te(n){function t(t,e){n.moveTo(t+o,e),n.arc(t,e,o,0,Ho)}function e(t,e){n.moveTo(t,e),a.point=r}function r(t,e){n.lineTo(t,e)}function i(){a.point=t}function u(){n.closePath()}var o=4.5,a={point:t,lineStart:function(){a.point=e},lineEnd:i,polygonStart:function(){a.lineEnd=u},polygonEnd:function(){a.lineEnd=i,a.point=t},pointRadius:function(n){return o=n,a},result:b};return a}function ee(n){function t(n){return(a?r:e)(n)}function e(t){return ue(t,function(e,r){e=n(e,r),t.point(e[0],e[1])})}function r(t){function e(e,r){e=n(e,r),t.point(e[0],e[1])}function r(){M=NaN,S.point=u,t.lineStart()}function u(e,r){var u=dt([e,r]),o=n(e,r);i(M,x,m,b,_,w,M=o[0],x=o[1],m=e,b=u[0],_=u[1],w=u[2],a,t),t.point(M,x)}function o(){S.point=e,t.lineEnd()}function l(){
+r(),S.point=c,S.lineEnd=f}function c(n,t){u(s=n,h=t),p=M,g=x,v=b,d=_,y=w,S.point=u}function f(){i(M,x,m,b,_,w,p,g,s,v,d,y,a,t),S.lineEnd=o,o()}var s,h,p,g,v,d,y,m,M,x,b,_,w,S={point:e,lineStart:r,lineEnd:o,polygonStart:function(){t.polygonStart(),S.lineStart=l},polygonEnd:function(){t.polygonEnd(),S.lineStart=r}};return S}function i(t,e,r,a,l,c,f,s,h,p,g,v,d,y){var m=f-t,M=s-e,x=m*m+M*M;if(x>4*u&&d--){var b=a+p,_=l+g,w=c+v,S=Math.sqrt(b*b+_*_+w*w),k=Math.asin(w/=S),N=xo(xo(w)-1)<Uo||xo(r-h)<Uo?(r+h)/2:Math.atan2(_,b),E=n(N,k),A=E[0],C=E[1],z=A-t,L=C-e,q=M*z-m*L;(q*q/x>u||xo((m*z+M*L)/x-.5)>.3||o>a*p+l*g+c*v)&&(i(t,e,r,a,l,c,A,C,N,b/=S,_/=S,w,d,y),y.point(A,C),i(A,C,N,b,_,w,f,s,h,p,g,v,d,y))}}var u=.5,o=Math.cos(30*Yo),a=16;return t.precision=function(n){return arguments.length?(a=(u=n*n)>0&&16,t):Math.sqrt(u)},t}function re(n){var t=ee(function(t,e){return n([t*Zo,e*Zo])});return function(n){return le(t(n))}}function ie(n){this.stream=n}function ue(n,t){return{point:t,sphere:function(){n.sphere()},lineStart:function(){n.lineStart()},lineEnd:function(){n.lineEnd()},polygonStart:function(){n.polygonStart()},polygonEnd:function(){n.polygonEnd()}}}function oe(n){return ae(function(){return n})()}function ae(n){function t(n){return n=a(n[0]*Yo,n[1]*Yo),[n[0]*h+l,c-n[1]*h]}function e(n){return n=a.invert((n[0]-l)/h,(c-n[1])/h),n&&[n[0]*Zo,n[1]*Zo]}function r(){a=Ct(o=se(y,M,x),u);var n=u(v,d);return l=p-n[0]*h,c=g+n[1]*h,i()}function i(){return f&&(f.valid=!1,f=null),t}var u,o,a,l,c,f,s=ee(function(n,t){return n=u(n,t),[n[0]*h+l,c-n[1]*h]}),h=150,p=480,g=250,v=0,d=0,y=0,M=0,x=0,b=Fa,_=m,w=null,S=null;return t.stream=function(n){return f&&(f.valid=!1),f=le(b(o,s(_(n)))),f.valid=!0,f},t.clipAngle=function(n){return arguments.length?(b=null==n?(w=n,Fa):It((w=+n)*Yo),i()):w},t.clipExtent=function(n){return arguments.length?(S=n,_=n?Zt(n[0][0],n[0][1],n[1][0],n[1][1]):m,i()):S},t.scale=function(n){return arguments.length?(h=+n,r()):h},t.translate=function(n){return arguments.length?(p=+n[0],g=+n[1],r()):[p,g]},t.center=function(n){return arguments.length?(v=n[0]%360*Yo,d=n[1]%360*Yo,r()):[v*Zo,d*Zo]},t.rotate=function(n){return arguments.length?(y=n[0]%360*Yo,M=n[1]%360*Yo,x=n.length>2?n[2]%360*Yo:0,r()):[y*Zo,M*Zo,x*Zo]},ao.rebind(t,s,"precision"),function(){return u=n.apply(this,arguments),t.invert=u.invert&&e,r()}}function le(n){return ue(n,function(t,e){n.point(t*Yo,e*Yo)})}function ce(n,t){return[n,t]}function fe(n,t){return[n>Fo?n-Ho:-Fo>n?n+Ho:n,t]}function se(n,t,e){return n?t||e?Ct(pe(n),ge(t,e)):pe(n):t||e?ge(t,e):fe}function he(n){return function(t,e){return t+=n,[t>Fo?t-Ho:-Fo>t?t+Ho:t,e]}}function pe(n){var t=he(n);return t.invert=he(-n),t}function ge(n,t){function e(n,t){var e=Math.cos(t),a=Math.cos(n)*e,l=Math.sin(n)*e,c=Math.sin(t),f=c*r+a*i;return[Math.atan2(l*u-f*o,a*r-c*i),tn(f*u+l*o)]}var r=Math.cos(n),i=Math.sin(n),u=Math.cos(t),o=Math.sin(t);return e.invert=function(n,t){var e=Math.cos(t),a=Math.cos(n)*e,l=Math.sin(n)*e,c=Math.sin(t),f=c*u-l*o;return[Math.atan2(l*u+c*o,a*r+f*i),tn(f*r-a*i)]},e}function ve(n,t){var e=Math.cos(n),r=Math.sin(n);return function(i,u,o,a){var l=o*t;null!=i?(i=de(e,i),u=de(e,u),(o>0?u>i:i>u)&&(i+=o*Ho)):(i=n+o*Ho,u=n-.5*l);for(var c,f=i;o>0?f>u:u>f;f-=l)a.point((c=_t([e,-r*Math.cos(f),-r*Math.sin(f)]))[0],c[1])}}function de(n,t){var e=dt(t);e[0]-=n,bt(e);var r=nn(-e[1]);return((-e[2]<0?-r:r)+2*Math.PI-Uo)%(2*Math.PI)}function ye(n,t,e){var r=ao.range(n,t-Uo,e).concat(t);return function(n){return r.map(function(t){return[n,t]})}}function me(n,t,e){var r=ao.range(n,t-Uo,e).concat(t);return function(n){return r.map(function(t){return[t,n]})}}function Me(n){return n.source}function xe(n){return n.target}function be(n,t,e,r){var i=Math.cos(t),u=Math.sin(t),o=Math.cos(r),a=Math.sin(r),l=i*Math.cos(n),c=i*Math.sin(n),f=o*Math.cos(e),s=o*Math.sin(e),h=2*Math.asin(Math.sqrt(on(r-t)+i*o*on(e-n))),p=1/Math.sin(h),g=h?function(n){var t=Math.sin(n*=h)*p,e=Math.sin(h-n)*p,r=e*l+t*f,i=e*c+t*s,o=e*u+t*a;return[Math.atan2(i,r)*Zo,Math.atan2(o,Math.sqrt(r*r+i*i))*Zo]}:function(){return[n*Zo,t*Zo]};return g.distance=h,g}function _e(){function n(n,i){var u=Math.sin(i*=Yo),o=Math.cos(i),a=xo((n*=Yo)-t),l=Math.cos(a);Ja+=Math.atan2(Math.sqrt((a=o*Math.sin(a))*a+(a=r*u-e*o*l)*a),e*u+r*o*l),t=n,e=u,r=o}var t,e,r;Ga.point=function(i,u){t=i*Yo,e=Math.sin(u*=Yo),r=Math.cos(u),Ga.point=n},Ga.lineEnd=function(){Ga.point=Ga.lineEnd=b}}function we(n,t){function e(t,e){var r=Math.cos(t),i=Math.cos(e),u=n(r*i);return[u*i*Math.sin(t),u*Math.sin(e)]}return e.invert=function(n,e){var r=Math.sqrt(n*n+e*e),i=t(r),u=Math.sin(i),o=Math.cos(i);return[Math.atan2(n*u,r*o),Math.asin(r&&e*u/r)]},e}function Se(n,t){function e(n,t){o>0?-Io+Uo>t&&(t=-Io+Uo):t>Io-Uo&&(t=Io-Uo);var e=o/Math.pow(i(t),u);return[e*Math.sin(u*n),o-e*Math.cos(u*n)]}var r=Math.cos(n),i=function(n){return Math.tan(Fo/4+n/2)},u=n===t?Math.sin(n):Math.log(r/Math.cos(t))/Math.log(i(t)/i(n)),o=r*Math.pow(i(n),u)/u;return u?(e.invert=function(n,t){var e=o-t,r=K(u)*Math.sqrt(n*n+e*e);return[Math.atan2(n,e)/u,2*Math.atan(Math.pow(o/r,1/u))-Io]},e):Ne}function ke(n,t){function e(n,t){var e=u-t;return[e*Math.sin(i*n),u-e*Math.cos(i*n)]}var r=Math.cos(n),i=n===t?Math.sin(n):(r-Math.cos(t))/(t-n),u=r/i+n;return xo(i)<Uo?ce:(e.invert=function(n,t){var e=u-t;return[Math.atan2(n,e)/i,u-K(i)*Math.sqrt(n*n+e*e)]},e)}function Ne(n,t){return[n,Math.log(Math.tan(Fo/4+t/2))]}function Ee(n){var t,e=oe(n),r=e.scale,i=e.translate,u=e.clipExtent;return e.scale=function(){var n=r.apply(e,arguments);return n===e?t?e.clipExtent(null):e:n},e.translate=function(){var n=i.apply(e,arguments);return n===e?t?e.clipExtent(null):e:n},e.clipExtent=function(n){var o=u.apply(e,arguments);if(o===e){if(t=null==n){var a=Fo*r(),l=i();u([[l[0]-a,l[1]-a],[l[0]+a,l[1]+a]])}}else t&&(o=null);return o},e.clipExtent(null)}function Ae(n,t){return[Math.log(Math.tan(Fo/4+t/2)),-n]}function Ce(n){return n[0]}function ze(n){return n[1]}function Le(n){for(var t=n.length,e=[0,1],r=2,i=2;t>i;i++){for(;r>1&&Q(n[e[r-2]],n[e[r-1]],n[i])<=0;)--r;e[r++]=i}return e.slice(0,r)}function qe(n,t){return n[0]-t[0]||n[1]-t[1]}function Te(n,t,e){return(e[0]-t[0])*(n[1]-t[1])<(e[1]-t[1])*(n[0]-t[0])}function Re(n,t,e,r){var i=n[0],u=e[0],o=t[0]-i,a=r[0]-u,l=n[1],c=e[1],f=t[1]-l,s=r[1]-c,h=(a*(l-c)-s*(i-u))/(s*o-a*f);return[i+h*o,l+h*f]}function De(n){var t=n[0],e=n[n.length-1];return!(t[0]-e[0]||t[1]-e[1])}function Pe(){rr(this),this.edge=this.site=this.circle=null}function Ue(n){var t=cl.pop()||new Pe;return t.site=n,t}function je(n){Be(n),ol.remove(n),cl.push(n),rr(n)}function Fe(n){var t=n.circle,e=t.x,r=t.cy,i={x:e,y:r},u=n.P,o=n.N,a=[n];je(n);for(var l=u;l.circle&&xo(e-l.circle.x)<Uo&&xo(r-l.circle.cy)<Uo;)u=l.P,a.unshift(l),je(l),l=u;a.unshift(l),Be(l);for(var c=o;c.circle&&xo(e-c.circle.x)<Uo&&xo(r-c.circle.cy)<Uo;)o=c.N,a.push(c),je(c),c=o;a.push(c),Be(c);var f,s=a.length;for(f=1;s>f;++f)c=a[f],l=a[f-1],nr(c.edge,l.site,c.site,i);l=a[0],c=a[s-1],c.edge=Ke(l.site,c.site,null,i),$e(l),$e(c)}function He(n){for(var t,e,r,i,u=n.x,o=n.y,a=ol._;a;)if(r=Oe(a,o)-u,r>Uo)a=a.L;else{if(i=u-Ie(a,o),!(i>Uo)){r>-Uo?(t=a.P,e=a):i>-Uo?(t=a,e=a.N):t=e=a;break}if(!a.R){t=a;break}a=a.R}var l=Ue(n);if(ol.insert(t,l),t||e){if(t===e)return Be(t),e=Ue(t.site),ol.insert(l,e),l.edge=e.edge=Ke(t.site,l.site),$e(t),void $e(e);if(!e)return void(l.edge=Ke(t.site,l.site));Be(t),Be(e);var c=t.site,f=c.x,s=c.y,h=n.x-f,p=n.y-s,g=e.site,v=g.x-f,d=g.y-s,y=2*(h*d-p*v),m=h*h+p*p,M=v*v+d*d,x={x:(d*m-p*M)/y+f,y:(h*M-v*m)/y+s};nr(e.edge,c,g,x),l.edge=Ke(c,n,null,x),e.edge=Ke(n,g,null,x),$e(t),$e(e)}}function Oe(n,t){var e=n.site,r=e.x,i=e.y,u=i-t;if(!u)return r;var o=n.P;if(!o)return-(1/0);e=o.site;var a=e.x,l=e.y,c=l-t;if(!c)return a;var f=a-r,s=1/u-1/c,h=f/c;return s?(-h+Math.sqrt(h*h-2*s*(f*f/(-2*c)-l+c/2+i-u/2)))/s+r:(r+a)/2}function Ie(n,t){var e=n.N;if(e)return Oe(e,t);var r=n.site;return r.y===t?r.x:1/0}function Ye(n){this.site=n,this.edges=[]}function Ze(n){for(var t,e,r,i,u,o,a,l,c,f,s=n[0][0],h=n[1][0],p=n[0][1],g=n[1][1],v=ul,d=v.length;d--;)if(u=v[d],u&&u.prepare())for(a=u.edges,l=a.length,o=0;l>o;)f=a[o].end(),r=f.x,i=f.y,c=a[++o%l].start(),t=c.x,e=c.y,(xo(r-t)>Uo||xo(i-e)>Uo)&&(a.splice(o,0,new tr(Qe(u.site,f,xo(r-s)<Uo&&g-i>Uo?{x:s,y:xo(t-s)<Uo?e:g}:xo(i-g)<Uo&&h-r>Uo?{x:xo(e-g)<Uo?t:h,y:g}:xo(r-h)<Uo&&i-p>Uo?{x:h,y:xo(t-h)<Uo?e:p}:xo(i-p)<Uo&&r-s>Uo?{x:xo(e-p)<Uo?t:s,y:p}:null),u.site,null)),++l)}function Ve(n,t){return t.angle-n.angle}function Xe(){rr(this),this.x=this.y=this.arc=this.site=this.cy=null}function $e(n){var t=n.P,e=n.N;if(t&&e){var r=t.site,i=n.site,u=e.site;if(r!==u){var o=i.x,a=i.y,l=r.x-o,c=r.y-a,f=u.x-o,s=u.y-a,h=2*(l*s-c*f);if(!(h>=-jo)){var p=l*l+c*c,g=f*f+s*s,v=(s*p-c*g)/h,d=(l*g-f*p)/h,s=d+a,y=fl.pop()||new Xe;y.arc=n,y.site=i,y.x=v+o,y.y=s+Math.sqrt(v*v+d*d),y.cy=s,n.circle=y;for(var m=null,M=ll._;M;)if(y.y<M.y||y.y===M.y&&y.x<=M.x){if(!M.L){m=M.P;break}M=M.L}else{if(!M.R){m=M;break}M=M.R}ll.insert(m,y),m||(al=y)}}}}function Be(n){var t=n.circle;t&&(t.P||(al=t.N),ll.remove(t),fl.push(t),rr(t),n.circle=null)}function We(n){for(var t,e=il,r=Yt(n[0][0],n[0][1],n[1][0],n[1][1]),i=e.length;i--;)t=e[i],(!Je(t,n)||!r(t)||xo(t.a.x-t.b.x)<Uo&&xo(t.a.y-t.b.y)<Uo)&&(t.a=t.b=null,e.splice(i,1))}function Je(n,t){var e=n.b;if(e)return!0;var r,i,u=n.a,o=t[0][0],a=t[1][0],l=t[0][1],c=t[1][1],f=n.l,s=n.r,h=f.x,p=f.y,g=s.x,v=s.y,d=(h+g)/2,y=(p+v)/2;if(v===p){if(o>d||d>=a)return;if(h>g){if(u){if(u.y>=c)return}else u={x:d,y:l};e={x:d,y:c}}else{if(u){if(u.y<l)return}else u={x:d,y:c};e={x:d,y:l}}}else if(r=(h-g)/(v-p),i=y-r*d,-1>r||r>1)if(h>g){if(u){if(u.y>=c)return}else u={x:(l-i)/r,y:l};e={x:(c-i)/r,y:c}}else{if(u){if(u.y<l)return}else u={x:(c-i)/r,y:c};e={x:(l-i)/r,y:l}}else if(v>p){if(u){if(u.x>=a)return}else u={x:o,y:r*o+i};e={x:a,y:r*a+i}}else{if(u){if(u.x<o)return}else u={x:a,y:r*a+i};e={x:o,y:r*o+i}}return n.a=u,n.b=e,!0}function Ge(n,t){this.l=n,this.r=t,this.a=this.b=null}function Ke(n,t,e,r){var i=new Ge(n,t);return il.push(i),e&&nr(i,n,t,e),r&&nr(i,t,n,r),ul[n.i].edges.push(new tr(i,n,t)),ul[t.i].edges.push(new tr(i,t,n)),i}function Qe(n,t,e){var r=new Ge(n,null);return r.a=t,r.b=e,il.push(r),r}function nr(n,t,e,r){n.a||n.b?n.l===e?n.b=r:n.a=r:(n.a=r,n.l=t,n.r=e)}function tr(n,t,e){var r=n.a,i=n.b;this.edge=n,this.site=t,this.angle=e?Math.atan2(e.y-t.y,e.x-t.x):n.l===t?Math.atan2(i.x-r.x,r.y-i.y):Math.atan2(r.x-i.x,i.y-r.y)}function er(){this._=null}function rr(n){n.U=n.C=n.L=n.R=n.P=n.N=null}function ir(n,t){var e=t,r=t.R,i=e.U;i?i.L===e?i.L=r:i.R=r:n._=r,r.U=i,e.U=r,e.R=r.L,e.R&&(e.R.U=e),r.L=e}function ur(n,t){var e=t,r=t.L,i=e.U;i?i.L===e?i.L=r:i.R=r:n._=r,r.U=i,e.U=r,e.L=r.R,e.L&&(e.L.U=e),r.R=e}function or(n){for(;n.L;)n=n.L;return n}function ar(n,t){var e,r,i,u=n.sort(lr).pop();for(il=[],ul=new Array(n.length),ol=new er,ll=new er;;)if(i=al,u&&(!i||u.y<i.y||u.y===i.y&&u.x<i.x))u.x===e&&u.y===r||(ul[u.i]=new Ye(u),He(u),e=u.x,r=u.y),u=n.pop();else{if(!i)break;Fe(i.arc)}t&&(We(t),Ze(t));var o={cells:ul,edges:il};return ol=ll=il=ul=null,o}function lr(n,t){return t.y-n.y||t.x-n.x}function cr(n,t,e){return(n.x-e.x)*(t.y-n.y)-(n.x-t.x)*(e.y-n.y)}function fr(n){return n.x}function sr(n){return n.y}function hr(){return{leaf:!0,nodes:[],point:null,x:null,y:null}}function pr(n,t,e,r,i,u){if(!n(t,e,r,i,u)){var o=.5*(e+i),a=.5*(r+u),l=t.nodes;l[0]&&pr(n,l[0],e,r,o,a),l[1]&&pr(n,l[1],o,r,i,a),l[2]&&pr(n,l[2],e,a,o,u),l[3]&&pr(n,l[3],o,a,i,u)}}function gr(n,t,e,r,i,u,o){var a,l=1/0;return function c(n,f,s,h,p){if(!(f>u||s>o||r>h||i>p)){if(g=n.point){var g,v=t-n.x,d=e-n.y,y=v*v+d*d;if(l>y){var m=Math.sqrt(l=y);r=t-m,i=e-m,u=t+m,o=e+m,a=g}}for(var M=n.nodes,x=.5*(f+h),b=.5*(s+p),_=t>=x,w=e>=b,S=w<<1|_,k=S+4;k>S;++S)if(n=M[3&S])switch(3&S){case 0:c(n,f,s,x,b);break;case 1:c(n,x,s,h,b);break;case 2:c(n,f,b,x,p);break;case 3:c(n,x,b,h,p)}}}(n,r,i,u,o),a}function vr(n,t){n=ao.rgb(n),t=ao.rgb(t);var e=n.r,r=n.g,i=n.b,u=t.r-e,o=t.g-r,a=t.b-i;return function(n){return"#"+bn(Math.round(e+u*n))+bn(Math.round(r+o*n))+bn(Math.round(i+a*n))}}function dr(n,t){var e,r={},i={};for(e in n)e in t?r[e]=Mr(n[e],t[e]):i[e]=n[e];for(e in t)e in n||(i[e]=t[e]);return function(n){for(e in r)i[e]=r[e](n);return i}}function yr(n,t){return n=+n,t=+t,function(e){return n*(1-e)+t*e}}function mr(n,t){var e,r,i,u=hl.lastIndex=pl.lastIndex=0,o=-1,a=[],l=[];for(n+="",t+="";(e=hl.exec(n))&&(r=pl.exec(t));)(i=r.index)>u&&(i=t.slice(u,i),a[o]?a[o]+=i:a[++o]=i),(e=e[0])===(r=r[0])?a[o]?a[o]+=r:a[++o]=r:(a[++o]=null,l.push({i:o,x:yr(e,r)})),u=pl.lastIndex;return u<t.length&&(i=t.slice(u),a[o]?a[o]+=i:a[++o]=i),a.length<2?l[0]?(t=l[0].x,function(n){return t(n)+""}):function(){return t}:(t=l.length,function(n){for(var e,r=0;t>r;++r)a[(e=l[r]).i]=e.x(n);return a.join("")})}function Mr(n,t){for(var e,r=ao.interpolators.length;--r>=0&&!(e=ao.interpolators[r](n,t)););return e}function xr(n,t){var e,r=[],i=[],u=n.length,o=t.length,a=Math.min(n.length,t.length);for(e=0;a>e;++e)r.push(Mr(n[e],t[e]));for(;u>e;++e)i[e]=n[e];for(;o>e;++e)i[e]=t[e];return function(n){for(e=0;a>e;++e)i[e]=r[e](n);return i}}function br(n){return function(t){return 0>=t?0:t>=1?1:n(t)}}function _r(n){return function(t){return 1-n(1-t)}}function wr(n){return function(t){return.5*(.5>t?n(2*t):2-n(2-2*t))}}function Sr(n){return n*n}function kr(n){return n*n*n}function Nr(n){if(0>=n)return 0;if(n>=1)return 1;var t=n*n,e=t*n;return 4*(.5>n?e:3*(n-t)+e-.75)}function Er(n){return function(t){return Math.pow(t,n)}}function Ar(n){return 1-Math.cos(n*Io)}function Cr(n){return Math.pow(2,10*(n-1))}function zr(n){return 1-Math.sqrt(1-n*n)}function Lr(n,t){var e;return arguments.length<2&&(t=.45),arguments.length?e=t/Ho*Math.asin(1/n):(n=1,e=t/4),function(r){return 1+n*Math.pow(2,-10*r)*Math.sin((r-e)*Ho/t)}}function qr(n){return n||(n=1.70158),function(t){return t*t*((n+1)*t-n)}}function Tr(n){return 1/2.75>n?7.5625*n*n:2/2.75>n?7.5625*(n-=1.5/2.75)*n+.75:2.5/2.75>n?7.5625*(n-=2.25/2.75)*n+.9375:7.5625*(n-=2.625/2.75)*n+.984375}function Rr(n,t){n=ao.hcl(n),t=ao.hcl(t);var e=n.h,r=n.c,i=n.l,u=t.h-e,o=t.c-r,a=t.l-i;return isNaN(o)&&(o=0,r=isNaN(r)?t.c:r),isNaN(u)?(u=0,e=isNaN(e)?t.h:e):u>180?u-=360:-180>u&&(u+=360),function(n){return sn(e+u*n,r+o*n,i+a*n)+""}}function Dr(n,t){n=ao.hsl(n),t=ao.hsl(t);var e=n.h,r=n.s,i=n.l,u=t.h-e,o=t.s-r,a=t.l-i;return isNaN(o)&&(o=0,r=isNaN(r)?t.s:r),isNaN(u)?(u=0,e=isNaN(e)?t.h:e):u>180?u-=360:-180>u&&(u+=360),function(n){return cn(e+u*n,r+o*n,i+a*n)+""}}function Pr(n,t){n=ao.lab(n),t=ao.lab(t);var e=n.l,r=n.a,i=n.b,u=t.l-e,o=t.a-r,a=t.b-i;return function(n){return pn(e+u*n,r+o*n,i+a*n)+""}}function Ur(n,t){return t-=n,function(e){return Math.round(n+t*e)}}function jr(n){var t=[n.a,n.b],e=[n.c,n.d],r=Hr(t),i=Fr(t,e),u=Hr(Or(e,t,-i))||0;t[0]*e[1]<e[0]*t[1]&&(t[0]*=-1,t[1]*=-1,r*=-1,i*=-1),this.rotate=(r?Math.atan2(t[1],t[0]):Math.atan2(-e[0],e[1]))*Zo,this.translate=[n.e,n.f],this.scale=[r,u],this.skew=u?Math.atan2(i,u)*Zo:0}function Fr(n,t){return n[0]*t[0]+n[1]*t[1]}function Hr(n){var t=Math.sqrt(Fr(n,n));return t&&(n[0]/=t,n[1]/=t),t}function Or(n,t,e){return n[0]+=e*t[0],n[1]+=e*t[1],n}function Ir(n){return n.length?n.pop()+",":""}function Yr(n,t,e,r){if(n[0]!==t[0]||n[1]!==t[1]){var i=e.push("translate(",null,",",null,")");r.push({i:i-4,x:yr(n[0],t[0])},{i:i-2,x:yr(n[1],t[1])})}else(t[0]||t[1])&&e.push("translate("+t+")")}function Zr(n,t,e,r){n!==t?(n-t>180?t+=360:t-n>180&&(n+=360),r.push({i:e.push(Ir(e)+"rotate(",null,")")-2,x:yr(n,t)})):t&&e.push(Ir(e)+"rotate("+t+")")}function Vr(n,t,e,r){n!==t?r.push({i:e.push(Ir(e)+"skewX(",null,")")-2,x:yr(n,t)}):t&&e.push(Ir(e)+"skewX("+t+")")}function Xr(n,t,e,r){if(n[0]!==t[0]||n[1]!==t[1]){var i=e.push(Ir(e)+"scale(",null,",",null,")");r.push({i:i-4,x:yr(n[0],t[0])},{i:i-2,x:yr(n[1],t[1])})}else 1===t[0]&&1===t[1]||e.push(Ir(e)+"scale("+t+")")}function $r(n,t){var e=[],r=[];return n=ao.transform(n),t=ao.transform(t),Yr(n.translate,t.translate,e,r),Zr(n.rotate,t.rotate,e,r),Vr(n.skew,t.skew,e,r),Xr(n.scale,t.scale,e,r),n=t=null,function(n){for(var t,i=-1,u=r.length;++i<u;)e[(t=r[i]).i]=t.x(n);return e.join("")}}function Br(n,t){return t=(t-=n=+n)||1/t,function(e){return(e-n)/t}}function Wr(n,t){return t=(t-=n=+n)||1/t,function(e){return Math.max(0,Math.min(1,(e-n)/t))}}function Jr(n){for(var t=n.source,e=n.target,r=Kr(t,e),i=[t];t!==r;)t=t.parent,i.push(t);for(var u=i.length;e!==r;)i.splice(u,0,e),e=e.parent;return i}function Gr(n){for(var t=[],e=n.parent;null!=e;)t.push(n),n=e,e=e.parent;return t.push(n),t}function Kr(n,t){if(n===t)return n;for(var e=Gr(n),r=Gr(t),i=e.pop(),u=r.pop(),o=null;i===u;)o=i,i=e.pop(),u=r.pop();return o}function Qr(n){n.fixed|=2}function ni(n){n.fixed&=-7}function ti(n){n.fixed|=4,n.px=n.x,n.py=n.y}function ei(n){n.fixed&=-5}function ri(n,t,e){var r=0,i=0;if(n.charge=0,!n.leaf)for(var u,o=n.nodes,a=o.length,l=-1;++l<a;)u=o[l],null!=u&&(ri(u,t,e),n.charge+=u.charge,r+=u.charge*u.cx,i+=u.charge*u.cy);if(n.point){n.leaf||(n.point.x+=Math.random()-.5,n.point.y+=Math.random()-.5);var c=t*e[n.point.index];n.charge+=n.pointCharge=c,r+=c*n.point.x,i+=c*n.point.y}n.cx=r/n.charge,n.cy=i/n.charge}function ii(n,t){return ao.rebind(n,t,"sort","children","value"),n.nodes=n,n.links=fi,n}function ui(n,t){for(var e=[n];null!=(n=e.pop());)if(t(n),(i=n.children)&&(r=i.length))for(var r,i;--r>=0;)e.push(i[r])}function oi(n,t){for(var e=[n],r=[];null!=(n=e.pop());)if(r.push(n),(u=n.children)&&(i=u.length))for(var i,u,o=-1;++o<i;)e.push(u[o]);for(;null!=(n=r.pop());)t(n)}function ai(n){return n.children}function li(n){return n.value}function ci(n,t){return t.value-n.value}function fi(n){return ao.merge(n.map(function(n){return(n.children||[]).map(function(t){return{source:n,target:t}})}))}function si(n){return n.x}function hi(n){return n.y}function pi(n,t,e){n.y0=t,n.y=e}function gi(n){return ao.range(n.length)}function vi(n){for(var t=-1,e=n[0].length,r=[];++t<e;)r[t]=0;return r}function di(n){for(var t,e=1,r=0,i=n[0][1],u=n.length;u>e;++e)(t=n[e][1])>i&&(r=e,i=t);return r}function yi(n){return n.reduce(mi,0)}function mi(n,t){return n+t[1]}function Mi(n,t){return xi(n,Math.ceil(Math.log(t.length)/Math.LN2+1))}function xi(n,t){for(var e=-1,r=+n[0],i=(n[1]-r)/t,u=[];++e<=t;)u[e]=i*e+r;return u}function bi(n){return[ao.min(n),ao.max(n)]}function _i(n,t){return n.value-t.value}function wi(n,t){var e=n._pack_next;n._pack_next=t,t._pack_prev=n,t._pack_next=e,e._pack_prev=t}function Si(n,t){n._pack_next=t,t._pack_prev=n}function ki(n,t){var e=t.x-n.x,r=t.y-n.y,i=n.r+t.r;return.999*i*i>e*e+r*r}function Ni(n){function t(n){f=Math.min(n.x-n.r,f),s=Math.max(n.x+n.r,s),h=Math.min(n.y-n.r,h),p=Math.max(n.y+n.r,p)}if((e=n.children)&&(c=e.length)){var e,r,i,u,o,a,l,c,f=1/0,s=-(1/0),h=1/0,p=-(1/0);if(e.forEach(Ei),r=e[0],r.x=-r.r,r.y=0,t(r),c>1&&(i=e[1],i.x=i.r,i.y=0,t(i),c>2))for(u=e[2],zi(r,i,u),t(u),wi(r,u),r._pack_prev=u,wi(u,i),i=r._pack_next,o=3;c>o;o++){zi(r,i,u=e[o]);var g=0,v=1,d=1;for(a=i._pack_next;a!==i;a=a._pack_next,v++)if(ki(a,u)){g=1;break}if(1==g)for(l=r._pack_prev;l!==a._pack_prev&&!ki(l,u);l=l._pack_prev,d++);g?(d>v||v==d&&i.r<r.r?Si(r,i=a):Si(r=l,i),o--):(wi(r,u),i=u,t(u))}var y=(f+s)/2,m=(h+p)/2,M=0;for(o=0;c>o;o++)u=e[o],u.x-=y,u.y-=m,M=Math.max(M,u.r+Math.sqrt(u.x*u.x+u.y*u.y));n.r=M,e.forEach(Ai)}}function Ei(n){n._pack_next=n._pack_prev=n}function Ai(n){delete n._pack_next,delete n._pack_prev}function Ci(n,t,e,r){var i=n.children;if(n.x=t+=r*n.x,n.y=e+=r*n.y,n.r*=r,i)for(var u=-1,o=i.length;++u<o;)Ci(i[u],t,e,r)}function zi(n,t,e){var r=n.r+e.r,i=t.x-n.x,u=t.y-n.y;if(r&&(i||u)){var o=t.r+e.r,a=i*i+u*u;o*=o,r*=r;var l=.5+(r-o)/(2*a),c=Math.sqrt(Math.max(0,2*o*(r+a)-(r-=a)*r-o*o))/(2*a);e.x=n.x+l*i+c*u,e.y=n.y+l*u-c*i}else e.x=n.x+r,e.y=n.y}function Li(n,t){return n.parent==t.parent?1:2}function qi(n){var t=n.children;return t.length?t[0]:n.t}function Ti(n){var t,e=n.children;return(t=e.length)?e[t-1]:n.t}function Ri(n,t,e){var r=e/(t.i-n.i);t.c-=r,t.s+=e,n.c+=r,t.z+=e,t.m+=e}function Di(n){for(var t,e=0,r=0,i=n.children,u=i.length;--u>=0;)t=i[u],t.z+=e,t.m+=e,e+=t.s+(r+=t.c)}function Pi(n,t,e){return n.a.parent===t.parent?n.a:e}function Ui(n){return 1+ao.max(n,function(n){return n.y})}function ji(n){return n.reduce(function(n,t){return n+t.x},0)/n.length}function Fi(n){var t=n.children;return t&&t.length?Fi(t[0]):n}function Hi(n){var t,e=n.children;return e&&(t=e.length)?Hi(e[t-1]):n}function Oi(n){return{x:n.x,y:n.y,dx:n.dx,dy:n.dy}}function Ii(n,t){var e=n.x+t[3],r=n.y+t[0],i=n.dx-t[1]-t[3],u=n.dy-t[0]-t[2];return 0>i&&(e+=i/2,i=0),0>u&&(r+=u/2,u=0),{x:e,y:r,dx:i,dy:u}}function Yi(n){var t=n[0],e=n[n.length-1];return e>t?[t,e]:[e,t]}function Zi(n){return n.rangeExtent?n.rangeExtent():Yi(n.range())}function Vi(n,t,e,r){var i=e(n[0],n[1]),u=r(t[0],t[1]);return function(n){return u(i(n))}}function Xi(n,t){var e,r=0,i=n.length-1,u=n[r],o=n[i];return u>o&&(e=r,r=i,i=e,e=u,u=o,o=e),n[r]=t.floor(u),n[i]=t.ceil(o),n}function $i(n){return n?{floor:function(t){return Math.floor(t/n)*n},ceil:function(t){return Math.ceil(t/n)*n}}:Sl}function Bi(n,t,e,r){var i=[],u=[],o=0,a=Math.min(n.length,t.length)-1;for(n[a]<n[0]&&(n=n.slice().reverse(),t=t.slice().reverse());++o<=a;)i.push(e(n[o-1],n[o])),u.push(r(t[o-1],t[o]));return function(t){var e=ao.bisect(n,t,1,a)-1;return u[e](i[e](t))}}function Wi(n,t,e,r){function i(){var i=Math.min(n.length,t.length)>2?Bi:Vi,l=r?Wr:Br;return o=i(n,t,l,e),a=i(t,n,l,Mr),u}function u(n){return o(n)}var o,a;return u.invert=function(n){return a(n)},u.domain=function(t){return arguments.length?(n=t.map(Number),i()):n},u.range=function(n){return arguments.length?(t=n,i()):t},u.rangeRound=function(n){return u.range(n).interpolate(Ur)},u.clamp=function(n){return arguments.length?(r=n,i()):r},u.interpolate=function(n){return arguments.length?(e=n,i()):e},u.ticks=function(t){return Qi(n,t)},u.tickFormat=function(t,e){return nu(n,t,e)},u.nice=function(t){return Gi(n,t),i()},u.copy=function(){return Wi(n,t,e,r)},i()}function Ji(n,t){return ao.rebind(n,t,"range","rangeRound","interpolate","clamp")}function Gi(n,t){return Xi(n,$i(Ki(n,t)[2])),Xi(n,$i(Ki(n,t)[2])),n}function Ki(n,t){null==t&&(t=10);var e=Yi(n),r=e[1]-e[0],i=Math.pow(10,Math.floor(Math.log(r/t)/Math.LN10)),u=t/r*i;return.15>=u?i*=10:.35>=u?i*=5:.75>=u&&(i*=2),e[0]=Math.ceil(e[0]/i)*i,e[1]=Math.floor(e[1]/i)*i+.5*i,e[2]=i,e}function Qi(n,t){return ao.range.apply(ao,Ki(n,t))}function nu(n,t,e){var r=Ki(n,t);if(e){var i=ha.exec(e);if(i.shift(),"s"===i[8]){var u=ao.formatPrefix(Math.max(xo(r[0]),xo(r[1])));return i[7]||(i[7]="."+tu(u.scale(r[2]))),i[8]="f",e=ao.format(i.join("")),function(n){return e(u.scale(n))+u.symbol}}i[7]||(i[7]="."+eu(i[8],r)),e=i.join("")}else e=",."+tu(r[2])+"f";return ao.format(e)}function tu(n){return-Math.floor(Math.log(n)/Math.LN10+.01)}function eu(n,t){var e=tu(t[2]);return n in kl?Math.abs(e-tu(Math.max(xo(t[0]),xo(t[1]))))+ +("e"!==n):e-2*("%"===n)}function ru(n,t,e,r){function i(n){return(e?Math.log(0>n?0:n):-Math.log(n>0?0:-n))/Math.log(t)}function u(n){return e?Math.pow(t,n):-Math.pow(t,-n)}function o(t){return n(i(t))}return o.invert=function(t){return u(n.invert(t))},o.domain=function(t){return arguments.length?(e=t[0]>=0,n.domain((r=t.map(Number)).map(i)),o):r},o.base=function(e){return arguments.length?(t=+e,n.domain(r.map(i)),o):t},o.nice=function(){var t=Xi(r.map(i),e?Math:El);return n.domain(t),r=t.map(u),o},o.ticks=function(){var n=Yi(r),o=[],a=n[0],l=n[1],c=Math.floor(i(a)),f=Math.ceil(i(l)),s=t%1?2:t;if(isFinite(f-c)){if(e){for(;f>c;c++)for(var h=1;s>h;h++)o.push(u(c)*h);o.push(u(c))}else for(o.push(u(c));c++<f;)for(var h=s-1;h>0;h--)o.push(u(c)*h);for(c=0;o[c]<a;c++);for(f=o.length;o[f-1]>l;f--);o=o.slice(c,f)}return o},o.tickFormat=function(n,e){if(!arguments.length)return Nl;arguments.length<2?e=Nl:"function"!=typeof e&&(e=ao.format(e));var r=Math.max(1,t*n/o.ticks().length);return function(n){var o=n/u(Math.round(i(n)));return t-.5>o*t&&(o*=t),r>=o?e(n):""}},o.copy=function(){return ru(n.copy(),t,e,r)},Ji(o,n)}function iu(n,t,e){function r(t){return n(i(t))}var i=uu(t),u=uu(1/t);return r.invert=function(t){return u(n.invert(t))},r.domain=function(t){return arguments.length?(n.domain((e=t.map(Number)).map(i)),r):e},r.ticks=function(n){return Qi(e,n)},r.tickFormat=function(n,t){return nu(e,n,t)},r.nice=function(n){return r.domain(Gi(e,n))},r.exponent=function(o){return arguments.length?(i=uu(t=o),u=uu(1/t),n.domain(e.map(i)),r):t},r.copy=function(){return iu(n.copy(),t,e)},Ji(r,n)}function uu(n){return function(t){return 0>t?-Math.pow(-t,n):Math.pow(t,n)}}function ou(n,t){function e(e){return u[((i.get(e)||("range"===t.t?i.set(e,n.push(e)):NaN))-1)%u.length]}function r(t,e){return ao.range(n.length).map(function(n){return t+e*n})}var i,u,o;return e.domain=function(r){if(!arguments.length)return n;n=[],i=new c;for(var u,o=-1,a=r.length;++o<a;)i.has(u=r[o])||i.set(u,n.push(u));return e[t.t].apply(e,t.a)},e.range=function(n){return arguments.length?(u=n,o=0,t={t:"range",a:arguments},e):u},e.rangePoints=function(i,a){arguments.length<2&&(a=0);var l=i[0],c=i[1],f=n.length<2?(l=(l+c)/2,0):(c-l)/(n.length-1+a);return u=r(l+f*a/2,f),o=0,t={t:"rangePoints",a:arguments},e},e.rangeRoundPoints=function(i,a){arguments.length<2&&(a=0);var l=i[0],c=i[1],f=n.length<2?(l=c=Math.round((l+c)/2),0):(c-l)/(n.length-1+a)|0;return u=r(l+Math.round(f*a/2+(c-l-(n.length-1+a)*f)/2),f),o=0,t={t:"rangeRoundPoints",a:arguments},e},e.rangeBands=function(i,a,l){arguments.length<2&&(a=0),arguments.length<3&&(l=a);var c=i[1]<i[0],f=i[c-0],s=i[1-c],h=(s-f)/(n.length-a+2*l);return u=r(f+h*l,h),c&&u.reverse(),o=h*(1-a),t={t:"rangeBands",a:arguments},e},e.rangeRoundBands=function(i,a,l){arguments.length<2&&(a=0),arguments.length<3&&(l=a);var c=i[1]<i[0],f=i[c-0],s=i[1-c],h=Math.floor((s-f)/(n.length-a+2*l));return u=r(f+Math.round((s-f-(n.length-a)*h)/2),h),c&&u.reverse(),o=Math.round(h*(1-a)),t={t:"rangeRoundBands",a:arguments},e},e.rangeBand=function(){return o},e.rangeExtent=function(){return Yi(t.a[0])},e.copy=function(){return ou(n,t)},e.domain(n)}function au(n,t){function u(){var e=0,r=t.length;for(a=[];++e<r;)a[e-1]=ao.quantile(n,e/r);return o}function o(n){return isNaN(n=+n)?void 0:t[ao.bisect(a,n)]}var a;return o.domain=function(t){return arguments.length?(n=t.map(r).filter(i).sort(e),u()):n},o.range=function(n){return arguments.length?(t=n,u()):t},o.quantiles=function(){return a},o.invertExtent=function(e){return e=t.indexOf(e),0>e?[NaN,NaN]:[e>0?a[e-1]:n[0],e<a.length?a[e]:n[n.length-1]]},o.copy=function(){return au(n,t)},u()}function lu(n,t,e){function r(t){return e[Math.max(0,Math.min(o,Math.floor(u*(t-n))))]}function i(){return u=e.length/(t-n),o=e.length-1,r}var u,o;return r.domain=function(e){return arguments.length?(n=+e[0],t=+e[e.length-1],i()):[n,t]},r.range=function(n){return arguments.length?(e=n,i()):e},r.invertExtent=function(t){return t=e.indexOf(t),t=0>t?NaN:t/u+n,[t,t+1/u]},r.copy=function(){return lu(n,t,e)},i()}function cu(n,t){function e(e){return e>=e?t[ao.bisect(n,e)]:void 0}return e.domain=function(t){return arguments.length?(n=t,e):n},e.range=function(n){return arguments.length?(t=n,e):t},e.invertExtent=function(e){return e=t.indexOf(e),[n[e-1],n[e]]},e.copy=function(){return cu(n,t)},e}function fu(n){function t(n){return+n}return t.invert=t,t.domain=t.range=function(e){return arguments.length?(n=e.map(t),t):n},t.ticks=function(t){return Qi(n,t)},t.tickFormat=function(t,e){return nu(n,t,e)},t.copy=function(){return fu(n)},t}function su(){return 0}function hu(n){return n.innerRadius}function pu(n){return n.outerRadius}function gu(n){return n.startAngle}function vu(n){return n.endAngle}function du(n){return n&&n.padAngle}function yu(n,t,e,r){return(n-e)*t-(t-r)*n>0?0:1}function mu(n,t,e,r,i){var u=n[0]-t[0],o=n[1]-t[1],a=(i?r:-r)/Math.sqrt(u*u+o*o),l=a*o,c=-a*u,f=n[0]+l,s=n[1]+c,h=t[0]+l,p=t[1]+c,g=(f+h)/2,v=(s+p)/2,d=h-f,y=p-s,m=d*d+y*y,M=e-r,x=f*p-h*s,b=(0>y?-1:1)*Math.sqrt(Math.max(0,M*M*m-x*x)),_=(x*y-d*b)/m,w=(-x*d-y*b)/m,S=(x*y+d*b)/m,k=(-x*d+y*b)/m,N=_-g,E=w-v,A=S-g,C=k-v;return N*N+E*E>A*A+C*C&&(_=S,w=k),[[_-l,w-c],[_*e/M,w*e/M]]}function Mu(n){function t(t){function o(){c.push("M",u(n(f),a))}for(var l,c=[],f=[],s=-1,h=t.length,p=En(e),g=En(r);++s<h;)i.call(this,l=t[s],s)?f.push([+p.call(this,l,s),+g.call(this,l,s)]):f.length&&(o(),f=[]);return f.length&&o(),c.length?c.join(""):null}var e=Ce,r=ze,i=zt,u=xu,o=u.key,a=.7;return t.x=function(n){return arguments.length?(e=n,t):e},t.y=function(n){return arguments.length?(r=n,t):r},t.defined=function(n){return arguments.length?(i=n,t):i},t.interpolate=function(n){return arguments.length?(o="function"==typeof n?u=n:(u=Tl.get(n)||xu).key,t):o},t.tension=function(n){return arguments.length?(a=n,t):a},t}function xu(n){return n.length>1?n.join("L"):n+"Z"}function bu(n){return n.join("L")+"Z"}function _u(n){for(var t=0,e=n.length,r=n[0],i=[r[0],",",r[1]];++t<e;)i.push("H",(r[0]+(r=n[t])[0])/2,"V",r[1]);return e>1&&i.push("H",r[0]),i.join("")}function wu(n){for(var t=0,e=n.length,r=n[0],i=[r[0],",",r[1]];++t<e;)i.push("V",(r=n[t])[1],"H",r[0]);return i.join("")}function Su(n){for(var t=0,e=n.length,r=n[0],i=[r[0],",",r[1]];++t<e;)i.push("H",(r=n[t])[0],"V",r[1]);return i.join("")}function ku(n,t){return n.length<4?xu(n):n[1]+Au(n.slice(1,-1),Cu(n,t))}function Nu(n,t){return n.length<3?bu(n):n[0]+Au((n.push(n[0]),n),Cu([n[n.length-2]].concat(n,[n[1]]),t))}function Eu(n,t){return n.length<3?xu(n):n[0]+Au(n,Cu(n,t))}function Au(n,t){if(t.length<1||n.length!=t.length&&n.length!=t.length+2)return xu(n);var e=n.length!=t.length,r="",i=n[0],u=n[1],o=t[0],a=o,l=1;if(e&&(r+="Q"+(u[0]-2*o[0]/3)+","+(u[1]-2*o[1]/3)+","+u[0]+","+u[1],i=n[1],l=2),t.length>1){a=t[1],u=n[l],l++,r+="C"+(i[0]+o[0])+","+(i[1]+o[1])+","+(u[0]-a[0])+","+(u[1]-a[1])+","+u[0]+","+u[1];for(var c=2;c<t.length;c++,l++)u=n[l],a=t[c],r+="S"+(u[0]-a[0])+","+(u[1]-a[1])+","+u[0]+","+u[1]}if(e){var f=n[l];r+="Q"+(u[0]+2*a[0]/3)+","+(u[1]+2*a[1]/3)+","+f[0]+","+f[1]}return r}function Cu(n,t){for(var e,r=[],i=(1-t)/2,u=n[0],o=n[1],a=1,l=n.length;++a<l;)e=u,u=o,o=n[a],r.push([i*(o[0]-e[0]),i*(o[1]-e[1])]);return r}function zu(n){if(n.length<3)return xu(n);var t=1,e=n.length,r=n[0],i=r[0],u=r[1],o=[i,i,i,(r=n[1])[0]],a=[u,u,u,r[1]],l=[i,",",u,"L",Ru(Pl,o),",",Ru(Pl,a)];for(n.push(n[e-1]);++t<=e;)r=n[t],o.shift(),o.push(r[0]),a.shift(),a.push(r[1]),Du(l,o,a);return n.pop(),l.push("L",r),l.join("")}function Lu(n){if(n.length<4)return xu(n);for(var t,e=[],r=-1,i=n.length,u=[0],o=[0];++r<3;)t=n[r],u.push(t[0]),o.push(t[1]);for(e.push(Ru(Pl,u)+","+Ru(Pl,o)),--r;++r<i;)t=n[r],u.shift(),u.push(t[0]),o.shift(),o.push(t[1]),Du(e,u,o);return e.join("")}function qu(n){for(var t,e,r=-1,i=n.length,u=i+4,o=[],a=[];++r<4;)e=n[r%i],o.push(e[0]),a.push(e[1]);for(t=[Ru(Pl,o),",",Ru(Pl,a)],--r;++r<u;)e=n[r%i],o.shift(),o.push(e[0]),a.shift(),a.push(e[1]),Du(t,o,a);return t.join("")}function Tu(n,t){var e=n.length-1;if(e)for(var r,i,u=n[0][0],o=n[0][1],a=n[e][0]-u,l=n[e][1]-o,c=-1;++c<=e;)r=n[c],i=c/e,r[0]=t*r[0]+(1-t)*(u+i*a),r[1]=t*r[1]+(1-t)*(o+i*l);return zu(n)}function Ru(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]+n[3]*t[3]}function Du(n,t,e){n.push("C",Ru(Rl,t),",",Ru(Rl,e),",",Ru(Dl,t),",",Ru(Dl,e),",",Ru(Pl,t),",",Ru(Pl,e))}function Pu(n,t){return(t[1]-n[1])/(t[0]-n[0])}function Uu(n){for(var t=0,e=n.length-1,r=[],i=n[0],u=n[1],o=r[0]=Pu(i,u);++t<e;)r[t]=(o+(o=Pu(i=u,u=n[t+1])))/2;return r[t]=o,r}function ju(n){for(var t,e,r,i,u=[],o=Uu(n),a=-1,l=n.length-1;++a<l;)t=Pu(n[a],n[a+1]),xo(t)<Uo?o[a]=o[a+1]=0:(e=o[a]/t,r=o[a+1]/t,i=e*e+r*r,i>9&&(i=3*t/Math.sqrt(i),o[a]=i*e,o[a+1]=i*r));for(a=-1;++a<=l;)i=(n[Math.min(l,a+1)][0]-n[Math.max(0,a-1)][0])/(6*(1+o[a]*o[a])),u.push([i||0,o[a]*i||0]);return u}function Fu(n){return n.length<3?xu(n):n[0]+Au(n,ju(n))}function Hu(n){for(var t,e,r,i=-1,u=n.length;++i<u;)t=n[i],e=t[0],r=t[1]-Io,t[0]=e*Math.cos(r),t[1]=e*Math.sin(r);return n}function Ou(n){function t(t){function l(){v.push("M",a(n(y),s),f,c(n(d.reverse()),s),"Z")}for(var h,p,g,v=[],d=[],y=[],m=-1,M=t.length,x=En(e),b=En(i),_=e===r?function(){
+return p}:En(r),w=i===u?function(){return g}:En(u);++m<M;)o.call(this,h=t[m],m)?(d.push([p=+x.call(this,h,m),g=+b.call(this,h,m)]),y.push([+_.call(this,h,m),+w.call(this,h,m)])):d.length&&(l(),d=[],y=[]);return d.length&&l(),v.length?v.join(""):null}var e=Ce,r=Ce,i=0,u=ze,o=zt,a=xu,l=a.key,c=a,f="L",s=.7;return t.x=function(n){return arguments.length?(e=r=n,t):r},t.x0=function(n){return arguments.length?(e=n,t):e},t.x1=function(n){return arguments.length?(r=n,t):r},t.y=function(n){return arguments.length?(i=u=n,t):u},t.y0=function(n){return arguments.length?(i=n,t):i},t.y1=function(n){return arguments.length?(u=n,t):u},t.defined=function(n){return arguments.length?(o=n,t):o},t.interpolate=function(n){return arguments.length?(l="function"==typeof n?a=n:(a=Tl.get(n)||xu).key,c=a.reverse||a,f=a.closed?"M":"L",t):l},t.tension=function(n){return arguments.length?(s=n,t):s},t}function Iu(n){return n.radius}function Yu(n){return[n.x,n.y]}function Zu(n){return function(){var t=n.apply(this,arguments),e=t[0],r=t[1]-Io;return[e*Math.cos(r),e*Math.sin(r)]}}function Vu(){return 64}function Xu(){return"circle"}function $u(n){var t=Math.sqrt(n/Fo);return"M0,"+t+"A"+t+","+t+" 0 1,1 0,"+-t+"A"+t+","+t+" 0 1,1 0,"+t+"Z"}function Bu(n){return function(){var t,e,r;(t=this[n])&&(r=t[e=t.active])&&(r.timer.c=null,r.timer.t=NaN,--t.count?delete t[e]:delete this[n],t.active+=.5,r.event&&r.event.interrupt.call(this,this.__data__,r.index))}}function Wu(n,t,e){return ko(n,Yl),n.namespace=t,n.id=e,n}function Ju(n,t,e,r){var i=n.id,u=n.namespace;return Y(n,"function"==typeof e?function(n,o,a){n[u][i].tween.set(t,r(e.call(n,n.__data__,o,a)))}:(e=r(e),function(n){n[u][i].tween.set(t,e)}))}function Gu(n){return null==n&&(n=""),function(){this.textContent=n}}function Ku(n){return null==n?"__transition__":"__transition_"+n+"__"}function Qu(n,t,e,r,i){function u(n){var t=v.delay;return f.t=t+l,n>=t?o(n-t):void(f.c=o)}function o(e){var i=g.active,u=g[i];u&&(u.timer.c=null,u.timer.t=NaN,--g.count,delete g[i],u.event&&u.event.interrupt.call(n,n.__data__,u.index));for(var o in g)if(r>+o){var c=g[o];c.timer.c=null,c.timer.t=NaN,--g.count,delete g[o]}f.c=a,qn(function(){return f.c&&a(e||1)&&(f.c=null,f.t=NaN),1},0,l),g.active=r,v.event&&v.event.start.call(n,n.__data__,t),p=[],v.tween.forEach(function(e,r){(r=r.call(n,n.__data__,t))&&p.push(r)}),h=v.ease,s=v.duration}function a(i){for(var u=i/s,o=h(u),a=p.length;a>0;)p[--a].call(n,o);return u>=1?(v.event&&v.event.end.call(n,n.__data__,t),--g.count?delete g[r]:delete n[e],1):void 0}var l,f,s,h,p,g=n[e]||(n[e]={active:0,count:0}),v=g[r];v||(l=i.time,f=qn(u,0,l),v=g[r]={tween:new c,time:l,timer:f,delay:i.delay,duration:i.duration,ease:i.ease,index:t},i=null,++g.count)}function no(n,t,e){n.attr("transform",function(n){var r=t(n);return"translate("+(isFinite(r)?r:e(n))+",0)"})}function to(n,t,e){n.attr("transform",function(n){var r=t(n);return"translate(0,"+(isFinite(r)?r:e(n))+")"})}function eo(n){return n.toISOString()}function ro(n,t,e){function r(t){return n(t)}function i(n,e){var r=n[1]-n[0],i=r/e,u=ao.bisect(Kl,i);return u==Kl.length?[t.year,Ki(n.map(function(n){return n/31536e6}),e)[2]]:u?t[i/Kl[u-1]<Kl[u]/i?u-1:u]:[tc,Ki(n,e)[2]]}return r.invert=function(t){return io(n.invert(t))},r.domain=function(t){return arguments.length?(n.domain(t),r):n.domain().map(io)},r.nice=function(n,t){function e(e){return!isNaN(e)&&!n.range(e,io(+e+1),t).length}var u=r.domain(),o=Yi(u),a=null==n?i(o,10):"number"==typeof n&&i(o,n);return a&&(n=a[0],t=a[1]),r.domain(Xi(u,t>1?{floor:function(t){for(;e(t=n.floor(t));)t=io(t-1);return t},ceil:function(t){for(;e(t=n.ceil(t));)t=io(+t+1);return t}}:n))},r.ticks=function(n,t){var e=Yi(r.domain()),u=null==n?i(e,10):"number"==typeof n?i(e,n):!n.range&&[{range:n},t];return u&&(n=u[0],t=u[1]),n.range(e[0],io(+e[1]+1),1>t?1:t)},r.tickFormat=function(){return e},r.copy=function(){return ro(n.copy(),t,e)},Ji(r,n)}function io(n){return new Date(n)}function uo(n){return JSON.parse(n.responseText)}function oo(n){var t=fo.createRange();return t.selectNode(fo.body),t.createContextualFragment(n.responseText)}var ao={version:"3.5.16"},lo=[].slice,co=function(n){return lo.call(n)},fo=this.document;if(fo)try{co(fo.documentElement.childNodes)[0].nodeType}catch(so){co=function(n){for(var t=n.length,e=new Array(t);t--;)e[t]=n[t];return e}}if(Date.now||(Date.now=function(){return+new Date}),fo)try{fo.createElement("DIV").style.setProperty("opacity",0,"")}catch(ho){var po=this.Element.prototype,go=po.setAttribute,vo=po.setAttributeNS,yo=this.CSSStyleDeclaration.prototype,mo=yo.setProperty;po.setAttribute=function(n,t){go.call(this,n,t+"")},po.setAttributeNS=function(n,t,e){vo.call(this,n,t,e+"")},yo.setProperty=function(n,t,e){mo.call(this,n,t+"",e)}}ao.ascending=e,ao.descending=function(n,t){return n>t?-1:t>n?1:t>=n?0:NaN},ao.min=function(n,t){var e,r,i=-1,u=n.length;if(1===arguments.length){for(;++i<u;)if(null!=(r=n[i])&&r>=r){e=r;break}for(;++i<u;)null!=(r=n[i])&&e>r&&(e=r)}else{for(;++i<u;)if(null!=(r=t.call(n,n[i],i))&&r>=r){e=r;break}for(;++i<u;)null!=(r=t.call(n,n[i],i))&&e>r&&(e=r)}return e},ao.max=function(n,t){var e,r,i=-1,u=n.length;if(1===arguments.length){for(;++i<u;)if(null!=(r=n[i])&&r>=r){e=r;break}for(;++i<u;)null!=(r=n[i])&&r>e&&(e=r)}else{for(;++i<u;)if(null!=(r=t.call(n,n[i],i))&&r>=r){e=r;break}for(;++i<u;)null!=(r=t.call(n,n[i],i))&&r>e&&(e=r)}return e},ao.extent=function(n,t){var e,r,i,u=-1,o=n.length;if(1===arguments.length){for(;++u<o;)if(null!=(r=n[u])&&r>=r){e=i=r;break}for(;++u<o;)null!=(r=n[u])&&(e>r&&(e=r),r>i&&(i=r))}else{for(;++u<o;)if(null!=(r=t.call(n,n[u],u))&&r>=r){e=i=r;break}for(;++u<o;)null!=(r=t.call(n,n[u],u))&&(e>r&&(e=r),r>i&&(i=r))}return[e,i]},ao.sum=function(n,t){var e,r=0,u=n.length,o=-1;if(1===arguments.length)for(;++o<u;)i(e=+n[o])&&(r+=e);else for(;++o<u;)i(e=+t.call(n,n[o],o))&&(r+=e);return r},ao.mean=function(n,t){var e,u=0,o=n.length,a=-1,l=o;if(1===arguments.length)for(;++a<o;)i(e=r(n[a]))?u+=e:--l;else for(;++a<o;)i(e=r(t.call(n,n[a],a)))?u+=e:--l;return l?u/l:void 0},ao.quantile=function(n,t){var e=(n.length-1)*t+1,r=Math.floor(e),i=+n[r-1],u=e-r;return u?i+u*(n[r]-i):i},ao.median=function(n,t){var u,o=[],a=n.length,l=-1;if(1===arguments.length)for(;++l<a;)i(u=r(n[l]))&&o.push(u);else for(;++l<a;)i(u=r(t.call(n,n[l],l)))&&o.push(u);return o.length?ao.quantile(o.sort(e),.5):void 0},ao.variance=function(n,t){var e,u,o=n.length,a=0,l=0,c=-1,f=0;if(1===arguments.length)for(;++c<o;)i(e=r(n[c]))&&(u=e-a,a+=u/++f,l+=u*(e-a));else for(;++c<o;)i(e=r(t.call(n,n[c],c)))&&(u=e-a,a+=u/++f,l+=u*(e-a));return f>1?l/(f-1):void 0},ao.deviation=function(){var n=ao.variance.apply(this,arguments);return n?Math.sqrt(n):n};var Mo=u(e);ao.bisectLeft=Mo.left,ao.bisect=ao.bisectRight=Mo.right,ao.bisector=function(n){return u(1===n.length?function(t,r){return e(n(t),r)}:n)},ao.shuffle=function(n,t,e){(u=arguments.length)<3&&(e=n.length,2>u&&(t=0));for(var r,i,u=e-t;u;)i=Math.random()*u--|0,r=n[u+t],n[u+t]=n[i+t],n[i+t]=r;return n},ao.permute=function(n,t){for(var e=t.length,r=new Array(e);e--;)r[e]=n[t[e]];return r},ao.pairs=function(n){for(var t,e=0,r=n.length-1,i=n[0],u=new Array(0>r?0:r);r>e;)u[e]=[t=i,i=n[++e]];return u},ao.transpose=function(n){if(!(i=n.length))return[];for(var t=-1,e=ao.min(n,o),r=new Array(e);++t<e;)for(var i,u=-1,a=r[t]=new Array(i);++u<i;)a[u]=n[u][t];return r},ao.zip=function(){return ao.transpose(arguments)},ao.keys=function(n){var t=[];for(var e in n)t.push(e);return t},ao.values=function(n){var t=[];for(var e in n)t.push(n[e]);return t},ao.entries=function(n){var t=[];for(var e in n)t.push({key:e,value:n[e]});return t},ao.merge=function(n){for(var t,e,r,i=n.length,u=-1,o=0;++u<i;)o+=n[u].length;for(e=new Array(o);--i>=0;)for(r=n[i],t=r.length;--t>=0;)e[--o]=r[t];return e};var xo=Math.abs;ao.range=function(n,t,e){if(arguments.length<3&&(e=1,arguments.length<2&&(t=n,n=0)),(t-n)/e===1/0)throw new Error("infinite range");var r,i=[],u=a(xo(e)),o=-1;if(n*=u,t*=u,e*=u,0>e)for(;(r=n+e*++o)>t;)i.push(r/u);else for(;(r=n+e*++o)<t;)i.push(r/u);return i},ao.map=function(n,t){var e=new c;if(n instanceof c)n.forEach(function(n,t){e.set(n,t)});else if(Array.isArray(n)){var r,i=-1,u=n.length;if(1===arguments.length)for(;++i<u;)e.set(i,n[i]);else for(;++i<u;)e.set(t.call(n,r=n[i],i),r)}else for(var o in n)e.set(o,n[o]);return e};var bo="__proto__",_o="\x00";l(c,{has:h,get:function(n){return this._[f(n)]},set:function(n,t){return this._[f(n)]=t},remove:p,keys:g,values:function(){var n=[];for(var t in this._)n.push(this._[t]);return n},entries:function(){var n=[];for(var t in this._)n.push({key:s(t),value:this._[t]});return n},size:v,empty:d,forEach:function(n){for(var t in this._)n.call(this,s(t),this._[t])}}),ao.nest=function(){function n(t,o,a){if(a>=u.length)return r?r.call(i,o):e?o.sort(e):o;for(var l,f,s,h,p=-1,g=o.length,v=u[a++],d=new c;++p<g;)(h=d.get(l=v(f=o[p])))?h.push(f):d.set(l,[f]);return t?(f=t(),s=function(e,r){f.set(e,n(t,r,a))}):(f={},s=function(e,r){f[e]=n(t,r,a)}),d.forEach(s),f}function t(n,e){if(e>=u.length)return n;var r=[],i=o[e++];return n.forEach(function(n,i){r.push({key:n,values:t(i,e)})}),i?r.sort(function(n,t){return i(n.key,t.key)}):r}var e,r,i={},u=[],o=[];return i.map=function(t,e){return n(e,t,0)},i.entries=function(e){return t(n(ao.map,e,0),0)},i.key=function(n){return u.push(n),i},i.sortKeys=function(n){return o[u.length-1]=n,i},i.sortValues=function(n){return e=n,i},i.rollup=function(n){return r=n,i},i},ao.set=function(n){var t=new y;if(n)for(var e=0,r=n.length;r>e;++e)t.add(n[e]);return t},l(y,{has:h,add:function(n){return this._[f(n+="")]=!0,n},remove:p,values:g,size:v,empty:d,forEach:function(n){for(var t in this._)n.call(this,s(t))}}),ao.behavior={},ao.rebind=function(n,t){for(var e,r=1,i=arguments.length;++r<i;)n[e=arguments[r]]=M(n,t,t[e]);return n};var wo=["webkit","ms","moz","Moz","o","O"];ao.dispatch=function(){for(var n=new _,t=-1,e=arguments.length;++t<e;)n[arguments[t]]=w(n);return n},_.prototype.on=function(n,t){var e=n.indexOf("."),r="";if(e>=0&&(r=n.slice(e+1),n=n.slice(0,e)),n)return arguments.length<2?this[n].on(r):this[n].on(r,t);if(2===arguments.length){if(null==t)for(n in this)this.hasOwnProperty(n)&&this[n].on(r,null);return this}},ao.event=null,ao.requote=function(n){return n.replace(So,"\\$&")};var So=/[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g,ko={}.__proto__?function(n,t){n.__proto__=t}:function(n,t){for(var e in t)n[e]=t[e]},No=function(n,t){return t.querySelector(n)},Eo=function(n,t){return t.querySelectorAll(n)},Ao=function(n,t){var e=n.matches||n[x(n,"matchesSelector")];return(Ao=function(n,t){return e.call(n,t)})(n,t)};"function"==typeof Sizzle&&(No=function(n,t){return Sizzle(n,t)[0]||null},Eo=Sizzle,Ao=Sizzle.matchesSelector),ao.selection=function(){return ao.select(fo.documentElement)};var Co=ao.selection.prototype=[];Co.select=function(n){var t,e,r,i,u=[];n=A(n);for(var o=-1,a=this.length;++o<a;){u.push(t=[]),t.parentNode=(r=this[o]).parentNode;for(var l=-1,c=r.length;++l<c;)(i=r[l])?(t.push(e=n.call(i,i.__data__,l,o)),e&&"__data__"in i&&(e.__data__=i.__data__)):t.push(null)}return E(u)},Co.selectAll=function(n){var t,e,r=[];n=C(n);for(var i=-1,u=this.length;++i<u;)for(var o=this[i],a=-1,l=o.length;++a<l;)(e=o[a])&&(r.push(t=co(n.call(e,e.__data__,a,i))),t.parentNode=e);return E(r)};var zo="http://www.w3.org/1999/xhtml",Lo={svg:"http://www.w3.org/2000/svg",xhtml:zo,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};ao.ns={prefix:Lo,qualify:function(n){var t=n.indexOf(":"),e=n;return t>=0&&"xmlns"!==(e=n.slice(0,t))&&(n=n.slice(t+1)),Lo.hasOwnProperty(e)?{space:Lo[e],local:n}:n}},Co.attr=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node();return n=ao.ns.qualify(n),n.local?e.getAttributeNS(n.space,n.local):e.getAttribute(n)}for(t in n)this.each(z(t,n[t]));return this}return this.each(z(n,t))},Co.classed=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node(),r=(n=T(n)).length,i=-1;if(t=e.classList){for(;++i<r;)if(!t.contains(n[i]))return!1}else for(t=e.getAttribute("class");++i<r;)if(!q(n[i]).test(t))return!1;return!0}for(t in n)this.each(R(t,n[t]));return this}return this.each(R(n,t))},Co.style=function(n,e,r){var i=arguments.length;if(3>i){if("string"!=typeof n){2>i&&(e="");for(r in n)this.each(P(r,n[r],e));return this}if(2>i){var u=this.node();return t(u).getComputedStyle(u,null).getPropertyValue(n)}r=""}return this.each(P(n,e,r))},Co.property=function(n,t){if(arguments.length<2){if("string"==typeof n)return this.node()[n];for(t in n)this.each(U(t,n[t]));return this}return this.each(U(n,t))},Co.text=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.textContent=null==t?"":t}:null==n?function(){this.textContent=""}:function(){this.textContent=n}):this.node().textContent},Co.html=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.innerHTML=null==t?"":t}:null==n?function(){this.innerHTML=""}:function(){this.innerHTML=n}):this.node().innerHTML},Co.append=function(n){return n=j(n),this.select(function(){return this.appendChild(n.apply(this,arguments))})},Co.insert=function(n,t){return n=j(n),t=A(t),this.select(function(){return this.insertBefore(n.apply(this,arguments),t.apply(this,arguments)||null)})},Co.remove=function(){return this.each(F)},Co.data=function(n,t){function e(n,e){var r,i,u,o=n.length,s=e.length,h=Math.min(o,s),p=new Array(s),g=new Array(s),v=new Array(o);if(t){var d,y=new c,m=new Array(o);for(r=-1;++r<o;)(i=n[r])&&(y.has(d=t.call(i,i.__data__,r))?v[r]=i:y.set(d,i),m[r]=d);for(r=-1;++r<s;)(i=y.get(d=t.call(e,u=e[r],r)))?i!==!0&&(p[r]=i,i.__data__=u):g[r]=H(u),y.set(d,!0);for(r=-1;++r<o;)r in m&&y.get(m[r])!==!0&&(v[r]=n[r])}else{for(r=-1;++r<h;)i=n[r],u=e[r],i?(i.__data__=u,p[r]=i):g[r]=H(u);for(;s>r;++r)g[r]=H(e[r]);for(;o>r;++r)v[r]=n[r]}g.update=p,g.parentNode=p.parentNode=v.parentNode=n.parentNode,a.push(g),l.push(p),f.push(v)}var r,i,u=-1,o=this.length;if(!arguments.length){for(n=new Array(o=(r=this[0]).length);++u<o;)(i=r[u])&&(n[u]=i.__data__);return n}var a=Z([]),l=E([]),f=E([]);if("function"==typeof n)for(;++u<o;)e(r=this[u],n.call(r,r.parentNode.__data__,u));else for(;++u<o;)e(r=this[u],n);return l.enter=function(){return a},l.exit=function(){return f},l},Co.datum=function(n){return arguments.length?this.property("__data__",n):this.property("__data__")},Co.filter=function(n){var t,e,r,i=[];"function"!=typeof n&&(n=O(n));for(var u=0,o=this.length;o>u;u++){i.push(t=[]),t.parentNode=(e=this[u]).parentNode;for(var a=0,l=e.length;l>a;a++)(r=e[a])&&n.call(r,r.__data__,a,u)&&t.push(r)}return E(i)},Co.order=function(){for(var n=-1,t=this.length;++n<t;)for(var e,r=this[n],i=r.length-1,u=r[i];--i>=0;)(e=r[i])&&(u&&u!==e.nextSibling&&u.parentNode.insertBefore(e,u),u=e);return this},Co.sort=function(n){n=I.apply(this,arguments);for(var t=-1,e=this.length;++t<e;)this[t].sort(n);return this.order()},Co.each=function(n){return Y(this,function(t,e,r){n.call(t,t.__data__,e,r)})},Co.call=function(n){var t=co(arguments);return n.apply(t[0]=this,t),this},Co.empty=function(){return!this.node()},Co.node=function(){for(var n=0,t=this.length;t>n;n++)for(var e=this[n],r=0,i=e.length;i>r;r++){var u=e[r];if(u)return u}return null},Co.size=function(){var n=0;return Y(this,function(){++n}),n};var qo=[];ao.selection.enter=Z,ao.selection.enter.prototype=qo,qo.append=Co.append,qo.empty=Co.empty,qo.node=Co.node,qo.call=Co.call,qo.size=Co.size,qo.select=function(n){for(var t,e,r,i,u,o=[],a=-1,l=this.length;++a<l;){r=(i=this[a]).update,o.push(t=[]),t.parentNode=i.parentNode;for(var c=-1,f=i.length;++c<f;)(u=i[c])?(t.push(r[c]=e=n.call(i.parentNode,u.__data__,c,a)),e.__data__=u.__data__):t.push(null)}return E(o)},qo.insert=function(n,t){return arguments.length<2&&(t=V(this)),Co.insert.call(this,n,t)},ao.select=function(t){var e;return"string"==typeof t?(e=[No(t,fo)],e.parentNode=fo.documentElement):(e=[t],e.parentNode=n(t)),E([e])},ao.selectAll=function(n){var t;return"string"==typeof n?(t=co(Eo(n,fo)),t.parentNode=fo.documentElement):(t=co(n),t.parentNode=null),E([t])},Co.on=function(n,t,e){var r=arguments.length;if(3>r){if("string"!=typeof n){2>r&&(t=!1);for(e in n)this.each(X(e,n[e],t));return this}if(2>r)return(r=this.node()["__on"+n])&&r._;e=!1}return this.each(X(n,t,e))};var To=ao.map({mouseenter:"mouseover",mouseleave:"mouseout"});fo&&To.forEach(function(n){"on"+n in fo&&To.remove(n)});var Ro,Do=0;ao.mouse=function(n){return J(n,k())};var Po=this.navigator&&/WebKit/.test(this.navigator.userAgent)?-1:0;ao.touch=function(n,t,e){if(arguments.length<3&&(e=t,t=k().changedTouches),t)for(var r,i=0,u=t.length;u>i;++i)if((r=t[i]).identifier===e)return J(n,r)},ao.behavior.drag=function(){function n(){this.on("mousedown.drag",u).on("touchstart.drag",o)}function e(n,t,e,u,o){return function(){function a(){var n,e,r=t(h,v);r&&(n=r[0]-M[0],e=r[1]-M[1],g|=n|e,M=r,p({type:"drag",x:r[0]+c[0],y:r[1]+c[1],dx:n,dy:e}))}function l(){t(h,v)&&(y.on(u+d,null).on(o+d,null),m(g),p({type:"dragend"}))}var c,f=this,s=ao.event.target.correspondingElement||ao.event.target,h=f.parentNode,p=r.of(f,arguments),g=0,v=n(),d=".drag"+(null==v?"":"-"+v),y=ao.select(e(s)).on(u+d,a).on(o+d,l),m=W(s),M=t(h,v);i?(c=i.apply(f,arguments),c=[c.x-M[0],c.y-M[1]]):c=[0,0],p({type:"dragstart"})}}var r=N(n,"drag","dragstart","dragend"),i=null,u=e(b,ao.mouse,t,"mousemove","mouseup"),o=e(G,ao.touch,m,"touchmove","touchend");return n.origin=function(t){return arguments.length?(i=t,n):i},ao.rebind(n,r,"on")},ao.touches=function(n,t){return arguments.length<2&&(t=k().touches),t?co(t).map(function(t){var e=J(n,t);return e.identifier=t.identifier,e}):[]};var Uo=1e-6,jo=Uo*Uo,Fo=Math.PI,Ho=2*Fo,Oo=Ho-Uo,Io=Fo/2,Yo=Fo/180,Zo=180/Fo,Vo=Math.SQRT2,Xo=2,$o=4;ao.interpolateZoom=function(n,t){var e,r,i=n[0],u=n[1],o=n[2],a=t[0],l=t[1],c=t[2],f=a-i,s=l-u,h=f*f+s*s;if(jo>h)r=Math.log(c/o)/Vo,e=function(n){return[i+n*f,u+n*s,o*Math.exp(Vo*n*r)]};else{var p=Math.sqrt(h),g=(c*c-o*o+$o*h)/(2*o*Xo*p),v=(c*c-o*o-$o*h)/(2*c*Xo*p),d=Math.log(Math.sqrt(g*g+1)-g),y=Math.log(Math.sqrt(v*v+1)-v);r=(y-d)/Vo,e=function(n){var t=n*r,e=rn(d),a=o/(Xo*p)*(e*un(Vo*t+d)-en(d));return[i+a*f,u+a*s,o*e/rn(Vo*t+d)]}}return e.duration=1e3*r,e},ao.behavior.zoom=function(){function n(n){n.on(L,s).on(Wo+".zoom",p).on("dblclick.zoom",g).on(R,h)}function e(n){return[(n[0]-k.x)/k.k,(n[1]-k.y)/k.k]}function r(n){return[n[0]*k.k+k.x,n[1]*k.k+k.y]}function i(n){k.k=Math.max(A[0],Math.min(A[1],n))}function u(n,t){t=r(t),k.x+=n[0]-t[0],k.y+=n[1]-t[1]}function o(t,e,r,o){t.__chart__={x:k.x,y:k.y,k:k.k},i(Math.pow(2,o)),u(d=e,r),t=ao.select(t),C>0&&(t=t.transition().duration(C)),t.call(n.event)}function a(){b&&b.domain(x.range().map(function(n){return(n-k.x)/k.k}).map(x.invert)),w&&w.domain(_.range().map(function(n){return(n-k.y)/k.k}).map(_.invert))}function l(n){z++||n({type:"zoomstart"})}function c(n){a(),n({type:"zoom",scale:k.k,translate:[k.x,k.y]})}function f(n){--z||(n({type:"zoomend"}),d=null)}function s(){function n(){a=1,u(ao.mouse(i),h),c(o)}function r(){s.on(q,null).on(T,null),p(a),f(o)}var i=this,o=D.of(i,arguments),a=0,s=ao.select(t(i)).on(q,n).on(T,r),h=e(ao.mouse(i)),p=W(i);Il.call(i),l(o)}function h(){function n(){var n=ao.touches(g);return p=k.k,n.forEach(function(n){n.identifier in d&&(d[n.identifier]=e(n))}),n}function t(){var t=ao.event.target;ao.select(t).on(x,r).on(b,a),_.push(t);for(var e=ao.event.changedTouches,i=0,u=e.length;u>i;++i)d[e[i].identifier]=null;var l=n(),c=Date.now();if(1===l.length){if(500>c-M){var f=l[0];o(g,f,d[f.identifier],Math.floor(Math.log(k.k)/Math.LN2)+1),S()}M=c}else if(l.length>1){var f=l[0],s=l[1],h=f[0]-s[0],p=f[1]-s[1];y=h*h+p*p}}function r(){var n,t,e,r,o=ao.touches(g);Il.call(g);for(var a=0,l=o.length;l>a;++a,r=null)if(e=o[a],r=d[e.identifier]){if(t)break;n=e,t=r}if(r){var f=(f=e[0]-n[0])*f+(f=e[1]-n[1])*f,s=y&&Math.sqrt(f/y);n=[(n[0]+e[0])/2,(n[1]+e[1])/2],t=[(t[0]+r[0])/2,(t[1]+r[1])/2],i(s*p)}M=null,u(n,t),c(v)}function a(){if(ao.event.touches.length){for(var t=ao.event.changedTouches,e=0,r=t.length;r>e;++e)delete d[t[e].identifier];for(var i in d)return void n()}ao.selectAll(_).on(m,null),w.on(L,s).on(R,h),N(),f(v)}var p,g=this,v=D.of(g,arguments),d={},y=0,m=".zoom-"+ao.event.changedTouches[0].identifier,x="touchmove"+m,b="touchend"+m,_=[],w=ao.select(g),N=W(g);t(),l(v),w.on(L,null).on(R,t)}function p(){var n=D.of(this,arguments);m?clearTimeout(m):(Il.call(this),v=e(d=y||ao.mouse(this)),l(n)),m=setTimeout(function(){m=null,f(n)},50),S(),i(Math.pow(2,.002*Bo())*k.k),u(d,v),c(n)}function g(){var n=ao.mouse(this),t=Math.log(k.k)/Math.LN2;o(this,n,e(n),ao.event.shiftKey?Math.ceil(t)-1:Math.floor(t)+1)}var v,d,y,m,M,x,b,_,w,k={x:0,y:0,k:1},E=[960,500],A=Jo,C=250,z=0,L="mousedown.zoom",q="mousemove.zoom",T="mouseup.zoom",R="touchstart.zoom",D=N(n,"zoomstart","zoom","zoomend");return Wo||(Wo="onwheel"in fo?(Bo=function(){return-ao.event.deltaY*(ao.event.deltaMode?120:1)},"wheel"):"onmousewheel"in fo?(Bo=function(){return ao.event.wheelDelta},"mousewheel"):(Bo=function(){return-ao.event.detail},"MozMousePixelScroll")),n.event=function(n){n.each(function(){var n=D.of(this,arguments),t=k;Hl?ao.select(this).transition().each("start.zoom",function(){k=this.__chart__||{x:0,y:0,k:1},l(n)}).tween("zoom:zoom",function(){var e=E[0],r=E[1],i=d?d[0]:e/2,u=d?d[1]:r/2,o=ao.interpolateZoom([(i-k.x)/k.k,(u-k.y)/k.k,e/k.k],[(i-t.x)/t.k,(u-t.y)/t.k,e/t.k]);return function(t){var r=o(t),a=e/r[2];this.__chart__=k={x:i-r[0]*a,y:u-r[1]*a,k:a},c(n)}}).each("interrupt.zoom",function(){f(n)}).each("end.zoom",function(){f(n)}):(this.__chart__=k,l(n),c(n),f(n))})},n.translate=function(t){return arguments.length?(k={x:+t[0],y:+t[1],k:k.k},a(),n):[k.x,k.y]},n.scale=function(t){return arguments.length?(k={x:k.x,y:k.y,k:null},i(+t),a(),n):k.k},n.scaleExtent=function(t){return arguments.length?(A=null==t?Jo:[+t[0],+t[1]],n):A},n.center=function(t){return arguments.length?(y=t&&[+t[0],+t[1]],n):y},n.size=function(t){return arguments.length?(E=t&&[+t[0],+t[1]],n):E},n.duration=function(t){return arguments.length?(C=+t,n):C},n.x=function(t){return arguments.length?(b=t,x=t.copy(),k={x:0,y:0,k:1},n):b},n.y=function(t){return arguments.length?(w=t,_=t.copy(),k={x:0,y:0,k:1},n):w},ao.rebind(n,D,"on")};var Bo,Wo,Jo=[0,1/0];ao.color=an,an.prototype.toString=function(){return this.rgb()+""},ao.hsl=ln;var Go=ln.prototype=new an;Go.brighter=function(n){return n=Math.pow(.7,arguments.length?n:1),new ln(this.h,this.s,this.l/n)},Go.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),new ln(this.h,this.s,n*this.l)},Go.rgb=function(){return cn(this.h,this.s,this.l)},ao.hcl=fn;var Ko=fn.prototype=new an;Ko.brighter=function(n){return new fn(this.h,this.c,Math.min(100,this.l+Qo*(arguments.length?n:1)))},Ko.darker=function(n){return new fn(this.h,this.c,Math.max(0,this.l-Qo*(arguments.length?n:1)))},Ko.rgb=function(){return sn(this.h,this.c,this.l).rgb()},ao.lab=hn;var Qo=18,na=.95047,ta=1,ea=1.08883,ra=hn.prototype=new an;ra.brighter=function(n){return new hn(Math.min(100,this.l+Qo*(arguments.length?n:1)),this.a,this.b)},ra.darker=function(n){return new hn(Math.max(0,this.l-Qo*(arguments.length?n:1)),this.a,this.b)},ra.rgb=function(){return pn(this.l,this.a,this.b)},ao.rgb=mn;var ia=mn.prototype=new an;ia.brighter=function(n){n=Math.pow(.7,arguments.length?n:1);var t=this.r,e=this.g,r=this.b,i=30;return t||e||r?(t&&i>t&&(t=i),e&&i>e&&(e=i),r&&i>r&&(r=i),new mn(Math.min(255,t/n),Math.min(255,e/n),Math.min(255,r/n))):new mn(i,i,i)},ia.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),new mn(n*this.r,n*this.g,n*this.b)},ia.hsl=function(){return wn(this.r,this.g,this.b)},ia.toString=function(){return"#"+bn(this.r)+bn(this.g)+bn(this.b)};var ua=ao.map({aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074});ua.forEach(function(n,t){ua.set(n,Mn(t))}),ao.functor=En,ao.xhr=An(m),ao.dsv=function(n,t){function e(n,e,u){arguments.length<3&&(u=e,e=null);var o=Cn(n,t,null==e?r:i(e),u);return o.row=function(n){return arguments.length?o.response(null==(e=n)?r:i(n)):e},o}function r(n){return e.parse(n.responseText)}function i(n){return function(t){return e.parse(t.responseText,n)}}function u(t){return t.map(o).join(n)}function o(n){return a.test(n)?'"'+n.replace(/\"/g,'""')+'"':n}var a=new RegExp('["'+n+"\n]"),l=n.charCodeAt(0);return e.parse=function(n,t){var r;return e.parseRows(n,function(n,e){if(r)return r(n,e-1);var i=new Function("d","return {"+n.map(function(n,t){return JSON.stringify(n)+": d["+t+"]"}).join(",")+"}");r=t?function(n,e){return t(i(n),e)}:i})},e.parseRows=function(n,t){function e(){if(f>=c)return o;if(i)return i=!1,u;var t=f;if(34===n.charCodeAt(t)){for(var e=t;e++<c;)if(34===n.charCodeAt(e)){if(34!==n.charCodeAt(e+1))break;++e}f=e+2;var r=n.charCodeAt(e+1);return 13===r?(i=!0,10===n.charCodeAt(e+2)&&++f):10===r&&(i=!0),n.slice(t+1,e).replace(/""/g,'"')}for(;c>f;){var r=n.charCodeAt(f++),a=1;if(10===r)i=!0;else if(13===r)i=!0,10===n.charCodeAt(f)&&(++f,++a);else if(r!==l)continue;return n.slice(t,f-a)}return n.slice(t)}for(var r,i,u={},o={},a=[],c=n.length,f=0,s=0;(r=e())!==o;){for(var h=[];r!==u&&r!==o;)h.push(r),r=e();t&&null==(h=t(h,s++))||a.push(h)}return a},e.format=function(t){if(Array.isArray(t[0]))return e.formatRows(t);var r=new y,i=[];return t.forEach(function(n){for(var t in n)r.has(t)||i.push(r.add(t))}),[i.map(o).join(n)].concat(t.map(function(t){return i.map(function(n){return o(t[n])}).join(n)})).join("\n")},e.formatRows=function(n){return n.map(u).join("\n")},e},ao.csv=ao.dsv(",","text/csv"),ao.tsv=ao.dsv("	","text/tab-separated-values");var oa,aa,la,ca,fa=this[x(this,"requestAnimationFrame")]||function(n){setTimeout(n,17)};ao.timer=function(){qn.apply(this,arguments)},ao.timer.flush=function(){Rn(),Dn()},ao.round=function(n,t){return t?Math.round(n*(t=Math.pow(10,t)))/t:Math.round(n)};var sa=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"].map(Un);ao.formatPrefix=function(n,t){var e=0;return(n=+n)&&(0>n&&(n*=-1),t&&(n=ao.round(n,Pn(n,t))),e=1+Math.floor(1e-12+Math.log(n)/Math.LN10),e=Math.max(-24,Math.min(24,3*Math.floor((e-1)/3)))),sa[8+e/3]};var ha=/(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i,pa=ao.map({b:function(n){return n.toString(2)},c:function(n){return String.fromCharCode(n)},o:function(n){return n.toString(8)},x:function(n){return n.toString(16)},X:function(n){return n.toString(16).toUpperCase()},g:function(n,t){return n.toPrecision(t)},e:function(n,t){return n.toExponential(t)},f:function(n,t){return n.toFixed(t)},r:function(n,t){return(n=ao.round(n,Pn(n,t))).toFixed(Math.max(0,Math.min(20,Pn(n*(1+1e-15),t))))}}),ga=ao.time={},va=Date;Hn.prototype={getDate:function(){return this._.getUTCDate()},getDay:function(){return this._.getUTCDay()},getFullYear:function(){return this._.getUTCFullYear()},getHours:function(){return this._.getUTCHours()},getMilliseconds:function(){return this._.getUTCMilliseconds()},getMinutes:function(){return this._.getUTCMinutes()},getMonth:function(){return this._.getUTCMonth()},getSeconds:function(){return this._.getUTCSeconds()},getTime:function(){return this._.getTime()},getTimezoneOffset:function(){return 0},valueOf:function(){return this._.valueOf()},setDate:function(){da.setUTCDate.apply(this._,arguments)},setDay:function(){da.setUTCDay.apply(this._,arguments)},setFullYear:function(){da.setUTCFullYear.apply(this._,arguments)},setHours:function(){da.setUTCHours.apply(this._,arguments)},setMilliseconds:function(){da.setUTCMilliseconds.apply(this._,arguments)},setMinutes:function(){da.setUTCMinutes.apply(this._,arguments)},setMonth:function(){da.setUTCMonth.apply(this._,arguments)},setSeconds:function(){da.setUTCSeconds.apply(this._,arguments)},setTime:function(){da.setTime.apply(this._,arguments)}};var da=Date.prototype;ga.year=On(function(n){return n=ga.day(n),n.setMonth(0,1),n},function(n,t){n.setFullYear(n.getFullYear()+t)},function(n){return n.getFullYear()}),ga.years=ga.year.range,ga.years.utc=ga.year.utc.range,ga.day=On(function(n){var t=new va(2e3,0);return t.setFullYear(n.getFullYear(),n.getMonth(),n.getDate()),t},function(n,t){n.setDate(n.getDate()+t)},function(n){return n.getDate()-1}),ga.days=ga.day.range,ga.days.utc=ga.day.utc.range,ga.dayOfYear=function(n){var t=ga.year(n);return Math.floor((n-t-6e4*(n.getTimezoneOffset()-t.getTimezoneOffset()))/864e5)},["sunday","monday","tuesday","wednesday","thursday","friday","saturday"].forEach(function(n,t){t=7-t;var e=ga[n]=On(function(n){return(n=ga.day(n)).setDate(n.getDate()-(n.getDay()+t)%7),n},function(n,t){n.setDate(n.getDate()+7*Math.floor(t))},function(n){var e=ga.year(n).getDay();return Math.floor((ga.dayOfYear(n)+(e+t)%7)/7)-(e!==t)});ga[n+"s"]=e.range,ga[n+"s"].utc=e.utc.range,ga[n+"OfYear"]=function(n){var e=ga.year(n).getDay();return Math.floor((ga.dayOfYear(n)+(e+t)%7)/7)}}),ga.week=ga.sunday,ga.weeks=ga.sunday.range,ga.weeks.utc=ga.sunday.utc.range,ga.weekOfYear=ga.sundayOfYear;var ya={"-":"",_:" ",0:"0"},ma=/^\s*\d+/,Ma=/^%/;ao.locale=function(n){return{numberFormat:jn(n),timeFormat:Yn(n)}};var xa=ao.locale({decimal:".",thousands:",",grouping:[3],currency:["$",""],dateTime:"%a %b %e %X %Y",date:"%m/%d/%Y",time:"%H:%M:%S",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],
+shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});ao.format=xa.numberFormat,ao.geo={},ft.prototype={s:0,t:0,add:function(n){st(n,this.t,ba),st(ba.s,this.s,this),this.s?this.t+=ba.t:this.s=ba.t},reset:function(){this.s=this.t=0},valueOf:function(){return this.s}};var ba=new ft;ao.geo.stream=function(n,t){n&&_a.hasOwnProperty(n.type)?_a[n.type](n,t):ht(n,t)};var _a={Feature:function(n,t){ht(n.geometry,t)},FeatureCollection:function(n,t){for(var e=n.features,r=-1,i=e.length;++r<i;)ht(e[r].geometry,t)}},wa={Sphere:function(n,t){t.sphere()},Point:function(n,t){n=n.coordinates,t.point(n[0],n[1],n[2])},MultiPoint:function(n,t){for(var e=n.coordinates,r=-1,i=e.length;++r<i;)n=e[r],t.point(n[0],n[1],n[2])},LineString:function(n,t){pt(n.coordinates,t,0)},MultiLineString:function(n,t){for(var e=n.coordinates,r=-1,i=e.length;++r<i;)pt(e[r],t,0)},Polygon:function(n,t){gt(n.coordinates,t)},MultiPolygon:function(n,t){for(var e=n.coordinates,r=-1,i=e.length;++r<i;)gt(e[r],t)},GeometryCollection:function(n,t){for(var e=n.geometries,r=-1,i=e.length;++r<i;)ht(e[r],t)}};ao.geo.area=function(n){return Sa=0,ao.geo.stream(n,Na),Sa};var Sa,ka=new ft,Na={sphere:function(){Sa+=4*Fo},point:b,lineStart:b,lineEnd:b,polygonStart:function(){ka.reset(),Na.lineStart=vt},polygonEnd:function(){var n=2*ka;Sa+=0>n?4*Fo+n:n,Na.lineStart=Na.lineEnd=Na.point=b}};ao.geo.bounds=function(){function n(n,t){M.push(x=[f=n,h=n]),s>t&&(s=t),t>p&&(p=t)}function t(t,e){var r=dt([t*Yo,e*Yo]);if(y){var i=mt(y,r),u=[i[1],-i[0],0],o=mt(u,i);bt(o),o=_t(o);var l=t-g,c=l>0?1:-1,v=o[0]*Zo*c,d=xo(l)>180;if(d^(v>c*g&&c*t>v)){var m=o[1]*Zo;m>p&&(p=m)}else if(v=(v+360)%360-180,d^(v>c*g&&c*t>v)){var m=-o[1]*Zo;s>m&&(s=m)}else s>e&&(s=e),e>p&&(p=e);d?g>t?a(f,t)>a(f,h)&&(h=t):a(t,h)>a(f,h)&&(f=t):h>=f?(f>t&&(f=t),t>h&&(h=t)):t>g?a(f,t)>a(f,h)&&(h=t):a(t,h)>a(f,h)&&(f=t)}else n(t,e);y=r,g=t}function e(){b.point=t}function r(){x[0]=f,x[1]=h,b.point=n,y=null}function i(n,e){if(y){var r=n-g;m+=xo(r)>180?r+(r>0?360:-360):r}else v=n,d=e;Na.point(n,e),t(n,e)}function u(){Na.lineStart()}function o(){i(v,d),Na.lineEnd(),xo(m)>Uo&&(f=-(h=180)),x[0]=f,x[1]=h,y=null}function a(n,t){return(t-=n)<0?t+360:t}function l(n,t){return n[0]-t[0]}function c(n,t){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:n<t[0]||t[1]<n}var f,s,h,p,g,v,d,y,m,M,x,b={point:n,lineStart:e,lineEnd:r,polygonStart:function(){b.point=i,b.lineStart=u,b.lineEnd=o,m=0,Na.polygonStart()},polygonEnd:function(){Na.polygonEnd(),b.point=n,b.lineStart=e,b.lineEnd=r,0>ka?(f=-(h=180),s=-(p=90)):m>Uo?p=90:-Uo>m&&(s=-90),x[0]=f,x[1]=h}};return function(n){p=h=-(f=s=1/0),M=[],ao.geo.stream(n,b);var t=M.length;if(t){M.sort(l);for(var e,r=1,i=M[0],u=[i];t>r;++r)e=M[r],c(e[0],i)||c(e[1],i)?(a(i[0],e[1])>a(i[0],i[1])&&(i[1]=e[1]),a(e[0],i[1])>a(i[0],i[1])&&(i[0]=e[0])):u.push(i=e);for(var o,e,g=-(1/0),t=u.length-1,r=0,i=u[t];t>=r;i=e,++r)e=u[r],(o=a(i[1],e[0]))>g&&(g=o,f=e[0],h=i[1])}return M=x=null,f===1/0||s===1/0?[[NaN,NaN],[NaN,NaN]]:[[f,s],[h,p]]}}(),ao.geo.centroid=function(n){Ea=Aa=Ca=za=La=qa=Ta=Ra=Da=Pa=Ua=0,ao.geo.stream(n,ja);var t=Da,e=Pa,r=Ua,i=t*t+e*e+r*r;return jo>i&&(t=qa,e=Ta,r=Ra,Uo>Aa&&(t=Ca,e=za,r=La),i=t*t+e*e+r*r,jo>i)?[NaN,NaN]:[Math.atan2(e,t)*Zo,tn(r/Math.sqrt(i))*Zo]};var Ea,Aa,Ca,za,La,qa,Ta,Ra,Da,Pa,Ua,ja={sphere:b,point:St,lineStart:Nt,lineEnd:Et,polygonStart:function(){ja.lineStart=At},polygonEnd:function(){ja.lineStart=Nt}},Fa=Rt(zt,jt,Ht,[-Fo,-Fo/2]),Ha=1e9;ao.geo.clipExtent=function(){var n,t,e,r,i,u,o={stream:function(n){return i&&(i.valid=!1),i=u(n),i.valid=!0,i},extent:function(a){return arguments.length?(u=Zt(n=+a[0][0],t=+a[0][1],e=+a[1][0],r=+a[1][1]),i&&(i.valid=!1,i=null),o):[[n,t],[e,r]]}};return o.extent([[0,0],[960,500]])},(ao.geo.conicEqualArea=function(){return Vt(Xt)}).raw=Xt,ao.geo.albers=function(){return ao.geo.conicEqualArea().rotate([96,0]).center([-.6,38.7]).parallels([29.5,45.5]).scale(1070)},ao.geo.albersUsa=function(){function n(n){var u=n[0],o=n[1];return t=null,e(u,o),t||(r(u,o),t)||i(u,o),t}var t,e,r,i,u=ao.geo.albers(),o=ao.geo.conicEqualArea().rotate([154,0]).center([-2,58.5]).parallels([55,65]),a=ao.geo.conicEqualArea().rotate([157,0]).center([-3,19.9]).parallels([8,18]),l={point:function(n,e){t=[n,e]}};return n.invert=function(n){var t=u.scale(),e=u.translate(),r=(n[0]-e[0])/t,i=(n[1]-e[1])/t;return(i>=.12&&.234>i&&r>=-.425&&-.214>r?o:i>=.166&&.234>i&&r>=-.214&&-.115>r?a:u).invert(n)},n.stream=function(n){var t=u.stream(n),e=o.stream(n),r=a.stream(n);return{point:function(n,i){t.point(n,i),e.point(n,i),r.point(n,i)},sphere:function(){t.sphere(),e.sphere(),r.sphere()},lineStart:function(){t.lineStart(),e.lineStart(),r.lineStart()},lineEnd:function(){t.lineEnd(),e.lineEnd(),r.lineEnd()},polygonStart:function(){t.polygonStart(),e.polygonStart(),r.polygonStart()},polygonEnd:function(){t.polygonEnd(),e.polygonEnd(),r.polygonEnd()}}},n.precision=function(t){return arguments.length?(u.precision(t),o.precision(t),a.precision(t),n):u.precision()},n.scale=function(t){return arguments.length?(u.scale(t),o.scale(.35*t),a.scale(t),n.translate(u.translate())):u.scale()},n.translate=function(t){if(!arguments.length)return u.translate();var c=u.scale(),f=+t[0],s=+t[1];return e=u.translate(t).clipExtent([[f-.455*c,s-.238*c],[f+.455*c,s+.238*c]]).stream(l).point,r=o.translate([f-.307*c,s+.201*c]).clipExtent([[f-.425*c+Uo,s+.12*c+Uo],[f-.214*c-Uo,s+.234*c-Uo]]).stream(l).point,i=a.translate([f-.205*c,s+.212*c]).clipExtent([[f-.214*c+Uo,s+.166*c+Uo],[f-.115*c-Uo,s+.234*c-Uo]]).stream(l).point,n},n.scale(1070)};var Oa,Ia,Ya,Za,Va,Xa,$a={point:b,lineStart:b,lineEnd:b,polygonStart:function(){Ia=0,$a.lineStart=$t},polygonEnd:function(){$a.lineStart=$a.lineEnd=$a.point=b,Oa+=xo(Ia/2)}},Ba={point:Bt,lineStart:b,lineEnd:b,polygonStart:b,polygonEnd:b},Wa={point:Gt,lineStart:Kt,lineEnd:Qt,polygonStart:function(){Wa.lineStart=ne},polygonEnd:function(){Wa.point=Gt,Wa.lineStart=Kt,Wa.lineEnd=Qt}};ao.geo.path=function(){function n(n){return n&&("function"==typeof a&&u.pointRadius(+a.apply(this,arguments)),o&&o.valid||(o=i(u)),ao.geo.stream(n,o)),u.result()}function t(){return o=null,n}var e,r,i,u,o,a=4.5;return n.area=function(n){return Oa=0,ao.geo.stream(n,i($a)),Oa},n.centroid=function(n){return Ca=za=La=qa=Ta=Ra=Da=Pa=Ua=0,ao.geo.stream(n,i(Wa)),Ua?[Da/Ua,Pa/Ua]:Ra?[qa/Ra,Ta/Ra]:La?[Ca/La,za/La]:[NaN,NaN]},n.bounds=function(n){return Va=Xa=-(Ya=Za=1/0),ao.geo.stream(n,i(Ba)),[[Ya,Za],[Va,Xa]]},n.projection=function(n){return arguments.length?(i=(e=n)?n.stream||re(n):m,t()):e},n.context=function(n){return arguments.length?(u=null==(r=n)?new Wt:new te(n),"function"!=typeof a&&u.pointRadius(a),t()):r},n.pointRadius=function(t){return arguments.length?(a="function"==typeof t?t:(u.pointRadius(+t),+t),n):a},n.projection(ao.geo.albersUsa()).context(null)},ao.geo.transform=function(n){return{stream:function(t){var e=new ie(t);for(var r in n)e[r]=n[r];return e}}},ie.prototype={point:function(n,t){this.stream.point(n,t)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}},ao.geo.projection=oe,ao.geo.projectionMutator=ae,(ao.geo.equirectangular=function(){return oe(ce)}).raw=ce.invert=ce,ao.geo.rotation=function(n){function t(t){return t=n(t[0]*Yo,t[1]*Yo),t[0]*=Zo,t[1]*=Zo,t}return n=se(n[0]%360*Yo,n[1]*Yo,n.length>2?n[2]*Yo:0),t.invert=function(t){return t=n.invert(t[0]*Yo,t[1]*Yo),t[0]*=Zo,t[1]*=Zo,t},t},fe.invert=ce,ao.geo.circle=function(){function n(){var n="function"==typeof r?r.apply(this,arguments):r,t=se(-n[0]*Yo,-n[1]*Yo,0).invert,i=[];return e(null,null,1,{point:function(n,e){i.push(n=t(n,e)),n[0]*=Zo,n[1]*=Zo}}),{type:"Polygon",coordinates:[i]}}var t,e,r=[0,0],i=6;return n.origin=function(t){return arguments.length?(r=t,n):r},n.angle=function(r){return arguments.length?(e=ve((t=+r)*Yo,i*Yo),n):t},n.precision=function(r){return arguments.length?(e=ve(t*Yo,(i=+r)*Yo),n):i},n.angle(90)},ao.geo.distance=function(n,t){var e,r=(t[0]-n[0])*Yo,i=n[1]*Yo,u=t[1]*Yo,o=Math.sin(r),a=Math.cos(r),l=Math.sin(i),c=Math.cos(i),f=Math.sin(u),s=Math.cos(u);return Math.atan2(Math.sqrt((e=s*o)*e+(e=c*f-l*s*a)*e),l*f+c*s*a)},ao.geo.graticule=function(){function n(){return{type:"MultiLineString",coordinates:t()}}function t(){return ao.range(Math.ceil(u/d)*d,i,d).map(h).concat(ao.range(Math.ceil(c/y)*y,l,y).map(p)).concat(ao.range(Math.ceil(r/g)*g,e,g).filter(function(n){return xo(n%d)>Uo}).map(f)).concat(ao.range(Math.ceil(a/v)*v,o,v).filter(function(n){return xo(n%y)>Uo}).map(s))}var e,r,i,u,o,a,l,c,f,s,h,p,g=10,v=g,d=90,y=360,m=2.5;return n.lines=function(){return t().map(function(n){return{type:"LineString",coordinates:n}})},n.outline=function(){return{type:"Polygon",coordinates:[h(u).concat(p(l).slice(1),h(i).reverse().slice(1),p(c).reverse().slice(1))]}},n.extent=function(t){return arguments.length?n.majorExtent(t).minorExtent(t):n.minorExtent()},n.majorExtent=function(t){return arguments.length?(u=+t[0][0],i=+t[1][0],c=+t[0][1],l=+t[1][1],u>i&&(t=u,u=i,i=t),c>l&&(t=c,c=l,l=t),n.precision(m)):[[u,c],[i,l]]},n.minorExtent=function(t){return arguments.length?(r=+t[0][0],e=+t[1][0],a=+t[0][1],o=+t[1][1],r>e&&(t=r,r=e,e=t),a>o&&(t=a,a=o,o=t),n.precision(m)):[[r,a],[e,o]]},n.step=function(t){return arguments.length?n.majorStep(t).minorStep(t):n.minorStep()},n.majorStep=function(t){return arguments.length?(d=+t[0],y=+t[1],n):[d,y]},n.minorStep=function(t){return arguments.length?(g=+t[0],v=+t[1],n):[g,v]},n.precision=function(t){return arguments.length?(m=+t,f=ye(a,o,90),s=me(r,e,m),h=ye(c,l,90),p=me(u,i,m),n):m},n.majorExtent([[-180,-90+Uo],[180,90-Uo]]).minorExtent([[-180,-80-Uo],[180,80+Uo]])},ao.geo.greatArc=function(){function n(){return{type:"LineString",coordinates:[t||r.apply(this,arguments),e||i.apply(this,arguments)]}}var t,e,r=Me,i=xe;return n.distance=function(){return ao.geo.distance(t||r.apply(this,arguments),e||i.apply(this,arguments))},n.source=function(e){return arguments.length?(r=e,t="function"==typeof e?null:e,n):r},n.target=function(t){return arguments.length?(i=t,e="function"==typeof t?null:t,n):i},n.precision=function(){return arguments.length?n:0},n},ao.geo.interpolate=function(n,t){return be(n[0]*Yo,n[1]*Yo,t[0]*Yo,t[1]*Yo)},ao.geo.length=function(n){return Ja=0,ao.geo.stream(n,Ga),Ja};var Ja,Ga={sphere:b,point:b,lineStart:_e,lineEnd:b,polygonStart:b,polygonEnd:b},Ka=we(function(n){return Math.sqrt(2/(1+n))},function(n){return 2*Math.asin(n/2)});(ao.geo.azimuthalEqualArea=function(){return oe(Ka)}).raw=Ka;var Qa=we(function(n){var t=Math.acos(n);return t&&t/Math.sin(t)},m);(ao.geo.azimuthalEquidistant=function(){return oe(Qa)}).raw=Qa,(ao.geo.conicConformal=function(){return Vt(Se)}).raw=Se,(ao.geo.conicEquidistant=function(){return Vt(ke)}).raw=ke;var nl=we(function(n){return 1/n},Math.atan);(ao.geo.gnomonic=function(){return oe(nl)}).raw=nl,Ne.invert=function(n,t){return[n,2*Math.atan(Math.exp(t))-Io]},(ao.geo.mercator=function(){return Ee(Ne)}).raw=Ne;var tl=we(function(){return 1},Math.asin);(ao.geo.orthographic=function(){return oe(tl)}).raw=tl;var el=we(function(n){return 1/(1+n)},function(n){return 2*Math.atan(n)});(ao.geo.stereographic=function(){return oe(el)}).raw=el,Ae.invert=function(n,t){return[-t,2*Math.atan(Math.exp(n))-Io]},(ao.geo.transverseMercator=function(){var n=Ee(Ae),t=n.center,e=n.rotate;return n.center=function(n){return n?t([-n[1],n[0]]):(n=t(),[n[1],-n[0]])},n.rotate=function(n){return n?e([n[0],n[1],n.length>2?n[2]+90:90]):(n=e(),[n[0],n[1],n[2]-90])},e([0,0,90])}).raw=Ae,ao.geom={},ao.geom.hull=function(n){function t(n){if(n.length<3)return[];var t,i=En(e),u=En(r),o=n.length,a=[],l=[];for(t=0;o>t;t++)a.push([+i.call(this,n[t],t),+u.call(this,n[t],t),t]);for(a.sort(qe),t=0;o>t;t++)l.push([a[t][0],-a[t][1]]);var c=Le(a),f=Le(l),s=f[0]===c[0],h=f[f.length-1]===c[c.length-1],p=[];for(t=c.length-1;t>=0;--t)p.push(n[a[c[t]][2]]);for(t=+s;t<f.length-h;++t)p.push(n[a[f[t]][2]]);return p}var e=Ce,r=ze;return arguments.length?t(n):(t.x=function(n){return arguments.length?(e=n,t):e},t.y=function(n){return arguments.length?(r=n,t):r},t)},ao.geom.polygon=function(n){return ko(n,rl),n};var rl=ao.geom.polygon.prototype=[];rl.area=function(){for(var n,t=-1,e=this.length,r=this[e-1],i=0;++t<e;)n=r,r=this[t],i+=n[1]*r[0]-n[0]*r[1];return.5*i},rl.centroid=function(n){var t,e,r=-1,i=this.length,u=0,o=0,a=this[i-1];for(arguments.length||(n=-1/(6*this.area()));++r<i;)t=a,a=this[r],e=t[0]*a[1]-a[0]*t[1],u+=(t[0]+a[0])*e,o+=(t[1]+a[1])*e;return[u*n,o*n]},rl.clip=function(n){for(var t,e,r,i,u,o,a=De(n),l=-1,c=this.length-De(this),f=this[c-1];++l<c;){for(t=n.slice(),n.length=0,i=this[l],u=t[(r=t.length-a)-1],e=-1;++e<r;)o=t[e],Te(o,f,i)?(Te(u,f,i)||n.push(Re(u,o,f,i)),n.push(o)):Te(u,f,i)&&n.push(Re(u,o,f,i)),u=o;a&&n.push(n[0]),f=i}return n};var il,ul,ol,al,ll,cl=[],fl=[];Ye.prototype.prepare=function(){for(var n,t=this.edges,e=t.length;e--;)n=t[e].edge,n.b&&n.a||t.splice(e,1);return t.sort(Ve),t.length},tr.prototype={start:function(){return this.edge.l===this.site?this.edge.a:this.edge.b},end:function(){return this.edge.l===this.site?this.edge.b:this.edge.a}},er.prototype={insert:function(n,t){var e,r,i;if(n){if(t.P=n,t.N=n.N,n.N&&(n.N.P=t),n.N=t,n.R){for(n=n.R;n.L;)n=n.L;n.L=t}else n.R=t;e=n}else this._?(n=or(this._),t.P=null,t.N=n,n.P=n.L=t,e=n):(t.P=t.N=null,this._=t,e=null);for(t.L=t.R=null,t.U=e,t.C=!0,n=t;e&&e.C;)r=e.U,e===r.L?(i=r.R,i&&i.C?(e.C=i.C=!1,r.C=!0,n=r):(n===e.R&&(ir(this,e),n=e,e=n.U),e.C=!1,r.C=!0,ur(this,r))):(i=r.L,i&&i.C?(e.C=i.C=!1,r.C=!0,n=r):(n===e.L&&(ur(this,e),n=e,e=n.U),e.C=!1,r.C=!0,ir(this,r))),e=n.U;this._.C=!1},remove:function(n){n.N&&(n.N.P=n.P),n.P&&(n.P.N=n.N),n.N=n.P=null;var t,e,r,i=n.U,u=n.L,o=n.R;if(e=u?o?or(o):u:o,i?i.L===n?i.L=e:i.R=e:this._=e,u&&o?(r=e.C,e.C=n.C,e.L=u,u.U=e,e!==o?(i=e.U,e.U=n.U,n=e.R,i.L=n,e.R=o,o.U=e):(e.U=i,i=e,n=e.R)):(r=n.C,n=e),n&&(n.U=i),!r){if(n&&n.C)return void(n.C=!1);do{if(n===this._)break;if(n===i.L){if(t=i.R,t.C&&(t.C=!1,i.C=!0,ir(this,i),t=i.R),t.L&&t.L.C||t.R&&t.R.C){t.R&&t.R.C||(t.L.C=!1,t.C=!0,ur(this,t),t=i.R),t.C=i.C,i.C=t.R.C=!1,ir(this,i),n=this._;break}}else if(t=i.L,t.C&&(t.C=!1,i.C=!0,ur(this,i),t=i.L),t.L&&t.L.C||t.R&&t.R.C){t.L&&t.L.C||(t.R.C=!1,t.C=!0,ir(this,t),t=i.L),t.C=i.C,i.C=t.L.C=!1,ur(this,i),n=this._;break}t.C=!0,n=i,i=i.U}while(!n.C);n&&(n.C=!1)}}},ao.geom.voronoi=function(n){function t(n){var t=new Array(n.length),r=a[0][0],i=a[0][1],u=a[1][0],o=a[1][1];return ar(e(n),a).cells.forEach(function(e,a){var l=e.edges,c=e.site,f=t[a]=l.length?l.map(function(n){var t=n.start();return[t.x,t.y]}):c.x>=r&&c.x<=u&&c.y>=i&&c.y<=o?[[r,o],[u,o],[u,i],[r,i]]:[];f.point=n[a]}),t}function e(n){return n.map(function(n,t){return{x:Math.round(u(n,t)/Uo)*Uo,y:Math.round(o(n,t)/Uo)*Uo,i:t}})}var r=Ce,i=ze,u=r,o=i,a=sl;return n?t(n):(t.links=function(n){return ar(e(n)).edges.filter(function(n){return n.l&&n.r}).map(function(t){return{source:n[t.l.i],target:n[t.r.i]}})},t.triangles=function(n){var t=[];return ar(e(n)).cells.forEach(function(e,r){for(var i,u,o=e.site,a=e.edges.sort(Ve),l=-1,c=a.length,f=a[c-1].edge,s=f.l===o?f.r:f.l;++l<c;)i=f,u=s,f=a[l].edge,s=f.l===o?f.r:f.l,r<u.i&&r<s.i&&cr(o,u,s)<0&&t.push([n[r],n[u.i],n[s.i]])}),t},t.x=function(n){return arguments.length?(u=En(r=n),t):r},t.y=function(n){return arguments.length?(o=En(i=n),t):i},t.clipExtent=function(n){return arguments.length?(a=null==n?sl:n,t):a===sl?null:a},t.size=function(n){return arguments.length?t.clipExtent(n&&[[0,0],n]):a===sl?null:a&&a[1]},t)};var sl=[[-1e6,-1e6],[1e6,1e6]];ao.geom.delaunay=function(n){return ao.geom.voronoi().triangles(n)},ao.geom.quadtree=function(n,t,e,r,i){function u(n){function u(n,t,e,r,i,u,o,a){if(!isNaN(e)&&!isNaN(r))if(n.leaf){var l=n.x,f=n.y;if(null!=l)if(xo(l-e)+xo(f-r)<.01)c(n,t,e,r,i,u,o,a);else{var s=n.point;n.x=n.y=n.point=null,c(n,s,l,f,i,u,o,a),c(n,t,e,r,i,u,o,a)}else n.x=e,n.y=r,n.point=t}else c(n,t,e,r,i,u,o,a)}function c(n,t,e,r,i,o,a,l){var c=.5*(i+a),f=.5*(o+l),s=e>=c,h=r>=f,p=h<<1|s;n.leaf=!1,n=n.nodes[p]||(n.nodes[p]=hr()),s?i=c:a=c,h?o=f:l=f,u(n,t,e,r,i,o,a,l)}var f,s,h,p,g,v,d,y,m,M=En(a),x=En(l);if(null!=t)v=t,d=e,y=r,m=i;else if(y=m=-(v=d=1/0),s=[],h=[],g=n.length,o)for(p=0;g>p;++p)f=n[p],f.x<v&&(v=f.x),f.y<d&&(d=f.y),f.x>y&&(y=f.x),f.y>m&&(m=f.y),s.push(f.x),h.push(f.y);else for(p=0;g>p;++p){var b=+M(f=n[p],p),_=+x(f,p);v>b&&(v=b),d>_&&(d=_),b>y&&(y=b),_>m&&(m=_),s.push(b),h.push(_)}var w=y-v,S=m-d;w>S?m=d+w:y=v+S;var k=hr();if(k.add=function(n){u(k,n,+M(n,++p),+x(n,p),v,d,y,m)},k.visit=function(n){pr(n,k,v,d,y,m)},k.find=function(n){return gr(k,n[0],n[1],v,d,y,m)},p=-1,null==t){for(;++p<g;)u(k,n[p],s[p],h[p],v,d,y,m);--p}else n.forEach(k.add);return s=h=n=f=null,k}var o,a=Ce,l=ze;return(o=arguments.length)?(a=fr,l=sr,3===o&&(i=e,r=t,e=t=0),u(n)):(u.x=function(n){return arguments.length?(a=n,u):a},u.y=function(n){return arguments.length?(l=n,u):l},u.extent=function(n){return arguments.length?(null==n?t=e=r=i=null:(t=+n[0][0],e=+n[0][1],r=+n[1][0],i=+n[1][1]),u):null==t?null:[[t,e],[r,i]]},u.size=function(n){return arguments.length?(null==n?t=e=r=i=null:(t=e=0,r=+n[0],i=+n[1]),u):null==t?null:[r-t,i-e]},u)},ao.interpolateRgb=vr,ao.interpolateObject=dr,ao.interpolateNumber=yr,ao.interpolateString=mr;var hl=/[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,pl=new RegExp(hl.source,"g");ao.interpolate=Mr,ao.interpolators=[function(n,t){var e=typeof t;return("string"===e?ua.has(t.toLowerCase())||/^(#|rgb\(|hsl\()/i.test(t)?vr:mr:t instanceof an?vr:Array.isArray(t)?xr:"object"===e&&isNaN(t)?dr:yr)(n,t)}],ao.interpolateArray=xr;var gl=function(){return m},vl=ao.map({linear:gl,poly:Er,quad:function(){return Sr},cubic:function(){return kr},sin:function(){return Ar},exp:function(){return Cr},circle:function(){return zr},elastic:Lr,back:qr,bounce:function(){return Tr}}),dl=ao.map({"in":m,out:_r,"in-out":wr,"out-in":function(n){return wr(_r(n))}});ao.ease=function(n){var t=n.indexOf("-"),e=t>=0?n.slice(0,t):n,r=t>=0?n.slice(t+1):"in";return e=vl.get(e)||gl,r=dl.get(r)||m,br(r(e.apply(null,lo.call(arguments,1))))},ao.interpolateHcl=Rr,ao.interpolateHsl=Dr,ao.interpolateLab=Pr,ao.interpolateRound=Ur,ao.transform=function(n){var t=fo.createElementNS(ao.ns.prefix.svg,"g");return(ao.transform=function(n){if(null!=n){t.setAttribute("transform",n);var e=t.transform.baseVal.consolidate()}return new jr(e?e.matrix:yl)})(n)},jr.prototype.toString=function(){return"translate("+this.translate+")rotate("+this.rotate+")skewX("+this.skew+")scale("+this.scale+")"};var yl={a:1,b:0,c:0,d:1,e:0,f:0};ao.interpolateTransform=$r,ao.layout={},ao.layout.bundle=function(){return function(n){for(var t=[],e=-1,r=n.length;++e<r;)t.push(Jr(n[e]));return t}},ao.layout.chord=function(){function n(){var n,c,s,h,p,g={},v=[],d=ao.range(u),y=[];for(e=[],r=[],n=0,h=-1;++h<u;){for(c=0,p=-1;++p<u;)c+=i[h][p];v.push(c),y.push(ao.range(u)),n+=c}for(o&&d.sort(function(n,t){return o(v[n],v[t])}),a&&y.forEach(function(n,t){n.sort(function(n,e){return a(i[t][n],i[t][e])})}),n=(Ho-f*u)/n,c=0,h=-1;++h<u;){for(s=c,p=-1;++p<u;){var m=d[h],M=y[m][p],x=i[m][M],b=c,_=c+=x*n;g[m+"-"+M]={index:m,subindex:M,startAngle:b,endAngle:_,value:x}}r[m]={index:m,startAngle:s,endAngle:c,value:v[m]},c+=f}for(h=-1;++h<u;)for(p=h-1;++p<u;){var w=g[h+"-"+p],S=g[p+"-"+h];(w.value||S.value)&&e.push(w.value<S.value?{source:S,target:w}:{source:w,target:S})}l&&t()}function t(){e.sort(function(n,t){return l((n.source.value+n.target.value)/2,(t.source.value+t.target.value)/2)})}var e,r,i,u,o,a,l,c={},f=0;return c.matrix=function(n){return arguments.length?(u=(i=n)&&i.length,e=r=null,c):i},c.padding=function(n){return arguments.length?(f=n,e=r=null,c):f},c.sortGroups=function(n){return arguments.length?(o=n,e=r=null,c):o},c.sortSubgroups=function(n){return arguments.length?(a=n,e=null,c):a},c.sortChords=function(n){return arguments.length?(l=n,e&&t(),c):l},c.chords=function(){return e||n(),e},c.groups=function(){return r||n(),r},c},ao.layout.force=function(){function n(n){return function(t,e,r,i){if(t.point!==n){var u=t.cx-n.x,o=t.cy-n.y,a=i-e,l=u*u+o*o;if(l>a*a/y){if(v>l){var c=t.charge/l;n.px-=u*c,n.py-=o*c}return!0}if(t.point&&l&&v>l){var c=t.pointCharge/l;n.px-=u*c,n.py-=o*c}}return!t.charge}}function t(n){n.px=ao.event.x,n.py=ao.event.y,l.resume()}var e,r,i,u,o,a,l={},c=ao.dispatch("start","tick","end"),f=[1,1],s=.9,h=ml,p=Ml,g=-30,v=xl,d=.1,y=.64,M=[],x=[];return l.tick=function(){if((i*=.99)<.005)return e=null,c.end({type:"end",alpha:i=0}),!0;var t,r,l,h,p,v,y,m,b,_=M.length,w=x.length;for(r=0;w>r;++r)l=x[r],h=l.source,p=l.target,m=p.x-h.x,b=p.y-h.y,(v=m*m+b*b)&&(v=i*o[r]*((v=Math.sqrt(v))-u[r])/v,m*=v,b*=v,p.x-=m*(y=h.weight+p.weight?h.weight/(h.weight+p.weight):.5),p.y-=b*y,h.x+=m*(y=1-y),h.y+=b*y);if((y=i*d)&&(m=f[0]/2,b=f[1]/2,r=-1,y))for(;++r<_;)l=M[r],l.x+=(m-l.x)*y,l.y+=(b-l.y)*y;if(g)for(ri(t=ao.geom.quadtree(M),i,a),r=-1;++r<_;)(l=M[r]).fixed||t.visit(n(l));for(r=-1;++r<_;)l=M[r],l.fixed?(l.x=l.px,l.y=l.py):(l.x-=(l.px-(l.px=l.x))*s,l.y-=(l.py-(l.py=l.y))*s);c.tick({type:"tick",alpha:i})},l.nodes=function(n){return arguments.length?(M=n,l):M},l.links=function(n){return arguments.length?(x=n,l):x},l.size=function(n){return arguments.length?(f=n,l):f},l.linkDistance=function(n){return arguments.length?(h="function"==typeof n?n:+n,l):h},l.distance=l.linkDistance,l.linkStrength=function(n){return arguments.length?(p="function"==typeof n?n:+n,l):p},l.friction=function(n){return arguments.length?(s=+n,l):s},l.charge=function(n){return arguments.length?(g="function"==typeof n?n:+n,l):g},l.chargeDistance=function(n){return arguments.length?(v=n*n,l):Math.sqrt(v)},l.gravity=function(n){return arguments.length?(d=+n,l):d},l.theta=function(n){return arguments.length?(y=n*n,l):Math.sqrt(y)},l.alpha=function(n){return arguments.length?(n=+n,i?n>0?i=n:(e.c=null,e.t=NaN,e=null,c.end({type:"end",alpha:i=0})):n>0&&(c.start({type:"start",alpha:i=n}),e=qn(l.tick)),l):i},l.start=function(){function n(n,r){if(!e){for(e=new Array(i),l=0;i>l;++l)e[l]=[];for(l=0;c>l;++l){var u=x[l];e[u.source.index].push(u.target),e[u.target.index].push(u.source)}}for(var o,a=e[t],l=-1,f=a.length;++l<f;)if(!isNaN(o=a[l][n]))return o;return Math.random()*r}var t,e,r,i=M.length,c=x.length,s=f[0],v=f[1];for(t=0;i>t;++t)(r=M[t]).index=t,r.weight=0;for(t=0;c>t;++t)r=x[t],"number"==typeof r.source&&(r.source=M[r.source]),"number"==typeof r.target&&(r.target=M[r.target]),++r.source.weight,++r.target.weight;for(t=0;i>t;++t)r=M[t],isNaN(r.x)&&(r.x=n("x",s)),isNaN(r.y)&&(r.y=n("y",v)),isNaN(r.px)&&(r.px=r.x),isNaN(r.py)&&(r.py=r.y);if(u=[],"function"==typeof h)for(t=0;c>t;++t)u[t]=+h.call(this,x[t],t);else for(t=0;c>t;++t)u[t]=h;if(o=[],"function"==typeof p)for(t=0;c>t;++t)o[t]=+p.call(this,x[t],t);else for(t=0;c>t;++t)o[t]=p;if(a=[],"function"==typeof g)for(t=0;i>t;++t)a[t]=+g.call(this,M[t],t);else for(t=0;i>t;++t)a[t]=g;return l.resume()},l.resume=function(){return l.alpha(.1)},l.stop=function(){return l.alpha(0)},l.drag=function(){return r||(r=ao.behavior.drag().origin(m).on("dragstart.force",Qr).on("drag.force",t).on("dragend.force",ni)),arguments.length?void this.on("mouseover.force",ti).on("mouseout.force",ei).call(r):r},ao.rebind(l,c,"on")};var ml=20,Ml=1,xl=1/0;ao.layout.hierarchy=function(){function n(i){var u,o=[i],a=[];for(i.depth=0;null!=(u=o.pop());)if(a.push(u),(c=e.call(n,u,u.depth))&&(l=c.length)){for(var l,c,f;--l>=0;)o.push(f=c[l]),f.parent=u,f.depth=u.depth+1;r&&(u.value=0),u.children=c}else r&&(u.value=+r.call(n,u,u.depth)||0),delete u.children;return oi(i,function(n){var e,i;t&&(e=n.children)&&e.sort(t),r&&(i=n.parent)&&(i.value+=n.value)}),a}var t=ci,e=ai,r=li;return n.sort=function(e){return arguments.length?(t=e,n):t},n.children=function(t){return arguments.length?(e=t,n):e},n.value=function(t){return arguments.length?(r=t,n):r},n.revalue=function(t){return r&&(ui(t,function(n){n.children&&(n.value=0)}),oi(t,function(t){var e;t.children||(t.value=+r.call(n,t,t.depth)||0),(e=t.parent)&&(e.value+=t.value)})),t},n},ao.layout.partition=function(){function n(t,e,r,i){var u=t.children;if(t.x=e,t.y=t.depth*i,t.dx=r,t.dy=i,u&&(o=u.length)){var o,a,l,c=-1;for(r=t.value?r/t.value:0;++c<o;)n(a=u[c],e,l=a.value*r,i),e+=l}}function t(n){var e=n.children,r=0;if(e&&(i=e.length))for(var i,u=-1;++u<i;)r=Math.max(r,t(e[u]));return 1+r}function e(e,u){var o=r.call(this,e,u);return n(o[0],0,i[0],i[1]/t(o[0])),o}var r=ao.layout.hierarchy(),i=[1,1];return e.size=function(n){return arguments.length?(i=n,e):i},ii(e,r)},ao.layout.pie=function(){function n(o){var a,l=o.length,c=o.map(function(e,r){return+t.call(n,e,r)}),f=+("function"==typeof r?r.apply(this,arguments):r),s=("function"==typeof i?i.apply(this,arguments):i)-f,h=Math.min(Math.abs(s)/l,+("function"==typeof u?u.apply(this,arguments):u)),p=h*(0>s?-1:1),g=ao.sum(c),v=g?(s-l*p)/g:0,d=ao.range(l),y=[];return null!=e&&d.sort(e===bl?function(n,t){return c[t]-c[n]}:function(n,t){return e(o[n],o[t])}),d.forEach(function(n){y[n]={data:o[n],value:a=c[n],startAngle:f,endAngle:f+=a*v+p,padAngle:h}}),y}var t=Number,e=bl,r=0,i=Ho,u=0;return n.value=function(e){return arguments.length?(t=e,n):t},n.sort=function(t){return arguments.length?(e=t,n):e},n.startAngle=function(t){return arguments.length?(r=t,n):r},n.endAngle=function(t){return arguments.length?(i=t,n):i},n.padAngle=function(t){return arguments.length?(u=t,n):u},n};var bl={};ao.layout.stack=function(){function n(a,l){if(!(h=a.length))return a;var c=a.map(function(e,r){return t.call(n,e,r)}),f=c.map(function(t){return t.map(function(t,e){return[u.call(n,t,e),o.call(n,t,e)]})}),s=e.call(n,f,l);c=ao.permute(c,s),f=ao.permute(f,s);var h,p,g,v,d=r.call(n,f,l),y=c[0].length;for(g=0;y>g;++g)for(i.call(n,c[0][g],v=d[g],f[0][g][1]),p=1;h>p;++p)i.call(n,c[p][g],v+=f[p-1][g][1],f[p][g][1]);return a}var t=m,e=gi,r=vi,i=pi,u=si,o=hi;return n.values=function(e){return arguments.length?(t=e,n):t},n.order=function(t){return arguments.length?(e="function"==typeof t?t:_l.get(t)||gi,n):e},n.offset=function(t){return arguments.length?(r="function"==typeof t?t:wl.get(t)||vi,n):r},n.x=function(t){return arguments.length?(u=t,n):u},n.y=function(t){return arguments.length?(o=t,n):o},n.out=function(t){return arguments.length?(i=t,n):i},n};var _l=ao.map({"inside-out":function(n){var t,e,r=n.length,i=n.map(di),u=n.map(yi),o=ao.range(r).sort(function(n,t){return i[n]-i[t]}),a=0,l=0,c=[],f=[];for(t=0;r>t;++t)e=o[t],l>a?(a+=u[e],c.push(e)):(l+=u[e],f.push(e));return f.reverse().concat(c)},reverse:function(n){return ao.range(n.length).reverse()},"default":gi}),wl=ao.map({silhouette:function(n){var t,e,r,i=n.length,u=n[0].length,o=[],a=0,l=[];for(e=0;u>e;++e){for(t=0,r=0;i>t;t++)r+=n[t][e][1];r>a&&(a=r),o.push(r)}for(e=0;u>e;++e)l[e]=(a-o[e])/2;return l},wiggle:function(n){var t,e,r,i,u,o,a,l,c,f=n.length,s=n[0],h=s.length,p=[];for(p[0]=l=c=0,e=1;h>e;++e){for(t=0,i=0;f>t;++t)i+=n[t][e][1];for(t=0,u=0,a=s[e][0]-s[e-1][0];f>t;++t){for(r=0,o=(n[t][e][1]-n[t][e-1][1])/(2*a);t>r;++r)o+=(n[r][e][1]-n[r][e-1][1])/a;u+=o*n[t][e][1]}p[e]=l-=i?u/i*a:0,c>l&&(c=l)}for(e=0;h>e;++e)p[e]-=c;return p},expand:function(n){var t,e,r,i=n.length,u=n[0].length,o=1/i,a=[];for(e=0;u>e;++e){for(t=0,r=0;i>t;t++)r+=n[t][e][1];if(r)for(t=0;i>t;t++)n[t][e][1]/=r;else for(t=0;i>t;t++)n[t][e][1]=o}for(e=0;u>e;++e)a[e]=0;return a},zero:vi});ao.layout.histogram=function(){function n(n,u){for(var o,a,l=[],c=n.map(e,this),f=r.call(this,c,u),s=i.call(this,f,c,u),u=-1,h=c.length,p=s.length-1,g=t?1:1/h;++u<p;)o=l[u]=[],o.dx=s[u+1]-(o.x=s[u]),o.y=0;if(p>0)for(u=-1;++u<h;)a=c[u],a>=f[0]&&a<=f[1]&&(o=l[ao.bisect(s,a,1,p)-1],o.y+=g,o.push(n[u]));return l}var t=!0,e=Number,r=bi,i=Mi;return n.value=function(t){return arguments.length?(e=t,n):e},n.range=function(t){return arguments.length?(r=En(t),n):r},n.bins=function(t){return arguments.length?(i="number"==typeof t?function(n){return xi(n,t)}:En(t),n):i},n.frequency=function(e){return arguments.length?(t=!!e,n):t},n},ao.layout.pack=function(){function n(n,u){var o=e.call(this,n,u),a=o[0],l=i[0],c=i[1],f=null==t?Math.sqrt:"function"==typeof t?t:function(){return t};if(a.x=a.y=0,oi(a,function(n){n.r=+f(n.value)}),oi(a,Ni),r){var s=r*(t?1:Math.max(2*a.r/l,2*a.r/c))/2;oi(a,function(n){n.r+=s}),oi(a,Ni),oi(a,function(n){n.r-=s})}return Ci(a,l/2,c/2,t?1:1/Math.max(2*a.r/l,2*a.r/c)),o}var t,e=ao.layout.hierarchy().sort(_i),r=0,i=[1,1];return n.size=function(t){return arguments.length?(i=t,n):i},n.radius=function(e){return arguments.length?(t=null==e||"function"==typeof e?e:+e,n):t},n.padding=function(t){return arguments.length?(r=+t,n):r},ii(n,e)},ao.layout.tree=function(){function n(n,i){var f=o.call(this,n,i),s=f[0],h=t(s);if(oi(h,e),h.parent.m=-h.z,ui(h,r),c)ui(s,u);else{var p=s,g=s,v=s;ui(s,function(n){n.x<p.x&&(p=n),n.x>g.x&&(g=n),n.depth>v.depth&&(v=n)});var d=a(p,g)/2-p.x,y=l[0]/(g.x+a(g,p)/2+d),m=l[1]/(v.depth||1);ui(s,function(n){n.x=(n.x+d)*y,n.y=n.depth*m})}return f}function t(n){for(var t,e={A:null,children:[n]},r=[e];null!=(t=r.pop());)for(var i,u=t.children,o=0,a=u.length;a>o;++o)r.push((u[o]=i={_:u[o],parent:t,children:(i=u[o].children)&&i.slice()||[],A:null,a:null,z:0,m:0,c:0,s:0,t:null,i:o}).a=i);return e.children[0]}function e(n){var t=n.children,e=n.parent.children,r=n.i?e[n.i-1]:null;if(t.length){Di(n);var u=(t[0].z+t[t.length-1].z)/2;r?(n.z=r.z+a(n._,r._),n.m=n.z-u):n.z=u}else r&&(n.z=r.z+a(n._,r._));n.parent.A=i(n,r,n.parent.A||e[0])}function r(n){n._.x=n.z+n.parent.m,n.m+=n.parent.m}function i(n,t,e){if(t){for(var r,i=n,u=n,o=t,l=i.parent.children[0],c=i.m,f=u.m,s=o.m,h=l.m;o=Ti(o),i=qi(i),o&&i;)l=qi(l),u=Ti(u),u.a=n,r=o.z+s-i.z-c+a(o._,i._),r>0&&(Ri(Pi(o,n,e),n,r),c+=r,f+=r),s+=o.m,c+=i.m,h+=l.m,f+=u.m;o&&!Ti(u)&&(u.t=o,u.m+=s-f),i&&!qi(l)&&(l.t=i,l.m+=c-h,e=n)}return e}function u(n){n.x*=l[0],n.y=n.depth*l[1]}var o=ao.layout.hierarchy().sort(null).value(null),a=Li,l=[1,1],c=null;return n.separation=function(t){return arguments.length?(a=t,n):a},n.size=function(t){return arguments.length?(c=null==(l=t)?u:null,n):c?null:l},n.nodeSize=function(t){return arguments.length?(c=null==(l=t)?null:u,n):c?l:null},ii(n,o)},ao.layout.cluster=function(){function n(n,u){var o,a=t.call(this,n,u),l=a[0],c=0;oi(l,function(n){var t=n.children;t&&t.length?(n.x=ji(t),n.y=Ui(t)):(n.x=o?c+=e(n,o):0,n.y=0,o=n)});var f=Fi(l),s=Hi(l),h=f.x-e(f,s)/2,p=s.x+e(s,f)/2;return oi(l,i?function(n){n.x=(n.x-l.x)*r[0],n.y=(l.y-n.y)*r[1]}:function(n){n.x=(n.x-h)/(p-h)*r[0],n.y=(1-(l.y?n.y/l.y:1))*r[1]}),a}var t=ao.layout.hierarchy().sort(null).value(null),e=Li,r=[1,1],i=!1;return n.separation=function(t){return arguments.length?(e=t,n):e},n.size=function(t){return arguments.length?(i=null==(r=t),n):i?null:r},n.nodeSize=function(t){return arguments.length?(i=null!=(r=t),n):i?r:null},ii(n,t)},ao.layout.treemap=function(){function n(n,t){for(var e,r,i=-1,u=n.length;++i<u;)r=(e=n[i]).value*(0>t?0:t),e.area=isNaN(r)||0>=r?0:r}function t(e){var u=e.children;if(u&&u.length){var o,a,l,c=s(e),f=[],h=u.slice(),g=1/0,v="slice"===p?c.dx:"dice"===p?c.dy:"slice-dice"===p?1&e.depth?c.dy:c.dx:Math.min(c.dx,c.dy);for(n(h,c.dx*c.dy/e.value),f.area=0;(l=h.length)>0;)f.push(o=h[l-1]),f.area+=o.area,"squarify"!==p||(a=r(f,v))<=g?(h.pop(),g=a):(f.area-=f.pop().area,i(f,v,c,!1),v=Math.min(c.dx,c.dy),f.length=f.area=0,g=1/0);f.length&&(i(f,v,c,!0),f.length=f.area=0),u.forEach(t)}}function e(t){var r=t.children;if(r&&r.length){var u,o=s(t),a=r.slice(),l=[];for(n(a,o.dx*o.dy/t.value),l.area=0;u=a.pop();)l.push(u),l.area+=u.area,null!=u.z&&(i(l,u.z?o.dx:o.dy,o,!a.length),l.length=l.area=0);r.forEach(e)}}function r(n,t){for(var e,r=n.area,i=0,u=1/0,o=-1,a=n.length;++o<a;)(e=n[o].area)&&(u>e&&(u=e),e>i&&(i=e));return r*=r,t*=t,r?Math.max(t*i*g/r,r/(t*u*g)):1/0}function i(n,t,e,r){var i,u=-1,o=n.length,a=e.x,c=e.y,f=t?l(n.area/t):0;
+if(t==e.dx){for((r||f>e.dy)&&(f=e.dy);++u<o;)i=n[u],i.x=a,i.y=c,i.dy=f,a+=i.dx=Math.min(e.x+e.dx-a,f?l(i.area/f):0);i.z=!0,i.dx+=e.x+e.dx-a,e.y+=f,e.dy-=f}else{for((r||f>e.dx)&&(f=e.dx);++u<o;)i=n[u],i.x=a,i.y=c,i.dx=f,c+=i.dy=Math.min(e.y+e.dy-c,f?l(i.area/f):0);i.z=!1,i.dy+=e.y+e.dy-c,e.x+=f,e.dx-=f}}function u(r){var i=o||a(r),u=i[0];return u.x=u.y=0,u.value?(u.dx=c[0],u.dy=c[1]):u.dx=u.dy=0,o&&a.revalue(u),n([u],u.dx*u.dy/u.value),(o?e:t)(u),h&&(o=i),i}var o,a=ao.layout.hierarchy(),l=Math.round,c=[1,1],f=null,s=Oi,h=!1,p="squarify",g=.5*(1+Math.sqrt(5));return u.size=function(n){return arguments.length?(c=n,u):c},u.padding=function(n){function t(t){var e=n.call(u,t,t.depth);return null==e?Oi(t):Ii(t,"number"==typeof e?[e,e,e,e]:e)}function e(t){return Ii(t,n)}if(!arguments.length)return f;var r;return s=null==(f=n)?Oi:"function"==(r=typeof n)?t:"number"===r?(n=[n,n,n,n],e):e,u},u.round=function(n){return arguments.length?(l=n?Math.round:Number,u):l!=Number},u.sticky=function(n){return arguments.length?(h=n,o=null,u):h},u.ratio=function(n){return arguments.length?(g=n,u):g},u.mode=function(n){return arguments.length?(p=n+"",u):p},ii(u,a)},ao.random={normal:function(n,t){var e=arguments.length;return 2>e&&(t=1),1>e&&(n=0),function(){var e,r,i;do e=2*Math.random()-1,r=2*Math.random()-1,i=e*e+r*r;while(!i||i>1);return n+t*e*Math.sqrt(-2*Math.log(i)/i)}},logNormal:function(){var n=ao.random.normal.apply(ao,arguments);return function(){return Math.exp(n())}},bates:function(n){var t=ao.random.irwinHall(n);return function(){return t()/n}},irwinHall:function(n){return function(){for(var t=0,e=0;n>e;e++)t+=Math.random();return t}}},ao.scale={};var Sl={floor:m,ceil:m};ao.scale.linear=function(){return Wi([0,1],[0,1],Mr,!1)};var kl={s:1,g:1,p:1,r:1,e:1};ao.scale.log=function(){return ru(ao.scale.linear().domain([0,1]),10,!0,[1,10])};var Nl=ao.format(".0e"),El={floor:function(n){return-Math.ceil(-n)},ceil:function(n){return-Math.floor(-n)}};ao.scale.pow=function(){return iu(ao.scale.linear(),1,[0,1])},ao.scale.sqrt=function(){return ao.scale.pow().exponent(.5)},ao.scale.ordinal=function(){return ou([],{t:"range",a:[[]]})},ao.scale.category10=function(){return ao.scale.ordinal().range(Al)},ao.scale.category20=function(){return ao.scale.ordinal().range(Cl)},ao.scale.category20b=function(){return ao.scale.ordinal().range(zl)},ao.scale.category20c=function(){return ao.scale.ordinal().range(Ll)};var Al=[2062260,16744206,2924588,14034728,9725885,9197131,14907330,8355711,12369186,1556175].map(xn),Cl=[2062260,11454440,16744206,16759672,2924588,10018698,14034728,16750742,9725885,12955861,9197131,12885140,14907330,16234194,8355711,13092807,12369186,14408589,1556175,10410725].map(xn),zl=[3750777,5395619,7040719,10264286,6519097,9216594,11915115,13556636,9202993,12426809,15186514,15190932,8666169,11356490,14049643,15177372,8077683,10834324,13528509,14589654].map(xn),Ll=[3244733,7057110,10406625,13032431,15095053,16616764,16625259,16634018,3253076,7652470,10607003,13101504,7695281,10394312,12369372,14342891,6513507,9868950,12434877,14277081].map(xn);ao.scale.quantile=function(){return au([],[])},ao.scale.quantize=function(){return lu(0,1,[0,1])},ao.scale.threshold=function(){return cu([.5],[0,1])},ao.scale.identity=function(){return fu([0,1])},ao.svg={},ao.svg.arc=function(){function n(){var n=Math.max(0,+e.apply(this,arguments)),c=Math.max(0,+r.apply(this,arguments)),f=o.apply(this,arguments)-Io,s=a.apply(this,arguments)-Io,h=Math.abs(s-f),p=f>s?0:1;if(n>c&&(g=c,c=n,n=g),h>=Oo)return t(c,p)+(n?t(n,1-p):"")+"Z";var g,v,d,y,m,M,x,b,_,w,S,k,N=0,E=0,A=[];if((y=(+l.apply(this,arguments)||0)/2)&&(d=u===ql?Math.sqrt(n*n+c*c):+u.apply(this,arguments),p||(E*=-1),c&&(E=tn(d/c*Math.sin(y))),n&&(N=tn(d/n*Math.sin(y)))),c){m=c*Math.cos(f+E),M=c*Math.sin(f+E),x=c*Math.cos(s-E),b=c*Math.sin(s-E);var C=Math.abs(s-f-2*E)<=Fo?0:1;if(E&&yu(m,M,x,b)===p^C){var z=(f+s)/2;m=c*Math.cos(z),M=c*Math.sin(z),x=b=null}}else m=M=0;if(n){_=n*Math.cos(s-N),w=n*Math.sin(s-N),S=n*Math.cos(f+N),k=n*Math.sin(f+N);var L=Math.abs(f-s+2*N)<=Fo?0:1;if(N&&yu(_,w,S,k)===1-p^L){var q=(f+s)/2;_=n*Math.cos(q),w=n*Math.sin(q),S=k=null}}else _=w=0;if(h>Uo&&(g=Math.min(Math.abs(c-n)/2,+i.apply(this,arguments)))>.001){v=c>n^p?0:1;var T=g,R=g;if(Fo>h){var D=null==S?[_,w]:null==x?[m,M]:Re([m,M],[S,k],[x,b],[_,w]),P=m-D[0],U=M-D[1],j=x-D[0],F=b-D[1],H=1/Math.sin(Math.acos((P*j+U*F)/(Math.sqrt(P*P+U*U)*Math.sqrt(j*j+F*F)))/2),O=Math.sqrt(D[0]*D[0]+D[1]*D[1]);R=Math.min(g,(n-O)/(H-1)),T=Math.min(g,(c-O)/(H+1))}if(null!=x){var I=mu(null==S?[_,w]:[S,k],[m,M],c,T,p),Y=mu([x,b],[_,w],c,T,p);g===T?A.push("M",I[0],"A",T,",",T," 0 0,",v," ",I[1],"A",c,",",c," 0 ",1-p^yu(I[1][0],I[1][1],Y[1][0],Y[1][1]),",",p," ",Y[1],"A",T,",",T," 0 0,",v," ",Y[0]):A.push("M",I[0],"A",T,",",T," 0 1,",v," ",Y[0])}else A.push("M",m,",",M);if(null!=S){var Z=mu([m,M],[S,k],n,-R,p),V=mu([_,w],null==x?[m,M]:[x,b],n,-R,p);g===R?A.push("L",V[0],"A",R,",",R," 0 0,",v," ",V[1],"A",n,",",n," 0 ",p^yu(V[1][0],V[1][1],Z[1][0],Z[1][1]),",",1-p," ",Z[1],"A",R,",",R," 0 0,",v," ",Z[0]):A.push("L",V[0],"A",R,",",R," 0 0,",v," ",Z[0])}else A.push("L",_,",",w)}else A.push("M",m,",",M),null!=x&&A.push("A",c,",",c," 0 ",C,",",p," ",x,",",b),A.push("L",_,",",w),null!=S&&A.push("A",n,",",n," 0 ",L,",",1-p," ",S,",",k);return A.push("Z"),A.join("")}function t(n,t){return"M0,"+n+"A"+n+","+n+" 0 1,"+t+" 0,"+-n+"A"+n+","+n+" 0 1,"+t+" 0,"+n}var e=hu,r=pu,i=su,u=ql,o=gu,a=vu,l=du;return n.innerRadius=function(t){return arguments.length?(e=En(t),n):e},n.outerRadius=function(t){return arguments.length?(r=En(t),n):r},n.cornerRadius=function(t){return arguments.length?(i=En(t),n):i},n.padRadius=function(t){return arguments.length?(u=t==ql?ql:En(t),n):u},n.startAngle=function(t){return arguments.length?(o=En(t),n):o},n.endAngle=function(t){return arguments.length?(a=En(t),n):a},n.padAngle=function(t){return arguments.length?(l=En(t),n):l},n.centroid=function(){var n=(+e.apply(this,arguments)+ +r.apply(this,arguments))/2,t=(+o.apply(this,arguments)+ +a.apply(this,arguments))/2-Io;return[Math.cos(t)*n,Math.sin(t)*n]},n};var ql="auto";ao.svg.line=function(){return Mu(m)};var Tl=ao.map({linear:xu,"linear-closed":bu,step:_u,"step-before":wu,"step-after":Su,basis:zu,"basis-open":Lu,"basis-closed":qu,bundle:Tu,cardinal:Eu,"cardinal-open":ku,"cardinal-closed":Nu,monotone:Fu});Tl.forEach(function(n,t){t.key=n,t.closed=/-closed$/.test(n)});var Rl=[0,2/3,1/3,0],Dl=[0,1/3,2/3,0],Pl=[0,1/6,2/3,1/6];ao.svg.line.radial=function(){var n=Mu(Hu);return n.radius=n.x,delete n.x,n.angle=n.y,delete n.y,n},wu.reverse=Su,Su.reverse=wu,ao.svg.area=function(){return Ou(m)},ao.svg.area.radial=function(){var n=Ou(Hu);return n.radius=n.x,delete n.x,n.innerRadius=n.x0,delete n.x0,n.outerRadius=n.x1,delete n.x1,n.angle=n.y,delete n.y,n.startAngle=n.y0,delete n.y0,n.endAngle=n.y1,delete n.y1,n},ao.svg.chord=function(){function n(n,a){var l=t(this,u,n,a),c=t(this,o,n,a);return"M"+l.p0+r(l.r,l.p1,l.a1-l.a0)+(e(l,c)?i(l.r,l.p1,l.r,l.p0):i(l.r,l.p1,c.r,c.p0)+r(c.r,c.p1,c.a1-c.a0)+i(c.r,c.p1,l.r,l.p0))+"Z"}function t(n,t,e,r){var i=t.call(n,e,r),u=a.call(n,i,r),o=l.call(n,i,r)-Io,f=c.call(n,i,r)-Io;return{r:u,a0:o,a1:f,p0:[u*Math.cos(o),u*Math.sin(o)],p1:[u*Math.cos(f),u*Math.sin(f)]}}function e(n,t){return n.a0==t.a0&&n.a1==t.a1}function r(n,t,e){return"A"+n+","+n+" 0 "+ +(e>Fo)+",1 "+t}function i(n,t,e,r){return"Q 0,0 "+r}var u=Me,o=xe,a=Iu,l=gu,c=vu;return n.radius=function(t){return arguments.length?(a=En(t),n):a},n.source=function(t){return arguments.length?(u=En(t),n):u},n.target=function(t){return arguments.length?(o=En(t),n):o},n.startAngle=function(t){return arguments.length?(l=En(t),n):l},n.endAngle=function(t){return arguments.length?(c=En(t),n):c},n},ao.svg.diagonal=function(){function n(n,i){var u=t.call(this,n,i),o=e.call(this,n,i),a=(u.y+o.y)/2,l=[u,{x:u.x,y:a},{x:o.x,y:a},o];return l=l.map(r),"M"+l[0]+"C"+l[1]+" "+l[2]+" "+l[3]}var t=Me,e=xe,r=Yu;return n.source=function(e){return arguments.length?(t=En(e),n):t},n.target=function(t){return arguments.length?(e=En(t),n):e},n.projection=function(t){return arguments.length?(r=t,n):r},n},ao.svg.diagonal.radial=function(){var n=ao.svg.diagonal(),t=Yu,e=n.projection;return n.projection=function(n){return arguments.length?e(Zu(t=n)):t},n},ao.svg.symbol=function(){function n(n,r){return(Ul.get(t.call(this,n,r))||$u)(e.call(this,n,r))}var t=Xu,e=Vu;return n.type=function(e){return arguments.length?(t=En(e),n):t},n.size=function(t){return arguments.length?(e=En(t),n):e},n};var Ul=ao.map({circle:$u,cross:function(n){var t=Math.sqrt(n/5)/2;return"M"+-3*t+","+-t+"H"+-t+"V"+-3*t+"H"+t+"V"+-t+"H"+3*t+"V"+t+"H"+t+"V"+3*t+"H"+-t+"V"+t+"H"+-3*t+"Z"},diamond:function(n){var t=Math.sqrt(n/(2*Fl)),e=t*Fl;return"M0,"+-t+"L"+e+",0 0,"+t+" "+-e+",0Z"},square:function(n){var t=Math.sqrt(n)/2;return"M"+-t+","+-t+"L"+t+","+-t+" "+t+","+t+" "+-t+","+t+"Z"},"triangle-down":function(n){var t=Math.sqrt(n/jl),e=t*jl/2;return"M0,"+e+"L"+t+","+-e+" "+-t+","+-e+"Z"},"triangle-up":function(n){var t=Math.sqrt(n/jl),e=t*jl/2;return"M0,"+-e+"L"+t+","+e+" "+-t+","+e+"Z"}});ao.svg.symbolTypes=Ul.keys();var jl=Math.sqrt(3),Fl=Math.tan(30*Yo);Co.transition=function(n){for(var t,e,r=Hl||++Zl,i=Ku(n),u=[],o=Ol||{time:Date.now(),ease:Nr,delay:0,duration:250},a=-1,l=this.length;++a<l;){u.push(t=[]);for(var c=this[a],f=-1,s=c.length;++f<s;)(e=c[f])&&Qu(e,f,i,r,o),t.push(e)}return Wu(u,i,r)},Co.interrupt=function(n){return this.each(null==n?Il:Bu(Ku(n)))};var Hl,Ol,Il=Bu(Ku()),Yl=[],Zl=0;Yl.call=Co.call,Yl.empty=Co.empty,Yl.node=Co.node,Yl.size=Co.size,ao.transition=function(n,t){return n&&n.transition?Hl?n.transition(t):n:ao.selection().transition(n)},ao.transition.prototype=Yl,Yl.select=function(n){var t,e,r,i=this.id,u=this.namespace,o=[];n=A(n);for(var a=-1,l=this.length;++a<l;){o.push(t=[]);for(var c=this[a],f=-1,s=c.length;++f<s;)(r=c[f])&&(e=n.call(r,r.__data__,f,a))?("__data__"in r&&(e.__data__=r.__data__),Qu(e,f,u,i,r[u][i]),t.push(e)):t.push(null)}return Wu(o,u,i)},Yl.selectAll=function(n){var t,e,r,i,u,o=this.id,a=this.namespace,l=[];n=C(n);for(var c=-1,f=this.length;++c<f;)for(var s=this[c],h=-1,p=s.length;++h<p;)if(r=s[h]){u=r[a][o],e=n.call(r,r.__data__,h,c),l.push(t=[]);for(var g=-1,v=e.length;++g<v;)(i=e[g])&&Qu(i,g,a,o,u),t.push(i)}return Wu(l,a,o)},Yl.filter=function(n){var t,e,r,i=[];"function"!=typeof n&&(n=O(n));for(var u=0,o=this.length;o>u;u++){i.push(t=[]);for(var e=this[u],a=0,l=e.length;l>a;a++)(r=e[a])&&n.call(r,r.__data__,a,u)&&t.push(r)}return Wu(i,this.namespace,this.id)},Yl.tween=function(n,t){var e=this.id,r=this.namespace;return arguments.length<2?this.node()[r][e].tween.get(n):Y(this,null==t?function(t){t[r][e].tween.remove(n)}:function(i){i[r][e].tween.set(n,t)})},Yl.attr=function(n,t){function e(){this.removeAttribute(a)}function r(){this.removeAttributeNS(a.space,a.local)}function i(n){return null==n?e:(n+="",function(){var t,e=this.getAttribute(a);return e!==n&&(t=o(e,n),function(n){this.setAttribute(a,t(n))})})}function u(n){return null==n?r:(n+="",function(){var t,e=this.getAttributeNS(a.space,a.local);return e!==n&&(t=o(e,n),function(n){this.setAttributeNS(a.space,a.local,t(n))})})}if(arguments.length<2){for(t in n)this.attr(t,n[t]);return this}var o="transform"==n?$r:Mr,a=ao.ns.qualify(n);return Ju(this,"attr."+n,t,a.local?u:i)},Yl.attrTween=function(n,t){function e(n,e){var r=t.call(this,n,e,this.getAttribute(i));return r&&function(n){this.setAttribute(i,r(n))}}function r(n,e){var r=t.call(this,n,e,this.getAttributeNS(i.space,i.local));return r&&function(n){this.setAttributeNS(i.space,i.local,r(n))}}var i=ao.ns.qualify(n);return this.tween("attr."+n,i.local?r:e)},Yl.style=function(n,e,r){function i(){this.style.removeProperty(n)}function u(e){return null==e?i:(e+="",function(){var i,u=t(this).getComputedStyle(this,null).getPropertyValue(n);return u!==e&&(i=Mr(u,e),function(t){this.style.setProperty(n,i(t),r)})})}var o=arguments.length;if(3>o){if("string"!=typeof n){2>o&&(e="");for(r in n)this.style(r,n[r],e);return this}r=""}return Ju(this,"style."+n,e,u)},Yl.styleTween=function(n,e,r){function i(i,u){var o=e.call(this,i,u,t(this).getComputedStyle(this,null).getPropertyValue(n));return o&&function(t){this.style.setProperty(n,o(t),r)}}return arguments.length<3&&(r=""),this.tween("style."+n,i)},Yl.text=function(n){return Ju(this,"text",n,Gu)},Yl.remove=function(){var n=this.namespace;return this.each("end.transition",function(){var t;this[n].count<2&&(t=this.parentNode)&&t.removeChild(this)})},Yl.ease=function(n){var t=this.id,e=this.namespace;return arguments.length<1?this.node()[e][t].ease:("function"!=typeof n&&(n=ao.ease.apply(ao,arguments)),Y(this,function(r){r[e][t].ease=n}))},Yl.delay=function(n){var t=this.id,e=this.namespace;return arguments.length<1?this.node()[e][t].delay:Y(this,"function"==typeof n?function(r,i,u){r[e][t].delay=+n.call(r,r.__data__,i,u)}:(n=+n,function(r){r[e][t].delay=n}))},Yl.duration=function(n){var t=this.id,e=this.namespace;return arguments.length<1?this.node()[e][t].duration:Y(this,"function"==typeof n?function(r,i,u){r[e][t].duration=Math.max(1,n.call(r,r.__data__,i,u))}:(n=Math.max(1,n),function(r){r[e][t].duration=n}))},Yl.each=function(n,t){var e=this.id,r=this.namespace;if(arguments.length<2){var i=Ol,u=Hl;try{Hl=e,Y(this,function(t,i,u){Ol=t[r][e],n.call(t,t.__data__,i,u)})}finally{Ol=i,Hl=u}}else Y(this,function(i){var u=i[r][e];(u.event||(u.event=ao.dispatch("start","end","interrupt"))).on(n,t)});return this},Yl.transition=function(){for(var n,t,e,r,i=this.id,u=++Zl,o=this.namespace,a=[],l=0,c=this.length;c>l;l++){a.push(n=[]);for(var t=this[l],f=0,s=t.length;s>f;f++)(e=t[f])&&(r=e[o][i],Qu(e,f,o,u,{time:r.time,ease:r.ease,delay:r.delay+r.duration,duration:r.duration})),n.push(e)}return Wu(a,o,u)},ao.svg.axis=function(){function n(n){n.each(function(){var n,c=ao.select(this),f=this.__chart__||e,s=this.__chart__=e.copy(),h=null==l?s.ticks?s.ticks.apply(s,a):s.domain():l,p=null==t?s.tickFormat?s.tickFormat.apply(s,a):m:t,g=c.selectAll(".tick").data(h,s),v=g.enter().insert("g",".domain").attr("class","tick").style("opacity",Uo),d=ao.transition(g.exit()).style("opacity",Uo).remove(),y=ao.transition(g.order()).style("opacity",1),M=Math.max(i,0)+o,x=Zi(s),b=c.selectAll(".domain").data([0]),_=(b.enter().append("path").attr("class","domain"),ao.transition(b));v.append("line"),v.append("text");var w,S,k,N,E=v.select("line"),A=y.select("line"),C=g.select("text").text(p),z=v.select("text"),L=y.select("text"),q="top"===r||"left"===r?-1:1;if("bottom"===r||"top"===r?(n=no,w="x",k="y",S="x2",N="y2",C.attr("dy",0>q?"0em":".71em").style("text-anchor","middle"),_.attr("d","M"+x[0]+","+q*u+"V0H"+x[1]+"V"+q*u)):(n=to,w="y",k="x",S="y2",N="x2",C.attr("dy",".32em").style("text-anchor",0>q?"end":"start"),_.attr("d","M"+q*u+","+x[0]+"H0V"+x[1]+"H"+q*u)),E.attr(N,q*i),z.attr(k,q*M),A.attr(S,0).attr(N,q*i),L.attr(w,0).attr(k,q*M),s.rangeBand){var T=s,R=T.rangeBand()/2;f=s=function(n){return T(n)+R}}else f.rangeBand?f=s:d.call(n,s,f);v.call(n,f,s),y.call(n,s,s)})}var t,e=ao.scale.linear(),r=Vl,i=6,u=6,o=3,a=[10],l=null;return n.scale=function(t){return arguments.length?(e=t,n):e},n.orient=function(t){return arguments.length?(r=t in Xl?t+"":Vl,n):r},n.ticks=function(){return arguments.length?(a=co(arguments),n):a},n.tickValues=function(t){return arguments.length?(l=t,n):l},n.tickFormat=function(e){return arguments.length?(t=e,n):t},n.tickSize=function(t){var e=arguments.length;return e?(i=+t,u=+arguments[e-1],n):i},n.innerTickSize=function(t){return arguments.length?(i=+t,n):i},n.outerTickSize=function(t){return arguments.length?(u=+t,n):u},n.tickPadding=function(t){return arguments.length?(o=+t,n):o},n.tickSubdivide=function(){return arguments.length&&n},n};var Vl="bottom",Xl={top:1,right:1,bottom:1,left:1};ao.svg.brush=function(){function n(t){t.each(function(){var t=ao.select(this).style("pointer-events","all").style("-webkit-tap-highlight-color","rgba(0,0,0,0)").on("mousedown.brush",u).on("touchstart.brush",u),o=t.selectAll(".background").data([0]);o.enter().append("rect").attr("class","background").style("visibility","hidden").style("cursor","crosshair"),t.selectAll(".extent").data([0]).enter().append("rect").attr("class","extent").style("cursor","move");var a=t.selectAll(".resize").data(v,m);a.exit().remove(),a.enter().append("g").attr("class",function(n){return"resize "+n}).style("cursor",function(n){return $l[n]}).append("rect").attr("x",function(n){return/[ew]$/.test(n)?-3:null}).attr("y",function(n){return/^[ns]/.test(n)?-3:null}).attr("width",6).attr("height",6).style("visibility","hidden"),a.style("display",n.empty()?"none":null);var l,s=ao.transition(t),h=ao.transition(o);c&&(l=Zi(c),h.attr("x",l[0]).attr("width",l[1]-l[0]),r(s)),f&&(l=Zi(f),h.attr("y",l[0]).attr("height",l[1]-l[0]),i(s)),e(s)})}function e(n){n.selectAll(".resize").attr("transform",function(n){return"translate("+s[+/e$/.test(n)]+","+h[+/^s/.test(n)]+")"})}function r(n){n.select(".extent").attr("x",s[0]),n.selectAll(".extent,.n>rect,.s>rect").attr("width",s[1]-s[0])}function i(n){n.select(".extent").attr("y",h[0]),n.selectAll(".extent,.e>rect,.w>rect").attr("height",h[1]-h[0])}function u(){function u(){32==ao.event.keyCode&&(C||(M=null,L[0]-=s[1],L[1]-=h[1],C=2),S())}function v(){32==ao.event.keyCode&&2==C&&(L[0]+=s[1],L[1]+=h[1],C=0,S())}function d(){var n=ao.mouse(b),t=!1;x&&(n[0]+=x[0],n[1]+=x[1]),C||(ao.event.altKey?(M||(M=[(s[0]+s[1])/2,(h[0]+h[1])/2]),L[0]=s[+(n[0]<M[0])],L[1]=h[+(n[1]<M[1])]):M=null),E&&y(n,c,0)&&(r(k),t=!0),A&&y(n,f,1)&&(i(k),t=!0),t&&(e(k),w({type:"brush",mode:C?"move":"resize"}))}function y(n,t,e){var r,i,u=Zi(t),l=u[0],c=u[1],f=L[e],v=e?h:s,d=v[1]-v[0];return C&&(l-=f,c-=d+f),r=(e?g:p)?Math.max(l,Math.min(c,n[e])):n[e],C?i=(r+=f)+d:(M&&(f=Math.max(l,Math.min(c,2*M[e]-r))),r>f?(i=r,r=f):i=f),v[0]!=r||v[1]!=i?(e?a=null:o=null,v[0]=r,v[1]=i,!0):void 0}function m(){d(),k.style("pointer-events","all").selectAll(".resize").style("display",n.empty()?"none":null),ao.select("body").style("cursor",null),q.on("mousemove.brush",null).on("mouseup.brush",null).on("touchmove.brush",null).on("touchend.brush",null).on("keydown.brush",null).on("keyup.brush",null),z(),w({type:"brushend"})}var M,x,b=this,_=ao.select(ao.event.target),w=l.of(b,arguments),k=ao.select(b),N=_.datum(),E=!/^(n|s)$/.test(N)&&c,A=!/^(e|w)$/.test(N)&&f,C=_.classed("extent"),z=W(b),L=ao.mouse(b),q=ao.select(t(b)).on("keydown.brush",u).on("keyup.brush",v);if(ao.event.changedTouches?q.on("touchmove.brush",d).on("touchend.brush",m):q.on("mousemove.brush",d).on("mouseup.brush",m),k.interrupt().selectAll("*").interrupt(),C)L[0]=s[0]-L[0],L[1]=h[0]-L[1];else if(N){var T=+/w$/.test(N),R=+/^n/.test(N);x=[s[1-T]-L[0],h[1-R]-L[1]],L[0]=s[T],L[1]=h[R]}else ao.event.altKey&&(M=L.slice());k.style("pointer-events","none").selectAll(".resize").style("display",null),ao.select("body").style("cursor",_.style("cursor")),w({type:"brushstart"}),d()}var o,a,l=N(n,"brushstart","brush","brushend"),c=null,f=null,s=[0,0],h=[0,0],p=!0,g=!0,v=Bl[0];return n.event=function(n){n.each(function(){var n=l.of(this,arguments),t={x:s,y:h,i:o,j:a},e=this.__chart__||t;this.__chart__=t,Hl?ao.select(this).transition().each("start.brush",function(){o=e.i,a=e.j,s=e.x,h=e.y,n({type:"brushstart"})}).tween("brush:brush",function(){var e=xr(s,t.x),r=xr(h,t.y);return o=a=null,function(i){s=t.x=e(i),h=t.y=r(i),n({type:"brush",mode:"resize"})}}).each("end.brush",function(){o=t.i,a=t.j,n({type:"brush",mode:"resize"}),n({type:"brushend"})}):(n({type:"brushstart"}),n({type:"brush",mode:"resize"}),n({type:"brushend"}))})},n.x=function(t){return arguments.length?(c=t,v=Bl[!c<<1|!f],n):c},n.y=function(t){return arguments.length?(f=t,v=Bl[!c<<1|!f],n):f},n.clamp=function(t){return arguments.length?(c&&f?(p=!!t[0],g=!!t[1]):c?p=!!t:f&&(g=!!t),n):c&&f?[p,g]:c?p:f?g:null},n.extent=function(t){var e,r,i,u,l;return arguments.length?(c&&(e=t[0],r=t[1],f&&(e=e[0],r=r[0]),o=[e,r],c.invert&&(e=c(e),r=c(r)),e>r&&(l=e,e=r,r=l),e==s[0]&&r==s[1]||(s=[e,r])),f&&(i=t[0],u=t[1],c&&(i=i[1],u=u[1]),a=[i,u],f.invert&&(i=f(i),u=f(u)),i>u&&(l=i,i=u,u=l),i==h[0]&&u==h[1]||(h=[i,u])),n):(c&&(o?(e=o[0],r=o[1]):(e=s[0],r=s[1],c.invert&&(e=c.invert(e),r=c.invert(r)),e>r&&(l=e,e=r,r=l))),f&&(a?(i=a[0],u=a[1]):(i=h[0],u=h[1],f.invert&&(i=f.invert(i),u=f.invert(u)),i>u&&(l=i,i=u,u=l))),c&&f?[[e,i],[r,u]]:c?[e,r]:f&&[i,u])},n.clear=function(){return n.empty()||(s=[0,0],h=[0,0],o=a=null),n},n.empty=function(){return!!c&&s[0]==s[1]||!!f&&h[0]==h[1]},ao.rebind(n,l,"on")};var $l={n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},Bl=[["n","e","s","w","nw","ne","se","sw"],["e","w"],["n","s"],[]],Wl=ga.format=xa.timeFormat,Jl=Wl.utc,Gl=Jl("%Y-%m-%dT%H:%M:%S.%LZ");Wl.iso=Date.prototype.toISOString&&+new Date("2000-01-01T00:00:00.000Z")?eo:Gl,eo.parse=function(n){var t=new Date(n);return isNaN(t)?null:t},eo.toString=Gl.toString,ga.second=On(function(n){return new va(1e3*Math.floor(n/1e3))},function(n,t){n.setTime(n.getTime()+1e3*Math.floor(t))},function(n){return n.getSeconds()}),ga.seconds=ga.second.range,ga.seconds.utc=ga.second.utc.range,ga.minute=On(function(n){return new va(6e4*Math.floor(n/6e4))},function(n,t){n.setTime(n.getTime()+6e4*Math.floor(t))},function(n){return n.getMinutes()}),ga.minutes=ga.minute.range,ga.minutes.utc=ga.minute.utc.range,ga.hour=On(function(n){var t=n.getTimezoneOffset()/60;return new va(36e5*(Math.floor(n/36e5-t)+t))},function(n,t){n.setTime(n.getTime()+36e5*Math.floor(t))},function(n){return n.getHours()}),ga.hours=ga.hour.range,ga.hours.utc=ga.hour.utc.range,ga.month=On(function(n){return n=ga.day(n),n.setDate(1),n},function(n,t){n.setMonth(n.getMonth()+t)},function(n){return n.getMonth()}),ga.months=ga.month.range,ga.months.utc=ga.month.utc.range;var Kl=[1e3,5e3,15e3,3e4,6e4,3e5,9e5,18e5,36e5,108e5,216e5,432e5,864e5,1728e5,6048e5,2592e6,7776e6,31536e6],Ql=[[ga.second,1],[ga.second,5],[ga.second,15],[ga.second,30],[ga.minute,1],[ga.minute,5],[ga.minute,15],[ga.minute,30],[ga.hour,1],[ga.hour,3],[ga.hour,6],[ga.hour,12],[ga.day,1],[ga.day,2],[ga.week,1],[ga.month,1],[ga.month,3],[ga.year,1]],nc=Wl.multi([[".%L",function(n){return n.getMilliseconds()}],[":%S",function(n){return n.getSeconds()}],["%I:%M",function(n){return n.getMinutes()}],["%I %p",function(n){return n.getHours()}],["%a %d",function(n){return n.getDay()&&1!=n.getDate()}],["%b %d",function(n){return 1!=n.getDate()}],["%B",function(n){return n.getMonth()}],["%Y",zt]]),tc={range:function(n,t,e){return ao.range(Math.ceil(n/e)*e,+t,e).map(io)},floor:m,ceil:m};Ql.year=ga.year,ga.scale=function(){return ro(ao.scale.linear(),Ql,nc)};var ec=Ql.map(function(n){return[n[0].utc,n[1]]}),rc=Jl.multi([[".%L",function(n){return n.getUTCMilliseconds()}],[":%S",function(n){return n.getUTCSeconds()}],["%I:%M",function(n){return n.getUTCMinutes()}],["%I %p",function(n){return n.getUTCHours()}],["%a %d",function(n){return n.getUTCDay()&&1!=n.getUTCDate()}],["%b %d",function(n){return 1!=n.getUTCDate()}],["%B",function(n){return n.getUTCMonth()}],["%Y",zt]]);ec.year=ga.year.utc,ga.scale.utc=function(){return ro(ao.scale.linear(),ec,rc)},ao.text=An(function(n){return n.responseText}),ao.json=function(n,t){return Cn(n,"application/json",uo,t)},ao.html=function(n,t){return Cn(n,"text/html",oo,t)},ao.xml=An(function(n){return n.responseXML}),"function"==typeof define&&define.amd?(this.d3=ao,define(ao)):"object"==typeof module&&module.exports?module.exports=ao:this.d3=ao}();
\ No newline at end of file
diff --git a/xos/core/xoslib/static/js/xosAdminSite.js b/xos/core/xoslib/static/js/xosAdminSite.js
new file mode 100644
index 0000000..035caab
--- /dev/null
+++ b/xos/core/xoslib/static/js/xosAdminSite.js
@@ -0,0 +1,249 @@
+/* eslint-disable */

+OBJS = ['deployment', 'image', 'networkTemplate', 'network', 'port',

+        'node', 'service', 'site', 'slice',  'slicePrivilege', 'instance',

+        'user', 'sliceRole',  'flavor', 'controller', 'siteDeployment',

+        'controller_image', 'controller_network', 'controller_slice', 'controller_user'];

+NAV_OBJS = ['deployment', 'site', 'slice', 'user'];

+

+REWRITES = {"/admin/core/deployment/": "#deployments",

+            "/admin/core/site/" : "#sites",

+            "/admin/core/slice/" : "#slices",

+            "/admin/core/user/" : "#users"};

+

+XOSAdminApp = new XOSApplication({

+    logTableId: "#logTable",

+    statusMsgId: "#statusMsg",

+    hideTabsByDefault: true

+});

+

+XOSAdminApp.addRegions({

+    navigation: "#navigationPanel",

+

+    detail: "#detail",

+    linkedObjs1: "#linkedObjs1",

+    linkedObjs2: "#linkedObjs2",

+    linkedObjs3: "#linkedObjs3",

+    linkedObjs4: "#linkedObjs4",

+

+    addChildDetail: "#xos-addchild-detail",

+

+    rightButtonPanel: "#rightButtonPanel"

+});

+

+XOSAdminApp.navigate = function(what, modelName, modelId) {

+    console.log("XOSAsminApp.navigate");

+    collection_name = modelName + "s";

+    if (what=="list") {

+        XOSAdminApp.Router.navigate(collection_name, {trigger: true})

+    } else if (what=="detail") {

+        XOSAdminApp.Router.navigate(collection_name + "/" + modelId, {trigger: true})

+    } else if (what=="add") {

+        XOSAdminApp.Router.navigate("add" + firstCharUpper(modelName), {trigger: true, force: true})

+    }

+}

+

+ICON_CLASSES = {home: "icon-home", deployments: "icon-deployment", sites: "icon-site", slices: "icon-slice", users: "icon-user"};

+

+XOSAdminApp.updateNavigationPanel = function() {

+    console.log('UPDATE NAV!!!');

+    buttonTemplate=$("#xos-navbutton").html();

+    assert(buttonTemplate != undefined, "buttonTemplate is undefined");

+    html="<div class='left-nav'><ul>";

+    for (var index in NAV_OBJS) {

+        name = NAV_OBJS[index];

+        collection_name = name+"s";

+        nav_url = "#" + collection_name;

+        id = "nav-"+name;

+        icon_class = ICON_CLASSES[collection_name] || "icon-cog";

+

+        html = html + _.template(buttonTemplate, {name: collection_name, router: "XOSAdminApp.Router", routeUrl: nav_url, iconClass: icon_class});

+    }

+

+    html = html + "</ul>";

+

+    $("#navigationPanel").html(html);

+};

+

+XOSAdminApp.buildViews = function() {

+     genericAddChildClass = XOSDetailView.extend({template: "#xos-add-template",

+                                                        app: XOSAdminApp});

+     XOSAdminApp["genericAddChildView"] = genericAddChildClass;

+

+     genericDetailClass = XOSDetailView.extend({template: "#xos-detail-template",

+                                                           app: XOSAdminApp});

+     XOSAdminApp["genericDetailView"] = genericDetailClass;

+

+     genericItemViewClass = XOSItemView.extend({template: "#xos-listitem-template",

+                                                app: XOSAdminApp});

+     XOSAdminApp["genericItemView"] = genericItemViewClass;

+

+     //genericListViewClass = XOSListView.extend({template: "#xos-list-template",

+     //                                           app: XOSAdminApp});

+

+     genericListViewClass = XOSDataTableView.extend({template: "#xos-list-template", app: XOSAdminApp});

+     XOSAdminApp["genericListView"] = genericListViewClass;

+

+     for (var index in OBJS) {

+         name = OBJS[index];

+         tr_template = '#xosAdmin-' + name + '-listitem-template';

+         table_template = '#xosAdmin-' + name + '-list-template';

+         detail_template = '#xosAdmin-' + name + '-detail-template';

+         add_child_template = '#xosAdmin-' + name + '-add-child-template';

+         collection_name = name + "s";

+         region_name = name + "List";

+

+         if (window["XOSDetailView_" + name]) {

+             detailClass = window["XOSDetailView_" + name].extend({template: "#xos-detail-template",

+                                                                    app: XOSAdminApp});

+         } else {

+             detailClass = genericDetailClass;

+         }

+         if ($(detail_template).length) {

+             detailClass = detailClass.extend({

+                template: detail_template,

+             });

+         }

+         XOSAdminApp[collection_name + "DetailView"] = detailClass;

+

+         if (window["XOSDetailView_" + name]) {

+             addClass = window["XOSDetailView_" + name].extend({template: "#xos-add-template",

+                                                                    app: XOSAdminApp});

+         } else {

+             addClass = genericAddChildClass;

+         }

+         if ($(add_child_template).length) {

+             addClass = detailClass.extend({

+                template: add_child_template,

+             });

+         }

+         XOSAdminApp[collection_name + "AddChildView"] = addClass;

+

+         if ($(tr_template).length) {

+             itemViewClass = XOSItemView.extend({

+                 template: tr_template,

+                 app: XOSAdminApp,

+             });

+         } else {

+             itemViewClass = genericItemViewClass;

+         }

+

+         if ($(table_template).length) {

+             listViewClass = XOSListView.extend({

+                 childView: itemViewClass,

+                 template: table_template,

+                 collection: xos[collection_name],

+                 title: name + "s",

+                 app: XOSAdminApp,

+             });

+         } else {

+             listViewClass = genericListViewClass.extend( { childView: itemViewClass,

+                                                            collection: xos[collection_name],

+                                                            title: name + "s",

+                                                           } );

+         }

+

+         XOSAdminApp[collection_name + "ListView"] = listViewClass;

+

+         xos[collection_name].fetch(); //startPolling();

+     }

+};

+

+XOSAdminApp.initRouter = function() {

+    router = XOSRouter;

+    var api = {};

+    var routes = {};

+

+    for (var index in OBJS) {

+        name = OBJS[index];

+        collection_name = name + "s";

+        nav_url = collection_name;

+        api_command = "list" + firstCharUpper(collection_name);

+        listViewName = collection_name + "ListView";

+        detailViewName = collection_name + "DetailView";

+        addChildViewName = collection_name + "AddChildView";

+

+        api[api_command] = XOSAdminApp.createListHandler(listViewName, collection_name, "detail", collection_name);

+        routes[nav_url] = api_command;

+

+        nav_url = collection_name + "/:id";

+        api_command = "detail" + firstCharUpper(collection_name);

+

+        api[api_command] = XOSAdminApp.createDetailHandler(detailViewName, collection_name, "detail", name);

+        routes[nav_url] = api_command;

+

+        nav_url = "add" + firstCharUpper(name);

+        api_command = "add" + firstCharUpper(name);

+        api[api_command] = XOSAdminApp.createAddHandler(detailViewName, collection_name, "detail", name);

+        routes[nav_url] = api_command;

+

+        nav_url = "addChild" + firstCharUpper(name) + "/:parentModel/:parentField/:parentId";

+        api_command = "addChild" + firstCharUpper(name);

+        api[api_command] = XOSAdminApp.createAddChildHandler(addChildViewName, collection_name);

+        routes[nav_url] = api_command;

+

+        nav_url = "delete" + firstCharUpper(name) + "/:id";

+        api_command = "delete" + firstCharUpper(name);

+        api[api_command] = XOSAdminApp.createDeleteHandler(collection_name, name);

+        routes[nav_url] = api_command;

+    };

+

+    routes["*part"] = "listSlices";

+

+    XOSAdminApp.Router = new router({ appRoutes: routes, controller: api });

+};

+

+/* rewriteLinks

+

+   Rewrite the links in the suit navbar from django-links to marionette

+   links. This let's us intercept the navbar and make it function within

+   this view rather than jumping back out to a django view.

+*/

+

+XOSAdminApp.rewriteLinks = function () {

+    $("a").each(function() {

+        href=$(this).attr("href");

+        rewrite_href=REWRITES[href];

+        if (rewrite_href) {

+            $(this).attr("href", rewrite_href);

+        }

+    });

+};

+

+XOSAdminApp.startNavigation = function() {

+    Backbone.history.start();

+    XOSAdminApp.navigationStarted = true;

+}

+

+XOSAdminApp.collectionLoadChange = function() {

+    stats = xos.getCollectionStatus();

+

+    if (!XOSAdminApp.navigationStarted) {

+        if (stats["isLoaded"] + stats["failedLoad"] >= stats["startedLoad"]) {

+            XOSAdminApp.startNavigation();

+        } else {

+            $("#detail").html("<h3>Loading...</h3><div id='xos-startup-progress'></div>");

+            $("#xos-startup-progress").progressbar({value: stats["completedLoad"], max: stats["startedLoad"]});

+        }

+    }

+};

+

+XOSAdminApp.on("start", function() {

+     XOSAdminApp.buildViews();

+

+     XOSAdminApp.initRouter();

+

+     XOSAdminApp.updateNavigationPanel();

+

+     XOSAdminApp.rewriteLinks();

+

+     // fire it once to initially show the progress bar

+     XOSAdminApp.collectionLoadChange();

+

+     // fire it each time the collection load status is updated

+     Backbone.on("xoslib:collectionLoadChange", XOSAdminApp.collectionLoadChange);

+});

+

+$(document).ready(function(){

+    XOSAdminApp.start();

+});

+/* eslint-enable */

diff --git a/xos/core/xoslib/static/js/xosCeilometerDashboard.js b/xos/core/xoslib/static/js/xosCeilometerDashboard.js
new file mode 100644
index 0000000..808ffde
--- /dev/null
+++ b/xos/core/xoslib/static/js/xosCeilometerDashboard.js
@@ -0,0 +1 @@
+"use strict";angular.module("xos.ceilometerDashboard",["ngResource","ngCookies","ui.router","xos.helpers","ngAnimate","chart.js","ui.bootstrap.accordion"]).config(["$stateProvider","$urlRouterProvider",function(e,t){e.state("ceilometerDashboard",{url:"/",template:"<ceilometer-dashboard></ceilometer-dashboard>"}).state("samples",{url:"/:name/:tenant/samples",template:"<ceilometer-samples></ceilometer-samples>"}),t.otherwise("/")}]).config(["$httpProvider",function(e){e.interceptors.push("NoHyperlinks")}]).run(["$rootScope",function(e){e.stateName="ceilometerDashboard",e.$on("$stateChangeStart",function(t,n){e.stateName=n.name})}]),angular.module("xos.ceilometerDashboard").run(["$templateCache",function(e){e.put("templates/accordion-group.html",'<div class="panel {{panelClass || \'panel-default\'}}">\n  <div class="panel-heading" ng-keypress="toggleOpen($event)">\n    <h5>\n      <a href tabindex="0" class="accordion-toggle" ng-click="toggleOpen()" uib-accordion-transclude="heading"><span ng-class="{\'text-muted\': isDisabled}">{{heading}}</span></a>\n    </h5>\n  </div>\n  <div class="panel-collapse collapse" uib-collapse="!isOpen">\n	  <div class="panel-body" ng-transclude></div>\n  </div>\n</div>\n'),e.put("templates/accordion.html",'<div class="panel-group" ng-transclude></div>'),e.put("templates/ceilometer-dashboard.tpl.html",'<div class="row">\n  <div class="col-sm-10">\n    <h3>XOS Monitoring Statistics</h3>\n  </div>\n  <div class="col-xs-2 text-right">\n    <a href="" class="btn btn-default" \n      ng-show="vm.selectedSlice && !vm.showStats"\n      ng-click="vm.showStats = true">\n      <i class="glyphicon glyphicon-transfer"></i>\n    </a>\n    <a href="" class="btn btn-default" \n      ng-show="vm.selectedSlice && vm.showStats"\n      ng-click="vm.showStats = false">\n      <i class="glyphicon glyphicon-transfer"></i>\n    </a>\n  </div>\n</div>\n\n<div class="row" ng-show="vm.loader">\n  <div class="col-xs-12">\n    <div class="loader">Loading</div>\n  </div>\n</div>\n\n<section ng-hide="vm.loader" ng-class="{animate: !vm.loader}">\n  <div class="row">\n    <div class="col-sm-3 service-list">\n        <h4>XOS Service: </h4>\n        <uib-accordion close-others="true" template-url="templates/accordion.html">\n          <uib-accordion-group\n            ng-repeat="service in vm.services | orderBy:\'-service\'"\n            template-url="templates/accordion-group.html"\n            is-open="vm.accordion.open[service.service]"\n            heading="{{service.service}}">\n            <h5>Slices:</h5>\n            <a ng-repeat="slice in service.slices" \n              ng-class="{active: slice.slice === vm.selectedSlice}"\n              ng-click="vm.loadSliceMeter(slice, service.service)"\n              href="#" class="list-group-item" >\n              {{slice.slice}} <i class="glyphicon glyphicon-chevron-right pull-right"></i>\n            </a>\n          </uib-accordion-group>\n        </uib-accordion>\n    </div>\n    <section class="side-container col-sm-9">\n      <div class="row">\n        <!-- STATS -->\n        <article ng-hide="!vm.showStats" class="stats animate-slide-left">\n          <div class="col-xs-12">\n            <div class="list-group">\n              <div class="list-group-item">\n                <h4>Stats</h4>\n              </div>\n              <div class="list-group-item">\n                <ceilometer-stats ng-if="vm.selectedSlice" name="vm.selectedSlice" tenant="vm.selectedTenant"></ceilometer-stats>\n              </div>\n            </div>\n          </div>\n        </article>\n        <!-- METERS -->\n        <article ng-hide="vm.showStats" class="meters animate-slide-left">\n          <div class="alert alert-danger" ng-show="vm.ceilometerError">\n            {{vm.ceilometerError}}\n          </div>\n          <div class="col-sm-4 animate-slide-left" ng-hide="!vm.selectedSlice">\n            <div class="list-group">\n              <div class="list-group-item">\n                <h4>Resources</h4>\n              </div>\n              <a href="#" \n                ng-click="vm.selectMeters(meters, resource)" \n                class="list-group-item" \n                ng-repeat="(resource, meters) in vm.selectedResources" \n                ng-class="{active: resource === vm.selectedResource}">\n                {{resource}} <i class="glyphicon glyphicon-chevron-right pull-right"></i>\n              </a>\n            </div>\n          </div>\n          <div class="col-sm-8 animate-slide-left" ng-hide="!vm.selectedMeters">\n            <div class="list-group">\n              <div class="list-group-item">\n                <h4>Meters</h4>\n              </div>\n              <div class="list-group-item">\n                <div class="row">\n                  <div class="col-xs-6">\n                    <label>Name:</label>\n                  </div>\n                  <div class="col-xs-3">\n                    <label>Unit:</label>\n                  </div>\n                  <div class="col-xs-3"></div>\n                </div>\n                <div class="row" ng-repeat="meter in vm.selectedMeters" style="margin-bottom: 10px;">\n                  <div class="col-xs-6">\n                    {{meter.name}}\n                  </div>\n                  <div class="col-xs-3">\n                    {{meter.unit}}\n                  </div>\n                  <div class="col-xs-3">\n                    <!-- tenant: meter.resource_id -->\n                    <a ui-sref="samples({name: meter.name, tenant: meter.resource_id})" class="btn btn-primary">\n                      <i class="glyphicon glyphicon-search"></i>\n                    </a>\n                  </div>\n                </div>\n              </div>\n            </div>\n          </div>\n        </article>\n      </div>\n    </section>\n  </div>\n</section>\n<section ng-if="!vm.loader && vm.error">\n  <div class="alert alert-danger">\n    {{vm.error}}\n  </div>\n</section>\n'),e.put("templates/ceilometer-samples.tpl.html",'<!-- <pre>{{ vm | json}}</pre> -->\n\n<div class="row">\n  <div class="col-xs-10">\n    <h1>{{vm.name | uppercase}}</h1>\n  </div>\n  <div class="col-xs-2">\n    <a ui-sref="ceilometerDashboard" class="btn btn-primary pull-right">\n      <i class="glyphicon glyphicon-arrow-left"></i> Back to list\n    </a>\n  </div>\n</div>\n<div class="row" ng-show="vm.loader">\n  <div class="col-xs-12">\n    <div class="loader">Loading</div>\n  </div>\n</div>\n<section ng-if="!vm.loader && !vm.error">\n  <div class="row">\n    <form class="form-inline col-xs-8" ng-submit="vm.addMeterToChart(vm.addMeterValue)">\n      <select ng-model="vm.addMeterValue" class="form-control" ng-options="resource.id as resource.name for resource in vm.sampleLabels"></select>\n      <button class="btn btn-success"> \n        <i class="glyphicon glyphicon-plus"></i> Add\n      </button>\n    </form>\n    <div class="col-xs-4 text-right">\n      <a ng-click="vm.chartType = \'line\'" class="btn" ng-class="{\'btn-default\': vm.chartType != \'bar\', \'btn-primary\': vm.chartType == \'line\'}">Lines</a>\n      <a ng-click="vm.chartType = \'bar\'" class="btn" ng-class="{\'btn-default\': vm.chartType != \'line\', \'btn-primary\': vm.chartType == \'bar\'}">Bars</a>\n    </div>\n  </div>\n  <div class="row" ng-if="!vm.loader">\n    <div class="col-xs-12">\n      <canvas ng-if="vm.chartType === \'line\'" id="line" class="chart chart-line" chart-data="vm.chart.data" chart-options="{datasetFill: false}"\n        chart-labels="vm.chart.labels" chart-legend="false" chart-series="vm.chart.series">\n      </canvas>\n      <canvas ng-if="vm.chartType === \'bar\'" id="bar" class="chart chart-bar" chart-data="vm.chart.data"\n        chart-labels="vm.chart.labels" chart-legend="false" chart-series="vm.chart.series">\n      </canvas>\n      <!-- <pre>{{vm.chartMeters | json}}</pre> -->\n    </div>\n  </div>\n  <div class="row" ng-if="!vm.loader">\n    <div class="col-xs-12">\n      <a ng-click="vm.removeFromChart(meter)" class="btn btn-chart" ng-style="{\'background-color\': vm.chartColors[$index]}" ng-repeat="meter in vm.chartMeters">\n        {{meter.resource_name || meter.resource_id}}\n      </a>\n    </div>\n  </div>\n</section>\n<section ng-if="!vm.loader && vm.error">\n  <div class="alert alert-danger">\n    {{vm.error}}\n  </div>\n</section>'),e.put("templates/ceilometer-stats.tpl.html",'<div ng-show="vm.loader" class="loader">Loading</div>\n\n<section ng-if="!vm.loader && !vm.error">\n\n  <div class="alert alert-danger" ng-if="vm.stats.length == 0">\n    No result\n  </div>  \n\n  <table class="table" ng-if="vm.stats.length > 0">\n    <tr>\n      <th>\n        <a ng-click="(order == \'category\') ? order = \'-category\' : order = \'category\'">Type:</a>\n      </th>\n      <th>\n        <a ng-click="(order == \'resource_name\') ? order = \'-resource_name\' : order = \'resource_name\'">Resource:</a>\n      </th>\n      <th>\n        <a ng-click="(order == \'meter\') ? order = \'-meter\' : order = \'meter\'">Meter:</a>\n      </th>\n      <th>\n        Unit:\n      </th>\n      <th>\n        Value:\n      </th>\n    </tr>\n    <!-- <tr>\n      <td>\n        <input type="text" ng-model="query.category">\n      </td>\n      <td>\n        <input type="text" ng-model="query.resource_name">\n      </td>\n      <td>\n        <input type="text" ng-model="query.meter">\n      </td>\n      <td>\n        <input type="text" ng-model="query.unit">\n      </td>\n      <td>\n        <input type="text" ng-model="query.value">\n      </td>\n    </tr> -->\n    <tr ng-repeat="item in vm.stats | orderBy:order">\n      <td>{{item.category}}</td>\n      <td>{{item.resource_name}}</td>\n      <td>{{item.meter}}</td>\n      <td>{{item.unit}}</td>\n      <td>{{item.value}}</td>\n    </tr>\n  </table>\n</section>\n\n<section ng-if="!vm.loader && vm.error">\n  <div class="alert alert-danger">\n    {{vm.error}}\n  </div>\n</section>\n'),e.put("templates/users-list.tpl.html",'<xos-table config="vm.tableConfig" data="vm.users"></xos-table>')}]),function(){angular.module("xos.ceilometerDashboard").directive("ceilometerStats",function(){return{restrict:"E",scope:{name:"=name",tenant:"=tenant"},bindToController:!0,controllerAs:"vm",templateUrl:"templates/ceilometer-stats.tpl.html",controller:["$scope","Ceilometer",function(e,t){var n=this;this.getStats=function(e){n.loader=!0,t.getStats({tenant:e}).then(function(e){e.map(function(e){return e.resource_name=e.resource_name.replace("mysite_onos_vbng","ONOS_FABRIC"),e.resource_name=e.resource_name.replace("mysite_onos_volt","ONOS_CORD"),e.resource_name=e.resource_name.replace("mysite_vbng","mysite_vRouter"),e}),n.stats=e})["catch"](function(e){n.error=e.data})["finally"](function(){n.loader=!1})},e.$watch(function(){return n.name},function(e){e&&n.getStats(n.tenant)})}]}})}(),function(){angular.module("xos.ceilometerDashboard").directive("ceilometerSamples",["_","$stateParams",function(e,t){return{restrict:"E",scope:{},bindToController:!0,controllerAs:"vm",templateUrl:"templates/ceilometer-samples.tpl.html",controller:["Ceilometer",function(n){var s=this;if(this.chartColors=["#286090","#F7464A","#46BFBD","#FDB45C","#97BBCD","#4D5360","#8c4f9f"],this.chart={series:[],labels:[],data:[]},Chart.defaults.global.colours=this.chartColors,this.chartType="line",!t.name||!t.tenant)throw new Error("Missing Name and Tenant Params!");this.name=t.name,this.tenant=t.tenant,this.getLabels=function(e){return e.reduce(function(e,t){var n=new Date(t.timestamp);return e.push(n.getHours()+":"+((n.getMinutes()<10?"0":"")+n.getMinutes())+":"+n.getSeconds()),e},[])},this.getData=function(e){return e.reduce(function(e,t){return e.push(t.volume),e},[])},this.chartMeters=[],this.addMeterToChart=function(t){s.chart.labels=s.getLabels(e.sortBy(s.samplesList[t],"timestamp")),s.chart.series.push(t),s.chart.data.push(s.getData(e.sortBy(s.samplesList[t],"timestamp"))),s.chartMeters.push(s.samplesList[t][0]),e.remove(s.sampleLabels,{id:t})},this.removeFromChart=function(t){s.chart.data.splice(s.chart.series.indexOf(t.resource_id),1),s.chart.series.splice(s.chart.series.indexOf(t.resource_id),1),s.chartMeters.splice(e.findIndex(s.chartMeters,{resource_id:t.resource_id}),1),s.sampleLabels.push({id:t.resource_id,name:t.resource_name||t.resource_id})},this.formatSamplesLabels=function(t){return e.uniq(t,"resource_id").reduce(function(e,t){return e.push({id:t.resource_id,name:t.resource_name||t.resource_id}),e},[])},this.showSamples=function(){s.loader=!0,n.getSamples(s.name).then(function(t){t.map(function(e){return e.resource_name=e.resource_name.replace("mysite_onos_vbng","ONOS_FABRIC"),e.resource_name=e.resource_name.replace("mysite_onos_volt","ONOS_CORD"),e.resource_name=e.resource_name.replace("mysite_vbng","mysite_vRouter"),e}),s.samplesList=e.groupBy(t,"resource_id"),s.sampleLabels=s.formatSamplesLabels(t),s.addMeterToChart(s.tenant)})["catch"](function(e){s.error=e.data.detail})["finally"](function(){s.loader=!1})},this.showSamples()}]}}])}(),function(){angular.module("xos.ceilometerDashboard").service("Ceilometer",["$http","$q",function(e,t){this.getMappings=function(){var n=t.defer();return e.get("/xoslib/xos-slice-service-mapping/").then(function(e){n.resolve(e.data)})["catch"](function(e){n.reject(e)}),n.promise},this.getMeters=function(n){var s=t.defer();return e.get("/xoslib/meters/",{cache:!0,params:n}).then(function(e){s.resolve(e.data)})["catch"](function(e){s.reject(e)}),s.promise},this.getSamples=function(n,s){var r=t.defer();return e.get("/xoslib/metersamples/",{params:{meter:n,tenant:s}}).then(function(e){r.resolve(e.data)})["catch"](function(e){r.reject(e)}),r.promise},this.getStats=function(n){var s=t.defer();return e.get("/xoslib/meterstatistics/",{cache:!0,params:n}).then(function(e){s.resolve(e.data)})["catch"](function(e){s.reject(e)}),s.promise},this.selectedService=null,this.selectedSlice=null,this.selectedResource=null}])}(),function(){angular.module("xos.ceilometerDashboard").directive("ceilometerDashboard",["_",function(e){return{restrict:"E",scope:{},bindToController:!0,controllerAs:"vm",templateUrl:"templates/ceilometer-dashboard.tpl.html",controller:["Ceilometer",function(t){var n=this;this.showStats=!1,this.accordion={open:{}},this.openPanels=function(){t.selectedService&&(n.accordion.open[t.selectedService]=!0,t.selectedSlice&&(n.loadSliceMeter(t.selectedSlice,t.selectedService),n.selectedSlice=t.selectedSlice,t.selectedResource&&(n.selectedResource=t.selectedResource)))},this.loadMappings=function(){n.loader=!0,t.getMappings().then(function(e){e.map(function(e){return"service_ONOS_vBNG"===e.service&&(e.service="ONOS_FABRIC"),"service_ONOS_vOLT"===e.service&&(e.service="ONOS_CORD"),e.slices.map(function(e){"mysite_onos_volt"===e.slice&&(e.slice="ONOS_CORD"),"mysite_onos_vbng"===e.slice&&(e.slice="ONOS_FABRIC"),"mysite_vbng"===e.slice&&(e.slice="mysite_vRouter")}),e}),n.services=e,n.openPanels()})["catch"](function(e){n.error=e.data&&e.data.detail?e.data.detail:"An Error occurred. Please try again later."})["finally"](function(){n.loader=!1})},this.loadMappings(),this.loadSliceMeter=function(s,r){t.selectedSlice=null,t.selectedService=null,t.selectedResources=null,n.loader=!0,n.error=null,n.ceilometerError=null,t.getMeters({tenant:s.project_id}).then(function(a){n.selectedSlice=s.slice,n.selectedTenant=s.project_id,t.selectedSlice=s,t.selectedService=r,a.map(function(e){return e.resource_name=e.resource_name.replace("mysite_onos_vbng","ONOS_FABRIC"),e.resource_name=e.resource_name.replace("mysite_onos_volt","ONOS_CORD"),e.resource_name=e.resource_name.replace("mysite_vbng","mysite_vRouter"),e}),n.selectedResources=e.groupBy(a,"resource_name"),t.selectedResource&&(n.selectedMeters=n.selectedResources[t.selectedResource])})["catch"](function(e){return 503===e.status?n.ceilometerError=e.data.detail.specific_error:void(n.ceilometerError=e.data&&e.data.detail&&e.data.detail.specific_error?e.data.detail.specific_error:"An Error occurred. Please try again later.")})["finally"](function(){n.loader=!1})},this.selectedMeters=null,this.selectMeters=function(e,s){n.selectedMeters=e,t.selectedResource=s,n.selectedResource=s}}]}}])}(),angular.module("xos.ceilometerDashboard").run(["$location",function(e){e.path("/")}]);
\ No newline at end of file
diff --git a/xos/core/xoslib/static/js/xosContentProvider.js b/xos/core/xoslib/static/js/xosContentProvider.js
new file mode 100644
index 0000000..44b9921
--- /dev/null
+++ b/xos/core/xoslib/static/js/xosContentProvider.js
@@ -0,0 +1 @@
+"use strict";angular.module("xos.contentProvider",["ngResource","ngCookies","xos.helpers","ui.router"]).config(["$stateProvider",function(n){n.state("list",{url:"/",template:"<content-provider-list></content-provider-list>"}).state("details",{url:"/contentProvider/:id",template:"<content-provider-detail></content-provider-detail>"}).state("cdn",{url:"/contentProvider/:id/cdn_prefix",template:"<content-provider-cdn></content-provider-cdn>"}).state("server",{url:"/contentProvider/:id/origin_server",template:"<content-provider-server></content-provider-server>"}).state("users",{url:"/contentProvider/:id/users",template:"<content-provider-users></content-provider-users>"})}]).config(["$httpProvider",function(n){n.interceptors.push("SetCSRFToken"),n.interceptors.push("NoHyperlinks")}]).service("ContentProvider",["$resource",function(n){return n("/hpcapi/contentproviders/:id/",{id:"@id"},{update:{method:"PUT"}})}]).service("ServiceProvider",["$resource",function(n){return n("/hpcapi/serviceproviders/:id/",{id:"@id"})}]).service("CdnPrefix",["$resource",function(n){return n("/hpcapi/cdnprefixs/:id/",{id:"@id"})}]).service("OriginServer",["$resource",function(n){return n("/hpcapi/originservers/:id/",{id:"@id"})}]).service("User",["$resource",function(n){return n("/xos/users/:id/",{id:"@id"})}]).directive("cpActions",["ContentProvider","$location",function(n,e){return{restrict:"E",scope:{id:"=id"},bindToController:!0,controllerAs:"vm",templateUrl:"templates/cp_actions.html",controller:function(){this.deleteCp=function(t){n["delete"]({id:t}).$promise.then(function(){e.url("/")})}}}}]).directive("contentProviderList",["ContentProvider","_",function(n,e){return{restrict:"E",controllerAs:"vm",scope:{},templateUrl:"templates/cp_list.html",controller:function(){this.tableConfig={columns:[{label:"Name",field:"humanReadableName"},{label:"Description",field:"description"},{label:"Status",field:"enabled"}],enableActions:!0};var t=this;n.query().$promise.then(function(n){t.contentProviderList=n})["catch"](function(n){throw new Error(n)}),this.deleteCp=function(s){n["delete"]({id:s}).$promise.then(function(){e.remove(t.contentProviderList,{id:s})})}}}}]).directive("contentProviderDetail",["ContentProvider","ServiceProvider","$stateParams","$location",function(n,e,t,s){return{restrict:"E",controllerAs:"vm",scope:{},templateUrl:"templates/cp_detail.html",controller:function(){this.pageName="detail";var i=this;t.id?n.get({id:t.id}).$promise.then(function(n){i.cp=n})["catch"](function(n){i.result={status:0,msg:n.data.detail}}):i.cp=new n,e.query().$promise.then(function(n){i.sp=n}),this.saveContentProvider=function(n){var e,t=!1;n.id?e=n.$update():(t=!0,n.name=n.humanReadableName,e=n.$save()),e.then(function(n){i.result={status:1,msg:"Content Provider Saved"},t&&s.url("contentProvider/"+n.id+"/")})["catch"](function(n){i.result={status:0,msg:n.data.detail}})}}}}]).directive("contentProviderCdn",["$stateParams","CdnPrefix","ContentProvider",function(n,e,t){return{restrict:"E",controllerAs:"vm",scope:{},templateUrl:"templates/cp_cdn_prefix.html",controller:["_",function(s){var i=this;this.pageName="cdn",n.id&&t.get({id:n.id}).$promise.then(function(n){i.cp=n})["catch"](function(n){i.result={status:0,msg:n.data?n.data.detail:""}}),e.query().$promise.then(function(e){i.prf=e,i.cp_prf=[],i.cp_prf.push(s.find(e,{contentProvider:parseInt(n.id)}))})["catch"](function(n){i.result={status:0,msg:n.data.detail}}),this.addPrefix=function(t){t.contentProvider=n.id;var s=new e(t);s.$save().then(function(n){i.cp_prf.push(n)})["catch"](function(n){i.result={status:0,msg:n.data.detail}})},this.removePrefix=function(n){n.$delete().then(function(){s.remove(i.cp_prf,n)})["catch"](function(n){i.result={status:0,msg:n.data.detail}})}}]}}]).directive("contentProviderServer",["$stateParams","OriginServer","ContentProvider",function(n,e,t){return{restrict:"E",controllerAs:"vm",scope:{},templateUrl:"templates/cp_origin_server.html",controller:["_",function(s){this.pageName="server",this.protocols={http:"HTTP",rtmp:"RTMP",rtp:"RTP",shout:"SHOUTcast"};var i=this;n.id&&t.get({id:n.id}).$promise.then(function(n){i.cp=n})["catch"](function(n){i.result={status:0,msg:n.data.detail}}),e.query({contentProvider:n.id}).$promise.then(function(n){i.cp_os=n})["catch"](function(n){i.result={status:0,msg:n.data.detail}}),this.addOrigin=function(t){t.contentProvider=n.id;var s=new e(t);s.$save().then(function(n){i.cp_os.push(n)})["catch"](function(n){i.result={status:0,msg:n.data.detail}})},this.removeOrigin=function(n){n.$delete().then(function(){s.remove(i.cp_os,n)})["catch"](function(n){i.result={status:0,msg:n.data.detail}})}}]}}]).directive("contentProviderUsers",["$stateParams","ContentProvider","User",function(n,e,t){return{restrict:"E",controllerAs:"vm",scope:{},templateUrl:"templates/cp_user.html",controller:["_",function(s){var i=this;this.pageName="user",this.cp_users=[],n.id&&t.query().$promise.then(function(t){return i.users=t,e.get({id:n.id}).$promise}).then(function(n){return n.users=i.populateUser(n.users,i.users),n}).then(function(n){i.cp=n})["catch"](function(n){i.result={status:0,msg:n.data.detail}}),this.populateUser=function(n,e){for(var t=0;t<n.length;t++)n[t]=s.find(e,{id:n[t]});return n},this.addUserToCp=function(n){i.cp.users.push(n)},this.removeUserFromCp=function(n){s.remove(i.cp.users,n)},this.saveContentProvider=function(n){n.users=s.map(n.users,"id"),n.$update().then(function(n){i.cp.users=i.populateUser(n.users,i.users),i.result={status:1,msg:"Content Provider Saved"}})["catch"](function(n){i.result={status:0,msg:n.data.detail}})}}]}}]),angular.module("xos.contentProvider").run(["$templateCache",function(n){n.put("templates/cp_actions.html",'<a href="#/" class="btn btn-default">\n  <i class="icon icon-arrow-left"></i>Back\n</a>\n<a href="#/contentProvider/" class="btn btn-success">\n  <i class="icon icon-plus"></i>Create\n</a>\n<a ng-click="vm.deleteCp(vm.id)" class="btn btn-danger">\n  <i class="icon icon-remove"></i>Remove\n</a>'),n.put("templates/cp_cdn_prefix.html",'<div class="row-fluid">\n  <div class="span6">\n    <h1>{$ vm.cp.humanReadableName $}</h1>\n  </div>\n  <div class="span6 text-right">\n    <cp-actions id="vm.cp.id"></cp-actions>\n  </div>\n</div>\n<hr>\n<div class="row-fluid">\n  <div class="span2">\n    <div ng-include="\'templates/cp_side_nav.html\'"></div>\n  </div>\n  <div class="span10">\n    <div ng-repeat="item in vm.cp_prf" class="well">\n      <div class="row-fluid">\n        <div class="span4">\n          {{item.humanReadableName}}\n        </div>\n        <div class="span6">\n          <!-- TODO show the name instead that id -->\n          {{item.defaultOriginServer}}\n        </div>\n        <div class="span2">\n          <a ng-click="vm.removePrefix(item)" class="btn btn-danger pull-right">\n            <i class="icon icon-remove"></i>\n          </a>\n        </div>\n      </div>\n    </div>\n    <hr>\n    <form ng-submit="vm.addPrefix(vm.new_prf)">\n      <div class="row-fluid">\n        <div class="span4">\n          <label>Prefix</label>\n          <input type="text" ng-model="vm.new_prf.prefix" required style="max-width: 90%">\n        </div>\n        <div class="span6">\n          <label>Default Origin Server</label>\n          <select ng-model="vm.new_prf.defaultOriginServer" style="max-width: 100%">\n            <option ng-repeat="prf in vm.prf" ng-value="prf.id">{$ prf.humanReadableName $}</option>\n          </select>\n        </div>\n        <div class="span2 text-right">\n          <button class="btn btn-success margin-wells">\n            <i class="icon icon-plus"></i>\n          </button>\n        </div>\n      </div>\n    </form>\n    <div class="alert" ng-show="vm.result" ng-class="{\'alert-success\': vm.result.status === 1,\'alert-error\': vm.result.status === 0}">\n      {$ vm.result.msg $}\n    </div>\n  </div>\n</div>'),n.put("templates/cp_detail.html",'<div class="row">\n  <div class="col-xs-6">\n    <h1>{$ vm.cp.humanReadableName $}</h1>\n  </div>\n  <div class="col-xs-6 text-right">\n    <cp-actions id="vm.cp.id"></cp-actions>\n  </div>\n</div>\n<hr>\n<div class="row">\n  <div ng-show="vm.cp.id" class="col-xs-2">\n    <div ng-include="\'templates/cp_side_nav.html\'"></div>\n  </div>\n  <div ng-class="{\'col-xs-10\': vm.cp.id, \'col-xs-12\': !vm.cp.id}">\n  <!-- TODO hide form on not found -->\n    <form ng-submit="vm.saveContentProvider(vm.cp)">\n      <fieldset>\n        <div class="row">\n          <div class="col-xs-6">\n            <label>Name:</label>\n            <input class="form-control" type="text" ng-model="vm.cp.humanReadableName" required/>\n          </div>\n          <div class="col-xs-6">\n            <label class="checkbox">\n              <input class="form-control" type="checkbox" ng-model="vm.cp.enabled" /> Enabled\n            </label>\n          </div>\n        </div>\n        <div class="row">\n          <div class="col-xs-12">\n            <label>Description</label>\n            <textarea class="form-control" ng-model="vm.cp.description"></textarea>\n          </div>\n        </div>\n        <div class="row">\n          <div class="col-xs-12">\n            <label>Service provider</label>\n            <select class="form-control" required ng-model="vm.cp.serviceProvider" ng-options="sp.id as sp.humanReadableName for sp in vm.sp"></select>\n          </div>\n        </div>\n        <div class="row">\n          <div class="col-xs-12">\n            <button class="btn btn-success">\n              <span ng-show="vm.cp.id">Save</span>\n              <span ng-show="!vm.cp.id">Create</span>\n            </button>\n          </div>\n        </div>\n      </fieldset>\n    </form>\n    <div class="alert" ng-show="vm.result" ng-class="{\'alert-success\': vm.result.status === 1,\'alert-danger\': vm.result.status === 0}">\n      {$ vm.result.msg $}\n    </div>\n  </div>\n</div>'),n.put("templates/cp_list.html",'<!-- <xos-table data="vm.contentProviderList" config="vm.config"/> -->\n\n<table class="table table-striped" ng-show="vm.contentProviderList.length > 0">\n  <thead>\n    <tr>\n      <th>\n        Name\n      </th>\n      <th>Description</th>\n      <th>Status</th>\n      <th></th>\n    </tr>\n  </thead>\n  <tr ng-repeat="item in vm.contentProviderList">\n    <td>\n      <a ui-sref="details({ id: item.id })">{$ item.humanReadableName $}</a>\n    </td>\n    <td>\n      {$ item.description $}\n    </td>\n    <td>\n      {$ item.enabled $}\n    </td>\n    <td class="text-right">\n      <a ng-click="vm.deleteCp(item.id)" class="btn btn-danger"><i class="glyphicon glyphicon-remove"></i></a></td>\n  </tr>\n</table>\n<div class="alert alert-error" ng-show="vm.contentProviderList.length == 0">\n  No Content Provider defined\n</div>\n\n<div class="row">\n  <div class="span12 text-right">\n    <a class="btn btn-success"href="#/contentProvider/">Create</a>\n  </div>\n</div>'),n.put("templates/cp_origin_server.html",'<div class="row-fluid">\n  <div class="span6">\n    <h1>{$ vm.cp.humanReadableName $}</h1>\n  </div>\n  <div class="span6 text-right">\n    <cp-actions id="vm.cp.id"></cp-actions>\n  </div>\n</div>\n<hr>\n<div class="row-fluid">\n  <div class="span2">\n    <div ng-include="\'templates/cp_side_nav.html\'"></div>\n  </div>\n  <div class="span10">\n    <div ng-repeat="item in vm.cp_os" class="well">\n      <div class="row-fluid">\n        <div class="span4">\n          {{item.humanReadableName}}\n        </div>\n        <div class="span6">\n          <!-- TODO shoe the name instead that url -->\n          {{item.defaultOriginServer}}\n        </div>\n        <div class="span2">\n          <a ng-click="vm.removeOrigin(item)" class="btn btn-danger pull-right">\n            <i class="icon icon-remove"></i>\n          </a>\n        </div>\n      </div>\n    </div>\n    <hr>\n    <form ng-submit="vm.addOrigin(vm.new_os)">\n      <div class="row-fluid">\n        <div class="span4">\n          <label>Protocol</label>\n          <select ng-model="vm.new_os.protocol" ng-options="k as v for (k,v) in vm.protocols" style="max-width: 100%;"></select>\n        </div>\n        <div class="span6">\n          <label>Url</label>\n          <input type="text" ng-model="vm.new_os.url" required>\n        </div>\n        <div class="span2 text-right">\n          <button class="btn btn-success margin-wells">\n            <i class="icon icon-plus"></i>\n          </button>\n        </div>\n      </div>\n    </form>\n    <div class="alert" ng-show="vm.result" ng-class="{\'alert-success\': vm.result.status === 1,\'alert-error\': vm.result.status === 0}">\n      {$ vm.result.msg $}\n    </div>\n  </div>\n</div>'),n.put("templates/cp_side_nav.html",'<ul class="nav nav-list">\n  <li>\n    <a class="btn" ng-class="{\'btn-primary\': vm.pageName == \'detail\'}" href="#/contentProvider/{$ vm.cp.id $}">Details</a>\n  </li>\n  <li>\n    <a class="btn" ng-class="{\'btn-primary\': vm.pageName == \'cdn\'}" href="#/contentProvider/{$ vm.cp.id $}/cdn_prefix">Cdn Prexix</a>\n  </li>\n  <li>\n    <a class="btn" ng-class="{\'btn-primary\': vm.pageName == \'server\'}" href="#/contentProvider/{$ vm.cp.id $}/origin_server">Origin Server</a>\n  </li>\n  <li>\n    <a class="btn" ng-class="{\'btn-primary\': vm.pageName == \'user\'}" href="#/contentProvider/{$ vm.cp.id $}/users">Users</a>\n  </li>\n</ul>'),n.put("templates/cp_user.html",'<div class="row-fluid">\n  <div class="span6">\n    <h1>{$ vm.cp.humanReadableName $}</h1>\n  </div>\n  <div class="span6 text-right">\n    <cp-actions id="vm.cp.id"></cp-actions>\n  </div>\n</div>\n<hr>\n<div class="row-fluid">\n  <div class="span2">\n    <div ng-include="\'templates/cp_side_nav.html\'"></div>\n  </div>\n  <div class="span10">\n    <div ng-repeat="item in vm.cp.users" class="well">\n      <div class="row-fluid">\n        <div class="span3">\n          {{item.firstname}}\n        </div>\n        <div class="span3">\n          {{item.lastname}}\n        </div>\n        <div class="span4">\n          {{item.email}}\n        </div>\n        <div class="span2">\n          <a ng-click="vm.removeUserFromCp(item)" class="btn btn-danger pull-right">\n            <i class="icon icon-remove"></i>\n          </a>\n        </div>\n      </div>\n    </div>\n    <hr>\n    <form ng-submit="vm.saveContentProvider(vm.cp)">\n      <div class="row-fluid">\n        <div class="span8">\n          <label>Select user:</label>\n          <select ng-model="vm.user" ng-options="u as u.username for u in vm.users" ng-change="vm.addUserToCp(vm.user)"></select>\n        </div>  \n        <div class="span4 text-right">\n          <button class="btn btn-success margin-wells">\n            Save\n          </button>\n        </div>\n      </div>\n    </form>\n    <div class="alert" ng-show="vm.result" ng-class="{\'alert-success\': vm.result.status === 1,\'alert-error\': vm.result.status === 0}">\n      {$ vm.result.msg $}\n    </div>\n  </div>\n</div>')}]),angular.module("xos.contentProvider").run(["$location",function(n){n.path("/")}]);
\ No newline at end of file
diff --git a/xos/core/xoslib/static/js/xosCord.js b/xos/core/xoslib/static/js/xosCord.js
new file mode 100644
index 0000000..c9be375
--- /dev/null
+++ b/xos/core/xoslib/static/js/xosCord.js
@@ -0,0 +1,197 @@
+/* eslint-disable */

+OBJS = ['cordSubscriber', 'cordUser'];

+

+CordAdminApp = new XOSApplication({

+    logTableId: "#logTable",

+    statusMsgId: "#statusMsg",

+    hideTabsByDefault: true

+});

+

+CordAdminApp.addRegions({

+    navigation: "#navigationPanel",

+

+    detail: "#detail",

+    linkedObjs1: "#linkedObjs1",

+    linkedObjs2: "#linkedObjs2",

+    linkedObjs3: "#linkedObjs3",

+    linkedObjs4: "#linkedObjs4",

+

+    addChildDetail: "#xos-addchild-detail",

+

+    rightButtonPanel: "#rightButtonPanel"

+});

+

+CordAdminApp.navigate = function(what, modelName, modelId) {

+    collection_name = modelName + "s";

+    if (what=="list") {

+        CordAdminApp.Router.navigate(collection_name, {trigger: true})

+    } else if (what=="detail") {

+        CordAdminApp.Router.navigate(collection_name + "/" + modelId, {trigger: true})

+    } else if (what=="add") {

+        CordAdminApp.Router.navigate("add" + firstCharUpper(modelName), {trigger: true, force: true})

+    }

+}

+

+CordAdminApp.buildViews = function() {

+     genericAddChildClass = XOSDetailView.extend({template: "#xos-add-template",

+                                                        app: CordAdminApp});

+     CordAdminApp["genericAddChildView"] = genericAddChildClass;

+

+     genericDetailClass = XOSDetailView.extend({template: "#xos-detail-template",

+                                                           app: CordAdminApp});

+     CordAdminApp["genericDetailView"] = genericDetailClass;

+

+     genericItemViewClass = XOSItemView.extend({template: "#xos-listitem-template",

+                                                app: CordAdminApp});

+     CordAdminApp["genericItemView"] = genericItemViewClass;

+

+     //genericListViewClass = XOSListView.extend({template: "#xos-list-template",

+     //                                           app: CordAdminApp});

+

+     genericListViewClass = XOSDataTableView.extend({template: "#xos-list-template", app: CordAdminApp});

+     CordAdminApp["genericListView"] = genericListViewClass;

+

+     for (var index in OBJS) {

+         name = OBJS[index];

+         tr_template = '#xosAdmin-' + name + '-listitem-template';

+         table_template = '#xosAdmin-' + name + '-list-template';

+         detail_template = '#xosAdmin-' + name + '-detail-template';

+         add_child_template = '#xosAdmin-' + name + '-add-child-template';

+         collection_name = name + "s";

+         region_name = name + "List";

+         templates = {cordSubscriber: "#xos-cord-subscriber-template"};

+

+         if (window["XOSDetailView_" + name]) {

+             detailClass = window["XOSDetailView_" + name].extend( {template: templates[name] || "#xos-detail-template",

+                                                                    app: CordAdminApp});

+         } else {

+             detailClass = genericDetailClass.extend( {template: templates[name] || "#xos-detail-template", });

+         }

+         if ($(detail_template).length) {

+             detailClass = detailClass.extend({

+                template: detail_template,

+             });

+         }

+         CordAdminApp[collection_name + "DetailView"] = detailClass;

+

+         if (window["XOSDetailView_" + name]) {

+             addClass = window["XOSDetailView_" + name].extend({template: "#xos-add-template",

+                                                                    app: CordAdminApp});

+         } else {

+             addClass = genericAddChildClass;

+         }

+         if ($(add_child_template).length) {

+             addClass = detailClass.extend({

+                template: add_child_template,

+             });

+         }

+         CordAdminApp[collection_name + "AddChildView"] = addClass;

+

+         if ($(tr_template).length) {

+             itemViewClass = XOSItemView.extend({

+                 template: tr_template,

+                 app: CordAdminApp,

+             });

+         } else {

+             itemViewClass = genericItemViewClass;

+         }

+

+         if ($(table_template).length) {

+             listViewClass = XOSListView.extend({

+                 childView: itemViewClass,

+                 template: table_template,

+                 collection: xos[collection_name],

+                 title: name + "s",

+                 app: CordAdminApp,

+             });

+         } else {

+             listViewClass = genericListViewClass.extend( { childView: itemViewClass,

+                                                            collection: xos[collection_name],

+                                                            title: name + "s",

+                                                           } );

+         }

+

+         CordAdminApp[collection_name + "ListView"] = listViewClass;

+

+         xos[collection_name].fetch(); //startPolling();

+     }

+};

+

+CordAdminApp.initRouter = function() {

+    router = XOSRouter;

+    var api = {};

+    var routes = {};

+

+    for (var index in OBJS) {

+        name = OBJS[index];

+        collection_name = name + "s";

+        nav_url = collection_name;

+        api_command = "list" + firstCharUpper(collection_name);

+        listViewName = collection_name + "ListView";

+        detailViewName = collection_name + "DetailView";

+        addChildViewName = collection_name + "AddChildView";

+

+        api[api_command] = CordAdminApp.createListHandler(listViewName, collection_name, "detail", collection_name);

+        routes[nav_url] = api_command;

+

+        nav_url = collection_name + "/:id";

+        api_command = "detail" + firstCharUpper(collection_name);

+

+        api[api_command] = CordAdminApp.createDetailHandler(detailViewName, collection_name, "detail", name);

+        routes[nav_url] = api_command;

+

+        nav_url = "add" + firstCharUpper(name);

+        api_command = "add" + firstCharUpper(name);

+        api[api_command] = CordAdminApp.createAddHandler(detailViewName, collection_name, "detail", name);

+        routes[nav_url] = api_command;

+

+        nav_url = "addChild" + firstCharUpper(name) + "/:parentModel/:parentField/:parentId";

+        api_command = "addChild" + firstCharUpper(name);

+        api[api_command] = CordAdminApp.createAddChildHandler(addChildViewName, collection_name);

+        routes[nav_url] = api_command;

+

+        nav_url = "delete" + firstCharUpper(name) + "/:id";

+        api_command = "delete" + firstCharUpper(name);

+        api[api_command] = CordAdminApp.createDeleteHandler(collection_name, name);

+        routes[nav_url] = api_command;

+    };

+

+    routes["*part"] = "listCordSubscribers";

+

+    CordAdminApp.Router = new router({ appRoutes: routes, controller: api });

+};

+

+CordAdminApp.startNavigation = function() {

+    Backbone.history.start();

+    CordAdminApp.navigationStarted = true;

+}

+

+CordAdminApp.collectionLoadChange = function() {

+    stats = xos.getCollectionStatus();

+

+    if (!CordAdminApp.navigationStarted) {

+        if (stats["isLoaded"] + stats["failedLoad"] >= stats["startedLoad"]) {

+            CordAdminApp.startNavigation();

+        } else {

+            $("#detail").html("<h3>Loading...</h3><div id='xos-startup-progress'></div>");

+            $("#xos-startup-progress").progressbar({value: stats["completedLoad"], max: stats["startedLoad"]});

+        }

+    }

+};

+

+CordAdminApp.on("start", function() {

+     CordAdminApp.buildViews();

+

+     CordAdminApp.initRouter();

+

+     // fire it once to initially show the progress bar

+     CordAdminApp.collectionLoadChange();

+

+     // fire it each time the collection load status is updated

+     Backbone.on("xoslib:collectionLoadChange", CordAdminApp.collectionLoadChange);

+});

+

+$(document).ready(function(){

+    CordAdminApp.start();

+});

+/* eslint-enable */

diff --git a/xos/core/xoslib/static/js/xosDeveloper.js b/xos/core/xoslib/static/js/xosDeveloper.js
new file mode 100644
index 0000000..8585eac
--- /dev/null
+++ b/xos/core/xoslib/static/js/xosDeveloper.js
@@ -0,0 +1 @@
+"use strict";angular.module("xos.developer",["ngResource","ngCookies","ui.router","xos.helpers"]).config(["$stateProvider",function(e){e.state("developer",{url:"/",template:"<developer-dashboard></developer-dashboard>"})}]).config(["$httpProvider",function(e){e.interceptors.push("NoHyperlinks")}]).directive("developerDashboard",function(){return{restrict:"E",scope:{},bindToController:!0,controllerAs:"vm",templateUrl:"templates/developer-dashboard.tpl.html",controller:["$scope","$timeout","SlicesPlus","Instances","_",function(e,t,n,s,i){var r=this;this.instancePerSliceConfig={data:[],groupBy:"slice",legend:!0,classes:"instance per slice",labelFormatter:function(e){return e.map(function(e){return i.find(r.slices,{id:parseInt(e)}).name})}},this.instancePerSiteConfig={data:[],groupBy:"site",legend:!0,classes:"instance per site"},this.networkPerSliceConfig={data:[],groupBy:"name",legend:!0,classes:"network per slice"},this.tableConfig={columns:[{label:"Name",prop:"name"},{label:"Privileges",prop:"current_user_roles",type:"array"},{label:"Number of Instances (active / total)",type:"custom",formatter:function(e){return e.instance_total_ready+" / "+e.instance_total}},{label:"Active Instances per Sites",type:"object",prop:"instance_distribution_ready"},{label:"Total Instances per Sites",type:"object",prop:"instance_distribution"},{label:"Networks",type:"custom",formatter:function(e){return e.networks.length}}]},n.query().$promise.then(function(e){return r.slices=e,s.query().$promise}).then(function(e){var t=i.reduce(r.slices,function(e,t){if(t.networks.length>1)for(var n=0;n<t.networks.length;n++)e.push({id:t.id,name:t.name,network:t.networks[n]});else 1===t.networks.length&&e.push({id:t.id,name:t.name,network:t.networks[0]});return e},[]),n=i.reduce(r.slices,function(e,t){return i.forEach(Object.keys(t.instance_distribution),function(n){for(var s=0;s<t.instance_distribution[n];s++)e.push({site:n,instance:s})}),e},[]);r.sites=Object.keys(i.groupBy(n,"site")),r.instancePerSliceConfig.data=e,r.instancePerSiteConfig.data=n,r.networkPerSliceConfig.data=t})["catch"](function(e){throw new Error(e)})}]}}),angular.module("xos.developer").run(["$templateCache",function(e){e.put("templates/developer-dashboard.tpl.html",'<div class="row">\n  <div ng-class="{\'col-sm-4\': vm.sites.length > 1 || !vm.sites, \'col-sm-6\': vm.sites.length <= 1}" class="text-center">\n    <h3>Instances per Slice</h3>\n    <xos-smart-pie ng-if="vm.instancePerSliceConfig.data.length > 0" config="vm.instancePerSliceConfig"></xos-smart-pie>\n  </div>\n  <div ng-if="vm.sites.length > 1" class="col-sm-4 text-center">\n    <h3>Instances per Site</h3>\n    <xos-smart-pie ng-if="vm.instancePerSiteConfig.data.length > 0" config="vm.instancePerSiteConfig"></xos-smart-pie>\n  </div>\n  <div ng-class="{\'col-sm-4\': vm.sites.length > 1 || !vm.sites, \'col-sm-6\': vm.sites.length <= 1}" class="text-center">\n    <h3>Network per Slice</h3>\n    <xos-smart-pie ng-if="vm.networkPerSliceConfig.data.length > 0" config="vm.networkPerSliceConfig"></xos-smart-pie>\n  </div>\n</div>\n\n<xos-table config="vm.tableConfig" data="vm.slices"></xos-table>')}]),angular.module("xos.developer").run(["$location",function(e){e.path("/")}]);
\ No newline at end of file
diff --git a/xos/core/xoslib/static/js/xosDiagnostic.js b/xos/core/xoslib/static/js/xosDiagnostic.js
new file mode 100644
index 0000000..6492672
--- /dev/null
+++ b/xos/core/xoslib/static/js/xosDiagnostic.js
@@ -0,0 +1,2 @@
+"use strict";!function(){angular.module("xos.diagnostic",["ngResource","ngCookies","ngAnimate","ui.router","xos.helpers"]).config(["$stateProvider",function(e){e.state("home",{url:"/",template:"<diagnostic-container></diagnostic-container>"})}]).config(["$httpProvider",function(e){e.interceptors.push("NoHyperlinks")}]).run(["$log",function(e){e.info("Diagnostic Started")}])}(),angular.module("xos.diagnostic").run(["$templateCache",function(e){e.put("templates/diagnostic.tpl.html",'<div class="container-fluid">\n  <div ng-hide="vm.error && vm.loader" style="height: 900px">\n    <div class="onethird-height">\n      <div class="well">\n        Services Graph\n      </div>\n      <div class="well pull-right" ng-click="vm.reloadGlobalScope()" ng-show="vm.selectedSubscriber">\n        Reset subscriber\n      </div>\n      <service-topology service-chain="vm.serviceChain"></service-topology>\n    </div>\n    <div class="twothird-height">\n      <div class="well">\n        Logical Resources\n      </div>\n      <logic-topology ng-if="vm.subscribers" subscribers="vm.subscribers" selected="vm.selectedSubscriber"></logic-topology>\n    </div>\n  </div>\n  <div class="row" ng-if="vm.error">\n    <div class="col-xs-12">\n      <div class="alert alert-danger">\n        {{vm.error}}\n      </div>\n    </div>\n  </div>\n  <div class="row" ng-if="vm.loader">\n    <div class="col-xs-12">\n      <div class="loader">Loading</div>\n    </div>\n  </div>\n</div>'),e.put("templates/logicTopology.tpl.html",'<select-subscriber-modal open="vm.openSelectSubscriberModal" subscribers="vm.subscribers"></select-subscriber-modal>\n<subscriber-status-modal open="vm.openSubscriberStatusModal" subscriber="vm.currentSubscriber"></subscriber-status-modal>\n<div class="alert alert-danger animate" ng-hide="!vm.error">\n  {{vm.error}}\n</div>\n<!-- <div class="instances-stats animate" ng-hide="vm.hideInstanceStats">\n  <div class="row">\n    <div class="col-sm-3 col-sm-offset-8">\n      <div class="panel panel-primary" ng-repeat="instance in vm.selectedInstances">\n        <div class="panel-heading">\n          {{instance.humanReadableName}}\n        </div>\n          <ul class="list-group">\n            <li class="list-group-item">Backend Status: {{instance.backend_status}}</li>\n            <li class="list-group-item">IP Address: {{instance.ip}}</li>\n          </ul>\n          <ul class="list-group">\n            <li class="list-group-item" ng-repeat="stat in instance.stats">\n              <span class="badge">{{stat.value}}</span>\n              {{stat.meter}}\n            </li>\n          </ul>\n        </div>\n      </div>  \n    </div>\n  </div>\n</div> -->'),e.put("templates/select-subscriber-modal.tpl.html",'<div class="modal fade" ng-class="{in: vm.open}" tabindex="-1" role="dialog">\n  <div class="modal-dialog modal-sm">\n    <div class="modal-content">\n      <div class="modal-header">\n        <button ng-click="vm.close()"  type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>\n        <h4 class="modal-title">Select a subscriber:</h4>\n      </div>\n      <div class="modal-body">\n        <select class="form-control" ng-options="s as s.humanReadableName for s in vm.subscribers" ng-model="vm.selected"></select>\n      </div>\n      <div class="modal-footer">\n        <button ng-click="vm.close()" type="button" class="btn btn-default" data-dismiss="modal">Close</button>\n        <button ng-click="vm.select(vm.selected)" type="button" class="btn btn-primary">Select</button>\n      </div>\n    </div><!-- /.modal-content -->\n  </div><!-- /.modal-dialog -->\n</div><!-- /.modal -->'),e.put("templates/subscriber-status-modal.tpl.html",'<div class="modal fade" ng-class="{in: vm.open}" tabindex="-1" role="dialog">\n  <div class="modal-dialog modal-sm">\n    <div class="modal-content">\n      <div class="modal-header">\n        <button ng-click="vm.close()"  type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>\n        <h4 class="modal-title">Manage subscriber:</h4>\n      </div>\n      <form name="vm.subscriber-detail">\n        <div class="modal-body">\n          <div class="row">\n            <div class="col-xs-12">\n              <label>Status</label>\n            </div>\n            <div class="col-xs-6">\n              <a ng-click="vm.subscriber.status = \'enabled\'"\n                class="btn btn-block"\n                ng-class="{\'btn-primary\': vm.subscriber.status === \'enabled\' ,\'btn-default\': vm.subscriber.status !== \'enabled\'}"\n                >Enabled</a>\n            </div>\n            <div class="col-xs-6">\n              <a ng-click="vm.subscriber.status = \'suspended\'"\n                class="btn btn-block"\n                ng-class="{\'btn-primary\': vm.subscriber.status === \'suspended\' ,\'btn-default\': vm.subscriber.status !== \'suspended\'}"\n                >Suspended</a>\n            </div>\n          </div>\n          <div class="row">\n            <div class="col-xs-6">\n              <a ng-click="vm.subscriber.status = \'delinquent\'"\n                class="btn btn-block"\n                ng-class="{\'btn-primary\': vm.subscriber.status === \'delinquent\' ,\'btn-default\': vm.subscriber.status !== \'delinquent\'}"\n                >Delinquent <br> payment</a>\n            </div>\n            <div class="col-xs-6">\n              <a ng-click="vm.subscriber.status = \'copyrightviolation\'"\n                class="btn btn-block"\n                ng-class="{\'btn-primary\': vm.subscriber.status === \'copyrightviolation\' ,\'btn-default\': vm.subscriber.status !== \'copyrightviolation\'}"\n                >Copyright <br> violation</a>\n            </div>\n          </div>\n          <div class="row">\n            <div class="col-xs-6">\n              <label>Uplink Speed</label>\n              <div class="input-group">\n                <input type="number" class="form-control small-padding" ng-model="vm.subscriber.uplink_speed"/>\n                <span class="input-group-addon">Mbps</span>\n              </div>\n            </div>\n            <div class="col-xs-6">\n              <label>Downlink Speed</label>\n              <div class="input-group">\n                <input type="number" class="form-control small-padding" ng-model="vm.subscriber.downlink_speed"/>\n                <span class="input-group-addon">Mbps</span>\n              </div>\n            </div>\n          </div>\n          <div class="row">\n            <div class="col-xs-6">\n              <label>Enable Internet</label>\n            </div>\n            <div class="col-xs-6">\n              <a \n                ng-click="vm.subscriber.enable_uverse = !vm.subscriber.enable_uverse" \n                ng-class="{\'btn-success\': vm.subscriber.enable_uverse, \'btn-danger\': !vm.subscriber.enable_uverse}"\n                class="btn btn-block">\n                <span ng-show="vm.subscriber.enable_uverse === true">Enabled</span>\n                <span ng-show="vm.subscriber.enable_uverse !== true">Disabled</span>\n              </a>\n            </div>\n          </div>\n        </div>\n        <div class="modal-footer" ng-show="vm.success || vm.formError">\n          <div class="alert alert-success" ng-show="vm.success">\n            {{vm.success}}\n          </div>\n          <div class="alert alert-danger" ng-show="vm.formError">\n            {{vm.formError}}\n          </div>\n        </div>\n        <div class="modal-footer">\n          <button ng-click="vm.close()" type="button" class="btn btn-default" data-dismiss="modal">Close</button>\n          <button ng-click="vm.updateSubscriber(vm.subscriber)" type="button" class="btn btn-primary">Save</button>\n        </div>\n      </form>\n    </div><!-- /.modal-content -->\n  </div><!-- /.modal-dialog -->\n</div><!-- /.modal -->')}]),function(){angular.module("xos.diagnostic").directive("selectSubscriberModal",function(){return{scope:{subscribers:"=",open:"="},bindToController:!0,restrict:"E",templateUrl:"templates/select-subscriber-modal.tpl.html",controllerAs:"vm",controller:["$rootScope",function(e){var t=this;this.close=function(){t.open=!1},this.select=function(n){e.$emit("subscriber.selected",n),t.close()}}]}}).directive("subscriberStatusModal",function(){return{scope:{open:"=",subscriber:"="},bindToController:!0,restrict:"E",templateUrl:"templates/subscriber-status-modal.tpl.html",controllerAs:"vm",controller:["$log","$timeout","$scope","Subscribers",function(e,t,n,r){var i=this,a=1e6;n.$watch(function(){return i.open},function(){i.success=null,i.formError=null}),n.$watch(function(){return i.subscriber},function(e,t){i.subscriber&&(console.log(e,t),console.log("subscriber change",e===t),i.subscriber.uplink_speed=parseInt(i.subscriber.uplink_speed,10)/a,i.subscriber.downlink_speed=parseInt(i.subscriber.downlink_speed,10)/a)}),this.close=function(){i.open=!1},this.updateSubscriber=function(e){var n=angular.copy(e,n);n.uplink_speed=n.uplink_speed*a,n.downlink_speed=n.downlink_speed*a,r.update(n).$promise.then(function(e){i.success="Subscriber successfully updated!"})["catch"](function(e){i.formError=e})["finally"](function(){t(function(){i.close()},1500)})}}]}})}(),function(){angular.module("xos.diagnostic").service("ServiceTopologyHelper",["$rootScope","$window","$log","_","ServiceRelation","serviceTopologyConfig","d3",function(e,t,n,r,i,a,s){var c,o,u,l,d=0,p=function(t,n,r){var p=arguments.length<=3||void 0===arguments[3]?l:arguments[3];p&&(l=p);var h=l.clientWidth-2*a.widthMargin;c=t,o=n,u=r;var m=i.depthOf(r),b=s.svg.diagonal().projection(function(e){return[e.y,e.x]}),g=n.nodes(r).reverse(),f=n.links(g);g.forEach(function(e){var t=(h-2*a.widthMargin)/(m-1);e.y=e.depth*t});var y=t.selectAll("g.node").data(g,function(e){return e.id||(e.id=++d)}),x=y.enter().append("g").attr({"class":function(e){return"node "+e.type},transform:function(e){return e.x&&e.y?"translate("+e.y+", "+e.x+")":"translate("+r.y0+", "+r.x0+")"}}),S=x.filter(".subscriber"),w=x.filter(".router"),T=x.filter(".service");S.append("rect").attr(a.square).on("click",function(){e.$emit("subscriber.modal.open")}),w.append("rect").attr(a.square),T.append("circle").attr("r",1e-6).style("fill",function(e){return e._children?"lightsteelblue":"#fff"}).on("click",v),x.append("text").attr({x:function(e){return e.children?-a.circle.selectedRadius-5:a.circle.selectedRadius+5},dy:".35em",y:function(e){return e.children&&e.parent?"-5":void 0},transform:function(e){return e.children&&e.parent?e.parent.x<e.x?"rotate(-30)":"rotate(30)":void 0},"text-anchor":function(e){return e.children?"end":"start"}}).text(function(e){return e.name}).style("fill-opacity",1e-6);var _=y.transition().duration(a.duration).attr({transform:function(e){return"translate("+e.y+","+e.x+")"}});_.select("circle").attr("r",function(e){return e.selected?a.circle.selectedRadius:a.circle.radius}).style("fill",function(e){return e.selected?"lightsteelblue":"#fff"}),_.select("text").style("fill-opacity",1);var C=y.exit().transition().duration(a.duration).remove();C.select("circle").attr("r",1e-6),C.select("text").style("fill-opacity",1e-6);var k=t.selectAll("path.link").data(f,function(e){return e.target.id});k.enter().insert("path","g").attr("class",function(e){return"link "+e.target.type+" "+(e.target.active?"":"active")}).attr("d",function(e){var t={x:r.x0,y:r.y0};return b({source:t,target:t})}),k.transition().duration(a.duration).attr("d",b),k.exit().transition().duration(a.duration).attr("d",function(e){var t={x:r.x,y:r.y};return b({source:t,target:t})}).remove(),g.forEach(function(e){e.x0=e.x,e.y0=e.y})},v=function(t){return t.selected?(t.selected=!t.selected,e.$emit("instance.detail.hide",{}),p(c,o,u)):(e.$emit("instance.detail",{name:t.name,service:t.service,tenant:t.tenant}),c.selectAll("circle").each(function(e){return e.selected=!1}),t.selected=!t.selected,void p(c,o,u))};this.updateTree=p}])}(),function(){angular.module("xos.diagnostic").directive("serviceTopology",function(){return{restrict:"E",scope:{serviceChain:"="},bindToController:!0,controllerAs:"vm",template:"",controller:["$element","$window","$scope","d3","serviceTopologyConfig","ServiceRelation","Slice","Instances","Subscribers","ServiceTopologyHelper",function(e,t,n,r,i,a,s,c,o,u){var l=this,d=e[0];r.select(window).on("resize.service",function(){h(l.serviceChain)});var p,v,h=function(t){if(!t)return void console.error("Tree is missing");r.select(e[0]).select("svg").remove();var n=d.clientWidth-2*i.widthMargin,a=d.clientHeight-2*i.heightMargin,s=r.layout.tree().size([a,n]);v=r.select(e[0]).append("svg").style("width",d.clientWidth+"px").style("height",d.clientHeight+"px");var c=v.append("g").attr("transform","translate("+2*i.widthMargin+","+i.heightMargin+")");p=t,p.x0=a/2,p.y0=n/2,u.updateTree(c,s,p,d)};n.$watch(function(){return l.serviceChain},function(e){angular.isDefined(e)&&h(e)})}]}})}(),function(){angular.module("xos.diagnostic").service("Services",["$resource",function(e){return e("/xos/services/:id",{id:"@id"})}]).service("Tenant",["$resource",function(e){return e("/xos/tenants",{id:"@id"},{queryVsgInstances:{method:"GET",isArray:!0,interceptor:{response:function(e){var t=[];return angular.forEach(e.data,function(e){var n=JSON.parse(e.service_specific_attribute);n&&n.instance_id&&t.push(n.instance_id)}),t}}},getSubscriberTag:{method:"GET",isArray:!0,interceptor:{response:function(e){return JSON.parse(e.data[0].service_specific_attribute)}}}})}]).service("Ceilometer",["$http","$q","Instances",function(e,t,n){var r=this;this.getInstanceStats=function(n){var r=t.defer();return e.get("/xoslib/xos-instance-statistics",{params:{"instance-uuid":n}}).then(function(e){r.resolve(e.data)})["catch"](function(e){r.reject(e)}),r.promise},this.getInstancesStats=function(e){var i=t.defer(),a=[],s=[];return e.forEach(function(e){a.push(n.get({id:e}).$promise)}),t.all(a).then(function(e){s=e;var n=[];return s.forEach(function(e){n.push(r.getInstanceStats(e.instance_uuid))}),t.all(n)}).then(function(e){s.map(function(t,n){t.stats=e[n]}),i.resolve(s)})["catch"](i.reject),i.promise},this.getContainerStats=function(n){var r=t.defer(),i={};return e.get("/xoslib/meterstatistics",{params:{resource:n}}).then(function(t){return i.stats=t.data,e.get("/xoslib/meterstatistics",{params:{resource:n+"-eth0"}})}).then(function(t){return i.port={eth0:t.data},e.get("/xoslib/meterstatistics",{params:{resource:n+"-eth1"}})}).then(function(e){i.port.eth1=e.data,r.resolve(i)})["catch"](function(e){r.reject(e)}),r.promise}}]).service("Slice",["$resource",function(e){return e("/xos/slices",{id:"@id"})}]).service("Instances",["$resource",function(e){return e("/xos/instances/:id",{id:"@id"})}]).service("Node",["$resource","$q","Instances",function(e,t,n){return e("/xos/nodes",{id:"@id"},{queryWithInstances:{method:"GET",isArray:!0,interceptor:{response:function(e){var r=t.defer(),i=[];return angular.forEach(e.data,function(e){i.push(n.query({node:e.id}).$promise)}),t.all(i).then(function(t){e.data.map(function(e,n){return e.instances=t[n],e}),r.resolve(e.data)}),r.promise}}}})}]).service("Subscribers",["$resource","$q","SubscriberDevice",function(e,t,n){return e("/xoslib/cordsubscriber/:id",{id:"@id"},{update:{method:"PUT",isArray:!1},queryWithDevices:{method:"GET",isArray:!0,interceptor:{response:function(e){var r=t.defer(),i=[];return angular.forEach(e.data,function(e){i.push(n.query({id:e.id}).$promise)}),t.all(i).then(function(t){e.data.map(function(e,n){return e.devices=t[n],e.type="subscriber",e.devices.map(function(e){return e.type="device"}),e}),r.resolve(e.data)}),r.promise}}},getWithDevices:{method:"GET",isArray:!1,interceptor:{response:function(e){var r=t.defer();return n.query({id:e.data.id}).$promise.then(function(t){t.map(function(e){return e.type="device"}),e.data.devices=t,e.data.type="subscriber",r.resolve(e.data)})["catch"](function(e){r.reject(e)}),r.promise}}}})}]).service("SubscriberDevice",["$resource",function(e){return e("/xoslib/rs/subscriber/:id/users/",{id:"@id"})}]).service("ServiceRelation",["$q","_","Services","Tenant","Slice","Instances",function(e,t,n,r,i,a){var s=function m(e){var t=0;return e.children&&e.children.forEach(function(e){var n=m(e);n>t&&(t=n)}),1+t},c=function(e,n){return t.filter(e,function(e){return e.subscriber_service===n})},o=function(e,n){var r,e=t.filter(e,function(e){return e.provider_service===n&&e.subscriber_tenant});return e.forEach(function(e){e.service_specific_attribute&&(r=JSON.parse(e.service_specific_attribute))}),r},u=function(e,n){var r=[];return t.forEach(e,function(e){var i=t.find(n,{id:e.provider_service});r.push(i)}),r},l=function b(e,n,r,i){var a=arguments.length<=4||void 0===arguments[4]?null:arguments[4],s=t.difference(n,[r]),l=c(e,r.id),d=u(l,n);s=t.difference(s,d),r.service_specific_attribute=o(e,r.id),"service_vbng"===r.humanReadableName&&(r.humanReadableName="service_vrouter");var p={name:r.humanReadableName,parent:a,type:"service",service:r,tenant:i,children:[]};return t.forEach(d,function(n){if("service_ONOS_vBNG"!==n.humanReadableName&&"service_ONOS_vOLT"!==n.humanReadableName){var a=t.find(e,{subscriber_tenant:i.id,provider_service:n.id});p.children.push(b(e,s,n,a,r.humanReadableName))}}),0===p.children.length&&p.children.push({name:"Router",type:"router",children:[]}),p},d=function(e,n){var r=arguments.length<=2||void 0===arguments[2]?{id:1,name:"fakeSubs"}:arguments[2],i=t.find(n,{subscriber_root:r.id}),a=t.find(e,{id:i.provider_service}),s=l(n,e,a,i);return{name:r.name||r.humanReadableName,parent:null,type:"subscriber",children:[s]}},p=function(e,n){var r=function s(e,n,r){"service_vbng"===r.humanReadableName&&(r.humanReadableName="service_vrouter");var i={type:"service",name:r.humanReadableName,service:r},a=t.find(n,{subscriber_service:r.id});if(a){var c=t.find(e,{id:a.provider_service});i.children=[s(e,n,c)]}else i.children=[{name:"Router",type:"router",children:[]}];return delete r.id,i},i=t.find(e,{id:3});if(!angular.isDefined(i))return void console.error("Missing Base service!");var a={name:"Subscriber",type:"subscriber",parent:null,children:[r(e,n,i)]};return a},v=function(t){var i,a,s=e.defer();return n.query().$promise.then(function(e){return i=e,r.query().$promise}).then(function(e){a=e,s.resolve(d(i,a,t))})["catch"](function(e){throw new Error(e)}),s.promise},h=function(){var t,i,a=e.defer();return n.query().$promise.then(function(e){return t=e,r.query({kind:"coarse"}).$promise}).then(function(e){i=e,a.resolve(p(t,i))})["catch"](function(e){throw new Error(e)}),a.promise};return{get:h,buildServiceTree:p,getBySubscriber:v,buildLevel:l,buildSubscriberServiceTree:d,findLevelRelation:c,findLevelServices:u,depthOf:s,findSpecificInformation:o}}])}();var _slicedToArray=function(){function e(e,t){var n=[],r=!0,i=!1,a=void 0;try{for(var s,c=e[Symbol.iterator]();!(r=(s=c.next()).done)&&(n.push(s.value),!t||n.length!==t);r=!0);}catch(o){i=!0,a=o}finally{try{!r&&c["return"]&&c["return"]()}finally{if(i)throw a}}return n}return function(t,n){if(Array.isArray(t))return t;if(Symbol.iterator in Object(t))return e(t,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}();!function(){angular.module("xos.diagnostic").service("RackHelper",["serviceTopologyConfig","_",function(e,t){var n=this;this.getComputeNodeLabelSize=function(){return e.computeNode.labelHeight+2*e.instance.margin},this.getComputeNodeSize=t.memoize(function(t){var r=3*e.instance.margin+2*e.instance.width,i=Math.round(t.length/2),a=n.getComputeNodeLabelSize(),s=e.instance.height*i+e.instance.margin*(i+1)+a;return[r,s]}),this.getRackSize=function(r){var i=0,a=e.computeNode.margin;return t.forEach(r,function(t){var r=n.getComputeNodeSize(t.instances),s=_slicedToArray(r,2),c=s[0],o=s[1];i=c+2*e.computeNode.margin,a+=o+e.computeNode.margin}),[i,a]},this.getInstancePosition=function(t){var r=Math.floor(t/2),i=t%2?1:0,a=n.getComputeNodeLabelSize(),s=e.instance.margin+e.instance.width*i+e.instance.margin*i,c=a+e.instance.margin+e.instance.height*r+e.instance.margin*r;return[s,c]},this.getComputeNodePosition=function(r,i){var a=e.computeNode.margin,s=t.reduce(r.slice(0,i),function(e,t){return e+n.getComputeNodeSize(t.instances)[1]},0),c=e.computeNode.margin+e.computeNode.margin*i+s;return[a,c]}}])}();var _slicedToArray=function(){function e(e,t){var n=[],r=!0,i=!1,a=void 0;try{for(var s,c=e[Symbol.iterator]();!(r=(s=c.next()).done)&&(n.push(s.value),!t||n.length!==t);r=!0);}catch(o){i=!0,a=o}finally{try{!r&&c["return"]&&c["return"]()}finally{if(i)throw a}}return n}return function(t,n){if(Array.isArray(t))return t;if(Symbol.iterator in Object(t))return e(t,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}();!function(){var e={cloud:" M 79.72 49.60 C 86.00 37.29 98.57 29.01 111.96 26.42 C 124.27 24.11 137.53 26.15 148.18 32.90 C 158.08 38.78 165.39 48.87 167.65 60.20 C 176.20 57.90 185.14 56.01 194.00 57.73 C 206.08 59.59 217.92 66.01 224.37 76.66 C 227.51 81.54 228.85 87.33 229.23 93.06 C 237.59 93.33 246.22 95.10 253.04 100.19 C 256.69 103.13 259.87 107.67 258.91 112.59 C 257.95 118.43 252.78 122.38 247.78 124.82 C 235.27 130.43 220.23 130.09 207.98 123.93 C 199.33 127.88 189.76 129.43 180.30 128.57 C 173.70 139.92 161.70 147.65 148.86 149.93 C 133.10 153.26 116.06 148.15 104.42 137.08 C 92.98 143.04 78.96 143.87 66.97 139.04 C 57.75 135.41 49.70 128.00 46.60 118.43 C 43.87 109.95 45.81 100.29 51.30 93.32 C 57.38 85.18 67.10 80.44 76.99 78.89 C 74.38 69.20 74.87 58.52 79.72 49.60 Z"},t=0,n=0;angular.module("xos.diagnostic").service("NodeDrawer",["d3","serviceTopologyConfig","RackHelper","_",function(r,i,a,s){var c=this,o=this;this.addNetworks=function(t){t.selectAll("*").remove(),t.append("path").attr({d:e.cloud,transform:"translate(-100, -72), scale(0.7)","class":"cloud"}),t.append("text").attr({"text-anchor":"middle",y:-5,x:5}).text(function(e){return e.name}),t.append("text").attr({"text-anchor":"middle",y:8,x:5,"class":"small"}).text(function(e){return e.subtitle}),t.each(function(e){var t=r.select(this);"LAN-Side"===e.name&&angular.isDefined(e.subscriberTag)&&(t.append("text").attr({"text-anchor":"middle",y:50}).text(function(){return"C-Tag: "+e.subscriberTag.cTag}),t.append("text").attr({"text-anchor":"middle",y:70}).text(function(){return"S-Tag: "+e.subscriberTag.sTag})),"WAN-Side"===e.name&&angular.isDefined(e.subscriberIP)&&t.append("text").attr({"text-anchor":"middle",y:50}).text(function(){return"Public IP: "+e.subscriberIP})})},this.addRack=function(e){e.each(function(t){var n=a.getRackSize(t.computeNodes),r=_slicedToArray(n,2),s=r[0],o=r[1];e.select("g").remove();var u=e.append("g");u.attr({transform:"translate(0,0)"}).transition().duration(i.duration).attr({transform:function(){return"translate("+-(s/2)+", "+-(o/2)+")"}}),u.append("rect").attr({width:0,height:0}).transition().duration(i.duration).attr({width:s,height:o}),u.append("text").attr({"text-anchor":"middle",y:-10,x:s/2,opacity:0}).text(function(e){return e.name}).transition().duration(i.duration).attr({opacity:1}),c.drawComputeNodes(u,t.computeNodes)})},this.drawComputeNodes=function(e,n){var s=e.selectAll(".compute-nodes").data(n,function(e){return angular.isString(e.d3Id)||(e.d3Id="compute-node-"+ ++t),e.d3Id}),c=e.node().getBoundingClientRect(),u=c.width,l=c.height,d=s.enter().append("g");d.attr({transform:"translate("+u/2+", "+l/2+")","class":"compute-node"}).transition().duration(i.duration).attr({transform:function(e){return"translate("+a.getComputeNodePosition(n,e.d3Id.replace("compute-node-","")-1)+")"}}),d.append("rect").attr({width:0,height:0}).transition().duration(i.duration).attr({width:function(e){return a.getComputeNodeSize(e.instances)[0]},height:function(e){return a.getComputeNodeSize(e.instances)[1]}}),d.append("text").attr({"text-anchor":"start",y:17,x:10,opacity:0}).text(function(e){return e.humanReadableName.split(".")[0]}).transition().duration(i.duration).attr({opacity:1}),d.length>0&&d.each(function(e){o.drawInstances(r.select(this),e.instances)})};var u=function(e){return e.replace("app_","").replace("service_","").replace("mysite_","").replace("_instance","")},l=function(e){function t(e,t){return t.substring(0,e.length)===e}return t("0 - ",e.backend_status)?"provisioning":t("1 - ",e.backend_status)?"good":t("2 - ",e.backend_status)?"bad":""},d=function(e,t){var n=e.append("g").attr({"class":"container",transform:"translate("+i.instance.margin+", 115)"});n.append("rect").attr({width:250-2*i.container.margin,height:i.container.height}),n.append("text").attr({y:20,x:i.instance.margin,"class":"name"}).text(t.name);var r=["memory","memory.usage","cpu_util"];r.forEach(function(e,r){var a=s.find(t.stats,{meter:e});angular.isDefined(a)&&n.append("text").attr({y:40+15*r,x:i.instance.margin,opacity:0}).text(a.description+": "+Math.round(a.value)+" "+a.unit).transition().duration(i.duration).attr({opacity:1})});var a=["eth0","eth1"],c=[{meter:"network.incoming.bytes.rate",label:"Incoming"},{meter:"network.outgoing.bytes.rate",label:"Outgoing"}];a.forEach(function(e,r){0!==t.port[e].length&&(n.append("text").attr({y:90,x:i.instance.margin+120*r,"class":"name"}).text(t.name+"-"+e),c.forEach(function(a,c){var o=s.find(t.port[e],{meter:a.meter});angular.isDefined(o)&&n.append("text").attr({y:105+15*c,x:i.instance.margin+120*r,opacity:0}).text(a.label+": "+Math.round(o.value)+" "+o.unit).transition().duration(i.duration).attr({opacity:1})}))})},p=function(e,t){var n={"mysite_vsg-1":"200, -120","mysite_vsg-2":"-300, 30","mysite_vsg-3":"-300, -250"},a=e.append("g").attr({transform:"translate("+(n[t.humanReadableName]||n["mysite_vsg-1"])+")","class":"stats-container"}).on("click",function(e){e.fade=!e.fade;var t=void 0;t=e.fade?.1:1,r.select(this).transition().duration(i.duration).attr({opacity:t})}),c={"mysite_vsg-1":{x1:-160,y1:120,x2:0,y2:50},"mysite_vsg-2":{x1:250,y1:50,x2:300,y2:-10},"mysite_vsg-3":{x1:250,y1:50,x2:300,y2:270}};a.append("line").attr({x1:function(e){return c[e.humanReadableName].x1||c["mysite_vsg-1"].x1},y1:function(e){return c[e.humanReadableName].y1||c["mysite_vsg-1"].y1},x2:function(e){return c[e.humanReadableName].x2||c["mysite_vsg-1"].x2},y2:function(e){return c[e.humanReadableName].y2||c["mysite_vsg-1"].y2},stroke:"black",opacity:0}).transition().duration(i.duration).attr({opacity:1});var o=110,u=250;t.container&&(o+=i.container.height+2*i.container.margin);a.append("rect").attr({width:u,height:o,opacity:0}).transition().duration(i.duration).attr({opacity:1});a.append("text").attr({y:15,x:i.instance.margin,"class":"name",opacity:0}).text(t.humanReadableName).transition().duration(i.duration).attr({opacity:1}),a.append("text").attr({y:30,x:i.instance.margin,"class":"ip",opacity:0}).text(t.ip).transition().duration(i.duration).attr({opacity:1});var l=["memory","memory.usage","cpu","cpu_util"];l.forEach(function(e,n){var r=s.find(t.stats,{meter:e});r&&a.append("text").attr({y:55+15*n,x:i.instance.margin,opacity:0}).text(r.description+": "+Math.round(r.value)+" "+r.unit).transition().duration(i.duration).attr({opacity:1})}),t.container&&d(a,t.container)};this.drawInstances=function(e,t){var s=e.node().getBoundingClientRect(),c=s.width,o=s.height,d=e.selectAll(".instances").data(t,function(e){return angular.isString(e.d3Id)?e.d3Id:e.d3Id="instance-"+ ++n}),v=d.enter().append("g");v.attr({transform:"translate("+c/2+", "+o/2+")","class":function(e){return"instance "+(e.selected?"active":"")+" "+l(e)}}).transition().duration(i.duration).attr({transform:function(e,t){return"translate("+a.getInstancePosition(t)+")"}}),v.append("rect").attr({width:0,height:0}).transition().duration(i.duration).attr({width:i.instance.width,height:i.instance.height}),v.append("text").attr({"text-anchor":"middle",y:23,x:40,opacity:0}).text(function(e){return u(e.humanReadableName)}).transition().duration(i.duration).attr({opacity:1}),v.each(function(e,t){var n=r.select(this);angular.isDefined(e.stats)&&e.selected&&p(n,e,t)})},this.addPhisical=function(e){e.select("rect").remove(),e.select("text").remove(),e.append("rect").attr(i.square),e.append("text").attr({"text-anchor":"middle",y:i.square.y-10}).text(function(e){return e.name||e.humanReadableName})},this.addDevice=function(e){e.append("circle").attr(i.circle),e.append("text").attr({"text-anchor":"end",x:-i.circle.r-10,y:i.circle.r/2}).text(function(e){return e.name||e.mac})}}])}();var _slicedToArray=function(){function e(e,t){var n=[],r=!0,i=!1,a=void 0;try{for(var s,c=e[Symbol.iterator]();!(r=(s=c.next()).done)&&(n.push(s.value),!t||n.length!==t);r=!0);}catch(o){i=!0,a=o}finally{try{!r&&c["return"]&&c["return"]()}finally{if(i)throw a}}return n}return function(t,n){if(Array.isArray(t))return t;if(Symbol.iterator in Object(t))return e(t,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}();!function(){angular.module("xos.diagnostic").service("LogicTopologyHelper",["$window","$log","$rootScope","_","serviceTopologyConfig","NodeDrawer","ChartData",function(e,t,n,r,i,a,s){var c,o,u,l,d,p,v=this,h=0,m=s.logicTopologyData;this.computeElementPosition=function(e){var t=[],n=r.reduce(i.elWidths,function(e,t){return t+e},0),a=e-n-2*i.widthMargin,s=a/(i.elWidths.length-1);return r.forEach(i.elWidths,function(n,a){var c=0;0!==a&&(c=r.reduce(i.elWidths.slice(0,a),function(e,t){return t+e},0));var o=i.widthMargin+s*a+n/2+c;t.push(e-o)}),t};var b=function(e){var t=p.nodes(e);t.forEach(function(e){e.y=v.computeElementPosition(l)[e.depth]});var n=p.links(t);return[t,n]},g=function(e,t){var r=e.selectAll("g.node").data(t,function(e){return angular.isString(e.d3Id)||(e.d3Id="tree-"+ ++h),e.d3Id});r.enter().append("g").attr({"class":function(e){return"node "+e.type},transform:"translate("+l/2+", "+d/2+")"});a.addNetworks(r.filter(".network")),a.addRack(r.filter(".rack")),a.addPhisical(r.filter(".router")),a.addPhisical(r.filter(".subscriber")),a.addDevice(r.filter(".device")),r.filter(".subscriber").on("click",function(){n.$emit("subscriber.modal.open")});r.transition().duration(i.duration).attr({transform:function(e){return"translate("+e.y+","+e.x+")"}}),r.exit().remove()},f=function(e,t){c=d3.svg.diagonal().projection(function(e){return[e.y,e.x]});var n=e.selectAll("path.link").data(t,function(e){return e.target.d3Id});n.enter().insert("path","g").attr("class",function(e){return"link "+e.target.type}).attr("d",function(e){var t={x:d/2,y:l/2};return c({source:t,target:t})}),n.transition().duration(i.duration).attr("d",c),n.exit().remove()};this.setupTree=function(e){l=e.node().getBoundingClientRect().width,d=e.node().getBoundingClientRect().height;var t=l-2*i.widthMargin,n=d-2*i.heightMargin;p=d3.layout.tree().size([n,t])},this.updateTree=function(e){var t=b(m),n=_slicedToArray(t,2);o=n[0],u=n[1],g(e,o),f(e,u)}}])}(),function(){angular.module("xos.diagnostic").directive("logicTopology",function(){return{restrict:"E",scope:{subscribers:"=",selected:"="},bindToController:!0,controllerAs:"vm",templateUrl:"templates/logicTopology.tpl.html",controller:["$element","$log","$scope","$rootScope","$timeout","d3","LogicTopologyHelper","Node","Tenant","Ceilometer","serviceTopologyConfig","ChartData",function(e,t,n,r,i,a,s,c,o,u,l,d){var p=this;t.info("Logic Plane");var v;this.selectedInstances=[],this.hideInstanceStats=!0;var h=this,m=function(t){a.select(e[0]).select("svg").remove(),v=a.select(t).append("svg").style("width",t.clientWidth+"px").style("height",t.clientHeight+"px")},b=function(){d.getLogicTree().then(function(e){s.updateTree(v)})};b(),n.$watch(function(){return p.selected},function(e){e?(d.selectSubscriber(e),s.updateTree(v)):(d.removeSubscriber(),s.updateTree(v))}),r.$on("instance.detail.hide",function(){p.hideInstanceStats=!0,i(function(){p.selectedInstances=[],d.highlightInstances([]),s.updateTree(v)},500)}),r.$on("instance.detail",function(e,t){d.getInstanceStatus(t).then(function(e){s.updateTree(v)})["catch"](function(e){h.error="Service statistics are not available at this time. Please try again later.",
+i(function(){h.error=null},2e3)})}),a.select(window).on("resize.logic",function(){m(e[0]),s.setupTree(v),s.updateTree(v)}),m(e[0]),s.setupTree(v),this.selectSubscriberModal=function(){p.openSelectSubscriberModal=!0,n.$apply()},this.subscriberStatusModal=function(){p.openSubscriberStatusModal=!0,n.$apply()},r.$on("subscriber.modal.open",function(){d.currentSubscriber?p.subscriberStatusModal():p.selectSubscriberModal()}),r.$on("subscriber.modal.open",function(){d.currentSubscriber?(p.currentSubscriber=d.currentSubscriber,p.subscriberStatusModal()):p.selectSubscriberModal()})}]}})}(),function(){angular.module("xos.diagnostic").directive("diagnosticContainer",function(){return{restrict:"E",templateUrl:"templates/diagnostic.tpl.html",controllerAs:"vm",controller:["ChartData","Subscribers","ServiceRelation","$rootScope","$log",function(e,t,n,r,i){var a=this;this.loader=!0,this.error=!1;var s=function(){t.query().$promise.then(function(e){return a.subscribers=e,n.get()}).then(function(e){a.serviceChain=e})["catch"](function(e){throw new Error(e)})["finally"](function(){a.loader=!1})};s(),this.reloadGlobalScope=function(){a.selectedSubscriber=null,s()};var c=function(r){n.getBySubscriber(r).then(function(n){return a.serviceChain=n,e.currentServiceChain=n,t.getWithDevices({id:r.id}).$promise}).then(function(t){a.selectedSubscriber=t,e.currentSubscriber=t})};r.$on("subscriber.selected",function(e,t){c(t)})}]}})}(),function(){angular.module("xos.diagnostic").factory("d3",["$window",function(e){return e.d3}])}(),function(){angular.module("xos.diagnostic").constant("serviceTopologyConfig",{widthMargin:60,heightMargin:30,duration:750,elWidths:[20,104,105,104,20],circle:{radius:10,r:10,selectedRadius:15},square:{width:20,height:20,x:-10,y:-10},rack:{width:105,height:50,x:-30,y:-25},computeNode:{width:50,height:20,margin:5,labelHeight:10,x:-25,y:-10},instance:{width:80,height:36,margin:5,x:-40,y:-18},container:{width:60,height:130,margin:5,x:-30,y:-15}})}(),function(){angular.module("xos.diagnostic").service("ChartData",["$rootScope","$q","_","Tenant","Node","serviceTopologyConfig","Ceilometer","Instances",function(e,t,n,r,i,a,s,c){var o=this;this.currentSubscriber=null,this.currentServiceChain=null,this.logicTopologyData={name:"Router",type:"router",children:[{name:"WAN-Side",subtitle:"Virtual Network",type:"network",children:[{name:"Compute Servers",type:"rack",computeNodes:[],children:[{name:"LAN-Side",subtitle:"Virtual Network",type:"network",children:[{name:"Subscriber",type:"subscriber"}]}]}]}]},this.getLogicTree=function(){var e=t.defer();return i.queryWithInstances().$promise.then(function(t){o.logicTopologyData.children[0].children[0].computeNodes=t,e.resolve(o.logicTopologyData)}),e.promise},this.addSubscriberTag=function(e){o.logicTopologyData.children[0].children[0].children[0].subscriberTag={cTag:e.cTag,sTag:e.sTag}},this.addSubscriber=function(e){return e.children=e.devices,o.logicTopologyData.children[0].children[0].children[0].children=[e],o.logicTopologyData},this.removeSubscriber=function(){o.logicTopologyData.children[0].children[0].children[0].children[0].humanReadableName="Subscriber",o.currentSubscriber=null,160===a.elWidths[a.elWidths.length-1]&&a.elWidths.pop(),delete o.logicTopologyData.children[0].children[0].children[0].subscriberTag,delete o.logicTopologyData.children[0].subscriberIP,o.highlightInstances([]),delete o.logicTopologyData.children[0].children[0].children[0].children[0].children},this.getSubscriberTag=function(e){var t={cTag:e.c_tag,sTag:e.s_tag};o.addSubscriberTag(t),o.currentSubscriber.tags=t},this.getSubscriberIP=function(e){o.logicTopologyData.children[0].subscriberIP=e.wan_container_ip},this.selectSubscriber=function(e){a.elWidths.push(160),o.addSubscriber(angular.copy(e)),o.highlightInstances([]),o.getSubscriberTag(e),o.getSubscriberIP(e)},this.highlightInstances=function(e){var t=o.logicTopologyData.children[0].children[0].computeNodes;t.map(function(e){e.instances.map(function(e){return e.selected=!1,e})}),n.forEach(e,function(e){t.map(function(t){t.instances.map(function(t){return t.id===e.id&&(t.selected=!0,t.stats=e.stats,t.container=e.container),t})})})},this.getInstanceStatus=function(e){var i=t.defer(),a=void 0;if(o.currentSubscriber){var u=void 0;try{u=JSON.parse(e.tenant.service_specific_attribute)}catch(l){u=null}if(u&&u.instance_id)!function(){var e={};a=c.get({id:u.instance_id}).$promise.then(function(t){return e=t,s.getInstanceStats(e.instance_uuid)}).then(function(t){e.stats=t;var n="vcpe-"+o.currentSubscriber.tags.sTag+"-"+o.currentSubscriber.tags.cTag;return e.container={name:n},s.getContainerStats(n)}).then(function(t){return e.container.stats=t.stats,e.container.port=t.port,[e]})}();else{var d=t.defer();d.resolve([]),a=d.promise}}else{var p={service_vsg:{kind:"vCPE"},service_vbng:{kind:"vBNG"},service_volt:{kind:"vOLT"}};a=r.queryVsgInstances(p[e.name]).$promise.then(function(e){return s.getInstancesStats(n.uniq(e))})}return a.then(function(e){o.highlightInstances(e),i.resolve(e)})["catch"](function(e){i.reject(e)}),i.promise}}])}(),angular.module("xos.diagnostic").run(["$location",function(e){e.path("/")}]);
\ No newline at end of file
diff --git a/xos/core/xoslib/static/js/xosHpc.js b/xos/core/xoslib/static/js/xosHpc.js
new file mode 100644
index 0000000..a1eb26e
--- /dev/null
+++ b/xos/core/xoslib/static/js/xosHpc.js
@@ -0,0 +1 @@
+"use strict";angular.module("xos.hpc",["ngResource","ngCookies","ui.router","xos.helpers"]).config(["$stateProvider",function(e){e.state("hpc-list",{url:"/",template:"<hpcs-list></hpcs-list>"})}]).config(["$httpProvider",function(e){e.interceptors.push("NoHyperlinks")}]).service("Hpc",["$q","$http",function(e,r){this.query=function(t){var n=e.defer();return r.get("/xoslib/hpcview",{params:t}).then(function(e){n.resolve(e.data)})["catch"](n.reject),{$promise:n.promise}}}]).directive("hpcsList",function(){return{restrict:"E",scope:{},bindToController:!0,controllerAs:"vm",templateUrl:"templates/hpc-list.tpl.html",controller:["Hpc",function(e){var r=this,t=function(e){e=Number(e);var r=Math.floor(e/3600),t=Math.floor(e%3600/60),n=Math.floor(e%3600%60);return(r>0?r+"h "+(10>t?"0":""):"")+t+"m "+(10>n?"0":"")+n+"s"},n=function(e){return function(r){return angular.isNumber(r[e])?t(r[e]):r[e]}};this.routerConfig={filter:"field",order:!0,columns:[{label:"Name",prop:"name"},{label:"Ip Address",prop:"ip"},{label:"Record Checker",prop:"watcher.DNS.msg"},{label:"Name Servers",prop:"nameservers",type:"array"},{label:"Dns Demux Config Age",prop:"dnsdemux_config_age",type:"custom",formatter:n("dnsdemux_config_age")},{label:"Dns Redir Config Age",prop:"dnsredir_config_age",type:"custom",formatter:n("dnsredir_config_age")}]},this.cacheConfig={filter:"field",order:!0,columns:[{label:"Name",prop:"name"},{label:"Prober",prop:"watcher.HPC-hb.msg"},{label:"Fetcher",prop:"watcher.HPC-fetch.msg"},{label:"Config Age",prop:"config_age",type:"custom",formatter:n("config_age")}]},this.fetch=function(){e.query().$promise.then(function(e){r.routers=e[0].dnsdemux,r.caches=e[0].hpc})["catch"](function(e){throw new Error(e)})},this.fetch()}]}}),angular.module("xos.hpc").run(["$templateCache",function(e){e.put("templates/hpc-list.tpl.html",'<div class="container-fluid">\n    <div class="row">\n        <div class="col-xs-10">\n            <h1>Request Routers</h1>\n        </div>\n        <div class="col-xs-2 text-right">\n            <a href="" ng-click="vm.fetch()" class="btn btn-primary btn-reload">\n                <i class="glyphicon glyphicon-refresh"></i>\n                Refresh\n            </a>\n        </div>\n    </div>\n    <div class="row">\n        <div class="col-xs-12">\n            <xos-table config="vm.routerConfig" data="vm.routers"></xos-table>\n        </div>\n    </div>\n    <div class="row">\n        <div class="col-xs-12">\n            <h1>HyperCache</h1>\n        </div>\n    </div>\n    <div class="row">\n        <div class="col-xs-12">\n            <xos-table config="vm.cacheConfig" data="vm.caches"></xos-table>\n        </div>\n    </div>\n</div>')}]),angular.module("xos.hpc").run(["$location",function(e){e.path("/")}]);
\ No newline at end of file
diff --git a/xos/core/xoslib/static/js/xosHpcNodes.js b/xos/core/xoslib/static/js/xosHpcNodes.js
new file mode 100644
index 0000000..850aeca
--- /dev/null
+++ b/xos/core/xoslib/static/js/xosHpcNodes.js
@@ -0,0 +1,109 @@
+/* eslint-disable */
+SC_HPC_FETCH = 3600;
+
+var hpc_data = null;
+
+function updateHpcUrlTable() {
+    hpcnode = null;
+    selected_url = $("#xos-hpc-url-select").val();
+
+    $('#xos-hpc-urls').html( '<table cellpadding="0" cellspacing="0" border="0" class="display" id="dynamic_hpc_urls"></table>' );
+    var actualEntries = [];
+
+    for (index in hpc_data) {
+        hpc_node = hpc_data[index];
+
+        if (parseInt(hpc_node["watcher.HPC-fetch.time"]) > SC_HPC_FETCH) {
+            $("#xos-hpc-urls").html("stale");
+            actualEntries.push( [hpc_node.name, "stale", "stale", "stale", "stale"] );
+        } else {
+            urls = hpc_node["watcher.HPC-fetch.urls"];
+
+            found = null;
+            for (j in urls) {
+                url = urls[j];
+
+                if (url[0] == selected_url) {
+                    found = url;
+                }
+            }
+
+            if (found==null) {
+                actualEntries.push( [hpc_node.name, "not found", "not found", "not found", "not found"] );
+            } else {
+                bytes_downloaded=url[2];
+                total_time = url[3];
+                if (total_time > 0) {
+                    KBps = Math.round(bytes_downloaded/total_time/1024.0);
+                } else {
+                    KBps = 0;
+                }
+                actualEntries.push( [hpc_node.name, url[1], bytes_downloaded, total_time, KBps] );
+            }
+        }
+    }
+
+    oTable = $('#dynamic_hpc_urls').dataTable( {
+        "bJQueryUI": true,
+        "aaData":  actualEntries ,
+        "bStateSave": true,
+        "bFilter": false,
+        "bPaginate": false,
+        "aoColumns": [
+            { "sTitle": "Node", },
+            { "sTitle": "Status" },
+            { "sTitle": "Bytes_Downloaded" },
+            { "sTitle": "Total_Time" },
+            { "sTitle": "KBps" },
+        ]
+    } );
+}
+
+function updateUrlList() {
+    selected_url = $("#xos-hpc-url-select").val();
+
+    urls = [];
+    for (index in hpc_data) {
+        node = hpc_data[index];
+        node_urls = node["watcher.HPC-fetch.urls"];
+        for (j in node_urls) {
+            url = node_urls[j][0];
+            if ($.inArray(url, urls) < 0) {
+                urls.push(url);
+            }
+        }
+    }
+
+    console.log(urls);
+
+    options = [];
+    for (index in urls) {
+        url = urls[index];
+        if (node.name == selected_url) {
+            options.push("<option value=\"" + url + "\" selected>" + url + "</option>");
+        } else {
+            options.push("<option value=\"" + url + "\">" + url + "</option>");
+        }
+    }
+
+    $("#xos-hpc-url-select").html(options);
+}
+
+function updateHpcView(data) {
+    data = data[0];
+    hpc_data = data.attributes.hpc;
+    updateUrlList();
+    updateHpcUrlTable();
+}
+
+$(document).ready(function(){
+    xos.hpcview.on("change", function() { console.log("change"); updateHpcView(xos.hpcview.models); });
+    xos.hpcview.on("remove", function() { console.log("sort"); updateHpcView(xos.hpcview.models); });
+    xos.hpcview.on("sort", function() { console.log("sort"); updateHpcView(xos.hpcview.models); });
+
+    $("#xos-hpc-node-select").click( function() { updateHpcUrlTable(); } );
+
+    xos.hpcview.startPolling();
+});
+/* eslint-enable */
+
diff --git a/xos/core/xoslib/static/js/xosHpcUrls.js b/xos/core/xoslib/static/js/xosHpcUrls.js
new file mode 100644
index 0000000..cda7b2d
--- /dev/null
+++ b/xos/core/xoslib/static/js/xosHpcUrls.js
@@ -0,0 +1,92 @@
+/* eslint-disable */
+SC_HPC_FETCH = 3600;
+
+var hpc_data = null;
+
+function updateHpcUrlTable() {
+    hpcnode = null;
+    selected_node_name = $("#xos-hpc-node-select").val();
+
+    for (index in hpc_data) {
+        if (hpc_data[index].name == selected_node_name) {
+            hpcnode = hpc_data[index];
+        };
+    }
+
+    if (hpcnode == null) {
+       $("#xos-hpc-urls").html("select a node");
+       return;
+    }
+
+    $('#xos-hpc-urls').html( '<table cellpadding="0" cellspacing="0" border="0" class="display" id="dynamic_hpc_urls"></table>' );
+    var actualEntries = [];
+
+    if (parseInt(hpcnode["watcher.HPC-fetch.time"])> SC_HPC_FETCH) {
+        $("#xos-hpc-urls").html("stale");
+        return;
+    }
+
+    urls = hpcnode["watcher.HPC-fetch.urls"];
+
+    for (index in urls) {
+        url = urls[index];
+        bytes_downloaded=url[2];
+        total_time = url[3];
+        if (total_time > 0) {
+            KBps = Math.round(bytes_downloaded/total_time/1024.0);
+        } else {
+            KBps = 0;
+        }
+        actualEntries.push( [url[0], url[1], bytes_downloaded, total_time, KBps] );
+    }
+
+    oTable = $('#dynamic_hpc_urls').dataTable( {
+        "bJQueryUI": true,
+        "aaData":  actualEntries ,
+        "bStateSave": true,
+        "bFilter": false,
+        "bPaginate": false,
+        "aoColumns": [
+            { "sTitle": "Url", },
+            { "sTitle": "Status" },
+            { "sTitle": "Bytes_Downloaded" },
+            { "sTitle": "Total_Time" },
+            { "sTitle": "KBps" },
+        ]
+    } );
+}
+
+function updateNodeList() {
+    selected_node_name = $("#xos-hpc-node-select").val();
+
+    options = [];
+    for (index in hpc_data) {
+        node = hpc_data[index];
+        if (node.name == selected_node_name) {
+            options.push("<option value=\"" + node.name + "\" selected>" + node.name + "</option>");
+        } else {
+            options.push("<option value=\"" + node.name + "\">" + node.name + "</option>");
+        }
+    }
+
+    $("#xos-hpc-node-select").html(options);
+}
+
+function updateHpcView(data) {
+    data = data[0];
+    hpc_data = data.attributes.hpc;
+    updateNodeList();
+    updateHpcUrlTable();
+}
+
+$(document).ready(function(){
+    xos.hpcview.on("change", function() { console.log("change"); updateHpcView(xos.hpcview.models); });
+    xos.hpcview.on("remove", function() { console.log("sort"); updateHpcView(xos.hpcview.models); });
+    xos.hpcview.on("sort", function() { console.log("sort"); updateHpcView(xos.hpcview.models); });
+
+    $("#xos-hpc-node-select").click( function() { updateHpcUrlTable(); } );
+
+    xos.hpcview.startPolling();
+});
+
+/* eslint-enable */
diff --git a/xos/core/xoslib/static/js/xosMcordTopology.js b/xos/core/xoslib/static/js/xosMcordTopology.js
new file mode 100644
index 0000000..c1decb6
--- /dev/null
+++ b/xos/core/xoslib/static/js/xosMcordTopology.js
@@ -0,0 +1 @@
+"use strict";angular.module("xos.mcordTopology",["ngResource","ngCookies","ui.router","xos.helpers"]).config(["$stateProvider",function(t){t.state("topology",{url:"/",template:"<m-cord-topology></m-cord-topology>"})}]).config(["$httpProvider",function(t){t.interceptors.push("NoHyperlinks")}]).factory("_",["$window",function(t){return t._}]).service("Traffic",["$http","$q",function(t,n){this.get=function(){var e=n.defer();return t.get("videoLocal.txt").then(function(t){e.resolve(t.data)})["catch"](function(t){console.log(t),e.resolve(10*Math.random())}),e.promise}}]).directive("mCordTopology",function(){return{restrict:"E",scope:{},bindToController:!0,controllerAs:"vm",template:"",controller:["$element","$interval","$rootScope","_","$http","TopologyElements","NodeDrawer","Traffic",function(t,n,e,r,a,i,o,c){var s=t[0],u=[],l=[],d=0,p=1,f=5,h=function(t){return r.filter(t,function(t){return t.name.indexOf("bbu")>=0})},m=function(t){return i.fakedInstance},y=function(){d3.select("svg").style("width",s.clientWidth+"px").style("height",s.clientHeight+"px"),u=i.nodes,l=i.links,c.get().then(function(t){if(d)if(t===d)p=p;else{var n=t-d;n>0?p+=n/f:p-=-1*n/f}else p=2;return.2>p&&(p=.2),d=t,a.get("/api/core/xos/instances")}).then(function(t){b(h(t.data)),w(m(t.data)),V(g,u,l)})["catch"](function(t){throw new Error(t)})},v=d3.layout.force(),g=d3.select(s).append("svg").style("width",s.clientWidth+"px").style("height",s.clientHeight+"px"),x=(g.append("g").attr({"class":"link-container"}),g.append("g").attr({"class":"node-container"}),function(t,n){return t.map(function(t){console.log(r.find);var e=r.findIndex(n,{id:t.source}),a=r.findIndex(n,{id:t.target});return{source:e,target:a,value:1,id:"link-"+e+"-"+a,type:t.source.indexOf("fabric")>=0?"big":"small"}})}),H=function(t){return r.map(t,function(t){return"fabric"!==t.type?t:(t.x=t.x*Z,t.y=t.y*M,t)})},b=function(t){var n=s.clientWidth/2/(t.length+1),e=t.map(function(t,e){return{type:"bbu",name:t.name,id:"bbu-"+t.id,fixed:!0,y:3*M,x:n*(e+1)}}),r=e.map(function(t){return{source:t.id,target:"fabric4"}});t.forEach(function(t,a){e.push({type:"rru",name:"rru",id:"rru-"+t.id,fixed:!0,y:4*M,x:n*(a+1)}),r.push({source:"rru-"+t.id,target:"bbu-"+t.id})}),u=u.concat(e),l=l.concat(r)},w=function(t){var n=s.clientWidth/2/(t.length+1),e=t.map(function(t,e){return{type:t.name.substring(0,3),name:t.name,id:t.name.substring(0,3)+"-"+t.id,fixed:!0,y:3*M,x:s.clientWidth/2+n*(e+1)}}),r=e.map(function(t){return{source:t.id,target:"fabric4"}});u=u.concat(e),l=l.concat(r)},Z=void 0,M=void 0;Z=s.clientWidth/3,M=s.clientHeight/5;var V=function(t,n,e){Z=s.clientWidth/3,M=s.clientHeight/5,e=x(e,n),n=H(n),console.log(n),v.nodes(n).links(e).size([s.clientWidth,s.clientHeight]).charge(-20).chargeDistance(200).linkDistance(80).linkStrength(.1).start();var r=d3.select(".link-container"),a=d3.select(".node-container");o.drawFabricBox(a,Z,M);var i=r.selectAll(".link").data(e,function(t){return t.id});i.enter().append("line").attr({"class":function(t){return"link "+t.type},"stroke-width":p,id:function(t){return t.id},opacity:0}).transition().duration(1e3).attr({opacity:1}),i.transition().duration(1e3).attr({"stroke-width":p,opacity:1}),i.exit().remove();var c=a.selectAll(".node").data(n,function(t){return t.id}),u=c.enter().append("g",function(t){return t.interfaceCfgIdentifier}).attr({"class":function(t){return t.type+" node"},transform:function(t){return"translate("+t.x+", "+t.y+")"}});o.drawBbus(u.filter(".bbu")),o.drawRrus(u.filter(".rru")),o.drawFabric(u.filter(".fabric")),o.drawOthers(u.filter(function(t){return console.log(t.type),"MME"===t.type||"SGW"===t.type||"PGW"===t.type||"Vid"===t.type}));var l=c.exit();o.removeElements(l),v.on("tick",function(){i.attr("x1",function(t){return t.source.x}).attr("y1",function(t){return t.source.y}).attr("x2",function(t){return t.target.x}).attr("y2",function(t){return t.target.y}),c.attr("transform",function(t){return"translate("+t.x+","+t.y+")"})})};y()}]}}),angular.module("xos.mcordTopology").run(["$templateCache",function(t){t.put("templates/users-list.tpl.html",'<div class="row">\n  <div class="col-xs-12">\n    <h1>Users List</h1>\n    <p>This is only an example view.</p>\n  </div>\n</div>\n<div class="row">\n  <div class="col-xs-4">Email</div>\n  <div class="col-xs-4">First Name</div>\n  <div class="col-xs-4">Last Name</div>\n</div>  \n<div class="row" ng-repeat="user in vm.users">\n  <div class="col-xs-4">{{user.email}}</div>\n  <div class="col-xs-4">{{user.firstname}}</div>\n  <div class="col-xs-4">{{user.lastname}}</div>\n</div>  ')}]),angular.module("xos.mcordTopology").constant("TopologyElements",{nodes:[{id:"fabric4",type:"fabric",name:"fabric4",fixed:!0,x:1.5,y:1.5}],links:[],fakedInstance:[{humanReadableName:"MME",name:"MME"},{humanReadableName:"PGW",name:"PGW"},{humanReadableName:"SGW",name:"SGW"},{humanReadableName:"Video Server",name:"Video Server"}],icons:{bbu:"M11.08,4.66H24.76l6.81,6.82H4.23Z M4.24,18.34V13.21H31.6v5.13H4.24Zm25.64-1.72V14.94H28.19v1.69h1.68Zm-13.65-1.7v1.69h1.69V14.93H16.22Zm-3.42,0v1.69h1.68V14.93H12.8Zm-3.42,0v1.69h1.68V14.93H9.38ZM6,14.93v1.69H7.64V14.93H6Z M32.8,33.23H3V11.42l0,0c1.17-1.16,2.54-2.5,3.87-3.8S9.59,5,10.72,3.87l0,0H25.08l0,0C26.25,5,27.6,6.32,28.9,7.61s2.68,2.63,3.83,3.78l0,0v0.06ZM3.3,33H32.53l0-21.43C31.36,10.39,30,9.07,28.71,7.8S26.09,5.22,25,4.1H10.86C9.75,5.21,8.41,6.52,7.12,7.77s-2.67,2.61-3.83,3.76V33Z M4.24,25.18V20.05H31.6v5.13H4.24Zm24-1.73h1.68V21.78H28.19v1.67Zm-12,0H17.9V21.78H16.21v1.68Zm-1.73-1.68H12.81v1.67h1.68V21.78Zm-3.43,1.68V21.78H9.38v1.69h1.68ZM6,23.46H7.64V21.78H6v1.68Z M31.6,26.89V32H4.24V26.89H31.6Zm-3.4,1.72V30.3h1.68V28.61H28.19Zm-10.28,0H16.22V30.3h1.68V28.62Zm-3.43,1.69V28.62H12.8v1.69h1.68Zm-3.42,0V28.62H9.38v1.69h1.68ZM7.65,28.62H6v1.67H7.65V28.62Z","switch":"M10,20a10,10,0,0,1,10-10h70a10,10,0,0,1,10,10v70a10,10,\n            0,0,1-10,10h-70a10,10,0,0,1-10-10zM60,26l12,0,0-8,18,13-18,13,0\n            -8-12,0zM60,60l12,0,0-8,18,13-18,13,0-8-12,0zM50,40l-12,0,0-8\n            -18,13,18,13,0-8,12,0zM50,74l-12,0,0-8-18,13,18,13,0-8,12,0z",rru:"M18.11,11a2.25,2.25,0,0,1,2.13,1.53A2.2,2.2,0,0,1,19.52,15a0.74,0.74,0,0,0-.3.61A7.49,7.49,0,0,0,20,19.35c2,4.55,3.94,9.13,5.89,13.7a1.14,1.14,0,0,1-.59,1.64A1.11,1.11,0,0,1,23.86,34q-0.53-1.2-1-2.41a0.38,0.38,0,0,0-.41-0.28H13.78a0.36,0.36,0,0,0-.39.26q-0.51,1.24-1.06,2.47a1.11,1.11,0,0,1-1.14.67,1.07,1.07,0,0,1-1-.89,1.47,1.47,0,0,1,.1-0.75q2.84-6.66,5.7-13.32a4.06,4.06,0,0,1,.18-0.42A6.39,6.39,0,0,0,17,15.53,0.58,0.58,0,0,0,16.74,15,2.21,2.21,0,0,1,16,12.5,2.26,2.26,0,0,1,18.11,11ZM21.74,29.1c-0.32-.74-0.61-1.43-0.92-2.12a0.35,0.35,0,0,0-.27-0.14H15.66a0.33,0.33,0,0,0-.26.11c-0.32.7-.62,1.41-0.93,2.15h7.26Zm-5.31-4.55h3.37L18.1,20.63Z M2.23,13.56A16,16,0,0,1,6.76,2.16a1.68,1.68,0,0,1,.8-0.46,1.06,1.06,0,0,1,1.18.59,1.16,1.16,0,0,1-.23,1.37A14.48,14.48,0,0,0,6.19,6.77a13.57,13.57,0,0,0,1.9,15.59l0.46,0.49a1.16,1.16,0,1,1-1.68,1.59,15.6,15.6,0,0,1-4.41-8.64C2.32,14.95,2.28,14.07,2.23,13.56Z M34,13.84a15.51,15.51,0,0,1-4.54,10.52,1.19,1.19,0,0,1-1.65.18,1.17,1.17,0,0,1,0-1.77,13.81,13.81,0,0,0,2.79-4.1,13.6,13.6,0,0,0-2.7-14.91A1.8,1.8,0,0,1,27.41,3,1.08,1.08,0,0,1,28,1.8,1.15,1.15,0,0,1,29.38,2a15.59,15.59,0,0,1,2.51,3.28A16.47,16.47,0,0,1,34,13.84Z M10.93,21.6A1.33,1.33,0,0,1,9.87,21a11.06,11.06,0,0,1-2.8-5.27A11.22,11.22,0,0,1,9.8,5.51l0.27-.28a1.16,1.16,0,1,1,1.64,1.63,8.62,8.62,0,0,0-2.06,3.22A8.87,8.87,0,0,0,11.18,19c0.18,0.23.4,0.44,0.59,0.66A1.13,1.13,0,0,1,11.95,21,1.08,1.08,0,0,1,10.93,21.6Z M29.47,13.57a11.11,11.11,0,0,1-3.27,7.64,1.18,1.18,0,0,1-1.51.21,1.13,1.13,0,0,1-.43-1.4,2.06,2.06,0,0,1,.39-0.54,8.85,8.85,0,0,0,2.49-5.89A9,9,0,0,0,24.64,7a1.85,1.85,0,0,1-.44-0.85A1,1,0,0,1,24.82,5a1.07,1.07,0,0,1,1.3.21,20.11,20.11,0,0,1,1.79,2.31A11.09,11.09,0,0,1,29.47,13.57Z M11.3,13.18a6.73,6.73,0,0,1,2-4.73,1.15,1.15,0,0,1,1.45-.2,1.12,1.12,0,0,1,.49,1.32,1.58,1.58,0,0,1-.33.53,4.49,4.49,0,0,0,0,6.26,1.16,1.16,0,1,1-1.7,1.57A6.81,6.81,0,0,1,11.3,13.18Z M24.94,13.14A6.9,6.9,0,0,1,23,18a1.16,1.16,0,1,1-1.7-1.58,4.5,4.5,0,0,0,0-6.29A1.16,1.16,0,1,1,23,8.5,6.75,6.75,0,0,1,24.94,13.14Z"}}),angular.module("xos.mcordTopology").service("NodeDrawer",["TopologyElements",function(t){var n=500,e=!1;this.drawFabricBox=function(t,n,r){if(!e){var a=t.append("g").attr({transform:"translate("+(n-25)+", "+(r-25)+")"});a.append("rect").attr({width:n+50,height:r+50,"class":"fabric-container"}),e=!0}},this.drawBbus=function(e){e.append("rect").attr({"class":function(t){return t.type},width:30,height:30,x:-15,y:-15,opacity:0}).transition().duration(n).attr({r:15,opacity:1}),e.append("path").attr({"class":function(t){return t.type+" antenna"},opacity:0,d:function(){return t.icons.bbu},transform:"translate(-18, -18)"}).transition().duration(n).attr({opacity:1}),e.append("text").attr({"text-anchor":"start",y:25,x:5,opacity:0}).text(function(t){return"vBBU "+t.name.substr(t.name.length-1,1)}).transition().duration(2*n).attr({opacity:1})},this.drawRrus=function(e){e.append("circle").attr({"class":function(t){return t.type+"-shadow"},r:0,opacity:0}).transition().duration(2*n).attr({r:40,opacity:1}),e.append("path").attr({"class":function(t){return t.type+" antenna"},opacity:0,d:function(){return t.icons.rru},transform:"translate(-18, -18)"}).transition().duration(n).attr({opacity:1})},this.drawFabric=function(e){e.append("rect").attr({width:30,height:30,x:-15,y:-15}),e.append("path").attr({"class":function(t){return t.type},opacity:0,d:function(){return t.icons["switch"]},transform:"translate(-22, -22), scale(0.4)"}).transition().duration(n).attr({opacity:1})},this.drawOthers=function(e){e.append("rect").attr({"class":function(t){return t.type},width:30,height:30,x:-15,y:-15,opacity:0}).transition().duration(n).attr({r:15,opacity:1}),e.append("path").attr({"class":function(t){return t.type+" antenna"},opacity:0,d:function(){return t.icons.bbu},transform:"translate(-18, -18)"}).transition().duration(n).attr({opacity:1}),e.append("text").attr({"text-anchor":"start",y:25,x:-12,opacity:0}).text(function(t){return t.name.toUpperCase()}).transition().duration(2*n).attr({opacity:1})},this.removeElements=function(t){t.transition().duration(n).attr({opacity:0}).remove()}}]),angular.module("xos.mcordTopology").run(["$location",function(t){t.path("/")}]);
diff --git a/xos/core/xoslib/static/js/xosOpenVPNDashboard.js b/xos/core/xoslib/static/js/xosOpenVPNDashboard.js
new file mode 100644
index 0000000..456dfcb
--- /dev/null
+++ b/xos/core/xoslib/static/js/xosOpenVPNDashboard.js
@@ -0,0 +1 @@
+"use strict";angular.module("xos.openVPNDashboard",["ngResource","ngCookies","ui.router","xos.helpers"]).config(["$stateProvider",function(n){n.state("openVPNList",{url:"/",template:"<vpn-list></vpn-list>"})}]).config(["$compileProvider",function(n){n.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|tel|file|blob):/)}]).service("Vpn",["$http","$q",function(n,t){this.getOpenVpnTenants=function(){var e=t.defer();return n.get("/api/tenant/openvpn/list/").then(function(n){e.resolve(n.data)})["catch"](function(n){e.reject(n)}),e.promise}}]).config(["$httpProvider",function(n){n.interceptors.push("NoHyperlinks")}]).directive("vpnList",function(){return{restrict:"E",scope:{},bindToController:!0,controllerAs:"vm",templateUrl:"templates/openvpn-list.tpl.html",controller:["Vpn",function(n){var t=this;n.getOpenVpnTenants().then(function(n){t.vpns=n;for(var e=0;e<t.vpns.length;e++){var i=new Blob([t.vpns[e].script_text],{type:"text/plain"});t.vpns[e].script_text=(window.URL||window.webkitURL).createObjectURL(i)}})["catch"](function(n){throw new Error(n)})}]}}),angular.module("xos.openVPNDashboard").run(["$templateCache",function(n){n.put("templates/openvpn-list.tpl.html",'<div style="display: table;">\n  <div class="vpn-row">\n    <h1 class="vpn-cell">VPN List</h1>\n  </div>\n  <div class="vpn-row">\n    <div class="vpn-cell vpn-header">ID</div>\n    <div class="vpn-cell vpn-header">VPN Network</div>\n    <div class="vpn-cell vpn-header">VPN Subnet</div>\n    <div class="vpn-cell vpn-header">Script Link</div>\n  </div>\n  <div class="vpn-row" ng-repeat="vpn in vm.vpns">\n    <div class="vpn-cell">{{ vpn.id }}</div>\n    <div class="vpn-cell">{{ vpn.server_network }}</div>\n    <div class="vpn-cell">{{ vpn.vpn_subnet }}</div>\n    <div class="vpn-cell">\n      <a download="connect-{{ vpn.id }}.vpn" ng-href="{{ vpn.script_text }}">Script</a>\n    </div>\n  </div>\n</div>\n'),n.put("templates/users-list.tpl.html",'<xos-table config="vm.tableConfig" data="vm.users"></xos-table>')}]),angular.module("xos.openVPNDashboard").run(["$location",function(n){n.path("/")}]);
\ No newline at end of file
diff --git a/xos/core/xoslib/static/js/xosServiceGrid.js b/xos/core/xoslib/static/js/xosServiceGrid.js
new file mode 100644
index 0000000..698d8ef
--- /dev/null
+++ b/xos/core/xoslib/static/js/xosServiceGrid.js
@@ -0,0 +1 @@
+"use strict";angular.module("xos.serviceGrid",["ngResource","ngCookies","ui.router","xos.helpers"]).config(["$stateProvider",function(e){e.state("serviceGrid",{url:"/",template:"<service-grid></service-grid>"}).state("serviceGraph",{url:"/graph",template:"<service-graph></service-graph>"})}]).config(["$httpProvider",function(e){e.interceptors.push("NoHyperlinks")}]).directive("serviceGrid",function(){return{restrict:"E",scope:{},bindToController:!0,controllerAs:"vm",templateUrl:"templates/service-grid.tpl.html",controller:["Services","_",function(e,t){var n=this;this.tableConfig={columns:[{label:"Status",prop:"status",type:"icon",formatter:function(e){var t=parseInt(e.backend_status.match(/^[0-9]/)[0]);switch(t){case 0:return"time";case 1:return"ok";case 2:return"remove"}}},{label:"Name",prop:"name",link:function(e){return""+e.view_url.replace(/\$[a-z]+\$/,e.id)}},{label:"Kind",prop:"kind"},{label:"Enabled",prop:"enabled",type:"boolean"}],filter:"field",order:{field:"name"}},e.query().$promise.then(function(e){n.services=t.map(e,function(e){return e.status=0!==parseInt(e.backend_status.match(/^[0-9]/)[0]),e})})["catch"](function(e){throw new Error(e)})}]}}),angular.module("xos.serviceGrid").run(["$templateCache",function(e){e.put("templates/service-graph.tpl.html",'<div class="row">\n  <div class="col-sm-10">\n    <h1>Graph</h1>\n    <ul>\n      <li>Use D3 to create a service chart based on coarse services?</li>\n    </ul>\n  </div>\n  <div class="col-sm-2">\n    <a href="/admin/core/service/add" class="btn btn-success btn-block">\n      <i class="glyphicon glyphicon-plus"></i>\n      Add Service\n    </a>\n    <a href="#/" class="btn btn-default btn-block">\n      Service List\n    </a>\n  </div>\n</div>'),e.put("templates/service-grid.tpl.html",'<div class="row">\n  <div class="col-md-10 table-responsive">\n    <xos-table config="vm.tableConfig" data="vm.services"></xos-table>\n  </div>\n  <div class="col-md-2">\n    <a href="/admin/core/service/add" class="btn btn-success btn-block">\n      <i class="glyphicon glyphicon-plus"></i>\n      Add Service\n    </a>\n    <!-- <a href="#/graph" class="btn btn-default btn-block">\n      Tenancy Graph\n    </a> -->\n  </div>\n</div>')}]),function(){angular.module("xos.serviceGrid").directive("serviceGraph",function(){return{restrict:"E",scope:{},bindToController:!0,controllerAs:"vm",templateUrl:"templates/service-graph.tpl.html",controller:["$element","GraphService",function(e,t){var n=void 0,r=e[0],i=void 0,s=void 0,a=function(e){i.attr({transform:function(e){return"translate("+e.x+", "+e.y+")"}}),s.attr("x1",function(e){return e.source.x}).attr("y1",function(e){return e.source.y}).attr("x2",function(e){return e.target.x}).attr("y2",function(e){return e.target.y})};t.loadCoarseData().then(function(e){e.tenants=e.tenants.map(function(e){return{source:e.provider_service,target:e.subscriber_service}}),e.services.push({name:"XOS","class":"xos",x:r.clientWidth/2,y:r.clientHeight/2,fixed:!0}),c(r);var t=d3.layout.force().nodes(e.services).links(e.tenants).charge(-1060).gravity(.1).linkDistance(200).size([r.clientWidth,r.clientHeight]).on("tick",a).start();s=n.selectAll(".link").data(e.tenants).enter().insert("line").attr("class","link"),i=n.selectAll(".node").data(e.services).enter().append("g").call(t.drag).on("mousedown",function(){d3.event.stopPropagation()}),i.append("circle").attr({"class":function(e){return"node "+(e["class"]||"")},r:10}),i.append("text").attr({"text-anchor":"middle"}).text(function(e){return e.name}),i.select("circle").attr({r:function(e){var t=d3.select(this).node().parentNode,n=d3.select(t).select("text").node().getBBox();return n.width/2+10}})});var c=function(e){d3.select(e).select("svg").remove(),n=d3.select(e).append("svg").style("width",e.clientWidth+"px").style("height",e.clientHeight+"px")}}]}})}(),angular.module("xos.serviceGrid").run(["$location",function(e){e.path("/")}]);
\ No newline at end of file
diff --git a/xos/core/xoslib/static/js/xosSubscribers.js b/xos/core/xoslib/static/js/xosSubscribers.js
new file mode 100644
index 0000000..21fa10c
--- /dev/null
+++ b/xos/core/xoslib/static/js/xosSubscribers.js
@@ -0,0 +1 @@
+"use strict";angular.module("xos.subscribers",["ngResource","ngCookies","ui.router","xos.helpers"]).config(["$stateProvider",function(s){s.state("user-list",{url:"/",template:"<subscribers-list></subscribers-list>"})}]).config(["$httpProvider",function(s){s.interceptors.push("NoHyperlinks")}]).directive("subscribersList",function(){return{restrict:"E",scope:{},bindToController:!0,controllerAs:"vm",templateUrl:"templates/subscribers-list.tpl.html",controller:function(){this.smartTableConfig={resource:"Subscribers"},this.model={label:{name:"aaa"},empty:{}},this.config={exclude:["password","last_login"],formName:"sampleForm",actions:[{label:"Save",icon:"ok",cb:function(s){console.log(s)},"class":"success"}]}}}}),angular.module("xos.subscribers").run(["$templateCache",function(s){s.put("templates/subscribers-list.tpl.html",'<!-- <xos-form ng-model="vm.model" config="vm.config"></xos-form> -->\n<xos-smart-table config="vm.smartTableConfig"></xos-smart-table>')}]),angular.module("xos.subscribers").run(["$location",function(s){s.path("/")}]);
\ No newline at end of file
diff --git a/xos/core/xoslib/static/js/xosSynchronizerNotifier.js b/xos/core/xoslib/static/js/xosSynchronizerNotifier.js
new file mode 100644
index 0000000..5d743c6
--- /dev/null
+++ b/xos/core/xoslib/static/js/xosSynchronizerNotifier.js
@@ -0,0 +1 @@
+"use strict";angular.module("xos.synchronizerNotifier",["ngResource","ngCookies","xos.helpers"]).run(["$rootScope",function(n){n.$on("$locationChangeStart",function(n){n.preventDefault()})}]).service("Diag",["$rootScope","$http","$q","$interval",function(n,t,s,e){var a=this,o=!1;this.getDiags=function(){var n=s.defer();return t.get("/api/core/diags").then(function(t){n.resolve(t.data)})["catch"](function(t){n.reject(t)}),n.promise},this.sendEvents=function(t){t.forEach(function(t){var s=JSON.parse(t.backend_register);s.last_run=new Date(1e3*s.last_run),s.last_duration=1e3*s.last_duration,s.last_synchronizer_start=new Date(1e3*s.last_synchronizer_start),s.last_syncrecord_start=s.last_syncrecord_start?new Date(1e3*s.last_syncrecord_start):null,n.$broadcast("diag",{name:t.name,updated:t.updated,info:s,status:a.getSyncStatus(s)})})},this.start=function(){return o=!0,a.getDiags().then(function(n){a.sendEvents(n)}),o},this.stop=function(){return o=!1},this.getSyncStatus=function(n){var t=new Date,s=9e5;return!(t-n.last_synchronizer_start>s&&t-n.last_syncrecord_start>s&&t-n.last_run>s)},e(function(){o&&a.getDiags().then(function(n){a.sendEvents(n)})},3e5)}]).directive("syncStatus",function(){return{restrict:"E",scope:{},bindToController:!0,controllerAs:"vm",templateUrl:"templates/sync-status.tpl.html",controller:["$log","$rootScope","Diag","xosNotification","XosUserPrefs",function(n,t,s,e,a){var o=this;s.start(),this.synchronizers={},this.showNoSync=!0,t.$on("diag",function(n,t){o.synchronizers[t.name]=t,t.status?a.setSynchronizerNotificationStatus(t.name,!1):(a.getSynchronizerNotificationStatus(t.name)||e.notify("CORD Synchronizer",{icon:"/static/cord-logo.png",body:"The "+t.name+" synchronizer has not performed actions in the last 15 minutes."}),a.setSynchronizerNotificationStatus(t.name,!0)),o.showNoSync=!1,0===Object.keys(o.synchronizers).length&&(o.showNoSync=!0)})}]}}),angular.element(document).ready(function(){angular.bootstrap("#xosSynchronizerNotifier",["xos.synchronizerNotifier"])}),angular.module("xos.synchronizerNotifier").run(["$templateCache",function(n){n.put("templates/sync-status.tpl.html",'<div class="sync-status-container">\n  <div class="btn btn-default" ng-click="vm.showNotificationPanel = !vm.showNotificationPanel">\n    <i class="glyphicon glyphicon-inbox"></i>\n  </div>\n  <div class="notification-panel panel panel-default" ng-show="vm.showNotificationPanel">\n    <ul class="list-group" ng-show="!vm.showNoSync">\n      <li class="list-group-item" ng-repeat="(syncName, syncStatus) in vm.synchronizers">\n        <span class="badge" ng-class="{success: syncStatus.status, warning: !syncStatus.status}">\n          <span ng-show="syncStatus.status"><i class="glyphicon glyphicon-ok"></i></span>\n          <span ng-hide="syncStatus.status"><i class="glyphicon glyphicon-time"></i></span>\n        </span>\n        <b>{{syncName}}</b>\n        <br/>\n        <small><i>{{syncStatus.info.last_run | date:\'mediumTime\'}}</i></small>\n      </li>\n    </ul>\n    <div class="alert alert-info" ng-show="vm.showNoSync">\n      No syncronizers are running.\n    </div>\n  </div>\n</div>\n')}]),angular.module("xos.synchronizerNotifier").run(["$location",function(n){n.path("/")}]);
\ No newline at end of file
diff --git a/xos/core/xoslib/static/js/xosTenant.js b/xos/core/xoslib/static/js/xosTenant.js
new file mode 100644
index 0000000..be4338c
--- /dev/null
+++ b/xos/core/xoslib/static/js/xosTenant.js
@@ -0,0 +1 @@
+"use strict";angular.module("xos.tenant",["ngResource","ngCookies","ui.router","xos.helpers"]).config(["$stateProvider",function(e){e.state("user-list",{url:"/",template:"<users-list></users-list>"}).state("site",{url:"/site/:id",template:"<site-detail></site-detail>"}).state("createslice",{url:"/site/:site/slice/:id?",template:"<create-slice></create-slice>"})}]).config(["$httpProvider",function(e){e.interceptors.push("NoHyperlinks")}]).directive("usersList",function(){return{restrict:"E",scope:{},bindToController:!0,controllerAs:"vm",templateUrl:"templates/users-list.tpl.html",controller:["Sites","SlicesPlus",function(e,t){var i=this;this.tableConfig={columns:[{label:"Site1",prop:"name",link:function(e){return"/#/site/"+e.id}},{label:"Allocated",prop:"instance_total"},{label:"Ready",prop:"instance_total_ready"}]},e.query().$promise.then(function(e){return i.sites=e,t.query().$promise}).then(function(e){i.slices=e,i.site_list=i.returnData(i.sites,i.slices)})["catch"](function(e){throw new Error(e)}),this.returnData=function(e,t){var i,s=0,l=[];for(i=0;i<e.length;i++){var n=0,a=0;for(s=0;s<t.length;s++)null!=e[i].id&&null!=t[s].site&&e[i].id===t[s].site&&(n+=t[s].instance_total,a+=t[s].instance_total_ready);var r={id:e[i].id,name:e[i].name,instance_total:n,instance_total_ready:a};l.push(r)}return l}}]}}).directive("siteDetail",function(){return{restrict:"E",scope:{},bindToController:!0,controllerAs:"sl",templateUrl:"templates/slicelist.html",controller:["SlicesPlus","$stateParams",function(e,t){var i=this;this.siteId=t.id,this.tableConfig={columns:[{label:"Slice List",prop:"name",link:function(e){return"/#/site/"+e.site+"/slice/"+e.id}},{label:"Allocated",prop:"instance_total"},{label:"Ready",prop:"instance_total_ready"}]},e.query({site:t.id}).$promise.then(function(e){i.sliceList=e})["catch"](function(e){throw new Error(e)})}]}}).directive("createSlice",function(){return{restrict:"E",scope:{},bindToController:!0,controllerAs:"cs",templateUrl:"templates/createslice.html",controller:["Slices","SlicesPlus","Sites","Images","$stateParams","$http","$state","$q",function(e,t,i,s,l,n,a,r){var o=this;this.config={exclude:["site","password","last_login","mount_data_sets","default_flavor","creator","exposed_ports","networks","omf_friendly","omf_friendly","no_sync","no_policy","lazy_blocked","write_protect","deleted","backend_status","backend_register","policed","enacted","updated","created","validators","humanReadableName"],formName:"SliceDetails",feedback:{show:!1,message:"Form submitted successfully !!!",type:"success"},actions:[{label:"Save",icon:"ok",cb:function(e,t){d(e,t).then(function(){a.go("site",{id:o.model.site})})},"class":"success"},{label:"Save and continue editing",icon:"ok",cb:function(e,t){d(e,t)},"class":"primary"},{label:"Save and add another",icon:"ok",cb:function(e,t){d(e,t).then(function(){a.go("createslice",{site:o.model.site,id:""})})},"class":"primary"}],fields:{site:{label:"Site",type:"select",validators:{required:!0},hint:"The Site this Slice belongs to",options:[]},name:{label:"Name",type:"string",hint:"The Name of the Slice",validators:{required:!0}},serviceClass:{label:"ServiceClass",type:"select",validators:{required:!0},hint:"The Site this Slice belongs to",options:[{id:1,label:"Best effort"}]},enabled:{label:"Enabled",type:"boolean",hint:"Status for this Slice"},description:{label:"Description",type:"string",hint:"High level description of the slice and expected activities",validators:{required:!1,minlength:10}},service:{label:"Service",type:"select",validators:{required:!1},options:[{id:0,label:"--------"}]},slice_url:{label:"Slice url",type:"string",validators:{required:!1,minlength:10}},max_instances:{label:"Max Instances",type:"number",validators:{required:!1,min:0}},default_isolation:{label:"Default Isolation",type:"select",validators:{required:!1},options:[{id:"vm",label:"Virtual Machine"},{id:"container",label:"Container"},{id:"container_vm",label:"Container in VM"}]},default_image:{label:"Default image",type:"select",validators:{required:!1},options:[]},network:{label:"Network",type:"select",validators:{required:!1},options:[{id:"default",label:"Default"},{id:"host",label:"Host"},{id:"bridged",label:"Bridged"},{id:"noauto",label:"No Automatic Networks"}]}}};var c;s.query().$promise.then(function(e){o.users=e,c=o.users,o.optionValImg=o.setData(c,{field1:"id",field2:"name"}),o.config.fields.default_image.options=o.optionValImg})["catch"](function(e){throw new Error(e)}),this.setData=function(e,t){var i,s=[];for(i=0;i<e.length;i++){var l={id:e[i][t.field1],label:e[i][t.field2]};s.push(l)}return s},l.id?(delete this.config.fields.site,this.config.exclude.push("site"),e.get({id:l.id}).$promise.then(function(e){o.users=e,c=e,o.model=c})["catch"](function(e){throw new Error(e)})):(this.model={},n.get("/xoslib/tenantview/").success(function(e){o.userList=e,o.model.creator=o.userList.current_user_id}),i.query().$promise.then(function(e){o.users_site=e,o.optionVal=o.setData(o.users_site,{field1:"id",field2:"name"}),o.config.fields.site.options=o.optionVal})["catch"](function(e){throw new Error(e)}));var d=function(t,i){var s=r.defer();if(delete t.networks,i.$valid){if(t.id)var l=e.update(t).$promise;else var l=e.save(t).$promise;l.then(function(e){o.model=e,o.config.feedback.show=!0,s.resolve(o.model)})["catch"](function(e){o.config.feedback.show=!0,o.config.feedback.type="danger",e.data&&e.data.detail?o.config.feedback.message=e.data.detail:o.config.feedback.message=e.statusText,s.reject(e)})}return s.promise}}]}}),angular.module("xos.tenant").run(["$templateCache",function(e){e.put("templates/createslice.html",'<!--<xos-table config="cs.tableConfig" data="cs.sites"></xos-table>-->\r\n<h2>Slice Details</h2>\r\n<hr></hr>\r\n<xos-form ng-model="cs.model" config="cs.config" ></xos-form>\r\n\r\n<!--<pre>-->\r\n<!--&lt;!&ndash;{{cs.users | json}}&ndash;&gt;-->\r\n\r\n<!--{{cs.users.name | json}}-->\r\n\r\n<!--</pre>-->'),e.put("templates/slicelist.html",'<!--<span ng-bind="siteNameSe"></span>-->\r\n<!--<xos-field></xos-field>-->\r\n<a class="addlink btn btn-info" ui-sref="createslice({site: sl.siteId})"><i class="glyphicon glyphicon-plus-sign"></i> Create Slice</a>\r\n<xos-table config="sl.tableConfig" data="sl.sliceList"></xos-table>\r\n<!--<div ui-view="sliceDetails"></div>-->\r\n<!--<pre>{{sl.users[0].site}}</pre>-->\r\n'),e.put("templates/users-list.tpl.html",'<xos-table config="vm.tableConfig" data="vm.site_list"></xos-table>')}]),angular.module("xos.tenant").run(["$location",function(e){e.path("/")}]);
diff --git a/xos/core/xoslib/static/js/xosTruckroll.js b/xos/core/xoslib/static/js/xosTruckroll.js
new file mode 100644
index 0000000..f6bc6dd
--- /dev/null
+++ b/xos/core/xoslib/static/js/xosTruckroll.js
@@ -0,0 +1 @@
+"use strict";angular.module("xos.truckroll",["ngResource","ngCookies","ui.router","xos.helpers"]).config(["$stateProvider",function(l){l.state("user-list",{url:"/",template:"<truckroll></truckroll>"})}]).config(["$httpProvider",function(l){l.interceptors.push("NoHyperlinks")}]).directive("truckroll",function(){return{restrict:"E",scope:{},bindToController:!0,controllerAs:"vm",templateUrl:"templates/truckroll.tpl.html",controller:["$timeout","$log","Subscribers","Truckroll",function(l,n,t,s){var r=this;t.query().$promise.then(function(l){r.subscribers=l}),this.loader=!1,this.runTest=function(){delete r.truckroll.result,delete r.truckroll.is_synced,delete r.truckroll.result_code,delete r.truckroll.backend_status;var l=new s(r.truckroll);r.loader=!0,l.$save().then(function(l){r.waitForTest(l.id)})},this.waitForTest=function(n){s.get({id:n}).$promise.then(function(t){t.backend_status.indexOf("2")>=0||t.result_code&&t.result_code.indexOf("2")>=0||t.is_synced?(r.truckroll=angular.copy(t),r.loader=!1,s["delete"]({id:n})):l(function(){r.waitForTest(n)},2e3)})}}]}}),angular.module("xos.truckroll").run(["$templateCache",function(l){l.put("templates/truckroll.tpl.html",'<div class="row">\n  <div class="col-xs-12">\n    <h2>Virtual Truck Roll</h2>\n    <p>Use this page to run test against your subscriber</p>\n  </div>\n</div>\n<form ng-submit="vm.runTest()">\n  <div class="row">\n    <div class="col-xs-12">\n      <label>Target:</label>\n    </div>\n    <div class="col-xs-12">\n      <select class="form-control" ng-model="vm.truckroll.target_id" ng-options="s.id as s.humanReadableName for s in vm.subscribers"></select>\n    </div>\n  </div>\n  <div class="row">\n    <div class="col-xs-12">\n      <label>Scope:</label>\n    </div>\n    <div class="col-xs-6">\n      <a \n      ng-click="vm.truckroll.scope = \'container\'"\n      ng-class="{\'btn-default\': vm.truckroll.scope !== \'container\', \'btn-primary\': vm.truckroll.scope === \'container\'}"\n      class="btn btn-block"\n      >\n        Container\n      </a>\n    </div>\n    <div class="col-xs-6">\n      <a \n      ng-click="vm.truckroll.scope = \'vm\'"\n      ng-class="{\'btn-default\': vm.truckroll.scope !== \'vm\', \'btn-primary\': vm.truckroll.scope === \'vm\'}"\n      class="btn btn-block"\n      >\n        VM\n      </a>\n    </div>\n  </div>\n  <div class="row">\n    <div class="col-xs-12">\n      <label>Test:</label>\n    </div>\n    <div class="col-xs-4">\n      <a \n      ng-click="vm.truckroll.test = \'ping\'"\n      ng-class="{\'btn-default\': vm.truckroll.test !== \'ping\', \'btn-primary\': vm.truckroll.test === \'ping\'}"\n      class="btn btn-block">Ping</a>\n    </div>\n    <div class="col-xs-4">\n      <a \n      ng-click="vm.truckroll.test = \'traceroute\'"\n      ng-class="{\'btn-default\': vm.truckroll.test !== \'traceroute\', \'btn-primary\': vm.truckroll.test === \'traceroute\'}"\n      class="btn btn-block">Traceroute</a>\n    </div>\n    <div class="col-xs-4">\n      <a \n      ng-click="vm.truckroll.test = \'tcpdump\'"\n      ng-class="{\'btn-default\': vm.truckroll.test !== \'tcpdump\', \'btn-primary\': vm.truckroll.test === \'tcpdump\'}"\n      class="btn btn-block">Tcp Dump</a>\n    </div>\n  </div>\n  <div class="row">\n    <div class="col-xs-12">\n      <label>Argument:</label>\n    </div>\n    <div class="col-xs-12">\n      <input type="text" class="form-control" ng-model="vm.truckroll.argument" required />\n    </div>\n  </div>\n  <div class="row">\n    <div class="col-xs-12" ng-show="!vm.loader">\n      <button class="btn btn-success btn-block">Run test</button>\n    </div>\n  </div>\n</form>\n<div class="row">\n    <div class="col-xs-12 animate-vertical" ng-show="vm.loader">\n      <div class="loader"></div>\n    </div>\n  </div>\n  <div class="row" ng-hide="!vm.truckroll.result_code">\n    <div class="col-xs-12">\n      <label>Result Code</label>\n    </div>\n    <div class="col-xs-12">\n      <pre>{{vm.truckroll.result_code}}</pre>\n    </div>\n  </div>\n  <div class="row" ng-hide="!vm.truckroll.result">\n    <div class="col-xs-12">\n      <label>\n        Result:\n      </label>\n    </div>\n    <div class="col-xs-12">\n      <pre>{{vm.truckroll.result}}</pre>\n    </div>\n  </div>\n  <div class="row" ng-hide="!vm.truckroll.backend_status">\n    <div class="col-xs-12">\n      <label>Backend Status</label>\n    </div>\n    <div class="col-xs-12">\n      <pre>{{vm.truckroll.backend_status}}</pre>\n    </div>\n  </div>'),l.put("templates/users-list.tpl.html",'<xos-table config="vm.tableConfig" data="vm.users"></xos-table>')}]),angular.module("xos.truckroll").run(["$location",function(l){l.path("/")}]);
\ No newline at end of file
diff --git a/xos/core/xoslib/static/js/xoslib/xos-backbone.js b/xos/core/xoslib/static/js/xoslib/xos-backbone.js
new file mode 100644
index 0000000..d22d0ec
--- /dev/null
+++ b/xos/core/xoslib/static/js/xoslib/xos-backbone.js
@@ -0,0 +1,905 @@
+
+/* eslint-disable*/
+if (! window.XOSLIB_LOADED) {
+    window.XOSLIB_LOADED=true;
+
+    XOS_BASE = "/xos";
+
+    SLIVER_API = XOS_BASE+"/instances/";
+    SLICE_API = XOS_BASE+"/slices/";
+    SLICEROLE_API = XOS_BASE+"/slice_roles/";
+    NODE_API = XOS_BASE+"/nodes/";
+    SITE_API = XOS_BASE+"/sites/";
+    SITEDEPLOYMENT_API = XOS_BASE+"/sitedeployments/";
+    USER_API = XOS_BASE+"/users/";
+    USERDEPLOYMENT_API = XOS_BASE+"/user_deployments/";
+    DEPLOYMENT_API = XOS_BASE+"/deployments/";
+    IMAGE_API = XOS_BASE+"/images/";
+    IMAGEDEPLOYMENTS_API = XOS_BASE+"/imagedeployments/";
+    NETWORKTEMPLATE_API = XOS_BASE+"/networktemplates/";
+    NETWORK_API = XOS_BASE+"/networks/";
+    PORT_API = XOS_BASE+"/ports/";
+    SERVICE_API = XOS_BASE+"/services/";
+    SLICEPRIVILEGE_API = XOS_BASE+"/slice_privileges/";
+    NETWORKDEPLOYMENT_API = XOS_BASE+"/networkdeployments/";
+    FLAVOR_API = XOS_BASE+"/flavors/";
+    CONTROLLER_API = XOS_BASE+"/controllers/";
+
+    CONTROLLERIMAGE_API = XOS_BASE+"/controllerimages/";
+    CONTROLLERNETWORK_API = XOS_BASE+"/controllernetworks/";
+    CONTROLLERSLICE_API = XOS_BASE+"/controllerslices/";
+    CONTROLLERUSER_API = XOS_BASE+"/controllerusers/";
+
+    SLICEDEPLOYMENT_API = XOS_BASE+"/slicedeployments/";
+    USERDEPLOYMENT_API = XOS_BASE+"/userdeployments/";
+
+    XOSLIB_BASE = "/xoslib";
+
+    SLICEPLUS_API = XOSLIB_BASE + "/slicesplus/";
+    TENANTVIEW_API = XOSLIB_BASE + "/tenantview/";
+    HPCVIEW_API = XOSLIB_BASE + "/hpcview/";
+
+    CORDSUBSCRIBER_API = XOSLIB_BASE + "/cordsubscriber/";
+    CORDUSER_API = XOSLIB_BASE + "/corduser/";
+
+    XOSModel = Backbone.Model.extend({
+        relatedCollections: [],
+        foreignCollections: [],
+        foreignFields: {},
+        m2mFields: {},
+        readonlyFields: [],
+        detailLinkFields: [],
+
+        /* from backbone-tastypie.js */
+        //idAttribute: 'resource_uri',
+
+        /* from backbone-tastypie.js */
+        url: function() {
+            // TODO handle error if no property
+            var url = this.attributes.resource_uri;
+
+            if (!url) {
+                if (this.id) {
+                    url = this.urlRoot + this.id;
+                }
+                else {
+                    // this happens when creating a new model.
+                    url = this.urlRoot;
+                }
+            }
+
+            if (!url) {
+                // XXX I'm not sure this does anything useful
+                url = _.isFunction(this.collection.url) ? this.collection.url() : this.collection.url;
+                url = url || this.urlRoot;
+            }
+
+            // remove any existing query parameters
+            url && url.indexOf("?") > -1  && (url = url.split("?")[0]);
+
+            url && ( url += ( url.length > 0 && url.charAt( url.length - 1 ) === '/' ) ? '' : '/' );
+
+            url && ( url += "?no_hyperlinks=1" );
+
+            return url;
+        },
+
+        listMethods: function() {
+            var res = [];
+            for(var m in this) {
+                if(typeof this[m] == "function") {
+                    res.push(m)
+                }
+            }
+            return res;
+        },
+
+        save: function(attributes, options) {
+            if (this.preSave) {
+                this.preSave();
+            }
+            return Backbone.Model.prototype.save.call(this, attributes, options);
+        },
+
+        getChoices: function(fieldName, excludeChosen) {
+            choices=[];
+
+            if (fieldName in this.m2mFields) {
+                for (index in xos[this.m2mFields[fieldName]].models) {
+                    candidate = xos[this.m2mFields[fieldName]].models[index];
+                    if (excludeChosen && idInArray(candidate.id, this.attributes[fieldName])) {
+                        continue;
+                    }
+                    choices.push(candidate.id);
+                }
+            }
+            return choices;
+        },
+
+        /* If a 'validate' method is supplied, then it will be called
+           automatically on save. Unfortunately, save calls neither the
+           'error' nor the 'success' callback if the validator fails.
+
+           For now, we're calling our validator 'xosValidate' so this
+           autoamtic validation doesn't occur.
+        */
+
+        /**
+        * This should call custom validators defined in the model
+        *
+        * @param {object} attrs an object containin the model attributes
+        * @param {object} options (unused)
+        * @returns {Array} Errors list
+        */
+        xosValidate: function(attrs, options) {
+            errors = {};
+            foundErrors = false;
+
+            _.each(this.validators, function(validatorList, fieldName) {
+                _.each(validatorList, function(validator) {
+                    if (fieldName in attrs) {
+                        // call validateField method in xos-utils.js
+                        validatorResult = validateField(validator, attrs[fieldName], this);
+                        if (validatorResult != true) {
+                            errors[fieldName] = validatorResult;
+                            foundErrors = true;
+                        }
+                    }
+                });
+            });
+            if (foundErrors) {
+                return errors;
+            }
+            // backbone.js semantics -- on successful validate, return nothing
+        },
+
+        /* uncommenting this would make validate() call xosValidate()
+        validate: function(attrs, options) {
+            r = this.xosValidate(attrs, options);
+            console.log("validate");
+            console.log(r);
+            return r;
+        }, */
+    });
+
+    XOSCollection = Backbone.Collection.extend({
+        objects: function() {
+            return this.models.map(function(element) {
+                return element.attributes;
+            });
+        },
+
+        initialize: function() {
+            this.isLoaded = false;
+            this.failedLoad = false;
+            this.startedLoad = false;
+            this.sortVar = 'name';
+            this.sortOrder = 'asc';
+            this.on('sort', this.sorted);
+        },
+
+        relatedCollections: [],
+        foreignCollections: [],
+        foreignFields: {},
+        m2mFields: {},
+        readonlyFields: [],
+        detailLinkFields: [],
+
+        sorted: function() {
+            //console.log("sorted " + this.modelName);
+        },
+
+        simpleComparator: function(model) {
+            parts=this.sortVar.split(".");
+            result = model.get(parts[0]);
+            for (index=1; index<parts.length; ++index) {
+                result=result[parts[index]];
+            }
+            return result;
+        },
+
+        comparator: function(left, right) {
+            var l = this.simpleComparator(left);
+            var r = this.simpleComparator(right);
+
+            if (l === void 0) {
+                return -1;
+            }
+            if (r === void 0) {
+                return 1;
+            }
+
+            if (this.sortOrder == "desc") {
+                return l < r ? 1 : l > r ? -1 : 0;
+            }
+            else {
+                return l < r ? -1 : l > r ? 1 : 0;
+            }
+        },
+
+        fetchSuccess: function(collection, response, options) {
+            //console.log("fetch succeeded " + collection.modelName);
+            this.failedLoad = false;
+            this.fetching = false;
+            if (!this.isLoaded) {
+                this.isLoaded = true;
+                Backbone.trigger("xoslib:collectionLoadChange", this);
+            }
+            this.trigger("fetchStateChange");
+            if (options["orig_success"]) {
+                options["orig_success"](collection, response, options);
+            }
+        },
+
+        fetchFailure: function(collection, response, options) {
+            //console.log("fetch failed " + collection.modelName);
+            this.fetching = false;
+            if (!this.isLoaded && !this.failedLoad) {
+                this.failedLoad=true;
+                Backbone.trigger("xoslib:collectionLoadChange", this);
+            }
+            this.trigger("fetchStateChange");
+            if (options["orig_failure"]) {
+                options["orig_failure"](collection, response, options);
+            }
+        },
+
+        fetch: function(options) {
+            var self=this;
+
+            this.fetching=true;
+            //console.log("fetch " + this.modelName);
+            if (!this.startedLoad) {
+                this.startedLoad=true;
+                Backbone.trigger("xoslib:collectionLoadChange", this);
+            }
+            this.trigger("fetchStateChange");
+            if (options == undefined) {
+                options = {};
+            }
+            options["orig_success"] = options["success"];
+            options["orig_failure"] = options["failure"];
+            options["success"] = function(collection, response, options) {
+                self.fetchSuccess.call(self, collection, response, options);
+            };
+            options["failure"] = this.fetchFailure;
+            Backbone.Collection.prototype.fetch.call(this, options);
+        },
+
+        startPolling: function() {
+            if (!this._polling) {
+                var collection=this;
+
+                setInterval(function() {
+                    collection.fetch();
+                }, 10000);
+                this._polling=true;
+                this.fetch();
+            }
+        },
+
+        refresh: function(refreshRelated) {
+            if (!this.fetching) {
+                this.fetch();
+            }
+            if (refreshRelated) {
+                for (related in this.relatedCollections) {
+                    related = xos[related];
+                    if (!related.fetching) {
+                        related.fetch();
+                    }
+                }
+            }
+        },
+
+        maybeFetch: function(options){
+                // Helper function to fetch only if this collection has not been fetched before.
+            if(this._fetched){
+                    // If this has already been fetched, call the success, if it exists
+                options.success && options.success();
+                console.log("alreadyFetched");
+                return;
+            }
+
+                // when the original success function completes mark this collection as fetched
+            var self = this;
+            var successWrapper = function(success){
+                return function(){
+                    self._fetched = true;
+                    success && success.apply(this, arguments);
+                };
+            };
+            options.success = successWrapper(options.success);
+            console.log("call fetch");
+            this.fetch(options);
+        },
+
+        getOrFetch: function(id, options){
+                // Helper function to use this collection as a cache for models on the server
+            var model = this.get(id);
+
+            if(model){
+                options.success && options.success(model);
+                return;
+            }
+
+            model = new this.model({
+                resource_uri: id
+            });
+
+            model.fetch(options);
+        },
+
+        /* filterBy: note that this yields a new collection. If you pass that
+              collection to a CompositeView, then the CompositeView won't get
+              any events that trigger on the original collection.
+
+              Using this function is probably wrong, and I wrote
+              FilteredCompositeView() to replace it.
+        */
+
+        filterBy: function(fieldName, value) {
+            filtered = this.filter(function(obj) {
+                return obj.get(fieldName) == value;
+                });
+            return new this.constructor(filtered);
+        },
+
+        /* from backbone-tastypie.js */
+        url: function( models ) {
+            var url = this.urlRoot || ( models && models.length && models[0].urlRoot );
+            url && ( url += ( url.length > 0 && url.charAt( url.length - 1 ) === '/' ) ? '' : '/' );
+
+            url && ( url += "?no_hyperlinks=1" );
+
+            if (this.currentUserCanSee) {
+                url && ( url += "&current_user_can_see=1" );
+            }
+
+            return url;
+        },
+
+        listMethods: function() {
+            var res = [];
+            for(var m in this) {
+                if(typeof this[m] == "function") {
+                    res.push(m)
+                }
+            }
+            return res;
+        },
+    });
+
+    function get_defaults(modelName) {
+        if ((typeof xosdefaults !== "undefined") && xosdefaults[modelName]) {
+            return xosdefaults[modelName];
+        }
+        return undefined;
+    }
+
+    function extend_defaults(modelName, stuff) {
+        defaults = get_defaults(modelName);
+        if (defaults) {
+            return $.extend({}, defaults, stuff);
+        } else {
+            return stuff;
+        }
+    }
+
+    /**
+    * This is an helper function to define XOS model.
+    *
+    * @param {object} lib A backbone collection library (eg: xos)
+    * @param {object} attrs The model attributes
+    * @param {string} attrs.modelName The name of the model
+    * @param {string} attrs.urlRoot The base url for the collection
+    * @param {object} [attrs.relatedCollections] collections which should be drawn as an inline 
+                                                 list when the detail view is displayed. 
+                                                 Format: **collection:collectionFieldName** 
+                                                 where **collectionFieldName** is the name of the field 
+                                                 in the collection that points back to the collection 
+                                                 in the detail view.
+    * @param {array} [attrs.foreignCollections] collections which are used in idToName() calls
+                                when presenting the data to the user. Used to
+                                create a listento event. Somewhat
+                                redundant with foreignFields.
+    * @param {object} [attrs.foreignFields] **localFieldName:collection**. Used to
+                                automatically map ids into humanReadableNames
+                                when presenting data to the user.
+    * @param {object} [attrs.m2mFields] **localFieldName:collection**. Used to
+                                populate choices in picker lists. Similar to
+                                foreignFields.
+    * @param {Array} [attrs.listFields] Fields to display in lists
+    * @param {Array} {attrs.detailFields} Fields to display in detail views
+    * @param {Array} [attrs.addFields] Fields to display in popup add windows
+    * @param {Object} [attrs.inputType] by default, "detailFields" will be displayed
+                                as text input controls. This will let you display
+                                a checkbox or a picker instead.
+    * @param {Object} [attrs.defaults] Override the model defaults, `extend_defaults` can be used.
+    * @param {Object} [attrs.validators] Add validators to this model. Use `validateField` method in xos-util.js
+    * @param {function} [attrs.preSave] A pre-save method
+    * @param {function} [attrs.xosValidate] Override the default xosValidate.
+    *                                       If you want to call it either start the function with
+    *                                       `errors = XOSModel.prototype.xosValidate.call(this, attrs, options);`
+    * @returns void
+    */
+
+    function define_model(lib, attrs) {
+
+        // NOTE shouldn't we trhow an error if no:
+        // - attrs.urlRoot
+        // - attrs.modelName
+
+        modelName = attrs.modelName;
+        modelClassName = modelName;
+        collectionClass = attrs.collectionClass || XOSCollection;
+        collectionClassName = modelName + "Collection";
+
+        if (!attrs.addFields) {
+            attrs.addFields = attrs.detailFields;
+        }
+
+        attrs.inputType = attrs.inputType || {};
+        attrs.foreignFields = attrs.foreignFields || {};
+        // NOTE m2mFields are not set in modelAttr,
+        // see list in for loop
+        attrs.m2mFields = attrs.m2mFields || {};
+        attrs.readOnlyFields = attrs.readOnlyFields || [];
+        attrs.detailLinkFields = attrs.detailLinkFields || ["id","name"];
+
+        if (!attrs.collectionName) {
+            attrs.collectionName = modelName + "s";
+        }
+        collectionName = attrs.collectionName;
+
+        modelAttrs = {}
+        collectionAttrs = {}
+
+        for (key in attrs) {
+            value = attrs[key];
+            if ($.inArray(key, ["urlRoot", "modelName", "collectionName", "listFields", "addFields", "detailFields", "detailLinkFields", "foreignFields", "inputType", "relatedCollections", "foreignCollections", "defaults", "disableAdd"])>=0) {
+                modelAttrs[key] = value;
+                collectionAttrs[key] = value;
+            }
+            // NOTE xosValidate added by Matteo Scandolo
+            // check with Scott
+            if ($.inArray(key, ["validate", "preSave", "readOnlyFields", "xosValidate", "m2mFields"]) >= 0) {
+                modelAttrs[key] = value;
+            }
+        }
+
+        if (!modelAttrs.defaults) {
+            modelAttrs.defaults = get_defaults(modelName);
+        }
+
+        // if there are default validators for this model
+        // extend with customs
+        if ((typeof xosvalidators !== "undefined") && xosvalidators[modelName]) {
+            modelAttrs["validators"] = $.extend({}, xosvalidators[modelName], attrs["validators"] || {});
+        }
+        // else use custom
+        else if (attrs["validators"]) {
+            modelAttrs["validators"] = attrs["validators"];
+            // console.log(attrs);
+            // console.log(modelAttrs);
+        }
+        // NOTE Why define validators in multiple places?
+
+        lib[modelName] = XOSModel.extend(modelAttrs);
+
+        collectionAttrs["model"] = lib[modelName];
+
+        lib[collectionClassName] = collectionClass.extend(collectionAttrs);
+        lib[collectionName] = new lib[collectionClassName]();
+
+        lib.allCollectionNames.push(collectionName);
+        lib.allCollections.push(lib[collectionName]);
+    };
+
+    function xoslib() {
+        this.allCollectionNames = [];
+        this.allCollections = [];
+
+        /* Give an id, the name of a collection, and the name of a field for models
+           within that collection, lookup the id and return the value of the field.
+        */
+
+        this.idToName = function(id, collectionName, fieldName) {
+            linkedObject = xos[collectionName].get(id);
+            if (linkedObject == undefined) {
+                return "#" + id;
+            } else {
+                return linkedObject.attributes[fieldName];
+            }
+        };
+
+        /* defining the models
+
+           modelName          - name of the model.
+
+           relatedCollections - collections which should be drawn as an inline
+                                list when the detail view is displayed.
+                                Format: <collection>:<collectionFieldName> where
+                                <collectionFieldName> is the name of the field
+                                in the collection that points back to the
+                                collection in the detail view.
+
+           foreignCollections - collections which are used in idToName() calls
+                                when presenting the data to the user. Used to
+                                create a listento event. Somewhat
+                                redundant with foreignFields.
+
+           foreignFields -      <localFieldName>:<collection>. Used to
+                                automatically map ids into humanReadableNames
+                                when presenting data to the user.
+
+           m2mfields -          <localFieldName>:<colleciton>. Used to
+                                populate choices in picker lists. Simalar to
+                                foreignFields.
+
+           listFields -         fields to display in lists
+
+           detailFields -       fields to display in detail views
+
+           addFields -          fields to display in popup add windows
+
+           inputType -          by default, "detailFields" will be displayed
+                                as text input controls. This will let you display
+                                a checkbox or a picker instead.
+        */
+
+        define_model(this, {urlRoot: SLIVER_API,
+                            relatedCollections: {"ports": "instance"},
+                            foreignCollections: ["slices", "deployments", "images", "nodes", "users", "flavors"],
+                            foreignFields: {"creator": "users", "image": "images", "node": "nodes", "deployment": "deployments", "slice": "slices", "flavor": "flavors"},
+                            modelName: "instance",
+                            listFields: ["backend_status", "id", "name", "instance_id", "instance_name", "slice", "deployment", "image", "node", "flavor"],
+                            addFields: ["slice", "deployment", "flavor", "image", "node"],
+                            detailFields: ["backend_status", "backend_register", "name", "instance_id", "instance_name", "slice", "deployment", "flavor", "image", "node", "creator"],
+                            preSave: function() { if (!this.attributes.name && this.attributes.slice) { this.attributes.name = xos.idToName(this.attributes.slice, "slices", "name"); } },
+                            });
+
+        define_model(this, {urlRoot: SLICE_API,
+                            relatedCollections: {"instances": "slice", "slicePrivileges": "slice", "networks": "owner", "controller_slices": "slice"},
+                            foreignCollections: ["services", "sites"],
+                            foreignFields: {"service": "services", "site": "sites"},
+                            listFields: ["backend_status", "id", "name", "enabled", "description", "slice_url", "site", "max_instances", "service"],
+                            detailFields: ["backend_status", "backend_register", "name", "site", "enabled", "description", "slice_url", "max_instances"],
+                            inputType: {"enabled": "checkbox"},
+                            modelName: "slice",
+                            xosValidate: function(attrs, options) {
+                                errors = XOSModel.prototype.xosValidate.call(this, attrs, options);
+                                // validate that slice.name starts with site.login_base
+                                site = attrs.site || this.site;
+                                console.log('Slice Validate!!!', site);
+                                if ((site!=undefined) && (attrs.name!=undefined)) {
+                                    site = xos.sites.get(site);
+                                    if (attrs.name.indexOf(site.attributes.login_base+"_") != 0) {
+                                        errors = errors || {};
+                                        errors["name"] = "must start with " + site.attributes.login_base + "_";
+                                    }
+
+                                    if(attrs.name.indexOf(' ') >= 0){
+                                        errors = errors || {};
+                                        errors["name"] = "must not contain spaces";   
+                                    }
+                                }
+                                return errors;
+                            },
+                        });
+
+        define_model(this, {urlRoot: SLICEPRIVILEGE_API,
+                            foreignCollections: ["slices", "users", "sliceRoles"],
+                            modelName: "slicePrivilege",
+                            foreignFields: {"user": "users", "slice": "slices", "role": "sliceRoles"},
+                            listFields: ["backend_status", "id", "user", "slice", "role"],
+                            detailFields: ["backend_status", "backend_register", "user", "slice", "role"],
+                            });
+
+        define_model(this, {urlRoot: SLICEROLE_API,
+                            modelName: "sliceRole",
+                            listFields: ["backend_status", "id", "role"],
+                            detailFields: ["backend_status", "backend_register", "role"],
+                            });
+
+        define_model(this, {urlRoot: NODE_API,
+                            foreignCollections: ["sites", "deployments"],
+                            modelName: "node",
+                            foreignFields: {"site": "sites", "deployment": "deployments"},
+                            listFields: ["backend_status", "id", "name", "site", "deployment"],
+                            detailFields: ["backend_status", "backend_register", "name", "site", "deployment"],
+                            });
+
+        define_model(this, {urlRoot: SITE_API,
+                            relatedCollections: {"users": "site", "slices": "site", "nodes": "site", "siteDeployments": "site"},
+                            modelName: "site",
+                            listFields: ["backend_status", "id", "name", "site_url", "enabled", "login_base", "is_public", "abbreviated_name"],
+                            detailFields: ["backend_status", "backend_register", "name", "abbreviated_name", "url", "enabled", "is_public", "login_base"],
+                            inputType: {"enabled": "checkbox", "is_public": "checkbox"},
+                            });
+
+        define_model(this, {urlRoot: SITEDEPLOYMENT_API,
+                            foreignCollections: ["sites", "deployments", "controllers"],
+                            foreignFields: {"site": "sites", "deployment": "deployments", "controller": "controllers"},
+                            modelName: "siteDeployment",
+                            listFields: ["backend_status", "id", "site", "deployment", "controller", "availability_zone"],
+                            detailFields: ["backend_status", "backend_register", "site", "deployment", "controller", "availability_zone"],
+                            inputType: {"enabled": "checkbox", "is_public": "checkbox"},
+                            });
+
+        define_model(this, {urlRoot: USER_API,
+                            relatedCollections: {"slicePrivileges": "user", "slices": "owner", "controller_users": "user"},
+                            foreignCollections: ["sites"],
+                            modelName: "user",
+                            foreignFields: {"site": "sites"},
+                            listFields: ["backend_status", "id", "username", "firstname", "lastname", "phone", "user_url", "site"],
+                            detailFields: ["backend_status", "backend_register", "username", "firstname", "lastname", "phone", "user_url", "site"],
+                            });
+
+        define_model(this, { urlRoot: DEPLOYMENT_API,
+                             relatedCollections: {"nodes": "deployment", "instances": "deployment"},
+                             m2mFields: {"flavors": "flavors", "sites": "sites", "images": "images"},
+                             modelName: "deployment",
+                             listFields: ["backend_status", "id", "name", "backend_type", "admin_tenant"],
+                             detailFields: ["backend_status", "backend_register", "name", "backend_type", "admin_tenant", "flavors", "sites", "images"],
+                             inputType: {"flavors": "picker", "sites": "picker", "images": "picker"},
+                             });
+
+        define_model(this, {urlRoot: IMAGE_API,
+                            relatedCollections: {"controller_images": "image"},
+                            model: this.image,
+                            modelName: "image",
+                            listFields: ["backend_status", "id", "name", "disk_format", "container_format", "path"],
+                            detailFields: ["backend_status", "backend_register", "name", "disk_format", "admin_tenant"],
+                            });
+
+        define_model(this, {urlRoot: NETWORKTEMPLATE_API,
+                            modelName: "networkTemplate",
+                            listFields: ["backend_status", "id", "name", "visibility", "translation", "shared_network_name", "shared_network_id"],
+                            detailFields: ["backend_status", "backend_register", "name", "description", "visibility", "translation", "shared_network_name", "shared_network_id"],
+                            });
+
+        define_model(this, {urlRoot: NETWORK_API,
+                            relatedCollections: {"ports": "network", "controller_networks": "network"},
+                            foreignCollections: ["slices", "networkTemplates"],
+                            modelName: "network",
+                            foreignFields: {"template": "networkTemplates", "owner": "slices"},
+                            listFields: ["backend_status", "id", "name", "template", "ports", "labels", "owner"],
+                            detailFields: ["backend_status", "backend_register", "name", "template", "ports", "labels", "owner"],
+                            });
+
+        define_model(this, {urlRoot: PORT_API,
+                            modelName: "port",
+                            foreignFields: {"network": "networks", "instance": "instances"},
+                            listFields: ["backend_status", "id", "network", "instance", "ip", "port_id"],
+                            detailFields: ["backend_status", "backend_register", "network", "instance", "ip", "mac", "port_id"],
+                            });
+
+        define_model(this, {urlRoot: SERVICE_API,
+                            modelName: "service",
+                            listFields: ["backend_status", "id", "name", "enabled", "versionNumber", "published"],
+                            detailFields: ["backend_status", "backend_register", "name", "description", "versionNumber"],
+                            });
+
+        define_model(this, {urlRoot: FLAVOR_API,
+                            modelName: "flavor",
+                            m2mFields: {"deployments": "deployments"},
+                            listFields: ["backend_status", "id", "name", "flavor", "order", "default"],
+                            detailFields: ["backend_status", "backend_register", "name", "description", "flavor", "order", "default", "deployments"],
+                            inputType: {"default": "checkbox", "deployments": "picker"},
+                            });
+
+        define_model(this, {urlRoot: CONTROLLER_API,
+                            relatedCollections: {"controller_images": "controller", "controller_networks": "controller", "controller_slices": "controller"},
+                            modelName: "controller",
+                            listFields: ["backend_status", "id", "name", "version", "backend_type"],
+                            detailFields: ["backend_status", "backend_register", "name", "version", "backend_type", "auth_url", "admin_user", "admin_password", "admin_tenant"],
+                            });
+
+        define_model(this, {urlRoot: CONTROLLERIMAGE_API,
+                            foreignCollections: ["images", "controllers"],
+                            foreignFields: {"image": "images", "controller": "controllers"},
+                            modelName: "controller_image",
+                            listFields: ["backend_status", "id", "image", "controller", "glance_image_id"],
+                            detailFields: ["backend_status", "backend_register", "image", "controller", "glance_image_id"],
+                            });
+
+        define_model(this, {urlRoot: CONTROLLERNETWORK_API,
+                            foreignCollections: ["networks", "controllers"],
+                            foreignFields: {"network": "networks", "controller": "controllers"},
+                            modelName: "controller_network",
+                            listFields: ["backend_status", "id", "network", "controller", "net_id"],
+                            detailFields: ["backend_status", "backend_register", "network", "controller", "net_id"],
+                            });
+
+        define_model(this, {urlRoot: CONTROLLERSLICE_API,
+                            foreignCollections: ["slices", "controllers"],
+                            foreignFields: {"slice": "slices", "controller": "controllers"},
+                            modelName: "controller_slice",
+                            listFields: ["backend_status", "id", "slice", "controller", "tenant_id"],
+                            detailFields: ["backend_status", "backend_register", "slice", "controller", "tenant_id"],
+                            });
+
+        define_model(this, {urlRoot: CONTROLLERUSER_API,
+                            foreignCollections: ["users", "controllers"],
+                            foreignFields: {"user": "users", "controller": "controllers"},
+                            modelName: "controller_user",
+                            listFields: ["backend_status", "id", "user", "controller", "kuser_id"],
+                            detailFields: ["backend_status", "backend_register", "user", "controller", "kuser_id"],
+                            });
+
+        /* removed
+        define_model(this, {urlRoot: CONTROLLERSITEDEPLOYMENT_API,
+                            modelName: "controllerSiteDeployment",
+                            foreignCollections: ["site_deployments", "controllers"],
+                            foreignFields: {"site_deployment": "siteDeployments", "controller": "controllers"},
+                            listFields: ["backend_status", "id", "site_deployment", "controller", "tenant_id"],
+                            detailFields: ["backend_status", "site_deployment", "controller", "tenant_id"],
+                            });
+        */
+
+        /* DELETED in site-controller branch
+
+        define_model(this, {urlRoot: NETWORKDEPLOYMENT_API,
+                            modelName: "networkDeployment",
+                            foreignFields: {"network": "networks", "deployment": "deployments"},
+                            listFields: ["backend_status", "id", "network", "deployment", "net_id"],
+                            detailFields: ["backend_status", "network", "deployment", "net_id"],
+                            });
+
+        define_model(this, {urlRoot: SLICEDEPLOYMENT_API,
+                           foreignCollections: ["slices", "deployments"],
+                           modelName: "sliceDeployment",
+                           foreignFields: {"slice": "slices", "deployment": "deployments"},
+                           listFields: ["backend_status", "id", "slice", "deployment", "tenant_id"],
+                           detailFields: ["backend_status", "slice", "deployment", "tenant_id"],
+                           });
+
+        define_model(this, {urlRoot: USERDEPLOYMENT_API,
+                            foreignCollections: ["users","deployments"],
+                            modelName: "userDeployment",
+                            foreignFields: {"deployment": "deployments", "user": "users"},
+                            listFields: ["backend_status", "id", "user", "deployment", "kuser_id"],
+                            detailFields: ["backend_status", "user", "deployment", "kuser_id"],
+                            });
+
+        END stuff deleted in site-controller branch */
+
+        /* not deleted, but obsolete since it has degenerated to a ManyToMany with no other fields
+
+        define_model(this, {urlRoot: IMAGEDEPLOYMENTS_API,
+                            modelName: "imageDeployment",
+                            foreignCollections: ["images", "deployments"],
+                            listFields: ["backend_status", "id", "image", "deployment", "glance_image_id"],
+                            detailFields: ["backend_status", "image", "deployment", "glance_image_id"],
+                            });
+
+        */
+
+        // enhanced REST
+        // XXX this really needs to somehow be combined with Slice, to avoid duplication
+        define_model(this, {urlRoot: SLICEPLUS_API,
+                            relatedCollections: {"instances": "slice", "slicePrivileges": "slice", "networks": "owner"},
+                            foreignCollections: ["services", "sites"],
+                            foreignFields: {"service": "services", "site": "sites"},
+                            listFields: ["backend_status", "id", "name", "enabled", "description", "slice_url", "site", "max_instances", "service"],
+                            detailFields: ["backend_status", "backend_register", "name", "site", "enabled", "description", "slice_url", "max_instances"],
+                            inputType: {"enabled": "checkbox"},
+                            modelName: "slicePlus",
+                            collectionName: "slicesPlus",
+                            defaults: extend_defaults("slice", {"network_ports": "", "site_allocation": []}),
+                            validators: {"network_ports": ["portspec"]},
+                            xosValidate: function(attrs, options) {
+                                errors = XOSModel.prototype.xosValidate.call(this, attrs, options);
+                                // validate that slice.name starts with site.login_base
+
+                                var site = xos.tenant().current_user_login_base;
+                                if ((site!=undefined) && (attrs.name!=undefined)) {
+                                    if (attrs.name.indexOf(site + "_") < 0) {
+                                        errors = errors || {};
+                                        errors["name"] = "must start with " + site + "_";
+                                    }
+
+                                    if(attrs.name.indexOf(' ') >= 0){
+                                        errors = errors || {};
+                                        errors["name"] = "must not contain spaces";   
+                                    }
+                                }
+
+                                return errors;
+                            },
+                        });
+
+        define_model(this, {urlRoot: TENANTVIEW_API,
+                            modelName: "tenantview",
+                            collectionName: "tenantview",
+                            listFields: [],
+                            detailFields: [],
+                            });
+
+        define_model(this, {urlRoot: HPCVIEW_API,
+                            modelName: "hpcview",
+                            collectionName: "hpcview",
+                            listFields: [],
+                            detailFields: [],
+                            });
+
+        define_model(this, {urlRoot: CORDSUBSCRIBER_API,
+                            modelName: "cordSubscriber",
+                            relatedCollections: {"cordUsers": "subscriber"},
+                            listFields: ["id", "service_specific_id", "routeable_subnet"],
+                            detailFields: ["id", "service_specific_id", "vcpe_id", "image_name", "instance_name",
+                                           "firewall_enable", "firewall_rules", "url_filter_enable", "url_filter_rules", "cdn_enable",
+                                           "nat_ip", "lan_ip", "wan_ip", "private_ip",
+                                           "vbng_id", "routeable_subnet"],
+                            inputType: {"firewall_enable": "checkbox",
+                                        "url_filter_enable": "checkbox",
+                                        "cdn_enable": "checkbox"},
+                            disableAdd: true,
+                            });
+
+        define_model(this, {urlRoot: CORDUSER_API,
+                            modelName: "cordUser",
+                            listFields: ["id", "subscriber", "name", "level", "mac"],
+                            detailFields: ["subscriber", "name", "level", "mac"],
+                            disableAdd: true,
+                            });
+
+        /* by default, have slicePlus only fetch the slices the user can see */
+        this.slicesPlus.currentUserCanSee = true;
+
+        this.tenant = function() { return this.tenantview.models[0].attributes; };
+
+        this.listObjects = function() { return this.allCollectionNames; };
+
+        this.getCollectionStatus = function() {
+            stats = {isLoaded: 0, failedLoad: 0, startedLoad: 0};
+            for (index in this.allCollections) {
+                collection = this.allCollections[index];
+                if (collection.isLoaded) {
+                    stats["isLoaded"] = stats["isLoaded"] + 1;
+                }
+                if (collection.failedLoad) {
+                    stats["failedLoad"] = stats["failedLoad"] + 1;
+                }
+                if (collection.startedLoad) {
+                    stats["startedLoad"] = stats["startedLoad"] + 1;
+                }
+            }
+            stats["completedLoad"] = stats["failedLoad"] + stats["isLoaded"];
+            return stats;
+        };
+    };
+
+    xos = new xoslib();
+
+    function getCookie(name) {
+        var cookieValue = null;
+        if (document.cookie && document.cookie != '') {
+            var cookies = document.cookie.split(';');
+            for (var i = 0; i < cookies.length; i++) {
+                var cookie = jQuery.trim(cookies[i]);
+                // Does this cookie string begin with the name we want?
+                if (cookie.substring(0, name.length + 1) == (name + '=')) {
+                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
+                    break;
+                }
+            }
+        }
+        return cookieValue;
+    }
+
+    (function() {
+        var _sync = Backbone.sync;
+        Backbone.sync = function(method, model, options){
+            options.beforeSend = function(xhr){
+                // var token = getCookie("csrftoken");
+                // xhr.setRequestHeader('X-CSRFToken', token);
+                var xosToken = getCookie('xoscsrftoken');
+                xhr.setRequestHeader('X-CSRFToken', xosToken);
+            };
+            return _sync(method, model, options);
+        };
+    })();
+}
+/* eslint-enable */
\ No newline at end of file
diff --git a/xos/core/xoslib/static/js/xoslib/xos-defaults.js b/xos/core/xoslib/static/js/xoslib/xos-defaults.js
new file mode 100644
index 0000000..4ce5f6b
--- /dev/null
+++ b/xos/core/xoslib/static/js/xoslib/xos-defaults.js
@@ -0,0 +1,70 @@
+/* eslint-disable quotes, no-undef, max-len, new-cap*/
+/* eslint indent: [2, 2]*/
+console.warn('**** XOS DEFAULT ****');
+function xos_get_defaults(){
+  this.account = {"updated": null, "policed": null, "created": null, "deleted": false, "site": null, "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "backend_status": "0 - Provisioning in progress", "no_sync": false, "enacted": null};
+  this.charge = {"updated": null, "slice": null, "date": null, "policed": null, "created": null, "deleted": false, "object": null, "account": null, "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "amount": 0.0, "state": "pending", "invoice": null, "coreHours": 0.0, "backend_status": "0 - Provisioning in progress", "kind": "besteffort", "no_sync": false, "enacted": null};
+  this.coarseTenant = {"subscriber_service": null, "connect_method": "na", "updated": null, "backend_status": "0 - Provisioning in progress", "policed": null, "created": null, "deleted": false, "service_specific_attribute": null, "kind": "coarse", "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "enacted": null, "service_specific_id": null, "subscriber_tenant": null, "subscriber_root": null, "subscriber_user": null, "no_sync": false, "provider_service": null};
+  this.controller = {"updated": null, "backend_type": "", "policed": null, "admin_user": null, "created": null, "deleted": false, "domain": null, "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "version": "", "auth_url": null, "admin_password": null, "deployment": null, "enacted": null, "backend_status": "0 - Provisioning in progress", "admin_tenant": null, "no_sync": false, "name": ""};
+  this.controllerDashboardView = {"updated": null, "policed": null, "created": null, "deleted": false, "enabled": true, "dashboardView": null, "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "controller": null, "url": "", "backend_status": "0 - Provisioning in progress", "no_sync": false, "enacted": null};
+  this.controllerImages = {"updated": null, "policed": null, "created": null, "deleted": false, "image": null, "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "controller": null, "backend_status": "0 - Provisioning in progress", "glance_image_id": null, "no_sync": false, "enacted": null};
+  this.controllerNetwork = {"router_id": null, "subnet": "", "updated": null, "policed": null, "created": null, "deleted": false, "net_id": null, "lazy_blocked": false, "backend_register": "{}", "subnet_id": null, "controller": null, "enacted": null, "backend_status": "0 - Provisioning in progress", "write_protect": false, "no_sync": false, "network": null};
+  this.controllerRole = {"updated": null, "policed": null, "created": null, "deleted": false, "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "role": "", "backend_status": "0 - Provisioning in progress", "no_sync": false, "enacted": null};
+  this.controllerSite = {"updated": null, "policed": null, "created": null, "deleted": false, "tenant_id": null, "site": null, "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "controller": null, "backend_status": "0 - Provisioning in progress", "no_sync": false, "enacted": null};
+  this.controllerSitePrivilege = {"updated": null, "backend_status": "0 - Provisioning in progress", "policed": null, "created": null, "deleted": false, "site_privilege": null, "role_id": null, "backend_register": "{}", "write_protect": false, "controller": null, "lazy_blocked": false, "no_sync": false, "enacted": null};
+  this.controllerSlice = {"updated": null, "slice": null, "policed": null, "created": null, "deleted": false, "tenant_id": null, "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "controller": null, "backend_status": "0 - Provisioning in progress", "no_sync": false, "enacted": null};
+  this.controllerSlicePrivilege = {"updated": null, "backend_status": "0 - Provisioning in progress", "slice_privilege": null, "created": null, "deleted": false, "role_id": null, "backend_register": "{}", "write_protect": false, "controller": null, "enacted": null, "lazy_blocked": false, "no_sync": false, "policed": null};
+  this.controllerUser = {"updated": null, "policed": null, "created": null, "deleted": false, "controller": null, "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "kuser_id": null, "user": null, "backend_status": "0 - Provisioning in progress", "no_sync": false, "enacted": null};
+  this.dashboardView = {"updated": null, "policed": null, "created": null, "deleted": false, "enabled": true, "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "url": "", "enacted": null, "backend_status": "0 - Provisioning in progress", "no_sync": false, "name": ""};
+  this.deployment = {"accessControl": "allow all", "updated": null, "policed": null, "created": null, "deleted": false, "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "enacted": null, "backend_status": "0 - Provisioning in progress", "no_sync": false, "name": ""};
+  this.deploymentPrivilege = {"updated": null, "policed": null, "created": null, "deleted": false, "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "role": null, "user": null, "deployment": null, "backend_status": "0 - Provisioning in progress", "no_sync": false, "enacted": null};
+  this.deploymentRole = {"updated": null, "policed": null, "created": null, "deleted": false, "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "role": "", "backend_status": "0 - Provisioning in progress", "no_sync": false, "enacted": null};
+  this.flavor = {"updated": null, "policed": null, "created": null, "default": false, "description": null, "enacted": null, "lazy_blocked": false, "backend_register": "{}", "deleted": false, "flavor": "", "backend_status": "0 - Provisioning in progress", "order": 0, "write_protect": false, "no_sync": false, "name": ""};
+  this.image = {"updated": null, "policed": null, "created": null, "deleted": false, "container_format": "", "disk_format": "", "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "path": null, "enacted": null, "backend_status": "0 - Provisioning in progress", "no_sync": false, "name": ""};
+  this.imageDeployments = {"updated": null, "policed": null, "created": null, "deleted": false, "image": null, "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "deployment": null, "backend_status": "0 - Provisioning in progress", "no_sync": false, "enacted": null};
+  this.instance = {"policed": null, "creator": null, "ip": null, "image": null, "backend_register": "{}", "flavor": 3, "backend_status": "0 - Provisioning in progress", "instance_id": null, "slice": null, "no_sync": false, "node": null, "userData": null, "updated": null, "deleted": false, "lazy_blocked": false, "deployment": null, "enacted": null, "instance_uuid": null, "numberCores": 0, "name": "", "created": null, "write_protect": false, "instance_name": null};
+  this.invoice = {"updated": null, "policed": null, "created": null, "deleted": false, "account": null, "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "date": null, "backend_status": "0 - Provisioning in progress", "no_sync": false, "enacted": null};
+  this.network = {"permit_all_slices": false, "policed": null, "labels": null, "backend_register": "{}", "owner": null, "backend_status": "0 - Provisioning in progress", "subnet": "", "subnet_id": null, "controller_parameters": null, "no_sync": false, "router_id": null, "updated": null, "controller_url": null, "template": null, "deleted": false, "lazy_blocked": false, "guaranteed_bandwidth": 0, "enacted": null, "autoconnect": true, "name": "", "created": null, "network_id": null, "write_protect": false, "topology_parameters": null, "ports": null};
+  this.networkParameter = {"updated": null, "policed": null, "created": null, "deleted": false, "value": "", "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "object_id": null, "content_type": null, "backend_status": "0 - Provisioning in progress", "parameter": null, "no_sync": false, "enacted": null};
+  this.networkParameterType = {"updated": null, "backend_status": "0 - Provisioning in progress", "description": "", "created": null, "deleted": false, "name": "", "backend_register": "{}", "write_protect": false, "enacted": null, "lazy_blocked": false, "no_sync": false, "policed": null};
+  this.networkSlice = {"updated": null, "slice": null, "policed": null, "created": null, "deleted": false, "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "enacted": null, "backend_status": "0 - Provisioning in progress", "no_sync": false, "network": null};
+  this.networkTemplate = {"updated": null, "shared_network_name": null, "name": "", "created": null, "deleted": false, "description": null, "enacted": null, "visibility": "private", "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "no_sync": false, "topology_kind": "bigswitch", "guaranteed_bandwidth": 0, "translation": "none", "backend_status": "0 - Provisioning in progress", "shared_network_id": null, "controller_kind": null, "policed": null};
+  this.node = {"updated": null, "policed": null, "created": null, "deleted": false, "site": null, "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "no_sync": false, "enacted": null, "backend_status": "0 - Provisioning in progress", "site_deployment": null, "name": ""};
+  this.payment = {"updated": null, "policed": null, "created": null, "deleted": false, "account": null, "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "amount": 0.0, "date": "2015-09-14T22:58:03.982Z", "backend_status": "0 - Provisioning in progress", "no_sync": false, "enacted": null};
+  this.port = {"updated": null, "policed": null, "created": null, "deleted": false, "ip": null, "lazy_blocked": false, "backend_register": "{}", "instance": null, "mac": null, "enacted": null, "backend_status": "0 - Provisioning in progress", "port_id": null, "write_protect": false, "no_sync": false, "network": null};
+  this.program = {"status": null, "updated": null, "policed": null, "created": null, "deleted": false, "description": null, "messages": null, "kind": "", "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "command": null, "no_sync": false, "owner": null, "output": null, "enacted": null, "backend_status": "0 - Provisioning in progress", "contents": null, "name": ""};
+  this.project = {"updated": null, "policed": null, "created": null, "deleted": false, "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "enacted": null, "backend_status": "0 - Provisioning in progress", "no_sync": false, "name": ""};
+  this.provider = {"updated": null, "policed": null, "created": null, "deleted": false, "service_specific_attribute": null, "kind": "Provider", "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "service_specific_id": null, "enacted": null, "backend_status": "0 - Provisioning in progress", "no_sync": false, "name": null};
+  this.reservation = {"updated": null, "slice": null, "policed": null, "created": null, "deleted": false, "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "startTime": null, "duration": 1, "backend_status": "0 - Provisioning in progress", "no_sync": false, "enacted": null};
+  this.reservedResource = {"updated": null, "resource": null, "policed": null, "created": null, "deleted": false, "lazy_blocked": false, "backend_register": "{}", "instance": null, "reservationSet": null, "enacted": null, "backend_status": "0 - Provisioning in progress", "write_protect": false, "no_sync": false, "quantity": 1};
+  this.role = {"updated": null, "description": "", "created": null, "deleted": false, "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "role": null, "no_sync": false, "content_type": null, "enacted": null, "backend_status": "0 - Provisioning in progress", "role_type": "", "policed": null};
+  this.router = {"updated": null, "policed": null, "created": null, "deleted": false, "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "owner": null, "enacted": null, "backend_status": "0 - Provisioning in progress", "no_sync": false, "name": ""};
+  this.service = {"public_key": null, "updated": null, "policed": null, "created": null, "deleted": false, "view_url": null, "description": null, "service_specific_attribute": null, "enabled": true, "kind": "generic", "published": true, "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "versionNumber": "", "service_specific_id": null, "enacted": null, "backend_status": "0 - Provisioning in progress", "icon_url": null, "no_sync": false, "name": ""};
+  this.serviceAttribute = {"updated": null, "policed": null, "service": null, "created": null, "deleted": false, "value": "", "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "enacted": null, "backend_status": "0 - Provisioning in progress", "no_sync": false, "name": ""};
+  this.serviceClass = {"backend_register": "{}", "updated": null, "name": "", "membershipFeeMonths": 12, "created": null, "deleted": false, "description": "", "commitment": 365, "lazy_blocked": false, "policed": null, "write_protect": false, "no_sync": false, "enacted": null, "backend_status": "0 - Provisioning in progress", "upgradeRequiresApproval": false, "membershipFee": 0};
+  this.servicePrivilege = {"updated": null, "policed": null, "service": null, "created": null, "deleted": false, "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "role": null, "user": null, "backend_status": "0 - Provisioning in progress", "no_sync": false, "enacted": null};
+  this.serviceResource = {"updated": null, "backend_status": "0 - Provisioning in progress", "name": "", "bucketMaxSize": 0, "created": null, "deleted": false, "maxUnitsNode": 1, "serviceClass": null, "maxUnitsDeployment": 1, "calendarReservable": true, "maxDuration": 1, "backend_register": "{}", "write_protect": false, "cost": 0, "enacted": null, "lazy_blocked": false, "bucketInRate": 0, "no_sync": false, "policed": null};
+  this.site = {"updated": null, "backend_status": "0 - Provisioning in progress", "hosts_users": true, "name": "", "created": null, "deleted": false, "enabled": true, "enacted": null, "longitude": null, "site_url": null, "backend_register": "{}", "write_protect": false, "login_base": "", "location": null, "hosts_nodes": true, "is_public": true, "latitude": null, "lazy_blocked": false, "abbreviated_name": "", "no_sync": false, "policed": null};
+  this.siteCredential = {"updated": null, "backend_status": "0 - Provisioning in progress", "policed": null, "created": null, "deleted": false, "site": null, "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "key_id": "", "enacted": null, "enc_value": "", "no_sync": false, "name": ""};
+  this.siteDeployment = {"updated": null, "policed": null, "availability_zone": null, "deleted": false, "created": null, "site": null, "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "controller": null, "deployment": null, "backend_status": "0 - Provisioning in progress", "no_sync": false, "enacted": null};
+  this.sitePrivilege = {"updated": null, "policed": null, "created": null, "deleted": false, "site": null, "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "role": null, "user": null, "backend_status": "0 - Provisioning in progress", "no_sync": false, "enacted": null};
+  this.siteRole = {"updated": null, "policed": null, "created": null, "deleted": false, "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "role": "", "backend_status": "0 - Provisioning in progress", "no_sync": false, "enacted": null};
+  this.slice = {"policed": null, "creator": null, "site": null, "max_instances": 10, "backend_register": "{}", "backend_status": "0 - Provisioning in progress", "network": "Private Only", "service": null, "no_sync": false, "default_flavor": null, "updated": null, "description": "", "deleted": false, "slice_url": "", "serviceClass": 1, "lazy_blocked": false, "omf_friendly": false, "mount_data_sets": "GenBank", "enacted": null, "name": "", "created": null, "write_protect": false, "enabled": true, "default_image": null};
+  this.sliceCredential = {"updated": null, "slice": null, "policed": null, "created": null, "deleted": false, "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "key_id": "", "enacted": null, "enc_value": "", "backend_status": "0 - Provisioning in progress", "no_sync": false, "name": ""};
+  this.slicePrivilege = {"updated": null, "slice": null, "policed": null, "created": null, "deleted": false, "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "role": null, "user": null, "backend_status": "0 - Provisioning in progress", "no_sync": false, "enacted": null};
+  this.sliceRole = {"updated": null, "policed": null, "created": null, "deleted": false, "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "role": "", "backend_status": "0 - Provisioning in progress", "no_sync": false, "enacted": null};
+  this.sliceTag = {"updated": null, "slice": null, "policed": null, "created": null, "deleted": false, "value": "", "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "enacted": null, "backend_status": "0 - Provisioning in progress", "no_sync": false, "name": ""};
+  this.subscriber = {"updated": null, "policed": null, "created": null, "deleted": false, "service_specific_attribute": null, "kind": "Subscriber", "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "service_specific_id": null, "enacted": null, "backend_status": "0 - Provisioning in progress", "no_sync": false, "name": null};
+  this.tag = {"updated": null, "name": "", "service": null, "created": null, "deleted": false, "value": "", "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "object_id": null, "content_type": null, "enacted": null, "backend_status": "0 - Provisioning in progress", "no_sync": false, "policed": null};
+  this.tenant = {"subscriber_service": null, "connect_method": "na", "updated": null, "backend_status": "0 - Provisioning in progress", "policed": null, "created": null, "deleted": false, "service_specific_attribute": null, "kind": "generic", "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "enacted": null, "service_specific_id": null, "subscriber_tenant": null, "subscriber_root": null, "subscriber_user": null, "no_sync": false, "provider_service": null};
+  this.tenantRoot = {"updated": null, "policed": null, "created": null, "deleted": false, "service_specific_attribute": null, "kind": "generic", "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "service_specific_id": null, "enacted": null, "backend_status": "0 - Provisioning in progress", "no_sync": false, "name": null};
+  this.tenantRootPrivilege = {"updated": null, "policed": null, "created": null, "deleted": false, "tenant_root": null, "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "role": null, "user": null, "backend_status": "0 - Provisioning in progress", "no_sync": false, "enacted": null};
+  this.tenantRootRole = {"updated": null, "policed": null, "created": null, "deleted": false, "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "role": "", "backend_status": "0 - Provisioning in progress", "no_sync": false, "enacted": null};
+  this.tenantWithContainer = {"subscriber_service": null, "connect_method": "na", "updated": null, "backend_status": "0 - Provisioning in progress", "policed": null, "created": null, "deleted": false, "service_specific_attribute": null, "kind": "generic", "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "enacted": null, "service_specific_id": null, "subscriber_tenant": null, "subscriber_root": null, "subscriber_user": null, "no_sync": false, "provider_service": null};
+  this.usableObject = {"updated": null, "policed": null, "created": null, "deleted": false, "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "enacted": null, "backend_status": "0 - Provisioning in progress", "no_sync": false, "name": ""};
+  this.user = {"policed": null, "site": null, "is_appuser": false, "is_staff": true, "timezone": "America/New_York", "backend_status": "Provisioning in progress", "is_registering": false, "last_login": "2015-09-14T22:58:04.005Z", "email": "", "username": "Something", "updated": null, "login_page": null, "firstname": "", "user_url": null, "deleted": false, "lastname": "", "is_active": true, "phone": null, "is_admin": false, "password": "", "enacted": null, "public_key": null, "is_readonly": false, "created": null, "write_protect": false};
+  this.userCredential = {"updated": null, "backend_status": "0 - Provisioning in progress", "policed": null, "created": null, "deleted": false, "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "user": null, "key_id": "", "enacted": null, "enc_value": "", "no_sync": false, "name": ""};
+  this.userDashboardView = {"updated": null, "policed": null, "created": null, "deleted": false, "dashboardView": null, "lazy_blocked": false, "backend_register": "{}", "write_protect": false, "user": null, "backend_status": "0 - Provisioning in progress", "order": 0, "no_sync": false, "enacted": null};
+};
+xosdefaults = new xos_get_defaults();
+/* eslint-enable quotes, no-undef, max-len, new-cap*/
\ No newline at end of file
diff --git a/xos/core/xoslib/static/js/xoslib/xos-util.js b/xos/core/xoslib/static/js/xoslib/xos-util.js
new file mode 100644
index 0000000..2b574e7
--- /dev/null
+++ b/xos/core/xoslib/static/js/xoslib/xos-util.js
@@ -0,0 +1,314 @@
+/* eslint-disable indent, space-before-blocks, no-unused-vars*/
+////////////////////////////
+// misc utility functions //
+////////////////////////////
+
+function idInArray(id, arr) {
+    // because sometimes ids are strings and sometimes they're integers
+    for (var index in arr) {
+        if (id.toString() === arr[index].toString()) {
+            return true;
+        }
+    }
+    return false;
+}
+
+function assert(outcome, description) {
+    if (!outcome) {
+        console.log(description);
+    }
+}
+
+function templateFromId(id) {
+    return _.template($(id).html());
+}
+
+function firstCharUpper(s) {
+    return s.charAt(0).toUpperCase() + s.slice(1);
+}
+
+function toTitleCase(str) {
+    return str.replace(/\w\S*/g, function(txt) {
+        return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
+    });
+}
+
+function fieldNameToHumanReadable(str) {
+    str = str.replace('_', ' ');
+    return toTitleCase(str);
+}
+
+// http://stackoverflow.com/questions/2117320/set-maximum-displayed-rows-count-for-html-table
+function limitTableRows(tableSelector, maxRows) {
+    var table = $(tableSelector)[0]; //document.getElementById(tableId);
+    var wrapper = table.parentNode;
+    var rowsInTable = table.rows.length;
+
+    try {
+        var border = getComputedStyle(table.rows[0].cells[0], '').getPropertyValue('border-top-width');
+
+        border = border.replace('px', '') * 1;
+    }
+    catch (e) {
+        var border = table.rows[0].cells[0].currentStyle.borderWidth;
+
+        border = border.replace('px', '') * 1 / 2;
+    }
+    var height = 0;
+
+    if (rowsInTable > maxRows) {
+        for (var i = 0; i < maxRows; i++) {
+            height += table.rows[i].clientHeight + border;
+            //console.log('XXX ' + height + ' ' + table.rows[i].clientHeight + ' ' + border);
+        }
+        wrapper.style.height = height + 'px';
+    }
+}
+
+function validateField(validatorName, value, obj) {
+    if (validatorName === 'notBlank') {
+        if (value === undefined || value === null || value === '') {
+            return 'can not be blank';
+        }
+    }
+
+    // if notBlank wasn't set, and the field is blank, then we can return
+    if (value === undefined || value === null || value === '') {
+        return true;
+    }
+    /* eslint-disable default-case */
+    switch (validatorName) {
+    case 'url':
+        /* eslint-disable max-len*/
+        if (! /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(value)) {
+        /* eslint-enable max-len*/
+            return 'must be a valid url';
+        }
+        break;
+
+    case 'portspec':
+        if (! $.trim(value).match(portlist_regexp())) {
+            return 'must be a valid portspec (example: \'tcp 123, udp 456-789\')';
+        }
+        break;
+    // TODO test this before add
+    // default:
+    //     return true;
+    //     break;
+    /* eslint-enable default-case */
+    }
+
+    return true;
+}
+
+function array_diff(a1, a2) {
+    var a = [], diff = [];
+
+    for(var i = 0;i < a1.length;i++) {
+        a[a1[i]] = true;
+    }
+
+    for(var i = 0;i < a2.length;i++) {
+        if(a[a2[i]]) {
+            delete a[a2[i]];
+        }
+        else {
+            a[a2[i]] = true;
+        }
+    }
+
+    for(var k in a) {
+        // check that the property in not inherithed
+        if ({}.hasOwnProperty.call(a, k)) {
+            diff.push(k);
+        }
+    }
+
+    return diff;
+}
+
+function array_subtract(a1, a2) {
+    var result = [];
+
+    // why not for ... of, move to lodash instead
+    for (var index in a1) {
+        if ({}.hasOwnProperty.call(a1, index)) {
+            var value = a1[index];
+
+            if (!$.inArray(value, a2) >= 0) {
+                result.push(value);
+            }
+        }
+
+    }
+    return result;
+}
+
+function array_same_elements(arr1, arr2) {
+    // return true if arrays have same elements, even if order is different
+    return $(arr1).not(arr2).length === 0 && $(arr2).not(arr1).length === 0;
+}
+
+function array_pair_lookup(x, names, values) {
+    for (var index in values) {
+        if (values[index] === x) {
+            return names[index];
+        }
+    }
+    return 'object #' + x;
+}
+
+function all_options(selector) {
+    var el = $(selector);
+    var result = [];
+
+    _.each(el.find('option'), function(option) {
+        result.push($(option).val());
+    });
+    return result;
+}
+
+function make_same_width(containerSelector, itemSelector) {
+    var maxWidth = 0;
+
+    $(containerSelector).find(itemSelector).each(function() {
+        maxWidth = Math.max(maxWidth, $(this).width());
+    });
+
+    $(containerSelector).find(itemSelector).each(function() {
+        $(this).width(maxWidth);
+    });
+}
+
+function strip_scripts(s) {
+    var div = document.createElement('div');
+
+    div.innerHTML = s;
+    var scripts = div.getElementsByTagName('script');
+    var i = scripts.length;
+
+    while (i--) {
+        scripts[i].parentNode.removeChild(scripts[i]);
+    }
+    return div.innerHTML;
+}
+
+function parse_portlist(ports) {
+    /* Support a list of ports in the format 'protocol:port, protocol:port, ...'
+        examples:
+            tcp 123
+            tcp 123:133
+            tcp 123, tcp 124, tcp 125, udp 201, udp 202
+
+        User can put either a '/' or a ' ' between protocol and ports
+        Port ranges can be specified with '-' or ':'
+
+        This is a straightforward port of the code in core/models/network.py
+    */
+
+    var nats = [];
+
+    if (ports) {
+        var parts = ports.split(',');
+        var parts2, protocol, first, last, portStr;
+
+        $.each(parts, function(index, part) {
+            part = $.trim(part);
+            if (part.indexOf('/') >= 0) {
+                parts2 = part.split('/',2);
+
+                protocol = parts2[0];
+                ports = parts2[1];
+            }
+            else if (part.indexOf(' ') >= 0) {
+                parts2 = part.split(' ',2);
+                protocol = parts2[0];
+                ports = parts2[1];
+            }
+            else {
+                throw 'malformed port specifier ' +
+                    part + ', format example: "tcp 123, tcp 201:206, udp 333"';
+            }
+
+            protocol = $.trim(protocol);
+            ports = $.trim(ports);
+
+            if (protocol !== 'tcp' && protocol !== 'udp') {
+                throw 'unknown protocol ' + protocol;
+            }
+
+            if (ports.indexOf('-') >= 0) {
+                parts2 = ports.split('-');
+                first = parseInt($.trim(parts2[0]));
+                last = parseInt($.trim(parts2[1]));
+                portStr = first + ':' + last;
+            }
+            else if (ports.indexOf(':') >= 0) {
+                parts2 = ports.split(':');
+                first = parseInt($.trim(parts2[0]));
+                last = parseInt($.trim(parts2[1]));
+                portStr = first + ':' + last;
+            }
+            else {
+                portStr = parseInt(ports).toString();
+            }
+
+            nats.push({l4_protocol: protocol, l4_port: portStr});
+        }); /* end $.each(ports) */
+    }
+    return nats;
+}
+
+function portlist_regexp() {
+    /* this constructs the big complicated regexp that validates port
+       specifiers. Saved here in long form, in case we need to change it
+       in the future.
+    */
+    var paren, whitespace, protocol,
+        protocolSlash, numbers, range,
+        protoPorts, protoPortsCommas,
+        numbersOrRange, portSpec, multiProtoPorts;
+
+    paren = function(x) {
+        return '(?:' + x + ')';
+    };
+
+    whitespace = ' *';
+    protocol = paren('tcp|udp');
+    protocolSlash = protocol + paren(whitespace + '|\/');
+    numbers = paren('[0-9]+');
+    range = paren(numbers + paren('-|:') + numbers);
+    numbersOrRange = paren(numbers + '|' + range);
+    protoPorts = paren(protocolSlash + numbersOrRange);
+    protoPortsCommas = paren(paren(protoPorts + ',' + whitespace) + '+');
+    multiProtoPorts = paren(protoPortsCommas + protoPorts);
+    portSpec = '^' + paren(protoPorts + '|' + multiProtoPorts) + '$';
+    return RegExp(portSpec);
+}
+
+function portlist_selftest() {
+    var r = portlist_regexp();
+
+/* eslint-disable quotes, max-len*/
+    assert(! "tcp".match(r), 'should not have matched: "tcp"');
+    assert("tcp 1".match(r), 'should have matched: "tcp 1"');
+    assert("tcp 123".match(r), 'should have matched: "tcp 123"');
+    assert("tcp  123".match(r), 'should have matched: "tcp 123"');
+    assert("tcp 123-456".match(r), 'should have matched: "tcp 123-456"');
+    assert("tcp 123:456".match(r), 'should have matched: "tcp 123:456"');
+    assert(! "tcp 123-".match(r), 'should have matched: "tcp 123-"');
+    assert(! "tcp 123:".match(r), 'should have matched: "tcp 123:"');
+    assert(! "foo 123".match(r), 'should not have matched "foo 123"');
+    assert("udp 123".match(r), 'should have matched: "udp 123"');
+    assert("tcp 123,udp 456".match(r), 'should have matched: "tcp 123,udp 456"');
+    assert("tcp 123, udp 456".match(r), 'should have matched: "tcp 123, udp 456"');
+    assert("tcp 123,  udp 456".match(r), 'should have matched: "tcp 123,  udp 456"');
+    assert("tcp 123-45, udp 456".match(r), 'should have matched: "tcp 123-45, udp 456"');
+    assert("tcp 123-45, udp 456, tcp 11, tcp 22:45, udp 76, udp 47:49, udp 60-61".match(r), 'should have matched: "tcp 123-45, udp 456, tcp 11, tcp 22:45, udp 76, udp 47:49, udp 60-61"');
+    /* eslint-enable quotes, max-len*/
+    return 'done';
+}
+
+//portlist_selftest();
+
+
diff --git a/xos/core/xoslib/static/js/xoslib/xos-validators.js b/xos/core/xoslib/static/js/xoslib/xos-validators.js
new file mode 100644
index 0000000..aa8e544
--- /dev/null
+++ b/xos/core/xoslib/static/js/xoslib/xos-validators.js
@@ -0,0 +1,75 @@
+/**
+* List of model validator
+*
+* @constructor
+*/
+
+/* eslint-disable quotes, no-undef, max-len, new-cap*/
+/* eslint indent: [2, 2]*/
+function xos_get_validators(){
+  this.account = {"updated": [], "policed": [], "created": [], "deleted": [], "site": ["notBlank"], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.charge = {"updated": [], "slice": [], "policed": [], "created": [], "deleted": [], "amount": ["notBlank"], "object": ["notBlank"], "account": ["notBlank"], "kind": ["notBlank"], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "state": ["notBlank"], "coreHours": ["notBlank"], "invoice": [], "date": ["notBlank"], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.coarseTenant = {"subscriber_service": [], "connect_method": ["notBlank"], "updated": [], "policed": [], "created": [], "deleted": [], "service_specific_attribute": [], "kind": ["notBlank"], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "subscriber_user": [], "provider_service": ["notBlank"], "service_specific_id": [], "subscriber_tenant": [], "subscriber_root": [], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.controller = {"updated": [], "backend_type": ["notBlank"], "policed": [], "name": ["notBlank"], "created": [], "deleted": [], "domain": [], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "version": ["notBlank"], "auth_url": [], "admin_user": [], "deployment": ["notBlank"], "admin_password": [], "backend_status": ["notBlank"], "admin_tenant": [], "id": [], "no_sync": [], "enacted": []};
+  this.controllerDashboardView = {"updated": [], "policed": [], "created": [], "deleted": [], "enabled": [], "dashboardView": ["notBlank"], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "controller": ["notBlank"], "url": ["notBlank"], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.controllerImages = {"updated": [], "glance_image_id": [], "policed": [], "created": [], "deleted": [], "image": ["notBlank"], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "controller": ["notBlank"], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.controllerNetwork = {"router_id": [], "subnet": [], "updated": [], "policed": [], "created": [], "deleted": [], "subnet_id": [], "net_id": [], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "controller": ["notBlank"], "network": ["notBlank"], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.controllerRole = {"updated": [], "policed": [], "created": [], "deleted": [], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "role": ["notBlank"], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.controllerSite = {"updated": [], "policed": [], "created": [], "deleted": [], "tenant_id": [], "site": ["notBlank"], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "controller": [], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.controllerSitePrivilege = {"updated": [], "policed": [], "created": [], "deleted": [], "role_id": [], "site_privilege": ["notBlank"], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "controller": ["notBlank"], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.controllerSlice = {"updated": [], "slice": ["notBlank"], "policed": [], "created": [], "deleted": [], "tenant_id": [], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "controller": ["notBlank"], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.controllerSlicePrivilege = {"updated": [], "slice_privilege": ["notBlank"], "policed": [], "created": [], "deleted": [], "role_id": [], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "controller": ["notBlank"], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.controllerUser = {"updated": [], "policed": [], "created": [], "deleted": [], "kuser_id": [], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "controller": ["notBlank"], "user": ["notBlank"], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.dashboardView = {"updated": [], "policed": [], "name": ["notBlank"], "created": [], "deleted": [], "enabled": [], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "url": ["notBlank"], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.deployment = {"accessControl": ["notBlank"], "updated": [], "policed": [], "name": ["notBlank"], "created": [], "deleted": [], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.deploymentPrivilege = {"updated": [], "policed": [], "created": [], "deleted": [], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "role": ["notBlank"], "user": ["notBlank"], "deployment": ["notBlank"], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.deploymentRole = {"updated": [], "policed": [], "created": [], "deleted": [], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "role": ["notBlank"], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.flavor = {"default": [], "updated": [], "policed": [], "name": ["notBlank"], "created": [], "deleted": [], "description": [], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "flavor": ["notBlank"], "backend_status": ["notBlank"], "order": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.image = {"updated": [], "policed": [], "name": ["notBlank"], "created": [], "deleted": [], "container_format": ["notBlank"], "disk_format": ["notBlank"], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "path": [], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.imageDeployments = {"updated": [], "policed": [], "created": [], "deleted": [], "image": ["notBlank"], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "deployment": ["notBlank"], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.instance = {"policed": [], "creator": [], "ip": [], "image": ["notBlank"], "backend_register": ["notBlank"], "flavor": ["notBlank"], "backend_status": ["notBlank"], "id": [], "instance_name": [], "slice": ["notBlank"], "no_sync": [], "node": ["notBlank"], "userData": [], "updated": [], "deleted": [], "lazy_blocked": [], "deployment": ["notBlank"], "enacted": [], "instance_uuid": [], "numberCores": ["notBlank"], "name": ["notBlank"], "created": [], "write_protect": [], "instance_id": []};
+  this.invoice = {"updated": [], "policed": [], "created": [], "deleted": [], "account": ["notBlank"], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "date": ["notBlank"], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.network = {"router_id": [], "policed": [], "labels": [], "backend_register": ["notBlank"], "owner": ["notBlank"], "backend_status": ["notBlank"], "id": [], "subnet": [], "subnet_id": [], "controller_parameters": [], "no_sync": [], "permit_all_slices": [], "updated": [], "controller_url": [], "template": ["notBlank"], "deleted": [], "lazy_blocked": [], "guaranteed_bandwidth": ["notBlank"], "enacted": [], "autoconnect": [], "name": ["notBlank"], "created": [], "write_protect": [], "network_id": [], "topology_parameters": [], "ports": []};
+  this.networkParameter = {"updated": [], "policed": [], "created": [], "deleted": [], "value": ["notBlank"], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "object_id": ["notBlank"], "content_type": ["notBlank"], "backend_status": ["notBlank"], "parameter": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.networkParameterType = {"updated": [], "policed": [], "name": ["notBlank"], "created": [], "deleted": [], "description": ["notBlank"], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.networkSlice = {"updated": [], "slice": ["notBlank"], "policed": [], "created": [], "deleted": [], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "network": ["notBlank"], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.networkTemplate = {"shared_network_id": [], "updated": [], "shared_network_name": [], "policed": [], "name": ["notBlank"], "created": [], "deleted": [], "description": [], "visibility": ["notBlank"], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "controller_kind": [], "topology_kind": ["notBlank"], "guaranteed_bandwidth": ["notBlank"], "translation": ["notBlank"], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.node = {"updated": [], "policed": [], "name": ["notBlank"], "created": [], "deleted": [], "site": [], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "site_deployment": ["notBlank"], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.payment = {"updated": [], "policed": [], "created": [], "deleted": [], "account": ["notBlank"], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "amount": ["notBlank"], "date": ["notBlank"], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.port = {"instance": [], "updated": [], "policed": [], "created": [], "deleted": [], "ip": [], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "mac": [], "network": ["notBlank"], "backend_status": ["notBlank"], "port_id": [], "id": [], "no_sync": [], "enacted": []};
+  this.program = {"status": [], "updated": [], "policed": [], "name": ["notBlank"], "created": [], "deleted": [], "description": [], "messages": [], "kind": ["notBlank"], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "command": [], "contents": [], "owner": ["notBlank"], "output": [], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.project = {"updated": [], "policed": [], "name": ["notBlank"], "created": [], "deleted": [], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.provider = {"updated": [], "policed": [], "name": [], "created": [], "deleted": [], "service_specific_attribute": [], "kind": ["notBlank"], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "service_specific_id": [], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.reservation = {"updated": [], "slice": ["notBlank"], "policed": [], "created": [], "deleted": [], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "startTime": ["notBlank"], "duration": ["notBlank"], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.reservedResource = {"instance": ["notBlank"], "updated": [], "resource": ["notBlank"], "policed": [], "created": [], "deleted": [], "quantity": ["notBlank"], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "reservationSet": ["notBlank"], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.role = {"updated": [], "policed": [], "created": [], "deleted": [], "description": ["notBlank"], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "role": [], "role_type": ["notBlank"], "content_type": ["notBlank"], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.router = {"updated": [], "policed": [], "name": ["notBlank"], "created": [], "deleted": [], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "owner": ["notBlank"], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.service = {"policed": [], "view_url": [], "backend_register": ["notBlank"], "backend_status": ["notBlank"], "id": [], "icon_url": [], "no_sync": [], "updated": [], "description": [], "deleted": [], "lazy_blocked": [], "versionNumber": ["notBlank"], "service_specific_id": [], "enacted": [], "public_key": [], "kind": ["notBlank"], "name": ["notBlank"], "created": [], "write_protect": [], "service_specific_attribute": [], "enabled": [], "published": []};
+  this.serviceAttribute = {"updated": [], "policed": [], "name": ["notBlank"], "created": [], "deleted": [], "value": ["notBlank"], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "service": ["notBlank"], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.serviceClass = {"membershipFeeMonths": ["notBlank"], "updated": [], "membershipFee": ["notBlank"], "policed": [], "name": ["notBlank"], "created": [], "deleted": [], "description": ["notBlank"], "commitment": ["notBlank"], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "upgradeRequiresApproval": [], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.servicePrivilege = {"updated": [], "policed": [], "service": ["notBlank"], "created": [], "deleted": [], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "role": ["notBlank"], "user": ["notBlank"], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.serviceResource = {"updated": [], "maxUnitsNode": ["notBlank"], "policed": [], "name": ["notBlank"], "created": [], "deleted": [], "serviceClass": ["notBlank"], "maxUnitsDeployment": ["notBlank"], "maxDuration": ["notBlank"], "bucketMaxSize": ["notBlank"], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "cost": ["notBlank"], "calendarReservable": [], "bucketInRate": ["notBlank"], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.site = {"policed": [], "backend_register": ["notBlank"], "id": [], "backend_status": ["notBlank"], "abbreviated_name": ["notBlank"], "site_url": ["url"], "location": ["notBlank"], "hosts_nodes": [], "no_sync": [], "updated": [], "deleted": [], "lazy_blocked": [], "latitude": [], "is_public": [], "enacted": [], "name": ["notBlank"], "created": [], "write_protect": [], "enabled": [], "longitude": [], "hosts_users": [], "login_base": ["notBlank"]};
+  this.siteCredential = {"updated": [], "enc_value": ["notBlank"], "policed": [], "name": ["notBlank"], "created": [], "deleted": [], "site": ["notBlank"], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "key_id": ["notBlank"], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.siteDeployment = {"updated": [], "policed": [], "created": [], "deleted": [], "availability_zone": [], "site": ["notBlank"], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "controller": [], "deployment": ["notBlank"], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.sitePrivilege = {"updated": [], "policed": [], "created": [], "deleted": [], "site": ["notBlank"], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "role": ["notBlank"], "user": ["notBlank"], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.siteRole = {"updated": [], "policed": [], "created": [], "deleted": [], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "role": ["notBlank"], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.slice = {"policed": [], "creator": [], "site": ["notBlank"], "max_instances": ["notBlank"], "backend_register": ["notBlank"], "backend_status": ["notBlank"], "id": [], "network": [], "service": [], "no_sync": [], "default_flavor": [], "updated": [], "description": [], "deleted": [], "slice_url": ["url"], "serviceClass": ["notBlank"], "lazy_blocked": [], "omf_friendly": [], "mount_data_sets": [], "enacted": [], "name": ["notBlank"], "created": [], "write_protect": [], "enabled": [], "default_image": []};
+  this.sliceCredential = {"updated": [], "slice": ["notBlank"], "enc_value": ["notBlank"], "policed": [], "name": ["notBlank"], "created": [], "deleted": [], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "key_id": ["notBlank"], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.slicePrivilege = {"updated": [], "slice": ["notBlank"], "policed": [], "created": [], "deleted": [], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "role": ["notBlank"], "user": ["notBlank"], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.sliceRole = {"updated": [], "policed": [], "created": [], "deleted": [], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "role": ["notBlank"], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.sliceTag = {"updated": [], "slice": ["notBlank"], "policed": [], "name": ["notBlank"], "created": [], "deleted": [], "value": ["notBlank"], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.subscriber = {"updated": [], "policed": [], "name": [], "created": [], "deleted": [], "service_specific_attribute": [], "kind": ["notBlank"], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "service_specific_id": [], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.tag = {"updated": [], "policed": [], "service": ["notBlank"], "created": [], "deleted": [], "name": ["notBlank"], "value": ["notBlank"], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "object_id": ["notBlank"], "content_type": ["notBlank"], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.tenant = {"subscriber_service": [], "connect_method": ["notBlank"], "updated": [], "policed": [], "created": [], "deleted": [], "service_specific_attribute": [], "kind": ["notBlank"], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "subscriber_user": [], "provider_service": ["notBlank"], "service_specific_id": [], "subscriber_tenant": [], "subscriber_root": [], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.tenantRoot = {"updated": [], "policed": [], "name": [], "created": [], "deleted": [], "service_specific_attribute": [], "kind": ["notBlank"], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "service_specific_id": [], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.tenantRootPrivilege = {"updated": [], "policed": [], "created": [], "deleted": [], "tenant_root": ["notBlank"], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "role": ["notBlank"], "user": ["notBlank"], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.tenantRootRole = {"updated": [], "policed": [], "created": [], "deleted": [], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "role": ["notBlank"], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.tenantWithContainer = {"subscriber_service": [], "connect_method": ["notBlank"], "updated": [], "policed": [], "created": [], "deleted": [], "service_specific_attribute": [], "kind": ["notBlank"], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "subscriber_user": [], "provider_service": ["notBlank"], "service_specific_id": [], "subscriber_tenant": [], "subscriber_root": [], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.usableObject = {"updated": [], "policed": [], "name": ["notBlank"], "created": [], "deleted": [], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.user = {"policed": ["notBlank"], "site": ["notBlank"], "is_appuser": [], "is_staff": [], "timezone": ["notBlank"], "backend_status": ["notBlank"], "id": [], "is_registering": [], "last_login": ["notBlank"], "email": ["notBlank"], "username": ["notBlank"], "updated": [], "login_page": [], "firstname": ["notBlank"], "user_url": ["url"], "deleted": [], "lastname": ["notBlank"], "is_active": [], "phone": [], "is_admin": [], "password": ["notBlank"], "enacted": ["notBlank"], "public_key": [], "is_readonly": [], "created": [], "write_protect": []};
+  this.userCredential = {"updated": [], "enc_value": ["notBlank"], "policed": [], "name": ["notBlank"], "created": [], "deleted": [], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "user": ["notBlank"], "key_id": ["notBlank"], "backend_status": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+  this.userDashboardView = {"updated": [], "policed": [], "created": [], "deleted": [], "dashboardView": ["notBlank"], "lazy_blocked": [], "backend_register": ["notBlank"], "write_protect": [], "user": ["notBlank"], "backend_status": ["notBlank"], "order": ["notBlank"], "id": [], "no_sync": [], "enacted": []};
+};
+xosvalidators = new xos_get_validators();
+/* eslint-enable quotes, no-undef, max-len, new-cap*/
diff --git a/xos/core/xoslib/static/js/xoslib/xosHelper.js b/xos/core/xoslib/static/js/xoslib/xosHelper.js
new file mode 100644
index 0000000..2f49a02
--- /dev/null
+++ b/xos/core/xoslib/static/js/xoslib/xosHelper.js
@@ -0,0 +1,1183 @@
+/* eslint-disable */
+HTMLView = Marionette.ItemView.extend({
+  render: function() {
+      this.$el.append(this.options.html);
+  },
+});
+
+FilteredCompositeView = Marionette.CompositeView.extend( {
+    showCollection: function() {
+      var ChildView;
+      this.collection.each(function(child, index) {
+        filterFunc = this.options.filter || this.filter;
+        if (filterFunc && !filterFunc(child)) {
+            return;
+        }
+        ChildView = this.getChildView(child);
+        this.addChild(child, ChildView, index);
+      }, this);
+
+    },
+});
+
+SliceSelectorOption = Marionette.ItemView.extend({
+    template: "#xos-sliceselector-option",
+    tagName: "option",
+    attributes: function() {
+        if (this.options.selectedID == this.model.get("id")) {
+            return { value: this.model.get("id"), selected: 1 };
+        } else {
+            return { value: this.model.get("id") };
+        }
+    },
+});
+
+SliceSelectorView = FilteredCompositeView.extend({
+    template: "#xos-sliceselector-select",
+    childViewContainer: "select",
+    childView: SliceSelectorOption,
+    caption: "Slice",
+
+    events: {"change select": "onSliceChanged"},
+
+    childViewOptions: function() {
+        return { selectedID: this.options.selectedID || this.selectedID || null };
+    },
+
+    onSliceChanged: function() {
+        this.sliceChanged(this.$el.find("select").val());
+    },
+
+    sliceChanged: function(id) {
+        console.log("sliceChanged " + id);
+    },
+
+    templateHelpers: function() { return {caption: this.options.caption || this.caption }; },
+});
+
+XOSRouter = Marionette.AppRouter.extend({
+        initialize: function() {
+            this.routeStack=[];
+        },
+
+        onRoute: function(x,y,z) {
+             this.routeStack.push(Backbone.history.fragment);
+             this.routeStack = this.routeStack.slice(-32);   // limit the size of routeStack to something reasonable
+        },
+
+        prevPage: function() {
+             return this.routeStack.slice(-1)[0];
+        },
+
+        showPreviousURL: function() {
+            prevPage = this.prevPage();
+            //console.log("showPreviousURL");
+            //console.log(this.routeStack);
+            if (prevPage) {
+                this.navigate("#"+prevPage, {trigger: false, replace: true} );
+            }
+        },
+
+        navigate: function(href, options) {
+            if (options.force) {
+                Marionette.AppRouter.prototype.navigate.call(this, "nowhere", {trigger: false, replace: true});
+            }
+            Marionette.AppRouter.prototype.navigate.call(this, href, options);
+        },
+    });
+
+// XXX - We import backbone multiple times (BAD!) since the import happens
+//   inside of the view's html. The second time it's imported (developer
+//   view), it wipes out Backbone.Syphon. So, save it as Backbone_Syphon for
+//   now.
+Backbone_Syphon = Backbone.Syphon
+Backbone_Syphon.InputReaders.register('select', function(el) {
+    // Modify syphon so that if a select has "syphonall" in the class, then
+    // the value of every option will be returned, regardless of whether of
+    // not it is selected.
+    if (el.hasClass("syphonall")) {
+        result = [];
+        _.each(el.find("option"), function(option) {
+            result.push($(option).val());
+        });
+        return result;
+    }
+    return el.val();
+});
+
+XOSApplication = Marionette.Application.extend({
+    detailBoxId: "#detailBox",
+    errorBoxId: "#errorBox",
+    errorCloseButtonId: "#close-error-box",
+    successBoxId: "#successBox",
+    successCloseButtonId: "#close-success-box",
+    errorTemplate: "#xos-error-template",
+    successTemplate: "#xos-success-template",
+    logMessageCount: 0,
+
+    confirmDialog: function(view, event, callback) {
+        $("#xos-confirm-dialog").dialog({
+           autoOpen: false,
+           modal: true,
+           buttons : {
+                "Confirm" : function() {
+                  $(this).dialog("close");
+                  if (event) {
+                      view.trigger(event);
+                  }
+                  if (callback) {
+                      callback();
+                  }
+                },
+                "Cancel" : function() {
+                  $(this).dialog("close");
+                }
+              }
+            });
+        $("#xos-confirm-dialog").dialog("open");
+    },
+
+    popupErrorDialog: function(responseText) {
+        try {
+            parsed_error=$.parseJSON(responseText);
+            width=300;
+        }
+        catch(err) {
+            parsed_error=undefined;
+            width=640;    // django stacktraces like wide width
+        }
+
+        console.log(responseText);
+        console.log(parsed_error);
+
+        if (parsed_error && ("detail" in parsed_error)) {
+            parsed_error = parsed_error["detail"];
+        }
+
+        if (parsed_error && ("error" in parsed_error)) {
+            if ((!parsed_error.reasons) && (parsed_error.fields)) {
+                // deal with me renaming 'reasons' to 'fields'
+                parsed_error.reasons = parsed_error.fields;
+            }
+            // this error comes from genapi views
+            $("#xos-error-dialog").html(templateFromId("#xos-error-response")(parsed_error));
+        } else {
+            $("#xos-error-dialog").html(templateFromId("#xos-error-rawresponse")({responseText: strip_scripts(responseText)}))
+        }
+
+        $("#xos-error-dialog").dialog({
+            modal: true,
+            width: width,
+            buttons: {
+                Ok: function() { $(this).dialog("close"); }
+            }
+        });
+    },
+
+    hideLinkedItems: function(result) {
+        var index=0;
+        while (index<4) {
+            this["linkedObjs" + (index+1)].empty();
+            index = index + 1;
+        }
+    },
+
+    hideTabs: function() { $("#tabs").hide(); },
+    showTabs: function() { $("#tabs").show(); },
+
+    createListHandler: function(listViewName, collection_name, regionName, title) {
+        var app=this;
+        return function() {
+            listView = new app[listViewName];
+            app[regionName].show(listView);
+            app.hideLinkedItems();
+            $("#contentTitle").html(templateFromId("#xos-title-list")({"title": title}));
+            $(document).attr('title', title);
+            $("#detail").show();
+            app.hideTabs();
+
+            listButtons = new XOSListButtonView({linkedView: listView});
+            app["rightButtonPanel"].show(listButtons);
+        }
+    },
+
+    createAddHandler: function(detailName, collection_name, regionName, title) {
+        var app=this;
+        return function() {
+            console.log("addHandler");
+
+            app.hideLinkedItems();
+            app.hideTabs();
+
+            model = new xos[collection_name].model();
+            detailViewClass = app[detailName];
+            detailView = new detailViewClass({model: model, collection:xos[collection_name]});
+            app[regionName].show(detailView);
+
+            detailButtons = new XOSDetailButtonView({linkedView: detailView});
+            app["rightButtonPanel"].show(detailButtons);
+        }
+    },
+
+    createAddChildHandler: function(addChildName, collection_name) {
+        var app=this;
+        return function(parent_modelName, parent_fieldName, parent_id) {
+            app.Router.showPreviousURL();
+            model = new xos[collection_name].model();
+            model.attributes[parent_fieldName] = parent_id;
+            model.readOnlyFields.push(parent_fieldName);
+            detailViewClass = app[addChildName];
+            var detailView = new detailViewClass({model: model, collection:xos[collection_name]});
+            detailView.dialog = $("xos-addchild-dialog");
+            app["addChildDetail"].show(detailView);
+            $("#xos-addchild-dialog").dialog({
+               autoOpen: false,
+               modal: true,
+               width: 640,
+               buttons : {
+                    "Save" : function() {
+                      var addDialog = this;
+                      detailView.synchronous = true;
+                      detailView.afterSave = function() { console.log("addChild afterSave"); $(addDialog).dialog("close"); }
+                      detailView.save();
+
+                      //$(this).dialog("close");
+                    },
+                    "Cancel" : function() {
+                      $(this).dialog("close");
+                    }
+                  }
+                });
+            $("#xos-addchild-dialog").dialog("open");
+        }
+    },
+
+    createDeleteHandler: function(collection_name) {
+        var app=this;
+        return function(model_id) {
+            console.log("deleteCalled");
+            collection = xos[collection_name];
+            model = collection.get(model_id);
+            assert(model!=undefined, "failed to get model " + model_id + " from collection " + collection_name);
+            app.Router.showPreviousURL();
+            app.deleteDialog(model);
+        }
+    },
+
+    createDetailHandler: function(detailName, collection_name, regionName, title) {
+        var app=this;
+        var detail_title=title;
+        showModelId = function(model_id) {
+            collection = xos[collection_name];
+            model = collection.get(model_id);
+            if (model == undefined) {
+                app[regionName].show(new HTMLView({html: "failed to load object " + model_id + " from collection " + collection_name}));
+            } else {
+                var title = detail_title + ": " + model.attributes.humanReadableName;
+
+                $("#contentTitle").html(templateFromId("#xos-title-detail")({"title": title}));
+
+                $(document).attr('title', title);
+
+                detailViewClass = app[detailName];
+                detailView = new detailViewClass({model: model});
+                app[regionName].show(detailView);
+                detailView.showLinkedItems();
+
+                detailButtons = new XOSDetailButtonView({linkedView: detailView});
+                app["rightButtonPanel"].show(detailButtons);
+            }
+        }
+        return showModelId;
+    },
+
+    /* error handling callbacks */
+
+    hideError: function() {
+        if (this.logWindowId) {
+        } else {
+            $(this.errorBoxId).hide();
+            $(this.successBoxId).hide();
+        }
+    },
+
+    showSuccess: function(result) {
+         result["statusclass"] = "success";
+         if (this.logTableId) {
+             this.appendLogWindow(result);
+         } else {
+             $(this.successBoxId).show();
+             $(this.successBoxId).html(_.template($(this.successTemplate).html())(result));
+             var that=this;
+             $(this.successCloseButtonId).unbind().bind('click', function() {
+                 $(that.successBoxId).hide();
+             });
+         }
+    },
+
+    showError: function(result) {
+         result["statusclass"] = "failure";
+         if (this.logTableId) {
+             this.appendLogWindow(result);
+             this.popupErrorDialog(result.responseText);
+         } else {
+             // this is really old stuff
+             $(this.errorBoxId).show();
+             $(this.errorBoxId).html(_.template($(this.errorTemplate).html())(result));
+             var that=this;
+             $(this.errorCloseButtonId).unbind().bind('click', function() {
+                 $(that.errorBoxId).hide();
+             });
+         }
+    },
+
+    showInformational: function(result) {
+         result["statusclass"] = "inprog";
+         if (this.logTableId) {
+             return this.appendLogWindow(result);
+         } else {
+             return undefined;
+         }
+    },
+
+    appendLogWindow: function(result) {
+        // compute a new logMessageId for this log message
+        logMessageId = "logMessage" + this.logMessageCount;
+        this.logMessageCount = this.logMessageCount + 1;
+        result["logMessageId"] = logMessageId;
+
+        logMessageTemplate=$("#xos-log-template").html();
+        assert(logMessageTemplate != undefined, "logMessageTemplate is undefined");
+        newRow = _.template(logMessageTemplate, result);
+        assert(newRow != undefined, "newRow is undefined");
+
+        if (result["infoMsgId"] != undefined) {
+            // We were passed the logMessageId of an informational message,
+            // and the caller wants us to replace that message with our own.
+            // i.e. replace an informational message with a success or an error.
+            $("#"+result["infoMsgId"]).replaceWith(newRow);
+        } else {
+            // Create a brand new log message rather than replacing one.
+            logTableBody = $(this.logTableId + " tbody");
+            logTableBody.prepend(newRow);
+        }
+
+        if (this.statusMsgId) {
+            $(this.statusMsgId).html( templateFromId("#xos-status-template")(result) );
+        }
+
+        limitTableRows(this.logTableId, 5);
+
+        return logMessageId;
+    },
+
+    saveError: function(model, result, xhr, infoMsgId) {
+        console.log("saveError");
+        result["what"] = "save " + model.modelName + " " + model.attributes.humanReadableName;
+        result["infoMsgId"] = infoMsgId;
+        this.showError(result);
+    },
+
+    saveSuccess: function(model, result, xhr, infoMsgId, addToCollection) {
+        console.log("saveSuccess");
+        if (model.addToCollection) {
+            console.log("addToCollection");
+            console.log(model.addToCollection);
+            model.addToCollection.add(model);
+            model.addToCollection.sort();
+            model.addToCollection = undefined;
+        }
+        result = {status: xhr.xhr.status, statusText: xhr.xhr.statusText};
+        result["what"] = "save " + model.modelName + " " + model.attributes.humanReadableName;
+        result["infoMsgId"] = infoMsgId;
+        this.showSuccess(result);
+    },
+
+    destroyError: function(model, result, xhr, infoMsgId) {
+        result["what"] = "destroy " + model.modelName + " " + model.attributes.humanReadableName;
+        result["infoMsgId"] = infoMsgId;
+        this.showError(result);
+    },
+
+    destroySuccess: function(model, result, xhr, infoMsgId) {
+        result = {status: xhr.xhr.status, statusText: xhr.xhr.statusText};
+        result["what"] = "destroy " + model.modelName + " " + model.attributes.humanReadableName;
+        result["infoMsgId"] = infoMsgId;
+        this.showSuccess(result);
+    },
+
+    /* end error handling callbacks */
+
+    destroyModel: function(model) {
+         //console.log("destroyModel"); console.log(model);
+         this.hideError();
+         var infoMsgId = this.showInformational( {what: "destroy " + model.modelName + " " + model.attributes.humanReadableName, status: "", statusText: "in progress..."} );
+         var that = this;
+         model.destroy({error: function(model, result, xhr) { that.destroyError(model,result,xhr,infoMsgId);},
+                        success: function(model, result, xhr) { that.destroySuccess(model,result,xhr,infoMsgId);}});
+    },
+
+    deleteDialog: function(model, afterDelete) {
+        var that=this;
+        assert(model!=undefined, "deleteDialog's model is undefined");
+        //console.log("deleteDialog"); console.log(model);
+        this.confirmDialog(null, null, function() {
+            //console.log("deleteConfirm"); console.log(model);
+            modelName = model.modelName;
+            that.destroyModel(model);
+            if (afterDelete=="list") {
+                that.navigate("list", modelName);
+            } else if (afterDelete) {
+                afterDelete();
+            }
+        });
+    },
+});
+
+XOSButtonView = Marionette.ItemView.extend({
+            events: {"click button.btn-xos-save-continue": "submitContinueClicked",
+                     "click button.btn-xos-save-leave": "submitLeaveClicked",
+                     "click button.btn-xos-save-another": "submitAddAnotherClicked",
+                     "click button.btn-xos-delete": "deleteClicked",
+                     "click button.btn-xos-add": "addClicked",
+                     "click button.btn-xos-refresh": "refreshClicked",
+                     },
+
+            submitLeaveClicked: function(e) {
+                     this.options.linkedView.submitLeaveClicked.call(this.options.linkedView, e);
+                     },
+
+            submitContinueClicked: function(e) {
+                     this.options.linkedView.submitContinueClicked.call(this.options.linkedView, e);
+                     },
+
+            submitAddAnotherClicked: function(e) {
+                     this.options.linkedView.submitAddAnotherClicked.call(this.options.linkedView, e);
+                     },
+
+            submitDeleteClicked: function(e) {
+                     this.options.linkedView.deleteClicked.call(this.options.linkedView, e);
+                     },
+
+            addClicked: function(e) {
+                     this.options.linkedView.addClicked.call(this.options.linkedView, e);
+                     },
+
+            refreshClicked: function(e) {
+                     this.options.linkedView.refreshClicked.call(this.options.linkedView, e);
+                     },
+
+            templateHelpers: function() { return {disableAdd: this.options.linkedView.disableAdd }; },
+            });
+
+
+XOSDetailButtonView = XOSButtonView.extend({ template: "#xos-savebuttons-template" });
+XOSListButtonView = XOSButtonView.extend({ template: "#xos-listbuttons-template" });
+
+/* XOSDetailView
+      extend with:
+         app - MarionetteApplication
+         template - template (See XOSHelper.html)
+*/
+
+XOSDetailView = Marionette.ItemView.extend({
+            tagName: "div",
+
+            viewInitializers: [],
+
+            events: {"click button.btn-xos-save-continue": "submitContinueClicked",
+                     "click button.btn-xos-save-leave": "submitLeaveClicked",
+                     "click button.btn-xos-save-another": "submitAddAnotherClicked",
+                     "click button.btn-xos-delete": "deleteClicked",
+                     "change input": "inputChanged"},
+
+            /* inputChanged is watching the onChange events of the input controls. We
+               do this to track when this view is 'dirty', so we can throw up a warning
+               if the user tries to change his slices without saving first.
+            */
+
+            initialize: function() {
+                this.on("saveSuccess", this.onSaveSuccess);
+                this.synchronous = false;
+            },
+
+            onShow: function() {
+                _.each(this.viewInitializers, function(initializer) {
+                    initializer();
+                });
+            },
+
+            saveSuccess: function(e) {
+                // always called after a save succeeds
+            },
+
+            afterSave: function(e) {
+                // if this.synchronous, then called after the save succeeds
+                // if !this.synchronous, then called after save is initiated
+            },
+
+            onSaveSuccess: function(e) {
+                this.saveSuccess(e);
+                if (this.synchronous) {
+                    this.afterSave(e);
+                }
+            },
+
+            inputChanged: function(e) {
+                this.dirty = true;
+            },
+
+            submitContinueClicked: function(e) {
+                console.log("saveContinue");
+                e.preventDefault();
+                this.afterSave = function() { };
+                this.save();
+            },
+
+            submitLeaveClicked: function(e) {
+                console.log("saveLeave");
+                e.preventDefault();
+                if (this.options.noSubmitButton || this.noSubmitButton) {
+                    return;
+                }
+                var that=this;
+                this.afterSave = function() {
+                    that.app.navigate("list", that.model.modelName);
+                }
+                this.save();
+            },
+
+            submitAddAnotherClicked: function(e) {
+                console.log("saveAnother");
+                console.log(this);
+                e.preventDefault();
+                var that=this;
+                this.afterSave = function() {
+                    console.log("addAnother afterSave");
+                    that.app.navigate("add", that.model.modelName);
+                }
+                this.save();
+            },
+
+            save: function() {
+                this.app.hideError();
+                var data = Backbone_Syphon.serialize(this);
+                var that = this;
+                var isNew = !this.model.id;
+
+                console.log('data', data);
+
+                this.$el.find(".help-inline").remove();
+
+                /* although model.validate() is called automatically by
+                   model.save, we call it ourselves, so we can throw up our
+                   validation error before creating the infoMsg in the log
+                */
+               
+                errors =  this.model.xosValidate(data);
+
+                if (errors) {
+                    this.onFormDataInvalid(errors);
+                    return;
+                }
+
+                if (isNew) {
+                    this.model.attributes.humanReadableName = "new " + this.model.modelName;
+                    this.model.addToCollection = this.collection;
+                } else {
+                    this.model.addToCollection = undefined;
+                }
+
+                var infoMsgId = this.app.showInformational( {what: "save " + this.model.modelName + " " + this.model.attributes.humanReadableName, status: "", statusText: "in progress..."} );
+
+                this.model.save(data, {error: function(model, result, xhr) { that.app.saveError(model,result,xhr,infoMsgId);},
+                                       success: function(model, result, xhr) { that.app.saveSuccess(model,result,xhr,infoMsgId);
+                                                                               that.trigger("saveSuccess");
+                                                                             }});
+                this.dirty = false;
+
+                if (!this.synchronous) {
+                    this.afterSave();
+                }
+            },
+
+            deleteClicked: function(e) {
+                e.preventDefault();
+                this.app.deleteDialog(this.model, "list");
+            },
+
+            tabClick: function(tabId, regionName) {
+                    region = this.app[regionName];
+                    if (this.currentTabRegion != undefined) {
+                        this.currentTabRegion.$el.hide();
+                    }
+                    if (this.currentTabId != undefined) {
+                        $(this.currentTabId).removeClass('active');
+                    }
+                    this.currentTabRegion = region;
+                    this.currentTabRegion.$el.show();
+
+                    this.currentTabId = tabId;
+                    $(tabId).addClass('active');
+            },
+
+            showTabs: function(tabs) {
+                template = templateFromId("#xos-tabs-template", {tabs: tabs});
+                $("#tabs").html(template(tabs));
+                var that = this;
+
+                _.each(tabs, function(tab) {
+                    var regionName = tab["region"];
+                    var tabId = '#xos-nav-'+regionName;
+                    $(tabId).bind('click', function() { that.tabClick(tabId, regionName); });
+                });
+
+                $("#tabs").show();
+            },
+
+            showLinkedItems: function() {
+                    tabs=[];
+
+                    tabs.push({name: "details", region: "detail"});
+
+                    makeFilter = function(relatedField, relatedId) {
+                        return function(model) { return model.attributes[relatedField] == relatedId; }
+                    };
+
+                    var index=0;
+                    for (relatedName in this.model.collection.relatedCollections) {
+                        var relatedField = this.model.collection.relatedCollections[relatedName];
+                        var relatedId = this.model.id;
+                        regionName = "linkedObjs" + (index+1);
+
+                        relatedListViewClassName = relatedName + "ListView";
+                        assert(this.app[relatedListViewClassName] != undefined, relatedListViewClassName + " not found");
+                        relatedListViewClass = this.app[relatedListViewClassName].extend({collection: xos[relatedName],
+                                                                                          filter: makeFilter(relatedField, relatedId),
+                                                                                          parentModel: this.model});
+                        this.app[regionName].show(new relatedListViewClass());
+                        if (this.app.hideTabsByDefault) {
+                            this.app[regionName].$el.hide();
+                        }
+                        tabs.push({name: relatedName, region: regionName});
+                        index = index + 1;
+                    }
+
+                    while (index<4) {
+                        this.app["linkedObjs" + (index+1)].empty();
+                        index = index + 1;
+                    }
+
+                    this.showTabs(tabs);
+                    this.tabClick('#xos-nav-detail', 'detail');
+              },
+
+            onFormDataInvalid: function(errors) {
+
+
+                var self=this;
+
+                var markErrors = function(value, key) {
+                    var $inputElement = self.$el.find("[name='" + key + "']");
+                    var $inputContainer = $inputElement.parent();
+                    //$inputContainer.find(".help-inline").remove();
+                    // var $errorEl = $("<span>", {class: "help-inline error", text: value});
+                    $inputContainer.find(".alert.alert-danger").remove();
+                    var $errorEl = $("<span>", {class: "alert alert-danger", text: value});
+                    $inputContainer.append($errorEl).addClass("error");
+                }
+                _.each(errors, markErrors);
+            },
+
+             templateHelpers: function() { return { modelName: this.model.modelName,
+                                                    collectionName: this.model.collectionName,
+                                                    addFields: this.model.addFields,
+                                                    listFields: this.model.listFields,
+                                                    detailFields: this.options.detailFields || this.detailFields || this.model.detailFields,
+                                                    fieldDisplayNames: this.options.fieldDisplayNames || this.fieldDisplayNames || this.model.fieldDisplayNames || {},
+                                                    foreignFields: this.model.foreignFields,
+                                                    detailLinkFields: this.model.detailLinkFields,
+                                                    inputType: this.model.inputType,
+                                                    model: this.model,
+                                                    detailView: this,
+                                                    choices: this.options.choices || this.choices || this.model.choices || {},
+                                                    helpText: this.options.helpText || this.helpText || this.model.helpText || {},
+                                         }},
+
+             disableAdd: function() { return this.disableAdd || this.options.disableAdd || this.model.disableAdd; },
+});
+
+XOSDetailView_instance = XOSDetailView.extend( {
+    events: $.extend(XOSDetailView.events,
+        {"change #field_deployment": "onDeploymentChange"}
+    ),
+
+    onShow: function() {
+        // Note that this causes the selects to be updated a second time. The
+        // first time was when the template was originally invoked, and the
+        // selects will all have the full unfiltered set of candidates. Then
+        // onShow will fire, and we'll update them with the filtered values.
+        this.onDeploymentChange();
+    },
+
+    onDeploymentChange: function(e) {
+        var deploymentID = this.$el.find("#field_deployment").val();
+
+        //console.log("onDeploymentChange");
+
+        filterFunc = function(model) { for (index in xos.siteDeployments.models) {
+                                           site_deployment = xos.siteDeployments.models[index];
+                                           if (site_deployment.attributes.id == model.attributes.site_deployment) {
+                                               return (site_deployment.attributes.deployment == deploymentID);
+                                           }
+                                        }
+                                        return false;
+                                        // return (model.attributes.deployment==deploymentID); }
+                                      };
+        newSelect = idToSelect("node",
+                               this.model.attributes.node,
+                               this.model.foreignFields["node"],
+                               "humanReadableName",
+                               false,
+                               filterFunc);
+        this.$el.find("#field_node").html(newSelect);
+
+        filterFunc = function(model) { for (index in model.attributes.deployments) {
+                                          if (model.attributes.deployments[index] == deploymentID) return true;
+                                        };
+                                        return false;
+                                     }
+        newSelect = idToSelect("flavor",
+                               this.model.attributes.flavor,
+                               this.model.foreignFields["flavor"],
+                               "humanReadableName",
+                               false,
+                               filterFunc);
+        this.$el.find("#field_flavor").html(newSelect);
+
+        filterFunc = function(model) { for (index in model.attributes.deployments) {
+                                           if (model.attributes.deployments[index] == deploymentID) return true;
+                                       };
+                                       return false;
+                                     };
+        newSelect = idToSelect("image",
+                               this.model.attributes.image,
+                               this.model.foreignFields["image"],
+                               "humanReadableName",
+                               false,
+                               filterFunc);
+        this.$el.find("#field_image").html(newSelect);
+    },
+});
+
+/* XOSItemView
+      This is for items that will be displayed as table rows.
+      extend with:
+         app - MarionetteApplication
+         template - template (See XOSHelper.html)
+*/
+
+XOSItemView = Marionette.ItemView.extend({
+             tagName: 'tr',
+             className: 'test-tablerow',
+
+             templateHelpers: function() { return { modelName: this.model.modelName,
+                                                    collectionName: this.model.collectionName,
+                                                    listFields: this.model.listFields,
+                                                    addFields: this.model.addFields,
+                                                    detailFields: this.model.detailFields,
+                                                    foreignFields: this.model.foreignFields,
+                                                    detailLinkFields: this.model.detailLinkFields,
+                                                    inputType: this.model.inputType,
+                                                    model: this.model,
+                                         }},
+});
+
+/* XOSListView:
+      extend with:
+         app - MarionetteApplication
+         childView - class of ItemView, probably an XOSItemView
+         template - template (see xosHelper.html)
+         collection - collection that holds these objects
+         title - title to display in template
+*/
+
+XOSListView = FilteredCompositeView.extend({
+             childViewContainer: 'tbody',
+             parentModel: null,
+
+             events: {"click button.btn-xos-add": "addClicked",
+                      "click button.btn-xos-refresh": "refreshClicked",
+                     },
+
+             _fetchStateChange: function() {
+                 if (this.collection.fetching) {
+                    $("#xos-list-title-spinner").show();
+                 } else {
+                    $("#xos-list-title-spinner").hide();
+                 }
+             },
+
+             addClicked: function(e) {
+                e.preventDefault();
+                this.app.Router.navigate("add" + firstCharUpper(this.collection.modelName), {trigger: true});
+             },
+
+             refreshClicked: function(e) {
+                 e.preventDefault();
+                 this.collection.refresh(refreshRelated=true);
+             },
+
+             initialize: function() {
+                 this.listenTo(this.collection, 'change', this._renderChildren)
+                 this.listenTo(this.collection, 'sort', function() { console.log("sort"); })
+                 this.listenTo(this.collection, 'add', function() { console.log("add"); })
+                 this.listenTo(this.collection, 'fetchStateChange', this._fetchStateChange);
+
+                 // Because many of the templates use idToName(), we need to
+                 // listen to the collections that hold the names for the ids
+                 // that we want to display.
+                 for (i in this.collection.foreignCollections) {
+                     foreignName = this.collection.foreignCollections[i];
+                     if (xos[foreignName] == undefined) {
+                         console.log("Failed to find xos class " + foreignName);
+                     }
+                     this.listenTo(xos[foreignName], 'change', this._renderChildren);
+                     this.listenTo(xos[foreignName], 'sort', this._renderChildren);
+                 }
+             },
+
+             getAddChildHash: function() {
+                if (this.parentModel) {
+                    parentFieldName = this.parentModel.relatedCollections[this.collection.collectionName];
+                    parentFieldName = parentFieldName || "unknown";
+
+                    /*parentFieldName = "unknown";
+
+                    for (fieldName in this.collection.foreignFields) {
+                        cname = this.collection.foreignFields[fieldName];
+                        if (cname = this.collection.collectionName) {
+                            parentFieldName = fieldName;
+                        }
+                    }*/
+                    return "#addChild" + firstCharUpper(this.collection.modelName) + "/" + this.parentModel.modelName + "/" + parentFieldName + "/" + this.parentModel.id; // modelName, fieldName, id
+                } else {
+                    return null;
+                }
+             },
+
+             templateHelpers: function() {
+                return { title: this.title,
+                         addChildHash: this.getAddChildHash(),
+                         foreignFields: this.collection.foreignFields,
+                         listFields: this.collection.listFields,
+                         detailLinkFields: this.collection.detailLinkFields, };
+             },
+
+             disableAdd: function() { return this.disableAdd || this.options.disableAdd || this.collection.disableAdd; }
+});
+
+XOSDataTableView = Marionette.View.extend( {
+    el: '<div style="overflow: hidden">' +
+        '<h3 class="xos-list-title title_placeholder"></h3>' +
+        '<div class="header_placeholder"></div>' +
+        '<table></table>' +
+        '<div class="footer_placeholder"></div>' +
+        '</div>',
+
+    filter: undefined,
+
+     events: {"click button.btn-xos-add": "addClicked",
+              "click button.btn-xos-refresh": "refreshClicked",
+             },
+
+     _fetchStateChange: function() {
+         if (this.collection.fetching) {
+            $("#xos-list-title-spinner").show();
+         } else {
+            $("#xos-list-title-spinner").hide();
+         }
+     },
+
+     addClicked: function(e) {
+        e.preventDefault();
+        this.app.Router.navigate("add" + firstCharUpper(this.collection.modelName), {trigger: true});
+     },
+
+     refreshClicked: function(e) {
+         e.preventDefault();
+         this.collection.refresh(refreshRelated=true);
+     },
+
+
+    initialize: function() {
+        $(this.el).find(".footer_placeholder").html( xosListFooterTemplate({addChildHash: this.getAddChildHash()}) );
+        $(this.el).find(".header_placeholder").html( xosListHeaderTemplate() );
+
+        this.listenTo(this.collection, 'fetchStateChange', this._fetchStateChange);
+    },
+
+    render: function() {
+        var view = this;
+        var fieldDisplayNames = view.options.fieldDisplayNames || view.fieldDisplayNames || {};
+
+        view.columnsByIndex = [];
+        view.columnsByFieldName = {};
+        _.each(this.collection.listFields, function(fieldName) {
+            inputType = view.options.inputType || view.inputType || {};
+            mRender = undefined;
+            mSearchText = undefined;
+            sTitle = fieldName in fieldDisplayNames ? fieldDisplayNames[fieldName] : fieldNameToHumanReadable(fieldName);
+            bSortable = true;
+            if (fieldName=="backend_status") {
+                mRender = function(x,y,z) { return xosBackendStatusIconTemplate(z); };
+                sTitle = "";
+                bSortable = false;
+            } else if (fieldName in view.collection.foreignFields) {
+                var foreignCollection = view.collection.foreignFields[fieldName];
+                mSearchText = function(x) { return idToName(x, foreignCollection, "humanReadableName"); };
+            } else if (inputType[fieldName] == "spinner") {
+                mRender = function(x,y,z) { return xosDataTableSpinnerTemplate( {value: x, collectionName: view.collection.collectionName, fieldName: fieldName, id: z.id, app: view.app} ); };
+            }
+            if ($.inArray(fieldName, view.collection.detailLinkFields)>=0) {
+                var collectionName = view.collection.collectionName;
+                mRender = function(x,y,z) { return '<a href="#' + collectionName + '/' + z.id + '">' + x + '</a>'; };
+            }
+            thisColumn = {sTitle: sTitle, bSortable: bSortable, mData: fieldName, mRender: mRender, mSearchText: mSearchText};
+            view.columnsByIndex.push( thisColumn );
+            view.columnsByFieldName[fieldName] = thisColumn;
+        });
+
+        if (!view.noDeleteColumn) {
+            deleteColumn = {sTitle: "", bSortable: false, mRender: function(x,y,z) { return xosDeleteButtonTemplate({modelName: view.collection.modelName, id: z.id}); }, mData: function() { return "delete"; }};
+            view.columnsByIndex.push(deleteColumn);
+            view.columnsByFieldName["delete"] = deleteColumn;
+        };
+
+        oTable = $(this.el).find("table").dataTable( {
+            "bJQueryUI": true,
+            "bStateSave": true,
+            "bServerSide": true,
+            "bFilter": ! (view.options.disableFilter || view.disableFilter),
+            "bPaginate": ! (view.options.disablePaginate || view.disablePaginate),
+            "aoColumns": view.columnsByIndex,
+
+            fnServerData: function(sSource, aoData, fnCallback, settings) {
+                var compareColumns = function(sortCols, sortDirs, a, b) {
+                    a = a[sortCols[0]];
+                    b = b[sortCols[0]];
+                    result = (a==b) ? 0 : ((a<b) ? -1 : 1);
+                    if (sortDirs[0] == "desc") {
+                        result = -result;
+                    }
+                    return result;
+                };
+
+                var searchMatch = function(row, sSearch) {
+                    for (fieldName in row) {
+                        if (fieldName in view.columnsByFieldName) {
+                            try {
+                                value = row[fieldName].toString();
+                            } catch(e) {
+                                continue;
+                            }
+                            if (value.indexOf(sSearch) >= 0) {
+                                return true;
+                            }
+                        }
+                    }
+                    return false;
+                };
+
+                //console.log(aoData);
+
+                // function used to populate the DataTable with the current
+                // content of the collection
+                var populateTable = function()
+                {
+                  //console.log("populatetable!");
+
+                  // clear out old row views
+                  rows = [];
+
+                  sSearch = null;
+                  iDisplayStart = 0;
+                  iDisplayLength = 1000;
+                  sortDirs = [];
+                  sortCols = [];
+                  _.each(aoData, function(param) {
+                      if (param.name == "sSortDir_0") {
+                          sortDirs = [param.value];
+                      } else if (param.name == "iSortCol_0") {
+                          sortCols = [view.columnsByIndex[param.value].mData];
+                      } else if (param.name == "iDisplayStart") {
+                          iDisplayStart = param.value;
+                      } else if (param.name == "iDisplayLength") {
+                          iDisplayLength = param.value;
+                      } else if (param.name == "sSearch") {
+                          sSearch = param.value;
+                      }
+                  });
+
+                  aaData = view.collection.toJSON();
+
+                  // apply backbone filtering on the models
+                  if (view.filter) {
+                      aaData = aaData.filter( function(row) { model = {}; model.attributes = row; return view.filter(model); } );
+                  }
+
+                  var totalSize = aaData.length;
+
+                  // turn the ForeignKey fields into human readable things
+                  for (rowIndex in aaData) {
+                      row = aaData[rowIndex];
+                      for (fieldName in row) {
+                          if (fieldName in view.columnsByFieldName) {
+                              mSearchText = view.columnsByFieldName[fieldName].mSearchText;
+                              if (mSearchText) {
+                                  row[fieldName] = mSearchText(row[fieldName]);
+                              }
+                          }
+                      }
+                  }
+
+                  // apply datatables search
+                  if (sSearch) {
+                      aaData = aaData.filter( function(row) { return searchMatch(row, sSearch); });
+                  }
+
+                  var filteredSize = aaData.length;
+
+                  // apply datatables sort
+                  aaData.sort(function(a,b) { return compareColumns(sortCols, sortDirs, a, b); });
+
+                  // slice it for pagination
+                  if (iDisplayLength >= 0) {
+                      aaData = aaData.slice(iDisplayStart, iDisplayStart+iDisplayLength);
+                  }
+
+                  return fnCallback({iTotalRecords: totalSize,
+                         iTotalDisplayRecords: filteredSize,
+                         aaData: aaData});
+                };
+
+                aoData.shift(); // ignore sEcho
+                populateTable();
+
+                view.listenTo(view.collection, 'change', populateTable);
+                view.listenTo(view.collection, 'add', populateTable);
+                view.listenTo(view.collection, 'remove', populateTable);
+            },
+        } );
+
+        return this;
+    },
+
+     getAddChildHash: function() {
+        if (this.parentModel) {
+            parentFieldName = this.parentModel.relatedCollections[this.collection.collectionName];
+            parentFieldName = parentFieldName || "unknown";
+
+            /*parentFieldName = "unknown";
+
+            for (fieldName in this.collection.foreignFields) {
+                cname = this.collection.foreignFields[fieldName];
+                if (cname = this.collection.collectionName) {
+                    parentFieldName = fieldName;
+                }
+            }*/
+            return "#addChild" + firstCharUpper(this.collection.modelName) + "/" + this.parentModel.modelName + "/" + parentFieldName + "/" + this.parentModel.id; // modelName, fieldName, id
+        } else {
+            return null;
+        }
+     },
+
+     disableAdd: function() { return this.disableAdd || this.options.disableAdd || this.collection.disableAdd; },
+
+});
+
+idToName = function(id, collectionName, fieldName) {
+    return xos.idToName(id, collectionName, fieldName);
+};
+
+makeIdToName = function(collectionName, fieldName) {
+    return function(id) { return idToName(id, collectionName, fieldName); }
+};
+
+/* Constructs lists of <option> html blocks for items in a collection.
+
+   selectedId = the id of an object that should be selected, if any
+   collectionName = name of collection
+   fieldName = name of field within models of collection that will be displayed
+*/
+
+idToOptions = function(selectedId, collectionName, fieldName, filterFunc) {
+    result=""
+    for (index in xos[collectionName].models) {
+        linkedObject = xos[collectionName].models[index];
+        linkedId = linkedObject["id"];
+        linkedName = linkedObject.attributes[fieldName];
+        if (linkedId == selectedId) {
+            selected = " selected";
+        } else {
+            selected = "";
+        }
+        if ((filterFunc) && (!filterFunc(linkedObject))) {
+            continue;
+        }
+        result = result + '<option value="' + linkedId + '"' + selected + '>' + linkedName + '</option>';
+    }
+    return result;
+};
+
+/* Constructs an html <select> and the <option>s to go with it.
+
+   variable = variable name to return to form
+   selectedId = the id of an object that should be selected, if any
+   collectionName = name of collection
+   fieldName = name of field within models of collection that will be displayed
+*/
+
+idToSelect = function(variable, selectedId, collectionName, fieldName, readOnly, filterFunc) {
+    if (readOnly) {
+        readOnly = " readonly";
+    } else {
+        readOnly = "";
+    }
+    result = '<select class="form-control" name="' + variable + '" id="field_' + variable + '"' + readOnly + '>' +
+             idToOptions(selectedId, collectionName, fieldName, filterFunc) +
+             '</select>';
+    return result;
+}
+
+choicesToOptions = function(selectedValue, choices) {
+    result="";
+    for (index in choices) {
+        choice = choices[index];
+        displayName = choice[0];
+        value = choice[1];
+        if (value == selectedValue) {
+            selected = " selected";
+        } else {
+            selected = "";
+        }
+        result = result + '<option value="' + value + '"' + selected + '>' + displayName + '</option>';
+    }
+    return result;
+}
+
+choicesToSelect = function(variable, selectedValue, choices) {
+    result = '<select class="form-control" name="' + variable + '" id="field_' + variable + '">' +
+             choicesToOptions(selectedValue, choices) +
+             '</select>';
+    return result;
+}
+
+escapeForFormField = function(s) {
+    if (s===undefined) {
+        return "";
+    } else {
+        return String(s).replace(/"/g,'&quot;')
+    }
+}
+/* eslint-enable */
\ No newline at end of file
diff --git a/xos/core/xoslib/static/js/xsh/constants.js b/xos/core/xoslib/static/js/xsh/constants.js
new file mode 100644
index 0000000..97b690a
--- /dev/null
+++ b/xos/core/xoslib/static/js/xsh/constants.js
@@ -0,0 +1,39 @@
+// TryMongo

+//

+// Copyright (c) 2009 Kyle Banker

+// Licensed under the MIT Licence.

+// http://www.opensource.org/licenses/mit-license.php

+

+var DefaultInputHtml = function(stack) {

+    var linePrompt = "";

+    if(stack == 0) {

+      linePrompt += "<span class='prompt'> ></span>";

+    }

+    else {

+      for(var i=0; i <= stack; i++) {

+        linePrompt += "<span class='prompt'>.</span>";

+      }

+    }

+    return "<div class='terminal_line'>" +

+           linePrompt +

+           "<input type='text' class='readLine active' />" +

+           "</div>";

+}

+

+var EnterKeyCode     = 13;

+var UpArrowKeyCode   = 38;

+var DownArrowKeyCode = 40;

+

+var PTAG = function(str) {

+  return '<pre class="terminal_help">' + str + '</pre>';

+}

+

+var BR = function() {

+  return "<br/>";

+}

+

+var JavascriptKeywords = ['abstract', 'boolean', 'break', 'byte', 'case', 'catch', 'char', 'class', 'const', 'continue', 'debugger', 'default', 'delete', 'do', 'double', 'else', 'enum', 'export', 'extends', 'false', 'final', 'finally', 'float', 'for', 'function', 'goto', 'if', 'implements', 'import', 'in', 'instanceof', 'int', 'interface', 'long', 'native', 'new', 'null', 'package', 'private', 'protected', 'public', 'return', 'short', 'static', 'super', 'switch', 'synchronized', 'this', 'throw', 'throws', 'transient', 'true', 'try', 'typeof', 'var', 'void', 'volatile', 'while', 'with', 'alert', 'date', 'eval'];

+

+var JavascriptClassNames = ['Array', 'String', 'Object']

+

+var MongoKeywords = ['help','tutorial','next','back','t0','t1','t2','t3','t4'];

diff --git a/xos/core/xoslib/static/js/xsh/object_id.js b/xos/core/xoslib/static/js/xsh/object_id.js
new file mode 100644
index 0000000..15cbbb9
--- /dev/null
+++ b/xos/core/xoslib/static/js/xsh/object_id.js
@@ -0,0 +1,12 @@
+var ObjectIdCounter = 0;
+
+var ObjectId = function() {
+  this.counter = (ObjectIdCounter += 1);
+  this.str     = this.counter;
+  this.initialize();
+  return this.counter;
+};
+
+ObjectId.prototype.initialize = function() {
+  return this.counter;
+}
diff --git a/xos/core/xoslib/static/js/xsh/shell_utils.js b/xos/core/xoslib/static/js/xsh/shell_utils.js
new file mode 100644
index 0000000..8ed5f4f
--- /dev/null
+++ b/xos/core/xoslib/static/js/xsh/shell_utils.js
@@ -0,0 +1,548 @@
+DB = function() {
+}
+
+print = function(msg) {
+  //console.log(msg);
+}
+
+
+friendlyEqual = function( a , b ){
+    if ( a == b )
+        return true;
+
+    if ( tojson( a ) == tojson( b ) )
+        return true;
+
+    return false;
+}
+
+
+doassert = function( msg ){
+    print( "assert: " + msg );
+    throw msg;
+}
+
+assert = function( b , msg ){
+    if ( assert._debug && msg ) print( "in assert for: " + msg );
+
+    if ( b )
+        return;
+    
+    doassert( "assert failed : " + msg );
+}
+
+assert.eq = function( a , b , msg ){
+    if ( assert._debug && msg ) print( "in assert for: " + msg );
+
+    if ( a == b )
+        return;
+
+    if ( ( a != null && b != null ) && friendlyEqual( a , b ) )
+        return;
+
+    doassert( "[" + tojson( a ) + "] != [" + tojson( b ) + "] are not equal : " + msg );
+}
+
+assert.neq = function( a , b , msg ){
+    if ( assert._debug && msg ) print( "in assert for: " + msg );
+    if ( a != b )
+        return;
+
+    doassert( "[" + a + "] != [" + b + "] are equal : " + msg );
+}
+
+assert.soon = function( f, msg, timeout, interval ) {
+    if ( assert._debug && msg ) print( "in assert for: " + msg );
+
+    var start = new Date();
+    timeout = timeout || 30000;
+    interval = interval || 200;
+    var last;
+    while( 1 ) {
+        
+        if ( typeof( f ) == "string" ){
+            if ( eval( f ) )
+                return;
+        }
+        else {
+            if ( f() )
+                return;
+        }
+        
+        if ( ( new Date() ).getTime() - start.getTime() > timeout )
+            doassert( "assert.soon failed: " + f + ", msg:" + msg );
+        sleep( interval );
+    }
+}
+
+assert.throws = function( func , params , msg ){
+    if ( assert._debug && msg ) print( "in assert for: " + msg );
+    try {
+        func.apply( null , params );
+    }
+    catch ( e ){
+        return e;
+    }
+
+    doassert( "did not throw exception: " + msg );
+}
+
+assert.commandWorked = function( res , msg ){
+    if ( assert._debug && msg ) print( "in assert for: " + msg );
+
+    if ( res.ok == 1 )
+        return;
+    
+    doassert( "command failed: " + tojson( res ) + " : " + msg );
+}
+
+assert.commandFailed = function( res , msg ){
+    if ( assert._debug && msg ) print( "in assert for: " + msg );
+
+    if ( res.ok == 0 )
+        return;
+    
+    doassert( "command worked when it should have failed: " + tojson( res ) + " : " + msg );
+}
+
+assert.isnull = function( what , msg ){
+    if ( assert._debug && msg ) print( "in assert for: " + msg );
+
+    if ( what == null )
+        return;
+    
+    doassert( "supposed to null (" + ( msg || "" ) + ") was: " + tojson( what ) );
+}
+
+assert.lt = function( a , b , msg ){
+    if ( assert._debug && msg ) print( "in assert for: " + msg );
+
+    if ( a < b )
+        return;
+    doassert( a + " is not less than " + b + " : " + msg );
+}
+
+assert.gt = function( a , b , msg ){
+    if ( assert._debug && msg ) print( "in assert for: " + msg );
+
+    if ( a > b )
+        return;
+    doassert( a + " is not greater than " + b + " : " + msg );
+}
+
+Object.extend = function( dst , src , deep ){
+    for ( var k in src ){
+        var v = src[k];
+        if ( deep && typeof(v) == "object" ){
+            v = Object.extend( typeof ( v.length ) == "number" ? [] : {} , v , true );
+        }
+        dst[k] = v;
+    }
+    return dst;
+}
+
+argumentsToArray = function( a ){
+    var arr = [];
+    for ( var i=0; i<a.length; i++ )
+        arr[i] = a[i];
+    return arr;
+}
+
+isString = function( x ){
+    return typeof( x ) == "string";
+}
+
+isNumber = function(x){
+    return typeof( x ) == "number";
+}
+
+isObject = function( x ){
+    return typeof( x ) == "object";
+}
+
+String.prototype.trim = function() {
+    return this.replace(/^\s+|\s+$/g,"");
+}
+String.prototype.ltrim = function() {
+    return this.replace(/^\s+/,"");
+}
+String.prototype.rtrim = function() {
+    return this.replace(/\s+$/,"");
+}
+
+Date.timeFunc = function( theFunc , numTimes ){
+
+    var start = new Date();
+    
+    numTimes = numTimes || 1;
+    for ( var i=0; i<numTimes; i++ ){
+        theFunc.apply( null , argumentsToArray( arguments ).slice( 2 ) );
+    }
+
+    return (new Date()).getTime() - start.getTime();
+}
+
+Date.prototype.tojson = function(){
+    return "\"" + this.toString() + "\"";
+}
+
+RegExp.prototype.tojson = RegExp.prototype.toString;
+
+Array.contains = function( a  , x ){
+    for ( var i=0; i<a.length; i++ ){
+        if ( a[i] == x )
+            return true;
+    }
+    return false;
+}
+
+Array.unique = function( a ){
+    var u = [];
+    for ( var i=0; i<a.length; i++){
+        var o = a[i];
+        if ( ! Array.contains( u , o ) ){
+            u.push( o );
+        }
+    }
+    return u;
+}
+
+Array.shuffle = function( arr ){
+    for ( var i=0; i<arr.length-1; i++ ){
+        var pos = i+Math.floor(Math.random()*(arr.length-i));
+        var save = arr[i];
+        arr[i] = arr[pos];
+        arr[pos] = save;
+    }
+    return arr;
+}
+
+
+Array.tojson = function( a , indent , x , html){
+    if (!indent) 
+        indent = "";
+    var spacer = "";
+    if(html) {
+      spacer = "<br/>";
+      indent = " &nbsp; "
+    }
+
+    var s = spacer + "[ " + spacer;
+    indent += " ";
+    for ( var i=0; i<a.length; i++){
+        s += indent + tojson( a[i], indent );
+        if ( i < a.length - 1 ){
+            s += "," + spacer;
+        }
+    }
+    if ( a.length == 0 ) {
+        s += indent;
+    }
+
+    indent = indent.substring(1);
+    s += spacer + " "+"]";
+    return s;
+}
+
+Array.fetchRefs = function( arr , coll ){
+    var n = [];
+    for ( var i=0; i<arr.length; i ++){
+        var z = arr[i];
+        if ( coll && coll != z.getCollection() )
+            continue;
+        n.push( z.fetch() );
+    }
+    
+    return n;
+}
+
+Array.sum = function( arr ){
+    if ( arr.length == 0 )
+        return null;
+    var s = arr[0];
+    for ( var i=1; i<arr.length; i++ )
+        s += arr[i];
+    return s;
+}
+
+Array.avg = function( arr ){
+    if ( arr.length == 0 )
+        return null;
+    return Array.sum( arr ) / arr.length;
+}
+
+Array.stdDev = function( arr ){
+    var avg = Array.avg( arr );
+    var sum = 0;
+
+    for ( var i=0; i<arr.length; i++ ){
+        sum += Math.pow( arr[i] - avg , 2 );
+    }
+
+    return Math.sqrt( sum / arr.length );
+}
+
+if ( ! ObjectId.prototype )
+    ObjectId.prototype = {}
+
+ObjectId.prototype.toString = function(){
+    return this.str;
+}
+
+ObjectId.prototype.tojson = function(){
+    return "ObjectId(\"" + this.str + "\")";
+}
+
+ObjectId.prototype.isObjectId = true;
+
+tojson = function( x, indent , nolint , html){
+    if ( x == null )
+        return "null";
+    
+    if ( x == undefined )
+        return "undefined";
+    
+    if (!indent) 
+        indent = "";
+
+    switch ( typeof x ){
+        
+    case "string": {
+        var s = "\"";
+        for ( var i=0; i<x.length; i++ ){
+            if ( x[i] == '"' ){
+                s += "\\\"";
+            }
+            else
+                s += x[i];
+        }
+        return s + "\"";
+    }
+        
+    case "number": 
+    case "boolean":
+        return "" + x;
+            
+    case "object":{
+        var s = tojsonObject( x, indent , nolint , html);
+        if ( ( nolint == null || nolint == true ) && s.length < 80 && ( indent == null || indent.length == 0 ) ){
+            s = s.replace( /[\s\r\n ]+/gm , " " );
+        }
+        return s;
+    }
+        
+    case "function":
+        return x.toString();
+        
+
+    default:
+        throw "tojson can't handle type " + ( typeof x );
+    }
+    
+}
+
+tojsonObject = function( x, indent , nolint , html){
+    if(html) {
+      var lineEnding = "<br/>";
+      var tabSpace   = "&nbsp;";
+    }
+    else {
+      var lineEnding = nolint ? " " : "\n";
+      var tabSpace = nolint ? "" : "\t";
+    }
+
+    assert.eq( ( typeof x ) , "object" , "tojsonObject needs object, not [" + ( typeof x ) + "]" );
+
+    if (!indent)
+        indent = "";
+
+    if ( x.hasOwnProperty("__str__")) {
+        return x.__str__();
+    }
+
+    if ( typeof( x.tojson ) == "function" && x.tojson != tojson ) {
+        return x.tojson(indent,nolint,html);
+    }
+
+    if ( typeof( x.constructor.tojson ) == "function" && x.constructor.tojson != tojson ) {
+        return x.constructor.tojson( x, indent , nolint, html );
+    }
+
+    if ( x.toString() == "[object MaxKey]" )
+        return "{ $maxKey : 1 }";
+    if ( x.toString() == "[object MinKey]" )
+        return "{ $minKey : 1 }";
+
+    var s = "{" + lineEnding;
+
+    // push one level of indent
+    indent += tabSpace;
+
+    var total = 0;
+    for ( var k in x ) total++;
+    if ( total == 0 ) {
+        s += indent + lineEnding;
+    }
+
+    var keys = x;
+    if ( typeof( x._simpleKeys ) == "function" )
+        keys = x._simpleKeys();
+    var num = 1;
+    for ( var k in keys ){
+        var val = x[k];
+
+        s += indent + "\"" + k + "\" : " + tojson( val, indent , nolint );
+        if (num != total) {
+            s += ",";
+            num++;
+        }
+        s += lineEnding;
+    }
+
+    // pop one level of indent
+    indent = indent.substring(1);
+    return s + indent + "}";
+}
+
+shellPrint = function( x ){
+    it = x;
+    if ( x != undefined )
+        shellPrintHelper( x );
+}
+
+printjson = function(x){
+    print( tojson( x ) );
+}
+
+shellPrintHelper = function( x ){
+
+    if ( typeof( x ) == "undefined" ){
+
+        return;
+    }
+    
+    if ( x == null ){
+        print( "null" );
+        return;
+    }
+
+    if ( typeof x != "object" ) 
+        return print( x );
+    
+    var p = x.shellPrint;
+    if ( typeof p == "function" )
+        return x.shellPrint();
+
+    var p = x.tojson;
+    if ( typeof p == "function" )
+        print( x.tojson() );
+    else
+        print( tojson( x ) );
+}
+
+shellHelper = function( command , rest , shouldPrint ){
+    command = command.trim();
+    var args = rest.trim().replace(/;$/,"").split( "\s+" );
+    
+    if ( ! shellHelper[command] )
+        throw "no command [" + command + "]";
+    
+    var res = shellHelper[command].apply( null , args );
+    if ( shouldPrint ){
+        shellPrintHelper( res );
+    }
+    return res;
+}
+
+help = shellHelper.help = function(){
+    print( "HELP" );
+    print( "\t" + "show dbs                     show database names");
+    print( "\t" + "show collections             show collections in current database");
+    print( "\t" + "show users                   show users in current database");
+    print( "\t" + "show profile                 show most recent system.profile entries with time >= 1ms");
+    print( "\t" + "use <db name>                set curent database to <db name>" );
+    print( "\t" + "db.help()                    help on DB methods");
+    print( "\t" + "db.foo.help()                help on collection methods");
+    print( "\t" + "db.foo.find()                list objects in collection foo" );
+    print( "\t" + "db.foo.find( { a : 1 } )     list objects in foo where a == 1" );
+    print( "\t" + "it                           result of the last line evaluated; use to further iterate");
+}
+
+if ( typeof( Map ) == "undefined" ){
+    Map = function(){
+        this._data = {};
+    }
+}
+
+Map.hash = function( val ){
+    if ( ! val )
+        return val;
+
+    switch ( typeof( val ) ){
+    case 'string':
+    case 'number':
+    case 'date':
+        return val.toString();
+    case 'object':
+    case 'array':
+        var s = "";
+        for ( var k in val ){
+            s += k + val[k];
+        }
+        return s;
+    }
+
+    throw "can't hash : " + typeof( val );
+}
+
+Map.prototype.put = function( key , value ){
+    var o = this._get( key );
+    var old = o.value;
+    o.value = value;
+    return old;
+}
+
+Map.prototype.get = function( key ){
+    return this._get( key ).value;
+}
+
+Map.prototype._get = function( key ){
+    var h = Map.hash( key );
+    var a = this._data[h];
+    if ( ! a ){
+        a = [];
+        this._data[h] = a;
+    }
+    
+    for ( var i=0; i<a.length; i++ ){
+        if ( friendlyEqual( key , a[i].key ) ){
+            return a[i];
+        }
+    }
+    var o = { key : key , value : null };
+    a.push( o );
+    return o;
+}
+
+Map.prototype.values = function(){
+    var all = [];
+    for ( var k in this._data ){
+        this._data[k].forEach( function(z){ all.push( z.value ); } );
+    }
+    return all;
+}
+
+if ( typeof( gc ) == "undefined" ){
+    gc = function(){
+    }
+}
+   
+
+Math.sigFig = function( x , N ){
+    if ( ! N ){
+        N = 3;
+    }
+    var p = Math.pow( 10, N - Math.ceil( Math.log( Math.abs(x) ) / Math.log( 10 )) );
+    return Math.round(x*p)/p;
+}
+
diff --git a/xos/core/xoslib/static/js/xsh/tokens.js b/xos/core/xoslib/static/js/xsh/tokens.js
new file mode 100644
index 0000000..49c246e
--- /dev/null
+++ b/xos/core/xoslib/static/js/xsh/tokens.js
@@ -0,0 +1,268 @@
+// tokens.js
+// 2009-05-17
+
+// (c) 2006 Douglas Crockford
+
+// Produce an array of simple token objects from a string.
+// A simple token object contains these members:
+//      type: 'name', 'string', 'number', 'operator'
+//      value: string or number value of the token
+//      from: index of first character of the token
+//      to: index of the last character + 1
+
+// Comments of the // type are ignored.
+
+// Operators are by default single characters. Multicharacter
+// operators can be made by supplying a string of prefix and
+// suffix characters.
+// characters. For example,
+//      '<>+-&', '=>&:'
+// will match any of these:
+//      <=  >>  >>>  <>  >=  +: -: &: &&: &&
+
+
+
+String.prototype.tokens = function (prefix, suffix) {
+    var c;                      // The current character.
+    var from;                   // The index of the start of the token.
+    var i = 0;                  // The index of the current character.
+    var length = this.length;
+    var n;                      // The number value.
+    var q;                      // The quote character.
+    var str;                    // The string value.
+
+    var result = [];            // An array to hold the results.
+
+    var make = function (type, value) {
+
+// Make a token object.
+
+        return {
+            type: type,
+            value: value,
+            from: from,
+            to: i
+        };
+    };
+
+// Begin tokenization. If the source string is empty, return nothing.
+
+    if (!this) {
+        return;
+    }
+
+// If prefix and suffix strings are not provided, supply defaults.
+
+    if (typeof prefix !== 'string') {
+        prefix = '<>+-&';
+    }
+    if (typeof suffix !== 'string') {
+        suffix = '=>&:';
+    }
+
+
+// Loop through this text, one character at a time.
+
+    c = this.charAt(i);
+    while (c) {
+        from = i;
+
+// Ignore whitespace.
+
+        if (c <= ' ') {
+            i += 1;
+            c = this.charAt(i);
+
+// name.
+
+        } else if (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z') {
+            str = c;
+            i += 1;
+            for (;;) {
+                c = this.charAt(i);
+                if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
+                        (c >= '0' && c <= '9') || c === '_') {
+                    str += c;
+                    i += 1;
+                } else {
+                    break;
+                }
+            }
+            result.push(make('name', str));
+
+// number.
+
+// A number cannot start with a decimal point. It must start with a digit,
+// possibly '0'.
+
+        } else if (c >= '0' && c <= '9') {
+            str = c;
+            i += 1;
+
+// Look for more digits.
+
+            for (;;) {
+                c = this.charAt(i);
+                if (c < '0' || c > '9') {
+                    break;
+                }
+                i += 1;
+                str += c;
+            }
+
+// Look for a decimal fraction part.
+
+            if (c === '.') {
+                i += 1;
+                str += c;
+                for (;;) {
+                    c = this.charAt(i);
+                    if (c < '0' || c > '9') {
+                        break;
+                    }
+                    i += 1;
+                    str += c;
+                }
+            }
+
+// Look for an exponent part.
+
+            if (c === 'e' || c === 'E') {
+                i += 1;
+                str += c;
+                c = this.charAt(i);
+                if (c === '-' || c === '+') {
+                    i += 1;
+                    str += c;
+                    c = this.charAt(i);
+                }
+                if (c < '0' || c > '9') {
+                    make('number', str).error("Bad exponent");
+                }
+                do {
+                    i += 1;
+                    str += c;
+                    c = this.charAt(i);
+                } while (c >= '0' && c <= '9');
+            }
+
+// Make sure the next character is not a letter.
+
+            if (c >= 'a' && c <= 'z') {
+                str += c;
+                i += 1;
+                make('number', str).error("Bad number");
+            }
+
+// Convert the string value to a number. If it is finite, then it is a good
+// token.
+
+            n = +str;
+            if (isFinite(n)) {
+                result.push(make('number', n));
+            } else {
+                make('number', str).error("Bad number");
+            }
+
+// string
+
+        } else if (c === '\'' || c === '"') {
+            str = '';
+            q = c;
+            i += 1;
+            for (;;) {
+                c = this.charAt(i);
+                if (c < ' ') {
+                    make('string', str).error(c === '\n' || c === '\r' || c === '' ?
+                        "Unterminated string." :
+                        "Control character in string.", make('', str));
+                }
+
+// Look for the closing quote.
+
+                if (c === q) {
+                    break;
+                }
+
+// Look for escapement.
+
+                if (c === '\\') {
+                    i += 1;
+                    if (i >= length) {
+                        make('string', str).error("Unterminated string");
+                    }
+                    c = this.charAt(i);
+                    switch (c) {
+                    case 'b':
+                        c = '\b';
+                        break;
+                    case 'f':
+                        c = '\f';
+                        break;
+                    case 'n':
+                        c = '\n';
+                        break;
+                    case 'r':
+                        c = '\r';
+                        break;
+                    case 't':
+                        c = '\t';
+                        break;
+                    case 'u':
+                        if (i >= length) {
+                            make('string', str).error("Unterminated string");
+                        }
+                        c = parseInt(this.substr(i + 1, 4), 16);
+                        if (!isFinite(c) || c < 0) {
+                            make('string', str).error("Unterminated string");
+                        }
+                        c = String.fromCharCode(c);
+                        i += 4;
+                        break;
+                    }
+                }
+                str += c;
+                i += 1;
+            }
+            i += 1;
+            result.push(make('string', str));
+            c = this.charAt(i);
+
+// comment.
+
+        } else if (c === '/' && this.charAt(i + 1) === '/') {
+            i += 1;
+            for (;;) {
+                c = this.charAt(i);
+                if (c === '\n' || c === '\r' || c === '') {
+                    break;
+                }
+                i += 1;
+            }
+
+// combining
+
+        } else if (prefix.indexOf(c) >= 0) {
+            str = c;
+            i += 1;
+            while (i < length) {
+                c = this.charAt(i);
+                if (suffix.indexOf(c) < 0) {
+                    break;
+                }
+                str += c;
+                i += 1;
+            }
+            result.push(make('operator', str));
+
+// single-character operator
+
+        } else {
+            i += 1;
+            result.push(make('operator', c));
+            c = this.charAt(i);
+        }
+    }
+    return result;
+};
+
diff --git a/xos/core/xoslib/static/js/xsh/utils.js b/xos/core/xoslib/static/js/xsh/utils.js
new file mode 100644
index 0000000..1ded27e
--- /dev/null
+++ b/xos/core/xoslib/static/js/xsh/utils.js
@@ -0,0 +1,81 @@
+// Try Mongo
+//
+// Copyright (c) 2009 Kyle Banker
+// Licensed under the MIT licence.
+// http://www.opensource.org/licenses/mit-license.php
+
+// extending array like this is breaking datatables
+
+/*Array.prototype.include = function(value) {
+  for(var i=0; i < this.length; i++) {
+    if(this[i] == value) {
+      return this[i];
+    }
+  }
+  return false;
+};
+
+Array.prototype.empty = function() {
+  return (this.length == 0);
+};*/
+
+function ArrayInclude(arr,value) {
+  for(var i=0; i < arr.length; i++) {
+    if(arr[i] == value) {
+      return arr[i];
+    }
+  }
+  return false;
+};
+
+Function.prototype.bind = function() {
+  var __method = this, object = arguments[0], args = [];
+
+  for(i = 1; i < arguments.length; i++) {
+   args.push(arguments[i]);
+  }
+
+ return function() {
+ return __method.apply(object, args);
+ };
+}; 
+
+String.prototype.trim = function() {
+  return this.replace(/^\s+|\s+$/g,"");
+};
+
+// Prints javascript types as readable strings.
+Inspect = function(obj) {
+  if(typeof(obj) != 'object') {
+    return obj;
+  }
+
+  else if (obj instanceof Array) {
+    var objRep = [];
+    for(var prop in obj) { 
+      if(obj.hasOwnProperty(prop)) {
+        objRep.push(obj[prop]); 
+      }
+    }
+    return '[' + objRep.join(', ') + ']';
+  }
+
+  else {
+    var objRep = [];
+    for(var prop in obj) {
+      if(obj.hasOwnProperty(prop)) {
+        objRep.push(prop + ': ' + ((typeof(obj[prop]) == 'object') ? Inspect(obj[prop]) : obj[prop]));
+      }
+    }
+    return '{' + objRep.join(', ') + '}';
+  }
+};
+
+// Prints an array of javascript objects.
+CollectionInspect = function(coll) {
+  var str = '';
+  for(var i=0; i<coll.length; i++) {
+    str += Inspect(coll[i]) + '<br />'; 
+  }
+  return str;
+};
diff --git a/xos/core/xoslib/static/js/xsh/xsh.js b/xos/core/xoslib/static/js/xsh/xsh.js
new file mode 100644
index 0000000..758559f
--- /dev/null
+++ b/xos/core/xoslib/static/js/xsh/xsh.js
@@ -0,0 +1,408 @@
+// TryMongo
+//
+// Copyright (c) 2009 Kyle Banker
+// Licensed under the MIT Licence.
+// http://www.opensource.org/licenses/mit-license.php
+
+// Readline class to handle line input.
+var ReadLine = function(options) {
+  this.options      = options || {};
+  this.htmlForInput = this.options.htmlForInput;
+  this.inputHandler = this.options.handler || this.mockHandler;
+  this.scoper       = this.options.scoper;
+  this.terminal     = $(this.options.terminalId || "#terminal");
+  this.lineClass    = this.options.lineClass || '.readLine';
+  this.history      = [];
+  this.historyPtr   = 0;
+
+  this.initialize();
+};
+
+ReadLine.prototype = {
+
+  initialize: function() {
+    this.addInputLine();
+  },
+
+  // Enter a new input line with proper behavior.
+  addInputLine: function(stackLevel) {
+    stackLevel = stackLevel || 0;
+    this.terminal.append(this.htmlForInput(stackLevel));
+    var ctx = this;
+    ctx.activeLine = $(this.lineClass + '.active');
+
+    // Bind key events for entering and navigting history.
+    ctx.activeLine.bind("keydown", function(ev) {
+      switch (ev.keyCode) {
+        case EnterKeyCode:
+          ctx.processInput(this.value); 
+          break;
+        case UpArrowKeyCode: 
+          ctx.getCommand('previous');
+          break;
+        case DownArrowKeyCode: 
+          ctx.getCommand('next');
+          break;
+      }
+    });
+
+    this.activeLine.focus();
+  },
+
+  // Returns the 'next' or 'previous' command in this history.
+  getCommand: function(direction) {
+    if(this.history.length === 0) {
+      return;
+    }
+    this.adjustHistoryPointer(direction);
+    this.activeLine[0].value = this.history[this.historyPtr];
+    $(this.activeLine[0]).focus();
+    //this.activeLine[0].value = this.activeLine[0].value;
+  },
+
+  // Moves the history pointer to the 'next' or 'previous' position. 
+  adjustHistoryPointer: function(direction) {
+    if(direction == 'previous') {
+      if(this.historyPtr - 1 >= 0) {
+        this.historyPtr -= 1;
+      }
+    }
+    else {
+      if(this.historyPtr + 1 < this.history.length) {
+        this.historyPtr += 1;
+      }
+    }
+  },
+
+  // Return the handler's response.
+  processInput: function(value) {
+    var response = this.inputHandler.apply(this.scoper, [value]);
+    this.insertResponse(response.result);
+
+    // Save to the command history...
+    if((lineValue = value.trim()) !== "") {
+      this.history.push(lineValue);
+      this.historyPtr = this.history.length;
+    }
+
+    // deactivate the line...
+    this.activeLine.value = "";
+    this.activeLine.attr({disabled: true});
+    this.activeLine.removeClass('active');
+
+    // and add add a new command line.
+    this.addInputLine(response.stack);
+  },
+
+  insertResponse: function(response) {
+    if((response.length < 1) || (response=='"donotprintme"') || (response=='donotprintme')) {
+      this.activeLine.parent().append("<p class='response'></p>");
+    }
+    else {
+      this.activeLine.parent().append("<p class='response'>" + response + "</p>");
+    }
+  },
+
+  // Simply return the entered string if the user hasn't specified a smarter handler.
+  mockHandler: function(inputString) {
+    return function() {
+      this._process = function() { return inputString; };
+    };
+  }
+};
+
+var MongoHandler = function() {
+  this._currentCommand = "";
+  this._rawCommand     = "";
+  this._commandStack   = 0;
+  this._tutorialPtr    = 0;
+  this._tutorialMax    = 4;
+
+  this._mongo          = {};
+  this._mongo.test     = [];
+  this.collections     = [];
+};
+
+MongoHandler.prototype = {
+
+  _process: function(inputString, errorCheck) {
+    this._rawCommand += ' ' + inputString;
+
+    try {
+      inputString += '  '; // fixes certain bugs with the tokenizer.
+      var tokens    = inputString.tokens();
+      var mongoFunc = this._getCommand(tokens);
+      if(this._commandStack === 0 && inputString.match(/^\s*$/)) {
+        return {stack: 0, result: ''};
+      }
+      else if(this._commandStack === 0 && mongoFunc) {
+        this._resetCurrentCommand();
+        return {stack: 0, result: mongoFunc.apply(this, [tokens])};
+      }
+      else {
+        return this._evaluator(tokens);
+      }
+    }
+
+    catch(err) {
+        this._resetCurrentCommand();
+        console.trace();
+        return {stack: 0, result: "JS Error: " + err};
+    }
+  },
+
+  // Calls eval on the input string when ready.
+  _evaluator: function(tokens) {
+    isAssignment = tokens.length>=2 && tokens[0].type=="name" && tokens[1].type=="operator" && tokens[1].value=="=";
+
+    this._currentCommand += " " + this._massageTokens(tokens);
+    if(this._shouldEvaluateCommand(tokens))  {
+        print = this.print;
+
+        // So this eval statement is the heart of the REPL.
+        var result = eval(this._currentCommand.trim());
+        if(result === undefined) {
+          throw('result is undefined');
+        } else if (typeof(result) === 'function') {
+          throw('result is a function. did you mean to call it?');
+        } else {
+          result = $htmlFormat(result);
+        }
+        this._resetCurrentCommand();
+        if (isAssignment) {
+            return {stack: this._commandStack, result: ""};
+        } else {
+            return {stack: this._commandStack, result: result};
+        }
+      }
+
+    else {
+      return {stack: this._commandStack, result: ""};
+    }
+  },
+
+  _resetCurrentCommand: function() {
+    this._currentCommand = '';
+    this._rawCommand     = '';
+  },
+
+  // Evaluate only when we've exited any blocks.
+  _shouldEvaluateCommand: function(tokens) {
+    for(var i=0; i < tokens.length; i++) {
+      var token = tokens[i];
+      if(token.type == 'operator') {
+        if(token.value == '(' || token.value == '{') {
+          this._commandStack += 1;
+        }
+        else if(token.value == ')' || token.value == '}') {
+          this._commandStack -= 1;
+        }
+      }
+    }
+
+    if(this._commandStack === 0) {
+      return true;
+    }
+    else {
+      return false;
+    }
+  },
+
+  _massageTokens: function(tokens) {
+    for(var i=0; i < tokens.length; i++) {
+      if(tokens[i].type == 'name') {
+        if(tokens[i].value == 'var') {
+          tokens[i].value = '';
+        }
+      }
+    }
+    return this._collectTokens(tokens);
+  },
+
+  // Collects tokens into a string, placing spaces between variables.
+  // This methods is called after we scope the vars.
+  _collectTokens: function(tokens) {
+    var result = "";
+    for(var i=0; i < tokens.length; i++) {
+      if(tokens[i].type == "name" && tokens[i+1] && tokens[i+1].type == 'name') {
+        result += tokens[i].value + ' ';
+      }
+      else if (tokens[i].type == 'string') {
+        result += "'" + tokens[i].value + "'";
+      }
+      else {
+        result += tokens[i].value;
+      }
+    }
+    return result;
+  },
+
+  // print output to the screen, e.g., in a loop
+  // TODO: remove dependency here
+  print: function() {
+   $('.readLine.active').parent().append('<p>' + JSON.stringify(arguments[0]) + '</p>');
+   return "donotprintme";
+  },
+
+  /* MongoDB     */
+  /* ________________________________________ */
+
+  // help command
+  _help: function() {
+      return PTAG('HELP') +
+             PTAG('xos                                 list xos API object types') +
+             PTAG('xos.slices.fetch()                  fetch slices from the server') +
+             PTAG('xos.slices                          get the slices that were fetched');
+
+  },
+
+  _tutorial: function() {
+    this._tutorialPtr = 0;
+    return PTAG("This is a self-guided tutorial on the xos shell.") +
+           PTAG("The tutorial is simple, more or less a few basic commands to try.") +
+           PTAG("To go directly to any part tutorial, enter one of the commands t0, t1, t2...t10") +
+           PTAG("Otherwise, use 'next' and 'back'. Start by typing 'next' and pressing enter.");
+  },
+
+  // go to the next step in the tutorial.
+  _next: function() {
+    if(this._tutorialPtr < this._tutorialMax) {
+      return this['_t' + (this._tutorialPtr + 1)]();
+    }
+    else {
+      return "You've reached the end of the tutorial. To go to the beginning, type 'tutorial'";
+    }
+  },
+
+  // go to the previous step in the tutorial.
+  _back: function() {
+    if(this._tutorialPtr > 1) {
+      return this['_t' + (this._tutorialPtr - 1)]();
+    }
+    else {
+      return this._tutorial();
+    }
+  },
+
+  _t1: function() {
+    this._tutorialPtr = 1;
+    return PTAG('1. JavaScript Shell') +
+           PTAG('The first thing to notice is that the MongoDB shell is JavaScript-based.') +
+           PTAG('So you can do things like:') +
+           PTAG('  a = 5; ') +
+           PTAG('  a * 10; ') +
+           PTAG('  print(a); ') +
+           PTAG("  for(i=0; i<10; i++) { print('hello'); }; ") +
+           PTAG("Try a few JS commands; when you're ready to move on, enter 'next'");
+
+  },
+
+  _t2: function() {
+    this._tutorialPtr = 2;
+    return PTAG('2. Reading from the server is asynchronous') +
+           PTAG('Try these:') +
+           PTAG('    xos.slices.models;') +
+           PTAG('    // the above should have printed empty list') +
+           PTAG('    xos.slices.fetch();') +
+           PTAG('    // wait a second or two...') +
+           PTAG('    xos.slices.models;');
+
+  },
+
+  _t3: function() {
+    this._tutorialPtr = 3;
+    return PTAG('3. Responding to events') +
+           PTAG('Try these:') +
+           PTAG('    xos.slices.fetch();') +
+           PTAG('    tmp=xos.slices.on("change", function() { alert("woot!"); });') +
+           PTAG('    xos.slices.models[0].set("description", "somerandomtext");');
+
+  },
+
+  _t4: function() {
+    this._tutorialPtr = 4;
+    return PTAG('4. Available xos objects and methods') +
+           PTAG('Try these:') +
+           PTAG('    xos.listObjects();') +
+           PTAG('    xos.slices.listMethods();');
+
+  },
+
+  _getCommand: function(tokens) {
+    if(tokens[0] && ArrayInclude(MongoKeywords,(tokens[0].value + '').toLowerCase())) {
+      switch(tokens[0].value.toLowerCase()) {
+        case 'help':
+          return this._help;
+
+        case 'tutorial':
+          return this._tutorial;
+        case 'next':
+          return this._next;
+        case 'back':
+          return this._back;
+        case 't0':
+          return this._tutorial;
+        case 't1':
+          return this._t1;
+        case 't2':
+          return this._t2;
+        case 't3':
+          return this._t3;
+        case 't4':
+          return this._t4;
+      }
+    }
+  }
+};
+
+function replaceAll(find, replace, str) {
+  return str.replace(new RegExp(find, 'g'), replace);

+}
+
+/* stackoverflow: http://stackoverflow.com/questions/4810841/how-can-i-pretty-print-json-using-javascript */
+function syntaxHighlight(json) {
+    if ( json.hasOwnProperty("__str__")) {
+        return syntaxHighlight(json.__str__());
+    }
+    if (typeof json != 'string') {

+         json = JSON.stringify(json, undefined, "\t");

+    }

+    json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');

+    return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {

+        var cls = 'terminal_number';

+        if (/^"/.test(match)) {

+            if (/:$/.test(match)) {

+                cls = 'terminal_key';

+            } else {

+                cls = 'terminal_string';

+            }

+        } else if (/true|false/.test(match)) {

+            cls = 'terminal_boolean';

+        } else if (/null/.test(match)) {

+            cls = 'terminal_null';

+        }

+        return '<span class="' + cls + '">' + match + '</span>';

+    });

+}
+
+$htmlFormat = function(obj) {
+  //JSON.stringify(obj,undefined,2)
+  result=replaceAll("\t","&nbsp;",replaceAll("\n","<br>",syntaxHighlight(obj))); //tojson(obj, ' ', ' ', true);
+  return result;
+}
+
+function startTerminal() {
+  var mongo       = new MongoHandler();
+  var terminal    = new ReadLine({htmlForInput: DefaultInputHtml,
+                                  handler: mongo._process,
+                                  scoper: mongo});
+  $("#terminal_help1").show();
+  $("#terminal_help2").show();
+  $("#terminal_wait").hide();
+
+  $("#terminal").bind('click', function() { $(".readLine.active").focus(); });
+};
+
+$(document).ready(function() {
+    startTerminal();
+});
diff --git a/xos/core/xoslib/templates/mustache/detailApp.mustache b/xos/core/xoslib/templates/mustache/detailApp.mustache
new file mode 100644
index 0000000..a178d5a
--- /dev/null
+++ b/xos/core/xoslib/templates/mustache/detailApp.mustache
@@ -0,0 +1,8 @@
+<h2>
+  <a class="home" href="/">All Instances</a>
+</h2>
+<ul id="instances">
+  <li class="instance"
+      {{>instanceTemplate}}
+  </li>
+</ul>
diff --git a/xos/core/xoslib/templates/mustache/listApp.mustache b/xos/core/xoslib/templates/mustache/listApp.mustache
new file mode 100644
index 0000000..79721ce
--- /dev/null
+++ b/xos/core/xoslib/templates/mustache/listApp.mustache
@@ -0,0 +1,3 @@
+<h2>All Instances</h2>
+<ul id="instances">
+</ul>
diff --git a/xos/core/xoslib/templates/mustache/sliverTemplate.mustache b/xos/core/xoslib/templates/mustache/sliverTemplate.mustache
new file mode 100644
index 0000000..9959a19
--- /dev/null
+++ b/xos/core/xoslib/templates/mustache/sliverTemplate.mustache
@@ -0,0 +1 @@
+<a class="permalink" href="/{{id}}/">{{ name }}</a>
diff --git a/xos/core/xoslib/templates/xosAdmin.html b/xos/core/xoslib/templates/xosAdmin.html
new file mode 100644
index 0000000..2ff4954
--- /dev/null
+++ b/xos/core/xoslib/templates/xosAdmin.html
@@ -0,0 +1,339 @@
+<!-- Error and Success templates -->
+
+<script type="text/template" id="xos-error-response">
+  <h5>Error</h5>
+  <table>
+  <tr><td>error:</td><td><%= error %></td></tr>
+  <tr><td>check:</td><td><%= specific_error %></td></tr>
+  </table>
+  <h5>Details:</h5>
+      <table>
+      <tbody>
+      <% _.each(reasons, function(element, index) { %>
+          <tr><td><%= index %></td><td><%= element %></td></tr>
+      <% }); %>
+      </tbody>
+      </table>
+</script>
+
+<script type="text/template" id="xos-error-rawresponse">
+  <h5>Error</h5>
+  <pre>The server returned:
+"<%= responseText %>"</pre>
+</script>
+
+<script type="text/template" id="xos-error-template">
+  <button id="close-error-box">Close Error Message</button>
+  <h3>An error has occurred.</h3>
+  <table class="test-error-table">
+  <tr><td>Code:</td><td><%= status %></td></tr>
+  <tr><td>Message:</td><td><%= statusText %></td></tr>
+  </table>
+</script>
+
+<script type="text/template" id="xos-success-template">
+  <button id="close-success-box">Close Success Message</button>
+  <h3>Success!</h3>
+  <table class="test-success-table">
+  <tr><td>Code:</td><td><%= status %></td></tr>
+  <tr><td>Message:</td><td><%= statusText %></td></tr>
+  </table>
+</script>
+
+<script type="text/template" id="xos-navbutton-old">
+  <button class="btn btn-default btn-xosnav" onclick="<%= router %>.navigate('<%= routeUrl %>', {trigger: true})"><%= name %></button><br>
+</script>
+
+<script type="text/template" id="xos-status-template">
+  <div class="xos-status xos-<%= statusclass %>"><%= what %>: <%= statusText %> (<%= status %>)</div>
+</script>
+
+<script type="text/template" id="xos-tabs-template">
+  <ul class="xos-nav-list">
+  <% _.each(tabs, function(tab) { %>
+      <li class="xos-nav-item" id="xos-nav-<%= tab["region"] %>"><%= tab["name"] %></li>
+  <% }); %>
+  </ul>
+</script>
+
+<script type="text/template" id="xos-title-list">
+  <h3><img src="/static/img/brokencircle.gif" height=16 width=16 id="xos-list-title-spinner"> <%= title %></h3>
+</script>
+
+<script type="text/template" id="xos-title-detail">
+  <h3><%= title %></h3>
+</script>
+
+<script type="text/template" id="xos-navbutton">
+  <li>
+      <a href="<%= routeUrl %>">
+          <i class="<%= iconClass %>"></i>
+          <%= name %>
+      </a>
+  </li>
+</script>
+
+<script type="text/template" id="xos-inline-detail-buttons-template">
+    <tr>
+       <td colspan=2><button class="btn js-submit btn-xos-detail btn-xos-save-leave">Save</button>
+           <button class="btn js-submit btn-xos-detail btn-xos-save-continue">Save and Continue Editing</button>
+           <button class="btn js-submit btn-xos-detail btn-xos-save-another">Save and Add Another</button>
+           <button class="btn js-submit btn-xos-detail btn-xos-delete">Delete</button>
+       </td>
+    </tr>
+</script>
+
+<script type="text/template" id="xos-backend-status-icon-template">
+    <% if (! ("enacted" in arguments) ) { %>
+        <!-- enacted is undefined; this must be a new object -->
+    <% } else if ((enacted) && (enacted >= updated)) { %>
+        <span style="min-width:16px;"><img src="/static/admin/img/icon_success.gif"></span>
+    <% } else { %>
+        <% if ((backend_status == "Provisioning in progress") || (!backend_status)) { %>
+            <span style="min-width:16px;" title="<%= _.escape(backend_status) %>"><img src="/static/admin/img/icon_clock.gif"></span>
+        <% } else { %>
+            <span style="min-width:16px;" title="<%= _.escape(backend_status) %>"><img src="/static/admin/img/icon_error.gif"></span>
+        <% } %>
+    <% } %>
+</script>
+
+<script type="text/template" id="xos-backend-status-text-template">
+    <%= xosBackendStatusIconTemplate.apply(this,arguments) %>
+    <% if (model.attributes.enacted === undefined) { %>
+        <!-- enacted is undefined; this must be a new object -->
+    <% } else if ((enacted) && (enacted >= updated)) { %>
+        Successfully enacted
+    <% } else { %>
+        <%= _.escape(backend_status) %>
+    <% } %>
+</script>
+
+<script type="text/template" id="xos-list-header-template">
+    <button class="btn js-submit btn-xos-list btn-xos-add">Add</button>
+    <button class="btn js-submit btn-xos-list btn-xos-refresh">Refresh</button>
+</script>
+
+<script type="text/template" id="xos-list-footer-template">
+    <% if (addChildHash) { %>
+        <a href="<%= addChildHash %>">Add...</a>
+    <% } %>
+</script>
+
+<script type="text/template" id="xos-delete-button-template">
+    <a href="#delete<%= firstCharUpper(modelName) %>/<%= id %>">delete</a>
+</script>
+
+<script type="text/template" id="xos-detail-link-template">
+    <a href="#<%= collectionName %>/<%= id %>"><%= text %></a>
+</script>
+
+<script type="text/template" id="xos-add-template">
+  <h3 class="xos-detail-title">Add Object: <%= modelName %></h3>
+  <form>
+  <table>
+  <% args = arguments; %>
+  <% _.each(addFields, function(fieldName) { %>
+     <tr><td><%= fieldNameToHumanReadable(fieldName) %>:</td>
+        <% readOnly = $.inArray(fieldName, model.readOnlyFields)>=0 ? " readonly" : "";  %>
+        <% if (fieldName in foreignFields) { %>
+            <td><%= idToSelect(fieldName, model.attributes[fieldName], foreignFields[fieldName], "humanReadableName", readOnly) %></td>
+        <% } else if (inputType[fieldName] == "checkbox") { %>
+            <td><input type="checkbox" name="<%= fieldName %>" <% if (model.attributes[fieldName]) print("checked"); %><%= readOnly %>></td>
+        <% } else if (fieldName=="backend_status") { %>
+            <td><%= xosBackendStatusTextTemplate.apply(this, args) %></td>
+        <% } else { %>
+            <td><input type="text" name="<%= fieldName %>" value="<%= model.attributes[fieldName] %>"<%= readOnly %>></td>
+        <% } %>
+     </tr>
+  <% }); %>
+  <%= xosInlineDetailButtonsTemplate() %>
+  </table>
+  </form>
+</script>
+
+<script type="text/template" id="xos-detail-template">
+  <h3 class="xos-detail-title">Edit Object: <%= modelName %></h3>
+  <form class="inline-form">
+  <table class="xos-detail-table">
+  <% args = arguments; %>
+  <% _.each(detailFields, function(fieldName) { %>
+     <tr>
+      <td class="xos-label-cell">
+        <label><%= fieldName in fieldDisplayNames ? fieldDisplayNames[fieldName] : fieldNameToHumanReadable(fieldName) %>:</label>
+      </td>
+        <% readOnly = $.inArray(fieldName, model.readOnlyFields)>=0 ? " readonly" : "";  %>
+        <% if (fieldName in choices) { %>
+            <td>
+              <%= choicesToSelect(fieldName, model.attributes[fieldName], choices[fieldName]) %>
+            </td>
+        <% } else if (fieldName in foreignFields) { %>
+            <td>
+              <%= idToSelect(fieldName, model.attributes[fieldName], foreignFields[fieldName], "humanReadableName", readOnly) %>
+            </td>
+        <% } else if (inputType[fieldName] == "spinner") { %>
+            <!-- note: I never finished working on this spinner stuff! -->
+            <td>
+              <%= xosSpinnerTemplate({id: "spinner_" + fieldName, fieldName: fieldName, value: model.attributes[fieldName]}) %>
+            </td>
+        <% } else if (inputType[fieldName] == "checkbox") { %>
+            <td>
+              <input type="checkbox" name="<%= fieldName %>" <% if (model.attributes[fieldName]) print("checked"); %><%= readOnly %>>
+            </td>
+        <% } else if (inputType[fieldName] == "picker") { %>
+            <% lookupFunc = makeIdToName(model.m2mFields[fieldName], "humanReadableName"); %>
+            <td>
+              <%= xosPickerTemplate({pickedItems: model.attributes[fieldName], unpickedItems: model.getChoices(fieldName,true), id: "picker_" + fieldName, fieldName: fieldName, detailView: detailView, lookupFunc: lookupFunc}) %>
+            </td>
+        <% } else if (fieldName=="backend_status") { %>
+            <td>
+              <%= xosBackendStatusTextTemplate.apply(this, args) %>
+            </td>
+        <% } else { %>
+            <td>
+              <input class="form-control" type="text" name="<%= fieldName %>" value="<%= escapeForFormField(model.attributes[fieldName]) %>"<%= readOnly %>>
+            </td>
+        <% } %>
+        <td  class="xos-help-cell"><%= helpText[fieldName] %></td>
+     </tr>
+  <% }); %>
+  <%= xosInlineDetailButtonsTemplate() %>
+  </table>
+  </form>
+</script>
+
+<script type="text/template" id="xos-list-template">
+  <h3 class="xos-list-title"><%= title %></h3>
+  <%= xosListHeaderTemplate() %>
+  <table class="test-table">
+  <thead>
+  <tr>
+  <% _.each(listFields, function(fieldName) { %>
+      <th><%= fieldNameToHumanReadable(fieldName) %></th>
+  <% }); %>
+  <th>delete</th>
+  </tr></thead>
+  <tbody></tbody>
+  </table>
+  <%= xosListFooterTemplate({addChildHash: addChildHash}) %>
+</script>
+
+<script type="text/template" id="xos-listitem-template">
+  <% _.each(listFields, function(fieldName) { %>
+      <% if ($.inArray(fieldName, model.detailLinkFields)>=0) { %>
+          <td><%= xosDetailLinkTemplate({collectionName: collectionName, id: id, text: model.attributes[fieldName]}) %></td>
+      <% } else if (fieldName in foreignFields) { %>
+          <td><%= idToName(model.attributes[fieldName], foreignFields[fieldName], "humanReadableName") %></td>
+      <% } else { %>
+      <td><%= model.attributes[fieldName] %></td>
+      <% } %>
+  <% }); %>
+  <td><%= xosDeleteButtonTemplate({modelName: modelName, id: id}) %></td>
+</script>
+
+<script type="text/template" id="xos-savebuttons-template">
+  <div class="box save-box">
+    <button class="btn btn-high btn-info btn-xos-contentButtonPanel btn-xos-save-leave">Save</button>
+    <button class="btn btn-high btn-xos-contentButtonPanel btn-xos-save-continue">Save and continue editing</button>
+    <% if (!disableAdd) { %>
+    <button class="btn btn-high btn-xos-contentButtonPanel btn-xos-save-another">Save and add another</button>
+    <% }; %>
+    <button class="btn btn-danger btn-xos-contentButtonPanel btn-xos-delete">Delete</button>
+  </div>
+</script>
+
+<script type="text/template" id="xos-listbuttons-template">
+  <div class="box save-box">
+    <button class="btn btn-high btn-primary btn-xos-contentButtonPanel btn-xos-refresh">Refresh</button>
+    <% if (!disableAdd) { %>
+    <button class="btn btn-high btn-success btn-xos-contentButtonPanel btn-xos-add">Add</button>
+    <% }; %>
+  </div>
+</script>
+
+<script type="text/template" id="xos-datatable-spinner-template">
+    <!-- arguments: value, id, collectionName, fieldName -->
+    <%= value %> <img style="cursor: pointer;" src="/static/img/plus_circle.png" onclick='<%= app.varName %>.adjustCollectionField("<%= collectionName %>", <%= id %>, "<%= fieldName %>", 1)'>
+                 <img style="cursor: pointer;" src="/static/img/minus_circle.png" onclick='<%= app.varName %>.adjustCollectionField("<%= collectionName %>", <%= id %>, "<%= fieldName %>", -1)'>
+</script>
+
+<script type="text/template" id="xos-datatable-spinner-template-old">
+    <!-- arguments: value, id, collectionName, fieldName -->
+    <%= value %> <a href="javascript:undefined" onclick='<%= app.varName %>.adjustCollectionField("<%= collectionName %>", <%= id %>, "<%= fieldName %>", 1)'> more </a>
+                 <a href="javascript:undefined" onclick='<%= app.varName %>.adjustCollectionField("<%= collectionName %>", <%= id %>, "<%= fieldName %>", -1)'> less </a>
+</script>
+
+<script type="text/template" id="xos-spinner-template">
+    <!-- arguments: fieldName, id, value -->
+    <input name="<%= fieldName %>" class="xos-spinner" id="<%= id %>">
+    <% detailView.viewInitializers.push( function() { init_spinner("#" + id, value); } ); %>
+</script>
+
+<script type="text/template" id="xos-picker-template">
+    <!-- arguments: unpickedItems, pickedItems, fieldName, id -->
+    <div id="<%= id %>">
+    <div class="picker_row">
+    <div class="picker_column">
+    <div>Available</div>
+    <select name="pickerfrom" class="select-picker-from" multiple size="5">
+        <% _.each(unpickedItems, function(item) { %>
+           <option value="<%= item %>"><%= lookupFunc? lookupFunc(item) : item %></option>
+        <% });%>
+    </select>
+    </div>
+    <div class="picker_column">
+    <br>
+    <div class="btn btn-success btn-picker-add">Add &raquo;</div><br><br>
+    <div class="btn btn-success btn-picker-remove">&laquo; Remove</div>
+    </div>
+    <div class="picker_column">
+    <div>Selected</div>
+    <select name=<%= fieldName %> class="select-picker-to syphonall" multiple size="5">
+        <% _.each(pickedItems, function(item) { %>
+           <option value="<%= item %>"><%= lookupFunc ? lookupFunc(item) : item %></option>
+        <% }); %>
+    </select>
+    </div>
+    <div class="picker_column">
+    <br>
+    <div class="btn btn-success btn-picker-up">Up</div><br><br>
+    <div class="btn btn-success btn-picker-down">Down</div>
+    </div>
+    </div>
+    </div>
+    <% detailView.viewInitializers.push( function() { init_picker("#" + id); } ); %>
+</script>
+
+<script type="text/template" id="xos-sliceselector-option">
+   <%= name %>
+</script>
+
+<script type="text/template" id="xos-sliceselector-select">
+    <% if (caption) { %>
+    <table class="xos-detail-table">
+      <tr>
+        <td class="xos-label-cell">
+          <label><%= caption %>:</label>
+        </td>
+        <td>
+          <select class="form-control"></select>
+        </td>
+      </tr>
+    </table>
+    <% } else { %>
+    <select></select>
+    <% } %>
+</script>
+
+<script>
+xosInlineDetailButtonsTemplate = _.template($("#xos-inline-detail-buttons-template").html());
+xosListHeaderTemplate = _.template($("#xos-list-header-template").html());
+xosListFooterTemplate = _.template($("#xos-list-footer-template").html());
+xosDeleteButtonTemplate = _.template($("#xos-delete-button-template").html());
+xosDetailLinkTemplate = _.template($("#xos-detail-link-template").html());
+xosBackendStatusIconTemplate = _.template($("#xos-backend-status-icon-template").html());
+xosBackendStatusTextTemplate = _.template($("#xos-backend-status-text-template").html());
+xosPickerTemplate = _.template($("#xos-picker-template").html());
+xosSpinnerTemplate = _.template($("#xos-spinner-template").html());
+xosDataTableSpinnerTemplate = _.template($("#xos-datatable-spinner-template").html());
+</script>
+
diff --git a/xos/core/xoslib/templates/xosAdminHeader.html b/xos/core/xoslib/templates/xosAdminHeader.html
new file mode 100644
index 0000000..1fb5638
--- /dev/null
+++ b/xos/core/xoslib/templates/xosAdminHeader.html
@@ -0,0 +1,73 @@
+{% load admin_static %}{% load suit_tags %}{% load i18n %}
+
+      <a href="{% url 'admin:index' %}"><h1 id="site-name"><img class="logo" height="70" width="259" src="{% static 'open-cloud-login-themed-light.png' %}"/></h1></a>
+      {% block header %}
+        {% if not is_popup %}
+          <!-- Header -->
+          <div id="header" class="header">
+            
+            <div id="branding">
+                  {% block quick-search %}
+                {% with 'SEARCH_URL'|suit_conf as search_url %}
+                  {% if search_url %}
+                    <form class="form-search nav-quick-search" autocomplete="off" action="{% if '/' in search_url %}{{ search_url }}{% else %}{% url search_url %}{% endif %}" method="GET">
+                      <i class="input-icon icon-search"></i>
+                      <input type="text" name="q" class="input-medium search-query" id="quick-search">
+                      <input type="submit" class="submit" value="">
+                    </form>
+                  {% endif %}
+                {% endwith %}
+              {% endblock %}
+            </div>
+          
+            {% block header_time %}
+            <div id="branding2">
+            <!--<div class="header-content header-content-first">
+              <div class="header-column icon">
+                <i class="icon-time"></i>
+              </div>
+              <div class="header-column">
+                <span class="date"> {% suit_date %}</span><br>
+                <span class="time" id="clock">{% suit_time %}</span>
+              </div>
+            </div>-->
+          
+            {% endblock %}
+
+            {% block header_content %}
+              <!--<div class="header-content">
+                <div class="header-column icon">
+                  <i class="icon-comment"></i>
+                </div>
+                <div class="header-column">
+                  <a href="" class="grey"><b>2</b> new messages</a>
+                </div>
+              </div>-->
+            {% endblock %}
+
+            {% if user.is_active and user.is_staff %}
+              <div id="user-tools">
+                {% trans 'Welcome,' %}
+                <a href="http://{{ request.get_host}}/admin/core/user/{{user.id}}">{{user.email}}</a>
+                <span class="user-links">
+                {% block userlinks %}
+                  {% url 'django-admindocs-docroot' as docsroot %}
+                  {% if docsroot %}
+                    <a href="{{ docsroot }}">{% trans 'Documentation' %}</a>
+                   <span class="separator">|</span>
+                  {% endif %}
+                  <a href="{% url 'admin:password_change' %}">{% trans 'Change password' %}</a>
+                  <span class="separator">|</span>
+                  <a href="{% url 'admin:logout' %}">{% trans 'Log out' %}</a>
+                  </span>
+                {% endblock %}
+              </div>
+            {% endif %}
+
+            {% block nav-global %}{% endblock %}
+
+          </div>
+           </div>
+        {% endif %}
+        <!-- END Header -->
+      {% endblock %}
diff --git a/xos/core/xoslib/templates/xosCordSubscriber.html b/xos/core/xoslib/templates/xosCordSubscriber.html
new file mode 100644
index 0000000..db42fb8
--- /dev/null
+++ b/xos/core/xoslib/templates/xosCordSubscriber.html
@@ -0,0 +1,54 @@
+<script type="text/template" id="xos-cord-subscriber-template">
+  <h3 class="xos-detail-title">CORD Subscriber</h3>
+  <form>
+
+  <div class="cord-subscriber-box">
+  <h3>vOLT</h3>
+  <table class="xos-detail-table cord-subscriber-table">
+  <tr><td class="xos-label-cell">Id:</td><td><%= model.attributes.id %></td></tr>
+  <tr><td class="xos-label-cell">Service Specific Id:</td><td><%= model.attributes.service_specific_id %></td></tr>

+  <tr><td class="xos-label-cell">S-Tag:</td><td><%= model.attributes.s_tag %></td></tr>

+  <tr><td class="xos-label-cell">C-Tag:</td><td><%= model.attributes.c_tag %></td></tr>

+  </table>

+  </div>

+

+  <br>

+

+  <div class="cord-subscriber-box">

+  <h3>vCPE</h3>

+  <table class="xos-detail-table cord-subscriber-table">

+  <tr><td class="xos-label-cell">Id:</td><td><%= model.attributes.vcpe_id %></td></tr>

+  <tr><td class="xos-label-cell">Synced:</td><td><% if (model.attributes.vcpe_synced) { print("Yes"); } else { print("No"); } %></td></tr>

+  <tr><td class="xos-label-cell">Image:</td><td><%= model.attributes.image_name %></td></tr>

+  <tr><td class="xos-label-cell">Instance Id:</td><td><%= model.attributes.instance %></td></tr>

+  <tr><td class="xos-label-cell">Firewall:</td><td><input type="checkbox" name="firewall_enable" <% if (model.attributes.firewall_enable) print("checked"); %>>Enable<br>

+                                                                  <textarea name="firewall_rules" style="width:320px; height:80px"><%= model.attributes.firewall_rules %></textarea></td></tr>

+  <tr><td class="xos-label-cell">URL Filter:</td><td><input type="checkbox" name="url_filter_enable" <% if (model.attributes.url_filter_enable) print("checked"); %>>Enable

+                                                                  <input name="url_filter_level" value="<%= model.attributes.url_filter_level %>"><br>

+                                                                  <textarea name="url_filter_rules" style="width:320px; height:80px"><%= model.attributes.url_filter_rules %></textarea><br>

+                                                                  BBS Account: <%= model.attributes.bbs_account %></td></tr>

+  <tr><td class="xos-label-cell">CDN:</td><td><input type="checkbox" name="cdn_enable" <% if (model.attributes.cdn_enable) print("checked"); %>>Enable</td></tr>

+  <tr><td class="xos-label-cell">Addresses:</td><td><%= model.attributes.wan_ip %> (wan)<br>

+                                                                   <%= model.attributes.lan_ip %> (lan)<br>

+                                                                   <%= model.attributes.nat_ip %> (nat)<br>

+                                                                   <%= model.attributes.private_ip %> (private) </td></tr>

+  <tr><td class="xos-label-cell">SSH Command:</td><td><%= model.attributes.ssh_command %></td></tr>

+  </table>

+  </div>

+

+  <br>

+

+  <div class="cord-subscriber-box">

+  <h3>vBNG</h3>

+  <table class="xos-detail-table cord-subscriber-table">

+  <tr><td class="xos-label-cell">Id:</td><td><%= model.attributes.vbng_id %></td></tr>

+  <tr><td class="xos-label-cell">Routeable Subnet:</td><td><%= model.attributes.routeable_subnet %></td></tr>

+  </table>

+  </div>

+

+  <%= xosInlineDetailButtonsTemplate() %>

+  </table>

+  </form>

+</script>

+

+

diff --git a/xos/core/xoslib/templatetags/mustache.py b/xos/core/xoslib/templatetags/mustache.py
new file mode 100644
index 0000000..a3b3b2a
--- /dev/null
+++ b/xos/core/xoslib/templatetags/mustache.py
@@ -0,0 +1,51 @@
+from django import template
+from django.conf import settings
+import pystache
+import os
+
+register = template.Library()
+
+class View(pystache.View):
+    template_path = settings.TEMPLATE_DIRS[0]
+
+    def __init__(self, template_dir, template_name, context):
+        self.template_path = template_dir
+        self.template_name = template_name
+        return super(View, self).__init__(context=context)
+
+class MustacheNode(template.Node):
+    def __init__(self, template_name, attr=None):
+        for template_dir in settings.TEMPLATE_DIRS:
+            if os.path.exists(os.path.join(template_dir, template_name) + ".mustache"):
+                break
+        else:
+            raise IOError("failed to find %s in %s" % (template_name, str(settings.TEMPLATE_DIRS)))
+
+        self.template_path = template_dir
+        self.template = template_name
+        self.attr = attr
+
+    def render(self, context):
+        mcontext = context[self.attr] if self.attr else {}
+        view = View(self.template_path, self.template, context=mcontext)
+        return view.render()
+
+def do_mustache(parser, token):
+    """
+    Loads a mustache template and render it inline
+    
+    Example::
+    
+    {% mustache "foo/bar" data %}
+    
+    """
+    bits = token.split_contents()
+    if len(bits) not in  [2,3]:
+        raise template.TemplateSyntaxError("%r tag takes two arguments: the location of the template file, and the template context" % bits[0])
+    path = bits[1]
+    path = path[1:-1]
+    attrs = bits[2:]
+    return MustacheNode(path, *attrs)
+
+
+register.tag("mustache", do_mustache)
diff --git a/xos/core/xoslib/templatetags/straight_include.py b/xos/core/xoslib/templatetags/straight_include.py
new file mode 100644
index 0000000..54710f3
--- /dev/null
+++ b/xos/core/xoslib/templatetags/straight_include.py
@@ -0,0 +1,62 @@
+"""
+Straight Include template tag by @HenrikJoreteg
+
+Django templates don't give us any way to escape template tags.
+
+So if you ever need to include client side templates for ICanHaz.js (or anything else that
+may confuse django's templating engine) You can is this little snippet.
+
+Just use it as you would a normal {% include %} tag. It just won't process the included text.
+
+It assumes your included templates are in you django templates directory.
+
+Usage:
+
+{% load straight_include %}
+
+{% straight_include "my_icanhaz_templates.html" %}
+
+"""
+
+import os
+from django import template
+from django.conf import settings
+
+
+register = template.Library()
+
+
+class StraightIncludeNode(template.Node):
+    def __init__(self, template_path):
+        for template_dir in settings.TEMPLATE_DIRS:
+            self.filepath = '%s/%s' % (template_dir, template_path)
+            if os.path.exists(self.filepath):
+                break
+        else:
+            raise IOError("cannot find %s in %s" % (template_path, str(TEMPLATE_DIRS)))
+
+    def render(self, context):
+        fp = open(self.filepath, 'r')
+        output = fp.read()
+        fp.close()
+        return output
+
+
+def do_straight_include(parser, token):
+    """
+    Loads a template and includes it without processing it
+    
+    Example::
+    
+    {% straight_include "foo/some_include" %}
+    
+    """
+    bits = token.split_contents()
+    if len(bits) != 2:
+        raise template.TemplateSyntaxError("%r tag takes one argument: the location of the file within the template folder" % bits[0])
+    path = bits[1][1:-1]
+    
+    return StraightIncludeNode(path)
+
+
+register.tag("straight_include", do_straight_include)
diff --git a/xos/core/xoslib/tools/make_defaults.py b/xos/core/xoslib/tools/make_defaults.py
new file mode 100644
index 0000000..1fc5c89
--- /dev/null
+++ b/xos/core/xoslib/tools/make_defaults.py
@@ -0,0 +1,42 @@
+import os
+import sys
+XOS_DIR="/opt/xos"
+os.chdir(XOS_DIR)
+sys.path.append(XOS_DIR)
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
+import django
+import core.models
+from django.db import models
+django.setup()
+from django.forms.models import model_to_dict
+import inspect
+from django.core import serializers
+import json
+
+print "function xos_get_defaults() {"
+
+for c in dir(core.models):
+    c = getattr(core.models,c)
+    if inspect.isclass(c) and issubclass(c, models.Model):
+        c=c()
+        classname = c.__class__.__name__
+        classname = classname[0].lower() + classname[1:]
+
+        if (classname in ["plCoreBase", "singletonModel"]):
+            continue
+
+        fieldNames = [f.name for f in c._meta.fields]
+
+        fields = json.loads(serializers.serialize("json",[c],fields=fieldNames))[0]["fields"]
+
+        for f in fields.keys():
+            if f in ['created', 'updated', 'enacted']:
+                fields[f] = None
+
+        fields_json = json.dumps(fields)
+
+        print "  this." + classname + " = " + fields_json + ";"
+
+print "};"
+print "xosdefaults = new xos_get_defaults();"
+
diff --git a/xos/core/xoslib/tools/make_validators.py b/xos/core/xoslib/tools/make_validators.py
new file mode 100644
index 0000000..56dc024
--- /dev/null
+++ b/xos/core/xoslib/tools/make_validators.py
@@ -0,0 +1,36 @@
+import os
+import sys
+XOS_DIR="/opt/xos"
+os.chdir(XOS_DIR)
+sys.path.append(XOS_DIR)
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
+import django
+import core.models
+from django.db import models
+django.setup()
+from django.forms.models import model_to_dict
+import inspect
+from django.core import serializers
+import json
+
+print "function xos_get_validators() {"
+
+for c in dir(core.models):
+    c = getattr(core.models,c)
+    if inspect.isclass(c) and issubclass(c, models.Model):
+        c=c()
+        classname = c.__class__.__name__
+        classname = classname[0].lower() + classname[1:]
+
+        if (classname in ["plCoreBase", "singletonModel"]):
+            continue
+
+        fields = c.getValidators();
+
+        fields_json = json.dumps(fields)
+
+        print "  this." + classname + " = " + fields_json + ";"
+
+print "};"
+print "xosvalidators = new xos_get_validators();"
+
diff --git a/xos/core/xoslib/up.sh b/xos/core/xoslib/up.sh
new file mode 100644
index 0000000..206c0d7
--- /dev/null
+++ b/xos/core/xoslib/up.sh
@@ -0,0 +1,6 @@
+SLICE=princeton_planetstack
+HOST=node54.princeton.vicci.org
+#SLICE=service_vini
+#HOST=bilby.cs.princeton.edu
+rsync -avz --exclude "__history" --exclude "*~" -e ssh . $SLICE@$HOST:/opt/planetstack/core/xoslib/
+
diff --git a/xos/core/xoslib/xos_dump.sql b/xos/core/xoslib/xos_dump.sql
new file mode 100644
index 0000000..02caae5
--- /dev/null
+++ b/xos/core/xoslib/xos_dump.sql
@@ -0,0 +1,7712 @@
+--
+-- PostgreSQL database dump
+--
+
+SET statement_timeout = 0;
+SET lock_timeout = 0;
+SET client_encoding = 'SQL_ASCII';
+SET standard_conforming_strings = on;
+SET check_function_bodies = false;
+SET client_min_messages = warning;
+
+--
+-- Name: plpgsql; Type: EXTENSION; Schema: -; Owner: 
+--
+
+CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog;
+
+
+--
+-- Name: EXTENSION plpgsql; Type: COMMENT; Schema: -; Owner: 
+--
+
+COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language';
+
+
+SET search_path = public, pg_catalog;
+
+SET default_tablespace = '';
+
+SET default_with_oids = false;
+
+--
+-- Name: auth_group; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE auth_group (
+    id integer NOT NULL,
+    name character varying(80) NOT NULL
+);
+
+
+ALTER TABLE public.auth_group OWNER TO postgres;
+
+--
+-- Name: auth_group_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE auth_group_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.auth_group_id_seq OWNER TO postgres;
+
+--
+-- Name: auth_group_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE auth_group_id_seq OWNED BY auth_group.id;
+
+
+--
+-- Name: auth_group_permissions; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE auth_group_permissions (
+    id integer NOT NULL,
+    group_id integer NOT NULL,
+    permission_id integer NOT NULL
+);
+
+
+ALTER TABLE public.auth_group_permissions OWNER TO postgres;
+
+--
+-- Name: auth_group_permissions_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE auth_group_permissions_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.auth_group_permissions_id_seq OWNER TO postgres;
+
+--
+-- Name: auth_group_permissions_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE auth_group_permissions_id_seq OWNED BY auth_group_permissions.id;
+
+
+--
+-- Name: auth_permission; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE auth_permission (
+    id integer NOT NULL,
+    name character varying(50) NOT NULL,
+    content_type_id integer NOT NULL,
+    codename character varying(100) NOT NULL
+);
+
+
+ALTER TABLE public.auth_permission OWNER TO postgres;
+
+--
+-- Name: auth_permission_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE auth_permission_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.auth_permission_id_seq OWNER TO postgres;
+
+--
+-- Name: auth_permission_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE auth_permission_id_seq OWNED BY auth_permission.id;
+
+
+--
+-- Name: core_account; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_account (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    site_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_account OWNER TO postgres;
+
+--
+-- Name: core_account_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_account_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_account_id_seq OWNER TO postgres;
+
+--
+-- Name: core_account_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_account_id_seq OWNED BY core_account.id;
+
+
+--
+-- Name: core_charge; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_charge (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    kind character varying(30) NOT NULL,
+    state character varying(30) NOT NULL,
+    date timestamp with time zone NOT NULL,
+    amount double precision NOT NULL,
+    "coreHours" double precision NOT NULL,
+    account_id integer NOT NULL,
+    invoice_id integer,
+    object_id integer NOT NULL,
+    slice_id integer
+);
+
+
+ALTER TABLE public.core_charge OWNER TO postgres;
+
+--
+-- Name: core_charge_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_charge_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_charge_id_seq OWNER TO postgres;
+
+--
+-- Name: core_charge_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_charge_id_seq OWNED BY core_charge.id;
+
+
+--
+-- Name: core_controller; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_controller (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(200) NOT NULL,
+    backend_type character varying(200) NOT NULL,
+    version character varying(200) NOT NULL,
+    auth_url character varying(200),
+    admin_user character varying(200),
+    admin_password character varying(200),
+    admin_tenant character varying(200),
+    domain character varying(200),
+    deployment_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_controller OWNER TO postgres;
+
+--
+-- Name: core_controller_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_controller_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_controller_id_seq OWNER TO postgres;
+
+--
+-- Name: core_controller_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_controller_id_seq OWNED BY core_controller.id;
+
+
+--
+-- Name: core_controllercredential; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_controllercredential (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(128) NOT NULL,
+    key_id character varying(1024) NOT NULL,
+    enc_value text NOT NULL,
+    controller_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_controllercredential OWNER TO postgres;
+
+--
+-- Name: core_controllercredential_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_controllercredential_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_controllercredential_id_seq OWNER TO postgres;
+
+--
+-- Name: core_controllercredential_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_controllercredential_id_seq OWNED BY core_controllercredential.id;
+
+
+--
+-- Name: core_controllerdashboardview; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_controllerdashboardview (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    enabled boolean NOT NULL,
+    url character varying(1024) NOT NULL,
+    controller_id integer NOT NULL,
+    "dashboardView_id" integer NOT NULL
+);
+
+
+ALTER TABLE public.core_controllerdashboardview OWNER TO postgres;
+
+--
+-- Name: core_controllerdashboardview_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_controllerdashboardview_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_controllerdashboardview_id_seq OWNER TO postgres;
+
+--
+-- Name: core_controllerdashboardview_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_controllerdashboardview_id_seq OWNED BY core_controllerdashboardview.id;
+
+
+--
+-- Name: core_controllerimages; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_controllerimages (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    glance_image_id character varying(200),
+    controller_id integer NOT NULL,
+    image_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_controllerimages OWNER TO postgres;
+
+--
+-- Name: core_controllerimages_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_controllerimages_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_controllerimages_id_seq OWNER TO postgres;
+
+--
+-- Name: core_controllerimages_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_controllerimages_id_seq OWNED BY core_controllerimages.id;
+
+
+--
+-- Name: core_controllernetwork; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_controllernetwork (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    net_id character varying(256),
+    router_id character varying(256),
+    subnet_id character varying(256),
+    subnet character varying(32) NOT NULL,
+    controller_id integer NOT NULL,
+    network_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_controllernetwork OWNER TO postgres;
+
+--
+-- Name: core_controllernetwork_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_controllernetwork_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_controllernetwork_id_seq OWNER TO postgres;
+
+--
+-- Name: core_controllernetwork_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_controllernetwork_id_seq OWNED BY core_controllernetwork.id;
+
+
+--
+-- Name: core_controllerrole; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_controllerrole (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    role character varying(30) NOT NULL
+);
+
+
+ALTER TABLE public.core_controllerrole OWNER TO postgres;
+
+--
+-- Name: core_controllerrole_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_controllerrole_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_controllerrole_id_seq OWNER TO postgres;
+
+--
+-- Name: core_controllerrole_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_controllerrole_id_seq OWNED BY core_controllerrole.id;
+
+
+--
+-- Name: core_controllersite; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_controllersite (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    tenant_id character varying(200),
+    controller_id integer,
+    site_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_controllersite OWNER TO postgres;
+
+--
+-- Name: core_controllersite_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_controllersite_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_controllersite_id_seq OWNER TO postgres;
+
+--
+-- Name: core_controllersite_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_controllersite_id_seq OWNED BY core_controllersite.id;
+
+
+--
+-- Name: core_controllersiteprivilege; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_controllersiteprivilege (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    role_id character varying(200),
+    controller_id integer NOT NULL,
+    site_privilege_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_controllersiteprivilege OWNER TO postgres;
+
+--
+-- Name: core_controllersiteprivilege_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_controllersiteprivilege_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_controllersiteprivilege_id_seq OWNER TO postgres;
+
+--
+-- Name: core_controllersiteprivilege_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_controllersiteprivilege_id_seq OWNED BY core_controllersiteprivilege.id;
+
+
+--
+-- Name: core_controllerslice; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_controllerslice (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    tenant_id character varying(200),
+    controller_id integer NOT NULL,
+    slice_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_controllerslice OWNER TO postgres;
+
+--
+-- Name: core_controllerslice_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_controllerslice_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_controllerslice_id_seq OWNER TO postgres;
+
+--
+-- Name: core_controllerslice_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_controllerslice_id_seq OWNED BY core_controllerslice.id;
+
+
+--
+-- Name: core_controllersliceprivilege; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_controllersliceprivilege (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    role_id character varying(200),
+    controller_id integer NOT NULL,
+    slice_privilege_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_controllersliceprivilege OWNER TO postgres;
+
+--
+-- Name: core_controllersliceprivilege_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_controllersliceprivilege_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_controllersliceprivilege_id_seq OWNER TO postgres;
+
+--
+-- Name: core_controllersliceprivilege_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_controllersliceprivilege_id_seq OWNED BY core_controllersliceprivilege.id;
+
+
+--
+-- Name: core_controlleruser; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_controlleruser (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    kuser_id character varying(200),
+    controller_id integer NOT NULL,
+    user_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_controlleruser OWNER TO postgres;
+
+--
+-- Name: core_controlleruser_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_controlleruser_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_controlleruser_id_seq OWNER TO postgres;
+
+--
+-- Name: core_controlleruser_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_controlleruser_id_seq OWNED BY core_controlleruser.id;
+
+
+--
+-- Name: core_dashboardview; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_dashboardview (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(200) NOT NULL,
+    url character varying(1024) NOT NULL,
+    enabled boolean NOT NULL
+);
+
+
+ALTER TABLE public.core_dashboardview OWNER TO postgres;
+
+--
+-- Name: core_dashboardview_deployments; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_dashboardview_deployments (
+    id integer NOT NULL,
+    dashboardview_id integer NOT NULL,
+    deployment_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_dashboardview_deployments OWNER TO postgres;
+
+--
+-- Name: core_dashboardview_deployments_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_dashboardview_deployments_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_dashboardview_deployments_id_seq OWNER TO postgres;
+
+--
+-- Name: core_dashboardview_deployments_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_dashboardview_deployments_id_seq OWNED BY core_dashboardview_deployments.id;
+
+
+--
+-- Name: core_dashboardview_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_dashboardview_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_dashboardview_id_seq OWNER TO postgres;
+
+--
+-- Name: core_dashboardview_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_dashboardview_id_seq OWNED BY core_dashboardview.id;
+
+
+--
+-- Name: core_deployment; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_deployment (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(200) NOT NULL,
+    "accessControl" text NOT NULL
+);
+
+
+ALTER TABLE public.core_deployment OWNER TO postgres;
+
+--
+-- Name: core_deployment_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_deployment_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_deployment_id_seq OWNER TO postgres;
+
+--
+-- Name: core_deployment_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_deployment_id_seq OWNED BY core_deployment.id;
+
+
+--
+-- Name: core_deploymentprivilege; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_deploymentprivilege (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    deployment_id integer NOT NULL,
+    role_id integer NOT NULL,
+    user_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_deploymentprivilege OWNER TO postgres;
+
+--
+-- Name: core_deploymentprivilege_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_deploymentprivilege_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_deploymentprivilege_id_seq OWNER TO postgres;
+
+--
+-- Name: core_deploymentprivilege_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_deploymentprivilege_id_seq OWNED BY core_deploymentprivilege.id;
+
+
+--
+-- Name: core_deploymentrole; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_deploymentrole (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    role character varying(30) NOT NULL
+);
+
+
+ALTER TABLE public.core_deploymentrole OWNER TO postgres;
+
+--
+-- Name: core_deploymentrole_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_deploymentrole_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_deploymentrole_id_seq OWNER TO postgres;
+
+--
+-- Name: core_deploymentrole_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_deploymentrole_id_seq OWNED BY core_deploymentrole.id;
+
+
+--
+-- Name: core_flavor; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_flavor (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(32) NOT NULL,
+    description character varying(1024),
+    flavor character varying(32) NOT NULL,
+    "order" integer NOT NULL,
+    "default" boolean NOT NULL
+);
+
+
+ALTER TABLE public.core_flavor OWNER TO postgres;
+
+--
+-- Name: core_flavor_deployments; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_flavor_deployments (
+    id integer NOT NULL,
+    flavor_id integer NOT NULL,
+    deployment_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_flavor_deployments OWNER TO postgres;
+
+--
+-- Name: core_flavor_deployments_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_flavor_deployments_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_flavor_deployments_id_seq OWNER TO postgres;
+
+--
+-- Name: core_flavor_deployments_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_flavor_deployments_id_seq OWNED BY core_flavor_deployments.id;
+
+
+--
+-- Name: core_flavor_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_flavor_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_flavor_id_seq OWNER TO postgres;
+
+--
+-- Name: core_flavor_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_flavor_id_seq OWNED BY core_flavor.id;
+
+
+--
+-- Name: core_image; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_image (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(256) NOT NULL,
+    disk_format character varying(256) NOT NULL,
+    container_format character varying(256) NOT NULL,
+    path character varying(256)
+);
+
+
+ALTER TABLE public.core_image OWNER TO postgres;
+
+--
+-- Name: core_image_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_image_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_image_id_seq OWNER TO postgres;
+
+--
+-- Name: core_image_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_image_id_seq OWNED BY core_image.id;
+
+
+--
+-- Name: core_imagedeployments; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_imagedeployments (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    deployment_id integer NOT NULL,
+    image_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_imagedeployments OWNER TO postgres;
+
+--
+-- Name: core_imagedeployments_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_imagedeployments_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_imagedeployments_id_seq OWNER TO postgres;
+
+--
+-- Name: core_imagedeployments_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_imagedeployments_id_seq OWNED BY core_imagedeployments.id;
+
+
+--
+-- Name: core_instance; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_instance (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    instance_id character varying(200),
+    instance_uuid character varying(200),
+    name character varying(200) NOT NULL,
+    instance_name character varying(200),
+    ip inet,
+    "numberCores" integer NOT NULL,
+    "userData" text,
+    creator_id integer,
+    deployment_id integer NOT NULL,
+    flavor_id integer NOT NULL,
+    image_id integer NOT NULL,
+    node_id integer NOT NULL,
+    slice_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_instance OWNER TO postgres;
+
+--
+-- Name: core_instance_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_instance_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_instance_id_seq OWNER TO postgres;
+
+--
+-- Name: core_instance_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_instance_id_seq OWNED BY core_instance.id;
+
+
+--
+-- Name: core_invoice; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_invoice (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    date timestamp with time zone NOT NULL,
+    account_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_invoice OWNER TO postgres;
+
+--
+-- Name: core_invoice_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_invoice_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_invoice_id_seq OWNER TO postgres;
+
+--
+-- Name: core_invoice_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_invoice_id_seq OWNED BY core_invoice.id;
+
+
+--
+-- Name: core_network; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_network (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(32) NOT NULL,
+    subnet character varying(32) NOT NULL,
+    ports character varying(1024),
+    labels character varying(1024),
+    guaranteed_bandwidth integer NOT NULL,
+    permit_all_slices boolean NOT NULL,
+    topology_parameters text,
+    controller_url character varying(1024),
+    controller_parameters text,
+    network_id character varying(256),
+    router_id character varying(256),
+    subnet_id character varying(256),
+    autoconnect boolean NOT NULL,
+    owner_id integer NOT NULL,
+    template_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_network OWNER TO postgres;
+
+--
+-- Name: core_network_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_network_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_network_id_seq OWNER TO postgres;
+
+--
+-- Name: core_network_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_network_id_seq OWNED BY core_network.id;
+
+
+--
+-- Name: core_network_permitted_slices; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_network_permitted_slices (
+    id integer NOT NULL,
+    network_id integer NOT NULL,
+    slice_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_network_permitted_slices OWNER TO postgres;
+
+--
+-- Name: core_network_permitted_slices_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_network_permitted_slices_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_network_permitted_slices_id_seq OWNER TO postgres;
+
+--
+-- Name: core_network_permitted_slices_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_network_permitted_slices_id_seq OWNED BY core_network_permitted_slices.id;
+
+
+--
+-- Name: core_networkparameter; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_networkparameter (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    value character varying(1024) NOT NULL,
+    object_id integer NOT NULL,
+    content_type_id integer NOT NULL,
+    parameter_id integer NOT NULL,
+    CONSTRAINT core_networkparameter_object_id_check CHECK ((object_id >= 0))
+);
+
+
+ALTER TABLE public.core_networkparameter OWNER TO postgres;
+
+--
+-- Name: core_networkparameter_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_networkparameter_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_networkparameter_id_seq OWNER TO postgres;
+
+--
+-- Name: core_networkparameter_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_networkparameter_id_seq OWNED BY core_networkparameter.id;
+
+
+--
+-- Name: core_networkparametertype; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_networkparametertype (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(128) NOT NULL,
+    description character varying(1024) NOT NULL
+);
+
+
+ALTER TABLE public.core_networkparametertype OWNER TO postgres;
+
+--
+-- Name: core_networkparametertype_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_networkparametertype_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_networkparametertype_id_seq OWNER TO postgres;
+
+--
+-- Name: core_networkparametertype_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_networkparametertype_id_seq OWNED BY core_networkparametertype.id;
+
+
+--
+-- Name: core_networkslice; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_networkslice (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    network_id integer NOT NULL,
+    slice_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_networkslice OWNER TO postgres;
+
+--
+-- Name: core_networkslice_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_networkslice_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_networkslice_id_seq OWNER TO postgres;
+
+--
+-- Name: core_networkslice_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_networkslice_id_seq OWNED BY core_networkslice.id;
+
+
+--
+-- Name: core_networktemplate; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_networktemplate (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(32) NOT NULL,
+    description character varying(1024),
+    guaranteed_bandwidth integer NOT NULL,
+    visibility character varying(30) NOT NULL,
+    translation character varying(30) NOT NULL,
+    shared_network_name character varying(30),
+    shared_network_id character varying(256),
+    topology_kind character varying(30) NOT NULL,
+    controller_kind character varying(30)
+);
+
+
+ALTER TABLE public.core_networktemplate OWNER TO postgres;
+
+--
+-- Name: core_networktemplate_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_networktemplate_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_networktemplate_id_seq OWNER TO postgres;
+
+--
+-- Name: core_networktemplate_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_networktemplate_id_seq OWNED BY core_networktemplate.id;
+
+
+--
+-- Name: core_node; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_node (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(200) NOT NULL,
+    site_id integer,
+    site_deployment_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_node OWNER TO postgres;
+
+--
+-- Name: core_node_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_node_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_node_id_seq OWNER TO postgres;
+
+--
+-- Name: core_node_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_node_id_seq OWNED BY core_node.id;
+
+
+--
+-- Name: core_payment; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_payment (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    amount double precision NOT NULL,
+    date timestamp with time zone NOT NULL,
+    account_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_payment OWNER TO postgres;
+
+--
+-- Name: core_payment_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_payment_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_payment_id_seq OWNER TO postgres;
+
+--
+-- Name: core_payment_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_payment_id_seq OWNED BY core_payment.id;
+
+
+--
+-- Name: core_port; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_port (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    ip inet,
+    port_id character varying(256),
+    mac character varying(256),
+    instance_id integer,
+    network_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_port OWNER TO postgres;
+
+--
+-- Name: core_port_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_port_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_port_id_seq OWNER TO postgres;
+
+--
+-- Name: core_port_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_port_id_seq OWNED BY core_port.id;
+
+
+--
+-- Name: core_program; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_program (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(30) NOT NULL,
+    description text,
+    kind character varying(30) NOT NULL,
+    command character varying(30),
+    contents text,
+    output text,
+    messages text,
+    status text,
+    owner_id integer
+);
+
+
+ALTER TABLE public.core_program OWNER TO postgres;
+
+--
+-- Name: core_program_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_program_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_program_id_seq OWNER TO postgres;
+
+--
+-- Name: core_program_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_program_id_seq OWNED BY core_program.id;
+
+
+--
+-- Name: core_project; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_project (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(200) NOT NULL
+);
+
+
+ALTER TABLE public.core_project OWNER TO postgres;
+
+--
+-- Name: core_project_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_project_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_project_id_seq OWNER TO postgres;
+
+--
+-- Name: core_project_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_project_id_seq OWNED BY core_project.id;
+
+
+--
+-- Name: core_reservation; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_reservation (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    "startTime" timestamp with time zone NOT NULL,
+    duration integer NOT NULL,
+    slice_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_reservation OWNER TO postgres;
+
+--
+-- Name: core_reservation_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_reservation_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_reservation_id_seq OWNER TO postgres;
+
+--
+-- Name: core_reservation_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_reservation_id_seq OWNED BY core_reservation.id;
+
+
+--
+-- Name: core_reservedresource; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_reservedresource (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    quantity integer NOT NULL,
+    instance_id integer NOT NULL,
+    "reservationSet_id" integer NOT NULL,
+    resource_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_reservedresource OWNER TO postgres;
+
+--
+-- Name: core_reservedresource_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_reservedresource_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_reservedresource_id_seq OWNER TO postgres;
+
+--
+-- Name: core_reservedresource_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_reservedresource_id_seq OWNED BY core_reservedresource.id;
+
+
+--
+-- Name: core_role; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_role (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    role_type character varying(80) NOT NULL,
+    role character varying(80),
+    description character varying(120) NOT NULL,
+    content_type_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_role OWNER TO postgres;
+
+--
+-- Name: core_role_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_role_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_role_id_seq OWNER TO postgres;
+
+--
+-- Name: core_role_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_role_id_seq OWNED BY core_role.id;
+
+
+--
+-- Name: core_router; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_router (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(32) NOT NULL,
+    owner_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_router OWNER TO postgres;
+
+--
+-- Name: core_router_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_router_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_router_id_seq OWNER TO postgres;
+
+--
+-- Name: core_router_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_router_id_seq OWNED BY core_router.id;
+
+
+--
+-- Name: core_router_networks; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_router_networks (
+    id integer NOT NULL,
+    router_id integer NOT NULL,
+    network_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_router_networks OWNER TO postgres;
+
+--
+-- Name: core_router_networks_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_router_networks_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_router_networks_id_seq OWNER TO postgres;
+
+--
+-- Name: core_router_networks_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_router_networks_id_seq OWNED BY core_router_networks.id;
+
+
+--
+-- Name: core_router_permittedNetworks; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE "core_router_permittedNetworks" (
+    id integer NOT NULL,
+    router_id integer NOT NULL,
+    network_id integer NOT NULL
+);
+
+
+ALTER TABLE public."core_router_permittedNetworks" OWNER TO postgres;
+
+--
+-- Name: core_router_permittedNetworks_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE "core_router_permittedNetworks_id_seq"
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public."core_router_permittedNetworks_id_seq" OWNER TO postgres;
+
+--
+-- Name: core_router_permittedNetworks_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE "core_router_permittedNetworks_id_seq" OWNED BY "core_router_permittedNetworks".id;
+
+
+--
+-- Name: core_service; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_service (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    description text,
+    enabled boolean NOT NULL,
+    kind character varying(30) NOT NULL,
+    name character varying(30) NOT NULL,
+    "versionNumber" character varying(30) NOT NULL,
+    published boolean NOT NULL,
+    view_url character varying(1024),
+    icon_url character varying(1024),
+    public_key text,
+    service_specific_id character varying(30),
+    service_specific_attribute text
+);
+
+
+ALTER TABLE public.core_service OWNER TO postgres;
+
+--
+-- Name: core_service_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_service_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_service_id_seq OWNER TO postgres;
+
+--
+-- Name: core_service_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_service_id_seq OWNED BY core_service.id;
+
+
+--
+-- Name: core_serviceattribute; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_serviceattribute (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(128) NOT NULL,
+    value character varying(1024) NOT NULL,
+    service_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_serviceattribute OWNER TO postgres;
+
+--
+-- Name: core_serviceattribute_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_serviceattribute_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_serviceattribute_id_seq OWNER TO postgres;
+
+--
+-- Name: core_serviceattribute_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_serviceattribute_id_seq OWNED BY core_serviceattribute.id;
+
+
+--
+-- Name: core_serviceclass; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_serviceclass (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(32) NOT NULL,
+    description character varying(255) NOT NULL,
+    commitment integer NOT NULL,
+    "membershipFee" integer NOT NULL,
+    "membershipFeeMonths" integer NOT NULL,
+    "upgradeRequiresApproval" boolean NOT NULL
+);
+
+
+ALTER TABLE public.core_serviceclass OWNER TO postgres;
+
+--
+-- Name: core_serviceclass_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_serviceclass_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_serviceclass_id_seq OWNER TO postgres;
+
+--
+-- Name: core_serviceclass_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_serviceclass_id_seq OWNED BY core_serviceclass.id;
+
+
+--
+-- Name: core_serviceclass_upgradeFrom; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE "core_serviceclass_upgradeFrom" (
+    id integer NOT NULL,
+    from_serviceclass_id integer NOT NULL,
+    to_serviceclass_id integer NOT NULL
+);
+
+
+ALTER TABLE public."core_serviceclass_upgradeFrom" OWNER TO postgres;
+
+--
+-- Name: core_serviceclass_upgradeFrom_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE "core_serviceclass_upgradeFrom_id_seq"
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public."core_serviceclass_upgradeFrom_id_seq" OWNER TO postgres;
+
+--
+-- Name: core_serviceclass_upgradeFrom_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE "core_serviceclass_upgradeFrom_id_seq" OWNED BY "core_serviceclass_upgradeFrom".id;
+
+
+--
+-- Name: core_serviceprivilege; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_serviceprivilege (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    role_id integer NOT NULL,
+    service_id integer NOT NULL,
+    user_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_serviceprivilege OWNER TO postgres;
+
+--
+-- Name: core_serviceprivilege_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_serviceprivilege_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_serviceprivilege_id_seq OWNER TO postgres;
+
+--
+-- Name: core_serviceprivilege_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_serviceprivilege_id_seq OWNED BY core_serviceprivilege.id;
+
+
+--
+-- Name: core_serviceresource; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_serviceresource (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(32) NOT NULL,
+    "maxUnitsDeployment" integer NOT NULL,
+    "maxUnitsNode" integer NOT NULL,
+    "maxDuration" integer NOT NULL,
+    "bucketInRate" integer NOT NULL,
+    "bucketMaxSize" integer NOT NULL,
+    cost integer NOT NULL,
+    "calendarReservable" boolean NOT NULL,
+    "serviceClass_id" integer NOT NULL
+);
+
+
+ALTER TABLE public.core_serviceresource OWNER TO postgres;
+
+--
+-- Name: core_serviceresource_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_serviceresource_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_serviceresource_id_seq OWNER TO postgres;
+
+--
+-- Name: core_serviceresource_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_serviceresource_id_seq OWNED BY core_serviceresource.id;
+
+
+--
+-- Name: core_servicerole; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_servicerole (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    role character varying(30) NOT NULL
+);
+
+
+ALTER TABLE public.core_servicerole OWNER TO postgres;
+
+--
+-- Name: core_servicerole_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_servicerole_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_servicerole_id_seq OWNER TO postgres;
+
+--
+-- Name: core_servicerole_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_servicerole_id_seq OWNED BY core_servicerole.id;
+
+
+--
+-- Name: core_site; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_site (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(200) NOT NULL,
+    site_url character varying(512),
+    enabled boolean NOT NULL,
+    hosts_nodes boolean NOT NULL,
+    hosts_users boolean NOT NULL,
+    location character varying(42) NOT NULL,
+    longitude double precision,
+    latitude double precision,
+    login_base character varying(50) NOT NULL,
+    is_public boolean NOT NULL,
+    abbreviated_name character varying(80) NOT NULL
+);
+
+
+ALTER TABLE public.core_site OWNER TO postgres;
+
+--
+-- Name: core_site_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_site_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_site_id_seq OWNER TO postgres;
+
+--
+-- Name: core_site_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_site_id_seq OWNED BY core_site.id;
+
+
+--
+-- Name: core_sitecredential; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_sitecredential (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(128) NOT NULL,
+    key_id character varying(1024) NOT NULL,
+    enc_value text NOT NULL,
+    site_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_sitecredential OWNER TO postgres;
+
+--
+-- Name: core_sitecredential_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_sitecredential_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_sitecredential_id_seq OWNER TO postgres;
+
+--
+-- Name: core_sitecredential_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_sitecredential_id_seq OWNED BY core_sitecredential.id;
+
+
+--
+-- Name: core_sitedeployment; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_sitedeployment (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    availability_zone character varying(200),
+    controller_id integer,
+    deployment_id integer NOT NULL,
+    site_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_sitedeployment OWNER TO postgres;
+
+--
+-- Name: core_sitedeployment_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_sitedeployment_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_sitedeployment_id_seq OWNER TO postgres;
+
+--
+-- Name: core_sitedeployment_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_sitedeployment_id_seq OWNED BY core_sitedeployment.id;
+
+
+--
+-- Name: core_siteprivilege; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_siteprivilege (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    role_id integer NOT NULL,
+    site_id integer NOT NULL,
+    user_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_siteprivilege OWNER TO postgres;
+
+--
+-- Name: core_siteprivilege_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_siteprivilege_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_siteprivilege_id_seq OWNER TO postgres;
+
+--
+-- Name: core_siteprivilege_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_siteprivilege_id_seq OWNED BY core_siteprivilege.id;
+
+
+--
+-- Name: core_siterole; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_siterole (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    role character varying(30) NOT NULL
+);
+
+
+ALTER TABLE public.core_siterole OWNER TO postgres;
+
+--
+-- Name: core_siterole_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_siterole_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_siterole_id_seq OWNER TO postgres;
+
+--
+-- Name: core_siterole_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_siterole_id_seq OWNED BY core_siterole.id;
+
+
+--
+-- Name: core_slice; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_slice (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(80) NOT NULL,
+    enabled boolean NOT NULL,
+    omf_friendly boolean NOT NULL,
+    description text NOT NULL,
+    slice_url character varying(512) NOT NULL,
+    max_instances integer NOT NULL,
+    network character varying(256),
+    mount_data_sets character varying(256),
+    creator_id integer,
+    default_flavor_id integer,
+    default_image_id integer,
+    service_id integer,
+    "serviceClass_id" integer,
+    site_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_slice OWNER TO postgres;
+
+--
+-- Name: core_slice_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_slice_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_slice_id_seq OWNER TO postgres;
+
+--
+-- Name: core_slice_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_slice_id_seq OWNED BY core_slice.id;
+
+
+--
+-- Name: core_slicecredential; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_slicecredential (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(128) NOT NULL,
+    key_id character varying(1024) NOT NULL,
+    enc_value text NOT NULL,
+    slice_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_slicecredential OWNER TO postgres;
+
+--
+-- Name: core_slicecredential_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_slicecredential_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_slicecredential_id_seq OWNER TO postgres;
+
+--
+-- Name: core_slicecredential_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_slicecredential_id_seq OWNED BY core_slicecredential.id;
+
+
+--
+-- Name: core_sliceprivilege; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_sliceprivilege (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    role_id integer NOT NULL,
+    slice_id integer NOT NULL,
+    user_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_sliceprivilege OWNER TO postgres;
+
+--
+-- Name: core_sliceprivilege_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_sliceprivilege_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_sliceprivilege_id_seq OWNER TO postgres;
+
+--
+-- Name: core_sliceprivilege_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_sliceprivilege_id_seq OWNED BY core_sliceprivilege.id;
+
+
+--
+-- Name: core_slicerole; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_slicerole (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    role character varying(30) NOT NULL
+);
+
+
+ALTER TABLE public.core_slicerole OWNER TO postgres;
+
+--
+-- Name: core_slicerole_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_slicerole_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_slicerole_id_seq OWNER TO postgres;
+
+--
+-- Name: core_slicerole_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_slicerole_id_seq OWNED BY core_slicerole.id;
+
+
+--
+-- Name: core_slicetag; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_slicetag (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(30) NOT NULL,
+    value character varying(1024) NOT NULL,
+    slice_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_slicetag OWNER TO postgres;
+
+--
+-- Name: core_slicetag_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_slicetag_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_slicetag_id_seq OWNER TO postgres;
+
+--
+-- Name: core_slicetag_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_slicetag_id_seq OWNED BY core_slicetag.id;
+
+
+--
+-- Name: core_tag; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_tag (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(128) NOT NULL,
+    value character varying(1024) NOT NULL,
+    object_id integer NOT NULL,
+    content_type_id integer NOT NULL,
+    service_id integer NOT NULL,
+    CONSTRAINT core_tag_object_id_check CHECK ((object_id >= 0))
+);
+
+
+ALTER TABLE public.core_tag OWNER TO postgres;
+
+--
+-- Name: core_tag_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_tag_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_tag_id_seq OWNER TO postgres;
+
+--
+-- Name: core_tag_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_tag_id_seq OWNED BY core_tag.id;
+
+
+--
+-- Name: core_tenant; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_tenant (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    kind character varying(30) NOT NULL,
+    service_specific_id character varying(30),
+    service_specific_attribute text,
+    connect_method character varying(30) NOT NULL,
+    provider_service_id integer NOT NULL,
+    subscriber_root_id integer,
+    subscriber_service_id integer,
+    subscriber_tenant_id integer,
+    subscriber_user_id integer
+);
+
+
+ALTER TABLE public.core_tenant OWNER TO postgres;
+
+--
+-- Name: core_tenant_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_tenant_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_tenant_id_seq OWNER TO postgres;
+
+--
+-- Name: core_tenant_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_tenant_id_seq OWNED BY core_tenant.id;
+
+
+--
+-- Name: core_tenantroot; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_tenantroot (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    kind character varying(30) NOT NULL,
+    name character varying(255),
+    service_specific_attribute text,
+    service_specific_id character varying(30)
+);
+
+
+ALTER TABLE public.core_tenantroot OWNER TO postgres;
+
+--
+-- Name: core_tenantroot_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_tenantroot_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_tenantroot_id_seq OWNER TO postgres;
+
+--
+-- Name: core_tenantroot_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_tenantroot_id_seq OWNED BY core_tenantroot.id;
+
+
+--
+-- Name: core_tenantrootprivilege; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_tenantrootprivilege (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    role_id integer NOT NULL,
+    tenant_root_id integer NOT NULL,
+    user_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_tenantrootprivilege OWNER TO postgres;
+
+--
+-- Name: core_tenantrootprivilege_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_tenantrootprivilege_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_tenantrootprivilege_id_seq OWNER TO postgres;
+
+--
+-- Name: core_tenantrootprivilege_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_tenantrootprivilege_id_seq OWNED BY core_tenantrootprivilege.id;
+
+
+--
+-- Name: core_tenantrootrole; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_tenantrootrole (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    role character varying(30) NOT NULL
+);
+
+
+ALTER TABLE public.core_tenantrootrole OWNER TO postgres;
+
+--
+-- Name: core_tenantrootrole_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_tenantrootrole_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_tenantrootrole_id_seq OWNER TO postgres;
+
+--
+-- Name: core_tenantrootrole_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_tenantrootrole_id_seq OWNED BY core_tenantrootrole.id;
+
+
+--
+-- Name: core_usableobject; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_usableobject (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(1024) NOT NULL
+);
+
+
+ALTER TABLE public.core_usableobject OWNER TO postgres;
+
+--
+-- Name: core_usableobject_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_usableobject_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_usableobject_id_seq OWNER TO postgres;
+
+--
+-- Name: core_usableobject_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_usableobject_id_seq OWNED BY core_usableobject.id;
+
+
+--
+-- Name: core_user; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_user (
+    id integer NOT NULL,
+    password character varying(128) NOT NULL,
+    last_login timestamp with time zone NOT NULL,
+    email character varying(255) NOT NULL,
+    username character varying(255) NOT NULL,
+    firstname character varying(200) NOT NULL,
+    lastname character varying(200) NOT NULL,
+    phone character varying(100),
+    user_url character varying(200),
+    public_key text,
+    is_active boolean NOT NULL,
+    is_admin boolean NOT NULL,
+    is_staff boolean NOT NULL,
+    is_readonly boolean NOT NULL,
+    is_registering boolean NOT NULL,
+    is_appuser boolean NOT NULL,
+    login_page character varying(200),
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    timezone character varying(100) NOT NULL,
+    site_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_user OWNER TO postgres;
+
+--
+-- Name: core_user_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_user_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_user_id_seq OWNER TO postgres;
+
+--
+-- Name: core_user_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_user_id_seq OWNED BY core_user.id;
+
+
+--
+-- Name: core_usercredential; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_usercredential (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(128) NOT NULL,
+    key_id character varying(1024) NOT NULL,
+    enc_value text NOT NULL,
+    user_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_usercredential OWNER TO postgres;
+
+--
+-- Name: core_usercredential_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_usercredential_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_usercredential_id_seq OWNER TO postgres;
+
+--
+-- Name: core_usercredential_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_usercredential_id_seq OWNED BY core_usercredential.id;
+
+
+--
+-- Name: core_userdashboardview; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE core_userdashboardview (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    "order" integer NOT NULL,
+    "dashboardView_id" integer NOT NULL,
+    user_id integer NOT NULL
+);
+
+
+ALTER TABLE public.core_userdashboardview OWNER TO postgres;
+
+--
+-- Name: core_userdashboardview_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE core_userdashboardview_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.core_userdashboardview_id_seq OWNER TO postgres;
+
+--
+-- Name: core_userdashboardview_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE core_userdashboardview_id_seq OWNED BY core_userdashboardview.id;
+
+
+--
+-- Name: django_admin_log; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE django_admin_log (
+    id integer NOT NULL,
+    action_time timestamp with time zone NOT NULL,
+    object_id text,
+    object_repr character varying(200) NOT NULL,
+    action_flag smallint NOT NULL,
+    change_message text NOT NULL,
+    content_type_id integer,
+    user_id integer NOT NULL,
+    CONSTRAINT django_admin_log_action_flag_check CHECK ((action_flag >= 0))
+);
+
+
+ALTER TABLE public.django_admin_log OWNER TO postgres;
+
+--
+-- Name: django_admin_log_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE django_admin_log_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.django_admin_log_id_seq OWNER TO postgres;
+
+--
+-- Name: django_admin_log_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE django_admin_log_id_seq OWNED BY django_admin_log.id;
+
+
+--
+-- Name: django_content_type; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE django_content_type (
+    id integer NOT NULL,
+    name character varying(100) NOT NULL,
+    app_label character varying(100) NOT NULL,
+    model character varying(100) NOT NULL
+);
+
+
+ALTER TABLE public.django_content_type OWNER TO postgres;
+
+--
+-- Name: django_content_type_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE django_content_type_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.django_content_type_id_seq OWNER TO postgres;
+
+--
+-- Name: django_content_type_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE django_content_type_id_seq OWNED BY django_content_type.id;
+
+
+--
+-- Name: django_migrations; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE django_migrations (
+    id integer NOT NULL,
+    app character varying(255) NOT NULL,
+    name character varying(255) NOT NULL,
+    applied timestamp with time zone NOT NULL
+);
+
+
+ALTER TABLE public.django_migrations OWNER TO postgres;
+
+--
+-- Name: django_migrations_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE django_migrations_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.django_migrations_id_seq OWNER TO postgres;
+
+--
+-- Name: django_migrations_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE django_migrations_id_seq OWNED BY django_migrations.id;
+
+
+--
+-- Name: django_session; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE django_session (
+    session_key character varying(40) NOT NULL,
+    session_data text NOT NULL,
+    expire_date timestamp with time zone NOT NULL
+);
+
+
+ALTER TABLE public.django_session OWNER TO postgres;
+
+--
+-- Name: hpc_accessmap; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE hpc_accessmap (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(64) NOT NULL,
+    description text,
+    map character varying(100) NOT NULL,
+    "contentProvider_id" integer NOT NULL
+);
+
+
+ALTER TABLE public.hpc_accessmap OWNER TO postgres;
+
+--
+-- Name: hpc_accessmap_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE hpc_accessmap_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.hpc_accessmap_id_seq OWNER TO postgres;
+
+--
+-- Name: hpc_accessmap_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE hpc_accessmap_id_seq OWNED BY hpc_accessmap.id;
+
+
+--
+-- Name: hpc_cdnprefix; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE hpc_cdnprefix (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    cdn_prefix_id integer,
+    prefix character varying(200) NOT NULL,
+    description text,
+    enabled boolean NOT NULL,
+    "contentProvider_id" integer NOT NULL,
+    "defaultOriginServer_id" integer
+);
+
+
+ALTER TABLE public.hpc_cdnprefix OWNER TO postgres;
+
+--
+-- Name: hpc_cdnprefix_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE hpc_cdnprefix_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.hpc_cdnprefix_id_seq OWNER TO postgres;
+
+--
+-- Name: hpc_cdnprefix_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE hpc_cdnprefix_id_seq OWNED BY hpc_cdnprefix.id;
+
+
+--
+-- Name: hpc_contentprovider; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE hpc_contentprovider (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    content_provider_id integer,
+    name character varying(254) NOT NULL,
+    enabled boolean NOT NULL,
+    description text,
+    "serviceProvider_id" integer NOT NULL
+);
+
+
+ALTER TABLE public.hpc_contentprovider OWNER TO postgres;
+
+--
+-- Name: hpc_contentprovider_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE hpc_contentprovider_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.hpc_contentprovider_id_seq OWNER TO postgres;
+
+--
+-- Name: hpc_contentprovider_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE hpc_contentprovider_id_seq OWNED BY hpc_contentprovider.id;
+
+
+--
+-- Name: hpc_contentprovider_users; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE hpc_contentprovider_users (
+    id integer NOT NULL,
+    contentprovider_id integer NOT NULL,
+    user_id integer NOT NULL
+);
+
+
+ALTER TABLE public.hpc_contentprovider_users OWNER TO postgres;
+
+--
+-- Name: hpc_contentprovider_users_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE hpc_contentprovider_users_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.hpc_contentprovider_users_id_seq OWNER TO postgres;
+
+--
+-- Name: hpc_contentprovider_users_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE hpc_contentprovider_users_id_seq OWNED BY hpc_contentprovider_users.id;
+
+
+--
+-- Name: hpc_hpchealthcheck; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE hpc_hpchealthcheck (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    kind character varying(30) NOT NULL,
+    resource_name character varying(1024) NOT NULL,
+    result_contains character varying(1024),
+    result_min_size integer,
+    result_max_size integer,
+    "hpcService_id" integer
+);
+
+
+ALTER TABLE public.hpc_hpchealthcheck OWNER TO postgres;
+
+--
+-- Name: hpc_hpchealthcheck_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE hpc_hpchealthcheck_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.hpc_hpchealthcheck_id_seq OWNER TO postgres;
+
+--
+-- Name: hpc_hpchealthcheck_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE hpc_hpchealthcheck_id_seq OWNED BY hpc_hpchealthcheck.id;
+
+
+--
+-- Name: hpc_hpcservice; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE hpc_hpcservice (
+    service_ptr_id integer NOT NULL,
+    cmi_hostname character varying(254),
+    hpc_port80 boolean NOT NULL,
+    watcher_hpc_network character varying(254),
+    watcher_dnsdemux_network character varying(254),
+    watcher_dnsredir_network character varying(254)
+);
+
+
+ALTER TABLE public.hpc_hpcservice OWNER TO postgres;
+
+--
+-- Name: hpc_originserver; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE hpc_originserver (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    origin_server_id integer,
+    url character varying(1024) NOT NULL,
+    authenticated boolean NOT NULL,
+    enabled boolean NOT NULL,
+    protocol character varying(12) NOT NULL,
+    redirects boolean NOT NULL,
+    description text,
+    "contentProvider_id" integer NOT NULL
+);
+
+
+ALTER TABLE public.hpc_originserver OWNER TO postgres;
+
+--
+-- Name: hpc_originserver_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE hpc_originserver_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.hpc_originserver_id_seq OWNER TO postgres;
+
+--
+-- Name: hpc_originserver_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE hpc_originserver_id_seq OWNED BY hpc_originserver.id;
+
+
+--
+-- Name: hpc_serviceprovider; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE hpc_serviceprovider (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    service_provider_id integer,
+    name character varying(254) NOT NULL,
+    description text,
+    enabled boolean NOT NULL,
+    "hpcService_id" integer NOT NULL
+);
+
+
+ALTER TABLE public.hpc_serviceprovider OWNER TO postgres;
+
+--
+-- Name: hpc_serviceprovider_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE hpc_serviceprovider_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.hpc_serviceprovider_id_seq OWNER TO postgres;
+
+--
+-- Name: hpc_serviceprovider_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE hpc_serviceprovider_id_seq OWNED BY hpc_serviceprovider.id;
+
+
+--
+-- Name: hpc_sitemap; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE hpc_sitemap (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(64) NOT NULL,
+    description text,
+    map character varying(100) NOT NULL,
+    map_id integer,
+    "cdnPrefix_id" integer,
+    "contentProvider_id" integer,
+    "hpcService_id" integer,
+    "serviceProvider_id" integer
+);
+
+
+ALTER TABLE public.hpc_sitemap OWNER TO postgres;
+
+--
+-- Name: hpc_sitemap_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE hpc_sitemap_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.hpc_sitemap_id_seq OWNER TO postgres;
+
+--
+-- Name: hpc_sitemap_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE hpc_sitemap_id_seq OWNED BY hpc_sitemap.id;
+
+
+--
+-- Name: requestrouter_requestrouterservice; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE requestrouter_requestrouterservice (
+    service_ptr_id integer NOT NULL,
+    "behindNat" boolean NOT NULL,
+    "defaultTTL" integer NOT NULL,
+    "defaultAction" character varying(30) NOT NULL,
+    "lastResortAction" character varying(30) NOT NULL,
+    "maxAnswers" integer NOT NULL,
+    CONSTRAINT "requestrouter_requestrouterservice_defaultTTL_check" CHECK (("defaultTTL" >= 0)),
+    CONSTRAINT "requestrouter_requestrouterservice_maxAnswers_check" CHECK (("maxAnswers" >= 0))
+);
+
+
+ALTER TABLE public.requestrouter_requestrouterservice OWNER TO postgres;
+
+--
+-- Name: requestrouter_servicemap; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE requestrouter_servicemap (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(50) NOT NULL,
+    prefix character varying(256) NOT NULL,
+    "siteMap" character varying(100) NOT NULL,
+    "accessMap" character varying(100) NOT NULL,
+    owner_id integer NOT NULL,
+    slice_id integer NOT NULL
+);
+
+
+ALTER TABLE public.requestrouter_servicemap OWNER TO postgres;
+
+--
+-- Name: requestrouter_servicemap_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE requestrouter_servicemap_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.requestrouter_servicemap_id_seq OWNER TO postgres;
+
+--
+-- Name: requestrouter_servicemap_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE requestrouter_servicemap_id_seq OWNED BY requestrouter_servicemap.id;
+
+
+--
+-- Name: syndicate_storage_slicesecret; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE syndicate_storage_slicesecret (
+    id integer NOT NULL,
+    secret text NOT NULL,
+    slice_id_id integer NOT NULL
+);
+
+
+ALTER TABLE public.syndicate_storage_slicesecret OWNER TO postgres;
+
+--
+-- Name: syndicate_storage_slicesecret_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE syndicate_storage_slicesecret_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.syndicate_storage_slicesecret_id_seq OWNER TO postgres;
+
+--
+-- Name: syndicate_storage_slicesecret_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE syndicate_storage_slicesecret_id_seq OWNED BY syndicate_storage_slicesecret.id;
+
+
+--
+-- Name: syndicate_storage_syndicateprincipal; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE syndicate_storage_syndicateprincipal (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    principal_id text NOT NULL,
+    public_key_pem text NOT NULL,
+    sealed_private_key text NOT NULL
+);
+
+
+ALTER TABLE public.syndicate_storage_syndicateprincipal OWNER TO postgres;
+
+--
+-- Name: syndicate_storage_syndicateprincipal_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE syndicate_storage_syndicateprincipal_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.syndicate_storage_syndicateprincipal_id_seq OWNER TO postgres;
+
+--
+-- Name: syndicate_storage_syndicateprincipal_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE syndicate_storage_syndicateprincipal_id_seq OWNED BY syndicate_storage_syndicateprincipal.id;
+
+
+--
+-- Name: syndicate_storage_syndicateservice; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE syndicate_storage_syndicateservice (
+    service_ptr_id integer NOT NULL
+);
+
+
+ALTER TABLE public.syndicate_storage_syndicateservice OWNER TO postgres;
+
+--
+-- Name: syndicate_storage_volume; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE syndicate_storage_volume (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    name character varying(64) NOT NULL,
+    description text,
+    blocksize integer NOT NULL,
+    private boolean NOT NULL,
+    archive boolean NOT NULL,
+    cap_read_data boolean NOT NULL,
+    cap_write_data boolean NOT NULL,
+    cap_host_data boolean NOT NULL,
+    owner_id_id integer NOT NULL,
+    CONSTRAINT syndicate_storage_volume_blocksize_check CHECK ((blocksize >= 0))
+);
+
+
+ALTER TABLE public.syndicate_storage_volume OWNER TO postgres;
+
+--
+-- Name: syndicate_storage_volume_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE syndicate_storage_volume_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.syndicate_storage_volume_id_seq OWNER TO postgres;
+
+--
+-- Name: syndicate_storage_volume_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE syndicate_storage_volume_id_seq OWNED BY syndicate_storage_volume.id;
+
+
+--
+-- Name: syndicate_storage_volumeaccessright; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE syndicate_storage_volumeaccessright (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    cap_read_data boolean NOT NULL,
+    cap_write_data boolean NOT NULL,
+    cap_host_data boolean NOT NULL,
+    owner_id_id integer NOT NULL,
+    volume_id integer NOT NULL
+);
+
+
+ALTER TABLE public.syndicate_storage_volumeaccessright OWNER TO postgres;
+
+--
+-- Name: syndicate_storage_volumeaccessright_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE syndicate_storage_volumeaccessright_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.syndicate_storage_volumeaccessright_id_seq OWNER TO postgres;
+
+--
+-- Name: syndicate_storage_volumeaccessright_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE syndicate_storage_volumeaccessright_id_seq OWNED BY syndicate_storage_volumeaccessright.id;
+
+
+--
+-- Name: syndicate_storage_volumeslice; Type: TABLE; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE TABLE syndicate_storage_volumeslice (
+    id integer NOT NULL,
+    created timestamp with time zone NOT NULL,
+    updated timestamp with time zone NOT NULL,
+    enacted timestamp with time zone,
+    policed timestamp with time zone,
+    backend_register character varying(140),
+    backend_status character varying(1024) NOT NULL,
+    deleted boolean NOT NULL,
+    write_protect boolean NOT NULL,
+    lazy_blocked boolean NOT NULL,
+    no_sync boolean NOT NULL,
+    cap_read_data boolean NOT NULL,
+    cap_write_data boolean NOT NULL,
+    cap_host_data boolean NOT NULL,
+    "UG_portnum" integer NOT NULL,
+    "RG_portnum" integer NOT NULL,
+    credentials_blob text,
+    slice_id_id integer NOT NULL,
+    volume_id_id integer NOT NULL,
+    CONSTRAINT "syndicate_storage_volumeslice_RG_portnum_check" CHECK (("RG_portnum" >= 0)),
+    CONSTRAINT "syndicate_storage_volumeslice_UG_portnum_check" CHECK (("UG_portnum" >= 0))
+);
+
+
+ALTER TABLE public.syndicate_storage_volumeslice OWNER TO postgres;
+
+--
+-- Name: syndicate_storage_volumeslice_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE syndicate_storage_volumeslice_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.syndicate_storage_volumeslice_id_seq OWNER TO postgres;
+
+--
+-- Name: syndicate_storage_volumeslice_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE syndicate_storage_volumeslice_id_seq OWNED BY syndicate_storage_volumeslice.id;
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY auth_group ALTER COLUMN id SET DEFAULT nextval('auth_group_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY auth_group_permissions ALTER COLUMN id SET DEFAULT nextval('auth_group_permissions_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY auth_permission ALTER COLUMN id SET DEFAULT nextval('auth_permission_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_account ALTER COLUMN id SET DEFAULT nextval('core_account_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_charge ALTER COLUMN id SET DEFAULT nextval('core_charge_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controller ALTER COLUMN id SET DEFAULT nextval('core_controller_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllercredential ALTER COLUMN id SET DEFAULT nextval('core_controllercredential_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllerdashboardview ALTER COLUMN id SET DEFAULT nextval('core_controllerdashboardview_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllerimages ALTER COLUMN id SET DEFAULT nextval('core_controllerimages_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllernetwork ALTER COLUMN id SET DEFAULT nextval('core_controllernetwork_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllerrole ALTER COLUMN id SET DEFAULT nextval('core_controllerrole_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllersite ALTER COLUMN id SET DEFAULT nextval('core_controllersite_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllersiteprivilege ALTER COLUMN id SET DEFAULT nextval('core_controllersiteprivilege_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllerslice ALTER COLUMN id SET DEFAULT nextval('core_controllerslice_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllersliceprivilege ALTER COLUMN id SET DEFAULT nextval('core_controllersliceprivilege_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controlleruser ALTER COLUMN id SET DEFAULT nextval('core_controlleruser_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_dashboardview ALTER COLUMN id SET DEFAULT nextval('core_dashboardview_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_dashboardview_deployments ALTER COLUMN id SET DEFAULT nextval('core_dashboardview_deployments_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_deployment ALTER COLUMN id SET DEFAULT nextval('core_deployment_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_deploymentprivilege ALTER COLUMN id SET DEFAULT nextval('core_deploymentprivilege_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_deploymentrole ALTER COLUMN id SET DEFAULT nextval('core_deploymentrole_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_flavor ALTER COLUMN id SET DEFAULT nextval('core_flavor_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_flavor_deployments ALTER COLUMN id SET DEFAULT nextval('core_flavor_deployments_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_image ALTER COLUMN id SET DEFAULT nextval('core_image_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_imagedeployments ALTER COLUMN id SET DEFAULT nextval('core_imagedeployments_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_instance ALTER COLUMN id SET DEFAULT nextval('core_instance_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_invoice ALTER COLUMN id SET DEFAULT nextval('core_invoice_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_network ALTER COLUMN id SET DEFAULT nextval('core_network_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_network_permitted_slices ALTER COLUMN id SET DEFAULT nextval('core_network_permitted_slices_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_networkparameter ALTER COLUMN id SET DEFAULT nextval('core_networkparameter_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_networkparametertype ALTER COLUMN id SET DEFAULT nextval('core_networkparametertype_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_networkslice ALTER COLUMN id SET DEFAULT nextval('core_networkslice_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_networktemplate ALTER COLUMN id SET DEFAULT nextval('core_networktemplate_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_node ALTER COLUMN id SET DEFAULT nextval('core_node_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_payment ALTER COLUMN id SET DEFAULT nextval('core_payment_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_port ALTER COLUMN id SET DEFAULT nextval('core_port_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_program ALTER COLUMN id SET DEFAULT nextval('core_program_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_project ALTER COLUMN id SET DEFAULT nextval('core_project_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_reservation ALTER COLUMN id SET DEFAULT nextval('core_reservation_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_reservedresource ALTER COLUMN id SET DEFAULT nextval('core_reservedresource_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_role ALTER COLUMN id SET DEFAULT nextval('core_role_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_router ALTER COLUMN id SET DEFAULT nextval('core_router_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_router_networks ALTER COLUMN id SET DEFAULT nextval('core_router_networks_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY "core_router_permittedNetworks" ALTER COLUMN id SET DEFAULT nextval('"core_router_permittedNetworks_id_seq"'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_service ALTER COLUMN id SET DEFAULT nextval('core_service_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_serviceattribute ALTER COLUMN id SET DEFAULT nextval('core_serviceattribute_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_serviceclass ALTER COLUMN id SET DEFAULT nextval('core_serviceclass_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY "core_serviceclass_upgradeFrom" ALTER COLUMN id SET DEFAULT nextval('"core_serviceclass_upgradeFrom_id_seq"'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_serviceprivilege ALTER COLUMN id SET DEFAULT nextval('core_serviceprivilege_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_serviceresource ALTER COLUMN id SET DEFAULT nextval('core_serviceresource_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_servicerole ALTER COLUMN id SET DEFAULT nextval('core_servicerole_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_site ALTER COLUMN id SET DEFAULT nextval('core_site_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_sitecredential ALTER COLUMN id SET DEFAULT nextval('core_sitecredential_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_sitedeployment ALTER COLUMN id SET DEFAULT nextval('core_sitedeployment_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_siteprivilege ALTER COLUMN id SET DEFAULT nextval('core_siteprivilege_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_siterole ALTER COLUMN id SET DEFAULT nextval('core_siterole_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_slice ALTER COLUMN id SET DEFAULT nextval('core_slice_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_slicecredential ALTER COLUMN id SET DEFAULT nextval('core_slicecredential_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_sliceprivilege ALTER COLUMN id SET DEFAULT nextval('core_sliceprivilege_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_slicerole ALTER COLUMN id SET DEFAULT nextval('core_slicerole_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_slicetag ALTER COLUMN id SET DEFAULT nextval('core_slicetag_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_tag ALTER COLUMN id SET DEFAULT nextval('core_tag_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_tenant ALTER COLUMN id SET DEFAULT nextval('core_tenant_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_tenantroot ALTER COLUMN id SET DEFAULT nextval('core_tenantroot_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_tenantrootprivilege ALTER COLUMN id SET DEFAULT nextval('core_tenantrootprivilege_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_tenantrootrole ALTER COLUMN id SET DEFAULT nextval('core_tenantrootrole_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_usableobject ALTER COLUMN id SET DEFAULT nextval('core_usableobject_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_user ALTER COLUMN id SET DEFAULT nextval('core_user_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_usercredential ALTER COLUMN id SET DEFAULT nextval('core_usercredential_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_userdashboardview ALTER COLUMN id SET DEFAULT nextval('core_userdashboardview_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY django_admin_log ALTER COLUMN id SET DEFAULT nextval('django_admin_log_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY django_content_type ALTER COLUMN id SET DEFAULT nextval('django_content_type_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY django_migrations ALTER COLUMN id SET DEFAULT nextval('django_migrations_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_accessmap ALTER COLUMN id SET DEFAULT nextval('hpc_accessmap_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_cdnprefix ALTER COLUMN id SET DEFAULT nextval('hpc_cdnprefix_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_contentprovider ALTER COLUMN id SET DEFAULT nextval('hpc_contentprovider_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_contentprovider_users ALTER COLUMN id SET DEFAULT nextval('hpc_contentprovider_users_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_hpchealthcheck ALTER COLUMN id SET DEFAULT nextval('hpc_hpchealthcheck_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_originserver ALTER COLUMN id SET DEFAULT nextval('hpc_originserver_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_serviceprovider ALTER COLUMN id SET DEFAULT nextval('hpc_serviceprovider_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_sitemap ALTER COLUMN id SET DEFAULT nextval('hpc_sitemap_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY requestrouter_servicemap ALTER COLUMN id SET DEFAULT nextval('requestrouter_servicemap_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY syndicate_storage_slicesecret ALTER COLUMN id SET DEFAULT nextval('syndicate_storage_slicesecret_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY syndicate_storage_syndicateprincipal ALTER COLUMN id SET DEFAULT nextval('syndicate_storage_syndicateprincipal_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY syndicate_storage_volume ALTER COLUMN id SET DEFAULT nextval('syndicate_storage_volume_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY syndicate_storage_volumeaccessright ALTER COLUMN id SET DEFAULT nextval('syndicate_storage_volumeaccessright_id_seq'::regclass);
+
+
+--
+-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY syndicate_storage_volumeslice ALTER COLUMN id SET DEFAULT nextval('syndicate_storage_volumeslice_id_seq'::regclass);
+
+
+--
+-- Name: auth_group_name_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY auth_group
+    ADD CONSTRAINT auth_group_name_key UNIQUE (name);
+
+
+--
+-- Name: auth_group_permissions_group_id_permission_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY auth_group_permissions
+    ADD CONSTRAINT auth_group_permissions_group_id_permission_id_key UNIQUE (group_id, permission_id);
+
+
+--
+-- Name: auth_group_permissions_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY auth_group_permissions
+    ADD CONSTRAINT auth_group_permissions_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: auth_group_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY auth_group
+    ADD CONSTRAINT auth_group_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: auth_permission_content_type_id_codename_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY auth_permission
+    ADD CONSTRAINT auth_permission_content_type_id_codename_key UNIQUE (content_type_id, codename);
+
+
+--
+-- Name: auth_permission_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY auth_permission
+    ADD CONSTRAINT auth_permission_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_account_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_account
+    ADD CONSTRAINT core_account_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_charge_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_charge
+    ADD CONSTRAINT core_charge_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_controller_name_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_controller
+    ADD CONSTRAINT core_controller_name_key UNIQUE (name);
+
+
+--
+-- Name: core_controller_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_controller
+    ADD CONSTRAINT core_controller_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_controllercredential_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_controllercredential
+    ADD CONSTRAINT core_controllercredential_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_controllerdashboardview_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_controllerdashboardview
+    ADD CONSTRAINT core_controllerdashboardview_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_controllerimages_image_id_77d3516dbca0a5d3_uniq; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_controllerimages
+    ADD CONSTRAINT core_controllerimages_image_id_77d3516dbca0a5d3_uniq UNIQUE (image_id, controller_id);
+
+
+--
+-- Name: core_controllerimages_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_controllerimages
+    ADD CONSTRAINT core_controllerimages_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_controllernetwork_network_id_30ce4dc681f2844f_uniq; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_controllernetwork
+    ADD CONSTRAINT core_controllernetwork_network_id_30ce4dc681f2844f_uniq UNIQUE (network_id, controller_id);
+
+
+--
+-- Name: core_controllernetwork_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_controllernetwork
+    ADD CONSTRAINT core_controllernetwork_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_controllerrole_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_controllerrole
+    ADD CONSTRAINT core_controllerrole_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_controllerrole_role_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_controllerrole
+    ADD CONSTRAINT core_controllerrole_role_key UNIQUE (role);
+
+
+--
+-- Name: core_controllersite_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_controllersite
+    ADD CONSTRAINT core_controllersite_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_controllersite_site_id_22f56d79564bc81b_uniq; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_controllersite
+    ADD CONSTRAINT core_controllersite_site_id_22f56d79564bc81b_uniq UNIQUE (site_id, controller_id);
+
+
+--
+-- Name: core_controllersiteprivileg_controller_id_5d0f19c7a7ceb9e5_uniq; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_controllersiteprivilege
+    ADD CONSTRAINT core_controllersiteprivileg_controller_id_5d0f19c7a7ceb9e5_uniq UNIQUE (controller_id, site_privilege_id, role_id);
+
+
+--
+-- Name: core_controllersiteprivilege_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_controllersiteprivilege
+    ADD CONSTRAINT core_controllersiteprivilege_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_controllerslice_controller_id_427703e66574ab83_uniq; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_controllerslice
+    ADD CONSTRAINT core_controllerslice_controller_id_427703e66574ab83_uniq UNIQUE (controller_id, slice_id);
+
+
+--
+-- Name: core_controllerslice_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_controllerslice
+    ADD CONSTRAINT core_controllerslice_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_controllersliceprivile_controller_id_4e8a6f6f999d67c3_uniq; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_controllersliceprivilege
+    ADD CONSTRAINT core_controllersliceprivile_controller_id_4e8a6f6f999d67c3_uniq UNIQUE (controller_id, slice_privilege_id);
+
+
+--
+-- Name: core_controllersliceprivilege_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_controllersliceprivilege
+    ADD CONSTRAINT core_controllersliceprivilege_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_controlleruser_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_controlleruser
+    ADD CONSTRAINT core_controlleruser_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_controlleruser_user_id_3beb039133bd099b_uniq; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_controlleruser
+    ADD CONSTRAINT core_controlleruser_user_id_3beb039133bd099b_uniq UNIQUE (user_id, controller_id);
+
+
+--
+-- Name: core_dashboardview_deployment_dashboardview_id_deployment_i_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_dashboardview_deployments
+    ADD CONSTRAINT core_dashboardview_deployment_dashboardview_id_deployment_i_key UNIQUE (dashboardview_id, deployment_id);
+
+
+--
+-- Name: core_dashboardview_deployments_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_dashboardview_deployments
+    ADD CONSTRAINT core_dashboardview_deployments_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_dashboardview_name_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_dashboardview
+    ADD CONSTRAINT core_dashboardview_name_key UNIQUE (name);
+
+
+--
+-- Name: core_dashboardview_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_dashboardview
+    ADD CONSTRAINT core_dashboardview_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_deployment_name_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_deployment
+    ADD CONSTRAINT core_deployment_name_key UNIQUE (name);
+
+
+--
+-- Name: core_deployment_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_deployment
+    ADD CONSTRAINT core_deployment_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_deploymentprivilege_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_deploymentprivilege
+    ADD CONSTRAINT core_deploymentprivilege_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_deploymentprivilege_user_id_8f49da97c7cff06_uniq; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_deploymentprivilege
+    ADD CONSTRAINT core_deploymentprivilege_user_id_8f49da97c7cff06_uniq UNIQUE (user_id, deployment_id, role_id);
+
+
+--
+-- Name: core_deploymentrole_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_deploymentrole
+    ADD CONSTRAINT core_deploymentrole_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_deploymentrole_role_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_deploymentrole
+    ADD CONSTRAINT core_deploymentrole_role_key UNIQUE (role);
+
+
+--
+-- Name: core_flavor_deployments_flavor_id_deployment_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_flavor_deployments
+    ADD CONSTRAINT core_flavor_deployments_flavor_id_deployment_id_key UNIQUE (flavor_id, deployment_id);
+
+
+--
+-- Name: core_flavor_deployments_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_flavor_deployments
+    ADD CONSTRAINT core_flavor_deployments_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_flavor_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_flavor
+    ADD CONSTRAINT core_flavor_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_image_name_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_image
+    ADD CONSTRAINT core_image_name_key UNIQUE (name);
+
+
+--
+-- Name: core_image_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_image
+    ADD CONSTRAINT core_image_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_imagedeployments_image_id_3bc8a23925d399ff_uniq; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_imagedeployments
+    ADD CONSTRAINT core_imagedeployments_image_id_3bc8a23925d399ff_uniq UNIQUE (image_id, deployment_id);
+
+
+--
+-- Name: core_imagedeployments_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_imagedeployments
+    ADD CONSTRAINT core_imagedeployments_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_instance_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_instance
+    ADD CONSTRAINT core_instance_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_invoice_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_invoice
+    ADD CONSTRAINT core_invoice_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_network_permitted_slices_network_id_slice_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_network_permitted_slices
+    ADD CONSTRAINT core_network_permitted_slices_network_id_slice_id_key UNIQUE (network_id, slice_id);
+
+
+--
+-- Name: core_network_permitted_slices_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_network_permitted_slices
+    ADD CONSTRAINT core_network_permitted_slices_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_network_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_network
+    ADD CONSTRAINT core_network_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_networkparameter_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_networkparameter
+    ADD CONSTRAINT core_networkparameter_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_networkparametertype_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_networkparametertype
+    ADD CONSTRAINT core_networkparametertype_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_networkslice_network_id_78984d02ac7c1fb3_uniq; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_networkslice
+    ADD CONSTRAINT core_networkslice_network_id_78984d02ac7c1fb3_uniq UNIQUE (network_id, slice_id);
+
+
+--
+-- Name: core_networkslice_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_networkslice
+    ADD CONSTRAINT core_networkslice_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_networktemplate_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_networktemplate
+    ADD CONSTRAINT core_networktemplate_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_node_name_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_node
+    ADD CONSTRAINT core_node_name_key UNIQUE (name);
+
+
+--
+-- Name: core_node_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_node
+    ADD CONSTRAINT core_node_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_payment_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_payment
+    ADD CONSTRAINT core_payment_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_port_network_id_693ab091ccd5a89a_uniq; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_port
+    ADD CONSTRAINT core_port_network_id_693ab091ccd5a89a_uniq UNIQUE (network_id, instance_id);
+
+
+--
+-- Name: core_port_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_port
+    ADD CONSTRAINT core_port_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_program_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_program
+    ADD CONSTRAINT core_program_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_project_name_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_project
+    ADD CONSTRAINT core_project_name_key UNIQUE (name);
+
+
+--
+-- Name: core_project_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_project
+    ADD CONSTRAINT core_project_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_reservation_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_reservation
+    ADD CONSTRAINT core_reservation_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_reservedresource_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_reservedresource
+    ADD CONSTRAINT core_reservedresource_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_role_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_role
+    ADD CONSTRAINT core_role_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_router_networks_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_router_networks
+    ADD CONSTRAINT core_router_networks_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_router_networks_router_id_network_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_router_networks
+    ADD CONSTRAINT core_router_networks_router_id_network_id_key UNIQUE (router_id, network_id);
+
+
+--
+-- Name: core_router_permittedNetworks_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY "core_router_permittedNetworks"
+    ADD CONSTRAINT "core_router_permittedNetworks_pkey" PRIMARY KEY (id);
+
+
+--
+-- Name: core_router_permittedNetworks_router_id_network_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY "core_router_permittedNetworks"
+    ADD CONSTRAINT "core_router_permittedNetworks_router_id_network_id_key" UNIQUE (router_id, network_id);
+
+
+--
+-- Name: core_router_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_router
+    ADD CONSTRAINT core_router_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_service_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_service
+    ADD CONSTRAINT core_service_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_serviceattribute_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_serviceattribute
+    ADD CONSTRAINT core_serviceattribute_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_serviceclass_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_serviceclass
+    ADD CONSTRAINT core_serviceclass_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_serviceclass_upgradeFrom_from_serviceclass_id_to_servi_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY "core_serviceclass_upgradeFrom"
+    ADD CONSTRAINT "core_serviceclass_upgradeFrom_from_serviceclass_id_to_servi_key" UNIQUE (from_serviceclass_id, to_serviceclass_id);
+
+
+--
+-- Name: core_serviceclass_upgradeFrom_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY "core_serviceclass_upgradeFrom"
+    ADD CONSTRAINT "core_serviceclass_upgradeFrom_pkey" PRIMARY KEY (id);
+
+
+--
+-- Name: core_serviceprivilege_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_serviceprivilege
+    ADD CONSTRAINT core_serviceprivilege_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_serviceprivilege_user_id_3e7ef04b1340e86c_uniq; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_serviceprivilege
+    ADD CONSTRAINT core_serviceprivilege_user_id_3e7ef04b1340e86c_uniq UNIQUE (user_id, service_id, role_id);
+
+
+--
+-- Name: core_serviceresource_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_serviceresource
+    ADD CONSTRAINT core_serviceresource_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_servicerole_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_servicerole
+    ADD CONSTRAINT core_servicerole_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_servicerole_role_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_servicerole
+    ADD CONSTRAINT core_servicerole_role_key UNIQUE (role);
+
+
+--
+-- Name: core_site_login_base_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_site
+    ADD CONSTRAINT core_site_login_base_key UNIQUE (login_base);
+
+
+--
+-- Name: core_site_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_site
+    ADD CONSTRAINT core_site_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_sitecredential_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_sitecredential
+    ADD CONSTRAINT core_sitecredential_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_sitedeployment_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_sitedeployment
+    ADD CONSTRAINT core_sitedeployment_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_sitedeployment_site_id_ed533b8a1954fbb_uniq; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_sitedeployment
+    ADD CONSTRAINT core_sitedeployment_site_id_ed533b8a1954fbb_uniq UNIQUE (site_id, deployment_id, controller_id);
+
+
+--
+-- Name: core_siteprivilege_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_siteprivilege
+    ADD CONSTRAINT core_siteprivilege_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_siterole_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_siterole
+    ADD CONSTRAINT core_siterole_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_siterole_role_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_siterole
+    ADD CONSTRAINT core_siterole_role_key UNIQUE (role);
+
+
+--
+-- Name: core_slice_name_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_slice
+    ADD CONSTRAINT core_slice_name_key UNIQUE (name);
+
+
+--
+-- Name: core_slice_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_slice
+    ADD CONSTRAINT core_slice_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_slicecredential_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_slicecredential
+    ADD CONSTRAINT core_slicecredential_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_sliceprivilege_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_sliceprivilege
+    ADD CONSTRAINT core_sliceprivilege_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_sliceprivilege_user_id_6bed734e37df8596_uniq; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_sliceprivilege
+    ADD CONSTRAINT core_sliceprivilege_user_id_6bed734e37df8596_uniq UNIQUE (user_id, slice_id, role_id);
+
+
+--
+-- Name: core_slicerole_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_slicerole
+    ADD CONSTRAINT core_slicerole_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_slicerole_role_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_slicerole
+    ADD CONSTRAINT core_slicerole_role_key UNIQUE (role);
+
+
+--
+-- Name: core_slicetag_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_slicetag
+    ADD CONSTRAINT core_slicetag_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_tag_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_tag
+    ADD CONSTRAINT core_tag_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_tenant_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_tenant
+    ADD CONSTRAINT core_tenant_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_tenantroot_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_tenantroot
+    ADD CONSTRAINT core_tenantroot_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_tenantrootprivilege_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_tenantrootprivilege
+    ADD CONSTRAINT core_tenantrootprivilege_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_tenantrootprivilege_user_id_2bfebdce70c89f50_uniq; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_tenantrootprivilege
+    ADD CONSTRAINT core_tenantrootprivilege_user_id_2bfebdce70c89f50_uniq UNIQUE (user_id, tenant_root_id, role_id);
+
+
+--
+-- Name: core_tenantrootrole_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_tenantrootrole
+    ADD CONSTRAINT core_tenantrootrole_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_tenantrootrole_role_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_tenantrootrole
+    ADD CONSTRAINT core_tenantrootrole_role_key UNIQUE (role);
+
+
+--
+-- Name: core_usableobject_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_usableobject
+    ADD CONSTRAINT core_usableobject_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_user_email_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_user
+    ADD CONSTRAINT core_user_email_key UNIQUE (email);
+
+
+--
+-- Name: core_user_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_user
+    ADD CONSTRAINT core_user_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_usercredential_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_usercredential
+    ADD CONSTRAINT core_usercredential_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: core_userdashboardview_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY core_userdashboardview
+    ADD CONSTRAINT core_userdashboardview_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: django_admin_log_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY django_admin_log
+    ADD CONSTRAINT django_admin_log_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: django_content_type_app_label_45f3b1d93ec8c61c_uniq; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY django_content_type
+    ADD CONSTRAINT django_content_type_app_label_45f3b1d93ec8c61c_uniq UNIQUE (app_label, model);
+
+
+--
+-- Name: django_content_type_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY django_content_type
+    ADD CONSTRAINT django_content_type_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: django_migrations_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY django_migrations
+    ADD CONSTRAINT django_migrations_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: django_session_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY django_session
+    ADD CONSTRAINT django_session_pkey PRIMARY KEY (session_key);
+
+
+--
+-- Name: hpc_accessmap_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY hpc_accessmap
+    ADD CONSTRAINT hpc_accessmap_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: hpc_cdnprefix_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY hpc_cdnprefix
+    ADD CONSTRAINT hpc_cdnprefix_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: hpc_contentprovider_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY hpc_contentprovider
+    ADD CONSTRAINT hpc_contentprovider_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: hpc_contentprovider_users_contentprovider_id_user_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY hpc_contentprovider_users
+    ADD CONSTRAINT hpc_contentprovider_users_contentprovider_id_user_id_key UNIQUE (contentprovider_id, user_id);
+
+
+--
+-- Name: hpc_contentprovider_users_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY hpc_contentprovider_users
+    ADD CONSTRAINT hpc_contentprovider_users_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: hpc_hpchealthcheck_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY hpc_hpchealthcheck
+    ADD CONSTRAINT hpc_hpchealthcheck_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: hpc_hpcservice_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY hpc_hpcservice
+    ADD CONSTRAINT hpc_hpcservice_pkey PRIMARY KEY (service_ptr_id);
+
+
+--
+-- Name: hpc_originserver_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY hpc_originserver
+    ADD CONSTRAINT hpc_originserver_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: hpc_serviceprovider_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY hpc_serviceprovider
+    ADD CONSTRAINT hpc_serviceprovider_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: hpc_sitemap_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY hpc_sitemap
+    ADD CONSTRAINT hpc_sitemap_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: requestrouter_requestrouterservice_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY requestrouter_requestrouterservice
+    ADD CONSTRAINT requestrouter_requestrouterservice_pkey PRIMARY KEY (service_ptr_id);
+
+
+--
+-- Name: requestrouter_servicemap_name_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY requestrouter_servicemap
+    ADD CONSTRAINT requestrouter_servicemap_name_key UNIQUE (name);
+
+
+--
+-- Name: requestrouter_servicemap_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY requestrouter_servicemap
+    ADD CONSTRAINT requestrouter_servicemap_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: syndicate_storage_slicesecret_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY syndicate_storage_slicesecret
+    ADD CONSTRAINT syndicate_storage_slicesecret_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: syndicate_storage_syndicateprincipal_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY syndicate_storage_syndicateprincipal
+    ADD CONSTRAINT syndicate_storage_syndicateprincipal_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: syndicate_storage_syndicateprincipal_principal_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY syndicate_storage_syndicateprincipal
+    ADD CONSTRAINT syndicate_storage_syndicateprincipal_principal_id_key UNIQUE (principal_id);
+
+
+--
+-- Name: syndicate_storage_syndicateservice_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY syndicate_storage_syndicateservice
+    ADD CONSTRAINT syndicate_storage_syndicateservice_pkey PRIMARY KEY (service_ptr_id);
+
+
+--
+-- Name: syndicate_storage_volume_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY syndicate_storage_volume
+    ADD CONSTRAINT syndicate_storage_volume_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: syndicate_storage_volumeaccessright_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY syndicate_storage_volumeaccessright
+    ADD CONSTRAINT syndicate_storage_volumeaccessright_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: syndicate_storage_volumeslice_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: 
+--
+
+ALTER TABLE ONLY syndicate_storage_volumeslice
+    ADD CONSTRAINT syndicate_storage_volumeslice_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: auth_group_permissions_0e939a4f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX auth_group_permissions_0e939a4f ON auth_group_permissions USING btree (group_id);
+
+
+--
+-- Name: auth_group_permissions_8373b171; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX auth_group_permissions_8373b171 ON auth_group_permissions USING btree (permission_id);
+
+
+--
+-- Name: auth_permission_417f1b1c; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX auth_permission_417f1b1c ON auth_permission USING btree (content_type_id);
+
+
+--
+-- Name: core_account_9365d6e7; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_account_9365d6e7 ON core_account USING btree (site_id);
+
+
+--
+-- Name: core_charge_8a089c2a; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_charge_8a089c2a ON core_charge USING btree (account_id);
+
+
+--
+-- Name: core_charge_af31437c; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_charge_af31437c ON core_charge USING btree (object_id);
+
+
+--
+-- Name: core_charge_be7f3a0f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_charge_be7f3a0f ON core_charge USING btree (slice_id);
+
+
+--
+-- Name: core_charge_f1f5d967; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_charge_f1f5d967 ON core_charge USING btree (invoice_id);
+
+
+--
+-- Name: core_controller_5921cd4f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controller_5921cd4f ON core_controller USING btree (deployment_id);
+
+
+--
+-- Name: core_controllercredential_a31c1112; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controllercredential_a31c1112 ON core_controllercredential USING btree (controller_id);
+
+
+--
+-- Name: core_controllercredential_b068931c; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controllercredential_b068931c ON core_controllercredential USING btree (name);
+
+
+--
+-- Name: core_controllerdashboardview_5da0369f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controllerdashboardview_5da0369f ON core_controllerdashboardview USING btree ("dashboardView_id");
+
+
+--
+-- Name: core_controllerdashboardview_a31c1112; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controllerdashboardview_a31c1112 ON core_controllerdashboardview USING btree (controller_id);
+
+
+--
+-- Name: core_controllerimages_a31c1112; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controllerimages_a31c1112 ON core_controllerimages USING btree (controller_id);
+
+
+--
+-- Name: core_controllerimages_f33175e6; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controllerimages_f33175e6 ON core_controllerimages USING btree (image_id);
+
+
+--
+-- Name: core_controllernetwork_4e19114d; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controllernetwork_4e19114d ON core_controllernetwork USING btree (network_id);
+
+
+--
+-- Name: core_controllernetwork_a31c1112; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controllernetwork_a31c1112 ON core_controllernetwork USING btree (controller_id);
+
+
+--
+-- Name: core_controllersite_38543614; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controllersite_38543614 ON core_controllersite USING btree (tenant_id);
+
+
+--
+-- Name: core_controllersite_9365d6e7; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controllersite_9365d6e7 ON core_controllersite USING btree (site_id);
+
+
+--
+-- Name: core_controllersite_a31c1112; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controllersite_a31c1112 ON core_controllersite USING btree (controller_id);
+
+
+--
+-- Name: core_controllersiteprivilege_28116b8e; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controllersiteprivilege_28116b8e ON core_controllersiteprivilege USING btree (site_privilege_id);
+
+
+--
+-- Name: core_controllersiteprivilege_84566833; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controllersiteprivilege_84566833 ON core_controllersiteprivilege USING btree (role_id);
+
+
+--
+-- Name: core_controllersiteprivilege_a31c1112; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controllersiteprivilege_a31c1112 ON core_controllersiteprivilege USING btree (controller_id);
+
+
+--
+-- Name: core_controllerslice_a31c1112; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controllerslice_a31c1112 ON core_controllerslice USING btree (controller_id);
+
+
+--
+-- Name: core_controllerslice_be7f3a0f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controllerslice_be7f3a0f ON core_controllerslice USING btree (slice_id);
+
+
+--
+-- Name: core_controllersliceprivilege_25740d9a; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controllersliceprivilege_25740d9a ON core_controllersliceprivilege USING btree (slice_privilege_id);
+
+
+--
+-- Name: core_controllersliceprivilege_84566833; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controllersliceprivilege_84566833 ON core_controllersliceprivilege USING btree (role_id);
+
+
+--
+-- Name: core_controllersliceprivilege_a31c1112; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controllersliceprivilege_a31c1112 ON core_controllersliceprivilege USING btree (controller_id);
+
+
+--
+-- Name: core_controlleruser_a31c1112; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controlleruser_a31c1112 ON core_controlleruser USING btree (controller_id);
+
+
+--
+-- Name: core_controlleruser_e8701ad4; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_controlleruser_e8701ad4 ON core_controlleruser USING btree (user_id);
+
+
+--
+-- Name: core_dashboardview_deployments_5921cd4f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_dashboardview_deployments_5921cd4f ON core_dashboardview_deployments USING btree (deployment_id);
+
+
+--
+-- Name: core_dashboardview_deployments_79bd56c8; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_dashboardview_deployments_79bd56c8 ON core_dashboardview_deployments USING btree (dashboardview_id);
+
+
+--
+-- Name: core_deploymentprivilege_5921cd4f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_deploymentprivilege_5921cd4f ON core_deploymentprivilege USING btree (deployment_id);
+
+
+--
+-- Name: core_deploymentprivilege_84566833; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_deploymentprivilege_84566833 ON core_deploymentprivilege USING btree (role_id);
+
+
+--
+-- Name: core_deploymentprivilege_e8701ad4; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_deploymentprivilege_e8701ad4 ON core_deploymentprivilege USING btree (user_id);
+
+
+--
+-- Name: core_flavor_deployments_5921cd4f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_flavor_deployments_5921cd4f ON core_flavor_deployments USING btree (deployment_id);
+
+
+--
+-- Name: core_flavor_deployments_dd3f198d; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_flavor_deployments_dd3f198d ON core_flavor_deployments USING btree (flavor_id);
+
+
+--
+-- Name: core_imagedeployments_5921cd4f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_imagedeployments_5921cd4f ON core_imagedeployments USING btree (deployment_id);
+
+
+--
+-- Name: core_imagedeployments_f33175e6; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_imagedeployments_f33175e6 ON core_imagedeployments USING btree (image_id);
+
+
+--
+-- Name: core_instance_3700153c; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_instance_3700153c ON core_instance USING btree (creator_id);
+
+
+--
+-- Name: core_instance_5921cd4f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_instance_5921cd4f ON core_instance USING btree (deployment_id);
+
+
+--
+-- Name: core_instance_be7f3a0f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_instance_be7f3a0f ON core_instance USING btree (slice_id);
+
+
+--
+-- Name: core_instance_c693ebc8; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_instance_c693ebc8 ON core_instance USING btree (node_id);
+
+
+--
+-- Name: core_instance_dd3f198d; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_instance_dd3f198d ON core_instance USING btree (flavor_id);
+
+
+--
+-- Name: core_instance_f33175e6; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_instance_f33175e6 ON core_instance USING btree (image_id);
+
+
+--
+-- Name: core_invoice_8a089c2a; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_invoice_8a089c2a ON core_invoice USING btree (account_id);
+
+
+--
+-- Name: core_network_5e7b1936; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_network_5e7b1936 ON core_network USING btree (owner_id);
+
+
+--
+-- Name: core_network_74f53564; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_network_74f53564 ON core_network USING btree (template_id);
+
+
+--
+-- Name: core_network_permitted_slices_4e19114d; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_network_permitted_slices_4e19114d ON core_network_permitted_slices USING btree (network_id);
+
+
+--
+-- Name: core_network_permitted_slices_be7f3a0f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_network_permitted_slices_be7f3a0f ON core_network_permitted_slices USING btree (slice_id);
+
+
+--
+-- Name: core_networkparameter_417f1b1c; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_networkparameter_417f1b1c ON core_networkparameter USING btree (content_type_id);
+
+
+--
+-- Name: core_networkparameter_80740216; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_networkparameter_80740216 ON core_networkparameter USING btree (parameter_id);
+
+
+--
+-- Name: core_networkparametertype_b068931c; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_networkparametertype_b068931c ON core_networkparametertype USING btree (name);
+
+
+--
+-- Name: core_networkslice_4e19114d; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_networkslice_4e19114d ON core_networkslice USING btree (network_id);
+
+
+--
+-- Name: core_networkslice_be7f3a0f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_networkslice_be7f3a0f ON core_networkslice USING btree (slice_id);
+
+
+--
+-- Name: core_node_86aed61a; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_node_86aed61a ON core_node USING btree (site_deployment_id);
+
+
+--
+-- Name: core_node_9365d6e7; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_node_9365d6e7 ON core_node USING btree (site_id);
+
+
+--
+-- Name: core_payment_8a089c2a; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_payment_8a089c2a ON core_payment USING btree (account_id);
+
+
+--
+-- Name: core_port_4e19114d; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_port_4e19114d ON core_port USING btree (network_id);
+
+
+--
+-- Name: core_port_51afcc4f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_port_51afcc4f ON core_port USING btree (instance_id);
+
+
+--
+-- Name: core_program_5e7b1936; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_program_5e7b1936 ON core_program USING btree (owner_id);
+
+
+--
+-- Name: core_reservation_be7f3a0f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_reservation_be7f3a0f ON core_reservation USING btree (slice_id);
+
+
+--
+-- Name: core_reservedresource_51afcc4f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_reservedresource_51afcc4f ON core_reservedresource USING btree (instance_id);
+
+
+--
+-- Name: core_reservedresource_732beb09; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_reservedresource_732beb09 ON core_reservedresource USING btree ("reservationSet_id");
+
+
+--
+-- Name: core_reservedresource_e2f3ef5b; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_reservedresource_e2f3ef5b ON core_reservedresource USING btree (resource_id);
+
+
+--
+-- Name: core_role_417f1b1c; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_role_417f1b1c ON core_role USING btree (content_type_id);
+
+
+--
+-- Name: core_router_5e7b1936; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_router_5e7b1936 ON core_router USING btree (owner_id);
+
+
+--
+-- Name: core_router_networks_4e19114d; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_router_networks_4e19114d ON core_router_networks USING btree (network_id);
+
+
+--
+-- Name: core_router_networks_52d4f3af; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_router_networks_52d4f3af ON core_router_networks USING btree (router_id);
+
+
+--
+-- Name: core_router_permittednetworks_4e19114d; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_router_permittednetworks_4e19114d ON "core_router_permittedNetworks" USING btree (network_id);
+
+
+--
+-- Name: core_router_permittednetworks_52d4f3af; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_router_permittednetworks_52d4f3af ON "core_router_permittedNetworks" USING btree (router_id);
+
+
+--
+-- Name: core_serviceattribute_b068931c; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_serviceattribute_b068931c ON core_serviceattribute USING btree (name);
+
+
+--
+-- Name: core_serviceattribute_b0dc1e29; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_serviceattribute_b0dc1e29 ON core_serviceattribute USING btree (service_id);
+
+
+--
+-- Name: core_serviceclass_upgradefrom_a90aba97; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_serviceclass_upgradefrom_a90aba97 ON "core_serviceclass_upgradeFrom" USING btree (to_serviceclass_id);
+
+
+--
+-- Name: core_serviceclass_upgradefrom_e970e0f1; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_serviceclass_upgradefrom_e970e0f1 ON "core_serviceclass_upgradeFrom" USING btree (from_serviceclass_id);
+
+
+--
+-- Name: core_serviceprivilege_84566833; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_serviceprivilege_84566833 ON core_serviceprivilege USING btree (role_id);
+
+
+--
+-- Name: core_serviceprivilege_b0dc1e29; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_serviceprivilege_b0dc1e29 ON core_serviceprivilege USING btree (service_id);
+
+
+--
+-- Name: core_serviceprivilege_e8701ad4; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_serviceprivilege_e8701ad4 ON core_serviceprivilege USING btree (user_id);
+
+
+--
+-- Name: core_serviceresource_aa578034; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_serviceresource_aa578034 ON core_serviceresource USING btree ("serviceClass_id");
+
+
+--
+-- Name: core_sitecredential_9365d6e7; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_sitecredential_9365d6e7 ON core_sitecredential USING btree (site_id);
+
+
+--
+-- Name: core_sitecredential_b068931c; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_sitecredential_b068931c ON core_sitecredential USING btree (name);
+
+
+--
+-- Name: core_sitedeployment_5921cd4f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_sitedeployment_5921cd4f ON core_sitedeployment USING btree (deployment_id);
+
+
+--
+-- Name: core_sitedeployment_9365d6e7; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_sitedeployment_9365d6e7 ON core_sitedeployment USING btree (site_id);
+
+
+--
+-- Name: core_sitedeployment_a31c1112; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_sitedeployment_a31c1112 ON core_sitedeployment USING btree (controller_id);
+
+
+--
+-- Name: core_siteprivilege_84566833; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_siteprivilege_84566833 ON core_siteprivilege USING btree (role_id);
+
+
+--
+-- Name: core_siteprivilege_9365d6e7; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_siteprivilege_9365d6e7 ON core_siteprivilege USING btree (site_id);
+
+
+--
+-- Name: core_siteprivilege_e8701ad4; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_siteprivilege_e8701ad4 ON core_siteprivilege USING btree (user_id);
+
+
+--
+-- Name: core_slice_3700153c; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_slice_3700153c ON core_slice USING btree (creator_id);
+
+
+--
+-- Name: core_slice_531a000f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_slice_531a000f ON core_slice USING btree (default_flavor_id);
+
+
+--
+-- Name: core_slice_9365d6e7; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_slice_9365d6e7 ON core_slice USING btree (site_id);
+
+
+--
+-- Name: core_slice_a82f732f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_slice_a82f732f ON core_slice USING btree (default_image_id);
+
+
+--
+-- Name: core_slice_aa578034; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_slice_aa578034 ON core_slice USING btree ("serviceClass_id");
+
+
+--
+-- Name: core_slice_b0dc1e29; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_slice_b0dc1e29 ON core_slice USING btree (service_id);
+
+
+--
+-- Name: core_slicecredential_b068931c; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_slicecredential_b068931c ON core_slicecredential USING btree (name);
+
+
+--
+-- Name: core_slicecredential_be7f3a0f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_slicecredential_be7f3a0f ON core_slicecredential USING btree (slice_id);
+
+
+--
+-- Name: core_sliceprivilege_84566833; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_sliceprivilege_84566833 ON core_sliceprivilege USING btree (role_id);
+
+
+--
+-- Name: core_sliceprivilege_be7f3a0f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_sliceprivilege_be7f3a0f ON core_sliceprivilege USING btree (slice_id);
+
+
+--
+-- Name: core_sliceprivilege_e8701ad4; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_sliceprivilege_e8701ad4 ON core_sliceprivilege USING btree (user_id);
+
+
+--
+-- Name: core_slicetag_be7f3a0f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_slicetag_be7f3a0f ON core_slicetag USING btree (slice_id);
+
+
+--
+-- Name: core_tag_417f1b1c; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_tag_417f1b1c ON core_tag USING btree (content_type_id);
+
+
+--
+-- Name: core_tag_b068931c; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_tag_b068931c ON core_tag USING btree (name);
+
+
+--
+-- Name: core_tag_b0dc1e29; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_tag_b0dc1e29 ON core_tag USING btree (service_id);
+
+
+--
+-- Name: core_tenant_6d0512e4; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_tenant_6d0512e4 ON core_tenant USING btree (subscriber_tenant_id);
+
+
+--
+-- Name: core_tenant_a5c60fe7; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_tenant_a5c60fe7 ON core_tenant USING btree (subscriber_service_id);
+
+
+--
+-- Name: core_tenant_d1fbfb28; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_tenant_d1fbfb28 ON core_tenant USING btree (provider_service_id);
+
+
+--
+-- Name: core_tenant_ec8cbfdc; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_tenant_ec8cbfdc ON core_tenant USING btree (subscriber_user_id);
+
+
+--
+-- Name: core_tenant_f687e49c; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_tenant_f687e49c ON core_tenant USING btree (subscriber_root_id);
+
+
+--
+-- Name: core_tenantrootprivilege_84566833; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_tenantrootprivilege_84566833 ON core_tenantrootprivilege USING btree (role_id);
+
+
+--
+-- Name: core_tenantrootprivilege_ad876f96; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_tenantrootprivilege_ad876f96 ON core_tenantrootprivilege USING btree (tenant_root_id);
+
+
+--
+-- Name: core_tenantrootprivilege_e8701ad4; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_tenantrootprivilege_e8701ad4 ON core_tenantrootprivilege USING btree (user_id);
+
+
+--
+-- Name: core_user_9365d6e7; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_user_9365d6e7 ON core_user USING btree (site_id);
+
+
+--
+-- Name: core_usercredential_b068931c; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_usercredential_b068931c ON core_usercredential USING btree (name);
+
+
+--
+-- Name: core_usercredential_e8701ad4; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_usercredential_e8701ad4 ON core_usercredential USING btree (user_id);
+
+
+--
+-- Name: core_userdashboardview_5da0369f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_userdashboardview_5da0369f ON core_userdashboardview USING btree ("dashboardView_id");
+
+
+--
+-- Name: core_userdashboardview_e8701ad4; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX core_userdashboardview_e8701ad4 ON core_userdashboardview USING btree (user_id);
+
+
+--
+-- Name: django_admin_log_417f1b1c; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX django_admin_log_417f1b1c ON django_admin_log USING btree (content_type_id);
+
+
+--
+-- Name: django_admin_log_e8701ad4; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX django_admin_log_e8701ad4 ON django_admin_log USING btree (user_id);
+
+
+--
+-- Name: django_session_de54fa62; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX django_session_de54fa62 ON django_session USING btree (expire_date);
+
+
+--
+-- Name: hpc_accessmap_bc4912a0; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX hpc_accessmap_bc4912a0 ON hpc_accessmap USING btree ("contentProvider_id");
+
+
+--
+-- Name: hpc_cdnprefix_8473b38b; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX hpc_cdnprefix_8473b38b ON hpc_cdnprefix USING btree ("defaultOriginServer_id");
+
+
+--
+-- Name: hpc_cdnprefix_bc4912a0; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX hpc_cdnprefix_bc4912a0 ON hpc_cdnprefix USING btree ("contentProvider_id");
+
+
+--
+-- Name: hpc_contentprovider_ebdbc659; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX hpc_contentprovider_ebdbc659 ON hpc_contentprovider USING btree ("serviceProvider_id");
+
+
+--
+-- Name: hpc_contentprovider_users_82c06917; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX hpc_contentprovider_users_82c06917 ON hpc_contentprovider_users USING btree (contentprovider_id);
+
+
+--
+-- Name: hpc_contentprovider_users_e8701ad4; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX hpc_contentprovider_users_e8701ad4 ON hpc_contentprovider_users USING btree (user_id);
+
+
+--
+-- Name: hpc_hpchealthcheck_591847bf; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX hpc_hpchealthcheck_591847bf ON hpc_hpchealthcheck USING btree ("hpcService_id");
+
+
+--
+-- Name: hpc_originserver_bc4912a0; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX hpc_originserver_bc4912a0 ON hpc_originserver USING btree ("contentProvider_id");
+
+
+--
+-- Name: hpc_serviceprovider_591847bf; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX hpc_serviceprovider_591847bf ON hpc_serviceprovider USING btree ("hpcService_id");
+
+
+--
+-- Name: hpc_sitemap_23b3ec8f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX hpc_sitemap_23b3ec8f ON hpc_sitemap USING btree ("cdnPrefix_id");
+
+
+--
+-- Name: hpc_sitemap_591847bf; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX hpc_sitemap_591847bf ON hpc_sitemap USING btree ("hpcService_id");
+
+
+--
+-- Name: hpc_sitemap_bc4912a0; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX hpc_sitemap_bc4912a0 ON hpc_sitemap USING btree ("contentProvider_id");
+
+
+--
+-- Name: hpc_sitemap_ebdbc659; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX hpc_sitemap_ebdbc659 ON hpc_sitemap USING btree ("serviceProvider_id");
+
+
+--
+-- Name: requestrouter_servicemap_5e7b1936; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX requestrouter_servicemap_5e7b1936 ON requestrouter_servicemap USING btree (owner_id);
+
+
+--
+-- Name: requestrouter_servicemap_be7f3a0f; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX requestrouter_servicemap_be7f3a0f ON requestrouter_servicemap USING btree (slice_id);
+
+
+--
+-- Name: syndicate_storage_slicesecret_b717f5ab; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX syndicate_storage_slicesecret_b717f5ab ON syndicate_storage_slicesecret USING btree (slice_id_id);
+
+
+--
+-- Name: syndicate_storage_volume_279564bf; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX syndicate_storage_volume_279564bf ON syndicate_storage_volume USING btree (owner_id_id);
+
+
+--
+-- Name: syndicate_storage_volumeaccessright_279564bf; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX syndicate_storage_volumeaccessright_279564bf ON syndicate_storage_volumeaccessright USING btree (owner_id_id);
+
+
+--
+-- Name: syndicate_storage_volumeaccessright_654102bb; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX syndicate_storage_volumeaccessright_654102bb ON syndicate_storage_volumeaccessright USING btree (volume_id);
+
+
+--
+-- Name: syndicate_storage_volumeslice_5b591651; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX syndicate_storage_volumeslice_5b591651 ON syndicate_storage_volumeslice USING btree (volume_id_id);
+
+
+--
+-- Name: syndicate_storage_volumeslice_b717f5ab; Type: INDEX; Schema: public; Owner: postgres; Tablespace: 
+--
+
+CREATE INDEX syndicate_storage_volumeslice_b717f5ab ON syndicate_storage_volumeslice USING btree (slice_id_id);
+
+
+--
+-- Name: auth_content_type_id_508cf46651277a81_fk_django_content_type_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY auth_permission
+    ADD CONSTRAINT auth_content_type_id_508cf46651277a81_fk_django_content_type_id FOREIGN KEY (content_type_id) REFERENCES django_content_type(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: auth_group_permissio_group_id_689710a9a73b7457_fk_auth_group_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY auth_group_permissions
+    ADD CONSTRAINT auth_group_permissio_group_id_689710a9a73b7457_fk_auth_group_id FOREIGN KEY (group_id) REFERENCES auth_group(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: auth_group_permission_id_1f49ccbbdc69d2fc_fk_auth_permission_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY auth_group_permissions
+    ADD CONSTRAINT auth_group_permission_id_1f49ccbbdc69d2fc_fk_auth_permission_id FOREIGN KEY (permission_id) REFERENCES auth_permission(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: b8a90faf34a5dd47a7f1e2f88e99f8a2; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_hpchealthcheck
+    ADD CONSTRAINT b8a90faf34a5dd47a7f1e2f88e99f8a2 FOREIGN KEY ("hpcService_id") REFERENCES hpc_hpcservice(service_ptr_id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: c_from_serviceclass_id_188a83eaefe26390_fk_core_serviceclass_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY "core_serviceclass_upgradeFrom"
+    ADD CONSTRAINT c_from_serviceclass_id_188a83eaefe26390_fk_core_serviceclass_id FOREIGN KEY (from_serviceclass_id) REFERENCES core_serviceclass(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: c_parameter_id_2c17791ba32bd8c8_fk_core_networkparametertype_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_networkparameter
+    ADD CONSTRAINT c_parameter_id_2c17791ba32bd8c8_fk_core_networkparametertype_id FOREIGN KEY (parameter_id) REFERENCES core_networkparametertype(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: c_site_deployment_id_2dc763428bdc2781_fk_core_sitedeployment_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_node
+    ADD CONSTRAINT c_site_deployment_id_2dc763428bdc2781_fk_core_sitedeployment_id FOREIGN KEY (site_deployment_id) REFERENCES core_sitedeployment(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: co_slice_privilege_id_21402f4f2399079_fk_core_sliceprivilege_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllersliceprivilege
+    ADD CONSTRAINT co_slice_privilege_id_21402f4f2399079_fk_core_sliceprivilege_id FOREIGN KEY (slice_privilege_id) REFERENCES core_sliceprivilege(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: cor_site_privilege_id_41490e8c05c2e685_fk_core_siteprivilege_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllersiteprivilege
+    ADD CONSTRAINT cor_site_privilege_id_41490e8c05c2e685_fk_core_siteprivilege_id FOREIGN KEY (site_privilege_id) REFERENCES core_siteprivilege(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: cor_to_serviceclass_id_4e2748248647c43b_fk_core_serviceclass_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY "core_serviceclass_upgradeFrom"
+    ADD CONSTRAINT cor_to_serviceclass_id_4e2748248647c43b_fk_core_serviceclass_id FOREIGN KEY (to_serviceclass_id) REFERENCES core_serviceclass(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core__reservationset_id_395058233c59a671_fk_core_reservation_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_reservedresource
+    ADD CONSTRAINT core__reservationset_id_395058233c59a671_fk_core_reservation_id FOREIGN KEY ("reservationSet_id") REFERENCES core_reservation(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core__subscriber_root_id_26f21610cb2711f9_fk_core_tenantroot_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_tenant
+    ADD CONSTRAINT core__subscriber_root_id_26f21610cb2711f9_fk_core_tenantroot_id FOREIGN KEY (subscriber_root_id) REFERENCES core_tenantroot(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core__subscriber_service_id_5049d522dc2feae7_fk_core_service_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_tenant
+    ADD CONSTRAINT core__subscriber_service_id_5049d522dc2feae7_fk_core_service_id FOREIGN KEY (subscriber_service_id) REFERENCES core_service(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_account_site_id_7d8af010f408acb2_fk_core_site_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_account
+    ADD CONSTRAINT core_account_site_id_7d8af010f408acb2_fk_core_site_id FOREIGN KEY (site_id) REFERENCES core_site(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_charge_account_id_277c66c32427fb_fk_core_account_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_charge
+    ADD CONSTRAINT core_charge_account_id_277c66c32427fb_fk_core_account_id FOREIGN KEY (account_id) REFERENCES core_account(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_charge_invoice_id_7af39adf58aad977_fk_core_invoice_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_charge
+    ADD CONSTRAINT core_charge_invoice_id_7af39adf58aad977_fk_core_invoice_id FOREIGN KEY (invoice_id) REFERENCES core_invoice(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_charge_object_id_349f8834f1bf5ce6_fk_core_usableobject_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_charge
+    ADD CONSTRAINT core_charge_object_id_349f8834f1bf5ce6_fk_core_usableobject_id FOREIGN KEY (object_id) REFERENCES core_usableobject(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_charge_slice_id_5f33de3b320604f2_fk_core_slice_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_charge
+    ADD CONSTRAINT core_charge_slice_id_5f33de3b320604f2_fk_core_slice_id FOREIGN KEY (slice_id) REFERENCES core_slice(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_content_type_id_150a10ada282bcf9_fk_django_content_type_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_role
+    ADD CONSTRAINT core_content_type_id_150a10ada282bcf9_fk_django_content_type_id FOREIGN KEY (content_type_id) REFERENCES django_content_type(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_content_type_id_3cc30601489a3056_fk_django_content_type_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_networkparameter
+    ADD CONSTRAINT core_content_type_id_3cc30601489a3056_fk_django_content_type_id FOREIGN KEY (content_type_id) REFERENCES django_content_type(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_content_type_id_413c7b5400f8ad9c_fk_django_content_type_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_tag
+    ADD CONSTRAINT core_content_type_id_413c7b5400f8ad9c_fk_django_content_type_id FOREIGN KEY (content_type_id) REFERENCES django_content_type(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_contr_controller_id_11d29f7e2a4a5462_fk_core_controller_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllersiteprivilege
+    ADD CONSTRAINT core_contr_controller_id_11d29f7e2a4a5462_fk_core_controller_id FOREIGN KEY (controller_id) REFERENCES core_controller(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_contr_controller_id_1f82c3216437715f_fk_core_controller_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllerdashboardview
+    ADD CONSTRAINT core_contr_controller_id_1f82c3216437715f_fk_core_controller_id FOREIGN KEY (controller_id) REFERENCES core_controller(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_contr_controller_id_46178c1d21384e5e_fk_core_controller_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllersite
+    ADD CONSTRAINT core_contr_controller_id_46178c1d21384e5e_fk_core_controller_id FOREIGN KEY (controller_id) REFERENCES core_controller(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_contr_controller_id_4fb982de67c3b742_fk_core_controller_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllersliceprivilege
+    ADD CONSTRAINT core_contr_controller_id_4fb982de67c3b742_fk_core_controller_id FOREIGN KEY (controller_id) REFERENCES core_controller(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_contr_controller_id_5cd05d37bbdf1d96_fk_core_controller_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controlleruser
+    ADD CONSTRAINT core_contr_controller_id_5cd05d37bbdf1d96_fk_core_controller_id FOREIGN KEY (controller_id) REFERENCES core_controller(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_contr_controller_id_60b467e792b15198_fk_core_controller_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllernetwork
+    ADD CONSTRAINT core_contr_controller_id_60b467e792b15198_fk_core_controller_id FOREIGN KEY (controller_id) REFERENCES core_controller(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_contr_controller_id_7095bdbd27f73f56_fk_core_controller_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllerslice
+    ADD CONSTRAINT core_contr_controller_id_7095bdbd27f73f56_fk_core_controller_id FOREIGN KEY (controller_id) REFERENCES core_controller(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_contr_deployment_id_772a055c58b6e43a_fk_core_deployment_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controller
+    ADD CONSTRAINT core_contr_deployment_id_772a055c58b6e43a_fk_core_deployment_id FOREIGN KEY (deployment_id) REFERENCES core_deployment(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_contro_controller_id_5906172a2f34d3a_fk_core_controller_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllercredential
+    ADD CONSTRAINT core_contro_controller_id_5906172a2f34d3a_fk_core_controller_id FOREIGN KEY (controller_id) REFERENCES core_controller(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_contro_controller_id_6d1311b7cc69cd7_fk_core_controller_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllerimages
+    ADD CONSTRAINT core_contro_controller_id_6d1311b7cc69cd7_fk_core_controller_id FOREIGN KEY (controller_id) REFERENCES core_controller(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_controllerimage_image_id_5713221a6b077f6b_fk_core_image_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllerimages
+    ADD CONSTRAINT core_controllerimage_image_id_5713221a6b077f6b_fk_core_image_id FOREIGN KEY (image_id) REFERENCES core_image(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_controllern_network_id_3fe7748f6851d06f_fk_core_network_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllernetwork
+    ADD CONSTRAINT core_controllern_network_id_3fe7748f6851d06f_fk_core_network_id FOREIGN KEY (network_id) REFERENCES core_network(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_controllersite_site_id_4fa87f0734a60665_fk_core_site_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllersite
+    ADD CONSTRAINT core_controllersite_site_id_4fa87f0734a60665_fk_core_site_id FOREIGN KEY (site_id) REFERENCES core_site(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_controllerslice_slice_id_7005d287c601356b_fk_core_slice_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllerslice
+    ADD CONSTRAINT core_controllerslice_slice_id_7005d287c601356b_fk_core_slice_id FOREIGN KEY (slice_id) REFERENCES core_slice(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_controlleruser_user_id_60dc3a7220b1005b_fk_core_user_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controlleruser
+    ADD CONSTRAINT core_controlleruser_user_id_60dc3a7220b1005b_fk_core_user_id FOREIGN KEY (user_id) REFERENCES core_user(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_dashbo_deployment_id_8b902dfc7ab128b_fk_core_deployment_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_dashboardview_deployments
+    ADD CONSTRAINT core_dashbo_deployment_id_8b902dfc7ab128b_fk_core_deployment_id FOREIGN KEY (deployment_id) REFERENCES core_deployment(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_dashboardview_id_1241776e11825a15_fk_core_dashboardview_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_controllerdashboardview
+    ADD CONSTRAINT core_dashboardview_id_1241776e11825a15_fk_core_dashboardview_id FOREIGN KEY ("dashboardView_id") REFERENCES core_dashboardview(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_dashboardview_id_623d5d799346e0f8_fk_core_dashboardview_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_dashboardview_deployments
+    ADD CONSTRAINT core_dashboardview_id_623d5d799346e0f8_fk_core_dashboardview_id FOREIGN KEY (dashboardview_id) REFERENCES core_dashboardview(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_dashboardview_id_7d9723f531eefdde_fk_core_dashboardview_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_userdashboardview
+    ADD CONSTRAINT core_dashboardview_id_7d9723f531eefdde_fk_core_dashboardview_id FOREIGN KEY ("dashboardView_id") REFERENCES core_dashboardview(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_deplo_deployment_id_4606c90fff2e5ecf_fk_core_deployment_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_deploymentprivilege
+    ADD CONSTRAINT core_deplo_deployment_id_4606c90fff2e5ecf_fk_core_deployment_id FOREIGN KEY (deployment_id) REFERENCES core_deployment(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_deploym_role_id_221f61258b29e608_fk_core_deploymentrole_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_deploymentprivilege
+    ADD CONSTRAINT core_deploym_role_id_221f61258b29e608_fk_core_deploymentrole_id FOREIGN KEY (role_id) REFERENCES core_deploymentrole(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_deploymentprivile_user_id_2ac00d41376e2a8d_fk_core_user_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_deploymentprivilege
+    ADD CONSTRAINT core_deploymentprivile_user_id_2ac00d41376e2a8d_fk_core_user_id FOREIGN KEY (user_id) REFERENCES core_user(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_flavo_deployment_id_33af1c761c0497e3_fk_core_deployment_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_flavor_deployments
+    ADD CONSTRAINT core_flavo_deployment_id_33af1c761c0497e3_fk_core_deployment_id FOREIGN KEY (deployment_id) REFERENCES core_deployment(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_flavor_deploy_flavor_id_3e598722be0b3446_fk_core_flavor_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_flavor_deployments
+    ADD CONSTRAINT core_flavor_deploy_flavor_id_3e598722be0b3446_fk_core_flavor_id FOREIGN KEY (flavor_id) REFERENCES core_flavor(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_image_deployment_id_31772dfdcf4b80eb_fk_core_deployment_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_imagedeployments
+    ADD CONSTRAINT core_image_deployment_id_31772dfdcf4b80eb_fk_core_deployment_id FOREIGN KEY (deployment_id) REFERENCES core_deployment(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_imagedeployment_image_id_4a6df22c06603b40_fk_core_image_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_imagedeployments
+    ADD CONSTRAINT core_imagedeployment_image_id_4a6df22c06603b40_fk_core_image_id FOREIGN KEY (image_id) REFERENCES core_image(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_insta_deployment_id_111e2cdd025ec8ef_fk_core_deployment_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_instance
+    ADD CONSTRAINT core_insta_deployment_id_111e2cdd025ec8ef_fk_core_deployment_id FOREIGN KEY (deployment_id) REFERENCES core_deployment(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_instance_creator_id_66a7e8c819d15b29_fk_core_user_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_instance
+    ADD CONSTRAINT core_instance_creator_id_66a7e8c819d15b29_fk_core_user_id FOREIGN KEY (creator_id) REFERENCES core_user(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_instance_flavor_id_61bc3198a5673218_fk_core_flavor_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_instance
+    ADD CONSTRAINT core_instance_flavor_id_61bc3198a5673218_fk_core_flavor_id FOREIGN KEY (flavor_id) REFERENCES core_flavor(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_instance_image_id_5c8c96fe9a61802c_fk_core_image_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_instance
+    ADD CONSTRAINT core_instance_image_id_5c8c96fe9a61802c_fk_core_image_id FOREIGN KEY (image_id) REFERENCES core_image(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_instance_node_id_ae899cb7a62df9a_fk_core_node_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_instance
+    ADD CONSTRAINT core_instance_node_id_ae899cb7a62df9a_fk_core_node_id FOREIGN KEY (node_id) REFERENCES core_node(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_instance_slice_id_2ddcfe06a9e4c985_fk_core_slice_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_instance
+    ADD CONSTRAINT core_instance_slice_id_2ddcfe06a9e4c985_fk_core_slice_id FOREIGN KEY (slice_id) REFERENCES core_slice(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_invoice_account_id_7802a49ab0cec433_fk_core_account_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_invoice
+    ADD CONSTRAINT core_invoice_account_id_7802a49ab0cec433_fk_core_account_id FOREIGN KEY (account_id) REFERENCES core_account(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_ne_template_id_7268a8d58aa4008e_fk_core_networktemplate_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_network
+    ADD CONSTRAINT core_ne_template_id_7268a8d58aa4008e_fk_core_networktemplate_id FOREIGN KEY (template_id) REFERENCES core_networktemplate(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_network_owner_id_1b5a720eac1f1d6c_fk_core_slice_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_network
+    ADD CONSTRAINT core_network_owner_id_1b5a720eac1f1d6c_fk_core_slice_id FOREIGN KEY (owner_id) REFERENCES core_slice(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_network_perm_network_id_79f8a18a0197dd1_fk_core_network_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_network_permitted_slices
+    ADD CONSTRAINT core_network_perm_network_id_79f8a18a0197dd1_fk_core_network_id FOREIGN KEY (network_id) REFERENCES core_network(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_network_permitt_slice_id_7d7e6e1a0b962f45_fk_core_slice_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_network_permitted_slices
+    ADD CONSTRAINT core_network_permitt_slice_id_7d7e6e1a0b962f45_fk_core_slice_id FOREIGN KEY (slice_id) REFERENCES core_slice(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_networkslic_network_id_2823f40a154bc2e6_fk_core_network_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_networkslice
+    ADD CONSTRAINT core_networkslic_network_id_2823f40a154bc2e6_fk_core_network_id FOREIGN KEY (network_id) REFERENCES core_network(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_networkslice_slice_id_801f34a8ab285a0_fk_core_slice_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_networkslice
+    ADD CONSTRAINT core_networkslice_slice_id_801f34a8ab285a0_fk_core_slice_id FOREIGN KEY (slice_id) REFERENCES core_slice(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_node_site_id_28bac05ef1a512ce_fk_core_site_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_node
+    ADD CONSTRAINT core_node_site_id_28bac05ef1a512ce_fk_core_site_id FOREIGN KEY (site_id) REFERENCES core_site(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_payment_account_id_3cc9ae7e7b925002_fk_core_account_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_payment
+    ADD CONSTRAINT core_payment_account_id_3cc9ae7e7b925002_fk_core_account_id FOREIGN KEY (account_id) REFERENCES core_account(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_port_instance_id_5bdb1ae59ca1dc73_fk_core_instance_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_port
+    ADD CONSTRAINT core_port_instance_id_5bdb1ae59ca1dc73_fk_core_instance_id FOREIGN KEY (instance_id) REFERENCES core_instance(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_port_network_id_655a9dc4ef32f845_fk_core_network_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_port
+    ADD CONSTRAINT core_port_network_id_655a9dc4ef32f845_fk_core_network_id FOREIGN KEY (network_id) REFERENCES core_network(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_program_owner_id_491cb2182952268e_fk_core_user_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_program
+    ADD CONSTRAINT core_program_owner_id_491cb2182952268e_fk_core_user_id FOREIGN KEY (owner_id) REFERENCES core_user(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_re_resource_id_1126f44e743a899d_fk_core_serviceresource_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_reservedresource
+    ADD CONSTRAINT core_re_resource_id_1126f44e743a899d_fk_core_serviceresource_id FOREIGN KEY (resource_id) REFERENCES core_serviceresource(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_reservation_slice_id_4df07726653daed_fk_core_slice_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_reservation
+    ADD CONSTRAINT core_reservation_slice_id_4df07726653daed_fk_core_slice_id FOREIGN KEY (slice_id) REFERENCES core_slice(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_reservedr_instance_id_626caea355f5195e_fk_core_instance_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_reservedresource
+    ADD CONSTRAINT core_reservedr_instance_id_626caea355f5195e_fk_core_instance_id FOREIGN KEY (instance_id) REFERENCES core_instance(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_router_netw_network_id_12bc59c5ca78fdc0_fk_core_network_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_router_networks
+    ADD CONSTRAINT core_router_netw_network_id_12bc59c5ca78fdc0_fk_core_network_id FOREIGN KEY (network_id) REFERENCES core_network(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_router_networ_router_id_3cf4f94bd7970e88_fk_core_router_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_router_networks
+    ADD CONSTRAINT core_router_networ_router_id_3cf4f94bd7970e88_fk_core_router_id FOREIGN KEY (router_id) REFERENCES core_router(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_router_owner_id_13c4ac38c56512c6_fk_core_slice_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_router
+    ADD CONSTRAINT core_router_owner_id_13c4ac38c56512c6_fk_core_slice_id FOREIGN KEY (owner_id) REFERENCES core_slice(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_router_permi_network_id_8ee54284c93cd43_fk_core_network_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY "core_router_permittedNetworks"
+    ADD CONSTRAINT core_router_permi_network_id_8ee54284c93cd43_fk_core_network_id FOREIGN KEY (network_id) REFERENCES core_network(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_router_permit_router_id_3506769cdaf40bb5_fk_core_router_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY "core_router_permittedNetworks"
+    ADD CONSTRAINT core_router_permit_router_id_3506769cdaf40bb5_fk_core_router_id FOREIGN KEY (router_id) REFERENCES core_router(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_s_serviceclass_id_7fa5b55190a88c84_fk_core_serviceclass_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_serviceresource
+    ADD CONSTRAINT core_s_serviceclass_id_7fa5b55190a88c84_fk_core_serviceclass_id FOREIGN KEY ("serviceClass_id") REFERENCES core_serviceclass(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_serviceattr_service_id_5dd88bdc4a289e9e_fk_core_service_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_serviceattribute
+    ADD CONSTRAINT core_serviceattr_service_id_5dd88bdc4a289e9e_fk_core_service_id FOREIGN KEY (service_id) REFERENCES core_service(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_servicepri_role_id_2516e31051d592b9_fk_core_servicerole_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_serviceprivilege
+    ADD CONSTRAINT core_servicepri_role_id_2516e31051d592b9_fk_core_servicerole_id FOREIGN KEY (role_id) REFERENCES core_servicerole(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_servicepriv_service_id_326f2584a82884fb_fk_core_service_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_serviceprivilege
+    ADD CONSTRAINT core_servicepriv_service_id_326f2584a82884fb_fk_core_service_id FOREIGN KEY (service_id) REFERENCES core_service(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_serviceprivilege_user_id_5e78485b5063e04_fk_core_user_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_serviceprivilege
+    ADD CONSTRAINT core_serviceprivilege_user_id_5e78485b5063e04_fk_core_user_id FOREIGN KEY (user_id) REFERENCES core_user(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_sitecredential_site_id_2ede808de256b5ca_fk_core_site_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_sitecredential
+    ADD CONSTRAINT core_sitecredential_site_id_2ede808de256b5ca_fk_core_site_id FOREIGN KEY (site_id) REFERENCES core_site(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_sited_controller_id_30291acda546cff3_fk_core_controller_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_sitedeployment
+    ADD CONSTRAINT core_sited_controller_id_30291acda546cff3_fk_core_controller_id FOREIGN KEY (controller_id) REFERENCES core_controller(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_sited_deployment_id_2073c8bc2ac33aee_fk_core_deployment_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_sitedeployment
+    ADD CONSTRAINT core_sited_deployment_id_2073c8bc2ac33aee_fk_core_deployment_id FOREIGN KEY (deployment_id) REFERENCES core_deployment(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_sitedeployment_site_id_10d760d1d81e2090_fk_core_site_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_sitedeployment
+    ADD CONSTRAINT core_sitedeployment_site_id_10d760d1d81e2090_fk_core_site_id FOREIGN KEY (site_id) REFERENCES core_site(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_siteprivilege_role_id_71e5069ae809cb06_fk_core_siterole_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_siteprivilege
+    ADD CONSTRAINT core_siteprivilege_role_id_71e5069ae809cb06_fk_core_siterole_id FOREIGN KEY (role_id) REFERENCES core_siterole(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_siteprivilege_site_id_33ec92307c1cb3bd_fk_core_site_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_siteprivilege
+    ADD CONSTRAINT core_siteprivilege_site_id_33ec92307c1cb3bd_fk_core_site_id FOREIGN KEY (site_id) REFERENCES core_site(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_siteprivilege_user_id_4a58c40e58eea8c5_fk_core_user_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_siteprivilege
+    ADD CONSTRAINT core_siteprivilege_user_id_4a58c40e58eea8c5_fk_core_user_id FOREIGN KEY (user_id) REFERENCES core_user(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_sl_serviceclass_id_77da7f94b58488b_fk_core_serviceclass_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_slice
+    ADD CONSTRAINT core_sl_serviceclass_id_77da7f94b58488b_fk_core_serviceclass_id FOREIGN KEY ("serviceClass_id") REFERENCES core_serviceclass(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_slice_creator_id_7c5fa82797e0d281_fk_core_user_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_slice
+    ADD CONSTRAINT core_slice_creator_id_7c5fa82797e0d281_fk_core_user_id FOREIGN KEY (creator_id) REFERENCES core_user(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_slice_default_flavor_id_7e9b60d7e92ce276_fk_core_flavor_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_slice
+    ADD CONSTRAINT core_slice_default_flavor_id_7e9b60d7e92ce276_fk_core_flavor_id FOREIGN KEY (default_flavor_id) REFERENCES core_flavor(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_slice_default_image_id_4cc5967fffec96da_fk_core_image_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_slice
+    ADD CONSTRAINT core_slice_default_image_id_4cc5967fffec96da_fk_core_image_id FOREIGN KEY (default_image_id) REFERENCES core_image(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_slice_service_id_56ec7a0b3401bf7c_fk_core_service_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_slice
+    ADD CONSTRAINT core_slice_service_id_56ec7a0b3401bf7c_fk_core_service_id FOREIGN KEY (service_id) REFERENCES core_service(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_slice_site_id_13fe089488dd45_fk_core_site_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_slice
+    ADD CONSTRAINT core_slice_site_id_13fe089488dd45_fk_core_site_id FOREIGN KEY (site_id) REFERENCES core_site(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_slicecredential_slice_id_1c79ffce7dd61f3c_fk_core_slice_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_slicecredential
+    ADD CONSTRAINT core_slicecredential_slice_id_1c79ffce7dd61f3c_fk_core_slice_id FOREIGN KEY (slice_id) REFERENCES core_slice(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_sliceprivile_role_id_1d55e0b0ac43107a_fk_core_slicerole_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_sliceprivilege
+    ADD CONSTRAINT core_sliceprivile_role_id_1d55e0b0ac43107a_fk_core_slicerole_id FOREIGN KEY (role_id) REFERENCES core_slicerole(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_sliceprivilege_slice_id_3fbaadbffeb24835_fk_core_slice_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_sliceprivilege
+    ADD CONSTRAINT core_sliceprivilege_slice_id_3fbaadbffeb24835_fk_core_slice_id FOREIGN KEY (slice_id) REFERENCES core_slice(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_sliceprivilege_user_id_253eeb2ddef0e745_fk_core_user_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_sliceprivilege
+    ADD CONSTRAINT core_sliceprivilege_user_id_253eeb2ddef0e745_fk_core_user_id FOREIGN KEY (user_id) REFERENCES core_user(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_slicetag_slice_id_75dfa2524457256_fk_core_slice_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_slicetag
+    ADD CONSTRAINT core_slicetag_slice_id_75dfa2524457256_fk_core_slice_id FOREIGN KEY (slice_id) REFERENCES core_slice(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_tag_service_id_5e53fc9f784e1c0_fk_core_service_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_tag
+    ADD CONSTRAINT core_tag_service_id_5e53fc9f784e1c0_fk_core_service_id FOREIGN KEY (service_id) REFERENCES core_service(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_te_provider_service_id_6f2ead723387396a_fk_core_service_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_tenant
+    ADD CONSTRAINT core_te_provider_service_id_6f2ead723387396a_fk_core_service_id FOREIGN KEY (provider_service_id) REFERENCES core_service(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_te_subscriber_tenant_id_5c45dc20d190aa0f_fk_core_tenant_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_tenant
+    ADD CONSTRAINT core_te_subscriber_tenant_id_5c45dc20d190aa0f_fk_core_tenant_id FOREIGN KEY (subscriber_tenant_id) REFERENCES core_tenant(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_tena_tenant_root_id_27d6362f903728d9_fk_core_tenantroot_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_tenantrootprivilege
+    ADD CONSTRAINT core_tena_tenant_root_id_27d6362f903728d9_fk_core_tenantroot_id FOREIGN KEY (tenant_root_id) REFERENCES core_tenantroot(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_tenant_subscriber_user_id_2fad15bb074ed3d6_fk_core_user_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_tenant
+    ADD CONSTRAINT core_tenant_subscriber_user_id_2fad15bb074ed3d6_fk_core_user_id FOREIGN KEY (subscriber_user_id) REFERENCES core_user(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_tenantro_role_id_56bfa65de5fb299_fk_core_tenantrootrole_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_tenantrootprivilege
+    ADD CONSTRAINT core_tenantro_role_id_56bfa65de5fb299_fk_core_tenantrootrole_id FOREIGN KEY (role_id) REFERENCES core_tenantrootrole(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_tenantrootprivile_user_id_77f85e71ff279b56_fk_core_user_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_tenantrootprivilege
+    ADD CONSTRAINT core_tenantrootprivile_user_id_77f85e71ff279b56_fk_core_user_id FOREIGN KEY (user_id) REFERENCES core_user(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_user_site_id_3cc7d076f7b58a7_fk_core_site_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_user
+    ADD CONSTRAINT core_user_site_id_3cc7d076f7b58a7_fk_core_site_id FOREIGN KEY (site_id) REFERENCES core_site(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_usercredential_user_id_2db1046eae94c01a_fk_core_user_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_usercredential
+    ADD CONSTRAINT core_usercredential_user_id_2db1046eae94c01a_fk_core_user_id FOREIGN KEY (user_id) REFERENCES core_user(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: core_userdashboardview_user_id_66fac29b72c1b321_fk_core_user_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY core_userdashboardview
+    ADD CONSTRAINT core_userdashboardview_user_id_66fac29b72c1b321_fk_core_user_id FOREIGN KEY (user_id) REFERENCES core_user(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: d9aeae61481f9ccd18f57c7b51a38461; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_sitemap
+    ADD CONSTRAINT d9aeae61481f9ccd18f57c7b51a38461 FOREIGN KEY ("hpcService_id") REFERENCES hpc_hpcservice(service_ptr_id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: defaultoriginserver_id_3cb657d79e69f1e9_fk_hpc_originserver_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_cdnprefix
+    ADD CONSTRAINT defaultoriginserver_id_3cb657d79e69f1e9_fk_hpc_originserver_id FOREIGN KEY ("defaultOriginServer_id") REFERENCES hpc_originserver(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: djan_content_type_id_697914295151027a_fk_django_content_type_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY django_admin_log
+    ADD CONSTRAINT djan_content_type_id_697914295151027a_fk_django_content_type_id FOREIGN KEY (content_type_id) REFERENCES django_content_type(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: django_admin_log_user_id_52fdd58701c5f563_fk_core_user_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY django_admin_log
+    ADD CONSTRAINT django_admin_log_user_id_52fdd58701c5f563_fk_core_user_id FOREIGN KEY (user_id) REFERENCES core_user(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: ea3ce8ae9fc3a320680647cef82b1a56; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_serviceprovider
+    ADD CONSTRAINT ea3ce8ae9fc3a320680647cef82b1a56 FOREIGN KEY ("hpcService_id") REFERENCES hpc_hpcservice(service_ptr_id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: h_contentprovider_id_1420a46480bb1aff_fk_hpc_contentprovider_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_contentprovider_users
+    ADD CONSTRAINT h_contentprovider_id_1420a46480bb1aff_fk_hpc_contentprovider_id FOREIGN KEY (contentprovider_id) REFERENCES hpc_contentprovider(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: h_contentprovider_id_2f27d5fdbb2459c8_fk_hpc_contentprovider_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_originserver
+    ADD CONSTRAINT h_contentprovider_id_2f27d5fdbb2459c8_fk_hpc_contentprovider_id FOREIGN KEY ("contentProvider_id") REFERENCES hpc_contentprovider(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: h_contentprovider_id_63639a8e6ca8e2cd_fk_hpc_contentprovider_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_cdnprefix
+    ADD CONSTRAINT h_contentprovider_id_63639a8e6ca8e2cd_fk_hpc_contentprovider_id FOREIGN KEY ("contentProvider_id") REFERENCES hpc_contentprovider(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: h_contentprovider_id_7acf72f284b3b30e_fk_hpc_contentprovider_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_accessmap
+    ADD CONSTRAINT h_contentprovider_id_7acf72f284b3b30e_fk_hpc_contentprovider_id FOREIGN KEY ("contentProvider_id") REFERENCES hpc_contentprovider(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: h_serviceprovider_id_1b9fb41a73ac1b6a_fk_hpc_serviceprovider_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_contentprovider
+    ADD CONSTRAINT h_serviceprovider_id_1b9fb41a73ac1b6a_fk_hpc_serviceprovider_id FOREIGN KEY ("serviceProvider_id") REFERENCES hpc_serviceprovider(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: h_serviceprovider_id_788bfbe86c90f205_fk_hpc_serviceprovider_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_sitemap
+    ADD CONSTRAINT h_serviceprovider_id_788bfbe86c90f205_fk_hpc_serviceprovider_id FOREIGN KEY ("serviceProvider_id") REFERENCES hpc_serviceprovider(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: hp_contentprovider_id_2a37a8e8bee9c03_fk_hpc_contentprovider_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_sitemap
+    ADD CONSTRAINT hp_contentprovider_id_2a37a8e8bee9c03_fk_hpc_contentprovider_id FOREIGN KEY ("contentProvider_id") REFERENCES hpc_contentprovider(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: hpc_contentprovider_us_user_id_480a7cd783fecf37_fk_core_user_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_contentprovider_users
+    ADD CONSTRAINT hpc_contentprovider_us_user_id_480a7cd783fecf37_fk_core_user_id FOREIGN KEY (user_id) REFERENCES core_user(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: hpc_hpcservi_service_ptr_id_1b2f328c77b1554d_fk_core_service_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_hpcservice
+    ADD CONSTRAINT hpc_hpcservi_service_ptr_id_1b2f328c77b1554d_fk_core_service_id FOREIGN KEY (service_ptr_id) REFERENCES core_service(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: hpc_sitemap_cdnprefix_id_3c0b2f75c5a9a81e_fk_hpc_cdnprefix_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY hpc_sitemap
+    ADD CONSTRAINT hpc_sitemap_cdnprefix_id_3c0b2f75c5a9a81e_fk_hpc_cdnprefix_id FOREIGN KEY ("cdnPrefix_id") REFERENCES hpc_cdnprefix(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: requestroute_service_ptr_id_479451a78740d081_fk_core_service_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY requestrouter_requestrouterservice
+    ADD CONSTRAINT requestroute_service_ptr_id_479451a78740d081_fk_core_service_id FOREIGN KEY (service_ptr_id) REFERENCES core_service(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: requestrouter_serv_owner_id_5c71a9586041d2bc_fk_core_service_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY requestrouter_servicemap
+    ADD CONSTRAINT requestrouter_serv_owner_id_5c71a9586041d2bc_fk_core_service_id FOREIGN KEY (owner_id) REFERENCES core_service(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: requestrouter_servic_slice_id_50e57057a561f22f_fk_core_slice_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY requestrouter_servicemap
+    ADD CONSTRAINT requestrouter_servic_slice_id_50e57057a561f22f_fk_core_slice_id FOREIGN KEY (slice_id) REFERENCES core_slice(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: sy_volume_id_id_7dd16c76bfd7b129_fk_syndicate_storage_volume_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY syndicate_storage_volumeslice
+    ADD CONSTRAINT sy_volume_id_id_7dd16c76bfd7b129_fk_syndicate_storage_volume_id FOREIGN KEY (volume_id_id) REFERENCES syndicate_storage_volume(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: syndi_volume_id_3718f5b02d2245ce_fk_syndicate_storage_volume_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY syndicate_storage_volumeaccessright
+    ADD CONSTRAINT syndi_volume_id_3718f5b02d2245ce_fk_syndicate_storage_volume_id FOREIGN KEY (volume_id) REFERENCES syndicate_storage_volume(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: syndicate_st_service_ptr_id_26ca3aeabed50b6d_fk_core_service_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY syndicate_storage_syndicateservice
+    ADD CONSTRAINT syndicate_st_service_ptr_id_26ca3aeabed50b6d_fk_core_service_id FOREIGN KEY (service_ptr_id) REFERENCES core_service(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: syndicate_storage__owner_id_id_3d3e3d492d6cd6b5_fk_core_user_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY syndicate_storage_volumeaccessright
+    ADD CONSTRAINT syndicate_storage__owner_id_id_3d3e3d492d6cd6b5_fk_core_user_id FOREIGN KEY (owner_id_id) REFERENCES core_user(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: syndicate_storage__owner_id_id_7a99f36bf51f2c78_fk_core_user_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY syndicate_storage_volume
+    ADD CONSTRAINT syndicate_storage__owner_id_id_7a99f36bf51f2c78_fk_core_user_id FOREIGN KEY (owner_id_id) REFERENCES core_user(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: syndicate_storage_slice_id_id_1c80c36535559ad6_fk_core_slice_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY syndicate_storage_slicesecret
+    ADD CONSTRAINT syndicate_storage_slice_id_id_1c80c36535559ad6_fk_core_slice_id FOREIGN KEY (slice_id_id) REFERENCES core_slice(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: syndicate_storage_slice_id_id_36fa39a9ae458538_fk_core_slice_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY syndicate_storage_volumeslice
+    ADD CONSTRAINT syndicate_storage_slice_id_id_36fa39a9ae458538_fk_core_slice_id FOREIGN KEY (slice_id_id) REFERENCES core_slice(id) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- Name: public; Type: ACL; Schema: -; Owner: postgres
+--
+
+REVOKE ALL ON SCHEMA public FROM PUBLIC;
+REVOKE ALL ON SCHEMA public FROM postgres;
+GRANT ALL ON SCHEMA public TO postgres;
+GRANT ALL ON SCHEMA public TO PUBLIC;
+
+
+--
+-- PostgreSQL database dump complete
+--
+
diff --git a/xos/core/xoslib/xos_dump_mysql.sql b/xos/core/xoslib/xos_dump_mysql.sql
new file mode 100644
index 0000000..5b0b412
--- /dev/null
+++ b/xos/core/xoslib/xos_dump_mysql.sql
@@ -0,0 +1,1821 @@
+# Converted with pg2mysql-1.9
+# Converted on Fri, 16 Oct 2015 05:12:46 -0400
+# Lightbox Technologies Inc. http://www.lightbox.ca
+
+SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
+SET time_zone="+00:00";
+
+CREATE TABLE auth_group (
+    id int(11) NOT NULL,
+    name varchar(80) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE auth_group_permissions (
+    id int(11) NOT NULL,
+    group_id int(11) NOT NULL,
+    permission_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE auth_permission (
+    id int(11) NOT NULL,
+    name varchar(50) NOT NULL,
+    content_type_id int(11) NOT NULL,
+    codename varchar(100) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_account (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    site_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_charge (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    kind varchar(30) NOT NULL,
+    state varchar(30) NOT NULL,
+    date timestamp NOT NULL,
+    amount double precision NOT NULL,
+    `coreHours` double precision NOT NULL,
+    account_id int(11) NOT NULL,
+    invoice_id int(11),
+    object_id int(11) NOT NULL,
+    slice_id int(11)
+) ENGINE=MyISAM;
+
+CREATE TABLE core_controller (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    name varchar(200) NOT NULL,
+    backend_type varchar(200) NOT NULL,
+    version varchar(200) NOT NULL,
+    auth_url varchar(200),
+    admin_user varchar(200),
+    admin_password varchar(200),
+    admin_tenant varchar(200),
+    domain varchar(200),
+    deployment_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_controllercredential (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    name varchar(128) NOT NULL,
+    key_id text NOT NULL,
+    enc_value text NOT NULL,
+    controller_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_controllerdashboardview (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    enabled bool NOT NULL,
+    url text NOT NULL,
+    controller_id int(11) NOT NULL,
+    `dashboardView_id` int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_controllerimages (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    glance_image_id varchar(200),
+    controller_id int(11) NOT NULL,
+    image_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_controllernetwork (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    net_id text,
+    router_id text,
+    subnet_id text,
+    subnet varchar(32) NOT NULL,
+    controller_id int(11) NOT NULL,
+    network_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_controllerrole (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    role varchar(30) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_controllersite (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    tenant_id varchar(200),
+    controller_id int(11),
+    site_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_controllersiteprivilege (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    role_id varchar(200),
+    controller_id int(11) NOT NULL,
+    site_privilege_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_controllerslice (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    tenant_id varchar(200),
+    controller_id int(11) NOT NULL,
+    slice_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_controllersliceprivilege (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    role_id varchar(200),
+    controller_id int(11) NOT NULL,
+    slice_privilege_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_controlleruser (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    kuser_id varchar(200),
+    controller_id int(11) NOT NULL,
+    user_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_dashboardview (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    name varchar(200) NOT NULL,
+    url text NOT NULL,
+    enabled bool NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_dashboardview_deployments (
+    id int(11) NOT NULL,
+    dashboardview_id int(11) NOT NULL,
+    deployment_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_deployment (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    name varchar(200) NOT NULL,
+    `accessControl` text NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_deploymentprivilege (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    deployment_id int(11) NOT NULL,
+    role_id int(11) NOT NULL,
+    user_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_deploymentrole (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    role varchar(30) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_flavor (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    name varchar(32) NOT NULL,
+    description text,
+    flavor varchar(32) NOT NULL,
+    `order` int(11) NOT NULL,
+    `default` bool NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_flavor_deployments (
+    id int(11) NOT NULL,
+    flavor_id int(11) NOT NULL,
+    deployment_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_image (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    name text NOT NULL,
+    disk_format text NOT NULL,
+    container_format text NOT NULL,
+    path text
+) ENGINE=MyISAM;
+
+CREATE TABLE core_imagedeployments (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    deployment_id int(11) NOT NULL,
+    image_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_instance (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    instance_id varchar(200),
+    instance_uuid varchar(200),
+    name varchar(200) NOT NULL,
+    instance_name varchar(200),
+    ip varchar(43),
+    numberCores int(11) NOT NULL,
+    userData text,
+    creator_id int(11),
+    deployment_id int(11) NOT NULL,
+    flavor_id int(11) NOT NULL,
+    image_id int(11) NOT NULL,
+    node_id int(11) NOT NULL,
+    slice_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_invoice (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    date timestamp NOT NULL,
+    account_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_network (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    name varchar(32) NOT NULL,
+    subnet varchar(32) NOT NULL,
+    ports text,
+    labels text,
+    guaranteed_bandwidth int(11) NOT NULL,
+    permit_all_slices bool NOT NULL,
+    topology_parameters text,
+    controller_url text,
+    controller_parameters text,
+    network_id text,
+    router_id text,
+    subnet_id text,
+    autoconnect bool NOT NULL,
+    owner_id int(11) NOT NULL,
+    template_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_network_permitted_slices (
+    id int(11) NOT NULL,
+    network_id int(11) NOT NULL,
+    slice_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_networkparameter (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    value text NOT NULL,
+    object_id int(11) NOT NULL,
+    content_type_id int(11) NOT NULL,
+    parameter_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_networkparametertype (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    name varchar(128) NOT NULL,
+    description text NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_networkslice (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    network_id int(11) NOT NULL,
+    slice_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_networktemplate (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    name varchar(32) NOT NULL,
+    description text,
+    guaranteed_bandwidth int(11) NOT NULL,
+    visibility varchar(30) NOT NULL,
+    translation varchar(30) NOT NULL,
+    shared_network_name varchar(30),
+    shared_network_id text,
+    topology_kind varchar(30) NOT NULL,
+    controller_kind varchar(30)
+) ENGINE=MyISAM;
+
+CREATE TABLE core_node (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    name varchar(200) NOT NULL,
+    site_id int(11),
+    site_deployment_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_payment (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    amount double precision NOT NULL,
+    date timestamp NOT NULL,
+    account_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_port (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    ip varchar(43),
+    port_id text,
+    mac text,
+    instance_id int(11),
+    network_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_program (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    name varchar(30) NOT NULL,
+    description text,
+    kind varchar(30) NOT NULL,
+    command varchar(30),
+    contents text,
+    output text,
+    messages text,
+    `status` text,
+    owner_id int(11)
+) ENGINE=MyISAM;
+
+CREATE TABLE core_project (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    name varchar(200) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_reservation (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    `startTime` timestamp NOT NULL,
+    duration int(11) NOT NULL,
+    slice_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_reservedresource (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    quantity int(11) NOT NULL,
+    instance_id int(11) NOT NULL,
+    `reservationSet_id` int(11) NOT NULL,
+    resource_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_role (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    role_type varchar(80) NOT NULL,
+    role varchar(80),
+    description varchar(120) NOT NULL,
+    content_type_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_router (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    name varchar(32) NOT NULL,
+    owner_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_router_networks (
+    id int(11) NOT NULL,
+    router_id int(11) NOT NULL,
+    network_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE `core_router_permittedNetworks` (
+    id int(11) NOT NULL,
+    router_id int(11) NOT NULL,
+    network_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_service (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    description text,
+    enabled bool NOT NULL,
+    kind varchar(30) NOT NULL,
+    name varchar(30) NOT NULL,
+    `versionNumber` varchar(30) NOT NULL,
+    published bool NOT NULL,
+    view_url text,
+    icon_url text,
+    public_key text,
+    service_specific_id varchar(30),
+    service_specific_attribute text
+) ENGINE=MyISAM;
+
+CREATE TABLE core_serviceattribute (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    name varchar(128) NOT NULL,
+    value text NOT NULL,
+    service_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_serviceclass (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    name varchar(32) NOT NULL,
+    description varchar(255) NOT NULL,
+    commitment int(11) NOT NULL,
+    `membershipFee` int(11) NOT NULL,
+    `membershipFeeMonths` int(11) NOT NULL,
+    `upgradeRequiresApproval` bool NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE `core_serviceclass_upgradeFrom` (
+    id int(11) NOT NULL,
+    from_serviceclass_id int(11) NOT NULL,
+    to_serviceclass_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_serviceprivilege (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    role_id int(11) NOT NULL,
+    service_id int(11) NOT NULL,
+    user_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_serviceresource (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    name varchar(32) NOT NULL,
+    `maxUnitsDeployment` int(11) NOT NULL,
+    `maxUnitsNode` int(11) NOT NULL,
+    `maxDuration` int(11) NOT NULL,
+    `bucketInRate` int(11) NOT NULL,
+    `bucketMaxSize` int(11) NOT NULL,
+    cost int(11) NOT NULL,
+    `calendarReservable` bool NOT NULL,
+    `serviceClass_id` int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_servicerole (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    role varchar(30) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_site (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    name varchar(200) NOT NULL,
+    site_url text,
+    enabled bool NOT NULL,
+    hosts_nodes bool NOT NULL,
+    hosts_users bool NOT NULL,
+    location varchar(42) NOT NULL,
+    longitude double precision,
+    latitude double precision,
+    login_base varchar(50) NOT NULL,
+    is_public bool NOT NULL,
+    abbreviated_name varchar(80) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_sitecredential (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    name varchar(128) NOT NULL,
+    key_id text NOT NULL,
+    enc_value text NOT NULL,
+    site_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_sitedeployment (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    availability_zone varchar(200),
+    controller_id int(11),
+    deployment_id int(11) NOT NULL,
+    site_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_siteprivilege (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    role_id int(11) NOT NULL,
+    site_id int(11) NOT NULL,
+    user_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_siterole (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    role varchar(30) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_slice (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    name varchar(80) NOT NULL,
+    enabled bool NOT NULL,
+    omf_friendly bool NOT NULL,
+    description text NOT NULL,
+    slice_url text NOT NULL,
+    max_instances int(11) NOT NULL,
+    network text,
+    mount_data_sets text,
+    creator_id int(11),
+    default_flavor_id int(11),
+    default_image_id int(11),
+    service_id int(11),
+    `serviceClass_id` int(11),
+    site_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_slicecredential (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    name varchar(128) NOT NULL,
+    key_id text NOT NULL,
+    enc_value text NOT NULL,
+    slice_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_sliceprivilege (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    role_id int(11) NOT NULL,
+    slice_id int(11) NOT NULL,
+    user_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_slicerole (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    role varchar(30) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_slicetag (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    name varchar(30) NOT NULL,
+    value text NOT NULL,
+    slice_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_tag (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    name varchar(128) NOT NULL,
+    value text NOT NULL,
+    object_id int(11) NOT NULL,
+    content_type_id int(11) NOT NULL,
+    service_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_tenant (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    kind varchar(30) NOT NULL,
+    service_specific_id varchar(30),
+    service_specific_attribute text,
+    connect_method varchar(30) NOT NULL,
+    provider_service_id int(11) NOT NULL,
+    subscriber_root_id int(11),
+    subscriber_service_id int(11),
+    subscriber_tenant_id int(11),
+    subscriber_user_id int(11)
+) ENGINE=MyISAM;
+
+CREATE TABLE core_tenantroot (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    kind varchar(30) NOT NULL,
+    name varchar(255),
+    service_specific_attribute text,
+    service_specific_id varchar(30)
+) ENGINE=MyISAM;
+
+CREATE TABLE core_tenantrootprivilege (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    role_id int(11) NOT NULL,
+    tenant_root_id int(11) NOT NULL,
+    user_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_tenantrootrole (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    role varchar(30) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_usableobject (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    name text NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_user (
+    id int(11) NOT NULL,
+    password varchar(128) NOT NULL,
+    last_login timestamp NOT NULL,
+    email varchar(255) NOT NULL,
+    username varchar(255) NOT NULL,
+    firstname varchar(200) NOT NULL,
+    lastname varchar(200) NOT NULL,
+    phone varchar(100),
+    user_url varchar(200),
+    public_key text,
+    is_active bool NOT NULL,
+    is_admin bool NOT NULL,
+    is_staff bool NOT NULL,
+    is_readonly bool NOT NULL,
+    is_registering bool NOT NULL,
+    is_appuser bool NOT NULL,
+    login_page varchar(200),
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    timezone varchar(100) NOT NULL,
+    site_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_usercredential (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    name varchar(128) NOT NULL,
+    key_id text NOT NULL,
+    enc_value text NOT NULL,
+    user_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE core_userdashboardview (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    `order` int(11) NOT NULL,
+    `dashboardView_id` int(11) NOT NULL,
+    user_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE django_admin_log (
+    id int(11) NOT NULL,
+    action_time timestamp NOT NULL,
+    object_id text,
+    object_repr varchar(200) NOT NULL,
+    action_flag smallint NOT NULL,
+    change_message text NOT NULL,
+    content_type_id int(11),
+    user_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE django_content_type (
+    id int(11) NOT NULL,
+    name varchar(100) NOT NULL,
+    app_label varchar(100) NOT NULL,
+    model varchar(100) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE django_migrations (
+    id int(11) NOT NULL,
+    app varchar(255) NOT NULL,
+    name varchar(255) NOT NULL,
+    applied timestamp NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE django_session (
+    session_key varchar(40) NOT NULL,
+    session_data text NOT NULL,
+    expire_date timestamp NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE hpc_accessmap (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    name varchar(64) NOT NULL,
+    description text,
+    map varchar(100) NOT NULL,
+    `contentProvider_id` int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE hpc_cdnprefix (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    cdn_prefix_id int(11),
+    prefix varchar(200) NOT NULL,
+    description text,
+    enabled bool NOT NULL,
+    `contentProvider_id` int(11) NOT NULL,
+    `defaultOriginServer_id` int(11)
+) ENGINE=MyISAM;
+
+CREATE TABLE hpc_contentprovider (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    content_provider_id int(11),
+    name varchar(254) NOT NULL,
+    enabled bool NOT NULL,
+    description text,
+    `serviceProvider_id` int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE hpc_contentprovider_users (
+    id int(11) NOT NULL,
+    contentprovider_id int(11) NOT NULL,
+    user_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE hpc_hpchealthcheck (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    kind varchar(30) NOT NULL,
+    resource_name text NOT NULL,
+    result_contains text,
+    result_min_size int(11),
+    result_max_size int(11),
+    `hpcService_id` int(11)
+) ENGINE=MyISAM;
+
+CREATE TABLE hpc_hpcservice (
+    service_ptr_id int(11) NOT NULL,
+    cmi_hostname varchar(254),
+    hpc_port80 bool NOT NULL,
+    watcher_hpc_network varchar(254),
+    watcher_dnsdemux_network varchar(254),
+    watcher_dnsredir_network varchar(254)
+) ENGINE=MyISAM;
+
+CREATE TABLE hpc_originserver (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    origin_server_id int(11),
+    url text NOT NULL,
+    authenticated bool NOT NULL,
+    enabled bool NOT NULL,
+    protocol varchar(12) NOT NULL,
+    redirects bool NOT NULL,
+    description text,
+    `contentProvider_id` int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE hpc_serviceprovider (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    service_provider_id int(11),
+    name varchar(254) NOT NULL,
+    description text,
+    enabled bool NOT NULL,
+    `hpcService_id` int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE hpc_sitemap (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    name varchar(64) NOT NULL,
+    description text,
+    map varchar(100) NOT NULL,
+    map_id int(11),
+    `cdnPrefix_id` int(11),
+    `contentProvider_id` int(11),
+    `hpcService_id` int(11),
+    `serviceProvider_id` int(11)
+) ENGINE=MyISAM;
+
+CREATE TABLE requestrouter_requestrouterservice (
+    service_ptr_id int(11) NOT NULL,
+    `behindNat` bool NOT NULL,
+    `defaultTTL` int(11) NOT NULL,
+    `defaultAction` varchar(30) NOT NULL,
+    `lastResortAction` varchar(30) NOT NULL,
+    `maxAnswers` int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE requestrouter_servicemap (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    name varchar(50) NOT NULL,
+    prefix text NOT NULL,
+    `siteMap` varchar(100) NOT NULL,
+    `accessMap` varchar(100) NOT NULL,
+    owner_id int(11) NOT NULL,
+    slice_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE syndicate_storage_slicesecret (
+    id int(11) NOT NULL,
+    secret text NOT NULL,
+    slice_id_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE syndicate_storage_syndicateprincipal (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    principal_id text NOT NULL,
+    public_key_pem text NOT NULL,
+    sealed_private_key text NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE syndicate_storage_syndicateservice (
+    service_ptr_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE syndicate_storage_volume (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    name varchar(64) NOT NULL,
+    description text,
+    blocksize int(11) NOT NULL,
+    private bool NOT NULL,
+    archive bool NOT NULL,
+    cap_read_data bool NOT NULL,
+    cap_write_data bool NOT NULL,
+    cap_host_data bool NOT NULL,
+    owner_id_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE syndicate_storage_volumeaccessright (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    cap_read_data bool NOT NULL,
+    cap_write_data bool NOT NULL,
+    cap_host_data bool NOT NULL,
+    owner_id_id int(11) NOT NULL,
+    volume_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+CREATE TABLE syndicate_storage_volumeslice (
+    id int(11) NOT NULL,
+    created timestamp NOT NULL,
+    updated timestamp NOT NULL,
+    enacted timestamp,
+    policed timestamp,
+    backend_register varchar(140),
+    backend_status text NOT NULL,
+    deleted bool NOT NULL,
+    write_protect bool NOT NULL,
+    lazy_blocked bool NOT NULL,
+    no_sync bool NOT NULL,
+    cap_read_data bool NOT NULL,
+    cap_write_data bool NOT NULL,
+    cap_host_data bool NOT NULL,
+    `UG_portnum` int(11) NOT NULL,
+    `RG_portnum` int(11) NOT NULL,
+    credentials_blob text,
+    slice_id_id int(11) NOT NULL,
+    volume_id_id int(11) NOT NULL
+) ENGINE=MyISAM;
+
+ALTER TABLE auth_group_permissions
+    ADD CONSTRAINT auth_group_permissions_pkey PRIMARY KEY (id);
+ALTER TABLE auth_group
+    ADD CONSTRAINT auth_group_pkey PRIMARY KEY (id);
+ALTER TABLE auth_permission
+    ADD CONSTRAINT auth_permission_pkey PRIMARY KEY (id);
+ALTER TABLE core_account
+    ADD CONSTRAINT core_account_pkey PRIMARY KEY (id);
+ALTER TABLE core_charge
+    ADD CONSTRAINT core_charge_pkey PRIMARY KEY (id);
+ALTER TABLE core_controller
+    ADD CONSTRAINT core_controller_pkey PRIMARY KEY (id);
+ALTER TABLE core_controllercredential
+    ADD CONSTRAINT core_controllercredential_pkey PRIMARY KEY (id);
+ALTER TABLE core_controllerdashboardview
+    ADD CONSTRAINT core_controllerdashboardview_pkey PRIMARY KEY (id);
+ALTER TABLE core_controllerimages
+    ADD CONSTRAINT core_controllerimages_pkey PRIMARY KEY (id);
+ALTER TABLE core_controllernetwork
+    ADD CONSTRAINT core_controllernetwork_pkey PRIMARY KEY (id);
+ALTER TABLE core_controllerrole
+    ADD CONSTRAINT core_controllerrole_pkey PRIMARY KEY (id);
+ALTER TABLE core_controllersite
+    ADD CONSTRAINT core_controllersite_pkey PRIMARY KEY (id);
+ALTER TABLE core_controllersiteprivilege
+    ADD CONSTRAINT core_controllersiteprivilege_pkey PRIMARY KEY (id);
+ALTER TABLE core_controllerslice
+    ADD CONSTRAINT core_controllerslice_pkey PRIMARY KEY (id);
+ALTER TABLE core_controllersliceprivilege
+    ADD CONSTRAINT core_controllersliceprivilege_pkey PRIMARY KEY (id);
+ALTER TABLE core_controlleruser
+    ADD CONSTRAINT core_controlleruser_pkey PRIMARY KEY (id);
+ALTER TABLE core_dashboardview_deployments
+    ADD CONSTRAINT core_dashboardview_deployments_pkey PRIMARY KEY (id);
+ALTER TABLE core_dashboardview
+    ADD CONSTRAINT core_dashboardview_pkey PRIMARY KEY (id);
+ALTER TABLE core_deployment
+    ADD CONSTRAINT core_deployment_pkey PRIMARY KEY (id);
+ALTER TABLE core_deploymentprivilege
+    ADD CONSTRAINT core_deploymentprivilege_pkey PRIMARY KEY (id);
+ALTER TABLE core_deploymentrole
+    ADD CONSTRAINT core_deploymentrole_pkey PRIMARY KEY (id);
+ALTER TABLE core_flavor_deployments
+    ADD CONSTRAINT core_flavor_deployments_pkey PRIMARY KEY (id);
+ALTER TABLE core_flavor
+    ADD CONSTRAINT core_flavor_pkey PRIMARY KEY (id);
+ALTER TABLE core_image
+    ADD CONSTRAINT core_image_pkey PRIMARY KEY (id);
+ALTER TABLE core_imagedeployments
+    ADD CONSTRAINT core_imagedeployments_pkey PRIMARY KEY (id);
+ALTER TABLE core_instance
+    ADD CONSTRAINT core_instance_pkey PRIMARY KEY (id);
+ALTER TABLE core_invoice
+    ADD CONSTRAINT core_invoice_pkey PRIMARY KEY (id);
+ALTER TABLE core_network_permitted_slices
+    ADD CONSTRAINT core_network_permitted_slices_pkey PRIMARY KEY (id);
+ALTER TABLE core_network
+    ADD CONSTRAINT core_network_pkey PRIMARY KEY (id);
+ALTER TABLE core_networkparameter
+    ADD CONSTRAINT core_networkparameter_pkey PRIMARY KEY (id);
+ALTER TABLE core_networkparametertype
+    ADD CONSTRAINT core_networkparametertype_pkey PRIMARY KEY (id);
+ALTER TABLE core_networkslice
+    ADD CONSTRAINT core_networkslice_pkey PRIMARY KEY (id);
+ALTER TABLE core_networktemplate
+    ADD CONSTRAINT core_networktemplate_pkey PRIMARY KEY (id);
+ALTER TABLE core_node
+    ADD CONSTRAINT core_node_pkey PRIMARY KEY (id);
+ALTER TABLE core_payment
+    ADD CONSTRAINT core_payment_pkey PRIMARY KEY (id);
+ALTER TABLE core_port
+    ADD CONSTRAINT core_port_pkey PRIMARY KEY (id);
+ALTER TABLE core_program
+    ADD CONSTRAINT core_program_pkey PRIMARY KEY (id);
+ALTER TABLE core_project
+    ADD CONSTRAINT core_project_pkey PRIMARY KEY (id);
+ALTER TABLE core_reservation
+    ADD CONSTRAINT core_reservation_pkey PRIMARY KEY (id);
+ALTER TABLE core_reservedresource
+    ADD CONSTRAINT core_reservedresource_pkey PRIMARY KEY (id);
+ALTER TABLE core_role
+    ADD CONSTRAINT core_role_pkey PRIMARY KEY (id);
+ALTER TABLE core_router_networks
+    ADD CONSTRAINT core_router_networks_pkey PRIMARY KEY (id);
+ALTER TABLE `core_router_permittedNetworks`
+    ADD CONSTRAINT core_router_permittedNetworks_pkey PRIMARY KEY (id);
+ALTER TABLE core_router
+    ADD CONSTRAINT core_router_pkey PRIMARY KEY (id);
+ALTER TABLE core_service
+    ADD CONSTRAINT core_service_pkey PRIMARY KEY (id);
+ALTER TABLE core_serviceattribute
+    ADD CONSTRAINT core_serviceattribute_pkey PRIMARY KEY (id);
+ALTER TABLE core_serviceclass
+    ADD CONSTRAINT core_serviceclass_pkey PRIMARY KEY (id);
+ALTER TABLE `core_serviceclass_upgradeFrom`
+    ADD CONSTRAINT core_serviceclass_upgradeFrom_pkey PRIMARY KEY (id);
+ALTER TABLE core_serviceprivilege
+    ADD CONSTRAINT core_serviceprivilege_pkey PRIMARY KEY (id);
+ALTER TABLE core_serviceresource
+    ADD CONSTRAINT core_serviceresource_pkey PRIMARY KEY (id);
+ALTER TABLE core_servicerole
+    ADD CONSTRAINT core_servicerole_pkey PRIMARY KEY (id);
+ALTER TABLE core_site
+    ADD CONSTRAINT core_site_pkey PRIMARY KEY (id);
+ALTER TABLE core_sitecredential
+    ADD CONSTRAINT core_sitecredential_pkey PRIMARY KEY (id);
+ALTER TABLE core_sitedeployment
+    ADD CONSTRAINT core_sitedeployment_pkey PRIMARY KEY (id);
+ALTER TABLE core_siteprivilege
+    ADD CONSTRAINT core_siteprivilege_pkey PRIMARY KEY (id);
+ALTER TABLE core_siterole
+    ADD CONSTRAINT core_siterole_pkey PRIMARY KEY (id);
+ALTER TABLE core_slice
+    ADD CONSTRAINT core_slice_pkey PRIMARY KEY (id);
+ALTER TABLE core_slicecredential
+    ADD CONSTRAINT core_slicecredential_pkey PRIMARY KEY (id);
+ALTER TABLE core_sliceprivilege
+    ADD CONSTRAINT core_sliceprivilege_pkey PRIMARY KEY (id);
+ALTER TABLE core_slicerole
+    ADD CONSTRAINT core_slicerole_pkey PRIMARY KEY (id);
+ALTER TABLE core_slicetag
+    ADD CONSTRAINT core_slicetag_pkey PRIMARY KEY (id);
+ALTER TABLE core_tag
+    ADD CONSTRAINT core_tag_pkey PRIMARY KEY (id);
+ALTER TABLE core_tenant
+    ADD CONSTRAINT core_tenant_pkey PRIMARY KEY (id);
+ALTER TABLE core_tenantroot
+    ADD CONSTRAINT core_tenantroot_pkey PRIMARY KEY (id);
+ALTER TABLE core_tenantrootprivilege
+    ADD CONSTRAINT core_tenantrootprivilege_pkey PRIMARY KEY (id);
+ALTER TABLE core_tenantrootrole
+    ADD CONSTRAINT core_tenantrootrole_pkey PRIMARY KEY (id);
+ALTER TABLE core_usableobject
+    ADD CONSTRAINT core_usableobject_pkey PRIMARY KEY (id);
+ALTER TABLE core_user
+    ADD CONSTRAINT core_user_pkey PRIMARY KEY (id);
+ALTER TABLE core_usercredential
+    ADD CONSTRAINT core_usercredential_pkey PRIMARY KEY (id);
+ALTER TABLE core_userdashboardview
+    ADD CONSTRAINT core_userdashboardview_pkey PRIMARY KEY (id);
+ALTER TABLE django_admin_log
+    ADD CONSTRAINT django_admin_log_pkey PRIMARY KEY (id);
+ALTER TABLE django_content_type
+    ADD CONSTRAINT django_content_type_pkey PRIMARY KEY (id);
+ALTER TABLE django_migrations
+    ADD CONSTRAINT django_migrations_pkey PRIMARY KEY (id);
+ALTER TABLE django_session
+    ADD CONSTRAINT django_session_pkey PRIMARY KEY (session_key);
+ALTER TABLE hpc_accessmap
+    ADD CONSTRAINT hpc_accessmap_pkey PRIMARY KEY (id);
+ALTER TABLE hpc_cdnprefix
+    ADD CONSTRAINT hpc_cdnprefix_pkey PRIMARY KEY (id);
+ALTER TABLE hpc_contentprovider
+    ADD CONSTRAINT hpc_contentprovider_pkey PRIMARY KEY (id);
+ALTER TABLE hpc_contentprovider_users
+    ADD CONSTRAINT hpc_contentprovider_users_pkey PRIMARY KEY (id);
+ALTER TABLE hpc_hpchealthcheck
+    ADD CONSTRAINT hpc_hpchealthcheck_pkey PRIMARY KEY (id);
+ALTER TABLE hpc_hpcservice
+    ADD CONSTRAINT hpc_hpcservice_pkey PRIMARY KEY (service_ptr_id);
+ALTER TABLE hpc_originserver
+    ADD CONSTRAINT hpc_originserver_pkey PRIMARY KEY (id);
+ALTER TABLE hpc_serviceprovider
+    ADD CONSTRAINT hpc_serviceprovider_pkey PRIMARY KEY (id);
+ALTER TABLE hpc_sitemap
+    ADD CONSTRAINT hpc_sitemap_pkey PRIMARY KEY (id);
+ALTER TABLE requestrouter_requestrouterservice
+    ADD CONSTRAINT requestrouter_requestrouterservice_pkey PRIMARY KEY (service_ptr_id);
+ALTER TABLE requestrouter_servicemap
+    ADD CONSTRAINT requestrouter_servicemap_pkey PRIMARY KEY (id);
+ALTER TABLE syndicate_storage_slicesecret
+    ADD CONSTRAINT syndicate_storage_slicesecret_pkey PRIMARY KEY (id);
+ALTER TABLE syndicate_storage_syndicateprincipal
+    ADD CONSTRAINT syndicate_storage_syndicateprincipal_pkey PRIMARY KEY (id);
+ALTER TABLE syndicate_storage_syndicateservice
+    ADD CONSTRAINT syndicate_storage_syndicateservice_pkey PRIMARY KEY (service_ptr_id);
+ALTER TABLE syndicate_storage_volume
+    ADD CONSTRAINT syndicate_storage_volume_pkey PRIMARY KEY (id);
+ALTER TABLE syndicate_storage_volumeaccessright
+    ADD CONSTRAINT syndicate_storage_volumeaccessright_pkey PRIMARY KEY (id);
+ALTER TABLE syndicate_storage_volumeslice
+    ADD CONSTRAINT syndicate_storage_volumeslice_pkey PRIMARY KEY (id);
+ALTER TABLE `auth_group_permissions` ADD INDEX ( group_id ) ;
+ALTER TABLE `auth_group_permissions` ADD INDEX ( permission_id ) ;
+ALTER TABLE `auth_permission` ADD INDEX ( content_type_id ) ;
+ALTER TABLE `core_account` ADD INDEX ( site_id ) ;
+ALTER TABLE `core_charge` ADD INDEX ( account_id ) ;
+ALTER TABLE `core_charge` ADD INDEX ( object_id ) ;
+ALTER TABLE `core_charge` ADD INDEX ( slice_id ) ;
+ALTER TABLE `core_charge` ADD INDEX ( invoice_id ) ;
+ALTER TABLE `core_controller` ADD INDEX ( deployment_id ) ;
+ALTER TABLE `core_controllercredential` ADD INDEX ( controller_id ) ;
+ALTER TABLE `core_controllercredential` ADD INDEX ( name ) ;
+ALTER TABLE `core_controllerdashboardview` ADD INDEX ( dashboardView_id ) ;
+ALTER TABLE `core_controllerdashboardview` ADD INDEX ( controller_id ) ;
+ALTER TABLE `core_controllerimages` ADD INDEX ( controller_id ) ;
+ALTER TABLE `core_controllerimages` ADD INDEX ( image_id ) ;
+ALTER TABLE `core_controllernetwork` ADD INDEX ( network_id ) ;
+ALTER TABLE `core_controllernetwork` ADD INDEX ( controller_id ) ;
+ALTER TABLE `core_controllersite` ADD INDEX ( tenant_id ) ;
+ALTER TABLE `core_controllersite` ADD INDEX ( site_id ) ;
+ALTER TABLE `core_controllersite` ADD INDEX ( controller_id ) ;
+ALTER TABLE `core_controllersiteprivilege` ADD INDEX ( site_privilege_id ) ;
+ALTER TABLE `core_controllersiteprivilege` ADD INDEX ( role_id ) ;
+ALTER TABLE `core_controllersiteprivilege` ADD INDEX ( controller_id ) ;
+ALTER TABLE `core_controllerslice` ADD INDEX ( controller_id ) ;
+ALTER TABLE `core_controllerslice` ADD INDEX ( slice_id ) ;
+ALTER TABLE `core_controllersliceprivilege` ADD INDEX ( slice_privilege_id ) ;
+ALTER TABLE `core_controllersliceprivilege` ADD INDEX ( role_id ) ;
+ALTER TABLE `core_controllersliceprivilege` ADD INDEX ( controller_id ) ;
+ALTER TABLE `core_controlleruser` ADD INDEX ( controller_id ) ;
+ALTER TABLE `core_controlleruser` ADD INDEX ( user_id ) ;
+ALTER TABLE `core_dashboardview_deployments` ADD INDEX ( deployment_id ) ;
+ALTER TABLE `core_dashboardview_deployments` ADD INDEX ( dashboardview_id ) ;
+ALTER TABLE `core_deploymentprivilege` ADD INDEX ( deployment_id ) ;
+ALTER TABLE `core_deploymentprivilege` ADD INDEX ( role_id ) ;
+ALTER TABLE `core_deploymentprivilege` ADD INDEX ( user_id ) ;
+ALTER TABLE `core_flavor_deployments` ADD INDEX ( deployment_id ) ;
+ALTER TABLE `core_flavor_deployments` ADD INDEX ( flavor_id ) ;
+ALTER TABLE `core_imagedeployments` ADD INDEX ( deployment_id ) ;
+ALTER TABLE `core_imagedeployments` ADD INDEX ( image_id ) ;
+ALTER TABLE `core_instance` ADD INDEX ( creator_id ) ;
+ALTER TABLE `core_instance` ADD INDEX ( deployment_id ) ;
+ALTER TABLE `core_instance` ADD INDEX ( slice_id ) ;
+ALTER TABLE `core_instance` ADD INDEX ( node_id ) ;
+ALTER TABLE `core_instance` ADD INDEX ( flavor_id ) ;
+ALTER TABLE `core_instance` ADD INDEX ( image_id ) ;
+ALTER TABLE `core_invoice` ADD INDEX ( account_id ) ;
+ALTER TABLE `core_network` ADD INDEX ( owner_id ) ;
+ALTER TABLE `core_network` ADD INDEX ( template_id ) ;
+ALTER TABLE `core_network_permitted_slices` ADD INDEX ( network_id ) ;
+ALTER TABLE `core_network_permitted_slices` ADD INDEX ( slice_id ) ;
+ALTER TABLE `core_networkparameter` ADD INDEX ( content_type_id ) ;
+ALTER TABLE `core_networkparameter` ADD INDEX ( parameter_id ) ;
+ALTER TABLE `core_networkparametertype` ADD INDEX ( name ) ;
+ALTER TABLE `core_networkslice` ADD INDEX ( network_id ) ;
+ALTER TABLE `core_networkslice` ADD INDEX ( slice_id ) ;
+ALTER TABLE `core_node` ADD INDEX ( site_deployment_id ) ;
+ALTER TABLE `core_node` ADD INDEX ( site_id ) ;
+ALTER TABLE `core_payment` ADD INDEX ( account_id ) ;
+ALTER TABLE `core_port` ADD INDEX ( network_id ) ;
+ALTER TABLE `core_port` ADD INDEX ( instance_id ) ;
+ALTER TABLE `core_program` ADD INDEX ( owner_id ) ;
+ALTER TABLE `core_reservation` ADD INDEX ( slice_id ) ;
+ALTER TABLE `core_reservedresource` ADD INDEX ( instance_id ) ;
+ALTER TABLE `core_reservedresource` ADD INDEX ( reservationSet_id ) ;
+ALTER TABLE `core_reservedresource` ADD INDEX ( resource_id ) ;
+ALTER TABLE `core_role` ADD INDEX ( content_type_id ) ;
+ALTER TABLE `core_router` ADD INDEX ( owner_id ) ;
+ALTER TABLE `core_router_networks` ADD INDEX ( network_id ) ;
+ALTER TABLE `core_router_networks` ADD INDEX ( router_id ) ;
+ALTER TABLE `core_router_permittedNetworks` ADD INDEX ( network_id ) ;
+ALTER TABLE `core_router_permittedNetworks` ADD INDEX ( router_id ) ;
+ALTER TABLE `core_serviceattribute` ADD INDEX ( name ) ;
+ALTER TABLE `core_serviceattribute` ADD INDEX ( service_id ) ;
+ALTER TABLE `core_serviceclass_upgradeFrom` ADD INDEX ( to_serviceclass_id ) ;
+ALTER TABLE `core_serviceclass_upgradeFrom` ADD INDEX ( from_serviceclass_id ) ;
+ALTER TABLE `core_serviceprivilege` ADD INDEX ( role_id ) ;
+ALTER TABLE `core_serviceprivilege` ADD INDEX ( service_id ) ;
+ALTER TABLE `core_serviceprivilege` ADD INDEX ( user_id ) ;
+ALTER TABLE `core_serviceresource` ADD INDEX ( serviceClass_id ) ;
+ALTER TABLE `core_sitecredential` ADD INDEX ( site_id ) ;
+ALTER TABLE `core_sitecredential` ADD INDEX ( name ) ;
+ALTER TABLE `core_sitedeployment` ADD INDEX ( deployment_id ) ;
+ALTER TABLE `core_sitedeployment` ADD INDEX ( site_id ) ;
+ALTER TABLE `core_sitedeployment` ADD INDEX ( controller_id ) ;
+ALTER TABLE `core_siteprivilege` ADD INDEX ( role_id ) ;
+ALTER TABLE `core_siteprivilege` ADD INDEX ( site_id ) ;
+ALTER TABLE `core_siteprivilege` ADD INDEX ( user_id ) ;
+ALTER TABLE `core_slice` ADD INDEX ( creator_id ) ;
+ALTER TABLE `core_slice` ADD INDEX ( default_flavor_id ) ;
+ALTER TABLE `core_slice` ADD INDEX ( site_id ) ;
+ALTER TABLE `core_slice` ADD INDEX ( default_image_id ) ;
+ALTER TABLE `core_slice` ADD INDEX ( serviceClass_id ) ;
+ALTER TABLE `core_slice` ADD INDEX ( service_id ) ;
+ALTER TABLE `core_slicecredential` ADD INDEX ( name ) ;
+ALTER TABLE `core_slicecredential` ADD INDEX ( slice_id ) ;
+ALTER TABLE `core_sliceprivilege` ADD INDEX ( role_id ) ;
+ALTER TABLE `core_sliceprivilege` ADD INDEX ( slice_id ) ;
+ALTER TABLE `core_sliceprivilege` ADD INDEX ( user_id ) ;
+ALTER TABLE `core_slicetag` ADD INDEX ( slice_id ) ;
+ALTER TABLE `core_tag` ADD INDEX ( content_type_id ) ;
+ALTER TABLE `core_tag` ADD INDEX ( name ) ;
+ALTER TABLE `core_tag` ADD INDEX ( service_id ) ;
+ALTER TABLE `core_tenant` ADD INDEX ( subscriber_tenant_id ) ;
+ALTER TABLE `core_tenant` ADD INDEX ( subscriber_service_id ) ;
+ALTER TABLE `core_tenant` ADD INDEX ( provider_service_id ) ;
+ALTER TABLE `core_tenant` ADD INDEX ( subscriber_user_id ) ;
+ALTER TABLE `core_tenant` ADD INDEX ( subscriber_root_id ) ;
+ALTER TABLE `core_tenantrootprivilege` ADD INDEX ( role_id ) ;
+ALTER TABLE `core_tenantrootprivilege` ADD INDEX ( tenant_root_id ) ;
+ALTER TABLE `core_tenantrootprivilege` ADD INDEX ( user_id ) ;
+ALTER TABLE `core_user` ADD INDEX ( site_id ) ;
+ALTER TABLE `core_usercredential` ADD INDEX ( name ) ;
+ALTER TABLE `core_usercredential` ADD INDEX ( user_id ) ;
+ALTER TABLE `core_userdashboardview` ADD INDEX ( dashboardView_id ) ;
+ALTER TABLE `core_userdashboardview` ADD INDEX ( user_id ) ;
+ALTER TABLE `django_admin_log` ADD INDEX ( content_type_id ) ;
+ALTER TABLE `django_admin_log` ADD INDEX ( user_id ) ;
+ALTER TABLE `django_session` ADD INDEX ( expire_date ) ;
+ALTER TABLE `hpc_accessmap` ADD INDEX ( contentProvider_id ) ;
+ALTER TABLE `hpc_cdnprefix` ADD INDEX ( defaultOriginServer_id ) ;
+ALTER TABLE `hpc_cdnprefix` ADD INDEX ( contentProvider_id ) ;
+ALTER TABLE `hpc_contentprovider` ADD INDEX ( serviceProvider_id ) ;
+ALTER TABLE `hpc_contentprovider_users` ADD INDEX ( contentprovider_id ) ;
+ALTER TABLE `hpc_contentprovider_users` ADD INDEX ( user_id ) ;
+ALTER TABLE `hpc_hpchealthcheck` ADD INDEX ( hpcService_id ) ;
+ALTER TABLE `hpc_originserver` ADD INDEX ( contentProvider_id ) ;
+ALTER TABLE `hpc_serviceprovider` ADD INDEX ( hpcService_id ) ;
+ALTER TABLE `hpc_sitemap` ADD INDEX ( cdnPrefix_id ) ;
+ALTER TABLE `hpc_sitemap` ADD INDEX ( hpcService_id ) ;
+ALTER TABLE `hpc_sitemap` ADD INDEX ( contentProvider_id ) ;
+ALTER TABLE `hpc_sitemap` ADD INDEX ( serviceProvider_id ) ;
+ALTER TABLE `requestrouter_servicemap` ADD INDEX ( owner_id ) ;
+ALTER TABLE `requestrouter_servicemap` ADD INDEX ( slice_id ) ;
+ALTER TABLE `syndicate_storage_slicesecret` ADD INDEX ( slice_id_id ) ;
+ALTER TABLE `syndicate_storage_volume` ADD INDEX ( owner_id_id ) ;
+ALTER TABLE `syndicate_storage_volumeaccessright` ADD INDEX ( owner_id_id ) ;
+ALTER TABLE `syndicate_storage_volumeaccessright` ADD INDEX ( volume_id ) ;
+ALTER TABLE `syndicate_storage_volumeslice` ADD INDEX ( volume_id_id ) ;
+ALTER TABLE `syndicate_storage_volumeslice` ADD INDEX ( slice_id_id ) ;
diff --git a/xos/generate/__init__.py b/xos/generate/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xos/generate/__init__.py
diff --git a/xos/generate/dependency_walker.py b/xos/generate/dependency_walker.py
new file mode 100644
index 0000000..210ec0f
--- /dev/null
+++ b/xos/generate/dependency_walker.py
@@ -0,0 +1,107 @@
+#!/usr/bin/env python
+
+import os
+import imp
+from xos.config import Config, XOS_DIR
+import inspect
+import time
+import traceback
+import commands
+import threading
+import json
+import pdb
+from core.models import *
+
+from xos.logger import Logger, logging
+logger = Logger(level=logging.INFO)
+
+missing_links={}
+
+try:
+	dep_data = open(Config().dependency_graph).read()
+except:
+	dep_data = open(XOS_DIR + '/model-deps').read()
+
+dependencies = json.loads(dep_data)
+
+inv_dependencies = {}
+for k, lst in dependencies.items():
+	for v in lst:
+		try:
+			inv_dependencies[v].append(k)
+		except KeyError:
+			inv_dependencies[v]=[k]
+	
+
+def plural(name):
+	if (name.endswith('s')):
+		return name+'es'
+	else:
+		return name+'s'
+
+
+def walk_deps(fn, object):
+	model = object.__class__.__name__
+	try:	
+		deps = dependencies[model]
+	except:
+		deps = []
+	return __walk_deps(fn, object, deps)
+
+def walk_inv_deps(fn, object):
+	model = object.__class__.__name__
+	try:	
+		deps = inv_dependencies[model]
+	except:
+		deps = []
+	return __walk_deps(fn, object, deps)
+
+def __walk_deps(fn, object, deps):
+	model = object.__class__.__name__
+	ret = []
+	for dep in deps:
+		#print "Checking dep %s"%dep
+		peer=None
+		link = dep.lower()
+		try:
+			peer = getattr(object, link)
+		except AttributeError:
+			link = plural(link)
+			try:
+				peer = getattr(object, link)
+			except AttributeError:
+				if not missing_links.has_key(model+'.'+link):
+					print "Model %s missing link for dependency %s"%(model, link)
+                                        logger.log_exc("WARNING: Model %s missing link for dependency %s."%(model, link))
+					missing_links[model+'.'+link]=True
+
+
+		if (peer):
+			try:
+				peer_objects = peer.all()
+			except AttributeError:
+				peer_objects = [peer]
+			except:
+				peer_objects = []
+
+			for o in peer_objects:
+				#if (isinstance(o,PlCoreBase)):
+				if (hasattr(o,'updated')):
+					fn(o, object)
+					ret.append(o)
+				# Uncomment the following line to enable recursion
+				# walk_inv_deps(fn, o)
+	return ret
+
+def p(x,source):
+	print x,x.__class__.__name__
+	return
+
+def main():
+	#pdb.set_trace()
+	s = Slice.objects.filter(name='princeton_sapan62')
+	#pdb.set_trace()
+	print walk_inv_deps(p,s[0])
+	
+if __name__=='__main__':
+	main()
diff --git a/xos/manage.py b/xos/manage.py
new file mode 100644
index 0000000..219d0e7
--- /dev/null
+++ b/xos/manage.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+import os
+import sys
+
+if __name__ == "__main__":
+    os.chdir('..')  # <<<---This is what you want to add
+    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
+
+    from django.core.management import execute_from_command_line
+
+    if "--makemigrations" in sys.argv:
+        os.system("/opt/xos/tools/xos-manage makemigrations")
+        sys.argv.remove("--makemigrations")
+
+    if "--nomodelpolicy" in sys.argv:
+        import synchronizers.model_policy as model_policy
+        model_policy.EnableModelPolicy(False)
+        sys.argv.remove("--nomodelpolicy")
+
+    if "--noobserver" in sys.argv:
+        import synchronizers.base as observer
+        observer.EnableObserver(False)
+        sys.argv.remove("--noobserver")
+
+    execute_from_command_line(sys.argv)
diff --git a/xos/model-deps b/xos/model-deps
new file mode 100644
index 0000000..59bbe25
--- /dev/null
+++ b/xos/model-deps
@@ -0,0 +1,117 @@
+{
+    "Slice": [
+        "Site", 
+        "User"
+    ], 
+    "ImageDeployments": [
+        "Image", 
+        "Deployment"
+    ], 
+    "ControllerImages": [
+        "Image"
+    ], 
+    "ReservedResource": [
+        "Instance"
+    ], 
+    "ControllerNetwork": [
+        "Network", 
+        "Controller"
+    ], 
+    "NetworkSlice": [
+        "Network", 
+        "Slice"
+    ], 
+    "Charge": [
+        "Account", 
+        "Slice", 
+        "Invoice"
+    ], 
+    "ControllerSite": [
+        "Site", 
+        "Controller"
+    ], 
+    "Node": [
+        "Site"
+    ], 
+    "ControllerSlice": [
+        "Controller", 
+        "Slice"
+    ], 
+    "ControllerSitePrivilege": [
+        "Controller"
+    ], 
+    "ControllerUser": [
+        "User", 
+        "Controller"
+    ], 
+    "UserCredential": [
+        "User"
+    ], 
+    "UserDashboardView": [
+        "User", 
+        "DashboardView"
+    ], 
+    "Controller": [
+        "Deployment"
+    ], 
+    "User": [
+        "Site"
+    ], 
+    "SliceTag": [
+        "Slice"
+    ], 
+    "Reservation": [
+        "Slice"
+    ], 
+    "Instance": [
+        "Image", 
+        "User", 
+        "Slice"
+    ], 
+    "Payment": [
+        "Account"
+    ], 
+    "Account": [
+        "Site"
+    ], 
+    "ControllerSlicePrivilege": [
+        "Controller"
+    ], 
+    "SiteDeployment": [
+        "Site", 
+        "Deployment", 
+        "Controller"
+    ], 
+    "SlicePrivilege": [
+        "User", 
+        "Slice", 
+        "Role"
+    ], 
+    "Port": [
+        "Network", 
+        "Instance"
+    ], 
+    "SitePrivilege": [
+        "User", 
+        "Site", 
+        "Role"
+    ], 
+    "SiteCredential": [
+        "Site"
+    ], 
+    "DeploymentPrivilege": [
+        "User", 
+        "Deployment", 
+        "Role"
+    ], 
+    "ControllerDashboardView": [
+        "Controller", 
+        "DashboardView"
+    ], 
+    "Invoice": [
+        "Account"
+    ], 
+    "SliceCredential": [
+        "Slice"
+    ]
+}
diff --git a/xos/model_autodeletion.py b/xos/model_autodeletion.py
new file mode 100644
index 0000000..6eaf63c
--- /dev/null
+++ b/xos/model_autodeletion.py
@@ -0,0 +1 @@
+ephemeral_models = ['ReservedResource','Instance','Image','Network','Tag','SitePrivilege','SliceMembership','SliceTag','Reservation','Slice']
diff --git a/xos/nginx/xos.conf b/xos/nginx/xos.conf
new file mode 100644
index 0000000..64d9d5e
--- /dev/null
+++ b/xos/nginx/xos.conf
@@ -0,0 +1,27 @@
+upstream backend {
+  # least_conn;   
+  server unix:/var/run/uwsgi/xos.sock;
+  server 127.0.0.1:9001;
+}
+
+
+server {
+    listen   80;
+    listen   [::]:80 default ipv6only=on; ## listen for ipv6
+    server_name 127.0.0.1;
+
+    location /static/ {
+        alias /opt/xos/core/static/;
+        expires 30d;
+        access_log off;
+    }
+
+    location /files/ {
+        alias /var/www/html/files/;
+    }
+
+    location / {
+        include /etc/nginx/uwsgi_params;
+        uwsgi_pass backend;
+    }
+}
diff --git a/xos/observer b/xos/observer
new file mode 120000
index 0000000..ae75af5
--- /dev/null
+++ b/xos/observer
@@ -0,0 +1 @@
+openstack_observer
\ No newline at end of file
diff --git a/xos/onboard/README.md b/xos/onboard/README.md
new file mode 100644
index 0000000..2030708
--- /dev/null
+++ b/xos/onboard/README.md
@@ -0,0 +1,3 @@
+This directory is a temporary placeholder for services that can be on-boarded. 
+
+Once we move to Gerritt and service-per-repo, this directory will be removed.
diff --git a/xos/onboard/ceilometer/admin.py b/xos/onboard/ceilometer/admin.py
new file mode 100644
index 0000000..062a2ae
--- /dev/null
+++ b/xos/onboard/ceilometer/admin.py
@@ -0,0 +1,214 @@
+from django.contrib import admin
+
+from services.ceilometer.models import *
+from django import forms
+from django.utils.safestring import mark_safe
+from django.contrib.auth.admin import UserAdmin
+from django.contrib.admin.widgets import FilteredSelectMultiple
+from django.contrib.auth.forms import ReadOnlyPasswordHashField
+from django.contrib.auth.signals import user_logged_in
+from django.utils import timezone
+from django.contrib.contenttypes import generic
+from suit.widgets import LinkedSelect
+from core.admin import ServiceAppAdmin,SliceInline,ServiceAttrAsTabInline, ReadOnlyAwareAdmin, XOSTabularInline, ServicePrivilegeInline, TenantRootTenantInline, TenantRootPrivilegeInline, TenantAttrAsTabInline
+from core.middleware import get_request
+
+from functools import update_wrapper
+from django.contrib.admin.views.main import ChangeList
+from django.core.urlresolvers import reverse
+from django.contrib.admin.utils import quote
+
+class CeilometerServiceForm(forms.ModelForm):
+    ceilometer_pub_sub_url = forms.CharField(required=False, max_length=1024, help_text="REST URL of ceilometer PUB/SUB component in http://IP:port/ format")
+
+    def __init__(self,*args,**kwargs):
+        super (CeilometerServiceForm,self ).__init__(*args,**kwargs)
+        if self.instance:
+            # fields for the attributes
+            self.fields['ceilometer_pub_sub_url'].initial = self.instance.ceilometer_pub_sub_url
+
+    def save(self, commit=True):
+        self.instance.ceilometer_pub_sub_url = self.cleaned_data.get("ceilometer_pub_sub_url")
+        return super(CeilometerServiceForm, self).save(commit=commit)
+
+    class Meta:
+        model = CeilometerService
+
+class CeilometerServiceAdmin(ReadOnlyAwareAdmin):
+    model = CeilometerService
+    verbose_name = "Ceilometer Service"
+    verbose_name_plural = "Ceilometer Service"
+    list_display = ("backend_status_icon", "name", "enabled")
+    list_display_links = ('backend_status_icon', 'name', )
+    fieldsets = [(None, {'fields': ['backend_status_text', 'name','enabled','versionNumber', 'description','ceilometer_pub_sub_url', "view_url","icon_url" ], 'classes':['suit-tab suit-tab-general']})]
+    readonly_fields = ('backend_status_text', )
+    inlines = [SliceInline,ServiceAttrAsTabInline,ServicePrivilegeInline]
+    form = CeilometerServiceForm
+
+    extracontext_registered_admins = True
+
+    user_readonly_fields = ["name", "enabled", "versionNumber", "description"]
+
+    suit_form_tabs =(('general', 'Ceilometer Service Details'),
+        ('administration', 'Administration'),
+        ('slices','Slices'),
+        ('serviceattrs','Additional Attributes'),
+        ('serviceprivileges','Privileges'),
+    )
+
+    suit_form_includes = (('ceilometeradmin.html', 'top', 'administration'),
+                           )
+
+    def queryset(self, request):
+        return CeilometerService.get_service_objects_by_user(request.user)
+
+class MonitoringChannelForm(forms.ModelForm):
+    creator = forms.ModelChoiceField(queryset=User.objects.all())
+
+    def __init__(self,*args,**kwargs):
+        super (MonitoringChannelForm,self ).__init__(*args,**kwargs)
+        self.fields['kind'].widget.attrs['readonly'] = True
+        self.fields['provider_service'].queryset = CeilometerService.get_service_objects().all()
+        if self.instance:
+            # fields for the attributes
+            self.fields['creator'].initial = self.instance.creator
+        if (not self.instance) or (not self.instance.pk):
+            # default fields for an 'add' form
+            self.fields['kind'].initial = CEILOMETER_KIND
+            self.fields['creator'].initial = get_request().user
+            if CeilometerService.get_service_objects().exists():
+               self.fields["provider_service"].initial = CeilometerService.get_service_objects().all()[0]
+
+
+    def save(self, commit=True):
+        self.instance.creator = self.cleaned_data.get("creator")
+        return super(MonitoringChannelForm, self).save(commit=commit)
+
+    class Meta:
+        model = MonitoringChannel
+
+class MonitoringChannelAdmin(ReadOnlyAwareAdmin):
+    list_display = ('backend_status_icon', 'id', )
+    list_display_links = ('backend_status_icon', 'id')
+    fieldsets = [ (None, {'fields': ['backend_status_text', 'kind', 'provider_service', 'service_specific_attribute',
+                                     'ceilometer_url', 'tenant_list_str',
+                                     'instance', 'creator'],
+                          'classes':['suit-tab suit-tab-general']})]
+    readonly_fields = ('backend_status_text', 'instance', 'service_specific_attribute', 'ceilometer_url', 'tenant_list_str')
+    form = MonitoringChannelForm
+
+    suit_form_tabs = (('general','Details'),)
+    actions=['delete_selected_objects']
+
+    def get_actions(self, request):
+        actions = super(MonitoringChannelAdmin, self).get_actions(request)
+        if 'delete_selected' in actions:
+            del actions['delete_selected']
+        return actions
+
+    def delete_selected_objects(self, request, queryset):
+        for obj in queryset:
+            obj.delete()
+    delete_selected_objects.short_description = "Delete Selected MonitoringChannel Objects"
+
+    def queryset(self, request):
+        return MonitoringChannel.get_tenant_objects_by_user(request.user)
+
+class SFlowServiceForm(forms.ModelForm):
+    sflow_port = forms.IntegerField(required=False)
+    sflow_api_port = forms.IntegerField(required=False)
+
+    def __init__(self,*args,**kwargs):
+        super (SFlowServiceForm,self ).__init__(*args,**kwargs)
+        if self.instance:
+            # fields for the attributes
+            self.fields['sflow_port'].initial = self.instance.sflow_port
+            self.fields['sflow_api_port'].initial = self.instance.sflow_api_port
+        if (not self.instance) or (not self.instance.pk):
+            # default fields for an 'add' form
+            self.fields['sflow_port'].initial = SFLOW_PORT
+            self.fields['sflow_api_port'].initial = SFLOW_API_PORT
+
+    def save(self, commit=True):
+        self.instance.sflow_port = self.cleaned_data.get("sflow_port")
+        self.instance.sflow_api_port = self.cleaned_data.get("sflow_api_port")
+        return super(SFlowServiceForm, self).save(commit=commit)
+
+    class Meta:
+        model = SFlowService
+
+class SFlowServiceAdmin(ReadOnlyAwareAdmin):
+    model = SFlowService
+    verbose_name = "SFlow Service"
+    verbose_name_plural = "SFlow Service"
+    list_display = ("backend_status_icon", "name", "enabled")
+    list_display_links = ('backend_status_icon', 'name', )
+    fieldsets = [(None, {'fields': ['backend_status_text', 'name','enabled','versionNumber', 'description',"view_url","sflow_port","sflow_api_port","icon_url" ], 'classes':['suit-tab suit-tab-general']})]
+    readonly_fields = ('backend_status_text', )
+    inlines = [SliceInline,ServiceAttrAsTabInline,ServicePrivilegeInline]
+    form = SFlowServiceForm
+
+    extracontext_registered_admins = True
+
+    user_readonly_fields = ["name", "enabled", "versionNumber", "description"]
+
+    suit_form_tabs =(('general', 'SFlow Service Details'),
+        ('administration', 'Administration'),
+        ('slices','Slices'),
+        ('serviceattrs','Additional Attributes'),
+        ('serviceprivileges','Privileges'),
+    )
+
+    suit_form_includes = (('sflowadmin.html', 'top', 'administration'),
+                           )
+
+    def queryset(self, request):
+        return SFlowService.get_service_objects_by_user(request.user)
+
+class SFlowTenantForm(forms.ModelForm):
+    creator = forms.ModelChoiceField(queryset=User.objects.all())
+    listening_endpoint = forms.CharField(max_length=1024, help_text="sFlow listening endpoint in udp://IP:port format")
+
+    def __init__(self,*args,**kwargs):
+        super (SFlowTenantForm,self ).__init__(*args,**kwargs)
+        self.fields['kind'].widget.attrs['readonly'] = True
+        self.fields['provider_service'].queryset = SFlowService.get_service_objects().all()
+        if self.instance:
+            # fields for the attributes
+            self.fields['creator'].initial = self.instance.creator
+            self.fields['listening_endpoint'].initial = self.instance.listening_endpoint
+        if (not self.instance) or (not self.instance.pk):
+            # default fields for an 'add' form
+            self.fields['kind'].initial = SFLOW_KIND
+            self.fields['creator'].initial = get_request().user
+            if SFlowService.get_service_objects().exists():
+               self.fields["provider_service"].initial = SFlowService.get_service_objects().all()[0]
+
+    def save(self, commit=True):
+        self.instance.creator = self.cleaned_data.get("creator")
+        self.instance.listening_endpoint = self.cleaned_data.get("listening_endpoint")
+        return super(SFlowTenantForm, self).save(commit=commit)
+
+    class Meta:
+        model = SFlowTenant
+
+class SFlowTenantAdmin(ReadOnlyAwareAdmin):
+    list_display = ('backend_status_icon', 'creator', 'listening_endpoint' )
+    list_display_links = ('backend_status_icon', 'listening_endpoint')
+    fieldsets = [ (None, {'fields': ['backend_status_text', 'kind', 'provider_service', 'subscriber_service', 'service_specific_attribute', 'listening_endpoint',
+                                     'creator'],
+                          'classes':['suit-tab suit-tab-general']})]
+    readonly_fields = ('backend_status_text', 'instance', 'service_specific_attribute')
+    inlines = [TenantAttrAsTabInline]
+    form = SFlowTenantForm
+
+    suit_form_tabs = (('general','Details'), ('tenantattrs', 'Attributes'))
+
+    def queryset(self, request):
+        return SFlowTenant.get_tenant_objects_by_user(request.user)
+
+admin.site.register(CeilometerService, CeilometerServiceAdmin)
+admin.site.register(SFlowService, SFlowServiceAdmin)
+admin.site.register(MonitoringChannel, MonitoringChannelAdmin)
+admin.site.register(SFlowTenant, SFlowTenantAdmin)
+
diff --git a/xos/onboard/ceilometer/api/tenant/ceilometer/monitoringchannel.py b/xos/onboard/ceilometer/api/tenant/ceilometer/monitoringchannel.py
new file mode 100644
index 0000000..43e1636
--- /dev/null
+++ b/xos/onboard/ceilometer/api/tenant/ceilometer/monitoringchannel.py
@@ -0,0 +1,94 @@
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+from rest_framework import serializers
+from rest_framework import generics
+from rest_framework import status
+from core.models import *
+from django.forms import widgets
+from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
+from api.xosapi_helpers import PlusModelSerializer, XOSViewSet, ReadOnlyField
+
+from services.ceilometer.models import MonitoringChannel, CeilometerService
+
+def get_default_ceilometer_service():
+    ceilometer_services = CeilometerService.get_service_objects().all()
+    if ceilometer_services:
+        return ceilometer_services[0].id
+    return None
+
+class MonitoringChannelForAPI(MonitoringChannel):
+    class Meta:
+        proxy = True
+        app_label = "ceilometer"
+
+    @property
+    def related(self):
+        related = {}
+        if self.creator:
+            related["creator"] = self.creator.username
+        if self.instance:
+            related["instance_id"] = self.instance.id
+            related["instance_name"] = self.instance.name
+            if self.instance.node:
+                related["compute_node_name"] = self.instance.node.name
+        return related
+
+class MonitoringChannelSerializer(PlusModelSerializer):
+        id = ReadOnlyField()
+        service_specific_attribute = ReadOnlyField()
+        ceilometer_url = ReadOnlyField()
+        tenant_list_str = ReadOnlyField()
+        #creator = ReadOnlyField()
+        #instance = ReadOnlyField()
+        provider_service = serializers.PrimaryKeyRelatedField(queryset=CeilometerService.get_service_objects().all(), default=get_default_ceilometer_service)
+
+        humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+        related = serializers.DictField(required=False)
+
+        #computeNodeName = serializers.SerializerMethodField("getComputeNodeName")
+
+        class Meta:
+            model = MonitoringChannelForAPI
+            fields = ('humanReadableName', 'id', 'provider_service', 'service_specific_attribute', 'ceilometer_url', 'tenant_list_str', 'related' )
+
+        def getHumanReadableName(self, obj):
+            return obj.__unicode__()
+
+        #def getComputeNodeName(self, obj):
+        #    instance = obj.instance
+        #    if not instance:
+        #        return None
+        #    return instance.node.name
+
+class MonitoringChannelSet(XOSViewSet):
+    base_name = "monitoringchannel"
+    method_name = "monitoringchannel"
+    method_kind = "viewset"
+    queryset = MonitoringChannelForAPI.get_tenant_objects().all()
+    serializer_class = MonitoringChannelSerializer
+
+    def get_queryset(self):
+        queryset = MonitoringChannelForAPI.get_tenant_objects().all()
+
+        current_user = self.request.user.username
+        if current_user is not None:
+            ids = [x.id for x in queryset if x.creator.username==current_user]
+            queryset = queryset.filter(id__in=ids)
+
+        return queryset
+
+    def create(self, request):
+        current_user = request.user.username
+        existing_obj = None
+        for obj in MonitoringChannelForAPI.get_tenant_objects().all():
+            if (obj.creator.username == current_user):
+               existing_obj = obj
+               break
+
+        if existing_obj:
+            serializer = MonitoringChannelSerializer(existing_obj)
+            headers = self.get_success_headers(serializer.data)
+            return Response( serializer.data, status=status.HTTP_200_OK )
+
+        return super(MonitoringChannelSet, self).create(request)
diff --git a/xos/onboard/ceilometer/ceilometer-onboard.yaml b/xos/onboard/ceilometer/ceilometer-onboard.yaml
new file mode 100644
index 0000000..82c955f
--- /dev/null
+++ b/xos/onboard/ceilometer/ceilometer-onboard.yaml
@@ -0,0 +1,25 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Onboard the exampleservice
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    servicecontroller#ceilometer:
+      type: tosca.nodes.ServiceController
+      properties:
+          base_url: file:///opt/xos/onboard/ceilometer/
+          # The following will concatenate with base_url automatically, if
+          # base_url is non-null.
+          models: models.py
+          admin: admin.py
+          admin_template: templates/ceilometeradmin.html, templates/sflowadmin.html
+          synchronizer: synchronizer/manifest
+          synchronizer_run: monitoring_channel_synchronizer.py
+          tosca_resource: tosca/resources/ceilometerservice.py, tosca/resources/ceilometertenant.py, tosca/resources/sflowservice.py
+          rest_tenant: subdirectory:ceilometer api/tenant/ceilometer/monitoringchannel.py
+          private_key: file:///opt/xos/key_import/monitoring_channel_rsa
+          public_key: file:///opt/xos/key_import/monitoring_channel_rsa.pub
+
diff --git a/xos/onboard/ceilometer/models.py b/xos/onboard/ceilometer/models.py
new file mode 100644
index 0000000..5285bd7
--- /dev/null
+++ b/xos/onboard/ceilometer/models.py
@@ -0,0 +1,307 @@
+from django.db import models
+from core.models import Service, PlCoreBase, Slice, Instance, Tenant, TenantWithContainer, Node, Image, User, Flavor, Subscriber
+from core.models.plcorebase import StrippedCharField
+import os
+from django.db import models, transaction
+from django.forms.models import model_to_dict
+from django.db.models import Q
+from operator import itemgetter, attrgetter, methodcaller
+import traceback
+from xos.exceptions import *
+from core.models import SlicePrivilege, SitePrivilege
+from sets import Set
+from urlparse import urlparse
+
+CEILOMETER_KIND = "ceilometer"
+
+class CeilometerService(Service):
+    KIND = CEILOMETER_KIND
+
+    class Meta:
+        app_label = "ceilometer"
+        verbose_name = "Ceilometer Service"
+        proxy = True
+
+    @property
+    def ceilometer_pub_sub_url(self):
+        return self.get_attribute("ceilometer_pub_sub_url", None)
+
+    @ceilometer_pub_sub_url.setter
+    def ceilometer_pub_sub_url(self, value):
+        self.set_attribute("ceilometer_pub_sub_url", value)
+
+class MonitoringChannel(TenantWithContainer):   # aka 'CeilometerTenant'
+    class Meta:
+        proxy = True
+
+    KIND = CEILOMETER_KIND
+    LOOK_FOR_IMAGES=[ #"trusty-server-multi-nic-docker", # CloudLab
+                      "ceilometer-trusty-server-multi-nic",
+                      #"trusty-server-multi-nic",
+                    ]
+
+
+    sync_attributes = ("private_ip", "private_mac",
+                       "ceilometer_ip", "ceilometer_mac",
+                       "nat_ip", "nat_mac", "ceilometer_port",)
+
+    default_attributes = {}
+    def __init__(self, *args, **kwargs):
+        ceilometer_services = CeilometerService.get_service_objects().all()
+        if ceilometer_services:
+            self._meta.get_field("provider_service").default = ceilometer_services[0].id
+        super(MonitoringChannel, self).__init__(*args, **kwargs)
+        self.set_attribute("use_same_instance_for_multiple_tenants", True)
+
+    def can_update(self, user):
+        #Allow creation of this model instances for non-admin users also
+        return True
+
+    def save(self, *args, **kwargs):
+        if not self.creator:
+            if not getattr(self, "caller", None):
+                # caller must be set when creating a monitoring channel since it creates a slice
+                raise XOSProgrammingError("MonitoringChannel's self.caller was not set")
+            self.creator = self.caller
+            if not self.creator:
+                raise XOSProgrammingError("MonitoringChannel's self.creator was not set")
+
+        if self.pk is None:
+            #Allow only one monitoring channel per user
+            channel_count = sum ( [1 for channel in MonitoringChannel.objects.filter(kind=CEILOMETER_KIND) if (channel.creator == self.creator)] )
+            if channel_count > 0:
+                raise XOSValidationError("Already %s channels exist for user Can only create max 1 MonitoringChannel instance per user" % str(channel_count))
+
+        super(MonitoringChannel, self).save(*args, **kwargs)
+        model_policy_monitoring_channel(self.pk)
+
+    def delete(self, *args, **kwargs):
+        self.cleanup_container()
+        super(MonitoringChannel, self).delete(*args, **kwargs)
+
+    @property
+    def addresses(self):
+        if (not self.id) or (not self.instance):
+            return {}
+
+        addresses = {}
+        for ns in self.instance.ports.all():
+            if "private" in ns.network.name.lower():
+                addresses["private"] = (ns.ip, ns.mac)
+            elif ("nat" in ns.network.name.lower()) or ("management" in ns.network.name.lower()):
+                addresses["nat"] = (ns.ip, ns.mac)
+            #TODO: Do we need this client_access_network. Revisit in VTN context
+            #elif "ceilometer_client_access" in ns.network.labels.lower():
+            #    addresses["ceilometer"] = (ns.ip, ns.mac)
+        return addresses
+
+    @property
+    def nat_ip(self):
+        return self.addresses.get("nat", (None, None))[0]
+
+    @property
+    def nat_mac(self):
+        return self.addresses.get("nat", (None, None))[1]
+
+    @property
+    def private_ip(self):
+        return self.addresses.get("nat", (None, None))[0]
+
+    @property
+    def private_mac(self):
+        return self.addresses.get("nat", (None, None))[1]
+
+    @property
+    def ceilometer_ip(self):
+        return self.addresses.get("ceilometer", (None, None))[0]
+
+    @property
+    def ceilometer_mac(self):
+        return self.addresses.get("ceilometer", (None, None))[1]
+
+    @property
+    def site_tenant_list(self):
+        tenant_ids = Set()
+        for sp in SitePrivilege.objects.filter(user=self.creator):
+            site = sp.site
+            for cs in site.controllersite.all():
+               if cs.tenant_id:
+                   tenant_ids.add(cs.tenant_id)
+        return tenant_ids
+
+    @property
+    def slice_tenant_list(self):
+        tenant_ids = Set()
+        for sp in SlicePrivilege.objects.filter(user=self.creator):
+            slice = sp.slice
+            for cs in slice.controllerslices.all():
+               if cs.tenant_id:
+                   tenant_ids.add(cs.tenant_id)
+        for slice in Slice.objects.filter(creator=self.creator):
+            for cs in slice.controllerslices.all():
+                if cs.tenant_id:
+                    tenant_ids.add(cs.tenant_id)
+        if self.creator.is_admin:
+            #TODO: Ceilometer publishes the SDN meters without associating to any tenant IDs.
+            #For now, ceilometer code is changed to pusblish all such meters with tenant
+            #id as "default_admin_tenant". Here add that default tenant as authroized tenant_id
+            #for all admin users. 
+            tenant_ids.add("default_admin_tenant")
+        return tenant_ids
+
+    @property
+    def tenant_list(self):
+        return self.slice_tenant_list | self.site_tenant_list
+
+    @property
+    def tenant_list_str(self):
+        return ", ".join(self.tenant_list)
+
+    @property
+    def ceilometer_port(self):
+        # TODO: Find a better logic to choose unique ceilometer port number for each instance 
+        if not self.id:
+            return None
+        return 8888+self.id
+
+    @property
+    def ceilometer_url(self):
+        if not self.private_ip:
+            return None
+        return "http://" + self.private_ip + ":" + str(self.ceilometer_port) + "/"
+
+def model_policy_monitoring_channel(pk):
+    # TODO: this should be made in to a real model_policy
+    with transaction.atomic():
+        mc = MonitoringChannel.objects.select_for_update().filter(pk=pk)
+        if not mc:
+            return
+        mc = mc[0]
+        mc.manage_container()
+
+
+SFLOW_KIND = "sflow"
+SFLOW_PORT = 6343
+SFLOW_API_PORT = 33333
+
+class SFlowService(Service):
+    KIND = SFLOW_KIND
+
+    class Meta:
+        app_label = "ceilometer"
+        verbose_name = "sFlow Collection Service"
+        proxy = True
+
+    default_attributes = {"sflow_port": SFLOW_PORT, "sflow_api_port": SFLOW_API_PORT}
+
+    sync_attributes = ("sflow_port", "sflow_api_port",)
+
+    @property
+    def sflow_port(self):
+        return self.get_attribute("sflow_port", self.default_attributes["sflow_port"])
+
+    @sflow_port.setter
+    def sflow_port(self, value):
+        self.set_attribute("sflow_port", value)
+
+    @property
+    def sflow_api_port(self):
+        return self.get_attribute("sflow_api_port", self.default_attributes["sflow_api_port"])
+
+    @sflow_api_port.setter
+    def sflow_api_port(self, value):
+        self.set_attribute("sflow_api_port", value)
+
+    def get_instance(self):
+        if self.slices.exists():
+            slice = self.slices.all()[0]
+            if slice.instances.exists():
+                return slice.instances.all()[0]
+
+        return None
+
+    @property
+    def sflow_api_url(self):
+        if not self.get_instance():
+            return None
+        return "http://" + self.get_instance().get_ssh_ip() + ":" + str(self.sflow_api_port) + "/"
+
+class SFlowTenant(Tenant): 
+    class Meta:
+        proxy = True
+
+    KIND = SFLOW_KIND
+
+    sync_attributes = ("listening_endpoint", )
+
+    default_attributes = {}
+    def __init__(self, *args, **kwargs):
+        sflow_services = SFlowService.get_service_objects().all()
+        if sflow_services:
+            self._meta.get_field("provider_service").default = sflow_services[0].id
+        super(SFlowTenant, self).__init__(*args, **kwargs)
+
+    @property
+    def creator(self):
+        from core.models import User
+        if getattr(self, "cached_creator", None):
+            return self.cached_creator
+        creator_id=self.get_attribute("creator_id")
+        if not creator_id:
+            return None
+        users=User.objects.filter(id=creator_id)
+        if not users:
+            return None
+        user=users[0]
+        self.cached_creator = users[0]
+        return user
+
+    @creator.setter
+    def creator(self, value):
+        if value:
+            value = value.id
+        if (value != self.get_attribute("creator_id", None)):
+            self.cached_creator=None
+        self.set_attribute("creator_id", value)
+
+    @property
+    def listening_endpoint(self):
+        return self.get_attribute("listening_endpoint", None)
+
+    @listening_endpoint.setter
+    def listening_endpoint(self, value):
+        if urlparse(value).scheme != 'udp':
+            raise XOSProgrammingError("SFlowTenant: Only UDP listening endpoint URLs are accepted...valid syntax is: udp://ip:port")
+        self.set_attribute("listening_endpoint", value)
+
+    def save(self, *args, **kwargs):
+        if not self.creator:
+            if not getattr(self, "caller", None):
+                # caller must be set when creating a SFlow tenant since it creates a slice
+                raise XOSProgrammingError("SFlowTenant's self.caller was not set")
+            self.creator = self.caller
+            if not self.creator:
+                raise XOSProgrammingError("SFlowTenant's self.creator was not set")
+
+        if not self.listening_endpoint:
+            raise XOSProgrammingError("SFlowTenant's self.listening_endpoint was not set")
+
+        if self.pk is None:
+            #Allow only one sflow channel per user and listening_endpoint
+            channel_count = sum ( [1 for channel in SFlowTenant.objects.filter(kind=SFLOW_KIND) if ((channel.creator == self.creator) and (channel.listening_endpoint == self.listening_endpoint))] )
+            if channel_count > 0:
+                raise XOSValidationError("Already %s sflow channels exist for user Can only create max 1 tenant per user and listening endpoint" % str(channel_count))
+
+        super(SFlowTenant, self).save(*args, **kwargs)
+
+    def delete(self, *args, **kwargs):
+        super(MonitoringChannel, self).delete(*args, **kwargs)
+
+    @property
+    def authorized_resource_list(self):
+        return ['all']
+
+    @property
+    def authorized_resource_list_str(self):
+        return ", ".join(self.authorized_resource_list)
+
diff --git a/xos/onboard/ceilometer/synchronizer/files/docker.list b/xos/onboard/ceilometer/synchronizer/files/docker.list
new file mode 100644
index 0000000..0ee9ae0
--- /dev/null
+++ b/xos/onboard/ceilometer/synchronizer/files/docker.list
@@ -0,0 +1 @@
+deb https://get.docker.com/ubuntu docker main
diff --git a/xos/onboard/ceilometer/synchronizer/files/vm-resolv.conf b/xos/onboard/ceilometer/synchronizer/files/vm-resolv.conf
new file mode 100644
index 0000000..cae093a
--- /dev/null
+++ b/xos/onboard/ceilometer/synchronizer/files/vm-resolv.conf
@@ -0,0 +1 @@
+nameserver 8.8.8.8
diff --git a/xos/onboard/ceilometer/synchronizer/manifest b/xos/onboard/ceilometer/synchronizer/manifest
new file mode 100644
index 0000000..c679225
--- /dev/null
+++ b/xos/onboard/ceilometer/synchronizer/manifest
@@ -0,0 +1,26 @@
+templates/Dockerfile.monitoring_channel
+templates/ceilometer_proxy_config.j2
+templates/Dockerfile.sflowpubsub
+templates/sflow_pub_sub/sample_sflow_pub_sub.conf_sample
+templates/sflow_pub_sub/README
+templates/sflow_pub_sub/sflow_sub_records.py
+templates/sflow_pub_sub/start_sflow_pub_sub
+templates/sflow_pub_sub/sflow_pub_sub_main.py
+templates/sflow_pub_sub/sflow_pub_sub_config.j2
+templates/start-monitoring-channel.sh.j2
+templates/monitoring-channel.conf.j2
+templates/ceilometer_proxy_server.py
+templates/start_ceilometer_proxy
+manifest
+monitoring_channel_synchronizer_config
+steps/sync_sflowtenant.yaml
+steps/sync_sflowtenant.py
+steps/sync_monitoringchannel.yaml
+steps/sync_monitoringchannel.py
+steps/sync_sflowservice.yaml
+steps/sync_sflowservice.py
+files/vm-resolv.conf
+files/docker.list
+model-deps
+supervisor/monitoring_channel_observer.conf
+monitoring_channel_synchronizer.py
diff --git a/xos/onboard/ceilometer/synchronizer/model-deps b/xos/onboard/ceilometer/synchronizer/model-deps
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/xos/onboard/ceilometer/synchronizer/model-deps
@@ -0,0 +1 @@
+{}
diff --git a/xos/onboard/ceilometer/synchronizer/monitoring_channel_synchronizer.py b/xos/onboard/ceilometer/synchronizer/monitoring_channel_synchronizer.py
new file mode 100755
index 0000000..84bec4f
--- /dev/null
+++ b/xos/onboard/ceilometer/synchronizer/monitoring_channel_synchronizer.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+# This imports and runs ../../xos-observer.py
+
+import importlib
+import os
+import sys
+observer_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),"../../synchronizers/base")
+sys.path.append(observer_path)
+mod = importlib.import_module("xos-synchronizer")
+mod.main()
diff --git a/xos/onboard/ceilometer/synchronizer/monitoring_channel_synchronizer_config b/xos/onboard/ceilometer/synchronizer/monitoring_channel_synchronizer_config
new file mode 100644
index 0000000..8c6578f
--- /dev/null
+++ b/xos/onboard/ceilometer/synchronizer/monitoring_channel_synchronizer_config
@@ -0,0 +1,41 @@
+
+[plc]
+name=plc
+deployment=VICCI
+
+[db]
+name=xos
+user=postgres
+password=password
+host=localhost
+port=5432
+
+[api]
+host=128.112.171.237
+port=8000
+ssl_key=None
+ssl_cert=None
+ca_ssl_cert=None
+ratelimit_enabled=0
+omf_enabled=0
+mail_support_address=support@localhost
+nova_enabled=True
+
+[observer]
+name=monitoring_channel
+dependency_graph=/opt/xos/synchronizers/monitoring_channel/model-deps
+steps_dir=/opt/xos/synchronizers/monitoring_channel/steps
+sys_dir=/opt/xos/synchronizers/monitoring_channel/sys
+deleters_dir=/opt/xos/synchronizers/monitoring_channel/deleters
+log_file=console
+driver=None
+pretend=False
+backoff_disabled=True
+save_ansible_output=True
+# set proxy_ssh to false on cloudlab
+proxy_ssh=False
+full_setup=True
+
+[feefie]
+client_id='vicci_dev_central'
+user_id='pl'
diff --git a/xos/onboard/ceilometer/synchronizer/steps/sync_monitoringchannel.py b/xos/onboard/ceilometer/synchronizer/steps/sync_monitoringchannel.py
new file mode 100644
index 0000000..2c0ba10
--- /dev/null
+++ b/xos/onboard/ceilometer/synchronizer/steps/sync_monitoringchannel.py
@@ -0,0 +1,84 @@
+import hashlib
+import os
+import socket
+import sys
+import base64
+import time
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.syncstep import SyncStep
+from synchronizers.base.ansible import run_template_ssh
+from synchronizers.base.SyncInstanceUsingAnsible import SyncInstanceUsingAnsible
+from core.models import Service, Slice
+from services.ceilometer.models import CeilometerService, MonitoringChannel
+from xos.logger import Logger, logging
+
+parentdir = os.path.join(os.path.dirname(__file__),"..")
+sys.path.insert(0,parentdir)
+
+logger = Logger(level=logging.INFO)
+
+class SyncMonitoringChannel(SyncInstanceUsingAnsible):
+    provides=[MonitoringChannel]
+    observes=MonitoringChannel
+    requested_interval=0
+    template_name = "sync_monitoringchannel.yaml"
+    service_key_name = "/opt/xos/synchronizers/monitoring_channel/monitoring_channel_private_key"
+
+    def __init__(self, *args, **kwargs):
+        super(SyncMonitoringChannel, self).__init__(*args, **kwargs)
+
+    def fetch_pending(self, deleted):
+        if (not deleted):
+            objs = MonitoringChannel.get_tenant_objects().filter(Q(enacted__lt=F('updated')) | Q(enacted=None),Q(lazy_blocked=False))
+        else:
+            objs = MonitoringChannel.get_deleted_tenant_objects()
+
+        return objs
+
+    def get_extra_attributes(self, o):
+        # This is a place to include extra attributes. In the case of Monitoring Channel, we need to know
+        #   1) Allowed tenant ids
+        #   2) Ceilometer API service endpoint URL if running externally
+        #   3) Credentials to access Ceilometer API service
+
+        ceilometer_services = CeilometerService.get_service_objects().filter(id=o.provider_service.id)
+        if not ceilometer_services:
+            raise "No associated Ceilometer service"
+        ceilometer_service = ceilometer_services[0]
+        ceilometer_pub_sub_url = ceilometer_service.ceilometer_pub_sub_url
+        if not ceilometer_pub_sub_url:
+            ceilometer_pub_sub_url = ''
+        instance = self.get_instance(o)
+
+        try:
+            full_setup = Config().observer_full_setup
+        except:
+            full_setup = True
+
+        fields = {"unique_id": o.id,
+                  "allowed_tenant_ids": o.tenant_list,
+                  "auth_url":instance.controller.auth_url,
+                  "admin_user":instance.controller.admin_user,
+                  "admin_password":instance.controller.admin_password,
+                  "admin_tenant":instance.controller.admin_tenant,
+                  "ceilometer_pub_sub_url": ceilometer_pub_sub_url,
+                  "full_setup": full_setup}
+
+        return fields
+
+    def run_playbook(self, o, fields):
+        #ansible_hash = hashlib.md5(repr(sorted(fields.items()))).hexdigest()
+        #quick_update = (o.last_ansible_hash == ansible_hash)
+
+        #if quick_update:
+        #    logger.info("quick_update triggered; skipping ansible recipe")
+        #else:
+        super(SyncMonitoringChannel, self).run_playbook(o, fields)
+
+        #o.last_ansible_hash = ansible_hash
+
+    def map_delete_inputs(self, o):
+        fields = {"unique_id": o.id,
+                  "delete": True}
+        return fields
diff --git a/xos/onboard/ceilometer/synchronizer/steps/sync_monitoringchannel.yaml b/xos/onboard/ceilometer/synchronizer/steps/sync_monitoringchannel.yaml
new file mode 100644
index 0000000..ca72c5f
--- /dev/null
+++ b/xos/onboard/ceilometer/synchronizer/steps/sync_monitoringchannel.yaml
@@ -0,0 +1,145 @@
+---
+- hosts: {{ instance_name }}
+  gather_facts: False
+  connection: ssh
+  user: ubuntu
+  sudo: yes
+  vars:
+      unique_id: {{ unique_id }}
+      auth_url: {{ auth_url }}
+      admin_user: {{ admin_user }}
+      admin_password: {{ admin_password }}
+      admin_tenant: {{ admin_tenant }}
+      shared_lan_ip: {{ private_ip }}
+      shared_lan_mac: {{ private_mac }}
+      headnode_flat_lan_ip: {{ rabbit_host }}
+      ceilometer_client_acess_ip: {{ ceilometer_ip }}
+      ceilometer_client_acess_mac: {{ ceilometer_mac }}
+      ceilometer_host_port: {{ ceilometer_port }}
+      ceilometer_pub_sub_url: {{ ceilometer_pub_sub_url }}
+      allowed_tenant_ids:
+        {% for allowed_tenant_id in allowed_tenant_ids %}
+        - {{ allowed_tenant_id }}
+        {% endfor %}
+
+  tasks:
+{% if delete %}
+  - name: Remove tenant
+# FIXME: Adding dummy template action to avoid "action attribute missing in task" error
+    template: src=/opt/xos/synchronizers/monitoring_channel/templates/ceilometer_proxy_config.j2 dest=/usr/local/share/monitoring-channel-{{ unique_id }}_ceilometer_proxy_config mode=0777
+    notify:
+     - stop monitoring-channel
+     - remove container
+{% else %}
+{% if full_setup %}
+#  - name: Docker repository
+#    copy: src=/opt/xos/synchronizers/monitoring_channel/files/docker.list
+#      dest=/etc/apt/sources.list.d/docker.list
+#
+#  - name: Import the repository key
+#    apt_key: keyserver=keyserver.ubuntu.com id=36A1D7869245C8950F966E92D8576A8BA88D21E9
+#
+#  - name: install Docker
+#    apt: name=lxc-docker state=present update_cache=yes
+#
+#  - name: install python-setuptools
+#    apt: name=python-setuptools state=present
+#
+#  - name: install pip
+#    easy_install: name=pip
+#
+#  - name: install docker-py
+#    pip: name=docker-py version=0.5.3
+#
+#  - name: install Pipework
+#    get_url: url=https://raw.githubusercontent.com/jpetazzo/pipework/master/pipework
+#       dest=/usr/local/bin/pipework
+#       mode=0755
+#
+#  - name: Disable resolvconf service
+#    shell: service resolvconf stop
+#    shell: echo manual > /etc/init/resolvconf.override
+#    shell: rm -f /etc/resolv.conf
+#
+#  - name: Install resolv.conf
+#    copy: src=/opt/xos/synchronizers/monitoring_channel/files/vm-resolv.conf
+#      dest=/etc/resolv.conf
+{% endif %}
+
+# FIXME: Temporary workaround to delete the monitoring-channel_ceilometer_proxy_config file always 
+# to trigger ansible notify handlers in the following task. 
+# Due to some issue, ansible "changed" flag is set to false even though there is a change of 
+# ceilometer configuration file, because of which the configuration change is not reflecting in 
+# ceilometer containers 
+#  - file: path=/usr/local/share/monitoring-channel-{{ unique_id }}_ceilometer_proxy_config state=absent
+
+  - name: ceilometer proxy config
+    template: src=/opt/xos/synchronizers/monitoring_channel/templates/ceilometer_proxy_config.j2 dest=/usr/local/share/monitoring-channel-{{ unique_id }}_ceilometer_proxy_config mode=0777
+    notify:
+     - copy ceilo-config-file
+     - restart monitoring-channel container
+#     - stop monitoring-channel
+#     - remove container
+#     - start monitoring-channel
+
+  - name: Monitoring channel upstart
+    template: src=/opt/xos/synchronizers/monitoring_channel/templates/monitoring-channel.conf.j2 dest=/etc/init/monitoring-channel-{{ unique_id }}.conf
+
+  - name: Monitoring channel startup script
+    template: src=/opt/xos/synchronizers/monitoring_channel/templates/start-monitoring-channel.sh.j2 dest=/usr/local/sbin/start-monitoring-channel-{{ unique_id }}.sh mode=0755
+    notify:
+#    - restart monitoring-channel
+     - stop monitoring-channel
+     - remove container
+     - start monitoring-channel
+
+#  - name: Start monitoring-channel container
+#    docker:
+#      docker_api_version: "1.18"
+#      name: monitoring-channel-{{ unique_id }}
+#      # was: reloaded
+#      state: running
+#      image: srikanthvavila/monitoring-channel
+#      expose:
+#      - 8000
+#      ports:
+#      - "{{ ceilometer_port }}:8000"
+#      volumes:
+#      - /usr/local/share/monitoring-channel-{{ unique_id }}_ceilometer_proxy_config:/usr/local/share/ceilometer_proxy_config
+#
+#  - name: Get Docker IP
+#    #TODO: copy dockerip.sh to monitoring service synchronizer
+#    script: /opt/xos/synchronizers/onos/scripts/dockerip.sh monitoring-channel-{{ unique_id }}
+#    register: dockerip
+#
+#  - name: Wait for Monitoring channel to come up
+#    wait_for:
+#      host={{ '{{' }} dockerip.stdout {{ '}}' }}
+#      port={{ '{{' }} item {{ '}}' }}
+#      state=present
+#    with_items:
+#    - {{ ceilometer_port }}
+# These are samples, not necessary for correct function of demo
+
+  - name: Make sure Monitoring channel service is running
+    service: name=monitoring-channel-{{ unique_id }} state=started
+{% endif %}
+
+  handlers:
+  - name: copy ceilo-config-file
+    shell: docker cp /usr/local/share/monitoring-channel-{{ unique_id }}_ceilometer_proxy_config monitoring-channel-{{ unique_id }}:/usr/local/share/ceilometer_proxy_config
+
+  - name: restart monitoring-channel container
+    shell: docker restart monitoring-channel-{{ unique_id }}
+
+  - name: restart monitoring-channel
+    shell: service monitoring-channel-{{ unique_id }} stop; sleep 1; service monitoring-channel-{{ unique_id }} start
+
+  - name: stop monitoring-channel
+    service: name=monitoring-channel-{{ unique_id }} state=stopped
+
+  - name: remove container
+    docker: name=monitoring-channel-{{ unique_id }} state=absent image=monitoring-channel
+
+  - name: start monitoring-channel
+    service: name=monitoring-channel-{{ unique_id }} state=started
diff --git a/xos/onboard/ceilometer/synchronizer/steps/sync_sflowservice.py b/xos/onboard/ceilometer/synchronizer/steps/sync_sflowservice.py
new file mode 100644
index 0000000..154c5ab
--- /dev/null
+++ b/xos/onboard/ceilometer/synchronizer/steps/sync_sflowservice.py
@@ -0,0 +1,74 @@
+import hashlib
+import os
+import socket
+import sys
+import base64
+import time
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.syncstep import SyncStep
+from synchronizers.base.ansible import run_template_ssh
+from synchronizers.base.SyncInstanceUsingAnsible import SyncInstanceUsingAnsible
+from core.models import Service, Slice
+from services.ceilometer.models import SFlowService
+from xos.logger import Logger, logging
+
+# hpclibrary will be in steps/..
+parentdir = os.path.join(os.path.dirname(__file__),"..")
+sys.path.insert(0,parentdir)
+
+logger = Logger(level=logging.INFO)
+
+class SyncSFlowService(SyncInstanceUsingAnsible):
+    provides=[SFlowService]
+    observes=SFlowService
+    requested_interval=0
+    template_name = "sync_sflowservice.yaml"
+    service_key_name = "/opt/xos/synchronizers/monitoring_channel/monitoring_channel_private_key"
+
+    def __init__(self, *args, **kwargs):
+        super(SyncSFlowService, self).__init__(*args, **kwargs)
+
+    def fetch_pending(self, deleted):
+        if (not deleted):
+            objs = SFlowService.get_service_objects().filter(Q(enacted__lt=F('updated')) | Q(enacted=None),Q(lazy_blocked=False))
+        else:
+            objs = SFlowService.get_deleted_service_objects()
+
+        return objs
+
+    def get_instance(self, o):
+        # We assume the ONOS service owns a slice, so pick one of the instances
+        # inside that slice to sync to.
+
+        serv = o
+
+        if serv.slices.exists():
+            slice = serv.slices.all()[0]
+            if slice.instances.exists():
+                return slice.instances.all()[0]
+
+        return None
+
+    def get_extra_attributes(self, o):
+        fields={}
+        fields["instance_hostname"] = self.get_instance(o).instance_name.replace("_","-")
+        fields["sflow_port"] = o.sflow_port
+        fields["sflow_api_port"] = o.sflow_api_port
+        fields["sflow_container"] = "sflowpubsub"
+        return fields
+
+    def sync_fields(self, o, fields):
+        # the super causes the playbook to be run
+        super(SyncSFlowService, self).sync_fields(o, fields)
+
+    def run_playbook(self, o, fields):
+        instance = self.get_instance(o)
+        if (instance.isolation=="container"):
+            # If the instance is already a container, then we don't need to
+            # install ONOS.
+            return
+        super(SyncSFlowService, self).run_playbook(o, fields)
+
+    def delete_record(self, m):
+        pass
diff --git a/xos/onboard/ceilometer/synchronizer/steps/sync_sflowservice.yaml b/xos/onboard/ceilometer/synchronizer/steps/sync_sflowservice.yaml
new file mode 100644
index 0000000..8d853a2
--- /dev/null
+++ b/xos/onboard/ceilometer/synchronizer/steps/sync_sflowservice.yaml
@@ -0,0 +1,74 @@
+---
+- hosts: {{ instance_name }}
+  gather_facts: False
+  connection: ssh
+  user: ubuntu
+  sudo: yes
+  vars:
+     sflow_port: {{ sflow_port }}
+     sflow_api_port: {{ sflow_api_port }}
+
+  tasks:
+
+  - name: Fix /etc/hosts
+    lineinfile:
+      dest=/etc/hosts
+      regexp="127.0.0.1 localhost"
+      line="127.0.0.1 localhost {{ instance_hostname }}"
+
+  - name: Add repo key
+    apt_key:
+      keyserver=hkp://pgp.mit.edu:80
+      id=58118E89F3A912897C070ADBF76221572C52609D
+
+  - name: Install Docker repo
+    apt_repository:
+      repo="deb https://apt.dockerproject.org/repo ubuntu-trusty main"
+      state=present
+
+  - name: Install Docker
+    apt:
+      name={{ '{{' }} item {{ '}}' }}
+      state=latest
+      update_cache=yes
+    with_items:
+    - docker-engine
+    - python-pip
+    - python-httplib2
+
+  - name: Install docker-py
+    pip:
+      name=docker-py
+      state=latest
+
+  - name: sflow pub-sub config
+    template: src=/opt/xos/synchronizers/monitoring_channel/templates/sflow_pub_sub/sflow_pub_sub_config.j2 dest=/usr/local/share/sflow_pub_sub.conf mode=0777
+
+  - name: Start SFLOW pub-sub container
+    docker:
+      docker_api_version: "1.18"
+      name: {{ sflow_container }}
+      # was: reloaded
+      state: running
+      image: srikanthvavila/sflowpubsub
+      expose:
+      - {{ sflow_api_port }}
+      - {{ sflow_port }}/udp
+      ports:
+      - "{{ sflow_port }}:{{ sflow_port }}/udp"
+      - "{{ sflow_api_port }}:{{ sflow_api_port }}"
+      volumes:
+      - /usr/local/share/sflow_pub_sub.conf:/usr/local/share/sflow_pub_sub/sflow_pub_sub.conf
+
+  - name: Get Docker IP
+    #TODO: copy dockerip.sh to monitoring service synchronizer
+    script: /opt/xos/synchronizers/onos/scripts/dockerip.sh {{ sflow_container }}
+    register: dockerip
+
+  - name: Wait for SFlow service to come up
+    wait_for:
+      host={{ '{{' }} dockerip.stdout {{ '}}' }}
+      port={{ '{{' }} item {{ '}}' }}
+      state=present
+    with_items:
+    - {{ sflow_api_port }}
diff --git a/xos/onboard/ceilometer/synchronizer/steps/sync_sflowtenant.py b/xos/onboard/ceilometer/synchronizer/steps/sync_sflowtenant.py
new file mode 100644
index 0000000..a15fa54
--- /dev/null
+++ b/xos/onboard/ceilometer/synchronizer/steps/sync_sflowtenant.py
@@ -0,0 +1,82 @@
+import hashlib
+import os
+import socket
+import socket
+import sys
+import base64
+import time
+import re
+import json
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.syncstep import SyncStep
+from synchronizers.base.ansible import run_template_ssh
+from synchronizers.base.SyncInstanceUsingAnsible import SyncInstanceUsingAnsible
+from core.models import Service, Slice, ControllerSlice, ControllerUser
+from services.ceilometer.models import SFlowService, SFlowTenant
+from xos.logger import Logger, logging
+
+# hpclibrary will be in steps/..
+parentdir = os.path.join(os.path.dirname(__file__),"..")
+sys.path.insert(0,parentdir)
+
+logger = Logger(level=logging.INFO)
+
+class SyncSFlowTenant(SyncInstanceUsingAnsible):
+    provides=[SFlowTenant]
+    observes=SFlowTenant
+    requested_interval=0
+    template_name = "sync_sflowtenant.yaml"
+    service_key_name = "/opt/xos/synchronizers/monitoring_channel/monitoring_channel_private_key"
+
+    def __init__(self, *args, **kwargs):
+        super(SyncSFlowTenant, self).__init__(*args, **kwargs)
+
+    def fetch_pending(self, deleted):
+        if (not deleted):
+            objs = SFlowTenant.get_tenant_objects().filter(Q(enacted__lt=F('updated')) | Q(enacted=None),Q(lazy_blocked=False))
+        else:
+            objs = SFlowTenant.get_deleted_tenant_objects()
+
+        return objs
+
+    def get_sflow_service(self, o):
+        sflows = SFlowService.get_service_objects().filter(id=o.provider_service.id)
+        if not sflows:
+           raise "No associated SFlow service"
+
+        return sflows[0]
+
+    def get_instance(self, o):
+        # We assume the SFlow service owns a slice, so pick one of the instances
+        # inside that slice to sync to.
+
+        serv = self.get_sflow_service(o)
+
+        if serv.slices.exists():
+            slice = serv.slices.all()[0]
+            if slice.instances.exists():
+                return slice.instances.all()[0]
+
+        return None
+
+    def get_extra_attributes(self, o):
+        instance = self.get_instance(o)
+
+        fields={}
+        fields["sflow_api_base_url"] = self.get_sflow_service(o).sflow_api_url
+        fields["sflow_api_port"] = self.get_sflow_service(o).sflow_api_port
+        fields["listening_endpoint"] = o.listening_endpoint
+        fields["sflow_container"] = "sflowpubsub"
+
+        return fields
+
+    def sync_fields(self, o, fields):
+        # the super causes the playbook to be run
+        super(SyncSFlowTenant, self).sync_fields(o, fields)
+
+    def run_playbook(self, o, fields):
+        super(SyncSFlowTenant, self).run_playbook(o, fields)
+
+    def delete_record(self, m):
+        pass
diff --git a/xos/onboard/ceilometer/synchronizer/steps/sync_sflowtenant.yaml b/xos/onboard/ceilometer/synchronizer/steps/sync_sflowtenant.yaml
new file mode 100644
index 0000000..701ce5c
--- /dev/null
+++ b/xos/onboard/ceilometer/synchronizer/steps/sync_sflowtenant.yaml
@@ -0,0 +1,28 @@
+---
+- hosts: {{ instance_name }}
+  gather_facts: False
+  connection: ssh
+  user: {{ username }}
+  sudo: yes
+
+  tasks:
+
+  - name: Get Docker IP
+    #TODO: copy dockerip.sh to monitoring service synchronizer
+    script: /opt/xos/synchronizers/onos/scripts/dockerip.sh {{ sflow_container }}
+    register: sflowserviceaddr
+
+  - name: Wait for SFlow service to come up
+    wait_for:
+      host={{ '{{' }} sflowserviceaddr.stdout {{ '}}' }}
+      port={{ '{{' }} item {{ '}}' }}
+      state=present
+    with_items:
+    - {{ sflow_api_port }}
+
+  - name: Invoke SFlow service REST API to subscribe
+    uri:
+      url: http://{{ '{{' }} sflowserviceaddr.stdout {{ '}}' }}:{{ sflow_api_port }}/subscribe
+      body: "{{ listening_endpoint }}"
+      body_format: raw
+      method: POST
diff --git a/xos/onboard/ceilometer/synchronizer/supervisor/monitoring_channel_observer.conf b/xos/onboard/ceilometer/synchronizer/supervisor/monitoring_channel_observer.conf
new file mode 100644
index 0000000..1c2dd42
--- /dev/null
+++ b/xos/onboard/ceilometer/synchronizer/supervisor/monitoring_channel_observer.conf
@@ -0,0 +1,2 @@
+[program:monitoring_channel_observer]
+command=python /opt/xos/synchronizers/monitoring_channel/monitoring_channel_synchronizer.py -C /opt/xos/synchronizers/monitoring_channel/monitoring_channel_synchronizer_config
diff --git a/xos/onboard/ceilometer/synchronizer/templates/Dockerfile.monitoring_channel b/xos/onboard/ceilometer/synchronizer/templates/Dockerfile.monitoring_channel
new file mode 100644
index 0000000..45defb8
--- /dev/null
+++ b/xos/onboard/ceilometer/synchronizer/templates/Dockerfile.monitoring_channel
@@ -0,0 +1,26 @@
+FROM       ubuntu:14.04.2
+MAINTAINER Andy Bavier <acb@cs.princeton.edu>
+
+# XXX Workaround for docker bug:
+# https://github.com/docker/docker/issues/6345
+# Kernel 3.15 breaks docker, uss the line below as a workaround
+# until there is a fix
+RUN ln -s -f /bin/true /usr/bin/chfn
+# XXX End workaround
+
+# Install.
+RUN apt-get update && apt-get install -y \
+    python-pip \
+    python-dev
+
+RUN pip install web.py
+RUN pip install wsgilog
+RUN pip install python-ceilometerclient
+RUN mkdir -p /usr/local/share
+ADD ceilometer_proxy_server.py /usr/local/share/
+RUN chmod +x /usr/local/share/ceilometer_proxy_server.py
+ADD start_ceilometer_proxy /usr/local/sbin/
+RUN chmod +x /usr/local/sbin/start_ceilometer_proxy
+EXPOSE 8000
+WORKDIR /usr/local/share
+CMD /usr/local/sbin/start_ceilometer_proxy
diff --git a/xos/onboard/ceilometer/synchronizer/templates/Dockerfile.sflowpubsub b/xos/onboard/ceilometer/synchronizer/templates/Dockerfile.sflowpubsub
new file mode 100644
index 0000000..c9025ee
--- /dev/null
+++ b/xos/onboard/ceilometer/synchronizer/templates/Dockerfile.sflowpubsub
@@ -0,0 +1,22 @@
+FROM       ubuntu:14.04.2
+MAINTAINER Andy Bavier <acb@cs.princeton.edu>
+
+# XXX Workaround for docker bug:
+# https://github.com/docker/docker/issues/6345
+# Kernel 3.15 breaks docker, uss the line below as a workaround
+# until there is a fix
+RUN ln -s -f /bin/true /usr/bin/chfn
+# XXX End workaround
+
+# Install.
+RUN apt-get update && apt-get install -y \
+    python-pip \
+    python-dev
+
+RUN pip install Flask
+RUN mkdir -p /usr/local/share/
+ADD sflow_pub_sub /usr/local/share/sflow_pub_sub
+RUN chmod +x /usr/local/share/sflow_pub_sub/sflow_pub_sub_main.py
+RUN chmod +x /usr/local/share/sflow_pub_sub/start_sflow_pub_sub
+WORKDIR /usr/local/share/sflow_pub_sub/
+CMD /usr/local/share/sflow_pub_sub/start_sflow_pub_sub
diff --git a/xos/onboard/ceilometer/synchronizer/templates/ceilometer_proxy_config.j2 b/xos/onboard/ceilometer/synchronizer/templates/ceilometer_proxy_config.j2
new file mode 100644
index 0000000..bd6c521
--- /dev/null
+++ b/xos/onboard/ceilometer/synchronizer/templates/ceilometer_proxy_config.j2
@@ -0,0 +1,17 @@
+# This file autogenerated by monitoring-channel observer
+# It contains a list of attributes to be used by ceilometer proxy web server
+# syntax: key=value
+
+[default]
+auth_url={{ auth_url }}
+admin_user={{ admin_user }}
+admin_tenant={{ admin_tenant }}
+admin_password={{ admin_password }}
+ceilometer_pub_sub_url={{ ceilometer_pub_sub_url }}
+
+[allowed_tenants]
+{% if allowed_tenant_ids %}
+{% for tenant_id in allowed_tenant_ids %}
+{{ tenant_id }}
+{% endfor %}
+{% endif %}
diff --git a/xos/onboard/ceilometer/synchronizer/templates/ceilometer_proxy_server.py b/xos/onboard/ceilometer/synchronizer/templates/ceilometer_proxy_server.py
new file mode 100644
index 0000000..c81b941
--- /dev/null
+++ b/xos/onboard/ceilometer/synchronizer/templates/ceilometer_proxy_server.py
@@ -0,0 +1,294 @@
+#!/usr/bin/env python
+import web
+import ConfigParser
+import io
+import json
+from ceilometerclient import client
+import logging
+import urllib
+import urllib2
+from urlparse import urlparse
+from wsgilog import WsgiLog
+
+web.config.debug=False
+
+logfile = "ceilometer_proxy_server.log"
+level=logging.INFO
+logger=logging.getLogger('ceilometer_proxy_server')
+logger.setLevel(level)
+handler=logging.handlers.RotatingFileHandler(logfile,maxBytes=1000000, backupCount=1)
+logger.addHandler(handler)
+
+class FileLog(WsgiLog):
+    def __init__(self, application):
+        WsgiLog.__init__(
+            self,
+            application,
+            logformat = '%(message)s',
+            tofile = True,
+            toprint = True,
+            prnlevel = level,
+            file = logfile,
+            backups =1
+            )
+    def __call__(self, environ, start_response):
+        def hstart_response(status, response_headers, *args):
+             out = start_response(status, response_headers, *args)
+             try:
+                 logline=environ["SERVER_PROTOCOL"]+" "+environ["REQUEST_METHOD"]+" "+environ["REQUEST_URI"]+" - "+status
+             except err:
+                 logline="Could not log <%s> due to err <%s>" % (str(environ), err)
+             logger.info(logline)
+
+             return out
+
+        return super(FileLog, self).__call__(environ, hstart_response)
+
+#TODOs:
+#-See if we can avoid using python-ceilometerclient and instead use the REST calls directly with AuthToken
+#
+urls = (
+    r'^/v2/meters$', 'meter_list',
+    r'^/v2/meters/(?P<meter_name>[A-Za-z0-9_:.\-]+)/statistics$', 'statistics_list',
+    r'^/v2/samples$', 'sample_list',
+    r'^/v2/resources$', 'resource_list',
+    r'^/v2/subscribe$', 'pubsub_handler',
+)
+
+app = web.application(urls, globals())
+
+config = None
+ceilometer_client = None
+
+
+def parse_ceilometer_proxy_config():
+    global config
+    config = ConfigParser.RawConfigParser(allow_no_value=True)
+    config.read('ceilometer_proxy_config')
+ 
+def ceilometerclient():
+    global config, ceilometer_client
+    if ceilometer_client:
+         return ceilometer_client
+
+    if not config:
+         parse_ceilometer_proxy_config()
+
+    keystone = {}
+    keystone['os_username']=config.get('default','admin_user')
+    keystone['os_password']=config.get('default','admin_password')
+    keystone['os_auth_url']=config.get('default','auth_url')
+    keystone['os_tenant_name']=config.get('default','admin_tenant')
+    ceilometer_client = client.get_client(2,**keystone)
+    logger.info('ceilometer get_client is successful')
+    return ceilometer_client
+
+def make_query(user_id=None, tenant_id=None, resource_id=None,
+               user_ids=None, tenant_ids=None, resource_ids=None):
+    """Returns query built from given parameters.
+
+    This query can be then used for querying resources, meters and
+    statistics.
+
+    :Parameters:
+      - `user_id`: user_id, has a priority over list of ids
+      - `tenant_id`: tenant_id, has a priority over list of ids
+      - `resource_id`: resource_id, has a priority over list of ids
+      - `user_ids`: list of user_ids
+      - `tenant_ids`: list of tenant_ids
+      - `resource_ids`: list of resource_ids
+    """
+    user_ids = user_ids or []
+    tenant_ids = tenant_ids or []
+    resource_ids = resource_ids or []
+
+    query = []
+    if user_id:
+        user_ids = [user_id]
+    for u_id in user_ids:
+        query.append({"field": "user_id", "op": "eq", "value": u_id})
+
+    if tenant_id:
+        tenant_ids = [tenant_id]
+    for t_id in tenant_ids:
+        query.append({"field": "project_id", "op": "eq", "value": t_id})
+
+    if resource_id:
+        resource_ids = [resource_id]
+    for r_id in resource_ids:
+        query.append({"field": "resource_id", "op": "eq", "value": r_id})
+
+    return query
+
+def filter_query_params(query_params):
+    new_query=[]
+    i=0
+    user_specified_tenants=[]
+    for field in query_params['q.field']:
+        if (field != 'project_id') and (field != 'project'):
+            query = {}
+            query['field']=field
+            if query_params['q.op'][i] != '':
+                 query['op']=query_params['q.op'][i]
+            query['value']=query_params['q.value'][i]
+            new_query.append(query)
+        else:
+            user_specified_tenants.append(query_params['q.value'][i])
+        i=i+1
+    return new_query,user_specified_tenants
+
+class meter_list:
+    def GET(self):
+        global config
+        keyword_args = {
+             "q.field": [],
+             "q.op": [],
+             "q.type": [],
+             "q.value": [],
+        }
+        query_params = web.input(**keyword_args)
+        new_query, user_specified_tenants = filter_query_params(query_params)
+
+        client = ceilometerclient()
+        meters=[]
+        for (k,v) in config.items('allowed_tenants'):
+             if user_specified_tenants and (k not in user_specified_tenants):
+                 continue
+             final_query=[]
+             final_query.extend(new_query)
+             query = make_query(tenant_id=k)
+             final_query.extend(query)
+             logger.debug('final query=%s',final_query)
+             results = client.meters.list(q=final_query)
+             meters.extend(results)
+        return json.dumps([ob._info for ob in meters])
+
+class statistics_list:
+    def GET(self, meter_name):
+        global config
+        keyword_args = {
+             "q.field": [],
+             "q.op": [],
+             "q.type": [],
+             "q.value": [],
+             "period": None
+        }
+        query_params = web.input(**keyword_args)
+        new_query, user_specified_tenants = filter_query_params(query_params)
+
+        client = ceilometerclient()
+        period = query_params.period
+        statistics = []
+        for (k,v) in config.items('allowed_tenants'):
+              if user_specified_tenants and (k not in user_specified_tenants):
+                  continue
+              final_query=[]
+              final_query.extend(new_query)
+              query = make_query(tenant_id=k)
+              final_query.extend(query)
+              logger.debug('final query=%s',final_query)
+              results = client.statistics.list(meter_name=meter_name, q=final_query, period=period)
+              statistics.extend(results)
+        return json.dumps([ob._info for ob in statistics])
+
+class sample_list:
+    def GET(self):
+        global config
+        keyword_args = {
+             "q.field": [],
+             "q.op": [],
+             "q.type": [],
+             "q.value": [],
+             "limit": None,
+        }
+        query_params = web.input(**keyword_args)
+        new_query, user_specified_tenants = filter_query_params(query_params)
+
+        client = ceilometerclient()
+        limit=query_params.limit
+        samples=[]
+        for (k,v) in config.items('allowed_tenants'):
+              if user_specified_tenants and (k not in user_specified_tenants):
+                  continue
+              final_query=[]
+              final_query.extend(new_query)
+              query = make_query(tenant_id=k)
+              final_query.extend(query)
+              logger.debug('final query=%s',final_query)
+              results = client.new_samples.list(q=final_query,limit=limit)
+              samples.extend(results)
+        return json.dumps([ob._info for ob in samples])
+
+class resource_list:
+    def GET(self):
+        global config
+        keyword_args = {
+             "q.field": [],
+             "q.op": [],
+             "q.type": [],
+             "q.value": [],
+             "limit": None,
+             "links": None,
+        }
+        query_params = web.input(**keyword_args)
+        new_query, user_specified_tenants = filter_query_params(query_params)
+
+        client = ceilometerclient()
+        limit=query_params.limit
+        links=query_params.links
+        resources=[]
+        for (k,v) in config.items('allowed_tenants'):
+              if user_specified_tenants and (k not in user_specified_tenants):
+                  continue
+              final_query=[]
+              final_query.extend(new_query)
+              query = make_query(tenant_id=k)
+              final_query.extend(query)
+              logger.debug('final query=%s',final_query)
+              results = client.resources.list(q=final_query, limit=limit, links=links)
+              resources.extend(results)
+        return json.dumps([ob._info for ob in resources])
+
+class pubsub_handler:
+    def POST(self):
+        global config
+        parse_ceilometer_proxy_config()
+        ceilometer_pub_sub_url = config.get('default', 'ceilometer_pub_sub_url')
+        url = urlparse(ceilometer_pub_sub_url)
+        if (not url.scheme) or (not url.netloc): 
+             raise Exception("Ceilometer PUB/SUB URL not set")
+        ceilometer_pub_sub_url = url.scheme + "://" + url.netloc + "/subscribe"
+        data_str = unicode(web.data(),'iso-8859-1')
+        post_data = json.loads(data_str)
+        final_query=[]
+        for (k,v) in config.items('allowed_tenants'):
+             query = make_query(tenant_id=k)
+             final_query.extend(query)
+        if not final_query:
+             raise Exception("Not allowed to subscribe to any meters")
+        post_data["query"] = final_query
+        #TODO: The PUB/SUB url needs to be read from config
+        put_request = urllib2.Request(ceilometer_pub_sub_url, json.dumps(post_data))
+        put_request.get_method = lambda: 'SUB'
+        put_request.add_header('Content-Type', 'application/json')
+        response = urllib2.urlopen(put_request)
+        response_text = response.read()
+        return json.dumps(response_text)
+
+    def DELETE(self):
+        ceilometer_pub_sub_url = config.get('default', 'ceilometer_pub_sub_url')
+        url = urlparse(ceilometer_pub_sub_url)
+        if (not url.scheme) or (not url.netloc): 
+             raise Exception("Ceilometer PUB/SUB URL not set")
+        ceilometer_pub_sub_url = url.scheme + "://" + url.netloc + "/unsubscribe"
+        data_str = web.data()
+        #TODO: The PUB/SUB url needs to be read from config
+        put_request = urllib2.Request(ceilometer_pub_sub_url, data_str)
+        put_request.get_method = lambda: 'UNSUB'
+        put_request.add_header('Content-Type', 'application/json')
+        response = urllib2.urlopen(put_request)
+        response_text = response.read()
+        return json.dumps(response_text)
+
+if __name__ == "__main__":
+    app.run(FileLog)
diff --git a/xos/onboard/ceilometer/synchronizer/templates/monitoring-channel.conf.j2 b/xos/onboard/ceilometer/synchronizer/templates/monitoring-channel.conf.j2
new file mode 100644
index 0000000..eb937ac
--- /dev/null
+++ b/xos/onboard/ceilometer/synchronizer/templates/monitoring-channel.conf.j2
@@ -0,0 +1,10 @@
+# Upstart script for Monitoring channel
+description "Upstart script for Monitoring channel container"
+author "andy@onlab.us"
+start on filesystem and started docker
+stop on runlevel [!2345]
+respawn
+
+script
+  /usr/local/sbin/start-monitoring-channel-{{ unique_id }}.sh
+end script
diff --git a/xos/onboard/ceilometer/synchronizer/templates/sflow_pub_sub/README b/xos/onboard/ceilometer/synchronizer/templates/sflow_pub_sub/README
new file mode 100644
index 0000000..ee8ad9b
--- /dev/null
+++ b/xos/onboard/ceilometer/synchronizer/templates/sflow_pub_sub/README
@@ -0,0 +1,37 @@
+
+Subscribe-Publish Frame Work:
+1.Command to Install Flask Webserver frame work.
+  sudo pip install Flask
+
+  Along with flask we need the following packages:
+   msgpack
+   fnmatch
+   operator
+   logging
+   oslo_utils
+   ConfigParser
+ 
+2.Files: i.sub_main.py
+         ii.pubrecords.py
+         iii.pub_sub.conf
+
+3.Command to start the server:
+    #python sun_main.py
+4.Command for subscription:
+      i.app_id:Application ID,should be unique.
+      ii.target:
+           Presently only udp is supported.
+           a.udp:<ip:portno>
+           b.kafka:<kafkaip:kafkaport>
+      iii.sub_info:Sunscription notifications.ex:cpu_util,cpu_*
+      iv.query:
+         Below information need to provide as part of query.
+         a.field:fileds like user id ,porject id etc.,
+         b.op:"eq","gt","lt" etc.,
+         c.value:value of the fileds.
+     Example:
+  		 curl -i -H "Content-Type: application/json" -X SUB -d '{"app_id":"10","target":"udp://10.11.10.1:5006","sub_info":"cpu_util","query":[{"field":"user_id","op":"eq","value":"e1271a86bd4e413c87248baf2e5f01e0"},{"field":"project_id","op":"eq","value":"b1a3bf16d2014b47be9aefea88087318"},{"field":"resource_id","op":"eq","value":"658cd03f-d0f0-4f55-9f48-39e7222a8646"}]}' -L http://10.11.10.1:4455/subscribe
+
+5.Command for unsunscription:
+    For unsubcription only appid will be needed.
+    curl -i -H "Content-Type: application/json" -X UNSUB -d '{"app_id":"10"}' http://10.11.10.1:4455/unsubscribe
diff --git a/xos/onboard/ceilometer/synchronizer/templates/sflow_pub_sub/sample_sflow_pub_sub.conf_sample b/xos/onboard/ceilometer/synchronizer/templates/sflow_pub_sub/sample_sflow_pub_sub.conf_sample
new file mode 100644
index 0000000..40b5bf5
--- /dev/null
+++ b/xos/onboard/ceilometer/synchronizer/templates/sflow_pub_sub/sample_sflow_pub_sub.conf_sample
@@ -0,0 +1,11 @@
+[LOGGING]
+level = DEBUG
+filename = sflow_pub_sub.log
+
+[WEB_SERVER]
+webserver_host = 0.0.0.0
+webserver_port = 33333
+
+[SFLOW]
+listening_ip_addr = 0.0.0.0
+listening_port = 6343
diff --git a/xos/onboard/ceilometer/synchronizer/templates/sflow_pub_sub/sflow_pub_sub_config.j2 b/xos/onboard/ceilometer/synchronizer/templates/sflow_pub_sub/sflow_pub_sub_config.j2
new file mode 100644
index 0000000..1c5c88c
--- /dev/null
+++ b/xos/onboard/ceilometer/synchronizer/templates/sflow_pub_sub/sflow_pub_sub_config.j2
@@ -0,0 +1,15 @@
+# This file autogenerated by sflow service synchronizer
+# It contains a list of attributes to be used by sflow service
+# syntax: key=value
+
+[LOGGING]
+level = DEBUG
+filename = sflow_pub_sub.log
+
+[WEB_SERVER]
+webserver_host = 0.0.0.0
+webserver_port = {{ sflow_api_port }}
+
+[SFLOW]
+listening_ip_addr = 0.0.0.0
+listening_port = {{ sflow_port }}
diff --git a/xos/onboard/ceilometer/synchronizer/templates/sflow_pub_sub/sflow_pub_sub_main.py b/xos/onboard/ceilometer/synchronizer/templates/sflow_pub_sub/sflow_pub_sub_main.py
new file mode 100644
index 0000000..1276721
--- /dev/null
+++ b/xos/onboard/ceilometer/synchronizer/templates/sflow_pub_sub/sflow_pub_sub_main.py
@@ -0,0 +1,136 @@
+#!/usr/bin/python
+import socket,thread
+import sys
+import fnmatch
+import operator
+import logging
+import ConfigParser
+from urlparse import urlparse
+from sflow_sub_records import *
+
+from flask import request, Request, jsonify
+from flask import Flask
+from flask import make_response
+app = Flask(__name__)
+
+COMPARATORS = {
+    'gt': operator.gt,
+    'lt': operator.lt,
+    'ge': operator.ge,
+    'le': operator.le,
+    'eq': operator.eq,
+    'ne': operator.ne,
+}
+
+LEVELS = {'DEBUG': logging.DEBUG,
+          'INFO': logging.INFO,
+          'WARNING': logging.WARNING,
+          'ERROR': logging.ERROR,
+          'CRITICAL': logging.CRITICAL}
+
+_DEFAULT_LOG_DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
+
+@app.route('/subscribe',methods=['POST'])
+def subscribe():
+    logging.debug(" SUB data:%s",request.data)
+    target = request.data
+    parse_target=urlparse(target)
+    if not parse_target.netloc:
+        err_str = "Error:Invalid target format"
+        logging.error("* Invalid target format")
+        return err_str 
+
+    status = "" 
+    if parse_target.scheme == "udp" :
+         host=parse_target.hostname
+         port=parse_target.port
+         scheme = parse_target.scheme
+         app_ip = host 
+         app_port = port
+ 
+         if host == None or port == None :
+             err_str = "* Error: Invalid IP Address format"
+             logging.error("* Invalid IP Address format")
+             return err_str
+  
+         subscrip_obj=sflow_sub_record(scheme,None,app_ip,app_port,None,None)
+         status = add_sflow_sub_record(subscrip_obj)
+         print_sflow_sub_records()
+
+    if parse_target.scheme == "kafka" :
+         pass
+    if parse_target.scheme == "file" :
+         pass
+    return status 
+
+@app.route('/unsubscribe',methods=['POST'])
+def unsubscribe():
+    try :  
+        target = request.data
+        parse_target=urlparse(target)
+        if not parse_target.netloc:
+            err_str = "Error:Invalid target format"
+            logging.error("* Invalid target format")
+            return err_str 
+
+        status = "" 
+        if parse_target.scheme == "udp" :
+            host=parse_target.hostname
+            port=parse_target.port
+            scheme = parse_target.scheme
+            app_ip = host 
+            app_port = port
+ 
+            delete_sflow_sub_record(app_ip, app_port)
+    except Exception as e:
+         logging.error("* %s",e.__str__())
+         return e.__str__()
+    return "UnSubscrition is sucessful! \n"
+
+@app.errorhandler(404)
+def not_found(error):
+    return make_response(jsonify({'error': 'Not found'}), 404)
+
+def sflow_recv(host,port):
+   udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # UDP
+   udp.bind((host, port))
+   logging.info("Started sflow receive thread on %s:%s",host, str(port))
+
+   while True:
+      data, source = udp.recvfrom(64000)
+      for obj in sflow_sub_database:
+         target_host = obj.ipaddress
+         target_port = int(obj.portno)
+         try:  
+             logging.debug("Replicating the sFlow data to:%s:%s",target_host, str(target_port))
+             udp.sendto(data,(target_host,target_port))
+         except Exception:
+             logging.error ("Unable to send sFlow data to target %s:%s ",target_host,str(target_port))
+   logging.warn("Exiting sflow receive thread")
+
+     
+def initialize(host,port):
+     thread.start_new(sflow_recv,(host,port,))
+        
+if __name__ == "__main__":
+
+    try:
+        config = ConfigParser.ConfigParser()
+        config.read('sflow_pub_sub.conf')
+        webserver_host = config.get('WEB_SERVER','webserver_host')
+        webserver_port = int (config.get('WEB_SERVER','webserver_port'))
+        sflow_listening_ip_addr  = config.get('SFLOW','listening_ip_addr')
+        sflow_listening_port  = int (config.get('SFLOW','listening_port'))
+
+        log_level    = config.get('LOGGING','level')
+        log_file       = config.get('LOGGING','filename')
+   
+        level = LEVELS.get(log_level, logging.NOTSET) 
+        logging.basicConfig(filename=log_file,format='%(asctime)s %(levelname)s %(message)s',\
+                    datefmt=_DEFAULT_LOG_DATE_FORMAT,level=level) 
+    except Exception as e:
+        print("* Error in config file:",e.__str__())
+        logging.error("* Error in confing file:%s",e.__str__())
+    else: 
+        initialize(sflow_listening_ip_addr,sflow_listening_port)
+        app.run(host=webserver_host,port=webserver_port,debug=False)
diff --git a/xos/onboard/ceilometer/synchronizer/templates/sflow_pub_sub/sflow_sub_records.py b/xos/onboard/ceilometer/synchronizer/templates/sflow_pub_sub/sflow_sub_records.py
new file mode 100644
index 0000000..f8b0038
--- /dev/null
+++ b/xos/onboard/ceilometer/synchronizer/templates/sflow_pub_sub/sflow_sub_records.py
@@ -0,0 +1,63 @@
+#!/usr/bin/python
+import fnmatch
+import logging
+
+class sflow_sub_record:
+    def __init__(self,scheme,app_id,app_ip,app_port,subscription_info,sub_info_filter):
+        logging.debug("* Updating subscription_info ") 
+        self.scheme = scheme
+        self.app_id = app_id
+        self.ipaddress = app_ip 
+        self.portno = app_port 
+        self.subscription_info = subscription_info
+        self.sub_info_filter = sub_info_filter 
+
+sflow_sub_database=[] 
+def add_sflow_sub_record(record):
+    logging.info("* inside %s",add_sflow_sub_record.__name__)
+    if not sflow_sub_database:
+        logging.debug("* -----------List is EMpty -------------") 
+        sflow_sub_database.append(record)
+        logging.debug("* Subscription is sucessful") 
+        return "Subscription is sucessful \n" 
+    for x in sflow_sub_database:
+        if (record.ipaddress == x.ipaddress) and (record.portno == x.portno) :
+            logging.warning("* entry already exists\n")
+            return "entry already exists \n" 
+    sflow_sub_database.append(record)
+    return "Subscription is sucessful \n"
+ 
+def delete_sflow_sub_record(ip,port):
+    logging.info("* inside %s",delete_sflow_sub_record.__name__)
+    Flag = False 
+    for x in sflow_sub_database:
+        if (ip == x.ipaddress) and (port == x.portno) :
+            sflow_sub_database.remove(x)
+            Flag = True
+            logging.debug("* Un-Subscription is sucessful") 
+            return "Un-Subscription is sucessful \n"
+    if not Flag :
+       err_str = "No subscription exists with target: udp://" + ip + ":" + str(port) + "\n"
+       logging.error(err_str)
+       raise Exception (err_str)
+       
+def print_sflow_sub_records():
+    logging.info("* inside %s",print_sflow_sub_records.__name__)
+    for obj in sflow_sub_database:
+        logging.debug("* ------------------------------------------------") 
+        logging.debug("* scheme:%s",obj.scheme)  
+        logging.debug("* app_id:%s",obj.app_id)
+        logging.debug("* portno:%s",obj.portno ) 
+        logging.debug("* ipaddress:%s",obj.ipaddress)  
+        logging.debug("* portno:%s",obj.portno)  
+        logging.debug("* subscription_info:%s",obj.subscription_info)
+        logging.debug("* sub_info_filter:%s",obj.sub_info_filter)
+        logging.debug("* ------------------------------------------------")
+ 
+def get_sflow_sub_records(notif_subscription_info):
+    logging.info("* inside %s",get_sflow_sub_records.__name__)
+    sub_list=[]  
+    for obj in sflow_sub_database:
+        if obj.subscription_info == notif_subscription_info:
+            sub_list.append(obj)
+    return sub_list
diff --git a/xos/onboard/ceilometer/synchronizer/templates/sflow_pub_sub/start_sflow_pub_sub b/xos/onboard/ceilometer/synchronizer/templates/sflow_pub_sub/start_sflow_pub_sub
new file mode 100644
index 0000000..e2edda2
--- /dev/null
+++ b/xos/onboard/ceilometer/synchronizer/templates/sflow_pub_sub/start_sflow_pub_sub
@@ -0,0 +1 @@
+/usr/local/share/sflow_pub_sub/sflow_pub_sub_main.py
diff --git a/xos/onboard/ceilometer/synchronizer/templates/start-monitoring-channel.sh.j2 b/xos/onboard/ceilometer/synchronizer/templates/start-monitoring-channel.sh.j2
new file mode 100755
index 0000000..4486985
--- /dev/null
+++ b/xos/onboard/ceilometer/synchronizer/templates/start-monitoring-channel.sh.j2
@@ -0,0 +1,49 @@
+#!/bin/bash
+
+function mac_to_iface {
+    MAC=$1
+    ifconfig|grep $MAC| awk '{print $1}'|grep -v '\.'
+}
+
+function generate_mac_from_ip {
+    IP=$1
+    printf "02:42:%02x:%02x:%02x:%02x\n" `echo $IP|awk -F '.' '{print $1, $2, $3, $4}'`
+}
+
+iptables -L > /dev/null
+ip6tables -L > /dev/null
+
+MONITORING_CHANNEL=monitoring-channel-{{ unique_id }}
+HEADNODEFLATLANIP={{ headnode_flat_lan_ip }}
+HOST_FORWARDING_PORT_FOR_CEILOMETER={{ ceilometer_host_port }}
+
+docker inspect $MONITORING_CHANNEL > /dev/null 2>&1
+if [ "$?" == 1 ]
+then
+    #sudo docker build -t monitoring-channel -f Dockerfile.monitoring_channel .
+    #sudo docker pull srikanthvavila/monitoring-channel
+if [ -z "$HEADNODEFLATLANIP" ] || [ "$HEADNODEFLATLANIP" == "None" ]
+then
+#    docker run -d --name=$MONITORING_CHANNEL --privileged=true -p $HOST_FORWARDING_PORT_FOR_CEILOMETER:8000 -v /usr/local/share/monitoring-channel-{{ unique_id }}_ceilometer_proxy_config:/usr/local/share/ceilometer_proxy_config srikanthvavila/monitoring-channel
+    docker run -d --name=$MONITORING_CHANNEL --privileged=true -p $HOST_FORWARDING_PORT_FOR_CEILOMETER:8000 srikanthvavila/monitoring-channel
+else
+#    docker run -d --name=$MONITORING_CHANNEL --add-host="ctl:$HEADNODEFLATLANIP" --privileged=true -p $HOST_FORWARDING_PORT_FOR_CEILOMETER:8000 -v /usr/local/share/monitoring-channel-{{ unique_id }}_ceilometer_proxy_config:/usr/local/share/ceilometer_proxy_config srikanthvavila/monitoring-channel
+    docker run -d --name=$MONITORING_CHANNEL --add-host="ctl:$HEADNODEFLATLANIP" --privileged=true -p $HOST_FORWARDING_PORT_FOR_CEILOMETER:8000 srikanthvavila/monitoring-channel
+fi
+else
+    docker start $MONITORING_CHANNEL
+fi
+
+# Set up networking via pipework
+#SHARED_LAN_IFACE=$( mac_to_iface {{ shared_lan_mac }} )
+#docker exec $MONITORING_CHANNEL ifconfig eth0 >> /dev/null || pipework $SHARED_LAN_IFACE -i eth0 $MONITORING_CHANNEL 192.168.0.1/24
+
+# Make sure VM's eth0 (hpc_client) has no IP address
+#ifconfig $HPC_IFACE 0.0.0.0
+
+# Now copy ceilometer proxy configuration to container
+#cat /usr/local/share/monitoring-channel-{{ unique_id }}_ceilometer_proxy_config | sudo docker exec -i $MONITORING_CHANNEL bash -c 'cat > /usr/local/share/ceilometer_proxy_config'
+docker cp /usr/local/share/monitoring-channel-{{ unique_id }}_ceilometer_proxy_config $MONITORING_CHANNEL:/usr/local/share/ceilometer_proxy_config
+
+# Attach to container
+docker start -a $MONITORING_CHANNEL
diff --git a/xos/onboard/ceilometer/synchronizer/templates/start_ceilometer_proxy b/xos/onboard/ceilometer/synchronizer/templates/start_ceilometer_proxy
new file mode 100644
index 0000000..ddaa9c8
--- /dev/null
+++ b/xos/onboard/ceilometer/synchronizer/templates/start_ceilometer_proxy
@@ -0,0 +1 @@
+/usr/local/share/ceilometer_proxy_server.py 8000
diff --git a/xos/onboard/ceilometer/templates/ceilometeradmin.html b/xos/onboard/ceilometer/templates/ceilometeradmin.html
new file mode 100644
index 0000000..40f57e8
--- /dev/null
+++ b/xos/onboard/ceilometer/templates/ceilometeradmin.html
@@ -0,0 +1,6 @@
+<div class = "row text-center">
+    <div class="col-xs-12">
+        <a class="btn btn-primary" href="/admin/ceilometer/monitoringchannel/">Monitoring Channels</a>
+    </div>
+</div>
+
diff --git a/xos/onboard/ceilometer/templates/sflowadmin.html b/xos/onboard/ceilometer/templates/sflowadmin.html
new file mode 100644
index 0000000..3cbb333
--- /dev/null
+++ b/xos/onboard/ceilometer/templates/sflowadmin.html
@@ -0,0 +1,6 @@
+<div class = "row text-center">
+    <div class="col-xs-12">
+        <a class="btn btn-primary" href="/admin/ceilometer/sflowtenant/">sFlow Tenants</a>
+    </div>
+</div>
+
diff --git a/xos/onboard/ceilometer/tosca/resources/ceilometerservice.py b/xos/onboard/ceilometer/tosca/resources/ceilometerservice.py
new file mode 100644
index 0000000..e77fa55
--- /dev/null
+++ b/xos/onboard/ceilometer/tosca/resources/ceilometerservice.py
@@ -0,0 +1,41 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from core.models import ServiceAttribute
+from services.ceilometer.models import CeilometerService
+
+from service import XOSService
+
+class XOSCeilometerService(XOSService):
+    provides = "tosca.nodes.CeilometerService"
+    xos_model = CeilometerService
+    copyin_props = ["view_url", "icon_url", "enabled", "published", "public_key", "versionNumber", "ceilometer_pub_sub_url"]
+
+    def set_service_attr(self, obj, prop_name, value):
+        value = self.try_intrinsic_function(value)
+        if value:
+            attrs = ServiceAttribute.objects.filter(service=obj, name=prop_name)
+            if attrs:
+                attr = attrs[0]
+                if attr.value != value:
+                    self.info("updating attribute %s" % prop_name)
+                    attr.value = value
+                    attr.save()
+            else:
+                self.info("adding attribute %s" % prop_name)
+                ta = ServiceAttribute(service=obj, name=prop_name, value=value)
+                ta.save()
+
+    def postprocess(self, obj):
+        props = self.nodetemplate.get_properties()
+        for (k,d) in props.items():
+            v = d.value
+            if k.startswith("config_"):
+                self.set_service_attr(obj, k, v)
+            elif k.startswith("rest_"):
+                self.set_service_attr(obj, k, v)
+
diff --git a/xos/onboard/ceilometer/tosca/resources/ceilometertenant.py b/xos/onboard/ceilometer/tosca/resources/ceilometertenant.py
new file mode 100644
index 0000000..cb3a623
--- /dev/null
+++ b/xos/onboard/ceilometer/tosca/resources/ceilometertenant.py
@@ -0,0 +1,39 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+import pdb
+
+from services.ceilometer.models import MonitoringChannel, CeilometerService
+
+from xosresource import XOSResource
+
+class XOSCeilometerTenant(XOSResource):
+    provides = "tosca.nodes.CeilometerTenant"
+    xos_model = MonitoringChannel
+    name_field = None
+
+    def get_xos_args(self, throw_exception=True):
+        args = super(XOSCeilometerTenant, self).get_xos_args()
+
+        provider_name = self.get_requirement("tosca.relationships.MemberOfService", throw_exception=throw_exception)
+        if provider_name:
+            args["provider_service"] = self.get_xos_object(CeilometerService, throw_exception=throw_exception, name=provider_name)
+
+        return args
+
+    def get_existing_objs(self):
+        args = self.get_xos_args(throw_exception=False)
+        provider_service = args.get("provider", None)
+        if provider_service:
+            return [ self.get_xos_object(provider_service=provider_service) ]
+        return []
+
+    def postprocess(self, obj):
+        pass
+
+    def can_delete(self, obj):
+        return super(XOSCeilometerTenant, self).can_delete(obj)
+
diff --git a/xos/onboard/ceilometer/tosca/resources/sflowservice.py b/xos/onboard/ceilometer/tosca/resources/sflowservice.py
new file mode 100644
index 0000000..272518e
--- /dev/null
+++ b/xos/onboard/ceilometer/tosca/resources/sflowservice.py
@@ -0,0 +1,41 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from core.models import ServiceAttribute
+from services.ceilometer.models import SFlowService
+
+from service import XOSService
+
+class XOSSFlowService(XOSService):
+    provides = "tosca.nodes.SFlowService"
+    xos_model = SFlowService
+    copyin_props = ["view_url", "icon_url", "enabled", "published", "public_key", "versionNumber", "sflow_port", "sflow_api_port"]
+
+    def set_service_attr(self, obj, prop_name, value):
+        value = self.try_intrinsic_function(value)
+        if value:
+            attrs = ServiceAttribute.objects.filter(service=obj, name=prop_name)
+            if attrs:
+                attr = attrs[0]
+                if attr.value != value:
+                    self.info("updating attribute %s" % prop_name)
+                    attr.value = value
+                    attr.save()
+            else:
+                self.info("adding attribute %s" % prop_name)
+                ta = ServiceAttribute(service=obj, name=prop_name, value=value)
+                ta.save()
+
+    def postprocess(self, obj):
+        props = self.nodetemplate.get_properties()
+        for (k,d) in props.items():
+            v = d.value
+            if k.startswith("config_"):
+                self.set_service_attr(obj, k, v)
+            elif k.startswith("rest_"):
+                self.set_service_attr(obj, k, v)
+
diff --git a/xos/onboard/exampleservice/admin.py b/xos/onboard/exampleservice/admin.py
new file mode 100644
index 0000000..f679e4e
--- /dev/null
+++ b/xos/onboard/exampleservice/admin.py
@@ -0,0 +1,116 @@
+# admin.py - ExampleService Django Admin
+
+from core.admin import ReadOnlyAwareAdmin, SliceInline
+from core.middleware import get_request
+from core.models import User
+
+from django import forms
+from django.contrib import admin
+
+from services.exampleservice.models import *
+
+class ExampleServiceForm(forms.ModelForm):
+
+    class Meta:
+        model = ExampleService
+
+    def __init__(self, *args, **kwargs):
+        super(ExampleServiceForm, self).__init__(*args, **kwargs)
+
+        if self.instance:
+            self.fields['service_message'].initial = self.instance.service_message
+
+    def save(self, commit=True):
+        self.instance.service_message = self.cleaned_data.get('service_message')
+        return super(ExampleServiceForm, self).save(commit=commit)
+
+class ExampleServiceAdmin(ReadOnlyAwareAdmin):
+
+    model = ExampleService
+    verbose_name = SERVICE_NAME_VERBOSE
+    verbose_name_plural = SERVICE_NAME_VERBOSE_PLURAL
+    form = ExampleServiceForm
+    inlines = [SliceInline]
+
+    list_display = ('backend_status_icon', 'name', 'service_message', 'enabled')
+    list_display_links = ('backend_status_icon', 'name', 'service_message' )
+
+    fieldsets = [(None, {
+        'fields': ['backend_status_text', 'name', 'enabled', 'versionNumber', 'service_message', 'description',],
+        'classes':['suit-tab suit-tab-general',],
+        })]
+
+    readonly_fields = ('backend_status_text', )
+    user_readonly_fields = ['name', 'enabled', 'versionNumber', 'description',]
+
+    extracontext_registered_admins = True
+
+    suit_form_tabs = (
+        ('general', 'Example Service Details', ),
+        ('slices', 'Slices',),
+        )
+
+    suit_form_includes = ((
+        'top',
+        'administration'),
+        )
+
+    def queryset(self, request):
+        return ExampleService.get_service_objects_by_user(request.user)
+
+admin.site.register(ExampleService, ExampleServiceAdmin)
+
+class ExampleTenantForm(forms.ModelForm):
+
+    class Meta:
+        model = ExampleTenant
+
+    creator = forms.ModelChoiceField(queryset=User.objects.all())
+
+    def __init__(self, *args, **kwargs):
+        super(ExampleTenantForm, self).__init__(*args, **kwargs)
+
+        self.fields['kind'].widget.attrs['readonly'] = True
+        self.fields['kind'].initial = SERVICE_NAME
+
+        self.fields['provider_service'].queryset = ExampleService.get_service_objects().all()
+
+        if self.instance:
+            self.fields['creator'].initial = self.instance.creator
+            self.fields['tenant_message'].initial = self.instance.tenant_message
+
+        if (not self.instance) or (not self.instance.pk):
+            self.fields['creator'].initial = get_request().user
+            if ExampleService.get_service_objects().exists():
+                self.fields['provider_service'].initial = ExampleService.get_service_objects().all()[0]
+
+    def save(self, commit=True):
+        self.instance.creator = self.cleaned_data.get('creator')
+        self.instance.tenant_message = self.cleaned_data.get('tenant_message')
+        return super(ExampleTenantForm, self).save(commit=commit)
+
+
+class ExampleTenantAdmin(ReadOnlyAwareAdmin):
+
+    verbose_name = TENANT_NAME_VERBOSE
+    verbose_name_plural = TENANT_NAME_VERBOSE_PLURAL
+
+    list_display = ('id', 'backend_status_icon', 'instance', 'tenant_message')
+    list_display_links = ('backend_status_icon', 'instance', 'tenant_message', 'id')
+
+    fieldsets = [(None, {
+        'fields': ['backend_status_text', 'kind', 'provider_service', 'instance', 'creator', 'tenant_message'],
+        'classes': ['suit-tab suit-tab-general'],
+        })]
+
+    readonly_fields = ('backend_status_text', 'instance',)
+
+    form = ExampleTenantForm
+
+    suit_form_tabs = (('general', 'Details'),)
+
+    def queryset(self, request):
+        return ExampleTenant.get_tenant_objects_by_user(request.user)
+
+admin.site.register(ExampleTenant, ExampleTenantAdmin)
+
diff --git a/xos/onboard/exampleservice/api/service/exampleservice.py b/xos/onboard/exampleservice/api/service/exampleservice.py
new file mode 100644
index 0000000..d8fe23a
--- /dev/null
+++ b/xos/onboard/exampleservice/api/service/exampleservice.py
@@ -0,0 +1,54 @@
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+from rest_framework import serializers
+from rest_framework import generics
+from rest_framework import viewsets
+from rest_framework import status
+from rest_framework.decorators import detail_route, list_route
+from rest_framework.views import APIView
+from core.models import *
+from django.forms import widgets
+from django.conf.urls import patterns, url
+from api.xosapi_helpers import PlusModelSerializer, XOSViewSet, ReadOnlyField
+from django.shortcuts import get_object_or_404
+from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
+from xos.exceptions import *
+import json
+import subprocess
+from services.exampleservice.models import ExampleService
+
+class ExampleServiceSerializer(PlusModelSerializer):
+        id = ReadOnlyField()
+        humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+        service_message = serializers.CharField(required=False)
+
+        class Meta:
+            model = ExampleService
+            fields = ('humanReadableName',
+                      'id',
+                      'service_message')
+
+        def getHumanReadableName(self, obj):
+            return obj.__unicode__()
+
+class ExampleServiceViewSet(XOSViewSet):
+    base_name = "exampleservice"
+    method_name = "exampleservice"
+    method_kind = "viewset"
+    queryset = ExampleService.get_service_objects().all()
+    serializer_class = ExampleServiceSerializer
+
+    @classmethod
+    def get_urlpatterns(self, api_path="^"):
+        patterns = super(ExampleServiceViewSet, self).get_urlpatterns(api_path=api_path)
+
+        return patterns
+
+    def list(self, request):
+        object_list = self.filter_queryset(self.get_queryset())
+
+        serializer = self.get_serializer(object_list, many=True)
+
+        return Response(serializer.data)
+
diff --git a/xos/onboard/exampleservice/api/tenant/exampletenant.py b/xos/onboard/exampleservice/api/tenant/exampletenant.py
new file mode 100644
index 0000000..f4778cc
--- /dev/null
+++ b/xos/onboard/exampleservice/api/tenant/exampletenant.py
@@ -0,0 +1,67 @@
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+from rest_framework import serializers
+from rest_framework import generics
+from rest_framework import status
+from core.models import *
+from django.forms import widgets
+from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
+from api.xosapi_helpers import PlusModelSerializer, XOSViewSet, ReadOnlyField
+
+from services.exampleservice.models import ExampleTenant, ExampleService
+
+def get_default_example_service():
+    example_services = ExampleService.get_service_objects().all()
+    if example_services:
+        return example_services[0]
+    return None
+
+class ExampleTenantSerializer(PlusModelSerializer):
+        id = ReadOnlyField()
+        provider_service = serializers.PrimaryKeyRelatedField(queryset=ExampleService.get_service_objects().all(), default=get_default_example_service)
+        tenant_message = serializers.CharField(required=False)
+        backend_status = ReadOnlyField()
+
+        humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+
+        class Meta:
+            model = ExampleTenant
+            fields = ('humanReadableName', 'id', 'provider_service', 'tenant_message', 'backend_status')
+
+        def getHumanReadableName(self, obj):
+            return obj.__unicode__()
+
+class ExampleTenantViewSet(XOSViewSet):
+    base_name = "exampletenant"
+    method_name = "exampletenant"
+    method_kind = "viewset"
+    queryset = ExampleTenant.get_tenant_objects().all()
+    serializer_class = ExampleTenantSerializer
+
+    @classmethod
+    def get_urlpatterns(self, api_path="^"):
+        patterns = super(ExampleTenantViewSet, self).get_urlpatterns(api_path=api_path)
+
+        # example to demonstrate adding a custom endpoint
+        patterns.append( self.detail_url("message/$", {"get": "get_message", "put": "set_message"}, "message") )
+
+        return patterns
+
+    def list(self, request):
+        queryset = self.filter_queryset(self.get_queryset())
+
+        serializer = self.get_serializer(queryset, many=True)
+
+        return Response(serializer.data)
+
+    def get_message(self, request, pk=None):
+        example_tenant = self.get_object()
+        return Response({"tenant_message": example_tenant.tenant_message})
+
+    def set_message(self, request, pk=None):
+        example_tenant = self.get_object()
+        example_tenant.tenant_message = request.data["tenant_message"]
+        example_tenant.save()
+        return Response({"tenant_message": example_tenant.tenant_message})
+
diff --git a/xos/onboard/exampleservice/exampleservice-onboard-longform.yaml b/xos/onboard/exampleservice/exampleservice-onboard-longform.yaml
new file mode 100644
index 0000000..0eddd51
--- /dev/null
+++ b/xos/onboard/exampleservice/exampleservice-onboard-longform.yaml
@@ -0,0 +1,57 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Onboard the exampleservice
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    exampleservice:
+      type: tosca.nodes.ServiceController
+      properties:
+          base_url: file:/opt/xos/onboard/exampleservice/
+
+    exampleservice_models:
+      type: tosca.nodes.ServiceControllerResource
+      properties:
+          kind: models
+          format: python
+          url: models.py
+      requirements:
+          - controller:
+              node: exampleservice
+              relationship: tosca.relationships.UsedByController
+
+    exampleservice_admin:
+      type: tosca.nodes.ServiceControllerResource
+      properties:
+          kind: admin
+          format: python
+          url: admin.py
+      requirements:
+          - controller:
+              node: exampleservice
+              relationship: tosca.relationships.UsedByController
+
+    exampleservice_synchronizer:
+      type: tosca.nodes.ServiceControllerResource
+      properties:
+          kind: synchronizer
+          format: manifest
+          url: synchronizer/manifest
+      requirements:
+          - controller:
+              node: exampleservice
+              relationship: tosca.relationships.UsedByController
+
+    exampleservice_tosca_types:
+      type: tosca.nodes.ServiceControllerResource
+      properties:
+          kind: tosca_custom_types
+          format: yaml
+          url: exampleservice.yaml
+      requirements:
+          - controller:
+              node: exampleservice
+              relationship: tosca.relationships.UsedByController
diff --git a/xos/onboard/exampleservice/exampleservice-onboard.yaml b/xos/onboard/exampleservice/exampleservice-onboard.yaml
new file mode 100644
index 0000000..9999a38
--- /dev/null
+++ b/xos/onboard/exampleservice/exampleservice-onboard.yaml
@@ -0,0 +1,25 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Onboard the exampleservice
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    exampleservice:
+      type: tosca.nodes.ServiceController
+      properties:
+          base_url: file:///opt/xos/onboard/exampleservice/
+          # The following will concatenate with base_url automatically, if
+          # base_url is non-null.
+          models: models.py
+          admin: admin.py
+          synchronizer: synchronizer/manifest
+          tosca_custom_types: exampleservice.yaml
+          tosca_resource: tosca/resources/exampleservice.py, tosca/resources/exampletenant.py
+          rest_service: api/service/exampleservice.py
+          rest_tenant: api/tenant/exampletenant.py
+          private_key: file:///opt/xos/key_import/exampleservice_rsa
+          public_key: file:///opt/xos/key_import/exampleservice_rsa.pub
+
diff --git a/xos/onboard/exampleservice/exampleservice.m4 b/xos/onboard/exampleservice/exampleservice.m4
new file mode 100644
index 0000000..720913e
--- /dev/null
+++ b/xos/onboard/exampleservice/exampleservice.m4
@@ -0,0 +1,31 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+# compile this with "m4 exampleservice.m4 > exampleservice.yaml"
+
+# include macros
+include(macros.m4)
+
+node_types:
+    tosca.nodes.ExampleService:
+        derived_from: tosca.nodes.Root
+        description: >
+            Example Service
+        capabilities:
+            xos_base_service_caps
+        properties:
+            xos_base_props
+            xos_base_service_props
+            service_message:
+                type: string
+                required: false
+
+    tosca.nodes.ExampleTenant:
+        derived_from: tosca.nodes.Root
+        description: >
+            A Tenant of the example service
+        properties:
+            xos_base_tenant_props
+            tenant_message:
+                type: string
+                required: false
+
diff --git a/xos/onboard/exampleservice/exampleservice.yaml b/xos/onboard/exampleservice/exampleservice.yaml
new file mode 100644
index 0000000..2cd70dd
--- /dev/null
+++ b/xos/onboard/exampleservice/exampleservice.yaml
@@ -0,0 +1,101 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+# compile this with "m4 exampleservice.m4 > exampleservice.yaml"
+
+# include macros
+# Note: Tosca derived_from isn't working the way I think it should, it's not
+#    inheriting from the parent template. Until we get that figured out, use
+#    m4 macros do our inheritance
+
+
+# Service
+
+
+# Subscriber
+
+
+
+
+# end m4 macros
+
+
+
+node_types:
+    tosca.nodes.ExampleService:
+        derived_from: tosca.nodes.Root
+        description: >
+            Example Service
+        capabilities:
+            scalable:
+                type: tosca.capabilities.Scalable
+            service:
+                type: tosca.capabilities.xos.Service
+        properties:
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+            kind:
+                type: string
+                default: generic
+                description: Type of service.
+            view_url:
+                type: string
+                required: false
+                description: URL to follow when icon is clicked in the Service Directory.
+            icon_url:
+                type: string
+                required: false
+                description: ICON to display in the Service Directory.
+            enabled:
+                type: boolean
+                default: true
+            published:
+                type: boolean
+                default: true
+                description: If True then display this Service in the Service Directory.
+            public_key:
+                type: string
+                required: false
+                description: Public key to install into Instances to allows Services to SSH into them.
+            private_key_fn:
+                type: string
+                required: false
+                description: Location of private key file
+            versionNumber:
+                type: string
+                required: false
+                description: Version number of Service.
+            service_message:
+                type: string
+                required: false
+
+    tosca.nodes.ExampleTenant:
+        derived_from: tosca.nodes.Root
+        description: >
+            A Tenant of the example service
+        properties:
+            kind:
+                type: string
+                default: generic
+                description: Kind of tenant
+            service_specific_id:
+                type: string
+                required: false
+                description: Service specific ID opaque to XOS but meaningful to service
+            tenant_message:
+                type: string
+                required: false
+
diff --git a/xos/onboard/exampleservice/macros.m4 b/xos/onboard/exampleservice/macros.m4
new file mode 100644
index 0000000..1f48f10
--- /dev/null
+++ b/xos/onboard/exampleservice/macros.m4
@@ -0,0 +1,84 @@
+# Note: Tosca derived_from isn't working the way I think it should, it's not
+#    inheriting from the parent template. Until we get that figured out, use
+#    m4 macros do our inheritance
+
+define(xos_base_props,
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object)
+# Service
+define(xos_base_service_caps,
+            scalable:
+                type: tosca.capabilities.Scalable
+            service:
+                type: tosca.capabilities.xos.Service)
+define(xos_base_service_props,
+            kind:
+                type: string
+                default: generic
+                description: Type of service.
+            view_url:
+                type: string
+                required: false
+                description: URL to follow when icon is clicked in the Service Directory.
+            icon_url:
+                type: string
+                required: false
+                description: ICON to display in the Service Directory.
+            enabled:
+                type: boolean
+                default: true
+            published:
+                type: boolean
+                default: true
+                description: If True then display this Service in the Service Directory.
+            public_key:
+                type: string
+                required: false
+                description: Public key to install into Instances to allows Services to SSH into them.
+            private_key_fn:
+                type: string
+                required: false
+                description: Location of private key file
+            versionNumber:
+                type: string
+                required: false
+                description: Version number of Service.)
+# Subscriber
+define(xos_base_subscriber_caps,
+            subscriber:
+                type: tosca.capabilities.xos.Subscriber)
+define(xos_base_subscriber_props,
+            kind:
+                type: string
+                default: generic
+                description: Kind of subscriber
+            service_specific_id:
+                type: string
+                required: false
+                description: Service specific ID opaque to XOS but meaningful to service)
+define(xos_base_tenant_props,
+            kind:
+                type: string
+                default: generic
+                description: Kind of tenant
+            service_specific_id:
+                type: string
+                required: false
+                description: Service specific ID opaque to XOS but meaningful to service)
+
+# end m4 macros
+
diff --git a/xos/onboard/exampleservice/make_synchronizer_manifest.sh b/xos/onboard/exampleservice/make_synchronizer_manifest.sh
new file mode 100644
index 0000000..4058982
--- /dev/null
+++ b/xos/onboard/exampleservice/make_synchronizer_manifest.sh
@@ -0,0 +1,2 @@
+#! /bin/bash
+find synchronizer -type f | cut -b 14- > synchronizer/manifest 
diff --git a/xos/onboard/exampleservice/models.py b/xos/onboard/exampleservice/models.py
new file mode 100644
index 0000000..5d3e258
--- /dev/null
+++ b/xos/onboard/exampleservice/models.py
@@ -0,0 +1,53 @@
+# models.py -  ExampleService Models
+
+from core.models import Service, TenantWithContainer
+from django.db import models, transaction
+
+SERVICE_NAME = 'exampleservice'
+SERVICE_NAME_VERBOSE = 'Example Service'
+SERVICE_NAME_VERBOSE_PLURAL = 'Example Services'
+TENANT_NAME_VERBOSE = 'Example Tenant'
+TENANT_NAME_VERBOSE_PLURAL = 'Example Tenants'
+
+class ExampleService(Service):
+
+    KIND = SERVICE_NAME
+
+    class Meta:
+        app_label = SERVICE_NAME
+        verbose_name = SERVICE_NAME_VERBOSE
+
+    service_message = models.CharField(max_length=254, help_text="Service Message to Display")
+
+class ExampleTenant(TenantWithContainer):
+
+    KIND = SERVICE_NAME
+
+    class Meta:
+        verbose_name = TENANT_NAME_VERBOSE
+
+    tenant_message = models.CharField(max_length=254, help_text="Tenant Message to Display")
+
+    def __init__(self, *args, **kwargs):
+        exampleservice = ExampleService.get_service_objects().all()
+        if exampleservice:
+            self._meta.get_field('provider_service').default = exampleservice[0].id
+        super(ExampleTenant, self).__init__(*args, **kwargs)
+
+    def save(self, *args, **kwargs):
+        super(ExampleTenant, self).save(*args, **kwargs)
+        model_policy_exampletenant(self.pk)
+
+    def delete(self, *args, **kwargs):
+        self.cleanup_container()
+        super(ExampleTenant, self).delete(*args, **kwargs)
+
+
+def model_policy_exampletenant(pk):
+    with transaction.atomic():
+        tenant = ExampleTenant.objects.select_for_update().filter(pk=pk)
+        if not tenant:
+            return
+        tenant = tenant[0]
+        tenant.manage_container()
+
diff --git a/xos/onboard/exampleservice/synchronizer/exampleservice-synchronizer.py b/xos/onboard/exampleservice/synchronizer/exampleservice-synchronizer.py
new file mode 100644
index 0000000..90d2c98
--- /dev/null
+++ b/xos/onboard/exampleservice/synchronizer/exampleservice-synchronizer.py
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+
+# Runs the standard XOS synchronizer
+
+import importlib
+import os
+import sys
+
+synchronizer_path = os.path.join(os.path.dirname(
+    os.path.realpath(__file__)), "../../synchronizers/base")
+sys.path.append(synchronizer_path)
+mod = importlib.import_module("xos-synchronizer")
+mod.main()
+
diff --git a/xos/onboard/exampleservice/synchronizer/exampleservice_config b/xos/onboard/exampleservice/synchronizer/exampleservice_config
new file mode 100644
index 0000000..7e59fdd
--- /dev/null
+++ b/xos/onboard/exampleservice/synchronizer/exampleservice_config
@@ -0,0 +1,24 @@
+# Required by XOS
+[db]
+name=xos
+user=postgres
+password=password
+host=localhost
+port=5432
+
+# Required by XOS
+[api]
+nova_enabled=True
+
+# Sets options for the synchronizer
+[observer]
+name=exampleservice
+dependency_graph=/opt/xos/synchronizers/exampleservice/model-deps
+steps_dir=/opt/xos/synchronizers/exampleservice/steps
+sys_dir=/opt/xos/synchronizers/exampleservice/sys
+logfile=/var/log/xos_backend.log
+pretend=False
+backoff_disabled=True
+save_ansible_output=True
+proxy_ssh=False
+
diff --git a/xos/onboard/exampleservice/synchronizer/manifest b/xos/onboard/exampleservice/synchronizer/manifest
new file mode 100644
index 0000000..8f43610
--- /dev/null
+++ b/xos/onboard/exampleservice/synchronizer/manifest
@@ -0,0 +1,10 @@
+manifest
+steps/sync_exampletenant.py
+steps/roles/install_apache/tasks/main.yml
+steps/roles/create_index/templates/index.html.j2
+steps/roles/create_index/tasks/main.yml
+steps/exampletenant_playbook.yaml
+exampleservice-synchronizer.py
+model-deps
+run.sh
+exampleservice_config
diff --git a/xos/onboard/exampleservice/synchronizer/model-deps b/xos/onboard/exampleservice/synchronizer/model-deps
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/xos/onboard/exampleservice/synchronizer/model-deps
@@ -0,0 +1 @@
+{}
diff --git a/xos/onboard/exampleservice/synchronizer/run.sh b/xos/onboard/exampleservice/synchronizer/run.sh
new file mode 100755
index 0000000..e6da8f6
--- /dev/null
+++ b/xos/onboard/exampleservice/synchronizer/run.sh
@@ -0,0 +1,2 @@
+export XOS_DIR=/opt/xos
+python exampleservice-synchronizer.py  -C $XOS_DIR/synchronizers/exampleservice/exampleservice_config
diff --git a/xos/onboard/exampleservice/synchronizer/steps/exampletenant_playbook.yaml b/xos/onboard/exampleservice/synchronizer/steps/exampletenant_playbook.yaml
new file mode 100644
index 0000000..89e4617
--- /dev/null
+++ b/xos/onboard/exampleservice/synchronizer/steps/exampletenant_playbook.yaml
@@ -0,0 +1,16 @@
+---
+# exampletenant_playbook
+
+- hosts: "{{ instance_name }}"
+  connection: ssh
+  user: ubuntu
+  sudo: yes
+  gather_facts: no
+  vars:
+    - tenant_message: "{{ tenant_message }}"
+    - service_message: "{{ service_message }}"
+
+  roles:
+    - install_apache
+    - create_index
+
diff --git a/xos/onboard/exampleservice/synchronizer/steps/roles/create_index/tasks/main.yml b/xos/onboard/exampleservice/synchronizer/steps/roles/create_index/tasks/main.yml
new file mode 100644
index 0000000..91c6029
--- /dev/null
+++ b/xos/onboard/exampleservice/synchronizer/steps/roles/create_index/tasks/main.yml
@@ -0,0 +1,7 @@
+---
+
+- name: Write index.html file to apache document root
+  template:
+    src=index.html.j2
+    dest=/var/www/html/index.html
+
diff --git a/xos/onboard/exampleservice/synchronizer/steps/roles/create_index/templates/index.html.j2 b/xos/onboard/exampleservice/synchronizer/steps/roles/create_index/templates/index.html.j2
new file mode 100644
index 0000000..9cec084
--- /dev/null
+++ b/xos/onboard/exampleservice/synchronizer/steps/roles/create_index/templates/index.html.j2
@@ -0,0 +1,4 @@
+ExampleService
+ Service Message: "{{ service_message }}"
+ Tenant Message: "{{ tenant_message }}"
+
diff --git a/xos/onboard/exampleservice/synchronizer/steps/roles/install_apache/tasks/main.yml b/xos/onboard/exampleservice/synchronizer/steps/roles/install_apache/tasks/main.yml
new file mode 100644
index 0000000..d9a155c
--- /dev/null
+++ b/xos/onboard/exampleservice/synchronizer/steps/roles/install_apache/tasks/main.yml
@@ -0,0 +1,7 @@
+---
+
+- name: Install apache using apt
+  apt:
+    name=apache2
+    update_cache=yes
+
diff --git a/xos/onboard/exampleservice/synchronizer/steps/sync_exampletenant.py b/xos/onboard/exampleservice/synchronizer/steps/sync_exampletenant.py
new file mode 100644
index 0000000..fbde96f
--- /dev/null
+++ b/xos/onboard/exampleservice/synchronizer/steps/sync_exampletenant.py
@@ -0,0 +1,55 @@
+import os
+import sys
+from django.db.models import Q, F
+from services.exampleservice.models import ExampleService, ExampleTenant
+from synchronizers.base.SyncInstanceUsingAnsible import SyncInstanceUsingAnsible
+
+parentdir = os.path.join(os.path.dirname(__file__), "..")
+sys.path.insert(0, parentdir)
+
+class SyncExampleTenant(SyncInstanceUsingAnsible):
+
+    provides = [ExampleTenant]
+
+    observes = ExampleTenant
+
+    requested_interval = 0
+
+    template_name = "exampletenant_playbook.yaml"
+
+    service_key_name = "/opt/xos/synchronizers/exampleservice/exampleservice_private_key"
+
+    def __init__(self, *args, **kwargs):
+        super(SyncExampleTenant, self).__init__(*args, **kwargs)
+
+    def fetch_pending(self, deleted):
+
+        if (not deleted):
+            objs = ExampleTenant.get_tenant_objects().filter(
+                Q(enacted__lt=F('updated')) | Q(enacted=None), Q(lazy_blocked=False))
+        else:
+            # If this is a deletion we get all of the deleted tenants..
+            objs = ExampleTenant.get_deleted_tenant_objects()
+
+        return objs
+
+    def get_exampleservice(self, o):
+        if not o.provider_service:
+            return None
+
+        exampleservice = ExampleService.get_service_objects().filter(id=o.provider_service.id)
+
+        if not exampleservice:
+            return None
+
+        return exampleservice[0]
+
+    # Gets the attributes that are used by the Ansible template but are not
+    # part of the set of default attributes.
+    def get_extra_attributes(self, o):
+        fields = {}
+        fields['tenant_message'] = o.tenant_message
+        exampleservice = self.get_exampleservice(o)
+        fields['service_message'] = exampleservice.service_message
+        return fields
+
diff --git a/xos/onboard/exampleservice/tosca/resources/exampleservice.py b/xos/onboard/exampleservice/tosca/resources/exampleservice.py
new file mode 100644
index 0000000..f26b8b7
--- /dev/null
+++ b/xos/onboard/exampleservice/tosca/resources/exampleservice.py
@@ -0,0 +1,38 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+import pdb
+
+from core.models import Service,User,CoarseTenant
+from services.exampleservice.models import ExampleService
+
+from xosresource import XOSResource
+
+class XOSExampleService(XOSResource):
+    provides = "tosca.nodes.ExampleService"
+    xos_model = ExampleService
+    copyin_props = ["view_url", "icon_url", "enabled", "published", "public_key", "private_key_fn", "versionNumber", "service_message"]
+
+    def postprocess(self, obj):
+        for provider_service_name in self.get_requirements("tosca.relationships.TenantOfService"):
+            provider_service = self.get_xos_object(ExampleService, name=provider_service_name)
+
+            existing_tenancy = CoarseTenant.get_tenant_objects().filter(provider_service = provider_service, subscriber_service = obj)
+            if existing_tenancy:
+                self.info("Tenancy relationship from %s to %s already exists" % (str(obj), str(provider_service)))
+            else:
+                tenancy = CoarseTenant(provider_service = provider_service,
+                                       subscriber_service = obj)
+                tenancy.save()
+
+                self.info("Created Tenancy relationship  from %s to %s" % (str(obj), str(provider_service)))
+
+    def can_delete(self, obj):
+        if obj.slices.exists():
+            self.info("Service %s has active slices; skipping delete" % obj.name)
+            return False
+        return super(XOSExampleService, self).can_delete(obj)
+
diff --git a/xos/onboard/exampleservice/tosca/resources/exampletenant.py b/xos/onboard/exampleservice/tosca/resources/exampletenant.py
new file mode 100644
index 0000000..d9239f9
--- /dev/null
+++ b/xos/onboard/exampleservice/tosca/resources/exampletenant.py
@@ -0,0 +1,36 @@
+import importlib
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+from core.models import Tenant, Service
+from services.exampleservice.models import ExampleTenant, SERVICE_NAME as EXAMPLETENANT_KIND
+
+from xosresource import XOSResource
+
+class XOSExampleTenant(XOSResource):
+    provides = "tosca.nodes.ExampleTenant"
+    xos_model = ExampleTenant
+    name_field = "service_specific_id"
+    copyin_props = ("tenant_message",)
+
+    def get_xos_args(self, throw_exception=True):
+        args = super(XOSExampleTenant, self).get_xos_args()
+
+        # ExampleTenant must always have a provider_service
+        provider_name = self.get_requirement("tosca.relationships.TenantOfService", throw_exception=True)
+        if provider_name:
+            args["provider_service"] = self.get_xos_object(Service, throw_exception=True, name=provider_name)
+
+        return args
+
+    def get_existing_objs(self):
+        args = self.get_xos_args(throw_exception=False)
+        return ExampleTenant.get_tenant_objects().filter(provider_service=args["provider_service"], service_specific_id=args["service_specific_id"])
+        return []
+
+    def can_delete(self, obj):
+        return super(XOSExampleTenant, self).can_delete(obj)
+
diff --git a/xos/onboard/fabric/admin.py b/xos/onboard/fabric/admin.py
new file mode 100644
index 0000000..e372a7d
--- /dev/null
+++ b/xos/onboard/fabric/admin.py
@@ -0,0 +1,62 @@
+from django.contrib import admin
+
+from services.fabric.models import *
+from django import forms
+from django.utils.safestring import mark_safe
+from django.contrib.auth.admin import UserAdmin
+from django.contrib.admin.widgets import FilteredSelectMultiple
+from django.contrib.auth.forms import ReadOnlyPasswordHashField
+from django.contrib.auth.signals import user_logged_in
+from django.utils import timezone
+from django.contrib.contenttypes import generic
+from suit.widgets import LinkedSelect
+from core.models import AddressPool
+from core.admin import ServiceAppAdmin,SliceInline,ServiceAttrAsTabInline, ReadOnlyAwareAdmin, XOSTabularInline, ServicePrivilegeInline, TenantRootTenantInline, TenantRootPrivilegeInline
+from core.middleware import get_request
+
+from functools import update_wrapper
+from django.contrib.admin.views.main import ChangeList
+from django.core.urlresolvers import reverse
+from django.contrib.admin.utils import quote
+
+class FabricServiceForm(forms.ModelForm):
+    def __init__(self,*args,**kwargs):
+        super (FabricServiceForm,self ).__init__(*args,**kwargs)
+
+    def save(self, commit=True):
+        return super(FabricServiceForm, self).save(commit=commit)
+
+    class Meta:
+        model = FabricService
+
+class FabricServiceAdmin(ReadOnlyAwareAdmin):
+    model = FabricService
+    verbose_name = "Fabric Service"
+    verbose_name_plural = "Fabric Services"
+    list_display = ("backend_status_icon", "name", "enabled")
+    list_display_links = ('backend_status_icon', 'name', )
+    fieldsets = [(None, {'fields': ['backend_status_text', 'name','enabled','versionNumber', 'description', "view_url", "icon_url", "autoconfig", ],
+                         'classes':['suit-tab suit-tab-general']})]
+    readonly_fields = ('backend_status_text', )
+    inlines = [SliceInline,ServiceAttrAsTabInline,ServicePrivilegeInline]
+    form = FabricServiceForm
+
+    extracontext_registered_admins = True
+
+    user_readonly_fields = ["name", "enabled", "versionNumber", "description"]
+
+    suit_form_tabs =(('general', 'Fabric Service Details'),
+        ('administration', 'Administration'),
+        #('tools', 'Tools'),
+        ('slices','Slices'),
+        ('serviceattrs','Additional Attributes'),
+        ('serviceprivileges','Privileges'),
+    )
+
+    suit_form_includes = (('fabricadmin.html', 'top', 'administration'),
+                           )
+
+    def queryset(self, request):
+        return FabricService.get_service_objects_by_user(request.user)
+
+admin.site.register(FabricService, FabricServiceAdmin)
diff --git a/xos/onboard/fabric/fabric-onboard.yaml b/xos/onboard/fabric/fabric-onboard.yaml
new file mode 100644
index 0000000..e0f0fa7
--- /dev/null
+++ b/xos/onboard/fabric/fabric-onboard.yaml
@@ -0,0 +1,24 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Onboard the fabric
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    servicecontroller#fabric:
+      type: tosca.nodes.ServiceController
+      properties:
+          base_url: file:///opt/xos/onboard/fabric/
+          # The following will concatenate with base_url automatically, if
+          # base_url is non-null.
+          models: models.py
+          admin: admin.py
+          admin_template: templates/fabricadmin.html
+          synchronizer: synchronizer/manifest
+          synchronizer_run: fabric-synchronizer.py
+          tosca_resource: tosca/resources/fabricservice.py
+          #private_key: file:///opt/xos/key_import/vsg_rsa
+          #public_key: file:///opt/xos/key_import/vsg_rsa.pub
+
diff --git a/xos/onboard/fabric/models.py b/xos/onboard/fabric/models.py
new file mode 100644
index 0000000..bd37416
--- /dev/null
+++ b/xos/onboard/fabric/models.py
@@ -0,0 +1,16 @@
+from django.db import models
+from core.models import Service
+import traceback
+from xos.exceptions import *
+from xos.config import Config
+
+FABRIC_KIND = "fabric"
+
+class FabricService(Service):
+    KIND = FABRIC_KIND
+
+    class Meta:
+        app_label = "fabric"
+        verbose_name = "Fabric Service"
+
+    autoconfig = models.BooleanField(default=True, help_text="Autoconfigure the fabric")
diff --git a/xos/onboard/fabric/synchronizer/fabric-synchronizer.py b/xos/onboard/fabric/synchronizer/fabric-synchronizer.py
new file mode 100755
index 0000000..84bec4f
--- /dev/null
+++ b/xos/onboard/fabric/synchronizer/fabric-synchronizer.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+# This imports and runs ../../xos-observer.py
+
+import importlib
+import os
+import sys
+observer_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),"../../synchronizers/base")
+sys.path.append(observer_path)
+mod = importlib.import_module("xos-synchronizer")
+mod.main()
diff --git a/xos/onboard/fabric/synchronizer/fabric_synchronizer_config b/xos/onboard/fabric/synchronizer/fabric_synchronizer_config
new file mode 100644
index 0000000..2ed56fe
--- /dev/null
+++ b/xos/onboard/fabric/synchronizer/fabric_synchronizer_config
@@ -0,0 +1,23 @@
+# Required by XOS
+[db]
+name=xos
+user=postgres
+password=password
+host=localhost
+port=5432
+
+# Required by XOS
+[api]
+nova_enabled=True
+
+# Sets options for the synchronizer
+[observer]
+name=fabric
+dependency_graph=/opt/xos/synchronizers/fabric/model-deps
+steps_dir=/opt/xos/synchronizers/fabric/steps
+sys_dir=/opt/xos/synchronizers/fabric/sys
+logfile=console
+pretend=False
+backoff_disabled=True
+save_ansible_output=True
+proxy_ssh=False
diff --git a/xos/onboard/fabric/synchronizer/manifest b/xos/onboard/fabric/synchronizer/manifest
new file mode 100644
index 0000000..62a0722
--- /dev/null
+++ b/xos/onboard/fabric/synchronizer/manifest
@@ -0,0 +1,9 @@
+manifest
+fabric_synchronizer_config
+steps/sync_host.yaml
+steps/sync_vroutertenant.py
+start.sh
+stop.sh
+model-deps
+run.sh
+fabric-synchronizer.py
diff --git a/xos/onboard/fabric/synchronizer/model-deps b/xos/onboard/fabric/synchronizer/model-deps
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/xos/onboard/fabric/synchronizer/model-deps
@@ -0,0 +1 @@
+{}
diff --git a/xos/onboard/fabric/synchronizer/run.sh b/xos/onboard/fabric/synchronizer/run.sh
new file mode 100755
index 0000000..4e0c214
--- /dev/null
+++ b/xos/onboard/fabric/synchronizer/run.sh
@@ -0,0 +1,2 @@
+export XOS_DIR=/opt/xos
+python fabric-synchronizer.py  -C $XOS_DIR/synchronizers/fabric/fabric_synchronizer_config
diff --git a/xos/onboard/fabric/synchronizer/start.sh b/xos/onboard/fabric/synchronizer/start.sh
new file mode 100755
index 0000000..8d02bf3
--- /dev/null
+++ b/xos/onboard/fabric/synchronizer/start.sh
@@ -0,0 +1,2 @@
+export XOS_DIR=/opt/xos
+nohup python fabric-synchronizer.py  -C $XOS_DIR/synchronizers/fabric/fabric_synchronizer_config > /dev/null 2>&1 &
diff --git a/xos/onboard/fabric/synchronizer/steps/sync_host.yaml b/xos/onboard/fabric/synchronizer/steps/sync_host.yaml
new file mode 100644
index 0000000..58bccba
--- /dev/null
+++ b/xos/onboard/fabric/synchronizer/steps/sync_host.yaml
@@ -0,0 +1,20 @@
+---
+- hosts: 127.0.0.1
+  connection: local
+  vars:
+    rest_hostname: {{ rest_hostname }}
+    rest_port: {{ rest_port }}
+    rest_endpoint: {{ rest_endpoint }}
+    rest_json: '{{ rest_json }}'
+
+  tasks:
+  - debug: var=rest_json
+
+  - name: Call Fabric REST API
+    uri:
+      url: http://{{ '{{' }} rest_hostname {{ '}}' }}:{{ '{{' }} rest_port {{ '}}' }}/{{ '{{' }} rest_endpoint {{ '}}' }} #http://localhost:8181/onos/v1/network/configuration/
+      body: "{{ '{{' }} rest_json {{ '}}' }}"
+      body_format: raw
+      method: POST
+      user: karaf
+      password: karaf
diff --git a/xos/onboard/fabric/synchronizer/steps/sync_vroutertenant.py b/xos/onboard/fabric/synchronizer/steps/sync_vroutertenant.py
new file mode 100644
index 0000000..fd77ca2
--- /dev/null
+++ b/xos/onboard/fabric/synchronizer/steps/sync_vroutertenant.py
@@ -0,0 +1,103 @@
+import os
+import base64
+from collections import defaultdict
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.openstacksyncstep import OpenStackSyncStep
+from synchronizers.base.syncstep import *
+from core.models import Controller
+from core.models import Image, ControllerImages
+from xos.logger import observer_logger as logger
+from synchronizers.base.ansible import *
+from services.vrouter.models import VRouterTenant
+from services.onos.models import ONOSService
+from services.fabric.models import FabricService
+import json
+
+class SyncVRouterTenant(SyncStep):
+    provides=[VRouterTenant]
+    observes = VRouterTenant
+    requested_interval=30
+    playbook='sync_host.yaml'
+
+    def get_fabric_onos_service(self):
+        fos = None
+        fs = FabricService.get_service_objects().all()[0]
+        if fs.subscribed_tenants.exists():
+            app = fs.subscribed_tenants.all()[0]
+            if app.provider_service:
+                ps = app.provider_service
+                fos = ONOSService.get_service_objects().filter(id=ps.id)[0]
+        return fos
+
+    def get_node_tag(self, node, tagname):
+        tags = Tag.select_by_content_object(node).filter(name=tagname)
+        return tags[0].value
+
+    def fetch_pending(self, deleted):
+        fs = FabricService.get_service_objects().all()[0]
+        if not fs.autoconfig:
+            return None
+
+        if (not deleted):
+            objs = VRouterTenant.get_tenant_objects().filter(Q(lazy_blocked=False))
+        else:
+            objs = VRouterTenant.get_deleted_tenant_objects()
+
+        return objs
+
+    def map_sync_inputs(self, vroutertenant):
+
+        fos = self.get_fabric_onos_service()
+
+        name = None
+        instance = None
+        # VRouterTenant setup is kind of hacky right now, we'll
+        # need to revisit.  The idea is:
+        # * Look up the instance corresponding to the address
+        # * Look up the node running the instance
+        # * Get the "location" tag, push to the fabric
+        #
+        # Do we have a vCPE subscriber_tenant?
+        if (vroutertenant.subscriber_tenant):
+            sub = vroutertenant.subscriber_tenant
+            if (sub.kind == 'vCPE'):
+                instance_id = sub.get_attribute("instance_id")
+                if instance_id:
+                    instance = Instance.objects.filter(id=instance_id)[0]
+                    name = str(sub)
+        else:
+            # Maybe the VRouterTenant is for an instance
+            instance_id = vroutertenant.get_attribute("tenant_for_instance_id")
+            if instance_id: 
+                instance = Instance.objects.filter(id=instance_id)[0]
+                name = str(instance)
+
+        node = instance.node
+        location = self.get_node_tag(node, "location")
+
+        # Is it a POST or DELETE?
+
+        # Create JSON
+        data = {
+            "%s/-1"%vroutertenant.public_mac : {
+                "basic" : {
+                    "ips" : [ vroutertenant.public_ip ],
+                    "location" : location
+                }
+            }
+        }
+
+        rest_json = json.dumps(data, indent=4)
+
+        fields = {
+            'rest_hostname': fos.rest_hostname,
+            'rest_port': fos.rest_port,
+            'rest_json': rest_json,
+            'rest_endpoint': "onos/v1/network/configuration/hosts",
+            'ansible_tag': '%s'%name, # name of ansible playbook
+        }
+        return fields
+
+    def map_sync_outputs(self, controller_image, res):
+        pass
diff --git a/xos/onboard/fabric/synchronizer/stop.sh b/xos/onboard/fabric/synchronizer/stop.sh
new file mode 100755
index 0000000..d35b057
--- /dev/null
+++ b/xos/onboard/fabric/synchronizer/stop.sh
@@ -0,0 +1 @@
+pkill -9 -f fabric-synchronizer.py
diff --git a/xos/onboard/fabric/templates/fabricadmin.html b/xos/onboard/fabric/templates/fabricadmin.html
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xos/onboard/fabric/templates/fabricadmin.html
diff --git a/xos/onboard/fabric/tosca/resources/fabricservice.py b/xos/onboard/fabric/tosca/resources/fabricservice.py
new file mode 100644
index 0000000..0c9cfb4
--- /dev/null
+++ b/xos/onboard/fabric/tosca/resources/fabricservice.py
@@ -0,0 +1,16 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from services.fabric.models import FabricService
+
+from service import XOSService
+
+class FabricService(XOSService):
+    provides = "tosca.nodes.FabricService"
+    xos_model = FabricService
+    copyin_props = ["view_url", "icon_url", "enabled", "published", "public_key", "versionNumber"]
+
diff --git a/xos/onboard/onos/admin.py b/xos/onboard/onos/admin.py
new file mode 100644
index 0000000..fb0f1d7
--- /dev/null
+++ b/xos/onboard/onos/admin.py
@@ -0,0 +1,124 @@
+from django.contrib import admin
+
+from services.onos.models import *
+from django import forms
+from django.utils.safestring import mark_safe
+from django.contrib.auth.admin import UserAdmin
+from django.contrib.admin.widgets import FilteredSelectMultiple
+from django.contrib.auth.forms import ReadOnlyPasswordHashField
+from django.contrib.auth.signals import user_logged_in
+from django.utils import timezone
+from django.contrib.contenttypes import generic
+from suit.widgets import LinkedSelect
+from core.admin import ServiceAppAdmin,SliceInline,ServiceAttrAsTabInline, ReadOnlyAwareAdmin, XOSTabularInline, ServicePrivilegeInline, TenantRootTenantInline, TenantRootPrivilegeInline, TenantAttrAsTabInline
+from core.middleware import get_request
+
+from functools import update_wrapper
+from django.contrib.admin.views.main import ChangeList
+from django.core.urlresolvers import reverse
+from django.contrib.admin.utils import quote
+
+class ONOSServiceForm(forms.ModelForm):
+    rest_hostname = forms.CharField(required=False)
+    rest_port = forms.CharField(required=False)
+    no_container = forms.BooleanField(required=False)
+#    external_hostname = forms.CharField(required=False)
+#    external_container = forms.CharField(required=False)
+
+    def __init__(self,*args,**kwargs):
+        super (ONOSServiceForm,self ).__init__(*args,**kwargs)
+        if self.instance:
+            # fields for the attributes
+            self.fields['rest_hostname'].initial = self.instance.rest_hostname
+            self.fields['rest_port'].initial = self.instance.rest_port
+            self.fields['no_container'].initial = self.instance.no_container
+#            self.fields['external_hostname'].initial = self.instance.external_hostname
+#            self.fields['external_container'].initial = self.instance.external_hostname
+
+    def save(self, commit=True):
+        self.instance.rest_hostname = self.cleaned_data.get("rest_hostname")
+        self.instance.rest_port = self.cleaned_data.get("rest_port")
+        self.instance.no_container = self.cleaned_data.get("no_container")
+#        self.instance.external_hostname = self.cleaned_data.get("external_hostname")
+#        self.instance.external_container = self.cleaned_data.get("external_container")
+        return super(ONOSServiceForm, self).save(commit=commit)
+
+    class Meta:
+        model = ONOSService
+
+class ONOSServiceAdmin(ReadOnlyAwareAdmin):
+    model = ONOSService
+    verbose_name = "ONOS Service"
+    verbose_name_plural = "ONOS Services"
+    list_display = ("backend_status_icon", "name", "enabled")
+    list_display_links = ('backend_status_icon', 'name', )
+    fieldsets = [(None, {'fields': ['backend_status_text', 'name','enabled','versionNumber', 'description',"view_url","icon_url", "rest_hostname", "rest_port", "no_container" ], 'classes':['suit-tab suit-tab-general']})]
+    readonly_fields = ('backend_status_text', )
+    inlines = [SliceInline,ServiceAttrAsTabInline,ServicePrivilegeInline]
+    form = ONOSServiceForm
+
+    extracontext_registered_admins = True
+
+    user_readonly_fields = ["name", "enabled", "versionNumber", "description"]
+
+    suit_form_tabs =(('general', 'ONOS Service Details'),
+        ('administration', 'Administration'),
+        ('slices','Slices'),
+        ('serviceattrs','Additional Attributes'),
+        ('serviceprivileges','Privileges'),
+    )
+
+    suit_form_includes = (('onosadmin.html', 'top', 'administration'),
+                           )
+
+    def queryset(self, request):
+        return ONOSService.get_service_objects_by_user(request.user)
+
+class ONOSAppForm(forms.ModelForm):
+    creator = forms.ModelChoiceField(queryset=User.objects.all())
+    name = forms.CharField()
+    dependencies = forms.CharField(required=False)
+
+    def __init__(self,*args,**kwargs):
+        super (ONOSAppForm,self ).__init__(*args,**kwargs)
+        self.fields['kind'].widget.attrs['readonly'] = True
+        self.fields['provider_service'].queryset = ONOSService.get_service_objects().all()
+        if self.instance:
+            # fields for the attributes
+            self.fields['creator'].initial = self.instance.creator
+            self.fields['name'].initial = self.instance.name
+            self.fields['dependencies'].initial = self.instance.dependencies
+        if (not self.instance) or (not self.instance.pk):
+            # default fields for an 'add' form
+            self.fields['kind'].initial = ONOS_KIND
+            self.fields['creator'].initial = get_request().user
+            if ONOSService.get_service_objects().exists():
+               self.fields["provider_service"].initial = ONOSService.get_service_objects().all()[0]
+
+    def save(self, commit=True):
+        self.instance.creator = self.cleaned_data.get("creator")
+        self.instance.name = self.cleaned_data.get("name")
+        self.instance.dependencies = self.cleaned_data.get("dependencies")
+        return super(ONOSAppForm, self).save(commit=commit)
+
+    class Meta:
+        model = ONOSApp
+
+class ONOSAppAdmin(ReadOnlyAwareAdmin):
+    list_display = ('backend_status_icon', 'name', )
+    list_display_links = ('backend_status_icon', 'name')
+    fieldsets = [ (None, {'fields': ['backend_status_text', 'kind', 'name', 'provider_service', 'subscriber_service', 'service_specific_attribute', "dependencies",
+                                     'creator'],
+                          'classes':['suit-tab suit-tab-general']})]
+    readonly_fields = ('backend_status_text', 'instance', 'service_specific_attribute')
+    inlines = [TenantAttrAsTabInline]
+    form = ONOSAppForm
+
+    suit_form_tabs = (('general','Details'), ('tenantattrs', 'Attributes'))
+
+    def queryset(self, request):
+        return ONOSApp.get_tenant_objects_by_user(request.user)
+
+admin.site.register(ONOSService, ONOSServiceAdmin)
+admin.site.register(ONOSApp, ONOSAppAdmin)
+
diff --git a/xos/onboard/onos/api/service/onos.py b/xos/onboard/onos/api/service/onos.py
new file mode 100644
index 0000000..a143b3d
--- /dev/null
+++ b/xos/onboard/onos/api/service/onos.py
@@ -0,0 +1,87 @@
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+from rest_framework import serializers
+from rest_framework import generics
+from rest_framework import status
+from core.models import *
+from django.forms import widgets
+from services.onos.models import ONOSService
+from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
+from api.xosapi_helpers import PlusModelSerializer, XOSViewSet, ReadOnlyField
+
+class ONOSServiceSerializer(PlusModelSerializer):
+    id = ReadOnlyField()
+    rest_hostname = serializers.CharField(required=False)
+    rest_port = serializers.CharField(default="8181")
+    no_container = serializers.BooleanField(default=False)
+    node_key = serializers.CharField(required=False)
+
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    class Meta:
+        model = ONOSService
+        fields = ('humanReadableName', 'id', 'rest_hostname', 'rest_port', 'no_container', 'node_key')
+
+    def getHumanReadableName(self, obj):
+        return obj.__unicode__()
+
+class ServiceAttributeSerializer(serializers.Serializer):
+    id = ReadOnlyField()
+    name = serializers.CharField(required=False)
+    value = serializers.CharField(required=False)
+
+class ONOSServiceViewSet(XOSViewSet):
+    base_name = "onos"
+    method_name = "onos"
+    method_kind = "viewset"
+    queryset = ONOSService.get_service_objects().all()
+    serializer_class = ONOSServiceSerializer
+
+    custom_serializers = {"set_attribute": ServiceAttributeSerializer}
+
+    @classmethod
+    def get_urlpatterns(self, api_path="^"):
+        patterns = super(ONOSServiceViewSet, self).get_urlpatterns(api_path=api_path)
+
+        patterns.append( self.detail_url("attributes/$", {"get": "get_attributes", "post": "add_attribute"}, "attributes") )
+        patterns.append( self.detail_url("attributes/(?P<attribute>[0-9]+)/$", {"get": "get_attribute", "put": "set_attribute", "delete": "delete_attribute"}, "attribute") )
+
+        return patterns
+
+    def get_attributes(self, request, pk=None):
+        svc = self.get_object()
+        return Response(ServiceAttributeSerializer(svc.serviceattributes.all(), many=True).data)
+
+    def add_attribute(self, request, pk=None):
+        svc = self.get_object()
+        ser = ServiceAttributeSerializer(data=request.data)
+        ser.is_valid(raise_exception = True)
+        att = ServiceAttribute(service=svc, **ser.validated_data)
+        att.save()
+        return Response(ServiceAttributeSerializer(att).data)
+
+    def get_attribute(self, request, pk=None, attribute=None):
+        svc = self.get_object()
+        att = ServiceAttribute.objects.get(pk=attribute)
+        return Response(ServiceAttributeSerializer(att).data)
+
+    def set_attribute(self, request, pk=None, attribute=None):
+        svc = self.get_object()
+        att = ServiceAttribute.objects.get(pk=attribute)
+        ser = ServicettributeSerializer(att, data=request.data)
+        ser.is_valid(raise_exception = True)
+        att.name = ser.validated_data.get("name", att.name)
+        att.value = ser.validated_data.get("value", att.value)
+        att.save()
+        return Response(ServiceAttributeSerializer(att).data)
+
+    def delete_attribute(self, request, pk=None, attribute=None):
+        att = ServiceAttribute.objects.get(pk=attribute)
+        att.delete()
+        return Response(status=status.HTTP_204_NO_CONTENT)
+
+
+
+
+
+
diff --git a/xos/onboard/onos/api/tenant/onos/app.py b/xos/onboard/onos/api/tenant/onos/app.py
new file mode 100644
index 0000000..481057d
--- /dev/null
+++ b/xos/onboard/onos/api/tenant/onos/app.py
@@ -0,0 +1,91 @@
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+from rest_framework import serializers
+from rest_framework import generics
+from rest_framework import status
+from core.models import *
+from django.forms import widgets
+from services.onos.models import ONOSService, ONOSApp
+from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
+from api.xosapi_helpers import PlusModelSerializer, XOSViewSet, ReadOnlyField
+
+def get_default_onos_service():
+    onos_services = ONOSService.get_service_objects().all()
+    if onos_services:
+        return onos_services[0].id
+    return None
+
+class ONOSAppSerializer(PlusModelSerializer):
+    id = ReadOnlyField()
+    name = serializers.CharField()
+    dependencies = serializers.CharField()
+
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    class Meta:
+        model = ONOSApp
+        fields = ('humanReadableName', 'id', 'name', 'dependencies')
+
+    def getHumanReadableName(self, obj):
+        return obj.__unicode__()
+
+class TenantAttributeSerializer(serializers.Serializer):
+    id = ReadOnlyField()
+    name = serializers.CharField(required=False)
+    value = serializers.CharField(required=False)
+
+class ONOSAppViewSet(XOSViewSet):
+    base_name = "app"
+    method_name = "app"
+    method_kind = "viewset"
+    queryset = ONOSApp.get_tenant_objects().all()
+    serializer_class = ONOSAppSerializer
+
+    custom_serializers = {"set_attribute": TenantAttributeSerializer}
+
+    @classmethod
+    def get_urlpatterns(self, api_path="^"):
+        patterns = super(ONOSAppViewSet, self).get_urlpatterns(api_path=api_path)
+
+        patterns.append( self.detail_url("attributes/$", {"get": "get_attributes", "post": "add_attribute"}, "attributes") )
+        patterns.append( self.detail_url("attributes/(?P<attribute>[0-9]+)/$", {"get": "get_attribute", "put": "set_attribute", "delete": "delete_attribute"}, "attribute") )
+
+        return patterns
+
+    def get_attributes(self, request, pk=None):
+        app = self.get_object()
+        return Response(TenantAttributeSerializer(app.tenantattributes.all(), many=True).data)
+
+    def add_attribute(self, request, pk=None):
+        app = self.get_object()
+        ser = TenantAttributeSerializer(data=request.data)
+        ser.is_valid(raise_exception = True)
+        att = TenantAttribute(tenant=app, **ser.validated_data)
+        att.save()
+        return Response(TenantAttributeSerializer(att).data)
+
+    def get_attribute(self, request, pk=None, attribute=None):
+        app = self.get_object()
+        att = TenantAttribute.objects.get(pk=attribute)
+        return Response(TenantAttributeSerializer(att).data)
+
+    def set_attribute(self, request, pk=None, attribute=None):
+        app = self.get_object()
+        att = TenantAttribute.objects.get(pk=attribute)
+        ser = TenantAttributeSerializer(att, data=request.data)
+        ser.is_valid(raise_exception = True)
+        att.name = ser.validated_data.get("name", att.name)
+        att.value = ser.validated_data.get("value", att.value)
+        att.save()
+        return Response(TenantAttributeSerializer(att).data)
+
+    def delete_attribute(self, request, pk=None, attribute=None):
+        att = TenantAttribute.objects.get(pk=attribute)
+        att.delete()
+        return Response(status=status.HTTP_204_NO_CONTENT)
+
+
+
+
+
+
diff --git a/xos/onboard/onos/models.py b/xos/onboard/onos/models.py
new file mode 100644
index 0000000..20fa73f
--- /dev/null
+++ b/xos/onboard/onos/models.py
@@ -0,0 +1,146 @@
+from django.db import models
+from core.models import Service, PlCoreBase, Slice, Instance, Tenant, TenantWithContainer, Node, Image, User, Flavor, Subscriber
+from core.models.plcorebase import StrippedCharField
+import os
+from django.db import models, transaction
+from django.forms.models import model_to_dict
+from django.db.models import Q
+from operator import itemgetter, attrgetter, methodcaller
+import traceback
+from xos.exceptions import *
+from core.models import SlicePrivilege, SitePrivilege
+from sets import Set
+
+ONOS_KIND = "onos"
+
+class ONOSService(Service):
+    KIND = ONOS_KIND
+
+    class Meta:
+        app_label = "onos"
+        verbose_name = "ONOS Service"
+        proxy = True
+
+    default_attributes = {"rest_hostname": "",
+                          "rest_port": "8181",
+                          "no_container": False,
+                          "node_key": ""}
+
+    @property
+    def rest_hostname(self):
+        return self.get_attribute("rest_hostname", self.default_attributes["rest_hostname"])
+
+    @rest_hostname.setter
+    def rest_hostname(self, value):
+        self.set_attribute("rest_hostname", value)
+
+    @property
+    def rest_port(self):
+        return self.get_attribute("rest_port", self.default_attributes["rest_port"])
+
+    @rest_port.setter
+    def rest_port(self, value):
+        self.set_attribute("rest_port", value)
+
+    @property
+    def no_container(self):
+        return self.get_attribute("no_container", self.default_attributes["no_container"])
+
+    @no_container.setter
+    def no_container(self, value):
+        self.set_attribute("no_container", value)
+
+    @property
+    def node_key(self):
+        return self.get_attribute("node_key", self.default_attributes["node_key"])
+
+    @node_key.setter
+    def node_key(self, value):
+        self.set_attribute("node_key", value)
+
+
+class ONOSApp(Tenant):   # aka 'ONOSTenant'
+    class Meta:
+        proxy = True
+
+    KIND = ONOS_KIND
+
+    default_attributes = {"name": "",
+                          "install_dependencies": "",
+                          "dependencies": ""}
+    def __init__(self, *args, **kwargs):
+        onos_services = ONOSService.get_service_objects().all()
+        if onos_services:
+            self._meta.get_field("provider_service").default = onos_services[0].id
+        super(ONOSApp, self).__init__(*args, **kwargs)
+
+    @property
+    def creator(self):
+        from core.models import User
+        if getattr(self, "cached_creator", None):
+            return self.cached_creator
+        creator_id=self.get_attribute("creator_id")
+        if not creator_id:
+            return None
+        users=User.objects.filter(id=creator_id)
+        if not users:
+            return None
+        user=users[0]
+        self.cached_creator = users[0]
+        return user
+
+    @creator.setter
+    def creator(self, value):
+        if value:
+            value = value.id
+        if (value != self.get_attribute("creator_id", None)):
+            self.cached_creator=None
+        self.set_attribute("creator_id", value)
+
+    @property
+    def name(self):
+        return self.get_attribute("name", self.default_attributes["name"])
+
+    @name.setter
+    def name(self, value):
+        self.set_attribute("name", value)
+
+    @property
+    def dependencies(self):
+        return self.get_attribute("dependencies", self.default_attributes["dependencies"])
+
+    @dependencies.setter
+    def dependencies(self, value):
+        self.set_attribute("dependencies", value)
+
+    @property
+    def install_dependencies(self):
+        return self.get_attribute("install_dependencies", self.default_attributes["install_dependencies"])
+
+    @install_dependencies.setter
+    def install_dependencies(self, value):
+        self.set_attribute("install_dependencies", value)
+
+    def save(self, *args, **kwargs):
+        if not self.creator:
+            if not getattr(self, "caller", None):
+                # caller must be set when creating a vCPE since it creates a slice
+                raise XOSProgrammingError("ONOSApp's self.caller was not set")
+            self.creator = self.caller
+            if not self.creator:
+                raise XOSProgrammingError("ONOSApp's self.creator was not set")
+
+        super(ONOSApp, self).save(*args, **kwargs)
+        model_policy_onos_app(self.pk)
+
+# TODO: Probably don't need this...
+def model_policy_onos_app(pk):
+    # TODO: this should be made in to a real model_policy
+    with transaction.atomic():
+        oa = ONOSApp.objects.select_for_update().filter(pk=pk)
+        if not oa:
+            return
+        oa = oa[0]
+        #oa.manage_container()
+
+
diff --git a/xos/onboard/onos/onos-onboard.yaml b/xos/onboard/onos/onos-onboard.yaml
new file mode 100644
index 0000000..3d4ac3b
--- /dev/null
+++ b/xos/onboard/onos/onos-onboard.yaml
@@ -0,0 +1,27 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Onboard the exampleservice
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    servicecontroller#onos:
+      type: tosca.nodes.ServiceController
+      properties:
+          base_url: file:///opt/xos/onboard/onos/
+          # The following will concatenate with base_url automatically, if
+          # base_url is non-null.
+          models: models.py
+          admin: admin.py
+          admin_template: templates/onosadmin.html
+          synchronizer: synchronizer/manifest
+          synchronizer_run: onos-synchronizer.py
+          #tosca_custom_types: exampleservice.yaml
+          tosca_resource: tosca/resources/onosservice.py, tosca/resources/onosapp.py
+          rest_service: api/service/onos.py
+          rest_tenant: subdirectory:onos api/tenant/onos/app.py
+          private_key: file:///opt/xos/key_import/onos_rsa
+          public_key: file:///opt/xos/key_import/onos_rsa.pub
+
diff --git a/xos/onboard/onos/synchronizer/manifest b/xos/onboard/onos/synchronizer/manifest
new file mode 100644
index 0000000..b96216a
--- /dev/null
+++ b/xos/onboard/onos/synchronizer/manifest
@@ -0,0 +1,16 @@
+manifest
+onos-ext-volt-event-publisher-1.0-SNAPSHOT.oar
+scripts/dockerip.sh
+steps/sync_onosapp.py
+steps/sync_onosapp_nocontainer.yaml
+steps/sync_onosservice.py
+steps/sync_onosservice.yaml
+steps/sync_onosapp.yaml
+onos-ext-notifier-1.0-SNAPSHOT.oar
+start.sh
+stop.sh
+model-deps
+onos_synchronizer_config
+supervisor/onos-observer.conf
+run.sh
+onos-synchronizer.py
diff --git a/xos/onboard/onos/synchronizer/model-deps b/xos/onboard/onos/synchronizer/model-deps
new file mode 100644
index 0000000..2da80e0
--- /dev/null
+++ b/xos/onboard/onos/synchronizer/model-deps
@@ -0,0 +1,5 @@
+{
+    "ONOSApp": [
+        "ONOSService"
+    ]
+}
diff --git a/xos/onboard/onos/synchronizer/onos-ext-notifier-1.0-SNAPSHOT.oar b/xos/onboard/onos/synchronizer/onos-ext-notifier-1.0-SNAPSHOT.oar
new file mode 100644
index 0000000..23c6fcd
--- /dev/null
+++ b/xos/onboard/onos/synchronizer/onos-ext-notifier-1.0-SNAPSHOT.oar
Binary files differ
diff --git a/xos/onboard/onos/synchronizer/onos-ext-volt-event-publisher-1.0-SNAPSHOT.oar b/xos/onboard/onos/synchronizer/onos-ext-volt-event-publisher-1.0-SNAPSHOT.oar
new file mode 100644
index 0000000..244f589
--- /dev/null
+++ b/xos/onboard/onos/synchronizer/onos-ext-volt-event-publisher-1.0-SNAPSHOT.oar
Binary files differ
diff --git a/xos/onboard/onos/synchronizer/onos-synchronizer.py b/xos/onboard/onos/synchronizer/onos-synchronizer.py
new file mode 100755
index 0000000..84bec4f
--- /dev/null
+++ b/xos/onboard/onos/synchronizer/onos-synchronizer.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+# This imports and runs ../../xos-observer.py
+
+import importlib
+import os
+import sys
+observer_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),"../../synchronizers/base")
+sys.path.append(observer_path)
+mod = importlib.import_module("xos-synchronizer")
+mod.main()
diff --git a/xos/onboard/onos/synchronizer/onos_synchronizer_config b/xos/onboard/onos/synchronizer/onos_synchronizer_config
new file mode 100644
index 0000000..c6ceece
--- /dev/null
+++ b/xos/onboard/onos/synchronizer/onos_synchronizer_config
@@ -0,0 +1,41 @@
+
+[plc]
+name=plc
+deployment=VICCI
+
+[db]
+name=xos
+user=postgres
+password=password
+host=localhost
+port=5432
+
+[api]
+host=128.112.171.237
+port=8000
+ssl_key=None
+ssl_cert=None
+ca_ssl_cert=None
+ratelimit_enabled=0
+omf_enabled=0
+mail_support_address=support@localhost
+nova_enabled=True
+
+[observer]
+name=onos
+dependency_graph=/opt/xos/synchronizers/onos/model-deps
+steps_dir=/opt/xos/synchronizers/onos/steps
+sys_dir=/opt/xos/synchronizers/onos/sys
+deleters_dir=/opt/xos/synchronizers/onos/deleters
+log_file=console
+driver=None
+pretend=False
+backoff_disabled=True
+save_ansible_output=True
+# set proxy_ssh to false on cloudlab
+proxy_ssh=False
+full_setup=True
+
+[feefie]
+client_id='vicci_dev_central'
+user_id='pl'
diff --git a/xos/onboard/onos/synchronizer/run.sh b/xos/onboard/onos/synchronizer/run.sh
new file mode 100755
index 0000000..b108d5b
--- /dev/null
+++ b/xos/onboard/onos/synchronizer/run.sh
@@ -0,0 +1,6 @@
+#if [[ ! -e ./vcpe-observer.py ]]; then
+#    ln -s ../../xos-observer.py vcpe-observer.py
+#fi
+
+export XOS_DIR=/opt/xos
+python onos-synchronizer.py  -C $XOS_DIR/synchronizers/onos/onos_synchronizer_config
diff --git a/xos/onboard/onos/synchronizer/scripts/dockerip.sh b/xos/onboard/onos/synchronizer/scripts/dockerip.sh
new file mode 100644
index 0000000..732c3fe
--- /dev/null
+++ b/xos/onboard/onos/synchronizer/scripts/dockerip.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+MODE=`docker inspect --format '{{ .HostConfig.NetworkMode }}' $1  | tr -d '\n' | tr -d '\r'`
+if [[ "$MODE" == "host" ]]; then
+    echo -n "127.0.0.1"
+else
+    docker inspect --format '{{ .NetworkSettings.IPAddress }}' $1 | tr -d '\n' | tr -d '\r'
+fi
+
diff --git a/xos/onboard/onos/synchronizer/start.sh b/xos/onboard/onos/synchronizer/start.sh
new file mode 100755
index 0000000..f0a1535
--- /dev/null
+++ b/xos/onboard/onos/synchronizer/start.sh
@@ -0,0 +1,6 @@
+#if [[ ! -e ./vcpe-observer.py ]]; then
+#    ln -s ../../xos-observer.py vcpe-observer.py
+#fi
+
+export XOS_DIR=/opt/xos
+nohup python onos-synchronizer.py  -C $XOS_DIR/synchronizers/onos/onos_synchronizer_config > /dev/null 2>&1 &
diff --git a/xos/onboard/onos/synchronizer/steps/sync_onosapp.py b/xos/onboard/onos/synchronizer/steps/sync_onosapp.py
new file mode 100644
index 0000000..78a8cc8
--- /dev/null
+++ b/xos/onboard/onos/synchronizer/steps/sync_onosapp.py
@@ -0,0 +1,536 @@
+import hashlib
+import os
+import socket
+import sys
+import base64
+import time
+import re
+import json
+from collections import OrderedDict
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.ansible import run_template
+from synchronizers.base.syncstep import SyncStep
+from synchronizers.base.ansible import run_template_ssh
+from synchronizers.base.SyncInstanceUsingAnsible import SyncInstanceUsingAnsible
+from core.models import Service, Slice, Controller, ControllerSlice, ControllerUser, Node, TenantAttribute, Tag
+from services.onos.models import ONOSService, ONOSApp
+from xos.logger import Logger, logging
+from services.vrouter.models import VRouterService
+from services.vtn.models import VTNService
+from services.volt.models import VOLTService, VOLTDevice, AccessDevice
+
+# hpclibrary will be in steps/..
+parentdir = os.path.join(os.path.dirname(__file__),"..")
+sys.path.insert(0,parentdir)
+
+logger = Logger(level=logging.INFO)
+
+class SyncONOSApp(SyncInstanceUsingAnsible):
+    provides=[ONOSApp]
+    observes=ONOSApp
+    requested_interval=0
+    template_name = "sync_onosapp.yaml"
+    #service_key_name = "/opt/xos/synchronizers/onos/onos_key"
+
+    def __init__(self, *args, **kwargs):
+        super(SyncONOSApp, self).__init__(*args, **kwargs)
+
+    def fetch_pending(self, deleted):
+        if (not deleted):
+            objs = ONOSApp.get_tenant_objects().filter(Q(enacted__lt=F('updated')) | Q(enacted=None),Q(lazy_blocked=False))
+        else:
+            objs = ONOSApp.get_deleted_tenant_objects()
+
+        return objs
+
+    def get_instance(self, o):
+        # We assume the ONOS service owns a slice, so pick one of the instances
+        # inside that slice to sync to.
+
+        serv = self.get_onos_service(o)
+
+        if serv.no_container:
+            raise Exception("get_instance() was called on a service that was marked no_container")
+
+        if serv.slices.exists():
+            slice = serv.slices.all()[0]
+            if slice.instances.exists():
+                return slice.instances.all()[0]
+
+        return None
+
+    def get_onos_service(self, o):
+        if not o.provider_service:
+            return None
+
+        onoses = ONOSService.get_service_objects().filter(id=o.provider_service.id)
+        if not onoses:
+            return None
+
+        return onoses[0]
+
+    def is_no_container(self, o):
+        return self.get_onos_service(o).no_container
+
+    def skip_ansible_fields(self, o):
+        return self.is_no_container(o)
+
+    def get_files_dir(self, o):
+        if not hasattr(Config(), "observer_steps_dir"):
+            # make steps_dir mandatory; there's no valid reason for it to not
+            # be defined.
+            raise Exception("observer_steps_dir is not defined in config file")
+
+        step_dir = Config().observer_steps_dir
+
+        return os.path.join(step_dir, "..", "files", str(self.get_onos_service(o).id), o.name)
+
+    def get_cluster_configuration(self, o):
+        instance = self.get_instance(o)
+        if not instance:
+           raise Exception("No instance for ONOS App")
+        node_ips = [socket.gethostbyname(instance.node.name)]
+
+        ipPrefix = ".".join(node_ips[0].split(".")[:3]) + ".*"
+        result = '{ "nodes": ['
+        result = result + ",".join(['{ "ip": "%s"}' % ip for ip in node_ips])
+        result = result + '], "ipPrefix": "%s"}' % ipPrefix
+        return result
+
+    def get_dynamic_parameter_value(self, o, param):
+        instance = self.get_instance(o)
+        if not instance:
+           raise Exception("No instance for ONOS App")
+        if param == 'rabbit_host':
+            return instance.controller.rabbit_host
+        if param == 'rabbit_user':
+            return instance.controller.rabbit_user
+        if param == 'rabbit_password':
+            return instance.controller.rabbit_password
+        if param == 'keystone_tenant_id':
+            cslice = ControllerSlice.objects.get(slice=instance.slice)
+            if not cslice:
+                raise Exception("Controller slice object for %s does not exist" % instance.slice.name)
+            return cslice.tenant_id
+        if param == 'keystone_user_id':
+            cuser = ControllerUser.objects.get(user=instance.creator)
+            if not cuser:
+                raise Exception("Controller user object for %s does not exist" % instance.creator)
+            return cuser.kuser_id
+
+    def get_node_tag(self, o, node, tagname):
+        tags = Tag.select_by_content_object(node).filter(name=tagname)
+        return tags[0].value
+
+    # Scan attrs for attribute name
+    # If it's not present, save it as a TenantAttribute
+    def attribute_default(self, tenant, attrs, name, default):
+        if name in attrs:
+            value = attrs[name]
+        else:
+            value = default
+            logger.info("saving default value %s for attribute %s" % (value, name))
+            ta = TenantAttribute(tenant=tenant, name=name, value=value)
+            ta.save()
+        return value
+
+    # This function currently assumes a single Deployment and Site
+    def get_vtn_config(self, o, attrs):
+
+        privateGatewayMac = None
+        localManagementIp = None
+        ovsdbPort = None
+        sshPort = None
+        sshUser = None
+        sshKeyFile = None
+        mgmtSubnetBits = None
+        xosEndpoint = None
+        xosUser = None
+        xosPassword = None
+
+        # VTN-specific configuration from the VTN Service
+        vtns = VTNService.get_service_objects().all()
+        if vtns:
+            vtn = vtns[0]
+            privateGatewayMac = vtn.privateGatewayMac
+            localManagementIp = vtn.localManagementIp
+            ovsdbPort = vtn.ovsdbPort
+            sshPort = vtn.sshPort
+            sshUser = vtn.sshUser
+            sshKeyFile = vtn.sshKeyFile
+            mgmtSubnetBits = vtn.mgmtSubnetBits
+            xosEndpoint = vtn.xosEndpoint
+            xosUser = vtn.xosUser
+            xosPassword = vtn.xosPassword
+
+        # OpenStack endpoints and credentials
+        keystone_server = "http://keystone:5000/v2.0/"
+        user_name = "admin"
+        password = "ADMIN_PASS"
+        controllers = Controller.objects.all()
+        if controllers:
+            controller = controllers[0]
+            keystone_server = controller.auth_url
+            user_name = controller.admin_user
+            tenant_name = controller.admin_tenant
+            password = controller.admin_password
+
+        data = {
+            "apps" : {
+                "org.onosproject.cordvtn" : {
+                    "cordvtn" : {
+                        "privateGatewayMac" : privateGatewayMac,
+                        "localManagementIp": localManagementIp,
+                        "ovsdbPort": ovsdbPort,
+                        "ssh": {
+                            "sshPort": sshPort,
+                            "sshUser": sshUser,
+                            "sshKeyFile": sshKeyFile
+                        },
+                        "openstack": {
+                            "endpoint": keystone_server,
+                            "tenant": tenant_name,
+                            "user": user_name,
+                            "password": password
+                        },
+                        "xos": {
+                            "endpoint": xosEndpoint,
+                            "user": xosUser,
+                            "password": xosPassword
+                        },
+                        "publicGateways": [],
+                        "nodes" : []
+                    }
+                }
+            }
+        }
+
+        # Generate apps->org.onosproject.cordvtn->cordvtn->nodes
+        nodes = Node.objects.all()
+        for node in nodes:
+            nodeip = socket.gethostbyname(node.name)
+
+            try:
+                bridgeId = self.get_node_tag(o, node, "bridgeId")
+                dataPlaneIntf = self.get_node_tag(o, node, "dataPlaneIntf")
+                dataPlaneIp = self.get_node_tag(o, node, "dataPlaneIp")
+            except:
+                logger.error("not adding node %s to the VTN configuration" % node.name)
+                continue
+
+            node_dict = {
+                "hostname": node.name,
+                "hostManagementIp": "%s/%s" % (nodeip, mgmtSubnetBits),
+                "bridgeId": bridgeId,
+                "dataPlaneIntf": dataPlaneIntf,
+                "dataPlaneIp": dataPlaneIp
+            }
+            data["apps"]["org.onosproject.cordvtn"]["cordvtn"]["nodes"].append(node_dict)
+
+        # Generate apps->org.onosproject.cordvtn->cordvtn->publicGateways
+        # Pull the gateway information from vRouter
+        vrouters = VRouterService.get_service_objects().all()
+        if vrouters:
+            for gateway in vrouters[0].get_gateways():
+                gatewayIp = gateway['gateway_ip'].split('/',1)[0]
+                gatewayMac = gateway['gateway_mac']
+                gateway_dict = {
+                    "gatewayIp": gatewayIp,
+                    "gatewayMac": gatewayMac
+                }
+                data["apps"]["org.onosproject.cordvtn"]["cordvtn"]["publicGateways"].append(gateway_dict)
+
+        return json.dumps(data, indent=4, sort_keys=True)
+
+    def get_volt_network_config(self, o, attrs):
+        try:
+            volt = VOLTService.get_service_objects().all()[0]
+        except:
+            return None
+
+        devices = []
+        for voltdev in volt.volt_devices.all():
+            access_devices = []
+            for access in voltdev.access_devices.all():
+                access_device = {
+                    "uplink" : access.uplink,
+                    "vlan" : access.vlan
+                }
+                access_devices.append(access_device)
+
+            if voltdev.access_agent:
+                agent = voltdev.access_agent
+                olts = {}
+                for port_mapping in agent.port_mappings.all():
+                    olts[port_mapping.port] = port_mapping.mac
+                agent_config = {
+                    "olts" : olts,
+                    "mac" : agent.mac
+                }
+
+            device = {
+                voltdev.openflow_id : {
+                    "accessDevice" : access_devices,
+                    "accessAgent" : agent_config
+                },
+                "basic" : {
+                    "driver" : voltdev.driver
+                }
+            }
+            devices.append(device)
+
+        data = {
+            "devices" : devices
+        }
+        return json.dumps(data, indent=4, sort_keys=True)
+
+    def get_volt_component_config(self, o, attrs):
+        data = {
+            "org.ciena.onos.ext_notifier.KafkaNotificationBridge":{
+                "rabbit.user": "<rabbit_user>",
+                "rabbit.password": "<rabbit_password>",
+                "rabbit.host": "<rabbit_host>",
+                "publish.kafka": "false",
+                "publish.rabbit": "true",
+                "volt.events.rabbit.topic": "notifications.info",
+                "volt.events.rabbit.exchange": "voltlistener",
+                "volt.events.opaque.info": "{project_id: <keystone_tenant_id>, user_id: <keystone_user_id>}",
+                "publish.volt.events": "true"
+            }
+        }
+        return json.dumps(data, indent=4, sort_keys=True)
+
+    def get_vrouter_network_config(self, o, attrs):
+        # From the onosproject wiki:
+        # https://wiki.onosproject.org/display/ONOS/vRouter
+        data = {
+            "devices" : {
+                "of:00000000000000b1" : {
+                    "basic" : {
+                        "driver" : "softrouter"
+                    }
+                }
+            },
+            "ports" : {
+                "of:00000000000000b1/1" : {
+                    "interfaces" : [
+                        {
+                            "name" : "b1-1",
+                            "ips"  : [ "10.0.1.2/24" ],
+                            "mac"  : "00:00:00:00:00:01"
+                        }
+                    ]
+                },
+                "of:00000000000000b1/2" : {
+                    "interfaces" : [
+                        {
+                            "name" : "b1-2",
+                            "ips"  : [ "10.0.2.2/24" ],
+                            "mac"  : "00:00:00:00:00:01"
+                        }
+                    ]
+                },
+                "of:00000000000000b1/3" : {
+                    "interfaces" : [
+                        {
+                            "name" : "b1-3",
+                            "ips"  : [ "10.0.3.2/24" ],
+                            "mac"  : "00:00:00:00:00:01"
+                        }
+                    ]
+                },
+                "of:00000000000000b1/4" : {
+                    "interfaces" : [
+                        {
+                            "name" : "b1-4",
+                            "ips"  : [ "10.0.4.2/24" ],
+                            "mac"  : "00:00:00:00:00:02",
+                            "vlan" : "100"
+                        }
+                    ]
+                }
+            },
+            "apps" : {
+                "org.onosproject.router" : {
+                    "router" : {
+                        "controlPlaneConnectPoint" : "of:00000000000000b1/5",
+                        "ospfEnabled" : "true",
+                        "interfaces" : [ "b1-1", "b1-2", "b1-2", "b1-4" ]
+                    }
+                }
+            }
+        }
+        return json.dumps(data, indent=4, sort_keys=True)
+
+    def write_configs(self, o):
+        o.config_fns = []
+        o.rest_configs = []
+        o.component_configs = []
+        o.files_dir = self.get_files_dir(o)
+
+        if not os.path.exists(o.files_dir):
+            os.makedirs(o.files_dir)
+
+        # Combine the service attributes with the tenant attributes. Tenant
+        # attribute can override service attributes.
+        attrs = o.provider_service.serviceattribute_dict
+        attrs.update(o.tenantattribute_dict)
+
+        ordered_attrs = attrs.keys()
+
+        onos = self.get_onos_service(o)
+        if onos.node_key:
+            file(os.path.join(o.files_dir, "node_key"),"w").write(onos.node_key)
+            o.node_key_fn="node_key"
+        else:
+            o.node_key_fn=None
+
+        o.early_rest_configs=[]
+        if ("cordvtn" in o.dependencies) and (not self.is_no_container(o)):
+            # For VTN, since it's running in a docker host container, we need
+            # to make sure it configures the cluster using the right ip addresses.
+            # NOTE: rest_onos/v1/cluster/configuration/ will reboot the cluster and
+            #   must go first.
+            name="rest_onos/v1/cluster/configuration/"
+            value= self.get_cluster_configuration(o)
+            fn = name[5:].replace("/","_")
+            endpoint = name[5:]
+            file(os.path.join(o.files_dir, fn),"w").write(" " +value)
+            o.early_rest_configs.append( {"endpoint": endpoint, "fn": fn} )
+
+        # Generate config files and save them to the appropriate tenant attributes
+        configs = []
+        for key, value in attrs.iteritems():
+            if key == "autogenerate" and value:
+                for config in value.split(','):
+                    configs.append(config.strip())
+
+        for label in configs:
+            config = None
+            value = None
+            if label == "vtn-network-cfg":
+                # Generate the VTN config file... where should this live?
+                config = "rest_onos/v1/network/configuration/"
+                value = self.get_vtn_config(o, attrs)
+            elif label == "volt-network-cfg":
+                config = "rest_onos/v1/network/configuration/"
+                value = self.get_volt_network_config(o, attrs)
+            elif label == "volt-component-cfg":
+                config = "component_config"
+                value = self.get_volt_component_config(o, attrs)
+            elif label == "vrouter-network-cfg":
+                config = "rest_onos/v1/network/configuration/"
+                value = self.get_vrouter_network_config(o, attrs)
+
+            if config:
+                tas = TenantAttribute.objects.filter(tenant=o, name=config)
+                if tas:
+                    ta = tas[0]
+                    if ta.value != value:
+                        logger.info("updating %s with autogenerated config" % config)
+                        ta.value = value
+                        ta.save()
+                        attrs[config] = value
+                else:
+                    logger.info("saving autogenerated config %s" % config)
+                    ta = TenantAttribute(tenant=o, name=config, value=value)
+                    ta.save()
+                    attrs[config] = value
+
+        for name in attrs.keys():
+            value = attrs[name]
+            if name.startswith("config_"):
+                fn = name[7:] # .replace("_json",".json")
+                o.config_fns.append(fn)
+                file(os.path.join(o.files_dir, fn),"w").write(value)
+            if name.startswith("rest_"):
+                fn = name[5:].replace("/","_")
+                endpoint = name[5:]
+                # Ansible goes out of it's way to make our life difficult. If
+                # 'lookup' sees a file that it thinks contains json, then it'll
+                # insist on parsing and return a json object. We just want
+                # a string, so prepend a space and then strip the space off
+                # later.
+                file(os.path.join(o.files_dir, fn),"w").write(" " +value)
+                o.rest_configs.append( {"endpoint": endpoint, "fn": fn} )
+            if name.startswith("component_config"):
+                components = json.loads(value,object_pairs_hook=OrderedDict)
+                for component in components.keys():
+                    config = components[component]
+                    for key in config.keys():
+                         config_val = config[key]
+                         found = re.findall('<(.+?)>',config_val)
+                         for x in found:
+                            #Get value corresponding to that string
+                            val = self.get_dynamic_parameter_value(o, x)
+                            if val:
+	                       config_val = re.sub('<'+x+'>', val, config_val)
+                            #TODO: else raise an exception?
+	                 o.component_configs.append( {"component": component, "config_params": "'{\""+key+"\":\""+config_val+"\"}'"} )
+
+    def prepare_record(self, o):
+        self.write_configs(o)
+
+    def get_extra_attributes_common(self, o):
+        fields = {}
+
+        # These are attributes that are not dependent on Instance. For example,
+        # REST API stuff.
+
+        onos = self.get_onos_service(o)
+
+        fields["files_dir"] = o.files_dir
+        fields["appname"] = o.name
+        fields["rest_configs"] = o.rest_configs
+        fields["rest_hostname"] = onos.rest_hostname
+        fields["rest_port"] = onos.rest_port
+
+        if o.dependencies:
+            fields["dependencies"] = [x.strip() for x in o.dependencies.split(",")]
+        else:
+            fields["dependencies"] = []
+
+        return fields
+
+    def get_extra_attributes_full(self, o):
+        instance = self.get_instance(o)
+
+        fields = self.get_extra_attributes_common(o)
+
+        fields["config_fns"] = o.config_fns
+        fields["early_rest_configs"] = o.early_rest_configs
+        fields["component_configs"] = o.component_configs
+        fields["node_key_fn"] = o.node_key_fn
+
+        if o.install_dependencies:
+            fields["install_dependencies"] = [x.strip() for x in o.install_dependencies.split(",")]
+        else:
+            fields["install_dependencies"] = []
+
+        if (instance.isolation=="container"):
+            fields["ONOS_container"] = "%s-%s" % (instance.slice.name, str(instance.id))
+        else:
+            fields["ONOS_container"] = "ONOS"
+        return fields
+
+    def get_extra_attributes(self, o):
+        if self.is_no_container(o):
+            return self.get_extra_attributes_common(o)
+        else:
+            return self.get_extra_attributes_full(o)
+
+    def sync_fields(self, o, fields):
+        # the super causes the playbook to be run
+        super(SyncONOSApp, self).sync_fields(o, fields)
+
+    def run_playbook(self, o, fields):
+        if self.is_no_container(o):
+            # There is no machine to SSH to, so use the synchronizer's
+            # run_template method directly.
+            run_template("sync_onosapp_nocontainer.yaml", fields)
+        else:
+            super(SyncONOSApp, self).run_playbook(o, fields)
+
+    def delete_record(self, m):
+        pass
diff --git a/xos/onboard/onos/synchronizer/steps/sync_onosapp.yaml b/xos/onboard/onos/synchronizer/steps/sync_onosapp.yaml
new file mode 100644
index 0000000..8235286
--- /dev/null
+++ b/xos/onboard/onos/synchronizer/steps/sync_onosapp.yaml
@@ -0,0 +1,172 @@
+---
+- hosts: {{ instance_name }}
+  gather_facts: False
+  connection: ssh
+  user: {{ username }}
+  sudo: yes
+  vars:
+    appname: {{ appname }}
+    dependencies: {{ dependencies }}
+{% if component_configs %}
+    component_configs:
+{% for component_config in component_configs %}
+       - component: {{ component_config.component }}
+         config_params: {{  component_config.config_params }}
+{% endfor %}
+{% endif %}
+{% if rest_configs %}
+    rest_configs:
+{% for rest_config in rest_configs %}
+       - endpoint: {{ rest_config.endpoint }}
+         body: "{{ '{{' }} lookup('file', '{{ files_dir }}/{{ rest_config.fn }}') {{ '}}' }}"
+{% endfor %}
+{% endif %}
+{% if early_rest_configs %}
+    early_rest_configs:
+{% for early_rest_config in early_rest_configs %}
+       - endpoint: {{ early_rest_config.endpoint }}
+         body: "{{ '{{' }} lookup('file', '{{ files_dir }}/{{ early_rest_config.fn }}') {{ '}}' }}"
+{% endfor %}
+{% endif %}
+
+  tasks:
+
+  - name: Get Docker IP
+    script: /opt/xos/synchronizers/onos/scripts/dockerip.sh {{ ONOS_container }}
+    register: onosaddr
+
+  - name: Wait for ONOS to come up
+    wait_for:
+      host={{ '{{' }} onosaddr.stdout {{ '}}' }}
+      port={{ '{{' }} item {{ '}}' }}
+      state=present
+    with_items:
+    - 8101
+    - 8181
+    - 9876
+
+  - name: Config file directory
+    file:
+      path=/home/ubuntu/{{ appname }}/
+      state=directory
+
+{% if node_key_fn %}
+  - name: Copy over key
+    copy:
+      src={{ files_dir }}/{{ node_key_fn }}
+      dest=/home/ubuntu/node_key
+
+  - name: Copy node key into container
+    shell: docker cp /home/ubuntu/node_key {{ ONOS_container }}:/root/node_key
+{% endif %}
+
+{% if config_fns %}
+  - name: Copy over configuration files
+    copy:
+      src={{ files_dir }}/{{ '{{' }} item {{ '}}' }}
+      dest=/home/ubuntu/{{ appname }}/{{ '{{' }} item {{ '}}' }}
+    with_items:
+        {% for config_fn in config_fns %}
+        - {{ config_fn }}
+        {% endfor %}
+
+  - name: Make sure config directory exists
+    shell: docker exec {{ ONOS_container }} mkdir -p /root/onos/config/
+    sudo: yes
+
+  - name: Copy config files into container
+    shell: docker cp {{ appname }}/{{ '{{' }} item {{ '}}' }} {{ ONOS_container }}:/root/onos/config/
+    sudo: yes
+    with_items:
+        {% for config_fn in config_fns %}
+        - {{ config_fn }}
+        {% endfor %}
+{% endif %}
+
+  # Don't know how to check for this condition, just wait
+  - name: Wait for ONOS to install the apps
+    wait_for: timeout=15
+
+{% if early_rest_configs %}
+  - name: Add ONOS early configuration values
+    uri:
+      url: http://{{ '{{' }} onosaddr.stdout {{ '}}' }}:8181/{{ '{{' }} item.endpoint {{ '}}' }}
+      body: "{{ '{{' }} item.body {{ '}}' }}"
+      body_format: raw
+      method: POST
+      user: karaf
+      password: karaf
+    with_items: "early_rest_configs"
+
+  # Don't know how to check for this condition, just wait
+  - name: Wait for ONOS to restart
+    wait_for: timeout=15
+{% endif %}
+
+{% if install_dependencies %}
+  - name: Install app file directory
+    file:
+      path=/home/ubuntu/{{ appname }}/apps/
+      state=directory
+
+  - name: Copy over app install files to ONOS host
+    copy:
+      src=/opt/xos/synchronizers/onos/{{ '{{' }} item {{ '}}' }}
+      dest=/home/ubuntu/{{ appname }}/apps/{{ '{{' }} item {{ '}}' }}
+    with_items:
+        {% for install_app in install_dependencies %}
+        - {{ install_app }}
+        {% endfor %}
+
+  - name: POST onos-app install command
+    command: >
+        curl -XPOST -HContent-Type:application/octet-stream -u karaf:karaf --data-binary @/home/ubuntu/{{ appname }}/apps/{{ '{{' }} item {{ '}}' }} http://{{ '{{' }} onosaddr.stdout  {{ '}}' }}:8181/onos/v1/applications
+    with_items:
+        {% for dependency in install_dependencies %}
+        - {{ dependency }}
+        {% endfor %}
+{% endif %}
+
+{% if dependencies %}
+  - name: Add dependencies to ONOS
+    uri:
+      url: http://{{ '{{' }} onosaddr.stdout {{ '}}' }}:8181/onos/v1/applications/{{ '{{' }} item {{ '}}' }}/active
+      method: POST
+      user: karaf
+      password: karaf
+    with_items:
+        {% for dependency in dependencies %}
+        - {{ dependency }}
+        {% endfor %}
+{% endif %}
+
+{% if component_configs %}
+  - name: Add ONOS component configuration values
+    command: >
+        curl -XPOST -HContent-Type:application/json -u karaf:karaf -d {{ '{{' }} item.config_params | to_json {{ '}}' }} http://{{ '{{' }} onosaddr.stdout  {{ '}}' }}:8181/onos/v1/configuration/{{
+ '{{' }} item.component {{ '}}' }}
+    with_items: "component_configs"
+
+#    uri:
+#      url: http://{{ '{{' }} onosaddr.stdout {{ '}}' }}:8181/onos/v1/configuration/{{ '{{' }} item.component {{ '}}' }} #http://localhost:8181/onos/v1/configuration/
+#      body: "{{ '{{' }} item.config_params | to_json {{ '}}' }}"
+#      body_format: json
+#      method: POST
+#      user: karaf
+#      password: karaf
+#    with_items: "component_configs"
+{% endif %}
+
+{% if rest_configs %}
+# Do this after services have been activated, or it will cause an exception.
+# vOLT will re-read its net config; vbng may not.
+  - name: Add ONOS configuration values
+    uri:
+      url: http://{{ '{{' }} onosaddr.stdout {{ '}}' }}:8181/{{ '{{' }} item.endpoint {{ '}}' }} #http://localhost:8181/onos/v1/network/configuration/
+      body: "{{ '{{' }} item.body {{ '}}' }}"
+      body_format: raw
+      method: POST
+      user: karaf
+      password: karaf
+    with_items: "rest_configs"
+{% endif %}
diff --git a/xos/onboard/onos/synchronizer/steps/sync_onosapp_nocontainer.yaml b/xos/onboard/onos/synchronizer/steps/sync_onosapp_nocontainer.yaml
new file mode 100644
index 0000000..5aad569
--- /dev/null
+++ b/xos/onboard/onos/synchronizer/steps/sync_onosapp_nocontainer.yaml
@@ -0,0 +1,57 @@
+---
+- hosts: 127.0.0.1
+  connection: local
+  vars:
+    appname: {{ appname }}
+    dependencies: {{ dependencies }}
+{% if component_configs %}
+    component_configs:
+{% for component_config in component_configs %}
+       - component: {{ component_config.component }}
+         config_params: {{  component_config.config_params }}
+{% endfor %}
+{% endif %}
+{% if rest_configs %}
+    rest_configs:
+{% for rest_config in rest_configs %}
+       - endpoint: {{ rest_config.endpoint }}
+         body: "{{ '{{' }} lookup('file', '{{ files_dir }}/{{ rest_config.fn }}') {{ '}}' }}"
+{% endfor %}
+{% endif %}
+{% if early_rest_configs %}
+    early_rest_configs:
+{% for early_rest_config in early_rest_configs %}
+       - endpoint: {{ early_rest_config.endpoint }}
+         body: "{{ '{{' }} lookup('file', '{{ files_dir }}/{{ early_rest_config.fn }}') {{ '}}' }}"
+{% endfor %}
+{% endif %}
+    rest_hostname: {{ rest_hostname }}
+    rest_port: {{ rest_port }}
+
+  tasks:
+{% if dependencies %}
+  - name: Add dependencies to ONOS
+    uri:
+      url: http://{{ '{{' }} rest_hostname {{ '}}' }}:{{ '{{' }} rest_port {{ '}}' }}/onos/v1/applications/{{ '{{' }} item {{ '}}' }}/active
+      method: POST
+      user: karaf
+      password: karaf
+    with_items:
+        {% for dependency in dependencies %}
+        - {{ dependency }}
+        {% endfor %}
+{% endif %}
+
+{% if rest_configs %}
+# Do this after services have been activated, or it will cause an exception.
+# vOLT will re-read its net config; vbng may not.
+  - name: Add ONOS configuration values
+    uri:
+      url: http://{{ '{{' }} rest_hostname {{ '}}' }}:{{ '{{' }} rest_port {{ '}}' }}/{{ '{{' }} item.endpoint {{ '}}' }} #http://localhost:8181/onos/v1/network/configuration/
+      body: "{{ '{{' }} item.body {{ '}}' }}"
+      body_format: raw
+      method: POST
+      user: karaf
+      password: karaf
+    with_items: "rest_configs"
+{% endif %}
diff --git a/xos/onboard/onos/synchronizer/steps/sync_onosservice.py b/xos/onboard/onos/synchronizer/steps/sync_onosservice.py
new file mode 100644
index 0000000..ce446cf
--- /dev/null
+++ b/xos/onboard/onos/synchronizer/steps/sync_onosservice.py
@@ -0,0 +1,80 @@
+import hashlib
+import os
+import socket
+import sys
+import base64
+import time
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.syncstep import SyncStep
+from synchronizers.base.ansible import run_template_ssh
+from synchronizers.base.SyncInstanceUsingAnsible import SyncInstanceUsingAnsible
+from core.models import Service, Slice
+from services.onos.models import ONOSService, ONOSApp
+from xos.logger import Logger, logging
+
+# hpclibrary will be in steps/..
+parentdir = os.path.join(os.path.dirname(__file__),"..")
+sys.path.insert(0,parentdir)
+
+logger = Logger(level=logging.INFO)
+
+class SyncONOSService(SyncInstanceUsingAnsible):
+    provides=[ONOSService]
+    observes=ONOSService
+    requested_interval=0
+    template_name = "sync_onosservice.yaml"
+    #service_key_name = "/opt/xos/synchronizers/onos/onos_key"
+
+    def __init__(self, *args, **kwargs):
+        super(SyncONOSService, self).__init__(*args, **kwargs)
+
+    def fetch_pending(self, deleted):
+        if (not deleted):
+            objs = ONOSService.get_service_objects().filter(Q(enacted__lt=F('updated')) | Q(enacted=None),Q(lazy_blocked=False))
+        else:
+            objs = ONOSService.get_deleted_service_objects()
+
+        return objs
+
+    def get_instance(self, o):
+        # We assume the ONOS service owns a slice, so pick one of the instances
+        # inside that slice to sync to.
+
+        serv = o
+
+        if serv.slices.exists():
+            slice = serv.slices.all()[0]
+            if slice.instances.exists():
+                return slice.instances.all()[0]
+
+        return None
+
+    def get_extra_attributes(self, o):
+        fields={}
+        fields["instance_hostname"] = self.get_instance(o).instance_name.replace("_","-")
+        fields["appname"] = o.name
+        fields["ONOS_container"] = "ONOS"
+        return fields
+
+    def sync_record(self, o):
+        if o.no_container:
+            logger.info("no work to do for onos service, because o.no_container is set",extra=o.tologdict())
+            o.save()
+        else:
+            super(SyncONOSService, self).sync_record(o)
+
+    def sync_fields(self, o, fields):
+        # the super causes the playbook to be run
+        super(SyncONOSService, self).sync_fields(o, fields)
+
+    def run_playbook(self, o, fields):
+        instance = self.get_instance(o)
+        if (instance.isolation=="container"):
+            # If the instance is already a container, then we don't need to
+            # install ONOS.
+            return
+        super(SyncONOSService, self).run_playbook(o, fields)
+
+    def delete_record(self, m):
+        pass
diff --git a/xos/onboard/onos/synchronizer/steps/sync_onosservice.yaml b/xos/onboard/onos/synchronizer/steps/sync_onosservice.yaml
new file mode 100644
index 0000000..a51fde5
--- /dev/null
+++ b/xos/onboard/onos/synchronizer/steps/sync_onosservice.yaml
@@ -0,0 +1,66 @@
+---
+- hosts: {{ instance_name }}
+  gather_facts: False
+  connection: ssh
+  user: ubuntu
+  sudo: yes
+
+  tasks:
+
+  - name: Fix /etc/hosts
+    lineinfile:
+      dest=/etc/hosts
+      regexp="127.0.0.1 localhost"
+      line="127.0.0.1 localhost {{ instance_hostname }}"
+
+  - name: Add repo key
+    apt_key:
+      keyserver=hkp://pgp.mit.edu:80
+      id=58118E89F3A912897C070ADBF76221572C52609D
+
+  - name: Install Docker repo
+    apt_repository:
+      repo="deb https://apt.dockerproject.org/repo ubuntu-trusty main"
+      state=present
+
+  - name: Install Docker
+    apt:
+      name={{ '{{' }} item {{ '}}' }}
+      state=latest
+      update_cache=yes
+    with_items:
+    - docker-engine
+    - python-pip
+    - python-httplib2
+
+  - name: Install docker-py
+    pip:
+      name=docker-py
+      state=latest
+
+  - name: Start ONOS container
+    docker:
+      docker_api_version: "1.18"
+      name: {{ ONOS_container }}
+      # was: reloaded
+      state: running
+      image: onosproject/onos
+      ports:
+      - "6653:6653"
+      - "8101:8101"
+      - "8181:8181"
+      - "9876:9876"
+
+  - name: Get Docker IP
+    script: /opt/xos/synchronizers/onos/scripts/dockerip.sh {{ ONOS_container }}
+    register: dockerip
+
+  - name: Wait for ONOS to come up
+    wait_for:
+      host={{ '{{' }} dockerip.stdout {{ '}}' }}
+      port={{ '{{' }} item {{ '}}' }}
+      state=present
+    with_items:
+    - 8101
+    - 8181
+    - 9876
diff --git a/xos/onboard/onos/synchronizer/stop.sh b/xos/onboard/onos/synchronizer/stop.sh
new file mode 100755
index 0000000..17d6eb7
--- /dev/null
+++ b/xos/onboard/onos/synchronizer/stop.sh
@@ -0,0 +1 @@
+pkill -9 -f onos-observer.py
diff --git a/xos/onboard/onos/synchronizer/supervisor/onos-observer.conf b/xos/onboard/onos/synchronizer/supervisor/onos-observer.conf
new file mode 100644
index 0000000..995644e
--- /dev/null
+++ b/xos/onboard/onos/synchronizer/supervisor/onos-observer.conf
@@ -0,0 +1,9 @@
+[supervisord]
+logfile=/var/log/supervisord.log ; (main log file;default $CWD/supervisord.log)
+pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid)
+nodaemon=true
+
+[program:synchronizer]
+command=python /opt/xos/synchronizers/onos/onos-synchronizer.py -C /opt/xos/synchronizers/onos/onos_synchronizer_config
+stderr_logfile=/var/log/supervisor/synchronizer.err.log
+stdout_logfile=/var/log/supervisor/synchronizer.out.log
diff --git a/xos/onboard/onos/templates/onosadmin.html b/xos/onboard/onos/templates/onosadmin.html
new file mode 100644
index 0000000..e50660e
--- /dev/null
+++ b/xos/onboard/onos/templates/onosadmin.html
@@ -0,0 +1,6 @@
+<div class = "row text-center">
+    <div class="col-xs-12">
+        <a class="btn btn-primary" href="/admin/onos/onosapp/">ONOS Apps</a>
+    </div>
+</div>
+
diff --git a/xos/onboard/onos/tosca/resources/onosapp.py b/xos/onboard/onos/tosca/resources/onosapp.py
new file mode 100644
index 0000000..a65c717
--- /dev/null
+++ b/xos/onboard/onos/tosca/resources/onosapp.py
@@ -0,0 +1,68 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+import pdb
+
+from core.models import User, TenantAttribute, Service
+from services.onos.models import ONOSApp, ONOSService
+
+from xosresource import XOSResource
+
+class XOSONOSApp(XOSResource):
+    provides = ["tosca.nodes.ONOSApp", "tosca.nodes.ONOSvBNGApp", "tosca.nodes.ONOSvOLTApp", "tosca.nodes.ONOSVTNApp", "tosca.nodes.ONOSvRouterApp"]
+    xos_model = ONOSApp
+    copyin_props = ["service_specific_id", "dependencies", "install_dependencies"]
+
+    def get_xos_args(self, throw_exception=True):
+        args = super(XOSONOSApp, self).get_xos_args()
+
+        # provider_service is mandatory and must be the ONOS Service
+        provider_name = self.get_requirement("tosca.relationships.TenantOfService", throw_exception=throw_exception)
+        if provider_name:
+            args["provider_service"] = self.get_xos_object(ONOSService, throw_exception=throw_exception, name=provider_name)
+
+        # subscriber_service is optional and can be any service
+        subscriber_name = self.get_requirement("tosca.relationships.UsedByService", throw_exception=False)
+        if subscriber_name:
+            args["subscriber_service"] = self.get_xos_object(Service, throw_exception=throw_exception, name=subscriber_name)
+
+        return args
+
+    def get_existing_objs(self):
+        objs = ONOSApp.get_tenant_objects().all()
+        objs = [x for x in objs if x.name == self.obj_name]
+        return objs
+
+    def set_tenant_attr(self, obj, prop_name, value):
+        value = self.try_intrinsic_function(value)
+        if value:
+            attrs = TenantAttribute.objects.filter(tenant=obj, name=prop_name)
+            if attrs:
+                attr = attrs[0]
+                if attr.value != value:
+                    self.info("updating attribute %s" % prop_name)
+                    attr.value = value
+                    attr.save()
+            else:
+                self.info("adding attribute %s" % prop_name)
+                ta = TenantAttribute(tenant=obj, name=prop_name, value=value)
+                ta.save()
+
+    def postprocess(self, obj):
+        props = self.nodetemplate.get_properties()
+        for (k,d) in props.items():
+            v = d.value
+            if k.startswith("config_"):
+                self.set_tenant_attr(obj, k, v)
+            elif k.startswith("rest_") and (k!="rest_hostname") and (k!="rest_port"):
+                self.set_tenant_attr(obj, k, v)
+            elif k.startswith("component_config"):
+                self.set_tenant_attr(obj, k, v)
+            elif k == "autogenerate":
+                self.set_tenant_attr(obj, k, v)
+
+    def can_delete(self, obj):
+        return super(XOSONOSApp, self).can_delete(obj)
diff --git a/xos/onboard/onos/tosca/resources/onosservice.py b/xos/onboard/onos/tosca/resources/onosservice.py
new file mode 100644
index 0000000..3540dd0
--- /dev/null
+++ b/xos/onboard/onos/tosca/resources/onosservice.py
@@ -0,0 +1,41 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from core.models import ServiceAttribute
+from services.onos.models import ONOSService
+
+from service import XOSService
+
+class XOSONOSService(XOSService):
+    provides = "tosca.nodes.ONOSService"
+    xos_model = ONOSService
+    copyin_props = ["view_url", "icon_url", "enabled", "published", "public_key", "versionNumber", "rest_hostname", "rest_port", "no_container", "node_key"]
+
+    def set_service_attr(self, obj, prop_name, value):
+        value = self.try_intrinsic_function(value)
+        if value:
+            attrs = ServiceAttribute.objects.filter(service=obj, name=prop_name)
+            if attrs:
+                attr = attrs[0]
+                if attr.value != value:
+                    self.info("updating attribute %s" % prop_name)
+                    attr.value = value
+                    attr.save()
+            else:
+                self.info("adding attribute %s" % prop_name)
+                ta = ServiceAttribute(service=obj, name=prop_name, value=value)
+                ta.save()
+
+    def postprocess(self, obj):
+        props = self.nodetemplate.get_properties()
+        for (k,d) in props.items():
+            v = d.value
+            if k.startswith("config_"):
+                self.set_service_attr(obj, k, v)
+            elif k.startswith("rest_")  and (k!="rest_hostname") and (k!="rest_port"):
+                self.set_service_attr(obj, k, v)
+
diff --git a/xos/onboard/openvpn/admin.py b/xos/onboard/openvpn/admin.py
new file mode 100644
index 0000000..28e778d
--- /dev/null
+++ b/xos/onboard/openvpn/admin.py
@@ -0,0 +1,229 @@
+from django import forms
+from django.contrib import admin
+
+from core.admin import ReadOnlyAwareAdmin, SliceInline, TenantPrivilegeInline
+from core.middleware import get_request
+from core.models import User
+from services.openvpn.models import OPENVPN_KIND, OpenVPNService, OpenVPNTenant
+from xos.exceptions import XOSValidationError
+
+
+class OpenVPNServiceForm(forms.ModelForm):
+
+    exposed_ports = forms.CharField(required=True)
+
+    def __init__(self, *args, **kwargs):
+        super(OpenVPNServiceForm, self).__init__(*args, **kwargs)
+
+        if self.instance:
+            self.fields['exposed_ports'].initial = (
+                self.instance.exposed_ports_str)
+
+    def save(self, commit=True):
+        self.instance.exposed_ports = self.cleaned_data['exposed_ports']
+        return super(OpenVPNServiceForm, self).save(commit=commit)
+
+    def clean_exposed_ports(self):
+        exposed_ports = self.cleaned_data['exposed_ports']
+        self.instance.exposed_ports_str = exposed_ports
+        port_mapping = {"udp": [], "tcp": []}
+        parts = exposed_ports.split(",")
+        for part in parts:
+            part = part.strip()
+            if "/" in part:
+                (protocol, ports) = part.split("/", 1)
+            elif " " in part:
+                (protocol, ports) = part.split(None, 1)
+            else:
+                raise XOSValidationError(
+                    'malformed port specifier %s, format example: ' +
+                    '"tcp 123, tcp 201:206, udp 333"' % part)
+
+            protocol = protocol.strip()
+            ports = ports.strip()
+
+            if not (protocol in ["udp", "tcp"]):
+                raise XOSValidationError('unknown protocol %s' % protocol)
+
+            if "-" in ports:
+                port_mapping[protocol].extend(
+                    self.parse_port_range(ports, "-"))
+            elif ":" in ports:
+                port_mapping[protocol].extend(
+                    self.parse_port_range(ports, ":"))
+            else:
+                port_mapping[protocol].append(int(ports))
+
+        return port_mapping
+
+    def parse_port_range(self, port_str, split_str):
+        (first, last) = port_str.split(split_str)
+        first = int(first.strip())
+        last = int(last.strip())
+        return list(range(first, last))
+
+    class Meta:
+        model = OpenVPNService
+
+
+class OpenVPNServiceAdmin(ReadOnlyAwareAdmin):
+    """Defines the admin for the OpenVPNService."""
+    model = OpenVPNService
+    form = OpenVPNServiceForm
+    verbose_name = "OpenVPN Service"
+
+    list_display = ("backend_status_icon", "name", "enabled")
+
+    list_display_links = ('backend_status_icon', 'name', )
+
+    fieldsets = [(None, {'fields': ['backend_status_text', 'name', 'enabled',
+                                    'versionNumber', 'description', "view_url",
+                                    'exposed_ports'],
+                         'classes':['suit-tab suit-tab-general']})]
+
+    readonly_fields = ('backend_status_text', )
+
+    inlines = [SliceInline]
+
+    extracontext_registered_admins = True
+
+    user_readonly_fields = ["name", "enabled", "versionNumber", "description"]
+
+    suit_form_tabs = (('general', 'VPN Service Details'),
+                      ('slices', 'Slices'),)
+
+    def queryset(self, request):
+        return OpenVPNService.get_service_objects_by_user(request.user)
+
+
+class OpenVPNTenantForm(forms.ModelForm):
+    """The form used to create and edit a OpenVPNTenant.
+
+    Attributes:
+        creator (forms.ModelChoiceField): The XOS user that created this
+            tenant.
+        server_network (forms.GenericIPAddressField): The IP address of the VPN network.
+        vpn_subnet (forms.GenericIPAddressField): The subnet used by the VPN network.
+        is_persistent (forms.BooleanField): Determines if this Tenant keeps
+            this connection alive through failures.
+        clients_can_see_each_other (forms.BooleanField): Determines if the clients on the VPN can
+            communicate with each other.
+        failover_servers (forms.ModelMultipleChoiceField): The other OpenVPNTenants to use as failover
+            servers.
+        protocol (forms.ChoiceField): The protocol to use.
+        use_ca_from (forms.ModelChoiceField): Another OpenVPNTenant to use the CA of, this is a very
+            hacky way to let VPNs have the same clients.
+    """
+    creator = forms.ModelChoiceField(queryset=User.objects.all())
+    server_network = forms.GenericIPAddressField(
+        protocol="IPv4", required=True)
+    vpn_subnet = forms.GenericIPAddressField(protocol="IPv4", required=True)
+    is_persistent = forms.BooleanField(required=False)
+    clients_can_see_each_other = forms.BooleanField(required=False)
+    failover_servers = forms.ModelMultipleChoiceField(
+        required=False, queryset=OpenVPNTenant.get_tenant_objects())
+    protocol = forms.ChoiceField(required=True, choices=[
+        ("tcp", "tcp"), ("udp", "udp")])
+    use_ca_from = forms.ModelChoiceField(
+        queryset=OpenVPNTenant.get_tenant_objects(), required=False)
+
+    def __init__(self, *args, **kwargs):
+        super(OpenVPNTenantForm, self).__init__(*args, **kwargs)
+        self.fields['kind'].widget.attrs['readonly'] = True
+        self.fields['failover_servers'].widget.attrs['rows'] = 300
+        self.fields[
+            'provider_service'].queryset = (
+                OpenVPNService.get_service_objects().all())
+
+        self.fields['kind'].initial = OPENVPN_KIND
+
+        if self.instance:
+            self.fields['creator'].initial = self.instance.creator
+            self.fields['vpn_subnet'].initial = self.instance.vpn_subnet
+            self.fields[
+                'server_network'].initial = self.instance.server_network
+            self.fields[
+                'clients_can_see_each_other'].initial = (
+                    self.instance.clients_can_see_each_other)
+            self.fields['is_persistent'].initial = self.instance.is_persistent
+            self.initial['protocol'] = self.instance.protocol
+            self.fields['failover_servers'].queryset = (
+                OpenVPNTenant.get_tenant_objects().exclude(pk=self.instance.pk))
+            self.initial['failover_servers'] = OpenVPNTenant.get_tenant_objects().filter(
+                pk__in=self.instance.failover_server_ids)
+            self.fields['use_ca_from'].queryset = (
+                OpenVPNTenant.get_tenant_objects().exclude(pk=self.instance.pk))
+            if (self.instance.use_ca_from_id):
+                self.initial['use_ca_from'] = (
+                    OpenVPNTenant.get_tenant_objects().filter(pk=self.instance.use_ca_from_id)[0])
+
+        if (not self.instance) or (not self.instance.pk):
+            self.fields['creator'].initial = get_request().user
+            self.fields['vpn_subnet'].initial = "255.255.255.0"
+            self.fields['server_network'].initial = "10.66.77.0"
+            self.fields['clients_can_see_each_other'].initial = True
+            self.fields['is_persistent'].initial = True
+            self.fields['failover_servers'].queryset = (
+                OpenVPNTenant.get_tenant_objects())
+            if OpenVPNService.get_service_objects().exists():
+                self.fields["provider_service"].initial = (
+                    OpenVPNService.get_service_objects().all()[0])
+
+    def save(self, commit=True):
+        self.instance.creator = self.cleaned_data.get("creator")
+        self.instance.is_persistent = self.cleaned_data.get('is_persistent')
+        self.instance.vpn_subnet = self.cleaned_data.get("vpn_subnet")
+        self.instance.server_network = self.cleaned_data.get('server_network')
+        self.instance.clients_can_see_each_other = self.cleaned_data.get(
+            'clients_can_see_each_other')
+
+        self.instance.failover_server_ids = [
+            tenant.id for tenant in self.cleaned_data.get('failover_servers')]
+
+        # Do not aquire a new port number if the protocol hasn't changed
+        if ((not self.instance.protocol) or
+                (self.instance.protocol != self.cleaned_data.get("protocol"))):
+            self.instance.protocol = self.cleaned_data.get("protocol")
+            self.instance.port_number = (
+                self.instance.provider_service.get_next_available_port(
+                    self.instance.protocol))
+
+        if (self.cleaned_data.get('use_ca_from')):
+            self.instance.use_ca_from_id = self.cleaned_data.get(
+                'use_ca_from').id
+        else:
+            self.instance.use_ca_from_id = None
+
+        return super(OpenVPNTenantForm, self).save(commit=commit)
+
+    class Meta:
+        model = OpenVPNTenant
+
+
+class OpenVPNTenantAdmin(ReadOnlyAwareAdmin):
+    verbose_name = "OpenVPN Tenant Admin"
+    list_display = ('id', 'backend_status_icon', 'instance',
+                    'server_network', 'vpn_subnet')
+    list_display_links = ('id', 'backend_status_icon',
+                          'instance', 'server_network', 'vpn_subnet')
+    fieldsets = [(None, {'fields': ['backend_status_text', 'kind',
+                                    'provider_service', 'instance', 'creator',
+                                    'server_network', 'vpn_subnet',
+                                    'is_persistent', 'use_ca_from',
+                                    'clients_can_see_each_other',
+                                    'failover_servers', "protocol"],
+                         'classes': ['suit-tab suit-tab-general']})]
+    readonly_fields = ('backend_status_text', 'instance')
+    form = OpenVPNTenantForm
+    inlines = [TenantPrivilegeInline]
+
+    suit_form_tabs = (('general', 'Details'),
+                      ('tenantprivileges', 'Privileges'))
+
+    def queryset(self, request):
+        return OpenVPNTenant.get_tenant_objects_by_user(request.user)
+
+
+# Associate the admin forms with the models.
+admin.site.register(OpenVPNService, OpenVPNServiceAdmin)
+admin.site.register(OpenVPNTenant, OpenVPNTenantAdmin)
diff --git a/xos/onboard/openvpn/api/tenant/openvpn/openvpn.py b/xos/onboard/openvpn/api/tenant/openvpn/openvpn.py
new file mode 100644
index 0000000..9cc13f0
--- /dev/null
+++ b/xos/onboard/openvpn/api/tenant/openvpn/openvpn.py
@@ -0,0 +1,78 @@
+import jinja2
+
+from api.xosapi_helpers import PlusModelSerializer, ReadOnlyField, XOSViewSet
+from core.models import TenantPrivilege
+from rest_framework import serializers
+from services.openvpn.models import OpenVPNService, OpenVPNTenant
+
+
+def get_default_openvpn_service():
+    openvpn_services = OpenVPNService.get_service_objects().all()
+    if openvpn_services:
+        return openvpn_services[0].id
+    return None
+
+
+class OpenVPNTenantSerializer(PlusModelSerializer):
+    """A Serializer for the OpenVPNTenant that has the minimum information required for clients.
+
+    Attributes:
+        id (ReadOnlyField): The ID of OpenVPNTenant.
+        server_network (ReadOnlyField): The network of the VPN.
+        vpn_subnet (ReadOnlyField): The subnet of the VPN.
+        script_text (SerializerMethodField): The text of the script for the client to use to
+            connect.
+    """
+    id = ReadOnlyField()
+    server_network = ReadOnlyField()
+    vpn_subnet = ReadOnlyField()
+    script_text = serializers.SerializerMethodField()
+
+    class Meta:
+        model = OpenVPNTenant
+        fields = ('id', 'service_specific_attribute', 'vpn_subnet',
+                  'server_network', 'script_text')
+
+    def get_script_text(self, obj):
+        """Gets the text of the client script for the requesting user.
+
+        Parameters:
+            obj (services.openvpn.models.OpenVPNTenant): The OpenVPNTenant to connect to.
+
+        Returns:
+            str: The client script as a str.
+        """
+        env = jinja2.Environment(
+            loader=jinja2.FileSystemLoader("/opt/xos/services/openvpn/templates"))
+        template = env.get_template("connect.vpn.j2")
+        client_name = self.context['request'].user.email + "-" + str(obj.id)
+        remote_ids = list(obj.failover_server_ids)
+        remote_ids.insert(0, obj.id)
+        remotes = OpenVPNTenant.get_tenant_objects().filter(pk__in=remote_ids)
+        pki_dir = OpenVPNService.get_pki_dir(obj)
+        fields = {"client_name": client_name,
+                  "remotes": remotes,
+                  "is_persistent": obj.is_persistent,
+                  "ca_crt": obj.get_ca_crt(pki_dir),
+                  "client_crt": obj.get_client_cert(client_name, pki_dir),
+                  "client_key": obj.get_client_key(client_name, pki_dir)
+                  }
+        return template.render(fields)
+
+
+class OpenVPNTenantViewSet(XOSViewSet):
+    """Class that provides a list of OpenVPNTenants that the user has permission to access."""
+    base_name = "openvpn"
+    method_kind = "viewset"
+    method_name = "list"
+    serializer_class = OpenVPNTenantSerializer
+
+    def get_queryset(self):
+        # Get every privilege for this user
+        tenants_privs = TenantPrivilege.objects.all().filter(
+            user=self.request.user)
+        vpn_tenants = []
+        for priv in tenants_privs:
+            vpn_tenants.append(
+                OpenVPNTenant.get_tenant_objects().filter(pk=priv.tenant.pk)[0])
+        return vpn_tenants
diff --git a/xos/onboard/openvpn/models.py b/xos/onboard/openvpn/models.py
new file mode 100644
index 0000000..8aaa825
--- /dev/null
+++ b/xos/onboard/openvpn/models.py
@@ -0,0 +1,316 @@
+from subprocess import PIPE, Popen
+
+from django.db import transaction
+
+from core.models import Service, TenantWithContainer
+from xos.exceptions import XOSConfigurationError, XOSValidationError
+
+OPENVPN_KIND = "openvpn"
+
+
+class OpenVPNService(Service):
+    """Defines the Service for creating VPN servers."""
+    KIND = OPENVPN_KIND
+    OPENVPN_PREFIX = "/opt/openvpn/"
+    """The location of the openvpn EASY RSA files and PKIs."""
+    SERVER_PREFIX = OPENVPN_PREFIX + "server-"
+    """The prefix for server PKIs."""
+    VARS = OPENVPN_PREFIX + "vars"
+    """The location of the vars file with information for using EASY RSA."""
+    EASYRSA_LOC = OPENVPN_PREFIX + "easyrsa3/easyrsa"
+    """The location of the EASY RSA binary."""
+    EASYRSA_COMMAND_PREFIX = EASYRSA_LOC + " --vars=" + VARS
+    """Prefix for EASY RSA commands."""
+
+    @classmethod
+    def execute_easyrsa_command(cls, pki_dir, command):
+        """Executes the given EASY RSA command using the given PKI.
+
+        Parameters:
+            pki_dir (str): The directory for the pki to execute the command on.
+            command (str): The command to execute using ESAY RSA.
+        """
+        full_command = (
+            OpenVPNService.EASYRSA_COMMAND_PREFIX + " --pki-dir=" +
+            pki_dir + " " + command)
+        proc = Popen(
+            full_command, shell=True, stdout=PIPE, stderr=PIPE
+        )
+        (stdout, stderr) = proc.communicate()
+        if (proc.returncode != 0):
+            raise XOSConfigurationError(
+                full_command + " failed with standard out:" + str(stdout) +
+                " and stderr: " + str(stderr))
+
+    @classmethod
+    def get_pki_dir(cls, tenant):
+        """Gets the directory of the PKI for the given tenant.
+
+        Parameters:
+            tenant (services.openvpn.models.OpenVPNTenant): The tenant to get the PKI directory for.
+
+        Returns:
+            str: The pki directory for the tenant.
+        """
+        return OpenVPNService.SERVER_PREFIX + str(tenant.id)
+
+    class Meta:
+        proxy = True
+        # The name used to find this service, all directories are named this
+        app_label = "openvpn"
+        verbose_name = "OpenVPN Service"
+
+    default_attributes = {'exposed_ports': None,
+                          'exposed_ports_str': None}
+
+    @property
+    def exposed_ports(self):
+        """Mapping[str, list(str)]: maps protocols to a list of ports for that protocol."""
+        return self.get_attribute("exposed_ports",
+                                  self.default_attributes["exposed_ports"])
+
+    @exposed_ports.setter
+    def exposed_ports(self, value):
+        self.set_attribute("exposed_ports", value)
+
+    @property
+    def exposed_ports_str(self):
+        """str: a raw str representing the exposed ports."""
+        return self.get_attribute("exposed_ports_str",
+                                  self.default_attributes["exposed_ports_str"])
+
+    @exposed_ports_str.setter
+    def exposed_ports_str(self, value):
+        self.set_attribute("exposed_ports_str", value)
+
+    def get_next_available_port(self, protocol):
+        """Gets the next free port for the given protocol.
+
+        Parameters:
+            protocol (str): The protocol to get a port for, must be tcp or udp.
+
+        Returns:
+            int: a port number.
+
+        Raises:
+            xos.exceptions.XOSValidationError: If there the protocol is not udp or tcp.
+            xos.exceptions.XOSValidationError: If there are no available ports for the protocol.
+        """
+        if protocol != "udp" and protocol != "tcp":
+            raise XOSValidationError("Port protocol must be udp or tcp")
+        if not self.exposed_ports[protocol]:
+            raise XOSValidationError(
+                "No availble ports for protocol: " + protocol)
+        tenants = [
+            tenant for tenant in OpenVPNTenant.get_tenant_objects().all()
+            if tenant.protocol == protocol]
+        port_numbers = self.exposed_ports[protocol]
+        for port_number in port_numbers:
+            if (
+                len([
+                    tenant for tenant in tenants
+                    if tenant.port_number == port_number]) == 0):
+                return port_number
+
+
+class OpenVPNTenant(TenantWithContainer):
+    """Defines the Tenant for creating VPN servers."""
+
+    class Meta:
+        proxy = True
+        verbose_name = "OpenVPN Tenant"
+
+    KIND = OPENVPN_KIND
+
+    sync_attributes = ("nat_ip", "nat_mac",)
+
+    default_attributes = {'vpn_subnet': None,
+                          'server_network': None,
+                          'clients_can_see_each_other': True,
+                          'is_persistent': True,
+                          'port': None,
+                          'use_ca_from_id': None,
+                          'failover_server_ids': list(),
+                          'protocol': None}
+
+    def __init__(self, *args, **kwargs):
+        vpn_services = OpenVPNService.get_service_objects().all()
+        if vpn_services:
+            self._meta.get_field(
+                "provider_service").default = vpn_services[0].id
+        super(OpenVPNTenant, self).__init__(*args, **kwargs)
+
+    def save(self, *args, **kwargs):
+        super(OpenVPNTenant, self).save(*args, **kwargs)
+        model_policy_vpn_tenant(self.pk)
+
+    def delete(self, *args, **kwargs):
+        self.cleanup_container()
+        super(OpenVPNTenant, self).delete(*args, **kwargs)
+
+    @property
+    def protocol(self):
+        """str: The protocol that this tenant is listening on."""
+        return self.get_attribute(
+            "protocol", self.default_attributes["protocol"])
+
+    @protocol.setter
+    def protocol(self, value):
+        self.set_attribute("protocol", value)
+
+    @property
+    def use_ca_from_id(self):
+        """int: The ID of OpenVPNTenant to use to obtain a CA."""
+        return self.get_attribute(
+            "use_ca_from_id", self.default_attributes["use_ca_from_id"])
+
+    @use_ca_from_id.setter
+    def use_ca_from_id(self, value):
+        self.set_attribute("use_ca_from_id", value)
+
+    @property
+    def addresses(self):
+        """Mapping[str, str]: The ip, mac address, and subnet of the NAT
+            network of this Tenant."""
+        if (not self.id) or (not self.instance):
+            return {}
+
+        addresses = {}
+        for ns in self.instance.ports.all():
+            if "nat" in ns.network.name.lower():
+                addresses["ip"] = ns.ip
+                addresses["mac"] = ns.mac
+                break
+
+        return addresses
+
+    # This getter is necessary because nat_ip is a sync_attribute
+    @property
+    def nat_ip(self):
+        """str: The IP of this Tenant on the NAT network."""
+        return self.addresses.get("ip", None)
+
+    # This getter is necessary because nat_mac is a sync_attribute
+    @property
+    def nat_mac(self):
+        """str: The MAC address of this Tenant on the NAT network."""
+        return self.addresses.get("mac", None)
+
+    @property
+    def server_network(self):
+        """str: The IP address of the server on the VPN."""
+        return self.get_attribute(
+            'server_network',
+            self.default_attributes['server_network'])
+
+    @server_network.setter
+    def server_network(self, value):
+        self.set_attribute("server_network", value)
+
+    @property
+    def vpn_subnet(self):
+        """str: The IP address of the client on the VPN."""
+        return self.get_attribute(
+            'vpn_subnet',
+            self.default_attributes['vpn_subnet'])
+
+    @vpn_subnet.setter
+    def vpn_subnet(self, value):
+        self.set_attribute("vpn_subnet", value)
+
+    @property
+    def is_persistent(self):
+        """bool: True if the VPN connection is persistence, false otherwise."""
+        return self.get_attribute(
+            "is_persistent",
+            self.default_attributes['is_persistent'])
+
+    @is_persistent.setter
+    def is_persistent(self, value):
+        self.set_attribute("is_persistent", value)
+
+    @property
+    def failover_server_ids(self):
+        """list(int): The IDs of the OpenVPNTenants to use as failover servers."""
+        return self.get_attribute(
+            "failover_server_ids", self.default_attributes["failover_server_ids"])
+
+    @failover_server_ids.setter
+    def failover_server_ids(self, value):
+        self.set_attribute("failover_server_ids", value)
+
+    @property
+    def clients_can_see_each_other(self):
+        """bool: True if the client can see the subnet of the server, false
+            otherwise."""
+        return self.get_attribute(
+            "clients_can_see_each_other",
+            self.default_attributes['clients_can_see_each_other'])
+
+    @clients_can_see_each_other.setter
+    def clients_can_see_each_other(self, value):
+        self.set_attribute("clients_can_see_each_other", value)
+
+    @property
+    def port_number(self):
+        """int: the integer representing the port number for this server"""
+        return self.get_attribute("port", self.default_attributes['port'])
+
+    @port_number.setter
+    def port_number(self, value):
+        self.set_attribute("port", value)
+
+    def get_ca_crt(self, pki_dir):
+        """Gets the lines fo the ca.crt file for this OpenVPNTenant.
+
+        Parameters:
+            pki_dir (str): The PKI directory to look in.
+
+        Returns:
+            list(str): The lines of the ca.crt file for this OpenVPNTenant.
+        """
+        with open(pki_dir + "/ca.crt", 'r') as f:
+            return f.readlines()
+
+    def get_client_cert(self, client_name, pki_dir):
+        """Gets the lines fo the crt file for a client.
+
+        Parameters:
+            pki_dir (str): The PKI directory to look in.
+            client_name (str): The client name to use.
+
+        Returns:
+            list(str): The lines of the crt file for the client.
+        """
+        with open(pki_dir + "/issued/" + client_name + ".crt", 'r') as f:
+            return f.readlines()
+
+    def get_client_key(self, client_name, pki_dir):
+        """Gets the lines fo the key file for a client.
+
+        Parameters:
+            pki_dir (str): The PKI directory to look in.
+            client_name (str): The client name to use.
+
+        Returns:
+            list(str): The lines of the key file for the client.
+        """
+        with open(pki_dir + "/private/" + client_name + ".key", 'r') as f:
+            return f.readlines()
+
+
+def model_policy_vpn_tenant(pk):
+    """Manages the container for the VPN Tenant.
+
+    Parameters
+        pk (int): The ID of this OpenVPNTenant.
+    """
+    # This section of code is atomic to prevent race conditions
+    with transaction.atomic():
+        # We find all of the tenants that are waiting to update
+        tenant = OpenVPNTenant.objects.select_for_update().filter(pk=pk)
+        if not tenant:
+            return
+        # Since this code is atomic it is safe to always use the first tenant
+        tenant = tenant[0]
+        tenant.manage_container()
diff --git a/xos/onboard/openvpn/openvpn-onboard.yaml b/xos/onboard/openvpn/openvpn-onboard.yaml
new file mode 100644
index 0000000..980e0b5
--- /dev/null
+++ b/xos/onboard/openvpn/openvpn-onboard.yaml
@@ -0,0 +1,25 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Onboard the OpenVPN Service
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    servicecontroller#openvpn:
+      type: tosca.nodes.ServiceController
+      properties:
+          base_url: file:///opt/xos/onboard/vsg/
+          # The following will concatenate with base_url automatically, if
+          # base_url is non-null.
+          models: models.py
+          admin: admin.py
+          admin_template: templates/connect.vpn.j2
+          synchronizer: synchronizer/manifest
+          synchronizer_run: openvpn-synchronizer.py
+          #tosca_custom_types: exampleservice.yaml
+          rest_tenant: subdirectory:openvpn api/tenant/openvpn/openvpn.py
+          private_key: file:///opt/xos/key_import/openvpn_rsa
+          public_key: file:///opt/xos/key_import/openvpn_rsa.pub
+
diff --git a/xos/onboard/openvpn/synchronizer/__init__.py b/xos/onboard/openvpn/synchronizer/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xos/onboard/openvpn/synchronizer/__init__.py
diff --git a/xos/onboard/openvpn/synchronizer/manifest b/xos/onboard/openvpn/synchronizer/manifest
new file mode 100644
index 0000000..44d6986
--- /dev/null
+++ b/xos/onboard/openvpn/synchronizer/manifest
@@ -0,0 +1,14 @@
+manifest
+openvpn_config
+__init__.py
+steps/sync_tenantprivilege.py
+steps/sync_openvpntenant.yaml
+steps/__init__.py
+steps/roles/openvpn/templates/server.conf.j2
+steps/roles/openvpn/handlers/main.yml
+steps/roles/openvpn/tasks/main.yml
+steps/sync_openvpntenant.py
+stop.sh
+model-deps
+openvpn-synchronizer.py
+run.sh
diff --git a/xos/onboard/openvpn/synchronizer/model-deps b/xos/onboard/openvpn/synchronizer/model-deps
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/xos/onboard/openvpn/synchronizer/model-deps
@@ -0,0 +1 @@
+{}
diff --git a/xos/onboard/openvpn/synchronizer/openvpn-synchronizer.py b/xos/onboard/openvpn/synchronizer/openvpn-synchronizer.py
new file mode 100755
index 0000000..3227ed9
--- /dev/null
+++ b/xos/onboard/openvpn/synchronizer/openvpn-synchronizer.py
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+
+import importlib
+import os
+import sys
+observer_path = os.path.join(os.path.dirname(
+    os.path.realpath(__file__)), "../../synchronizers/base")
+sys.path.append(observer_path)
+mod = importlib.import_module("xos-synchronizer")
+mod.main()
diff --git a/xos/onboard/openvpn/synchronizer/openvpn_config b/xos/onboard/openvpn/synchronizer/openvpn_config
new file mode 100644
index 0000000..8a58b52
--- /dev/null
+++ b/xos/onboard/openvpn/synchronizer/openvpn_config
@@ -0,0 +1,23 @@
+# Required by XOS
+[db]
+name=xos
+user=postgres
+password=password
+host=localhost
+port=5432
+
+# Required by XOS
+[api]
+nova_enabled=True
+
+# Sets options for the synchronizer
+[observer]
+name=openvpn
+dependency_graph=/opt/xos/synchronizers/openvpn/model-deps
+steps_dir=/opt/xos/synchronizers/openvpn/steps
+sys_dir=/opt/xos/synchronizers/openvpn/sys
+logfile=/var/log/xos_backend.log
+pretend=False
+backoff_disabled=True
+save_ansible_output=True
+proxy_ssh=False
diff --git a/xos/onboard/openvpn/synchronizer/run.sh b/xos/onboard/openvpn/synchronizer/run.sh
new file mode 100755
index 0000000..a5d90c9
--- /dev/null
+++ b/xos/onboard/openvpn/synchronizer/run.sh
@@ -0,0 +1,2 @@
+export XOS_DIR=/opt/xos
+python openvpn-synchronizer.py  -C $XOS_DIR/synchronizers/openvpn/openvpn_config
diff --git a/xos/onboard/openvpn/synchronizer/steps/__init__.py b/xos/onboard/openvpn/synchronizer/steps/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xos/onboard/openvpn/synchronizer/steps/__init__.py
diff --git a/xos/onboard/openvpn/synchronizer/steps/roles/openvpn/handlers/main.yml b/xos/onboard/openvpn/synchronizer/steps/roles/openvpn/handlers/main.yml
new file mode 100644
index 0000000..8725e29
--- /dev/null
+++ b/xos/onboard/openvpn/synchronizer/steps/roles/openvpn/handlers/main.yml
@@ -0,0 +1,4 @@
+---
+
+- name: restart openvpn
+  shell: (kill -9 $(cat {{ pki_dir }}/pid) || true) && (openvpn {{ pki_dir }}/server.conf &)
diff --git a/xos/onboard/openvpn/synchronizer/steps/roles/openvpn/tasks/main.yml b/xos/onboard/openvpn/synchronizer/steps/roles/openvpn/tasks/main.yml
new file mode 100644
index 0000000..47093b2
--- /dev/null
+++ b/xos/onboard/openvpn/synchronizer/steps/roles/openvpn/tasks/main.yml
@@ -0,0 +1,38 @@
+---
+
+- name: install openvpn
+  apt: name=openvpn state=present update_cache=yes
+
+- name: make sure /opt/openvpn exists
+  file: path=/opt/openvpn state=directory
+
+- name: make sure directory for this server exists
+  file: path={{ pki_dir }} state=directory
+
+- name: get server key
+  copy: src={{ pki_dir }}/private/server.key dest={{ pki_dir }}/server.key
+  notify:
+  - restart openvpn
+
+- name: get server crt
+  copy: src={{ pki_dir }}/issued/server.crt dest={{ pki_dir }}/server.crt
+  notify:
+  - restart openvpn
+
+- name: get ca crt
+  copy: src={{ pki_dir }}/ca.crt dest={{ pki_dir }}/ca.crt
+  notify:
+  - restart openvpn
+
+- name: get crl
+  copy: src={{ pki_dir }}/crl.pem dest={{ pki_dir }}/crl.pem
+
+- name: get dh
+  copy: src={{ pki_dir }}/dh.pem dest={{ pki_dir }}/dh.pem
+  notify:
+  - restart openvpn
+
+- name: write config
+  template: src=server.conf.j2 dest={{ pki_dir }}/server.conf owner=root group=root
+  notify:
+  - restart openvpn
diff --git a/xos/onboard/openvpn/synchronizer/steps/roles/openvpn/templates/server.conf.j2 b/xos/onboard/openvpn/synchronizer/steps/roles/openvpn/templates/server.conf.j2
new file mode 100644
index 0000000..4766e7b
--- /dev/null
+++ b/xos/onboard/openvpn/synchronizer/steps/roles/openvpn/templates/server.conf.j2
@@ -0,0 +1,24 @@
+# This file autogenerated by OpenVPNTenant synchronizer
+# It contains the OPENVPN config file for the server
+script-security 3 system
+port {{ port_number }}
+proto {{ protocol }}
+dev tun
+writepid {{ pki_dir }}/pid
+ca {{ pki_dir }}/ca.crt
+cert {{ pki_dir }}/server.crt
+key {{ pki_dir }}/server.key
+dh {{ pki_dir }}/dh.pem
+crl-verify {{ pki_dir }}/crl.pem
+server {{ server_network }} {{ vpn_subnet }}
+ifconfig-pool-persist {{ pki_dir }}/ipp.txt
+status {{ pki_dir }}/openvpn-status.log
+verb 3
+{% if is_persistent %}
+keepalive 10 60
+persist-tun
+persist-key
+{% endif %}
+{% if clients_can_see_each_other %}
+client-to-client
+{% endif %}
diff --git a/xos/onboard/openvpn/synchronizer/steps/sync_openvpntenant.py b/xos/onboard/openvpn/synchronizer/steps/sync_openvpntenant.py
new file mode 100644
index 0000000..b58dd94
--- /dev/null
+++ b/xos/onboard/openvpn/synchronizer/steps/sync_openvpntenant.py
@@ -0,0 +1,75 @@
+import os
+import shutil
+import sys
+
+from django.db.models import F, Q
+
+from services.openvpn.models import OpenVPNService, OpenVPNTenant
+from synchronizers.base.SyncInstanceUsingAnsible import \
+    SyncInstanceUsingAnsible
+
+parentdir = os.path.join(os.path.dirname(__file__), "..")
+sys.path.insert(0, parentdir)
+
+
+class SyncOpenVPNTenant(SyncInstanceUsingAnsible):
+    """Class for syncing a OpenVPNTenant using Ansible.
+
+    This SyncStep creates any necessary files for the OpenVPNTenant using ESAY RSA and then runs the
+    Ansible template to start the server on an instance.
+    """
+    provides = [OpenVPNTenant]
+    observes = OpenVPNTenant
+    requested_interval = 0
+    template_name = "sync_openvpntenant.yaml"
+    service_key_name = "/opt/xos/synchronizers/openvpn/openvpn_private_key"
+
+    def fetch_pending(self, deleted):
+        if (not deleted):
+            objs = OpenVPNTenant.get_tenant_objects().filter(
+                Q(enacted__lt=F('updated')) |
+                Q(enacted=None), Q(lazy_blocked=False))
+        else:
+            objs = OpenVPNTenant.get_deleted_tenant_objects()
+
+        return objs
+
+    def get_extra_attributes(self, tenant):
+        return {"is_persistent": tenant.is_persistent,
+                "vpn_subnet": tenant.vpn_subnet,
+                "server_network": tenant.server_network,
+                "clients_can_see_each_other": (
+                    tenant.clients_can_see_each_other),
+                "port_number": tenant.port_number,
+                "protocol": tenant.protocol,
+                "pki_dir": OpenVPNService.get_pki_dir(tenant)
+                }
+
+    def sync_fields(self, o, fields):
+        pki_dir = OpenVPNService.get_pki_dir(o)
+
+        if (not os.path.isdir(pki_dir)):
+            OpenVPNService.execute_easyrsa_command(pki_dir, "init-pki")
+            OpenVPNService.execute_easyrsa_command(
+                pki_dir, "--req-cn=XOS build-ca nopass")
+
+        # Very hacky way to handle VPNs that need to share CAs
+        if (o.use_ca_from_id):
+            tenant = OpenVPNTenant.get_tenant_objects().filter(
+                pk=o.use_ca_from_id)[0]
+            other_pki_dir = OpenVPNService.get_pki_dir(tenant)
+            shutil.copy2(other_pki_dir + "/ca.crt", pki_dir)
+            shutil.copy2(other_pki_dir + "/private/ca.key",
+                         pki_dir + "/private")
+
+        # If the server has to be built then we need to build it
+        if (not os.path.isfile(pki_dir + "/issued/server.crt")):
+            OpenVPNService.execute_easyrsa_command(
+                pki_dir, "build-server-full server nopass")
+            OpenVPNService.execute_easyrsa_command(pki_dir, "gen-dh")
+
+        # Get the most recent list of revoked clients
+        OpenVPNService.execute_easyrsa_command(pki_dir, "gen-crl")
+
+        # Super runs the playbook
+        super(SyncOpenVPNTenant, self).sync_fields(o, fields)
diff --git a/xos/onboard/openvpn/synchronizer/steps/sync_openvpntenant.yaml b/xos/onboard/openvpn/synchronizer/steps/sync_openvpntenant.yaml
new file mode 100644
index 0000000..e36f51b
--- /dev/null
+++ b/xos/onboard/openvpn/synchronizer/steps/sync_openvpntenant.yaml
@@ -0,0 +1,17 @@
+---
+- hosts: {{ instance_name }}
+  gather_facts: False
+  connection: ssh
+  user: ubuntu
+  sudo: yes
+  vars:
+    server_network: {{ server_network }}
+    is_persistent: {{ is_persistent }}
+    vpn_subnet: {{ vpn_subnet }}
+    clients_can_see_each_other: {{ clients_can_see_each_other }}
+    port_number: {{ port_number }}
+    protocol: {{ protocol }}
+    pki_dir: {{ pki_dir }}
+
+  roles:
+    - openvpn
diff --git a/xos/onboard/openvpn/synchronizer/steps/sync_tenantprivilege.py b/xos/onboard/openvpn/synchronizer/steps/sync_tenantprivilege.py
new file mode 100644
index 0000000..51ee6df
--- /dev/null
+++ b/xos/onboard/openvpn/synchronizer/steps/sync_tenantprivilege.py
@@ -0,0 +1,79 @@
+import os
+import sys
+
+from core.models import TenantPrivilege
+from services.openvpn.models import OPENVPN_KIND, OpenVPNService, OpenVPNTenant
+from synchronizers.base.syncstep import DeferredException, SyncStep
+
+parentdir = os.path.join(os.path.dirname(__file__), "..")
+sys.path.insert(0, parentdir)
+
+
+class SyncTenantPrivilege(SyncStep):
+    """Class for syncing a TenantPrivilege for a OpenVPNTenant.
+
+    This SyncStep isolates the updated TenantPrivileges that are for OpenVPNTenants and performs
+    actions if the TenantPrivilege has been added or deleted. For added privileges a new client
+    certificate and key are made, signed with the ca.crt file used by this OpenVPNTenant. For deleted
+    privileges the client certificate is revoked and the files associated are deleted. In both
+    cases the associated OpenVPNTenant is saved causing the OpenVPNTenant synchronizer to run.
+    """
+    provides = [TenantPrivilege]
+    observes = TenantPrivilege
+    requested_interval = 0
+
+    def fetch_pending(self, deleted):
+        privs = super(SyncTenantPrivilege, self).fetch_pending(deleted)
+        # Get only the TenantPrivileges that relate to OpenVPNTenants
+        privs = [priv for priv in privs if priv.tenant.kind == OPENVPN_KIND]
+        return privs
+
+    def sync_record(self, record):
+        if (not record.tenant.id):
+            raise DeferredException("Privilege waiting on VPN Tenant ID")
+        certificate = self.get_certificate_name(record)
+        tenant = OpenVPNTenant.get_tenant_objects().filter(pk=record.tenant.id)[0]
+        if (not tenant):
+            raise DeferredException("Privilege waiting on VPN Tenant")
+        # Only add a certificate if ones does not yet exist
+        pki_dir = OpenVPNService.get_pki_dir(tenant)
+        if (not os.path.isfile(pki_dir + "/issued/" + certificate + ".crt")):
+            OpenVPNService.execute_easyrsa_command(
+                pki_dir, "build-client-full " + certificate + " nopass")
+            tenant.save()
+        record.save()
+
+    def delete_record(self, record):
+        if (not record.tenant.id):
+            return
+        certificate = self.get_certificate_name(record)
+        tenant = OpenVPNTenant.get_tenant_objects().filter(pk=record.tenant.id)[0]
+        if (not tenant):
+            return
+        # If the client has already been reovked don't do it again
+        pki_dir = OpenVPNService.get_pki_dir(tenant)
+        if (os.path.isfile(pki_dir + "/issued/" + certificate + ".crt")):
+            OpenVPNService.execute_easyrsa_command(
+                pki_dir, "revoke " + certificate)
+            # Revoking a client cert does not delete any of the files
+            # to make sure that we can add this user again we need to
+            # delete all of the files created by easyrsa
+            os.remove(pki_dir + "/issued/" + certificate + ".crt")
+            os.remove(pki_dir + "/private/" + certificate + ".key")
+            os.remove(pki_dir + "/reqs/" + certificate + ".req")
+            tenant.save()
+
+        record.delete()
+
+    def get_certificate_name(self, tenant_privilege):
+        """Gets the name of a certificate for the given TenantPrivilege
+
+        Parameters:
+            tenant_privilege (core.models.TenantPrivilege): The TenantPrivilege to use to generate
+                the certificate name.
+
+        Returns:
+            str: The certificate name.
+        """
+        return (str(tenant_privilege.user.email) +
+                "-" + str(tenant_privilege.tenant.id))
diff --git a/xos/onboard/openvpn/synchronizer/stop.sh b/xos/onboard/openvpn/synchronizer/stop.sh
new file mode 100755
index 0000000..4a83aca
--- /dev/null
+++ b/xos/onboard/openvpn/synchronizer/stop.sh
@@ -0,0 +1,2 @@
+# Kill the observer
+pkill -9 -f openvpn-synchronizer.py
diff --git a/xos/onboard/openvpn/templates/connect.vpn.j2 b/xos/onboard/openvpn/templates/connect.vpn.j2
new file mode 100644
index 0000000..2028cd9
--- /dev/null
+++ b/xos/onboard/openvpn/templates/connect.vpn.j2
@@ -0,0 +1,24 @@
+#! /bin/bash
+# This file autogenerated by OpenVPNTenant.
+# It contains a script used to generate the OPENVPN client files.
+printf "%b" "client
+dev tun
+remote-cert-tls server
+resolv-retry 60
+nobind
+ca ca.crt
+cert {{ client_name }}.crt
+key {{ client_name }}.key
+verb 3
+{% for tenant in remotes %}remote {{ tenant.nat_ip }} {{ tenant.port_number }} {{ tenant.protocol }}{% endfor %}
+{% if is_persistent %}
+persist-tun
+persist-key
+{% endif %}
+" > client.conf
+printf "%b" "{% for line in ca_crt %}{{ line }}{% endfor %}" > ca.crt
+printf "%b" "{% for line in client_crt %}{{ line }}{% endfor %}" > {{ client_name }}.crt
+printf "%b" "{% for line in client_key %}{{ line }}{% endfor %}" > {{ client_name }}.key
+apt-get update
+apt-get install openvpn -y
+openvpn client.conf
diff --git a/xos/onboard/volt/admin.py b/xos/onboard/volt/admin.py
new file mode 100644
index 0000000..cf5dfa6
--- /dev/null
+++ b/xos/onboard/volt/admin.py
@@ -0,0 +1,237 @@
+from django.contrib import admin
+
+from services.volt.models import *
+from django import forms
+from django.utils.safestring import mark_safe
+from django.contrib.auth.admin import UserAdmin
+from django.contrib.admin.widgets import FilteredSelectMultiple
+from django.contrib.auth.forms import ReadOnlyPasswordHashField
+from django.contrib.auth.signals import user_logged_in
+from django.utils import timezone
+from django.contrib.contenttypes import generic
+from suit.widgets import LinkedSelect
+from core.admin import ServiceAppAdmin,SliceInline,ServiceAttrAsTabInline, ReadOnlyAwareAdmin, XOSTabularInline, ServicePrivilegeInline, TenantRootTenantInline, TenantRootPrivilegeInline
+from core.middleware import get_request
+
+from functools import update_wrapper
+from django.contrib.admin.views.main import ChangeList
+from django.core.urlresolvers import reverse
+from django.contrib.admin.utils import quote
+
+#-----------------------------------------------------------------------------
+# vOLT
+#-----------------------------------------------------------------------------
+
+class VOLTServiceAdmin(ReadOnlyAwareAdmin):
+    model = VOLTService
+    verbose_name = "vOLT Service"
+    verbose_name_plural = "vOLT Service"
+    list_display = ("backend_status_icon", "name", "enabled")
+    list_display_links = ('backend_status_icon', 'name', )
+    fieldsets = [(None, {'fields': ['backend_status_text', 'name','enabled','versionNumber', 'description',"view_url","icon_url" ], 'classes':['suit-tab suit-tab-general']})]
+    readonly_fields = ('backend_status_text', )
+    inlines = [SliceInline,ServiceAttrAsTabInline,ServicePrivilegeInline]
+
+    extracontext_registered_admins = True
+
+    user_readonly_fields = ["name", "enabled", "versionNumber", "description"]
+
+    suit_form_tabs =(('general', 'vOLT Service Details'),
+        ('administration', 'Administration'),
+        #('tools', 'Tools'),
+        ('slices','Slices'),
+        ('serviceattrs','Additional Attributes'),
+        ('serviceprivileges','Privileges'),
+    )
+
+    suit_form_includes = (('voltadmin.html', 'top', 'administration'),
+                           ) #('hpctools.html', 'top', 'tools') )
+
+    def queryset(self, request):
+        return VOLTService.get_service_objects_by_user(request.user)
+
+class VOLTTenantForm(forms.ModelForm):
+    s_tag = forms.CharField()
+    c_tag = forms.CharField()
+    creator = forms.ModelChoiceField(queryset=User.objects.all())
+
+    def __init__(self,*args,**kwargs):
+        super (VOLTTenantForm,self ).__init__(*args,**kwargs)
+        self.fields['kind'].widget.attrs['readonly'] = True
+        self.fields['provider_service'].queryset = VOLTService.get_service_objects().all()
+        if self.instance:
+            # fields for the attributes
+            self.fields['c_tag'].initial = self.instance.c_tag
+            self.fields['s_tag'].initial = self.instance.s_tag
+            self.fields['creator'].initial = self.instance.creator
+        if (not self.instance) or (not self.instance.pk):
+            # default fields for an 'add' form
+            self.fields['kind'].initial = VOLT_KIND
+            self.fields['creator'].initial = get_request().user
+            if VOLTService.get_service_objects().exists():
+               self.fields["provider_service"].initial = VOLTService.get_service_objects().all()[0]
+
+    def save(self, commit=True):
+        self.instance.s_tag = self.cleaned_data.get("s_tag")
+        self.instance.c_tag = self.cleaned_data.get("c_tag")
+        self.instance.creator = self.cleaned_data.get("creator")
+        return super(VOLTTenantForm, self).save(commit=commit)
+
+    class Meta:
+        model = VOLTTenant
+
+class VOLTTenantAdmin(ReadOnlyAwareAdmin):
+    list_display = ('backend_status_icon', 'id', 'service_specific_id', 's_tag', 'c_tag', 'subscriber_root' )
+    list_display_links = ('backend_status_icon', 'id')
+    fieldsets = [ (None, {'fields': ['backend_status_text', 'kind', 'provider_service', 'subscriber_root', 'service_specific_id', # 'service_specific_attribute',
+                                     's_tag', 'c_tag', 'creator'],
+                          'classes':['suit-tab suit-tab-general']})]
+    readonly_fields = ('backend_status_text', 'service_specific_attribute')
+    form = VOLTTenantForm
+
+    suit_form_tabs = (('general','Details'),)
+
+    def queryset(self, request):
+        return VOLTTenant.get_tenant_objects_by_user(request.user)
+
+class AccessDeviceInline(XOSTabularInline):
+    model = AccessDevice
+    fields = ['volt_device','uplink','vlan']
+    readonly_fields = []
+    extra = 0
+#    max_num = 0
+    suit_classes = 'suit-tab suit-tab-accessdevices'
+
+#    @property
+#    def selflink_reverse_path(self):
+#        return "admin:cord_volttenant_change"
+
+class VOLTDeviceAdmin(ReadOnlyAwareAdmin):
+    list_display = ('backend_status_icon', 'name', 'openflow_id', 'driver' )
+    list_display_links = ('backend_status_icon', 'name', 'openflow_id')
+    fieldsets = [ (None, {'fields': ['backend_status_text','name','volt_service','openflow_id','driver','access_agent'],
+                          'classes':['suit-tab suit-tab-general']})]
+    readonly_fields = ('backend_status_text',)
+    inlines = [AccessDeviceInline]
+
+    suit_form_tabs = (('general','Details'), ('accessdevices','Access Devices'))
+
+class AccessDeviceAdmin(ReadOnlyAwareAdmin):
+    list_display = ('backend_status_icon', 'id', 'volt_device', 'uplink', 'vlan' )
+    list_display_links = ('backend_status_icon', 'id')
+    fieldsets = [ (None, {'fields': ['backend_status_text','volt_device','uplink','vlan'],
+                          'classes':['suit-tab suit-tab-general']})]
+    readonly_fields = ('backend_status_text',)
+
+    suit_form_tabs = (('general','Details'),)
+
+class AgentPortMappingInline(XOSTabularInline):
+    model = AgentPortMapping
+    fields = ['access_agent', 'mac', 'port']
+    readonly_fields = []
+    extra = 0
+#    max_num = 0
+    suit_classes = 'suit-tab suit-tab-accessportmaps'
+
+#    @property
+#    def selflink_reverse_path(self):
+#        return "admin:cord_volttenant_change"
+
+class AccessAgentAdmin(ReadOnlyAwareAdmin):
+    list_display = ('backend_status_icon', 'name', 'mac' )
+    list_display_links = ('backend_status_icon', 'name')
+    fieldsets = [ (None, {'fields': ['backend_status_text','name','volt_service','mac'],
+                          'classes':['suit-tab suit-tab-general']})]
+    readonly_fields = ('backend_status_text',)
+    inlines= [AgentPortMappingInline]
+
+    suit_form_tabs = (('general','Details'), ('accessportmaps', 'Port Mappings'))
+
+# -------------------------------------------
+# CORDSubscriberRoot
+# -------------------------------------------
+
+class VOLTTenantInline(XOSTabularInline):
+    model = VOLTTenant
+    fields = ['provider_service', 'subscriber_root', 'service_specific_id']
+    readonly_fields = ['provider_service', 'subscriber_root', 'service_specific_id']
+    extra = 0
+    max_num = 0
+    suit_classes = 'suit-tab suit-tab-volttenants'
+    fk_name = 'subscriber_root'
+    verbose_name = 'subscribed tenant'
+    verbose_name_plural = 'subscribed tenants'
+
+    @property
+    def selflink_reverse_path(self):
+        return "admin:cord_volttenant_change"
+
+    def queryset(self, request):
+        qs = super(VOLTTenantInline, self).queryset(request)
+        return qs.filter(kind=VOLT_KIND)
+
+class CordSubscriberRootForm(forms.ModelForm):
+    url_filter_level = forms.CharField(required = False)
+    uplink_speed = forms.CharField(required = False)
+    downlink_speed = forms.CharField(required = False)
+    status = forms.ChoiceField(choices=CordSubscriberRoot.status_choices, required=True)
+    enable_uverse = forms.BooleanField(required=False)
+    cdn_enable = forms.BooleanField(required=False)
+
+    def __init__(self,*args,**kwargs):
+        super (CordSubscriberRootForm,self ).__init__(*args,**kwargs)
+        self.fields['kind'].widget.attrs['readonly'] = True
+        if self.instance:
+            self.fields['url_filter_level'].initial = self.instance.url_filter_level
+            self.fields['uplink_speed'].initial = self.instance.uplink_speed
+            self.fields['downlink_speed'].initial = self.instance.downlink_speed
+            self.fields['status'].initial = self.instance.status
+            self.fields['enable_uverse'].initial = self.instance.enable_uverse
+            self.fields['cdn_enable'].initial = self.instance.cdn_enable
+        if (not self.instance) or (not self.instance.pk):
+            # default fields for an 'add' form
+            self.fields['kind'].initial = CORD_SUBSCRIBER_KIND
+            self.fields['uplink_speed'].initial = CordSubscriberRoot.get_default_attribute("uplink_speed")
+            self.fields['downlink_speed'].initial = CordSubscriberRoot.get_default_attribute("downlink_speed")
+            self.fields['status'].initial = CordSubscriberRoot.get_default_attribute("status")
+            self.fields['enable_uverse'].initial = CordSubscriberRoot.get_default_attribute("enable_uverse")
+            self.fields['cdn_enable'].initial = CordSubscriberRoot.get_default_attribute("cdn_enable")
+
+    def save(self, commit=True):
+        self.instance.url_filter_level = self.cleaned_data.get("url_filter_level")
+        self.instance.uplink_speed = self.cleaned_data.get("uplink_speed")
+        self.instance.downlink_speed = self.cleaned_data.get("downlink_speed")
+        self.instance.status = self.cleaned_data.get("status")
+        self.instance.enable_uverse = self.cleaned_data.get("enable_uverse")
+        self.instance.cdn_enable = self.cleaned_data.get("cdn_enable")
+        return super(CordSubscriberRootForm, self).save(commit=commit)
+
+    class Meta:
+        model = CordSubscriberRoot
+
+class CordSubscriberRootAdmin(ReadOnlyAwareAdmin):
+    list_display = ('backend_status_icon', 'id',  'name', )
+    list_display_links = ('backend_status_icon', 'id', 'name', )
+    fieldsets = [ (None, {'fields': ['backend_status_text', 'kind', 'name', 'service_specific_id', # 'service_specific_attribute',
+                                     'url_filter_level', "uplink_speed", "downlink_speed", "status", "enable_uverse", "cdn_enable"],
+                          'classes':['suit-tab suit-tab-general']})]
+    readonly_fields = ('backend_status_text', 'service_specific_attribute',)
+    form = CordSubscriberRootForm
+    inlines = (VOLTTenantInline, TenantRootPrivilegeInline)
+
+    suit_form_tabs =(('general', 'Cord Subscriber Root Details'),
+        ('volttenants','VOLT Tenancy'),
+        ('tenantrootprivileges','Privileges')
+    )
+
+    def queryset(self, request):
+        return CordSubscriberRoot.get_tenant_objects_by_user(request.user)
+
+admin.site.register(VOLTService, VOLTServiceAdmin)
+admin.site.register(VOLTTenant, VOLTTenantAdmin)
+admin.site.register(VOLTDevice, VOLTDeviceAdmin)
+admin.site.register(AccessDevice, AccessDeviceAdmin)
+admin.site.register(AccessAgent, AccessAgentAdmin)
+
+admin.site.register(CordSubscriberRoot, CordSubscriberRootAdmin)
+
diff --git a/xos/onboard/volt/api/tenant/cord/subscriber.py b/xos/onboard/volt/api/tenant/cord/subscriber.py
new file mode 100644
index 0000000..52f9b63
--- /dev/null
+++ b/xos/onboard/volt/api/tenant/cord/subscriber.py
@@ -0,0 +1,384 @@
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+from rest_framework import serializers
+from rest_framework import generics
+from rest_framework import viewsets
+from rest_framework import status
+from rest_framework.decorators import detail_route, list_route
+from rest_framework.views import APIView
+from core.models import *
+from django.forms import widgets
+from django.conf.urls import patterns, url
+from services.volt.models import VOLTTenant, CordSubscriberRoot
+from api.xosapi_helpers import PlusModelSerializer, XOSViewSet, ReadOnlyField
+from django.shortcuts import get_object_or_404
+from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
+from xos.exceptions import *
+import json
+import subprocess
+from django.views.decorators.csrf import ensure_csrf_cookie
+
+class CordSubscriberNew(CordSubscriberRoot):
+    class Meta:
+        proxy = True
+        app_label = "cord"
+
+    def __init__(self, *args, **kwargs):
+        super(CordSubscriberNew, self).__init__(*args, **kwargs)
+
+    def __unicode__(self):
+        return u"cordSubscriber-%s" % str(self.id)
+
+    @property
+    def features(self):
+        return {"cdn": self.cdn_enable,
+                "uplink_speed": self.uplink_speed,
+                "downlink_speed": self.downlink_speed,
+                "uverse": self.enable_uverse,
+                "status": self.status}
+
+    @features.setter
+    def features(self, value):
+        self.cdn_enable = value.get("cdn", self.get_default_attribute("cdn_enable"))
+        self.uplink_speed = value.get("uplink_speed", self.get_default_attribute("uplink_speed"))
+        self.downlink_speed = value.get("downlink_speed", self.get_default_attribute("downlink_speed"))
+        self.enable_uverse = value.get("uverse", self.get_default_attribute("enable_uverse"))
+        self.status = value.get("status", self.get_default_attribute("status"))
+
+
+    def update_features(self, value):
+        d=self.features
+        d.update(value)
+        self.features = d
+
+    @property
+    def identity(self):
+        return {"account_num": self.service_specific_id,
+                "name": self.name}
+
+    @identity.setter
+    def identity(self, value):
+        self.service_specific_id = value.get("account_num", self.service_specific_id)
+        self.name = value.get("name", self.name)
+
+    def update_identity(self, value):
+        d=self.identity
+        d.update(value)
+        self.identity = d
+
+    @property
+    def related(self):
+        related = {}
+        if self.volt:
+            related["volt_id"] = self.volt.id
+            related["s_tag"] = self.volt.s_tag
+            related["c_tag"] = self.volt.c_tag
+            if self.volt.vcpe:
+                related["vsg_id"] = self.volt.vcpe.id
+                if self.volt.vcpe.instance:
+                    related["instance_id"] = self.volt.vcpe.instance.id
+                    related["instance_name"] = self.volt.vcpe.instance.name
+                    related["wan_container_ip"] = self.volt.vcpe.wan_container_ip
+                    if self.volt.vcpe.instance.node:
+                         related["compute_node_name"] = self.volt.vcpe.instance.node.name
+        return related
+
+    def save(self, *args, **kwargs):
+        super(CordSubscriberNew, self).save(*args, **kwargs)
+
+class CordDevice(object):
+    def __init__(self, d={}, subscriber=None):
+        self.d = d
+        self.subscriber = subscriber
+
+    @property
+    def mac(self):
+        return self.d.get("mac", None)
+
+    @mac.setter
+    def mac(self, value):
+        self.d["mac"] = value
+
+    @property
+    def identity(self):
+        return {"name": self.d.get("name", None)}
+
+    @identity.setter
+    def identity(self, value):
+        self.d["name"] = value.get("name", None)
+
+    @property
+    def features(self):
+        return {"uplink_speed": self.d.get("uplink_speed", None),
+                "downlink_speed": self.d.get("downlink_speed", None)}
+
+    @features.setter
+    def features(self, value):
+        self.d["uplink_speed"] = value.get("uplink_speed", None)
+        self.d["downlink_speed"] = value.get("downlink_speed", None)
+
+    def update_features(self, value):
+        d=self.features
+        d.update(value)
+        self.features = d
+
+    def update_identity(self, value):
+        d=self.identity
+        d.update(value)
+        self.identity = d
+
+    def save(self):
+        if self.subscriber:
+            dev=self.subscriber.find_device(self.mac)
+            if dev:
+                self.subscriber.update_device(**self.d)
+            else:
+                self.subscriber.create_device(**self.d)
+
+# Add some structure to the REST API by subdividing the object into
+# features, identity, and related.
+
+class FeatureSerializer(serializers.Serializer):
+    cdn = serializers.BooleanField(required=False)
+    uplink_speed = serializers.IntegerField(required=False)
+    downlink_speed = serializers.IntegerField(required=False)
+    uverse = serializers.BooleanField(required=False)
+    status = serializers.CharField(required=False)
+
+class IdentitySerializer(serializers.Serializer):
+    account_num = serializers.CharField(required=False)
+    name = serializers.CharField(required=False)
+
+class DeviceFeatureSerializer(serializers.Serializer):
+    uplink_speed = serializers.IntegerField(required=False)
+    downlink_speed = serializers.IntegerField(required=False)
+
+class DeviceIdentitySerializer(serializers.Serializer):
+    name = serializers.CharField(required=False)
+
+class DeviceSerializer(serializers.Serializer):
+    mac = serializers.CharField(required=True)
+    identity = DeviceIdentitySerializer(required=False)
+    features = DeviceFeatureSerializer(required=False)
+
+    class Meta:
+        fields = ('mac', 'identity', 'features')
+
+class CordSubscriberSerializer(PlusModelSerializer):
+        id = ReadOnlyField()
+        humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+        features = FeatureSerializer(required=False)
+        identity = IdentitySerializer(required=False)
+        related = serializers.DictField(required=False)
+
+        nested_fields = ["features", "identity"]
+
+        class Meta:
+            model = CordSubscriberNew
+            fields = ('humanReadableName',
+                      'id',
+                      'features',
+                      'identity',
+                      'related')
+
+        def getHumanReadableName(self, obj):
+            return obj.__unicode__()
+
+# @ensure_csrf_cookie
+class CordSubscriberViewSet(XOSViewSet):
+    base_name = "subscriber"
+    method_name = "subscriber"
+    method_kind = "viewset"
+    queryset = CordSubscriberNew.get_tenant_objects().select_related().all()
+    serializer_class = CordSubscriberSerializer
+
+    custom_serializers = {"set_features": FeatureSerializer,
+                          "set_feature": FeatureSerializer,
+                          "set_identities": IdentitySerializer,
+                          "set_identity": IdentitySerializer,
+                          "get_devices": DeviceSerializer,
+                          "add_device": DeviceSerializer,
+                          "get_device_feature": DeviceFeatureSerializer,
+                          "set_device_feature": DeviceFeatureSerializer}
+
+    @classmethod
+    def get_urlpatterns(self, api_path="^"):
+        patterns = super(CordSubscriberViewSet, self).get_urlpatterns(api_path=api_path)
+        patterns.append( self.detail_url("features/$", {"get": "get_features", "put": "set_features"}, "features") )
+        patterns.append( self.detail_url("features/(?P<feature>[a-zA-Z0-9\-_]+)/$", {"get": "get_feature", "put": "set_feature"}, "get_feature") )
+        patterns.append( self.detail_url("identity/$", {"get": "get_identities", "put": "set_identities"}, "identities") )
+        patterns.append( self.detail_url("identity/(?P<identity>[a-zA-Z0-9\-_]+)/$", {"get": "get_identity", "put": "set_identity"}, "get_identity") )
+
+        patterns.append( self.detail_url("devices/$", {"get": "get_devices", "post": "add_device"}, "devicees") )
+        patterns.append( self.detail_url("devices/(?P<mac>[a-zA-Z0-9\-_:]+)/$", {"get": "get_device", "delete": "delete_device"}, "getset_device") )
+        patterns.append( self.detail_url("devices/(?P<mac>[a-zA-Z0-9\-_:]+)/features/(?P<feature>[a-zA-Z0-9\-_]+)/$", {"get": "get_device_feature", "put": "set_device_feature"}, "getset_device_feature") )
+        patterns.append( self.detail_url("devices/(?P<mac>[a-zA-Z0-9\-_:]+)/identity/(?P<identity>[a-zA-Z0-9\-_]+)/$", {"get": "get_device_identity", "put": "set_device_identity"}, "getset_device_identity") )
+
+        patterns.append( url(self.api_path + "account_num_lookup/(?P<account_num>[0-9\-]+)/$", self.as_view({"get": "account_num_detail"}), name="account_num_detail") )
+
+        patterns.append( url(self.api_path + "ssidmap/(?P<ssid>[0-9\-]+)/$", self.as_view({"get": "ssiddetail"}), name="ssiddetail") )
+        patterns.append( url(self.api_path + "ssidmap/$", self.as_view({"get": "ssidlist"}), name="ssidlist") )
+
+        return patterns
+
+    def list(self, request):
+        object_list = self.filter_queryset(self.get_queryset())
+
+        serializer = self.get_serializer(object_list, many=True)
+
+        return Response(serializer.data)
+
+    def get_features(self, request, pk=None):
+        subscriber = self.get_object()
+        return Response(FeatureSerializer(subscriber.features).data)
+
+    def set_features(self, request, pk=None):
+        subscriber = self.get_object()
+        ser = FeatureSerializer(subscriber.features, data=request.data)
+        ser.is_valid(raise_exception = True)
+        subscriber.update_features(ser.validated_data)
+        subscriber.save()
+        return Response(FeatureSerializer(subscriber.features).data)
+
+    def get_feature(self, request, pk=None, feature=None):
+        subscriber = self.get_object()
+        return Response({feature: FeatureSerializer(subscriber.features).data[feature]})
+
+    def set_feature(self, request, pk=None, feature=None):
+        subscriber = self.get_object()
+        if [feature] != request.data.keys():
+             raise serializers.ValidationError("feature %s does not match keys in request body (%s)" % (feature, ",".join(request.data.keys())))
+        ser = FeatureSerializer(subscriber.features, data=request.data)
+        ser.is_valid(raise_exception = True)
+        subscriber.update_features(ser.validated_data)
+        subscriber.save()
+        return Response({feature: FeatureSerializer(subscriber.features).data[feature]})
+
+    def get_identities(self, request, pk=None):
+        subscriber = self.get_object()
+        return Response(IdentitySerializer(subscriber.identity).data)
+
+    def set_identities(self, request, pk=None):
+        subscriber = self.get_object()
+        ser = IdentitySerializer(subscriber.identity, data=request.data)
+        ser.is_valid(raise_exception = True)
+        subscriber.update_identity(ser.validated_data)
+        subscriber.save()
+        return Response(IdentitySerializer(subscriber.identity).data)
+
+    def get_identity(self, request, pk=None, identity=None):
+        subscriber = self.get_object()
+        return Response({identity: IdentitySerializer(subscriber.identity).data[identity]})
+
+    def set_identity(self, request, pk=None, identity=None):
+        subscriber = self.get_object()
+        if [identity] != request.data.keys():
+             raise serializers.ValidationError("identity %s does not match keys in request body (%s)" % (identity, ",".join(request.data.keys())))
+        ser = IdentitySerializer(subscriber.identity, data=request.data)
+        ser.is_valid(raise_exception = True)
+        subscriber.update_identity(ser.validated_data)
+        subscriber.save()
+        return Response({identity: IdentitySerializer(subscriber.identity).data[identity]})
+
+    def get_devices(self, request, pk=None):
+        subscriber = self.get_object()
+        result = []
+        for device in subscriber.devices:
+            device = CordDevice(device, subscriber)
+            result.append(DeviceSerializer(device).data)
+        return Response(result)
+
+    def add_device(self, request, pk=None):
+        subscriber = self.get_object()
+        ser = DeviceSerializer(subscriber.devices, data=request.data)
+        ser.is_valid(raise_exception = True)
+        newdevice = CordDevice(subscriber.create_device(**ser.validated_data), subscriber)
+        subscriber.save()
+        return Response(DeviceSerializer(newdevice).data)
+
+    def get_device(self, request, pk=None, mac=None):
+        subscriber = self.get_object()
+        device = subscriber.find_device(mac)
+        if not device:
+            return Response("Failed to find device %s" % mac, status=status.HTTP_404_NOT_FOUND)
+        return Response(DeviceSerializer(CordDevice(device, subscriber)).data)
+
+    def delete_device(self, request, pk=None, mac=None):
+        subscriber = self.get_object()
+        device = subscriber.find_device(mac)
+        if not device:
+            return Response("Failed to find device %s" % mac, status=status.HTTP_404_NOT_FOUND)
+        subscriber.delete_device(mac)
+        subscriber.save()
+        return Response("Okay")
+
+    def get_device_feature(self, request, pk=None, mac=None, feature=None):
+        subscriber = self.get_object()
+        device = subscriber.find_device(mac)
+        if not device:
+            return Response("Failed to find device %s" % mac, status=status.HTTP_404_NOT_FOUND)
+        return Response({feature: DeviceFeatureSerializer(CordDevice(device, subscriber).features).data[feature]})
+
+    def set_device_feature(self, request, pk=None, mac=None, feature=None):
+        subscriber = self.get_object()
+        device = subscriber.find_device(mac)
+        if not device:
+            return Response("Failed to find device %s" % mac, status=status.HTTP_404_NOT_FOUND)
+        if [feature] != request.data.keys():
+             raise serializers.ValidationError("feature %s does not match keys in request body (%s)" % (feature, ",".join(request.data.keys())))
+        device = CordDevice(device, subscriber)
+        ser = DeviceFeatureSerializer(device.features, data=request.data)
+        ser.is_valid(raise_exception = True)
+        device.update_features(ser.validated_data)
+        device.save()
+        subscriber.save()
+        return Response({feature: DeviceFeatureSerializer(device.features).data[feature]})
+
+    def get_device_identity(self, request, pk=None, mac=None, identity=None):
+        subscriber = self.get_object()
+        device = subscriber.find_device(mac)
+        if not device:
+            return Response("Failed to find device %s" % mac, status=status.HTTP_404_NOT_FOUND)
+        return Response({identity: DeviceIdentitySerializer(CordDevice(device, subscriber).identity).data[identity]})
+
+    def set_device_identity(self, request, pk=None, mac=None, identity=None):
+        subscriber = self.get_object()
+        device = subscriber.find_device(mac)
+        if not device:
+            return Response("Failed to find device %s" % mac, status=status.HTTP_404_NOT_FOUND)
+        if [identity] != request.data.keys():
+             raise serializers.ValidationError("identity %s does not match keys in request body (%s)" % (feature, ",".join(request.data.keys())))
+        device = CordDevice(device, subscriber)
+        ser = DeviceIdentitySerializer(device.identity, data=request.data)
+        ser.is_valid(raise_exception = True)
+        device.update_identity(ser.validated_data)
+        device.save()
+        subscriber.save()
+        return Response({identity: DeviceIdentitySerializer(device.identity).data[identity]})
+
+    def account_num_detail(self, pk=None, account_num=None):
+        object_list = CordSubscriberNew.get_tenant_objects().all()
+        object_list = [x for x in object_list if x.service_specific_id == account_num]
+        if not object_list:
+            return Response("Failed to find account_num %s" % account_num, status=status.HTTP_404_NOT_FOUND)
+
+        return Response( object_list[0].id )
+
+    def ssidlist(self, request):
+        object_list = CordSubscriberNew.get_tenant_objects().all()
+
+        ssidmap = [ {"service_specific_id": x.service_specific_id, "subscriber_id": x.id} for x in object_list ]
+
+        return Response({"ssidmap": ssidmap})
+
+    def ssiddetail(self, pk=None, ssid=None):
+        object_list = CordSubscriberNew.get_tenant_objects().all()
+
+        ssidmap = [ {"service_specific_id": x.service_specific_id, "subscriber_id": x.id} for x in object_list if str(x.service_specific_id)==str(ssid) ]
+
+        if len(ssidmap)==0:
+            raise XOSNotFound("didn't find ssid %s" % str(ssid))
+
+        return Response( ssidmap[0] )
+
diff --git a/xos/onboard/volt/api/tenant/cord/volt.py b/xos/onboard/volt/api/tenant/cord/volt.py
new file mode 100644
index 0000000..5c9634a
--- /dev/null
+++ b/xos/onboard/volt/api/tenant/cord/volt.py
@@ -0,0 +1,96 @@
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+from rest_framework import serializers
+from rest_framework import generics
+from rest_framework import status
+from core.models import *
+from django.forms import widgets
+from services.volt.models import VOLTTenant, VOLTService, CordSubscriberRoot
+from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
+from api.xosapi_helpers import PlusModelSerializer, XOSViewSet, ReadOnlyField
+
+def get_default_volt_service():
+    volt_services = VOLTService.get_service_objects().all()
+    if volt_services:
+        return volt_services[0].id
+    return None
+
+class VOLTTenantForAPI(VOLTTenant):
+    class Meta:
+        proxy = True
+        app_label = "cord"
+
+    @property
+    def subscriber(self):
+        return self.subscriber_root.id
+
+    @subscriber.setter
+    def subscriber(self, value):
+        self.subscriber_root = value # CordSubscriberRoot.get_tenant_objects().get(id=value)
+
+    @property
+    def related(self):
+        related = {}
+        if self.vcpe:
+            related["vsg_id"] = self.vcpe.id
+            if self.vcpe.instance:
+                related["instance_id"] = self.vcpe.instance.id
+                related["instance_name"] = self.vcpe.instance.name
+                related["wan_container_ip"] = self.vcpe.wan_container_ip
+                if self.vcpe.instance.node:
+                    related["compute_node_name"] = self.vcpe.instance.node.name
+        return related
+
+class VOLTTenantSerializer(PlusModelSerializer):
+    id = ReadOnlyField()
+    service_specific_id = serializers.CharField(required=False)
+    s_tag = serializers.CharField()
+    c_tag = serializers.CharField()
+    subscriber = serializers.PrimaryKeyRelatedField(queryset=CordSubscriberRoot.get_tenant_objects().all(), required=False)
+    related = serializers.DictField(required=False)
+
+    property_fields=["subscriber"]
+
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    class Meta:
+        model = VOLTTenantForAPI
+        fields = ('humanReadableName', 'id', 'service_specific_id', 's_tag', 'c_tag', 'subscriber', 'related' )
+
+    def getHumanReadableName(self, obj):
+        return obj.__unicode__()
+
+class VOLTTenantViewSet(XOSViewSet):
+    base_name = "volt"
+    method_name = "volt"
+    method_kind = "viewset"
+    queryset = VOLTTenantForAPI.get_tenant_objects().all() # select_related().all()
+    serializer_class = VOLTTenantSerializer
+
+    @classmethod
+    def get_urlpatterns(self, api_path="^"):
+        patterns = super(VOLTTenantViewSet, self).get_urlpatterns(api_path=api_path)
+
+        return patterns
+
+    def list(self, request):
+        queryset = self.filter_queryset(self.get_queryset())
+
+        c_tag = self.request.query_params.get('c_tag', None)
+        if c_tag is not None:
+            ids = [x.id for x in queryset if x.get_attribute("c_tag", None)==c_tag]
+            queryset = queryset.filter(id__in=ids)
+
+        s_tag = self.request.query_params.get('s_tag', None)
+        if s_tag is not None:
+            ids = [x.id for x in queryset if x.get_attribute("s_tag", None)==s_tag]
+            queryset = queryset.filter(id__in=ids)
+
+        serializer = self.get_serializer(queryset, many=True)
+
+        return Response(serializer.data)
+
+
+
+
+
diff --git a/xos/onboard/volt/models.py b/xos/onboard/volt/models.py
new file mode 100644
index 0000000..8f3cc1f
--- /dev/null
+++ b/xos/onboard/volt/models.py
@@ -0,0 +1,367 @@
+from django.db import models
+from core.models import Service, PlCoreBase, Slice, Instance, Tenant, TenantWithContainer, Node, Image, User, Flavor, Subscriber, NetworkParameter, NetworkParameterType, Port, AddressPool, User
+from core.models.plcorebase import StrippedCharField
+import os
+from django.db import models, transaction
+from django.forms.models import model_to_dict
+from django.db.models import Q
+from operator import itemgetter, attrgetter, methodcaller
+from core.models import Tag
+from core.models.service import LeastLoadedNodeScheduler
+from services.vrouter.models import VRouterService, VRouterTenant
+import traceback
+from xos.exceptions import *
+from xos.config import Config
+
+class ConfigurationError(Exception):
+    pass
+
+VOLT_KIND = "vOLT"
+CORD_SUBSCRIBER_KIND = "CordSubscriberRoot"
+
+CORD_USE_VTN = getattr(Config(), "networking_use_vtn", False)
+
+# -------------------------------------------
+# CordSubscriberRoot
+# -------------------------------------------
+
+class CordSubscriberRoot(Subscriber):
+    class Meta:
+        proxy = True
+
+    KIND = CORD_SUBSCRIBER_KIND
+
+    status_choices = (("enabled", "Enabled"),
+                      ("suspended", "Suspended"),
+                      ("delinquent", "Delinquent"),
+                      ("copyrightviolation", "Copyright Violation"))
+
+    # 'simple_attributes' will be expanded into properties and setters that
+    # store the attribute using self.set_attribute / self.get_attribute.
+
+    simple_attributes = ( ("firewall_enable", False),
+                          ("firewall_rules", "accept all anywhere anywhere"),
+                          ("url_filter_enable", False),
+                          ("url_filter_rules", "allow all"),
+                          ("url_filter_level", "PG"),
+                          ("cdn_enable", False),
+                          ("devices", []),
+                          ("is_demo_user", False),
+
+                          ("uplink_speed", 1000000000),  # 1 gigabit, a reasonable default?
+                          ("downlink_speed", 1000000000),
+                          ("enable_uverse", True) )
+
+    default_attributes = {"status": "enabled"}
+
+    sync_attributes = ("firewall_enable",
+                       "firewall_rules",
+                       "url_filter_enable",
+                       "url_filter_rules",
+                       "cdn_enable",
+                       "uplink_speed",
+                       "downlink_speed",
+                       "enable_uverse",
+                       "status")
+
+    def __init__(self, *args, **kwargs):
+        super(CordSubscriberRoot, self).__init__(*args, **kwargs)
+        self.cached_volt = None
+        self._initial_url_filter_enable = self.url_filter_enable
+
+    @property
+    def volt(self):
+        volt = self.get_newest_subscribed_tenant(VOLTTenant)
+        if not volt:
+            return None
+
+        # always return the same object when possible
+        if (self.cached_volt) and (self.cached_volt.id == volt.id):
+            return self.cached_volt
+
+        #volt.caller = self.creator
+        self.cached_volt = volt
+        return volt
+
+    @property
+    def status(self):
+        return self.get_attribute("status", self.default_attributes["status"])
+
+    @status.setter
+    def status(self, value):
+        if not value in [x[0] for x in self.status_choices]:
+            raise Exception("invalid status %s" % value)
+        self.set_attribute("status", value)
+
+    def find_device(self, mac):
+        for device in self.devices:
+            if device["mac"] == mac:
+                return device
+        return None
+
+    def update_device(self, mac, **kwargs):
+        # kwargs may be "level" or "mac"
+        #    Setting one of these to None will cause None to be stored in the db
+        devices = self.devices
+        for device in devices:
+            if device["mac"] == mac:
+                for arg in kwargs.keys():
+                    device[arg] = kwargs[arg]
+                self.devices = devices
+                return device
+        raise ValueError("Device with mac %s not found" % mac)
+
+    def create_device(self, **kwargs):
+        if "mac" not in kwargs:
+            raise XOSMissingField("The mac field is required")
+
+        if self.find_device(kwargs['mac']):
+                raise XOSDuplicateKey("Device with mac %s already exists" % kwargs["mac"])
+
+        device = kwargs.copy()
+
+        devices = self.devices
+        devices.append(device)
+        self.devices = devices
+
+        return device
+
+    def delete_device(self, mac):
+        devices = self.devices
+        for device in devices:
+            if device["mac"]==mac:
+                devices.remove(device)
+                self.devices = devices
+                return
+
+        raise ValueError("Device with mac %s not found" % mac)
+
+    #--------------------------------------------------------------------------
+    # Deprecated -- devices used to be called users
+
+    def find_user(self, uid):
+        return self.find_device(uid)
+
+    def update_user(self, uid, **kwargs):
+        return self.update_device(uid, **kwargs)
+
+    def create_user(self, **kwargs):
+        return self.create_device(**kwargs)
+
+    def delete_user(self, uid):
+        return self.delete_user(uid)
+
+    # ------------------------------------------------------------------------
+
+    @property
+    def services(self):
+        return {"cdn": self.cdn_enable,
+                "url_filter": self.url_filter_enable,
+                "firewall": self.firewall_enable}
+
+    @services.setter
+    def services(self, value):
+        pass
+
+    def save(self, *args, **kwargs):
+        self.validate_unique_service_specific_id(none_okay=True)
+        if (not hasattr(self, 'caller') or not self.caller.is_admin):
+            if (self.has_field_changed("service_specific_id")):
+                raise XOSPermissionDenied("You do not have permission to change service_specific_id")
+        super(CordSubscriberRoot, self).save(*args, **kwargs)
+        if (self.volt) and (self.volt.vcpe): # and (self._initial_url_filter_enabled != self.url_filter_enable):
+            # 1) trigger manage_bbs_account to run
+            # 2) trigger vcpe observer to wake up
+            self.volt.vcpe.save()
+
+CordSubscriberRoot.setup_simple_attributes()
+
+# -------------------------------------------
+# VOLT
+# -------------------------------------------
+
+class VOLTService(Service):
+    KIND = VOLT_KIND
+
+    class Meta:
+        app_label = "volt"
+        verbose_name = "vOLT Service"
+
+class VOLTTenant(Tenant):
+    KIND = VOLT_KIND
+
+    class Meta:
+        app_label = "volt"
+        verbose_name = "vOLT Tenant"
+
+    s_tag = models.IntegerField(null=True, blank=True, help_text="s-tag")
+    c_tag = models.IntegerField(null=True, blank=True, help_text="c-tag")
+
+    # at some point, this should probably end up part of Tenant.
+    creator = models.ForeignKey(User, related_name='created_volts', blank=True, null=True)
+
+    def __init__(self, *args, **kwargs):
+        volt_services = VOLTService.get_service_objects().all()
+        if volt_services:
+            self._meta.get_field("provider_service").default = volt_services[0].id
+        super(VOLTTenant, self).__init__(*args, **kwargs)
+        self.cached_vcpe = None
+
+    @property
+    def vcpe(self):
+        from services.vsg.models import VSGTenant
+        vcpe = self.get_newest_subscribed_tenant(VSGTenant)
+        if not vcpe:
+            return None
+
+        # always return the same object when possible
+        if (self.cached_vcpe) and (self.cached_vcpe.id == vcpe.id):
+            return self.cached_vcpe
+
+        vcpe.caller = self.creator
+        self.cached_vcpe = vcpe
+        return vcpe
+
+    @vcpe.setter
+    def vcpe(self, value):
+        raise XOSConfigurationError("vOLT.vCPE cannot be set this way -- create a new vCPE object and set its subscriber_tenant instead")
+
+    @property
+    def subscriber(self):
+        if not self.subscriber_root:
+            return None
+        subs = CordSubscriberRoot.objects.filter(id=self.subscriber_root.id)
+        if not subs:
+            return None
+        return subs[0]
+
+    def manage_vcpe(self):
+        # Each VOLT object owns exactly one VCPE object
+
+        if self.deleted:
+            return
+
+        if self.vcpe is None:
+            from services.vsg.models import VSGService, VSGTenant
+            vsgServices = VSGService.get_service_objects().all()
+            if not vsgServices:
+                raise XOSConfigurationError("No VSG Services available")
+
+            vcpe = VSGTenant(provider_service = vsgServices[0],
+                              subscriber_tenant = self)
+            vcpe.caller = self.creator
+            vcpe.save()
+
+    def manage_subscriber(self):
+        if (self.subscriber_root is None):
+            # The vOLT is not connected to a Subscriber, so either find an
+            # existing subscriber with the same SSID, or autogenerate a new
+            # subscriber.
+            #
+            # TODO: This probably goes away when we rethink the ONOS-to-XOS
+            # vOLT API.
+
+            subs = CordSubscriberRoot.get_tenant_objects().filter(service_specific_id = self.service_specific_id)
+            if subs:
+                sub = subs[0]
+            else:
+                sub = CordSubscriberRoot(service_specific_id = self.service_specific_id,
+                                         name = "autogenerated-for-vOLT-%s" % self.id)
+                sub.save()
+            self.subscriber_root = sub
+            self.save()
+
+    def cleanup_vcpe(self):
+        if self.vcpe:
+            # print "XXX cleanup vcpe", self.vcpe
+            self.vcpe.delete()
+
+    def cleanup_orphans(self):
+        from services.vsg.models import VSGTenant
+        # ensure vOLT only has one vCPE
+        cur_vcpe = self.vcpe
+        for vcpe in list(self.get_subscribed_tenants(VSGTenant)):
+            if (not cur_vcpe) or (vcpe.id != cur_vcpe.id):
+                # print "XXX clean up orphaned vcpe", vcpe
+                vcpe.delete()
+
+    def save(self, *args, **kwargs):
+        # VOLTTenant probably doesn't need a SSID anymore; that will be handled
+        # by CORDSubscriberRoot...
+        # self.validate_unique_service_specific_id()
+
+        if (self.subscriber_root is not None):
+            subs = self.subscriber_root.get_subscribed_tenants(VOLTTenant)
+            if (subs) and (self not in subs):
+                raise XOSDuplicateKey("Subscriber should only be linked to one vOLT")
+
+        if not self.creator:
+            if not getattr(self, "caller", None):
+                # caller must be set when creating a vCPE since it creates a slice
+                raise XOSProgrammingError("VOLTTenant's self.caller was not set")
+            self.creator = self.caller
+            if not self.creator:
+                raise XOSProgrammingError("VOLTTenant's self.creator was not set")
+
+        super(VOLTTenant, self).save(*args, **kwargs)
+        model_policy_volt(self.pk)
+
+    def delete(self, *args, **kwargs):
+        self.cleanup_vcpe()
+        super(VOLTTenant, self).delete(*args, **kwargs)
+
+def model_policy_volt(pk):
+    # TODO: this should be made in to a real model_policy
+    with transaction.atomic():
+        volt = VOLTTenant.objects.select_for_update().filter(pk=pk)
+        if not volt:
+            return
+        volt = volt[0]
+        volt.manage_vcpe()
+        volt.manage_subscriber()
+        volt.cleanup_orphans()
+
+class VOLTDevice(PlCoreBase):
+    class Meta:
+        app_label = "volt"
+
+    name = models.CharField(max_length=254, help_text="name of device", null=False, blank=False)
+    volt_service = models.ForeignKey(VOLTService, related_name='volt_devices')
+    openflow_id = models.CharField(max_length=254, help_text="OpenFlow ID", null=True, blank=True)
+    driver = models.CharField(max_length=254, help_text="driver", null=True, blank=True)
+    access_agent = models.ForeignKey("AccessAgent", related_name='volt_devices', blank=True, null=True)
+
+    def __unicode__(self): return u'%s' % (self.name)
+
+class AccessDevice(PlCoreBase):
+    class Meta:
+        app_label = "volt"
+
+    volt_device = models.ForeignKey(VOLTDevice, related_name='access_devices')
+    uplink = models.IntegerField(null=True, blank=True)
+    vlan = models.IntegerField(null=True, blank=True)
+
+    def __unicode__(self): return u'%s-%d:%d' % (self.volt_device.name,self.uplink,self.vlan)
+
+class AccessAgent(PlCoreBase):
+    class Meta:
+        app_label = "volt"
+
+    name = models.CharField(max_length=254, help_text="name of agent", null=False, blank=False)
+    volt_service = models.ForeignKey(VOLTService, related_name='access_agents')
+    mac = models.CharField(max_length=32, help_text="MAC Address or Access Agent", null=True, blank=True)
+
+    def __unicode__(self): return u'%s' % (self.name)
+
+class AgentPortMapping(PlCoreBase):
+    class Meta:
+        app_label = "volt"
+
+    access_agent = models.ForeignKey(AccessAgent, related_name='port_mappings')
+    mac = models.CharField(max_length=32, help_text="MAC Address", null=True, blank=True)
+    port = models.CharField(max_length=32, help_text="Openflow port ID", null=True, blank=True)
+
+    def __unicode__(self): return u'%s-%s-%s' % (self.access_agent.name, self.port, self.mac)
+
+
+
diff --git a/xos/onboard/volt/templates/voltadmin.html b/xos/onboard/volt/templates/voltadmin.html
new file mode 100644
index 0000000..807ab2c
--- /dev/null
+++ b/xos/onboard/volt/templates/voltadmin.html
@@ -0,0 +1,10 @@
+<div class = "row text-center">
+    <div class="col-xs-12">
+        <a href="/admin/cord/volttenant/">vOLT Tenants</a>
+    </div><div class="col-xs-12">
+        <a href="/admin/cord/voltdevice/">vOLT Devices</a>
+    </div><div class="col-xs-12">
+        <a href="/admin/cord/accessagent/">vOLT Access Agents</a>
+    </div>
+</div>
+
diff --git a/xos/onboard/volt/tosca/resources/CORDSubscriber.py b/xos/onboard/volt/tosca/resources/CORDSubscriber.py
new file mode 100644
index 0000000..5cdb2ef
--- /dev/null
+++ b/xos/onboard/volt/tosca/resources/CORDSubscriber.py
@@ -0,0 +1,25 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+import pdb
+
+from core.models import User, TenantRootPrivilege, TenantRootRole
+from services.volt.models import CordSubscriberRoot
+
+from xosresource import XOSResource
+
+class XOSCORDSubscriber(XOSResource):
+    provides = "tosca.nodes.CORDSubscriber"
+    xos_model = CordSubscriberRoot
+    copyin_props = ["service_specific_id", "firewall_enable", "url_filter_enable", "cdn_enable", "url_filter_level"]
+
+    def postprocess(self, obj):
+        rolemap = ( ("tosca.relationships.AdminPrivilege", "admin"), ("tosca.relationships.AccessPrivilege", "access"), )
+        self.postprocess_privileges(TenantRootRole, TenantRootPrivilege, rolemap, obj, "tenant_root")
+
+    def can_delete(self, obj):
+        return super(XOSCORDSubscriber, self).can_delete(obj)
+
diff --git a/xos/onboard/volt/tosca/resources/CORDUser.py b/xos/onboard/volt/tosca/resources/CORDUser.py
new file mode 100644
index 0000000..d1ae1cc
--- /dev/null
+++ b/xos/onboard/volt/tosca/resources/CORDUser.py
@@ -0,0 +1,63 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+import pdb
+
+from core.models import User
+from services.volt.models import CordSubscriberRoot
+
+from xosresource import XOSResource
+
+class XOSCORDUser(XOSResource):
+    provides = "tosca.nodes.CORDUser"
+
+    def get_model_class_name(self):
+        return "CORDUser"
+
+    def get_subscriber_root(self, throw_exception=True):
+        sub_name = self.get_requirement("tosca.relationships.SubscriberDevice", throw_exception=throw_exception)
+        sub = self.get_xos_object(CordSubscriberRoot, name=sub_name, throw_exception=throw_exception)
+        return sub
+
+    def get_existing_objs(self):
+        result = []
+        sub = self.get_subscriber_root(throw_exception=False)
+        if not sub:
+           return []
+        for user in sub.devices:
+            if user["name"] == self.obj_name:
+                result.append(user)
+        return result
+
+    def get_xos_args(self):
+        args = {"name": self.obj_name,
+                "level": self.get_property("level"),
+                "mac": self.get_property("mac")}
+        return args
+
+
+    def create(self):
+        xos_args = self.get_xos_args()
+        sub = self.get_subscriber_root()
+
+        sub.create_device(**xos_args)
+        sub.save()
+
+        self.info("Created CORDUser %s for Subscriber %s" % (self.obj_name, sub.name))
+
+    def update(self, obj):
+        pass
+
+    def delete(self, obj):
+        if (self.can_delete(obj)):
+            self.info("destroying CORDUser %s" % obj["name"])
+            sub = self.get_subscriber_root()
+            sub.delete_user(obj["id"])
+            sub.save()
+
+    def can_delete(self, obj):
+        return True
+
diff --git a/xos/onboard/volt/tosca/resources/VOLTTenant.py b/xos/onboard/volt/tosca/resources/VOLTTenant.py
new file mode 100644
index 0000000..cbc3837
--- /dev/null
+++ b/xos/onboard/volt/tosca/resources/VOLTTenant.py
@@ -0,0 +1,48 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+import pdb
+
+from core.models import User
+from services.volt.models import VOLTTenant, VOLTService, CordSubscriberRoot, VOLT_KIND
+
+from xosresource import XOSResource
+
+class XOSVOLTTenant(XOSResource):
+    provides = "tosca.nodes.VOLTTenant"
+    xos_model = VOLTTenant
+    copyin_props = ["service_specific_id", "s_tag", "c_tag"]
+    name_field = None
+
+    def get_xos_args(self, throw_exception=True):
+        args = super(XOSVOLTTenant, self).get_xos_args()
+
+        provider_name = self.get_requirement("tosca.relationships.MemberOfService", throw_exception=throw_exception)
+        if provider_name:
+            args["provider_service"] = self.get_xos_object(VOLTService, throw_exception=throw_exception, name=provider_name)
+
+        subscriber_name = self.get_requirement("tosca.relationships.BelongsToSubscriber")
+        if subscriber_name:
+            args["subscriber_root"] = self.get_xos_object(CordSubscriberRoot, throw_exception=throw_exception, name=subscriber_name)
+
+        return args
+
+    def get_existing_objs(self):
+        args = self.get_xos_args(throw_exception=False)
+        provider_service = args.get("provider_service", None)
+        service_specific_id = args.get("service_specific_id", None)
+        if (provider_service) and (service_specific_id):
+            existing_obj = self.get_xos_object(VOLTTenant, kind=VOLT_KIND, provider_service=provider_service, service_specific_id=service_specific_id, throw_exception=False)
+            if existing_obj:
+                return [ existing_obj ]
+        return []
+
+    def postprocess(self, obj):
+        pass
+
+    def can_delete(self, obj):
+        return super(XOSVOLTTenant, self).can_delete(obj)
+
diff --git a/xos/onboard/volt/tosca/resources/accessagent.py b/xos/onboard/volt/tosca/resources/accessagent.py
new file mode 100644
index 0000000..e40a1cb
--- /dev/null
+++ b/xos/onboard/volt/tosca/resources/accessagent.py
@@ -0,0 +1,56 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from services.volt.models import AccessAgent, VOLTDevice, VOLTService, AgentPortMapping
+from xosresource import XOSResource
+
+class XOSAccessAgent(XOSResource):
+    provides = "tosca.nodes.AccessAgent"
+    xos_model = AccessAgent
+    copyin_props = ["mac"]
+
+    def get_xos_args(self, throw_exception=True):
+        args = super(XOSAccessAgent, self).get_xos_args()
+
+        volt_service_name = self.get_requirement("tosca.relationships.MemberOfService", throw_exception=throw_exception)
+        if volt_service_name:
+            args["volt_service"] = self.get_xos_object(VOLTService, throw_exception=throw_exception, name=volt_service_name)
+
+        return args
+
+    def postprocess(self, obj):
+        # For convenient, allow the port mappings to be specified by a Tosca
+        # string with commas between lines.
+        #      <port> <mac>,
+        #      <port> <mac>,
+        #      ...
+        #      <port> <mac>
+
+        port_mappings_str = self.get_property("port_mappings")
+        port_mappings = []
+        if port_mappings_str:
+            lines = [x.strip() for x in port_mappings_str.split(",")]
+            for line in lines:
+                if not (" " in line):
+                    raise "Malformed port mapping `%s`", line
+                (port, mac) = line.split(" ")
+                port=port.strip()
+                mac=mac.strip()
+                port_mappings.append( (port, mac) )
+
+            for apm in list(AgentPortMapping.objects.filter(access_agent=obj)):
+                if (apm.port, apm.mac) not in port_mappings:
+                    print "Deleting AgentPortMapping '%s'" % apm
+                    apm.delete()
+
+            for port_mapping in port_mappings:
+                existing_objs = AgentPortMapping.objects.filter(access_agent=obj, port=port_mapping[0], mac=port_mapping[1])
+                if not existing_objs:
+                    apm = AgentPortMapping(access_agent=obj, port=port_mapping[0], mac=port_mapping[1])
+                    apm.save()
+                    print "Created AgentPortMapping '%s'" % apm
+
diff --git a/xos/onboard/volt/tosca/resources/accessdevice.py b/xos/onboard/volt/tosca/resources/accessdevice.py
new file mode 100644
index 0000000..f31b37a
--- /dev/null
+++ b/xos/onboard/volt/tosca/resources/accessdevice.py
@@ -0,0 +1,40 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from services.volt.models import AccessDevice, VOLTDevice
+from xosresource import XOSResource
+
+class XOSAccessDevice(XOSResource):
+    provides = "tosca.nodes.AccessDevice"
+    xos_model = AccessDevice
+    copyin_props = ["uplink", "vlan"]
+    name_field = None
+
+    def get_xos_args(self, throw_exception=True):
+        args = super(XOSAccessDevice, self).get_xos_args()
+
+        volt_device_name = self.get_requirement("tosca.relationships.MemberOfDevice", throw_exception=throw_exception)
+        if volt_device_name:
+            args["volt_device"] = self.get_xos_object(VOLTDevice, throw_exception=throw_exception, name=volt_device_name)
+
+        return args
+
+    # AccessDevice has no name field, so we rely on matching the keys. We assume
+    # the for a given VOLTDevice, there is only one AccessDevice per (uplink, vlan)
+    # pair.
+
+    def get_existing_objs(self):
+        args = self.get_xos_args(throw_exception=False)
+        volt_device = args.get("volt_device", None)
+        uplink = args.get("uplink", None)
+        vlan = args.get("vlan", None)
+        if (volt_device is not None) and (uplink is not None) and (vlan is not None):
+            existing_obj = self.get_xos_object(AccessDevice, volt_device=volt_device, uplink=uplink, vlan=vlan, throw_exception=False)
+            if existing_obj:
+                return [ existing_obj ]
+        return []
+
diff --git a/xos/onboard/volt/tosca/resources/voltdevice.py b/xos/onboard/volt/tosca/resources/voltdevice.py
new file mode 100644
index 0000000..9665b85
--- /dev/null
+++ b/xos/onboard/volt/tosca/resources/voltdevice.py
@@ -0,0 +1,52 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from services.volt.models import VOLTDevice, VOLTService, AccessDevice, AccessAgent
+from xosresource import XOSResource
+
+class XOSVOLTDevice(XOSResource):
+    provides = "tosca.nodes.VOLTDevice"
+    xos_model = VOLTDevice
+    copyin_props = ["openflow_id", "driver"]
+
+    def get_xos_args(self, throw_exception=True):
+        args = super(XOSVOLTDevice, self).get_xos_args()
+
+        volt_service_name = self.get_requirement("tosca.relationships.MemberOfService", throw_exception=throw_exception)
+        if volt_service_name:
+            args["volt_service"] = self.get_xos_object(VOLTService, throw_exception=throw_exception, name=volt_service_name)
+
+        agent_name = self.get_requirement("tosca.relationships.UsesAgent", throw_exception=throw_exception)
+        if agent_name:
+            args["access_agent"] = self.get_xos_object(AccessAgent, throw_exception=throw_exception, name=agent_name)
+
+        return args
+
+    def postprocess(self, obj):
+        access_devices_str = self.get_property("access_devices")
+        access_devices = []
+        if access_devices_str:
+            lines = [x.strip() for x in access_devices_str.split(",")]
+            for line in lines:
+                if not (" " in line):
+                    raise "Malformed access device `%s`", line
+                (uplink, vlan) = line.split(" ")
+                uplink=int(uplink.strip())
+                vlan=int(vlan.strip())
+                access_devices.append( (uplink, vlan) )
+
+            for ad in list(AccessDevice.objects.filter(volt_device=obj)):
+                if (ad.uplink, ad.vlan) not in access_devices:
+                    print "Deleting AccessDevice '%s'" % ad
+                    ad.delete()
+
+            for access_device in access_devices:
+                existing_objs = AccessDevice.objects.filter(volt_device=obj, uplink=access_device[0], vlan=access_device[1])
+                if not existing_objs:
+                    ad = AccessDevice(volt_device=obj, uplink=access_device[0], vlan=access_device[1])
+                    ad.save()
+                    print "Created AccessDevice '%s'" % ad
diff --git a/xos/onboard/volt/tosca/resources/voltservice.py b/xos/onboard/volt/tosca/resources/voltservice.py
new file mode 100644
index 0000000..9df4259
--- /dev/null
+++ b/xos/onboard/volt/tosca/resources/voltservice.py
@@ -0,0 +1,15 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from services.volt.models import VOLTService
+
+from service import XOSService
+
+class XOSVOLTService(XOSService):
+    provides = "tosca.nodes.VOLTService"
+    xos_model = VOLTService
+    copyin_props = ["view_url", "icon_url", "kind", "enabled", "published", "public_key", "private_key_fn", "versionNumber"]
diff --git a/xos/onboard/volt/volt-onboard.yaml b/xos/onboard/volt/volt-onboard.yaml
new file mode 100644
index 0000000..e91ea93
--- /dev/null
+++ b/xos/onboard/volt/volt-onboard.yaml
@@ -0,0 +1,24 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Onboard the exampleservice
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    servicecontroller#volt:
+      type: tosca.nodes.ServiceController
+      properties:
+          base_url: file:///opt/xos/onboard/volt/
+          # The following will concatenate with base_url automatically, if
+          # base_url is non-null.
+          models: models.py
+          admin: admin.py
+          admin_template: templates/voltadmin.html
+          #synchronizer: synchronizer/manifest
+          tosca_resource: tosca/resources/voltdevice.py, tosca/resources/voltservice.py, tosca/resources/CORDSubscriber.py, tosca/resources/CORDUser.py, tosca/resources/VOLTTenant.py, tosca/resources/accessagent.py, tosca/resources/accessdevice.py
+          rest_tenant: subdirectory:cord api/tenant/cord/volt.py, subdirectory:cord api/tenant/cord/subscriber.py
+          private_key: file:///opt/xos/key_import/volt_rsa
+          public_key: file:///opt/xos/key_import/volt_rsa.pub
+
diff --git a/xos/onboard/vrouter/admin.py b/xos/onboard/vrouter/admin.py
new file mode 100644
index 0000000..4bd99b6
--- /dev/null
+++ b/xos/onboard/vrouter/admin.py
@@ -0,0 +1,114 @@
+from django.contrib import admin
+
+from services.vrouter.models import *
+from django import forms
+from django.utils.safestring import mark_safe
+from django.contrib.auth.admin import UserAdmin
+from django.contrib.admin.widgets import FilteredSelectMultiple
+from django.contrib.auth.forms import ReadOnlyPasswordHashField
+from django.contrib.auth.signals import user_logged_in
+from django.utils import timezone
+from django.contrib.contenttypes import generic
+from suit.widgets import LinkedSelect
+from core.models import AddressPool
+from core.admin import ServiceAppAdmin,SliceInline,ServiceAttrAsTabInline, ReadOnlyAwareAdmin, XOSTabularInline, ServicePrivilegeInline, AddressPoolInline
+from core.middleware import get_request
+
+from functools import update_wrapper
+from django.contrib.admin.views.main import ChangeList
+from django.core.urlresolvers import reverse
+from django.contrib.admin.utils import quote
+
+class VRouterServiceForm(forms.ModelForm):
+    def __init__(self,*args,**kwargs):
+        super (VRouterServiceForm,self ).__init__(*args,**kwargs)
+
+    def save(self, commit=True):
+        return super(VRouterServiceForm, self).save(commit=commit)
+
+    class Meta:
+        model = VRouterService
+
+class VRouterServiceAdmin(ReadOnlyAwareAdmin):
+    model = VRouterService
+    verbose_name = "vRouter Service"
+    verbose_name_plural = "vRouter Service"
+    list_display = ("backend_status_icon", "name", "enabled")
+    list_display_links = ('backend_status_icon', 'name', )
+    fieldsets = [(None, {'fields': ['backend_status_text', 'name','enabled','versionNumber', 'description', "view_url", "icon_url", ],
+                         'classes':['suit-tab suit-tab-general']})]
+    readonly_fields = ('backend_status_text', )
+    inlines = [SliceInline,ServiceAttrAsTabInline,ServicePrivilegeInline,AddressPoolInline]
+    form = VRouterServiceForm
+
+    extracontext_registered_admins = True
+
+    user_readonly_fields = ["name", "enabled", "versionNumber", "description"]
+
+    suit_form_tabs =(('general', 'vRouter Service Details'),
+        ('administration', 'Administration'),
+        ('addresspools', 'Addresses'),
+        #('tools', 'Tools'),
+        ('slices','Slices'),
+        ('serviceattrs','Additional Attributes'),
+        ('serviceprivileges','Privileges'),
+    )
+
+    suit_form_includes = (('vrouteradmin.html', 'top', 'administration'),
+                           ) #('hpctools.html', 'top', 'tools') )
+
+    def queryset(self, request):
+        return VRouterService.get_service_objects_by_user(request.user)
+
+class VRouterTenantForm(forms.ModelForm):
+    public_ip = forms.CharField(required=True)
+    public_mac = forms.CharField(required=True)
+    gateway_ip = forms.CharField(required=False)
+    gateway_mac = forms.CharField(required=False)
+    cidr = forms.CharField(required=False)
+    address_pool = forms.ModelChoiceField(queryset=AddressPool.objects.all(),required=False)
+
+    def __init__(self,*args,**kwargs):
+        super (VRouterTenantForm,self ).__init__(*args,**kwargs)
+        self.fields['kind'].widget.attrs['readonly'] = True
+        self.fields['provider_service'].queryset = VRouterService.get_service_objects().all()
+        if self.instance:
+            # fields for the attributes
+            self.fields['address_pool'].initial = self.instance.address_pool
+            self.fields['public_ip'].initial = self.instance.public_ip
+            self.fields['public_mac'].initial = self.instance.public_mac
+            self.fields['gateway_ip'].initial = self.instance.gateway_ip
+            self.fields['gateway_mac'].initial = self.instance.gateway_mac
+            self.fields['cidr'].initial = self.instance.cidr
+        if (not self.instance) or (not self.instance.pk):
+            # default fields for an 'add' form
+            self.fields['kind'].initial = VROUTER_KIND
+            if VRouterService.get_service_objects().exists():
+               self.fields["provider_service"].initial = VRouterService.get_service_objects().all()[0]
+
+    def save(self, commit=True):
+        self.instance.public_ip = self.cleaned_data.get("public_ip")
+        self.instance.public_mac = self.cleaned_data.get("public_mac")
+        self.instance.address_pool = self.cleaned_data.get("address_pool")
+        return super(VRouterTenantForm, self).save(commit=commit)
+
+    class Meta:
+        model = VRouterTenant
+
+class VRouterTenantAdmin(ReadOnlyAwareAdmin):
+    list_display = ('backend_status_icon', 'id', 'subscriber_tenant', 'public_ip' )
+    list_display_links = ('backend_status_icon', 'id')
+    fieldsets = [ (None, {'fields': ['backend_status_text', 'kind', 'provider_service', 'subscriber_tenant', 'subscriber_service',
+                                     'address_pool', 'public_ip', 'public_mac', 'gateway_ip', 'gateway_mac', 'cidr'],
+                          'classes':['suit-tab suit-tab-general']})]
+    readonly_fields = ('backend_status_text', 'service_specific_attribute', 'gateway_ip', 'gateway_mac', 'cidr')
+    form = VRouterTenantForm
+
+    suit_form_tabs = (('general','Details'),)
+
+    def queryset(self, request):
+        return VRouterTenant.get_tenant_objects_by_user(request.user)
+
+admin.site.register(VRouterService, VRouterServiceAdmin)
+admin.site.register(VRouterTenant, VRouterTenantAdmin)
+
diff --git a/xos/onboard/vrouter/models.py b/xos/onboard/vrouter/models.py
new file mode 100644
index 0000000..d302b13
--- /dev/null
+++ b/xos/onboard/vrouter/models.py
@@ -0,0 +1,143 @@
+from django.db import models
+from core.models import Service, PlCoreBase, Slice, Instance, Tenant, TenantWithContainer, Node, Image, User, Flavor, Subscriber, NetworkParameter, NetworkParameterType, Port, AddressPool
+from core.models.plcorebase import StrippedCharField
+import os
+from django.db import models, transaction
+from django.forms.models import model_to_dict
+from django.db.models import Q
+from operator import itemgetter, attrgetter, methodcaller
+from core.models import Tag
+from core.models.service import LeastLoadedNodeScheduler
+import traceback
+from xos.exceptions import *
+from xos.config import Config
+
+class ConfigurationError(Exception):
+    pass
+
+
+VROUTER_KIND = "vROUTER"
+
+# NOTE: don't change VROUTER_KIND unless you also change the reference to it
+#   in tosca/resources/network.py
+
+CORD_USE_VTN = getattr(Config(), "networking_use_vtn", False)
+
+class VRouterService(Service):
+    KIND = VROUTER_KIND
+
+    class Meta:
+        app_label = "vrouter"
+        verbose_name = "vRouter Service"
+        proxy = True
+
+    def ip_to_mac(self, ip):
+        (a, b, c, d) = ip.split('.')
+        return "02:42:%02x:%02x:%02x:%02x" % (int(a), int(b), int(c), int(d))
+
+    def get_gateways(self):
+        gateways=[]
+
+        aps = self.addresspools.all()
+        for ap in aps:
+            gateways.append( {"gateway_ip": ap.gateway_ip, "gateway_mac": ap.gateway_mac} )
+
+        return gateways
+
+    def get_address_pool(self, name):
+        ap = AddressPool.objects.filter(name=name, service=self)
+        if not ap:
+            raise Exception("vRouter unable to find addresspool %s" % name)
+        return ap[0]
+
+    def get_tenant(self, **kwargs):
+        address_pool_name = kwargs.pop("address_pool_name")
+
+        ap = self.get_address_pool(address_pool_name)
+
+        ip = ap.get_address()
+        if not ip:
+            raise Exception("AddressPool '%s' has run out of addresses." % ap.name)
+
+        t = VRouterTenant(provider_service=self, **kwargs)
+        t.public_ip = ip
+        t.public_mac = self.ip_to_mac(ip)
+        t.address_pool_id = ap.id
+        t.save()
+
+        return t
+
+#VRouterService.setup_simple_attributes()
+
+class VRouterTenant(Tenant):
+    class Meta:
+        proxy = True
+
+    KIND = VROUTER_KIND
+
+    simple_attributes = ( ("public_ip", None),
+                          ("public_mac", None),
+                          ("address_pool_id", None),
+                          )
+
+    @property
+    def gateway_ip(self):
+        if not self.address_pool:
+            return None
+        return self.address_pool.gateway_ip
+
+    @property
+    def gateway_mac(self):
+        if not self.address_pool:
+            return None
+        return self.address_pool.gateway_mac
+
+    @property
+    def cidr(self):
+        if not self.address_pool:
+            return None
+        return self.address_pool.cidr
+
+    @property
+    def netbits(self):
+        # return number of bits in the network portion of the cidr
+        if self.cidr:
+            parts = self.cidr.split("/")
+            if len(parts)==2:
+                return int(parts[1].strip())
+        return None
+
+    @property
+    def address_pool(self):
+        if getattr(self, "cached_address_pool", None):
+            return self.cached_address_pool
+        if not self.address_pool_id:
+            return None
+        aps=AddressPool.objects.filter(id=self.address_pool_id)
+        if not aps:
+            return None
+        ap=aps[0]
+        self.cached_address_pool = ap
+        return ap
+
+    @address_pool.setter
+    def address_pool(self, value):
+        if value:
+            value = value.id
+        if (value != self.get_attribute("address_pool_id", None)):
+            self.cached_address_pool=None
+        self.set_attribute("address_pool_id", value)
+
+    def cleanup_addresspool(self):
+        if self.address_pool_id:
+            ap = AddressPool.objects.filter(id=self.address_pool_id)
+            if ap:
+                ap[0].put_address(self.public_ip)
+                self.public_ip = None
+
+    def delete(self, *args, **kwargs):
+        self.cleanup_addresspool()
+        super(VRouterTenant, self).delete(*args, **kwargs)
+
+VRouterTenant.setup_simple_attributes()
+
diff --git a/xos/onboard/vrouter/templates/vrouteradmin.html b/xos/onboard/vrouter/templates/vrouteradmin.html
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xos/onboard/vrouter/templates/vrouteradmin.html
diff --git a/xos/onboard/vrouter/tosca/resources/vrouterservice.py b/xos/onboard/vrouter/tosca/resources/vrouterservice.py
new file mode 100644
index 0000000..14dabcc
--- /dev/null
+++ b/xos/onboard/vrouter/tosca/resources/vrouterservice.py
@@ -0,0 +1,16 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from services.vrouter.models import VRouterService
+
+from service import XOSService
+
+class XOSVRouterService(XOSService):
+    provides = "tosca.nodes.VRouterService"
+    xos_model = VRouterService
+    copyin_props = ["view_url", "icon_url", "enabled", "published", "public_key", "versionNumber"]
+
diff --git a/xos/onboard/vrouter/vrouter-onboard.yaml b/xos/onboard/vrouter/vrouter-onboard.yaml
new file mode 100644
index 0000000..e956c96
--- /dev/null
+++ b/xos/onboard/vrouter/vrouter-onboard.yaml
@@ -0,0 +1,20 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Onboard the vRouter SErvice
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    servicecontroller#vrouter:
+      type: tosca.nodes.ServiceController
+      properties:
+          base_url: file:///opt/xos/onboard/vrouter/
+          # The following will concatenate with base_url automatically, if
+          # base_url is non-null.
+          models: models.py
+          admin: admin.py
+          admin_template: templates/vrouteradmin.html
+          tosca_resource: tosca/resources/vrouterservice.py
+
diff --git a/xos/onboard/vsg/admin.py b/xos/onboard/vsg/admin.py
new file mode 100644
index 0000000..92fa51d
--- /dev/null
+++ b/xos/onboard/vsg/admin.py
@@ -0,0 +1,150 @@
+from django.contrib import admin
+
+from services.vsg.models import *
+from django import forms
+from django.utils.safestring import mark_safe
+from django.contrib.auth.admin import UserAdmin
+from django.contrib.admin.widgets import FilteredSelectMultiple
+from django.contrib.auth.forms import ReadOnlyPasswordHashField
+from django.contrib.auth.signals import user_logged_in
+from django.utils import timezone
+from django.contrib.contenttypes import generic
+from suit.widgets import LinkedSelect
+from core.admin import ServiceAppAdmin,SliceInline,ServiceAttrAsTabInline, ReadOnlyAwareAdmin, XOSTabularInline, ServicePrivilegeInline, TenantRootTenantInline, TenantRootPrivilegeInline
+from core.middleware import get_request
+
+from functools import update_wrapper
+from django.contrib.admin.views.main import ChangeList
+from django.core.urlresolvers import reverse
+from django.contrib.admin.utils import quote
+
+#-----------------------------------------------------------------------------
+# vSG
+#-----------------------------------------------------------------------------
+
+class VSGServiceForm(forms.ModelForm):
+    bbs_api_hostname = forms.CharField(required=False)
+    bbs_api_port = forms.IntegerField(required=False)
+    bbs_server = forms.CharField(required=False)
+    backend_network_label = forms.CharField(required=False)
+    bbs_slice = forms.ModelChoiceField(queryset=Slice.objects.all(), required=False)
+    dns_servers = forms.CharField(required=False)
+    url_filter_kind = forms.ChoiceField(choices=VSGService.URL_FILTER_KIND_CHOICES, required=False)
+    node_label = forms.CharField(required=False)
+
+    def __init__(self,*args,**kwargs):
+        super (VSGServiceForm,self ).__init__(*args,**kwargs)
+        if self.instance:
+            self.fields['bbs_api_hostname'].initial = self.instance.bbs_api_hostname
+            self.fields['bbs_api_port'].initial = self.instance.bbs_api_port
+            self.fields['bbs_server'].initial = self.instance.bbs_server
+            self.fields['backend_network_label'].initial = self.instance.backend_network_label
+            self.fields['bbs_slice'].initial = self.instance.bbs_slice
+            self.fields['dns_servers'].initial = self.instance.dns_servers
+            self.fields['url_filter_kind']. initial = self.instance.url_filter_kind
+            self.fields['node_label'].initial = self.instance.node_label
+
+    def save(self, commit=True):
+        self.instance.bbs_api_hostname = self.cleaned_data.get("bbs_api_hostname")
+        self.instance.bbs_api_port = self.cleaned_data.get("bbs_api_port")
+        self.instance.bbs_server = self.cleaned_data.get("bbs_server")
+        self.instance.backend_network_label = self.cleaned_data.get("backend_network_label")
+        self.instance.bbs_slice = self.cleaned_data.get("bbs_slice")
+        self.instance.dns_servers = self.cleaned_data.get("dns_servers")
+        self.instance.url_filter_kind = self.cleaned_data.get("url_filter_kind")
+        self.instance.node_label = self.cleaned_data.get("node_label")
+        return super(VSGServiceForm, self).save(commit=commit)
+
+    class Meta:
+        model = VSGService
+
+class VSGServiceAdmin(ReadOnlyAwareAdmin):
+    model = VSGService
+    verbose_name = "vSG Service"
+    verbose_name_plural = "vSG Service"
+    list_display = ("backend_status_icon", "name", "enabled")
+    list_display_links = ('backend_status_icon', 'name', )
+    fieldsets = [(None,             {'fields': ['backend_status_text', 'name','enabled','versionNumber', 'description', "view_url", "icon_url", "service_specific_attribute", "node_label"],
+                                     'classes':['suit-tab suit-tab-general']}),
+                 ("backend config", {'fields': [ "backend_network_label", "url_filter_kind", "bbs_api_hostname", "bbs_api_port", "bbs_server", "bbs_slice"],
+                                     'classes':['suit-tab suit-tab-backend']}),
+                 ("vSG config", {'fields': ["dns_servers"],
+                                     'classes':['suit-tab suit-tab-vsg']}) ]
+    readonly_fields = ('backend_status_text', "service_specific_attribute")
+    inlines = [SliceInline,ServiceAttrAsTabInline,ServicePrivilegeInline]
+    form = VSGServiceForm
+
+    extracontext_registered_admins = True
+
+    user_readonly_fields = ["name", "enabled", "versionNumber", "description"]
+
+    suit_form_tabs =(('general', 'Service Details'),
+        ('backend', 'Backend Config'),
+        ('vsg', 'vSG Config'),
+        ('administration', 'Administration'),
+        #('tools', 'Tools'),
+        ('slices','Slices'),
+        ('serviceattrs','Additional Attributes'),
+        ('serviceprivileges','Privileges') ,
+    )
+
+    suit_form_includes = (('vcpeadmin.html', 'top', 'administration'),
+                           ) #('hpctools.html', 'top', 'tools') )
+
+    def queryset(self, request):
+        return VSGService.get_service_objects_by_user(request.user)
+
+class VSGTenantForm(forms.ModelForm):
+    bbs_account = forms.CharField(required=False)
+    creator = forms.ModelChoiceField(queryset=User.objects.all())
+    instance = forms.ModelChoiceField(queryset=Instance.objects.all(),required=False)
+    last_ansible_hash = forms.CharField(required=False)
+    wan_container_ip = forms.CharField(required=False)
+    wan_container_mac = forms.CharField(required=False)
+
+    def __init__(self,*args,**kwargs):
+        super (VSGTenantForm,self ).__init__(*args,**kwargs)
+        self.fields['kind'].widget.attrs['readonly'] = True
+        self.fields['provider_service'].queryset = VSGService.get_service_objects().all()
+        if self.instance:
+            # fields for the attributes
+            self.fields['bbs_account'].initial = self.instance.bbs_account
+            self.fields['creator'].initial = self.instance.creator
+            self.fields['instance'].initial = self.instance.instance
+            self.fields['last_ansible_hash'].initial = self.instance.last_ansible_hash
+            self.fields['wan_container_ip'].initial = self.instance.wan_container_ip
+            self.fields['wan_container_mac'].initial = self.instance.wan_container_mac
+        if (not self.instance) or (not self.instance.pk):
+            # default fields for an 'add' form
+            self.fields['kind'].initial = VCPE_KIND
+            self.fields['creator'].initial = get_request().user
+            if VSGService.get_service_objects().exists():
+               self.fields["provider_service"].initial = VSGService.get_service_objects().all()[0]
+
+    def save(self, commit=True):
+        self.instance.creator = self.cleaned_data.get("creator")
+        self.instance.instance = self.cleaned_data.get("instance")
+        self.instance.last_ansible_hash = self.cleaned_data.get("last_ansible_hash")
+        return super(VSGTenantForm, self).save(commit=commit)
+
+    class Meta:
+        model = VSGTenant
+
+class VSGTenantAdmin(ReadOnlyAwareAdmin):
+    list_display = ('backend_status_icon', 'id', 'subscriber_tenant' )
+    list_display_links = ('backend_status_icon', 'id')
+    fieldsets = [ (None, {'fields': ['backend_status_text', 'kind', 'provider_service', 'subscriber_tenant', 'service_specific_id', # 'service_specific_attribute',
+                                     'wan_container_ip', 'wan_container_mac', 'bbs_account', 'creator', 'instance', 'last_ansible_hash'],
+                          'classes':['suit-tab suit-tab-general']})]
+    readonly_fields = ('backend_status_text', 'service_specific_attribute', 'bbs_account', 'wan_container_ip', 'wan_container_mac')
+    form = VSGTenantForm
+
+    suit_form_tabs = (('general','Details'),)
+
+    def queryset(self, request):
+        return VSGTenant.get_tenant_objects_by_user(request.user)
+
+
+admin.site.register(VSGService, VSGServiceAdmin)
+admin.site.register(VSGTenant, VSGTenantAdmin)
+
diff --git a/xos/onboard/vsg/api/service/vsg/vsgservice.py b/xos/onboard/vsg/api/service/vsg/vsgservice.py
new file mode 100644
index 0000000..a04fb3e
--- /dev/null
+++ b/xos/onboard/vsg/api/service/vsg/vsgservice.py
@@ -0,0 +1,78 @@
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+from rest_framework import serializers
+from rest_framework import generics
+from rest_framework import viewsets
+from rest_framework import status
+from rest_framework.decorators import detail_route, list_route
+from rest_framework.views import APIView
+from core.models import *
+from django.forms import widgets
+from django.conf.urls import patterns, url
+from services.vsg.models import VSGService
+from api.xosapi_helpers import PlusModelSerializer, XOSViewSet, ReadOnlyField
+from django.shortcuts import get_object_or_404
+from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
+from xos.exceptions import *
+import json
+import subprocess
+from django.views.decorators.csrf import ensure_csrf_cookie
+
+class VSGServiceForApi(VSGService):
+    class Meta:
+        proxy = True
+        app_label = "cord"
+
+    def __init__(self, *args, **kwargs):
+        super(VSGServiceForApi, self).__init__(*args, **kwargs)
+
+    def save(self, *args, **kwargs):
+        super(VSGServiceForApi, self).save(*args, **kwargs)
+
+    def __init__(self, *args, **kwargs):
+        super(VSGService, self).__init__(*args, **kwargs)
+
+class VSGServiceSerializer(PlusModelSerializer):
+        id = ReadOnlyField()
+        humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+        wan_container_gateway_ip = serializers.CharField(required=False)
+        wan_container_gateway_mac = serializers.CharField(required=False)
+        dns_servers = serializers.CharField(required=False)
+        url_filter_kind = serializers.CharField(required=False)
+        node_label = serializers.CharField(required=False)
+
+        class Meta:
+            model = VSGServiceForApi
+            fields = ('humanReadableName',
+                      'id',
+                      'wan_container_gateway_ip',
+                      'wan_container_gateway_mac',
+                      'dns_servers',
+                      'url_filter_kind',
+                      'node_label')
+
+        def getHumanReadableName(self, obj):
+            return obj.__unicode__()
+
+# @ensure_csrf_cookie
+class VSGServiceViewSet(XOSViewSet):
+    base_name = "vsgservice"
+    method_name = None # use the api endpoint /api/service/vsg/
+    method_kind = "viewset"
+    queryset = VSGService.get_service_objects().select_related().all()
+    serializer_class = VSGServiceSerializer
+
+    @classmethod
+    def get_urlpatterns(self, api_path="^"):
+        patterns = super(VSGServiceViewSet, self).get_urlpatterns(api_path=api_path)
+
+        return patterns
+
+    def list(self, request):
+        object_list = self.filter_queryset(self.get_queryset())
+
+        serializer = self.get_serializer(object_list, many=True)
+
+        return Response(serializer.data)
+
diff --git a/xos/onboard/vsg/api/tenant/cord/vsg.py b/xos/onboard/vsg/api/tenant/cord/vsg.py
new file mode 100644
index 0000000..c6a4247
--- /dev/null
+++ b/xos/onboard/vsg/api/tenant/cord/vsg.py
@@ -0,0 +1,62 @@
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+from rest_framework import serializers
+from rest_framework import generics
+from rest_framework import status
+from core.models import *
+from django.forms import widgets
+from services.vsg.models import VSGTenant, VSGService
+from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
+from api.xosapi_helpers import PlusModelSerializer, XOSViewSet, ReadOnlyField
+
+def get_default_vsg_service():
+    vsg_services = VSGService.get_service_objects().all()
+    if vsg_services:
+        return vsg_services[0].id
+    return None
+
+class VSGTenantForAPI(VSGTenant):
+    class Meta:
+        proxy = True
+        app_label = "cord"
+
+    @property
+    def related(self):
+        related = {}
+        if self.instance:
+            related["instance_id"] = self.instance.id
+        return related
+
+class VSGTenantSerializer(PlusModelSerializer):
+    id = ReadOnlyField()
+    wan_container_ip = serializers.CharField()
+    wan_container_mac = ReadOnlyField()
+    related = serializers.DictField(required=False)
+
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    class Meta:
+        model = VSGTenantForAPI
+        fields = ('humanReadableName', 'id', 'wan_container_ip', 'wan_container_mac', 'related' )
+
+    def getHumanReadableName(self, obj):
+        return obj.__unicode__()
+
+class VSGTenantViewSet(XOSViewSet):
+    base_name = "vsg"
+    method_name = "vsg"
+    method_kind = "viewset"
+    queryset = VSGTenantForAPI.get_tenant_objects().all()
+    serializer_class = VSGTenantSerializer
+
+    @classmethod
+    def get_urlpatterns(self, api_path="^"):
+        patterns = super(VSGTenantViewSet, self).get_urlpatterns(api_path=api_path)
+
+        return patterns
+
+
+
+
+
+
diff --git a/xos/onboard/vsg/models.py b/xos/onboard/vsg/models.py
new file mode 100644
index 0000000..ad25c98
--- /dev/null
+++ b/xos/onboard/vsg/models.py
@@ -0,0 +1,448 @@
+from django.db import models
+from core.models import Service, PlCoreBase, Slice, Instance, Tenant, TenantWithContainer, Node, Image, User, Flavor, Subscriber, NetworkParameter, NetworkParameterType, Port, AddressPool, User
+from core.models.plcorebase import StrippedCharField
+import os
+from django.db import models, transaction
+from django.forms.models import model_to_dict
+from django.db.models import Q
+from operator import itemgetter, attrgetter, methodcaller
+from core.models import Tag
+from core.models.service import LeastLoadedNodeScheduler
+from services.vrouter.models import VRouterService, VRouterTenant
+import traceback
+from xos.exceptions import *
+from xos.config import Config
+
+class ConfigurationError(Exception):
+    pass
+
+VCPE_KIND = "vCPE"
+CORD_SUBSCRIBER_KIND = "CordSubscriberRoot"
+
+CORD_USE_VTN = getattr(Config(), "networking_use_vtn", False)
+
+# -------------------------------------------
+# VCPE
+# -------------------------------------------
+
+class VSGService(Service):
+    KIND = VCPE_KIND
+
+    URL_FILTER_KIND_CHOICES = ( (None, "None"), ("safebrowsing", "Safe Browsing"), ("answerx", "AnswerX") )
+
+    simple_attributes = ( ("bbs_api_hostname", None),
+                          ("bbs_api_port", None),
+                          ("bbs_server", None),
+                          ("backend_network_label", "hpc_client"),
+                          ("dns_servers", "8.8.8.8"),
+                          ("url_filter_kind", None),
+                          ("node_label", None) )
+
+    def __init__(self, *args, **kwargs):
+        super(VSGService, self).__init__(*args, **kwargs)
+
+    class Meta:
+        app_label = "vsg"
+        verbose_name = "vSG Service"
+        proxy = True
+
+    def allocate_bbs_account(self):
+        vcpes = VSGTenant.get_tenant_objects().all()
+        bbs_accounts = [vcpe.bbs_account for vcpe in vcpes]
+
+        # There's a bit of a race here; some other user could be trying to
+        # allocate a bbs_account at the same time we are.
+
+        for i in range(2,21):
+             account_name = "bbs%02d@onlab.us" % i
+             if (account_name not in bbs_accounts):
+                 return account_name
+
+        raise XOSConfigurationError("We've run out of available broadbandshield accounts. Delete some vcpe and try again.")
+
+    @property
+    def bbs_slice(self):
+        bbs_slice_id=self.get_attribute("bbs_slice_id")
+        if not bbs_slice_id:
+            return None
+        bbs_slices=Slice.objects.filter(id=bbs_slice_id)
+        if not bbs_slices:
+            return None
+        return bbs_slices[0]
+
+    @bbs_slice.setter
+    def bbs_slice(self, value):
+        if value:
+            value = value.id
+        self.set_attribute("bbs_slice_id", value)
+
+VSGService.setup_simple_attributes()
+
+class VSGTenant(TenantWithContainer):
+    class Meta:
+        proxy = True
+
+    KIND = VCPE_KIND
+
+    sync_attributes = ("wan_container_ip", "wan_container_mac", "wan_container_netbits",
+                       "wan_container_gateway_ip", "wan_container_gateway_mac",
+                       "wan_vm_ip", "wan_vm_mac")
+
+    default_attributes = {"instance_id": None,
+                          "container_id": None,
+                          "users": [],
+                          "bbs_account": None,
+                          "last_ansible_hash": None,
+                          "wan_container_ip": None}
+
+    def __init__(self, *args, **kwargs):
+        super(VSGTenant, self).__init__(*args, **kwargs)
+        self.cached_vrouter=None
+
+    @property
+    def vbng(self):
+        # not supported
+        return None
+
+    @vbng.setter
+    def vbng(self, value):
+        raise XOSConfigurationError("vCPE.vBNG cannot be set this way -- create a new vBNG object and set it's subscriber_tenant instead")
+
+    @property
+    def vrouter(self):
+        vrouter = self.get_newest_subscribed_tenant(VRouterTenant)
+        if not vrouter:
+            return None
+
+        # always return the same object when possible
+        if (self.cached_vrouter) and (self.cached_vrouter.id == vrouter.id):
+            return self.cached_vrouter
+
+        vrouter.caller = self.creator
+        self.cached_vrouter = vrouter
+        return vrouter
+
+    @vrouter.setter
+    def vrouter(self, value):
+        raise XOSConfigurationError("vCPE.vRouter cannot be set this way -- create a new vRuter object and set its subscriber_tenant instead")
+
+    @property
+    def volt(self):
+        from services.volt.models import VOLTTenant
+        if not self.subscriber_tenant:
+            return None
+        volts = VOLTTenant.objects.filter(id=self.subscriber_tenant.id)
+        if not volts:
+            return None
+        return volts[0]
+
+    @property
+    def bbs_account(self):
+        return self.get_attribute("bbs_account", self.default_attributes["bbs_account"])
+
+    @bbs_account.setter
+    def bbs_account(self, value):
+        return self.set_attribute("bbs_account", value)
+
+    @property
+    def last_ansible_hash(self):
+        return self.get_attribute("last_ansible_hash", self.default_attributes["last_ansible_hash"])
+
+    @last_ansible_hash.setter
+    def last_ansible_hash(self, value):
+        return self.set_attribute("last_ansible_hash", value)
+
+    @property
+    def ssh_command(self):
+        if self.instance:
+            return self.instance.get_ssh_command()
+        else:
+            return "no-instance"
+
+    @ssh_command.setter
+    def ssh_command(self, value):
+        pass
+
+    def get_vrouter_field(self, name, default=None):
+        if self.vrouter:
+            return getattr(self.vrouter, name, default)
+        else:
+            return default
+
+    @property
+    def wan_container_ip(self):
+        return self.get_vrouter_field("public_ip", None)
+
+    @property
+    def wan_container_mac(self):
+        return self.get_vrouter_field("public_mac", None)
+
+    @property
+    def wan_container_netbits(self):
+        return self.get_vrouter_field("netbits", None)
+
+    @property
+    def wan_container_gateway_ip(self):
+        return self.get_vrouter_field("gateway_ip", None)
+
+    @property
+    def wan_container_gateway_mac(self):
+        return self.get_vrouter_field("gateway_mac", None)
+
+    @property
+    def wan_vm_ip(self):
+        tags = Tag.select_by_content_object(self.instance).filter(name="vm_vrouter_tenant")
+        if tags:
+            tenant = VRouterTenant.objects.get(id=tags[0].value)
+            return tenant.public_ip
+        else:
+            raise Exception("no vm_vrouter_tenant tag for instance %s" % o.instance)
+
+    @property
+    def wan_vm_mac(self):
+        tags = Tag.select_by_content_object(self.instance).filter(name="vm_vrouter_tenant")
+        if tags:
+            tenant = VRouterTenant.objects.get(id=tags[0].value)
+            return tenant.public_mac
+        else:
+            raise Exception("no vm_vrouter_tenant tag for instance %s" % o.instance)
+
+    @property
+    def is_synced(self):
+        return (self.enacted is not None) and (self.enacted >= self.updated)
+
+    @is_synced.setter
+    def is_synced(self, value):
+        pass
+
+    def get_vrouter_service(self):
+        vrouterServices = VRouterService.get_service_objects().all()
+        if not vrouterServices:
+            raise XOSConfigurationError("No VROUTER Services available")
+        return vrouterServices[0]
+
+    def manage_vrouter(self):
+        # Each vCPE object owns exactly one vRouterTenant object
+
+        if self.deleted:
+            return
+
+        if self.vrouter is None:
+            vrouter = self.get_vrouter_service().get_tenant(address_pool_name="addresses_vsg", subscriber_tenant = self)
+            vrouter.caller = self.creator
+            vrouter.save()
+
+    def cleanup_vrouter(self):
+        if self.vrouter:
+            # print "XXX cleanup vrouter", self.vrouter
+            self.vrouter.delete()
+
+    def cleanup_orphans(self):
+        # ensure vCPE only has one vRouter
+        cur_vrouter = self.vrouter
+        for vrouter in list(self.get_subscribed_tenants(VRouterTenant)):
+            if (not cur_vrouter) or (vrouter.id != cur_vrouter.id):
+                # print "XXX clean up orphaned vrouter", vrouter
+                vrouter.delete()
+
+        if self.orig_instance_id and (self.orig_instance_id != self.get_attribute("instance_id")):
+            instances=Instance.objects.filter(id=self.orig_instance_id)
+            if instances:
+                # print "XXX clean up orphaned instance", instances[0]
+                instances[0].delete()
+
+    def get_slice(self):
+        if not self.provider_service.slices.count():
+            print self, "dio porco"
+            raise XOSConfigurationError("The service has no slices")
+        slice = self.provider_service.slices.all()[0]
+        return slice
+
+    def get_vsg_service(self):
+        return VSGService.get_service_objects().get(id=self.provider_service.id)
+
+    def find_instance_for_s_tag(self, s_tag):
+        #s_tags = STagBlock.objects.find(s_s_tag)
+        #if s_tags:
+        #    return s_tags[0].instance
+
+        tags = Tag.objects.filter(name="s_tag", value=s_tag)
+        if tags:
+            return tags[0].content_object
+
+        return None
+
+    def find_or_make_instance_for_s_tag(self, s_tag):
+        instance = self.find_instance_for_s_tag(self.volt.s_tag)
+        if instance:
+            return instance
+
+        flavors = Flavor.objects.filter(name="m1.small")
+        if not flavors:
+            raise XOSConfigurationError("No m1.small flavor")
+
+        slice = self.provider_service.slices.all()[0]
+
+        if slice.default_isolation == "container_vm":
+            (node, parent) = ContainerVmScheduler(slice).pick()
+        else:
+            (node, parent) = LeastLoadedNodeScheduler(slice, label=self.get_vsg_service().node_label).pick()
+
+        instance = Instance(slice = slice,
+                        node = node,
+                        image = self.image,
+                        creator = self.creator,
+                        deployment = node.site_deployment.deployment,
+                        flavor = flavors[0],
+                        isolation = slice.default_isolation,
+                        parent = parent)
+
+        self.save_instance(instance)
+
+        return instance
+
+    def manage_container(self):
+        from core.models import Instance, Flavor
+
+        if self.deleted:
+            return
+
+        # For container or container_vm isolation, use what TenantWithCotnainer
+        # provides us
+        slice = self.get_slice()
+        if slice.default_isolation in ["container_vm", "container"]:
+            super(VSGTenant,self).manage_container()
+            return
+
+        if not self.volt:
+            raise XOSConfigurationError("This vCPE container has no volt")
+
+        if self.instance:
+            # We're good.
+            return
+
+        instance = self.find_or_make_instance_for_s_tag(self.volt.s_tag)
+        self.instance = instance
+        super(TenantWithContainer, self).save()
+
+    def cleanup_container(self):
+        if self.get_slice().default_isolation in ["container_vm", "container"]:
+            super(VSGTenant,self).cleanup_container()
+
+        # To-do: cleanup unused instances
+        pass
+
+    def manage_bbs_account(self):
+        if self.deleted:
+            return
+
+        if self.volt and self.volt.subscriber and self.volt.subscriber.url_filter_enable:
+            if not self.bbs_account:
+                # make sure we use the proxied VSGService object, not the generic Service object
+                vcpe_service = VSGService.objects.get(id=self.provider_service.id)
+                self.bbs_account = vcpe_service.allocate_bbs_account()
+                super(VSGTenant, self).save()
+        else:
+            if self.bbs_account:
+                self.bbs_account = None
+                super(VSGTenant, self).save()
+
+    def find_or_make_port(self, instance, network, **kwargs):
+        port = Port.objects.filter(instance=instance, network=network)
+        if port:
+            port = port[0]
+        else:
+            port = Port(instance=instance, network=network, **kwargs)
+            port.save()
+        return port
+
+    def get_lan_network(self, instance):
+        slice = self.provider_service.slices.all()[0]
+        if CORD_USE_VTN:
+            # there should only be one network private network, and its template should not be the management template
+            lan_networks = [x for x in slice.networks.all() if x.template.visibility=="private" and (not "management" in x.template.name)]
+            if len(lan_networks)>1:
+                raise XOSProgrammingError("The vSG slice should only have one non-management private network")
+        else:
+            lan_networks = [x for x in slice.networks.all() if "lan" in x.name]
+        if not lan_networks:
+            raise XOSProgrammingError("No lan_network")
+        return lan_networks[0]
+
+    def save_instance(self, instance):
+        with transaction.atomic():
+            instance.volumes = "/etc/dnsmasq.d,/etc/ufw"
+            super(VSGTenant, self).save_instance(instance)
+
+            if instance.isolation in ["container", "container_vm"]:
+                lan_network = self.get_lan_network(instance)
+                port = self.find_or_make_port(instance, lan_network, ip="192.168.0.1", port_id="unmanaged")
+                port.set_parameter("c_tag", self.volt.c_tag)
+                port.set_parameter("s_tag", self.volt.s_tag)
+                port.set_parameter("device", "eth1")
+                port.set_parameter("bridge", "br-lan")
+
+                wan_networks = [x for x in instance.slice.networks.all() if "wan" in x.name]
+                if not wan_networks:
+                    raise XOSProgrammingError("No wan_network")
+                port = self.find_or_make_port(instance, wan_networks[0])
+                port.set_parameter("next_hop", value="10.0.1.253")   # FIX ME
+                port.set_parameter("device", "eth0")
+
+            if instance.isolation in ["vm"]:
+                lan_network = self.get_lan_network(instance)
+                port = self.find_or_make_port(instance, lan_network)
+                port.set_parameter("c_tag", self.volt.c_tag)
+                port.set_parameter("s_tag", self.volt.s_tag)
+                port.set_parameter("neutron_port_name", "stag-%s" % self.volt.s_tag)
+                port.save()
+
+            # tag the instance with the s-tag, so we can easily find the
+            # instance later
+            if self.volt and self.volt.s_tag:
+                tags = Tag.objects.filter(name="s_tag", value=self.volt.s_tag)
+                if not tags:
+                    tag = Tag(service=self.provider_service, content_object=instance, name="s_tag", value=self.volt.s_tag)
+                    tag.save()
+
+            # VTN-CORD needs a WAN address for the VM, so that the VM can
+            # be configured.
+            if CORD_USE_VTN:
+                tags = Tag.select_by_content_object(instance).filter(name="vm_vrouter_tenant")
+                if not tags:
+                    vrouter = self.get_vrouter_service().get_tenant(address_pool_name="addresses_vsg", subscriber_service = self.provider_service)
+                    vrouter.set_attribute("tenant_for_instance_id", instance.id)
+                    vrouter.save()
+                    tag = Tag(service=self.provider_service, content_object=instance, name="vm_vrouter_tenant", value="%d" % vrouter.id)
+                    tag.save()
+
+    def save(self, *args, **kwargs):
+        if not self.creator:
+            if not getattr(self, "caller", None):
+                # caller must be set when creating a vCPE since it creates a slice
+                raise XOSProgrammingError("VSGTenant's self.caller was not set")
+            self.creator = self.caller
+            if not self.creator:
+                raise XOSProgrammingError("VSGTenant's self.creator was not set")
+
+        super(VSGTenant, self).save(*args, **kwargs)
+        model_policy_vcpe(self.pk)
+
+    def delete(self, *args, **kwargs):
+        self.cleanup_vrouter()
+        self.cleanup_container()
+        super(VSGTenant, self).delete(*args, **kwargs)
+
+def model_policy_vcpe(pk):
+    # TODO: this should be made in to a real model_policy
+    with transaction.atomic():
+        vcpe = VSGTenant.objects.select_for_update().filter(pk=pk)
+        if not vcpe:
+            return
+        vcpe = vcpe[0]
+        vcpe.manage_container()
+        vcpe.manage_vrouter()
+        vcpe.manage_bbs_account()
+        vcpe.cleanup_orphans()
+
+
diff --git a/xos/onboard/vsg/synchronizer/broadbandshield.py b/xos/onboard/vsg/synchronizer/broadbandshield.py
new file mode 100644
index 0000000..dd2f00b
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/broadbandshield.py
@@ -0,0 +1,396 @@
+import requests
+import logging
+import json
+import sys
+from rest_framework.exceptions import APIException
+
+""" format of settings
+
+    ["settings"]
+        ["watershed"]
+        ["rating"]
+        ["categories"]
+        ["blocklist"]
+        ["allowlist"]
+
+    ["users"]
+        array
+            ["account_id"] - 58
+            ["reporting"] - False
+            ["name"] - Scott1
+            ["devices"]
+            ["settings"] -
+                ["watershed"]
+                ["rating"]
+                ["categories"]
+                ["blocklist"]
+                ["allowlist"]
+
+    ["devices"]
+        array
+            ["username"] - "Scott1" or "" if whole-house
+            ["uuid"] - empty
+            ["mac_address"] - mac address as hex digits in ascii
+            ["type"] - "laptop"
+            ["name"] - human readable name of device ("Scott's laptop")
+            ["settings"]
+                 ["watershed"]
+                     array
+                         array
+                             ["rating"]
+                             ["category"]
+                 ["rating"] - ["G" | "NONE"]
+                 ["categories"] - list of categories set by rating
+                 ["blocklist"] - []
+                 ["allowlist"] - []
+"""
+
+class BBS_Failure(APIException):
+    status_code=400
+    def __init__(self, why="broadbandshield error", fields={}):
+        APIException.__init__(self, {"error": "BBS_Failure",
+                            "specific_error": why,
+                            "fields": fields})
+
+
+class BBS:
+    level_map = {"PG_13": "PG13",
+                 "NONE": "OFF",
+                 "ALL": "NONE",
+                 None: "NONE"}
+
+    def __init__(self, username, password, bbs_hostname=None, bbs_port=None):
+        self.username = username
+        self.password = password
+
+        # XXX not tested on port 80
+        #self.bbs_hostname = "www.broadbandshield.com"
+        #self.bbs_port = 80
+
+        if not bbs_hostname:
+            bbs_hostname = "cordcompute01.onlab.us"
+        if not bbs_port:
+            bbs_port = 8018
+
+        self.bbs_hostname = bbs_hostname
+        self.bbs_port = int(bbs_port)
+
+        self.api = "http://%s:%d/api" % (self.bbs_hostname, self.bbs_port)
+        self.nic_update = "http://%s:%d/nic/update" % (self.bbs_hostname, self.bbs_port)
+
+        self.session = None
+        self.settings = None
+
+    def login(self):
+        self.session = requests.Session()
+        r = self.session.post(self.api + "/login", data = json.dumps({"email": self.username, "password": self.password}))
+        if (r.status_code != 200):
+            raise BBS_Failure("Failed to login (%d)" % r.status_code)
+
+    def get_account(self):
+        if not self.session:
+            self.login()
+
+        r = self.session.get(self.api + "/account")
+        if (r.status_code != 200):
+            raise BBS_Failure("Failed to get account settings (%d)" % r.status_code)
+        self.settings = r.json()
+
+        return self.settings
+
+    def post_account(self):
+        if not self.settings:
+             raise XOSProgrammingError("no settings to post")
+
+        r = self.session.post(self.api + "/account/settings", data= json.dumps(self.settings))
+        if (r.status_code != 200):
+            raise BBS_Failure("Failed to set account settings (%d)" % r.status_code)
+
+    def add_device(self, name, mac, type="tablet", username=""):
+        data = {"name": name, "mac_address": mac, "type": type, "username": username}
+        r = self.session.post(self.api + "/device", data = json.dumps(data))
+        if (r.status_code != 200):
+            raise BBS_Failure("Failed to add device (%d)" % r.status_code)
+
+    def delete_device(self, data):
+        r = self.session.delete(self.api + "/device", data = json.dumps(data))
+        if (r.status_code != 200):
+            raise BBS_Failure("Failed to delete device (%d)" % r.status_code)
+
+    def add_user(self, name, rating="NONE", categories=[]):
+        data = {"name": name, "settings": {"rating": rating, "categories": categories}}
+        r = self.session.post(self.api + "/users", data = json.dumps(data))
+        if (r.status_code != 200):
+            raise BBS_Failure("Failed to add user (%d)" % r.status_code)
+
+    def delete_user(self, data):
+        r = self.session.delete(self.api + "/users", data = json.dumps(data))
+        if (r.status_code != 200):
+            raise BBS_Failure("Failed to delete user (%d)" % r.status_code)
+
+    def clear_users_and_devices(self):
+        if not self.settings:
+            self.get_account()
+
+        for device in self.settings["devices"]:
+            self.delete_device(device)
+
+        for user in self.settings["users"]:
+            self.delete_user(user)
+
+    def get_whole_home_level(self):
+        if not self.settings:
+            self.get_account()
+
+        return self.settings["settings"]["rating"]
+
+    def sync(self, whole_home_level, users):
+        if not self.settings:
+            self.get_account()
+
+        vcpe_users = {}
+        for user in users:
+            user = user.copy()
+            user["level"] = self.level_map.get(user["level"], user["level"])
+            user["mac"] = user.get("mac", "")
+            vcpe_users[user["name"]] = user
+
+        whole_home_level = self.level_map.get(whole_home_level, whole_home_level)
+
+        if (whole_home_level != self.settings["settings"]["rating"]):
+            print "*** set whole_home", whole_home_level, "***"
+            self.settings["settings"]["rating"] = whole_home_level
+            self.post_account()
+
+        bbs_usernames = [bbs_user["name"] for bbs_user in self.settings["users"]]
+        bbs_devicenames = [bbs_device["name"] for bbs_device in self.settings["devices"]]
+
+        add_users = []
+        add_devices = []
+        delete_users = []
+        delete_devices = []
+
+        for bbs_user in self.settings["users"]:
+             bbs_username = bbs_user["name"]
+             if bbs_username in vcpe_users.keys():
+                 vcpe_user = vcpe_users[bbs_username]
+                 if bbs_user["settings"]["rating"] != vcpe_user["level"]:
+                     print "set user", vcpe_user["name"], "rating", vcpe_user["level"]
+                     #bbs_user["settings"]["rating"] = vcpe_user["level"]
+                     # add can be used as an update
+                     add_users.append(vcpe_user)
+             else:
+                 delete_users.append(bbs_user)
+
+        for bbs_device in self.settings["devices"]:
+             bbs_devicename = bbs_device["name"]
+             if bbs_devicename in vcpe_users.keys():
+                 vcpe_user = vcpe_users[bbs_devicename]
+                 if bbs_device["mac_address"] != vcpe_user["mac"]:
+                     print "set device", vcpe_user["name"], "mac", vcpe_user["mac"]
+                     #bbs_device["mac_address"] = vcpe_user["mac"]
+                     # add of a device can't be used as an update, as you'll end
+                     # up with two of them.
+                     delete_devices.append(bbs_device)
+                     add_devices.append(vcpe_user)
+             else:
+                 delete_devices.append(bbs_device)
+
+        for (username, user) in vcpe_users.iteritems():
+            if not username in bbs_usernames:
+                add_users.append(user)
+            if not username in bbs_devicenames:
+                add_devices.append(user)
+
+        for bbs_user in delete_users:
+            print "delete user", bbs_user["name"]
+            self.delete_user(bbs_user)
+
+        for bbs_device in delete_devices:
+            print "delete device", bbs_device["name"]
+            self.delete_device(bbs_device)
+
+        for vcpe_user in add_users:
+            print "add user", vcpe_user["name"], "level", vcpe_user["level"]
+            self.add_user(vcpe_user["name"], vcpe_user["level"])
+
+        for vcpe_user in add_devices:
+            print "add device", vcpe_user["name"], "mac", vcpe_user["mac"]
+            self.add_device(vcpe_user["name"], vcpe_user["mac"], "tablet", vcpe_user["name"])
+
+    def get_whole_home_rating(self):
+        return self.settings["settings"]["rating"]
+
+    def get_user(self, name):
+        for user in self.settings["users"]:
+            if user["name"]==name:
+                return user
+        return None
+
+    def get_device(self, name):
+        for device in self.settings["devices"]:
+             if device["name"]==name:
+                 return device
+        return None
+
+    def dump(self):
+        if not self.settings:
+            self.get_account()
+
+        print "whole_home_rating:", self.settings["settings"]["rating"]
+        print "users:"
+        for user in self.settings["users"]:
+            print "  user", user["name"], "rating", user["settings"]["rating"]
+
+        print "devices:"
+        for device in self.settings["devices"]:
+            print "  device", device["name"], "user", device["username"], "rating", device["settings"]["rating"], "mac", device["mac_address"]
+
+    def associate(self, ip):
+        bbs_hostname = "cordcompute01.onlab.us"
+        r = requests.get(self.nic_update, params={"hostname": "onlab.us"}, headers={"X-Forwarded-For": ip}, auth=requests.auth.HTTPBasicAuth(self.username,self.password))
+        if (r.status_code != 200):
+            raise BBS_Failure("Failed to associate account with ip (%d)" % r.status_code)
+
+def dump():
+    bbs = BBS(sys.argv[2], sys.argv[3])
+    bbs.dump()
+
+def associate():
+    if len(sys.argv)<5:
+        print "you need to specify IP address"
+        sys.exit(-1)
+
+    bbs = BBS(sys.argv[2], sys.argv[3])
+    bbs.associate(sys.argv[4])
+
+def self_test():
+    bbs = BBS(sys.argv[2], sys.argv[3])
+
+    print "*** initial ***"
+    bbs.dump()
+
+    open("bbs.json","w").write(json.dumps(bbs.settings))
+
+    # a new BBS account will throw a 500 error if it has no rating
+    bbs.settings["settings"]["rating"] = "R"
+    #bbs.settings["settings"]["category"] = [u'PORNOGRAPHY', u'ADULT', u'ILLEGAL', u'WEAPONS', u'DRUGS', u'GAMBLING', u'CYBERBULLY', u'ANONYMIZERS', u'SUICIDE', u'MALWARE']
+    #bbs.settings["settings"]["blocklist"] = []
+    #bbs.settings["settings"]["allowlist"] = []
+    #for water in bbs.settings["settings"]["watershed"];
+    #    water["categories"]=[]
+    # delete everything
+    bbs.post_account()
+    bbs.clear_users_and_devices()
+
+    print "*** cleared ***"
+    bbs.settings=None
+    bbs.dump()
+
+    users = [{"name": "Moms pc", "level": "R", "mac": "010203040506"},
+             {"name": "Dads pc", "level": "R", "mac": "010203040507"},
+             {"name": "Jacks ipad", "level": "PG", "mac": "010203040508"},
+             {"name": "Jills iphone", "level": "G", "mac": "010203040509"}]
+
+    print "*** syncing mom-R, Dad-R, jack-PG, Jill-G, wholehome-PG-13 ***"
+
+    bbs.settings = None
+    bbs.sync("PG-13", users)
+
+    print "*** after sync ***"
+    bbs.settings=None
+    bbs.dump()
+    assert(bbs.get_whole_home_rating() == "PG-13")
+    assert(bbs.get_user("Moms pc")["settings"]["rating"] == "R")
+    assert(bbs.get_user("Dads pc")["settings"]["rating"] == "R")
+    assert(bbs.get_user("Jacks ipad")["settings"]["rating"] == "PG")
+    assert(bbs.get_user("Jills iphone")["settings"]["rating"] == "G")
+    assert(bbs.get_device("Moms pc")["mac_address"] == "010203040506")
+    assert(bbs.get_device("Dads pc")["mac_address"] == "010203040507")
+    assert(bbs.get_device("Jacks ipad")["mac_address"] == "010203040508")
+    assert(bbs.get_device("Jills iphone")["mac_address"] == "010203040509")
+
+    print "*** update whole home level ***"
+    bbs.settings=None
+    bbs.get_account()
+    bbs.settings["settings"]["rating"] = "PG"
+    bbs.post_account()
+
+    print "*** after sync ***"
+    bbs.settings=None
+    bbs.dump()
+    assert(bbs.get_whole_home_rating() == "PG")
+    assert(bbs.get_user("Moms pc")["settings"]["rating"] == "R")
+    assert(bbs.get_user("Dads pc")["settings"]["rating"] == "R")
+    assert(bbs.get_user("Jacks ipad")["settings"]["rating"] == "PG")
+    assert(bbs.get_user("Jills iphone")["settings"]["rating"] == "G")
+    assert(bbs.get_device("Moms pc")["mac_address"] == "010203040506")
+    assert(bbs.get_device("Dads pc")["mac_address"] == "010203040507")
+    assert(bbs.get_device("Jacks ipad")["mac_address"] == "010203040508")
+    assert(bbs.get_device("Jills iphone")["mac_address"] == "010203040509")
+
+    print "*** delete dad, change moms IP, change jills level to PG, change whole home to PG-13 ***"
+    users = [{"name": "Moms pc", "level": "R", "mac": "010203040511"},
+             {"name": "Jacks ipad", "level": "PG", "mac": "010203040508"},
+             {"name": "Jills iphone", "level": "PG", "mac": "010203040509"}]
+
+    bbs.settings = None
+    bbs.sync("PG-13", users)
+
+    print "*** after sync ***"
+    bbs.settings=None
+    bbs.dump()
+    assert(bbs.get_whole_home_rating() == "PG-13")
+    assert(bbs.get_user("Moms pc")["settings"]["rating"] == "R")
+    assert(bbs.get_user("Dads pc") == None)
+    assert(bbs.get_user("Jacks ipad")["settings"]["rating"] == "PG")
+    assert(bbs.get_user("Jills iphone")["settings"]["rating"] == "PG")
+    assert(bbs.get_device("Moms pc")["mac_address"] == "010203040511")
+    assert(bbs.get_device("Dads pc") == None)
+    assert(bbs.get_device("Jacks ipad")["mac_address"] == "010203040508")
+
+    print "add dad's laptop"
+    users = [{"name": "Moms pc", "level": "R", "mac": "010203040511"},
+             {"name": "Dads laptop", "level": "PG-13", "mac": "010203040512"},
+             {"name": "Jacks ipad", "level": "PG", "mac": "010203040508"},
+             {"name": "Jills iphone", "level": "PG", "mac": "010203040509"}]
+
+    bbs.settings = None
+    bbs.sync("PG-13", users)
+
+    print "*** after sync ***"
+    bbs.settings=None
+    bbs.dump()
+    assert(bbs.get_whole_home_rating() == "PG-13")
+    assert(bbs.get_user("Moms pc")["settings"]["rating"] == "R")
+    assert(bbs.get_user("Dads pc") == None)
+    assert(bbs.get_user("Dads laptop")["settings"]["rating"] == "PG-13")
+    assert(bbs.get_user("Jacks ipad")["settings"]["rating"] == "PG")
+    assert(bbs.get_user("Jills iphone")["settings"]["rating"] == "PG")
+    assert(bbs.get_device("Moms pc")["mac_address"] == "010203040511")
+    assert(bbs.get_device("Dads pc") == None)
+    assert(bbs.get_device("Dads laptop")["mac_address"] == "010203040512")
+    assert(bbs.get_device("Jacks ipad")["mac_address"] == "010203040508")
+
+    #bbs.add_user("tom", "G", [u'PORNOGRAPHY', u'ADULT', u'ILLEGAL', u'WEAPONS', u'DRUGS', u'GAMBLING', u'SOCIAL', u'CYBERBULLY', u'GAMES', u'ANONYMIZERS', u'SUICIDE', u'MALWARE'])
+    #bbs.add_device(name="tom's iphone", mac="010203040506", type="tablet", username="tom")
+
+def main():
+    if len(sys.argv)<4:
+        print "syntax: broadbandshield.py <operation> <email> <password>"
+        print "        operation = [dump | selftest | assocate"
+        sys.exit(-1)
+
+    operation = sys.argv[1]
+
+    if operation=="dump":
+        dump()
+    elif operation=="selftest":
+        self_test()
+    elif operation=="associate":
+        associate()
+
+if __name__ == "__main__":
+    main()
+
+
diff --git a/xos/onboard/vsg/synchronizer/files/docker.list b/xos/onboard/vsg/synchronizer/files/docker.list
new file mode 100644
index 0000000..0ee9ae0
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/files/docker.list
@@ -0,0 +1 @@
+deb https://get.docker.com/ubuntu docker main
diff --git a/xos/onboard/vsg/synchronizer/files/etc/rc.local b/xos/onboard/vsg/synchronizer/files/etc/rc.local
new file mode 100755
index 0000000..2c7588f
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/files/etc/rc.local
@@ -0,0 +1,23 @@
+#!/bin/sh -e
+#
+# rc.local
+#
+# This script is executed at the end of each multiuser runlevel.
+# Make sure that the script will "exit 0" on success or any other
+# value on error.
+#
+# In order to enable or disable this script just change the execution
+# bits.
+#
+# By default this script does nothing.
+
+ufw enable
+ufw allow bootps
+ufw allow from 192.168.0.0/24
+ufw route allow in on eth1 out on eth0
+ufw route allow in on eth1 out on eth2
+
+BWLIMIT=/usr/local/sbin/bwlimit.sh
+[ -e $BWLIMIT ] && $BWLIMIT start || true
+
+exit 0
diff --git a/xos/onboard/vsg/synchronizer/files/etc/service/message/run b/xos/onboard/vsg/synchronizer/files/etc/service/message/run
new file mode 100755
index 0000000..7b587d8
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/files/etc/service/message/run
@@ -0,0 +1,19 @@
+#!/usr/bin/python
+
+import BaseHTTPServer
+
+
+class HTTPHandlerOne(BaseHTTPServer.BaseHTTPRequestHandler):
+    def do_GET(self):
+        with open('./message.html', 'r') as msgfile:
+            message = msgfile.read()
+        self.wfile.write(message)
+
+
+def run(server_class=BaseHTTPServer.HTTPServer,
+        handler_class=BaseHTTPServer.BaseHTTPRequestHandler):
+    server_address = ('192.168.0.1', 8000)
+    httpd = server_class(server_address, handler_class)
+    httpd.serve_forever()
+
+run(handler_class=HTTPHandlerOne)
diff --git a/xos/onboard/vsg/synchronizer/files/etc/ufw/after.init b/xos/onboard/vsg/synchronizer/files/etc/ufw/after.init
new file mode 100644
index 0000000..e89217d
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/files/etc/ufw/after.init
@@ -0,0 +1,40 @@
+#!/bin/sh
+#
+# after.init: if executable, called by ufw-init. See 'man ufw-framework' for
+#             details. Note that output from these scripts is not seen via the
+#             the ufw command, but instead via ufw-init.
+#
+# Copyright 2013 Canonical Ltd.
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License version 3,
+#    as published by the Free Software Foundation.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+set -e
+
+case "$1" in
+start)
+    # typically required
+    ;;
+stop)
+    # typically required
+    ;;
+status)
+    # optional
+    ;;
+flush-all)
+    # optional
+    ;;
+*)
+    echo "'$1' not supported"
+    echo "Usage: after.init {start|stop|flush-all|status}"
+    ;;
+esac
diff --git a/xos/onboard/vsg/synchronizer/files/etc/ufw/after.rules b/xos/onboard/vsg/synchronizer/files/etc/ufw/after.rules
new file mode 100644
index 0000000..0d6c646
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/files/etc/ufw/after.rules
@@ -0,0 +1,30 @@
+#
+# rules.input-after
+#
+# Rules that should be run after the ufw command line added rules. Custom
+# rules should be added to one of these chains:
+#   ufw-after-input
+#   ufw-after-output
+#   ufw-after-forward
+#
+
+# Don't delete these required lines, otherwise there will be errors
+*filter
+:ufw-after-input - [0:0]
+:ufw-after-output - [0:0]
+:ufw-after-forward - [0:0]
+# End required lines
+
+# don't log noisy services by default
+-A ufw-after-input -p udp --dport 137 -j ufw-skip-to-policy-input
+-A ufw-after-input -p udp --dport 138 -j ufw-skip-to-policy-input
+-A ufw-after-input -p tcp --dport 139 -j ufw-skip-to-policy-input
+-A ufw-after-input -p tcp --dport 445 -j ufw-skip-to-policy-input
+-A ufw-after-input -p udp --dport 67 -j ufw-skip-to-policy-input
+-A ufw-after-input -p udp --dport 68 -j ufw-skip-to-policy-input
+
+# don't log noisy broadcast
+-A ufw-after-input -m addrtype --dst-type BROADCAST -j ufw-skip-to-policy-input
+
+# don't delete the 'COMMIT' line or these rules won't be processed
+COMMIT
diff --git a/xos/onboard/vsg/synchronizer/files/etc/ufw/after6.rules b/xos/onboard/vsg/synchronizer/files/etc/ufw/after6.rules
new file mode 100644
index 0000000..0d99672
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/files/etc/ufw/after6.rules
@@ -0,0 +1,27 @@
+#
+# rules.input-after
+#
+# Rules that should be run after the ufw command line added rules. Custom
+# rules should be added to one of these chains:
+#   ufw6-after-input
+#   ufw6-after-output
+#   ufw6-after-forward
+#
+
+# Don't delete these required lines, otherwise there will be errors
+*filter
+:ufw6-after-input - [0:0]
+:ufw6-after-output - [0:0]
+:ufw6-after-forward - [0:0]
+# End required lines
+
+# don't log noisy services by default
+-A ufw6-after-input -p udp --dport 137 -j ufw6-skip-to-policy-input
+-A ufw6-after-input -p udp --dport 138 -j ufw6-skip-to-policy-input
+-A ufw6-after-input -p tcp --dport 139 -j ufw6-skip-to-policy-input
+-A ufw6-after-input -p tcp --dport 445 -j ufw6-skip-to-policy-input
+-A ufw6-after-input -p udp --dport 546 -j ufw6-skip-to-policy-input
+-A ufw6-after-input -p udp --dport 547 -j ufw6-skip-to-policy-input
+
+# don't delete the 'COMMIT' line or these rules won't be processed
+COMMIT
diff --git a/xos/onboard/vsg/synchronizer/files/etc/ufw/applications.d/openssh-server b/xos/onboard/vsg/synchronizer/files/etc/ufw/applications.d/openssh-server
new file mode 100644
index 0000000..9bbe906
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/files/etc/ufw/applications.d/openssh-server
@@ -0,0 +1,4 @@
+[OpenSSH]
+title=Secure shell server, an rshd replacement
+description=OpenSSH is a free implementation of the Secure Shell protocol.
+ports=22/tcp
diff --git a/xos/onboard/vsg/synchronizer/files/etc/ufw/before.init b/xos/onboard/vsg/synchronizer/files/etc/ufw/before.init
new file mode 100644
index 0000000..1348cb1
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/files/etc/ufw/before.init
@@ -0,0 +1,40 @@
+#!/bin/sh
+#
+# before.init: if executable, called by ufw-init. See 'man ufw-framework' for
+#              details. Note that output from these scripts is not seen via the
+#              the ufw command, but instead via ufw-init.
+#
+# Copyright 2013 Canonical Ltd.
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License version 3,
+#    as published by the Free Software Foundation.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+set -e
+
+case "$1" in
+start)
+    # typically required
+    ;;
+stop)
+    # typically required
+    ;;
+status)
+    # optional
+    ;;
+flush-all)
+    # optional
+    ;;
+*)
+    echo "'$1' not supported"
+    echo "Usage: before.init {start|stop|flush-all|status}"
+    ;;
+esac
diff --git a/xos/onboard/vsg/synchronizer/files/etc/ufw/before6.rules b/xos/onboard/vsg/synchronizer/files/etc/ufw/before6.rules
new file mode 100644
index 0000000..0b26ed8
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/files/etc/ufw/before6.rules
@@ -0,0 +1,73 @@
+#
+# rules.before
+#
+# Rules that should be run before the ufw command line added rules. Custom
+# rules should be added to one of these chains:
+#   ufw6-before-input
+#   ufw6-before-output
+#   ufw6-before-forward
+#
+
+# Don't delete these required lines, otherwise there will be errors
+*filter
+:ufw6-before-input - [0:0]
+:ufw6-before-output - [0:0]
+:ufw6-before-forward - [0:0]
+# End required lines
+
+
+# allow all on loopback
+-A ufw6-before-input -i lo -j ACCEPT
+-A ufw6-before-output -o lo -j ACCEPT
+
+# drop packets with RH0 headers
+-A ufw6-before-input -m rt --rt-type 0 -j DROP
+-A ufw6-before-forward -m rt --rt-type 0 -j DROP
+-A ufw6-before-output -m rt --rt-type 0 -j DROP
+
+# for stateless autoconfiguration (restrict NDP messages to hop limit of 255)
+-A ufw6-before-input -p icmpv6 --icmpv6-type neighbor-solicitation -m hl --hl-eq 255 -j ACCEPT
+-A ufw6-before-output -p icmpv6 --icmpv6-type neighbor-solicitation -m hl --hl-eq 255 -j ACCEPT
+-A ufw6-before-input -p icmpv6 --icmpv6-type neighbor-advertisement -m hl --hl-eq 255 -j ACCEPT
+-A ufw6-before-output -p icmpv6 --icmpv6-type neighbor-advertisement -m hl --hl-eq 255 -j ACCEPT
+-A ufw6-before-input -p icmpv6 --icmpv6-type router-solicitation -m hl --hl-eq 255 -j ACCEPT
+-A ufw6-before-input -p icmpv6 --icmpv6-type router-advertisement -m hl --hl-eq 255 -j ACCEPT
+
+# quickly process packets for which we already have a connection
+-A ufw6-before-input -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
+-A ufw6-before-output -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
+-A ufw6-before-forward -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
+
+# for multicast ping replies from link-local addresses (these don't have an
+# associated connection and would otherwise be marked INVALID)
+-A ufw6-before-input -p icmpv6 --icmpv6-type echo-reply -s fe80::/10 -j ACCEPT
+
+# drop INVALID packets (logs these in loglevel medium and higher)
+-A ufw6-before-input -m conntrack --ctstate INVALID -j ufw6-logging-deny
+-A ufw6-before-input -m conntrack --ctstate INVALID -j DROP
+
+# ok icmp codes for INPUT
+-A ufw6-before-input -p icmpv6 --icmpv6-type destination-unreachable -j ACCEPT
+-A ufw6-before-input -p icmpv6 --icmpv6-type packet-too-big -j ACCEPT
+-A ufw6-before-input -p icmpv6 --icmpv6-type time-exceeded -j ACCEPT
+-A ufw6-before-input -p icmpv6 --icmpv6-type parameter-problem -j ACCEPT
+-A ufw6-before-input -p icmpv6 --icmpv6-type echo-request -j ACCEPT
+
+# ok icmp code for FORWARD
+-A ufw6-before-forward -p icmpv6 --icmpv6-type destination-unreachable -j ACCEPT
+-A ufw6-before-forward -p icmpv6 --icmpv6-type packet-too-big -j ACCEPT
+-A ufw6-before-forward -p icmpv6 --icmpv6-type time-exceeded -j ACCEPT
+-A ufw6-before-forward -p icmpv6 --icmpv6-type parameter-problem -j ACCEPT
+-A ufw6-before-forward -p icmpv6 --icmpv6-type echo-request -j ACCEPT
+
+# allow dhcp client to work
+-A ufw6-before-input -p udp -s fe80::/10 --sport 547 -d fe80::/10 --dport 546 -j ACCEPT
+
+# allow MULTICAST mDNS for service discovery
+-A ufw6-before-input -p udp -d ff02::fb --dport 5353 -j ACCEPT
+
+# allow MULTICAST UPnP for service discovery
+-A ufw6-before-input -p udp -d ff02::f --dport 1900 -j ACCEPT
+
+# don't delete the 'COMMIT' line or these rules won't be processed
+COMMIT
diff --git a/xos/onboard/vsg/synchronizer/files/etc/ufw/sysctl.conf b/xos/onboard/vsg/synchronizer/files/etc/ufw/sysctl.conf
new file mode 100644
index 0000000..8707032
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/files/etc/ufw/sysctl.conf
@@ -0,0 +1,57 @@
+#
+# Configuration file for setting network variables. Please note these settings
+# override /etc/sysctl.conf. If you prefer to use /etc/sysctl.conf, please
+# adjust IPT_SYSCTL in /etc/default/ufw.
+#
+
+# Uncomment this to allow this host to route packets between interfaces
+#net/ipv4/ip_forward=1
+#net/ipv6/conf/default/forwarding=1
+#net/ipv6/conf/all/forwarding=1
+
+# Turn on Source Address Verification in all interfaces to prevent some
+# spoofing attacks
+net/ipv4/conf/default/rp_filter=1
+net/ipv4/conf/all/rp_filter=1
+
+# Do not accept IP source route packets (we are not a router)
+net/ipv4/conf/default/accept_source_route=0
+net/ipv4/conf/all/accept_source_route=0
+net/ipv6/conf/default/accept_source_route=0
+net/ipv6/conf/all/accept_source_route=0
+
+# Disable ICMP redirects. ICMP redirects are rarely used but can be used in
+# MITM (man-in-the-middle) attacks. Disabling ICMP may disrupt legitimate
+# traffic to those sites.
+net/ipv4/conf/default/accept_redirects=0
+net/ipv4/conf/all/accept_redirects=0
+net/ipv6/conf/default/accept_redirects=0
+net/ipv6/conf/all/accept_redirects=0
+
+# Ignore bogus ICMP errors
+net/ipv4/icmp_echo_ignore_broadcasts=1
+net/ipv4/icmp_ignore_bogus_error_responses=1
+net/ipv4/icmp_echo_ignore_all=0
+
+# Don't log Martian Packets (impossible packets)
+net/ipv4/conf/default/log_martians=0
+net/ipv4/conf/all/log_martians=0
+
+# Change to '1' to enable TCP/IP SYN cookies This disables TCP Window Scaling
+# (http://lkml.org/lkml/2008/2/5/167)
+net/ipv4/tcp_syncookies=0
+
+#net/ipv4/tcp_fin_timeout=30
+#net/ipv4/tcp_keepalive_intvl=1800
+
+# normally allowing tcp_sack is ok, but if going through OpenBSD 3.8 RELEASE or
+# earlier pf firewall, should set this to 0
+net/ipv4/tcp_sack=1
+
+# Uncomment this to turn off ipv6 autoconfiguration
+#net/ipv6/conf/default/autoconf=0
+#net/ipv6/conf/all/autoconf=0
+
+# Uncomment this to enable ipv6 privacy addressing
+#net/ipv6/conf/default/use_tempaddr=2
+#net/ipv6/conf/all/use_tempaddr=2
diff --git a/xos/onboard/vsg/synchronizer/files/etc/ufw/ufw.conf b/xos/onboard/vsg/synchronizer/files/etc/ufw/ufw.conf
new file mode 100644
index 0000000..28fe534
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/files/etc/ufw/ufw.conf
@@ -0,0 +1,10 @@
+# /etc/ufw/ufw.conf
+#
+
+# Set to yes to start on boot. If setting this remotely, be sure to add a rule
+# to allow your remote connection before starting ufw. Eg: 'ufw allow 22/tcp'
+ENABLED=yes
+
+# Please use the 'ufw' command to set the loglevel. Eg: 'ufw logging medium'.
+# See 'man ufw' for details.
+LOGLEVEL=low
diff --git a/xos/onboard/vsg/synchronizer/files/vcpe.conf b/xos/onboard/vsg/synchronizer/files/vcpe.conf
new file mode 100644
index 0000000..752c57a
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/files/vcpe.conf
@@ -0,0 +1,10 @@
+# Upstart script for vCPE 
+description "vCPE container"
+author "andy@onlab.us"
+start on filesystem and started docker
+stop on runlevel [!2345]
+respawn
+
+script
+  /usr/local/sbin/start-vcpe.sh
+end script
diff --git a/xos/onboard/vsg/synchronizer/files/vcpe.dnsmasq b/xos/onboard/vsg/synchronizer/files/vcpe.dnsmasq
new file mode 100644
index 0000000..2b2687b
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/files/vcpe.dnsmasq
@@ -0,0 +1,2 @@
+listen-address=192.168.0.1
+dhcp-range=192.168.0.2,192.168.0.254,6
diff --git a/xos/onboard/vsg/synchronizer/files/vm-resolv.conf b/xos/onboard/vsg/synchronizer/files/vm-resolv.conf
new file mode 100644
index 0000000..cae093a
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/files/vm-resolv.conf
@@ -0,0 +1 @@
+nameserver 8.8.8.8
diff --git a/xos/onboard/vsg/synchronizer/manifest b/xos/onboard/vsg/synchronizer/manifest
new file mode 100644
index 0000000..d13ee05
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/manifest
@@ -0,0 +1,49 @@
+templates/bwlimit.sh.j2
+templates/vlan_sample.j2
+templates/before.rules.j2
+templates/start-vcpe.sh.j2
+templates/dnsmasq_safe_servers.j2
+templates/firewall_sample.j2
+templates/rc.local.j2
+templates/vcpe.conf.j2
+templates/message.html.j2
+templates/dnsmasq_servers.j2
+templates/start-vcpe-vtn.sh.j2
+manifest
+broadbandshield.py
+observer_ansible_test.py
+vcpe_synchronizer_config
+start-bbs.sh
+steps/sync_vcpetenant.py
+steps/sync_vcpetenant_new.yaml
+steps/sync_vcpetenant_vtn.yaml
+steps/sync_vcpetenant.yaml
+steps/test.yaml
+steps/ansible_test/README
+steps/ansible_test/test.yaml
+steps/ansible_test/xos.py
+steps/ansible_test/test.sh
+steps/ansible_test/inventory.txt
+start.sh
+files/vcpe.conf
+files/etc/service/message/run
+files/etc/rc.local
+files/etc/ufw/after6.rules
+files/etc/ufw/applications.d/openssh-server
+files/etc/ufw/sysctl.conf
+files/etc/ufw/ufw.conf
+files/etc/ufw/before6.rules
+files/etc/ufw/after.init
+files/etc/ufw/before.init
+files/etc/ufw/after.rules
+files/vm-resolv.conf
+files/docker.list
+files/vcpe.dnsmasq
+run-vtn.sh
+stop.sh
+vcpe-synchronizer.py
+model-deps
+supervisor/vcpe-observer.conf
+run.sh
+vtn_vcpe_synchronizer_config
+vcpe_stats_notifier.py
diff --git a/xos/onboard/vsg/synchronizer/model-deps b/xos/onboard/vsg/synchronizer/model-deps
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/model-deps
@@ -0,0 +1 @@
+{}
diff --git a/xos/onboard/vsg/synchronizer/observer_ansible_test.py b/xos/onboard/vsg/synchronizer/observer_ansible_test.py
new file mode 100644
index 0000000..b28da63
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/observer_ansible_test.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+import os
+import sys
+
+sys.path.append("../..")
+import synchronizers.base.ansible
+
+print sys.argv
+
+private_key="""-----BEGIN RSA PRIVATE KEY-----
+MIIEpQIBAAKCAQEAtJiuarud5S4Y2quDeWyaS0UCQGQtfuSzzNhplFwujYnJGL65
+e14REtv+UuHGymyr/SfkTrBd8vH5NI2UZ/4sZW13ieI/1d97OeVe2+ct0Y4BaFEI
+3Hja6DIpsY3Q2cBQsWUwcQzbMIF9jIq8SzwR1zk8UtZi09fNxqjCchRPlBvbiLKX
+g0/yirN237WbaKzK++8EPy3nuv83216MXHFFSjuxfICe/RhjaqMzVp7isSbv1suU
+geyvNNzU71c/K13gTggdcIXeRQBiJYio2Sn3h2nsV6AFqFH4fjERxWG55Q4e3jeE
+tWM/Dw+hqYKg/25UcmM862a6sUmuDCmM5S3VEQIDAQABAoIBACH88iZoNOki6c6N
+pOq/Q7KSxD+2GtHc3PHacNRZHPHKUqxziJjtNS1lddHHaBBEr4GvdkpQ6v2ECLCZ
+TKrdrSFRnsO2bukjbB+TSWz9byQXI7CsP4yuuhQlDK+7zuiMRyN7tcgw8TeJx0Uh
+/xnxrjHhNbcpXeQcoz+WFzI9HFT1MEGmMS4Lyp/zLB/pmfY9h7V9d+EeRZDi78jq
+Vir6MI6iCTa0T02dvHUFOg+wXLb0nb8V1xKDL+6cAJla7LzwoG8lTnvp5DSYCojI
+5JrILYafeO8RbBV2GWmaE5mkHgeBkFZ+qZQ7K0MjR30Yh6tajB7P3+F/Max8FUgW
+xLHr8AECgYEA2+o0ge3HtZcepEFBKKYnLTwoEpPCfLElWZHzUJYDz259s4JLsfak
+tROANFEdsJUjpmWG52MCL+bgKFFOedDkt4p1jgcIneaHk0jvoU11wG7W3jZZVy1q
+WjQNH5vDU+hg5tm/CREwm7lbUxR9Xuj9K63CNAAGp8KO7h2tOH8woIECgYEA0jrb
+LUg30RxO3+vrq9dUYohrDRisk5zKXuRLfxRA+E+ruvZ7CctG2OpM+658/qZM/w95
+7pOj6zz3//w7tAvH9erY+JOISnzaYKx04sYC1MfbFiFkq5j0gpuYm/MULDYNvFqr
+NU2Buj4dW+ZB+SeficsQOqm5QeNxh1kgiDCs7JECgYEAjSLGCAzeesA9vhTTCI95
+3SIaZbHGw9e8rLtqeHGOiHXU3nvksJYmJsAZK3pTn5xXgNbvuVhlcvCtM7LatntG
+DjUiNMB22z+0CuZoRBE+XP3FkF84/yX6d2Goenyw4wzkA8QDQoJxu789yRgBTgQh
+VwLw/AZ4PvoyWMdbAENApgECgYEAvFikosYP09XTyIPaKaOKY5iqqBoSC1GucSOB
+jAG+T3k5dxB6nQS0nYQUomvqak7drqnT6O33Lrr5ySrW5nCjnmvgJZwvv+Rp1bDM
+K5uRT8caPpJ+Wcp4TUdPi3BVA2MOHVDyEJg3AH/D1+DL/IgGQ/JcwOHsKt61iLhO
+EBXj5zECgYEAk+HuwksUPkSxg/AiJGbapGDK6XGymEUzo2duWlnofRqGcZ3NT3bB
+/kDI1KxQdlpODXSi4/BuTpbQiFOrzcEq5e5ytoMxlCHh3Fl3Jxl+JlgO21vAUvP6
+4SET7Q/6LxmfBlCVRg0dXDwcfJLgbnWxyvprIcz4e0FSFVZTBs/6tFk=
+-----END RSA PRIVATE KEY-----
+"""
+
+observer.ansible.run_template_ssh("test.yaml",
+                                  {"instance_name": "onlab_test405-378",
+                                   "instance_id": "instance-0000004d",
+                                   "hostname": "node67.washington.vicci.org",
+                                   "private_key": private_key})
+
diff --git a/xos/onboard/vsg/synchronizer/run-vtn.sh b/xos/onboard/vsg/synchronizer/run-vtn.sh
new file mode 100755
index 0000000..c4c3b00
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/run-vtn.sh
@@ -0,0 +1,8 @@
+#if [[ ! -e ./vcpe-observer.py ]]; then
+#    ln -s ../../xos-observer.py vcpe-observer.py
+#fi
+
+export XOS_DIR=/opt/xos
+cp /root/setup/node_key $XOS_DIR/synchronizers/vcpe/node_key
+chmod 0600 $XOS_DIR/synchronizers/vcpe/node_key
+python vcpe-synchronizer.py  -C $XOS_DIR/synchronizers/vcpe/vtn_vcpe_synchronizer_config
diff --git a/xos/onboard/vsg/synchronizer/run.sh b/xos/onboard/vsg/synchronizer/run.sh
new file mode 100755
index 0000000..f7c670d
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/run.sh
@@ -0,0 +1,6 @@
+#if [[ ! -e ./vcpe-observer.py ]]; then
+#    ln -s ../../xos-observer.py vcpe-observer.py
+#fi
+
+export XOS_DIR=/opt/xos
+python vcpe-synchronizer.py  -C $XOS_DIR/synchronizers/vcpe/vcpe_synchronizer_config
diff --git a/xos/onboard/vsg/synchronizer/start-bbs.sh b/xos/onboard/vsg/synchronizer/start-bbs.sh
new file mode 100755
index 0000000..c8ee147
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/start-bbs.sh
@@ -0,0 +1,14 @@
+#! /bin/bash
+
+# put this in /opt/xerocole/start-bbs.sh
+# make sure it's executable
+# set it up in crontab
+#   @reboot /opt/xerocole/start-bbs.sh
+
+ulimit -n 200000
+cd /opt/xerocole/answerx
+/opt/xerocole/answerx/startStop checkconfig answerx
+/opt/xerocole/answerx/startStop start answerx
+cd /opt/xerocole/namecontrols
+nohup /opt/xerocole/namecontrols/broadbandshield &
+nohup socat TCP-LISTEN:80,bind=0.0.0.0,fork TCP4:127.0.0.1:8018 &  
diff --git a/xos/onboard/vsg/synchronizer/start.sh b/xos/onboard/vsg/synchronizer/start.sh
new file mode 100755
index 0000000..dc5619b
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/start.sh
@@ -0,0 +1,6 @@
+#if [[ ! -e ./vcpe-observer.py ]]; then
+#    ln -s ../../xos-observer.py vcpe-observer.py
+#fi
+
+export XOS_DIR=/opt/xos
+nohup python vcpe-synchronizer.py  -C $XOS_DIR/synchronizers/vcpe/vcpe_synchronizer_config > /dev/null 2>&1 &
diff --git a/xos/onboard/vsg/synchronizer/steps/ansible_test/README b/xos/onboard/vsg/synchronizer/steps/ansible_test/README
new file mode 100644
index 0000000..d3b2c54
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/steps/ansible_test/README
@@ -0,0 +1,4 @@
+Some scripts used while testing the Ansible instance configuraiton observer
+
+xos.py was probably the prototype of an XOS SSH module for Ansible, that understood how to SSH into the instances
+without needing to play config file and environment tricks. 
diff --git a/xos/onboard/vsg/synchronizer/steps/ansible_test/inventory.txt b/xos/onboard/vsg/synchronizer/steps/ansible_test/inventory.txt
new file mode 100644
index 0000000..bd5b542
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/steps/ansible_test/inventory.txt
@@ -0,0 +1,16 @@
+[onlab_hpc-355]
+node67.washington.vicci.org instance_id=instance-00000045 instance_name=onlab_hpc-355
+
+[onlab_test405-372]
+node67.washington.vicci.org instance_id=instance-0000004c instance_name=onlab_test405-372
+
+[onlab_test405-376]
+node1.cs.arizona.edu
+
+[onlab_test405-378]
+node67.washington.vicci.org ansible_ssh_private_key_file=/home/smbaker/.ssh/id_rsa
+#/home/smbaker/projects/vicci/keys/test_service_key_rsa
+
+[mysite_test2-48]
+cordcompute02.onlab.us ansible_ssh_private_key_file=/home/smbaker/projects/vicci/keys/demo_admin.rsa
+
diff --git a/xos/onboard/vsg/synchronizer/steps/ansible_test/test.sh b/xos/onboard/vsg/synchronizer/steps/ansible_test/test.sh
new file mode 100755
index 0000000..157ba9c
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/steps/ansible_test/test.sh
@@ -0,0 +1,2 @@
+#! /bin/bash
+ansible-playbook --private-key /home/smbaker/.ssh/id_rsa -i ./inventory.txt test.yaml
diff --git a/xos/onboard/vsg/synchronizer/steps/ansible_test/test.yaml b/xos/onboard/vsg/synchronizer/steps/ansible_test/test.yaml
new file mode 100644
index 0000000..6a29d56
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/steps/ansible_test/test.yaml
@@ -0,0 +1,12 @@
+---
+- hosts: onlab_test405-372
+  connection: xos
+  user: ubuntu
+  vars:
+     foo: 25
+#  instance_name: instance-00000045
+#  slice_name: onlab_hpc-355
+
+  tasks:
+    - name: foobar
+      shell: echo foo > /tmp/foobar
diff --git a/xos/onboard/vsg/synchronizer/steps/ansible_test/xos.py b/xos/onboard/vsg/synchronizer/steps/ansible_test/xos.py
new file mode 100755
index 0000000..eb4f3eb
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/steps/ansible_test/xos.py
@@ -0,0 +1,444 @@
+# (c) 2012, Michael DeHaan <michael.dehaan@gmail.com>
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+import os
+import re
+import subprocess
+import shlex
+import pipes
+import random
+import select
+import fcntl
+import hmac
+import pwd
+import gettext
+import pty
+from hashlib import sha1
+import ansible.constants as C
+from ansible.callbacks import vvv
+from ansible import errors
+from ansible import utils
+
+class Connection(object):
+    ''' ssh based connections '''
+
+    def __init__(self, runner, host, port, user, password, private_key_file, *args, **kwargs):
+        self.runner = runner
+        self.host = host
+        self.ipv6 = ':' in self.host
+        self.port = port
+        self.user = str(user)
+        self.password = password
+        self.private_key_file = private_key_file
+        self.HASHED_KEY_MAGIC = "|1|"
+        self.has_pipelining = True
+        #self.instance_id = "instance-00000045" # C.get_config(C.p, "xos", "instance_id", "INSTANCE_ID", None)
+        #self.instance_name = "onlab_hpc-355" # C.get_config(C.p, "xos", "instance_name", "SLIVER_NAME", None)
+
+        inject={}
+        inject= utils.combine_vars(inject, self.runner.inventory.get_variables(self.host))
+
+        self.instance_id = inject["instance_id"]
+        self.instance_name = inject["instance_name"]
+
+        fcntl.lockf(self.runner.process_lockfile, fcntl.LOCK_EX)
+        self.cp_dir = utils.prepare_writeable_dir('$HOME/.ansible/cp',mode=0700)
+        fcntl.lockf(self.runner.process_lockfile, fcntl.LOCK_UN)
+
+    def connect(self):
+        ''' connect to the remote host '''
+
+        vvv("ESTABLISH CONNECTION FOR USER: %s" % self.user, host=self.host)
+
+        self.common_args = []
+        extra_args = C.ANSIBLE_SSH_ARGS
+        if extra_args is not None:
+            # make sure there is no empty string added as this can produce weird errors
+            self.common_args += [x.strip() for x in shlex.split(extra_args) if x.strip()]
+        else:
+            self.common_args += ["-o", "ControlMaster=auto",
+                                 "-o", "ControlPersist=60s",
+                                 "-o", "ControlPath=%s" % (C.ANSIBLE_SSH_CONTROL_PATH % dict(directory=self.cp_dir))]
+
+        self.common_args += ["-o", "ProxyCommand ssh -q -i %s %s@%s" % (self.private_key_file, self.instance_id, self.host)]
+
+        cp_in_use = False
+        cp_path_set = False
+        for arg in self.common_args:
+            if "ControlPersist" in arg:
+                cp_in_use = True
+            if "ControlPath" in arg:
+                cp_path_set = True
+
+        if cp_in_use and not cp_path_set:
+            self.common_args += ["-o", "ControlPath=%s" % (C.ANSIBLE_SSH_CONTROL_PATH % dict(directory=self.cp_dir))]
+
+        if not C.HOST_KEY_CHECKING:
+            self.common_args += ["-o", "StrictHostKeyChecking=no"]
+
+        if self.port is not None:
+            self.common_args += ["-o", "Port=%d" % (self.port)]
+        if self.private_key_file is not None:
+            self.common_args += ["-o", "IdentityFile=\"%s\"" % os.path.expanduser(self.private_key_file)]
+        elif self.runner.private_key_file is not None:
+            self.common_args += ["-o", "IdentityFile=\"%s\"" % os.path.expanduser(self.runner.private_key_file)]
+        if self.password:
+            self.common_args += ["-o", "GSSAPIAuthentication=no",
+                                 "-o", "PubkeyAuthentication=no"]
+        else:
+            self.common_args += ["-o", "KbdInteractiveAuthentication=no",
+                                 "-o", "PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey",
+                                 "-o", "PasswordAuthentication=no"]
+        if self.user != pwd.getpwuid(os.geteuid())[0]:
+            self.common_args += ["-o", "User="+self.user]
+        self.common_args += ["-o", "ConnectTimeout=%d" % self.runner.timeout]
+
+        return self
+
+    def _run(self, cmd, indata):
+        if indata:
+            # do not use pseudo-pty
+            p = subprocess.Popen(cmd, stdin=subprocess.PIPE,
+                                     stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+            stdin = p.stdin
+        else:
+            # try to use upseudo-pty
+            try:
+                # Make sure stdin is a proper (pseudo) pty to avoid: tcgetattr errors
+                master, slave = pty.openpty()
+                p = subprocess.Popen(cmd, stdin=slave,
+                                     stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+                stdin = os.fdopen(master, 'w', 0)
+                os.close(slave)
+            except:
+                p = subprocess.Popen(cmd, stdin=subprocess.PIPE,
+                                     stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+                stdin = p.stdin
+
+        return (p, stdin)
+
+    def _password_cmd(self):
+        if self.password:
+            try:
+                p = subprocess.Popen(["sshpass"], stdin=subprocess.PIPE,
+                    stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+                p.communicate()
+            except OSError:
+                raise errors.AnsibleError("to use the 'ssh' connection type with passwords, you must install the sshpass program")
+            (self.rfd, self.wfd) = os.pipe()
+            return ["sshpass", "-d%d" % self.rfd]
+        return []
+
+    def _send_password(self):
+        if self.password:
+            os.close(self.rfd)
+            os.write(self.wfd, "%s\n" % self.password)
+            os.close(self.wfd)
+
+    def _communicate(self, p, stdin, indata, su=False, sudoable=False, prompt=None):
+        fcntl.fcntl(p.stdout, fcntl.F_SETFL, fcntl.fcntl(p.stdout, fcntl.F_GETFL) & ~os.O_NONBLOCK)
+        fcntl.fcntl(p.stderr, fcntl.F_SETFL, fcntl.fcntl(p.stderr, fcntl.F_GETFL) & ~os.O_NONBLOCK)
+        # We can't use p.communicate here because the ControlMaster may have stdout open as well
+        stdout = ''
+        stderr = ''
+        rpipes = [p.stdout, p.stderr]
+        if indata:
+            try:
+                stdin.write(indata)
+                stdin.close()
+            except:
+                raise errors.AnsibleError('SSH Error: data could not be sent to the remote host. Make sure this host can be reached over ssh')
+        # Read stdout/stderr from process
+        while True:
+            rfd, wfd, efd = select.select(rpipes, [], rpipes, 1)
+
+            # fail early if the sudo/su password is wrong
+            if self.runner.sudo and sudoable:
+                if self.runner.sudo_pass:
+                    incorrect_password = gettext.dgettext(
+                        "sudo", "Sorry, try again.")
+                    if stdout.endswith("%s\r\n%s" % (incorrect_password,
+                                                     prompt)):
+                        raise errors.AnsibleError('Incorrect sudo password')
+
+                if stdout.endswith(prompt):
+                    raise errors.AnsibleError('Missing sudo password')
+
+            if self.runner.su and su and self.runner.su_pass:
+                incorrect_password = gettext.dgettext(
+                    "su", "Sorry")
+                if stdout.endswith("%s\r\n%s" % (incorrect_password, prompt)):
+                    raise errors.AnsibleError('Incorrect su password')
+
+            if p.stdout in rfd:
+                dat = os.read(p.stdout.fileno(), 9000)
+                stdout += dat
+                if dat == '':
+                    rpipes.remove(p.stdout)
+            if p.stderr in rfd:
+                dat = os.read(p.stderr.fileno(), 9000)
+                stderr += dat
+                if dat == '':
+                    rpipes.remove(p.stderr)
+            # only break out if no pipes are left to read or
+            # the pipes are completely read and
+            # the process is terminated
+            if (not rpipes or not rfd) and p.poll() is not None:
+                break
+            # No pipes are left to read but process is not yet terminated
+            # Only then it is safe to wait for the process to be finished
+            # NOTE: Actually p.poll() is always None here if rpipes is empty
+            elif not rpipes and p.poll() == None:
+                p.wait()
+                # The process is terminated. Since no pipes to read from are
+                # left, there is no need to call select() again.
+                break
+        # close stdin after process is terminated and stdout/stderr are read
+        # completely (see also issue #848)
+        stdin.close()
+        return (p.returncode, stdout, stderr)
+
+    def not_in_host_file(self, host):
+        if 'USER' in os.environ:
+            user_host_file = os.path.expandvars("~${USER}/.ssh/known_hosts")
+        else:
+            user_host_file = "~/.ssh/known_hosts"
+        user_host_file = os.path.expanduser(user_host_file)
+        
+        host_file_list = []
+        host_file_list.append(user_host_file)
+        host_file_list.append("/etc/ssh/ssh_known_hosts")
+        host_file_list.append("/etc/ssh/ssh_known_hosts2")
+        
+        hfiles_not_found = 0
+        for hf in host_file_list:
+            if not os.path.exists(hf):
+                hfiles_not_found += 1
+                continue
+            try:
+                host_fh = open(hf)
+            except IOError, e:
+                hfiles_not_found += 1
+                continue
+            else:
+                data = host_fh.read()
+                host_fh.close()
+                
+            for line in data.split("\n"):
+                if line is None or " " not in line:
+                    continue
+                tokens = line.split()
+                if tokens[0].find(self.HASHED_KEY_MAGIC) == 0:
+                    # this is a hashed known host entry
+                    try:
+                        (kn_salt,kn_host) = tokens[0][len(self.HASHED_KEY_MAGIC):].split("|",2)
+                        hash = hmac.new(kn_salt.decode('base64'), digestmod=sha1)
+                        hash.update(host)
+                        if hash.digest() == kn_host.decode('base64'):
+                            return False
+                    except:
+                        # invalid hashed host key, skip it
+                        continue
+                else:
+                    # standard host file entry
+                    if host in tokens[0]:
+                        return False
+
+        if (hfiles_not_found == len(host_file_list)):
+            vvv("EXEC previous known host file not found for %s" % host)
+        return True
+
+    def exec_command(self, cmd, tmp_path, sudo_user=None, sudoable=False, executable='/bin/sh', in_data=None, su_user=None, su=False):
+        ''' run a command on the remote host '''
+
+        ssh_cmd = self._password_cmd()
+        ssh_cmd += ["ssh", "-C"]
+        if not in_data:
+            # we can only use tty when we are not pipelining the modules. piping data into /usr/bin/python
+            # inside a tty automatically invokes the python interactive-mode but the modules are not
+            # compatible with the interactive-mode ("unexpected indent" mainly because of empty lines)
+            ssh_cmd += ["-tt"]
+        if utils.VERBOSITY > 3:
+            ssh_cmd += ["-vvv"]
+        else:
+            ssh_cmd += ["-q"]
+        ssh_cmd += self.common_args
+
+        if self.ipv6:
+            ssh_cmd += ['-6']
+        #ssh_cmd += [self.host]
+        ssh_cmd += [self.instance_name]
+
+        if su and su_user:
+            sudocmd, prompt, success_key = utils.make_su_cmd(su_user, executable, cmd)
+            prompt_re = re.compile(prompt)
+            ssh_cmd.append(sudocmd)
+        elif not self.runner.sudo or not sudoable:
+            prompt = None
+            if executable:
+                ssh_cmd.append(executable + ' -c ' + pipes.quote(cmd))
+            else:
+                ssh_cmd.append(cmd)
+        else:
+            sudocmd, prompt, success_key = utils.make_sudo_cmd(sudo_user, executable, cmd)
+            ssh_cmd.append(sudocmd)
+
+        vvv("EXEC %s" % ssh_cmd, host=self.host)
+
+        not_in_host_file = self.not_in_host_file(self.host)
+
+        if C.HOST_KEY_CHECKING and not_in_host_file:
+            # lock around the initial SSH connectivity so the user prompt about whether to add 
+            # the host to known hosts is not intermingled with multiprocess output.
+            fcntl.lockf(self.runner.process_lockfile, fcntl.LOCK_EX)
+            fcntl.lockf(self.runner.output_lockfile, fcntl.LOCK_EX)
+
+        # create process
+        (p, stdin) = self._run(ssh_cmd, in_data)
+
+        self._send_password()
+
+        if (self.runner.sudo and sudoable and self.runner.sudo_pass) or \
+                (self.runner.su and su and self.runner.su_pass):
+            # several cases are handled for sudo privileges with password
+            # * NOPASSWD (tty & no-tty): detect success_key on stdout
+            # * without NOPASSWD:
+            #   * detect prompt on stdout (tty)
+            #   * detect prompt on stderr (no-tty)
+            fcntl.fcntl(p.stdout, fcntl.F_SETFL,
+                        fcntl.fcntl(p.stdout, fcntl.F_GETFL) | os.O_NONBLOCK)
+            fcntl.fcntl(p.stderr, fcntl.F_SETFL,
+                        fcntl.fcntl(p.stderr, fcntl.F_GETFL) | os.O_NONBLOCK)
+            sudo_output = ''
+            sudo_errput = ''
+
+            while True:
+                if success_key in sudo_output or \
+                    (self.runner.sudo_pass and sudo_output.endswith(prompt)) or \
+                    (self.runner.su_pass and prompt_re.match(sudo_output)):
+                    break
+
+                rfd, wfd, efd = select.select([p.stdout, p.stderr], [],
+                                              [p.stdout], self.runner.timeout)
+                if p.stderr in rfd:
+                    chunk = p.stderr.read()
+                    if not chunk:
+                        raise errors.AnsibleError('ssh connection closed waiting for sudo or su password prompt')
+                    sudo_errput += chunk
+                    incorrect_password = gettext.dgettext(
+                        "sudo", "Sorry, try again.")
+                    if sudo_errput.strip().endswith("%s%s" % (prompt, incorrect_password)):
+                        raise errors.AnsibleError('Incorrect sudo password')
+                    elif sudo_errput.endswith(prompt):
+                        stdin.write(self.runner.sudo_pass + '\n')
+
+                if p.stdout in rfd:
+                    chunk = p.stdout.read()
+                    if not chunk:
+                        raise errors.AnsibleError('ssh connection closed waiting for sudo or su password prompt')
+                    sudo_output += chunk
+
+                if not rfd:
+                    # timeout. wrap up process communication
+                    stdout = p.communicate()
+                    raise errors.AnsibleError('ssh connection error waiting for sudo or su password prompt')
+
+            if success_key not in sudo_output:
+                if sudoable:
+                    stdin.write(self.runner.sudo_pass + '\n')
+                elif su:
+                    stdin.write(self.runner.su_pass + '\n')
+
+        (returncode, stdout, stderr) = self._communicate(p, stdin, in_data, su=su, sudoable=sudoable, prompt=prompt)
+
+        if C.HOST_KEY_CHECKING and not_in_host_file:
+            # lock around the initial SSH connectivity so the user prompt about whether to add 
+            # the host to known hosts is not intermingled with multiprocess output.
+            fcntl.lockf(self.runner.output_lockfile, fcntl.LOCK_UN)
+            fcntl.lockf(self.runner.process_lockfile, fcntl.LOCK_UN)
+        controlpersisterror = 'Bad configuration option: ControlPersist' in stderr or \
+                              'unknown configuration option: ControlPersist' in stderr
+
+        if C.HOST_KEY_CHECKING:
+            if ssh_cmd[0] == "sshpass" and p.returncode == 6:
+                raise errors.AnsibleError('Using a SSH password instead of a key is not possible because Host Key checking is enabled and sshpass does not support this.  Please add this host\'s fingerprint to your known_hosts file to manage this host.')
+
+        if p.returncode != 0 and controlpersisterror:
+            raise errors.AnsibleError('using -c ssh on certain older ssh versions may not support ControlPersist, set ANSIBLE_SSH_ARGS="" (or ssh_args in [ssh_connection] section of the config file) before running again')
+        if p.returncode == 255 and (in_data or self.runner.module_name == 'raw'):
+            raise errors.AnsibleError('SSH Error: data could not be sent to the remote host. Make sure this host can be reached over ssh')
+
+        return (p.returncode, '', stdout, stderr)
+
+    def put_file(self, in_path, out_path):
+        ''' transfer a file from local to remote '''
+        vvv("PUT %s TO %s" % (in_path, out_path), host=self.host)
+        if not os.path.exists(in_path):
+            raise errors.AnsibleFileNotFound("file or module does not exist: %s" % in_path)
+        cmd = self._password_cmd()
+
+        host = self.host
+        if self.ipv6:
+            host = '[%s]' % host
+
+        if C.DEFAULT_SCP_IF_SSH:
+            cmd += ["scp"] + self.common_args
+            cmd += [in_path,host + ":" + pipes.quote(out_path)]
+            indata = None
+        else:
+            cmd += ["sftp"] + self.common_args + [host]
+            indata = "put %s %s\n" % (pipes.quote(in_path), pipes.quote(out_path))
+
+        (p, stdin) = self._run(cmd, indata)
+
+        self._send_password()
+
+        (returncode, stdout, stderr) = self._communicate(p, stdin, indata)
+
+        if returncode != 0:
+            raise errors.AnsibleError("failed to transfer file to %s:\n%s\n%s" % (out_path, stdout, stderr))
+
+    def fetch_file(self, in_path, out_path):
+        ''' fetch a file from remote to local '''
+        vvv("FETCH %s TO %s" % (in_path, out_path), host=self.host)
+        cmd = self._password_cmd()
+
+        host = self.host
+        if self.ipv6:
+            host = '[%s]' % host
+
+        if C.DEFAULT_SCP_IF_SSH:
+            cmd += ["scp"] + self.common_args
+            cmd += [host + ":" + in_path, out_path]
+            indata = None
+        else:
+            cmd += ["sftp"] + self.common_args + [host]
+            indata = "get %s %s\n" % (in_path, out_path)
+
+        p = subprocess.Popen(cmd, stdin=subprocess.PIPE,
+                             stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+        self._send_password()
+        stdout, stderr = p.communicate(indata)
+
+        if p.returncode != 0:
+            raise errors.AnsibleError("failed to transfer file from %s:\n%s\n%s" % (in_path, stdout, stderr))
+
+    def close(self):
+        ''' not applicable since we're executing openssh binaries '''
+        pass
+
diff --git a/xos/onboard/vsg/synchronizer/steps/sync_vcpetenant.py b/xos/onboard/vsg/synchronizer/steps/sync_vcpetenant.py
new file mode 100644
index 0000000..0b777c7
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/steps/sync_vcpetenant.py
@@ -0,0 +1,253 @@
+import hashlib
+import os
+import socket
+import sys
+import base64
+import time
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.syncstep import SyncStep
+from synchronizers.base.ansible import run_template_ssh
+from synchronizers.base.SyncInstanceUsingAnsible import SyncInstanceUsingAnsible
+from core.models import Service, Slice, Tag
+from services.vsg.models import VSGService, VSGTenant
+from services.hpc.models import HpcService, CDNPrefix
+from xos.logger import Logger, logging
+
+# hpclibrary will be in steps/..
+parentdir = os.path.join(os.path.dirname(__file__),"..")
+sys.path.insert(0,parentdir)
+
+from broadbandshield import BBS
+
+logger = Logger(level=logging.INFO)
+
+ENABLE_QUICK_UPDATE=False
+
+CORD_USE_VTN = getattr(Config(), "networking_use_vtn", False)
+
+class SyncVSGTenant(SyncInstanceUsingAnsible):
+    provides=[VSGTenant]
+    observes=VSGTenant
+    requested_interval=0
+    template_name = "sync_vcpetenant.yaml"
+
+    def __init__(self, *args, **kwargs):
+        super(SyncVSGTenant, self).__init__(*args, **kwargs)
+
+    def fetch_pending(self, deleted):
+        if (not deleted):
+            objs = VSGTenant.get_tenant_objects().filter(Q(enacted__lt=F('updated')) | Q(enacted=None),Q(lazy_blocked=False))
+        else:
+            objs = VSGTenant.get_deleted_tenant_objects()
+
+        return objs
+
+    def get_vcpe_service(self, o):
+        if not o.provider_service:
+            return None
+
+        vcpes = VSGService.get_service_objects().filter(id=o.provider_service.id)
+        if not vcpes:
+            return None
+
+        return vcpes[0]
+
+    def get_extra_attributes(self, o):
+        # This is a place to include extra attributes that aren't part of the
+        # object itself. In the case of vCPE, we need to know:
+        #   1) the addresses of dnsdemux, to setup dnsmasq in the vCPE
+        #   2) CDN prefixes, so we know what URLs to send to dnsdemux
+        #   3) BroadBandShield server addresses, for parental filtering
+        #   4) vlan_ids, for setting up networking in the vCPE VM
+
+        vcpe_service = self.get_vcpe_service(o)
+
+        dnsdemux_ip = None
+        cdn_prefixes = []
+
+        cdn_config_fn = "/opt/xos/synchronizers/vsg/cdn_config"
+        if os.path.exists(cdn_config_fn):
+            # manual CDN configuration
+            #   the first line is the address of dnsredir
+            #   the remaining lines are domain names, one per line
+            lines = file(cdn_config_fn).readlines()
+            if len(lines)>=2:
+                dnsdemux_ip = lines[0].strip()
+                cdn_prefixes = [x.strip() for x in lines[1:] if x.strip()]
+        else:
+            # automatic CDN configuiration
+            #    it learns everything from CDN objects in XOS
+            #    not tested on pod.
+            if vcpe_service.backend_network_label:
+                # Connect to dnsdemux using the network specified by
+                #     vcpe_service.backend_network_label
+                for service in HpcService.objects.all():
+                    for slice in service.slices.all():
+                        if "dnsdemux" in slice.name:
+                            for instance in slice.instances.all():
+                                for ns in instance.ports.all():
+                                    if ns.ip and ns.network.labels and (vcpe_service.backend_network_label in ns.network.labels):
+                                        dnsdemux_ip = ns.ip
+                if not dnsdemux_ip:
+                    logger.info("failed to find a dnsdemux on network %s" % vcpe_service.backend_network_label,extra=o.tologdict())
+            else:
+                # Connect to dnsdemux using the instance's public address
+                for service in HpcService.objects.all():
+                    for slice in service.slices.all():
+                        if "dnsdemux" in slice.name:
+                            for instance in slice.instances.all():
+                                if dnsdemux_ip=="none":
+                                    try:
+                                        dnsdemux_ip = socket.gethostbyname(instance.node.name)
+                                    except:
+                                        pass
+                if not dnsdemux_ip:
+                    logger.info("failed to find a dnsdemux with a public address",extra=o.tologdict())
+
+            for prefix in CDNPrefix.objects.all():
+                cdn_prefixes.append(prefix.prefix)
+
+        dnsdemux_ip = dnsdemux_ip or "none"
+
+        # Broadbandshield can either be set up internally, using vcpe_service.bbs_slice,
+        # or it can be setup externally using vcpe_service.bbs_server.
+
+        bbs_addrs = []
+        if vcpe_service.bbs_slice:
+            if vcpe_service.backend_network_label:
+                for bbs_instance in vcpe_service.bbs_slice.instances.all():
+                    for ns in bbs_instance.ports.all():
+                        if ns.ip and ns.network.labels and (vcpe_service.backend_network_label in ns.network.labels):
+                            bbs_addrs.append(ns.ip)
+            else:
+                logger.info("unsupported configuration -- bbs_slice is set, but backend_network_label is not",extra=o.tologdict())
+            if not bbs_addrs:
+                logger.info("failed to find any usable addresses on bbs_slice",extra=o.tologdict())
+        elif vcpe_service.bbs_server:
+            bbs_addrs.append(vcpe_service.bbs_server)
+        else:
+            logger.info("neither bbs_slice nor bbs_server is configured in the vCPE",extra=o.tologdict())
+
+        s_tags = []
+        c_tags = []
+        if o.volt:
+            s_tags.append(o.volt.s_tag)
+            c_tags.append(o.volt.c_tag)
+
+        try:
+            full_setup = Config().observer_full_setup
+        except:
+            full_setup = True
+
+        safe_macs=[]
+        if vcpe_service.url_filter_kind == "safebrowsing":
+            if o.volt and o.volt.subscriber:
+                for user in o.volt.subscriber.devices:
+                    level = user.get("level",None)
+                    mac = user.get("mac",None)
+                    if level in ["G", "PG"]:
+                        if mac:
+                            safe_macs.append(mac)
+
+        fields = {"s_tags": s_tags,
+                "c_tags": c_tags,
+                "dnsdemux_ip": dnsdemux_ip,
+                "cdn_prefixes": cdn_prefixes,
+                "bbs_addrs": bbs_addrs,
+                "full_setup": full_setup,
+                "isolation": o.instance.isolation,
+                "safe_browsing_macs": safe_macs,
+                "container_name": "vcpe-%s-%s" % (s_tags[0], c_tags[0]),
+                "dns_servers": [x.strip() for x in vcpe_service.dns_servers.split(",")],
+                "url_filter_kind": vcpe_service.url_filter_kind }
+
+        # add in the sync_attributes that come from the SubscriberRoot object
+
+        if o.volt and o.volt.subscriber and hasattr(o.volt.subscriber, "sync_attributes"):
+            for attribute_name in o.volt.subscriber.sync_attributes:
+                fields[attribute_name] = getattr(o.volt.subscriber, attribute_name)
+
+        return fields
+
+    def sync_fields(self, o, fields):
+        # the super causes the playbook to be run
+
+        super(SyncVSGTenant, self).sync_fields(o, fields)
+
+        # now do all of our broadbandshield stuff...
+
+        service = self.get_vcpe_service(o)
+        if not service:
+            # Ansible uses the service's keypair in order to SSH into the
+            # instance. It would be bad if the slice had no service.
+
+            raise Exception("Slice %s is not associated with a service" % instance.slice.name)
+
+        # Make sure the slice is configured properly
+        if (service != o.instance.slice.service):
+            raise Exception("Slice %s is associated with some service that is not %s" % (str(instance.slice), str(service)))
+
+        # only enable filtering if we have a subscriber object (see below)
+        url_filter_enable = False
+
+        # for attributes that come from CordSubscriberRoot
+        if o.volt and o.volt.subscriber:
+            url_filter_enable = o.volt.subscriber.url_filter_enable
+            url_filter_level = o.volt.subscriber.url_filter_level
+            url_filter_users = o.volt.subscriber.devices
+
+        if service.url_filter_kind == "broadbandshield":
+            # disable url_filter if there are no bbs_addrs
+            if url_filter_enable and (not fields.get("bbs_addrs",[])):
+                logger.info("disabling url_filter because there are no bbs_addrs",extra=o.tologdict())
+                url_filter_enable = False
+
+            if url_filter_enable:
+                bbs_hostname = None
+                if service.bbs_api_hostname and service.bbs_api_port:
+                    bbs_hostname = service.bbs_api_hostname
+                else:
+                    # TODO: extract from slice
+                    bbs_hostname = "cordcompute01.onlab.us"
+
+                if service.bbs_api_port:
+                    bbs_port = service.bbs_api_port
+                else:
+                    bbs_port = 8018
+
+                if not bbs_hostname:
+                    logger.info("broadbandshield is not configured",extra=o.tologdict())
+                else:
+                    tStart = time.time()
+                    bbs = BBS(o.bbs_account, "123", bbs_hostname, bbs_port)
+                    bbs.sync(url_filter_level, url_filter_users)
+
+                    if o.hpc_client_ip:
+                        logger.info("associate account %s with ip %s" % (o.bbs_account, o.hpc_client_ip),extra=o.tologdict())
+                        bbs.associate(o.hpc_client_ip)
+                    else:
+                        logger.info("no hpc_client_ip to associate",extra=o.tologdict())
+
+                    logger.info("bbs update time %d" % int(time.time()-tStart),extra=o.tologdict())
+
+
+    def run_playbook(self, o, fields):
+        ansible_hash = hashlib.md5(repr(sorted(fields.items()))).hexdigest()
+        quick_update = (o.last_ansible_hash == ansible_hash)
+
+        if ENABLE_QUICK_UPDATE and quick_update:
+            logger.info("quick_update triggered; skipping ansible recipe",extra=o.tologdict())
+        else:
+            if o.instance.isolation in ["container", "container_vm"]:
+                super(SyncVSGTenant, self).run_playbook(o, fields, "sync_vcpetenant_new.yaml")
+            else:
+                if CORD_USE_VTN:
+                    super(SyncVSGTenant, self).run_playbook(o, fields, template_name="sync_vcpetenant_vtn.yaml")
+                else:
+                    super(SyncVSGTenant, self).run_playbook(o, fields)
+
+        o.last_ansible_hash = ansible_hash
+
+    def delete_record(self, m):
+        pass
diff --git a/xos/onboard/vsg/synchronizer/steps/sync_vcpetenant.yaml b/xos/onboard/vsg/synchronizer/steps/sync_vcpetenant.yaml
new file mode 100644
index 0000000..880895e
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/steps/sync_vcpetenant.yaml
@@ -0,0 +1,179 @@
+---
+- hosts: {{ instance_name }}
+  gather_facts: False
+  connection: ssh
+  user: ubuntu
+  sudo: yes
+  vars:
+      cdn_enable: {{ cdn_enable }}
+      dnsdemux_ip: {{ dnsdemux_ip }}
+      firewall_enable: {{ firewall_enable }}
+      url_filter_enable: {{ url_filter_enable }}
+      c_tags:
+        {% for c_tag in c_tags %}
+        - {{ c_tag }}
+        {% endfor %}
+      s_tags:
+        {% for s_tag in s_tags %}
+        - {{ s_tag }}
+        {% endfor %}
+      firewall_rules:
+        {% for firewall_rule in firewall_rules.split("\n") %}
+        - {{ firewall_rule }}
+        {% endfor %}
+      cdn_prefixes:
+        {% for prefix in cdn_prefixes %}
+        - {{ prefix }}
+        {% endfor %}
+      bbs_addrs:
+        {% for bbs_addr in bbs_addrs %}
+        - {{ bbs_addr }}
+        {% endfor %}
+      dns_servers:
+        {% for dns_server in dns_servers %}
+        - {{ dns_server }}
+        {% endfor %}
+      nat_ip: {{ nat_ip }}
+      nat_mac: {{ nat_mac }}
+      lan_ip: {{ lan_ip }}
+      lan_mac: {{ lan_mac }}
+      wan_ip: {{ wan_ip }}
+      wan_mac: {{ wan_mac }}
+      wan_container_mac: {{ wan_container_mac }}
+      wan_next_hop: 10.0.1.253   # FIX ME
+      private_ip: {{ private_ip }}
+      private_mac: {{ private_mac }}
+      hpc_client_ip: {{ hpc_client_ip }}
+      hpc_client_mac: {{ hpc_client_mac }}
+      keystone_tenant_id: {{ keystone_tenant_id }}
+      keystone_user_id: {{ keystone_user_id }}
+      rabbit_user: {{ rabbit_user }}
+      rabbit_password: {{ rabbit_password }}
+      rabbit_host: {{ rabbit_host }}
+      safe_browsing:
+        {% for mac in safe_browsing_macs %}
+        - {{ mac }}
+        {% endfor %}
+      uplink_speed: {{ uplink_speed }}
+      downlink_speed: {{ downlink_speed }}
+      status: {{ status }}
+      enable_uverse: {{ enable_uverse }}
+      url_filter_kind: {{ url_filter_kind }}
+
+  tasks:
+{% if full_setup %}
+  - name: Docker repository
+    copy: src=/opt/xos/synchronizers/vsg/files/docker.list
+      dest=/etc/apt/sources.list.d/docker.list
+
+  - name: Import the repository key
+    apt_key: keyserver=keyserver.ubuntu.com id=36A1D7869245C8950F966E92D8576A8BA88D21E9
+
+  - name: install Docker
+    apt: name=lxc-docker state=present update_cache=yes
+
+  - name: install python-setuptools
+    apt: name=python-setuptools state=present
+
+  - name: install pip
+    easy_install: name=pip
+
+  - name: install docker-py
+    pip: name=docker-py version=0.5.3
+
+  - name: install Pipework
+    get_url: url=https://raw.githubusercontent.com/jpetazzo/pipework/master/pipework
+       dest=/usr/local/bin/pipework
+       mode=0755
+
+  - name: make sure /etc/dnsmasq.d exists
+    file: path=/etc/dnsmasq.d state=directory owner=root group=root
+
+  - name: Disable resolvconf service
+    shell: service resolvconf stop
+    shell: echo manual > /etc/init/resolvconf.override
+    shell: rm -f /etc/resolv.conf
+
+  - name: Install resolv.conf
+    copy: src=/opt/xos/synchronizers/vsg/files/vm-resolv.conf
+      dest=/etc/resolv.conf
+
+  - name: Verify if vcpe_stats_notifier ([] is to avoid capturing the shell process) cron job is already running
+    shell: pgrep -f [v]cpe_stats_notifier | wc -l
+    register: cron_job_pids_count
+
+#  - name: DEBUG
+#    debug: var=cron_job_pids_count.stdout
+
+#  - name: make sure ~/bin exists
+#    file: path=~/bin state=directory owner=root group=root
+#    when: cron_job_pids_count.stdout == "0"
+
+  - name: Copy cron job to destination
+    copy: src=/opt/xos/synchronizers/vsg/vcpe_stats_notifier.py
+      dest=/usr/local/sbin/vcpe_stats_notifier.py
+    when: cron_job_pids_count.stdout == "0"
+
+  - name: install python-kombu
+    apt: name=python-kombu state=present
+    when: cron_job_pids_count.stdout == "0"
+
+  - name: Initiate vcpe_stats_notifier cron job
+    command: sudo python /usr/local/sbin/vcpe_stats_notifier.py --keystone_tenant_id={{ keystone_tenant_id }} --keystone_user_id={{ keystone_user_id }} --rabbit_user={{ rabbit_user }} --rabbit_password={{ rabbit_password }} --rabbit_host={{ rabbit_host }} --vcpeservice_rabbit_exchange='vcpeservice'
+    async: 9999999999999999
+    poll: 0
+    when: cron_job_pids_count.stdout == "0"
+{% endif %}
+
+  - name: vCPE upstart
+    template: src=/opt/xos/synchronizers/vsg/templates/vcpe.conf.j2 dest=/etc/init/vcpe-{{ s_tags[0] }}-{{ c_tags[0] }}.conf
+
+  - name: vCPE startup script
+    template: src=/opt/xos/synchronizers/vsg/templates/start-vcpe.sh.j2 dest=/usr/local/sbin/start-vcpe-{{ s_tags[0] }}-{{ c_tags[0] }}.sh mode=0755
+    notify:
+#    - restart vcpe
+     - stop vcpe
+     - remove container
+     - start vcpe
+
+  - name: create /etc/vcpe-{{ s_tags[0] }}-{{ c_tags[0] }}/dnsmasq.d
+    file: path=/etc/vcpe-{{ s_tags[0] }}-{{ c_tags[0] }}/dnsmasq.d state=directory owner=root group=root
+
+  - name: vCPE basic dnsmasq config
+    copy: src=/opt/xos/synchronizers/vsg/files/vcpe.dnsmasq dest=/etc/vcpe-{{ s_tags[0] }}-{{ c_tags[0] }}/dnsmasq.d/vcpe.conf owner=root group=root
+    notify:
+    - restart dnsmasq
+
+  - name: dnsmasq config
+    template: src=/opt/xos/synchronizers/vsg/templates/dnsmasq_servers.j2 dest=/etc/vcpe-{{ s_tags[0] }}-{{ c_tags[0] }}/dnsmasq.d/servers.conf owner=root group=root
+    notify:
+    - restart dnsmasq
+
+# These are samples, not necessary for correct function of demo
+
+#  - name: networking info
+#    template: src=/opt/xos/synchronizers/vsg/templates/vlan_sample.j2 dest=/etc/vlan_sample owner=root group=root
+
+#  - name: firewall info
+#    template: src=/opt/xos/synchronizers/vsg/templates/firewall_sample.j2 dest=/etc/firewall_sample owner=root group=root
+
+  - name: Make sure vCPE service is running
+    service: name=vcpe-{{ s_tags[0] }}-{{ c_tags[0] }} state=started
+
+  handlers:
+  # Dnsmasq is automatically restarted in the container
+  - name: restart dnsmasq
+    shell: docker exec vcpe-{{ s_tags[0] }}-{{ c_tags[0] }} killall dnsmasq
+
+  - name: restart vcpe
+    shell: service vcpe-{{ s_tags[0] }}-{{ c_tags[0] }} stop; sleep 1; service vcpe-{{ s_tags[0] }}-{{ c_tags[0] }} start
+
+  - name: stop vcpe
+    service: name=vcpe-{{ s_tags[0] }}-{{ c_tags[0] }} state=stopped
+
+  - name: remove container
+    docker: name=vcpe-{{ s_tags[0] }}-{{ c_tags[0] }} state=absent image=docker-vcpe
+
+  - name: start vcpe
+    service: name=vcpe-{{ s_tags[0] }}-{{ c_tags[0] }} state=started
+
diff --git a/xos/onboard/vsg/synchronizer/steps/sync_vcpetenant_new.yaml b/xos/onboard/vsg/synchronizer/steps/sync_vcpetenant_new.yaml
new file mode 100644
index 0000000..9c59280
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/steps/sync_vcpetenant_new.yaml
@@ -0,0 +1,136 @@
+---
+- hosts: {{ instance_name }}
+  gather_facts: False
+  connection: ssh
+  user: {{ username }}
+  sudo: yes
+  vars:
+      container_name: {{ container_name }}
+      cdn_enable: {{ cdn_enable }}
+      dnsdemux_ip: {{ dnsdemux_ip }}
+      firewall_enable: {{ firewall_enable }}
+      url_filter_enable: {{ url_filter_enable }}
+      c_tags:
+        {% for c_tag in c_tags %}
+        - {{ c_tag }}
+        {% endfor %}
+      s_tags:
+        {% for s_tag in s_tags %}
+        - {{ s_tag }}
+        {% endfor %}
+      firewall_rules:
+        {% for firewall_rule in firewall_rules.split("\n") %}
+        - {{ firewall_rule }}
+        {% endfor %}
+      cdn_prefixes:
+        {% for prefix in cdn_prefixes %}
+        - {{ prefix }}
+        {% endfor %}
+      bbs_addrs:
+        {% for bbs_addr in bbs_addrs %}
+        - {{ bbs_addr }}
+        {% endfor %}
+      dns_servers:
+        {% for dns_server in dns_servers %}
+        - {{ dns_server }}
+        {% endfor %}
+      nat_ip: {{ nat_ip }}
+      nat_mac: {{ nat_mac }}
+      lan_ip: {{ lan_ip }}
+      lan_mac: {{ lan_mac }}
+      wan_ip: {{ wan_ip }}
+      wan_mac: {{ wan_mac }}
+      wan_container_mac: {{ wan_container_mac }}
+      wan_next_hop: 10.0.1.253   # FIX ME
+      private_ip: {{ private_ip }}
+      private_mac: {{ private_mac }}
+      hpc_client_ip: {{ hpc_client_ip }}
+      hpc_client_mac: {{ hpc_client_mac }}
+      keystone_tenant_id: {{ keystone_tenant_id }}
+      keystone_user_id: {{ keystone_user_id }}
+      rabbit_user: {{ rabbit_user }}
+      rabbit_password: {{ rabbit_password }}
+      rabbit_host: {{ rabbit_host }}
+      safe_browsing:
+        {% for mac in safe_browsing_macs %}
+        - {{ mac }}
+        {% endfor %}
+      uplink_speed: {{ uplink_speed }}
+      downlink_speed: {{ downlink_speed }}
+      status: {{ status }}
+      enable_uverse: {{ enable_uverse }}
+      url_filter_kind: {{ url_filter_kind }}
+
+  tasks:
+  - name: Verify if vcpe_stats_notifier ([] is to avoid capturing the shell process) cron job is already running
+    shell: pgrep -f [v]cpe_stats_notifier | wc -l
+    register: cron_job_pids_count
+
+#  - name: DEBUG
+#    debug: var=cron_job_pids_count.stdout
+
+  - name: make sure ~/bin exists
+    file: path=~/bin state=directory owner=root group=root
+    when: cron_job_pids_count.stdout == "0"
+
+  - name: Copy cron job to destination
+    copy: src=/opt/xos/synchronizers/vsg/vcpe_stats_notifier.py
+      dest=~/bin/vcpe_stats_notifier.py
+    when: cron_job_pids_count.stdout == "0"
+
+  - name: install python-kombu
+    apt: name=python-kombu state=present
+    when: cron_job_pids_count.stdout == "0"
+
+  - name: Initiate vcpe_stats_notifier cron job
+    command: python ~/bin/vcpe_stats_notifier.py --keystone_tenant_id={{ keystone_tenant_id }} --keystone_user_id={{ keystone_user_id }} --rabbit_user={{ rabbit_user }} --rabbit_password={{ rabbit_password }} --rabbit_host={{ rabbit_host }} --vcpeservice_rabbit_exchange='vcpeservice'
+    async: 9999999999999999
+    poll: 0
+    when: cron_job_pids_count.stdout == "0"
+
+  - name: vCPE basic dnsmasq config
+    copy: src=/opt/xos/synchronizers/vsg/files/vcpe.dnsmasq dest=/var/container_volumes/{{ container_name }}/etc/dnsmasq.d/vcpe.conf owner=root group=root
+    notify:
+    - restart dnsmasq
+
+  - name: dnsmasq config
+    template: src=/opt/xos/synchronizers/vsg/templates/dnsmasq_servers.j2 dest=/var/container_volumes/{{ container_name }}/etc/dnsmasq.d/servers.conf owner=root group=root
+    notify:
+    - restart dnsmasq
+
+  - name: create directory for "safe" config
+    file: path=/var/container_volumes/{{ container_name }}/etc/dnsmasq.d/safe state=directory
+
+  - name: dnsmasq "safe" config
+    template: src=/opt/xos/synchronizers/vsg/templates/dnsmasq_safe_servers.j2 dest=/var/container_volumes/{{ container_name }}/etc/dnsmasq.d/safe/servers.conf owner=root group=root
+    notify:
+    - restart dnsmasq
+
+  - name: copy base ufw files
+    synchronize: src=/opt/xos/synchronizers/vsg/files/etc/ufw/ dest=/var/container_volumes/{{ container_name }}/etc/ufw/
+    notify:
+    - reload ufw
+
+  - name: redirection rules for safe DNS
+    template: src=/opt/xos/synchronizers/vsg/templates/before.rules.j2 dest=/var/container_volumes/{{ container_name }}/etc/ufw/before.rules owner=root group=root
+    notify:
+    - reload ufw
+
+  - name: base ufw setup uses /etc/rc.local
+    copy: src=/opt/xos/synchronizers/vsg/files/etc/rc.local dest=/var/container_volumes/{{ container_name }}/etc/ owner=root group=root
+    notify:
+    - copy in /etc/rc.local
+
+  handlers:
+  # Dnsmasq is automatically restarted in the container
+  - name: restart dnsmasq
+    shell: docker exec {{ container_name }} /usr/bin/killall dnsmasq
+
+  - name: reload ufw
+    shell: docker exec {{ container_name }} bash -c "/sbin/iptables -t nat -F PREROUTING; /usr/sbin/ufw reload"
+
+  # Use docker cp instead of single-file volume
+  # The reason is that changes to external file volume don't show up inside the container
+  # Probably Ansible deletes and then recreates the external file, and container has old version
+  - name: copy in /etc/rc.local
+    shell: docker cp /var/container_volumes/{{ container_name }}/etc/rc.local {{ container_name }}:/etc/
diff --git a/xos/onboard/vsg/synchronizer/steps/sync_vcpetenant_vtn.yaml b/xos/onboard/vsg/synchronizer/steps/sync_vcpetenant_vtn.yaml
new file mode 100644
index 0000000..0226354
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/steps/sync_vcpetenant_vtn.yaml
@@ -0,0 +1,244 @@
+---
+- hosts: {{ instance_name }}
+  #gather_facts: False
+  connection: ssh
+  user: ubuntu
+  sudo: yes
+  vars:
+      container_name: {{ container_name }}
+      cdn_enable: {{ cdn_enable }}
+      dnsdemux_ip: {{ dnsdemux_ip }}
+      firewall_enable: {{ firewall_enable }}
+      url_filter_enable: {{ url_filter_enable }}
+      c_tags:
+        {% for c_tag in c_tags %}
+        - {{ c_tag }}
+        {% endfor %}
+      s_tags:
+        {% for s_tag in s_tags %}
+        - {{ s_tag }}
+        {% endfor %}
+      firewall_rules:
+        {% for firewall_rule in firewall_rules.split("\n") %}
+        - {{ firewall_rule }}
+        {% endfor %}
+      cdn_prefixes:
+        {% for prefix in cdn_prefixes %}
+        - {{ prefix }}
+        {% endfor %}
+      bbs_addrs:
+        {% for bbs_addr in bbs_addrs %}
+        - {{ bbs_addr }}
+        {% endfor %}
+      dns_servers:
+        {% for dns_server in dns_servers %}
+        - {{ dns_server }}
+        {% endfor %}
+      nat_ip: {{ nat_ip }}
+      nat_mac: {{ nat_mac }}
+      lan_ip: {{ lan_ip }}
+      lan_mac: {{ lan_mac }}
+      wan_ip: {{ wan_ip }}
+      wan_mac: {{ wan_mac }}
+      wan_container_ip: {{ wan_container_ip }}
+      wan_container_netbits: {{ wan_container_netbits }}
+      wan_container_mac: {{ wan_container_mac }}
+      wan_container_gateway_ip: {{ wan_container_gateway_ip }}
+      wan_vm_ip: {{ wan_vm_ip }}
+      wan_vm_mac: {{ wan_vm_mac }}
+      wan_next_hop: 10.0.1.253   # FIX ME
+      private_ip: {{ private_ip }}
+      private_mac: {{ private_mac }}
+      hpc_client_ip: {{ hpc_client_ip }}
+      hpc_client_mac: {{ hpc_client_mac }}
+      keystone_tenant_id: {{ keystone_tenant_id }}
+      keystone_user_id: {{ keystone_user_id }}
+      rabbit_user: {{ rabbit_user }}
+      rabbit_password: {{ rabbit_password }}
+      rabbit_host: {{ rabbit_host }}
+      safe_browsing:
+        {% for mac in safe_browsing_macs %}
+        - {{ mac }}
+        {% endfor %}
+      uplink_speed: {{ uplink_speed }}
+      downlink_speed: {{ downlink_speed }}
+      status: {{ status }}
+      enable_uverse: {{ enable_uverse }}
+      url_filter_kind: {{ url_filter_kind }}
+
+
+  tasks:
+  - name: Add hostname to /etc/hosts
+    lineinfile: dest=/etc/hosts
+      regexp='^127\.0\.0\.1'
+      line="127.0.0.1 localhost {{ '{{' }} ansible_hostname {{ '}}' }}"
+      owner=root group=root mode=0644
+
+  - name: Verify that bridge-utils is installed
+    shell: stat /sbin/brctl
+
+  - name: Verify that docker is installed
+    shell: stat /usr/bin/docker
+
+  - name: Check to see if network is setup
+    stat: path=/root/network_is_setup
+    register: network_is_setup
+
+  - name: set up the network
+    shell: "{{ '{{' }} item {{ '}}' }}"
+    with_items:
+       - ip link del link eth0 eth0.500 || true
+       - ip link add link eth0 eth0.500 type vlan id 500
+       - ip link set eth0.500 up
+       - ifconfig br-wan down || true
+       - brctl delbr br-wan || true
+       - brctl addbr br-wan
+       - brctl addif br-wan eth0.500
+       - ifconfig br-wan hw ether {{ wan_vm_mac }}
+       - ip addr add {{ wan_vm_ip }}/{{ wan_container_netbits }} dev br-wan
+       - ip link set br-wan up
+       - ip route del default || true
+       - ip route add default via {{ wan_container_gateway_ip }}
+       - ip link set dev br-wan promisc on
+    when: network_is_setup.stat.exists == False
+
+  - name: Remember that the network is setup, so we never do the above again
+    shell: touch /root/network_is_setup
+
+{% if full_setup %}
+  - name: Check to see if environment is setup
+    stat: path=/root/environment_is_setup
+    register: environment_is_setup
+
+# Everything here is now baked into the vCPE image
+# Leave this spot in place for future temporary setup stuff
+
+  - name: Remember that the environment is setup, so we never do the above again
+    shell: touch /root/environment_is_setup
+
+  - name: Verify if vcpe_stats_notifier ([] is to avoid capturing the shell process) cron job is already running
+    shell: pgrep -f [v]cpe_stats_notifier | wc -l
+    register: cron_job_pids_count
+
+#  - name: DEBUG
+#    debug: var=cron_job_pids_count.stdout
+
+#  - name: make sure ~/bin exists
+#    file: path=~/bin state=directory owner=root group=root
+#    when: cron_job_pids_count.stdout == "0"
+
+#  - name: Copy cron job to destination
+#    copy: src=/opt/xos/synchronizers/vsg/vcpe_stats_notifier.py
+#      dest=/usr/local/sbin/vcpe_stats_notifier.py
+#    when: cron_job_pids_count.stdout == "0"
+
+#  - name: install python-kombu
+#    apt: name=python-kombu state=present
+#    when: cron_job_pids_count.stdout == "0"
+
+#  - name: Initiate vcpe_stats_notifier cron job
+#    command: sudo python /usr/local/sbin/vcpe_stats_notifier.py --keystone_tenant_id={{ keystone_tenant_id }} --keystone_user_id={{ keystone_user_id }} --rabbit_user={{ rabbit_user }} --rabbit_password={{ rabbit_password }} --rabbit_host={{ rabbit_host }} --vcpeservice_rabbit_exchange='vcpeservice'
+#    async: 9999999999999999
+#    poll: 0
+#    when: cron_job_pids_count.stdout == "0"
+{% endif %}
+
+  - name: vCPE upstart
+    template: src=/opt/xos/synchronizers/vsg/templates/vcpe.conf.j2 dest=/etc/init/{{ container_name }}.conf
+
+  - name: vCPE startup script
+    template: src=/opt/xos/synchronizers/vsg/templates/start-vcpe-vtn.sh.j2 dest=/usr/local/sbin/start-{{ container_name }}.sh mode=0755
+    notify:
+#    - restart vcpe
+     - stop vcpe
+     - remove container
+     - start vcpe
+
+  - name: create /var/container_volumes/{{ container_name }}/etc/dnsmasq.d/safe/
+    file: path=/var/container_volumes/{{ container_name }}/etc/dnsmasq.d/safe state=directory owner=root group=root
+
+  - name: vCPE basic dnsmasq config
+    copy: src=/opt/xos/synchronizers/vsg/files/vcpe.dnsmasq dest=/var/container_volumes/{{ container_name }}/etc/dnsmasq.d/vcpe.conf owner=root group=root
+    notify:
+    - restart dnsmasq
+
+  - name: dnsmasq config
+    template: src=/opt/xos/synchronizers/vsg/templates/dnsmasq_servers.j2 dest=/var/container_volumes/{{ container_name }}/etc/dnsmasq.d/servers.conf owner=root group=root
+    notify:
+    - restart dnsmasq
+
+  - name: dnsmasq "safe" config
+    template: src=/opt/xos/synchronizers/vsg/templates/dnsmasq_safe_servers.j2 dest=/var/container_volumes/{{ container_name }}/etc/dnsmasq.d/safe/servers.conf owner=root group=root
+    notify:
+    - restart dnsmasq
+
+  - name: create /var/container_volumes/{{ container_name }}/mount/
+    file: path=/var/container_volumes/{{ container_name }}/mount state=directory owner=root group=root
+
+  - name: redirection rules for safe DNS
+    template: src=/opt/xos/synchronizers/vsg/templates/before.rules.j2 dest=/var/container_volumes/{{ container_name }}/mount/before.rules owner=root group=root mode=0644
+    notify:
+    - reload ufw
+
+  - name: base ufw setup uses /etc/rc.local
+    template: src=/opt/xos/synchronizers/vsg/templates/rc.local.j2 dest=/var/container_volumes/{{ container_name }}/mount/rc.local owner=root group=root mode=0755
+    notify:
+    - rerun /etc/rc.local
+
+  - name: create directory for local programs
+    file: path=/var/container_volumes/{{ container_name }}/usr/local/sbin state=directory
+
+  - name: bandwidth limit script
+    template: src=/opt/xos/synchronizers/vsg/templates/bwlimit.sh.j2 dest=/var/container_volumes/{{ container_name }}/usr/local/sbin/bwlimit.sh owner=root group=root mode=0755
+    notify:
+    - reset bwlimits
+
+  - name: create directory for simple webserver
+    file: path=/var/container_volumes/{{ container_name }}/etc/service/message state=directory
+
+  - name: copy simple webserver
+    copy: src=/opt/xos/synchronizers/vsg/files/etc/service/ dest=/var/container_volumes/{{ container_name }}/etc/service/ owner=root group=root
+    when: status != "enabled"
+
+  - name: make webserver script executable
+    file: path=/var/container_volumes/{{ container_name }}/etc/service/message/run mode=0755
+    when: status != "enabled"
+
+  - name: generate the message page
+    template: src=/opt/xos/synchronizers/vsg/templates/message.html.j2 dest=/var/container_volumes/{{ container_name }}/etc/service/message/message.html owner=root group=root mode=0644
+    when: status != "enabled"
+    #notify: restart vcpe
+
+  - name: remove simple webserver
+    file: path=/var/container_volumes/{{ container_name }}/etc/service/message/run state=absent
+    when: status == "enabled"
+    #notify: restart vcpe
+
+  - name: Make sure vCPE service is running
+    service: name={{ container_name }} state=started
+
+  handlers:
+  # Dnsmasq is automatically restarted in the container
+  - name: restart dnsmasq
+    shell: docker exec {{ container_name }} killall dnsmasq
+
+  - name: stop vcpe
+    service: name={{ container_name }} state=stopped
+
+  - name: remove container
+    docker: name={{ container_name }} state=absent image=docker-vcpe
+
+  - name: start vcpe
+    service: name={{ container_name }} state=started
+
+  - name: reload ufw
+    shell: docker exec {{ container_name }} bash -c "/sbin/iptables -t nat -F PREROUTING; /sbin/iptables -t nat -F POSTROUTING; /usr/sbin/ufw reload"
+
+  - name: rerun /etc/rc.local
+    shell: docker exec {{ container_name }} bash -c "/etc/rc.local"
+
+  - name: reset bwlimits
+    shell: docker exec {{ container_name }} bash -c "/usr/local/sbin/bwlimit.sh restart"
+
+  - name: restart vcpe
+    shell: service {{ container_name }} stop; sleep 1; service {{ container_name }} start
diff --git a/xos/onboard/vsg/synchronizer/steps/test.yaml b/xos/onboard/vsg/synchronizer/steps/test.yaml
new file mode 100644
index 0000000..fc8251d
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/steps/test.yaml
@@ -0,0 +1,7 @@
+---
+- hosts: {{ instance_name }}
+  connection: ssh
+  user: ubuntu
+  tasks:
+    - name: foobar
+      shell: echo foo > /tmp/foobar
diff --git a/xos/onboard/vsg/synchronizer/stop.sh b/xos/onboard/vsg/synchronizer/stop.sh
new file mode 100755
index 0000000..e90e16c
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/stop.sh
@@ -0,0 +1 @@
+pkill -9 -f vcpe-observer.py
diff --git a/xos/onboard/vsg/synchronizer/supervisor/vcpe-observer.conf b/xos/onboard/vsg/synchronizer/supervisor/vcpe-observer.conf
new file mode 100644
index 0000000..2d90293
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/supervisor/vcpe-observer.conf
@@ -0,0 +1,2 @@
+[program:vcpe-observer]
+command=python /opt/xos/synchronizers/vsg/vcpe-synchronizer.py -C /opt/xos/synchronizers/vsg/vcpe_synchronizer_config
diff --git a/xos/onboard/vsg/synchronizer/templates/before.rules.j2 b/xos/onboard/vsg/synchronizer/templates/before.rules.j2
new file mode 100644
index 0000000..b60aaef
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/templates/before.rules.j2
@@ -0,0 +1,101 @@
+#
+# rules.before
+#
+# Rules that should be run before the ufw command line added rules. Custom
+# rules should be added to one of these chains:
+#   ufw-before-input
+#   ufw-before-output
+#   ufw-before-forward
+#
+
+# nat Table rules
+*nat
+:POSTROUTING ACCEPT [0:0]
+
+# Forward traffic from eth1 through eth0.
+-A POSTROUTING -o eth0 -j MASQUERADE
+
+# Set up NAT for CDN services
+-A POSTROUTING -o eth2 -j MASQUERADE
+
+# DNS safe browsing
+{% if safe_browsing %}
+{% for mac in safe_browsing %}
+-A PREROUTING -i eth1 -m mac --mac-source {{ mac }} -p udp --dport 53 -j REDIRECT --to-port 5353
+-A PREROUTING -i eth1 -m mac --mac-source {{ mac }} -p tcp --dport 53 -j REDIRECT --to-port 5353
+{% endfor %}
+{% endif %}
+
+{% if status != "enabled" %}
+-A PREROUTING -i eth1 -p tcp --dport 80 -j REDIRECT --to-port 8000
+{% endif %}
+
+# don't delete the 'COMMIT' line or these nat table rules won't be processed
+COMMIT
+
+# Don't delete these required lines, otherwise there will be errors
+*filter
+:ufw-before-input - [0:0]
+:ufw-before-output - [0:0]
+:ufw-before-forward - [0:0]
+:ufw-not-local - [0:0]
+# End required lines
+
+# allow all on loopback
+-A ufw-before-input -i lo -j ACCEPT
+-A ufw-before-output -o lo -j ACCEPT
+
+# quickly process packets for which we already have a connection
+-A ufw-before-input -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
+-A ufw-before-output -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
+-A ufw-before-forward -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
+
+# drop INVALID packets (logs these in loglevel medium and higher)
+-A ufw-before-input -m conntrack --ctstate INVALID -j ufw-logging-deny
+-A ufw-before-input -m conntrack --ctstate INVALID -j DROP
+
+# ok icmp codes for INPUT
+-A ufw-before-input -p icmp --icmp-type destination-unreachable -j ACCEPT
+-A ufw-before-input -p icmp --icmp-type source-quench -j ACCEPT
+-A ufw-before-input -p icmp --icmp-type time-exceeded -j ACCEPT
+-A ufw-before-input -p icmp --icmp-type parameter-problem -j ACCEPT
+-A ufw-before-input -p icmp --icmp-type echo-request -j ACCEPT
+
+# ok icmp code for FORWARD
+-A ufw-before-forward -p icmp --icmp-type destination-unreachable -j ACCEPT
+-A ufw-before-forward -p icmp --icmp-type source-quench -j ACCEPT
+-A ufw-before-forward -p icmp --icmp-type time-exceeded -j ACCEPT
+-A ufw-before-forward -p icmp --icmp-type parameter-problem -j ACCEPT
+-A ufw-before-forward -p icmp --icmp-type echo-request -j ACCEPT
+
+# allow dhcp client to work
+-A ufw-before-input -p udp --sport 67 --dport 68 -j ACCEPT
+
+#
+# ufw-not-local
+#
+-A ufw-before-input -j ufw-not-local
+
+# if LOCAL, RETURN
+-A ufw-not-local -m addrtype --dst-type LOCAL -j RETURN
+
+# if MULTICAST, RETURN
+-A ufw-not-local -m addrtype --dst-type MULTICAST -j RETURN
+
+# if BROADCAST, RETURN
+-A ufw-not-local -m addrtype --dst-type BROADCAST -j RETURN
+
+# all other non-local packets are dropped
+-A ufw-not-local -m limit --limit 3/min --limit-burst 10 -j ufw-logging-deny
+-A ufw-not-local -j DROP
+
+# allow MULTICAST mDNS for service discovery (be sure the MULTICAST line above
+# is uncommented)
+-A ufw-before-input -p udp -d 224.0.0.251 --dport 5353 -j ACCEPT
+
+# allow MULTICAST UPnP for service discovery (be sure the MULTICAST line above
+# is uncommented)
+-A ufw-before-input -p udp -d 239.255.255.250 --dport 1900 -j ACCEPT
+
+# don't delete the 'COMMIT' line or these rules won't be processed
+COMMIT
diff --git a/xos/onboard/vsg/synchronizer/templates/bwlimit.sh.j2 b/xos/onboard/vsg/synchronizer/templates/bwlimit.sh.j2
new file mode 100644
index 0000000..b267ada
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/templates/bwlimit.sh.j2
@@ -0,0 +1,131 @@
+#!/bin/bash
+#  tc uses the following units when passed as a parameter.
+#  kbps: Kilobytes per second
+#  mbps: Megabytes per second
+#  kbit: Kilobits per second
+#  mbit: Megabits per second
+#  bps: Bytes per second
+#       Amounts of data can be specified in:
+#       kb or k: Kilobytes
+#       mb or m: Megabytes
+#       mbit: Megabits
+#       kbit: Kilobits
+#  To get the byte figure from bits, divide the number by 8 bit
+#
+
+TC=/sbin/tc
+
+WAN=eth0             # External (WAN side) interface
+LAN=eth1             # Customer (LAN side) interface
+
+MAXRATE=10gbit       # Maximum upload/download rate
+DNLD={{ downlink_speed }}          # DOWNLOAD Limit
+UPLD={{ uplink_speed }}            # UPLOAD Limit
+
+[ "$DNLD" == "None" ] && DNLD=$MAXRATE
+[ "$UPLD" == "None" ] && UPLD=$MAXRATE
+
+start() {
+
+# We'll use Hierarchical Token Bucket (HTB) to shape bandwidth.
+# For detailed configuration options, please consult Linux man
+# page.
+
+    #
+    # WAN side (upload limiting)
+    #
+    $TC qdisc add dev $WAN root handle 1: htb default 30
+    $TC class add dev $WAN parent 1: classid 1:1 htb rate $MAXRATE burst 15k
+
+    # The default class
+    $TC class add dev $WAN parent 1:1 classid 1:30 htb rate 1kbit ceil $UPLD burst 15k
+    $TC qdisc add dev $WAN parent 1:30 handle 30: sfq perturb 10
+
+    # This class is exempt from the upload limit
+    $TC class add dev $WAN parent 1:1 classid 1:50 htb rate 1kbit ceil $MAXRATE burst 15k
+    $TC qdisc add dev $WAN parent 1:50 handle 50: sfq perturb 10
+
+    #
+    # LAN side (download limiting)
+    #
+    $TC qdisc add dev $LAN root handle 1: htb default 30
+    $TC class add dev $LAN parent 1: classid 1:1 htb rate $MAXRATE burst 15k
+
+    # The default class
+    $TC class add dev $LAN parent 1:1 classid 1:30 htb rate 1kbit ceil $DNLD burst 15k
+    $TC qdisc add dev $LAN parent 1:30 handle 30: sfq perturb 10
+
+    # This class is exempt from the download limit
+    $TC class add dev $LAN parent 1:1 classid 1:50 htb rate 1kbit ceil $MAXRATE burst 15k
+    $TC qdisc add dev $LAN parent 1:50 handle 50: sfq perturb 10
+
+}
+
+stop() {
+
+# Stop the bandwidth shaping.
+    $TC qdisc del dev $WAN root
+    $TC qdisc del dev $LAN root
+
+}
+
+restart() {
+
+# Self-explanatory.
+    stop
+    sleep 1
+    start
+
+}
+
+show() {
+
+# Display status of traffic control status.
+    echo "Download ($LAN):"
+    $TC -s class show dev $LAN
+
+    echo ""
+    echo "Upload ($WAN):"
+    $TC -s class show dev $WAN
+
+}
+
+case "$1" in
+
+  start)
+
+    echo -n "Starting bandwidth shaping: "
+    start
+    echo "done"
+    ;;
+
+  stop)
+
+    echo -n "Stopping bandwidth shaping: "
+    stop
+    echo "done"
+    ;;
+
+  restart)
+
+    echo -n "Restarting bandwidth shaping: "
+    restart
+    echo "done"
+    ;;
+
+  show)
+
+    echo "Bandwidth shaping status:"
+    show
+    echo ""
+    ;;
+
+  *)
+
+    pwd=$(pwd)
+    echo "Usage: tc.bash {start|stop|restart|show}"
+    ;;
+
+esac
+
+exit 0
diff --git a/xos/onboard/vsg/synchronizer/templates/dnsmasq_safe_servers.j2 b/xos/onboard/vsg/synchronizer/templates/dnsmasq_safe_servers.j2
new file mode 100644
index 0000000..0b3c807
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/templates/dnsmasq_safe_servers.j2
@@ -0,0 +1,16 @@
+# This file autogenerated by vCPE observer
+# It contains a list of DNS servers for dnsmasq to use.
+no-resolv
+
+{% if cdn_enable %}
+{% if cdn_prefixes %}
+# CDN
+{% for prefix in cdn_prefixes %}
+server=/{{ prefix }}/{{ dnsdemux_ip }}
+{% endfor %}
+{% endif %}
+{% endif %}
+
+# use OpenDNS service
+server=208.67.222.123
+server=208.67.220.123
diff --git a/xos/onboard/vsg/synchronizer/templates/dnsmasq_servers.j2 b/xos/onboard/vsg/synchronizer/templates/dnsmasq_servers.j2
new file mode 100644
index 0000000..7ecb319
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/templates/dnsmasq_servers.j2
@@ -0,0 +1,26 @@
+# This file autogenerated by vCPE observer
+# It contains a list of DNS servers for dnsmasq to use.
+no-resolv
+
+{% if cdn_enable %}
+{% if cdn_prefixes %}
+# CDN
+{% for prefix in cdn_prefixes %}
+server=/{{ prefix }}/{{ dnsdemux_ip }}
+{% endfor %}
+{% endif %}
+{% endif %}
+
+{% if url_filter_kind=="answerx" %}
+cache-size=0
+add-mac
+{% endif %}
+
+# temporary for ONS demo
+address=/z.cdn.turner.com/207.141.192.134
+
+# use google's DNS service
+{% for dns_server in dns_servers %}
+server={{ dns_server }}
+{% endfor %}
+
diff --git a/xos/onboard/vsg/synchronizer/templates/firewall_sample.j2 b/xos/onboard/vsg/synchronizer/templates/firewall_sample.j2
new file mode 100644
index 0000000..ce85e68
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/templates/firewall_sample.j2
@@ -0,0 +1,5 @@
+firewall_enable = {{ firewall_enable }}
+
+{% for firewall_rule in firewall_rules %}
+{{ firewall_rule }}
+{% endfor %}
diff --git a/xos/onboard/vsg/synchronizer/templates/message.html.j2 b/xos/onboard/vsg/synchronizer/templates/message.html.j2
new file mode 100644
index 0000000..eb4497a
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/templates/message.html.j2
@@ -0,0 +1,111 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8">
+  <title>Service Suspended</title>
+  <style>
+    
+    .row {
+      width: 100%;
+    }
+
+    .col-sm-offset-2 {
+      margin-left: 16.66666667%;
+    }
+
+    .col-sm-8 {
+      width: 66.66666667%;
+    }
+
+    .alert-danger {
+        color: #a94442;
+        background-color: #f2dede;
+        border-color: #a94442;
+    }
+    .alert {
+        padding: 15px;
+        margin-bottom: 20px;
+        border: 1px solid transparent;
+        border-radius: 4px;
+    }
+
+    body {
+      background-size: cover;
+      background-color: #00BFEC;
+      font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
+      font-size: 18px;
+      line-height: 1.42857143;
+    }
+
+    .vertical-center {
+      min-height: 100%;  /* Fallback for browsers do NOT support vh unit */
+      min-height: 100vh; /* These two lines are counted as one :-)       */
+
+      display: flex;
+      align-items: center;
+    }
+
+    .jumbotron {
+      padding: 60px;
+      border-radius: 6px;
+      background-color: #eee;
+      box-shadow: 4px 4px 18px black;
+    }
+
+    .cord-logo-title{
+      font-size: 150px;
+      display: inline-block;
+      color: #007EC4;
+    }
+
+    path {
+      fill: #B2181E;
+    }
+
+    #cord-logo {
+      transform: scale(1.3)
+    }
+
+    @media only screen 
+    and (min-device-width : 768px) 
+    and (max-device-width : 1024px)  {
+      #cord-logo {
+        transform: scale(1.2)
+      }
+      .cord-logo-title{
+        font-size: 100px;
+      }
+    }
+  </style>
+</head>
+<body>
+  
+  <div class="container vertical-center">
+    <div class="row">
+      <div class="col-sm-8 col-sm-offset-2">
+        <div class="jumbotron">
+          <div class="cord-logo-title">
+            <svg height="150" width="150">
+              <path id="cord-logo" d="M92.5,62.3l-33,33,2.5,2.5c4.1,4.1,7.4,3.6,11.2-.1L95.9,75l-4.5-4.5,4.7-4.7-3.6-3.6Zm2.6,7L98.4,66l3.3,3.3-3.3,3.3-3.3-3.3ZM94.5,60l4.9-4.9,4.9,4.9-4.9,4.9ZM36.2,36.1L18.6,53.8c-7.8,7.8-5.8,17.4-2.4,22l-2.2-2.2c-10.6-10.6-11.2-20,0-31.2L28.2,28.1L31.3,25l8,8-3.1,3.1ZM55.5,55.4l3.6-3.6L66.9,44l-8-8l-2.5,2.5-5.2,5.2l-3.6,3.6L33.2,61.6C22,72.7,22.5,82.2,33.2,92.8L35.4,95c-3.4-4.5-5.4-14.1,2.4-22L55.5,55.4ZM50.7,21.7l-8-8L35,21.2l8,8,7.6-7.6ZM62.8,9.6L55.4,17l-8-8,7.4-7.4,8,8Zm0.7,18.3-7.6,7.6-8-8,7.6-7.6,8,8Zm26.1-6.6-8.1,8.1-8-8,8.1-8.1,8,8ZM79.3,31.5l-7.4,7.4-8-8,7.4-7.4,8,8ZM45.7,45.6L54.3,37l-8-8-8.6,8.6L23.4,51.8C12.2,63,12.8,72.4,23.4,83l2.2,2.2c-3.4-4.5-5.4-14.1,2.4-22ZM34.9,80.7l20.6,20.5c2,2,4.6,4.1,7.9,3.2-2.9,2.9-8.9,1.7-11.9-1.3L35.1,86.8,35,86.6H34.9l-0.8-.8a15,15,0,0,1,.1-1.9,14.7,14.7,0,0,1,.7-3.2Zm-0.6,7.4a21.3,21.3,0,0,0,5.9,11.7l5.7,5.7c3,3,9,4.1,11.9,1.3-3.3.9-5.9-1.2-7.9-3.2L34.3,88.1Zm3.5-12.4a16.6,16.6,0,0,0-2.3,3.6L57,100.8c3,3,9,4.1,11.9,1.3-3.3.9-5.9-1.2-7.9-3.2Z" />
+              Sorry, your browser does not support inline SVG.
+            </svg>
+            CORD
+          </div>
+          <div class="alert alert-danger">
+            {% if status == "delinquent" %}
+            Your account is delinquent.  Please visit the customer portal to pay your bill.
+            {% elif status == "copyrightviolation" %}
+            Someone in your home has been illegally downloading copyrighted material.
+            Please visit the customer portal and perform the Copyright Training course.
+            {% else %}
+            Your service has been suspended.  Please visit the customer portal to resume.
+            {% endif %}
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+
+
+</body>
+</html>
\ No newline at end of file
diff --git a/xos/onboard/vsg/synchronizer/templates/rc.local.j2 b/xos/onboard/vsg/synchronizer/templates/rc.local.j2
new file mode 100755
index 0000000..4226a48
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/templates/rc.local.j2
@@ -0,0 +1,28 @@
+#!/bin/sh -e
+#
+# rc.local
+#
+# This script is executed at the end of each multiuser runlevel.
+# Make sure that the script will "exit 0" on success or any other
+# value on error.
+#
+# In order to enable or disable this script just change the execution
+# bits.
+#
+# By default this script does nothing.
+
+ufw enable
+ufw allow bootps
+ufw allow from 192.168.0.0/24
+{% if status == "enabled" %}
+ufw route allow in on eth1 out on eth0
+ufw route allow in on eth1 out on eth2
+{% else %}
+ufw route deny in on eth1 out on eth0
+ufw route deny in on eth1 out on eth2
+{% endif %}
+
+BWLIMIT=/usr/local/sbin/bwlimit.sh
+[ -e $BWLIMIT ] && $BWLIMIT restart || true
+
+exit 0
diff --git a/xos/onboard/vsg/synchronizer/templates/start-vcpe-vtn.sh.j2 b/xos/onboard/vsg/synchronizer/templates/start-vcpe-vtn.sh.j2
new file mode 100644
index 0000000..dfdce0a
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/templates/start-vcpe-vtn.sh.j2
@@ -0,0 +1,49 @@
+#!/bin/bash
+
+function mac_to_iface {
+    MAC=$1
+    ifconfig|grep $MAC| awk '{print $1}'|grep -v '\.'
+}
+
+iptables -L > /dev/null
+ip6tables -L > /dev/null
+
+STAG={{ s_tags[0] }}
+CTAG={{ c_tags[0] }}
+VCPE=vcpe-$STAG-$CTAG
+
+docker inspect $VCPE > /dev/null 2>&1
+if [ "$?" == 1 ]
+then
+    docker pull andybavier/docker-vcpe
+    docker run -d --name=$VCPE --privileged=true --net=none \
+    -v /var/container_volumes/$VCPE/mount:/mount:ro \
+    -v /var/container_volumes/$VCPE/etc/dnsmasq.d:/etc/dnsmasq.d:ro \
+    -v /var/container_volumes/$VCPE/etc/service/message:/etc/service/message \
+    -v /var/container_volumes/$VCPE/usr/local/sbin:/usr/local/sbin:ro \
+    andybavier/docker-vcpe
+else
+    docker start $VCPE
+fi
+
+# Set up networking via pipework
+WAN_IFACE=br-wan
+docker exec $VCPE ifconfig eth0 >> /dev/null || pipework $WAN_IFACE -i eth0 $VCPE {{ wan_container_ip }}/{{ wan_container_netbits }}@{{ wan_container_gateway_ip }} {{ wan_container_mac }}
+
+LAN_IFACE=eth0
+ifconfig $LAN_IFACE >> /dev/null
+if [ "$?" == 0 ]
+then
+    ifconfig $LAN_IFACE.$STAG >> /dev/null || ip link add link $LAN_IFACE name $LAN_IFACE.$STAG type vlan id $STAG
+    ifconfig $LAN_IFACE.$STAG up
+    docker exec $VCPE ifconfig eth1 >> /dev/null || pipework $LAN_IFACE.$STAG -i eth1 $VCPE 192.168.0.1/24 @$CTAG
+fi
+
+#HPC_IFACE=$( mac_to_iface {{ hpc_client_mac }} )
+#docker exec $VCPE ifconfig eth2 >> /dev/null || pipework $HPC_IFACE -i eth2 $VCPE {{ hpc_client_ip }}/24
+
+# Make sure VM's eth0 (hpc_client) has no IP address
+#ifconfig $HPC_IFACE 0.0.0.0
+
+# Attach to container
+docker start -a $VCPE
diff --git a/xos/onboard/vsg/synchronizer/templates/start-vcpe.sh.j2 b/xos/onboard/vsg/synchronizer/templates/start-vcpe.sh.j2
new file mode 100755
index 0000000..c4128f3
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/templates/start-vcpe.sh.j2
@@ -0,0 +1,50 @@
+#!/bin/bash
+
+function mac_to_iface {
+    MAC=$1
+    ifconfig|grep $MAC| awk '{print $1}'|grep -v '\.'
+}
+
+iptables -L > /dev/null
+ip6tables -L > /dev/null
+
+STAG={{ s_tags[0] }}
+CTAG={{ c_tags[0] }}
+VCPE=vcpe-$STAG-$CTAG
+
+docker inspect $VCPE > /dev/null 2>&1
+if [ "$?" == 1 ]
+then
+    docker pull andybavier/docker-vcpe
+    docker run -d --name=$VCPE --privileged=true --net=none -v /etc/$VCPE/dnsmasq.d:/etc/dnsmasq.d andybavier/docker-vcpe
+else
+    docker start $VCPE
+fi
+
+# Set up networking via pipework
+WAN_IFACE=$( mac_to_iface {{ wan_mac }} )
+docker exec $VCPE ifconfig eth0 >> /dev/null || pipework $WAN_IFACE -i eth0 $VCPE {{ wan_ip }}/24@{{ wan_next_hop }} {{ wan_container_mac }}
+
+# LAN_IFACE=$( mac_to_iface {{ lan_mac }} )
+# Need to encapsulate VLAN traffic so that Neutron doesn't eat it
+# Assumes that br-lan has been set up appropriately by a previous step
+LAN_IFACE=br-lan
+ifconfig $LAN_IFACE >> /dev/null
+if [ "$?" == 0 ]
+then
+    ifconfig $LAN_IFACE.$STAG >> /dev/null || ip link add link $LAN_IFACE name $LAN_IFACE.$STAG type vlan id $STAG
+    ifconfig $LAN_IFACE.$STAG up
+    docker exec $VCPE ifconfig eth1 >> /dev/null || pipework $LAN_IFACE.$STAG -i eth1 $VCPE 192.168.0.1/24 @$CTAG
+fi
+
+#HPC_IFACE=$( mac_to_iface {{ hpc_client_mac }} )
+#docker exec $VCPE ifconfig eth2 >> /dev/null || pipework $HPC_IFACE -i eth2 $VCPE {{ hpc_client_ip }}/24
+
+# Make sure VM's eth0 (hpc_client) has no IP address
+#ifconfig $HPC_IFACE 0.0.0.0
+
+# Now can start up dnsmasq
+docker exec $VCPE service dnsmasq start
+
+# Attach to container
+docker start -a $VCPE
diff --git a/xos/onboard/vsg/synchronizer/templates/vcpe.conf.j2 b/xos/onboard/vsg/synchronizer/templates/vcpe.conf.j2
new file mode 100644
index 0000000..fa7885e
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/templates/vcpe.conf.j2
@@ -0,0 +1,10 @@
+# Upstart script for vCPE
+description "vCPE container"
+author "andy@onlab.us"
+start on filesystem and started docker
+stop on runlevel [!2345]
+respawn
+
+script
+  /usr/local/sbin/start-vcpe-{{ s_tags[0] }}-{{ c_tags[0] }}.sh
+end script
diff --git a/xos/onboard/vsg/synchronizer/templates/vlan_sample.j2 b/xos/onboard/vsg/synchronizer/templates/vlan_sample.j2
new file mode 100644
index 0000000..b73954b
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/templates/vlan_sample.j2
@@ -0,0 +1,5 @@
+# below is a list of all vlan_ids associated with this vcpe
+
+{% for vlan_id in c_tags %}
+{{ vlan_id }}
+{% endfor %}
diff --git a/xos/onboard/vsg/synchronizer/vcpe-synchronizer.py b/xos/onboard/vsg/synchronizer/vcpe-synchronizer.py
new file mode 100755
index 0000000..84bec4f
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/vcpe-synchronizer.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+# This imports and runs ../../xos-observer.py
+
+import importlib
+import os
+import sys
+observer_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),"../../synchronizers/base")
+sys.path.append(observer_path)
+mod = importlib.import_module("xos-synchronizer")
+mod.main()
diff --git a/xos/onboard/vsg/synchronizer/vcpe_stats_notifier.py b/xos/onboard/vsg/synchronizer/vcpe_stats_notifier.py
new file mode 100644
index 0000000..4d2cc76
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/vcpe_stats_notifier.py
@@ -0,0 +1,344 @@
+import six
+import uuid
+import datetime
+from kombu.connection import BrokerConnection
+from kombu.messaging import Exchange, Queue, Consumer, Producer
+import subprocess
+import re
+import time, threading
+import sys, getopt
+import logging
+import os
+
+
+logfile = "vcpe_stats_notifier.log"
+level=logging.INFO
+logger=logging.getLogger('vcpe_stats_notifier')
+logger.setLevel(level)
+# create formatter
+formatter = logging.Formatter("%(asctime)s;%(levelname)s;%(message)s")
+handler=logging.handlers.RotatingFileHandler(logfile,maxBytes=1000000, backupCount=1)
+# add formatter to handler
+handler.setFormatter(formatter)
+logger.addHandler(handler)
+
+def get_all_docker_containers():
+    p = subprocess.Popen('docker ps --no-trunc', shell=True, stdout=subprocess.PIPE) 
+    firstline = True
+    dockercontainers = {}
+    while True:
+        out = p.stdout.readline()
+        if out == '' and p.poll() != None:
+            break
+        if out != '':
+            if firstline is True:
+                firstline = False
+            else:
+                fields = out.split()
+                container_fields = {}
+                container_fields['id'] = fields[0]
+                dockercontainers[fields[-1]] = container_fields
+    return dockercontainers
+
+def extract_compute_stats_from_all_vcpes(dockercontainers):
+    for k,v in dockercontainers.iteritems():
+        cmd = 'sudo docker stats --no-stream=true ' + v['id'] 
+        p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) 
+        firstline = True
+        while True:
+            out = p.stdout.readline()
+            if out == '' and p.poll() != None:
+                break
+            if out != '':
+                if firstline is True:
+                    firstline = False
+                else:
+                    fields = out.split()
+                    #['CONTAINER_ID', 'CPU%', 'MEMUSE', 'UNITS', '/', 'MEMLIMIT', 'UNITS', 'MEM%', 'NET I/O', 'UNITS', '/', 'NET I/O LIMIT', 'UNITS', 'BLOCK I/O', 'UNITS', '/', 'BLOCK I/O LIMIT', 'UNITS']
+                    v['cpu_util'] = fields[1][:-1]
+                    if fields[6] == 'GB':
+                       v['memory'] = str(float(fields[5]) * 1000)
+                    else:
+                       v['memory'] = fields[5]
+                    if fields[3] == 'GB':
+                       v['memory_usage'] = str(float(fields[2]) * 1000)
+                    else:
+                       v['memory_usage'] = fields[2]
+        v['network_stats'] = []
+        for intf in ['eth0', 'eth1']:
+            cmd = 'sudo docker exec ' + v['id'] + ' ifconfig ' + intf
+            p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
+            out,err = p.communicate()
+            if out:
+                intf_stats = {}
+                m = re.search("RX bytes:(\d+)", str(out))
+                if m:
+                    intf_stats['rx_bytes'] = m.group(1)
+                m = re.search("TX bytes:(\d+)", str(out))
+                if m:
+                    intf_stats['tx_bytes'] = m.group(1)
+                m = re.search("RX packets:(\d+)", str(out))
+                if m:
+                    intf_stats['rx_packets'] = m.group(1)
+                m = re.search("TX packets:(\d+)", str(out))
+                if m:
+                    intf_stats['tx_packets'] = m.group(1)
+                if intf_stats:
+                    intf_stats['intf'] = intf
+                    v['network_stats'].append(intf_stats)
+
+def extract_dns_stats_from_all_vcpes(dockercontainers):
+    for k,v in dockercontainers.iteritems():
+         cmd = 'docker exec ' + v['id'] + ' killall -10 dnsmasq'
+         p = subprocess.Popen (cmd, shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
+         (output, error) = p.communicate()
+         if error:
+             logger.error("killall dnsmasq command failed with error = %s",error)
+             continue
+         cmd = 'docker exec ' + v['id'] + ' tail -7 /var/log/syslog'
+         p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
+         (output, error) = p.communicate()
+         if error:
+             logger.error("tail on dnsmasq log command failed with error = %s",error)
+             continue
+         log_list = output.splitlines()
+         i = 0
+         while i < len(log_list):
+             m = re.search('(?<=:\scache size\s)(\S*)(?=,\s),\s(\S*)(?=/)/(\S*)(?=\scache insertions re-used unexpired cache entries)', log_list[i])
+             if m == None:
+                 i = i+1
+                 continue;
+             v['cache_size'] = m.group(1)
+             v['replaced_unexpired_entries'] = m.group(2)
+             v['total_inserted_entries'] = m.group(3)
+             i = i+1
+             m = re.search('(?<=:\squeries forwarded\s)(\S*)(?=,),\squeries answered locally\s(\S*)(?=$)', log_list[i])
+             v['queries_forwarded'] = m.group(1)
+             v['queries_answered_locally'] = m.group(2)
+             break;
+         i = i+2
+         v['server_stats'] = []
+         while i < len(log_list):
+             m = re.search('(?<=:\sserver\s)(\S*)(?=#)#\d*:\squeries sent\s(\S*)(?=,),\sretried or failed\s(\S*)(?=$)', log_list[i])
+             if m == None:
+                 i = i+1
+                 continue
+             dns_server = {}
+             dns_server['id'] = m.group(1)
+             dns_server['queries_sent'] = m.group(2)
+             dns_server['queries_failed'] = m.group(3)
+             v['server_stats'].append(dns_server)
+             i = i+1
+    return dockercontainers
+
+
+keystone_tenant_id='3a397e70f64e4e40b69b6266c634d9d0'
+keystone_user_id='1e3ce043029547f1a61c1996d1a531a2'
+rabbit_user='openstack'
+rabbit_password='80608318c273f348a7c3'
+rabbit_host='10.11.10.1'
+vcpeservice_rabbit_exchange='vcpeservice'
+cpe_publisher_id='vcpe_publisher'
+
+producer = None
+
+def setup_rabbit_mq_channel():
+     global producer
+     global rabbit_user, rabbit_password, rabbit_host, vcpeservice_rabbit_exchange,cpe_publisher_id
+     vcpeservice_exchange = Exchange(vcpeservice_rabbit_exchange, "topic", durable=False)
+     # connections/channels
+     connection = BrokerConnection(rabbit_host, rabbit_user, rabbit_password)
+     logger.info('Connection to RabbitMQ server successful')
+     channel = connection.channel()
+     # produce
+     producer = Producer(channel, exchange=vcpeservice_exchange, routing_key='notifications.info')
+     p = subprocess.Popen('hostname', shell=True, stdout=subprocess.PIPE)
+     (hostname, error) = p.communicate()
+     cpe_publisher_id = cpe_publisher_id + '_on_' + hostname
+     logger.info('cpe_publisher_id=%s',cpe_publisher_id)
+
+def publish_cpe_stats():
+     global producer
+     global keystone_tenant_id, keystone_user_id, cpe_publisher_id
+
+     logger.debug('publish_cpe_stats invoked')
+
+     dockercontainers = get_all_docker_containers()
+     cpe_container_compute_stats = extract_compute_stats_from_all_vcpes(dockercontainers)
+     cpe_container_dns_stats = extract_dns_stats_from_all_vcpes(dockercontainers)
+
+     for k,v in cpe_container_dns_stats.iteritems():
+          msg = {'event_type': 'vcpe', 
+                 'message_id':six.text_type(uuid.uuid4()),
+                 'publisher_id': cpe_publisher_id,
+                 'timestamp':datetime.datetime.now().isoformat(),
+                 'priority':'INFO',
+                 'payload': {'vcpe_id':k, 
+                             'user_id':keystone_user_id, 
+                             'tenant_id':keystone_tenant_id 
+                            }
+                }
+          producer.publish(msg)
+          logger.debug('Publishing vcpe event: %s', msg)
+
+          compute_payload = {}
+          if 'cpu_util' in v:
+               compute_payload['cpu_util']= v['cpu_util']
+          if 'memory' in v:
+               compute_payload['memory']= v['memory']
+          if 'memory_usage' in v:
+               compute_payload['memory_usage']= v['memory_usage']
+          if ('network_stats' in v) and (v['network_stats']):
+               compute_payload['network_stats']= v['network_stats']
+          if compute_payload:
+               compute_payload['vcpe_id'] = k
+               compute_payload['user_id'] = keystone_user_id
+               compute_payload['tenant_id'] = keystone_tenant_id
+               msg = {'event_type': 'vcpe.compute.stats', 
+                      'message_id':six.text_type(uuid.uuid4()),
+                      'publisher_id': cpe_publisher_id,
+                      'timestamp':datetime.datetime.now().isoformat(),
+                      'priority':'INFO',
+                      'payload': compute_payload 
+                     }
+               producer.publish(msg)
+               logger.debug('Publishing vcpe.dns.cache.size event: %s', msg)
+
+          if 'cache_size' in v:
+               msg = {'event_type': 'vcpe.dns.cache.size', 
+                      'message_id':six.text_type(uuid.uuid4()),
+                      'publisher_id': cpe_publisher_id,
+                      'timestamp':datetime.datetime.now().isoformat(),
+                      'priority':'INFO',
+                      'payload': {'vcpe_id':k, 
+                                  'user_id':keystone_user_id,
+                                  'tenant_id':keystone_tenant_id, 
+                                  'cache_size':v['cache_size'] 
+                                 }
+                     }
+               producer.publish(msg)
+               logger.debug('Publishing vcpe.dns.cache.size event: %s', msg)
+
+          if 'total_inserted_entries' in v:
+               msg = {'event_type': 'vcpe.dns.total_inserted_entries', 
+                      'message_id':six.text_type(uuid.uuid4()),
+                      'publisher_id': cpe_publisher_id,
+                      'timestamp':datetime.datetime.now().isoformat(),
+                      'priority':'INFO',
+                      'payload': {'vcpe_id':k, 
+                                  'user_id':keystone_user_id,
+                                  'tenant_id':keystone_tenant_id, 
+                                  'total_inserted_entries':v['total_inserted_entries'] 
+                                 }
+                     }
+               producer.publish(msg)
+               logger.debug('Publishing vcpe.dns.total_inserted_entries event: %s', msg)
+
+          if 'replaced_unexpired_entries' in v:
+               msg = {'event_type': 'vcpe.dns.replaced_unexpired_entries', 
+                      'message_id':six.text_type(uuid.uuid4()),
+                      'publisher_id': cpe_publisher_id,
+                      'timestamp':datetime.datetime.now().isoformat(),
+                      'priority':'INFO',
+                      'payload': {'vcpe_id':k, 
+                                  'user_id':keystone_user_id,
+                                  'tenant_id':keystone_tenant_id, 
+                                  'replaced_unexpired_entries':v['replaced_unexpired_entries'] 
+                                 }
+                     }
+               producer.publish(msg)
+               logger.debug('Publishing vcpe.dns.replaced_unexpired_entries event: %s', msg)
+
+          if 'queries_forwarded' in v:
+               msg = {'event_type': 'vcpe.dns.queries_forwarded', 
+                      'message_id':six.text_type(uuid.uuid4()),
+                      'publisher_id': cpe_publisher_id,
+                      'timestamp':datetime.datetime.now().isoformat(),
+                      'priority':'INFO',
+                      'payload': {'vcpe_id':k, 
+                                  'user_id':keystone_user_id,
+                                  'tenant_id':keystone_tenant_id, 
+                                  'queries_forwarded':v['queries_forwarded'] 
+                                 }
+                     }
+               producer.publish(msg)
+               logger.debug('Publishing vcpe.dns.queries_forwarded event: %s', msg)
+
+          if 'queries_answered_locally' in v:
+               msg = {'event_type': 'vcpe.dns.queries_answered_locally', 
+                      'message_id':six.text_type(uuid.uuid4()),
+                      'publisher_id': cpe_publisher_id,
+                      'timestamp':datetime.datetime.now().isoformat(),
+                      'priority':'INFO',
+                      'payload': {'vcpe_id':k, 
+                                  'user_id':keystone_user_id,
+                                  'tenant_id':keystone_tenant_id, 
+                                  'queries_answered_locally':v['queries_answered_locally'] 
+                                 }
+                     }
+               producer.publish(msg)
+               logger.debug('Publishing vcpe.dns.queries_answered_locally event: %s', msg)
+
+          if 'server_stats' in v:
+               for server in v['server_stats']:
+                   msg = {'event_type': 'vcpe.dns.server.queries_sent', 
+                          'message_id':six.text_type(uuid.uuid4()),
+                          'publisher_id': cpe_publisher_id,
+                          'timestamp':datetime.datetime.now().isoformat(),
+                          'priority':'INFO',
+                          'payload': {'vcpe_id':k, 
+                                      'user_id':keystone_user_id,
+                                      'tenant_id':keystone_tenant_id, 
+                                      'upstream_server':server['id'],
+                                      'queries_sent':server['queries_sent'] 
+                                     }
+                         }
+                   producer.publish(msg)
+                   logger.debug('Publishing vcpe.dns.server.queries_sent event: %s', msg)
+
+                   msg = {'event_type': 'vcpe.dns.server.queries_failed', 
+                          'message_id':six.text_type(uuid.uuid4()),
+                          'publisher_id': cpe_publisher_id,
+                          'timestamp':datetime.datetime.now().isoformat(),
+                          'priority':'INFO',
+                          'payload': {'vcpe_id':k, 
+                                      'user_id':keystone_user_id,
+                                      'tenant_id':keystone_tenant_id, 
+                                      'upstream_server':server['id'],
+                                      'queries_failed':server['queries_failed'] 
+                                     }
+                         }
+                   producer.publish(msg)
+                   logger.debug('Publishing vcpe.dns.server.queries_failed event: %s', msg)
+
+def periodic_publish():
+     publish_cpe_stats()
+     #Publish every 5minutes
+     threading.Timer(300, periodic_publish).start()
+
+def main(argv):
+   global keystone_tenant_id, keystone_user_id, rabbit_user, rabbit_password, rabbit_host, vcpeservice_rabbit_exchange
+   try:
+      opts, args = getopt.getopt(argv,"",["keystone_tenant_id=","keystone_user_id=","rabbit_host=","rabbit_user=","rabbit_password=","vcpeservice_rabbit_exchange="])
+   except getopt.GetoptError:
+      print 'vcpe_stats_notifier.py keystone_tenant_id=<keystone_tenant_id> keystone_user_id=<keystone_user_id> rabbit_host=<IP addr> rabbit_user=<user> rabbit_password=<password> vcpeservice_rabbit_exchange=<exchange name>'
+      sys.exit(2)
+   for opt, arg in opts:
+      if opt in ("--keystone_tenant_id"):
+         keystone_tenant_id = arg
+      elif opt in ("--keystone_user_id"):
+         keystone_user_id = arg
+      elif opt in ("--rabbit_user"):
+         rabbit_user = arg
+      elif opt in ("--rabbit_password"):
+         rabbit_password = arg
+      elif opt in ("--rabbit_host"):
+         rabbit_host = arg
+      elif opt in ("--vcpeservice_rabbit_exchange"):
+         vcpeservice_rabbit_exchange = arg
+   logger.info("vcpe_stats_notifier args:keystone_tenant_id=%s keystone_user_id=%s rabbit_user=%s rabbit_host=%s vcpeservice_rabbit_exchange=%s",keystone_tenant_id,keystone_user_id,rabbit_user,rabbit_host,vcpeservice_rabbit_exchange)
+   setup_rabbit_mq_channel()
+   periodic_publish()
+
+if __name__ == "__main__":
+   main(sys.argv[1:])
diff --git a/xos/onboard/vsg/synchronizer/vcpe_synchronizer_config b/xos/onboard/vsg/synchronizer/vcpe_synchronizer_config
new file mode 100644
index 0000000..e41dc9a
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/vcpe_synchronizer_config
@@ -0,0 +1,42 @@
+
+[plc]
+name=plc
+deployment=VICCI
+
+[db]
+name=xos
+user=postgres
+password=password
+host=localhost
+port=5432
+
+[api]
+host=128.112.171.237
+port=8000
+ssl_key=None
+ssl_cert=None
+ca_ssl_cert=None
+ratelimit_enabled=0
+omf_enabled=0
+mail_support_address=support@localhost
+nova_enabled=True
+
+[observer]
+name=vcpe
+dependency_graph=/opt/xos/synchronizers/vsg/model-deps
+steps_dir=/opt/xos/synchronizers/vsg/steps
+sys_dir=/opt/xos/synchronizers/vsg/sys
+deleters_dir=/opt/xos/synchronizers/vsg/deleters
+log_file=console
+#/var/log/hpc.log
+driver=None
+pretend=False
+backoff_disabled=True
+save_ansible_output=True
+# set proxy_ssh to false on cloudlab
+proxy_ssh=False
+full_setup=True
+
+[feefie]
+client_id='vicci_dev_central'
+user_id='pl'
diff --git a/xos/onboard/vsg/synchronizer/vtn_vcpe_synchronizer_config b/xos/onboard/vsg/synchronizer/vtn_vcpe_synchronizer_config
new file mode 100644
index 0000000..b43d831
--- /dev/null
+++ b/xos/onboard/vsg/synchronizer/vtn_vcpe_synchronizer_config
@@ -0,0 +1,47 @@
+
+[plc]
+name=plc
+deployment=VICCI
+
+[db]
+name=xos
+user=postgres
+password=password
+host=localhost
+port=5432
+
+[api]
+host=128.112.171.237
+port=8000
+ssl_key=None
+ssl_cert=None
+ca_ssl_cert=None
+ratelimit_enabled=0
+omf_enabled=0
+mail_support_address=support@localhost
+nova_enabled=True
+
+[observer]
+name=vcpe
+dependency_graph=/opt/xos/synchronizers/vsg/model-deps
+steps_dir=/opt/xos/synchronizers/vsg/steps
+sys_dir=/opt/xos/synchronizers/vsg/sys
+deleters_dir=/opt/xos/synchronizers/vsg/deleters
+log_file=console
+#/var/log/hpc.log
+driver=None
+pretend=False
+backoff_disabled=True
+save_ansible_output=True
+# set proxy_ssh to false on cloudlab
+full_setup=True
+proxy_ssh=True
+proxy_ssh_key=/opt/xos/synchronizers/vsg/node_key
+proxy_ssh_user=root
+
+[networking]
+use_vtn=True
+
+[feefie]
+client_id='vicci_dev_central'
+user_id='pl'
diff --git a/xos/onboard/vsg/templates/vcpeadmin.html b/xos/onboard/vsg/templates/vcpeadmin.html
new file mode 100644
index 0000000..334a3e8
--- /dev/null
+++ b/xos/onboard/vsg/templates/vcpeadmin.html
@@ -0,0 +1,9 @@
+<div class = "row text-center">
+    <div class="col-xs-6">
+        <a class="btn btn-primary" href="/admin/cord/vsgtenant/">vSG Tenants</a>
+    </div>
+    <div class="col-xs-6">
+        <a class="btn btn-primary" href="/admin/dashboard/subscribers/">Subscriber View</a>
+    </div>
+</div>
+
diff --git a/xos/onboard/vsg/tosca/resources/vcpeservice.py b/xos/onboard/vsg/tosca/resources/vcpeservice.py
new file mode 100644
index 0000000..956d888
--- /dev/null
+++ b/xos/onboard/vsg/tosca/resources/vcpeservice.py
@@ -0,0 +1,18 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from services.vsg.models import VSGService
+
+from service import XOSService
+
+class XOSVsgService(XOSService):
+    provides = "tosca.nodes.VSGService"
+    xos_model = VSGService
+    copyin_props = ["view_url", "icon_url", "enabled", "published", "public_key",
+                    "private_key_fn", "versionNumber", "backend_network_label",
+                    "dns_servers", "node_label"]
+
diff --git a/xos/onboard/vsg/vsg-onboard.yaml b/xos/onboard/vsg/vsg-onboard.yaml
new file mode 100644
index 0000000..48f6ad4
--- /dev/null
+++ b/xos/onboard/vsg/vsg-onboard.yaml
@@ -0,0 +1,27 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Onboard the exampleservice
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    servicecontroller#vsg:
+      type: tosca.nodes.ServiceController
+      properties:
+          base_url: file:///opt/xos/onboard/vsg/
+          # The following will concatenate with base_url automatically, if
+          # base_url is non-null.
+          models: models.py
+          admin: admin.py
+          admin_template: templates/vcpeadmin.html
+          synchronizer: synchronizer/manifest
+          synchronizer_run: vcpe-synchronizer.py
+          #tosca_custom_types: exampleservice.yaml
+          tosca_resource: tosca/resources/vcpeservice.py
+          rest_service: subdirectory:vsg api/service/vsg/vsgservice.py
+          rest_tenant: subdirectory:cord api/tenant/cord/vsg.py
+          private_key: file:///opt/xos/key_import/vsg_rsa
+          public_key: file:///opt/xos/key_import/vsg_rsa.pub
+
diff --git a/xos/onboard/vtn/admin.py b/xos/onboard/vtn/admin.py
new file mode 100644
index 0000000..464f197
--- /dev/null
+++ b/xos/onboard/vtn/admin.py
@@ -0,0 +1,93 @@
+from django.contrib import admin
+
+from django import forms
+from django.utils.safestring import mark_safe
+from django.contrib.auth.admin import UserAdmin
+from django.contrib.admin.widgets import FilteredSelectMultiple
+from django.contrib.auth.forms import ReadOnlyPasswordHashField
+from django.contrib.auth.signals import user_logged_in
+from django.utils import timezone
+from django.contrib.contenttypes import generic
+from suit.widgets import LinkedSelect
+from core.admin import ServiceAppAdmin,SliceInline,ServiceAttrAsTabInline, ReadOnlyAwareAdmin, XOSTabularInline, ServicePrivilegeInline, TenantRootTenantInline, TenantRootPrivilegeInline
+from core.middleware import get_request
+
+from services.vtn.models import *
+
+from functools import update_wrapper
+from django.contrib.admin.views.main import ChangeList
+from django.core.urlresolvers import reverse
+from django.contrib.admin.utils import quote
+
+class VTNServiceForm(forms.ModelForm):
+    privateGatewayMac = forms.CharField(required=False)
+    localManagementIp = forms.CharField(required=False)
+    ovsdbPort = forms.CharField(required=False)
+    sshPort = forms.CharField(required=False)
+    sshUser = forms.CharField(required=False)
+    sshKeyFile = forms.CharField(required=False)
+    mgmtSubnetBits = forms.CharField(required=False)
+    xosEndpoint = forms.CharField(required=False)
+    xosUser = forms.CharField(required=False)
+    xosPassword = forms.CharField(required=False)
+
+    def __init__(self,*args,**kwargs):
+        super (VTNServiceForm,self ).__init__(*args,**kwargs)
+        if self.instance:
+            self.fields['privateGatewayMac'].initial = self.instance.privateGatewayMac
+            self.fields['localManagementIp'].initial = self.instance.localManagementIp
+            self.fields['ovsdbPort'].initial = self.instance.ovsdbPort
+            self.fields['sshPort'].initial = self.instance.sshPort
+            self.fields['sshUser'].initial = self.instance.sshUser
+            self.fields['sshKeyFile'].initial = self.instance.sshKeyFile
+            self.fields['mgmtSubnetBits'].initial = self.instance.mgmtSubnetBits
+            self.fields['xosEndpoint'].initial = self.instance.xosEndpoint
+            self.fields['xosUser'].initial = self.instance.xosUser
+            self.fields['xosPassword'].initial = self.instance.xosPassword
+
+    def save(self, commit=True):
+        self.instance.privateGatewayMac = self.cleaned_data.get("privateGatewayMac")
+        self.instance.localManagementIp = self.cleaned_data.get("localManagementIp")
+        self.instance.ovsdbPort = self.cleaned_data.get("ovsdbPort")
+        self.instance.sshPort = self.cleaned_data.get("sshPort")
+        self.instance.sshUser = self.cleaned_data.get("sshUser")
+        self.instance.sshKeyFile = self.cleaned_data.get("sshKeyFile")
+        self.instance.mgmtSubnetBits = self.cleaned_data.get("mgmtSubnetBits")
+        self.instance.xosEndpoint = self.cleaned_data.get("xosEndpoint")
+        self.instance.xosUser = self.cleaned_data.get("xosUser")
+        self.instance.xosPassword = self.cleaned_data.get("xosPassword")
+        return super(VTNServiceForm, self).save(commit=commit)
+
+    class Meta:
+        model = VTNService
+
+class VTNServiceAdmin(ReadOnlyAwareAdmin):
+    model = VTNService
+    form = VTNServiceForm
+    verbose_name = "VTN Service"
+    verbose_name_plural = "VTN Service"
+    list_display = ("backend_status_icon", "name", "enabled")
+    list_display_links = ('backend_status_icon', 'name', )
+    fieldsets = [(None, {'fields': ['backend_status_text', 'name','enabled','versionNumber','description',"view_url","icon_url",
+                                    'privateGatewayMac', 'localManagementIp', 'ovsdbPort', 'sshPort', 'sshUser', 'sshKeyFile', 'mgmtSubnetBits', 'xosEndpoint', 'xosUser', 'xosPassword' ], 'classes':['suit-tab suit-tab-general']})]
+    readonly_fields = ('backend_status_text', )
+    inlines = [SliceInline,ServiceAttrAsTabInline,ServicePrivilegeInline]
+
+    extracontext_registered_admins = True
+
+    user_readonly_fields = ["name", "enabled", "versionNumber", "description"]
+
+    suit_form_tabs =(('general', 'VTN Service Details'),
+#        ('administration', 'Administration'),
+        ('slices','Slices'),
+        ('serviceattrs','Additional Attributes'),
+        ('serviceprivileges','Privileges'),
+    )
+
+    suit_form_includes = ( # ('vtnadmin.html', 'top', 'administration'),
+                           ) #('hpctools.html', 'top', 'tools') )
+
+    def queryset(self, request):
+        return VTNService.get_service_objects_by_user(request.user)
+
+admin.site.register(VTNService, VTNServiceAdmin)
diff --git a/xos/onboard/vtn/api/service/vtn.py b/xos/onboard/vtn/api/service/vtn.py
new file mode 100644
index 0000000..6b02616
--- /dev/null
+++ b/xos/onboard/vtn/api/service/vtn.py
@@ -0,0 +1,96 @@
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+from rest_framework import serializers
+from rest_framework import generics
+from rest_framework import viewsets
+from rest_framework.decorators import detail_route, list_route
+from rest_framework.views import APIView
+from core.models import *
+from services.vtn.models import VTNService
+from django.forms import widgets
+from django.conf.urls import patterns, url
+from api.xosapi_helpers import PlusModelSerializer, XOSViewSet, ReadOnlyField
+from django.shortcuts import get_object_or_404
+from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
+from xos.exceptions import *
+import json
+import subprocess
+
+class VTNServiceSerializer(PlusModelSerializer):
+    id = ReadOnlyField()
+
+    privateGatewayMac = serializers.CharField(required=False)
+    localManagementIp = serializers.CharField(required=False)
+    ovsdbPort = serializers.IntegerField(required=False)
+    sshPort = serializers.IntegerField(required=False)
+    sshUser = serializers.CharField(required=False)
+    sshKeyFile = serializers.CharField(required=False)
+    mgmtSubnetBits = serializers.IntegerField(required=False)
+    xosEndpoint = serializers.CharField(required=False)
+    xosUser = serializers.CharField(required=False)
+    xosPassword = serializers.CharField(required=False)
+
+
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    class Meta:
+        model = VTNService
+        fields = ('humanReadableName', 'id', 'privateGatewayMac', 'localManagementIp', 'ovsdbPort', 'sshPort', 'sshUser', 'sshKeyFile',
+                  'mgmtSubnetBits', 'xosEndpoint', 'xosUser', 'xosPassword')
+
+    def getHumanReadableName(self, obj):
+        return obj.__unicode__()
+
+class VTNViewSet(XOSViewSet):
+    base_name = "vtn"
+    method_name = "vtn"
+    method_kind = "viewset"
+
+    # these are just because ViewSet needs some queryset and model, even if we don't use the
+    # default endpoints
+    queryset = VTNService.get_service_objects().all()
+    model = VTNService
+    serializer_class = VTNServiceSerializer
+
+    @classmethod
+    def get_urlpatterns(self, api_path="^"):
+        patterns = []
+
+        patterns.append( self.detail_url("services/$", {"get": "get_services"}, "services") )
+        patterns.append( self.detail_url("services_names/$", {"get": "get_services_names"}, "services") )
+        patterns.append( self.detail_url("services/(?P<service>[a-zA-Z0-9\-_]+)/$", {"get": "get_service"}, "get_service") )
+
+        # Not as RESTful as it could be, but maintain these endpoints for compability
+        patterns.append( self.list_url("services/$", {"get": "get_services"}, "rootvtn_services") )
+        patterns.append( self.list_url("services_names/$", {"get": "get_services_names"}, "rootvtn_services") )
+        patterns.append( self.list_url("services/(?P<service>[a-zA-Z0-9\-_]+)/$", {"get": "get_service"}, "rootvtn_get_service") )
+
+        patterns = patterns + super(VTNViewSet,self).get_urlpatterns(api_path)
+
+        return patterns
+
+    def get_services_names(self, request, pk=None):
+        result = {}
+        for service in Service.objects.all():
+           for id in service.get_vtn_src_names():
+               dependencies = service.get_vtn_dependencies_names()
+               if dependencies:
+                   result[id] = dependencies
+        return Response(result)
+
+    def get_services(self, request, pk=None):
+        result = {}
+        for service in Service.objects.all():
+           for id in service.get_vtn_src_ids():
+               dependencies = service.get_vtn_dependencies_ids()
+               if dependencies:
+                   result[id] = dependencies
+        return Response(result)
+
+    def get_service(self, request, pk=None, service=None):
+        for xos_service in Service.objects.all():
+            if service in xos_service.get_vtn_src_ids():
+                return Response(xos_service.get_vtn_dependencies_ids())
+        return Response([])
+
+
diff --git a/xos/onboard/vtn/models.py b/xos/onboard/vtn/models.py
new file mode 100644
index 0000000..c805f24
--- /dev/null
+++ b/xos/onboard/vtn/models.py
@@ -0,0 +1,45 @@
+from django.db import models
+from core.models import Service, PlCoreBase, Slice, Instance, Tenant, TenantWithContainer, Node, Image, User, Flavor, Subscriber, NetworkParameter, NetworkParameterType, Port, AddressPool
+from core.models.plcorebase import StrippedCharField
+import os
+from django.db import models, transaction
+from django.forms.models import model_to_dict
+from django.db.models import Q
+from operator import itemgetter, attrgetter, methodcaller
+from core.models import Tag
+from core.models.service import LeastLoadedNodeScheduler
+import traceback
+from xos.exceptions import *
+from xos.config import Config
+
+class ConfigurationError(Exception):
+    pass
+
+VTN_KIND = "VTN"
+
+# -------------------------------------------
+# VTN
+# -------------------------------------------
+
+class VTNService(Service):
+    KIND = VTN_KIND
+
+    class Meta:
+        app_label = "vtn"
+        verbose_name = "VTN Service"
+        proxy = True
+
+    simple_attributes = ( ("privateGatewayMac", "00:00:00:00:00:01"),
+                          ("localManagementIp", "172.27.0.1/24"),
+                          ("ovsdbPort", "6641"),
+                          ("sshPort", "22"),
+                          ("sshUser", "root"),
+                          ("sshKeyFile", "/root/node_key") ,
+                          ("mgmtSubnetBits", "24"),
+                          ("xosEndpoint", "http://xos/"),
+                          ("xosUser", "padmin@vicci.org"),
+                          ("xosPassword", "letmein"),
+
+                         )
+
+VTNService.setup_simple_attributes()
diff --git a/xos/onboard/vtn/synchronizer/manifest b/xos/onboard/vtn/synchronizer/manifest
new file mode 100644
index 0000000..dccfcdc
--- /dev/null
+++ b/xos/onboard/vtn/synchronizer/manifest
@@ -0,0 +1,10 @@
+manifest
+vtn-synchronizer.py
+steps/sync_tenant.py
+steps/sync_port_addresses.py
+start.sh
+stop.sh
+model-deps
+supervisor/vtn-observer.conf
+run.sh
+vtn_synchronizer_config
diff --git a/xos/onboard/vtn/synchronizer/model-deps b/xos/onboard/vtn/synchronizer/model-deps
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/xos/onboard/vtn/synchronizer/model-deps
@@ -0,0 +1 @@
+{}
diff --git a/xos/onboard/vtn/synchronizer/run.sh b/xos/onboard/vtn/synchronizer/run.sh
new file mode 100755
index 0000000..000a563
--- /dev/null
+++ b/xos/onboard/vtn/synchronizer/run.sh
@@ -0,0 +1,2 @@
+export XOS_DIR=/opt/xos
+python vtn-synchronizer.py  -C $XOS_DIR/synchronizers/vtn/vtn_synchronizer_config
diff --git a/xos/onboard/vtn/synchronizer/start.sh b/xos/onboard/vtn/synchronizer/start.sh
new file mode 100755
index 0000000..2c43440
--- /dev/null
+++ b/xos/onboard/vtn/synchronizer/start.sh
@@ -0,0 +1,2 @@
+export XOS_DIR=/opt/xos
+nohup python vtn-synchronizer.py  -C $XOS_DIR/synchronizers/vtn/vtn_synchronizer_config > /dev/null 2>&1 &
diff --git a/xos/onboard/vtn/synchronizer/steps/sync_port_addresses.py b/xos/onboard/vtn/synchronizer/steps/sync_port_addresses.py
new file mode 100644
index 0000000..553df6f
--- /dev/null
+++ b/xos/onboard/vtn/synchronizer/steps/sync_port_addresses.py
@@ -0,0 +1,133 @@
+import os
+import requests
+import socket
+import sys
+import base64
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.syncstep import SyncStep
+from core.models import Service, Port, Controller, Tag, Tenant
+from core.models.service import COARSE_KIND
+from services.vsg.models import VSGTenant
+from xos.logger import Logger, logging
+from requests.auth import HTTPBasicAuth
+
+# hpclibrary will be in steps/..
+parentdir = os.path.join(os.path.dirname(__file__),"..")
+sys.path.insert(0,parentdir)
+
+logger = Logger(level=logging.INFO)
+
+# XXX should save and load this
+glo_saved_vtn_maps = []
+
+class SyncPortAddresses(SyncStep):
+    requested_interval = 0 # 3600
+    provides=[Port]
+    observes=Port
+
+    def __init__(self, **args):
+        SyncStep.__init__(self, **args)
+
+    def call(self, **args):
+        global glo_saved_vtn_maps
+
+        logger.info("sync'ing vsg tenant to port addresses")
+
+        # build up a dictionary of port-->[wan_addrs] mappings
+        port_addrs = {}
+        for vsg in VSGTenant.get_tenant_objects().all():
+            if not vsg.instance:
+                logger.info("skipping vsg %s because it has no instance" % vsg)
+
+            wan_ip = vsg.wan_container_ip
+            if not wan_ip:
+                logger.info("skipping vsg %s because it has no wan_container_ip" % vsg)
+
+            wan_mac = vsg.wan_container_mac
+            if not wan_mac:
+                logger.info("skipping vsg %s because it has no wan_container_mac" % vsg)
+
+            lan_network = vsg.get_lan_network(vsg.instance)
+            if not lan_network:
+                logger.info("skipping vsg %s because it has no lan_network" % vsg)
+
+            lan_port = Port.objects.filter(instance = vsg.instance, network=lan_network)
+            if not lan_port:
+                logger.info("skipping vsg %s because it has no lan_port" % vsg)
+            lan_port = lan_port[0]
+
+            if not lan_port.port_id:
+                logger.info("skipping vsg %s because its lan_port has no port_id" % vsg)
+
+            if not (lan_port.pk in port_addrs):
+                port_addrs[lan_port.pk] = []
+            entry = {"mac_address": wan_mac, "ip_address": wan_ip}
+            addr_pairs = port_addrs[lan_port.pk]
+            if not entry in addr_pairs:
+                 addr_pairs.append(entry)
+
+            # now do the VM_WAN_IP from the instance
+            if vsg.instance:
+                wan_vm_ip = vsg.wan_vm_ip
+                wan_vm_mac = vsg.wan_vm_mac
+                entry = {"mac_address": wan_vm_mac, "ip_address": wan_vm_ip}
+                if not entry in addr_pairs:
+                    addr_pairs.append(entry)
+
+        # Get all ports in all controllers
+        ports_by_id = {}
+        for controller in Controller.objects.all():
+            if not controller.admin_tenant:
+                logger.info("controller %s has no admin_tenant" % controller)
+                continue
+            try:
+                driver = self.driver.admin_driver(controller = controller)
+                ports = driver.shell.quantum.list_ports()["ports"]
+            except:
+                logger.log_exc("failed to get ports from controller %s" % controller)
+                continue
+
+            for port in ports:
+                ports_by_id[port["id"]] = port
+
+        for port_pk in port_addrs.keys():
+            port = Port.objects.get(pk=port_pk)
+            addr_pairs = port_addrs[port_pk]
+            neutron_port = ports_by_id.get(port.port_id,None)
+            if not neutron_port:
+                logger.info("failed to get neutron port for port %s" % port)
+                continue
+
+            ips = [x["ip_address"] for x in addr_pairs]
+
+            changed = False
+
+            # delete addresses in neutron that don't exist in XOS
+            aaps = neutron_port.get("allowed_address_pairs", [])
+            for aap in aaps[:]:
+                if not aap["ip_address"] in ips:
+                    logger.info("removing address %s from port %s" % (aap["ip_address"], port))
+                    aaps.remove(aap)
+                    changed = True
+
+            aaps_ips = [x["ip_address"] for x in aaps]
+
+            # add addresses in XOS that don't exist in neutron
+            for addr in addr_pairs:
+                if not addr["ip_address"] in aaps_ips:
+                    logger.info("adding address %s to port %s" % (addr, port))
+                    aaps.append( addr )
+                    aaps_ips.append(addr["ip_address"])
+                    changed = True
+
+            if changed:
+                logger.info("updating port %s" % port)
+                driver.shell.quantum.update_port(port.port_id, {"port": {"allowed_address_pairs": aaps}})
+
+
+
+
+
+
+
diff --git a/xos/onboard/vtn/synchronizer/steps/sync_tenant.py b/xos/onboard/vtn/synchronizer/steps/sync_tenant.py
new file mode 100644
index 0000000..a0e6cdb
--- /dev/null
+++ b/xos/onboard/vtn/synchronizer/steps/sync_tenant.py
@@ -0,0 +1,94 @@
+import os
+import requests
+import socket
+import sys
+import base64
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.syncstep import SyncStep
+from core.models import Service, Tenant
+from core.models.service import COARSE_KIND
+from xos.logger import Logger, logging
+from requests.auth import HTTPBasicAuth
+
+# hpclibrary will be in steps/..
+parentdir = os.path.join(os.path.dirname(__file__),"..")
+sys.path.insert(0,parentdir)
+
+logger = Logger(level=logging.INFO)
+
+# XXX should save and load this
+glo_saved_vtn_maps = []
+
+class SyncTenant(SyncStep):
+    provides=[Tenant]
+    observes=Tenant
+    requested_interval=0
+
+    def __init__(self, **args):
+        SyncStep.__init__(self, **args)
+
+    def get_vtn_onos_service(self):
+#        vtn_tenant = Tenant.objects.filter(name="VTN_ONOS_app")   # XXX fixme - hardcoded
+#        if not vtn_tenant:
+#            raise "No VTN Onos App found"
+#        vtn_tenant = vtn_tenant[0]
+#
+#        vtn_service = vtn_tenant.provider_service
+        vtn_service = Service.objects.filter(name="service_ONOS_VTN")  # XXX fixme - harcoded
+        if not vtn_service:
+            raise "No VTN Onos Service"
+
+        return vtn_service[0]
+
+    def get_vtn_addr(self):
+        vtn_service = self.get_vtn_onos_service()
+
+        if not vtn_service.slices.exists():
+            raise "VTN Service has no slices"
+
+        vtn_slice = vtn_service.slices.all()[0]
+
+        if not vtn_slice.instances.exists():
+            raise "VTN Slice has no instances"
+
+        vtn_instance = vtn_slice.instances.all()[0]
+
+        return vtn_instance.node.name
+
+    def call(self, **args):
+        global glo_saved_vtn_maps
+
+        logger.info("sync'ing vtn services")
+
+        vtn_maps = []
+        for service in Service.objects.all():
+           for id in service.get_vtn_src_ids():
+               dependencies = service.get_vtn_dependencies_ids()
+               if dependencies:
+                   for dependency in dependencies:
+                       vtn_maps.append( (id, dependency) )
+
+        for vtn_map in vtn_maps:
+            if not (vtn_map in glo_saved_vtn_maps):
+                # call vtn rest api to add map
+                url = "http://" + self.get_vtn_addr() + ":8181/onos/cordvtn/service-dependency/%s/%s" % (vtn_map[0], vtn_map[1])
+
+                print "POST %s" % url
+                r = requests.post(url, auth=HTTPBasicAuth('karaf', 'karaf') )    # XXX fixme - hardcoded auth
+                if (r.status_code != 200):
+                    raise Exception("Received error from vtn service (%d)" % r.status_code)
+
+        for vtn_map in glo_saved_vtn_maps:
+            if not vtn_map in vtn_maps:
+                # call vtn rest api to delete map
+                url = "http://" + self.get_vtn_addr() + ":8181/onos/cordvtn/service-dependency/%s/%s" % (vtn_map[0],vtn_map[1])
+
+                print "DELETE %s" % url
+                r = requests.delete(url, auth=HTTPBasicAuth('karaf', 'karaf') )    # XXX fixme - hardcoded auth
+                if (r.status_code != 200):
+                    raise Exception("Received error from vtn service (%d)" % r.status_code)
+
+        glo_saved_vtn_maps = vtn_maps
+        # TODO: save this
+
diff --git a/xos/onboard/vtn/synchronizer/stop.sh b/xos/onboard/vtn/synchronizer/stop.sh
new file mode 100755
index 0000000..7ff2b06
--- /dev/null
+++ b/xos/onboard/vtn/synchronizer/stop.sh
@@ -0,0 +1 @@
+pkill -9 -f vtn-synchronizer.py
diff --git a/xos/onboard/vtn/synchronizer/supervisor/vtn-observer.conf b/xos/onboard/vtn/synchronizer/supervisor/vtn-observer.conf
new file mode 100644
index 0000000..714afa7
--- /dev/null
+++ b/xos/onboard/vtn/synchronizer/supervisor/vtn-observer.conf
@@ -0,0 +1,2 @@
+[program:vtn-observer]
+command=python /opt/xos/observers/vbng/vtn-observer.py -C /opt/xos/observers/vbng/vtn_observer_config
diff --git a/xos/onboard/vtn/synchronizer/vtn-synchronizer.py b/xos/onboard/vtn/synchronizer/vtn-synchronizer.py
new file mode 100755
index 0000000..84bec4f
--- /dev/null
+++ b/xos/onboard/vtn/synchronizer/vtn-synchronizer.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+# This imports and runs ../../xos-observer.py
+
+import importlib
+import os
+import sys
+observer_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),"../../synchronizers/base")
+sys.path.append(observer_path)
+mod = importlib.import_module("xos-synchronizer")
+mod.main()
diff --git a/xos/onboard/vtn/synchronizer/vtn_synchronizer_config b/xos/onboard/vtn/synchronizer/vtn_synchronizer_config
new file mode 100644
index 0000000..d931839
--- /dev/null
+++ b/xos/onboard/vtn/synchronizer/vtn_synchronizer_config
@@ -0,0 +1,44 @@
+
+[plc]
+name=plc
+deployment=VICCI
+
+[db]
+name=xos
+user=postgres
+password=password
+host=localhost
+port=5432
+
+[api]
+host=128.112.171.237
+port=8000
+ssl_key=None
+ssl_cert=None
+ca_ssl_cert=None
+ratelimit_enabled=0
+omf_enabled=0
+mail_support_address=support@localhost
+nova_enabled=True
+
+[observer]
+name=vtn
+dependency_graph=/opt/xos/synchronizers/vtn/model-deps
+steps_dir=/opt/xos/synchronizers/vtn/steps
+sys_dir=/opt/xos/synchronizers/vtn/sys
+deleters_dir=/opt/xos/synchronizers/vtn/deleters
+log_file=console
+#/var/log/hpc.log
+driver=openstack
+pretend=False
+backoff_disabled=True
+
+[nova]
+ca_ssl_cert=/etc/ssl/certs/ca-certificates.crt
+
+[feefie]
+client_id='vicci_dev_central'
+user_id='pl'
+
+[networking]
+use_vtn=True
diff --git a/xos/onboard/vtn/templates/vtnadmin.html b/xos/onboard/vtn/templates/vtnadmin.html
new file mode 100644
index 0000000..a3a2a52
--- /dev/null
+++ b/xos/onboard/vtn/templates/vtnadmin.html
@@ -0,0 +1,5 @@
+<div class = "row text-center">
+    <div class="col-xs-12">
+        <a href="/admin/vtn/vnrtenant/">vTN Tenants</a>
+    </div>
+</div>
diff --git a/xos/onboard/vtn/tosca/resources/vtnservice.py b/xos/onboard/vtn/tosca/resources/vtnservice.py
new file mode 100644
index 0000000..2a5738f
--- /dev/null
+++ b/xos/onboard/vtn/tosca/resources/vtnservice.py
@@ -0,0 +1,15 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from services.vtn.models import VTNService
+
+from service import XOSService
+
+class XOSVTNService(XOSService):
+    provides = "tosca.nodes.VTNService"
+    xos_model = VTNService
+    copyin_props = ["view_url", "icon_url", "enabled", "published", "public_key", "versionNumber", 'privateGatewayMac', 'localManagementIp', 'ovsdbPort', 'sshPort', 'sshUser', 'sshKeyFile', 'mgmtSubnetBits', 'xosEndpoint', 'xosUser', 'xosPassword']
diff --git a/xos/onboard/vtn/vtn-onboard.yaml b/xos/onboard/vtn/vtn-onboard.yaml
new file mode 100644
index 0000000..460af5a
--- /dev/null
+++ b/xos/onboard/vtn/vtn-onboard.yaml
@@ -0,0 +1,25 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Onboard the exampleservice
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    servicecontroller#vtn:
+      type: tosca.nodes.ServiceController
+      properties:
+          base_url: file:///opt/xos/onboard/vtn/
+          # The following will concatenate with base_url automatically, if
+          # base_url is non-null.
+          models: models.py
+          admin: admin.py
+          admin_template: templates/vtnadmin.html
+          synchronizer: synchronizer/manifest
+          synchronizer_run: vtn-synchronizer.py
+          tosca_resource: tosca/resources/vtnservice.py
+          rest_service: api/service/vtn.py
+          #private_key: file:///opt/xos/key_import/vsg_rsa
+          #public_key: file:///opt/xos/key_import/vsg_rsa.pub
+
diff --git a/xos/onboard/vtr/admin.py b/xos/onboard/vtr/admin.py
new file mode 100644
index 0000000..0120e66
--- /dev/null
+++ b/xos/onboard/vtr/admin.py
@@ -0,0 +1,111 @@
+from django.contrib import admin
+
+from django import forms
+from django.utils.safestring import mark_safe
+from django.contrib.auth.admin import UserAdmin
+from django.contrib.admin.widgets import FilteredSelectMultiple
+from django.contrib.auth.forms import ReadOnlyPasswordHashField
+from django.contrib.auth.signals import user_logged_in
+from django.utils import timezone
+from django.contrib.contenttypes import generic
+from suit.widgets import LinkedSelect
+from core.admin import ServiceAppAdmin,SliceInline,ServiceAttrAsTabInline, ReadOnlyAwareAdmin, XOSTabularInline, ServicePrivilegeInline, TenantRootTenantInline, TenantRootPrivilegeInline
+from core.middleware import get_request
+
+from services.vtr.models import *
+from services.volt.models import CordSubscriberRoot
+
+from functools import update_wrapper
+from django.contrib.admin.views.main import ChangeList
+from django.core.urlresolvers import reverse
+from django.contrib.admin.utils import quote
+
+class VTRServiceAdmin(ReadOnlyAwareAdmin):
+    model = VTRService
+    verbose_name = "vTR Service"
+    verbose_name_plural = "vTR Service"
+    list_display = ("backend_status_icon", "name", "enabled")
+    list_display_links = ('backend_status_icon', 'name', )
+    fieldsets = [(None, {'fields': ['backend_status_text', 'name','enabled','versionNumber', 'description',"view_url","icon_url" ], 'classes':['suit-tab suit-tab-general']})]
+    readonly_fields = ('backend_status_text', )
+    inlines = [SliceInline,ServiceAttrAsTabInline,ServicePrivilegeInline]
+
+    extracontext_registered_admins = True
+
+    user_readonly_fields = ["name", "enabled", "versionNumber", "description"]
+
+    suit_form_tabs =(('general', 'vTR Service Details'),
+        ('administration', 'Administration'),
+        ('slices','Slices'),
+        ('serviceattrs','Additional Attributes'),
+        ('serviceprivileges','Privileges'),
+    )
+
+    suit_form_includes = (('vtradmin.html', 'top', 'administration'),
+                           ) #('hpctools.html', 'top', 'tools') )
+
+    def queryset(self, request):
+        return VTRService.get_service_objects_by_user(request.user)
+
+class VTRTenantForm(forms.ModelForm):
+    test = forms.ChoiceField(choices=VTRTenant.TEST_CHOICES, required=True)
+    scope = forms.ChoiceField(choices=VTRTenant.SCOPE_CHOICES, required=True)
+    argument = forms.CharField(required=False)
+    result_code = forms.CharField(required=False)
+    result = forms.CharField(required=False, widget=forms.Textarea(attrs={'rows': 10, 'cols': 80, 'class': 'input-xxlarge'}))
+    target = forms.ModelChoiceField(queryset=CordSubscriberRoot.objects.all())
+
+    def __init__(self,*args,**kwargs):
+        super (VTRTenantForm,self ).__init__(*args,**kwargs)
+        self.fields['provider_service'].queryset = VTRService.get_service_objects().all()
+        if self.instance:
+            # fields for the attributes
+            self.fields['test'].initial = self.instance.test
+            self.fields['argument'].initial = self.instance.argument
+            self.fields['target'].initial = self.instance.target
+            self.fields['scope'].initial = self.instance.scope
+            if (self.instance.enacted is not None) and (self.instance.enacted >= self.instance.updated):
+                self.fields['result'].initial = self.instance.result
+                self.fields['result_code'].initial = self.instance.result_code
+            else:
+                self.fields['result'].initial = ""
+                self.fields['result_code'].initial= ""
+        if (not self.instance) or (not self.instance.pk):
+            # default fields for an 'add' form
+            self.fields['kind'].initial = VTR_KIND
+            self.fields["scope"].initial = VTRTenant.get_default_attribute("scope")
+            if VTRService.get_service_objects().exists():
+               self.fields["provider_service"].initial = VTRService.get_service_objects().all()[0]
+
+    def save(self, commit=True):
+        self.instance.test = self.cleaned_data.get("test")
+        self.instance.argument = self.cleaned_data.get("argument")
+        self.instance.target = self.cleaned_data.get("target")
+        self.instance.result = self.cleaned_data.get("result")
+        self.instance.result_code = self.cleaned_data.get("result_code")
+        self.instance.scope = self.cleaned_data.get("scope")
+        return super(VTRTenantForm, self).save(commit=commit)
+
+    class Meta:
+        model = VTRTenant
+
+class VTRTenantAdmin(ReadOnlyAwareAdmin):
+    list_display = ('backend_status_icon', 'id', 'target', 'test', 'argument' )
+    list_display_links = ('backend_status_icon', 'id')
+    fieldsets = [ (None, {'fields': ['backend_status_text', 'kind', 'provider_service', # 'subscriber_root', 'service_specific_id', 'service_specific_attribute',
+                                     'target', 'scope', 'test', 'argument', 'is_synced', 'result_code', 'result'],
+                          'classes':['suit-tab suit-tab-general']})]
+    readonly_fields = ('backend_status_text', 'service_specific_attribute', 'is_synced')
+    form = VTRTenantForm
+
+    suit_form_tabs = (('general','Details'),)
+
+    def is_synced(self, obj):
+        return (obj.enacted is not None) and (obj.enacted >= obj.updated)
+
+    def queryset(self, request):
+        return VTRTenant.get_tenant_objects_by_user(request.user)
+
+admin.site.register(VTRService, VTRServiceAdmin)
+admin.site.register(VTRTenant, VTRTenantAdmin)
+
diff --git a/xos/onboard/vtr/api/tenant/truckroll.py b/xos/onboard/vtr/api/tenant/truckroll.py
new file mode 100644
index 0000000..cc8d62b
--- /dev/null
+++ b/xos/onboard/vtr/api/tenant/truckroll.py
@@ -0,0 +1,67 @@
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+from rest_framework import serializers
+from rest_framework import generics
+from rest_framework import status
+from core.models import *
+from django.forms import widgets
+from services.vtr.models import VTRTenant, VTRService
+from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
+from api.xosapi_helpers import PlusModelSerializer, XOSViewSet, ReadOnlyField
+
+def get_default_vtr_service():
+    vtr_services = VTRService.get_service_objects().all()
+    if vtr_services:
+        return vtr_services[0]
+    return None
+
+class VTRTenantForAPI(VTRTenant):
+    class Meta:
+        proxy = True
+        app_label = "cord"
+
+class VTRTenantSerializer(PlusModelSerializer):
+        id = ReadOnlyField()
+        target_id = serializers.IntegerField()
+        test = serializers.CharField()
+        scope = serializers.CharField()
+        argument = serializers.CharField(required=False)
+        provider_service = serializers.PrimaryKeyRelatedField(queryset=VTRService.get_service_objects().all(), default=get_default_vtr_service)
+        result = serializers.CharField(required=False)
+        result_code = serializers.CharField(required=False)
+        backend_status = ReadOnlyField()
+
+        humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+        is_synced = serializers.SerializerMethodField("isSynced")
+
+        class Meta:
+            model = VTRTenantForAPI
+            fields = ('humanReadableName', 'id', 'provider_service', 'target_id', 'scope', 'test', 'argument', 'result', 'result_code', 'is_synced', 'backend_status' )
+
+        def getHumanReadableName(self, obj):
+            return obj.__unicode__()
+
+        def isSynced(self, obj):
+            return (obj.enacted is not None) and (obj.enacted >= obj.updated)
+
+class TruckRollViewSet(XOSViewSet):
+    base_name = "truckroll"
+    method_name = "truckroll"
+    method_kind = "viewset"
+    queryset = VTRTenantForAPI.get_tenant_objects().all() # select_related().all()
+    serializer_class = VTRTenantSerializer
+
+    @classmethod
+    def get_urlpatterns(self, api_path="^"):
+        patterns = super(TruckRollViewSet, self).get_urlpatterns(api_path=api_path)
+
+        return patterns
+
+    def list(self, request):
+        queryset = self.filter_queryset(self.get_queryset())
+
+        serializer = self.get_serializer(queryset, many=True)
+
+        return Response(serializer.data)
+
diff --git a/xos/onboard/vtr/models.py b/xos/onboard/vtr/models.py
new file mode 100644
index 0000000..ce2e345
--- /dev/null
+++ b/xos/onboard/vtr/models.py
@@ -0,0 +1,89 @@
+from django.db import models
+from core.models import Service, PlCoreBase, Slice, Instance, Tenant, TenantWithContainer, Node, Image, User, Flavor, Subscriber, NetworkParameter, NetworkParameterType, Port, AddressPool
+from core.models.plcorebase import StrippedCharField
+import os
+from django.db import models, transaction
+from django.forms.models import model_to_dict
+from django.db.models import Q
+from operator import itemgetter, attrgetter, methodcaller
+from core.models import Tag
+from core.models.service import LeastLoadedNodeScheduler
+from services.volt.models import CordSubscriberRoot
+import traceback
+from xos.exceptions import *
+from xos.config import Config
+
+class ConfigurationError(Exception):
+    pass
+
+VTR_KIND = "vTR"
+
+CORD_USE_VTN = getattr(Config(), "networking_use_vtn", False)
+
+# -------------------------------------------
+# VOLT
+# -------------------------------------------
+
+class VTRService(Service):
+    KIND = VTR_KIND
+
+    class Meta:
+        app_label = "vtr"
+        verbose_name = "vTR Service"
+        proxy = True
+
+class VTRTenant(Tenant):
+    class Meta:
+        proxy = True
+
+    KIND = VTR_KIND
+
+    TEST_CHOICES = ( ("ping", "Ping"), ("traceroute", "Trace Route"), ("tcpdump", "Tcp Dump") )
+    SCOPE_CHOICES = ( ("container", "Container"), ("vm", "VM") )
+
+    simple_attributes = ( ("test", None),
+                          ("argument", None),
+                          ("result", None),
+                          ("result_code", None),
+                          ("target_id", None),
+                          ("scope", "container") )
+
+    sync_attributes = ( 'test', 'argument', "scope" )
+
+    def __init__(self, *args, **kwargs):
+        vtr_services = VTRService.get_service_objects().all()
+        if vtr_services:
+            self._meta.get_field("provider_service").default = vtr_services[0].id
+        super(VTRTenant, self).__init__(*args, **kwargs)
+
+    @property
+    def target(self):
+        if getattr(self, "cached_target", None):
+            return self.cached_target
+        target_id=self.target_id
+        if not target_id:
+            return None
+        users=CordSubscriberRoot.objects.filter(id=target_id)
+        if not users:
+            return None
+        user=users[0]
+        self.cached_target = users[0]
+        return user
+
+    @target.setter
+    def target(self, value):
+        if value:
+            value = value.id
+        if (value != self.get_attribute("target_id", None)):
+            self.cached_target=None
+        self.target_id = value
+
+    def save(self, *args, **kwargs):
+        super(VTRTenant, self).save(*args, **kwargs)
+
+    def delete(self, *args, **kwargs):
+        super(VTRTenant, self).delete(*args, **kwargs)
+
+
+VTRTenant.setup_simple_attributes()
+
diff --git a/xos/onboard/vtr/synchronizer/files/run_tcpdump.sh b/xos/onboard/vtr/synchronizer/files/run_tcpdump.sh
new file mode 100644
index 0000000..ed75bf0
--- /dev/null
+++ b/xos/onboard/vtr/synchronizer/files/run_tcpdump.sh
@@ -0,0 +1,9 @@
+#! /bin/bash
+INTERFACE=$1
+tcpdump -n -e -i $INTERFACE -c 100 &
+PID_TCPDUMP=$!
+curl http://www.xosproject.org/ &> /dev/null &
+PID_CURL=$!
+sleep 30s
+kill $PID_TCPDUMP
+kill $PIUD_CURL
diff --git a/xos/onboard/vtr/synchronizer/manifest b/xos/onboard/vtr/synchronizer/manifest
new file mode 100644
index 0000000..61ffb39
--- /dev/null
+++ b/xos/onboard/vtr/synchronizer/manifest
@@ -0,0 +1,10 @@
+manifest
+vtr-synchronizer.py
+vtn_vtr_synchronizer_config
+steps/sync_vtrtenant.py
+steps/sync_vtrtenant.yaml
+vtr_synchronizer_config
+files/run_tcpdump.sh
+run-vtn.sh
+model-deps
+run.sh
diff --git a/xos/onboard/vtr/synchronizer/model-deps b/xos/onboard/vtr/synchronizer/model-deps
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/xos/onboard/vtr/synchronizer/model-deps
@@ -0,0 +1 @@
+{}
diff --git a/xos/onboard/vtr/synchronizer/run-vtn.sh b/xos/onboard/vtr/synchronizer/run-vtn.sh
new file mode 100755
index 0000000..b2f9518
--- /dev/null
+++ b/xos/onboard/vtr/synchronizer/run-vtn.sh
@@ -0,0 +1,4 @@
+export XOS_DIR=/opt/xos
+cp /root/setup/node_key $XOS_DIR/synchronizers/vtr/node_key
+chmod 0600 $XOS_DIR/synchronizers/vtr/node_key
+python vtr-synchronizer.py  -C $XOS_DIR/synchronizers/vtr/vtn_vtr_synchronizer_config
diff --git a/xos/onboard/vtr/synchronizer/run.sh b/xos/onboard/vtr/synchronizer/run.sh
new file mode 100755
index 0000000..388fdf9
--- /dev/null
+++ b/xos/onboard/vtr/synchronizer/run.sh
@@ -0,0 +1,2 @@
+export XOS_DIR=/opt/xos
+python vtr-synchronizer.py  -C $XOS_DIR/synchronizers/vtr/vtr_synchronizer_config
diff --git a/xos/onboard/vtr/synchronizer/steps/sync_vtrtenant.py b/xos/onboard/vtr/synchronizer/steps/sync_vtrtenant.py
new file mode 100644
index 0000000..f0f7ef3
--- /dev/null
+++ b/xos/onboard/vtr/synchronizer/steps/sync_vtrtenant.py
@@ -0,0 +1,147 @@
+import os
+import socket
+import sys
+import base64
+import time
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.syncstep import SyncStep
+from synchronizers.base.ansible import run_template_ssh
+from synchronizers.base.SyncInstanceUsingAnsible import SyncInstanceUsingAnsible
+from core.models import Service, Slice, Tag
+from services.vsg.models import VSGService, VCPE_KIND
+from services.vtr.models import VTRService, VTRTenant
+from services.hpc.models import HpcService, CDNPrefix
+from xos.logger import Logger, logging
+
+# hpclibrary will be in steps/..
+parentdir = os.path.join(os.path.dirname(__file__),"..")
+sys.path.insert(0,parentdir)
+
+logger = Logger(level=logging.INFO)
+
+CORD_USE_VTN = getattr(Config(), "networking_use_vtn", False)
+
+class SyncVTRTenant(SyncInstanceUsingAnsible):
+    provides=[VTRTenant]
+    observes=VTRTenant
+    requested_interval=0
+    template_name = "sync_vtrtenant.yaml"
+    #service_key_name = "/opt/xos/services/vtr/vcpe_private_key"
+
+    def __init__(self, *args, **kwargs):
+        super(SyncVTRTenant, self).__init__(*args, **kwargs)
+
+    def fetch_pending(self, deleted):
+        if (not deleted):
+            objs = VTRTenant.get_tenant_objects().filter(Q(enacted__lt=F('updated')) | Q(enacted=None),Q(lazy_blocked=False))
+        else:
+            objs = VTRTenant.get_deleted_tenant_objects()
+
+        return objs
+
+    def get_vtr_service(self, o):
+        if not o.provider_service:
+            return None
+
+        vtrs = VTRService.get_service_objects().filter(id=o.provider_service.id)
+        if not vtrs:
+            return None
+
+        return vtrs[0]
+
+    def get_vcpe_service(self, o):
+        if o.target:
+            # o.target is a CordSubscriberRoot
+            if o.target.volt and o.target.volt.vcpe:
+                vcpes = VSGService.get_service_objects().filter(id=o.target.volt.vcpe.provider_service.id)
+                if not vcpes:
+                    return None
+                return vcpes[0]
+        return None
+
+    def get_instance(self, o):
+        if o.target and o.target.volt and o.target.volt.vcpe:
+            return o.target.volt.vcpe.instance
+        else:
+            return None
+
+    def get_key_name(self, instance):
+        if instance.slice.service and (instance.slice.service.kind==VCPE_KIND):
+            # We need to use the vsg service's private key. Onboarding won't
+            # by default give us another service's private key, so let's assume
+            # onboarding has been configured to add vsg_rsa to the vtr service.
+            return "/opt/xos/services/vtr/keys/vsg_rsa"
+        else:
+            raise Exception("VTR doesn't know how to get the private key for this instance")
+
+    def get_extra_attributes(self, o):
+        vtr_service = self.get_vtr_service(o)
+        vcpe_service = self.get_vcpe_service(o)
+
+        if not vcpe_service:
+            raise Exception("No vcpeservice")
+
+        instance = self.get_instance(o)
+
+        if not instance:
+            raise Exception("No instance")
+
+        s_tags = []
+        c_tags = []
+        if o.target and o.target.volt:
+            s_tags.append(o.target.volt.s_tag)
+            c_tags.append(o.target.volt.c_tag)
+
+        fields = {"s_tags": s_tags,
+                "c_tags": c_tags,
+                "isolation": instance.isolation,
+                "container_name": "vcpe-%s-%s" % (s_tags[0], c_tags[0]),
+                "dns_servers": [x.strip() for x in vcpe_service.dns_servers.split(",")],
+
+                "result_fn": "%s-vcpe-%s-%s" % (o.test, s_tags[0], c_tags[0]),
+                "resultcode_fn": "code-%s-vcpe-%s-%s" % (o.test, s_tags[0], c_tags[0]) }
+
+        # add in the sync_attributes that come from the vSG object
+        # this will be wan_ip, wan_mac, wan_container_ip, wan_container_mac, ...
+        if o.target and o.target.volt and o.target.volt.vcpe:
+            for attribute_name in o.target.volt.vcpe.sync_attributes:
+                fields[attribute_name] = getattr(o.target.volt.vcpe, attribute_name)
+
+        # add in the sync_attributes that come from the SubscriberRoot object
+        if o.target and hasattr(o.target, "sync_attributes"):
+            for attribute_name in o.target.sync_attributes:
+                fields[attribute_name] = getattr(o.target, attribute_name)
+
+        for attribute_name in o.sync_attributes:
+            fields[attribute_name] = getattr(o,attribute_name)
+
+        return fields
+
+    def sync_fields(self, o, fields):
+        # the super causes the playbook to be run
+
+        super(SyncVTRTenant, self).sync_fields(o, fields)
+
+    def run_playbook(self, o, fields):
+        o.result = ""
+
+        result_fn = os.path.join("/opt/xos/synchronizers/vtr/result", fields["result_fn"])
+        if os.path.exists(result_fn):
+            os.remove(result_fn)
+
+        resultcode_fn = os.path.join("/opt/xos/synchronizers/vtr/result", fields["resultcode_fn"])
+        if os.path.exists(resultcode_fn):
+            os.remove(resultcode_fn)
+
+        super(SyncVTRTenant, self).run_playbook(o, fields)
+
+        if os.path.exists(result_fn):
+            o.result = open(result_fn).read()
+
+        if os.path.exists(resultcode_fn):
+            o.result_code = open(resultcode_fn).read()
+
+
+    def delete_record(self, m):
+        pass
diff --git a/xos/onboard/vtr/synchronizer/steps/sync_vtrtenant.yaml b/xos/onboard/vtr/synchronizer/steps/sync_vtrtenant.yaml
new file mode 100644
index 0000000..35d9032
--- /dev/null
+++ b/xos/onboard/vtr/synchronizer/steps/sync_vtrtenant.yaml
@@ -0,0 +1,123 @@
+---
+- hosts: {{ instance_name }}
+  #gather_facts: False
+  connection: ssh
+  user: ubuntu
+  sudo: yes
+  vars:
+      container_name: {{ container_name }}
+      wan_container_ip: {{ wan_container_ip }}
+      wan_container_netbits: {{ wan_container_netbits }}
+      wan_container_mac: {{ wan_container_mac }}
+      wan_container_gateway_ip: {{ wan_container_gateway_ip }}
+      wan_vm_ip: {{ wan_vm_ip }}
+      wan_vm_mac: {{ wan_vm_mac }}
+
+      scope: {{ scope }}
+      test: {{ test }}
+      argument: {{ argument }}
+      result_fn: {{ result_fn }}
+      resultcode_fn: {{ resultcode_fn }}
+
+
+  tasks:
+  - name: Remove any old result file
+    shell: rm -f /tmp/{{ result_fn }}
+
+  - name: Copy run_tcpdump.sh to VM
+    copy: src=/opt/xos/synchronizers/vtr/files/run_tcpdump.sh dest=/root/run_tcpdump.sh mode=0755
+    when: (test=="tcpdump")
+
+
+# -----------------
+# scope == VM
+# -----------------
+
+  - name: Send the pings from VM
+    shell: ping -c 10 {{ argument }} 2>&1 > /tmp/{{ result_fn }}
+    ignore_errors: yes
+    register: vm_ping_result
+    when: (scope=="vm") and (test=="ping")
+
+  - name: Store VM ping resultcode to file
+    shell: echo "{{ '{{' }} vm_ping_result.rc {{ '}}' }}" > /tmp/{{ resultcode_fn }}
+    when: (scope=="vm") and (test=="ping")
+
+  - name: Install traceroute
+    apt: name=traceroute state=present
+    when: (scope=="vm") and (test=="traceroute")
+
+  - name: Send traceroute from VM
+    shell: traceroute {{ argument }} 2>&1 > /tmp/{{ result_fn }}
+    ignore_errors: yes
+    register: vm_traceroute_result
+    when: (scope=="vm") and (test=="traceroute")
+
+  - name: Store VM traceroute resultcode to file
+    shell: echo "{{ '{{' }} vm_traceroute_result.rc {{ '}}' }}" > /tmp/{{ resultcode_fn }}
+    when: (scope=="vm") and (test=="traceroute")
+
+  - name: Run tcpdump for 30 seconds on VM
+    shell: /root/run_tcpdump.sh {{ argument }} 2>&1 > /tmp/{{ result_fn }}
+    ignore_errors: yes
+    register: vm_tcpdump_result
+    when: (scope=="vm") and (test=="tcpdump")
+
+  - name: Store VM tcpdump resultcode to file
+    shell: echo "{{ '{{' }} vm_tcpdump_result.rc {{ '}}' }}" > /tmp/{{ resultcode_fn }}
+    when: (scope=="vm") and (test=="tcpdump")
+
+# ------------------
+# scope == container
+# ------------------
+
+  - name: Send the pings from Container
+    shell: docker exec {{ container_name }} ping -c 10 {{ argument }} 2>&1 > /tmp/{{ result_fn }}
+    ignore_errors: yes
+    register: ctr_ping_result
+    when: (scope=="container") and (test=="ping")
+
+  - name: Store ctr ping resultcode to file
+    shell: echo "{{ '{{' }} ctr_ping_result.rc {{ '}}' }}" > /tmp/{{ resultcode_fn }}
+    when: (scope=="container") and (test=="ping")
+
+  - name: Install traceroute into Container
+    shell: docker exec {{ container_name }} apt-get -y install traceroute
+    when: (scope=="container") and (test=="traceroute")
+
+  - name: Send traceroute from Container
+    shell: docker exec {{ container_name }} traceroute {{ argument }} 2>&1 > /tmp/{{ result_fn }}
+    ignore_errors: yes
+    register: ctr_traceroute_result
+    when: (scope=="container") and (test=="traceroute")
+
+  - name: Store ctr traceroute resultcode to file
+    shell: echo "{{ '{{' }} ctr_traceroute_result.rc {{ '}}' }}" > /tmp/{{ resultcode_fn }}
+    when: (scope=="container") and (test=="traceroute")
+
+  - name: Copy run_tcpdump.sh to container
+    command: docker cp /root/run_tcpdump.sh {{ container_name }}:/root/run_tcpdump.sh
+    when: (scope=="container") and (test=="tcpdump")
+
+  - name: Run tcpdump for 30 seconds from Container
+    shell: docker exec {{ container_name }} /root/run_tcpdump.sh {{ argument }} 2>&1 > /tmp/{{ result_fn }}
+    ignore_errors: yes
+    register: diagresult
+    when: (scope=="container") and (test=="tcpdump")
+
+  - name: Store ctr tcpdump resultcode to file
+    shell: echo "{{ '{{' }} ctr_tcpdump_result.rc {{ '}}' }}" > /tmp/{{ resultcode_fn }}
+    when: (scope=="container") and (test=="tcpdump")
+
+# ------------------
+# scope == *
+# ------------------
+  - name: Fetch the result
+    fetch: src=/tmp/{{ result_fn }} dest=/opt/xos/synchronizers/vtr/result/{{ result_fn }} flat=yes
+
+  - name: Fetch the resultcode
+    fetch: src=/tmp/{{ resultcode_fn }} dest=/opt/xos/synchronizers/vtr/result/{{ resultcode_fn }} flat=yes
+
+
+
+
diff --git a/xos/onboard/vtr/synchronizer/vtn_vtr_synchronizer_config b/xos/onboard/vtr/synchronizer/vtn_vtr_synchronizer_config
new file mode 100644
index 0000000..2c9140a
--- /dev/null
+++ b/xos/onboard/vtr/synchronizer/vtn_vtr_synchronizer_config
@@ -0,0 +1,47 @@
+
+[plc]
+name=plc
+deployment=VICCI
+
+[db]
+name=xos
+user=postgres
+password=password
+host=localhost
+port=5432
+
+[api]
+host=128.112.171.237
+port=8000
+ssl_key=None
+ssl_cert=None
+ca_ssl_cert=None
+ratelimit_enabled=0
+omf_enabled=0
+mail_support_address=support@localhost
+nova_enabled=True
+
+[observer]
+name=vtr
+dependency_graph=/opt/xos/synchronizers/vtr/model-deps
+steps_dir=/opt/xos/synchronizers/vtr/steps
+sys_dir=/opt/xos/synchronizers/vtr/sys
+deleters_dir=/opt/xos/synchronizers/vtr/deleters
+log_file=console
+#/var/log/hpc.log
+driver=None
+pretend=False
+backoff_disabled=True
+save_ansible_output=True
+# set proxy_ssh to false on cloudlab
+full_setup=True
+proxy_ssh=True
+proxy_ssh_key=/opt/xos/synchronizers/vtr/node_key
+proxy_ssh_user=root
+
+[networking]
+use_vtn=True
+
+[feefie]
+client_id='vicci_dev_central'
+user_id='pl'
diff --git a/xos/onboard/vtr/synchronizer/vtr-synchronizer.py b/xos/onboard/vtr/synchronizer/vtr-synchronizer.py
new file mode 100755
index 0000000..84bec4f
--- /dev/null
+++ b/xos/onboard/vtr/synchronizer/vtr-synchronizer.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+# This imports and runs ../../xos-observer.py
+
+import importlib
+import os
+import sys
+observer_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),"../../synchronizers/base")
+sys.path.append(observer_path)
+mod = importlib.import_module("xos-synchronizer")
+mod.main()
diff --git a/xos/onboard/vtr/synchronizer/vtr_synchronizer_config b/xos/onboard/vtr/synchronizer/vtr_synchronizer_config
new file mode 100644
index 0000000..51bf25a
--- /dev/null
+++ b/xos/onboard/vtr/synchronizer/vtr_synchronizer_config
@@ -0,0 +1,41 @@
+
+[plc]
+name=plc
+deployment=VICCI
+
+[db]
+name=xos
+user=postgres
+password=password
+host=localhost
+port=5432
+
+[api]
+host=128.112.171.237
+port=8000
+ssl_key=None
+ssl_cert=None
+ca_ssl_cert=None
+ratelimit_enabled=0
+omf_enabled=0
+mail_support_address=support@localhost
+nova_enabled=True
+
+[observer]
+name=vtr
+dependency_graph=/opt/xos/synchronizers/vtr/model-deps
+steps_dir=/opt/xos/synchronizers/vtr/steps
+sys_dir=/opt/xos/synchronizers/vtr/sys
+deleters_dir=/opt/xos/synchronizers/vtr/deleters
+log_file=console
+driver=None
+pretend=False
+backoff_disabled=True
+save_ansible_output=True
+# set proxy_ssh to false on cloudlab
+proxy_ssh=False
+full_setup=True
+
+[feefie]
+client_id='vicci_dev_central'
+user_id='pl'
diff --git a/xos/onboard/vtr/templates/vtradmin.html b/xos/onboard/vtr/templates/vtradmin.html
new file mode 100644
index 0000000..e8a33bc
--- /dev/null
+++ b/xos/onboard/vtr/templates/vtradmin.html
@@ -0,0 +1,6 @@
+<div class = "row text-center">
+    <div class="col-xs-12">
+        <a href="/admin/vtr/vtrtenant/">vTR Tenants</a>
+    </div>
+</div>
+
diff --git a/xos/onboard/vtr/vtr-onboard.yaml b/xos/onboard/vtr/vtr-onboard.yaml
new file mode 100644
index 0000000..38dddd1
--- /dev/null
+++ b/xos/onboard/vtr/vtr-onboard.yaml
@@ -0,0 +1,24 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Onboard the exampleservice
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    servicecontroller#vtr:
+      type: tosca.nodes.ServiceController
+      properties:
+          base_url: file:///opt/xos/onboard/vtr/
+          # The following will concatenate with base_url automatically, if
+          # base_url is non-null.
+          models: models.py
+          admin: admin.py
+          admin_template: templates/vtradmin.html
+          synchronizer: synchronizer/manifest
+          synchronizer_run: vtr-synchronizer.py
+          rest_tenant: api/tenant/truckroll.py
+          private_key: file:///opt/xos/key_import/vsg_rsa
+          public_key: file:///opt/xos/key_import/vsg_rsa.pub
+
diff --git a/xos/openstack/__init__.py b/xos/openstack/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xos/openstack/__init__.py
diff --git a/xos/openstack/client.py b/xos/openstack/client.py
new file mode 100644
index 0000000..c500204
--- /dev/null
+++ b/xos/openstack/client.py
@@ -0,0 +1,198 @@
+import urlparse
+try:
+    from keystoneclient.v2_0 import client as keystone_client
+    #from glance import client as glance_client
+    import glanceclient
+    from novaclient.v1_1 import client as nova_client
+    from neutronclient.v2_0 import client as quantum_client
+    has_openstack = True
+except:
+    has_openstack = False
+
+from xos.config import Config
+
+def require_enabled(callable):
+    def wrapper(*args, **kwds):
+        if has_openstack:
+            return callable(*args, **kwds)
+        else:
+            return None
+    return wrapper
+
+def parse_novarc(filename):
+    opts = {}
+    f = open(filename, 'r')
+    for line in f:
+        try:
+            line = line.replace('export', '').strip()
+            parts = line.split('=')
+            if len(parts) > 1:
+                value = parts[1].replace("\'", "")
+                value = value.replace('\"', '')
+                opts[parts[0]] = value
+        except:
+            pass
+    f.close()
+    return opts
+
+class Client:
+    def __init__(self, username=None, password=None, tenant=None, url=None, token=None, endpoint=None, controller=None, cacert=None, admin=True, *args, **kwds):
+       
+        self.has_openstack = has_openstack
+        self.url = controller.auth_url
+        if admin:
+            self.username = controller.admin_user
+            self.password = controller.admin_password
+            self.tenant = controller.admin_tenant
+        else:
+            self.username = None
+            self.password = None
+            self.tenant = None
+
+        if username:
+            self.username = username
+        if password:
+            self.password = password
+        if tenant:
+            self.tenant = tenant
+        if url:
+            self.url = url
+        if token:
+            self.token = token    
+        if endpoint:
+            self.endpoint = endpoint
+
+        self.cacert = cacert
+
+        #if '@' in self.username:
+        #    self.username = self.username[:self.username.index('@')]
+
+class KeystoneClient(Client):
+    def __init__(self, *args, **kwds):
+        Client.__init__(self, *args, **kwds)
+        if has_openstack:
+            self.client = keystone_client.Client(username=self.username,
+                                                 password=self.password,
+                                                 tenant_name=self.tenant,
+                                                 auth_url=self.url
+                                                )
+
+    @require_enabled
+    def connect(self, *args, **kwds):
+        self.__init__(*args, **kwds)
+
+    @require_enabled
+    def __getattr__(self, name):
+        return getattr(self.client, name)
+
+
+class Glance(Client):
+    def __init__(self, *args, **kwds):
+        Client.__init__(self, *args, **kwds)
+        if has_openstack:
+            self.client = glanceclient.get_client(host='0.0.0.0',
+                                                   username=self.username,
+                                                   password=self.password,
+                                                   tenant=self.tenant,
+                                                   auth_url=self.url)
+    @require_enabled
+    def __getattr__(self, name):
+        return getattr(self.client, name)
+
+class GlanceClient(Client):
+    def __init__(self, version, endpoint, token, cacert=None, *args, **kwds):
+        Client.__init__(self, *args, **kwds)
+        if has_openstack:
+            self.client = glanceclient.Client(version, 
+                endpoint=endpoint, 
+                token=token,
+                cacert=cacert
+            )
+
+    @require_enabled
+    def __getattr__(self, name):
+        return getattr(self.client, name)        
+
+class NovaClient(Client):
+    def __init__(self, *args, **kwds):
+        Client.__init__(self, *args, **kwds)
+        if has_openstack:
+            self.client = nova_client.Client(username=self.username,
+                                             api_key=self.password,
+                                             project_id=self.tenant,
+                                             auth_url=self.url,
+                                             region_name='',
+                                             extensions=[],
+                                             service_type='compute',
+                                             service_name='',
+                                             )
+
+    @require_enabled
+    def connect(self, *args, **kwds):
+        self.__init__(*args, **kwds)
+
+    @require_enabled
+    def __getattr__(self, name):
+        return getattr(self.client, name)
+
+class NovaDB(Client):
+    def __init__(self, *args, **kwds):
+        Client.__init__(self, *args, **kwds)
+        if has_openstack:
+            self.ctx = get_admin_context()
+            nova_db_api.FLAGS(default_config_files=['/etc/nova/nova.conf'])
+            self.client = nova_db_api
+
+
+    @require_enabled
+    def connect(self, *args, **kwds):
+        self.__init__(*args, **kwds)
+
+    @require_enabled
+    def __getattr__(self, name):
+        return getattr(self.client, name)
+
+class QuantumClient(Client):
+    def __init__(self, *args, **kwds):
+        Client.__init__(self, *args, **kwds)
+        if has_openstack:
+            self.client = quantum_client.Client(username=self.username,
+                                                password=self.password,
+                                                tenant_name=self.tenant,
+                                                auth_url=self.url,
+                                                ca_cert=self.cacert)
+    @require_enabled
+    def connect(self, *args, **kwds):
+        self.__init__(*args, **kwds)
+
+    @require_enabled
+    def __getattr__(self, name):
+        return getattr(self.client, name)
+
+class OpenStackClient:
+    """
+    A simple native shell to the openstack backend services.
+    This class can receive all nova calls to the underlying testbed
+    """
+
+    def __init__ ( self, *args, **kwds) :
+        # instantiate managers
+        self.keystone = KeystoneClient(*args, **kwds)
+        url_parsed = urlparse.urlparse(self.keystone.url)
+        hostname = url_parsed.netloc.split(':')[0]
+        token = self.keystone.client.tokens.authenticate(username=self.keystone.username, password=self.keystone.password, tenant_name=self.keystone.tenant)
+        glance_endpoint = self.keystone.service_catalog.url_for(service_type='image', endpoint_type='publicURL')
+        
+        self.glanceclient = GlanceClient('1', endpoint=glance_endpoint, token=token.id, **kwds)
+        self.nova = NovaClient(*args, **kwds)
+        # self.nova_db = NovaDB(*args, **kwds)
+        self.quantum = QuantumClient(*args, **kwds)
+    
+
+    @require_enabled
+    def connect(self, *args, **kwds):
+        self.__init__(*args, **kwds)
+
+    @require_enabled
+    def authenticate(self):
+        return self.keystone.authenticate()
diff --git a/xos/openstack/driver.py b/xos/openstack/driver.py
new file mode 100644
index 0000000..15668b9
--- /dev/null
+++ b/xos/openstack/driver.py
@@ -0,0 +1,485 @@
+import commands
+import hashlib
+from xos.config import Config
+from core.models import Controller
+
+try:
+    from openstack.client import OpenStackClient
+    has_openstack = True
+except:
+    has_openstack = False
+
+manager_enabled = Config().api_nova_enabled
+
+class OpenStackDriver:
+
+    def __init__(self, config = None, client=None):
+        if config:
+            self.config = Config(config)
+        else:
+            self.config = Config()
+
+        if client:
+            self.shell = client
+
+        self.enabled = manager_enabled
+        self.has_openstack = has_openstack
+        self.controller = None
+        self.admin_user = None
+
+    def client_driver(self, caller=None, tenant=None, controller=None):
+        if caller:
+            auth = {'username': caller.email,
+                    'password': hashlib.md5(caller.password).hexdigest()[:6],
+                    'tenant': tenant}
+            client = OpenStackClient(controller=controller, cacert=self.config.nova_ca_ssl_cert, **auth)
+        else:
+            admin_driver = self.admin_driver(tenant=tenant, controller=controller)
+            client = OpenStackClient(tenant=tenant, controller=admin_driver.controller)
+
+        driver = OpenStackDriver(client=client)
+        #driver.admin_user = admin_driver.admin_user
+        #driver.controller = admin_driver.controller
+        return driver
+
+    def admin_driver(self, tenant=None, controller=None):
+        if isinstance(controller, int):
+            controller = Controller.objects.get(id=controller.id)
+        if not tenant:
+            tenant = controller.admin_tenant
+        client = OpenStackClient(tenant=tenant, controller=controller, cacert=self.config.nova_ca_ssl_cert)
+        driver = OpenStackDriver(client=client)
+        driver.admin_user = client.keystone.users.find(name=controller.admin_user)
+        driver.controller = controller
+        return driver    
+
+    def create_role(self, name):
+        roles = self.shell.keystone.roles.findall(name=name)
+        roles_title = self.shell.keystone.roles.findall(name=name.title())
+        roles_found = roles + roles_title
+        if not roles_found:
+            role = self.shell.keystone.roles.create(name)
+        else:
+            role = roles_found[0]
+        return role
+
+    def delete_role(self, filter):
+        roles = self.shell.keystone.roles.findall(**filter)
+        for role in roles:
+            self.shell.keystone.roles.delete(role)
+        return 1
+
+    def create_tenant(self, tenant_name, enabled, description):
+        """Create keystone tenant. Suggested fields: name, description, enabled"""  
+        tenants = self.shell.keystone.tenants.findall(name=tenant_name)
+        if not tenants:
+            fields = {'tenant_name': tenant_name, 'enabled': enabled, 
+                      'description': description}  
+            tenant = self.shell.keystone.tenants.create(**fields)
+        else:
+            tenant = tenants[0]
+
+        # always give the admin user the admin role to any tenant created 
+        # by the driver. 
+        self.add_user_role(self.admin_user.id, tenant.id, 'admin')
+        return tenant
+
+    def update_tenant(self, id, **kwds):
+        return self.shell.keystone.tenants.update(id, **kwds)
+
+    def delete_tenant(self, id):
+        ctx = self.shell.nova_db.ctx
+        tenants = self.shell.keystone.tenants.findall(id=id)
+        for tenant in tenants:
+            # nova does not automatically delete the tenant's instances
+            # so we manually delete instances before deleteing the tenant   
+            instances = self.shell.nova_db.instance_get_all_by_filters(ctx,
+                       {'project_id': tenant.id}, 'id', 'asc')
+            client = OpenStackClient(tenant=tenant.name)
+            driver = OpenStackDriver(client=client)
+            for instance in instances:
+                driver.destroy_instance(instance.id)
+            self.shell.keystone.tenants.delete(tenant)
+        return 1
+
+    def create_user(self, name, email, password, enabled):
+        users = self.shell.keystone.users.findall(email=email)
+        if not users:
+            fields = {'name': name, 'email': email, 'password': password,
+                      'enabled': enabled}
+            user = self.shell.keystone.users.create(**fields)
+        else: 
+            user = users[0]
+        return user
+
+    def delete_user(self, id):
+        users = self.shell.keystone.users.findall(id=id)
+        for user in users:
+            # delete users keys
+            keys = self.shell.nova.keypairs.findall()
+            for key in keys:
+                self.shell.nova.keypairs.delete(key)
+            self.shell.keystone.users.delete(user)
+        return 1
+
+    def get_admin_role(self):
+        role = None
+        for admin_role_name in ['admin', 'Admin']:
+            roles = self.shell.keystone.roles.findall(name=admin_role_name)
+            if roles:
+                role = roles[0]
+                break
+        return role 
+
+    def add_user_role(self, kuser_id, tenant_id, role_name):
+        user = self.shell.keystone.users.find(id=kuser_id)
+        tenant = self.shell.keystone.tenants.find(id=tenant_id)
+        # admin role can be lowercase or title. Look for both
+        role = None
+        if role_name.lower() == 'admin':
+            role = self.get_admin_role()
+        else:
+            # look up non admin role or force exception when admin role isnt found 
+            role = self.shell.keystone.roles.find(name=role_name)                   
+
+        role_found = False
+        user_roles = user.list_roles(tenant.id)
+        for user_role in user_roles:
+            if user_role.name == role.name:
+                role_found = True
+        if not role_found:
+            tenant.add_user(user, role)
+
+        return 1
+
+    def delete_user_role(self, kuser_id, tenant_id, role_name):
+        user = self.shell.keystone.users.find(id=kuser_id)
+        tenant = self.shell.keystone.tenants.find(id=tenant_id)
+        # admin role can be lowercase or title. Look for both
+        role = None
+        if role_name.lower() == 'admin':
+            role = self.get_admin_role()
+        else:
+            # look up non admin role or force exception when admin role isnt found
+            role = self.shell.keystone.roles.find(name=role_name)
+
+        role_found = False
+        user_roles = user.list_roles(tenant.id)
+        for user_role in user_roles:
+            if user_role.name == role.name:
+                role_found = True
+        if role_found:
+            tenant.remove_user(user, role)
+
+        return 1 
+
+    def update_user(self, id, fields):
+        if 'password' in fields:
+            self.shell.keystone.users.update_password(id, fields['password'])
+        if 'enabled' in fields:
+            self.shell.keystone.users.update_enabled(id, fields['enabled']) 
+        return 1 
+
+    def create_router(self, name, set_gateway=True):
+        routers = self.shell.quantum.list_routers(name=name)['routers']
+        if routers:
+            router = routers[0]
+        else:
+            router = self.shell.quantum.create_router({'router': {'name': name}})['router']
+        # add router to external network
+        if set_gateway:
+            nets = self.shell.quantum.list_networks()['networks']
+            for net in nets:
+                if net['router:external'] == True: 
+                    self.shell.quantum.add_gateway_router(router['id'],
+                                                          {'network_id': net['id']})
+        
+        return router
+
+    def delete_router(self, id):
+        routers = self.shell.quantum.list_routers(id=id)['routers']
+        for router in routers:
+            self.shell.quantum.delete_router(router['id'])
+            # remove router form external network
+            #nets = self.shell.quantum.list_networks()['networks']
+            #for net in nets:
+            #    if net['router:external'] == True:
+            #        self.shell.quantum.remove_gateway_router(router['id'])
+
+    def add_router_interface(self, router_id, subnet_id):
+        router = self.shell.quantum.show_router(router_id)['router']
+        subnet = self.shell.quantum.show_subnet(subnet_id)['subnet']
+        if router and subnet:
+            self.shell.quantum.add_interface_router(router_id, {'subnet_id': subnet_id})
+
+    def delete_router_interface(self, router_id, subnet_id):
+        router = self.shell.quantum.show_router(router_id)
+        subnet = self.shell.quantum.show_subnet(subnet_id)
+        if router and subnet:
+            self.shell.quantum.remove_interface_router(router_id, {'subnet_id': subnet_id})
+ 
+    def create_network(self, name, shared=False):
+        nets = self.shell.quantum.list_networks(name=name)['networks']
+        if nets: 
+            net = nets[0]
+        else:
+            net = self.shell.quantum.create_network({'network': {'name': name, 'shared': shared}})['network']
+        return net
+ 
+    def delete_network(self, id):
+        nets = self.shell.quantum.list_networks()['networks']
+        for net in nets:
+            if net['id'] == id:
+                # delete_all ports
+                self.delete_network_ports(net['id'])
+                # delete all subnets:
+                for subnet_id in net['subnets']:
+                    self.delete_subnet(subnet_id)
+                self.shell.quantum.delete_network(net['id'])
+        return 1
+
+    def delete_network_ports(self, network_id):
+        ports = self.shell.quantum.list_ports()['ports']
+        for port in ports:
+            if port['network_id'] == network_id:
+                self.shell.quantum.delete_port(port['id'])
+        return 1         
+
+    def delete_subnet_ports(self, subnet_id):
+        ports = self.shell.quantum.list_ports()['ports']
+        for port in ports:
+            delete = False
+            for fixed_ip in port['fixed_ips']:
+                if fixed_ip['subnet_id'] == subnet_id:
+                    delete=True
+                    break
+            if delete:
+                self.shell.quantum.delete_port(port['id'])
+        return 1
+ 
+    def create_subnet(self, name, network_id, cidr_ip, ip_version, start, end):
+        #nets = self.shell.quantum.list_networks(name=network_name)['networks']
+        #if not nets:
+        #    raise Exception, "No such network: %s" % network_name   
+        #net = nets[0]
+
+        subnet = None 
+        subnets = self.shell.quantum.list_subnets()['subnets']
+        for snet in subnets:
+            if snet['cidr'] == cidr_ip and snet['network_id'] == network_id:
+                subnet = snet
+
+        if not subnet:
+            # HACK: Add metadata route -- Neutron does not reliably supply this
+            metadata_ip = cidr_ip.replace("0/24", "3")
+
+            allocation_pools = [{'start': start, 'end': end}]
+            subnet = {'subnet': {'name': name,
+                                 'network_id': network_id,
+                                 'ip_version': ip_version,
+                                 'cidr': cidr_ip,
+                                 #'dns_nameservers': ['8.8.8.8', '8.8.4.4'],
+                                 'host_routes': [{'destination':'169.254.169.254/32','nexthop':metadata_ip}],
+                                 'gateway_ip': None,
+                                 'allocation_pools': allocation_pools}}
+            subnet = self.shell.quantum.create_subnet(subnet)['subnet']
+            # self.add_external_route(subnet)
+
+        return subnet
+
+    def update_subnet(self, id, fields):
+        return self.shell.quantum.update_subnet(id, fields)
+
+    def delete_subnet(self, id):
+        #return self.shell.quantum.delete_subnet(id=id)
+        # inefficient but fault tolerant
+        subnets = self.shell.quantum.list_subnets()['subnets']
+        for subnet in subnets:
+            if subnet['id'] == id:
+                self.delete_subnet_ports(subnet['id'])
+                self.shell.quantum.delete_subnet(id)
+                self.delete_external_route(subnet)
+        return 1
+
+    def get_external_routes(self):
+        status, output = commands.getstatusoutput('route')
+        routes = output.split('\n')[3:]
+        return routes
+
+    def add_external_route(self, subnet, routes=[]):
+        if not routes:
+            routes = self.get_external_routes()
+ 
+        ports = self.shell.quantum.list_ports()['ports']
+
+        gw_ip = subnet['gateway_ip']
+        subnet_id = subnet['id']
+
+        # 1. Find the port associated with the subnet's gateway
+        # 2. Find the router associated with that port
+        # 3. Find the port associated with this router and on the external net
+        # 4. Set up route to the subnet through the port from step 3
+        ip_address = None
+        for port in ports:
+            for fixed_ip in port['fixed_ips']:
+                if fixed_ip['subnet_id'] == subnet_id and fixed_ip['ip_address'] == gw_ip:
+                    gw_port = port
+                    router_id = gw_port['device_id']
+                    router = self.shell.quantum.show_router(router_id)['router']
+                    if router and router.get('external_gateway_info'):
+                        ext_net = router['external_gateway_info']['network_id']
+                        for port in ports:
+                            if port['device_id'] == router_id and port['network_id'] == ext_net:
+                                ip_address = port['fixed_ips'][0]['ip_address']
+
+        if ip_address:
+            # check if external route already exists
+            route_exists = False
+            if routes:
+                for route in routes:
+                    if subnet['cidr'] in route and ip_address in route:
+                        route_exists = True
+            if not route_exists:
+                cmd = "route add -net %s dev br-ex gw %s" % (subnet['cidr'], ip_address)
+                s, o = commands.getstatusoutput(cmd)
+                #print cmd, "\n", s, o
+
+        return 1
+
+    def delete_external_route(self, subnet):
+        ports = self.shell.quantum.list_ports()['ports']
+
+        gw_ip = subnet['gateway_ip']
+        subnet_id = subnet['id']
+
+        # 1. Find the port associated with the subnet's gateway
+        # 2. Find the router associated with that port
+        # 3. Find the port associated with this router and on the external net
+        # 4. Set up route to the subnet through the port from step 3
+        ip_address = None
+        for port in ports:
+            for fixed_ip in port['fixed_ips']:
+                if fixed_ip['subnet_id'] == subnet_id and fixed_ip['ip_address'] == gw_ip:
+                    gw_port = port
+                    router_id = gw_port['device_id']
+                    router = self.shell.quantum.show_router(router_id)['router']
+                    ext_net = router['external_gateway_info']['network_id']
+                    for port in ports:
+                        if port['device_id'] == router_id and port['network_id'] == ext_net:
+                            ip_address = port['fixed_ips'][0]['ip_address']
+
+        if ip_address:
+            cmd = "route delete -net %s" % (subnet['cidr'])
+            commands.getstatusoutput(cmd)
+             
+        return 1
+    
+    def create_keypair(self, name, public_key):
+        keys = self.shell.nova.keypairs.findall(name=name)
+        if keys:
+            key = keys[0]
+            # update key     
+            if key.public_key != public_key:
+                self.delete_keypair(key.id)
+                key = self.shell.nova.keypairs.create(name=name, public_key=public_key)
+        else:
+            key = self.shell.nova.keypairs.create(name=name, public_key=public_key)
+        return key
+
+    def delete_keypair(self, id):
+        keys = self.shell.nova.keypairs.findall(id=id)
+        for key in keys:
+            self.shell.nova.keypairs.delete(key) 
+        return 1
+
+    def get_private_networks(self, tenant=None):
+        if not tenant:
+            tenant = self.shell.nova.tenant
+        tenant = self.shell.keystone.tenants.find(name=tenant)
+        search_opts = {"tenant_id": tenant.id, "shared": False}
+        private_networks = self.shell.quantum.list_networks(**search_opts)
+        return private_networks
+
+    def get_shared_networks(self):
+        search_opts = {"shared": True}
+        shared_networks = self.shell.quantum.list_networks(**search_opts)
+        return shared_networks
+
+    def get_network_subnet(self, network_id):
+        subnet_id = None
+        subnet = None
+        if network_id:
+            os_networks = self.shell.quantum.list_networks(id=network_id)["networks"]
+            if os_networks:
+                os_network = os_networks[0]
+                if os_network['subnets']:
+                    subnet_id = os_network['subnets'][0]
+                    os_subnets = self.shell.quantum.list_subnets(id=subnet_id)['subnets']
+                    if os_subnets:
+                        subnet = os_subnets[0]['cidr']
+
+        return (subnet_id, subnet)
+
+    def spawn_instance(self, name, key_name=None, availability_zone=None, hostname=None, image_id=None, security_group=None, pubkeys=[], nics=None, metadata=None, userdata=None, flavor_name=None):
+        if not flavor_name:
+            flavor_name = self.config.nova_default_flavor
+
+        flavor = self.shell.nova.flavors.find(name=flavor_name)
+
+        if not security_group:
+            security_group = self.config.nova_default_security_group
+
+        files = {}
+        #if pubkeys:
+        #    files["/root/.ssh/authorized_keys"] = "\n".join(pubkeys).encode('base64')
+        hints = {}
+        
+        # determine availability zone and compute host 
+        availability_zone_filter = None
+        if availability_zone is None or not availability_zone:
+            availability_zone_filter = 'nova'
+        else: 
+            availability_zone_filter = availability_zone
+        if hostname:
+            availability_zone_filter += ':%s' % hostname
+
+        server = self.shell.nova.servers.create(
+                                            name=name,
+                                            key_name = key_name,
+                                            flavor=flavor.id,
+                                            image=image_id,
+                                            security_group = security_group,
+                                            #files = files,
+                                            scheduler_hints=hints,
+                                            availability_zone=availability_zone_filter,
+                                            nics=nics,
+                                            networks=nics,
+                                            meta=metadata,
+                                            userdata=userdata)
+        return server
+
+    def destroy_instance(self, id):
+        if (self.shell.nova.tenant=="admin"):
+            # findall() is implemented as a list() followed by a python search of the
+            # list. Since findall() doesn't accept "all_tenants", we do this using
+            # list() ourselves. This allows us to delete an instance as admin.
+            servers = self.shell.nova.servers.list(search_opts={"all_tenants": True})
+        else:
+            servers = self.shell.nova.servers.list()
+        for server in servers:
+            if server.id == id:
+                result=self.shell.nova.servers.delete(server)
+
+    def update_instance_metadata(self, id, metadata):
+        servers = self.shell.nova.servers.findall(id=id)
+        for server in servers:
+            self.shell.nova.servers.set_meta(server, metadata)
+            # note: set_meta() returns a broken Server() object. Don't try to
+            # print it in the shell or it will fail in __repr__.
+
+    def delete_instance_metadata(self, id, metadata):
+        # note: metadata is a dict. Only the keys matter, not the values.
+        servers = self.shell.nova.servers.findall(id=id)
+        for server in servers:
+            self.shell.nova.servers.delete_meta(server, metadata)
+
diff --git a/xos/openstack/get_token.sh b/xos/openstack/get_token.sh
new file mode 100755
index 0000000..93e3cb0
--- /dev/null
+++ b/xos/openstack/get_token.sh
@@ -0,0 +1,23 @@
+curl --insecure -i -X POST $ENDPOINT/auth/tokens \
+  -H "Content-type: application/json" \
+  -d '
+{ "auth": {
+    "identity": {
+      "methods": ["password"],
+      "password": {
+        "user": {
+          "name": "'$USERNAME'",
+          "domain": { "id": "'$DOMAIN'" },
+          "password": "'$PASSWORD'"
+        }
+      }
+    },
+    "scope": {
+      "project": {
+        "name": "'$TENANT'",
+        "domain": { "id": "'$DOMAIN'" }
+      }
+    }
+  }
+}' \
+  | grep X-Subject-Token | awk '{print $2;}'
diff --git a/xos/openstack/instanceagent.py b/xos/openstack/instanceagent.py
new file mode 100644
index 0000000..8e50cf3
--- /dev/null
+++ b/xos/openstack/instanceagent.py
@@ -0,0 +1,39 @@
+import os
+import sys
+#os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
+import time
+from core.models.instance import Instance
+from openstack.manager import OpenStackManager
+
+class InstanceAgent:
+
+    def run(self):
+        manager = OpenStackManager()
+        # exit if openstack is disable or unavailable
+        if not manager.enabled or not manager.has_openstack:
+            sys.exit()
+
+        while True :
+            # fill in null ip addresses 
+            instances = Instance.objects.filter(ip=None)
+            for instance in instances:
+                # update connection
+                manager.client.connect(username=manager.client.keystone.username,
+                               password=manager.client.keystone.password,
+                               tenant=instance.slice.name)  
+                instance.os_manager = manager
+                servers = manager.client.nova.servers.findall(id=instance.instance_id)
+                if not servers:
+                    continue
+                server = servers[0]
+                ips = server.addresses.get(instance.slice.name, [])
+                if not ips:
+                    continue
+                instance.ip = ips[0]['addr']
+                instance.save()
+            time.sleep(7)
+                
+                                        
+if __name__ == '__main__':
+    InstanceAgent().run()
+                 
diff --git a/xos/openstack/manager.py b/xos/openstack/manager.py
new file mode 100644
index 0000000..ba163c7
--- /dev/null
+++ b/xos/openstack/manager.py
@@ -0,0 +1,569 @@
+import os
+#os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
+import string
+import random
+import hashlib
+from datetime import datetime
+from django.utils import timezone
+
+from netaddr import IPAddress, IPNetwork
+from xos import settings
+from django.core import management
+from core.models import *
+from xos.config import Config
+try:
+    from openstack.client import OpenStackClient
+    from openstack.driver import OpenStackDriver
+    has_openstack = True
+except:
+    has_openstack = False
+
+manager_enabled = Config().api_nova_enabled
+
+
+def random_string(size=6):
+    return ''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(size))
+
+def require_enabled(callable):
+    def wrapper(*args, **kwds):
+        if manager_enabled and has_openstack:
+            return callable(*args, **kwds)
+        else:
+            return None
+    return wrapper
+
+
+class OpenStackManager:
+
+    def __init__(self, auth={}, caller=None):
+        self.client = None
+        self.driver = None
+        self.caller = None
+        self.has_openstack = has_openstack       
+        self.enabled = manager_enabled
+
+        if has_openstack and manager_enabled:
+            if auth:
+                try:
+                    self.init_user(auth, caller)
+                except:
+                    # if this fails then it meanse the caller doesn't have a
+                    # role at the slice's tenant. if the caller is an admin
+                    # just use the admin client/manager.
+                    if caller and caller.is_admin: 
+                        self.init_admin()
+                    else: raise
+            else:
+                self.init_admin()
+
+    @require_enabled 
+    def init_caller(self, caller, tenant):
+        auth = {'username': caller.email,
+                'password': hashlib.md5(caller.password).hexdigest()[:6],
+                'tenant': tenant}
+        self.client = OpenStackClient(**auth)
+        self.driver = OpenStackDriver(client=self.client)
+        self.caller = caller                 
+    
+    @require_enabled
+    def init_admin(self, tenant=None):
+        # use the admin credentials 
+        self.client = OpenStackClient(tenant=tenant)
+        self.driver = OpenStackDriver(client=self.client)
+        self.caller = self.driver.admin_user
+        self.caller.kuser_id = self.caller.id 
+
+    @require_enabled
+    def save_role(self, role):
+        if not role.role:
+            keystone_role = self.driver.create_role(role.role_type)
+            role.role = keystone_role.id
+
+    @require_enabled
+    def delete_role(self, role):
+        if role.role:
+            self.driver.delete_role({'id': role.role})
+
+    @require_enabled
+    def save_key(self, key, name):
+        key_fields = {'name': name,
+                      'public_key': key}
+        nova_key = self.driver.create_keypair(**key_fields)
+
+    @require_enabled
+    def delete_key(self, key):
+        if key.nkey_id:
+            self.driver.delete_keypair(key.nkey_id)
+
+    @require_enabled
+    def save_user(self, user):
+        name = user.email[:user.email.find('@')]
+        user_fields = {'name': name,
+                       'email': user.email,
+                       'password': hashlib.md5(user.password).hexdigest()[:6],
+                       'enabled': True}
+        if not user.kuser_id:
+            keystone_user = self.driver.create_user(**user_fields)
+            user.kuser_id = keystone_user.id
+        else:
+            self.driver.update_user(user.kuser_id, user_fields)     
+
+        if user.site:
+            self.driver.add_user_role(user.kuser_id, user.site.tenant_id, 'user')
+            if user.is_admin:
+                self.driver.add_user_role(user.kuser_id, user.site.tenant_id, 'admin')
+            else:
+                # may have admin role so attempt to remove it
+                self.driver.delete_user_role(user.kuser_id, user.site.tenant_id, 'admin')
+
+        if user.public_key:
+            self.init_caller(user, user.site.login_base)
+            self.save_key(user.public_key, user.keyname)
+            self.init_admin()
+
+        user.save()
+        user.enacted = timezone.now()
+        user.save(update_fields=['enacted'])
+  
+    @require_enabled
+    def delete_user(self, user):
+        if user.kuser_id:
+            self.driver.delete_user(user.kuser_id)        
+    
+    @require_enabled
+    def save_site(self, site, add_role=True):
+        if not site.tenant_id:
+            tenant = self.driver.create_tenant(tenant_name=site.login_base,
+                                               description=site.name,
+                                               enabled=site.enabled)
+            site.tenant_id = tenant.id
+            # give caller an admin role at the tenant they've created
+            self.driver.add_user_role(self.caller.kuser_id, tenant.id, 'admin')
+
+        # update the record
+        if site.id and site.tenant_id:
+            self.driver.update_tenant(site.tenant_id,
+                                      description=site.name,
+                                      enabled=site.enabled)
+
+        # commit the updated record
+        site.save()
+        site.enacted = timezone.now()
+        site.save(update_fields=['enacted']) # enusre enacted > updated  
+        
+
+    @require_enabled
+    def delete_site(self, site):
+        if site.tenant_id:
+            self.driver.delete_tenant(site.tenant_id)
+               
+    @require_enabled
+    def save_site_privilege(self, site_priv):
+        if site_priv.user.kuser_id and site_priv.site.tenant_id:
+            self.driver.add_user_role(site_priv.user.kuser_id,
+                                      site_priv.site.tenant_id,
+                                      site_priv.role.role_type)
+        site_priv.enacted = timezone.now()
+        site_priv.save(update_fields=['enacted'])
+
+    
+    @require_enabled
+    def delete_site_privilege(self, site_priv):
+        self.driver.delete_user_role(site_priv.user.kuser_id, 
+                                     site_priv.site.tenant_id, 
+                                     site_priv.role.role_type)
+
+    @require_enabled
+    def save_slice(self, slice):
+        if not slice.tenant_id:
+            nova_fields = {'tenant_name': slice.name,
+                   'description': slice.description,
+                   'enabled': slice.enabled}
+            tenant = self.driver.create_tenant(**nova_fields)
+            slice.tenant_id = tenant.id
+
+            # give caller an admin role at the tenant they've created
+            self.driver.add_user_role(self.caller.kuser_id, tenant.id, 'admin')
+
+            # refresh credentials using this tenant
+            self.driver.shell.connect(username=self.driver.shell.keystone.username,
+                                      password=self.driver.shell.keystone.password,
+                                      tenant=tenant.name)
+
+            # create network
+            network = self.driver.create_network(slice.name)
+            slice.network_id = network['id']
+
+            # create router
+            router = self.driver.create_router(slice.name)
+            slice.router_id = router['id']
+
+            # create subnet
+            next_subnet = self.get_next_subnet()
+            cidr = str(next_subnet.cidr)
+            ip_version = next_subnet.version
+            start = str(next_subnet[2])
+            end = str(next_subnet[-2]) 
+            subnet = self.driver.create_subnet(name=slice.name,
+                                               network_id = network['id'],
+                                               cidr_ip = cidr,
+                                               ip_version = ip_version,
+                                               start = start,
+                                               end = end)
+            slice.subnet_id = subnet['id']
+            # add subnet as interface to slice's router
+            self.driver.add_router_interface(router['id'], subnet['id'])
+            # add external route
+            self.driver.add_external_route(subnet)
+
+
+        if slice.id and slice.tenant_id:
+            self.driver.update_tenant(slice.tenant_id,
+                                      description=slice.description,
+                                      enabled=slice.enabled)   
+
+        slice.save()
+        slice.enacted = timezone.now()
+        slice.save(update_fields=['enacted']) 
+
+    @require_enabled
+    def delete_slice(self, slice):
+        if slice.tenant_id:
+            self._delete_slice(slice.tenant_id, slice.network_id, 
+                               slice.router_id, slice.subnet_id)
+    @require_enabled
+    def _delete_slice(self, tenant_id, network_id, router_id, subnet_id):
+        self.driver.delete_router_interface(slice.router_id, slice.subnet_id)
+        self.driver.delete_subnet(slice.subnet_id)
+        self.driver.delete_router(slice.router_id)
+        self.driver.delete_network(slice.network_id)
+        self.driver.delete_tenant(slice.tenant_id)
+        # delete external route
+        subnet = None
+        subnets = self.driver.shell.quantum.list_subnets()['subnets']
+        for snet in subnets:
+            if snet['id'] == slice.subnet_id:
+                subnet = snet
+        if subnet:
+            self.driver.delete_external_route(subnet) 
+
+    
+    @require_enabled
+    def save_slice_membership(self, slice_memb):
+        if slice_memb.user.kuser_id and slice_memb.slice.tenant_id:
+            self.driver.add_user_role(slice_memb.user.kuser_id,
+                                      slice_memb.slice.tenant_id,
+                                      slice_memb.role.role_type)
+        slice_memb.enacted = timezone.now()
+        slice_memb.save(update_fields=['enacted'])
+
+
+    @require_enabled
+    def delete_slice_membership(self, slice_memb):
+        self.driver.delete_user_role(slice_memb.user.kuser_id,
+                                     slice_memb.slice.tenant_id,
+                                     slice_memb.role.role_type)
+
+
+    @require_enabled
+    def get_next_subnet(self):
+        # limit ourself to 10.0.x.x for now
+        valid_subnet = lambda net: net.startswith('10.0')  
+        subnets = self.driver.shell.quantum.list_subnets()['subnets']
+        ints = [int(IPNetwork(subnet['cidr']).ip) for subnet in subnets \
+                if valid_subnet(subnet['cidr'])] 
+        ints.sort()
+        last_ip = IPAddress(ints[-1])
+        last_network = IPNetwork(str(last_ip) + "/24")
+        next_network = IPNetwork(str(IPAddress(last_network) + last_network.size) + "/24")
+        return next_network
+
+    @require_enabled
+    def save_subnet(self, subnet):    
+        if not subnet.subnet_id:
+            quantum_subnet = self.driver.create_subnet(name= subnet.slice.name,
+                                          network_id=subnet.slice.network_id,
+                                          cidr_ip = subnet.cidr,
+                                          ip_version=subnet.ip_version,
+                                          start = subnet.start,
+                                          end = subnet.end)
+            subnet.subnet_id = quantum_subnet['id']
+            # add subnet as interface to slice's router
+            self.driver.add_router_interface(subnet.slice.router_id, subnet.subnet_id)
+            #add_route = 'route add -net %s dev br-ex gw 10.100.0.5' % self.cidr
+            #commands.getstatusoutput(add_route)
+
+    
+    @require_enabled
+    def delete_subnet(self, subnet):
+        if subnet.subnet_id:
+            self.driver.delete_router_interface(subnet.slice.router_id, subnet.subnet_id)
+            self.driver.delete_subnet(subnet.subnet_id)
+            #del_route = 'route del -net %s' % self.cidr
+            #commands.getstatusoutput(del_route)
+
+    def get_requested_networks(self, slice):
+        network_ids = [x.network_id for x in slice.networks.all()]
+
+        if slice.network_id is not None:
+            network_ids.append(slice.network_id)
+
+        networks = []
+        for network_id in network_ids:
+            networks.append({"net-id": network_id})
+
+        return networks
+
+    @require_enabled
+    def save_instance(self, instance):
+        metadata_update = {}
+        if ("numberCores" in instance.changed_fields):
+            metadata_update["cpu_cores"] = str(instance.numberCores)
+
+        for tag in instance.slice.tags.all():
+            if tag.name.startswith("sysctl-"):
+                metadata_update[tag.name] = tag.value
+
+        if not instance.instance_id:
+            nics = self.get_requested_networks(instance.slice)
+            for nic in nics:
+                # If a network hasn't been instantiated yet, then we'll fail
+                # during slice creation. Defer saving the instance for now.
+                if not nic.get("net-id", None):
+                    instance.save()   # in case it hasn't been saved yet
+                    return
+            slice_memberships = SliceMembership.objects.filter(slice=instance.slice)
+            pubkeys = [sm.user.public_key for sm in slice_memberships if sm.user.public_key]
+            pubkeys.append(instance.creator.public_key)
+            instance = self.driver.spawn_instance(name=instance.name,
+                                   key_name = instance.creator.keyname,
+                                   image_id = instance.image.image_id,
+                                   hostname = instance.node.name,
+                                   pubkeys = pubkeys,
+                                   nics = nics,
+                                   metadata = metadata_update )
+            instance.instance_id = instance.id
+            instance.instance_name = getattr(instance, 'OS-EXT-SRV-ATTR:instance_name')
+        else:
+            if metadata_update:
+                self.driver.update_instance_metadata(instance.instance_id, metadata_update)
+
+        instance.save()
+        instance.enacted = timezone.now()
+        instance.save(update_fields=['enacted'])
+
+    @require_enabled
+    def delete_instance(self, instance):
+        if instance.instance_id:
+            self.driver.destroy_instance(instance.instance_id) 
+    
+
+    def refresh_nodes(self):
+        # collect local nodes
+        nodes = Node.objects.all()
+        nodes_dict = {}
+        for node in nodes:
+            if 'viccidev10' not in node.name:
+                nodes_dict[node.name] = node 
+        
+        deployment = Deployment.objects.filter(name='VICCI')[0]
+        login_bases = ['princeton', 'stanford', 'gt', 'uw', 'mpisws']
+        sites = Site.objects.filter(login_base__in=login_bases)
+        # collect nova nodes:
+        compute_nodes = self.client.nova.hypervisors.list()
+
+        compute_nodes_dict = {}
+        for compute_node in compute_nodes:
+            compute_nodes_dict[compute_node.hypervisor_hostname] = compute_node
+
+        # add new nodes:
+        new_node_names = set(compute_nodes_dict.keys()).difference(nodes_dict.keys())
+        i = 0
+        max = len(sites)
+        for name in new_node_names:
+            if i == max:
+                i = 0
+            site = sites[i]
+            node = Node(name=compute_nodes_dict[name].hypervisor_hostname,
+                        site=site,
+                        deployment=deployment)
+            node.save()
+            i+=1
+
+        # remove old nodes
+        old_node_names = set(nodes_dict.keys()).difference(compute_nodes_dict.keys())
+        Node.objects.filter(name__in=old_node_names).delete()
+
+    def refresh_images(self):
+        from core.models.image import Image
+        # collect local images
+        images = Image.objects.all()
+        images_dict = {}
+        for image in images:
+            images_dict[image.name] = image
+
+        # collect glance images
+        glance_images = self.client.glance.get_images()
+        glance_images_dict = {}
+        for glance_image in glance_images:
+            glance_images_dict[glance_image['name']] = glance_image
+
+        # add new images
+        new_image_names = set(glance_images_dict.keys()).difference(images_dict.keys())
+        for name in new_image_names:
+            image = Image(image_id=glance_images_dict[name]['id'],
+                          name=glance_images_dict[name]['name'],
+                          disk_format=glance_images_dict[name]['disk_format'],
+                          container_format=glance_images_dict[name]['container_format'])
+            image.save()
+
+        # remove old images
+        old_image_names = set(images_dict.keys()).difference(glance_images_dict.keys())
+        Image.objects.filter(name__in=old_image_names).delete()
+
+    @require_enabled
+    def save_network(self, network):
+        if not network.network_id:
+            if network.template.shared_network_name:
+                network.network_id = network.template.shared_network_id
+                (network.subnet_id, network.subnet) = self.driver.get_network_subnet(network.network_id)
+            else:
+                network_name = network.name
+
+                # create network
+                os_network = self.driver.create_network(network_name, shared=True)
+                network.network_id = os_network['id']
+
+                # create router
+                router = self.driver.create_router(network_name)
+                network.router_id = router['id']
+
+                # create subnet
+                next_subnet = self.get_next_subnet()
+                cidr = str(next_subnet.cidr)
+                ip_version = next_subnet.version
+                start = str(next_subnet[2])
+                end = str(next_subnet[-2])
+                subnet = self.driver.create_subnet(name=network_name,
+                                                   network_id = network.network_id,
+                                                   cidr_ip = cidr,
+                                                   ip_version = ip_version,
+                                                   start = start,
+                                                   end = end)
+                network.subnet = cidr
+                network.subnet_id = subnet['id']
+                # add subnet as interface to slice's router
+                self.driver.add_router_interface(router['id'], subnet['id'])
+                # add external route
+                self.driver.add_external_route(subnet)
+
+        network.save()
+        network.enacted = timezone.now()
+        network.save(update_fields=['enacted'])
+
+    def delete_network(self, network):
+        if (network.router_id) and (network.subnet_id):
+            self.driver.delete_router_interface(network.router_id, network.subnet_id)
+        if network.subnet_id:
+            self.driver.delete_subnet(network.subnet_id)
+        if network.router_id:
+            self.driver.delete_router(network.router_id)
+        if network.network_id:
+            self.driver.delete_network(network.network_id)
+
+    def save_network_template(self, template):
+        if (template.shared_network_name) and (not template.shared_network_id):
+            os_networks = self.driver.shell.quantum.list_networks(name=template.shared_network_name)['networks']
+            if os_networks:
+                template.shared_network_id = os_networks[0]["id"]
+
+        template.save()
+        template.enacted = timezone.now()
+        template.save(update_fields=['enacted'])
+
+    def find_or_make_template_for_network(self, name):
+        """ Given a network name, try to guess the right template for it """
+
+        # templates for networks we may encounter
+        if name=='nat-net':
+            template_dict = None # {"name": "private-nat", "visibility": "private", "translation": "nat"}
+        elif name=='sharednet1':
+            template_dict = {"name": "dedicated-public", "visibility": "public", "translation": "none"}
+        else:
+            template_dict = {"name": "private", "visibility": "private", "translation": "none"}
+
+        # if we have an existing template return it
+        templates = NetworkTemplate.objects.filter(name=template_dict["name"])
+        if templates:
+            return templates[0]
+
+        if template_dict == None:
+            return None
+
+        template = NetworkTemplate(**template_dict)
+        template.save()
+        return template
+
+    def refresh_network_templates(self):
+        for template in NetworkTemplate.objects.all():
+            if (template.shared_network_name) and (not template.shared_network_id):
+                 # this will cause us to try to fill in the shared_network_id
+                 self.save_network_template(template)
+
+    def refresh_networks(self):
+        # get a list of all networks in the model
+
+        networks = Network.objects.all()
+        networks_by_name = {}
+        networks_by_id = {}
+        for network in networks:
+            networks_by_name[network.name] = network
+            networks_by_id[network.network_id] = network
+
+        # Get a list of all shared networks in OS
+
+        os_networks = self.driver.shell.quantum.list_networks()['networks']
+        os_networks_by_name = {}
+        os_networks_by_id = {}
+        for os_network in os_networks:
+            os_networks_by_name[os_network['name']] = os_network
+            os_networks_by_id[os_network['id']] = os_network
+
+        for (uuid, os_network) in os_networks_by_id.items():
+            #print "checking OS network", os_network['name']
+            if (os_network['shared']) and (uuid not in networks_by_id):
+                # Only automatically create shared networks. This is for Andy's
+                # nat-net and sharednet1.
+
+                owner_slice = Slice.objects.get(tenant_id = os_network['tenant_id'])
+                template = self.find_or_make_template_for_network(os_network['name'])
+
+                if (template is None):
+                    # This is our way of saying we don't want to auto-instantiate
+                    # this network type.
+                    continue
+
+                (subnet_id, subnet) = self.driver.get_network_subnet(os_network['id'])
+
+                if owner_slice:
+                    #print "creating model object for OS network", os_network['name']
+                    new_network = Network(name = os_network['name'],
+                                          template = template,
+                                          owner = owner_slice,
+                                          network_id = uuid,
+                                          subnet_id = subnet_id)
+                    new_network.save()
+
+        for (network_id, network) in networks_by_id.items():
+            # If the network disappeared from OS, then reset its network_id to None
+            if (network.network_id is not None) and (network.network_id not in os_networks_by_id):
+                network.network_id = None
+
+            # If no OS object exists, then saving the network will create one
+            if (network.network_id is None):
+                #print "creating OS network for", network.name
+                self.save_network(network)
+            else:
+                pass #print "network", network.name, "has its OS object"
+
+
diff --git a/xos/openstack/reservationagent.py b/xos/openstack/reservationagent.py
new file mode 100644
index 0000000..5cb9c8e
--- /dev/null
+++ b/xos/openstack/reservationagent.py
@@ -0,0 +1,51 @@
+import datetime
+import os
+import sys
+#os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
+import time
+import django.utils
+from core.models.instance import Instance
+from core.models.reservation import Reservation, ReservedResource
+
+class ReservationAgent:
+
+    def run(self):
+        while True :
+            instances = {}
+
+            tNow = django.utils.timezone.now()
+            print "Processing reservations, tNow is %s" % tNow
+            reservations = Reservation.objects.filter(startTime__lte = tNow)
+            for reservation in reservations:
+                print "  Processing reservation %s" % reservation
+                if reservation.endTime <= tNow:
+                    print "    deleting expired reservation"
+                    reservation.delete()
+                for reservedResource in reservation.reservedresources.all():
+                    instance_resources = instances.get(reservedResource.instance.id, {})
+                    instance_resources[reservedResource.resource.name] = reservedResource.quantity
+                    instances[reservedResource.instance.id] = instance_resources
+
+            print "Instance reservation set"
+            for (instanceid, instance_resources) in instances.items():
+                print "  instance", instanceid,
+                for (name, value) in instance_resources.items():
+                    print str(name)+":", value,
+                print
+
+            print "Updating instances"
+            for instance in Instance.objects.all():
+                instance_resv = instances.get(instance.id, {})
+                numberCores = instance_resv.get("numberCores", 0)
+                if numberCores != instance.numberCores:
+                    print "instance %s setting numberCores to %s" % (instance.name, numberCores)
+                    instance.numberCores = numberCores
+                    instance.save()
+
+            print "sleep"
+            time.sleep(7)
+
+
+if __name__ == '__main__':
+    ReservationAgent().run()
+                 
diff --git a/xos/openstack_synchronizer b/xos/openstack_synchronizer
new file mode 120000
index 0000000..ae75af5
--- /dev/null
+++ b/xos/openstack_synchronizer
@@ -0,0 +1 @@
+openstack_observer
\ No newline at end of file
diff --git a/xos/services/__init__.py b/xos/services/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xos/services/__init__.py
diff --git a/xos/services/hpc/__init__.py b/xos/services/hpc/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xos/services/hpc/__init__.py
diff --git a/xos/services/hpc/admin.py b/xos/services/hpc/admin.py
new file mode 100644
index 0000000..d9f28c6
--- /dev/null
+++ b/xos/services/hpc/admin.py
@@ -0,0 +1,228 @@
+from django.contrib import admin
+
+from services.hpc.models import *
+from django import forms
+from django.utils.safestring import mark_safe
+from django.contrib.auth.admin import UserAdmin
+from django.contrib.admin.widgets import FilteredSelectMultiple
+from django.contrib.auth.forms import ReadOnlyPasswordHashField
+from django.contrib.auth.signals import user_logged_in
+from django.utils import timezone
+from django.contrib.contenttypes import generic
+from suit.widgets import LinkedSelect
+from core.admin import ServiceAppAdmin,SliceInline,ServiceAttrAsTabInline, ReadOnlyAwareAdmin, XOSTabularInline, SliderWidget, ServicePrivilegeInline
+from core.middleware import get_request
+
+from functools import update_wrapper
+from django.contrib.admin.views.main import ChangeList
+from django.core.urlresolvers import reverse, NoReverseMatch
+from django.contrib.admin.utils import quote
+
+from filteredadmin import FilteredChangeList, FilteredAdmin, FilteredInline
+
+class HpcServiceForm(forms.ModelForm):
+    scale = forms.IntegerField(widget = SliderWidget, required=False)
+
+    def __init__(self, *args, **kwargs):
+        super(HpcServiceForm, self).__init__(*args, **kwargs)
+        if ("instance" in kwargs) and (hasattr(kwargs["instance"], "scale")):
+            self.fields['scale'].initial = kwargs["instance"].scale
+
+    def save(self, *args, **kwargs):
+        if self.cleaned_data['scale']:
+             self.instance.scale = self.cleaned_data['scale']
+
+        return super(HpcServiceForm, self).save(*args, **kwargs)
+
+class HpcServiceAdmin(ReadOnlyAwareAdmin):
+    model = HpcService
+    verbose_name = "HPC Service"
+    verbose_name_plural = "HPC Service"
+    list_display = ("backend_status_icon", "name","enabled")
+    list_display_links = ('backend_status_icon', 'name', )
+    fieldsets = [(None, {'fields': ['backend_status_text', 'name','scale','enabled','versionNumber', 'description', "cmi_hostname", "hpc_port80", "watcher_hpc_network", "watcher_dnsredir_network", "watcher_dnsdemux_network"], 'classes':['suit-tab suit-tab-general']})]
+    readonly_fields = ('backend_status_text', )
+    inlines = [SliceInline,ServiceAttrAsTabInline,ServicePrivilegeInline]
+    form = HpcServiceForm
+
+    extracontext_registered_admins = True
+
+    user_readonly_fields = ["name", "enabled", "versionNumber", "description"]
+
+    suit_form_tabs =(('general', 'HPC Service Details'),
+        ('administration', 'Administration'),
+        ('tools', 'Tools'),
+        ('slices','Slices'),
+        ('serviceattrs','Additional Attributes'),
+                ('serviceprivileges','Privileges'),
+    )
+
+    suit_form_includes = (('hpcadmin.html', 'top', 'administration'),
+                          ('hpctools.html', 'top', 'tools') )
+
+    def url_for_model_changelist(self, request, model):
+       if not request.resolver_match.args:
+           return reverse('admin:%s_%s_changelist' % (model._meta.app_label, model._meta.model_name), current_app=model._meta.app_label)
+       else:
+           obj_id = request.resolver_match.args[0]
+           changelist_url = reverse('admin:%s_%s_filteredchangelist' % (model._meta.app_label, model._meta.model_name), args=(obj_id,), current_app=model._meta.app_label)
+           return changelist_url
+
+class HPCAdmin(FilteredAdmin):
+   # Change the application breadcrumb to point to an HPC Service if one is
+   # defined
+
+   custom_app_breadcrumb_name = "Hpc"
+   @property
+   def custom_app_breadcrumb_url(self):
+       services = HpcService.objects.all()
+       if len(services)==1:
+           return "/admin/hpc/hpcservice/%s/" % services[0].id
+       else:
+           return "/admin/hpc/hpcservice/"
+
+class CDNPrefixInline(FilteredInline):
+    model = CDNPrefix
+    extra = 0
+    suit_classes = 'suit-tab suit-tab-prefixes'
+    fields = ('backend_status_icon', 'cdn_prefix_id', 'prefix', 'defaultOriginServer', 'enabled')
+    readonly_fields = ('backend_status_icon', 'cdn_prefix_id',)
+
+class OriginServerInline(FilteredInline):
+    model = OriginServer
+    extra = 0
+    suit_classes = 'suit-tab suit-tab-origins'
+    fields = ('backend_status_icon', 'origin_server_id', 'url')
+    readonly_fields = ('backend_status_icon', 'origin_server_id')
+
+class ContentProviderInline(FilteredInline):
+    model = ContentProvider
+    extra = 0
+    suit_classes = 'suit-tab suit-tab-cps'
+    fields = ('backend_status_icon', 'content_provider_id', 'name', 'enabled')
+    readonly_fields = ('backend_status_icon', 'content_provider_id',)
+
+class OriginServerAdmin(HPCAdmin):
+    list_display = ('backend_status_icon', 'url','protocol','redirects','contentProvider','authenticated','enabled' )
+    list_display_links = ('backend_status_icon', 'url', )
+
+    fields = ('backend_status_text', 'url','protocol','redirects','contentProvider','authenticated','enabled','origin_server_id','description' )
+    readonly_fields = ('backend_status_text', 'origin_server_id',)
+    user_readonly_fields = ('url','protocol','redirects','contentProvider','authenticated','enabled','origin_server_id','description')
+
+class ContentProviderForm(forms.ModelForm):
+    users = forms.ModelMultipleChoiceField(
+        queryset=User.objects.all(),
+        required=False,
+        help_text="Select which users can manage this ContentProvider",
+        widget=FilteredSelectMultiple(
+            verbose_name=('Users'), is_stacked=False
+        )
+    )
+
+    class Meta:
+        model = ContentProvider
+        widgets = {
+            'serviceProvider' : LinkedSelect
+        }
+
+    def __init__(self, *args, **kwargs):
+      request = kwargs.pop('request', None)
+      super(ContentProviderForm, self).__init__(*args, **kwargs)
+
+      if self.instance and self.instance.pk:
+        self.fields['users'].initial = self.instance.users.all()
+
+class ContentProviderAdmin(HPCAdmin):
+    form = ContentProviderForm
+    list_display = ('backend_status_icon', 'name','description','enabled' )
+    list_display_links = ('backend_status_icon', 'name', )
+    readonly_fields = ('backend_status_text', )
+    admin_readonly_fields = ('backend_status_text', )
+    cp_readonly_fields = ('backend_status_text', 'name', 'enabled', 'serviceProvider', 'users')
+    fieldsets = [ (None, {'fields': ['backend_status_text', 'name','enabled','description','serviceProvider','users'], 'classes':['suit-tab suit-tab-general']})]
+
+    inlines = [CDNPrefixInline, OriginServerInline]
+
+    user_readonly_fields = ('name','description','enabled','serviceProvider','users')
+
+    suit_form_tabs = (('general','Details'),('prefixes','CDN Prefixes'), ('origins','Origin Servers'))
+
+    def change_view(self,request, *args, **kwargs):
+        if request.user.is_admin:
+            self.readonly_fields = self.admin_readonly_fields
+        else:
+            self.readonly_fields = self.cp_readonly_fields
+
+        return super(ContentProviderAdmin, self).change_view(request, *args, **kwargs)
+
+    def has_add_permission(self, request):
+        return request.user.is_admin
+
+    def has_delete_permission(self, request, obj=None):
+        return request.user.is_admin
+
+class ServiceProviderAdmin(HPCAdmin):
+    list_display = ('backend_status_icon', 'name', 'description', 'enabled')
+    list_display_links = ('backend_status_icon', 'name', )
+    fieldsets = [
+        (None, {'fields': ['backend_status_text', 'name','description','enabled', 'hpcService'], 'classes':['suit-tab suit-tab-general']})]
+#, ('Content Providers', {'fields':['contentProviders'],'classes':['suit-tab suit-tab-cps']})]
+
+    readonly_fields = ('backend_status_text', )
+    user_readonly_fields = ('name', 'description', 'enabled')
+
+    suit_form_tabs = (('general','Details'),('cps','Content Providers'))
+    inlines = [ContentProviderInline]
+
+class CDNPrefixForm(forms.ModelForm):
+    class Meta:
+        widgets = {
+            'contentProvider' : LinkedSelect
+        }
+
+class CDNPrefixAdmin(HPCAdmin):
+    form = CDNPrefixForm
+    list_display = ['backend_status_icon', 'prefix','contentProvider']
+    list_display_links = ('backend_status_icon', 'prefix', )
+    fields = ['backend_status_text', 'prefix', 'contentProvider', 'cdn_prefix_id', 'description', 'defaultOriginServer', 'enabled']
+    readonly_fields = ('backend_status_text', )
+    user_readonly_fields = ['prefix','contentProvider', "cdn_prefix_id", "description", "defaultOriginServer", "enabled"]
+
+class SiteMapAdmin(HPCAdmin):
+    model = SiteMap
+    verbose_name = "Site Map"
+    verbose_name_plural = "Site Map"
+    list_display = ("backend_status_icon", "name", "contentProvider", "serviceProvider")
+    list_display_links = ('backend_status_icon', 'name', )
+    fields = ['backend_status_text', 'name', 'hpcService', 'cdnPrefix', 'contentProvider', 'serviceProvider', 'map', 'map_id']
+    user_readonly_fields = ('backend_status_text', "name", "hpcService", "cdnPrefix", "contentProvider", "serviceProvider", "description", "map")
+    readonly_fields = ('backend_status_text', )
+
+class AccessMapAdmin(HPCAdmin):
+    model = AccessMap
+    verbose_name = "Access Map"
+    verbose_name_plural = "Access Map"
+    list_display = ("backend_status_icon", "name", "contentProvider")
+    list_display_links = ('backend_status_icon', 'name', )
+    user_readonly_fields = ('backend_status_text', "name", "contentProvider", "description", "map")
+    readonly_fields = ('backend_status_text', )
+
+class HpcHealthCheckAdmin(HPCAdmin):
+    model = HpcHealthCheck
+    verbose_name = "Health Check"
+    verbose_name = "Health Checks"
+    list_display = ["backend_status_icon", "resource_name", "kind"]
+    list_display_links = ["backend_status_icon", "resource_name"]
+    fields = ["backend_status_text", "hpcService", "resource_name", "kind", "result_contains", "result_min_size", "result_max_size"]
+    readonly_fields = ["backend_status_text",]
+
+admin.site.register(ServiceProvider, ServiceProviderAdmin)
+admin.site.register(ContentProvider, ContentProviderAdmin)
+admin.site.register(CDNPrefix, CDNPrefixAdmin)
+admin.site.register(OriginServer,OriginServerAdmin)
+admin.site.register(HpcService, HpcServiceAdmin)
+admin.site.register(SiteMap, SiteMapAdmin)
+admin.site.register(AccessMap, AccessMapAdmin)
+admin.site.register(HpcHealthCheck, HpcHealthCheckAdmin)
+
diff --git a/xos/services/hpc/filteredadmin.py b/xos/services/hpc/filteredadmin.py
new file mode 100644
index 0000000..b677b54
--- /dev/null
+++ b/xos/services/hpc/filteredadmin.py
@@ -0,0 +1,191 @@
+from django.contrib import admin
+
+from django import forms
+from services.hpc.models import HpcService
+from core.admin import ServiceAppAdmin,SliceInline,ServiceAttrAsTabInline, ReadOnlyAwareAdmin, XOSTabularInline, SliderWidget, ServicePrivilegeInline
+from core.middleware import get_request
+
+from functools import update_wrapper
+from django.contrib.admin.views.main import ChangeList
+from django.core.urlresolvers import reverse, NoReverseMatch
+from django.contrib.admin.utils import quote
+
+import threading
+_thread_locals = threading.local()
+
+class FilteredChangeList(ChangeList):
+    """ A special ChangeList with a doctored url_for_result function that
+        points to the filteredchange view instead of the default change
+        view.
+    """
+
+    def __init__(self, request, *args, **kwargs):
+        self.service = getattr(request, "hpcService", None)
+        self.embedded = getattr(request, "embedded", False)
+        super(FilteredChangeList, self).__init__(request, *args, **kwargs)
+
+    def url_for_result(self, result):
+        if (self.service is None):
+             return super(FilteredChangeList, self).url_for_result(result)
+
+        pk = getattr(result, self.pk_attname)
+        if self.embedded:
+            return reverse('admin:%s_%s_embeddedfilteredchange' % (self.opts.app_label,
+                                                           self.opts.model_name),
+                           args=(quote(self.service.id), quote(pk),),
+                           current_app=self.model_admin.admin_site.name)
+
+        else:
+            return reverse('admin:%s_%s_filteredchange' % (self.opts.app_label,
+                                                           self.opts.model_name),
+                           args=(quote(self.service.id), quote(pk),),
+                           current_app=self.model_admin.admin_site.name)
+
+class FilteredAdmin(ReadOnlyAwareAdmin):
+   """
+      One approach to filtering the HPC Admin views by HPCService. Encode
+      the HPCService into the URL for the changelist view. Then we could do our
+      custom filtering in self.filtered_changelist_view.
+
+      To make this work, a few changes needed to be made to the change and
+      change_list templates.
+
+      1) "custom_changelist_breadcrumb_url" is used to replace the breadcrumb
+         in change and add views with one that will point back to the filtered
+         list.
+
+      2) "custom_add_url" is used to replace the Add button's URL with one
+         that points to the filtered add view.
+
+      TODO: Save & Add Another,
+            the add link when the changelist is empty
+   """
+
+   @property
+   def change_list_template(self):
+       return _thread_locals.change_list_template
+
+   @property
+   def change_form_template(self):
+       return _thread_locals.change_form_template
+
+   def get_urls(self):
+       from django.conf.urls import patterns, url
+
+       def wrap(view):
+            def wrapper(*args, **kwargs):
+                return self.admin_site.admin_view(view)(*args, **kwargs)
+            return update_wrapper(wrapper, view)
+
+       urls = super(FilteredAdmin, self).get_urls()
+       info = self.model._meta.app_label, self.model._meta.model_name
+       my_urls = [
+           url(r'^(.+)/filteredlist/$', wrap(self.filtered_changelist_view), name="%s_%s_filteredchangelist" % info),
+           url(r'^(.+)/embeddedfilteredlist/$', wrap(self.embedded_filtered_changelist_view), name="%s_%s_embeddedfilteredchangelist" % info),
+           url(r'^(.+)/(.+)/filteredchange$', wrap(self.filtered_change_view), name='%s_%s_filteredchange' % info),
+           url(r'^(.+)/(.+)/embeddedfilteredchange$', wrap(self.embedded_filtered_change_view), name='%s_%s_embeddedfilteredchange' % info),
+           url(r'^(.+)/filteredadd/$', wrap(self.filtered_add_view), name='%s_%s_filteredadd' % info),
+           url(r'^(.+)/embeddedfilteredadd/$', wrap(self.embedded_filtered_add_view), name='%s_%s_embeddedfilteredadd' % info),
+       ]
+       return my_urls + urls
+
+   def add_extra_context(self, request, extra_context):
+       super(FilteredAdmin, self).add_extra_context(request, extra_context)
+
+       if getattr(request,"hpcService",None) is not None:
+            extra_context["custom_changelist_breadcrumb_url"] = "/admin/hpc/%s/%s/filteredlist/" % (self.model._meta.model_name, str(request.hpcService.id))
+            if getattr(request,"embedded",False):
+                extra_context["custom_add_url"] = "/admin/hpc/%s/%s/embeddedfilteredadd/" % (self.model._meta.model_name, str(request.hpcService.id))
+            else:
+                extra_context["custom_add_url"] = "/admin/hpc/%s/%s/filteredadd/" % (self.model._meta.model_name, str(request.hpcService.id))
+                if len(request.resolver_match.args)>1:
+                    # this is only useful on change views, not changelist views
+                    extra_context["custom_delete_url"] = "/admin/hpc/%s/%s/delete/" % (self.model._meta.model_name, request.resolver_match.args[1])
+
+       extra_context["show_save"] = False
+       extra_context["show_save_and_add_another"] = False
+
+   def changelist_view(self, *args, **kwargs):
+       if "template" in kwargs:
+           _thread_locals.change_list_template = kwargs["template"]
+           del kwargs["template"]
+       else:
+           _thread_locals.change_list_template = "admin/change_list_bc.html"
+       return super(FilteredAdmin, self).changelist_view(*args, **kwargs)
+
+   def filtered_changelist_view(self, request, hpcServiceId, extra_context=None):
+       request.hpcService = HpcService.objects.get(id=hpcServiceId)
+       return self.changelist_view(request, extra_context=extra_context)
+
+   def embedded_filtered_changelist_view(self, request, hpcServiceId, extra_context=None):
+       request.hpcService = HpcService.objects.get(id=hpcServiceId)
+       request.embedded = True
+       return self.changelist_view(request, template="admin/change_list_embedded.html", extra_context=extra_context)
+
+   def change_view(self, *args, **kwargs):
+       if "template" in kwargs:
+           _thread_locals.change_form_template = kwargs["template"]
+           del kwargs["template"]
+       else:
+           _thread_locals.change_form_template = "admin/change_form_bc.html"
+       return super(FilteredAdmin, self).change_view(*args, **kwargs)
+
+   def filtered_change_view(self, request, hpcServiceId, object_id, extra_context=None):
+       request.hpcService = HpcService.objects.get(id=hpcServiceId)
+       return self.change_view(request, object_id, extra_context=extra_context)
+
+   def embedded_filtered_change_view(self, request, hpcServiceId, object_id, extra_context=None):
+       request.hpcService = HpcService.objects.get(id=hpcServiceId)
+       request.embedded = True
+       return self.change_view(request, object_id, template="admin/change_form_embedded.html", extra_context=extra_context)
+
+   def add_view(self, *args, **kwargs):
+       if "template" in kwargs:
+           _thread_locals.change_form_template = kwargs["template"]
+           del kwargs["template"]
+       else:
+           _thread_locals.change_form_template = "admin/change_form_bc.html"
+       return super(FilteredAdmin, self).add_view(*args, **kwargs)
+
+   def filtered_add_view(self, request, hpcServiceId, extra_context=None):
+       request.hpcService = HpcService.objects.get(id=hpcServiceId)
+       return self.add_view(request, extra_context=extra_context)
+
+   def embedded_filtered_add_view(self, request, hpcServiceId, extra_context=None):
+       request.hpcService = HpcService.objects.get(id=hpcServiceId)
+       request.embedded = True
+       return self.add_view(request, template="admin/change_form_embedded.html", extra_context=extra_context)
+
+   def get_queryset(self, request):
+       # request.hpcService will be set in filtered_changelist_view so we can
+       # use it to filter what will be displayed in the list.
+       qs = self.model.objects.all()
+       if (getattr(request,"hpcService",None) is not None) and (hasattr(self.model, "filter_by_hpcService")):
+           qs = self.model.filter_by_hpcService(qs, request.hpcService)
+       return qs
+
+   def get_changelist(self, request, **kwargs):
+       # We implement a custom ChangeList, so the URLs point to the
+       # filtered_change_view rather than the default change_view.
+       return FilteredChangeList
+
+class FilteredInline(XOSTabularInline):
+   def get_change_url(self, id):
+       request = get_request()
+       embedded = getattr(request, "embedded", False)
+       service_id = request.resolver_match.args[0]
+
+       if embedded:
+           reverse_path = "admin:%s_embeddedfilteredchange" % (self.selflink_model._meta.db_table)
+           args = (service_id, id)
+       else:
+           reverse_path = "admin:%s_filteredchange" % (self.selflink_model._meta.db_table)
+           args = (service_id, id)
+
+       try:
+           url = reverse(reverse_path, args=args, current_app=self.selflink_model._meta.app_label)
+       except NoReverseMatch:
+           return None
+
+       return url
+
diff --git a/xos/services/hpc/migrations/__init__.py b/xos/services/hpc/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xos/services/hpc/migrations/__init__.py
diff --git a/xos/services/hpc/models.py b/xos/services/hpc/models.py
new file mode 100644
index 0000000..e49bf4e
--- /dev/null
+++ b/xos/services/hpc/models.py
@@ -0,0 +1,229 @@
+from django.db import models
+from core.models import User, Service, SingletonModel, PlCoreBase
+from core.models.plcorebase import StrippedCharField
+import os
+from django.db import models
+from django.forms.models import model_to_dict
+from django.db.models import Q
+
+
+# Create your models here.
+
+class HpcService(Service):
+
+    class Meta:
+        app_label = "hpc"
+        verbose_name = "HPC Service"
+
+    cmi_hostname = StrippedCharField(max_length=254, null=True, blank=True)
+
+    hpc_port80 = models.BooleanField(default=True, help_text="Enable port 80 for HPC")
+    watcher_hpc_network = StrippedCharField(max_length=254, null=True, blank=True, help_text="Network for hpc_watcher to contact hpc instance")
+    watcher_dnsdemux_network = StrippedCharField(max_length=254, null=True, blank=True, help_text="Network for hpc_watcher to contact dnsdemux instance")
+    watcher_dnsredir_network = StrippedCharField(max_length=254, null=True, blank=True, help_text="Network for hpc_watcher to contact dnsredir instance")
+
+    @property
+    def scale(self):
+        hpc_slices = [x for x in self.slices.all() if "hpc" in x.name]
+        if not hpc_slices:
+            return 0
+        return hpc_slices[0].instances.count()
+
+    @scale.setter
+    def scale(self, value):
+        self.set_scale = value
+
+    def save(self, *args, **kwargs):
+        super(HpcService, self).save(*args, **kwargs)
+
+        # scale up/down
+        scale = getattr(self, "set_scale", None)
+        if scale is not None:
+            exclude_slices = [x for x in self.slices.all() if "cmi" in x.name]
+            self.adjust_scale(slice_hint="hpc", scale=scale, exclusive_slices = exclude_slices, max_per_node=1)
+
+class ServiceProvider(PlCoreBase):
+    class Meta:
+        app_label = "hpc"
+
+    hpcService = models.ForeignKey(HpcService)
+    service_provider_id = models.IntegerField(null=True, blank=True)
+    name = models.CharField(max_length=254,help_text="Service Provider Name")
+    description = models.TextField(max_length=254,null=True, blank=True, help_text="Description of Service Provider")
+    enabled = models.BooleanField(default=True)
+
+    def __unicode__(self):  return u'%s' % (self.name)
+
+    @classmethod
+    def filter_by_hpcService(cls, qs, hpcService):
+        # This should be overridden by descendant classes that want to perform
+        # filtering of visible objects by user.
+        return qs.filter(hpcService=hpcService)
+
+class ContentProvider(PlCoreBase):
+    class Meta:
+        app_label = "hpc"
+
+    # legacy vicci content providers already have names.
+    CP_TO_ACCOUNT = {"ON.LAB": "onlabcp",
+                     "Syndicate": "syndicatecp"}
+
+    content_provider_id = models.IntegerField(null=True, blank=True)
+    name = models.CharField(max_length=254)
+    enabled = models.BooleanField(default=True)
+    description = models.TextField(max_length=254,null=True, blank=True,help_text="Description of Content Provider")
+    serviceProvider = models.ForeignKey(ServiceProvider)
+
+    # Note user relationships are directed not requiring a role.
+    users = models.ManyToManyField(User)
+
+    def __unicode__(self):  return u'%s' % (self.name)
+
+    @property
+    def account(self):
+        return self.CP_TO_ACCOUNT.get(self.name, self.name)
+
+    @classmethod
+    def filter_by_hpcService(cls, qs, hpcService):
+        # This should be overridden by descendant classes that want to perform
+        # filtering of visible objects by user.
+        return qs.filter(serviceProvider__hpcService=hpcService)
+
+    def can_update(self, user):
+        if super(ContentProvider, self).can_update(user):
+            return True
+
+        if user in self.users.all():
+            return True
+
+        return False
+
+class OriginServer(PlCoreBase):
+    class Meta:
+        app_label = "hpc"
+
+    origin_server_id = models.IntegerField(null=True, blank=True)
+    url = models.CharField(max_length=1024)
+    contentProvider = models.ForeignKey(ContentProvider)
+
+    authenticated = models.BooleanField(default=False, help_text="Status for this Site")
+    enabled = models.BooleanField(default=True, help_text="Status for this Site")
+    PROTOCOL_CHOICES = (('http', 'HTTP'),('rtmp', 'RTMP'), ('rtp', 'RTP'),('shout', 'SHOUTcast')) 
+    protocol = models.CharField(default="HTTP", max_length = 12, choices=PROTOCOL_CHOICES)
+    redirects = models.BooleanField(default=True, help_text="Indicates whether Origin Server redirects should be used for this Origin Server")
+    description = models.TextField(null=True, blank=True, max_length=255)
+    
+    def __unicode__(self):  return u'%s' % (self.url)
+
+    @classmethod
+    def filter_by_hpcService(cls, qs, hpcService):
+        # This should be overridden by descendant classes that want to perform
+        # filtering of visible objects by user.
+        return qs.filter(contentProvider__serviceProvider__hpcService=hpcService)
+
+    def can_update(self, user):
+        if super(OriginServer, self).can_update(user):
+            return True
+
+        if self.contentProvider and self.contentProvider.can_update(user):
+            return True
+
+        return False
+
+class CDNPrefix(PlCoreBase):
+    class Meta:
+        app_label = "hpc"
+
+    cdn_prefix_id = models.IntegerField(null=True, blank=True)
+    prefix = models.CharField(max_length=200, help_text="Registered Prefix for Domain")
+    contentProvider = models.ForeignKey(ContentProvider)
+    description = models.TextField(max_length=254,null=True, blank=True,help_text="Description of Content Provider")
+
+    defaultOriginServer = models.ForeignKey(OriginServer, blank=True, null=True)
+    enabled = models.BooleanField(default=True)
+
+    def __unicode__(self):  return u'%s' % (self.prefix)
+
+    @classmethod
+    def filter_by_hpcService(cls, qs, hpcService):
+        # This should be overridden by descendant classes that want to perform
+        # filtering of visible objects by user.
+        return qs.filter(contentProvider__serviceProvider__hpcService=hpcService)
+
+    def can_update(self, user):
+        if super(CDNPrefix, self).can_update(user):
+            return True
+
+        if self.contentProvider and self.contentProvider.can_update(user):
+            return True
+
+        return False
+
+class AccessMap(PlCoreBase):
+    class Meta:
+        app_label = "hpc"
+
+    contentProvider = models.ForeignKey(ContentProvider)
+    name = models.CharField(max_length=64, help_text="Name of the Access Map")
+    description = models.TextField(null=True, blank=True,max_length=130)
+    map = models.FileField(upload_to="maps/", help_text="specifies which client requests are allowed")
+
+    def __unicode__(self):  return self.name
+
+class SiteMap(PlCoreBase):
+    class Meta:
+        app_label = "hpc"
+
+    """ can be bound to a ContentProvider, ServiceProvider, or neither """
+    contentProvider = models.ForeignKey(ContentProvider, blank=True, null=True)
+    serviceProvider = models.ForeignKey(ServiceProvider, blank=True, null=True)
+    cdnPrefix = models.ForeignKey(CDNPrefix, blank = True, null=True)
+    hpcService = models.ForeignKey(HpcService, blank = True, null=True)
+    name = models.CharField(max_length=64, help_text="Name of the Site Map")
+    description = models.TextField(null=True, blank=True,max_length=130)
+    map = models.FileField(upload_to="maps/", help_text="specifies how to map requests to hpc instances")
+    map_id = models.IntegerField(null=True, blank=True)
+
+    def __unicode__(self):  return self.name
+
+    def save(self, *args, **kwds):
+        if (self.contentProvider) and (self.serviceProvider or self.cdnPrefix or self.hpcService):
+            raise ValueError("You may only set one of contentProvider, serviceProvider, cdnPrefix, or hpcService")
+        if (self.serviceProvider) and (self.cdnPrefix or self.hpcService):
+            raise ValueError("You may only set one of contentProvider, serviceProvider, cdnPrefix, or hpcService")
+        if (self.cdnPrefix) and (self.hpcService):
+            raise ValueError("You may only set one of contentProvider, serviceProvider, cdnPrefix, or hpcService")
+
+        super(SiteMap, self).save(*args, **kwds)
+
+    @classmethod
+    def filter_by_hpcService(cls, qs, hpcService):
+        # This should be overridden by descendant classes that want to perform
+        # filtering of visible objects by user.
+        return qs.filter(Q(hpcService=hpcService) |
+                                  Q(serviceProvider__hpcService=hpcService) |
+                                  Q(contentProvider__serviceProvider__hpcService=hpcService) |
+                                  Q(cdnPrefix__contentProvider__serviceProvider__hpcService=hpcService))
+
+class HpcHealthCheck(PlCoreBase):
+    class Meta:
+        app_label = "hpc"
+
+    KIND_CHOICES = (('dns', 'DNS'), ('http', 'HTTP'), ('nameserver', 'Name Server'))
+
+    hpcService = models.ForeignKey(HpcService, blank = True, null=True)
+    kind = models.CharField(max_length=30, choices=KIND_CHOICES, default="dns")
+    resource_name = StrippedCharField(max_length=1024, blank=False, null=False)
+    result_contains = StrippedCharField(max_length=1024, blank=True, null=True)
+    result_min_size = models.IntegerField(null=True, blank=True)
+    result_max_size = models.IntegerField(null=True, blank=True)
+
+    def __unicode__(self): return self.resource_name
+
+    @classmethod
+    def filter_by_hpcService(cls, qs, hpcService):
+        # This should be overridden by descendant classes that want to perform
+        # filtering of visible objects by user.
+        return qs.filter(hpcService=hpcService)
+
+
diff --git a/xos/services/hpc/templates/hpcadmin.html b/xos/services/hpc/templates/hpcadmin.html
new file mode 100644
index 0000000..5c05020
--- /dev/null
+++ b/xos/services/hpc/templates/hpcadmin.html
@@ -0,0 +1,18 @@
+<div class = "left-nav">
+<ul>
+{% for admin in registered_admins %}
+    <li><a href="{{ admin.url }}">{{ admin.name }}</a></li>
+{% endfor %}
+</ul>
+</div>
+
+<!--
+<ul>
+<li><a href="/admin/hpc/originserver/">Origin Servers</a></li>
+<li><a href="/admin/hpc/contentprovider/">Content Providers</a></li>
+<li><a href="/admin/hpc/serviceprovider/">Server Providers</a></li>
+<li><a href="/admin/hpc/cdnprefix/">CDN Prefixes</a></li>
+<li><a href="/admin/hpc/sitemap/">Site Maps</a></li>
+<li><a href="/admin/hpc/accessmap/">Access Maps</a></li>
+</ul>
+-->
diff --git a/xos/services/hpc/templates/hpctools.html b/xos/services/hpc/templates/hpctools.html
new file mode 100644
index 0000000..28ab5c0
--- /dev/null
+++ b/xos/services/hpc/templates/hpctools.html
@@ -0,0 +1,9 @@
+<div class = "left-nav">
+
+<ul>
+<li><a href="/dashboard/xosHpc">Service Monitor</a></li>
+<li><a href="/dashboard/xosHpcUrls">HPC Node Drilldown</a></li>
+<li><a href="/dashboard/xosHpcNodes">HPC Url Drilldown</a></li>
+</ul>
+
+</div>
diff --git a/xos/services/hpc/tests.py b/xos/services/hpc/tests.py
new file mode 100644
index 0000000..501deb7
--- /dev/null
+++ b/xos/services/hpc/tests.py
@@ -0,0 +1,16 @@
+"""
+This file demonstrates writing tests using the unittest module. These will pass
+when you run "manage.py test".
+
+Replace this with more appropriate tests for your application.
+"""
+
+from django.test import TestCase
+
+
+class SimpleTest(TestCase):
+    def test_basic_addition(self):
+        """
+        Tests that 1 + 1 always equals 2.
+        """
+        self.assertEqual(1 + 1, 2)
diff --git a/xos/services/hpc/views.py b/xos/services/hpc/views.py
new file mode 100644
index 0000000..60f00ef
--- /dev/null
+++ b/xos/services/hpc/views.py
@@ -0,0 +1 @@
+# Create your views here.
diff --git a/xos/services/mcord/__init__.py b/xos/services/mcord/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xos/services/mcord/__init__.py
diff --git a/xos/services/mcord/admin.py b/xos/services/mcord/admin.py
new file mode 100644
index 0000000..ee19c7e
--- /dev/null
+++ b/xos/services/mcord/admin.py
@@ -0,0 +1,212 @@
+
+from core.admin import ReadOnlyAwareAdmin, SliceInline
+from core.middleware import get_request
+from core.models import User
+from django import forms
+from django.contrib import admin
+from services.mcord.models import MCORDService, VBBUComponent, VPGWCComponent, MCORD_KIND
+
+# The class to provide an admin interface on the web for the service.
+# We do only configuration here and don't change any logic because the logic
+# is taken care of for us by ReadOnlyAwareAdmin
+class MCORDServiceAdmin(ReadOnlyAwareAdmin):
+    # We must set the model so that the admin knows what fields to use
+    model = MCORDService
+    verbose_name = "MCORD Service"
+    verbose_name_plural = "MCORD Services"
+
+    # Setting list_display creates columns on the admin page, each value here
+    # is a column, the column is populated for every instance of the model.
+    list_display = ("backend_status_icon", "name", "enabled")
+
+    # Used to indicate which values in the columns of the admin form are links.
+    list_display_links = ('backend_status_icon', 'name', )
+
+    # Denotes the sections of the form, the fields in the section, and the
+    # CSS classes used to style them. We represent this as a set of tuples, each
+    # tuple as a name (or None) and a set of fields and classes.
+    # Here the first section does not have a name so we use none. That first
+    # section has several fields indicated in the 'fields' attribute, and styled
+    # by the classes indicated in the 'classes' attribute. The classes given
+    # here are important for rendering the tabs on the form. To give the tabs
+    # we must assign the classes suit-tab and suit-tab-<name> where
+    # where <name> will be used later.
+    fieldsets = [(None, {'fields': ['backend_status_text', 'name', 'enabled',
+                                    'versionNumber', 'description', "view_url"],
+                         'classes':['suit-tab suit-tab-general']})]
+
+    # Denotes the fields that are readonly and cannot be changed.
+    readonly_fields = ('backend_status_text', )
+
+    # Inlines are used to denote other models that can be edited on the same
+    # form as this one. In this case the service form also allows changes
+    # to slices.
+    inlines = [SliceInline]
+
+    extracontext_registered_admins = True
+
+    # Denotes the fields that can be changed by an admin but not be all users
+    user_readonly_fields = ["name", "enabled", "versionNumber", "description"]
+
+    # Associates fieldsets from this form and from the inlines.
+    # The format here are tuples, of (<name>, tab title). <name> comes from the
+    # <name> in the fieldsets.
+    suit_form_tabs = (('general', 'MCORD Service Details'),
+                      ('administration', 'Components'),
+                      ('slices', 'Slices'),)
+
+    # Used to include a template for a tab. Here we include the
+    # helloworldserviceadmin template in the top position for the administration
+    # tab.
+    suit_form_includes = (('mcordadmin.html',
+                           'top',
+                           'administration'),)
+
+    # Used to get the objects for this model that are associated with the
+    # requesting user.
+    def queryset(self, request):
+        return MCORDService.get_service_objects_by_user(request.user)
+
+# Class to represent the form to add and edit tenants.
+# We need to define this instead of just using an admin like we did for the
+# service because tenants vary more than services and there isn't a common form.
+# This allows us to change the python behavior for the admin form to save extra
+# fields and control defaults.
+class VBBUComponentForm(forms.ModelForm):
+    # Defines a field for the creator of this service. It is a dropdown which
+    # is populated with all of the users.
+    creator = forms.ModelChoiceField(queryset=User.objects.all())
+    # Defines a text field for the display message, it is not required.
+    display_message = forms.CharField(required=False)
+
+    def __init__(self, *args, **kwargs):
+        super(VBBUComponentForm, self).__init__(*args, **kwargs)
+        # Set the kind field to readonly
+        self.fields['kind'].widget.attrs['readonly'] = True
+        # Define the logic for obtaining the objects for the provider_service
+        # dropdown of the tenant form.
+        self.fields[
+            'provider_service'].queryset = MCORDService.get_service_objects().all()
+        # Set the initial kind to HELLO_WORLD_KIND for this tenant.
+        self.fields['kind'].initial = MCORD_KIND
+        # If there is an instance of this model then we can set the initial
+        # form values to the existing values.
+        if self.instance:
+            self.fields['creator'].initial = self.instance.creator
+            self.fields[
+                'display_message'].initial = self.instance.display_message
+
+        # If there is not an instance then we need to set initial values.
+        if (not self.instance) or (not self.instance.pk):
+            self.fields['creator'].initial = get_request().user
+            if MCORDService.get_service_objects().exists():
+                self.fields["provider_service"].initial = MCORDService.get_service_objects().all()[0]
+
+    # This function describes what happens when the save button is pressed on
+    # the tenant form. In this case we set the values for the instance that were
+    # entered.
+    def save(self, commit=True):
+        self.instance.creator = self.cleaned_data.get("creator")
+        self.instance.display_message = self.cleaned_data.get(
+            "display_message")
+        return super(VBBUComponentForm, self).save(commit=commit)
+
+    class Meta:
+        model = VBBUComponent
+
+# Class to represent the form to add and edit tenants.
+# We need to define this instead of just using an admin like we did for the
+# service because tenants vary more than services and there isn't a common form.
+# This allows us to change the python behavior for the admin form to save extra
+# fields and control defaults.
+class VPGWCComponentForm(forms.ModelForm):
+    # Defines a field for the creator of this service. It is a dropdown which
+    # is populated with all of the users.
+    creator = forms.ModelChoiceField(queryset=User.objects.all())
+    # Defines a text field for the display message, it is not required.
+    display_message = forms.CharField(required=False)
+
+    def __init__(self, *args, **kwargs):
+        super(VPGWCComponentForm, self).__init__(*args, **kwargs)
+        # Set the kind field to readonly
+        self.fields['kind'].widget.attrs['readonly'] = True
+        # Define the logic for obtaining the objects for the provider_service
+        # dropdown of the tenant form.
+        self.fields[
+            'provider_service'].queryset = MCORDService.get_service_objects().all()
+        # Set the initial kind to HELLO_WORLD_KIND for this tenant.
+        self.fields['kind'].initial = MCORD_KIND
+        # If there is an instance of this model then we can set the initial
+        # form values to the existing values.
+        if self.instance:
+            self.fields['creator'].initial = self.instance.creator
+            self.fields[
+                'display_message'].initial = self.instance.display_message
+
+        # If there is not an instance then we need to set initial values.
+        if (not self.instance) or (not self.instance.pk):
+            self.fields['creator'].initial = get_request().user
+            if MCORDService.get_service_objects().exists():
+                self.fields["provider_service"].initial = MCORDService.get_service_objects().all()[0]
+
+    # This function describes what happens when the save button is pressed on
+    # the tenant form. In this case we set the values for the instance that were
+    # entered.
+    def save(self, commit=True):
+        self.instance.creator = self.cleaned_data.get("creator")
+        self.instance.display_message = self.cleaned_data.get(
+            "display_message")
+        return super(VPGWCComponentForm, self).save(commit=commit)
+
+    class Meta:
+        model = VPGWCComponent
+
+
+
+# Define the admin form for the tenant. This uses a similar structure as the
+# service but uses HelloWorldTenantCompleteForm to change the python behavior.
+
+
+class VBBUComponentAdmin(ReadOnlyAwareAdmin):
+    verbose_name = "vBBU Component"
+    verbose_name_plural = "vBBU Components"
+    list_display = ('id', 'backend_status_icon', 'instance', 'display_message')
+    list_display_links = ('backend_status_icon', 'instance', 'display_message',
+                          'id')
+    fieldsets = [(None, {'fields': ['backend_status_text', 'kind',
+                                    'provider_service', 'instance', 'creator',
+                                    'display_message'],
+                         'classes': ['suit-tab suit-tab-general']})]
+    readonly_fields = ('backend_status_text', 'instance',)
+    form = VBBUComponentForm
+
+    suit_form_tabs = (('general', 'Details'),)
+
+    def queryset(self, request):
+        return VBBUComponent.get_tenant_objects_by_user(request.user)
+
+
+# Define the admin form for the tenant. This uses a similar structure as the
+# service but uses HelloWorldTenantCompleteForm to change the python behavior.
+class VPGWCComponentAdmin(ReadOnlyAwareAdmin):
+    verbose_name = "vPGWC Component"
+    verbose_name_plural = "vPGWC Components"
+    list_display = ('id', 'backend_status_icon', 'instance', 'display_message')
+    list_display_links = ('backend_status_icon', 'instance', 'display_message',
+                          'id')
+    fieldsets = [(None, {'fields': ['backend_status_text', 'kind',
+                                    'provider_service', 'instance', 'creator',
+                                    'display_message'],
+                         'classes': ['suit-tab suit-tab-general']})]
+    readonly_fields = ('backend_status_text', 'instance',)
+    form = VPGWCComponentForm
+
+    suit_form_tabs = (('general', 'Details'),)
+
+    def queryset(self, request):
+        return VPGWCComponent.get_tenant_objects_by_user(request.user)
+
+# Associate the admin forms with the models.
+admin.site.register(MCORDService, MCORDServiceAdmin)
+admin.site.register(VBBUComponent, VBBUComponentAdmin)
+admin.site.register(VPGWCComponent, VPGWCComponentAdmin)
diff --git a/xos/services/mcord/migrations/0001_initial.py b/xos/services/mcord/migrations/0001_initial.py
new file mode 100644
index 0000000..a11fe30
--- /dev/null
+++ b/xos/services/mcord/migrations/0001_initial.py
@@ -0,0 +1,44 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('core', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='MCORDService',
+            fields=[
+            ],
+            options={
+                'verbose_name': 'MCORD Service',
+                'proxy': True,
+            },
+            bases=('core.service',),
+        ),
+        migrations.CreateModel(
+            name='VBBUComponent',
+            fields=[
+            ],
+            options={
+                'verbose_name': 'VBBU MCORD Service Component',
+                'proxy': True,
+            },
+            bases=('core.tenantwithcontainer',),
+        ),
+        migrations.CreateModel(
+            name='VPGWCComponent',
+            fields=[
+            ],
+            options={
+                'verbose_name': 'VPGWC MCORD Service Component',
+                'proxy': True,
+            },
+            bases=('core.tenantwithcontainer',),
+        ),
+    ]
diff --git a/xos/services/mcord/migrations/__init__.py b/xos/services/mcord/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xos/services/mcord/migrations/__init__.py
diff --git a/xos/services/mcord/models.py b/xos/services/mcord/models.py
new file mode 100644
index 0000000..6d070d8
--- /dev/null
+++ b/xos/services/mcord/models.py
@@ -0,0 +1,483 @@
+from django.db import models
+from core.models import Service, PlCoreBase, Slice, Instance, Tenant, TenantWithContainer, Node, Image, User, Flavor, Subscriber, NetworkParameter, NetworkParameterType, AddressPool, Port
+from core.models.plcorebase import StrippedCharField
+import os
+from django.db import models, transaction
+from django.forms.models import model_to_dict
+from django.db.models import Q
+from operator import itemgetter, attrgetter, methodcaller
+from core.models import Tag
+from core.models.service import LeastLoadedNodeScheduler
+import traceback
+from xos.exceptions import *
+from core.models import SlicePrivilege, SitePrivilege
+from sets import Set
+from xos.config import Config
+
+MCORD_KIND = "RAN" # This should be changed later I did it fo demo
+MCORD_USE_VTN = getattr(Config(), "networking_use_vtn", False)
+VBBU_KIND = "RAN"
+VSGW_KIND = "vSGW"
+VPGWC_KIND = "RAN"
+vbbu_net_types = ("s1u", "s1mme", "rru")
+vpgwc_net_types = ("s5s8")
+# The class to represent the service. Most of the service logic is given for us
+# in the Service class but, we have some configuration that is specific for
+# this example.
+class MCORDService(Service):
+    KIND = MCORD_KIND
+
+    class Meta:
+        # When the proxy field is set to True the model is represented as
+        # it's superclass in the database, but we can still change the python
+        # behavior. In this case HelloWorldServiceComplete is a Service in the
+        # database.
+        proxy = True
+        # The name used to find this service, all directories are named this
+        app_label = "mcord"
+        verbose_name = "MCORD Service"
+
+# This is the class to represent the tenant. Most of the logic is given to use
+# in TenantWithContainer, however there is some configuration and logic that
+# we need to define for this example.
+class VBBUComponent(TenantWithContainer):
+
+    class Meta:
+        # Same as a above, HelloWorldTenantComplete is represented as a
+        # TenantWithContainer, but we change the python behavior.
+        proxy = True
+        verbose_name = "VBBU MCORD Service Component"
+
+    # The kind of the service is used on forms to differentiate this service
+    # from the other services.
+    KIND = VBBU_KIND
+
+    # Ansible requires that the sync_attributes field contain nat_ip and nat_mac
+    # these will be used to determine where to SSH to for ansible.
+    # Getters must be defined for every attribute specified here.
+    sync_attributes = ("s1u_ip", "s1u_mac",
+                       "s1mme_ip", "s1mme_mac",
+                       "rru_ip", "rru_mac")
+    # default_attributes is used cleanly indicate what the default values for
+    # the fields are.
+    default_attributes = {"display_message": "New vBBU Component", "s1u_tag": "901", "s1mme_tag": "900", "rru_tag": "999"}
+    def __init__(self, *args, **kwargs):
+        mcord_services = MCORDService.get_service_objects().all()
+        # When the tenant is created the default service in the form is set
+        # to be the first created HelloWorldServiceComplete
+        if mcord_services:
+            self._meta.get_field(
+                "provider_service").default = mcord_services[0].id
+        super(VBBUComponent, self).__init__(*args, **kwargs)
+
+    def can_update(self, user):
+        #Allow creation of this model instances for non-admin users also
+        return True
+
+    def save(self, *args, **kwargs):
+        if not self.creator:
+            if not getattr(self, "caller", None):
+                # caller must be set when creating a monitoring channel since it creates a slice
+                raise XOSProgrammingError("ServiceComponents's self.caller was not set")
+            self.creator = self.caller
+            if not self.creator:
+                raise XOSProgrammingError("ServiceComponents's self.creator was not set")
+
+        super(VBBUComponent, self).save(*args, **kwargs)
+        # This call needs to happen so that an instance is created for this
+        # tenant is created in the slice. One instance is created per tenant.
+        model_policy_mcord_servicecomponent(self.pk)
+
+    def save_instance(self, instance):
+        with transaction.atomic():
+            super(VBBUComponent, self).save_instance(instance)
+            if instance.isolation in ["vm"]:
+                for ntype in vbbu_net_types:
+                    lan_network = self.get_lan_network(instance, ntype)
+                    port = self.find_or_make_port(instance,lan_network)
+                    if (ntype == "s1u"):
+                        port.set_parameter("s_tag", self.s1u_tag)
+                        port.set_parameter("neutron_port_name", "stag-%s" % self.s1u_tag)
+                        port.save()
+                    elif (ntype == "s1mme"):
+                        port.set_parameter("s_tag", self.s1mme_tag)
+                        port.set_parameter("neutron_port_name", "stag-%s" % self.s1mme_tag)
+                        port.save()
+                    elif (ntype == "rru"):
+                        port.set_parameter("s_tag", self.rru_tag)
+                        port.set_parameter("neutron_port_name", "stag-%s" % self.rru_tag)
+                        port.save()
+    
+    def delete(self, *args, **kwargs):
+        # Delete the instance that was created for this tenant
+        self.cleanup_container()
+        super(VBBUComponent, self).delete(*args, **kwargs)
+
+    def find_or_make_port(self, instance, network, **kwargs):
+        port = Port.objects.filter(instance=instance, network=network)
+        if port:
+            port = port[0]
+            print "port already exist", port[0]
+        else:
+            port = Port(instance=instance, network=network, **kwargs)
+            print "NETWORK", network, "MAKE_PORT", port 
+            port.save()
+        return port
+
+    def get_lan_network(self, instance, ntype):
+        slice = self.provider_service.slices.all()[0]
+        lan_networks = [x for x in slice.networks.all() if ntype in x.name]
+        if not lan_networks:
+            raise XOSProgrammingError("No lan_network")
+        return lan_networks[0]
+
+    def manage_container(self):
+        from core.models import Instance, Flavor
+
+        if self.deleted:
+            return
+
+        # For container or container_vm isolation, use what TenantWithCotnainer
+        # provides us
+        slice = self.get_slice()
+        if slice.default_isolation in ["container_vm", "container"]:
+            super(VBBUComponent,self).manage_container()
+            return
+
+        if not self.s1u_tag:
+            raise XOSConfigurationError("S1U_TAG is missed")
+
+        if not self.s1mme_tag:
+            raise XOSConfigurationError("S1U_TAG is missed")
+
+        if not self.rru_tag:
+            raise XOSConfigurationError("S1U_TAG is missed")
+
+        if self.instance:
+            # We're good.
+            return
+
+        instance = self.make_instance()
+        self.instance = instance
+        super(TenantWithContainer, self).save()
+
+    def get_slice(self):
+        if not self.provider_service.slices.count():
+            raise XOSConfigurationError("The service has no slices")
+        slice = self.provider_service.slices.all()[0]
+        return slice
+
+    def make_instance(self):
+        slice = self.provider_service.slices.all()[0]            
+        flavors = Flavor.objects.filter(name=slice.default_flavor)
+#        flavors = Flavor.objects.filter(name="m1.xlarge")
+        if not flavors:
+            raise XOSConfigurationError("No default flavor")
+        default_flavor = slice.default_flavor
+        slice = self.provider_service.slices.all()[0]
+        if slice.default_isolation == "container_vm":
+            (node, parent) = ContainerVmScheduler(slice).pick()
+        else:
+            (node, parent) = LeastLoadedNodeScheduler(slice).pick()
+        instance = Instance(slice = slice,
+                        node = node,
+                        image = self.image,
+                        creator = self.creator,
+                        deployment = node.site_deployment.deployment,
+                        flavor = flavors[0],
+                        isolation = slice.default_isolation,
+                        parent = parent)
+        self.save_instance(instance)
+        return instance
+
+    def ip_to_mac(self, ip):
+        (a, b, c, d) = ip.split('.')
+        return "02:42:%02x:%02x:%02x:%02x" % (int(a), int(b), int(c), int(d))
+
+    # Getter for the message that will appear on the webpage
+    # By default it is "Hello World!"
+    @property
+    def display_message(self):
+        return self.get_attribute(
+            "display_message",
+            self.default_attributes['display_message'])
+
+    @display_message.setter
+    def display_message(self, value):
+        self.set_attribute("display_message", value)
+
+    @property
+    def s1u_tag(self):
+        return self.get_attribute(
+            "s1u_tag",
+            self.default_attributes['s1u_tag'])
+
+    @s1u_tag.setter
+    def s1u_tag(self, value):
+        self.set_attribute("s1u_tag", value)
+
+    @property
+    def s1mme_tag(self):
+        return self.get_attribute(
+            "s1mme_tag",
+            self.default_attributes['s1mme_tag'])
+
+    @s1mme_tag.setter
+    def s1mme_tag(self, value):
+        self.set_attribute("s1mme_tag", value)
+
+    @property
+    def rru_tag(self):
+        return self.get_attribute(
+            "rru_tag",
+            self.default_attributes['rru_tag'])
+
+    @rru_tag.setter
+    def rru_tag(self, value):
+        self.set_attribute("rru_tag", value)
+
+
+    @property
+    def addresses(self):
+        if (not self.id) or (not self.instance):
+            return {}
+
+        addresses = {}
+        for ns in self.instance.ports.all():
+            if "s1u" in ns.network.name.lower():
+                addresses["s1u"] = (ns.ip, ns.mac)
+            elif "s1mme" in ns.network.name.lower():
+                addresses["s1mme"] = (ns.ip, ns.mac)
+            elif "rru" in ns.network.name.lower():
+                addresses["rru"] = (ns.ip, ns.mac)
+        return addresses
+
+
+    @property
+    def s1u_ip(self):
+        return self.addresses.get("s1u", (None, None))[0]
+    @property
+    def s1u_mac(self):
+        return self.addresses.get("s1u", (None, None))[1]
+    @property
+    def s1mme_ip(self):
+        return self.addresses.get("s1mme", (None, None))[0]
+    @property
+    def s1mme_mac(self):
+        return self.addresses.get("s1mme", (None, None))[1]
+    @property
+    def rru_ip(self):
+        return self.addresses.get("rru", (None, None))[0]
+    @property
+    def rru_mac(self):
+        return self.addresses.get("rru", (None, None))[1]
+
+
+# This is the class to represent the tenant. Most of the logic is given to use
+# in TenantWithContainer, however there is some configuration and logic that
+# we need to define for this example.
+class VPGWCComponent(TenantWithContainer):
+
+    class Meta:
+        # Same as a above, HelloWorldTenantComplete is represented as a
+        # TenantWithContainer, but we change the python behavior.
+        proxy = True
+        verbose_name = "VPGWC MCORD Service Component"
+
+    # The kind of the service is used on forms to differentiate this service
+    # from the other services.
+    KIND = VPGWC_KIND
+
+    # Ansible requires that the sync_attributes field contain nat_ip and nat_mac
+    # these will be used to determine where to SSH to for ansible.
+    # Getters must be defined for every attribute specified here.
+    sync_attributes = ("s5s8_pgw_ip", "s5s8_pgw_mac")
+
+    # default_attributes is used cleanly indicate what the default values for
+    # the fields are.
+    default_attributes = {"display_message": "New vPGWC Component", "s5s8_pgw_tag": "300"}
+    def __init__(self, *args, **kwargs):
+        mcord_services = MCORDService.get_service_objects().all()
+        # When the tenant is created the default service in the form is set
+        # to be the first created HelloWorldServiceComplete
+        if mcord_services:
+            self._meta.get_field(
+                "provider_service").default = mcord_services[0].id
+        super(VPGWCComponent, self).__init__(*args, **kwargs)
+
+    def can_update(self, user):
+        #Allow creation of this model instances for non-admin users also
+        return True
+
+    def save(self, *args, **kwargs):
+        if not self.creator:
+            if not getattr(self, "caller", None):
+                # caller must be set when creating a monitoring channel since it creates a slice
+                raise XOSProgrammingError("ServiceComponents's self.caller was not set")
+            self.creator = self.caller
+            if not self.creator:
+                raise XOSProgrammingError("ServiceComponents's self.creator was not set")
+
+        super(VPGWCComponent, self).save(*args, **kwargs)
+        # This call needs to happen so that an instance is created for this
+        # tenant is created in the slice. One instance is created per tenant.
+        model_policy_mcord_servicecomponent(self.pk)
+
+    def save_instance(self, instance):
+        with transaction.atomic():
+            super(VPGWCComponent, self).save_instance(instance)
+            if instance.isolation in ["vm"]:
+                for ntype in vpgwc_net_types:
+                    lan_network = self.get_lan_network(instance, ntype)
+                    port = self.find_or_make_port(instance,lan_network)
+                    if (ntype == "s5s8"):
+                        port.set_parameter("s_tag", self.s5s8_pgw_tag)
+                        port.set_parameter("neutron_port_name", "stag-%s" % self.s5s8_pgw_tag)
+                        port.save()
+                    else:
+			return True
+
+    def delete(self, *args, **kwargs):
+        # Delete the instance that was created for this tenant
+        self.cleanup_container()
+        super(VPGWCComponent, self).delete(*args, **kwargs)
+
+    def find_or_make_port(self, instance, network, **kwargs):
+        port = Port.objects.filter(instance=instance, network=network)
+        if port:
+            port = port[0]
+            print "port already exist", port[0]
+        else:
+            port = Port(instance=instance, network=network, **kwargs)
+            print "NETWORK", network, "MAKE_PORT", port 
+            port.save()
+        return port
+
+    def get_lan_network(self, instance, ntype):
+        slice = self.provider_service.slices.all()[0]
+        lan_networks = [x for x in slice.networks.all() if ntype in x.name]
+        if not lan_networks:
+            raise XOSProgrammingError("No lan_network")
+        return lan_networks[0]
+
+    def manage_container(self):
+        from core.models import Instance, Flavor
+
+        if self.deleted:
+            return
+
+        # For container or container_vm isolation, use what TenantWithCotnainer
+        # provides us
+        slice = self.get_slice()
+        if slice.default_isolation in ["container_vm", "container"]:
+            super(VPGWCComponent,self).manage_container()
+            return
+
+        if not self.s5s8_pgw_tag:
+            raise XOSConfigurationError("S5S8_PGW_TAG is missed")
+
+        if self.instance:
+            # We're good.
+            return
+
+        instance = self.make_instance()
+        self.instance = instance
+        super(TenantWithContainer, self).save()
+
+    def get_slice(self):
+        if not self.provider_service.slices.count():
+            raise XOSConfigurationError("The service has no slices")
+        slice = self.provider_service.slices.all()[0]
+        return slice
+
+    def make_instance(self):
+        slice = self.provider_service.slices.all()[0]            
+        flavors = Flavor.objects.filter(name=slice.default_flavor)
+#        flavors = Flavor.objects.filter(name="m1.xlarge")
+        if not flavors:
+            raise XOSConfigurationError("No default flavor")
+        default_flavor = slice.default_flavor
+        slice = self.provider_service.slices.all()[0]
+        if slice.default_isolation == "container_vm":
+            (node, parent) = ContainerVmScheduler(slice).pick()
+        else:
+            (node, parent) = LeastLoadedNodeScheduler(slice).pick()
+        instance = Instance(slice = slice,
+                        node = node,
+                        image = self.image,
+                        creator = self.creator,
+                        deployment = node.site_deployment.deployment,
+                        flavor = flavors[0],
+                        isolation = slice.default_isolation,
+                        parent = parent)
+        self.save_instance(instance)
+        return instance
+
+    def ip_to_mac(self, ip):
+        (a, b, c, d) = ip.split('.')
+        return "02:42:%02x:%02x:%02x:%02x" % (int(a), int(b), int(c), int(d))
+
+    # Getter for the message that will appear on the webpage
+    # By default it is "Hello World!"
+    @property
+    def display_message(self):
+        return self.get_attribute(
+            "display_message",
+            self.default_attributes['display_message'])
+
+    @display_message.setter
+    def display_message(self, value):
+        self.set_attribute("display_message", value)
+
+    @property
+    def s5s8_pgw_tag(self):
+        return self.get_attribute(
+            "s5s8_pgw_tag",
+            self.default_attributes['s5s8_pgw_tag'])
+
+    @s5s8_pgw_tag.setter
+    def s5s8_pgw_tag(self, value):
+        self.set_attribute("s5s8_pgw_tag", value)
+
+
+    @property
+    def addresses(self):
+        if (not self.id) or (not self.instance):
+            return {}
+
+        addresses = {}
+        for ns in self.instance.ports.all():
+            if "s5s8_pgw" in ns.network.name.lower():
+                addresses["s5s8_pgw"] = (ns.ip, ns.mac)
+        return addresses
+
+
+    @property
+    def s5s8_pgw_ip(self):
+        return self.addresses.get("s5s8_pgw", (None, None))[0]
+    @property
+    def s5s8_pgw_mac(self):
+        return self.addresses.get("s5s8_pgw", (None, None))[1]
+
+def model_policy_mcord_servicecomponent(pk):
+    # This section of code is atomic to prevent race conditions
+    with transaction.atomic():
+        # We find all of the tenants that are waiting to update
+        component = VBBUComponent.objects.select_for_update().filter(pk=pk)
+        if not component:
+            return
+        # Since this code is atomic it is safe to always use the first tenant
+        component = component[0]
+        component.manage_container()
+
+
+def model_policy_mcord_servicecomponent(pk):
+    # This section of code is atomic to prevent race conditions
+    with transaction.atomic():
+        # We find all of the tenants that are waiting to update
+        component = VPGWCComponent.objects.select_for_update().filter(pk=pk)
+        if not component:
+            return
+        # Since this code is atomic it is safe to always use the first tenant
+        component = component[0]
+        component.manage_container()
diff --git a/xos/services/mcord/templates/mcordadmin.html b/xos/services/mcord/templates/mcordadmin.html
new file mode 100644
index 0000000..4a69dcc
--- /dev/null
+++ b/xos/services/mcord/templates/mcordadmin.html
@@ -0,0 +1,10 @@
+<!-- Template used to for the button leading to the HelloWorldTenantComplete form. -->
+<div class = "left-nav">
+  <ul>
+    <li>
+      <a href="/admin/mcordservice/vbbucomponent/">
+        MCORD Service Components
+      </a>
+    </li>
+  </ul>
+</div>
diff --git a/xos/services/mcord/view.py b/xos/services/mcord/view.py
new file mode 100644
index 0000000..dc5f06a
--- /dev/null
+++ b/xos/services/mcord/view.py
@@ -0,0 +1,106 @@
+from django.http import HttpResponse
+from django.views.generic import TemplateView, View
+from django import template
+from core.models import *
+import json
+import os
+import time
+import tempfile
+
+
+class MCordView(TemplateView):
+    head_template = r"""{% extends "admin/dashboard/dashboard_base.html" %}
+       {% load admin_static %}
+       {% block content %}
+    """
+
+    tail_template = r"{% endblock %}"
+
+    def get(self, request, name="root", *args, **kwargs):
+        head_template = self.head_template
+        tail_template = self.tail_template
+
+        title = request.GET.get('service', '')
+        url = "/mcord/?service=%s" % (title)
+
+        form = """
+        <h2 class="content-title">Change %s Service</h2>
+        <div id="content-main">
+            <form class="form-horizontal">
+                <div class="tab-content tab-content-main">
+                    <div class="suit-include suit-tab suit-tab-administration hide">
+                        <div class="left-nav">
+                            <ul>
+                                <li><a href="/admin/ceilometer/monitoringchannel/">Monitoring Channels</a></li>
+                            </ul>
+                        </div>
+                    </div>
+                    <fieldset class="module aligned suit-tab suit-tab-general show">
+                        <div class="panel fieldset-body">
+                            <div class="form-group field-backend_status_text ">
+                                <label class="control-label col-xs-12 col-sm-2"><label>Backend status text:</label></label>
+                                <div class="form-column col-xs-12 col-sm-8 col-md-6 col-lg-4">
+                                    <p><img src="/static/admin/img/icon_clock.gif"> Pending sync, last_status = 0 - Provisioning in progress</p>
+                                </div>
+                            </div>
+                            <div class="form-group field-name ">
+                                <label class="control-label col-xs-12 col-sm-2"><label class="required" for="id_name">Name:</label></label>
+                                <div class="form-column widget-AdminTextInputWidget col-xs-12 col-sm-8 col-md-6 col-lg-4">
+                                    <input class="vTextField form-control" id="id_name" maxlength="30" name="name" type="text" value="%s">
+                                    <div class="help-block">Service Name</div>
+                                </div>
+                            </div>
+                            <div class="form-group field-enabled ">
+                                <label class="control-label col-xs-12 col-sm-2"><label class="vCheckboxLabel" for="id_enabled">Enabled</label></label>
+                                <div class="form-column widget-CheckboxInput col-xs-12 col-sm-8 col-md-6 col-lg-4">
+                                    <input checked="checked" id="id_enabled" name="enabled" type="checkbox">
+                                </div>
+                            </div>
+                            <div class="form-group field-versionNumber ">
+                                <label class="control-label col-xs-12 col-sm-2"><label class="required" for="id_versionNumber">VersionNumber:</label></label>
+                                <div class="form-column widget-AdminTextInputWidget col-xs-12 col-sm-8 col-md-6 col-lg-4">
+                                    <input class="vTextField form-control" id="id_versionNumber" maxlength="30" name="versionNumber" type="text">
+                                    <div class="help-block">Version of Service Definition</div>
+                                </div>
+                            </div>
+                            <div class="form-group field-description ">
+                                <label class="control-label col-xs-12 col-sm-2"><label for="id_description">Description:</label></label>
+                                <div class="form-column widget-AdminTextareaWidget col-xs-12 col-sm-8 col-md-6 col-lg-4">
+                                    <textarea class="vLargeTextField form-control" cols="40" id="id_description" maxlength="254" name="description" rows="10"></textarea>
+                                    <div class="help-block">Description of Service</div>
+                                </div>
+                            </div>
+                            <div class="form-group field-view_url ">
+                                <label class="control-label col-xs-12 col-sm-2"><label for="id_view_url">View url:</label></label>
+                                <div class="form-column widget-AdminTextInputWidget col-xs-12 col-sm-8 col-md-6 col-lg-4">
+                                    <input class="vTextField form-control" id="id_view_url" maxlength="1024" name="view_url" type="text" value="%s">
+                                </div>
+                            </div>
+                            <div class="form-group field-icon_url ">
+                                <label class="control-label col-xs-12 col-sm-2"><label for="id_icon_url">Icon url:</label></label>
+                                <div class="form-column widget-AdminTextInputWidget col-xs-12 col-sm-8 col-md-6 col-lg-4">
+                                    <input class="vTextField form-control" id="id_icon_url" maxlength="1024" name="icon_url" type="text">
+                                </div>
+                            </div>
+                        </div>
+                    </fieldset>
+                </div>
+            </form>
+            <div class="form-buttons clearfix">
+                <button type="submit" class="btn btn-high btn-success" name="_save">Save</button>
+                <button type="submit" name="_continue" class=" btn btn-high btn-info">Save and continue editing</button>
+                <button type="submit" name="_addanother" class="btn btn-info">Save and add another</button>
+                <a href="delete/" class="text-error deletelink">Delete</a>
+            </div>
+        </div>
+        """ % (title, title, url)
+
+        t = template.Template(head_template + form + tail_template)
+
+        response_kwargs = {}
+        response_kwargs.setdefault('content_type', self.content_type)
+        return self.response_class(
+            request=request,
+            template=t,
+            **response_kwargs
+        )
diff --git a/xos/services/requestrouter/__init__.py b/xos/services/requestrouter/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xos/services/requestrouter/__init__.py
diff --git a/xos/services/requestrouter/admin.py b/xos/services/requestrouter/admin.py
new file mode 100644
index 0000000..6d9e2fe
--- /dev/null
+++ b/xos/services/requestrouter/admin.py
@@ -0,0 +1,63 @@
+from django.contrib import admin
+
+from services.requestrouter.models import *
+from django import forms
+from django.utils.safestring import mark_safe
+from django.contrib.auth.admin import UserAdmin
+from django.contrib.admin.widgets import FilteredSelectMultiple
+from django.contrib.auth.forms import ReadOnlyPasswordHashField
+from django.contrib.auth.signals import user_logged_in
+from django.utils import timezone
+from django.contrib.contenttypes import generic
+from suit.widgets import LinkedSelect
+from core.admin import ServiceAppAdmin,SliceInline,ServiceAttrAsTabInline, ReadOnlyAwareAdmin, ServicePrivilegeInline
+
+class RequestRouterAdmin(ReadOnlyAwareAdmin):
+   # Change the application breadcrumb to point to an RR Service if one is
+   # defined
+
+   change_form_template = "admin/change_form_bc.html"
+   change_list_template = "admin/change_list_bc.html"
+   custom_app_breadcrumb_name = "Request Router"
+   @property
+   def custom_app_breadcrumb_url(self):
+       services = RequestRouterService.objects.all()
+       if len(services)==1:
+           return "/admin/requestrouter/requestrouterservice/%s/" % services[0].id
+       else:
+           return "/admin/requestrouter/requestrouterservice/"
+
+class RequestRouterServiceAdmin(ServiceAppAdmin):
+    model = RequestRouterService
+    verbose_name = "Request Router Service"
+    verbose_name_plural = "Request Router Service"
+    list_display = ("name","enabled")
+    fieldsets = [(None, {'fields': ['name','enabled','versionNumber', 'description','behindNat','defaultTTL','defaultAction','lastResortAction','maxAnswers'], 'classes':['suit-tab suit-tab-general']})]
+    inlines = [SliceInline,ServiceAttrAsTabInline,ServicePrivilegeInline]
+
+    user_readonly_fields = ["name", "enabled", "versionNumber", "description", "behindNat", "defaultTTL", "defaultAction", "lastResortAction", "maxAnswers"]
+
+    suit_form_tabs =(('general', 'Request Router Service Details'),
+        ('administration', 'Administration'),
+        ('slices','Slices'),
+        ('serviceattrs','Additional Attributes'),
+        ('serviceprivileges','Privileges'),
+    )
+
+    suit_form_includes = (('rradmin.html', 'top', 'administration'),)
+
+class ServiceMapAdmin(RequestRouterAdmin):
+    model = ServiceMap
+    verbose_name = "Service Map"
+    verbose_name_plural = "Service Map"
+    list_display = ("name", "owner", "slice", "prefix")
+    fieldsets = [(None, {'fields': ['name','owner','slice', 'prefix','siteMap','accessMap'], 'classes':['suit-tab suit-tab-general']})]
+
+    user_readonly_fields = ["name", "owner", "slice", "prefix", "siteMap", "accessMap"]
+
+    suit_form_tabs =(('general', 'Service Map Details'),
+    )
+
+admin.site.register(RequestRouterService, RequestRouterServiceAdmin)
+admin.site.register(ServiceMap, ServiceMapAdmin)
+
diff --git a/xos/services/requestrouter/migrations/__init__.py b/xos/services/requestrouter/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xos/services/requestrouter/migrations/__init__.py
diff --git a/xos/services/requestrouter/models.py b/xos/services/requestrouter/models.py
new file mode 100644
index 0000000..8e4cc43
--- /dev/null
+++ b/xos/services/requestrouter/models.py
@@ -0,0 +1,41 @@
+from core.models import User,Site,Service,SingletonModel,PlCoreBase, Slice
+import os
+from django.db import models
+from django.forms.models import model_to_dict
+
+# Create your models here.
+
+class RequestRouterService(SingletonModel,Service):
+    class Meta:
+        app_label = "requestrouter"
+        verbose_name = "Request Router Service"
+
+    behindNat = models.BooleanField(default=False, help_text="Enables 'Behind NAT' mode.")
+    defaultTTL = models.PositiveIntegerField(default=30, help_text="DNS response time-to-live(TTL)")
+    defaultAction = models.CharField(max_length=30, default = "best", help_text="Review if this should be enum")
+    lastResortAction = models.CharField(max_length=30, default = "random", help_text="Review if this should be enum")
+    maxAnswers = models.PositiveIntegerField(default=3, help_text="Maximum number of answers in DNS response.")
+
+    def __unicode__(self):  return u'Request Router Service'
+
+class ServiceMap(PlCoreBase):
+
+    class Meta:
+        app_label = "requestrouter"
+
+    name = models.SlugField(max_length=50, unique=True, blank=False, null=False, help_text="name of this service map")
+    owner = models.ForeignKey(Service, help_text="service which owns this map")
+    slice = models.ForeignKey(Slice, help_text="slice that implements this service")
+    prefix = models.CharField(max_length=256, help_text="FQDN of the region of URI space managed by RR on behalf of this service")
+	# need to fix the upload location appropriately, for now we are not using access/site map
+    siteMap = models.FileField(upload_to="maps/", help_text="maps client requests to service instances", blank=True)
+    accessMap = models.FileField(upload_to="maps/", help_text="specifies which client requests are allowed", blank=True)
+
+    def siteMapName(self):
+        return self.name + ".site"
+
+    def accessMapName(self):
+        return self.name + ".access"
+
+    def __unicode__(self): return u'%s' % self.name
+
diff --git a/xos/services/requestrouter/templates/rradmin.html b/xos/services/requestrouter/templates/rradmin.html
new file mode 100644
index 0000000..142d87a
--- /dev/null
+++ b/xos/services/requestrouter/templates/rradmin.html
@@ -0,0 +1,13 @@
+<div class = "left-nav">
+<ul>
+{% for admin in registered_admins %}
+    <li><a href="{{ admin.url }}">{{ admin.name }}</a></li>
+{% endfor %}
+</ul>
+</div>
+
+<!--
+<ul>
+<li><a href="/admin/requestrouter/servicemap/">Service Maps</a></li>
+</ul>
+-->
diff --git a/xos/services/syndicate_storage/__init__.py b/xos/services/syndicate_storage/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xos/services/syndicate_storage/__init__.py
diff --git a/xos/services/syndicate_storage/admin.py b/xos/services/syndicate_storage/admin.py
new file mode 100644
index 0000000..779f83b
--- /dev/null
+++ b/xos/services/syndicate_storage/admin.py
@@ -0,0 +1,158 @@
+from django.contrib import admin
+
+from services.syndicate_storage.models import *
+from django import forms
+from django.utils.safestring import mark_safe
+from django.contrib.auth.admin import UserAdmin
+from django.contrib.admin.widgets import FilteredSelectMultiple
+from django.contrib.auth.forms import ReadOnlyPasswordHashField
+from django.contrib.auth.signals import user_logged_in
+from django.utils import timezone
+from django.contrib.contenttypes import generic
+from suit.widgets import LinkedSelect
+from core.admin import ReadOnlyAwareAdmin,ServiceAppAdmin,SliceInline,ServiceAttrAsTabInline,XOSBaseAdmin, XOSTabularInline
+from suit.widgets import LinkedSelect
+from django.core.exceptions import ValidationError, ObjectDoesNotExist
+
+class SyndicateAdmin(ReadOnlyAwareAdmin):
+   # Change the application breadcrumb to point to an RR Service if one is
+   # defined
+
+   change_form_template = "admin/change_form_bc.html"
+   change_list_template = "admin/change_list_bc.html"
+   custom_app_breadcrumb_name = "Syndicate_Storage"
+   @property
+   def custom_app_breadcrumb_url(self):
+       services = SyndicateService.objects.all()
+       if len(services)==1:
+           return "/admin/syndicate_storage/syndicateservice/%s/" % services[0].id
+       else:
+           return "/admin/syncdicate_storage/syndicateservice/"
+
+class SyndicateServiceAdmin(ServiceAppAdmin):
+    model = SyndicateService
+    verbose_name = "Syndicate Storage"
+    verbose_name_plural = "Syndicate Storage"
+    list_display = ("name","enabled")
+    fieldsets = [(None, {'fields': ['name','enabled','versionNumber', 'description',], 'classes':['suit-tab suit-tab-general']})]
+    inlines = [SliceInline,ServiceAttrAsTabInline]
+
+    user_readonly_fields = ['name','enabled','versionNumber','description']
+
+    suit_form_tabs =(('general', 'Syndicate Storage Details'),
+        ('administration', 'Administration'),
+        ('slices','Slices'),
+        ('serviceattrs','Additional Attributes'),
+    )
+
+    suit_form_includes = (('syndicateadmin.html', 'top', 'administration'),)
+
+
+class VolumeAccessRightInline(XOSTabularInline):
+    model = VolumeAccessRight
+    extra = 0
+    suit_classes = 'suit-tab suit-tab-volumeAccessRights'
+
+
+class VolumeSliceFormSet( forms.models.BaseInlineFormSet ):
+    # verify that our VolumeSlice is valid
+
+    @classmethod
+    def verify_unchanged( cls, volume_pk, slice_pk, field_name, new_value ):
+        vs = None
+        try:
+           vs = VolumeSlice.objects.get( volume_id=volume_pk, slice_id=slice_pk )
+        except ObjectDoesNotExist, dne:
+           return True, None
+
+        old_value = getattr( vs, field_name )
+        if old_value != new_value:
+            return False, old_value
+        else:
+            return True, None
+
+
+    def clean( self ):
+        for form in self.forms:
+            # check each inline's cleaned data, if it's valid
+            cleaned_data = None
+            try:
+                if form.cleaned_data:
+                    cleaned_data = form.cleaned_data
+            except AttributeError:
+                continue
+             
+            # verify that the ports haven't changed 
+            volume_pk = cleaned_data['volume_id'].pk
+            slice_pk = cleaned_data['slice_id'].pk
+           
+            if not cleaned_data.has_key('UG_portnum'):
+                raise ValidationError("Missing UG port number")
+
+            if not cleaned_data.has_key('RG_portnum'):
+                raise ValidationError("Missing RG port number")
+
+            rc1, old_peer_port = VolumeSliceFormSet.verify_unchanged( volume_pk, slice_pk, 'UG_portnum', cleaned_data['UG_portnum'] )
+            rc2, old_replicate_port = VolumeSliceFormSet.verify_unchanged( volume_pk, slice_pk, 'RG_portnum', cleaned_data['RG_portnum'] )
+
+            err1str = ""
+            err2str = ""
+            if not rc1:
+                err1str = "change %s back to %s" % (cleaned_data['UG_portnum'], old_peer_port)
+            if not rc2:
+                err2str = " and change %s back to %s" % (cleaned_data['RG_portnum'], old_replicate_port )
+
+            if not rc1 or not rc2:
+                raise ValidationError("At this time, port numbers cannot be changed once they are set. Please %s %s" % (err1str, err2str))
+            
+            
+
+class VolumeSliceInline(XOSTabularInline):
+    model = VolumeSlice
+    extra = 0
+    suit_classes = 'suit-tab suit-tab-volumeSlices'
+    fields = ['volume_id', 'slice_id', 'cap_read_data', 'cap_write_data', 'cap_host_data', 'UG_portnum', 'RG_portnum']
+
+    formset = VolumeSliceFormSet
+    
+    readonly_fields = ['credentials_blob']
+ 
+
+class VolumeAdmin(SyndicateAdmin):
+    model = Volume
+   
+    def get_readonly_fields(self, request, obj=None ):
+       always_readonly = []
+       if obj == None:
+          # all fields are editable on add
+          return always_readonly
+
+       else:
+          # can't change owner, slice id, or block size on update
+          return ['blocksize', 'owner_id'] + always_readonly
+
+
+    list_display = ['name', 'owner_id']
+
+    detailsFieldList = ['name', 'owner_id', 'description','blocksize', 'private','archive', 'cap_read_data', 'cap_write_data', 'cap_host_data' ]
+
+    fieldsets = [
+        (None, {'fields': detailsFieldList, 'classes':['suit-tab suit-tab-general']}),
+    ]
+
+    inlines = [VolumeAccessRightInline, VolumeSliceInline]
+
+    user_readonly_fields = ['name','owner_id','description','blocksize','private', 'archive', 'cap_read_data', 'cap_write_data', 'cap_host_data']
+    
+    suit_form_tabs =(('general', 'Volume Details'),
+                     ('volumeSlices', 'Slices'),
+                     ('volumeAccessRights', 'Volume Access Rights'))
+    
+    def queryset(self, request):
+       # only show volumes that are public, or owned by the caller 
+       return Volume.select_by_user(request.user)
+    
+    
+# left panel:
+admin.site.register(SyndicateService, SyndicateServiceAdmin)
+admin.site.register(Volume, VolumeAdmin)
diff --git a/xos/services/syndicate_storage/migrations/__init__.py b/xos/services/syndicate_storage/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xos/services/syndicate_storage/migrations/__init__.py
diff --git a/xos/services/syndicate_storage/models.py b/xos/services/syndicate_storage/models.py
new file mode 100644
index 0000000..27db059
--- /dev/null
+++ b/xos/services/syndicate_storage/models.py
@@ -0,0 +1,259 @@
+from core.models import User,Site,Service,SingletonModel,PlCoreBase,Slice,SlicePrivilege
+import os
+from django.db import models
+from django.db.models import Q
+from django.forms.models import model_to_dict
+from django.core.exceptions import ValidationError, ObjectDoesNotExist
+
+# Create your models here.
+
+class SyndicateService(SingletonModel,Service):
+    class Meta:
+        app_label = "syndicate_storage"
+        verbose_name = "Syndicate Service"
+        verbose_name_plural = "Syndicate Service"
+
+    def __unicode__(self):  return u'Syndicate Service'
+
+
+class SyndicatePrincipal(PlCoreBase):
+    class Meta:
+        app_label = "syndicate_storage"
+
+    # for now, this is a user email address 
+    principal_id = models.TextField(unique=True)
+    public_key_pem = models.TextField()
+    sealed_private_key = models.TextField()
+
+    def __unicode__self(self):  return "%s" % self.principal_id
+
+
+class Volume(PlCoreBase):
+    class Meta:
+        app_label = "syndicate_storage"
+
+    name = models.CharField(max_length=64, help_text="Human-readable, searchable name of the Volume")
+    
+    owner_id = models.ForeignKey(User, verbose_name='Owner')
+
+    description = models.TextField(null=True, blank=True,max_length=130, help_text="Human-readable description of what this Volume is used for.")
+    blocksize = models.PositiveIntegerField(help_text="Number of bytes per block.")
+    private = models.BooleanField(default=True, help_text="Indicates if the Volume is visible to users other than the Volume Owner and Syndicate Administrators.")
+    archive = models.BooleanField(default=False, help_text="Indicates if this Volume is read-only, and only an Aquisition Gateway owned by the Volume owner (or Syndicate admin) can write to it.")
+
+    cap_read_data = models.BooleanField(default=True, help_text="VM can read Volume data")
+    cap_write_data = models.BooleanField(default=True, help_text="VM can write Volume data")
+    cap_host_data = models.BooleanField(default=True, help_text="VM can host Volume data")
+    
+    slice_id = models.ManyToManyField(Slice, through="VolumeSlice")
+    
+    def __unicode__(self):  return self.name
+ 
+    
+    @staticmethod
+    def select_by_user(user):
+        """
+        Only return Volumes accessible by the user.
+        Admin users can see everything.
+        """
+        if user.is_admin:
+            qs = Volume.objects.all()
+        else:
+            qs = Volume.objects.filter( Q(owner_id=user) | Q(private=False) )
+            
+        return qs
+
+
+class VolumeAccessRight(PlCoreBase):
+    class Meta:
+        app_label = "syndicate_storage"
+
+    owner_id = models.ForeignKey(User, verbose_name='user')
+    
+    volume = models.ForeignKey(Volume)
+
+    cap_read_data = models.BooleanField(default=True, help_text="VM can read Volume data")
+    cap_write_data = models.BooleanField(default=True, help_text="VM can write Volume data")
+    cap_host_data = models.BooleanField(default=True, help_text="VM can host Volume data")
+
+
+    def __unicode__(self):  return "%s-%s" % (self.owner_id.email, self.volume.name)
+
+
+class ObserverSecretValue( models.TextField ):
+    class Meta:
+        app_label = "syndicate_storage"
+    
+    __metaclass__ = models.SubfieldBase
+    
+    MAGIC_PREFIX = "$SECRET$:"
+    
+    @classmethod 
+    def is_encrypted( cls, secret_str ):
+       # all encrypted secrets start with MAGIC_PREFIX, which is NOT base64-encoded
+       return secret_str.startswith( cls.MAGIC_PREFIX )
+    
+    @classmethod 
+    def unserialize( cls, serialized_ciphertext ):
+       # strip prefix and return ciphertext 
+       return serialized_ciphertext[len(cls.MAGIC_PREFIX):]
+    
+    @classmethod 
+    def serialize( cls, ciphertext ):
+       # prepend a magic prefix so we know it's encrypted 
+       return cls.MAGIC_PREFIX + ciphertext
+    
+    def to_python( self, secret_str ):
+       """
+       Decrypt the value with the Observer key
+       """
+       
+       # is this in the clear?
+       if not ObserverSecretValue.is_encrypted( secret_str ):
+          # nothing to do
+          return secret_str
+       
+       # otherwise, decrypt it
+       from observers.syndicate import syndicatelib
+       
+       # get observer private key
+       config = syndicatelib.get_config()
+       
+       try:
+          observer_pkey_path = config.SYNDICATE_PRIVATE_KEY
+          observer_pkey_pem = syndicatelib.get_private_key_pem( observer_pkey_path )
+       except:
+          raise syndicatelib.SyndicateObserverError( "Internal Syndicate Observer error: failed to load Observer private key" )
+       
+       # deserialize 
+       secret_str = ObserverSecretValue.unserialize( secret_str )
+       
+       # decrypt
+       if secret_str is not None and len(secret_str) > 0:
+          
+          slice_secret = syndicatelib.decrypt_slice_secret( observer_pkey_pem, secret_str )
+          
+          if slice_secret is not None:
+             return slice_secret 
+          
+          else:
+             raise syndicatelib.SyndicateObserverError( "Internal Syndicate Observer error: failed to decrypt slice secret value" )
+       else:
+          return None
+       
+       
+    def pre_save( self, model_inst, add ):
+       """
+       Encrypt the value with the Observer key
+       """
+       
+       from observers.syndicate import syndicatelib 
+       
+       # get observer private key
+       config = syndicatelib.get_config()
+       
+       try:
+          observer_pkey_path = config.SYNDICATE_PRIVATE_KEY
+          observer_pkey_pem = syndicatelib.get_private_key_pem( observer_pkey_path )
+       except:
+          raise syndicatelib.SyndicateObserverError( "Internal Syndicate Observer error: failed to load Observer private key" )
+       
+       slice_secret = getattr(model_inst, self.attname )
+       
+       if slice_secret is not None:
+          
+          # encrypt it 
+          sealed_slice_secret = syndicatelib.encrypt_slice_secret( observer_pkey_pem, slice_secret )
+          
+          return ObserverSecretValue.serialize( sealed_slice_secret )
+       
+       else:
+          raise syndicatelib.SyndicateObserverError( "Internal Syndicate Observer error: No slice secret generated" )
+                                                    
+
+class SliceSecret(models.Model):        # NOTE: not a PlCoreBase
+    class Meta:
+       app_label = "syndicate_storage"
+    
+    slice_id = models.ForeignKey(Slice)
+    secret = ObserverSecretValue(blank=True, help_text="Shared secret between OpenCloud and this slice's Syndicate daemons.")
+    
+    def __unicode__(self):  return self.slice_id.name
+ 
+    @staticmethod
+    def select_by_user(user):
+        """
+        Only return slice secrets for slices where this user has 'admin' role.
+        Admin users can see everything.
+        """
+        if user.is_admin:
+            qs = SliceSecret.objects.all()
+        else:
+            visible_slice_ids = [sp.slice.id for sp in SlicePrivilege.objects.filter(user=user,role__role='admin')]
+            qs = SliceSecret.objects.filter(slice_id__id__in=visible_slice_ids)
+            
+        return qs
+ 
+
+class VolumeSlice(PlCoreBase):
+    class Meta:
+        app_label = "syndicate_storage"
+
+    volume_id = models.ForeignKey(Volume, verbose_name="Volume")
+    slice_id = models.ForeignKey(Slice, verbose_name="Slice")
+    
+    cap_read_data = models.BooleanField(default=True, help_text="VM can read Volume data")
+    cap_write_data = models.BooleanField(default=True, help_text="VM can write Volume data")
+    cap_host_data = models.BooleanField(default=True, help_text="VM can host Volume data")
+    
+    UG_portnum = models.PositiveIntegerField(help_text="User Gateway port.  Any port above 1024 will work, but it must be available slice-wide.", verbose_name="UG port")
+    RG_portnum = models.PositiveIntegerField(help_text="Replica Gateway port.  Any port above 1024 will work, but it must be available slice-wide.", verbose_name="RG port")
+    
+    credentials_blob = models.TextField(null=True, blank=True, help_text="Encrypted slice credentials, sealed with the slice secret.")
+ 
+    def __unicode__(self):  return "%s-%s" % (self.volume_id.name, self.slice_id.name)
+
+    def clean(self):
+        """
+        Verify that our fields are in order:
+            * UG_portnum and RG_portnum have to be valid port numbers between 1025 and 65534
+            * UG_portnum and RG_portnum cannot be changed once set.
+            * UG_portnum and RG_portnum are unique
+        """
+
+        if self.UG_portnum == self.RG_portnum:
+            raise ValidationError( "UG and RG ports must be unique" )
+         
+        if self.UG_portnum < 1025 or self.UG_portnum > 65534:
+            raise ValidationError( "UG port number must be between 1025 and 65534" )
+
+        if self.RG_portnum < 1025 or self.RG_portnum > 65534:
+            raise ValidationError( "RG port number must be between 1025 and 65534" )
+         
+         
+    def save(self, *args, **kw):
+       """
+       Make sure a SliceSecret exists for this slice
+       """
+       
+       from observers.syndicate import syndicatelib
+       
+       # get observer private key
+       config = syndicatelib.get_config()
+       
+       try:
+          observer_pkey_path = config.SYNDICATE_PRIVATE_KEY
+          observer_pkey_pem = syndicatelib.get_private_key_pem( observer_pkey_path )
+       except:
+          raise syndicatelib.SyndicateObserverError( "Internal Syndicate Observer error: failed to load Observer private key" )
+       
+       # get or create the slice secret 
+       slice_secret = syndicatelib.get_or_create_slice_secret( observer_pkey_pem, None, slice_fk=self.slice_id )
+       
+       if slice_secret is None:
+          raise SyndicateObserverError( "Failed to get or create slice secret for %s" % self.slice_id.name )
+       
+       super(VolumeSlice, self).save(*args, **kw)
+       
+
+
diff --git a/xos/services/syndicate_storage/templates/syndicateadmin.html b/xos/services/syndicate_storage/templates/syndicateadmin.html
new file mode 100644
index 0000000..0c46206
--- /dev/null
+++ b/xos/services/syndicate_storage/templates/syndicateadmin.html
@@ -0,0 +1,13 @@
+<div class = "left-nav">
+<ul>
+{% for admin in registered_admins %}
+    <li><a href="{{ admin.url }}">{{ admin.name }}</a></li>
+{% endfor %}
+</ul>
+</div>
+
+<!--
+<ul>
+<li><a href="/admin/syndicate_storage/volume/">Volumes</a></li>
+</ul>
+-->
diff --git a/xos/synchronizers/__init__.py b/xos/synchronizers/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/xos/synchronizers/__init__.py
@@ -0,0 +1 @@
+
diff --git a/xos/synchronizers/base/SyncInstanceUsingAnsible.py b/xos/synchronizers/base/SyncInstanceUsingAnsible.py
new file mode 100644
index 0000000..dd7e5c6
--- /dev/null
+++ b/xos/synchronizers/base/SyncInstanceUsingAnsible.py
@@ -0,0 +1,263 @@
+import hashlib
+import os
+import socket
+import sys
+import base64
+import time
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.syncstep import SyncStep
+from synchronizers.base.ansible import run_template_ssh
+from core.models import Service, Slice, ControllerSlice, ControllerUser
+from xos.logger import Logger, logging
+
+logger = Logger(level=logging.INFO)
+
+class SyncInstanceUsingAnsible(SyncStep):
+    # All of the following should be defined for classes derived from this
+    # base class. Examples below use VSGTenant.
+
+    # provides=[VSGTenant]
+    # observes=VSGTenant
+    # requested_interval=0
+    # template_name = "sync_vcpetenant.yaml"
+
+    def __init__(self, **args):
+        SyncStep.__init__(self, **args)
+
+    def skip_ansible_fields(self, o):
+        # Return True if the instance processing and get_ansible_fields stuff
+        # should be skipped. This hook is primarily for the OnosApp
+        # sync step, so it can do its external REST API sync thing.
+        return False
+
+    def defer_sync(self, o, reason):
+        logger.info("defer object %s due to %s" % (str(o), reason),extra=o.tologdict())
+        raise Exception("defer object %s due to %s" % (str(o), reason))
+
+    def get_extra_attributes(self, o):
+        # This is a place to include extra attributes that aren't part of the
+        # object itself.
+
+        return {}
+
+    def get_instance(self, o):
+        # We need to know what instance is associated with the object. Let's
+        # assume 'o' has a field called 'instance'. If the field is called
+        # something else, or if custom logic is needed, then override this
+        # method.
+
+        return o.instance
+
+    def get_external_sync(self, o):
+        hostname = getattr(o, "external_hostname", None)
+        container = getattr(o, "external_container", None)
+        if hostname and container:
+            return (hostname, container)
+        else:
+            return None
+
+    def run_playbook(self, o, fields, template_name=None):
+        if not template_name:
+            template_name = self.template_name
+        tStart = time.time()
+        run_template_ssh(template_name, fields)
+        logger.info("playbook execution time %d" % int(time.time()-tStart),extra=o.tologdict())
+
+    def pre_sync_hook(self, o, fields):
+        pass
+
+    def post_sync_hook(self, o, fields):
+        pass
+
+    def sync_fields(self, o, fields):
+        self.run_playbook(o, fields)
+
+    def prepare_record(self, o):
+        pass
+
+    def get_node(self,o):
+        return o.node
+
+    def get_node_key(self, node):
+        return "/root/setup/node_key"
+
+    def get_key_name(self, instance):
+        if instance.isolation=="vm":
+            if (instance.slice) and (instance.slice.service) and (instance.slice.service.private_key_fn):
+                key_name = instance.slice.service.private_key_fn
+            else:
+                raise Exception("Make sure to set private_key_fn in the service")
+        elif instance.isolation=="container":
+            node = self.get_node(instance)
+            key_name = self.get_node_key(node)
+        else:
+            # container in VM
+            key_name = instance.parent.slice.service.private_key_fn
+
+        return key_name
+
+    def get_ansible_fields(self, instance):
+        # return all of the fields that tell Ansible how to talk to the context
+        # that's setting up the container.
+
+        if (instance.isolation == "vm"):
+            # legacy where container was configured by sync_vcpetenant.py
+
+            fields = { "instance_name": instance.name,
+                       "hostname": instance.node.name,
+                       "instance_id": instance.instance_id,
+                       "username": "ubuntu",
+                       "ssh_ip": instance.get_ssh_ip(),
+                     }
+
+        elif (instance.isolation == "container"):
+            # container on bare metal
+            node = self.get_node(instance)
+            hostname = node.name
+            fields = { "hostname": hostname,
+                       "baremetal_ssh": True,
+                       "instance_name": "rootcontext",
+                       "username": "root",
+                       "container_name": "%s-%s" % (instance.slice.name, str(instance.id))
+                       # ssh_ip is not used for container-on-metal
+                     }
+        else:
+            # container in a VM
+            if not instance.parent:
+                raise Exception("Container-in-VM has no parent")
+            if not instance.parent.instance_id:
+                raise Exception("Container-in-VM parent is not yet instantiated")
+            if not instance.parent.slice.service:
+                raise Exception("Container-in-VM parent has no service")
+            if not instance.parent.slice.service.private_key_fn:
+                raise Exception("Container-in-VM parent service has no private_key_fn")
+            fields = { "hostname": instance.parent.node.name,
+                       "instance_name": instance.parent.name,
+                       "instance_id": instance.parent.instance_id,
+                       "username": "ubuntu",
+                       "ssh_ip": instance.parent.get_ssh_ip(),
+                       "container_name": "%s-%s" % (instance.slice.name, str(instance.id))
+                         }
+
+        key_name = self.get_key_name(instance)
+        if not os.path.exists(key_name):
+            raise Exception("Node key %s does not exist" % key_name)
+
+        key = file(key_name).read()
+
+        fields["private_key"] = key
+
+        # now the ceilometer stuff
+
+        cslice = ControllerSlice.objects.get(slice=instance.slice)
+        if not cslice:
+            raise Exception("Controller slice object for %s does not exist" % instance.slice.name)
+
+        cuser = ControllerUser.objects.get(user=instance.creator)
+        if not cuser:
+            raise Exception("Controller user object for %s does not exist" % instance.creator)
+
+        fields.update({"keystone_tenant_id": cslice.tenant_id,
+                       "keystone_user_id": cuser.kuser_id,
+                       "rabbit_user": getattr(instance.controller,"rabbit_user", None),
+                       "rabbit_password": getattr(instance.controller, "rabbit_password", None),
+                       "rabbit_host": getattr(instance.controller, "rabbit_host", None)})
+
+        return fields
+
+    def sync_record(self, o):
+        logger.info("sync'ing object %s" % str(o),extra=o.tologdict())
+
+        self.prepare_record(o)
+
+        if self.skip_ansible_fields(o):
+            fields = {}
+        else:
+            if self.get_external_sync(o):
+                # sync to some external host
+
+                # UNTESTED
+
+                (hostname, container_name) = self.get_external_sync(o)
+                fields = { "hostname": hostname,
+                           "baremetal_ssh": True,
+                           "instance_name": "rootcontext",
+                           "username": "root",
+                           "container_name": container_name
+                         }
+                key_name = self.get_node_key(node)
+                if not os.path.exists(key_name):
+                    raise Exception("Node key %s does not exist" % key_name)
+
+                key = file(key_name).read()
+
+                fields["private_key"] = key
+                # TO DO: Ceilometer stuff
+            else:
+                instance = self.get_instance(o)
+                # sync to an XOS instance
+                if not instance:
+                    self.defer_sync(o, "waiting on instance")
+                    return
+
+                if not instance.instance_name:
+                    self.defer_sync(o, "waiting on instance.instance_name")
+                    return
+
+                fields = self.get_ansible_fields(instance)
+
+        fields["ansible_tag"] =  o.__class__.__name__ + "_" + str(o.id)
+
+        # If 'o' defines a 'sync_attributes' list, then we'll copy those
+        # attributes into the Ansible recipe's field list automatically.
+        if hasattr(o, "sync_attributes"):
+            for attribute_name in o.sync_attributes:
+                fields[attribute_name] = getattr(o, attribute_name)
+
+        fields.update(self.get_extra_attributes(o))
+
+        self.sync_fields(o, fields)
+
+        o.save()
+
+    def delete_record(self, o):
+        try:
+            controller = o.get_controller()
+            controller_register = json.loads(o.node.site_deployment.controller.backend_register)
+
+            if (controller_register.get('disabled',False)):
+                raise InnocuousException('Controller %s is disabled'%o.node.site_deployment.controller.name)
+        except AttributeError:
+            pass
+
+        instance = self.get_instance(o)
+        if isinstance(instance, basestring):
+            # sync to some external host
+
+            # XXX - this probably needs more work...
+
+            fields = { "hostname": instance,
+                       "instance_id": "ubuntu",     # this is the username to log into
+                       "private_key": service.key,
+                     }
+        else:
+            # sync to an XOS instance
+            fields = self.get_ansible_fields(instance)
+
+            fields["ansible_tag"] =  o.__class__.__name__ + "_" + str(o.id)
+
+        # If 'o' defines a 'sync_attributes' list, then we'll copy those
+        # attributes into the Ansible recipe's field list automatically.
+        if hasattr(o, "sync_attributes"):
+            for attribute_name in o.sync_attributes:
+                fields[attribute_name] = getattr(o, attribute_name)
+
+        fields.update(self.map_delete_inputs(o))
+
+        fields['delete']=True
+        res = self.run_playbook(o,fields)
+        try:
+                self.map_delete_outputs(o,res)
+        except AttributeError:
+                pass
diff --git a/xos/synchronizers/base/__init__.py b/xos/synchronizers/base/__init__.py
new file mode 100644
index 0000000..e56cd39
--- /dev/null
+++ b/xos/synchronizers/base/__init__.py
@@ -0,0 +1,36 @@
+from xos.config import Config
+
+try:
+    observer_disabled = Config().observer_disabled
+except:
+    observer_disabled = False
+
+def EnableObserver(x):
+    """ used for manage.py --noobserver """
+    global observer_disabled
+    observer_disabled = not x
+
+print_once = True
+
+def notify_observer(model=None, delete=False, pk=None, model_dict={}):
+    if (observer_disabled):
+        global print_once
+        if (print_once):
+            print "The observer is disabled"
+            print_once = False
+        return
+
+    try:
+        from .event_manager import EventSender
+        if (model and delete):
+            if hasattr(model,"__name__"):
+                modelName = model.__name__
+            else:
+                modelName = model.__class__.__name__
+            EventSender().fire(delete_flag = delete, model = modelName, pk = pk, model_dict=model_dict)
+        else:
+            EventSender().fire()
+    except Exception,e:
+        print "Exception in Observer. This should not disrupt the front end. %s"%str(e)
+
+
diff --git a/xos/synchronizers/base/ansible.py b/xos/synchronizers/base/ansible.py
new file mode 100644
index 0000000..b6f1ca2
--- /dev/null
+++ b/xos/synchronizers/base/ansible.py
@@ -0,0 +1,237 @@
+#!/usr/bin/env python
+import jinja2
+import tempfile
+import os
+import json
+import pdb
+import string
+import random
+import re
+import traceback
+import subprocess
+from xos.config import Config, XOS_DIR
+from xos.logger import observer_logger
+
+try:
+    step_dir = Config().observer_steps_dir
+    sys_dir = Config().observer_sys_dir
+except:
+    step_dir = XOS_DIR + '/synchronizers/openstack/steps'
+    sys_dir = '/opt/opencloud'
+
+os_template_loader = jinja2.FileSystemLoader( searchpath=step_dir)
+os_template_env = jinja2.Environment(loader=os_template_loader)
+
+def parse_output(msg):
+    lines = msg.splitlines()
+    results = []
+
+    observer_logger.info(msg)
+
+    for l in lines:
+        magic_str = 'ok: [127.0.0.1] => '
+        magic_str2 = 'changed: [127.0.0.1] => '
+        if (l.startswith(magic_str)):
+            w = len(magic_str)
+            str = l[w:]
+
+            # handle ok: [127.0.0.1] => (item=org.onosproject.driver) => {...
+            if str.startswith("(") and (" => {" in str):
+                str = str.split("=> ",1)[1]
+
+            d = json.loads(str)
+            results.append(d)
+        elif (l.startswith(magic_str2)):
+            w = len(magic_str2)
+            str = l[w:]
+
+            if str.startswith("(") and (" => {" in str):
+                str = str.split("=> ",1)[1]
+
+            d = json.loads(str)
+            results.append(d)
+
+
+    return results
+
+def parse_unreachable(msg):
+    total_unreachable=0
+    total_failed=0
+    for l in msg.splitlines():
+        x = re.findall('ok=([0-9]+).*changed=([0-9]+).*unreachable=([0-9]+).*failed=([0-9]+)', l)
+        if x:
+            (ok, changed, unreachable, failed) = x[0]
+            ok=int(ok)
+            changed=int(changed)
+            unreachable=int(unreachable)
+            failed=int(failed)
+
+            total_unreachable += unreachable
+            total_failed += failed
+    return {'unreachable':total_unreachable,'failed':total_failed}
+
+
+def id_generator(size=6, chars=string.ascii_uppercase + string.digits):
+    return ''.join(random.choice(chars) for _ in range(size))
+
+def shellquote(s):
+    return "'" + s.replace("'", "'\\''") + "'"
+
+def get_playbook_fn(opts, path):
+    if not opts.get("ansible_tag", None):
+        # if no ansible_tag is in the options, then generate a unique one
+        objname= id_generator()
+        opts = opts.copy()
+        opts["ansible_tag"] = objname
+
+    objname = opts["ansible_tag"]
+
+    pathed_sys_dir = os.path.join(sys_dir, path)
+    if not os.path.isdir(pathed_sys_dir):
+        os.makedirs(pathed_sys_dir)
+
+    # symlink steps/roles into sys/roles so that playbooks can access roles
+    roledir = os.path.join(step_dir,"roles")
+    rolelink = os.path.join(pathed_sys_dir, "roles")
+    if os.path.isdir(roledir) and not os.path.islink(rolelink):
+        os.symlink(roledir,rolelink)
+
+    return (opts, os.path.join(pathed_sys_dir,objname))
+
+def run_template(name, opts, path='', expected_num=None, ansible_config=None, ansible_hosts=None, run_ansible_script=None):
+    template = os_template_env.get_template(name)
+    buffer = template.render(opts)
+
+    (opts, fqp) = get_playbook_fn(opts, path)
+
+    f = open(fqp,'w')
+    f.write(buffer)
+    f.flush()
+
+    # This is messy -- there's no way to specify ansible config file from
+    # the command line, but we can specify it using the environment.
+    env = os.environ.copy()
+    if ansible_config:
+       env["ANSIBLE_CONFIG"] = ansible_config
+    if ansible_hosts:
+       env["ANSIBLE_HOSTS"] = ansible_hosts
+
+    if (not Config().observer_pretend):
+        if not run_ansible_script:
+            run_ansible_script = os.path.join(XOS_DIR, "synchronizers/base/run_ansible")
+
+        process = subprocess.Popen("%s %s" % (run_ansible_script, shellquote(fqp)), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env)
+        msg = process.stdout.read()
+        err_msg = process.stderr.read()
+
+        if getattr(Config(), "observer_save_ansible_output", False):
+            try:
+                open(fqp+".out","w").write(msg)
+                open(fqp+".err","w").write(err_msg)
+            except:
+                # fail silently
+                pass
+
+    else:
+        msg = open(fqp+'.out').read()
+
+    try:
+        ok_results = parse_output(msg)
+        if (expected_num is not None) and (len(ok_results) != expected_num):
+            raise ValueError('Unexpected num %s!=%d' % (str(expected_num), len(ok_results)) )
+
+        parsed = parse_unreachable(msg)
+        total_unreachable = parsed['unreachable']
+	failed = parsed['failed']
+	if (failed):
+		raise ValueError('Ansible playbook failed.')
+
+        if (total_unreachable > 0):
+            raise ValueError("Unreachable results in ansible recipe")
+    except ValueError,e:
+        all_fatal = [e.message] + re.findall(r'^msg: (.*)',msg,re.MULTILINE)
+        all_fatal2 = re.findall(r'^ERROR: (.*)',msg,re.MULTILINE)
+
+        all_fatal.extend(all_fatal2)
+        try:
+            error = ' // '.join(all_fatal)
+        except:
+            pass
+        raise Exception(error)
+
+    return ok_results
+
+def run_template_ssh(name, opts, path='', expected_num=None):
+    instance_name = opts["instance_name"]
+    hostname = opts["hostname"]
+    private_key = opts["private_key"]
+    baremetal_ssh = opts.get("baremetal_ssh",False)
+    if baremetal_ssh:
+        # no instance_id or ssh_ip for baremetal
+        # we never proxy to baremetal
+        proxy_ssh = False
+    else:
+        instance_id = opts["instance_id"]
+        ssh_ip = opts["ssh_ip"]
+        try:
+            proxy_ssh = Config().observer_proxy_ssh
+        except:
+            proxy_ssh = True
+
+    (opts, fqp) = get_playbook_fn(opts, path)
+    private_key_pathname = fqp + ".key"
+    config_pathname = fqp + ".config"
+    hosts_pathname = fqp + ".hosts"
+
+    f = open(private_key_pathname, "w")
+    f.write(private_key)
+    f.close()
+
+    f = open(config_pathname, "w")
+    f.write("[ssh_connection]\n")
+    if proxy_ssh:
+        proxy_ssh_key = getattr(Config(), "observer_proxy_ssh_key", None)
+        proxy_ssh_user = getattr(Config(), "observer_proxy_ssh_user", "root")
+        if proxy_ssh_key:
+            # If proxy_ssh_key is known, then we can proxy into the compute
+            # node without needing to have the OpenCloud sshd machinery in
+            # place.
+            proxy_command = "ProxyCommand ssh -q -i %s -o StrictHostKeyChecking=no %s@%s nc %s 22" % (proxy_ssh_key, proxy_ssh_user, hostname, ssh_ip)
+        else:
+            proxy_command = "ProxyCommand ssh -q -i %s -o StrictHostKeyChecking=no %s@%s" % (private_key_pathname, instance_id, hostname)
+        f.write('ssh_args = -o "%s"\n' % proxy_command)
+    f.write('scp_if_ssh = True\n')
+    f.write('pipelining = True\n')
+    f.write('\n[defaults]\n')
+    f.write('host_key_checking = False\n')
+    f.close()
+
+    f = open(hosts_pathname, "w")
+    f.write("[%s]\n" % instance_name)
+    if proxy_ssh or baremetal_ssh:
+        f.write("%s ansible_ssh_private_key_file=%s\n" % (hostname, private_key_pathname))
+    else:
+        # acb: Login user is hardcoded, this is not great
+        f.write("%s ansible_ssh_private_key_file=%s ansible_ssh_user=ubuntu\n" % (ssh_ip, private_key_pathname))
+    f.close()
+
+    # SSH will complain if private key is world or group readable
+    os.chmod(private_key_pathname, 0600)
+
+    print "ANSIBLE_CONFIG=%s" % config_pathname
+    print "ANSIBLE_HOSTS=%s" % hosts_pathname
+
+    return run_template(name, opts, path, ansible_config = config_pathname, ansible_hosts = hosts_pathname, run_ansible_script="/opt/xos/synchronizers/base/run_ansible_verbose")
+
+
+
+def main():
+    run_template('ansible/sync_user_deployments.yaml',{ "endpoint" : "http://172.31.38.128:5000/v2.0/",
+             "name" : "Sapan Bhatia",
+             "email": "gwsapan@gmail.com",
+             "password": "foobar",
+             "admin_user":"admin",
+             "admin_password":"6a789bf69dd647e2",
+             "admin_tenant":"admin",
+             "tenant":"demo",
+             "roles":['user','admin'] })
diff --git a/xos/synchronizers/base/backend.py b/xos/synchronizers/base/backend.py
new file mode 100644
index 0000000..206c27f
--- /dev/null
+++ b/xos/synchronizers/base/backend.py
@@ -0,0 +1,50 @@
+import os
+import sys
+import threading
+import time
+from synchronizers.base.event_loop import XOSObserver
+#from synchronizers.base.event_manager import EventListener
+from xos.logger import Logger, logging
+from synchronizers.model_policy import run_policy
+from xos.config import Config
+from django.utils import timezone
+from diag import update_diag
+
+logger = Logger(level=logging.INFO)
+
+class Backend:
+
+    def run(self):
+        update_diag(sync_start=time.time(), backend_status="0 - Synchronizer Start")
+
+        # start the openstack observer
+        observer = XOSObserver()
+        observer_thread = threading.Thread(target=observer.run,name='synchronizer')
+        observer_thread.start()
+
+        # start model policies thread
+        observer_name = getattr(Config(), "observer_name", "")
+        if (not observer_name):
+            model_policy_thread = threading.Thread(target=run_policy)
+            model_policy_thread.start()
+        else:
+            model_policy_thread = None
+            print "Skipping model policies thread for service observer."
+
+
+        # start event listene
+        #event_manager = EventListener(wake_up=observer.wake_up)
+        #event_manager_thread = threading.Thread(target=event_manager.run)
+        #event_manager_thread.start()
+
+        while True:
+            try:
+                time.sleep(1000)
+            except KeyboardInterrupt:
+                print "exiting due to keyboard interrupt"
+                # TODO: See about setting the threads as daemons
+                observer_thread._Thread__stop()
+                if model_policy_thread:
+                    model_policy_thread._Thread__stop()
+                sys.exit(1)
+
diff --git a/xos/synchronizers/base/backend.py.bak b/xos/synchronizers/base/backend.py.bak
new file mode 100644
index 0000000..6e46b85
--- /dev/null
+++ b/xos/synchronizers/base/backend.py.bak
@@ -0,0 +1,34 @@
+import threading
+import time
+from observer.event_loop import XOSObserver
+from observer.event_manager import EventListener
+from util.logger import Logger, logging
+from model_policy import run_policy
+from xos.config import Config
+
+logger = Logger(level=logging.INFO)
+
+class Backend:
+    
+    def run(self):
+            # start the openstack observer
+            observer = XOSObserver()
+            observer_thread = threading.Thread(target=observer.run)
+            observer_thread.start()
+            
+            # start model policies thread
+            observer_name = getattr(Config(), "observer_name", "")
+     	    if (not observer_name):	
+             	model_policy_thread = threading.Thread(target=run_policy)
+             	model_policy_thread.start()
+     	    else:
+         		print "Skipping model policies thread for service observer."
+
+            model_policy_thread = threading.Thread(target=run_policy)
+            model_policy_thread.start()
+
+            # start event listene
+            event_manager = EventListener(wake_up=observer.wake_up)
+            event_manager_thread = threading.Thread(target=event_manager.run)
+            event_manager_thread.start()
+
diff --git a/xos/synchronizers/base/controller.diff b/xos/synchronizers/base/controller.diff
new file mode 100644
index 0000000..865b83e
--- /dev/null
+++ b/xos/synchronizers/base/controller.diff
@@ -0,0 +1,37 @@
+diff -up xos/model_policies/model_policy_Controller.py.orig xos/model_policies/model_policy_Controller.py
+--- xos/model_policies/model_policy_Controller.py.orig	2015-01-19 20:09:13.000000000 +0000
++++ xos/model_policies/model_policy_Controller.py	2015-04-07 21:48:51.462215000 +0000
+@@ -1,6 +1,6 @@
+ 
+ def handle(controller):
+-    from core.models import Controller, Site, ControllerSite, Slice, ControllerSlice, User, ControllerUser
++    from core.models import Controller, Site, ControllerSite, Slice, ControllerSlice, User, ControllerUser, ControllerImages, ControllerNetwork
+     from collections import defaultdict
+ 
+     # relations for all sites
+@@ -36,3 +36,25 @@ def handle(controller):
+             controller not in ctrls_by_user[user]:
+             controller_user = ControllerUser(controller=controller, user=user)
+             controller_user.save()
++    # relations for all networks
++    ctrls_by_network = defaultdict(list)
++    ctrl_networks = ControllerNetwork.objects.all()
++    for ctrl_network in ctrl_networks:
++        ctrls_by_network[ctrl_network.network].append(ctrl_network.controller)
++    networks = Network.objects.all()
++    for network in networks:
++        if network not in ctrls_by_network or \
++            controller not in ctrls_by_network[network]:
++            controller_network = ControllerNetwork(controller=controller, network=network)
++            controller_network.save()
++    # relations for all images
++    ctrls_by_image = defaultdict(list)
++    ctrl_images = ControllerImages.objects.all()
++    for ctrl_image in ctrl_images:
++        ctrls_by_image[ctrl_image.image].append(ctrl_image.controller)
++    images = Image.objects.all()
++    for image in images:
++        if image not in ctrls_by_image or \
++            controller not in ctrls_by_image[image]:
++            controller_image = ControllerImages(controller=controller, image=image)
++            controller_image.save()
diff --git a/xos/synchronizers/base/deleter.py b/xos/synchronizers/base/deleter.py
new file mode 100644
index 0000000..93fa572
--- /dev/null
+++ b/xos/synchronizers/base/deleter.py
@@ -0,0 +1,16 @@
+import os
+import base64
+from xos.config import Config
+
+class Deleter:
+	model=None # Must be overridden
+
+        def __init__(self, *args, **kwargs):
+                pass
+
+	def call(self, pk, model_dict):
+		# Fetch object from XOS db and delete it
+		pass
+
+	def __call__(self, *args, **kwargs):
+		return self.call(*args, **kwargs)
diff --git a/xos/synchronizers/base/diag.py b/xos/synchronizers/base/diag.py
new file mode 100644
index 0000000..87fab70
--- /dev/null
+++ b/xos/synchronizers/base/diag.py
@@ -0,0 +1,40 @@
+import os
+import time
+import sys
+import traceback
+import json
+
+from core.models import Diag
+from xos.config import Config, XOS_DIR
+from xos.logger import Logger, logging, logger
+
+logger = Logger(level=logging.INFO)
+
+def update_diag(loop_end=None, loop_start=None, syncrecord_start=None, sync_start=None, backend_status=None):
+    try:
+        observer_name = Config().observer_name
+    except:
+        observer_name = 'openstack'
+
+    try:
+        diag = Diag.objects.filter(name=observer_name).first()
+        if (not diag):
+            diag = Diag(name=observer_name)
+        br_str = diag.backend_register
+        br = json.loads(br_str)
+        if loop_end:
+            br['last_run'] = loop_end
+        if loop_end and loop_start:
+            br['last_duration'] = loop_end - loop_start
+        if syncrecord_start:
+            br['last_syncrecord_start'] = syncrecord_start
+        if sync_start:
+            br['last_synchronizer_start'] = sync_start
+        if backend_status:
+            diag.backend_status = backend_status
+        diag.backend_register = json.dumps(br)
+        diag.save()
+    except:
+        logger.log_exc("Exception in update_diag")
+        traceback.print_exc()
+
diff --git a/xos/synchronizers/base/error_mapper.py b/xos/synchronizers/base/error_mapper.py
new file mode 100644
index 0000000..9eb878d
--- /dev/null
+++ b/xos/synchronizers/base/error_mapper.py
@@ -0,0 +1,25 @@
+from xos.config import Config
+from xos.logger import Logger, logging, logger
+
+class ErrorMapper:
+	def __init__(self, error_map_file):
+		self.error_map = {}
+		try:
+			error_map_lines = open(error_map_file).read().splitlines()
+			for l in error_map_lines:
+				if (not l.startswith('#')):
+					splits = l.split('->')
+					k,v = map(lambda i:i.rstrip(),splits)
+					self.error_map[k]=v
+		except:
+			logging.info('Could not read error map')
+
+
+	def map(self, error):
+		return self.error_map[error]
+
+
+
+
+
+
diff --git a/xos/synchronizers/base/event_loop.py b/xos/synchronizers/base/event_loop.py
new file mode 100644
index 0000000..ae97329
--- /dev/null
+++ b/xos/synchronizers/base/event_loop.py
@@ -0,0 +1,555 @@
+import os
+import imp
+import inspect
+import time
+import sys
+import traceback
+import commands
+import threading
+import json
+import pdb
+import pprint
+import traceback
+
+
+from datetime import datetime
+from collections import defaultdict
+from core.models import *
+from django.db.models import F, Q
+from django.db import connection
+from django.db import reset_queries
+#from openstack.manager import OpenStackManager
+from openstack.driver import OpenStackDriver
+from xos.logger import Logger, logging, logger
+#from timeout import timeout
+from xos.config import Config, XOS_DIR
+from synchronizers.base.steps import *
+from syncstep import SyncStep
+from toposort import toposort
+from synchronizers.base.error_mapper import *
+from synchronizers.openstack.openstacksyncstep import OpenStackSyncStep
+from synchronizers.base.steps.sync_object import SyncObject
+from django.utils import timezone
+from diag import update_diag
+
+# Load app models
+
+try:
+    app_module_names = Config().observer_applist.split(',')
+except AttributeError:
+    app_module_names = []
+
+if (type(app_module_names)!=list):
+    app_module_names=[app_module_names]
+
+app_modules = []
+
+for m in app_module_names:
+    model_path = m+'.models'
+    module = __import__(model_path,fromlist=[m])
+    app_modules.append(module)
+
+
+debug_mode = False
+
+class bcolors:
+    HEADER = '\033[95m'
+    OKBLUE = '\033[94m'
+    OKGREEN = '\033[92m'
+    WARNING = '\033[93m'
+    FAIL = '\033[91m'
+    ENDC = '\033[0m'
+    BOLD = '\033[1m'
+    UNDERLINE = '\033[4m'
+
+logger = Logger(level=logging.INFO)
+
+class StepNotReady(Exception):
+	pass
+
+class NoOpDriver:
+	def __init__(self):
+		 self.enabled = True
+		 self.dependency_graph = None
+
+STEP_STATUS_WORKING=1
+STEP_STATUS_OK=2
+STEP_STATUS_KO=3
+
+def invert_graph(g):
+	ig = {}
+	for k,v in g.items():
+		for v0 in v:
+			try:
+				ig[v0].append(k)
+			except:
+				ig[v0]=[k]
+	return ig
+
+class XOSObserver:
+	sync_steps = []
+
+
+	def __init__(self):
+		# The Condition object that gets signalled by Feefie events
+		self.step_lookup = {}
+		self.load_sync_step_modules()
+		self.load_sync_steps()
+		self.event_cond = threading.Condition()
+
+		self.driver_kind = getattr(Config(), "observer_driver", "openstack")
+		self.observer_name = getattr(Config(), "observer_name", "")
+		if self.driver_kind=="openstack":
+			self.driver = OpenStackDriver()
+		else:
+			self.driver = NoOpDriver()
+
+        def consolePrint(self, what):
+            if getattr(Config(), "observer_console_print", True):
+                print what
+
+	def wait_for_event(self, timeout):
+		self.event_cond.acquire()
+		self.event_cond.wait(timeout)
+		self.event_cond.release()
+
+	def wake_up(self):
+		logger.info('Wake up routine called. Event cond %r'%self.event_cond)
+		self.event_cond.acquire()
+		self.event_cond.notify()
+		self.event_cond.release()
+
+	def load_sync_step_modules(self, step_dir=None):
+		if step_dir is None:
+			if hasattr(Config(), "observer_steps_dir"):
+				step_dir = Config().observer_steps_dir
+			else:
+				step_dir = XOS_DIR + "/synchronizers/openstack/steps"
+
+		for fn in os.listdir(step_dir):
+			pathname = os.path.join(step_dir,fn)
+			if os.path.isfile(pathname) and fn.endswith(".py") and (fn!="__init__.py"):
+				module = imp.load_source(fn[:-3],pathname)
+				for classname in dir(module):
+					c = getattr(module, classname, None)
+
+					# make sure 'c' is a descendent of SyncStep and has a
+					# provides field (this eliminates the abstract base classes
+					# since they don't have a provides)
+
+					if inspect.isclass(c) and (issubclass(c, SyncStep) or issubclass(c,OpenStackSyncStep)) and hasattr(c,"provides") and (c not in self.sync_steps):
+						self.sync_steps.append(c)
+		logger.info('loaded sync steps: %s' % ",".join([x.__name__ for x in self.sync_steps]))
+
+	def load_sync_steps(self):
+		dep_path = Config().observer_dependency_graph
+		logger.info('Loading model dependency graph from %s' % dep_path)
+		try:
+			# This contains dependencies between records, not sync steps
+			self.model_dependency_graph = json.loads(open(dep_path).read())
+			for left,lst in self.model_dependency_graph.items():
+                                new_lst = [] 
+				for k in lst:
+					try:
+                                                tup = (k,k.lower())
+                                                new_lst.append(tup)
+						deps = self.model_dependency_graph[k]
+					except:
+						self.model_dependency_graph[k] = []
+
+                                self.model_dependency_graph[left] = new_lst
+		except Exception,e:
+			raise e
+
+		try:
+			backend_path = Config().observer_pl_dependency_graph
+			logger.info('Loading backend dependency graph from %s' % backend_path)
+			# This contains dependencies between backend records
+			self.backend_dependency_graph = json.loads(open(backend_path).read())
+			for k,v in self.backend_dependency_graph.items():
+				try:
+					self.model_dependency_graph[k].extend(v)
+				except KeyError:
+					self.model_dependency_graphp[k] = v
+
+		except Exception,e:
+			logger.info('Backend dependency graph not loaded')
+			# We can work without a backend graph
+			self.backend_dependency_graph = {}
+
+		provides_dict = {}
+		for s in self.sync_steps:
+			self.step_lookup[s.__name__] = s 
+			for m in s.provides:
+				try:
+					provides_dict[m.__name__].append(s.__name__)
+				except KeyError:
+					provides_dict[m.__name__]=[s.__name__]
+
+		step_graph = {}
+                phantom_steps = []
+		for k,v in self.model_dependency_graph.items():
+			try:
+				for source in provides_dict[k]:
+					if (not v):
+						step_graph[source] = []
+		
+					for m,_ in v:
+						try:
+							for dest in provides_dict[m]:
+								# no deps, pass
+								try:
+									if (dest not in step_graph[source]):
+										step_graph[source].append(dest)
+								except:
+									step_graph[source]=[dest]
+						except KeyError:
+							if (not provides_dict.has_key(m)):
+                                                                try:
+								    step_graph[source]+=['#%s'%m]
+                                                                except:
+                                                                    step_graph[source]=['#%s'%m]
+
+                                                                phantom_steps+=['#%s'%m]
+							pass
+					
+			except KeyError:
+				pass
+				# no dependencies, pass
+		
+
+		self.dependency_graph = step_graph
+		self.deletion_dependency_graph = invert_graph(step_graph)
+
+		pp = pprint.PrettyPrinter(indent=4)
+                logger.info(pp.pformat(step_graph))
+		self.ordered_steps = toposort(self.dependency_graph, phantom_steps+map(lambda s:s.__name__,self.sync_steps))
+		self.ordered_steps = [i for i in self.ordered_steps if i!='SyncObject']
+
+		logger.info("Order of steps=%s" % self.ordered_steps)
+
+		self.load_run_times()
+		
+
+	def check_duration(self, step, duration):
+		try:
+			if (duration > step.deadline):
+				logger.info('Sync step %s missed deadline, took %.2f seconds'%(step.name,duration))
+		except AttributeError:
+			# S doesn't have a deadline
+			pass
+
+	def update_run_time(self, step, deletion):
+		if (not deletion):
+			self.last_run_times[step.__name__]=time.time()
+		else:
+			self.last_deletion_run_times[step.__name__]=time.time()
+
+
+	def check_schedule(self, step, deletion):
+		last_run_times = self.last_run_times if not deletion else self.last_deletion_run_times
+
+		time_since_last_run = time.time() - last_run_times.get(step.__name__, 0)
+		try:
+			if (time_since_last_run < step.requested_interval):
+				raise StepNotReady
+		except AttributeError:
+			logger.info('Step %s does not have requested_interval set'%step.__name__)
+			raise StepNotReady
+	
+	def load_run_times(self):
+		try:
+			jrun_times = open('/tmp/%sobserver_run_times'%self.observer_name).read()
+			self.last_run_times = json.loads(jrun_times)
+		except:
+			self.last_run_times={}
+			for e in self.ordered_steps:
+				self.last_run_times[e]=0
+		try:
+			jrun_times = open('/tmp/%sobserver_deletion_run_times'%self.observer_name).read()
+			self.last_deletion_run_times = json.loads(jrun_times)
+		except:
+			self.last_deletion_run_times={}
+			for e in self.ordered_steps:
+				self.last_deletion_run_times[e]=0
+
+        def lookup_step_class(self,s):
+		if ('#' in s):
+			return SyncObject
+		else:
+			step = self.step_lookup[s]
+		return step
+
+	def lookup_step(self,s):
+		if ('#' in s):
+			objname = s[1:]
+			so = SyncObject()
+			
+                        try:
+			    obj = globals()[objname]
+                        except:
+                            for m in app_modules:
+                                if (hasattr(m,objname)):
+                                    obj = getattr(m,objname)
+
+			so.provides=[obj]
+			so.observes=[obj]
+			step = so
+		else:
+			step_class = self.step_lookup[s]
+                        step = step_class(driver=self.driver,error_map=self.error_mapper)
+		return step
+			
+	def save_run_times(self):
+		run_times = json.dumps(self.last_run_times)
+		open('/tmp/%sobserver_run_times'%self.observer_name,'w').write(run_times)
+
+		deletion_run_times = json.dumps(self.last_deletion_run_times)
+		open('/tmp/%sobserver_deletion_run_times'%self.observer_name,'w').write(deletion_run_times)
+
+	def check_class_dependency(self, step, failed_steps):
+		step.dependenices = []
+		for obj in step.provides:
+		        lst = self.model_dependency_graph.get(obj.__name__, [])
+			nlst = map(lambda(a,b):b,lst)
+			step.dependenices.extend(nlst)
+		for failed_step in failed_steps:
+			if (failed_step in step.dependencies):
+				raise StepNotReady
+
+	def sync(self, S, deletion):
+            try:
+		step = self.lookup_step_class(S)
+		start_time=time.time()
+
+                logger.info("Starting to work on step %s, deletion=%s" % (step.__name__, str(deletion)))
+		
+		dependency_graph = self.dependency_graph if not deletion else self.deletion_dependency_graph
+                step_conditions = self.step_conditions# if not deletion else self.deletion_step_conditions
+                step_status = self.step_status# if not deletion else self.deletion_step_status
+
+		# Wait for step dependencies to be met
+		try:
+			deps = dependency_graph[S]
+			has_deps = True
+		except KeyError:
+			has_deps = False
+
+		go = True
+
+                failed_dep = None
+		if (has_deps):
+			for d in deps:
+                                if d==step.__name__:
+                                    logger.info("   step %s self-wait skipped" % step.__name__)
+				    go = True
+                                    continue
+
+				cond = step_conditions[d]
+				cond.acquire()
+				if (step_status[d] is STEP_STATUS_WORKING):
+                                        logger.info("  step %s wait on dep %s" % (step.__name__, d))
+					cond.wait()
+                                        logger.info("  step %s wait on dep %s cond returned" % (step.__name__, d))
+				elif step_status[d] == STEP_STATUS_OK:
+					go = True
+				else:
+                                        logger.info("  step %s has failed dep %s" % (step.__name__, d))
+					go = False
+                        		failed_dep = d
+				cond.release()
+				if (not go):
+					break
+		else:
+			go = True
+
+		if (not go):
+                        logger.info("Step %s skipped" % step.__name__)
+                        self.consolePrint(bcolors.FAIL + "Step %r skipped on %r" % (step,failed_dep) + bcolors.ENDC)
+                        # SMBAKER: sync_step was not defined here, so I changed
+                        #    this from 'sync_step' to 'step'. Verify.
+			self.failed_steps.append(step)
+			my_status = STEP_STATUS_KO
+		else:
+			sync_step = self.lookup_step(S)
+			sync_step. __name__= step.__name__
+			sync_step.dependencies = []
+			try:
+				mlist = sync_step.provides
+
+                                try:
+                                    for m in mlist:
+                                            lst =  self.model_dependency_graph[m.__name__]
+                                            nlst = map(lambda(a,b):b,lst)
+                                            sync_step.dependencies.extend(nlst)
+                                except Exception,e:
+                                    raise e
+
+			except KeyError:
+				pass
+			sync_step.debug_mode = debug_mode
+
+			should_run = False
+			try:
+				# Various checks that decide whether
+				# this step runs or not
+				self.check_class_dependency(sync_step, self.failed_steps) # dont run Slices if Sites failed
+				self.check_schedule(sync_step, deletion) # dont run sync_network_routes if time since last run < 1 hour
+				should_run = True
+			except StepNotReady:
+				logger.info('Step not ready: %s'%sync_step.__name__)
+				self.failed_steps.append(sync_step)
+				my_status = STEP_STATUS_KO
+			except Exception,e:
+				logger.error('%r' % e)
+				logger.log_exc("sync step failed: %r. Deletion: %r"%(sync_step,deletion))
+				self.failed_steps.append(sync_step)
+				my_status = STEP_STATUS_KO
+
+			if (should_run):
+				try:
+					duration=time.time() - start_time
+
+					logger.info('Executing step %s, deletion=%s' % (sync_step.__name__, deletion))
+
+					self.consolePrint(bcolors.OKBLUE + "Executing step %s" % sync_step.__name__ + bcolors.ENDC)
+					failed_objects = sync_step(failed=list(self.failed_step_objects), deletion=deletion)
+
+					self.check_duration(sync_step, duration)
+
+					if failed_objects:
+						self.failed_step_objects.update(failed_objects)
+
+                                        logger.info("Step %r succeeded, deletion=%s" % (sync_step.__name__, deletion))
+                                        self.consolePrint(bcolors.OKGREEN + "Step %r succeeded" % sync_step.__name__ + bcolors.ENDC)
+					my_status = STEP_STATUS_OK
+					self.update_run_time(sync_step,deletion)
+				except Exception,e:
+                        		self.consolePrint(bcolors.FAIL + "Model step %r failed" % (sync_step.__name__) + bcolors.ENDC)
+					logger.error('Model step %r failed. This seems like a misconfiguration or bug: %r. This error will not be relayed to the user!' % (sync_step.__name__, e))
+					logger.log_exc("Exception in sync step")
+					self.failed_steps.append(S)
+					my_status = STEP_STATUS_KO
+			else:
+                                logger.info("Step %r succeeded due to non-run" % step)
+				my_status = STEP_STATUS_OK
+
+		try:
+			my_cond = step_conditions[S]
+			my_cond.acquire()
+			step_status[S]=my_status
+			my_cond.notify_all()
+			my_cond.release()
+		except KeyError,e:
+			logger.info('Step %r is a leaf' % step)
+			pass
+            finally:
+                try:
+                    reset_queries()
+                except:
+                    # this shouldn't happen, but in case it does, catch it...
+                    logger.log_exc("exception in reset_queries")
+
+                connection.close()
+
+	def run(self):
+		if not self.driver.enabled:
+			return
+
+		if (self.driver_kind=="openstack") and (not self.driver.has_openstack):
+			return
+
+		while True:
+                    logger.info('Waiting for event')
+                    self.wait_for_event(timeout=5)
+                    logger.info('Observer woke up')
+
+                    self.run_once()
+
+        def check_db_connection_okay(self):
+            # django implodes if the database connection is closed by docker-compose
+            try:
+                diag = Diag.objects.filter(name="foo").first()
+            except Exception, e:
+                from django import db
+                if "connection already closed" in traceback.format_exc():
+                   logger.error("XXX connection already closed")
+                   try:
+#                       if db.connection:
+#                           db.connection.close()
+                       db.close_connection()
+                   except:
+                        logger.log_exc("XXX we failed to fix the failure")
+                else:
+                   logger.log_exc("XXX some other error")
+
+        def run_once(self):
+                try:
+                        self.check_db_connection_okay()
+
+                        loop_start = time.time()
+                        error_map_file = getattr(Config(), "error_map_path", XOS_DIR + "/error_map.txt")
+                        self.error_mapper = ErrorMapper(error_map_file)
+
+                        # Two passes. One for sync, the other for deletion.
+                        for deletion in [False,True]:
+                                # Set of individual objects within steps that failed
+                                self.failed_step_objects = set()
+
+                                # Set up conditions and step status
+                                # This is needed for steps to run in parallel
+                                # while obeying dependencies.
+
+                                providers = set()
+                                dependency_graph = self.dependency_graph if not deletion else self.deletion_dependency_graph
+
+                                for v in dependency_graph.values():
+                                        if (v):
+                                                providers.update(v)
+
+                                self.step_conditions = {}
+                                self.step_status = {}
+
+                                for p in list(providers):
+                                        self.step_conditions[p] = threading.Condition()
+
+                                        self.step_status[p] = STEP_STATUS_WORKING
+
+                                self.failed_steps = []
+
+                                threads = []
+                                logger.info('Deletion=%r...'%deletion)
+                                schedule = self.ordered_steps if not deletion else reversed(self.ordered_steps)
+
+                                for S in schedule:
+                                        thread = threading.Thread(target=self.sync, name='synchronizer', args=(S, deletion))
+
+                                        logger.info('Deletion=%r...'%deletion)
+                                        threads.append(thread)
+
+                                # Start threads
+                                for t in threads:
+                                        t.start()
+
+                                # another spot to clean up debug state
+                                try:
+                                    reset_queries()
+                                except:
+                                    # this shouldn't happen, but in case it does, catch it...
+                                    logger.log_exc("exception in reset_queries")
+
+                                # Wait for all threads to finish before continuing with the run loop
+                                for t in threads:
+                                        t.join()
+
+                        self.save_run_times()
+
+                        loop_end = time.time()
+
+                        update_diag(loop_end=loop_end, loop_start=loop_start, backend_status="1 - Bottom Of Loop")
+
+                except Exception, e:
+                        logger.error('Core error. This seems like a misconfiguration or bug: %r. This error will not be relayed to the user!' % e)
+                        logger.log_exc("Exception in observer run loop")
+                        traceback.print_exc()
+                        update_diag(backend_status="2 - Exception in Event Loop")
diff --git a/xos/synchronizers/base/event_manager.py b/xos/synchronizers/base/event_manager.py
new file mode 100644
index 0000000..fce2b68
--- /dev/null
+++ b/xos/synchronizers/base/event_manager.py
@@ -0,0 +1,120 @@
+import threading
+import requests, json
+
+from xos.config import Config, XOS_DIR
+
+import uuid
+import os
+import imp
+import inspect
+import base64
+import json
+import traceback
+
+if getattr(Config(),"observer_fofum_disabled", False) != True:
+    from fofum import Fofum
+    fofum_enabled = True
+else:
+    fofum_enabled = False
+
+random_client_id=None
+def get_random_client_id():
+    global random_client_id
+
+    if (random_client_id is None) and os.path.exists(XOS_DIR + "/random_client_id"):
+        # try to use the last one we used, if we saved it
+        try:
+            random_client_id = open(XOS_DIR+"/random_client_id","r").readline().strip()
+            print "get_random_client_id: loaded %s" % random_client_id
+        except:
+            print "get_random_client_id: failed to read " + XOS_DIR + "/random_client_id"
+
+    if random_client_id is None:
+        random_client_id = base64.urlsafe_b64encode(os.urandom(12))
+        print "get_random_client_id: generated new id %s" % random_client_id
+
+        # try to save it for later (XXX: could race with another client here)
+        try:
+            open(XOS_DIR + "/random_client_id","w").write("%s\n" % random_client_id)
+        except:
+            print "get_random_client_id: failed to write " + XOS_DIR + "/random_client_id"
+
+    return random_client_id
+
+# decorator that marks dispatachable event methods
+def event(func):
+    setattr(func, 'event', func.__name__)
+    return func
+
+class EventHandler:
+    # This code is currently not in use.
+    def __init__(self):
+        pass
+
+    @staticmethod
+    def get_events():
+        events = []
+        for name in dir(EventHandler):
+            attribute = getattr(EventHandler, name)
+            if hasattr(attribute, 'event'):
+                events.append(getattr(attribute, 'event'))
+        return events
+
+    def dispatch(self, event, *args, **kwds):
+        if hasattr(self, event):
+            return getattr(self, event)(*args, **kwds)
+            
+
+class EventSender:
+    def __init__(self,user=None,clientid=None):
+        try:
+            user = Config().feefie_client_user
+        except:
+            user = 'pl'
+
+        try:
+            clid = Config().feefie_client_id
+        except:
+            clid = get_random_client_id()
+            print "EventSender: no feefie_client_id configured. Using random id %s" % clid
+
+        if fofum_enabled:
+            self.fofum = Fofum(user=user)
+            self.fofum.make(clid)
+
+    def fire(self,**kwargs):
+        kwargs["uuid"] = str(uuid.uuid1())
+        if fofum_enabled:
+            self.fofum.fire(json.dumps(kwargs))
+
+class EventListener:
+    def __init__(self,wake_up=None):
+        self.handler = EventHandler()
+        self.wake_up = wake_up
+
+    def handle_event(self, payload):
+        payload_dict = json.loads(payload)
+
+        if (self.wake_up):
+            self.wake_up()
+
+    def run(self):
+        # This is our unique client id, to be used when firing and receiving events
+        # It needs to be generated once and placed in the config file
+
+        try:
+            user = Config().feefie_client_user
+        except:
+            user = 'pl'
+
+        try:
+            clid = Config().feefie_client_id
+        except:
+            clid = get_random_client_id()
+            print "EventListener: no feefie_client_id configured. Using random id %s" % clid
+
+        if fofum_enabled:
+            f = Fofum(user=user)
+
+            listener_thread = threading.Thread(target=f.listen_for_event,args=(clid,self.handle_event))
+            listener_thread.start()
diff --git a/xos/synchronizers/base/observer b/xos/synchronizers/base/observer
new file mode 120000
index 0000000..ae75af5
--- /dev/null
+++ b/xos/synchronizers/base/observer
@@ -0,0 +1 @@
+openstack_observer
\ No newline at end of file
diff --git a/xos/synchronizers/base/openstacksyncstep.py b/xos/synchronizers/base/openstacksyncstep.py
new file mode 100644
index 0000000..cc568f8
--- /dev/null
+++ b/xos/synchronizers/base/openstacksyncstep.py
@@ -0,0 +1,14 @@
+import os
+import base64
+from syncstep import SyncStep
+
+class OpenStackSyncStep(SyncStep):
+    """ XOS Sync step for copying data to OpenStack 
+    """ 
+    
+    def __init__(self, **args):
+        SyncStep.__init__(self, **args)
+        return
+
+    def __call__(self, **args):
+        return self.call(**args)
diff --git a/xos/synchronizers/base/run_ansible b/xos/synchronizers/base/run_ansible
new file mode 100755
index 0000000..a504ec3
--- /dev/null
+++ b/xos/synchronizers/base/run_ansible
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+source /opt/ansible/hacking/env-setup >> /dev/null
+ansible-playbook -v "$@"
diff --git a/xos/synchronizers/base/run_ansible_verbose b/xos/synchronizers/base/run_ansible_verbose
new file mode 100755
index 0000000..d17cad7
--- /dev/null
+++ b/xos/synchronizers/base/run_ansible_verbose
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+source /opt/ansible/hacking/env-setup >> /dev/null
+ansible-playbook -vvv "$@"
diff --git a/xos/synchronizers/base/steps/__init__.py b/xos/synchronizers/base/steps/__init__.py
new file mode 100644
index 0000000..c70b0c0
--- /dev/null
+++ b/xos/synchronizers/base/steps/__init__.py
@@ -0,0 +1,6 @@
+#from .sync_controller_sites import SyncControllerSites
+#from .sync_controller_slices import SyncControllerSlices
+#from .sync_controller_users import SyncControllerUsers
+#from .sync_controller_site_privileges import SyncControllerSitePrivileges
+#from .sync_controller_slice_privileges import SyncControllerSlicePrivileges
+#from .sync_controller_networks import SyncControllerNetworks
diff --git a/xos/synchronizers/base/steps/delete_slivers.yaml b/xos/synchronizers/base/steps/delete_slivers.yaml
new file mode 100644
index 0000000..fa6b879
--- /dev/null
+++ b/xos/synchronizers/base/steps/delete_slivers.yaml
@@ -0,0 +1,8 @@
+---
+- hosts: 127.0.0.1
+  connection: local
+  tasks:
+
+  - nova_compute:
+      state: absent
+      name: {{ name }}
diff --git a/xos/synchronizers/base/steps/purge_disabled_users.py b/xos/synchronizers/base/steps/purge_disabled_users.py
new file mode 100644
index 0000000..0973b8c
--- /dev/null
+++ b/xos/synchronizers/base/steps/purge_disabled_users.py
@@ -0,0 +1,25 @@
+import os
+import base64
+import datetime
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.openstacksyncstep import OpenStackSyncStep
+from core.models.user import User
+from xos.logger import observer_logger as logger
+
+class SyncRoles(OpenStackSyncStep):
+    provides=[User]
+    requested_interval=0
+    observes=User
+
+    def fetch_pending(self, deleted):
+        if (deleted):
+            # users marked as deleted
+            return User.deleted_objects.all()
+        else:
+            # disabled users that haven't been updated in over a week 
+            one_week_ago = datetime.datetime.now() - datetime.timedelta(days=7)
+            return User.objects.filter(is_active=False, updated__gt=one_week_ago)             
+
+    def sync_record(self, user):
+        user.delete() 
diff --git a/xos/synchronizers/base/steps/sliver.yaml b/xos/synchronizers/base/steps/sliver.yaml
new file mode 100644
index 0000000..e630415
--- /dev/null
+++ b/xos/synchronizers/base/steps/sliver.yaml
@@ -0,0 +1,17 @@
+---
+- hosts: 127.0.0.1
+  connection: local
+  tasks:
+  - nova_compute:
+       state: present
+       auth_url: http://172.31.38.128:5000/v2.0/
+       login_username: admin
+       login_password: 6a789bf69dd647e2
+       login_tenant_name: admin
+       name: gloopy
+       image_id: 3ee851df-b35a-41c5-8551-f681e7209095
+       key_name: boo
+       wait_for: 200
+       flavor_id: 3
+       nics:
+         - net-id: d1de537b-80dc-4c1b-aa5f-4a197b33b5f6
diff --git a/xos/synchronizers/base/steps/sync_container.py b/xos/synchronizers/base/steps/sync_container.py
new file mode 100644
index 0000000..b944495
--- /dev/null
+++ b/xos/synchronizers/base/steps/sync_container.py
@@ -0,0 +1,163 @@
+import hashlib
+import os
+import socket
+import sys
+import base64
+import time
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.SyncInstanceUsingAnsible import SyncInstanceUsingAnsible
+from synchronizers.base.syncstep import SyncStep, DeferredException
+from synchronizers.base.ansible import run_template_ssh
+from core.models import Service, Slice, Instance
+from services.onos.models import ONOSService, ONOSApp
+from xos.logger import Logger, logging
+
+# hpclibrary will be in steps/..
+parentdir = os.path.join(os.path.dirname(__file__),"..")
+sys.path.insert(0,parentdir)
+
+logger = Logger(level=logging.INFO)
+
+class SyncContainer(SyncInstanceUsingAnsible):
+    provides=[Instance]
+    observes=Instance
+    requested_interval=0
+    template_name = "sync_container.yaml"
+
+    def __init__(self, *args, **kwargs):
+        super(SyncContainer, self).__init__(*args, **kwargs)
+
+    def fetch_pending(self, deletion=False):
+        objs = super(SyncContainer, self).fetch_pending(deletion)
+        objs = [x for x in objs if x.isolation in ["container", "container_vm"]]
+        return objs
+
+    def get_instance_port(self, container_port):
+        for p in container_port.network.links.all():
+            if (p.instance) and (p.instance.isolation=="vm") and (p.instance.node == container_port.instance.node) and (p.mac):
+                return p
+        return None
+
+    def get_parent_port_mac(self, instance, port):
+        if not instance.parent:
+            raise Exception("instance has no parent")
+        for parent_port in instance.parent.ports.all():
+            if parent_port.network == port.network:
+                if not parent_port.mac:
+                     raise DeferredException("parent port on network %s does not have mac yet" % parent_port.network.name)
+                return parent_port.mac
+        raise Exception("failed to find corresponding parent port for network %s" % port.network.name)
+
+    def get_ports(self, o):
+        i=0
+        ports = []
+        if (o.slice.network in ["host", "bridged"]):
+            pass # no ports in host or bridged mode
+        else:
+            for port in o.ports.all():
+                if (not port.ip):
+                    # 'unmanaged' ports may have an ip, but no mac
+                    # XXX: are there any ports that have a mac but no ip?
+                    raise DeferredException("Port on network %s is not yet ready" % port.network.name)
+
+                pd={}
+                pd["mac"] = port.mac or ""
+                pd["ip"] = port.ip or ""
+                pd["xos_network_id"] = port.network.id
+
+                if port.network.name == "wan_network":
+                    if port.ip:
+                        (a, b, c, d) = port.ip.split('.')
+                        pd["mac"] = "02:42:%02x:%02x:%02x:%02x" % (int(a), int(b), int(c), int(d))
+
+
+                if o.isolation == "container":
+                    # container on bare metal
+                    instance_port = self.get_instance_port(port)
+                    if not instance_port:
+                        raise DeferredException("No instance on slice for port on network %s" % port.network.name)
+
+                    pd["snoop_instance_mac"] = instance_port.mac
+                    pd["snoop_instance_id"] = instance_port.instance.instance_id
+                    pd["src_device"] = ""
+                    pd["bridge"] = "br-int"
+                else:
+                    # container in VM
+                    pd["snoop_instance_mac"] = ""
+                    pd["snoop_instance_id"] = ""
+                    pd["parent_mac"] = self.get_parent_port_mac(o, port)
+                    pd["bridge"] = ""
+
+                for (k,v) in port.get_parameters().items():
+                    pd[k] = v
+
+                ports.append(pd)
+
+            # for any ports that don't have a device, assign one
+            used_ports = [x["device"] for x in ports if ("device" in x)]
+            avail_ports = ["eth%d"%i for i in range(0,64) if ("eth%d"%i not in used_ports)]
+            for port in ports:
+                if not port.get("device",None):
+                    port["device"] = avail_ports.pop(0)
+
+        return ports
+
+    def get_extra_attributes(self, o):
+        fields={}
+        fields["ansible_tag"] = "container-%s" % str(o.id)
+        if o.image.tag:
+            fields["docker_image"] = o.image.path + ":" + o.image.tag
+        else:
+            fields["docker_image"] = o.image.path
+        fields["ports"] = self.get_ports(o)
+        if o.volumes:
+            fields["volumes"] = [x.strip() for x in o.volumes.split(",")]
+        else:
+            fields["volumes"] = ""
+        fields["network_method"] = o.slice.network or "default"
+        return fields
+
+    def sync_record(self, o):
+        logger.info("sync'ing object %s" % str(o),extra=o.tologdict())
+
+        fields = self.get_ansible_fields(o)
+
+        # If 'o' defines a 'sync_attributes' list, then we'll copy those
+        # attributes into the Ansible recipe's field list automatically.
+        if hasattr(o, "sync_attributes"):
+            for attribute_name in o.sync_attributes:
+                fields[attribute_name] = getattr(o, attribute_name)
+
+        fields.update(self.get_extra_attributes(o))
+
+        self.run_playbook(o, fields)
+
+        o.instance_id = fields["container_name"]
+        o.instance_name = fields["container_name"]
+
+        o.save()
+
+    def delete_record(self, o):
+        logger.info("delete'ing object %s" % str(o),extra=o.tologdict())
+
+        fields = self.get_ansible_fields(o)
+
+        # If 'o' defines a 'sync_attributes' list, then we'll copy those
+        # attributes into the Ansible recipe's field list automatically.
+        if hasattr(o, "sync_attributes"):
+            for attribute_name in o.sync_attributes:
+                fields[attribute_name] = getattr(o, attribute_name)
+
+        fields.update(self.get_extra_attributes(o))
+
+        self.run_playbook(o, fields, "teardown_container.yaml")
+
+    def run_playbook(self, o, fields, template_name=None):
+        if not template_name:
+            template_name = self.template_name
+        tStart = time.time()
+        run_template_ssh(template_name, fields, path="container")
+        logger.info("playbook execution time %d" % int(time.time()-tStart,extra=o.tologdict())
+
+
diff --git a/xos/synchronizers/base/steps/sync_container.yaml b/xos/synchronizers/base/steps/sync_container.yaml
new file mode 100644
index 0000000..77e57cd
--- /dev/null
+++ b/xos/synchronizers/base/steps/sync_container.yaml
@@ -0,0 +1,116 @@
+---
+- hosts: {{ instance_name }}
+  gather_facts: False
+  connection: ssh
+  user: {{ username }}
+  sudo: yes
+
+  vars:
+    container_name: {{ container_name }}
+    docker_image: {{ docker_image }}
+    network_method: {{ network_method }}
+    ports:
+    {% for port in ports %}
+       - device: {{ port.device }}
+         xos_network_id: {{ port.xos_network_id }}
+         mac: {{ port.mac|default("") }}
+         ip: {{ port.ip }}
+         snoop_instance_mac: {{ port.snoop_instance_mac }}
+         snoop_instance_id: {{ port.snoop_instance_id }}
+         parent_mac: {{ port.parent_mac|default("") }}
+         s_tag: {{ port.s_tag|default("")  }}
+         c_tag: {{ port.c_tag|default("") }}
+         next_hop: {{ port.next_hop|default("") }}
+         bridge: {{ port.bridge }}
+    {% endfor %}
+    volumes:
+    {% for volume in volumes %}
+       - {{ volume }}
+    {% endfor %}
+
+  tasks:
+
+#  - name: Fix /etc/hosts
+#    lineinfile:
+#      dest=/etc/hosts
+#      regexp="127.0.0.1 localhost"
+#      line="127.0.0.1 localhost {{ instance_hostname }}"
+
+  - name: Add repo key
+    apt_key:
+      keyserver=hkp://pgp.mit.edu:80
+      id=58118E89F3A912897C070ADBF76221572C52609D
+
+  - name: Install Docker repo
+    apt_repository:
+      repo="deb https://apt.dockerproject.org/repo ubuntu-trusty main"
+      state=present
+
+  - name: Install Docker
+    apt:
+      name={{ '{{' }} item {{ '}}' }}
+      state=latest
+      update_cache=yes
+    with_items:
+    - docker-engine
+    - python-pip
+    - python-httplib2
+
+  # Something is installing a requests library that is incompative with pip, and
+  # will cause this recipe to fail next time it tries to run pip. Only the one
+  # in /usr/local/lib is bad. There's still a good one in /usr/lib
+  - name: check if bad requests library installed
+    stat: path=/usr/local/lib/python2.7/dist-packages/requests
+    register: bad_requests
+
+  - name: remove bad request library
+    shell: mv /usr/local/lib/python2.7/dist-packages/requests /usr/local/lib/python2.7/dist-packages/requests-bad
+    when: bad_requests.stat.exists == True
+
+  - name: Install docker-py
+    pip:
+      name=docker-py
+      state=latest
+
+  - name: install Pipework
+    get_url: url=https://raw.githubusercontent.com/jpetazzo/pipework/master/pipework
+       dest=/usr/local/bin/pipework
+       mode=0755
+
+#  - name: Start Container
+#    docker:
+#      docker_api_version: "1.18"
+#      name: {{ container_name }}
+#      # was: reloaded
+#      state: running
+#      image: {{ docker_image }}
+
+  - name: check if systemd is installed
+    stat: path=/usr/bin/systemctl
+    register: systemctl
+
+  - name: container upstart
+    template: src=/opt/xos/openstack_observer/templates/container.conf.j2 dest=/etc/init/container-{{ container_name }}.conf
+
+  - name: container systemd
+    template: src=/opt/xos/openstack_observer/templates/container.service.j2 dest=/lib/systemd/system/container-{{ container_name }}.service
+
+  - name: container startup script
+    template: src=/opt/xos/openstack_observer/templates/start-container.sh.j2 dest=/usr/local/sbin/start-container-{{ container_name }}.sh mode=0755
+
+  - name: container teardown script
+    template: src=/opt/xos/openstack_observer/templates/stop-container.sh.j2 dest=/usr/local/sbin/stop-container-{{ container_name }}.sh mode=0755
+
+  - name: restart systemd
+    shell: systemctl daemon-reload
+    when: systemctl.stat.exists == True
+
+{% if ports %}
+  - name: make sure bridges are setup
+    shell: ifconfig {{ '{{' }} item.bridge {{ '}}' }}
+    with_items: "ports"
+{% endif %}
+
+  - name: Make sure container is running
+    service: name=container-{{ container_name }} state=started
+
diff --git a/xos/synchronizers/base/steps/sync_controller_images.py b/xos/synchronizers/base/steps/sync_controller_images.py
new file mode 100644
index 0000000..c1e5136
--- /dev/null
+++ b/xos/synchronizers/base/steps/sync_controller_images.py
@@ -0,0 +1,44 @@
+import os
+import base64
+from collections import defaultdict
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.openstacksyncstep import OpenStackSyncStep
+from synchronizers.base.syncstep import *
+from core.models import Controller
+from core.models import Image, ControllerImages
+from xos.logger import observer_logger as logger 
+from synchronizers.base.ansible import *
+import json
+
+class SyncControllerImages(OpenStackSyncStep):
+    provides=[ControllerImages]
+    observes = ControllerImages
+    requested_interval=0
+    playbook='sync_controller_images.yaml'
+
+    def fetch_pending(self, deleted):
+        if (deleted):
+            return []
+
+        # now we return all images that need to be enacted
+        return ControllerImages.objects.filter(Q(enacted__lt=F('updated')) | Q(enacted=None))
+
+    def map_sync_inputs(self, controller_image):
+        image_fields = {'endpoint':controller_image.controller.auth_url,
+                        'endpoint_v3': controller_image.controller.auth_url_v3,
+                        'admin_user':controller_image.controller.admin_user,
+                        'admin_password':controller_image.controller.admin_password,
+                        'domain': controller_image.controller.domain,
+                        'name':controller_image.image.name,
+                        'filepath':controller_image.image.path,
+                        'ansible_tag': '%s@%s'%(controller_image.image.name,controller_image.controller.name), # name of ansible playbook
+                        }
+
+	return image_fields
+
+    def map_sync_outputs(self, controller_image, res):
+        image_id = res[0]['id']
+        controller_image.glance_image_id = image_id
+	controller_image.backend_status = '1 - OK'
+        controller_image.save()
diff --git a/xos/synchronizers/base/steps/sync_controller_images.yaml b/xos/synchronizers/base/steps/sync_controller_images.yaml
new file mode 100644
index 0000000..6247a30
--- /dev/null
+++ b/xos/synchronizers/base/steps/sync_controller_images.yaml
@@ -0,0 +1,13 @@
+---
+- hosts: 127.0.0.1
+  connection: local
+  tasks:
+  - glance_image:
+        auth_url={{ endpoint }}
+        login_username="{{ admin_user }}"
+        login_tenant_name="admin"
+        login_password="{{ admin_password }}"
+        name="{{ name }}"
+        file="{{ filepath }}"
+        disk_format='raw'
+        is_public=true
diff --git a/xos/synchronizers/base/steps/sync_controller_networks.py b/xos/synchronizers/base/steps/sync_controller_networks.py
new file mode 100644
index 0000000..990cb87
--- /dev/null
+++ b/xos/synchronizers/base/steps/sync_controller_networks.py
@@ -0,0 +1,136 @@
+import os
+import base64
+from collections import defaultdict
+from netaddr import IPAddress, IPNetwork
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.openstacksyncstep import OpenStackSyncStep
+from synchronizers.base.syncstep import *
+from core.models.network import *
+from core.models.slice import *
+from core.models.instance import Instance
+from xos.logger import observer_logger as logger
+from synchronizers.base.ansible import *
+from openstack.driver import OpenStackDriver
+from xos.config import Config
+import json
+
+import pdb
+
+class SyncControllerNetworks(OpenStackSyncStep):
+    requested_interval = 0
+    provides=[Network]
+    observes=ControllerNetwork	
+    playbook='sync_controller_networks.yaml'
+
+    def alloc_subnet(self, uuid):
+        # 16 bits only
+        uuid_masked = uuid & 0xffff
+        a = 10
+        b = uuid_masked >> 8
+        c = uuid_masked & 0xff
+        d = 0
+
+        cidr = '%d.%d.%d.%d/24'%(a,b,c,d)
+        return cidr
+
+    def alloc_gateway(self, uuid):
+        # 16 bits only
+        uuid_masked = uuid & 0xffff
+        a = 10
+        b = uuid_masked >> 8
+        c = uuid_masked & 0xff
+        d = 1
+
+        gateway = '%d.%d.%d.%d'%(a,b,c,d)
+        return gateway
+
+
+    def save_controller_network(self, controller_network):
+        network_name = controller_network.network.name
+        subnet_name = '%s-%d'%(network_name,controller_network.pk)
+        cidr = self.alloc_subnet(controller_network.pk)
+        self.cidr=cidr
+        slice = controller_network.network.owner
+
+        network_fields = {'endpoint':controller_network.controller.auth_url,
+                    'endpoint_v3': controller_network.controller.auth_url_v3,
+                    'admin_user':slice.creator.email,
+                    'tenant_name':slice.name,
+                    'admin_password':slice.creator.remote_password,
+                    'domain': controller_network.controller.domain,
+                    'name':network_name,
+                    'subnet_name':subnet_name,
+                    'ansible_tag':'%s-%s@%s'%(network_name,slice.slicename,controller_network.controller.name),
+                    'cidr':cidr,
+                    'gateway':self.alloc_gateway(controller_network.pk),
+                    'use_vtn':getattr(Config(), "networking_use_vtn", False),
+                    'delete':False	
+                    }
+        return network_fields
+
+    def map_sync_outputs(self, controller_network,res):
+        network_id = res[0]['id']
+        subnet_id = res[1]['id']
+        controller_network.net_id = network_id
+        controller_network.subnet = self.cidr
+        controller_network.subnet_id = subnet_id
+	controller_network.backend_status = '1 - OK'
+        controller_network.save()
+
+
+    def map_sync_inputs(self, controller_network):
+        # XXX This check should really be made from booleans, rather than using hardcoded network names
+        if (controller_network.network.template.name not in ['Private', 'Private-Indirect', 'Private-Direct']):
+            logger.info("skipping network controller %s because it is not private" % controller_network)
+            # We only sync private networks
+            return SyncStep.SYNC_WITHOUT_RUNNING
+        
+        if not controller_network.controller.admin_user:
+            logger.info("controller %r has no admin_user, skipping" % controller_network.controller)
+            return
+
+        if controller_network.network.owner and controller_network.network.owner.creator:
+	    return self.save_controller_network(controller_network)
+        else:
+            raise Exception('Could not save network controller %s'%controller_network)
+
+    def map_delete_inputs(self, controller_network):
+        # XXX This check should really be made from booleans, rather than using hardcoded network names
+	if (controller_network.network.template.name not in ['Private', 'Private-Indirect', 'Private-Direct']):
+            # We only sync private networks
+            return
+	try:
+        	slice = controller_network.network.owner # XXX: FIXME!!
+        except:
+                raise Exception('Could not get slice for Network %s'%controller_network.network.name)
+
+	network_name = controller_network.network.name
+        subnet_name = '%s-%d'%(network_name,controller_network.pk)
+	cidr = controller_network.subnet
+	network_fields = {'endpoint':controller_network.controller.auth_url,
+                    'admin_user':slice.creator.email, # XXX: FIXME
+                    'tenant_name':slice.name, # XXX: FIXME
+                    'admin_password':slice.creator.remote_password,
+                    'name':network_name,
+                    'subnet_name':subnet_name,
+                    'ansible_tag':'%s-%s@%s'%(network_name,slice.slicename,controller_network.controller.name),
+                    'cidr':cidr,
+		    'delete':True	
+                    }
+
+        return network_fields
+
+	"""
+        driver = OpenStackDriver().client_driver(caller=controller_network.network.owner.creator,
+                                                 tenant=controller_network.network.owner.name,
+                                                 controller=controller_network.controller.name)
+        if (controller_network.router_id) and (controller_network.subnet_id):
+            driver.delete_router_interface(controller_network.router_id, controller_network.subnet_id)
+        if controller_network.subnet_id:
+            driver.delete_subnet(controller_network.subnet_id)
+        if controller_network.router_id:
+            driver.delete_router(controller_network.router_id)
+        if controller_network.net_id:
+            driver.delete_network(controller_network.net_id)
+	"""
diff --git a/xos/synchronizers/base/steps/sync_controller_networks.yaml b/xos/synchronizers/base/steps/sync_controller_networks.yaml
new file mode 100644
index 0000000..b885516
--- /dev/null
+++ b/xos/synchronizers/base/steps/sync_controller_networks.yaml
@@ -0,0 +1,39 @@
+---
+- hosts: 127.0.0.1
+  connection: local
+  tasks:
+  - quantum_network:
+        auth_url={{ endpoint }}
+        login_username={{ admin_user }}
+        login_tenant_name={{ tenant_name }}
+        login_password={{ admin_password }}
+        tenant_name={{ tenant_name }}
+        name={{ name }}
+        {% if delete %}
+        state=absent
+        {% else %}
+        state=present
+        {% endif %}
+        shared=true
+  {% if not delete %}
+  - quantum_subnet:
+        auth_url={{ endpoint }}
+        login_username={{ admin_user }}
+        login_tenant_name={{ tenant_name }}
+        login_password={{ admin_password }}
+        tenant_name={{ tenant_name }}
+        name={{ subnet_name }}
+        network_name={{ name }}
+        {% if delete %}
+        state=absent
+        {% else %}
+        state=present
+        {% if use_vtn %}
+        gateway_ip={{ gateway }}
+        {% else %}
+        no_gateway=true
+        {% endif %}
+        dns_nameservers=8.8.8.8
+        cidr={{ cidr }}
+        {% endif %}
+  {% endif %}
diff --git a/xos/synchronizers/base/steps/sync_controller_site_privileges.py b/xos/synchronizers/base/steps/sync_controller_site_privileges.py
new file mode 100644
index 0000000..59919fe
--- /dev/null
+++ b/xos/synchronizers/base/steps/sync_controller_site_privileges.py
@@ -0,0 +1,84 @@
+import os
+import base64
+from collections import defaultdict
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.openstacksyncstep import OpenStackSyncStep
+from synchronizers.base.syncstep import *
+from core.models.site import Controller, SitePrivilege 
+from core.models.user import User
+from core.models.controlleruser import ControllerUser, ControllerSitePrivilege
+from xos.logger import observer_logger as logger
+from synchronizers.base.ansible import *
+import json
+
+class SyncControllerSitePrivileges(OpenStackSyncStep):
+    provides=[SitePrivilege]
+    requested_interval=0
+    observes=ControllerSitePrivilege
+    playbook='sync_controller_users.yaml'
+
+    def map_sync_inputs(self, controller_site_privilege):
+	controller_register = json.loads(controller_site_privilege.controller.backend_register)
+        if not controller_site_privilege.controller.admin_user:
+            logger.info("controller %r has no admin_user, skipping" % controller_site_privilege.controller)
+            return
+
+        roles = [controller_site_privilege.site_privilege.role.role]
+	# setup user home site roles at controller 
+        if not controller_site_privilege.site_privilege.user.site:
+            raise Exception('Siteless user %s'%controller_site_privilege.site_privilege.user.email)
+        else:
+            # look up tenant id for the user's site at the controller
+            #ctrl_site_deployments = SiteDeployment.objects.filter(
+            #  site_deployment__site=controller_site_privilege.user.site,
+            #  controller=controller_site_privilege.controller)
+
+            #if ctrl_site_deployments:
+            #    # need the correct tenant id for site at the controller
+            #    tenant_id = ctrl_site_deployments[0].tenant_id  
+            #    tenant_name = ctrl_site_deployments[0].site_deployment.site.login_base
+            user_fields = {
+               'endpoint':controller_site_privilege.controller.auth_url,
+               'endpoint_v3': controller_site_privilege.controller.auth_url_v3,
+               'domain': controller_site_privilege.controller.domain,
+		       'name': controller_site_privilege.site_privilege.user.email,
+               'email': controller_site_privilege.site_privilege.user.email,
+               'password': controller_site_privilege.site_privilege.user.remote_password,
+               'admin_user': controller_site_privilege.controller.admin_user,
+		       'admin_password': controller_site_privilege.controller.admin_password,
+	           'ansible_tag':'%s@%s'%(controller_site_privilege.site_privilege.user.email.replace('@','-at-'),controller_site_privilege.controller.name),
+		       'admin_tenant': controller_site_privilege.controller.admin_tenant,
+		       'roles':roles,
+		       'tenant':controller_site_privilege.site_privilege.site.login_base}    
+	
+	    return user_fields
+
+    def map_sync_outputs(self, controller_site_privilege, res):
+	    # results is an array in which each element corresponds to an 
+	    # "ok" string received per operation. If we get as many oks as
+	    # the number of operations we issued, that means a grand success.
+	    # Otherwise, the number of oks tell us which operation failed.
+            controller_site_privilege.role_id = res[0]['id']
+            controller_site_privilege.save()
+
+    def delete_record(self, controller_site_privilege):
+	controller_register = json.loads(controller_site_privilege.controller.backend_register)
+        if (controller_register.get('disabled',False)):
+                raise InnocuousException('Controller %s is disabled'%controller_site_privilege.controller.name)
+
+        if controller_site_privilege.role_id:
+            driver = self.driver.admin_driver(controller=controller_site_privilege.controller)
+            user = ControllerUser.objects.get(
+                controller=controller_site_privilege.controller, 
+                user=controller_site_privilege.site_privilege.user
+            )
+            site = ControllerSite.objects.get(
+                controller=controller_site_privilege.controller, 
+                user=controller_site_privilege.site_privilege.user
+            )
+            driver.delete_user_role(
+                user.kuser_id, 
+                site.tenant_id, 
+                controller_site_privilege.site_prvilege.role.role
+            )
diff --git a/xos/synchronizers/base/steps/sync_controller_sites.py b/xos/synchronizers/base/steps/sync_controller_sites.py
new file mode 100644
index 0000000..1b3c2ba
--- /dev/null
+++ b/xos/synchronizers/base/steps/sync_controller_sites.py
@@ -0,0 +1,67 @@
+import os
+import base64
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.openstack.openstacksyncstep import OpenStackSyncStep
+from core.models.site import *
+from synchronizers.base.syncstep import *
+from synchronizers.base.ansible import *
+from xos.logger import observer_logger as logger
+import json
+
+class SyncControllerSites(OpenStackSyncStep):
+    requested_interval=0
+    provides=[Site]
+    observes=ControllerSite
+    playbook = 'sync_controller_sites.yaml'
+
+    def fetch_pending(self, deleted=False):
+        lobjs = ControllerSite.objects.filter(Q(enacted__lt=F('updated')) | Q(enacted=None),Q(lazy_blocked=False),Q(controller__isnull=False))
+        return lobjs
+
+    def map_sync_inputs(self, controller_site):
+	tenant_fields = {'endpoint':controller_site.controller.auth_url,
+                 'endpoint_v3': controller_site.controller.auth_url_v3,
+                 'domain': controller_site.controller.domain,
+		         'admin_user': controller_site.controller.admin_user,
+		         'admin_password': controller_site.controller.admin_password,
+		         'admin_tenant': controller_site.controller.admin_tenant,
+	             'ansible_tag': '%s@%s'%(controller_site.site.login_base,controller_site.controller.name), # name of ansible playbook
+		         'tenant': controller_site.site.login_base,
+		         'tenant_description': controller_site.site.name}
+        return tenant_fields
+
+    def map_sync_outputs(self, controller_site, res):
+	controller_site.tenant_id = res[0]['id']
+	controller_site.backend_status = '1 - OK'
+        controller_site.save()
+            
+    def delete_record(self, controller_site):
+	controller_register = json.loads(controller_site.controller.backend_register)
+        if (controller_register.get('disabled',False)):
+                raise InnocuousException('Controller %s is disabled'%controller_site.controller.name)
+
+	if controller_site.tenant_id:
+            driver = self.driver.admin_driver(controller=controller_site.controller)
+            driver.delete_tenant(controller_site.tenant_id)
+
+	"""
+        Ansible does not support tenant deletion yet
+
+	import pdb
+	pdb.set_trace()
+        template = os_template_env.get_template('delete_controller_sites.yaml')
+	tenant_fields = {'endpoint':controller_site.controller.auth_url,
+		         'admin_user': controller_site.controller.admin_user,
+		         'admin_password': controller_site.controller.admin_password,
+		         'admin_tenant': 'admin',
+	                 'ansible_tag': 'controller_sites/%s@%s'%(controller_site.controller_site.site.login_base,controller_site.controller_site.deployment.name), # name of ansible playbook
+		         'tenant': controller_site.controller_site.site.login_base,
+		         'delete': True}
+
+	rendered = template.render(tenant_fields)
+	res = run_template('sync_controller_sites.yaml', tenant_fields)
+
+	if (len(res)!=1):
+		raise Exception('Could not assign roles for user %s'%tenant_fields['tenant'])
+	"""
diff --git a/xos/synchronizers/base/steps/sync_controller_sites.yaml b/xos/synchronizers/base/steps/sync_controller_sites.yaml
new file mode 100644
index 0000000..4129802
--- /dev/null
+++ b/xos/synchronizers/base/steps/sync_controller_sites.yaml
@@ -0,0 +1,5 @@
+---
+- hosts: 127.0.0.1
+  connection: local
+  tasks:
+  - keystone_user: endpoint={{ endpoint }} login_user={{ admin_user }} login_password={{ admin_password }} login_tenant_name={{ admin_tenant }} tenant={{ tenant }} tenant_description="{{ tenant_description }}"
diff --git a/xos/synchronizers/base/steps/sync_controller_slice_privileges.py b/xos/synchronizers/base/steps/sync_controller_slice_privileges.py
new file mode 100644
index 0000000..b78e4a0
--- /dev/null
+++ b/xos/synchronizers/base/steps/sync_controller_slice_privileges.py
@@ -0,0 +1,79 @@
+import os
+import base64
+from collections import defaultdict
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.openstacksyncstep import OpenStackSyncStep
+from synchronizers.base.syncstep import *
+from core.models.slice import Controller, SlicePrivilege 
+from core.models.user import User
+from core.models.controlleruser import ControllerUser, ControllerSlicePrivilege
+from synchronizers.base.ansible import *
+from xos.logger import observer_logger as logger
+import json
+
+class SyncControllerSlicePrivileges(OpenStackSyncStep):
+    provides=[SlicePrivilege]
+    requested_interval=0
+    observes=ControllerSlicePrivilege
+    playbook = 'sync_controller_users.yaml'
+
+    def map_inputs(self, controller_slice_privilege):
+        if not controller_slice_privilege.controller.admin_user:
+            logger.info("controller %r has no admin_user, skipping" % controller_slice_privilege.controller)
+            return
+
+	template = os_template_env.get_template('sync_controller_users.yaml')
+        roles = [controller_slice_privilege.slice_privilege.role.role]
+	# setup user home slice roles at controller 
+        if not controller_slice_privilege.slice_privilege.user.site:
+            raise Exception('Sliceless user %s'%controller_slice_privilege.slice_privilege.user.email)
+        else:
+            # look up tenant id for the user's slice at the controller
+            #ctrl_slice_deployments = SliceDeployment.objects.filter(
+            #  slice_deployment__slice=controller_slice_privilege.user.slice,
+            #  controller=controller_slice_privilege.controller)
+
+            #if ctrl_slice_deployments:
+            #    # need the correct tenant id for slice at the controller
+            #    tenant_id = ctrl_slice_deployments[0].tenant_id  
+            #    tenant_name = ctrl_slice_deployments[0].slice_deployment.slice.login_base
+            user_fields = {
+               'endpoint':controller_slice_privilege.controller.auth_url,
+               'endpoint_v3': controller_slice_privilege.controller.auth_url_v3,
+               'domain': controller_slice_privilege.controller.domain,
+		       'name': controller_slice_privilege.slice_privilege.user.email,
+               'email': controller_slice_privilege.slice_privilege.user.email,
+               'password': controller_slice_privilege.slice_privilege.user.remote_password,
+               'admin_user': controller_slice_privilege.controller.admin_user,
+		       'admin_password': controller_slice_privilege.controller.admin_password,
+               'ansible_tag':'%s@%s@%s'%(controller_slice_privilege.slice_privilege.user.email.replace('@','-at-'),controller_slice_privilege.slice_privilege.slice.name,controller_slice_privilege.controller.name),
+		       'admin_tenant': controller_slice_privilege.controller.admin_tenant,
+		       'roles':roles,
+		       'tenant':controller_slice_privilege.slice_privilege.slice.name}    
+            return user_fields
+	
+    def map_sync_outputs(self, controller_slice_privilege, res):
+        controller_slice_privilege.role_id = res[0]['id']
+        controller_slice_privilege.save()
+
+    def delete_record(self, controller_slice_privilege):
+	controller_register = json.loads(controller_slice_privilege.controller.backend_register)
+        if (controller_register.get('disabled',False)):
+                raise InnocuousException('Controller %s is disabled'%controller_slice_privilege.controller.name)
+
+        if controller_slice_privilege.role_id:
+            driver = self.driver.admin_driver(controller=controller_slice_privilege.controller)
+            user = ControllerUser.objects.get(
+                controller=controller_slice_privilege.controller, 
+                user=controller_slice_privilege.slice_privilege.user
+            )
+            slice = ControllerSlice.objects.get(
+                controller=controller_slice_privilege.controller, 
+                user=controller_slice_privilege.slice_privilege.user
+            )
+            driver.delete_user_role(
+                user.kuser_id, 
+                slice.tenant_id, 
+                controller_slice_privilege.slice_prvilege.role.role
+            )
diff --git a/xos/synchronizers/base/steps/sync_controller_slices.py b/xos/synchronizers/base/steps/sync_controller_slices.py
new file mode 100644
index 0000000..97d8c29
--- /dev/null
+++ b/xos/synchronizers/base/steps/sync_controller_slices.py
@@ -0,0 +1,84 @@
+import os
+import base64
+from collections import defaultdict
+from netaddr import IPAddress, IPNetwork
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.openstacksyncstep import OpenStackSyncStep
+from synchronizers.base.syncstep import *
+from core.models import *
+from synchronizers.base.ansible import *
+from openstack.driver import OpenStackDriver
+from xos.logger import observer_logger as logger
+import json
+
+class SyncControllerSlices(OpenStackSyncStep):
+    provides=[Slice]
+    requested_interval=0
+    observes=ControllerSlice
+    playbook='sync_controller_slices.yaml'
+
+    def map_sync_inputs(self, controller_slice):
+        logger.info("sync'ing slice controller %s" % controller_slice)
+
+        if not controller_slice.controller.admin_user:
+            logger.info("controller %r has no admin_user, skipping" % controller_slice.controller)
+            return
+
+        controller_users = ControllerUser.objects.filter(user=controller_slice.slice.creator,
+                                                             controller=controller_slice.controller)
+        if not controller_users:
+            raise Exception("slice createor %s has not accout at controller %s" % (controller_slice.slice.creator, controller_slice.controller.name))
+        else:
+            controller_user = controller_users[0]
+            roles = ['admin']
+
+        max_instances=int(controller_slice.slice.max_instances)
+        tenant_fields = {'endpoint':controller_slice.controller.auth_url,
+                         'endpoint_v3': controller_slice.controller.auth_url_v3,
+                         'domain': controller_slice.controller.domain,
+                         'admin_user': controller_slice.controller.admin_user,
+                         'admin_password': controller_slice.controller.admin_password,
+                         'admin_tenant': 'admin',
+                         'tenant': controller_slice.slice.name,
+                         'tenant_description': controller_slice.slice.description,
+                         'roles':roles,
+                         'name':controller_user.user.email,
+                         'ansible_tag':'%s@%s'%(controller_slice.slice.name,controller_slice.controller.name),
+                         'max_instances':max_instances}
+
+        return tenant_fields
+
+    def map_sync_outputs(self, controller_slice, res):
+        tenant_id = res[0]['id']
+        if (not controller_slice.tenant_id):
+            try:
+                driver = OpenStackDriver().admin_driver(controller=controller_slice.controller)
+                driver.shell.nova.quotas.update(tenant_id=tenant_id, instances=int(controller_slice.slice.max_instances))
+            except:
+                logger.log_exc('Could not update quota for %s'%controller_slice.slice.name)
+                raise Exception('Could not update quota for %s'%controller_slice.slice.name)
+
+            controller_slice.tenant_id = tenant_id
+            controller_slice.backend_status = '1 - OK'
+            controller_slice.save()
+
+
+    def map_delete_inputs(self, controller_slice):
+        controller_users = ControllerUser.objects.filter(user=controller_slice.slice.creator,
+                                                              controller=controller_slice.controller)
+        if not controller_users:
+            raise Exception("slice createor %s has not accout at controller %s" % (controller_slice.slice.creator, controller_slice.controller.name))
+        else:
+            controller_user = controller_users[0]
+
+        tenant_fields = {'endpoint':controller_slice.controller.auth_url,
+                          'admin_user': controller_slice.controller.admin_user,
+                          'admin_password': controller_slice.controller.admin_password,
+                          'admin_tenant': 'admin',
+                          'tenant': controller_slice.slice.name,
+                          'tenant_description': controller_slice.slice.description,
+                          'name':controller_user.user.email,
+                          'ansible_tag':'%s@%s'%(controller_slice.slice.name,controller_slice.controller.name),
+                          'delete': True}
+	return tenant_fields
diff --git a/xos/synchronizers/base/steps/sync_controller_slices.py.bak b/xos/synchronizers/base/steps/sync_controller_slices.py.bak
new file mode 100644
index 0000000..e04da8e
--- /dev/null
+++ b/xos/synchronizers/base/steps/sync_controller_slices.py.bak
@@ -0,0 +1,95 @@
+import os
+import base64
+from collections import defaultdict
+from netaddr import IPAddress, IPNetwork
+from django.db.models import F, Q
+from xos.config import Config
+from observer.openstacksyncstep import OpenStackSyncStep
+from core.models import *
+from observer.ansible import *
+from openstack.driver import OpenStackDriver
+from util.logger import observer_logger as logger
+import json
+
+class SyncControllerSlices(OpenStackSyncStep):
+    provides=[Slice]
+    requested_interval=0
+    observes=ControllerSlice
+
+    def fetch_pending(self, deleted):
+        if (deleted):
+            return ControllerSlice.deleted_objects.all()
+        else:
+            return ControllerSlice.objects.filter(Q(enacted__lt=F('updated')) | Q(enacted=None))
+
+    def sync_record(self, controller_slice):
+        logger.info("sync'ing slice controller %s" % controller_slice)
+
+	controller_register = json.loads(controller_slice.controller.backend_register)
+	if (controller_register.get('disabled',False)):
+		raise Exception('Controller %s is disabled'%controller_slice.controller.name)
+
+        if not controller_slice.controller.admin_user:
+            logger.info("controller %r has no admin_user, skipping" % controller_slice.controller)
+            return
+
+        controller_users = ControllerUser.objects.filter(user=controller_slice.slice.creator,
+                                                             controller=controller_slice.controller)
+        if not controller_users:
+            raise Exception("slice createor %s has not accout at controller %s" % (controller_slice.slice.creator, controller_slice.controller.name))
+        else:
+            controller_user = controller_users[0]
+            roles = ['Admin']
+
+        max_instances=int(controller_slice.slice.max_slivers)
+        tenant_fields = {'endpoint':controller_slice.controller.auth_url,
+                         'admin_user': controller_slice.controller.admin_user,
+                         'admin_password': controller_slice.controller.admin_password,
+                         'admin_tenant': 'admin',
+                         'tenant': controller_slice.slice.name,
+                         'tenant_description': controller_slice.slice.description,
+                         'roles':roles,
+                         'name':controller_user.user.email,
+                         'ansible_tag':'%s@%s'%(controller_slice.slice.name,controller_slice.controller.name),
+                         'max_instances':max_instances}
+
+        expected_num = len(roles)+1
+        res = run_template('sync_controller_slices.yaml', tenant_fields, path='controller_slices', expected_num=expected_num)
+        tenant_id = res[0]['id']
+        if (not controller_slice.tenant_id):
+            try:
+                    driver = OpenStackDriver().admin_driver(controller=controller_slice.controller)
+                    driver.shell.nova.quotas.update(tenant_id=controller_slice.tenant_id, instances=int(controller_slice.slice.max_slivers))
+            except:
+                    logger.log_exc('Could not update quota for %s'%controller_slice.slice.name)
+                    raise Exception('Could not update quota for %s'%controller_slice.slice.name)
+                
+            controller_slice.tenant_id = tenant_id
+            controller_slice.backend_status = '1 - OK'
+            controller_slice.save()
+
+
+    def delete_record(self, controller_slice):
+        controller_register = json.loads(controller_slice.controller.backend_register)
+ 	if (controller_register.get('disabled',False)):
+ 		raise Exception('Controller %s is disabled'%controller_slice.controller.name)
+ 
+ 	controller_users = ControllerUser.objects.filter(user=controller_slice.slice.creator,
+                                                              controller=controller_slice.controller)
+         if not controller_users:
+             raise Exception("slice createor %s has not accout at controller %s" % (controller_slice.slice.creator, controller_slice.controller.name))
+         else:
+             controller_user = controller_users[0]
+ 
+ 	tenant_fields = {'endpoint':controller_slice.controller.auth_url,
+                          'admin_user': controller_slice.controller.admin_user,
+                          'admin_password': controller_slice.controller.admin_password,
+                          'admin_tenant': 'admin',
+                          'tenant': controller_slice.slice.name,
+                          'tenant_description': controller_slice.slice.description,
+                          'name':controller_user.user.email,
+                          'ansible_tag':'%s@%s'%(controller_slice.slice.name,controller_slice.controller.name),
+ 			 'delete': True}
+ 
+         expected_num = 1
+         res = run_template('sync_controller_slices.yaml', tenant_fields, path='controller_slices', expected_num=expected_num)
diff --git a/xos/synchronizers/base/steps/sync_controller_slices.yaml b/xos/synchronizers/base/steps/sync_controller_slices.yaml
new file mode 100644
index 0000000..61470ce
--- /dev/null
+++ b/xos/synchronizers/base/steps/sync_controller_slices.yaml
@@ -0,0 +1,12 @@
+---
+- hosts: 127.0.0.1
+  connection: local
+  tasks:
+  {% if delete -%}
+  - keystone_user: endpoint={{ endpoint }} login_user={{ admin_user }} login_password={{ admin_password }} login_tenant_name={{ admin_tenant }} tenant={{ tenant }} tenant_description="{{ tenant_description }}" state=absent
+  {% else -%}
+  - keystone_user: endpoint={{ endpoint }} login_user={{ admin_user }} login_password={{ admin_password }} login_tenant_name={{ admin_tenant }} tenant={{ tenant }} tenant_description="{{ tenant_description }}"
+  {% for role in roles %}
+  - keystone_user: endpoint={{ endpoint }} login_user={{ admin_user }} login_password={{ admin_password }} login_tenant_name={{ admin_tenant }} user="{{ name }}" role={{ role }} tenant={{ tenant }}
+  {% endfor %}
+  {% endif %}
diff --git a/xos/synchronizers/base/steps/sync_controller_users.py b/xos/synchronizers/base/steps/sync_controller_users.py
new file mode 100644
index 0000000..9af48e5
--- /dev/null
+++ b/xos/synchronizers/base/steps/sync_controller_users.py
@@ -0,0 +1,69 @@
+import os
+import base64
+from collections import defaultdict
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.openstacksyncstep import OpenStackSyncStep
+from synchronizers.base.syncstep import *
+from core.models.site import Controller, SiteDeployment, SiteDeployment
+from core.models.user import User
+from core.models.controlleruser import ControllerUser
+from synchronizers.base.ansible import *
+from xos.logger import observer_logger as logger
+import json
+
+class SyncControllerUsers(OpenStackSyncStep):
+    provides=[User]
+    requested_interval=0
+    observes=ControllerUser
+    playbook='sync_controller_users.yaml'
+
+    def map_sync_inputs(self, controller_user):
+        if not controller_user.controller.admin_user:
+            logger.info("controller %r has no admin_user, skipping" % controller_user.controller)
+            return
+
+        # All users will have at least the 'user' role at their home site/tenant.
+        # We must also check if the user should have the admin role
+        roles = ['user']
+        if controller_user.user.is_admin:
+            roles.append('admin')
+
+        # setup user home site roles at controller
+        if not controller_user.user.site:
+            raise Exception('Siteless user %s'%controller_user.user.email)
+        else:
+            # look up tenant id for the user's site at the controller
+            #ctrl_site_deployments = SiteDeployment.objects.filter(
+            #  site_deployment__site=controller_user.user.site,
+            #  controller=controller_user.controller)
+
+            #if ctrl_site_deployments:
+            #    # need the correct tenant id for site at the controller
+            #    tenant_id = ctrl_site_deployments[0].tenant_id
+            #    tenant_name = ctrl_site_deployments[0].site_deployment.site.login_base
+            user_fields = {
+                'endpoint':controller_user.controller.auth_url,
+                'endpoint_v3': controller_user.controller.auth_url_v3,
+                'domain': controller_user.controller.domain,
+                'name': controller_user.user.email,
+                'email': controller_user.user.email,
+                'password': controller_user.user.remote_password,
+                'admin_user': controller_user.controller.admin_user,
+                'admin_password': controller_user.controller.admin_password,
+                'ansible_tag':'%s@%s'%(controller_user.user.email.replace('@','-at-'),controller_user.controller.name),
+                'admin_tenant': controller_user.controller.admin_tenant,
+                'roles':roles,
+                'tenant':controller_user.user.site.login_base
+                }
+	    return user_fields
+
+    def map_sync_outputs(self, controller_user, res):
+        controller_user.kuser_id = res[0]['id']
+        controller_user.backend_status = '1 - OK'
+        controller_user.save()
+
+    def delete_record(self, controller_user):
+        if controller_user.kuser_id:
+            driver = self.driver.admin_driver(controller=controller_user.controller)
+            driver.delete_user(controller_user.kuser_id)
diff --git a/xos/synchronizers/base/steps/sync_controller_users.yaml b/xos/synchronizers/base/steps/sync_controller_users.yaml
new file mode 100644
index 0000000..4f2db5e
--- /dev/null
+++ b/xos/synchronizers/base/steps/sync_controller_users.yaml
@@ -0,0 +1,16 @@
+---
+- hosts: 127.0.0.1
+  connection: local
+  tasks:
+  - keystone_user:
+       endpoint={{ endpoint }}
+       login_user={{ admin_user }} 
+       login_password={{ admin_password }} 
+       login_tenant_name={{ admin_tenant }} 
+       user="{{ name }}"
+       email={{ email }}
+       password={{ password }}
+       tenant={{ tenant }}
+  {% for role in roles %}
+  - keystone_user: endpoint={{ endpoint}}  login_user={{ admin_user }} login_password={{ admin_password }} login_tenant_name={{ admin_tenant }} user="{{ name }}" role={{ role }} tenant={{ tenant }}
+  {% endfor %}
diff --git a/xos/synchronizers/base/steps/sync_images.py b/xos/synchronizers/base/steps/sync_images.py
new file mode 100644
index 0000000..8049ac1
--- /dev/null
+++ b/xos/synchronizers/base/steps/sync_images.py
@@ -0,0 +1,52 @@
+import os
+import base64
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.openstacksyncstep import OpenStackSyncStep
+from core.models.image import Image
+from xos.logger import observer_logger as logger
+
+class SyncImages(OpenStackSyncStep):
+    provides=[Image]
+    requested_interval=0
+    observes=Image
+
+    def fetch_pending(self, deleted):
+        # Images come from the back end
+        # You can't delete them
+        if (deleted):
+            logger.info("SyncImages: returning because deleted=True")
+            return []
+
+        # get list of images on disk
+        images_path = Config().observer_images_directory
+
+        logger.info("SyncImages: deleted=False, images_path=%s" % images_path)
+
+        available_images = {}
+        if os.path.exists(images_path):
+            for f in os.listdir(images_path):
+                filename = os.path.join(images_path, f)
+                if os.path.isfile(filename):
+                    available_images[f] = filename
+
+        logger.info("SyncImages: available_images = %s" % str(available_images))
+
+        images = Image.objects.all()
+        image_names = [image.name for image in images]
+
+        for image_name in available_images:
+            #remove file extension
+            clean_name = ".".join(image_name.split('.')[:-1])
+            if clean_name not in image_names:
+                logger.info("SyncImages: adding %s" % clean_name)
+                image = Image(name=clean_name,
+                              disk_format='raw',
+                              container_format='bare', 
+                              path = available_images[image_name])
+                image.save()
+
+        return Image.objects.filter(Q(enacted__lt=F('updated')) | Q(enacted=None)) 
+
+    def sync_record(self, image):
+        image.save()
diff --git a/xos/synchronizers/base/steps/sync_instances.py b/xos/synchronizers/base/steps/sync_instances.py
new file mode 100644
index 0000000..335ca4a
--- /dev/null
+++ b/xos/synchronizers/base/steps/sync_instances.py
@@ -0,0 +1,174 @@
+import os
+import base64
+import socket
+from django.db.models import F, Q
+from xos.config import Config
+from xos.settings import RESTAPI_HOSTNAME, RESTAPI_PORT
+from synchronizers.base.openstacksyncstep import OpenStackSyncStep
+from core.models.instance import Instance
+from core.models.slice import Slice, SlicePrivilege, ControllerSlice
+from core.models.network import Network, NetworkSlice, ControllerNetwork
+from synchronizers.base.ansible import *
+from synchronizers.base.syncstep import *
+from xos.logger import observer_logger as logger
+
+def escape(s):
+    s = s.replace('\n',r'\n').replace('"',r'\"')
+    return s
+
+class SyncInstances(OpenStackSyncStep):
+    provides=[Instance]
+    requested_interval=0
+    observes=Instance
+    playbook='sync_instances.yaml'
+
+    def fetch_pending(self, deletion=False):
+        objs = super(SyncInstances, self).fetch_pending(deletion)
+        objs = [x for x in objs if x.isolation=="vm"]
+        return objs
+
+    def get_userdata(self, instance, pubkeys):
+        userdata = '#cloud-config\n\nopencloud:\n   slicename: "%s"\n   hostname: "%s"\n   restapi_hostname: "%s"\n   restapi_port: "%s"\n' % (instance.slice.name, instance.node.name, RESTAPI_HOSTNAME, str(RESTAPI_PORT))
+        userdata += 'ssh_authorized_keys:\n'
+        for key in pubkeys:
+            userdata += '  - %s\n' % key
+        return userdata
+
+    def map_sync_inputs(self, instance):
+        inputs = {}
+	metadata_update = {}
+        if (instance.numberCores):
+            metadata_update["cpu_cores"] = str(instance.numberCores)
+
+        for tag in instance.slice.tags.all():
+            if tag.name.startswith("sysctl-"):
+                metadata_update[tag.name] = tag.value
+
+	slice_memberships = SlicePrivilege.objects.filter(slice=instance.slice)
+        pubkeys = set([sm.user.public_key for sm in slice_memberships if sm.user.public_key])
+        if instance.creator.public_key:
+            pubkeys.add(instance.creator.public_key)
+
+        if instance.slice.creator.public_key:
+            pubkeys.add(instance.slice.creator.public_key)
+
+        if instance.slice.service and instance.slice.service.public_key:
+            pubkeys.add(instance.slice.service.public_key)
+
+        nics = []
+        networks = [ns.network for ns in NetworkSlice.objects.filter(slice=instance.slice)]
+        controller_networks = ControllerNetwork.objects.filter(network__in=networks,
+                                                                controller=instance.node.site_deployment.controller)
+
+        for controller_network in controller_networks:
+
+            # Lenient exception - causes slow backoff
+            if controller_network.network.template.visibility == 'private' and \
+               controller_network.network.template.translation == 'none':
+                   if not controller_network.net_id:
+                        raise DeferredException("Instance %s Private Network %s has no id; Try again later" % (instance, controller_network.network.name))
+                   nics.append(controller_network.net_id)
+
+        # now include network template
+        network_templates = [network.template.shared_network_name for network in networks \
+                             if network.template.shared_network_name]
+
+        #driver = self.driver.client_driver(caller=instance.creator, tenant=instance.slice.name, controller=instance.controllerNetwork)
+        driver = self.driver.admin_driver(tenant='admin', controller=instance.node.site_deployment.controller)
+        nets = driver.shell.quantum.list_networks()['networks']
+        for net in nets:
+            if net['name'] in network_templates:
+                nics.append(net['id'])
+
+        if (not nics):
+            for net in nets:
+                if net['name']=='public':
+                    nics.append(net['id'])
+
+        image_name = None
+        controller_images = instance.image.controllerimages.filter(controller=instance.node.site_deployment.controller)
+        if controller_images:
+            image_name = controller_images[0].image.name
+            logger.info("using image from ControllerImage object: " + str(image_name))
+
+        if image_name is None:
+            controller_driver = self.driver.admin_driver(controller=instance.node.site_deployment.controller)
+            images = controller_driver.shell.glanceclient.images.list()
+            for image in images:
+                if image.name == instance.image.name or not image_name:
+                    image_name = image.name
+                    logger.info("using image from glance: " + str(image_name))
+
+	try:
+            legacy = Config().observer_legacy
+        except:
+            legacy = False
+
+        if (legacy):
+            host_filter = instance.node.name.split('.',1)[0]
+        else:
+            host_filter = instance.node.name.strip()
+
+        availability_zone_filter = 'nova:%s'%host_filter
+        instance_name = '%s-%d'%(instance.slice.name,instance.id)
+        self.instance_name = instance_name
+
+        userData = self.get_userdata(instance, pubkeys)
+        if instance.userData:
+            userData += instance.userData
+
+        controller = instance.node.site_deployment.controller
+        fields = {'endpoint':controller.auth_url,
+                     'endpoint_v3': controller.auth_url_v3,
+                     'domain': controller.domain,
+                     'admin_user': instance.creator.email,
+                     'admin_password': instance.creator.remote_password,
+                     'admin_tenant': instance.slice.name,
+                     'tenant': instance.slice.name,
+                     'tenant_description': instance.slice.description,
+                     'name':instance_name,
+                     'ansible_tag':instance_name,
+                     'availability_zone': availability_zone_filter,
+                     'image_name':image_name,
+                     'flavor_name':instance.flavor.name,
+                     'nics':nics,
+                     'meta':metadata_update,
+                     'user_data':r'%s'%escape(userData)}
+        return fields
+
+
+    def map_sync_outputs(self, instance, res):
+	instance_id = res[0]['info']['OS-EXT-SRV-ATTR:instance_name']
+        instance_uuid = res[0]['id']
+
+	try:
+            hostname = res[0]['info']['OS-EXT-SRV-ATTR:hypervisor_hostname']
+            ip = socket.gethostbyname(hostname)
+            instance.ip = ip
+        except:
+            pass
+
+        instance.instance_id = instance_id
+        instance.instance_uuid = instance_uuid
+        instance.instance_name = self.instance_name
+        instance.save()
+	
+	
+    def map_delete_inputs(self, instance):
+        controller_register = json.loads(instance.node.site_deployment.controller.backend_register)
+
+        if (controller_register.get('disabled',False)):
+            raise InnocuousException('Controller %s is disabled'%instance.node.site_deployment.controller.name)
+
+        instance_name = '%s-%d'%(instance.slice.name,instance.id)
+        controller = instance.node.site_deployment.controller
+        input = {'endpoint':controller.auth_url,
+                     'admin_user': instance.creator.email,
+                     'admin_password': instance.creator.remote_password,
+                     'admin_tenant': instance.slice.name,
+                     'tenant': instance.slice.name,
+                     'tenant_description': instance.slice.description,
+                     'name':instance_name,
+                     'ansible_tag':instance_name,
+                     'delete': True}
+        return input
diff --git a/xos/synchronizers/base/steps/sync_instances.yaml b/xos/synchronizers/base/steps/sync_instances.yaml
new file mode 100644
index 0000000..a61e5cf
--- /dev/null
+++ b/xos/synchronizers/base/steps/sync_instances.yaml
@@ -0,0 +1,35 @@
+---
+- hosts: 127.0.0.1
+  connection: local
+  tasks:
+  - nova_compute:
+      auth_url: {{ endpoint }}
+      login_username: {{ admin_user }}
+      login_password: {{ admin_password }}
+      login_tenant_name: {{ admin_tenant }}
+      name: {{ name }}
+      {% if delete -%}
+      state: absent
+      {% else -%}
+      state: present
+      availability_zone: {{ availability_zone }}
+      image_name: {{ image_name }}
+      wait_for: 200
+      flavor_name: {{ flavor_name }}
+      user_data: "{{ user_data }}"
+      config_drive: yes
+      nics:
+      {% for net in nics %}
+          - net-id: {{ net }}
+      {% endfor %}
+      {% for port in ports %}
+          - port-id: {{ port }}
+      {% endfor %}
+
+      {% if meta %}
+      meta:
+      {% for k,v in meta.items() %}
+          {{ k }} : "{{ v }}"
+      {% endfor %}
+      {% endif %}
+      {% endif %}
diff --git a/xos/synchronizers/base/steps/sync_object.py b/xos/synchronizers/base/steps/sync_object.py
new file mode 100644
index 0000000..a6a939f
--- /dev/null
+++ b/xos/synchronizers/base/steps/sync_object.py
@@ -0,0 +1,20 @@
+import os
+import base64
+from collections import defaultdict
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.openstacksyncstep import OpenStackSyncStep
+from synchronizers.base.syncstep import *
+from core.models import *
+from synchronizers.base.ansible import *
+from openstack.driver import OpenStackDriver
+from xos.logger import observer_logger as logger
+import json
+
+class SyncObject(OpenStackSyncStep):
+    provides=[] # Caller fills this in
+    requested_interval=0
+    observes=[] # Caller fills this in
+
+    def sync_record(self, r):
+        raise DeferredException('Waiting for Service dependency: %r'%r)
diff --git a/xos/synchronizers/base/steps/sync_ports.py b/xos/synchronizers/base/steps/sync_ports.py
new file mode 100644
index 0000000..21376e5
--- /dev/null
+++ b/xos/synchronizers/base/steps/sync_ports.py
@@ -0,0 +1,196 @@
+import os
+import base64
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.openstacksyncstep import OpenStackSyncStep
+from core.models import Controller
+from core.models.network import *
+from xos.logger import observer_logger as logger
+
+class SyncPorts(OpenStackSyncStep):
+    requested_interval = 0 # 3600
+    provides=[Port]
+    observes=Port
+
+    #     The way it works is to enumerate the all of the ports that quantum
+    #     has, and then work backward from each port's network-id to determine
+    #     which Network is associated from the port.
+
+    def call(self, **args):
+        logger.info("sync'ing network instances")
+
+        ports = Port.objects.all()
+        ports_by_id = {}
+        ports_by_neutron_port = {}
+        for port in ports:
+            ports_by_id[port.id] = port
+            ports_by_neutron_port[port.port_id] = port
+
+        networks = Network.objects.all()
+        networks_by_id = {}
+        for network in networks:
+            for nd in network.controllernetworks.all():
+                networks_by_id[nd.net_id] = network
+
+        #logger.info("networks_by_id = ")
+        #for (network_id, network) in networks_by_id.items():
+        #    logger.info("   %s: %s" % (network_id, network.name))
+
+        instances = Instance.objects.all()
+        instances_by_instance_uuid = {}
+        for instance in instances:
+            instances_by_instance_uuid[instance.instance_uuid] = instance
+
+        # Get all ports in all controllers
+
+        ports_by_id = {}
+        templates_by_id = {}
+        for controller in Controller.objects.all():
+            if not controller.admin_tenant:
+                logger.info("controller %s has no admin_tenant" % controller)
+                continue
+            try:
+                driver = self.driver.admin_driver(controller = controller)
+                ports = driver.shell.quantum.list_ports()["ports"]
+            except:
+                logger.log_exc("failed to get ports from controller %s" % controller)
+                continue
+
+            for port in ports:
+                ports_by_id[port["id"]] = port
+
+            # public-nat and public-dedicated networks don't have a net-id anywhere
+            # in the data model, so build up a list of which ids map to which network
+            # templates.
+            try:
+                neutron_networks = driver.shell.quantum.list_networks()["networks"]
+            except:
+                print "failed to get networks from controller %s" % controller
+                continue
+            for network in neutron_networks:
+                for template in NetworkTemplate.objects.all():
+                    if template.shared_network_name == network["name"]:
+                        templates_by_id[network["id"]] = template
+
+        for port in ports_by_id.values():
+            #logger.info("port %s" % str(port))
+            if port["id"] in ports_by_neutron_port:
+                # we already have it
+                #logger.info("already accounted for port %s" % port["id"])
+                continue
+
+            if port["device_owner"] != "compute:nova":
+                # we only want the ports that connect to instances
+                #logger.info("port %s is not a compute port, it is a %s" % (port["id"], port["device_owner"]))
+                continue
+
+            instance = instances_by_instance_uuid.get(port['device_id'], None)
+            if not instance:
+                logger.info("no instance for port %s device_id %s" % (port["id"], port['device_id']))
+                continue
+
+            network = networks_by_id.get(port['network_id'], None)
+            if not network:
+                # maybe it's public-nat or public-dedicated. Search the templates for
+                # the id, then see if the instance's slice has some network that uses
+                # that template
+                template = templates_by_id.get(port['network_id'], None)
+                if template and instance.slice:
+                    for candidate_network in instance.slice.networks.all():
+                         if candidate_network.template == template:
+                             network=candidate_network
+            if not network:
+                logger.info("no network for port %s network %s" % (port["id"], port["network_id"]))
+
+                # we know it's associated with a instance, but we don't know
+                # which network it is part of.
+
+                continue
+
+            if network.template.shared_network_name:
+                # If it's a shared network template, then more than one network
+                # object maps to the quantum network. We have to do a whole bunch
+                # of extra work to find the right one.
+                networks = network.template.network_set.all()
+                network = None
+                for candidate_network in networks:
+                    if (candidate_network.owner == instance.slice):
+                        logger.info("found network %s" % candidate_network)
+                        network = candidate_network
+
+                if not network:
+                    logger.info("failed to find the correct network for a shared template for port %s network %s" % (port["id"], port["network_id"]))
+                    continue
+
+            if not port["fixed_ips"]:
+                logger.info("port %s has no fixed_ips" % port["id"])
+                continue
+
+            ip=port["fixed_ips"][0]["ip_address"]
+            mac=port["mac_address"]
+            logger.info("creating Port (%s, %s, %s, %s)" % (str(network), str(instance), ip, str(port["id"])))
+
+            ns = Port(network=network,
+                               instance=instance,
+                               ip=ip,
+                               mac=mac,
+                               port_id=port["id"])
+
+            try:
+                ns.save()
+            except:
+                logger.log_exc("failed to save port %s" % str(ns))
+                continue
+
+        # For ports that were created by the user, find that ones
+        # that don't have neutron ports, and create them.
+        for port in Port.objects.filter(Q(port_id__isnull=True), Q(instance__isnull=False) ):
+            logger.info("XXX working on port %s" % port)
+            controller = port.instance.node.site_deployment.controller
+            slice = port.instance.slice
+
+            if controller:
+                cn=port.network.controllernetworks.filter(controller=controller)
+                if not cn:
+                    logger.log_exc("no controllernetwork for %s" % port)
+                    continue
+                cn=cn[0]
+                if cn.lazy_blocked:
+                    cn.lazy_blocked=False
+                    cn.save()
+                    logger.info("deferring port %s because controllerNetwork was lazy-blocked" % port)
+                    continue
+                if not cn.net_id:
+                    logger.info("deferring port %s because controllerNetwork does not have a port-id yet" % port)
+                    continue
+                try:
+                    # We need to use a client driver that specifies the tenant
+                    # of the destination instance. Nova-compute will not connect
+                    # ports to instances if the port's tenant does not match
+                    # the instance's tenant.
+
+                    # A bunch of stuff to compensate for OpenStackDriver.client_driveR()
+                    # not being in working condition.
+                    from openstack.client import OpenStackClient
+                    from openstack.driver import OpenStackDriver
+                    caller = port.network.owner.creator
+                    auth = {'username': caller.email,
+                            'password': caller.remote_password,
+                            'tenant': slice.name}
+                    client = OpenStackClient(controller=controller, **auth) # cacert=self.config.nova_ca_ssl_cert,
+                    driver = OpenStackDriver(client=client)
+
+                    neutron_port = driver.shell.quantum.create_port({"port": {"network_id": cn.net_id}})["port"]
+                    port.port_id = neutron_port["id"]
+                    if neutron_port["fixed_ips"]:
+                        port.ip = neutron_port["fixed_ips"][0]["ip_address"]
+                    port.mac = neutron_port["mac_address"]
+                except:
+                    logger.log_exc("failed to create neutron port for %s" % port)
+                    continue
+                port.save()
+
+    def delete_record(self, network_instance):
+        # Nothing to do, this is an OpenCloud object
+        pass
+
diff --git a/xos/synchronizers/base/steps/sync_roles.py b/xos/synchronizers/base/steps/sync_roles.py
new file mode 100644
index 0000000..e859316
--- /dev/null
+++ b/xos/synchronizers/base/steps/sync_roles.py
@@ -0,0 +1,23 @@
+import os
+import base64
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.openstacksyncstep import OpenStackSyncStep
+from core.models.role import Role
+from core.models.site import SiteRole, Controller, ControllerRole
+from core.models.slice import SliceRole
+from xos.logger import observer_logger as logger
+
+class SyncRoles(OpenStackSyncStep):
+    provides=[Role]
+    requested_interval=0
+    observes=[SiteRole,SliceRole,ControllerRole]
+
+    def sync_record(self, role):
+        if not role.enacted:
+            controllers = Controller.objects.all()
+       	    for controller in controllers:
+                driver = self.driver.admin_driver(controller=controller)
+                driver.create_role(role.role)
+            role.save()
+    
diff --git a/xos/synchronizers/base/steps/sync_slivers.py.bak b/xos/synchronizers/base/steps/sync_slivers.py.bak
new file mode 100644
index 0000000..c4240fa
--- /dev/null
+++ b/xos/synchronizers/base/steps/sync_slivers.py.bak
@@ -0,0 +1,179 @@
+import os
+import base64
+import socket
+from django.db.models import F, Q
+from xos.config import Config
+from xos.settings import RESTAPI_HOSTNAME, RESTAPI_PORT
+from observer.openstacksyncstep import OpenStackSyncStep
+from core.models.sliver import Sliver
+from core.models.slice import Slice, SlicePrivilege, ControllerSlice
+from core.models.network import Network, NetworkSlice, ControllerNetwork
+from observer.ansible import *
+from util.logger import observer_logger as logger
+
+def escape(s):
+    s = s.replace('\n',r'\n').replace('"',r'\"')
+    return s
+
+class SyncSlivers(OpenStackSyncStep):
+    provides=[Sliver]
+    requested_interval=0
+    observes=Sliver
+
+    def get_userdata(self, sliver, pubkeys):
+        userdata = '#cloud-config\n\nopencloud:\n   slicename: "%s"\n   hostname: "%s"\n   restapi_hostname: "%s"\n   restapi_port: "%s"\n' % (sliver.slice.name, sliver.node.name, RESTAPI_HOSTNAME, str(RESTAPI_PORT))
+        userdata += 'ssh_authorized_keys:\n'
+        for key in pubkeys:
+            userdata += '  - %s\n' % key
+        return userdata
+
+    def sync_record(self, sliver):
+        logger.info("sync'ing sliver:%s slice:%s controller:%s " % (sliver, sliver.slice.name, sliver.node.site_deployment.controller))
+    	controller_register = json.loads(sliver.node.site_deployment.controller.backend_register)
+ 
+        if (controller_register.get('disabled',False)):
+                raise Exception('Controller %s is disabled'%sliver.node.site_deployment.controller.name)
+
+        metadata_update = {}
+        if (sliver.numberCores):
+            metadata_update["cpu_cores"] = str(sliver.numberCores)
+
+        for tag in sliver.slice.tags.all():
+            if tag.name.startswith("sysctl-"):
+                metadata_update[tag.name] = tag.value
+
+        # public keys
+        slice_memberships = SlicePrivilege.objects.filter(slice=sliver.slice)
+        pubkeys = set([sm.user.public_key for sm in slice_memberships if sm.user.public_key])
+        if sliver.creator.public_key:
+            pubkeys.add(sliver.creator.public_key)
+
+        if sliver.slice.creator.public_key:
+            pubkeys.add(sliver.slice.creator.public_key)
+
+        if sliver.slice.service and sliver.slice.service.public_key:
+            pubkeys.add(sliver.slice.service.public_key)
+
+        if sliver.slice.service and sliver.slice.service.public_key:
+            pubkeys.add(sliver.slice.service.public_key)
+
+        nics = []
+        networks = [ns.network for ns in NetworkSlice.objects.filter(slice=sliver.slice)]
+        controller_networks = ControllerNetwork.objects.filter(network__in=networks,
+                                                                controller=sliver.node.site_deployment.controller)
+
+        for controller_network in controller_networks:
+            if controller_network.network.template.visibility == 'private' and \
+               controller_network.network.template.translation == 'none':
+                   if not controller_network.net_id:
+                        raise Exception("Private Network %s has no id; Try again later" % controller_network.network.name)
+                   nics.append(controller_network.net_id)
+
+        # now include network template
+        network_templates = [network.template.shared_network_name for network in networks \
+                             if network.template.shared_network_name]
+
+        #driver = self.driver.client_driver(caller=sliver.creator, tenant=sliver.slice.name, controller=sliver.controllerNetwork)
+        driver = self.driver.admin_driver(tenant='admin', controller=sliver.node.site_deployment.controller)
+        nets = driver.shell.quantum.list_networks()['networks']
+        for net in nets:
+            if net['name'] in network_templates:
+                nics.append(net['id'])
+
+        if (not nics):
+            for net in nets:
+                if net['name']=='public':
+                    nics.append(net['id'])
+
+        image_id = None
+        controller_images = sliver.image.controllerimages.filter(controller=sliver.node.site_deployment.controller)
+        if controller_images:
+            image_id = controller_images[0].glance_image_id
+            logger.info("using image_id from ControllerImage object: " + str(image_id))
+
+        if image_id is None:
+            controller_driver = self.driver.admin_driver(controller=sliver.node.site_deployment.controller)
+            image_id = None
+            images = controller_driver.shell.glanceclient.images.list()
+            for image in images:
+                if image.name == sliver.image.name or not image_id:
+                    image_id = image.id
+                    logger.info("using image_id from glance: " + str(image_id))
+
+        try:
+            legacy = Config().observer_legacy
+        except:
+            legacy = False
+
+        if (legacy):
+            host_filter = sliver.node.name.split('.',1)[0]
+        else:
+            host_filter = sliver.node.name.strip()
+
+        availability_zone_filter = 'nova:%s'%host_filter
+        sliver_name = '%s-%d'%(sliver.slice.name,sliver.id)
+
+        userData = self.get_userdata(sliver, pubkeys)
+        if sliver.userData:
+            userData = sliver.userData
+
+        controller = sliver.node.site_deployment.controller
+        tenant_fields = {'endpoint':controller.auth_url,
+                     'admin_user': sliver.creator.email,
+                     'admin_password': sliver.creator.remote_password,
+                     'admin_tenant': sliver.slice.name,
+                     'tenant': sliver.slice.name,
+                     'tenant_description': sliver.slice.description,
+                     'name':sliver_name,
+                     'ansible_tag':sliver_name,
+                     'availability_zone': availability_zone_filter,
+                     'image_id':image_id,
+                     'flavor_id':sliver.flavor.id,
+                     'nics':nics,
+                     'meta':metadata_update,
+                     'user_data':r'%s'%escape(userData)}
+
+        res = run_template('sync_slivers.yaml', tenant_fields,path='slivers', expected_num=1)
+        sliver_id = res[0]['info']['OS-EXT-SRV-ATTR:instance_name']
+        sliver_uuid = res[0]['id']
+
+        try:
+            hostname = res[0]['info']['OS-EXT-SRV-ATTR:hypervisor_hostname']
+            ip = socket.gethostbyname(hostname)
+            sliver.ip = ip
+        except:
+            pass
+
+        sliver.instance_id = sliver_id
+        sliver.instance_uuid = sliver_uuid
+        sliver.instance_name = sliver_name
+        sliver.save()
+
+    def delete_record(self, sliver):
+	controller_register = json.loads(sliver.node.site_deployment.controller.backend_register)
+
+        if (controller_register.get('disabled',False)):
+                raise Exception('Controller %s is disabled'%sliver.node.site_deployment.controller.name)
+
+        sliver_name = '%s-%d'%(sliver.slice.name,sliver.id)
+        controller = sliver.node.site_deployment.controller
+        tenant_fields = {'endpoint':controller.auth_url,
+                     'admin_user': sliver.creator.email,
+                     'admin_password': sliver.creator.remote_password,
+                     'admin_tenant': sliver.slice.name,
+                     'tenant': sliver.slice.name,
+                     'tenant_description': sliver.slice.description,
+                     'name':sliver_name,
+                     'ansible_tag':sliver_name,
+                     'delete': True}
+
+        try:
+               res = run_template('sync_slivers.yaml', tenant_fields,path='slivers', expected_num=1)

+        except Exception,e:

+               print "Could not sync %s"%sliver_name

+               #import traceback

+               #traceback.print_exc()

+               raise e

+
+        if (len(res)!=1):
+            raise Exception('Could not delete sliver %s'%sliver.slice.name)
diff --git a/xos/synchronizers/base/steps/teardown_container.yaml b/xos/synchronizers/base/steps/teardown_container.yaml
new file mode 100644
index 0000000..5cabc78
--- /dev/null
+++ b/xos/synchronizers/base/steps/teardown_container.yaml
@@ -0,0 +1,33 @@
+---
+- hosts: {{ instance_name }}
+  gather_facts: False
+  connection: ssh
+  user: {{ username }}
+  sudo: yes
+
+  vars:
+    container_name: {{ container_name }}
+    docker_image: {{ docker_image }}
+    ports:
+    {% for port in ports %}
+       - device: {{ port.device }}
+         xos_network_id: {{ port.xos_network_id }}
+         mac: {{ port.mac|default("") }}
+         ip: {{ port.ip }}
+         snoop_instance_mac: {{ port.snoop_instance_mac }}
+         snoop_instance_id: {{ port.snoop_instance_id }}
+         parent_mac: {{ port.parent_mac|default("") }}
+         s_tag: {{ port.s_tag|default("")  }}
+         c_tag: {{ port.c_tag|default("") }}
+         next_hop: {{ port.next_hop|default("") }}
+         bridge: {{ port.bridge }}
+    {% endfor %}
+    volumes:
+    {% for volume in volumes %}
+       - {{ volume }}
+    {% endfor %}
+
+  tasks:
+  - name: Make sure container is stopped
+    service: name=container-{{ container_name }} state=stopped
+
diff --git a/xos/synchronizers/base/syncstep-portal.py b/xos/synchronizers/base/syncstep-portal.py
new file mode 100644
index 0000000..07abb0b
--- /dev/null
+++ b/xos/synchronizers/base/syncstep-portal.py
@@ -0,0 +1,222 @@
+import os
+import base64
+from datetime import datetime
+from xos.config import Config
+from xos.logger import Logger, logging
+from synchronizers.base.steps import *
+from django.db.models import F, Q
+from django.utils import timezone
+from core.models import * 
+from django.db import reset_queries
+import json
+import time
+import pdb
+import traceback
+
+logger = Logger(level=logging.INFO)
+
+def f7(seq):
+    seen = set()
+    seen_add = seen.add
+    return [ x for x in seq if not (x in seen or seen_add(x))]
+
+def elim_dups(backend_str):
+    strs = backend_str.split('/')
+    strs = map(lambda x:x.split('(')[0],strs) 
+    strs2 = f7(strs)
+    return '/'.join(strs2)
+    
+def deepgetattr(obj, attr):
+    return reduce(getattr, attr.split('.'), obj)
+
+
+class InnocuousException(Exception):
+    pass
+
+class FailedDependency(Exception):
+    pass
+
+class SyncStep(object):
+    """ An XOS Sync step. 
+
+    Attributes:
+        psmodel        Model name the step synchronizes 
+        dependencies    list of names of models that must be synchronized first if the current model depends on them
+    """ 
+    slow=False
+    def get_prop(prop):
+        try:
+            sync_config_dir = Config().sync_config_dir
+        except:
+            sync_config_dir = '/etc/xos/sync'
+        prop_config_path = '/'.join(sync_config_dir,self.name,prop)
+        return open(prop_config_path).read().rstrip()
+
+    def __init__(self, **args):
+        """Initialize a sync step
+           Keyword arguments:
+                   name -- Name of the step
+                provides -- XOS models sync'd by this step
+        """
+        dependencies = []
+        self.driver = args.get('driver')
+        self.error_map = args.get('error_map')
+
+        try:
+            self.soft_deadline = int(self.get_prop('soft_deadline_seconds'))
+        except:
+            self.soft_deadline = 5 # 5 seconds
+
+        return
+
+    def fetch_pending(self, deletion=False):
+        # This is the most common implementation of fetch_pending
+        # Steps should override it if they have their own logic
+        # for figuring out what objects are outstanding.
+        main_obj = self.observes
+        if (not deletion):
+            objs = main_obj.objects.filter(Q(enacted__lt=F('updated')) | Q(enacted=None),Q(lazy_blocked=False))
+        else:
+            objs = main_obj.deleted_objects.all()
+
+        return objs
+        #return Sliver.objects.filter(ip=None)
+    
+    def check_dependencies(self, obj, failed):
+        for dep in self.dependencies:
+            peer_name = dep[0].lower() + dep[1:]    # django names are camelCased with the first letter lower
+ 
+            try:
+                peer_object = deepgetattr(obj, peer_name)
+                try: 
+                    peer_objects = peer_object.all() 
+                except AttributeError:
+                    peer_objects = [peer_object] 
+            except:
+                peer_objects = []
+
+            if (hasattr(obj,'controller')):
+                try:
+                	peer_objects = filter(lambda o:o.controller==obj.controller, peer_objects)
+                except AttributeError:
+                        pass
+
+            if (failed in peer_objects):
+                if (obj.backend_status!=failed.backend_status):
+                    obj.backend_status = failed.backend_status
+                    obj.save(update_fields=['backend_status'])
+                raise FailedDependency("Failed dependency for %s:%s peer %s:%s failed  %s:%s" % (obj.__class__.__name__, str(getattr(obj,"pk","no_pk")), peer_object.__class__.__name__, str(getattr(peer_object,"pk","no_pk")), failed.__class__.__name__, str(getattr(failed,"pk","no_pk"))))
+
+    def call(self, failed=[], deletion=False):
+        pending = self.fetch_pending(deletion)
+        for o in pending:
+            # another spot to clean up debug state
+            try:
+                reset_queries()
+            except:
+                # this shouldn't happen, but in case it does, catch it...
+                logger.log_exc("exception in reset_queries",extra=o.tologdict())
+
+            sync_failed = False
+            try:
+                backoff_disabled = Config().observer_backoff_disabled
+            except:
+                backoff_disabled = 0
+
+            try:
+                scratchpad = json.loads(o.backend_register)
+                if (scratchpad):
+                    next_run = scratchpad['next_run']
+                    if (not backoff_disabled and next_run>time.time()):
+                        sync_failed = True
+            except:
+                logger.log_exc("Exception while loading scratchpad",extra=o.tologdict())
+                pass
+
+            if (not sync_failed):
+                try:
+                    for f in failed:
+                        self.check_dependencies(o,f) # Raises exception if failed
+                    if (deletion):
+                        self.delete_record(o)
+                        o.delete(purge=True)
+                    else:
+                        self.sync_record(o)
+                        o.enacted = timezone.now() # Is this the same timezone? XXX
+                        scratchpad = {'next_run':0, 'exponent':0}
+                        o.backend_register = json.dumps(scratchpad)
+                        o.backend_status = "1 - OK"
+                        o.save(update_fields=['enacted','backend_status','backend_register'])
+		except (InnocuousException,Exception) as e:
+                    logger.log_exc("Syncstep caught exception",extra=o.tologdict())
+
+                    force_error = False
+                    try:
+                        if (o.backend_status.startswith('2 - ')):
+                            force_error = False # Already in error state
+                            str_e = '%s/%s'%(o.backend_status[4:],str(e))
+			    str_e = elim_dups(str_e)
+                        else:
+                            str_e = str(e)
+                    except:
+                        str_e = str(e)
+
+                    if (not str_e):
+                        str_e = 'Unknown'
+
+                    try:
+                        error = self.error_map.map(str_e)
+                    except:
+                        error = str_e
+
+                    if isinstance(e, InnocuousException) and not force_error:
+ 		    	o.backend_status = '1 - %s'%error
+		    else:	
+ 		    	o.backend_status = '2 - %s'%error 
+
+                    cmd = 'wget -O /dev/null -q "http://xoslnprof.appspot.com/command?action=pushlog&node=1&log_path=/%s/%s"'%(self.__class__.__name__,error)
+		    os.system(cmd)	
+                     
+                    try:
+                        scratchpad = json.loads(o.backend_register)
+                        scratchpad['exponent']
+                    except:
+                        logger.log_exc("Exception while updating scratchpad",extra=o.tologdict())
+                        scratchpad = {'next_run':0, 'exponent':0}
+
+                    # Second failure
+                    if (scratchpad['exponent']):
+                        delay = scratchpad['exponent'] * 600 # 10 minutes
+                        if (delay<1440):
+                            delay = 1440
+                        scratchpad['next_run'] = time.time() + delay
+
+                    scratchpad['exponent']+=1
+
+                    o.backend_register = json.dumps(scratchpad)
+
+                    # TOFIX:
+                    # DatabaseError: value too long for type character varying(140)
+                    if (o.pk):
+                        try:
+                            o.backend_status = o.backend_status[:1024]
+                            o.save(update_fields=['backend_status','backend_register','updated'])
+                        except:
+                            print "Could not update backend status field!"
+                            pass
+                    sync_failed = True
+
+
+            if (sync_failed):
+                failed.append(o)
+
+        return failed
+
+    def sync_record(self, o):
+        return
+
+    def delete_record(self, o):
+        return
+
+    def __call__(self, **args):
+        return self.call(**args)
diff --git a/xos/synchronizers/base/syncstep.py b/xos/synchronizers/base/syncstep.py
new file mode 100644
index 0000000..eeb61db
--- /dev/null
+++ b/xos/synchronizers/base/syncstep.py
@@ -0,0 +1,321 @@
+import os
+import base64
+from datetime import datetime
+from django.utils import timezone
+from xos.config import Config
+from xos.logger import Logger, logging
+from synchronizers.base.steps import *
+from django.db.models import F, Q
+from core.models import *
+from django.db import reset_queries
+from synchronizers.base.ansible import *
+from generate.dependency_walker import *
+from diag import update_diag
+
+import json
+import time
+import pdb
+
+logger = Logger(level=logging.INFO)
+
+def f7(seq):
+    seen = set()
+    seen_add = seen.add
+    return [ x for x in seq if not (x in seen or seen_add(x))]
+
+def elim_dups(backend_str):
+    strs = backend_str.split(' // ')
+    strs2 = f7(strs)
+    return ' // '.join(strs2)
+
+def deepgetattr(obj, attr):
+    return reduce(getattr, attr.split('.'), obj)
+
+
+class InnocuousException(Exception):
+    pass
+
+class DeferredException(Exception):
+    pass
+
+class FailedDependency(Exception):
+    pass
+
+class SyncStep(object):
+    """ An XOS Sync step.
+
+    Attributes:
+        psmodel        Model name the step synchronizes
+        dependencies    list of names of models that must be synchronized first if the current model depends on them
+    """
+
+    # map_sync_outputs can return this value to cause a step to be marked
+    # successful without running ansible. Used for sync_network_controllers
+    # on nat networks.
+    SYNC_WITHOUT_RUNNING = "sync_without_running"
+
+    slow=False
+    def get_prop(self, prop):
+        try:
+            sync_config_dir = Config().sync_config_dir
+        except:
+            sync_config_dir = '/etc/xos/sync'
+        prop_config_path = '/'.join(sync_config_dir,self.name,prop)
+        return open(prop_config_path).read().rstrip()
+
+    def __init__(self, **args):
+        """Initialize a sync step
+           Keyword arguments:
+                   name -- Name of the step
+                provides -- XOS models sync'd by this step
+        """
+        dependencies = []
+        self.driver = args.get('driver')
+        self.error_map = args.get('error_map')
+
+        try:
+            self.soft_deadline = int(self.get_prop('soft_deadline_seconds'))
+        except:
+            self.soft_deadline = 5 # 5 seconds
+
+        return
+
+    def fetch_pending(self, deletion=False):
+        # This is the most common implementation of fetch_pending
+        # Steps should override it if they have their own logic
+        # for figuring out what objects are outstanding.
+
+        main_objs = self.observes
+	if (type(main_objs) is not list):
+		main_objs=[main_objs]
+	
+	objs = []
+	for main_obj in main_objs:
+		if (not deletion):
+		    lobjs = main_obj.objects.filter(Q(enacted__lt=F('updated')) | Q(enacted=None),Q(lazy_blocked=False),Q(no_sync=False))
+		else:
+		    lobjs = main_obj.deleted_objects.all()
+	        objs.extend(lobjs)
+
+        return objs
+        #return Instance.objects.filter(ip=None)
+
+    def check_dependencies(self, obj, failed):
+        for dep in self.dependencies:
+            peer_name = dep[0].lower() + dep[1:]    # django names are camelCased with the first letter lower
+
+            peer_objects=[]
+            try:
+                peer_names = plural(peer_name)
+                peer_object_list=[]
+
+                try:
+                    peer_object_list.append(deepgetattr(obj, peer_name))
+                except:
+                    pass
+
+                try:
+                    peer_object_list.append(deepgetattr(obj, peer_names))
+                except:
+                    pass
+
+                for peer_object in peer_object_list:
+                    try:
+                        peer_objects.extend(peer_object.all())
+                    except AttributeError:
+                        peer_objects.append(peer_object)
+            except:
+                peer_objects = []
+
+            if (hasattr(obj,'controller')):
+                try:
+                    peer_objects = filter(lambda o:o.controller==obj.controller, peer_objects)
+                except AttributeError:
+                    pass
+
+            if (failed in peer_objects):
+                if (obj.backend_status!=failed.backend_status):
+                    obj.backend_status = failed.backend_status
+                    obj.save(update_fields=['backend_status'])
+                raise FailedDependency("Failed dependency for %s:%s peer %s:%s failed  %s:%s" % (obj.__class__.__name__, str(getattr(obj,"pk","no_pk")), peer_object.__class__.__name__, str(getattr(peer_object,"pk","no_pk")), failed.__class__.__name__, str(getattr(failed,"pk","no_pk"))))
+
+
+    def sync_record(self, o):
+        logger.info("Sync_record called for %s %s" % (o.__class__.__name__, str(o)))
+
+        try:
+            controller = o.get_controller()
+            controller_register = json.loads(controller.backend_register)
+
+            if (controller_register.get('disabled',False)):
+                raise InnocuousException('Controller %s is disabled'%controller.name)
+        except AttributeError:
+            pass
+
+        tenant_fields = self.map_sync_inputs(o)
+        if tenant_fields == SyncStep.SYNC_WITHOUT_RUNNING:
+            return
+        main_objs=self.observes
+        if (type(main_objs) is list):
+            main_objs=main_objs[0]
+
+        path = ''.join(main_objs.__name__).lower()
+        res = run_template(self.playbook,tenant_fields,path=path)
+
+        try:
+            self.map_sync_outputs(o,res)
+        except AttributeError:
+            pass
+         
+    def delete_record(self, o):
+        try:
+            controller = o.get_controller()
+            controller_register = json.loads(o.node.site_deployment.controller.backend_register)
+
+            if (controller_register.get('disabled',False)):
+                raise InnocuousException('Controller %s is disabled'%sliver.node.site_deployment.controller.name)
+        except AttributeError:
+            pass
+
+        tenant_fields = self.map_delete_inputs(o)
+
+        main_objs=self.observes
+        if (type(main_objs) is list):
+            main_objs=main_objs[0]
+
+        path = ''.join(main_objs.__name__).lower()
+
+        tenant_fields['delete']=True
+        res = run_template(self.playbook,tenant_fields,path=path)
+        try:
+                self.map_delete_outputs(o,res)
+        except AttributeError:
+                pass
+
+    def call(self, failed=[], deletion=False):
+        #if ('Instance' in self.__class__.__name__):
+        #    pdb.set_trace()
+
+        pending = self.fetch_pending(deletion)
+
+        for o in pending:
+            # another spot to clean up debug state
+            try:
+                reset_queries()
+            except:
+                # this shouldn't happen, but in case it does, catch it...
+                logger.log_exc("exception in reset_queries",extra=o.tologdict())
+
+            sync_failed = False
+            try:
+                backoff_disabled = Config().observer_backoff_disabled
+            except:
+                backoff_disabled = 0
+
+            try:
+                scratchpad = json.loads(o.backend_register)
+                if (scratchpad):
+                    next_run = scratchpad['next_run']
+                    if (not backoff_disabled and next_run>time.time()):
+                        sync_failed = True
+            except:
+                logger.log_exc("Exception while loading scratchpad",extra=o.tologdict())
+                pass
+
+            if (not sync_failed):
+                try:
+                    for f in failed:
+                        self.check_dependencies(o,f) # Raises exception if failed
+                    if (deletion):
+                        self.delete_record(o)
+                        o.delete(purge=True)
+                    else:
+                        new_enacted = timezone.now()
+                        try:
+                            run_always = self.run_always
+                        except AttributeError:
+                            run_always = False
+
+                        self.sync_record(o)
+
+#                         if (not run_always):
+#                             o.enacted = new_enacted
+
+                        update_diag(syncrecord_start = time.time(), backend_status="1 - Synced Record")
+                        o.enacted = new_enacted
+                        scratchpad = {'next_run':0, 'exponent':0, 'last_success':time.time()}
+                        o.backend_register = json.dumps(scratchpad)
+                        o.backend_status = "1 - OK"
+                        o.save(update_fields=['enacted','backend_status','backend_register'])
+                except (InnocuousException,Exception,DeferredException) as e:
+                    logger.log_exc("sync step failed!",extra=o.tologdict())
+                    try:
+                        if (o.backend_status.startswith('2 - ')):
+                            str_e = '%s // %r'%(o.backend_status[4:],e)
+                            str_e = elim_dups(str_e)
+                        else:
+                            str_e = '%r'%e
+                    except:
+                        str_e = '%r'%e
+
+                    try:
+                        error = self.error_map.map(str_e)
+                    except:
+                        error = '%s'%str_e
+
+                    if isinstance(e, InnocuousException):
+                        o.backend_status = '1 - %s'%error
+                    else:
+                        o.backend_status = '2 - %s'%error
+
+                    try:
+                        scratchpad = json.loads(o.backend_register)
+                        scratchpad['exponent']
+                    except:
+                        logger.log_exc("Exception while updating scratchpad",extra=o.tologdict())
+                        scratchpad = {'next_run':0, 'exponent':0, 'last_success':time.time(),'failures':0}
+
+                    # Second failure
+                    if (scratchpad['exponent']):
+                        if isinstance(e,DeferredException):
+                            delay = scratchpad['exponent'] * 60 # 1 minute
+                        else:
+                            delay = scratchpad['exponent'] * 600 # 10 minutes
+                        # cap delays at 8 hours
+                        if (delay>8*60*60):
+                            delay=8*60*60
+                        scratchpad['next_run'] = time.time() + delay
+
+                    try:
+                        scratchpad['exponent']+=1
+                    except:
+                        scratchpad['exponent']=1
+
+                    try:
+                        scratchpad['failures']+=1
+                    except KeyError:
+                        scratchpad['failures']=1
+
+                    scratchpad['last_failure']=time.time()
+
+                    o.backend_register = json.dumps(scratchpad)
+
+                    # TOFIX:
+                    # DatabaseError: value too long for type character varying(140)
+                    if (o.pk):
+                        try:
+                            o.backend_status = o.backend_status[:1024]
+                            o.save(update_fields=['backend_status','backend_register','updated'])
+                        except:
+                            print "Could not update backend status field!"
+                            pass
+                    sync_failed = True
+
+
+            if (sync_failed):
+                failed.append(o)
+
+        return failed
+
+    def __call__(self, **args):
+        return self.call(**args)
diff --git a/xos/synchronizers/base/syncstep.py.bak b/xos/synchronizers/base/syncstep.py.bak
new file mode 100644
index 0000000..a1f242b
--- /dev/null
+++ b/xos/synchronizers/base/syncstep.py.bak
@@ -0,0 +1,203 @@
+import os
+import base64
+from datetime import datetime
+from xos.config import Config
+from util.logger import Logger, logging
+from observer.steps import *
+from django.db.models import F, Q
+from core.models import * 
+import json
+import time
+import pdb
+import traceback
+
+logger = Logger(level=logging.INFO)
+
+def f7(seq):
+    seen = set()
+    seen_add = seen.add
+    return [ x for x in seq if not (x in seen or seen_add(x))]
+
+def elim_dups(backend_str):
+    strs = backend_str.split(' // ')
+    strs2 = f7(strs)
+    return ' // '.join(strs2)
+    
+def deepgetattr(obj, attr):
+    return reduce(getattr, attr.split('.'), obj)
+
+
+class InnocuousException(Exception):
+    pass
+
+class FailedDependency(Exception):
+    pass
+
+class SyncStep(object):
+    """ An XOS Sync step. 
+
+    Attributes:
+        psmodel        Model name the step synchronizes 
+        dependencies    list of names of models that must be synchronized first if the current model depends on them
+    """ 
+    slow=False
+    def get_prop(self, prop):
+        try:
+            sync_config_dir = Config().sync_config_dir
+        except:
+            sync_config_dir = '/etc/xos/sync'
+        prop_config_path = '/'.join(sync_config_dir,self.name,prop)
+        return open(prop_config_path).read().rstrip()
+
+    def __init__(self, **args):
+        """Initialize a sync step
+           Keyword arguments:
+                   name -- Name of the step
+                provides -- XOS models sync'd by this step
+        """
+        dependencies = []
+        self.driver = args.get('driver')
+        self.error_map = args.get('error_map')
+
+        try:
+            self.soft_deadline = int(self.get_prop('soft_deadline_seconds'))
+        except:
+            self.soft_deadline = 5 # 5 seconds
+
+        return
+
+    def fetch_pending(self, deletion=False):
+        # This is the most common implementation of fetch_pending
+        # Steps should override it if they have their own logic
+        # for figuring out what objects are outstanding.
+        main_obj = self.observes
+        if (not deletion):
+            objs = main_obj.objects.filter(Q(enacted__lt=F('updated')) | Q(enacted=None),Q(lazy_blocked=False))
+        else:
+            objs = main_obj.deleted_objects.all()
+
+        return objs
+        #return Sliver.objects.filter(ip=None)
+    
+    def check_dependencies(self, obj, failed):
+        for dep in self.dependencies:
+            peer_name = dep[0].lower() + dep[1:]    # django names are camelCased with the first letter lower
+ 
+            try:
+                peer_object = deepgetattr(obj, peer_name)
+                try: 
+                    peer_objects = peer_object.all() 
+                except AttributeError:
+                    peer_objects = [peer_object] 
+            except:
+                peer_objects = []
+
+            if (hasattr(obj,'controller')):
+                try:
+                	peer_objects = filter(lambda o:o.controller==obj.controller, peer_objects)
+                except AttributeError:
+                        pass
+
+            if (failed in peer_objects):
+                if (obj.backend_status!=failed.backend_status):
+                    obj.backend_status = failed.backend_status
+                    obj.save(update_fields=['backend_status'])
+                raise FailedDependency("Failed dependency for %s:%s peer %s:%s failed  %s:%s" % (obj.__class__.__name__, str(getattr(obj,"pk","no_pk")), peer_object.__class__.__name__, str(getattr(peer_object,"pk","no_pk")), failed.__class__.__name__, str(getattr(failed,"pk","no_pk"))))
+
+    def call(self, failed=[], deletion=False):
+        pending = self.fetch_pending(deletion)
+        for o in pending:
+            sync_failed = False
+            try:
+                backoff_disabled = Config().observer_backoff_disabled
+            except:
+                backoff_disabled = 0
+
+            try:
+                scratchpad = json.loads(o.backend_register)
+                if (scratchpad):
+                    next_run = scratchpad['next_run']
+                    if (not backoff_disabled and next_run>time.time()):
+                        sync_failed = True
+            except:
+                logger.log_exc("Exception while loading scratchpad")
+                pass
+
+            if (not sync_failed):
+                try:
+                    for f in failed:
+                        self.check_dependencies(o,f) # Raises exception if failed
+                    if (deletion):
+                        self.delete_record(o)
+                        o.delete(purge=True)
+                    else:
+                        self.sync_record(o)
+                        o.enacted = datetime.now() # Is this the same timezone? XXX
+                        scratchpad = {'next_run':0, 'exponent':0}
+                        o.backend_register = json.dumps(scratchpad)
+                        o.backend_status = "1 - OK"
+                        o.save(update_fields=['enacted','backend_status','backend_register'])
+                except (InnocuousException,Exception) as e:
+                    logger.log_exc("sync step failed!")
+                    try:
+                        if (o.backend_status.startswith('2 - ')):
+                            str_e = '%s // %r'%(o.backend_status[4:],e)
+			    str_e = elim_dups(str_e)
+                        else:
+                            str_e = '%r'%e
+                    except:
+                        str_e = '%r'%e
+
+                    try:
+                        error = self.error_map.map(str_e)
+                    except:
+                        error = '2 - %s'%str_e
+
+                    if isinstance(e, InnocuousException) and not force_error:
+                        o.backend_status = '1 - %s'%error
+                    else:
+                        o.backend_status = '3 - %s'%error
+
+                    try:
+                        scratchpad = json.loads(o.backend_register)
+                        scratchpad['exponent']
+                    except:
+                        logger.log_exc("Exception while updating scratchpad")
+                        scratchpad = {'next_run':0, 'exponent':0}
+
+                    # Second failure
+                    if (scratchpad['exponent']):
+                        delay = scratchpad['exponent'] * 600 # 10 minutes
+                        if (delay<1440):
+                            delay = 1440
+                        scratchpad['next_run'] = time.time() + delay
+
+                    scratchpad['exponent']+=1
+
+                    o.backend_register = json.dumps(scratchpad)
+
+                    # TOFIX:
+                    # DatabaseError: value too long for type character varying(140)
+                    if (o.pk):
+                        try:
+                            o.backend_status = o.backend_status[:1024]
+                            o.save(update_fields=['backend_status','backend_register','updated'])
+                        except:
+                            print "Could not update backend status field!"
+                            pass
+                    sync_failed = True
+
+
+            if (sync_failed):
+                failed.append(o)
+
+        return failed
+
+    def sync_record(self, o):
+        return
+
+    def delete_record(self, o):
+        return
+
+    def __call__(self, **args):
+        return self.call(**args)
diff --git a/xos/synchronizers/base/templates/container.conf.j2 b/xos/synchronizers/base/templates/container.conf.j2
new file mode 100644
index 0000000..7cbb880
--- /dev/null
+++ b/xos/synchronizers/base/templates/container.conf.j2
@@ -0,0 +1,14 @@
+# Upstart script for container
+description "container"
+author "smbaker@gmail.com"
+start on filesystem and started docker
+stop on runlevel [!2345]
+respawn
+
+script
+  /usr/local/sbin/start-container-{{ container_name }}.sh ATTACH
+end script
+
+post-stop script
+  /usr/local/sbin/stop-container-{{ container_name }}.sh
+end script
\ No newline at end of file
diff --git a/xos/synchronizers/base/templates/container.service.j2 b/xos/synchronizers/base/templates/container.service.j2
new file mode 100644
index 0000000..817d6d7
--- /dev/null
+++ b/xos/synchronizers/base/templates/container.service.j2
@@ -0,0 +1,11 @@
+[Unit]
+Description={{ container_name }}
+After=docker.service
+
+[Service]
+ExecStart=/bin/bash -c "/usr/local/sbin/start-container-{{ container_name }}.sh ATTACH"
+ExecStop=/bin/bash -c "/usr/local/sbin/stop-container-{{ container_name }}.sh"
+SuccessExitStatus=0 137
+
+[Install]
+WantedBy=multi-user.target
diff --git a/xos/synchronizers/base/templates/start-container.sh.j2 b/xos/synchronizers/base/templates/start-container.sh.j2
new file mode 100644
index 0000000..2fbf478
--- /dev/null
+++ b/xos/synchronizers/base/templates/start-container.sh.j2
@@ -0,0 +1,136 @@
+#!/bin/bash
+
+iptables -L > /dev/null
+ip6tables -L > /dev/null
+
+CONTAINER={{ container_name }}
+IMAGE={{ docker_image }}
+
+function mac_to_iface {
+    PARENT_MAC=$1
+    ifconfig|grep $PARENT_MAC| awk '{print $1}'|grep -v '\.'
+}
+
+function encapsulate_stag {
+    LAN_IFACE=$1
+    STAG=$2
+    ifconfig $LAN_IFACE >> /dev/null
+    if [ "$?" == 0 ]; then
+        STAG_IFACE=$LAN_IFACE.$STAG
+        ifconfig $LAN_IFACE up
+        ifconfig $STAG_IFACE
+        if [ "$?" == 0 ]; then
+            echo $STAG_IFACE is already created
+        else
+            ifconfig $STAG_IFACE >> /dev/null || ip link add link $LAN_IFACE name $STAG_IFACE type vlan id $STAG
+        fi
+            ifconfig $STAG_IFACE up
+    else
+        echo There is no $LAN_IFACE. Aborting.
+        exit -1
+    fi
+}
+
+
+{% if volumes %}
+{% for volume in volumes %}
+DEST_DIR=/var/container_volumes/$CONTAINER/{{ volume }}
+mkdir -p $DEST_DIR
+VOLUME_ARGS="$VOLUME_ARGS -v $DEST_DIR:{{ volume }}"
+{% endfor %}
+{% endif %}
+
+docker inspect $CONTAINER > /dev/null 2>&1
+if [ "$?" == 1 ]
+then
+    docker pull $IMAGE
+{% if network_method=="host" %}
+    docker run -d --name=$CONTAINER --privileged=true --net=host $VOLUME_ARGS $IMAGE
+{% elif network_method=="bridged" %}
+    docker run -d --name=$CONTAINER --privileged=true --net=bridge $VOLUME_ARGS $IMAGE
+{% else %}
+    docker run -d --name=$CONTAINER --privileged=true --net=none $VOLUME_ARGS $IMAGE
+{% endif %}
+else
+    docker start $CONTAINER
+fi
+
+{% if ports %}
+{% for port in ports %}
+
+{% if port.next_hop %}
+NEXTHOP_ARG="@{{ port.next_hop }}"
+{% else %}
+NEXTHOP_ARG=""
+{% endif %}
+
+{% if port.c_tag %}
+CTAG_ARG="@{{ port.c_tag }}"
+{% else %}
+CTAG_ARG=""
+{% endif %}
+
+{% if port.parent_mac %}
+# container-in-VM
+SRC_DEV=$( mac_to_iface "{{ port.parent_mac }}" )
+CMD="docker exec $CONTAINER ifconfig $SRC_DEV >> /dev/null || pipework $SRC_DEV -i {{ port.device }} $CONTAINER {{ port.ip }}/24$NEXTHOP_ARG {{ port.mac }} $CTAG_ARG"
+echo $CMD
+eval $CMD
+
+{% else %}
+# container-on-metal
+IP="{{ port.ip }}"
+{% if port.mac %}
+MAC="{{ port.mac }}"
+{% else %}
+MAC=""
+{% endif %}
+
+DEVICE="{{ port.device }}"

+BRIDGE="{{ port.bridge }}"

+{% if port.s_tag %}

+# This is intended for lan_network. Assume that BRIDGE is set to br_lan. We

+# create a device that strips off the S-TAG.

+STAG="{{ port.s_tag }}"

+encapsulate_stag $BRIDGE $STAG

+SRC_DEV=$STAG_IFACE

+{% else %}

+# This is for a standard neutron private network. We use a donor VM to setup

+# openvswitch for us, and we snoop at its devices and create a tap using the

+# same settings.

+XOS_NETWORK_ID="{{ port.xos_network_id }}"

+INSTANCE_MAC="{{ port.snoop_instance_mac }}"
+INSTANCE_ID="{{ port.snoop_instance_id }}"
+INSTANCE_TAP=`virsh domiflist $INSTANCE_ID | grep -i $INSTANCE_MAC | awk '{print $1}'`
+INSTANCE_TAP=${INSTANCE_TAP:3}
+VLAN_ID=`ovs-vsctl show | grep -i -A 1 port.*$INSTANCE_TAP | grep -i tag | awk '{print $2}'`
+# One tap for all containers per XOS/neutron network. Included the VLAN_ID in the
+# hash, to cover the case where XOS is reinstalled and the XOS network ids
+# get reused.
+TAP="con`echo ${XOS_NETWORK_ID}_$VLAN_ID|md5sum|awk '{print $1}'`"
+TAP=${TAP:0:10}
+echo im=$INSTANCE_MAC ii=$INSTANCE_ID it=$INSTANCE_TAP vlan=$VLAN_ID tap=$TAP con=$CONTAINER dev=$DEVICE mac=$MAC
+ovs-vsctl show | grep -i $TAP
+if [[ $? == 1 ]]; then
+    echo creating tap
+    ovs-vsctl add-port $BRIDGE $TAP tag=$VLAN_ID -- set interface $TAP type=internal
+else
+    echo tap exists
+fi
+SRC_DEV=$TAP
+{% endif %}
+
+CMD="docker exec $CONTAINER ifconfig $DEVICE >> /dev/null || pipework $SRC_DEV -i $DEVICE $CONTAINER $IP/24$NEXTHOP_ARG $MAC $CTAG_ARG"
+echo $CMD
+eval $CMD
+{% endif %}
+{% endfor %}
+{% endif %}
+
+# Attach to container
+# (this is only done when using upstart, since upstart expects to be attached
+#  to a running service)
+if [[ "$1" == "ATTACH" ]]; then
+    docker start -a $CONTAINER
+fi
+
diff --git a/xos/synchronizers/base/templates/stop-container.sh.j2 b/xos/synchronizers/base/templates/stop-container.sh.j2
new file mode 100644
index 0000000..9cabb00
--- /dev/null
+++ b/xos/synchronizers/base/templates/stop-container.sh.j2
@@ -0,0 +1,4 @@
+CONTAINER={{ container_name }}
+
+docker stop $CONTAINER
+docker rm $CONTAINER
diff --git a/xos/synchronizers/base/toposort.py b/xos/synchronizers/base/toposort.py
new file mode 100644
index 0000000..6839861
--- /dev/null
+++ b/xos/synchronizers/base/toposort.py
@@ -0,0 +1,72 @@
+#!/usr/bin/env python
+
+import time
+import traceback
+import commands
+import threading
+import json
+import pdb
+
+from datetime import datetime
+from collections import defaultdict
+
+# Topological sort
+# Notes:
+# - Uses a stack instead of recursion
+# - Forfeits optimization involving tracking currently visited nodes
+def toposort(g, steps=None):
+	# Get set of all nodes, including those without outgoing edges
+	keys = set(g.keys())
+	values = set({})
+	for v in g.values():
+		values=values | set(v)
+	
+	all_nodes=list(keys|values)
+	if (not steps):
+		steps = all_nodes
+
+	# Final order
+	order = []
+
+	# DFS stack, not using recursion
+	stack = []
+
+	# Unmarked set
+	unmarked = all_nodes
+
+	# visiting = [] - skip, don't expect 1000s of nodes, |E|/|V| is small
+
+	while unmarked:
+		stack.insert(0,unmarked[0]) # push first unmarked
+
+		while (stack):
+			n = stack[0]
+			add = True
+			try:
+				for m in g[n]:
+					if (m in unmarked):
+					    add = False
+					    stack.insert(0,m)
+			except KeyError:
+				pass
+			if (add):
+				if (n in steps and n not in order):
+					order.append(n)
+				item = stack.pop(0)
+				try:
+					unmarked.remove(item)
+				except ValueError:
+					pass
+
+	noorder = list(set(steps) - set(order))
+	return order + noorder
+
+def main():
+	graph_file=open('xos.deps').read()
+	g = json.loads(graph_file)
+	print toposort(g)
+
+if (__name__=='__main__'):
+	main()
+
+#print toposort({'a':'b','b':'c','c':'d','d':'c'},['d','c','b','a'])
diff --git a/xos/synchronizers/base/xos-synchronizer.py b/xos/synchronizers/base/xos-synchronizer.py
new file mode 100644
index 0000000..493b94a
--- /dev/null
+++ b/xos/synchronizers/base/xos-synchronizer.py
@@ -0,0 +1,85 @@
+#!/usr/bin/env python
+import os
+import argparse
+import sys
+
+sys.path.append('/opt/xos')
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
+from synchronizers.base.backend import Backend
+from xos.config import Config, DEFAULT_CONFIG_FN
+from core.models import Instance,NetworkTemplate
+from xos.logger import Logger, logging, logger
+from django.db import ProgrammingError
+import time
+
+try:
+    from django import setup as django_setup # django 1.7
+except:
+    django_setup = False
+
+config = Config()
+
+# after http://www.erlenstar.demon.co.uk/unix/faq_2.html
+def daemon():
+    """Daemonize the current process."""
+    if os.fork() != 0: os._exit(0)
+    os.setsid()
+    if os.fork() != 0: os._exit(0)
+    os.umask(0)
+    devnull = os.open(os.devnull, os.O_RDWR)
+    os.dup2(devnull, 0)
+    # xxx fixme - this is just to make sure that nothing gets stupidly lost - should use devnull
+    logdir=os.path.dirname(config.observer_logfile)
+    # when installed in standalone we might not have httpd installed
+    if not os.path.isdir(logdir): os.mkdir(logdir)
+    crashlog = os.open('%s'%config.observer_logfile, os.O_RDWR | os.O_APPEND | os.O_CREAT, 0644)
+    os.dup2(crashlog, 1)
+    os.dup2(crashlog, 2)
+
+    if hasattr(config, "observer_pidfile"):
+        pidfile = config.get("observer_pidfile")
+    else:
+        pidfile = "/var/run/xosobserver.pid"
+    try:
+        file(pidfile,"w").write(str(os.getpid()))
+    except:
+        print "failed to create pidfile %s" % pidfile
+
+def main():
+    # Generate command line parser
+    parser = argparse.ArgumentParser(usage='%(prog)s [options]')
+    parser.add_argument('-d', '--daemon', dest='daemon', action='store_true', default=False,
+                        help='Run as daemon.')
+    # smbaker: util/config.py parses sys.argv[] directly to get config file name; include the option here to avoid
+    #   throwing unrecognized argument exceptions
+    parser.add_argument('-C', '--config', dest='config_file', action='store', default=DEFAULT_CONFIG_FN,
+                        help='Name of config file.')
+    args = parser.parse_args()
+
+    if args.daemon: daemon()
+
+    if django_setup: # 1.7
+        django_setup()
+
+    models_active = False
+    wait = False
+    while not models_active:
+        try:
+            _ = Instance.objects.first()
+            _ = NetworkTemplate.objects.first()
+            models_active = True
+        except Exception,e:
+            logger.info(str(e))
+            logger.info('Waiting for data model to come up before starting...')
+            time.sleep(10)
+            wait = True
+
+    if (wait):
+        time.sleep(60) # Safety factor, seeing that we stumbled waiting for the data model to come up.
+    backend = Backend()
+    backend.run()    
+
+if __name__ == '__main__':
+    
+    main() 
diff --git a/xos/synchronizers/ec2/__init__.py b/xos/synchronizers/ec2/__init__.py
new file mode 100644
index 0000000..f4c7743
--- /dev/null
+++ b/xos/synchronizers/ec2/__init__.py
@@ -0,0 +1,32 @@
+from xos.config import Config
+
+try:
+    observer_disabled = Config().observer_disabled
+except:
+    observer_disabled = False
+
+print_once = True
+
+if (not observer_disabled):
+    from .event_manager import EventSender
+
+    def notify_observer(model=None, delete=False, pk=None, model_dict={}):
+        try:
+            if (model and delete):
+                if hasattr(model,"__name__"):
+                    modelName = model.__name__
+                else:
+                    modelName = model.__class__.__name__
+                EventSender().fire(delete_flag = delete, model = modelName, pk = pk, model_dict=model_dict)
+            else:
+                EventSender().fire()
+        except Exception,e:
+            print "Exception in Observer. This should not disrupt the front end. %s"%str(e)
+
+else:
+    def notify_observer(model=None, delete=False, pk=None, model_dict={}):
+        global print_once
+        if (print_once):
+            print "The observer is disabled"
+            print_once = False
+        return
diff --git a/xos/synchronizers/ec2/aws_lib.py b/xos/synchronizers/ec2/aws_lib.py
new file mode 100644
index 0000000..e116295
--- /dev/null
+++ b/xos/synchronizers/ec2/aws_lib.py
@@ -0,0 +1,18 @@
+import os
+import json
+
+class AwsException(Exception):
+	pass
+
+def aws_run(cmd):
+	cmd = 'aws %s'%cmd
+	pipe = os.popen(cmd)
+	output_str = pipe.read()
+
+	if (not pipe.close()):
+		output = json.loads(output_str)
+		return output
+	else:
+		raise AwsException("Error running command: %s"%cmd)
+
+
diff --git a/xos/synchronizers/ec2/awslib.py b/xos/synchronizers/ec2/awslib.py
new file mode 100644
index 0000000..ca708ff
--- /dev/null
+++ b/xos/synchronizers/ec2/awslib.py
@@ -0,0 +1,18 @@
+import os
+import json
+
+class AwsException(Exception):
+	pass
+
+def aws_run(cmd,env=''):
+	cmd = '%s aws %s'%(env,cmd)
+	pipe = os.popen(cmd)
+	output_str = pipe.read()
+
+	if (not pipe.close()):
+		output = json.loads(output_str)
+		return output
+	else:
+		raise AwsException("Error: %s"%output_str)
+
+
diff --git a/xos/synchronizers/ec2/backend.py b/xos/synchronizers/ec2/backend.py
new file mode 100644
index 0000000..7288e61
--- /dev/null
+++ b/xos/synchronizers/ec2/backend.py
@@ -0,0 +1,22 @@
+import threading
+import time
+from ec2_observer.event_loop import XOSObserver
+from ec2_observer.event_manager import EventListener
+from xos.logger import Logger, logging
+
+logger = Logger(level=logging.INFO)
+
+class Backend:
+    
+    def run(self):
+        # start the openstack observer
+        observer = XOSObserver()
+        observer_thread = threading.Thread(target=observer.run)
+        observer_thread.start()
+        
+        # start event listene
+        event_manager = EventListener(wake_up=observer.wake_up)
+        event_manager_thread = threading.Thread(target=event_manager.run)
+        event_manager_thread.start()
+        logger.log_exc("Exception in child thread")
+
diff --git a/xos/synchronizers/ec2/creds.py b/xos/synchronizers/ec2/creds.py
new file mode 100644
index 0000000..0a29c0d
--- /dev/null
+++ b/xos/synchronizers/ec2/creds.py
@@ -0,0 +1,16 @@
+from core.models import *
+
+def get_creds(user=None, slice=None, site=None, deployment=None):
+    if (not user or not site):
+        raise Exception('User and Site have to be in context to use EC2')
+
+    cred = UserCredential.objects.filter(user=user)
+    if (not cred):
+        cred = SiteCredential.objects.filter(site=site)
+        
+    if (cred):
+        env = 'AWS_ACCESS_KEY_ID=%s AWS_SECRET_ACCESS_KEY=%s'%(cred.key_id, cred.enc_value) 
+    else:
+        env = ''
+
+    return env
diff --git a/xos/synchronizers/ec2/deleter.py b/xos/synchronizers/ec2/deleter.py
new file mode 100644
index 0000000..93fa572
--- /dev/null
+++ b/xos/synchronizers/ec2/deleter.py
@@ -0,0 +1,16 @@
+import os
+import base64
+from xos.config import Config
+
+class Deleter:
+	model=None # Must be overridden
+
+        def __init__(self, *args, **kwargs):
+                pass
+
+	def call(self, pk, model_dict):
+		# Fetch object from XOS db and delete it
+		pass
+
+	def __call__(self, *args, **kwargs):
+		return self.call(*args, **kwargs)
diff --git a/xos/synchronizers/ec2/deleters/__init__.py b/xos/synchronizers/ec2/deleters/__init__.py
new file mode 100644
index 0000000..9cfd951
--- /dev/null
+++ b/xos/synchronizers/ec2/deleters/__init__.py
@@ -0,0 +1,18 @@
+import os
+
+deleters = {}
+_path = os.path.join('.',os.path.dirname(__file__))
+
+_files = os.listdir(_path)
+_files = filter(lambda x:x.endswith('deleter.py'),_files)
+_files = map(lambda x:x.rstrip('.py'),_files)
+
+"""
+for f in _files:
+	m = __import__(f)
+	deleter = getattr(m,f.title().replace('_',''))
+	try:
+		deleters[deleter.model].append(deleter)
+	except KeyError:
+		deleters[deleter.model]=[deleter]
+"""
diff --git a/xos/synchronizers/ec2/deleters/instance_deleter.py b/xos/synchronizers/ec2/deleters/instance_deleter.py
new file mode 100644
index 0000000..ba454e7
--- /dev/null
+++ b/xos/synchronizers/ec2/deleters/instance_deleter.py
@@ -0,0 +1,14 @@
+from core.models import Instance, SliceDeployments
+from synchronizers.base.deleter import Deleter
+
+class InstanceDeleter(Deleter):
+    model='Instance'
+
+    def call(self, pk):
+        instance = Instance.objects.get(pk=pk)
+        if instance.instance_id:
+            driver = self.driver.client_driver(caller=instance.creator, 
+                                               tenant=instance.slice.name,
+                                               deployment=instance.deploymentNetwork.name)
+            driver.destroy_instance(instance.instance_id)
+        instance.delete()
diff --git a/xos/synchronizers/ec2/deleters/network_deleter.py b/xos/synchronizers/ec2/deleters/network_deleter.py
new file mode 100644
index 0000000..ba9cd09
--- /dev/null
+++ b/xos/synchronizers/ec2/deleters/network_deleter.py
@@ -0,0 +1,19 @@
+from core.models import Network, NetworkDeployments
+from synchronizers.base.deleter import Deleter
+from synchronizers.base.deleters.network_deployment_deleter import NetworkDeploymentDeleter
+from xos.logger import Logger, logging
+
+logger = Logger(level=logging.INFO)
+
+class NetworkDeleter(Deleter):
+    model='Network'
+
+    def call(self, pk):
+        network = Network.objects.get(pk=pk) 
+        network_deployment_deleter = NetworkDeploymentDeleter()
+        for network_deployment in NetworkDeployments.objects.filter(network=network):
+            try:
+                network_deployment_deleter(network_deployment.id)    
+            except:
+                logger.log_exc("Failed to delete network deployment %s" % network_deployment,extra=network.tologdict())
+        network.delete()
diff --git a/xos/synchronizers/ec2/deleters/network_deployment_deleter.py b/xos/synchronizers/ec2/deleters/network_deployment_deleter.py
new file mode 100644
index 0000000..f8aaa29
--- /dev/null
+++ b/xos/synchronizers/ec2/deleters/network_deployment_deleter.py
@@ -0,0 +1,21 @@
+from core.models import Network, NetworkDeployments
+from synchronizers.base.deleter import Deleter
+from openstack.driver import OpenStackDriver
+
+class NetworkDeploymentDeleter(Deleter):
+    model='NetworkDeployment'
+
+    def call(self, pk):
+        network_deployment = NetworkDeployments.objects.get(pk=pk)
+        driver = OpenStackDriver().client_driver(caller=network_deployment.network.owner.creator,
+                                                 tenant=network_deployment.network.owner.name,
+                                                 deployment=network_deployment.deployment.name)
+        if (network_deployment.router_id) and (network_deployment.subnet_id):
+            driver.delete_router_interface(network_deployment.router_id, network_deployment.subnet_id)
+        if network_deployment.subnet_id:
+            driver.delete_subnet(network_deployment.subnet_id)
+        if network_deployment.router_id:
+            driver.delete_router(network_deployment.router_id)
+        if network_deployment.net_id:
+            driver.delete_network(network_deployment.net_id)
+        network_deployment.delete()
diff --git a/xos/synchronizers/ec2/deleters/network_instance_deleter.py b/xos/synchronizers/ec2/deleters/network_instance_deleter.py
new file mode 100644
index 0000000..21fe87f
--- /dev/null
+++ b/xos/synchronizers/ec2/deleters/network_instance_deleter.py
@@ -0,0 +1,13 @@
+from core.models import NetworkInstance
+from synchronizers.base.deleter import Deleter
+
+class NetworkInstanceDeleter(Deleter):
+    model='NetworkInstance'
+
+    def call(self, pk):
+        network_instance = NetworkInstances.objects.get(pk=pk)
+        # handle openstack delete
+
+        network_instance.delete() 
+
+    
diff --git a/xos/synchronizers/ec2/deleters/site_deleter.py b/xos/synchronizers/ec2/deleters/site_deleter.py
new file mode 100644
index 0000000..832baf9
--- /dev/null
+++ b/xos/synchronizers/ec2/deleters/site_deleter.py
@@ -0,0 +1,14 @@
+from core.models import Site, SiteDeployment
+from synchronizers.base.deleter import Deleter
+from synchronizers.base.deleters.site_deployment_deleter import SiteDeploymentDeleter
+
+class SiteDeleter(Deleter):
+    model='Site'
+    
+    def call(self, pk):
+        site = Site.objects.get(pk=pk)
+        site_deployments = SiteDeployment.objects.filter(site=site)
+        site_deployment_deleter = SiteDeploymentDeleter()
+        for site_deployment in site_deployments:
+            site_deployment_deleter(site_deployment.id)
+        site.delete() 
diff --git a/xos/synchronizers/ec2/deleters/site_deployment_deleter.py b/xos/synchronizers/ec2/deleters/site_deployment_deleter.py
new file mode 100644
index 0000000..794b438
--- /dev/null
+++ b/xos/synchronizers/ec2/deleters/site_deployment_deleter.py
@@ -0,0 +1,12 @@
+from core.models import Site, SiteDeployment
+from synchronizers.base.deleter import Deleter
+
+class SiteDeploymentDeleter(Deleter):
+    model='SiteDeployment'
+
+    def call(self, pk):
+        site_deployment = SiteDeployment.objects.get(pk=pk)
+        if site_deployment.tenant_id:
+            driver = self.driver.admin_driver(deployment=site_deployment.deployment.name)
+            driver.delete_tenant(site_deployment.tenant_id)
+        site_deployment.delete()
diff --git a/xos/synchronizers/ec2/deleters/slice_deleter.py b/xos/synchronizers/ec2/deleters/slice_deleter.py
new file mode 100644
index 0000000..6b800ac
--- /dev/null
+++ b/xos/synchronizers/ec2/deleters/slice_deleter.py
@@ -0,0 +1,19 @@
+from core.models import Slice, SliceDeployments, User
+from synchronizers.base.deleter import Deleter
+from synchronizers.base.deleters.slice_deployment_deleter import SliceDeploymentsDeleter
+from xos.logger import Logger, logging
+
+logger = Logger(level=logging.INFO)
+
+class SliceDeleter(Deleter):
+    model='Slice'
+
+    def call(self, pk):
+        slice = Slice.objects.get(pk=pk)
+        slice_deployment_deleter = SliceDeploymentsDeleter()
+        for slice_deployment in SliceDeployments.objects.filter(slice=slice):
+            try:
+                slice_deployment_deleter(slice_deployment.id)
+            except:
+                logger.log_exc("Failed to delete slice_deployment %s" % slice_deployment,extra=slice.tologdict()) 
+        slice.delete()
diff --git a/xos/synchronizers/ec2/deleters/slice_deployment_deleter.py b/xos/synchronizers/ec2/deleters/slice_deployment_deleter.py
new file mode 100644
index 0000000..39c557a
--- /dev/null
+++ b/xos/synchronizers/ec2/deleters/slice_deployment_deleter.py
@@ -0,0 +1,34 @@
+from core.models import Slice, SliceDeployments, User
+from synchronizers.base.deleter import Deleter
+from openstack.driver import OpenStackDriver
+
+class SliceDeploymentsDeleter(Deleter):
+    model='SliceDeployments'
+
+    def call(self, pk):
+        slice_deployment = SliceDeployments.objects.get(pk=pk)
+        user = User.objects.get(id=slice_deployment.slice.creator.id)
+        driver = OpenStackDriver().admin_driver(deployment=slice_deployment.deployment.name)
+        client_driver = driver.client_driver(caller=user,
+                                             tenant=slice_deployment.slice.name,
+                                             deployment=slice_deployment.deployment.name)
+
+        if slice_deployment.router_id and slice_deployment.subnet_id:
+            client_driver.delete_router_interface(slice_deployment.router_id, slice_deployment.subnet_id)
+        if slice_deployment.subnet_id:
+            client_driver.delete_subnet(slice_deployment.subnet_id)
+        if slice_deployment.router_id:    
+            client_driver.delete_router(slice_deployment.router_id)
+        if slice_deployment.network_id:
+            client_driver.delete_network(slice_deployment.network_id)
+        if slice_deployment.tenant_id:
+            driver.delete_tenant(slice_deployment.tenant_id)
+        # delete external route
+        #subnet = None
+        #subnets = client_driver.shell.quantum.list_subnets()['subnets']
+        #for snet in subnets:
+        #    if snet['id'] == slice_deployment.subnet_id:
+        #        subnet = snet
+        #if subnet:
+        #    driver.delete_external_route(subnet)
+        slice_deployment.delete()
diff --git a/xos/synchronizers/ec2/deleters/user_deleter.py b/xos/synchronizers/ec2/deleters/user_deleter.py
new file mode 100644
index 0000000..12c8224
--- /dev/null
+++ b/xos/synchronizers/ec2/deleters/user_deleter.py
@@ -0,0 +1,13 @@
+from core.models import User, UserDeployments
+from synchronizers.base.deleter import Deleter
+from synchronizers.base.deleters.user_deployment_deleter import UserDeploymentsDeleter
+
+class UserDeleter(Deleter):
+    model='User'
+
+    def call(self, pk):
+        user = User.objects.get(pk=pk)
+        user_deployment_deleter = UserDeploymentsDeleter()
+        for user_deployment in UserDeployments.objects.filter(user=user):
+            user_deployment_deleter(user_deployment.id)
+        user.delete()
diff --git a/xos/synchronizers/ec2/deleters/user_deployment_deleter.py b/xos/synchronizers/ec2/deleters/user_deployment_deleter.py
new file mode 100644
index 0000000..3b6113b
--- /dev/null
+++ b/xos/synchronizers/ec2/deleters/user_deployment_deleter.py
@@ -0,0 +1,12 @@
+from core.models import User, UserDeployments
+from synchronizers.base.deleter import Deleter
+
+class UserDeploymentsDeleter(Deleter):
+    model='UserDeployments'
+
+    def call(self, pk):
+        user_deployment = UserDeployments.objects.get(pk=pk)
+        if user_deployment.user.kuser_id:
+            driver = self.driver.admin_driver(deployment=user_deployment.deployment.name)
+            driver.delete_user(user_deployment.user.kuser_id)
+        user_deployment.delete()
diff --git a/xos/synchronizers/ec2/dmdot b/xos/synchronizers/ec2/dmdot
new file mode 100644
index 0000000..de07a78
--- /dev/null
+++ b/xos/synchronizers/ec2/dmdot
@@ -0,0 +1,49 @@
+#!/usr/bin/python
+
+import os
+import pdb
+import sys
+import json
+
+sys.path.append('.')
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
+
+from django.db.models.fields.related import ForeignKey
+from core.models import *
+
+try:
+	output = sys.args[1]
+except:
+	output = '-json'
+
+g = globals()
+model_classes = []
+class_names = []
+for c in g.values():
+	if type(c)==type(PlCoreBase):
+		model_classes.append(c)
+		class_names.append(c.__name__)
+
+
+if (output=='-dot'):
+	print "digraph plstack {";
+	for c in model_classes:
+		fields = c._meta.fields
+		for f in fields:
+			if type(f)==ForeignKey and f.name.title() in class_names:
+				print '\t"%s"->"%s";'%(c.__name__,f.name.title())
+	print "}\n";
+elif (output=='-json'):
+	d = {}
+	for c in model_classes:
+		fields = c._meta.fields
+		for f in fields:
+			if type(f)==ForeignKey and f.name.title() in class_names:
+				try:
+					d[c.__name__].append(f.name.title())
+				except KeyError:
+					d[c.__name__]=[f.name.title()]
+	print json.dumps(d,indent=4)
+	
+	
diff --git a/xos/synchronizers/ec2/ec2_backend.py b/xos/synchronizers/ec2/ec2_backend.py
new file mode 100644
index 0000000..7edf63c
--- /dev/null
+++ b/xos/synchronizers/ec2/ec2_backend.py
@@ -0,0 +1,24 @@
+import threading
+import time
+from ec2_observer.event_loop import XOSObserver
+from ec2_observer.event_manager import EventListener
+from xos.logger import Logger, logging
+
+logger = Logger(level=logging.INFO)
+
+class Backend:
+    
+    def run(self):
+        try:
+            # start the openstack observer
+            observer = XOSObserver()
+            observer_thread = threading.Thread(target=observer.run)
+            observer_thread.start()
+            
+            # start event listene
+            event_manager = EventListener(wake_up=observer.wake_up)
+            event_manager_thread = threading.Thread(target=event_manager.run)
+            event_manager_thread.start()
+        except:
+            logger.log_exc("Exception in child thread")
+
diff --git a/xos/synchronizers/ec2/error_mapper.py b/xos/synchronizers/ec2/error_mapper.py
new file mode 100644
index 0000000..9eb878d
--- /dev/null
+++ b/xos/synchronizers/ec2/error_mapper.py
@@ -0,0 +1,25 @@
+from xos.config import Config
+from xos.logger import Logger, logging, logger
+
+class ErrorMapper:
+	def __init__(self, error_map_file):
+		self.error_map = {}
+		try:
+			error_map_lines = open(error_map_file).read().splitlines()
+			for l in error_map_lines:
+				if (not l.startswith('#')):
+					splits = l.split('->')
+					k,v = map(lambda i:i.rstrip(),splits)
+					self.error_map[k]=v
+		except:
+			logging.info('Could not read error map')
+
+
+	def map(self, error):
+		return self.error_map[error]
+
+
+
+
+
+
diff --git a/xos/synchronizers/ec2/event_loop.py b/xos/synchronizers/ec2/event_loop.py
new file mode 100644
index 0000000..cfeb212
--- /dev/null
+++ b/xos/synchronizers/ec2/event_loop.py
@@ -0,0 +1,393 @@
+import os
+import imp
+import inspect
+import time
+import traceback
+import commands
+import threading
+import json
+import pdb
+
+from datetime import datetime
+from collections import defaultdict
+from core.models import *
+from django.db.models import F, Q
+#from openstack.manager import OpenStackManager
+from openstack.driver import OpenStackDriver
+from xos.logger import Logger, logging, logger
+#from timeout import timeout
+from xos.config import Config, XOS_DIR
+from synchronizers.base.steps import *
+from syncstep import SyncStep
+from toposort import toposort
+from synchronizers.base.error_mapper import *
+
+debug_mode = False
+
+logger = Logger(level=logging.INFO)
+
+class StepNotReady(Exception):
+	pass
+
+class NoOpDriver:
+	def __init__(self):
+		 self.enabled = True
+		 self.dependency_graph = None
+
+STEP_STATUS_WORKING=1
+STEP_STATUS_OK=2
+STEP_STATUS_KO=3
+
+def invert_graph(g):
+	ig = {}
+	for k,v in g.items():
+		for v0 in v:
+			try:
+				ig[v0].append(k)
+			except:
+				ig=[k]
+	return ig
+
+class XOSObserver:
+	#sync_steps = [SyncNetworks,SyncNetworkInstances,SyncSites,SyncSitePrivilege,SyncSlices,SyncSliceMemberships,SyncInstances,SyncInstanceIps,SyncExternalRoutes,SyncUsers,SyncRoles,SyncNodes,SyncImages,GarbageCollector]
+	sync_steps = []
+
+	
+	def __init__(self):
+		# The Condition object that gets signalled by Feefie events
+		self.step_lookup = {}
+		self.load_sync_step_modules()
+		self.load_sync_steps()
+		self.event_cond = threading.Condition()
+
+		self.driver_kind = getattr(Config(), "observer_driver", "openstack")
+		if self.driver_kind=="openstack":
+			self.driver = OpenStackDriver()
+		else:
+			self.driver = NoOpDriver()
+
+	def wait_for_event(self, timeout):
+		self.event_cond.acquire()
+		self.event_cond.wait(timeout)
+		self.event_cond.release()
+
+	def wake_up(self):
+		logger.info('Wake up routine called. Event cond %r'%self.event_cond)
+		self.event_cond.acquire()
+		self.event_cond.notify()
+		self.event_cond.release()
+
+	def load_sync_step_modules(self, step_dir=None):
+		if step_dir is None:
+			if hasattr(Config(), "observer_steps_dir"):
+				step_dir = Config().observer_steps_dir
+			else:
+				step_dir = XOS_DIR + "/observer/steps"
+
+		for fn in os.listdir(step_dir):
+			pathname = os.path.join(step_dir,fn)
+			if os.path.isfile(pathname) and fn.endswith(".py") and (fn!="__init__.py"):
+				module = imp.load_source(fn[:-3],pathname)
+				for classname in dir(module):
+					c = getattr(module, classname, None)
+
+					# make sure 'c' is a descendent of SyncStep and has a
+					# provides field (this eliminates the abstract base classes
+					# since they don't have a provides)
+
+					if inspect.isclass(c) and issubclass(c, SyncStep) and hasattr(c,"provides") and (c not in self.sync_steps):
+						self.sync_steps.append(c)
+		logger.info('loaded sync steps: %s' % ",".join([x.__name__ for x in self.sync_steps]))
+		# print 'loaded sync steps: %s' % ",".join([x.__name__ for x in self.sync_steps])
+
+	def load_sync_steps(self):
+		dep_path = Config().observer_dependency_graph
+		logger.info('Loading model dependency graph from %s' % dep_path)
+		try:
+			# This contains dependencies between records, not sync steps
+			self.model_dependency_graph = json.loads(open(dep_path).read())
+		except Exception,e:
+			raise e
+
+		try:
+			backend_path = Config().observer_pl_dependency_graph
+			logger.info('Loading backend dependency graph from %s' % backend_path)
+			# This contains dependencies between backend records
+			self.backend_dependency_graph = json.loads(open(backend_path).read())
+		except Exception,e:
+			logger.info('Backend dependency graph not loaded')
+			# We can work without a backend graph
+			self.backend_dependency_graph = {}
+
+		provides_dict = {}
+		for s in self.sync_steps:
+			self.step_lookup[s.__name__] = s 
+			for m in s.provides:
+				try:
+					provides_dict[m.__name__].append(s.__name__)
+				except KeyError:
+					provides_dict[m.__name__]=[s.__name__]
+
+		step_graph = {}
+		for k,v in self.model_dependency_graph.iteritems():
+			try:
+				for source in provides_dict[k]:
+					for m in v:
+						try:
+							for dest in provides_dict[m]:
+								# no deps, pass
+								try:
+									if (dest not in step_graph[source]):
+										step_graph[source].append(dest)
+								except:
+									step_graph[source]=[dest]
+						except KeyError:
+							pass
+					
+			except KeyError:
+				pass
+				# no dependencies, pass
+		
+		#import pdb
+		#pdb.set_trace()
+		if (self.backend_dependency_graph):
+			backend_dict = {}
+			for s in self.sync_steps:
+				for m in s.serves:
+					backend_dict[m]=s.__name__
+					
+			for k,v in backend_dependency_graph.iteritems():
+				try:
+					source = backend_dict[k]
+					for m in v:
+						try:
+							dest = backend_dict[m]
+						except KeyError:
+							# no deps, pass
+							pass
+						step_graph[source]=dest
+						
+				except KeyError:
+					pass
+					# no dependencies, pass
+
+		self.dependency_graph = step_graph
+		self.deletion_dependency_graph = invert_graph(step_graph)
+
+		self.ordered_steps = toposort(self.dependency_graph, map(lambda s:s.__name__,self.sync_steps))
+		print "Order of steps=",self.ordered_steps
+		self.load_run_times()
+		
+
+	def check_duration(self, step, duration):
+		try:
+			if (duration > step.deadline):
+				logger.info('Sync step %s missed deadline, took %.2f seconds'%(step.name,duration))
+		except AttributeError:
+			# S doesn't have a deadline
+			pass
+
+	def update_run_time(self, step, deletion):
+		if (not deletion):
+			self.last_run_times[step.__name__]=time.time()
+		else:
+			self.last_deletion_run_times[step.__name__]=time.time()
+
+
+	def check_schedule(self, step, deletion):
+		last_run_times = self.last_run_times if not deletion else self.last_deletion_run_times
+
+		time_since_last_run = time.time() - last_run_times.get(step.__name__, 0)
+		try:
+			if (time_since_last_run < step.requested_interval):
+				raise StepNotReady
+		except AttributeError:
+			logger.info('Step %s does not have requested_interval set'%step.__name__)
+			raise StepNotReady
+	
+	def load_run_times(self):
+		try:
+			jrun_times = open('/tmp/observer_run_times').read()
+			self.last_run_times = json.loads(jrun_times)
+		except:
+			self.last_run_times={}
+			for e in self.ordered_steps:
+				self.last_run_times[e]=0
+		try:
+			jrun_times = open('/tmp/observer_deletion_run_times').read()
+			self.last_deletion_run_times = json.loads(jrun_times)
+		except:
+			self.last_deletion_run_times={}
+			for e in self.ordered_steps:
+				self.last_deletion_run_times[e]=0
+
+
+	def save_run_times(self):
+		run_times = json.dumps(self.last_run_times)
+		open('/tmp/observer_run_times','w').write(run_times)
+
+		deletion_run_times = json.dumps(self.last_deletion_run_times)
+		open('/tmp/observer_deletion_run_times','w').write(deletion_run_times)
+
+	def check_class_dependency(self, step, failed_steps):
+		step.dependenices = []
+		for obj in step.provides:
+			step.dependenices.extend(self.model_dependency_graph.get(obj.__name__, []))
+		for failed_step in failed_steps:
+			if (failed_step in step.dependencies):
+				raise StepNotReady
+
+	def sync(self, S, deletion):
+		step = self.step_lookup[S]
+		start_time=time.time()
+		
+		dependency_graph = self.dependency_graph if not deletion else self.deletion_dependency_graph
+
+		# Wait for step dependencies to be met
+		try:
+			deps = self.dependency_graph[S]
+			has_deps = True
+		except KeyError:
+			has_deps = False
+
+		if (has_deps):
+			for d in deps:
+				cond = self.step_conditions[d]
+				cond.acquire()
+				if (self.step_status[d] is STEP_STATUS_WORKING):
+					cond.wait()
+				cond.release()
+			go = self.step_status[d] == STEP_STATUS_OK
+		else:
+			go = True
+
+		if (not go):
+			self.failed_steps.append(sync_step)
+			my_status = STEP_STATUS_KO
+		else:
+			sync_step = step(driver=self.driver,error_map=self.error_mapper)
+			sync_step.__name__ = step.__name__
+			sync_step.dependencies = []
+			try:
+				mlist = sync_step.provides
+				
+				for m in mlist:
+					sync_step.dependencies.extend(self.model_dependency_graph[m.__name__])
+			except KeyError:
+				pass
+			sync_step.debug_mode = debug_mode
+
+			should_run = False
+			try:
+				# Various checks that decide whether
+				# this step runs or not
+				self.check_class_dependency(sync_step, self.failed_steps) # dont run Slices if Sites failed
+				self.check_schedule(sync_step, deletion) # dont run sync_network_routes if time since last run < 1 hour
+				should_run = True
+			except StepNotReady:
+				logging.info('Step not ready: %s'%sync_step.__name__)
+				self.failed_steps.append(sync_step)
+				my_status = STEP_STATUS_KO
+			except Exception,e:
+				logging.error('%r',e)
+				logger.log_exc("sync step failed: %r. Deletion: %r"%(sync_step,deletion))
+				self.failed_steps.append(sync_step)
+				my_status = STEP_STATUS_KO
+
+			if (should_run):
+				try:
+					duration=time.time() - start_time
+
+					logger.info('Executing step %s' % sync_step.__name__)
+
+					failed_objects = sync_step(failed=list(self.failed_step_objects), deletion=deletion)
+
+					self.check_duration(sync_step, duration)
+
+					if failed_objects:
+						self.failed_step_objects.update(failed_objects)
+
+					my_status = STEP_STATUS_OK
+					self.update_run_time(sync_step,deletion)
+				except Exception,e:
+					logging.error('Model step failed. This seems like a misconfiguration or bug: %r. This error will not be relayed to the user!',e)
+					logger.log_exc(e)
+					self.failed_steps.append(S)
+					my_status = STEP_STATUS_KO
+			else:
+				my_status = STEP_STATUS_OK
+		
+		try:
+			my_cond = self.step_conditions[S]
+			my_cond.acquire()
+			self.step_status[S]=my_status
+			my_cond.notify_all()
+			my_cond.release()
+		except KeyError,e:
+			logging.info('Step %r is a leaf')
+			pass
+
+	def run(self):
+		if not self.driver.enabled:
+			return
+
+		if (self.driver_kind=="openstack") and (not self.driver.has_openstack):
+			return
+
+		while True:
+			try:
+				error_map_file = getattr(Config(), "error_map_path", XOS_DIR + "/error_map.txt")
+				self.error_mapper = ErrorMapper(error_map_file)
+
+				# Set of whole steps that failed
+				self.failed_steps = []
+
+				# Set of individual objects within steps that failed
+				self.failed_step_objects = set()
+
+				# Set up conditions and step status
+				# This is needed for steps to run in parallel
+				# while obeying dependencies.
+
+				providers = set()
+				for v in self.dependency_graph.values():
+					if (v):
+						providers.update(v)
+
+				self.step_conditions = {}
+				self.step_status = {}
+				for p in list(providers):
+					self.step_conditions[p] = threading.Condition()
+					self.step_status[p] = STEP_STATUS_WORKING
+
+
+				logger.info('Waiting for event')
+				tBeforeWait = time.time()
+				self.wait_for_event(timeout=30)
+				logger.info('Observer woke up')
+
+				# Two passes. One for sync, the other for deletion.
+				for deletion in [False,True]:
+					threads = []
+					logger.info('Deletion=%r...'%deletion)
+					schedule = self.ordered_steps if not deletion else reversed(self.ordered_steps)
+
+					for S in schedule:
+						thread = threading.Thread(target=self.sync, args=(S, deletion))
+
+						logger.info('Deletion=%r...'%deletion)
+						threads.append(thread)
+
+					# Start threads 
+					for t in threads:
+						t.start()
+
+					# Wait for all threads to finish before continuing with the run loop
+					for t in threads:
+						t.join()
+
+				self.save_run_times()
+			except Exception, e:
+				logging.error('Core error. This seems like a misconfiguration or bug: %r. This error will not be relayed to the user!',e)
+				logger.log_exc("Exception in observer run loop")
+				traceback.print_exc()
diff --git a/xos/synchronizers/ec2/event_manager.py b/xos/synchronizers/ec2/event_manager.py
new file mode 100644
index 0000000..fc07f64
--- /dev/null
+++ b/xos/synchronizers/ec2/event_manager.py
@@ -0,0 +1,112 @@
+import threading
+import requests, json
+
+from xos.config import Config, XOS_DIR
+
+import uuid
+import os
+import imp
+import inspect
+import base64
+from fofum import Fofum
+import json
+import traceback
+
+random_client_id=None
+def get_random_client_id():
+    global random_client_id
+
+    if (random_client_id is None) and os.path.exists(XOS_DIR + "/random_client_id"):
+        # try to use the last one we used, if we saved it
+        try:
+            random_client_id = open(XOS_DIR+"/random_client_id","r").readline().strip()
+            print "get_random_client_id: loaded %s" % random_client_id
+        except:
+            print "get_random_client_id: failed to read " + XOS_DIR + "/random_client_id"
+
+    if random_client_id is None:
+        random_client_id = base64.urlsafe_b64encode(os.urandom(12))
+        print "get_random_client_id: generated new id %s" % random_client_id
+
+        # try to save it for later (XXX: could race with another client here)
+        try:
+            open(XOS_DIR + "/random_client_id","w").write("%s\n" % random_client_id)
+        except:
+            print "get_random_client_id: failed to write " + XOS_DIR + "/random_client_id"
+
+    return random_client_id
+
+# decorator that marks dispatachable event methods
+def event(func):
+    setattr(func, 'event', func.__name__)
+    return func
+
+class EventHandler:
+    # This code is currently not in use.
+    def __init__(self):
+        pass
+
+    @staticmethod
+    def get_events():
+        events = []
+        for name in dir(EventHandler):
+            attribute = getattr(EventHandler, name)
+            if hasattr(attribute, 'event'):
+                events.append(getattr(attribute, 'event'))
+        return events
+
+    def dispatch(self, event, *args, **kwds):
+        if hasattr(self, event):
+            return getattr(self, event)(*args, **kwds)
+            
+
+class EventSender:
+    def __init__(self,user=None,clientid=None):
+        try:
+            user = Config().feefie_client_user
+        except:
+            user = 'pl'
+
+        try:
+            clid = Config().feefie_client_id
+        except:
+            clid = get_random_client_id()
+            print "EventSender: no feefie_client_id configured. Using random id %s" % clid
+
+        self.fofum = Fofum(user=user)
+        self.fofum.make(clid)
+
+    def fire(self,**kwargs):
+        kwargs["uuid"] = str(uuid.uuid1())
+        self.fofum.fire(json.dumps(kwargs))
+
+class EventListener:
+    def __init__(self,wake_up=None):
+        self.handler = EventHandler()
+        self.wake_up = wake_up
+
+    def handle_event(self, payload):
+        payload_dict = json.loads(payload)
+
+        if (self.wake_up):
+            self.wake_up()
+
+    def run(self):
+        # This is our unique client id, to be used when firing and receiving events
+        # It needs to be generated once and placed in the config file
+
+        try:
+            user = Config().feefie_client_user
+        except:
+            user = 'pl'
+
+        try:
+            clid = Config().feefie_client_id
+        except:
+            clid = get_random_client_id()
+            print "EventListener: no feefie_client_id configured. Using random id %s" % clid
+
+        f = Fofum(user=user)
+        
+        listener_thread = threading.Thread(target=f.listen_for_event,args=(clid,self.handle_event))
+        listener_thread.start()
diff --git a/xos/synchronizers/ec2/steps/__init__.py b/xos/synchronizers/ec2/steps/__init__.py
new file mode 100644
index 0000000..de7a1fd
--- /dev/null
+++ b/xos/synchronizers/ec2/steps/__init__.py
@@ -0,0 +1,15 @@
+#from .sync_external_routes import SyncExternalRoutes
+#from .sync_network_instances import SyncNetworkInstances
+#from .sync_networks import SyncNetworks
+#from .sync_network_deployments import SyncNetworkDeployments
+#from .sync_site_privileges import SyncSitePrivilege
+#from .sync_slice_memberships import SyncSliceMemberships
+#from .sync_slices import SyncSlices
+#from .sync_instance_ips import SyncInstanceIps
+#from .sync_instances import SyncInstances
+#from .sync_users import SyncUsers
+#from .sync_roles import SyncRoles
+#from .sync_nodes import SyncNodes
+#from .sync_images import SyncImages
+#from .garbage_collector import GarbageCollector
+
diff --git a/xos/synchronizers/ec2/steps/sync_deployments.py b/xos/synchronizers/ec2/steps/sync_deployments.py
new file mode 100644
index 0000000..097a6e9
--- /dev/null
+++ b/xos/synchronizers/ec2/steps/sync_deployments.py
@@ -0,0 +1,25 @@
+import os
+import base64
+from django.db.models import F, Q
+from xos.config import Config
+from ec2_observer.syncstep import SyncStep
+from core.models.site import *
+
+class SyncDeployments(SyncStep):
+    requested_interval=86400
+    provides=[Deployment]
+
+    def fetch_pending(self,deletion):
+        if (deletion):
+            return []
+
+        deployments = Deployment.objects.filter(Q(name="Amazon EC2"))
+        if (not deployments):
+            deployments = [Deployment(name="Amazon EC2")]
+        else:
+            deployments = []
+
+        return deployments
+
+    def sync_record(self, deployment):
+        deployment.save()
diff --git a/xos/synchronizers/ec2/steps/sync_images.py b/xos/synchronizers/ec2/steps/sync_images.py
new file mode 100644
index 0000000..c3dc5a1
--- /dev/null
+++ b/xos/synchronizers/ec2/steps/sync_images.py
@@ -0,0 +1,64 @@
+import os
+import base64
+from django.db.models import F, Q
+from xos.config import Config, XOS_DIR
+from ec2_observer.syncstep import SyncStep
+from core.models.image import Image
+from ec2_observer.awslib import *
+
+
+class SyncImages(SyncStep):
+    provides=[Image]
+    requested_interval=3600
+
+    def fetch_pending(self,deletion):
+        if (deletion):
+            return []
+
+        images = Image.objects.all()
+        image_names = [image.name for image in images]
+       
+        new_images = []
+
+        try:
+            aws_images = json.loads(open(XOS_DIR + '/aws-images').read())
+        except:
+            aws_images = aws_run('ec2 describe-images --owner 099720109477')
+            open(XOS_DIR + '/aws-images','w').write(json.dumps(aws_images))
+
+        
+
+        aws_images=aws_images['Images']
+        aws_images=filter(lambda x:x['ImageType']=='machine',aws_images)[:50]
+
+        names = set([])
+        for aws_image in aws_images:
+            desc_ok = True
+
+            try:
+                desc = aws_image['Description']
+            except:
+                try:
+                    desc = aws_image['ImageLocation']
+                except:
+                    desc_ok = False
+            
+            if (desc_ok):
+                try:
+                    desc_ok =  desc and desc not in names and desc not in image_names and '14.04' in desc
+                except KeyError:
+                    desc_ok = False
+
+            if desc_ok and aws_image['ImageType']=='machine':
+                image = Image(disk_format=aws_image['ImageLocation'],
+                                name=desc,
+                                container_format=aws_image['Hypervisor'],
+                                path=aws_image['ImageId'])
+                new_images.append(image)
+                names.add(image.name)
+
+        #print new_images
+        return new_images
+
+    def sync_record(self, image):
+        image.save()
diff --git a/xos/synchronizers/ec2/steps/sync_instances.py b/xos/synchronizers/ec2/steps/sync_instances.py
new file mode 100644
index 0000000..efab74d
--- /dev/null
+++ b/xos/synchronizers/ec2/steps/sync_instances.py
@@ -0,0 +1,117 @@
+import os
+import json
+import base64
+from django.db.models import F, Q
+from xos.config import Config
+from ec2_observer.syncstep import SyncStep
+from core.models.instance import Instance
+from core.models.slice import SlicePrivilege, SliceDeployments
+from core.models.network import Network, NetworkSlice, NetworkDeployments
+from xos.logger import Logger, logging
+from ec2_observer.awslib import *
+from core.models.site import *
+from core.models.slice import *
+from ec2_observer.creds import *
+import pdb
+
+logger = Logger(level=logging.INFO)
+
+class SyncInstances(SyncStep):
+    provides=[Instance]
+    requested_interval=0
+
+    def fetch_pending(self, deletion):
+        if deletion:
+            object_source = Instance.deleted_objects
+        else:
+            object_source = Instance.objects
+
+        all_instances = object_source.filter(Q(enacted__lt=F('updated')) | Q(enacted=None))
+        my_instances = [] 
+
+        for instance in all_instances:
+            sd = SliceDeployments.objects.filter(Q(slice=instance.slice))
+            if (sd):
+                if (sd.deployment.name=='Amazon EC2'):
+                    my_instances.append(instance)
+            if (instance.node.deployment.name=='Amazon EC2'):
+                my_instances.append(instance)
+        return my_instances
+
+    def delete_record(self, instance):
+        user = instance.creator
+        e = get_creds(user=user, site=user.site)
+        result = aws_run('ec2 terminate-instances --instance-ids=%s'%instance.instance_id, env=e)
+
+    def sync_record(self, instance):
+        logger.info("sync'ing instance:%s deployment:%s " % (instance, instance.node.deployment),extra=instance.tologdict())
+
+        if not instance.instance_id:
+            # public keys
+            slice_memberships = SlicePrivilege.objects.filter(slice=instance.slice)
+            pubkeys = [sm.user.public_key for sm in slice_memberships if sm.user.public_key]
+
+            if instance.creator.public_key:
+                pubkeys.append(instance.creator.public_key)
+
+            if instance.slice.creator.public_key:
+                pubkeys.append(instance.slice.creator.public_key) 
+
+            # netowrks
+            # include all networks available to the slice and/or associated network templates
+            #nics = []
+            #networks = [ns.network for ns in NetworkSlice.objects.filter(slice=instance.slice)]  
+            #network_deployments = NetworkDeployments.objects.filter(network__in=networks, 
+                                                                    #deployment=instance.node.deployment)
+            # Gather private networks first. This includes networks with a template that has
+            # visibility = private and translation = none
+            #for network_deployment in network_deployments:
+            #   if network_deployment.network.template.visibility == 'private' and \
+            #      network_deployment.network.template.translation == 'none': 
+            #       nics.append({'net-id': network_deployment.net_id})
+    
+            # now include network template
+            #network_templates = [network.template.sharedNetworkName for network in networks \
+            #                    if network.template.sharedNetworkName]
+            #for net in driver.shell.quantum.list_networks()['networks']:
+            #   if net['name'] in network_templates: 
+            #       nics.append({'net-id': net['id']}) 
+            # look up image id
+
+            instance_type = instance.node.name.rsplit('.',1)[0]
+
+            # Bail out of we don't have a key
+            key_name = instance.creator.email.lower().replace('@', 'AT').replace('.', '')
+            u = instance.creator
+            s = u.site
+            e = get_creds(user=u, site=s)
+            key_sig = aws_run('ec2 describe-key-pairs', env=e)
+            ec2_keys = key_sig['KeyPairs']
+            key_found = False
+            for key in ec2_keys:
+                if (key['KeyName']==key_name):
+                    key_found = True
+                    break
+
+            if (not key_found):
+                # set backend_status
+                raise Exception('Will not sync instance without key')
+
+            image_id = instance.image.path
+            instance_sig = aws_run('ec2 run-instances --image-id %s --instance-type %s --count 1 --key-name %s --placement AvailabilityZone=%s'%(image_id,instance_type,key_name,instance.node.site.name), env=e)
+            instance.instance_id = instance_sig['Instances'][0]['InstanceId']
+            instance.save()
+            state = instance_sig['Instances'][0]['State']['Code']
+            if (state==16):
+                instance.ip = instance_sig['Instances'][0]['PublicIpAddress']
+                instance.save()
+            else:
+                # This status message should go into backend_status
+                raise Exception('Waiting for instance to start')
+        else:
+            ret = aws_run('ec2 describe-instances --instance-ids %s'%instance.instance_id, env=e)
+            state = ret['Reservations'][0]['Instances'][0]['State']['Code']
+            if (state==16):
+                instance.ip = ret['Reservations'][0]['Instances'][0]['PublicIpAddress']
+                instance.save()
+
diff --git a/xos/synchronizers/ec2/steps/sync_site_deployments.py b/xos/synchronizers/ec2/steps/sync_site_deployments.py
new file mode 100644
index 0000000..ef66783
--- /dev/null
+++ b/xos/synchronizers/ec2/steps/sync_site_deployments.py
@@ -0,0 +1,50 @@
+import os
+import base64
+from django.db.models import F, Q
+from xos.config import Config
+from ec2_observer.syncstep import SyncStep
+from core.models.site import *
+from ec2_observer.awslib import *
+import pdb
+
+class SyncSiteDeployment(SyncStep):
+    requested_interval=86400
+    provides=[SiteDeployment]
+
+    def fetch_pending(self, deletion):
+        if (deletion):
+            return []
+
+        zone_ret = aws_run('ec2 describe-availability-zones')
+        zones = zone_ret['AvailabilityZones']
+        available_sites = [zone['ZoneName'] for zone in zones]
+
+        current_sites = []
+        for s in available_sites:
+            site = Site.objects.filter(Q(name=s))
+            if (site):
+                current_sites.append(site[0])
+
+        # OK not to catch exception
+        # The syncstep should catch it
+        # At any rate, we should not run if there are no deployments
+        deployment = Deployment.objects.filter(Q(name="Amazon EC2"))[0]
+        current_site_deployments = SiteDeployment.objects.filter(Q(deployment=deployment))
+        site_dict = {}
+
+        for sd in current_site_deployments:
+            site_dict[sd.site]=sd
+
+        updated_site_deployments = []
+        for site in current_sites:
+            try:
+                site_record = site_dict[site]
+            except KeyError:
+                sd = SiteDeployment(site=site,deployment=deployment,tenant_id=base64.urlsafe_b64encode(os.urandom(12)))
+                updated_site_deployments.append(sd)
+
+        return updated_site_deployments
+
+
+    def sync_record(self, site_deployment):
+        site_deployment.save()
diff --git a/xos/synchronizers/ec2/steps/sync_sites.py b/xos/synchronizers/ec2/steps/sync_sites.py
new file mode 100644
index 0000000..d139cc5
--- /dev/null
+++ b/xos/synchronizers/ec2/steps/sync_sites.py
@@ -0,0 +1,43 @@
+import os
+import base64
+from django.db.models import F, Q
+from xos.config import Config
+from ec2_observer.syncstep import SyncStep
+from core.models.site import *
+from ec2_observer.awslib import *
+import pdb
+
+class SyncSites(SyncStep):
+    provides=[Site]
+    requested_interval=3600
+
+    def fetch_pending(self, deletion):
+        if (deletion):
+            return []
+
+        deployment = Deployment.objects.filter(Q(name="Amazon EC2"))[0]
+        current_site_deployments = SiteDeployment.objects.filter(Q(deployment=deployment))
+
+        zone_ret = aws_run('ec2 describe-availability-zones')
+        zones = zone_ret['AvailabilityZones']
+
+        available_sites = [zone['ZoneName'] for zone in zones]
+        site_names = [sd.site.name for sd in current_site_deployments]
+
+        new_site_names = list(set(available_sites) - set(site_names))
+
+        new_sites = []
+        for s in new_site_names:
+            site = Site(name=s,
+                        login_base=s,
+                        site_url="www.amazon.com",
+                        enabled=True,
+                        is_public=True,
+                        abbreviated_name=s)
+            new_sites.append(site)
+        
+        return new_sites
+
+    def sync_record(self, site):
+        site.save()
+
diff --git a/xos/synchronizers/ec2/steps/sync_users.py b/xos/synchronizers/ec2/steps/sync_users.py
new file mode 100644
index 0000000..5fe70c7
--- /dev/null
+++ b/xos/synchronizers/ec2/steps/sync_users.py
@@ -0,0 +1,52 @@
+import os
+import base64
+import random
+import time
+from datetime import datetime 
+from django.db.models import F, Q
+from xos.config import Config
+from ec2_observer.syncstep import SyncStep
+from core.models.user import User
+from core.models.site import *
+from ec2_observer.awslib import *
+from ec2_observer.creds import *
+import pdb
+
+class SyncUsers(SyncStep):
+    provides=[User]
+    requested_interval=0
+
+    def fetch_pending(self, deletion):
+        if (deletion):
+            return []
+
+        users = User.objects.filter(Q(enacted__lt=F('updated')) | Q(enacted=None))
+        
+        keys = []
+        creds = []
+        for u in users:
+            e = get_creds(user=u, site=u.site)
+            key_sig = aws_run('ec2 describe-key-pairs', env=e)
+            ec2_keys = key_sig['KeyPairs']
+            creds.append(e)
+            keys.append(ec2_keys)
+        else:
+            ec2_keys = []
+
+        for user,ec2_keys,e in zip(users,keys,creds):
+            if (user.public_key): 
+                key_name = user.email.lower().replace('@', 'AT').replace('.', '')
+                key_found = False
+
+                for key in ec2_keys:
+                    if (key['KeyName']==key_name):
+                        key_found = True
+                        break
+
+                if (not key_found):
+                    aws_run('ec2 import-key-pair --key-name %s --public-key-material "%s"'%(key_name, user.public_key),env=e)
+                    
+        return users
+
+    def sync_record(self, node):
+        node.save()
diff --git a/xos/synchronizers/ec2/syncstep.py b/xos/synchronizers/ec2/syncstep.py
new file mode 100644
index 0000000..3a31cb6
--- /dev/null
+++ b/xos/synchronizers/ec2/syncstep.py
@@ -0,0 +1,101 @@
+import os
+import base64
+from datetime import datetime
+
+from django.db.models import F, Q
+
+from xos.config import Config
+from xos.logger import Logger, logging
+from synchronizers.base.steps import *
+
+logger = Logger(level=logging.INFO)
+
+class FailedDependency(Exception):
+    pass
+
+class SyncStep:
+    """ A XOS Sync step. 
+
+    Attributes:
+        psmodel        Model name the step synchronizes 
+        dependencies    list of names of models that must be synchronized first if the current model depends on them
+    """ 
+    slow=False
+    def get_prop(self, prop):
+        try:
+            sync_config_dir = Config().sync_config_dir
+        except:
+            sync_config_dir = '/etc/xos/sync'    # XXX TODO: update path
+        prop_config_path = '/'.join(sync_config_dir,self.name,prop)
+        return open(prop_config_path).read().rstrip()
+
+    def __init__(self, **args):
+        """Initialize a sync step
+           Keyword arguments:
+                   name -- Name of the step
+                provides -- XOS models sync'd by this step
+        """
+        dependencies = []
+        self.driver = args.get('driver')
+        self.error_map = args.get('error_map')
+
+        try:
+            self.soft_deadline = int(self.get_prop('soft_deadline_seconds'))
+        except:
+            self.soft_deadline = 5 # 5 seconds
+
+        return
+
+    def fetch_pending(self, deletion=False):
+        # This is the most common implementation of fetch_pending
+        # Steps should override it if they have their own logic
+        # for figuring out what objects are outstanding.
+        main_obj = self.provides[0]
+        if (not deletion):
+            objs = main_obj.objects.filter(Q(enacted__lt=F('updated')) | Q(enacted=None))
+        else:
+            objs = main_obj.deleted_objects.all()
+
+        return objs
+        #return Instance.objects.filter(ip=None)
+    
+    def check_dependencies(self, obj, failed):
+        for dep in self.dependencies:
+            peer_name = dep[0].lower() + dep[1:]    # django names are camelCased with the first letter lower
+            peer_object = getattr(obj, peer_name)
+            
+            # peer_object can be None, and if so there
+            # is no object-level dependency
+            if (peer_object and peer_object.pk==failed.pk):
+                raise FailedDependency
+
+    def call(self, failed=[], deletion=False):
+        pending = self.fetch_pending(deletion)
+        for o in pending:
+            try:
+                for f in failed:
+                    self.check_dependencies(o,f) # Raises exception if failed
+                if (deletion):
+                    self.delete_record(o)
+                    o.delete(purge=True)
+                else:
+                    self.sync_record(o)
+                    o.enacted = datetime.now() # Is this the same timezone? XXX
+                    o.backend_status = "OK"
+                    o.save(update_fields=['enacted'])
+            except Exception,e:
+                try:
+                    o.backend_status = self.error_map.map(str(e))
+                except:
+                    o.backend_status = str(e)
+
+                if (o.pk):
+                    o.save(update_fields=['backend_status'])
+
+                logger.log_exc("sync step failed!",extra=o.tologdict())
+                failed.append(o)
+
+        return failed
+
+    def __call__(self, **args):
+        return self.call(**args)
diff --git a/xos/synchronizers/ec2/toposort.py b/xos/synchronizers/ec2/toposort.py
new file mode 100644
index 0000000..c0ec779
--- /dev/null
+++ b/xos/synchronizers/ec2/toposort.py
@@ -0,0 +1,99 @@
+#!/usr/bin/env python
+
+import time
+import traceback
+import commands
+import threading
+import json
+import pdb
+
+from datetime import datetime
+from collections import defaultdict
+
+# Assumes that there are no empty dependencies
+# in the graph. E.g. Foo -> []
+def dfs(graph, visit):
+	nodes = graph.keys()
+	edge_nodes = set()
+
+	for n in nodes:
+		edge_nodes|=set(graph[n])
+
+	sinks = list(edge_nodes - set(nodes))
+	sources = list(set(nodes) - edge_nodes)
+	
+	nodes.extend(sinks)
+
+	visited = set(sources)
+	stack = sources
+	while stack:
+		current = stack.pop()
+		visit(current)
+		for node in graph[current]:
+			if node not in visited:
+				stack.append(node)
+				visited.add(node)
+
+	return sources
+
+# Topological sort
+# Notes:
+# - Uses a stack instead of recursion
+# - Forfeits optimization involving tracking currently visited nodes
+def toposort(g, steps=None):
+	# Get set of all nodes, including those without outgoing edges
+	keys = set(g.keys())
+	values = set({})
+	for v in g.values():
+		values=values | set(v)
+	
+	all_nodes=list(keys|values)
+	if (not steps):
+		steps = all_nodes
+
+	# Final order
+	order = []
+
+	# DFS stack, not using recursion
+	stack = []
+
+	# Unmarked set
+	unmarked = all_nodes
+
+	# visiting = [] - skip, don't expect 1000s of nodes, |E|/|V| is small
+
+	while unmarked:
+		stack.insert(0,unmarked[0]) # push first unmarked
+
+		while (stack):
+			n = stack[0]
+			add = True
+			try:
+				for m in g[n]:
+					if (m in unmarked):
+						if (m not in stack):
+							add = False
+							stack.insert(0,m)
+						else:
+							# Should not happen, if so there's a loop
+							print 'Loop at %s'%m
+			except KeyError:
+				pass
+			if (add):
+				if (n in steps):
+					order.append(n)
+				item = stack.pop(0)
+				unmarked.remove(item)
+
+	noorder = list(set(steps) - set(order))
+	return order + noorder
+
+def main():
+	graph_file=open('xos.deps').read()
+	g = json.loads(graph_file)
+	print toposort(g)
+
+if (__name__=='__main__'):
+	main()
+
+#print toposort({'a':'b','b':'c','c':'d','d':'c'},['d','c','b','a'])
diff --git a/xos/synchronizers/ec2/xos.deps b/xos/synchronizers/ec2/xos.deps
new file mode 100644
index 0000000..6abf765
--- /dev/null
+++ b/xos/synchronizers/ec2/xos.deps
@@ -0,0 +1,47 @@
+{
+    "Node": [
+        "Site", 
+        "Deployment"
+    ], 
+    "Slice": [
+        "Site"
+    ], 
+    "ReservedResource": [
+        "Instance"
+    ], 
+    "SliceMembership": [
+        "User", 
+        "Slice", 
+        "Role"
+    ], 
+    "NetworkSlice": [
+        "Network", 
+        "Slice"
+    ], 
+    "Tag": [
+        "Project"
+    ], 
+    "User": [
+        "Site"
+    ], 
+    "SliceTag": [
+        "Slice"
+    ], 
+    "Reservation": [
+        "Slice"
+    ], 
+    "NetworkInstance": [
+        "Network", 
+        "Instance"
+    ], 
+    "SitePrivilege": [
+        "User", 
+        "Site", 
+        "Role"
+    ], 
+    "Instance": [
+        "Image", 
+        "Slice", 
+        "Node"
+    ]
+}
diff --git a/xos/synchronizers/exampleservice_old/exampleservice-synchronizer.py b/xos/synchronizers/exampleservice_old/exampleservice-synchronizer.py
new file mode 100644
index 0000000..90d2c98
--- /dev/null
+++ b/xos/synchronizers/exampleservice_old/exampleservice-synchronizer.py
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+
+# Runs the standard XOS synchronizer
+
+import importlib
+import os
+import sys
+
+synchronizer_path = os.path.join(os.path.dirname(
+    os.path.realpath(__file__)), "../../synchronizers/base")
+sys.path.append(synchronizer_path)
+mod = importlib.import_module("xos-synchronizer")
+mod.main()
+
diff --git a/xos/synchronizers/exampleservice_old/exampleservice_config b/xos/synchronizers/exampleservice_old/exampleservice_config
new file mode 100644
index 0000000..7e59fdd
--- /dev/null
+++ b/xos/synchronizers/exampleservice_old/exampleservice_config
@@ -0,0 +1,24 @@
+# Required by XOS
+[db]
+name=xos
+user=postgres
+password=password
+host=localhost
+port=5432
+
+# Required by XOS
+[api]
+nova_enabled=True
+
+# Sets options for the synchronizer
+[observer]
+name=exampleservice
+dependency_graph=/opt/xos/synchronizers/exampleservice/model-deps
+steps_dir=/opt/xos/synchronizers/exampleservice/steps
+sys_dir=/opt/xos/synchronizers/exampleservice/sys
+logfile=/var/log/xos_backend.log
+pretend=False
+backoff_disabled=True
+save_ansible_output=True
+proxy_ssh=False
+
diff --git a/xos/synchronizers/exampleservice_old/model-deps b/xos/synchronizers/exampleservice_old/model-deps
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/xos/synchronizers/exampleservice_old/model-deps
@@ -0,0 +1 @@
+{}
diff --git a/xos/synchronizers/exampleservice_old/steps/exampletenant_playbook.yaml b/xos/synchronizers/exampleservice_old/steps/exampletenant_playbook.yaml
new file mode 100644
index 0000000..89e4617
--- /dev/null
+++ b/xos/synchronizers/exampleservice_old/steps/exampletenant_playbook.yaml
@@ -0,0 +1,16 @@
+---
+# exampletenant_playbook
+
+- hosts: "{{ instance_name }}"
+  connection: ssh
+  user: ubuntu
+  sudo: yes
+  gather_facts: no
+  vars:
+    - tenant_message: "{{ tenant_message }}"
+    - service_message: "{{ service_message }}"
+
+  roles:
+    - install_apache
+    - create_index
+
diff --git a/xos/synchronizers/exampleservice_old/steps/roles/create_index/tasks/main.yml b/xos/synchronizers/exampleservice_old/steps/roles/create_index/tasks/main.yml
new file mode 100644
index 0000000..91c6029
--- /dev/null
+++ b/xos/synchronizers/exampleservice_old/steps/roles/create_index/tasks/main.yml
@@ -0,0 +1,7 @@
+---
+
+- name: Write index.html file to apache document root
+  template:
+    src=index.html.j2
+    dest=/var/www/html/index.html
+
diff --git a/xos/synchronizers/exampleservice_old/steps/roles/create_index/templates/index.html.j2 b/xos/synchronizers/exampleservice_old/steps/roles/create_index/templates/index.html.j2
new file mode 100644
index 0000000..9cec084
--- /dev/null
+++ b/xos/synchronizers/exampleservice_old/steps/roles/create_index/templates/index.html.j2
@@ -0,0 +1,4 @@
+ExampleService
+ Service Message: "{{ service_message }}"
+ Tenant Message: "{{ tenant_message }}"
+
diff --git a/xos/synchronizers/exampleservice_old/steps/roles/install_apache/tasks/main.yml b/xos/synchronizers/exampleservice_old/steps/roles/install_apache/tasks/main.yml
new file mode 100644
index 0000000..d9a155c
--- /dev/null
+++ b/xos/synchronizers/exampleservice_old/steps/roles/install_apache/tasks/main.yml
@@ -0,0 +1,7 @@
+---
+
+- name: Install apache using apt
+  apt:
+    name=apache2
+    update_cache=yes
+
diff --git a/xos/synchronizers/exampleservice_old/steps/sync_exampletenant.py b/xos/synchronizers/exampleservice_old/steps/sync_exampletenant.py
new file mode 100644
index 0000000..fbde96f
--- /dev/null
+++ b/xos/synchronizers/exampleservice_old/steps/sync_exampletenant.py
@@ -0,0 +1,55 @@
+import os
+import sys
+from django.db.models import Q, F
+from services.exampleservice.models import ExampleService, ExampleTenant
+from synchronizers.base.SyncInstanceUsingAnsible import SyncInstanceUsingAnsible
+
+parentdir = os.path.join(os.path.dirname(__file__), "..")
+sys.path.insert(0, parentdir)
+
+class SyncExampleTenant(SyncInstanceUsingAnsible):
+
+    provides = [ExampleTenant]
+
+    observes = ExampleTenant
+
+    requested_interval = 0
+
+    template_name = "exampletenant_playbook.yaml"
+
+    service_key_name = "/opt/xos/synchronizers/exampleservice/exampleservice_private_key"
+
+    def __init__(self, *args, **kwargs):
+        super(SyncExampleTenant, self).__init__(*args, **kwargs)
+
+    def fetch_pending(self, deleted):
+
+        if (not deleted):
+            objs = ExampleTenant.get_tenant_objects().filter(
+                Q(enacted__lt=F('updated')) | Q(enacted=None), Q(lazy_blocked=False))
+        else:
+            # If this is a deletion we get all of the deleted tenants..
+            objs = ExampleTenant.get_deleted_tenant_objects()
+
+        return objs
+
+    def get_exampleservice(self, o):
+        if not o.provider_service:
+            return None
+
+        exampleservice = ExampleService.get_service_objects().filter(id=o.provider_service.id)
+
+        if not exampleservice:
+            return None
+
+        return exampleservice[0]
+
+    # Gets the attributes that are used by the Ansible template but are not
+    # part of the set of default attributes.
+    def get_extra_attributes(self, o):
+        fields = {}
+        fields['tenant_message'] = o.tenant_message
+        exampleservice = self.get_exampleservice(o)
+        fields['service_message'] = exampleservice.service_message
+        return fields
+
diff --git a/xos/synchronizers/hpc/Makefile b/xos/synchronizers/hpc/Makefile
new file mode 100644
index 0000000..4a03bd4
--- /dev/null
+++ b/xos/synchronizers/hpc/Makefile
@@ -0,0 +1,10 @@
+hpcobserver.tar.gz:
+	rm -rf BUILD/hpc_observer
+	mkdir -p BUILD/hpc_observer
+	mkdir -p BUILD/hpc_observer/steps
+	mkdir -p BUILD/hpc_observer/deleters
+	cp hpclib.py hpc_observer_config run.sh start.sh  stop.sh BUILD/hpc_observer/
+	cp steps/*.py BUILD/hpc_observer/steps/
+	cp deleters/*.py BUILD/hpc_observer/deleters/
+	mkdir -p TARS
+	cd BUILD; tar -czf ../TARS/hpc_observer.tar.gz hpc_observer
diff --git a/xos/synchronizers/hpc/fsck.py b/xos/synchronizers/hpc/fsck.py
new file mode 100644
index 0000000..448bfb7
--- /dev/null
+++ b/xos/synchronizers/hpc/fsck.py
@@ -0,0 +1,79 @@
+#!/usr/bin/env python
+import argparse
+import imp
+import inspect
+import os
+import sys
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
+sys.path.append("/opt/xos")
+from xos.config import Config, DEFAULT_CONFIG_FN, XOS_DIR
+from xos.logger import Logger, logging
+from synchronizers.base.syncstep import SyncStep
+
+try:
+    from django import setup as django_setup # django 1.7
+except:
+    django_setup = False
+
+logger = Logger(level=logging.INFO)
+
+class XOSConsistencyCheck:
+	def __init__(self):
+                self.sync_steps = []
+		self.load_sync_step_modules()
+
+	def load_sync_step_modules(self, step_dir=None):
+		if step_dir is None:
+			if hasattr(Config(), "observer_steps_dir"):
+				step_dir = Config().observer_steps_dir
+			else:
+				step_dir = XOS_DIR+"/observer/steps"
+
+		for fn in os.listdir(step_dir):
+			pathname = os.path.join(step_dir,fn)
+			if os.path.isfile(pathname) and fn.endswith(".py") and (fn!="__init__.py"):
+				module = imp.load_source(fn[:-3],pathname)
+				for classname in dir(module):
+					c = getattr(module, classname, None)
+
+					# make sure 'c' is a descendent of SyncStep and has a
+					# provides field (this eliminates the abstract base classes
+					# since they don't have a provides)
+
+					if inspect.isclass(c) and issubclass(c, SyncStep) and hasattr(c,"provides") and (c not in self.sync_steps):
+						self.sync_steps.append(c)
+		logger.info('loaded sync steps: %s' % ",".join([x.__name__ for x in self.sync_steps]))
+
+        def run(self):
+            updated = True
+            while updated:
+                updated = False
+
+                for step in self.sync_steps:
+                    if hasattr(step, "consistency_check"):
+                        updated = updated or step(driver=None).consistency_check()
+
+                if updated:
+                    logger.info('re-running consistency checks because something changed')
+
+def main():
+    if not "-C" in sys.argv:
+        print >> sys.stderr, "You probably wanted to use -C " + XOS_DIR + "/hpc_observer/hpc_observer_config"
+
+    # Generate command line parser
+    parser = argparse.ArgumentParser(usage='%(prog)s [options]')
+    # smbaker: util/config.py parses sys.argv[] directly to get config file name; include the option here to avoid
+    #   throwing unrecognized argument exceptions
+    parser.add_argument('-C', '--config', dest='config_file', action='store', default=DEFAULT_CONFIG_FN,
+                        help='Name of config file.')
+    args = parser.parse_args()
+
+    if django_setup: # 1.7
+        django_setup()
+
+    cc = XOSConsistencyCheck()
+    cc.run()
+
+if __name__ == '__main__':
+    main()
+
diff --git a/xos/synchronizers/hpc/hpc-synchronizer.py b/xos/synchronizers/hpc/hpc-synchronizer.py
new file mode 100755
index 0000000..84bec4f
--- /dev/null
+++ b/xos/synchronizers/hpc/hpc-synchronizer.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+# This imports and runs ../../xos-observer.py
+
+import importlib
+import os
+import sys
+observer_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),"../../synchronizers/base")
+sys.path.append(observer_path)
+mod = importlib.import_module("xos-synchronizer")
+mod.main()
diff --git a/xos/synchronizers/hpc/hpc_synchronizer_config b/xos/synchronizers/hpc/hpc_synchronizer_config
new file mode 100644
index 0000000..9d4e70a
--- /dev/null
+++ b/xos/synchronizers/hpc/hpc_synchronizer_config
@@ -0,0 +1,36 @@
+
+[plc]
+name=plc
+deployment=VICCI
+
+[db]
+name=xos
+user=postgres
+password=password
+host=localhost
+port=5432
+
+[api]
+host=128.112.171.237
+port=8000
+ssl_key=None
+ssl_cert=None
+ca_ssl_cert=None
+ratelimit_enabled=0
+omf_enabled=0
+mail_support_address=support@localhost
+nova_enabled=True
+
+[observer]
+name=hpc
+dependency_graph=/opt/xos/synchronizers/hpc/model-deps
+steps_dir=/opt/xos/synchronizers/hpc/steps
+deleters_dir=/opt/xos/synchronizers/hpc/deleters
+log_file=console
+#/var/log/hpc.log
+driver=None
+#cmi_hostname=openclouddev0.internet2.edu
+
+[feefie]
+client_id='vicci_dev_central'
+user_id='pl'
diff --git a/xos/synchronizers/hpc/hpc_watcher.py b/xos/synchronizers/hpc/hpc_watcher.py
new file mode 100644
index 0000000..d2efdcc
--- /dev/null
+++ b/xos/synchronizers/hpc/hpc_watcher.py
@@ -0,0 +1,629 @@
+"""
+    hpc_watcher.py
+
+    Daemon to watch the health of HPC and RR instances.
+
+    This deamon uses HpcHealthCheck objects in the Data Model to conduct
+    periodic tests of HPC and RR nodes. Two types of Health Checks are
+    supported:
+
+       kind="dns": checks the request routers to make sure that a DNS
+         name is resolveable and returns the right kind of records.
+
+         resource_name should be set to the domain name to lookup.
+
+         result_contains is option and can be used to hold "A", "CNAME", or
+            a particular address or hostname that should be contained in the
+            query's answer.
+
+       kind="http": checks the hpc nodes to make sure that a URL can be
+         retrieved from the node.
+
+         resource_name should be set to the HostName:Url to fetch. For
+         example, cdn-stream.htm.fiu.edu:/hft2441/intro.mp4
+
+     In addition to the above, HPC heartbeat probes are conducted, similar to
+     the ones that dnsredir conducts.
+
+     The results of health checks are stored in a tag attached to the Instance
+     the healthcheck was conducted against. If all healthchecks of a particular
+     variety were successful for a instance, then "success" will be stored in
+     the tag. Otherwise, the first healthcheck to fail will be stored in the
+     tag.
+
+     Ubuntu prereqs:
+         apt-get install python-pycurl
+         pip install dnslib
+"""
+
+import os
+import socket
+import sys
+sys.path.append("/opt/xos")
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
+import django
+from django.contrib.contenttypes.models import ContentType
+from core.models import *
+from services.hpc.models import *
+from services.requestrouter.models import *
+django.setup()
+import time
+import pycurl
+import traceback
+import json
+from StringIO import StringIO
+
+from dnslib.dns import DNSRecord,DNSHeader,DNSQuestion,QTYPE
+from dnslib.digparser import DigParser
+
+from threading import Thread, Condition
+
+"""
+from dnslib import *
+q = DNSRecord(q=DNSQuestion("cdn-stream.htm.fiu.edu"))
+a_pkt = q.send("150.135.65.10", tcp=False, timeout=10)
+a = DNSRecord.parse(a_pkt)
+
+from dnslib import *
+q = DNSRecord(q=DNSQuestion("onlab.vicci.org"))
+a_pkt = q.send("150.135.65.10", tcp=False, timeout=10)
+a = DNSRecord.parse(a_pkt)
+"""
+
+class WorkQueue:
+    def __init__(self):
+        self.job_cv = Condition()
+        self.jobs = []
+        self.result_cv = Condition()
+        self.results = []
+        self.outstanding = 0
+
+    def get_job(self):
+        self.job_cv.acquire()
+        while not self.jobs:
+            self.job_cv.wait()
+        result = self.jobs.pop()
+        self.job_cv.release()
+        return result
+
+    def submit_job(self, job):
+        self.job_cv.acquire()
+        self.jobs.append(job)
+        self.job_cv.notify()
+        self.job_cv.release()
+        self.outstanding = self.outstanding + 1
+
+    def get_result(self):
+        self.result_cv.acquire()
+        while not self.results:
+            self.result_cv.wait()
+        result = self.results.pop()
+        self.result_cv.release()
+        self.outstanding = self.outstanding - 1
+        return result
+
+    def submit_result(self, result):
+        self.result_cv.acquire()
+        self.results.append(result)
+        self.result_cv.notify()
+        self.result_cv.release()
+
+class DnsResolver(Thread):
+    def __init__(self, queue):
+        Thread.__init__(self)
+        self.queue = queue
+        self.daemon = True
+        self.start()
+
+    def run(self):
+        while True:
+            job = self.queue.get_job()
+            self.handle_job(job)
+            self.queue.submit_result(job)
+
+    def handle_job(self, job):
+        domain = job["domain"]
+        server = job["server"]
+        port = job["port"]
+        result_contains = job.get("result_contains", None)
+
+        try:
+            q = DNSRecord(q=DNSQuestion(domain)) #, getattr(QTYPE,"A")))
+
+            a_pkt = q.send(server, port, tcp=False, timeout=10)
+            a = DNSRecord.parse(a_pkt)
+
+            found_record = False
+            for record in a.rr:
+                if (not result_contains):
+                    QTYPE_A = getattr(QTYPE,"A")
+                    QTYPE_CNAME = getattr(QTYPE, "CNAME")
+                    if ((record.rtype==QTYPE_A) or (record.qtype==QTYPE_CNAME)):
+                        found_record = True
+                else:
+                    tmp = QTYPE.get(record.rtype) + str(record.rdata)
+                    if (result_contains in tmp):
+                        found_record = True
+
+            if not found_record:
+                if result_contains:
+                    job["status"] =  "%s,No %s records" % (domain, result_contains)
+                else:
+                    job["status"] =  "%s,No A or CNAME records" % domain
+
+                return
+
+        except Exception, e:
+            job["status"] = "%s,Exception: %s" % (domain, str(e))
+            return
+
+        job["status"] = "success"
+
+class HpcHeartbeat(Thread):
+    def __init__(self, queue):
+        Thread.__init__(self)
+        self.queue = queue
+        self.daemon = True
+        self.start()
+
+    def run(self):
+        while True:
+            job = self.queue.get_job()
+            self.handle_job(job)
+            self.queue.submit_result(job)
+
+    def curl_error_message(self, e):
+        if e.args[0] == 6:
+            return "couldn't resolve host"
+        if e.args[0] == 7:
+            return "failed to connect"
+        return "curl error %d" % e.args[0]
+
+    def handle_job(self, job):
+        server = job["server"]
+        port = job["port"]
+
+        try:
+            buffer = StringIO()
+            c = pycurl.Curl()
+
+            c.setopt(c.URL, "http://%s:%s/heartbeat" % (server, port))
+            c.setopt(c.WRITEDATA, buffer)
+            c.setopt(c.HTTPHEADER, ['host: hpc-heartbeat', 'X-heartbeat: 1'])
+            c.setopt(c.TIMEOUT, 10)
+            c.setopt(c.CONNECTTIMEOUT, 10)
+            c.setopt(c.NOSIGNAL, 1)
+
+            try:
+                c.perform()
+                response_code = c.getinfo(c.RESPONSE_CODE)
+            except Exception, e:
+                #traceback.print_exc()
+                job["status"] = self.curl_error_message(e)
+                return
+            finally:
+                c.close()
+
+            if response_code != 200:
+                job["status"] = "error response %d" % response_code
+                return
+
+        except Exception, e:
+            job["status"] = "Exception: %s" % str(e)
+            return
+
+        job["status"] = "success"
+
+class HpcFetchUrl(Thread):
+    def __init__(self, queue):
+        Thread.__init__(self)
+        self.queue = queue
+        self.daemon = True
+        self.start()
+
+    def run(self):
+        while True:
+            job = self.queue.get_job()
+            self.handle_job(job)
+            self.queue.submit_result(job)
+
+    def curl_error_message(self, e):
+        if e.args[0] == 6:
+            return "couldn't resolve host"
+        if e.args[0] == 7:
+            return "failed to connect"
+        return "curl error %d" % e.args[0]
+
+    def handle_job(self, job):
+        server = job["server"]
+        port = job["port"]
+        url = job["url"]
+        domain = job["domain"]
+
+        def progress(download_t, download_d, upload_t, upload_d):
+            # limit download size to a megabyte
+            if (download_d > 1024*1024):
+                return 1
+            else:
+                return 0
+
+        try:
+            buffer = StringIO()
+            c = pycurl.Curl()
+
+            c.setopt(c.URL, "http://%s:%s/%s" % (server, port, url))
+            c.setopt(c.WRITEDATA, buffer)
+            c.setopt(c.HTTPHEADER, ['host: ' + domain])
+            c.setopt(c.TIMEOUT, 10)
+            c.setopt(c.CONNECTTIMEOUT, 10)
+            c.setopt(c.NOSIGNAL, 1)
+            c.setopt(c.NOPROGRESS, 0)
+            c.setopt(c.PROGRESSFUNCTION, progress)
+
+            try:
+                try:
+                    c.perform()
+                except Exception, e:
+                    # prevent callback abort from raising exception
+                    if (e.args[0] != pycurl.E_ABORTED_BY_CALLBACK):
+                        raise
+                response_code = c.getinfo(c.RESPONSE_CODE)
+                bytes_downloaded = int(c.getinfo(c.SIZE_DOWNLOAD))
+                total_time = float(c.getinfo(c.TOTAL_TIME))
+            except Exception, e:
+                #traceback.print_exc()
+                job["status"] = self.curl_error_message(e)
+                return
+            finally:
+                c.close()
+
+            if response_code != 200:
+                job["status"] = "error response %s" %  str(response_code)
+                return
+
+        except Exception, e:
+            #traceback.print_exc()
+            job["status"] = "Exception: %s" % str(e)
+            return
+
+        job["status"] = "success"
+        job["bytes_downloaded"] = bytes_downloaded
+        job["total_time"] = total_time
+
+class WatcherWorker(Thread):
+    def __init__(self, queue):
+        Thread.__init__(self)
+        self.queue = queue
+        self.daemon = True
+        self.start()
+
+    def run(self):
+        while True:
+            job = self.queue.get_job()
+            self.handle_job(job)
+            self.queue.submit_result(job)
+
+    def curl_error_message(self, e):
+        if e.args[0] == 6:
+            return "couldn't resolve host"
+        if e.args[0] == 7:
+            return "failed to connect"
+        return "curl error %d" % e.args[0]
+
+    def handle_job(self, job):
+        server = job["server"]
+        port = job["port"]
+
+        try:
+            buffer = StringIO()
+            c = pycurl.Curl()
+
+            c.setopt(c.URL, "http://%s:%s/" % (server, port))
+            c.setopt(c.WRITEDATA, buffer)
+            c.setopt(c.TIMEOUT, 10)
+            c.setopt(c.CONNECTTIMEOUT, 10)
+            c.setopt(c.NOSIGNAL, 1)
+
+            try:
+                c.perform()
+                response_code = c.getinfo(c.RESPONSE_CODE)
+            except Exception, e:
+                #traceback.print_exc()
+                job["status"] = json.dumps( {"status": self.curl_error_message(e)} )
+                return
+            finally:
+                c.close()
+
+            if response_code != 200:
+                job["status"] = json.dumps( {"status": "error response %d" % response_code} )
+                return
+
+            d = json.loads(buffer.getvalue())
+            d["status"] = "success";
+            job["status"] = json.dumps(d)
+
+        except Exception, e:
+            job["status"] = json.dumps( {"status": "Exception: %s" % str(e)} )
+            return
+
+class BaseWatcher(Thread):
+    def __init__(self):
+        Thread.__init__(self)
+        self.daemon = True
+
+    def get_public_ip(self, service, instance):
+        network_name = None
+        if "hpc" in instance.slice.name:
+            network_name = getattr(service, "watcher_hpc_network", None)
+        elif "demux" in instance.slice.name:
+            network_name = getattr(service, "watcher_dnsdemux_network", None)
+        elif "redir" in instance.slice.name:
+            network_name = getattr(service, "watcher_dnsredir_network", None)
+
+        if network_name and network_name.lower()=="nat":
+            return None
+
+        if (network_name is None) or (network_name=="") or (network_name.lower()=="public"):
+            return instance.get_public_ip()
+
+        for ns in instance.ports.all():
+            if (ns.ip) and (ns.network.name==network_name):
+                return ns.ip
+
+        raise ValueError("Couldn't find network %s" % str(network_name))
+
+    def set_status(self, instance, service, kind, msg, check_error=True):
+        #print instance.node.name, kind, msg
+        if check_error:
+            instance.has_error = (msg!="success")
+
+        instance_type = ContentType.objects.get_for_model(instance)
+
+        t = Tag.objects.filter(service=service, name=kind+".msg", content_type__pk=instance_type.id, object_id=instance.id)
+        if t:
+            t=t[0]
+            if (t.value != msg):
+                t.value = msg
+                t.save()
+        else:
+            Tag(service=service, name=kind+".msg", content_object = instance, value=msg).save()
+
+        t = Tag.objects.filter(service=service, name=kind+".time", content_type__pk=instance_type.id, object_id=instance.id)
+        if t:
+            t=t[0]
+            t.value = str(time.time())
+            t.save()
+        else:
+            Tag(service=service, name=kind+".time", content_object = instance, value=str(time.time())).save()
+
+    def get_service_slices(self, service, kind=None):
+        try:
+            slices = service.slices.all()
+        except:
+            # buggy data model
+            slices = service.service.all()
+
+        if kind:
+            return [x for x in slices if (kind in x.name)]
+        else:
+            return list(slices)
+
+class RRWatcher(BaseWatcher):
+    def __init__(self):
+        BaseWatcher.__init__(self)
+
+        self.resolver_queue = WorkQueue()
+        for i in range(0,10):
+            DnsResolver(queue = self.resolver_queue)
+
+    def check_request_routers(self, service, instances):
+        for instance in instances:
+            instance.has_error = False
+
+            try:
+                ip = self.get_public_ip(service, instance)
+            except Exception, e:
+                self.set_status(instance, service, "watcher.DNS", "exception: %s" % str(e))
+                continue
+            if not ip:
+                try:
+                    ip = socket.gethostbyname(instance.node.name)
+                except:
+                    self.set_status(instance, service, "watcher.DNS", "dns resolution failure")
+                    continue
+
+            if not ip:
+                self.set_status(instance, service, "watcher.DNS", "no IP address")
+                continue
+
+            checks = HpcHealthCheck.objects.filter(kind="dns")
+            if not checks:
+                self.set_status(instance, service, "watcher.DNS", "no DNS HealthCheck tests configured")
+
+            for check in checks:
+                self.resolver_queue.submit_job({"domain": check.resource_name, "server": ip, "port": 53, "instance": instance, "result_contains": check.result_contains})
+
+        while self.resolver_queue.outstanding > 0:
+            result = self.resolver_queue.get_result()
+            instance = result["instance"]
+            if (result["status"]!="success") and (not instance.has_error):
+                self.set_status(instance, service, "watcher.DNS", result["status"])
+
+        for instance in instances:
+            if not instance.has_error:
+                self.set_status(instance, service, "watcher.DNS", "success")
+
+    def run_once(self):
+        for hpcService in HpcService.objects.all():
+            for slice in self.get_service_slices(hpcService, "dnsdemux"):
+                self.check_request_routers(hpcService, slice.instances.all())
+
+        for rrService in RequestRouterService.objects.all():
+            for slice in self.get_service_slices(rrService, "dnsdemux"):
+                self.check_request_routers(rrService, slice.instances.all())
+
+    def run(self):
+        while True:
+            self.run_once()
+            time.sleep(10)
+
+            django.db.reset_queries()
+
+class HpcProber(BaseWatcher):
+    def __init__(self):
+        BaseWatcher.__init__(self)
+
+        self.heartbeat_queue = WorkQueue()
+        for i in range(0, 10):
+            HpcHeartbeat(queue = self.heartbeat_queue)
+
+    def probe_hpc(self, service, instances):
+        for instance in instances:
+            instance.has_error = False
+
+            self.heartbeat_queue.submit_job({"server": instance.node.name, "port": 8009, "instance": instance})
+
+        while self.heartbeat_queue.outstanding > 0:
+            result = self.heartbeat_queue.get_result()
+            instance = result["instance"]
+            if (result["status"]!="success") and (not instance.has_error):
+                self.set_status(instance, service, "watcher.HPC-hb", result["status"])
+
+        for instance in instances:
+            if not instance.has_error:
+                self.set_status(instance, service, "watcher.HPC-hb", "success")
+
+    def run_once(self):
+        for hpcService in HpcService.objects.all():
+            for slice in self.get_service_slices(hpcService, "hpc"):
+                self.probe_hpc(hpcService, slice.instances.all())
+
+    def run(self):
+        while True:
+            self.run_once()
+            time.sleep(10)
+
+            django.db.reset_queries()
+
+class HpcFetcher(BaseWatcher):
+    def __init__(self):
+        BaseWatcher.__init__(self)
+
+        self.fetch_queue = WorkQueue()
+        for i in range(0, 10):
+            HpcFetchUrl(queue = self.fetch_queue)
+
+    def fetch_hpc(self, service, instances):
+        for instance in instances:
+            instance.has_error = False
+            instance.url_status = []
+
+            checks = HpcHealthCheck.objects.filter(kind="http")
+            if not checks:
+                self.set_status(instance, service, "watcher.HPC-fetch", "no HTTP HealthCheck tests configured")
+
+            for check in checks:
+                if (not check.resource_name) or (":" not in check.resource_name):
+                    self.set_status(instance, service, "watcher.HPC-fetch", "malformed resource_name: " + str(check.resource_name))
+                    break
+
+                (domain, url) = check.resource_name.split(":",1)
+
+                self.fetch_queue.submit_job({"server": instance.node.name, "port": 80, "instance": instance, "domain": domain, "url": url})
+
+        while self.fetch_queue.outstanding > 0:
+            result = self.fetch_queue.get_result()
+            instance = result["instance"]
+            if (result["status"] == "success"):
+                instance.url_status.append( (result["domain"] + result["url"], "success", result["bytes_downloaded"], result["total_time"]) )
+            if (result["status"]!="success") and (not instance.has_error):
+                self.set_status(instance, service, "watcher.HPC-fetch", result["status"])
+
+        for instance in instances:
+            self.set_status(instance, service, "watcher.HPC-fetch-urls", json.dumps(instance.url_status), check_error=False)
+            if not instance.has_error:
+                self.set_status(instance, service, "watcher.HPC-fetch", "success")
+
+    def run_once(self):
+        for hpcService in HpcService.objects.all():
+            for slice in self.get_service_slices(hpcService, "hpc"):
+                try:
+                    self.fetch_hpc(hpcService, slice.instances.all())
+                except:
+                    traceback.print_exc()
+
+    def run(self):
+        while True:
+            self.run_once()
+            time.sleep(10)
+
+            django.db.reset_queries()
+
+class WatcherFetcher(BaseWatcher):
+    def __init__(self):
+        BaseWatcher.__init__(self)
+
+        self.fetch_queue = WorkQueue()
+        for i in range(0, 10):
+             WatcherWorker(queue = self.fetch_queue)
+
+    def fetch_watcher(self, service, instances):
+        for instance in instances:
+            try:
+                ip = self.get_public_ip(service, instance)
+            except Exception, e:
+                self.set_status(instance, service, "watcher.watcher", json.dumps({"status": "exception: %s" % str(e)}) )
+                continue
+            if not ip:
+                try:
+                    ip = socket.gethostbyname(instance.node.name)
+                except:
+                    self.set_status(instance, service, "watcher.watcher", json.dumps({"status": "dns resolution failure"}) )
+                    continue
+
+            if not ip:
+                self.set_status(instance, service, "watcher.watcher", json.dumps({"status": "no IP address"}) )
+                continue
+
+            port = 8015
+            if ("redir" in instance.slice.name):
+                port = 8016
+            elif ("demux" in instance.slice.name):
+                port = 8017
+
+            self.fetch_queue.submit_job({"server": ip, "port": port, "instance": instance})
+
+        while self.fetch_queue.outstanding > 0:
+            result = self.fetch_queue.get_result()
+            instance = result["instance"]
+            self.set_status(instance, service, "watcher.watcher", result["status"])
+
+    def run_once(self):
+        for hpcService in HpcService.objects.all():
+            for slice in self.get_service_slices(hpcService):
+                self.fetch_watcher(hpcService, slice.instances.all())
+
+    def run(self):
+        while True:
+            self.run_once()
+            time.sleep(10)
+
+            django.db.reset_queries()
+
+
+if __name__ == "__main__":
+    if "--once" in sys.argv:
+        RRWatcher().run_once()
+        HpcProber().run_once()
+        HpcFetcher().run_once()
+        WatcherFetcher().run_once()
+    else:
+        RRWatcher().start()
+        HpcProber().start()
+        HpcFetcher().start()
+        WatcherFetcher().start()
+
+        print "Running forever..."
+        while True:
+            time.sleep(60)
+
diff --git a/xos/synchronizers/hpc/hpclib.py b/xos/synchronizers/hpc/hpclib.py
new file mode 100644
index 0000000..bb1c263
--- /dev/null
+++ b/xos/synchronizers/hpc/hpclib.py
@@ -0,0 +1,126 @@
+import os
+import base64
+import string
+import sys
+import xmlrpclib
+
+if __name__ == '__main__':
+    sys.path.append("/opt/xos")
+    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
+
+from xos.config import Config
+from core.models import Service
+from services.hpc.models import HpcService
+from services.requestrouter.models import RequestRouterService
+from xos.logger import Logger, logging
+
+logger = Logger(level=logging.INFO)
+
+class APIHelper:
+    def __init__(self, proxy, auth, method=None):
+        self.proxy = proxy
+        self.auth = auth
+        self.method = method
+
+    def __getattr__(self, name):
+        if name.startswith("_"):
+            return getattr(self, name)
+        else:
+            return APIHelper(self.proxy, self.auth, name)
+
+    def __call__(self, *args):
+        method = getattr(self.proxy, self.method)
+        return method(self.auth, *args)
+
+class CmiClient:
+    def __init__(self, hostname, port=8003, username="apiuser", password="apiuser"):
+        self.connect_api(hostname, port, username, password)
+
+    def connect_api(self, hostname, port=8003, username="apiuser", password="apiuser"):
+        #print "https://%s:%d/COAPI/" % (hostname, port)
+        cob = xmlrpclib.ServerProxy("https://%s:%d/COAPI/" % (hostname, port), allow_none=True)
+        cob_auth = {}
+        cob_auth["Username"] = username
+        cob_auth["AuthString"] = password
+        cob_auth["AuthMethod"] = "password"
+
+        onev = xmlrpclib.ServerProxy("https://%s:%d/ONEV_API/" % (hostname, port), allow_none=True)
+        onev_auth = {}
+        onev_auth["Username"] = username
+        onev_auth["AuthString"] = password
+        onev_auth["AuthMethod"] = "password"
+
+        self.cob = APIHelper(cob, cob_auth)
+        self.onev = APIHelper(onev, onev_auth)
+
+class HpcLibrary:
+    def __init__(self):
+        self._client = None
+
+    def make_account_name(self, x):
+        x=x.lower()
+        y = ""
+        for c in x:
+            if (c in (string.lowercase + string.digits)):
+                y = y + c
+        return y[:20]
+
+    def get_hpc_service(self):
+        hpc_service_name = getattr(Config(), "observer_hpc_service", None)
+        if hpc_service_name:
+            hpc_service = HpcService.objects.filter(name = hpc_service_name)
+        else:
+            hpc_service = HpcService.objects.all()
+
+        if not hpc_service:
+            if hpc_service_name:
+                raise Exception("No HPC Service with name %s" % hpc_service_name)
+            else:
+                raise Exception("No HPC Services")
+        hpc_service = hpc_service[0]
+
+        return hpc_service
+
+    def get_cmi_hostname(self, hpc_service=None):
+        if getattr(Config(),"observer_cmi_hostname",None):
+            return getattr(Config(),"observer_cmi_hostname")
+
+        if (hpc_service is None):
+            hpc_service = self.get_hpc_service()
+
+        if hpc_service.cmi_hostname:
+            return hpc_service.cmi_hostname
+
+        try:
+            slices = hpc_service.slices.all()
+        except:
+            # deal with buggy data model
+            slices = hpc_service.service.all()
+
+        for slice in slices:
+            if slice.name.endswith("cmi"):
+                for instance in slice.instances.all():
+                    if instance.node:
+                         return instance.node.name
+
+        raise Exception("Failed to find a CMI instance")
+
+    @property
+    def client(self):
+        if self._client is None:
+            self._client = CmiClient(self.get_cmi_hostname())
+        return self._client
+
+if __name__ == '__main__':
+    import django
+    django.setup()
+
+    lib = HpcLibrary()
+
+    print "testing API connection to", lib.get_cmi_hostname()
+    lib.client.cob.GetNewObjects()
+    lib.client.onev.ListAll("CDN")
+
+
+
+
diff --git a/xos/synchronizers/hpc/model-deps b/xos/synchronizers/hpc/model-deps
new file mode 100644
index 0000000..63188f0
--- /dev/null
+++ b/xos/synchronizers/hpc/model-deps
@@ -0,0 +1,19 @@
+{
+    "OriginServer": [
+        "ContentProvider"
+    ], 
+    "ContentProvider": [
+        "ServiceProvider"
+    ], 
+    "CDNPrefix": [
+        "ContentProvider"
+    ], 
+    "AccessMap": [
+        "ContentProvider"
+    ], 
+    "SiteMap": [
+        "ContentProvider", 
+        "ServiceProvider", 
+        "CDNPrefix"
+    ]
+}
diff --git a/xos/synchronizers/hpc/run.sh b/xos/synchronizers/hpc/run.sh
new file mode 100755
index 0000000..9d22047
--- /dev/null
+++ b/xos/synchronizers/hpc/run.sh
@@ -0,0 +1,2 @@
+export XOS_DIR=/opt/xos
+python hpc-synchronizer.py  -C $XOS_DIR/synchronizers/hpc/hpc_synchronizer_config
diff --git a/xos/synchronizers/hpc/start.sh b/xos/synchronizers/hpc/start.sh
new file mode 100755
index 0000000..3153a7d
--- /dev/null
+++ b/xos/synchronizers/hpc/start.sh
@@ -0,0 +1,2 @@
+export XOS_DIR=/opt/xos
+nohup python hpc-synchronizer.py  -C $XOS_DIR/synchronizers/hpc/hpc_synchronizer_config > /dev/null 2>&1 &
diff --git a/xos/synchronizers/hpc/steps/garbage_collector.py b/xos/synchronizers/hpc/steps/garbage_collector.py
new file mode 100644
index 0000000..658f7a1
--- /dev/null
+++ b/xos/synchronizers/hpc/steps/garbage_collector.py
@@ -0,0 +1,67 @@
+import os
+import sys
+import base64
+import traceback
+from collections import defaultdict
+from django.db.models import F, Q
+from xos.config import Config
+from xos.logger import Logger, logging
+from synchronizers.base.syncstep import SyncStep
+from services.hpc.models import ServiceProvider, ContentProvider, CDNPrefix, OriginServer
+from core.models import *
+
+# hpclibrary will be in steps/..
+parentdir = os.path.join(os.path.dirname(__file__),"..")
+sys.path.insert(0,parentdir)
+
+from hpclib import HpcLibrary
+
+logger = Logger(level=logging.INFO)
+
+class GarbageCollector(SyncStep, HpcLibrary):
+#    requested_interval = 86400
+    requested_interval = 0
+    provides=[]
+
+    def __init__(self, **args):
+        SyncStep.__init__(self, **args)
+        HpcLibrary.__init__(self)
+
+    def call(self, **args):
+        logger.info("running garbage collector")
+        try:
+            self.gc_originservers()
+            self.gc_cdnprefixes()
+            self.gc_contentproviders()
+            self.gc_serviceproviders()
+        except:
+            traceback.print_exc()
+
+    def gc_onev(self, ps_class, ps_idField, onev_className, onev_idField):
+        # get the CMI's objects
+        onev_objs = self.client.onev.ListAll(onev_className)
+
+        # get the data model's objects,
+        ps_objs = ps_class.objects.filter(enacted__isnull=False)
+        ps_ids = [str(getattr(x,ps_idField,None)) for x in ps_objs]
+
+        # for each onev object, if it's id does not exist in a data model
+        # object, then delete it.
+        for onev_obj in onev_objs:
+            onev_id = onev_obj[onev_idField]
+            if str(onev_id) not in ps_ids:
+                logger.info("garbage collecting %s %s" % (onev_className, str(onev_id)))
+                self.client.onev.Delete(onev_className, onev_id)
+
+    def gc_originservers(self):
+        self.gc_onev(OriginServer, "origin_server_id", "OriginServer", "origin_server_id")
+
+    def gc_cdnprefixes(self):
+        self.gc_onev(CDNPrefix, "cdn_prefix_id", "CDNPrefix", "cdn_prefix_id")
+
+    def gc_contentproviders(self):
+        self.gc_onev(ContentProvider, "content_provider_id", "ContentProvider", "content_provider_id")
+
+    def gc_serviceproviders(self):
+        self.gc_onev(ServiceProvider, "service_provider_id", "ServiceProvider", "service_provider_id")
+
diff --git a/xos/synchronizers/hpc/steps/sync_cdnprefix.py b/xos/synchronizers/hpc/steps/sync_cdnprefix.py
new file mode 100644
index 0000000..eff3b5d
--- /dev/null
+++ b/xos/synchronizers/hpc/steps/sync_cdnprefix.py
@@ -0,0 +1,101 @@
+import os
+import sys
+import base64
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.syncstep import SyncStep
+from core.models import Service
+from services.hpc.models import ServiceProvider, ContentProvider, CDNPrefix
+from xos.logger import Logger, logging
+
+# hpclibrary will be in steps/..
+parentdir = os.path.join(os.path.dirname(__file__),"..")
+sys.path.insert(0,parentdir)
+
+from hpclib import HpcLibrary
+
+logger = Logger(level=logging.INFO)
+
+class SyncCDNPrefix(SyncStep, HpcLibrary):
+    provides=[CDNPrefix]
+    observes=CDNPrefix
+    requested_interval=0
+
+    def __init__(self, **args):
+        SyncStep.__init__(self, **args)
+        HpcLibrary.__init__(self)
+
+    def filter_hpc_service(self, objs):
+        hpcService = self.get_hpc_service()
+
+        return [x for x in objs if x.contentProvider.serviceProvider.hpcService == hpcService]
+
+    def fetch_pending(self, deleted):
+        #self.consistency_check()
+
+        return self.filter_hpc_service(SyncStep.fetch_pending(self, deleted))
+
+    def consistency_check(self):
+        # set to true if something changed
+        result=False
+
+        # sanity check to make sure our PS objects have CMI objects behind them
+        all_p_ids = [x["cdn_prefix_id"] for x in self.client.onev.ListAll("CDNPrefix")]
+
+        all_p_ids = []
+        all_origins = {}
+        for x in self.client.onev.ListAll("CDNPrefix"):
+            id = x["cdn_prefix_id"]
+            all_p_ids.append(id)
+            all_origins[id] = x.get("default_origin_server", None)
+
+        for p in CDNPrefix.objects.all():
+            if (p.cdn_prefix_id is None):
+                continue
+
+            if (p.cdn_prefix_id not in all_p_ids):
+                logger.info("CDN Prefix %s was not found on CMI" % p.cdn_prefix_id)
+                p.cdn_prefix_id=None
+                p.save()
+                result = True
+
+            if (p.defaultOriginServer!=None) and (all_origins.get(p.cdn_prefix_id,None) != p.defaultOriginServer.url):
+                logger.info("CDN Prefix %s does not have default origin server on CMI" % str(p))
+                p.save() # this will set updated>enacted and force observer to re-sync
+                result = True
+
+        return result
+
+    def sync_record(self, cp):
+        logger.info("sync'ing cdn prefix %s" % str(cp),extra=cp.tologdict())
+
+        if (not cp.contentProvider) or (not cp.contentProvider.content_provider_id):
+            raise Exception("CDN Prefix %s is linked to a contentProvider without an id" % str(cp))
+
+        cpid = cp.contentProvider.content_provider_id
+
+        cp_dict = {"service": "HyperCache", "enabled": cp.enabled, "content_provider_id": cpid, "cdn_prefix": cp.prefix}
+
+        if cp.defaultOriginServer and cp.defaultOriginServer.url:
+            if (not cp.defaultOriginServer.origin_server_id):
+                # It's probably a bad idea to try to set defaultOriginServer before
+                # we've crated defaultOriginServer.
+                raise Exception("cdn prefix %s is waiting for it's default origin server to get an id" % str(cp))
+
+            cp_dict["default_origin_server"] = cp.defaultOriginServer.url
+
+        #print cp_dict
+
+        if not cp.cdn_prefix_id:
+            id = self.client.onev.Create("CDNPrefix", cp_dict)
+            cp.cdn_prefix_id = id
+        else:
+            del cp_dict["content_provider_id"]  # this can't be updated
+            del cp_dict["cdn_prefix"] # this can't be updated either
+            self.client.onev.Update("CDNPrefix", cp.cdn_prefix_id, cp_dict)
+
+        cp.save()
+
+    def delete_record(self, m):
+        if m.cdn_prefix_id is not None:
+            self.client.onev.Delete("CDNPrefix", m.cdn_prefix_id)
diff --git a/xos/synchronizers/hpc/steps/sync_contentprovider.py b/xos/synchronizers/hpc/steps/sync_contentprovider.py
new file mode 100644
index 0000000..3e30ed3
--- /dev/null
+++ b/xos/synchronizers/hpc/steps/sync_contentprovider.py
@@ -0,0 +1,78 @@
+import os
+import sys
+import base64
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.syncstep import SyncStep
+from core.models import Service
+from services.hpc.models import ServiceProvider, ContentProvider
+from xos.logger import Logger, logging
+
+# hpclibrary will be in steps/..
+parentdir = os.path.join(os.path.dirname(__file__),"..")
+sys.path.insert(0,parentdir)
+
+from hpclib import HpcLibrary
+
+logger = Logger(level=logging.INFO)
+
+class SyncContentProvider(SyncStep, HpcLibrary):
+    provides=[ContentProvider]
+    observes=ContentProvider
+    requested_interval=0
+
+    def __init__(self, **args):
+        SyncStep.__init__(self, **args)
+        HpcLibrary.__init__(self)
+
+    def filter_hpc_service(self, objs):
+        hpcService = self.get_hpc_service()
+
+        return [x for x in objs if x.serviceProvider.hpcService == hpcService]
+
+    def fetch_pending(self, deleted):
+        #self.consistency_check()
+
+        return self.filter_hpc_service(SyncStep.fetch_pending(self, deleted))
+
+    def consistency_check(self):
+        # set to true if something changed
+        result=False
+
+        # sanity check to make sure our PS objects have CMI objects behind them
+        all_cp_ids = [x["content_provider_id"] for x in self.client.onev.ListAll("ContentProvider")]
+        for cp in ContentProvider.objects.all():
+            if (cp.content_provider_id is not None) and (cp.content_provider_id not in all_cp_ids):
+                logger.info("Content provider %s was not found on CMI" % cp.content_provider_id)
+                cp.content_provider_id=None
+                cp.save()
+                result = True
+
+        return result
+
+    def sync_record(self, cp):
+        logger.info("sync'ing content provider %s" % str(cp), extra=cp.tologdict())
+        account_name = self.make_account_name(cp.name)
+
+        if (not cp.serviceProvider) or (not cp.serviceProvider.service_provider_id):
+            raise Exception("ContentProvider %s is linked to a serviceProvider with no id" % str(cp))
+
+        spid = cp.serviceProvider.service_provider_id
+
+        cp_dict = {"account": account_name, "name": cp.name, "enabled": cp.enabled}
+
+        #print cp_dict
+
+        if not cp.content_provider_id:
+            cp_dict["service_provider_id"] = spid
+            id = self.client.onev.Create("ContentProvider", cp_dict)
+            cp.content_provider_id = id
+        else:
+            self.client.onev.Update("ContentProvider", cp.content_provider_id, cp_dict)
+
+        cp.save()
+
+    def delete_record(self, m):
+        if m.content_provider_id is not None:
+            self.client.onev.Delete("ContentProvider", m.content_provider_id)
+
diff --git a/xos/synchronizers/hpc/steps/sync_hpcservices.py b/xos/synchronizers/hpc/steps/sync_hpcservices.py
new file mode 100644
index 0000000..63bf19b
--- /dev/null
+++ b/xos/synchronizers/hpc/steps/sync_hpcservices.py
@@ -0,0 +1,43 @@
+import os
+import sys
+import base64
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.syncstep import SyncStep
+from core.models import Service
+from services.hpc.models import HpcService
+from services.requestrouter.models import RequestRouterService
+from xos.logger import Logger, logging
+
+# hpclibrary will be in steps/..
+parentdir = os.path.join(os.path.dirname(__file__),"..")
+sys.path.insert(0,parentdir)
+
+from hpclib import HpcLibrary
+
+logger = Logger(level=logging.INFO)
+
+class SyncHpcService(SyncStep, HpcLibrary):
+    provides=[HpcService]
+    observes=HpcService
+    requested_interval=0
+
+    def __init__(self, **args):
+        SyncStep.__init__(self, **args)
+        HpcLibrary.__init__(self)
+
+    def filter_hpc_service(self, objs):
+        hpcService = self.get_hpc_service()
+
+        return [x for x in objs if x == hpcService]
+
+    def fetch_pending(self, deleted):
+        # Looks like deletion is not supported for this object - Sapan
+        if (deleted):
+            return []
+        else:
+            return self.filter_hpc_service(HpcService.objects.filter(Q(enacted__lt=F('updated')) | Q(enacted=None)))
+
+    def sync_record(self, hpc_service):
+        logger.info("sync'ing hpc_service %s" % str(hpc_service),extra=hpc_service.tologdict())
+        hpc_service.save()
diff --git a/xos/synchronizers/hpc/steps/sync_originserver.py b/xos/synchronizers/hpc/steps/sync_originserver.py
new file mode 100644
index 0000000..bd5b227
--- /dev/null
+++ b/xos/synchronizers/hpc/steps/sync_originserver.py
@@ -0,0 +1,92 @@
+import os
+import sys
+import base64
+
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.syncstep import SyncStep
+from core.models import Service
+from services.hpc.models import ServiceProvider, ContentProvider, CDNPrefix, OriginServer
+from xos.logger import Logger, logging
+
+# hpclibrary will be in steps/..
+parentdir = os.path.join(os.path.dirname(__file__),"..")
+sys.path.insert(0,parentdir)
+
+from hpclib import HpcLibrary
+
+logger = Logger(level=logging.INFO)
+
+class SyncOriginServer(SyncStep, HpcLibrary):
+    provides=[OriginServer]
+    observes=OriginServer
+    requested_interval=0
+
+    def __init__(self, **args):
+        SyncStep.__init__(self, **args)
+        HpcLibrary.__init__(self)
+
+    def filter_hpc_service(self, objs):
+        hpcService = self.get_hpc_service()
+
+        return [x for x in objs if x.contentProvider.serviceProvider.hpcService == hpcService]
+
+    def fetch_pending(self, deleted):
+        #self.consistency_check()
+
+        return self.filter_hpc_service(SyncStep.fetch_pending(self, deleted))
+
+    def consistency_check(self):
+        # set to true if something changed
+        result=False
+
+        # sanity check to make sure our PS objects have CMI objects behind them
+        all_ors_ids = [x["origin_server_id"] for x in self.client.onev.ListAll("OriginServer")]
+        for ors in OriginServer.objects.all():
+            if (ors.origin_server_id is not None) and (ors.origin_server_id not in all_ors_ids):
+                # we have an origin server ID, but it doesn't exist in the CMI
+                # something went wrong
+                # start over
+                logger.info("origin server %s was not found on CMI" % ors.origin_server_id)
+                ors.origin_server_id=None
+                ors.save()
+                result = True
+
+        return result
+
+    def sync_record(self, ors):
+        logger.info("sync'ing origin server %s" % str(ors),extra=ors.tologdict())
+
+        if (not ors.contentProvider) or (not ors.contentProvider.content_provider_id):
+            raise Exception("Origin Server %s is linked to a contentProvider with no id" % str(ors))
+
+        cpid = ors.contentProvider.content_provider_id
+
+        # validation requires URL start with http://
+        url = ors.url
+        if not url.startswith("http://"):
+            url = "http://" + url
+
+        ors_dict = {"authenticated_content": ors.authenticated, "zone_redirects": ors.redirects, "content_provider_id": cpid, "url": url, "service_type": "HyperCache", "caching_type": "Optimistic", "description": ors.description}
+        if not ors_dict["description"]:
+            ors_dict["description"] = "blank"
+
+        #print os_dict
+
+        if not ors.origin_server_id:
+            id = self.client.onev.Create("OriginServer", ors_dict)
+            ors.origin_server_id = id
+        else:
+            self.client.onev.Update("OriginServer", ors.origin_server_id, ors_dict)
+
+        # ... something breaks (analytics) if the URL starts with http://, so we
+        # change it in cob after we added it via onev.
+        url = url[7:]
+        self.client.cob.UpdateContent(ors.origin_server_id, {"url": url})
+
+        ors.silent = True
+        ors.save()
+
+    def delete_record(self, m):
+        if m.origin_server_id is not None:
+            self.client.onev.Delete("OriginServer", m.origin_server_id)
diff --git a/xos/synchronizers/hpc/steps/sync_serviceprovider.py b/xos/synchronizers/hpc/steps/sync_serviceprovider.py
new file mode 100644
index 0000000..af6d685
--- /dev/null
+++ b/xos/synchronizers/hpc/steps/sync_serviceprovider.py
@@ -0,0 +1,67 @@
+import os
+import sys
+import base64
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.syncstep import SyncStep
+from core.models import Service
+from services.hpc.models import ServiceProvider
+from xos.logger import Logger, logging
+
+# hpclibrary will be in steps/..
+parentdir = os.path.join(os.path.dirname(__file__),"..")
+sys.path.insert(0,parentdir)
+
+from hpclib import HpcLibrary
+
+logger = Logger(level=logging.INFO)
+
+class SyncServiceProvider(SyncStep, HpcLibrary):
+    provides=[ServiceProvider]
+    observes=ServiceProvider
+    requested_interval=0
+
+    def __init__(self, **args):
+        SyncStep.__init__(self, **args)
+        HpcLibrary.__init__(self)
+
+    def filter_hpc_service(self, objs):
+        hpcService = self.get_hpc_service()
+
+        return [x for x in objs if x.hpcService == hpcService]
+
+    def fetch_pending(self, deleted):
+        #self.consistency_check()
+
+        return self.filter_hpc_service(SyncStep.fetch_pending(self, deleted))
+
+    def consistency_check(self):
+        # set to true if something changed
+        result=False
+
+        # sanity check to make sure our PS objects have CMI objects behind them
+        all_sp_ids = [x["service_provider_id"] for x in self.client.onev.ListAll("ServiceProvider")]
+        for sp in ServiceProvider.objects.all():
+            if (sp.service_provider_id is not None) and (sp.service_provider_id not in all_sp_ids):
+                logger.info("Service provider %s was not found on CMI" % sp.service_provider_id)
+                sp.service_provider_id=None
+                sp.save()
+                result = True
+
+        return result
+
+    def sync_record(self, sp):
+        logger.info("sync'ing service provider %s" % str(sp),extra=sp.tologdict())
+        account_name = self.make_account_name(sp.name)
+        sp_dict = {"account": account_name, "name": sp.name, "enabled": sp.enabled}
+        if not sp.service_provider_id:
+            id = self.client.onev.Create("ServiceProvider", sp_dict)
+            sp.service_provider_id = id
+        else:
+            self.client.onev.Update("ServiceProvider", sp.service_provider_id, sp_dict)
+
+        sp.save()
+
+    def delete_record(self, m):
+        if m.service_provider_id is not None:
+            self.client.onev.Delete("ServiceProvider", m.service_provider_id)
diff --git a/xos/synchronizers/hpc/steps/sync_sitemap.py b/xos/synchronizers/hpc/steps/sync_sitemap.py
new file mode 100644
index 0000000..a1d177b
--- /dev/null
+++ b/xos/synchronizers/hpc/steps/sync_sitemap.py
@@ -0,0 +1,118 @@
+import os
+import sys
+import base64
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.syncstep import SyncStep
+from core.models import Service
+from services.hpc.models import ServiceProvider, ContentProvider, CDNPrefix, SiteMap
+from xos.logger import Logger, logging
+
+# hpclibrary will be in steps/..
+parentdir = os.path.join(os.path.dirname(__file__),"..")
+sys.path.insert(0,parentdir)
+
+from hpclib import HpcLibrary
+
+logger = Logger(level=logging.INFO)
+
+class SyncSiteMap(SyncStep, HpcLibrary):
+    provides=[SiteMap]
+    observes=SiteMap
+    requested_interval=0
+
+    def __init__(self, **args):
+        SyncStep.__init__(self, **args)
+        HpcLibrary.__init__(self)
+
+    def filter_hpc_service(self, objs):
+        hpcService = self.get_hpc_service()
+
+        filtered_objs = []
+        for x in objs:
+            if ((x.hpcService == hpcService) or
+               ((x.serviceProvider != None) and (x.serviceProvider.hpcService == hpcService)) or
+               ((x.contentProvider != None) and (x.contentProvider.serviceProvider.hpcService == hpcService)) or
+               ((x.cdnPrefix!= None) and (x.cdnPrefix.contentProvider.serviceProvider.hpcService == hpcService))):
+                filtered_objs.append(x)
+
+        return filtered_objs
+
+    def fetch_pending(self, deleted):
+        return self.filter_hpc_service(SyncStep.fetch_pending(self, deleted))
+
+    def consistency_check(self):
+        # set to true if something changed
+        result=False
+
+        # sanity check to make sure our PS objects have CMI objects behind them
+        all_map_ids = [x["map_id"] for x in self.client.onev.ListAll("Map")]
+        for map in SiteMap.objects.all():
+            if (map.map_id is not None) and (map.map_id not in all_map_ids):
+                logger.info("Map %s was not found on CMI" % map.map_id,extra=map.tologdict())
+                map.map_id=None
+                map.save()
+                result = True
+
+        return result
+
+    def update_bind(self, map, map_dict, field_name, to_name, ids):
+        for id in ids:
+            if (not id in map_dict.get(field_name, [])):
+                print "Bind Map", map.map_id, "to", to_name, id
+                self.client.onev.Bind("Map", map.map_id, to_name, id)
+
+        for id in map_dict.get(field_name, []):
+            if (not id in ids):
+                print "Unbind Map", map.map_id, "from", to_name, id
+                self.client.onev.UnBind("map", map.map_id, to_name, id)
+
+    def sync_record(self, map):
+        logger.info("sync'ing SiteMap %s" % str(map),extra=map.tologdict())
+
+        if not map.map:
+            # no contents
+            return
+
+        content = map.map.read()
+
+        map_dict = {"name": map.name, "type": "site", "content": content}
+
+        cdn_prefix_ids=[]
+        service_provider_ids=[]
+        content_provider_ids=[]
+
+        if (map.contentProvider):
+            if not map.contentProvider.content_provider_id:
+                raise Exception("Map %s links to a contentProvider with no id" % map.name)
+            conent_provider_ids = [map.contentProvider.content_provider_id]
+
+        if (map.serviceProvider):
+            if not map.serviceProvider.service_provider_id:
+                raise Exception("Map %s links to a serviceProvider with no id" % map.name)
+            service_provider_ids = [map.serviceProvider.service_provider_id]
+
+        if (map.cdnPrefix):
+            if not map.cdnPrefix.cdn_prefix_id:
+                raise Exception("Map %s links to a cdnPrefix with no id" % map.name)
+            cdn_prefix_ids = [map.cdnPrefix.cdn_prefix_id]
+
+        if not map.map_id:
+            print "Create Map", map_dict
+            id = self.client.onev.Create("Map", map_dict)
+            map.map_id = id
+        else:
+            print "Update Map", map_dict
+            # these things we probably cannot update
+            del map_dict["name"]
+            self.client.onev.Update("Map", map.map_id, map_dict)
+
+        cmi_map_dict = self.client.onev.Read("Map", map.map_id)
+
+        self.update_bind(map, cmi_map_dict, "cdn_prefix_ids", "CDNPrefix", cdn_prefix_ids)
+
+        map.save()
+
+    def delete_record(self, m):
+        if m.map_id is not None:
+            self.client.onev.Delete("Map", m.map_id)
diff --git a/xos/synchronizers/hpc/stop.sh b/xos/synchronizers/hpc/stop.sh
new file mode 100755
index 0000000..780e25c
--- /dev/null
+++ b/xos/synchronizers/hpc/stop.sh
@@ -0,0 +1 @@
+pkill -9 -f hpc-synchronizer.py
diff --git a/xos/synchronizers/hpc/supervisor/hpc-observer.conf b/xos/synchronizers/hpc/supervisor/hpc-observer.conf
new file mode 100644
index 0000000..f2c79d4
--- /dev/null
+++ b/xos/synchronizers/hpc/supervisor/hpc-observer.conf
@@ -0,0 +1,2 @@
+[program:hpc-observer]
+command=python /opt/xos/observers/hpc/hpc-observer.py -C /opt/xos/observers/hpc/hpc_observer_config
diff --git a/xos/synchronizers/hpc/supervisor/hpc-watcher.conf b/xos/synchronizers/hpc/supervisor/hpc-watcher.conf
new file mode 100644
index 0000000..e0f4eb1
--- /dev/null
+++ b/xos/synchronizers/hpc/supervisor/hpc-watcher.conf
@@ -0,0 +1,2 @@
+[program:hpc-watcher]
+command=python /opt/xos/observers/hpc/hpc_watcher.py
diff --git a/xos/synchronizers/model_policy.py b/xos/synchronizers/model_policy.py
new file mode 100644
index 0000000..aa12092
--- /dev/null
+++ b/xos/synchronizers/model_policy.py
@@ -0,0 +1,172 @@
+from django.db.models.signals import post_save
+from django.dispatch import receiver
+import pdb
+from generate.dependency_walker import *
+from synchronizers.openstack import model_policies
+from xos.logger import Logger, logging
+from datetime import datetime
+from django.utils import timezone
+import time
+import traceback
+from core.models import *
+from django.db import reset_queries
+from django.db.transaction import atomic
+from django.db.models import F, Q
+
+modelPolicyEnabled = True
+bad_instances=[]
+
+logger = Logger(level=logging.INFO)
+
+def EnableModelPolicy(x):
+    global modelPolicyEnabled
+    modelPolicyEnabled = x
+
+def update_wp(d, o):
+    try:
+        save_fields = []
+        if (d.write_protect != o.write_protect):
+            d.write_protect = o.write_protect
+            save_fields.append('write_protect')
+        if (save_fields):
+            d.save(update_fields=save_fields)
+    except AttributeError,e:
+        raise e
+
+def update_dep(d, o):
+    try:
+        print 'Trying to update %s'%d
+        save_fields = []
+        if (d.updated < o.updated):
+            save_fields = ['updated']
+
+        if (save_fields):
+            d.save(update_fields=save_fields)
+    except AttributeError,e:
+        logger.log_exc("AttributeError in update_dep")
+        raise e
+    except Exception,e:
+        logger.log_exc("Exception in update_dep")
+
+def delete_if_inactive(d, o):
+    try:
+        d.delete()
+        print "Deleted %s (%s)"%(d,d.__class__.__name__)
+    except:
+        pass
+    return
+
+
+#@atomic
+def execute_model_policy(instance, deleted):
+    # Automatic dirtying
+    if (instance in bad_instances):
+        return
+
+    # These are the models whose children get deleted when they are
+    delete_policy_models = ['Slice','Instance','Network']
+    sender_name = instance.__class__.__name__
+    policy_name = 'model_policy_%s'%sender_name
+    noargs = False
+
+    if (not deleted):
+        walk_inv_deps(update_dep, instance)
+        walk_deps(update_wp, instance)
+    elif (sender_name in delete_policy_models):
+        walk_inv_deps(delete_if_inactive, instance)
+
+
+
+    try:
+        policy_handler = getattr(model_policies, policy_name, None)
+        logger.info("MODEL POLICY: handler %s %s" % (policy_name, policy_handler))
+        if policy_handler is not None:
+            if (deleted):
+                try:
+                    policy_handler.handle_delete(instance)
+                except AttributeError:
+                    pass
+            else:
+                policy_handler.handle(instance)
+        logger.info("MODEL POLICY: completed handler %s %s" % (policy_name, policy_handler))
+    except:
+        logger.log_exc("MODEL POLICY: Exception when running handler")
+
+    try:
+        instance.policed=timezone.now()
+        instance.save(update_fields=['policed'])
+    except:
+        logger.log_exc('MODEL POLICY: Object %r is defective'%instance)
+        bad_instances.append(instance)
+
+def noop(o,p):
+        pass
+
+def check_db_connection_okay():
+    # django implodes if the database connection is closed by docker-compose
+    from django import db
+    try:
+        db.connection.cursor()
+        #diag = Diag.objects.filter(name="foo").first()
+    except Exception, e:
+        if "connection already closed" in traceback.format_exc():
+           logger.error("XXX connection already closed")
+           try:
+#               if db.connection:
+#                   db.connection.close()
+               db.close_connection()
+           except:
+                logger.log_exc("XXX we failed to fix the failure")
+        else:
+           logger.log_exc("XXX some other error")
+
+def run_policy():
+    while (True):
+        start = time.time()
+        try:
+            run_policy_once()
+        except:
+            logger.log_exc("MODEL_POLICY: Exception in run_policy()")
+        if (time.time()-start<1):
+            time.sleep(1)
+
+def run_policy_once():
+        from core.models import Instance,Slice,Controller,Network,User,SlicePrivilege,Site,SitePrivilege,Image,ControllerSlice,ControllerUser,ControllerSite
+        models = [Controller, Site, SitePrivilege, Image, ControllerSlice, ControllerSite, ControllerUser, User, Slice, Network, Instance, SlicePrivilege]
+        objects = []
+        deleted_objects = []
+
+        logger.info("MODEL POLICY: run_policy_once()")
+
+        check_db_connection_okay()
+
+        for m in models:
+            res = m.objects.filter((Q(policed__lt=F('updated')) | Q(policed=None)) & Q(no_policy=False))
+            objects.extend(res)
+            res = m.deleted_objects.filter(Q(policed__lt=F('updated')) | Q(policed=None))
+            deleted_objects.extend(res)
+
+        for o in objects:
+            execute_model_policy(o, o.deleted)
+
+        for o in deleted_objects:
+            execute_model_policy(o, True)
+
+        # Reap non-sync'd models here
+        reaped = [Slice]
+
+        for m in reaped:
+            dobjs = m.deleted_objects.all()
+            for d in dobjs:
+                deps = walk_inv_deps(noop, d)
+                if (not deps):
+                    print 'Purging object %r'%d
+                    d.delete(purge=True)
+
+        try:
+            reset_queries()
+        except:
+            # this shouldn't happen, but in case it does, catch it...
+            logger.log_exc("MODEL POLICY: exception in reset_queries")
+
+        logger.info("MODEL POLICY: finished run_policy_once()")
diff --git a/xos/synchronizers/onboarding/files/__init__.py b/xos/synchronizers/onboarding/files/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/xos/synchronizers/onboarding/files/__init__.py
@@ -0,0 +1 @@
+
diff --git a/xos/synchronizers/onboarding/model-deps b/xos/synchronizers/onboarding/model-deps
new file mode 100644
index 0000000..4aa86c7
--- /dev/null
+++ b/xos/synchronizers/onboarding/model-deps
@@ -0,0 +1,8 @@
+{
+    "XOS": [
+        "ServiceController"
+    ], 
+    "ServiceController": [
+        "ServiceControllerResource"
+    ]
+}
diff --git a/xos/synchronizers/onboarding/onboarding-synchronizer.py b/xos/synchronizers/onboarding/onboarding-synchronizer.py
new file mode 100755
index 0000000..84bec4f
--- /dev/null
+++ b/xos/synchronizers/onboarding/onboarding-synchronizer.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+# This imports and runs ../../xos-observer.py
+
+import importlib
+import os
+import sys
+observer_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),"../../synchronizers/base")
+sys.path.append(observer_path)
+mod = importlib.import_module("xos-synchronizer")
+mod.main()
diff --git a/xos/synchronizers/onboarding/onboarding_synchronizer_config b/xos/synchronizers/onboarding/onboarding_synchronizer_config
new file mode 100644
index 0000000..e2b92fd
--- /dev/null
+++ b/xos/synchronizers/onboarding/onboarding_synchronizer_config
@@ -0,0 +1,38 @@
+
+[plc]
+name=plc
+deployment=VICCI
+
+[db]
+name=xos
+user=postgres
+password=password
+host=localhost
+port=5432
+
+[api]
+host=128.112.171.237
+port=8000
+ssl_key=None
+ssl_cert=None
+ca_ssl_cert=None
+ratelimit_enabled=0
+omf_enabled=0
+mail_support_address=support@localhost
+nova_enabled=True
+
+[observer]
+name=onboarding
+dependency_graph=/opt/xos/synchronizers/onboarding/model-deps
+steps_dir=/opt/xos/synchronizers/onboarding/steps
+sys_dir=/opt/xos/synchronizers/onboarding/sys
+deleters_dir=/opt/xos/synchronizers/onboarding/deleters
+log_file=console
+driver=None
+backoff_disabled=True
+pretend=False
+save_ansible_output=True
+
+[feefie]
+client_id='vicci_dev_central'
+user_id='pl'
diff --git a/xos/synchronizers/onboarding/run.sh b/xos/synchronizers/onboarding/run.sh
new file mode 100755
index 0000000..d52d39c
--- /dev/null
+++ b/xos/synchronizers/onboarding/run.sh
@@ -0,0 +1,2 @@
+export XOS_DIR=/opt/xos
+python onboarding-synchronizer.py  -C $XOS_DIR/synchronizers/onboarding/onboarding_synchronizer_config
diff --git a/xos/synchronizers/onboarding/steps/sync_servicecontroller.py b/xos/synchronizers/onboarding/steps/sync_servicecontroller.py
new file mode 100644
index 0000000..77d8e12
--- /dev/null
+++ b/xos/synchronizers/onboarding/steps/sync_servicecontroller.py
@@ -0,0 +1,53 @@
+import os
+import sys
+import base64
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.syncstep import SyncStep, DeferredException
+from core.models import XOS, ServiceController
+from xos.logger import Logger, logging
+from synchronizers.base.ansible import run_template
+
+# xosbuilder will be in steps/..
+parentdir = os.path.join(os.path.dirname(__file__),"..")
+sys.path.insert(0,parentdir)
+
+from xosbuilder import XOSBuilder
+
+logger = Logger(level=logging.INFO)
+
+class SyncServiceController(SyncStep, XOSBuilder):
+    provides=[ServiceController]
+    observes=ServiceController
+    requested_interval=0
+    playbook = "sync_servicecontroller.yaml"
+
+    def __init__(self, **args):
+        SyncStep.__init__(self, **args)
+        XOSBuilder.__init__(self)
+
+    def sync_record(self, sc):
+        logger.info("Sync'ing ServiceController %s" % sc)
+
+        if sc.xos and (not sc.xos.enable_build):
+            raise DeferredException("XOS build is currently disabled")
+
+        unready = self.check_controller_unready(sc)
+        if unready:
+            raise Exception("Controller %s has unready resources: %s" % (str(sc), ",".join([str(x) for x in unready])))
+
+        dockerfiles = [self.create_synchronizer_dockerfile(sc)]
+        tenant_fields = {"dockerfiles": dockerfiles,
+                         "build_dir": self.build_dir,
+                         "ansible_tag": sc.__class__.__name__ + "_" + str(sc.id)}
+
+        path="servicecontroller"
+        res = run_template(self.playbook, tenant_fields, path=path)
+
+    def delete_record(self, m):
+        pass
+
+    def fetch_pending(self, deleted=False):
+        pend = super(SyncServiceController, self).fetch_pending(deleted)
+        return pend
+
diff --git a/xos/synchronizers/onboarding/steps/sync_servicecontroller.yaml b/xos/synchronizers/onboarding/steps/sync_servicecontroller.yaml
new file mode 100644
index 0000000..9431427
--- /dev/null
+++ b/xos/synchronizers/onboarding/steps/sync_servicecontroller.yaml
@@ -0,0 +1,20 @@
+---
+- hosts: 127.0.0.1
+  connection: local
+
+  vars:
+    dockerfiles:
+    {% for dockerfile in dockerfiles %}
+      - docker_image_name: {{ dockerfile.docker_image_name }}
+        dockerfile_fn: {{ dockerfile.dockerfile_fn }}
+    {% endfor %}  
+
+  tasks: 
+    {% for dockerfile in dockerfiles %}
+    - name: build_docker_{{ dockerfile.docker_image_name }}
+      shell: chdir={{ build_dir }} docker build -f {{ dockerfile.dockerfile_fn }} --rm -t {{ dockerfile.docker_image_name }} .
+    {% endfor %}
+
+#  - build_dockers:
+#    shell: docker build -f {{ '{{' }} item.dockerfile_fn {{ '}}' }} --rm -t {{ '{{' }} item.docker_image_name {{ '}}' }} .
+#    with items: "dockerfiles"
diff --git a/xos/synchronizers/onboarding/steps/sync_servicecontrollerresource.py b/xos/synchronizers/onboarding/steps/sync_servicecontrollerresource.py
new file mode 100644
index 0000000..59ae93f
--- /dev/null
+++ b/xos/synchronizers/onboarding/steps/sync_servicecontrollerresource.py
@@ -0,0 +1,37 @@
+import os
+import sys
+import base64
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.syncstep import SyncStep
+from core.models import Service, ServiceController, ServiceControllerResource
+from xos.logger import Logger, logging
+
+# xosbuilder will be in steps/..
+parentdir = os.path.join(os.path.dirname(__file__),"..")
+sys.path.insert(0,parentdir)
+
+from xosbuilder import XOSBuilder
+
+logger = Logger(level=logging.INFO)
+
+class SyncServiceControllerResource(SyncStep, XOSBuilder):
+    provides=[ServiceControllerResource]
+    observes=ServiceControllerResource
+    requested_interval=0
+
+    def __init__(self, **args):
+        SyncStep.__init__(self, **args)
+        XOSBuilder.__init__(self)
+
+    def sync_record(self, scr):
+        logger.info("Sync'ing ServiceControllerResource %s" % scr)
+        self.download_resource(scr)
+
+    def delete_record(self, m):
+        pass
+
+    def fetch_pending(self, deleted=False):
+        pend = super(SyncServiceControllerResource, self).fetch_pending(deleted)
+        return pend
+
diff --git a/xos/synchronizers/onboarding/steps/sync_xos.py b/xos/synchronizers/onboarding/steps/sync_xos.py
new file mode 100644
index 0000000..567e0ad
--- /dev/null
+++ b/xos/synchronizers/onboarding/steps/sync_xos.py
@@ -0,0 +1,55 @@
+import os
+import sys
+import base64
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.syncstep import SyncStep, DeferredException
+from core.models import XOS
+from xos.logger import Logger, logging
+from synchronizers.base.ansible import run_template
+
+# xosbuilder will be in steps/..
+parentdir = os.path.join(os.path.dirname(__file__),"..")
+sys.path.insert(0,parentdir)
+
+from xosbuilder import XOSBuilder
+
+logger = Logger(level=logging.INFO)
+
+class SyncXOS(SyncStep, XOSBuilder):
+    provides=[XOS]
+    observes=XOS
+    requested_interval=0
+    playbook = "sync_xos.yaml"
+
+    def __init__(self, **args):
+        SyncStep.__init__(self, **args)
+        XOSBuilder.__init__(self)
+
+    def sync_record(self, xos):
+        logger.info("Sync'ing XOS %s" % xos)
+
+        if not xos.docker_project_name:
+            raise Exception("xos.docker_project_name is not set")
+
+        if (not xos.enable_build):
+            raise DeferredException("XOS build is currently disabled")
+
+        self.create_docker_compose()
+
+        dockerfiles = [self.create_ui_dockerfile()]
+        tenant_fields = {"dockerfiles": dockerfiles,
+                         "build_dir": self.build_dir,
+                         "docker_project_name": xos.docker_project_name,
+                         "ansible_tag": xos.__class__.__name__ + "_" + str(xos.id)}
+
+        path="XOS"
+        res = run_template(self.playbook, tenant_fields, path=path)
+
+    def delete_record(self, m):
+        pass
+
+    def fetch_pending(self, deleted=False):
+        pend = super(SyncXOS, self).fetch_pending(deleted)
+        return pend
+
diff --git a/xos/synchronizers/onboarding/steps/sync_xos.yaml b/xos/synchronizers/onboarding/steps/sync_xos.yaml
new file mode 100644
index 0000000..8a98873
--- /dev/null
+++ b/xos/synchronizers/onboarding/steps/sync_xos.yaml
@@ -0,0 +1,20 @@
+---
+- hosts: 127.0.0.1
+  connection: local
+
+  vars:
+    dockerfiles:
+    {% for dockerfile in dockerfiles %}
+      - docker_image_name: {{ dockerfile.docker_image_name }}
+        dockerfile_fn: {{ dockerfile.dockerfile_fn }}
+    {% endfor %}  
+
+  tasks: 
+    {% for dockerfile in dockerfiles %}
+    - name: build_docker_{{ dockerfile.docker_image_name }}
+      shell: chdir={{ build_dir }} docker build -f {{ dockerfile.dockerfile_fn }} --rm -t {{ dockerfile.docker_image_name }} .
+    {% endfor %}
+
+    - name: run docker-compose
+      shell: docker-compose -p {{ docker_project_name }} -f /opt/xos/synchronizers/onboarding/docker-compose/docker-compose.yml up -d
+
diff --git a/xos/synchronizers/onboarding/templates/docker-compose.yml.j2 b/xos/synchronizers/onboarding/templates/docker-compose.yml.j2
new file mode 100644
index 0000000..faa9d02
--- /dev/null
+++ b/xos/synchronizers/onboarding/templates/docker-compose.yml.j2
@@ -0,0 +1,48 @@
+{% for container_name, container in containers.iteritems() %}
+
+{{ container_name}}:
+#  container_name: {{ container.container_base_name }}_{{ container_name }}_1
+  image: {{ container.image }}
+{%- if container.command %}
+  command: {{ container.command }}
+{%- endif %}
+{%- if container.ports %}
+  ports:
+{%- for src,dest in container.ports.iteritems() %}
+    - "{{ src }}:{{ dest }}"
+{%- endfor %}
+{%- endif %}
+{%- if container.links %}
+  links:
+{%- for link in container.links %}
+    - {{ link }}
+{%- endfor %}
+{%- endif %}
+{%- if container.external_links %}
+  external_links:
+{%- for link in container.external_links %}
+    - {{ link }}
+{%- endfor %}
+{%- endif %}
+{%- if container.volumes %}
+  volumes:
+{%- for volume in container.volumes %}
+{%- if volume.read_only %}
+    - {{ volume.host_path }}:{{ volume.container_path }}:ro
+{%- else %}
+    - {{ volume.host_path }}:{{ volume.container_path }}
+{%- endif %}
+{%- endfor %}
+{%- endif %}
+{%- if container.expose %}
+  expose:
+{%- for expose in container.expose %}
+    - "{{ expose }}"
+{%- endfor %}
+{%- endif %}
+  log_driver: "json-file"
+  log_opt:

+    max-size: "100k"

+    max-file: "5"
+
+{%- endfor %}
diff --git a/xos/synchronizers/onboarding/xosbuilder.py b/xos/synchronizers/onboarding/xosbuilder.py
new file mode 100644
index 0000000..6e24a28
--- /dev/null
+++ b/xos/synchronizers/onboarding/xosbuilder.py
@@ -0,0 +1,318 @@
+import os
+import base64
+import jinja2
+import string
+import sys
+import urllib2
+import urlparse
+import xmlrpclib
+
+from xos.config import Config
+from core.models import Service, ServiceController, ServiceControllerResource, XOS
+from xos.logger import Logger, logging
+
+logger = Logger(level=logging.INFO)
+
+class XOSBuilder(object):
+    UI_KINDS=["models", "admin", "admin_template", "django_library", "rest_service", "rest_tenant", "tosca_custom_types", "tosca_resource","public_key"]
+    SYNC_CONTROLLER_KINDS=["synchronizer", "private_key", "public_key"]
+    SYNC_ALLCONTROLLER_KINDS=["models", "django_library"]
+
+    def __init__(self):
+        self.source_sync_image = "xosproject/xos-synchronizer-openstack"
+        self.build_dir = "/opt/xos/BUILD/"
+
+    # stuff that has to do with downloading
+
+    def get_dest_dir(self, scr):
+        xos_base = "opt/xos"
+        service_name = scr.service_controller.name
+        base_dirs = {"models": "%s/services/%s/" % (xos_base, service_name),
+                     "admin": "%s/services/%s/" % (xos_base, service_name),
+                     "admin_template": "%s/services/%s/templates/" % (xos_base, service_name),
+                     "django_library": "%s/services/%s/" % (xos_base, service_name),
+                     "synchronizer": "%s/synchronizers/%s/" % (xos_base, service_name),
+                     "tosca_custom_types": "%s/tosca/custom_types/" % (xos_base),
+                     "tosca_resource": "%s/tosca/resources/" % (xos_base),
+                     "rest_service": "%s/api/service/" % (xos_base),
+                     "rest_tenant": "%s/api/tenant/" % (xos_base),
+                     "private_key": "%s/services/%s/keys/" % (xos_base, service_name),
+                     "public_key": "%s/services/%s/keys/" % (xos_base, service_name)}
+        dest_dir = base_dirs[scr.kind]
+
+        if scr.subdirectory:
+            dest_dir = os.path.join(dest_dir, scr.subdirectory)
+
+        return dest_dir
+
+    def get_build_fn(self, scr):
+        dest_dir = self.get_dest_dir(scr)
+        dest_fn = os.path.split(urlparse.urlsplit(scr.full_url).path)[-1]
+        return os.path.join(dest_dir, dest_fn)
+
+    def get_download_fn(self, scr):
+        dest_fn = self.get_build_fn(scr)
+        return os.path.join(self.build_dir, dest_fn)
+
+    def read_manifest(self, scr, fn):
+        manifest = []
+        manifest_lines = file(fn).readlines()
+        manifest_lines = [x.strip() for x in manifest_lines]
+        manifest_lines = [x for x in manifest_lines if x]
+        for line in manifest_lines:
+            url_parts = urlparse.urlsplit(scr.full_url)
+            new_path = os.path.join(os.path.join(*os.path.split(url_parts.path)[:-1]),line)
+            url = urlparse.urlunsplit( (url_parts.scheme, url_parts.netloc, new_path, url_parts.query, url_parts.fragment) )
+
+            build_fn = os.path.join(self.get_dest_dir(scr), line)
+            download_fn = os.path.join(self.build_dir, build_fn)
+
+            manifest.append( (url, download_fn, build_fn) )
+        return manifest
+
+    def download_file(self, url, dest_fn):
+        logger.info("Download %s to %s" % (url, dest_fn))
+        if not os.path.exists(os.path.dirname(dest_fn)):
+            os.makedirs(os.path.dirname(dest_fn))
+        obj = urllib2.urlopen(url)
+        file(dest_fn,"w").write(obj.read())
+
+        # make python files executable
+        if dest_fn.endswith(".py"): # and contents.startswith("#!"):
+            os.chmod(dest_fn, 0755)
+
+    def download_resource(self, scr):
+        if scr.format == "manifest":
+            manifest_fn = self.get_download_fn(scr)
+            self.download_file(scr.full_url, manifest_fn)
+            manifest = self.read_manifest(scr, manifest_fn)
+            for (url, download_fn, build_fn) in manifest:
+                self.download_file(url, download_fn)
+        else:
+            self.download_file(scr.full_url, self.get_download_fn(scr))
+
+# XXX docker creates a new container and commits it for every single COPY
+# line in the dockerfile. This causes services with many files (for example,
+# vsg) to take ~ 10-15 minutes to build the docker file. So instead we'll copy
+# the whole build directory, and then run a script that copies the files
+# we want.
+
+#    def get_docker_lines(self, scr):
+#        if scr.format == "manifest":
+#            manifest_fn = self.get_download_fn(scr)
+#            manifest = self.read_manifest(scr, manifest_fn)
+#            lines = []
+#            for (url, download_fn, build_fn) in manifest:
+#               script.append("mkdir -p
+#               #lines.append("COPY %s /%s" % (build_fn, build_fn))
+#            return lines
+#        else:
+#            build_fn = self.get_build_fn(scr)
+#            #return ["COPY %s /%s" % (build_fn, build_fn)]
+
+#    def get_controller_docker_lines(self, controller, kinds):
+#        need_service_init_py = False
+#        dockerfile=[]
+#        for scr in controller.service_controller_resources.all():
+#            if scr.kind in kinds:
+#                lines = self.get_docker_lines(scr)
+#                dockerfile = dockerfile + lines
+#            if scr.kind in ["admin", "models"]:
+#                need_service_init_py = True
+#
+#        if need_service_init_py:
+#            file(os.path.join(self.build_dir, "opt/xos/empty__init__.py"),"w").write("")
+#            dockerfile.append("COPY opt/xos/empty__init__.py /opt/xos/services/%s/__init__.py" % controller.name)
+#
+#        return dockerfile
+
+    def get_script_lines(self, scr):
+        if scr.format == "manifest":
+            manifest_fn = self.get_download_fn(scr)
+            manifest = self.read_manifest(scr, manifest_fn)
+            lines = []
+            for (url, download_fn, build_fn) in manifest:
+               lines.append("mkdir -p /%s" % os.path.dirname(build_fn))
+               lines.append("cp /build/%s /%s" % (build_fn, build_fn))
+            return lines
+        else:
+            build_fn = self.get_build_fn(scr)
+            return ["mkdir -p /%s" % os.path.dirname(build_fn),
+                    "cp /build/%s /%s" % (build_fn, build_fn)]
+
+    def get_controller_script_lines(self, controller, kinds):
+        need_service_init_py = False
+        script=[]
+        for scr in controller.service_controller_resources.all():
+            if scr.kind in kinds:
+                lines = self.get_script_lines(scr)
+                script = script + lines
+            if scr.kind in ["admin", "models"]:
+                need_service_init_py = True
+
+        if need_service_init_py:
+            script.append("echo > /opt/xos/services/%s/__init__.py" % controller.name)
+
+        return script
+
+    def check_controller_unready(self, controller):
+        unready_resources=[]
+        for scr in controller.service_controller_resources.all():
+            if (not scr.backend_status) or (not scr.backend_status.startswith("1")):
+                unready_resources.append(scr)
+
+        return unready_resources
+
+    # stuff that has to do with building
+
+    def create_xos_app_data(self, name, script, app_list, migration_list):
+        if not os.path.exists(os.path.join(self.build_dir,"opt/xos/xos")):
+            os.makedirs(os.path.join(self.build_dir,"opt/xos/xos"))
+
+        if app_list:
+            script.append("mkdir -p /opt/xos/xos")
+            script.append("cp /build/opt/xos/xos/%s_xosbuilder_app_list /opt/xos/xos/xosbuilder_app_list" % name)
+            #dockerfile.append("COPY opt/xos/xos/%s_xosbuilder_app_list /opt/xos/xos/xosbuilder_app_list" % name)
+            file(os.path.join(self.build_dir, "opt/xos/xos/%s_xosbuilder_app_list") % name, "w").write("\n".join(app_list)+"\n")
+
+        if migration_list:
+            script.append("mkdir -p /opt/xos/xos")
+            script.append("cp /build/opt/xos/xos/%s_xosbuilder_migration_list /opt/xos/xos/xosbuilder_migration_list" % name)
+            #dockerfile.append("COPY opt/xos/xos/%s_xosbuilder_migration_list /opt/xos/xos/xosbuilder_migration_list" % name)
+            file(os.path.join(self.build_dir, "opt/xos/xos/%s_xosbuilder_migration_list") % name, "w").write("\n".join(migration_list)+"\n")
+
+    def create_ui_dockerfile(self):
+        xos = XOS.objects.all()[0]
+        dockerfile_fn = "Dockerfile.UI"
+
+        app_list = []
+        migration_list = []
+
+        dockerfile = ["FROM %s" % xos.source_ui_image]
+        script = []
+        for controller in ServiceController.objects.all():
+            if self.check_controller_unready(controller):
+                 logger.warning("Controller %s has unready resources" % str(controller))
+                 continue
+
+            #dockerfile = dockerfile + self.get_controller_docker_lines(controller, self.UI_KINDS)
+            script = script + self.get_controller_script_lines(controller, self.UI_KINDS)
+            if controller.service_controller_resources.filter(kind="models").exists():
+                app_list.append("services." + controller.name)
+                migration_list.append(controller.name)
+
+        self.create_xos_app_data("ui", script, app_list, migration_list)
+
+        file(os.path.join(self.build_dir, "install-xos.sh"), "w").write("\n".join(script)+"\n")
+        dockerfile.append("COPY . /build/")
+        dockerfile.append("RUN bash /build/install-xos.sh")
+
+        file(os.path.join(self.build_dir, dockerfile_fn), "w").write("\n".join(dockerfile)+"\n")
+
+        return {"dockerfile_fn": dockerfile_fn,
+                "docker_image_name": "xosproject/xos-ui"}
+
+    def create_synchronizer_dockerfile(self, controller):
+        # bake in the synchronizer from this controller
+        sync_lines = self.get_controller_script_lines(controller, self.SYNC_CONTROLLER_KINDS)
+        if not sync_lines:
+            return []
+
+        dockerfile_fn = "Dockerfile.%s" % controller.name
+        dockerfile = ["FROM %s" % self.source_sync_image]
+        script = []
+
+        # Now bake in models from this controller as well as the others
+        # It's important to bake all services in, because some services'
+        # synchronizers may depend on models from another service.
+        app_list = []
+        for c in ServiceController.objects.all():
+            #dockerfile = dockerfile + self.get_controller_docker_lines(c, self.SYNC_ALLCONTROLLER_KINDS)
+            script = script + self.get_controller_script_lines(c, self.SYNC_ALLCONTROLLER_KINDS)
+            if controller.service_controller_resources.filter(kind="models").exists():
+                app_list.append("services." + c.name)
+
+        self.create_xos_app_data(controller.name, script, app_list, None)
+
+        script = script + sync_lines
+
+        file(os.path.join(self.build_dir, "install-%s.sh" % controller.name), "w").write("\n".join(script)+"\n")
+        dockerfile.append("COPY . /build/")
+        dockerfile.append("RUN bash /build/install-%s.sh" % controller.name)
+
+        file(os.path.join(self.build_dir, dockerfile_fn), "w").write("\n".join(dockerfile)+"\n")
+
+        return {"dockerfile_fn": dockerfile_fn,
+                "docker_image_name": "xosproject/xos-synchronizer-%s" % controller.name}
+
+    def create_docker_compose(self):
+         xos = XOS.objects.all()[0]
+
+         volume_list = []
+         for volume in xos.volumes.all():
+             volume_list.append({"host_path": volume.host_path,
+                                 "container_path": volume.container_path,
+                                 "read_only": volume.read_only})
+
+         containers = {}
+
+#         containers["xos_db"] = \
+#                            {"image": "xosproject/xos-postgres",
+#                             "expose": [5432]}
+
+         db_container_name = xos.docker_project_name + "_xos_db_1"
+
+         containers["xos_ui"] = \
+                            {"image": "xosproject/xos-ui",
+                             "command": "python /opt/xos/manage.py runserver 0.0.0.0:%d --insecure --makemigrations" % xos.ui_port,
+                             "ports": {"%d"%xos.ui_port : "%d"%xos.ui_port},
+                             #"links": ["xos_db"],
+                             "external_links": ["%s:%s" % (db_container_name, "xos_db")],
+                             "volumes": volume_list}
+
+#         containers["xos_bootstrap_ui"] = {"image": "xosproject/xos",
+#                             "command": "python /opt/xos/manage.py runserver 0.0.0.0:%d --insecure --makemigrations" % xos.bootstrap_ui_port,
+#                             "ports": {"%d"%xos.bootstrap_ui_port : "%d"%xos.bootstrap_ui_port},
+#                             #"external_links": ["%s:%s" % (db_container_name, "xos_db")],
+#                             "links": ["xos_db"],
+#                             "volumes": volume_list}
+
+         if not xos.frontend_only:
+             for c in ServiceController.objects.all():
+                 if self.check_controller_unready(c):
+                     logger.warning("Controller %s has unready resources" % str(c))
+                     continue
+
+                 if c.service_controller_resources.filter(kind="synchronizer").exists():
+                     if c.synchronizer_run and c.synchronizer_config:
+                         command = 'bash -c "sleep 120; cd /opt/xos/synchronizers/%s; python ./%s -C %s"' % (c.name, c.synchronizer_run, c.synchronizer_config)
+                     else:
+                         command = 'bash -c "sleep 120; cd /opt/xos/synchronizers/%s; bash ./run.sh"' % c.name
+
+                     containers["xos_synchronizer_%s" % c.name] = \
+                                    {"image": "xosproject/xos-synchronizer-%s" % c.name,
+                                     "command": command,
+                                     "external_links": ["%s:%s" % (db_container_name, "xos_db")],
+                                     #"links": ["xos_db"],
+                                     "volumes": volume_list}
+
+         vars = { "containers": containers }
+
+         template_loader = jinja2.FileSystemLoader( "/opt/xos/synchronizers/onboarding/templates/" )
+         template_env = jinja2.Environment(loader=template_loader)
+         template = template_env.get_template("docker-compose.yml.j2")
+         buffer = template.render(vars)
+
+         if not os.path.exists("/opt/xos/synchronizers/onboarding/docker-compose"):
+             os.makedirs("/opt/xos/synchronizers/onboarding/docker-compose")
+         file("/opt/xos/synchronizers/onboarding/docker-compose/docker-compose.yml", "w").write(buffer)
+
+#    def build_xos(self):
+#        dockerfiles=[]
+#        dockerfiles.append(self.create_ui_dockerfile())
+#
+#        for controller in ServiceController.objects.all():
+#            dockerfiles.append(self.create_synchronizer_dockerfile(controller))
+
+
+
diff --git a/xos/synchronizers/openstack/__init__.py b/xos/synchronizers/openstack/__init__.py
new file mode 100644
index 0000000..e56cd39
--- /dev/null
+++ b/xos/synchronizers/openstack/__init__.py
@@ -0,0 +1,36 @@
+from xos.config import Config
+
+try:
+    observer_disabled = Config().observer_disabled
+except:
+    observer_disabled = False
+
+def EnableObserver(x):
+    """ used for manage.py --noobserver """
+    global observer_disabled
+    observer_disabled = not x
+
+print_once = True
+
+def notify_observer(model=None, delete=False, pk=None, model_dict={}):
+    if (observer_disabled):
+        global print_once
+        if (print_once):
+            print "The observer is disabled"
+            print_once = False
+        return
+
+    try:
+        from .event_manager import EventSender
+        if (model and delete):
+            if hasattr(model,"__name__"):
+                modelName = model.__name__
+            else:
+                modelName = model.__class__.__name__
+            EventSender().fire(delete_flag = delete, model = modelName, pk = pk, model_dict=model_dict)
+        else:
+            EventSender().fire()
+    except Exception,e:
+        print "Exception in Observer. This should not disrupt the front end. %s"%str(e)
+
+
diff --git a/xos/synchronizers/openstack/error_mapper.py b/xos/synchronizers/openstack/error_mapper.py
new file mode 100644
index 0000000..9eb878d
--- /dev/null
+++ b/xos/synchronizers/openstack/error_mapper.py
@@ -0,0 +1,25 @@
+from xos.config import Config
+from xos.logger import Logger, logging, logger
+
+class ErrorMapper:
+	def __init__(self, error_map_file):
+		self.error_map = {}
+		try:
+			error_map_lines = open(error_map_file).read().splitlines()
+			for l in error_map_lines:
+				if (not l.startswith('#')):
+					splits = l.split('->')
+					k,v = map(lambda i:i.rstrip(),splits)
+					self.error_map[k]=v
+		except:
+			logging.info('Could not read error map')
+
+
+	def map(self, error):
+		return self.error_map[error]
+
+
+
+
+
+
diff --git a/xos/synchronizers/openstack/model_policies/__init__.py b/xos/synchronizers/openstack/model_policies/__init__.py
new file mode 100644
index 0000000..36c6e25
--- /dev/null
+++ b/xos/synchronizers/openstack/model_policies/__init__.py
@@ -0,0 +1,12 @@
+from .model_policy_Slice import *
+from .model_policy_Instance import *
+from .model_policy_User import *
+from .model_policy_Network import *
+from .model_policy_Site import *
+from .model_policy_SitePrivilege import *
+from .model_policy_SlicePrivilege import *
+from .model_policy_ControllerSlice import *
+from .model_policy_ControllerSite import *
+from .model_policy_ControllerUser import *
+from .model_policy_Controller import *
+from .model_policy_Image import *
diff --git a/xos/synchronizers/openstack/model_policies/model_policy_Controller.py b/xos/synchronizers/openstack/model_policies/model_policy_Controller.py
new file mode 100644
index 0000000..c62b612
--- /dev/null
+++ b/xos/synchronizers/openstack/model_policies/model_policy_Controller.py
@@ -0,0 +1,62 @@
+
+def handle(controller):
+    from core.models import Controller, Site, ControllerSite, Slice, ControllerSlice, User, ControllerUser, ControllerImages, ControllerNetwork, Image, Network
+    from collections import defaultdict
+
+    # relations for all sites
+    ctrls_by_site = defaultdict(list)
+    ctrl_sites = ControllerSite.objects.all()
+    for ctrl_site in ctrl_sites:
+        ctrls_by_site[ctrl_site.site].append(ctrl_site.controller)
+    sites = Site.objects.all()
+    for site in sites:
+        if site not in ctrls_by_site or \
+            controller not in ctrls_by_site[site]:
+            controller_site = ControllerSite(controller=controller, site=site)
+            controller_site.save()
+    # relations for all slices
+    ctrls_by_slice = defaultdict(list)
+    ctrl_slices = ControllerSlice.objects.all()
+    for ctrl_slice in ctrl_slices:
+        ctrls_by_slice[ctrl_slice.slice].append(ctrl_slice.controller)
+    slices = Slice.objects.all()
+    for slice in slices:
+        if slice not in ctrls_by_slice or \
+            controller not in ctrls_by_slice[slice]:
+            controller_slice = ControllerSlice(controller=controller, slice=slice)
+            controller_slice.save()
+    # relations for all users
+    ctrls_by_user = defaultdict(list)
+    ctrl_users = ControllerUser.objects.all()
+    for ctrl_user in ctrl_users:
+        ctrls_by_user[ctrl_user.user].append(ctrl_user.controller)
+    users = User.objects.all()
+    for user in users:
+        if user not in ctrls_by_user or \
+            controller not in ctrls_by_user[user]:
+            controller_user = ControllerUser(controller=controller, user=user)
+            controller_user.save()
+    # relations for all networks
+    ctrls_by_network = defaultdict(list)
+    ctrl_networks = ControllerNetwork.objects.all()
+    for ctrl_network in ctrl_networks:
+        ctrls_by_network[ctrl_network.network].append(ctrl_network.controller)
+    networks = Network.objects.all()
+    for network in networks:
+        if network not in ctrls_by_network or \
+            controller not in ctrls_by_network[network]:
+            controller_network = ControllerNetwork(controller=controller, network=network)
+            if network.subnet and network.subnet.strip():
+                controller_network.subnet = network.subnet.strip()
+            controller_network.save()
+    # relations for all images
+    ctrls_by_image = defaultdict(list)
+    ctrl_images = ControllerImages.objects.all()
+    for ctrl_image in ctrl_images:
+        ctrls_by_image[ctrl_image.image].append(ctrl_image.controller)
+    images = Image.objects.all()
+    for image in images:
+        if image not in ctrls_by_image or \
+            controller not in ctrls_by_image[image]:
+            controller_image = ControllerImages(controller=controller, image=image)
+            controller_image.save()
diff --git a/xos/synchronizers/openstack/model_policies/model_policy_ControllerSite.py b/xos/synchronizers/openstack/model_policies/model_policy_ControllerSite.py
new file mode 100644
index 0000000..4b76080
--- /dev/null
+++ b/xos/synchronizers/openstack/model_policies/model_policy_ControllerSite.py
@@ -0,0 +1,16 @@
+def handle(controller_site):
+    from core.models import ControllerSite, Site
+   
+    try:
+        my_status_code = int(controller_site.backend_status[0])
+        try:
+            his_status_code = int(controller_site.site.backend_status[0])
+        except:
+            his_status_code = 0
+ 
+        if (my_status_code not in [0,his_status_code]):
+            controller_site.site.backend_status = controller_site.backend_status
+            controller_site.site.save(update_fields = ['backend_status'])
+    except Exception,e:
+        print str(e)	
+        pass
diff --git a/xos/synchronizers/openstack/model_policies/model_policy_ControllerSlice.py b/xos/synchronizers/openstack/model_policies/model_policy_ControllerSlice.py
new file mode 100644
index 0000000..bfe7995
--- /dev/null
+++ b/xos/synchronizers/openstack/model_policies/model_policy_ControllerSlice.py
@@ -0,0 +1,25 @@
+def handle(controller_slice):
+    from core.models import ControllerSlice, Slice
+   
+    try:
+        my_status_code = int(controller_slice.backend_status[0])
+        try:
+            his_status_code = int(controller_slice.slice.backend_status[0])
+        except:
+            his_status_code = 0
+ 
+        fields = []
+        if (my_status_code not in [0,his_status_code]):
+            controller_slice.slice.backend_status = controller_slice.backend_status
+            fields+=['backend_status']
+
+        if (controller_slice.backend_register != controller_slice.slice.backend_register):
+            controller_slice.slice.backend_register = controller_slice.backend_register
+            fields+=['backend_register']
+
+        controller_slice.slice.save(update_fields = fields)
+
+        
+    except Exception,e:
+        print str(e)	
+        pass
diff --git a/xos/synchronizers/openstack/model_policies/model_policy_ControllerUser.py b/xos/synchronizers/openstack/model_policies/model_policy_ControllerUser.py
new file mode 100644
index 0000000..b69c9b8
--- /dev/null
+++ b/xos/synchronizers/openstack/model_policies/model_policy_ControllerUser.py
@@ -0,0 +1,16 @@
+def handle(controller_user):
+    from core.models import ControllerUser, User
+   
+    try:
+        my_status_code = int(controller_user.backend_status[0])
+        try:
+            his_status_code = int(controller_user.user.backend_status[0])
+        except:
+            his_status_code = 0
+ 
+        if (my_status_code not in [0,his_status_code]):
+            controller_user.user.backend_status = controller_user.backend_status
+            controller_user.user.save(update_fields = ['backend_status'])
+    except Exception,e:
+        print str(e)	
+        pass
diff --git a/xos/synchronizers/openstack/model_policies/model_policy_Image.py b/xos/synchronizers/openstack/model_policies/model_policy_Image.py
new file mode 100644
index 0000000..c77d5bb
--- /dev/null
+++ b/xos/synchronizers/openstack/model_policies/model_policy_Image.py
@@ -0,0 +1,17 @@
+def handle(image):
+    from core.models import Controller, ControllerImages, Image
+    from collections import defaultdict
+
+    if (image.kind == "container"):
+        # container images do not get instantiated
+        return
+
+    controller_images = ControllerImages.objects.filter(image=image)
+    existing_controllers = [cs.controller for cs in controller_images] 
+    
+    all_controllers = Controller.objects.all() 
+    for controller in all_controllers:
+        if controller not in existing_controllers:
+            sd = ControllerImages(image=image, controller=controller)
+            sd.save()
+
diff --git a/xos/synchronizers/openstack/model_policies/model_policy_Instance.py b/xos/synchronizers/openstack/model_policies/model_policy_Instance.py
new file mode 100644
index 0000000..dd1a8d5
--- /dev/null
+++ b/xos/synchronizers/openstack/model_policies/model_policy_Instance.py
@@ -0,0 +1,58 @@
+def handle_container_on_metal(instance):
+        from core.models import Instance, Flavor, Port, Image
+
+        print "MODEL POLICY: instance", instance, "handle container_on_metal"
+
+        if instance.deleted:
+            return
+
+        if (instance.isolation in ["container"]) and (instance.slice.network not in ["host", "bridged"]):
+            # Our current docker-on-metal network strategy requires that there be some
+            # VM on the server that connects to the networks, so that
+            # the containers can piggyback off of that configuration.
+            if not Instance.objects.filter(slice=instance.slice, node=instance.node, isolation="vm").exists():
+                flavors = Flavor.objects.filter(name="m1.small")
+                if not flavors:
+                    raise XOSConfigurationError("No m1.small flavor")
+
+                images = Image.objects.filter(kind="vm")
+
+                companion_instance = Instance(slice = instance.slice,
+                                node = instance.node,
+                                image = images[0],
+                                creator = instance.creator,
+                                deployment = instance.node.site_deployment.deployment,
+                                flavor = flavors[0])
+                companion_instance.save()
+
+                print "MODEL POLICY: instance", instance, "created companion", companion_instance
+
+        # Add the ports for the container
+        for network in instance.slice.networks.all():
+            # hmmm... The NAT ports never become ready, because sync_ports never
+            # instantiates them. Need to think about this.
+            print "MODEL POLICY: instance", instance, "handling network", network
+            if (network.name.endswith("-nat")):
+                continue
+
+            if not Port.objects.filter(network=network, instance=instance).exists():
+                port = Port(network = network, instance=instance)
+                port.save()
+                print "MODEL POLICY: instance", instance, "created port", port
+
+def handle(instance):
+    from core.models import Controller, ControllerSlice, ControllerNetwork, NetworkSlice
+
+    networks = [ns.network for ns in NetworkSlice.objects.filter(slice=instance.slice)]
+    controller_networks = ControllerNetwork.objects.filter(network__in=networks,
+                                                                controller=instance.node.site_deployment.controller)
+
+    for cn in controller_networks:
+        if (cn.lazy_blocked):
+                print "MODEL POLICY: instance", instance, "unblocking network", cn.network
+		cn.lazy_blocked=False
+		cn.backend_register = '{}'
+		cn.save()
+
+    if (instance.isolation in ["container", "container_vm"]):
+        handle_container_on_metal(instance)
diff --git a/xos/synchronizers/openstack/model_policies/model_policy_Network.py b/xos/synchronizers/openstack/model_policies/model_policy_Network.py
new file mode 100644
index 0000000..9f9e5fd
--- /dev/null
+++ b/xos/synchronizers/openstack/model_policies/model_policy_Network.py
@@ -0,0 +1,30 @@
+from core.models import *
+
+def handle(network):
+	from core.models import ControllerSlice,ControllerNetwork, Network
+	from collections import defaultdict
+
+        # network = Network.get(network_id)
+	# network controllers are not visible to users. We must ensure
+	# networks are deployed at all deploymets available to their slices.
+	slice_controllers = ControllerSlice.objects.all()
+	slice_deploy_lookup = defaultdict(list)
+	for slice_controller in slice_controllers:
+		slice_deploy_lookup[slice_controller.slice].append(slice_controller.controller)
+
+	network_controllers = ControllerNetwork.objects.all()
+	network_deploy_lookup = defaultdict(list)
+	for network_controller in network_controllers:
+		network_deploy_lookup[network_controller.network].append(network_controller.controller)
+
+	expected_controllers = slice_deploy_lookup[network.owner]
+	for expected_controller in expected_controllers:
+		if network not in network_deploy_lookup or \
+		  expected_controller not in network_deploy_lookup[network]:
+			nd = ControllerNetwork(network=network, controller=expected_controller, lazy_blocked=True)
+                        if network.subnet:
+                            # XXX: Possibly unpredictable behavior if there is
+                            # more than one ControllerNetwork and the subnet
+                            # is specified.
+                            nd.subnet = network.subnet
+			nd.save()
diff --git a/xos/synchronizers/openstack/model_policies/model_policy_Site.py b/xos/synchronizers/openstack/model_policies/model_policy_Site.py
new file mode 100644
index 0000000..23010a2
--- /dev/null
+++ b/xos/synchronizers/openstack/model_policies/model_policy_Site.py
@@ -0,0 +1,14 @@
+
+def handle(site):
+    from core.models import Controller, ControllerSite, Site 
+
+    # site = Site.get(site_id)
+    # make sure site has a ControllerSite record for each controller
+    ctrl_sites = ControllerSite.objects.filter(site=site)
+    existing_controllers = [cs.controller for cs in ctrl_sites]
+
+    all_controllers = Controller.objects.all()
+    for ctrl in all_controllers:
+        if ctrl not in existing_controllers:
+            ctrl_site = ControllerSite(controller=ctrl, site=site)
+            ctrl_site.save() 
diff --git a/xos/synchronizers/openstack/model_policies/model_policy_SitePrivilege.py b/xos/synchronizers/openstack/model_policies/model_policy_SitePrivilege.py
new file mode 100644
index 0000000..d9c6a1e
--- /dev/null
+++ b/xos/synchronizers/openstack/model_policies/model_policy_SitePrivilege.py
@@ -0,0 +1,15 @@
+def handle(site_privilege):
+    from core.models import Controller, SitePrivilege, ControllerSitePrivilege
+    
+    # site_privilege = SitePrivilege.get(site_privilege_id)
+    # apply site privilage at all controllers
+    controller_site_privileges = ControllerSitePrivilege.objects.filter(
+        site_privilege = site_privilege,
+        )
+    existing_controllers = [sp.controller for sp in controller_site_privileges]
+    all_controllers = Controller.objects.all()
+    for controller in all_controllers:
+        if controller not in existing_controllers:
+            ctrl_site_priv = ControllerSitePrivilege(controller=controller, site_privilege=site_privilege)
+            ctrl_site_priv.save()  
+
diff --git a/xos/synchronizers/openstack/model_policies/model_policy_Slice.py b/xos/synchronizers/openstack/model_policies/model_policy_Slice.py
new file mode 100644
index 0000000..088d583
--- /dev/null
+++ b/xos/synchronizers/openstack/model_policies/model_policy_Slice.py
@@ -0,0 +1,102 @@
+from xos.config import Config
+
+def handle_delete(slice):
+    from core.models import Controller, ControllerSlice, SiteDeployment, Network, NetworkSlice,NetworkTemplate, Slice
+    from collections import defaultdict
+
+    public_nets = []
+    private_net = None
+    networks = Network.objects.filter(owner=slice)
+
+    for n in networks:
+        n.delete()	
+    
+    # Note that sliceprivileges and slicecontrollers are autodeleted, through the dependency graph
+
+def handle(slice):
+    from core.models import Controller, ControllerSlice, SiteDeployment, Network, NetworkSlice,NetworkTemplate, Slice
+    from collections import defaultdict
+
+    # only create nat_net if not using VTN
+    support_nat_net = not getattr(Config(), "networking_use_vtn", False)
+
+    print "MODEL POLICY: slice", slice
+
+    # slice = Slice.get(slice_id)
+
+    controller_slices = ControllerSlice.objects.filter(slice=slice)
+    existing_controllers = [cs.controller for cs in controller_slices] 
+        
+    print "MODEL POLICY: slice existing_controllers=", existing_controllers
+
+    all_controllers = Controller.objects.all()
+    for controller in all_controllers:
+        if controller not in existing_controllers:
+            print "MODEL POLICY: slice adding controller", controller
+            sd = ControllerSlice(slice=slice, controller=controller)
+            sd.save()
+
+    if slice.network in ["host", "bridged"]:
+        # Host and Bridged docker containers need no networks and they will
+        # only get in the way.
+        print "MODEL POLICY: Skipping network creation"
+    elif slice.network in ["noauto"]:
+        # do nothing
+        pass
+    else:
+        # make sure slice has at least 1 public and 1 private networkd
+        public_nets = []
+        private_nets = []
+        networks = Network.objects.filter(owner=slice)
+        for network in networks:
+            if not network.autoconnect:
+                continue
+            if network.template.name == 'Public dedicated IPv4':
+                public_nets.append(network)
+            elif network.template.name == 'Public shared IPv4':
+                public_nets.append(network)
+            elif network.template.name == 'Private':
+                private_nets.append(network)
+        if support_nat_net and (not public_nets):
+            # ensure there is at least one public network, and default it to dedicated
+            nat_net = Network(
+                    name = slice.name+'-nat',
+                        template = NetworkTemplate.objects.get(name='Public shared IPv4'),
+                    owner = slice
+                    )
+            if slice.exposed_ports:
+                nat_net.ports = slice.exposed_ports
+            nat_net.save()
+            public_nets.append(nat_net)
+            print "MODEL POLICY: slice", slice, "made nat-net"
+
+        if not private_nets:
+            private_net = Network(
+                name = slice.name+'-private',
+                template = NetworkTemplate.objects.get(name='Private'),
+                owner = slice
+            )
+            private_net.save()
+            print "MODEL POLICY: slice", slice, "made private net"
+            private_nets = [private_net]
+        # create slice networks
+        public_net_slice = None
+        private_net_slice = None
+        net_slices = NetworkSlice.objects.filter(slice=slice, network__in=private_nets+public_nets)
+        for net_slice in net_slices:
+            if net_slice.network in public_nets:
+                public_net_slice = net_slice
+            elif net_slice.network in private_nets:
+                private_net_slice = net_slice
+        if support_nat_net and (not public_net_slice):
+            public_net_slice = NetworkSlice(slice=slice, network=public_nets[0])
+            public_net_slice.save()
+            print "MODEL POLICY: slice", slice, "made public_net_slice"
+        if not private_net_slice:
+            private_net_slice = NetworkSlice(slice=slice, network=private_nets[0])
+            private_net_slice.save()
+            print "MODEL POLICY: slice", slice, "made private_net_slice"
+
+    print "MODEL POLICY: slice", slice, "DONE"
+
+
diff --git a/xos/synchronizers/openstack/model_policies/model_policy_SlicePrivilege.py b/xos/synchronizers/openstack/model_policies/model_policy_SlicePrivilege.py
new file mode 100644
index 0000000..bca7f22
--- /dev/null
+++ b/xos/synchronizers/openstack/model_policies/model_policy_SlicePrivilege.py
@@ -0,0 +1,15 @@
+def handle(slice_privilege):
+    from core.models import Controller, SlicePrivilege, ControllerSlicePrivilege
+   
+    # slice_privilege = SlicePrivilege.get(slice_privilege_id) 
+    # apply slice privilage at all controllers
+    controller_slice_privileges = ControllerSlicePrivilege.objects.filter(
+        slice_privilege = slice_privilege,
+        )
+    existing_controllers = [sp.controller for sp in controller_slice_privileges]
+    all_controllers = Controller.objects.all()
+    for controller in all_controllers:
+        if controller not in existing_controllers:
+            ctrl_slice_priv = ControllerSlicePrivilege(controller=controller, slice_privilege=slice_privilege)
+            ctrl_slice_priv.save()  
+
diff --git a/xos/synchronizers/openstack/model_policies/model_policy_Sliver.py b/xos/synchronizers/openstack/model_policies/model_policy_Sliver.py
new file mode 100644
index 0000000..a13428d
--- /dev/null
+++ b/xos/synchronizers/openstack/model_policies/model_policy_Sliver.py
@@ -0,0 +1,13 @@
+
+def handle(instance):
+    from core.models import Controller, ControllerSlice, ControllerNetwork, NetworkSlice
+
+    networks = [ns.network for ns in NetworkSlice.objects.filter(slice=instance.slice)]
+    controller_networks = ControllerNetwork.objects.filter(network__in=networks,
+                                                                controller=instance.node.site_deployment.controller)
+
+    for cn in controller_networks:
+        if (cn.lazy_blocked):	
+		cn.lazy_blocked=False
+		cn.backend_register = '{}'
+		cn.save()
diff --git a/xos/synchronizers/openstack/model_policies/model_policy_User.py b/xos/synchronizers/openstack/model_policies/model_policy_User.py
new file mode 100644
index 0000000..8d14244
--- /dev/null
+++ b/xos/synchronizers/openstack/model_policies/model_policy_User.py
@@ -0,0 +1,14 @@
+def handle(user):
+    from core.models import Controller, ControllerSite, ControllerUser, User
+    from collections import defaultdict
+
+    # user = User.get(user_id)
+    
+    controller_users = ControllerUser.objects.filter(user=user)
+    existing_controllers = [cu.controller for cu in controller_users]
+    all_controllers = Controller.objects.all()
+    for controller in all_controllers:
+        if controller not in existing_controllers:
+            ctrl_user = ControllerUser(controller=controller, user=user)
+            ctrl_user.save()  
+
diff --git a/xos/synchronizers/openstack/openstacksyncstep.py b/xos/synchronizers/openstack/openstacksyncstep.py
new file mode 100644
index 0000000..46056cf
--- /dev/null
+++ b/xos/synchronizers/openstack/openstacksyncstep.py
@@ -0,0 +1,14 @@
+import os
+import base64
+from synchronizers.base.syncstep import SyncStep
+
+class OpenStackSyncStep(SyncStep):
+    """ XOS Sync step for copying data to OpenStack 
+    """ 
+    
+    def __init__(self, **args):
+        SyncStep.__init__(self, **args)
+        return
+
+    def __call__(self, **args):
+        return self.call(**args)
diff --git a/xos/synchronizers/openstack/steps/__init__.py b/xos/synchronizers/openstack/steps/__init__.py
new file mode 100644
index 0000000..c70b0c0
--- /dev/null
+++ b/xos/synchronizers/openstack/steps/__init__.py
@@ -0,0 +1,6 @@
+#from .sync_controller_sites import SyncControllerSites
+#from .sync_controller_slices import SyncControllerSlices
+#from .sync_controller_users import SyncControllerUsers
+#from .sync_controller_site_privileges import SyncControllerSitePrivileges
+#from .sync_controller_slice_privileges import SyncControllerSlicePrivileges
+#from .sync_controller_networks import SyncControllerNetworks
diff --git a/xos/synchronizers/openstack/steps/delete_slivers.yaml b/xos/synchronizers/openstack/steps/delete_slivers.yaml
new file mode 100644
index 0000000..fa6b879
--- /dev/null
+++ b/xos/synchronizers/openstack/steps/delete_slivers.yaml
@@ -0,0 +1,8 @@
+---
+- hosts: 127.0.0.1
+  connection: local
+  tasks:
+
+  - nova_compute:
+      state: absent
+      name: {{ name }}
diff --git a/xos/synchronizers/openstack/steps/purge_disabled_users.py b/xos/synchronizers/openstack/steps/purge_disabled_users.py
new file mode 100644
index 0000000..6b1dac3
--- /dev/null
+++ b/xos/synchronizers/openstack/steps/purge_disabled_users.py
@@ -0,0 +1,25 @@
+import os
+import base64
+import datetime
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.openstacksyncstep import OpenStackSyncStep
+from core.models.user import User
+from xos.logger import observer_logger as logger
+
+#class SyncRoles(OpenStackSyncStep):
+#    provides=[User]
+#    requested_interval=0
+#    observes=User
+#
+#    def fetch_pending(self, deleted):
+#        if (deleted):
+#            # users marked as deleted
+#            return User.deleted_objects.all()
+#        else:
+#            # disabled users that haven't been updated in over a week
+#            one_week_ago = datetime.datetime.now() - datetime.timedelta(days=7)
+#            return User.objects.filter(is_active=False, updated__gt=one_week_ago)
+#
+#    def sync_record(self, user):
+#        user.delete()
diff --git a/xos/synchronizers/openstack/steps/sliver.yaml b/xos/synchronizers/openstack/steps/sliver.yaml
new file mode 100644
index 0000000..e630415
--- /dev/null
+++ b/xos/synchronizers/openstack/steps/sliver.yaml
@@ -0,0 +1,17 @@
+---
+- hosts: 127.0.0.1
+  connection: local
+  tasks:
+  - nova_compute:
+       state: present
+       auth_url: http://172.31.38.128:5000/v2.0/
+       login_username: admin
+       login_password: 6a789bf69dd647e2
+       login_tenant_name: admin
+       name: gloopy
+       image_id: 3ee851df-b35a-41c5-8551-f681e7209095
+       key_name: boo
+       wait_for: 200
+       flavor_id: 3
+       nics:
+         - net-id: d1de537b-80dc-4c1b-aa5f-4a197b33b5f6
diff --git a/xos/synchronizers/openstack/steps/sync_container.py b/xos/synchronizers/openstack/steps/sync_container.py
new file mode 100644
index 0000000..41e1305
--- /dev/null
+++ b/xos/synchronizers/openstack/steps/sync_container.py
@@ -0,0 +1,162 @@
+import hashlib
+import os
+import socket
+import sys
+import base64
+import time
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.SyncInstanceUsingAnsible import SyncInstanceUsingAnsible
+from synchronizers.base.syncstep import SyncStep, DeferredException
+from synchronizers.base.ansible import run_template_ssh
+from core.models import Service, Slice, Instance
+from xos.logger import Logger, logging
+
+# hpclibrary will be in steps/..
+parentdir = os.path.join(os.path.dirname(__file__),"..")
+sys.path.insert(0,parentdir)
+
+logger = Logger(level=logging.INFO)
+
+class SyncContainer(SyncInstanceUsingAnsible):
+    provides=[Instance]
+    observes=Instance
+    requested_interval=0
+    template_name = "sync_container.yaml"
+
+    def __init__(self, *args, **kwargs):
+        super(SyncContainer, self).__init__(*args, **kwargs)
+
+    def fetch_pending(self, deletion=False):
+        objs = super(SyncContainer, self).fetch_pending(deletion)
+        objs = [x for x in objs if x.isolation in ["container", "container_vm"]]
+        return objs
+
+    def get_instance_port(self, container_port):
+        for p in container_port.network.links.all():
+            if (p.instance) and (p.instance.isolation=="vm") and (p.instance.node == container_port.instance.node) and (p.mac):
+                return p
+        return None
+
+    def get_parent_port_mac(self, instance, port):
+        if not instance.parent:
+            raise Exception("instance has no parent")
+        for parent_port in instance.parent.ports.all():
+            if parent_port.network == port.network:
+                if not parent_port.mac:
+                     raise DeferredException("parent port on network %s does not have mac yet" % parent_port.network.name)
+                return parent_port.mac
+        raise Exception("failed to find corresponding parent port for network %s" % port.network.name)
+
+    def get_ports(self, o):
+        i=0
+        ports = []
+        if (o.slice.network in ["host", "bridged"]):
+            pass # no ports in host or bridged mode
+        else:
+            for port in o.ports.all():
+                if (not port.ip):
+                    # 'unmanaged' ports may have an ip, but no mac
+                    # XXX: are there any ports that have a mac but no ip?
+                    raise DeferredException("Port on network %s is not yet ready" % port.network.name)
+
+                pd={}
+                pd["mac"] = port.mac or ""
+                pd["ip"] = port.ip or ""
+                pd["xos_network_id"] = port.network.id
+
+                if port.network.name == "wan_network":
+                    if port.ip:
+                        (a, b, c, d) = port.ip.split('.')
+                        pd["mac"] = "02:42:%02x:%02x:%02x:%02x" % (int(a), int(b), int(c), int(d))
+
+
+                if o.isolation == "container":
+                    # container on bare metal
+                    instance_port = self.get_instance_port(port)
+                    if not instance_port:
+                        raise DeferredException("No instance on slice for port on network %s" % port.network.name)
+
+                    pd["snoop_instance_mac"] = instance_port.mac
+                    pd["snoop_instance_id"] = instance_port.instance.instance_id
+                    pd["src_device"] = ""
+                    pd["bridge"] = "br-int"
+                else:
+                    # container in VM
+                    pd["snoop_instance_mac"] = ""
+                    pd["snoop_instance_id"] = ""
+                    pd["parent_mac"] = self.get_parent_port_mac(o, port)
+                    pd["bridge"] = ""
+
+                for (k,v) in port.get_parameters().items():
+                    pd[k] = v
+
+                ports.append(pd)
+
+            # for any ports that don't have a device, assign one
+            used_ports = [x["device"] for x in ports if ("device" in x)]
+            avail_ports = ["eth%d"%i for i in range(0,64) if ("eth%d"%i not in used_ports)]
+            for port in ports:
+                if not port.get("device",None):
+                    port["device"] = avail_ports.pop(0)
+
+        return ports
+
+    def get_extra_attributes(self, o):
+        fields={}
+        fields["ansible_tag"] = "container-%s" % str(o.id)
+        if o.image.tag:
+            fields["docker_image"] = o.image.path + ":" + o.image.tag
+        else:
+            fields["docker_image"] = o.image.path
+        fields["ports"] = self.get_ports(o)
+        if o.volumes:
+            fields["volumes"] = [x.strip() for x in o.volumes.split(",")]
+        else:
+            fields["volumes"] = ""
+        fields["network_method"] = o.slice.network or "default"
+        return fields
+
+    def sync_record(self, o):
+        logger.info("sync'ing object %s" % str(o),extra=o.tologdict())
+
+        fields = self.get_ansible_fields(o)
+
+        # If 'o' defines a 'sync_attributes' list, then we'll copy those
+        # attributes into the Ansible recipe's field list automatically.
+        if hasattr(o, "sync_attributes"):
+            for attribute_name in o.sync_attributes:
+                fields[attribute_name] = getattr(o, attribute_name)
+
+        fields.update(self.get_extra_attributes(o))
+
+        self.run_playbook(o, fields)
+
+        o.instance_id = fields["container_name"]
+        o.instance_name = fields["container_name"]
+
+        o.save()
+
+    def delete_record(self, o):
+        logger.info("delete'ing object %s" % str(o),extra=o.tologdict())
+
+        fields = self.get_ansible_fields(o)
+
+        # If 'o' defines a 'sync_attributes' list, then we'll copy those
+        # attributes into the Ansible recipe's field list automatically.
+        if hasattr(o, "sync_attributes"):
+            for attribute_name in o.sync_attributes:
+                fields[attribute_name] = getattr(o, attribute_name)
+
+        fields.update(self.get_extra_attributes(o))
+
+        self.run_playbook(o, fields, "teardown_container.yaml")
+
+    def run_playbook(self, o, fields, template_name=None):
+        if not template_name:
+            template_name = self.template_name
+        tStart = time.time()
+        run_template_ssh(template_name, fields, path="container")
+        logger.info("playbook execution time %d" % int(time.time()-tStart),extra=o.tologdict())
+
+
diff --git a/xos/synchronizers/openstack/steps/sync_container.yaml b/xos/synchronizers/openstack/steps/sync_container.yaml
new file mode 100644
index 0000000..4ae4eb2
--- /dev/null
+++ b/xos/synchronizers/openstack/steps/sync_container.yaml
@@ -0,0 +1,124 @@
+---
+- hosts: {{ instance_name }}
+  gather_facts: False
+  connection: ssh
+  user: {{ username }}
+  sudo: yes
+
+  vars:
+    container_name: {{ container_name }}
+    docker_image: {{ docker_image }}
+    network_method: {{ network_method }}
+    ports:
+    {% for port in ports %}
+       - device: {{ port.device }}
+         xos_network_id: {{ port.xos_network_id }}
+         mac: {{ port.mac|default("") }}
+         ip: {{ port.ip }}
+         snoop_instance_mac: {{ port.snoop_instance_mac }}
+         snoop_instance_id: {{ port.snoop_instance_id }}
+         parent_mac: {{ port.parent_mac|default("") }}
+         s_tag: {{ port.s_tag|default("")  }}
+         c_tag: {{ port.c_tag|default("") }}
+         next_hop: {{ port.next_hop|default("") }}
+         bridge: {{ port.bridge }}
+    {% endfor %}
+    volumes:
+    {% for volume in volumes %}
+       - {{ volume }}
+    {% endfor %}
+
+  tasks:
+
+#  - name: Fix /etc/hosts
+#    lineinfile:
+#      dest=/etc/hosts
+#      regexp="127.0.0.1 localhost"
+#      line="127.0.0.1 localhost {{ instance_hostname }}"
+
+  - name: Add repo key
+    apt_key:
+      keyserver=hkp://pgp.mit.edu:80
+      id=58118E89F3A912897C070ADBF76221572C52609D
+
+  - name: Install Docker repo
+    apt_repository:
+      repo="deb https://apt.dockerproject.org/repo ubuntu-trusty main"
+      state=present
+
+  - name: Install Docker
+    apt:
+      name={{ '{{' }} item {{ '}}' }}
+      state=latest
+      update_cache=yes
+    with_items:
+# XXX docker 1.10 is not working on cloudlab
+#    - docker-engine
+    - python-pip
+    - python-httplib2
+
+  - name: Install Docker 1.9.1
+    apt:
+      name={{ '{{' }} item {{ '}}' }}
+      update_cache=yes
+    with_items:
+    - docker-engine=1.9.1-0~trusty
+
+  # Something is installing a requests library that is incompative with pip, and
+  # will cause this recipe to fail next time it tries to run pip. Only the one
+  # in /usr/local/lib is bad. There's still a good one in /usr/lib
+  - name: check if bad requests library installed
+    stat: path=/usr/local/lib/python2.7/dist-packages/requests
+    register: bad_requests
+
+  - name: remove bad request library
+    shell: mv /usr/local/lib/python2.7/dist-packages/requests /usr/local/lib/python2.7/dist-packages/requests-bad
+    when: bad_requests.stat.exists == True
+
+  - name: Install docker-py
+    pip:
+      name=docker-py
+      state=latest
+
+  - name: install Pipework
+    get_url: url=https://raw.githubusercontent.com/jpetazzo/pipework/master/pipework
+       dest=/usr/local/bin/pipework
+       mode=0755
+
+#  - name: Start Container
+#    docker:
+#      docker_api_version: "1.18"
+#      name: {{ container_name }}
+#      # was: reloaded
+#      state: running
+#      image: {{ docker_image }}
+
+  - name: check if systemd is installed
+    stat: path=/usr/bin/systemctl
+    register: systemctl
+
+  - name: container upstart
+    template: src=/opt/xos/synchronizers/openstack/templates/container.conf.j2 dest=/etc/init/container-{{ container_name }}.conf
+
+  - name: container systemd
+    template: src=/opt/xos/synchronizers/openstack/templates/container.service.j2 dest=/lib/systemd/system/container-{{ container_name }}.service
+
+  - name: container startup script
+    template: src=/opt/xos/synchronizers/openstack/templates/start-container.sh.j2 dest=/usr/local/sbin/start-container-{{ container_name }}.sh mode=0755
+
+  - name: container teardown script
+    template: src=/opt/xos/synchronizers/openstack/templates/stop-container.sh.j2 dest=/usr/local/sbin/stop-container-{{ container_name }}.sh mode=0755
+
+  - name: restart systemd
+    shell: systemctl daemon-reload
+    when: systemctl.stat.exists == True
+
+{% if ports %}
+  - name: make sure bridges are setup
+    shell: ifconfig {{ '{{' }} item.bridge {{ '}}' }}
+    with_items: "ports"
+{% endif %}
+
+  - name: Make sure container is running
+    service: name=container-{{ container_name }} state=started
+
diff --git a/xos/synchronizers/openstack/steps/sync_controller_images.py b/xos/synchronizers/openstack/steps/sync_controller_images.py
new file mode 100644
index 0000000..c1e5136
--- /dev/null
+++ b/xos/synchronizers/openstack/steps/sync_controller_images.py
@@ -0,0 +1,44 @@
+import os
+import base64
+from collections import defaultdict
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.openstacksyncstep import OpenStackSyncStep
+from synchronizers.base.syncstep import *
+from core.models import Controller
+from core.models import Image, ControllerImages
+from xos.logger import observer_logger as logger 
+from synchronizers.base.ansible import *
+import json
+
+class SyncControllerImages(OpenStackSyncStep):
+    provides=[ControllerImages]
+    observes = ControllerImages
+    requested_interval=0
+    playbook='sync_controller_images.yaml'
+
+    def fetch_pending(self, deleted):
+        if (deleted):
+            return []
+
+        # now we return all images that need to be enacted
+        return ControllerImages.objects.filter(Q(enacted__lt=F('updated')) | Q(enacted=None))
+
+    def map_sync_inputs(self, controller_image):
+        image_fields = {'endpoint':controller_image.controller.auth_url,
+                        'endpoint_v3': controller_image.controller.auth_url_v3,
+                        'admin_user':controller_image.controller.admin_user,
+                        'admin_password':controller_image.controller.admin_password,
+                        'domain': controller_image.controller.domain,
+                        'name':controller_image.image.name,
+                        'filepath':controller_image.image.path,
+                        'ansible_tag': '%s@%s'%(controller_image.image.name,controller_image.controller.name), # name of ansible playbook
+                        }
+
+	return image_fields
+
+    def map_sync_outputs(self, controller_image, res):
+        image_id = res[0]['id']
+        controller_image.glance_image_id = image_id
+	controller_image.backend_status = '1 - OK'
+        controller_image.save()
diff --git a/xos/synchronizers/openstack/steps/sync_controller_images.yaml b/xos/synchronizers/openstack/steps/sync_controller_images.yaml
new file mode 100644
index 0000000..6247a30
--- /dev/null
+++ b/xos/synchronizers/openstack/steps/sync_controller_images.yaml
@@ -0,0 +1,13 @@
+---
+- hosts: 127.0.0.1
+  connection: local
+  tasks:
+  - glance_image:
+        auth_url={{ endpoint }}
+        login_username="{{ admin_user }}"
+        login_tenant_name="admin"
+        login_password="{{ admin_password }}"
+        name="{{ name }}"
+        file="{{ filepath }}"
+        disk_format='raw'
+        is_public=true
diff --git a/xos/synchronizers/openstack/steps/sync_controller_networks.py b/xos/synchronizers/openstack/steps/sync_controller_networks.py
new file mode 100644
index 0000000..cf855c6
--- /dev/null
+++ b/xos/synchronizers/openstack/steps/sync_controller_networks.py
@@ -0,0 +1,163 @@
+import os
+import base64
+import struct
+import socket
+from collections import defaultdict
+from netaddr import IPAddress, IPNetwork
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.openstacksyncstep import OpenStackSyncStep
+from synchronizers.base.syncstep import *
+from core.models.network import *
+from core.models.slice import *
+from core.models.instance import Instance
+from xos.logger import observer_logger as logger
+from synchronizers.base.ansible import *
+from openstack.driver import OpenStackDriver
+from xos.config import Config
+import json
+
+import pdb
+
+class SyncControllerNetworks(OpenStackSyncStep):
+    requested_interval = 0
+    provides=[Network]
+    observes=ControllerNetwork	
+    playbook='sync_controller_networks.yaml'
+
+    def alloc_subnet(self, uuid):
+        # 16 bits only
+        uuid_masked = uuid & 0xffff
+        a = 10
+        b = uuid_masked >> 8
+        c = uuid_masked & 0xff
+        d = 0
+
+        cidr = '%d.%d.%d.%d/24'%(a,b,c,d)
+        return cidr
+
+    def alloc_gateway(self, subnet):
+        # given a CIDR, allocate a default gateway using the .1 address within
+        # the subnet.
+        #    10.123.0.0/24 --> 10.123.0.1
+        #    207.141.192.128/28 --> 207.141.192.129
+        (network, bits) = subnet.split("/")
+        network=network.strip()
+        bits=int(bits.strip())
+        netmask = (~(pow(2,32-bits)-1) & 0xFFFFFFFF)
+        ip = struct.unpack("!L", socket.inet_aton(network))[0]
+        ip = ip & netmask | 1
+        return socket.inet_ntoa(struct.pack("!L", ip))
+
+    def save_controller_network(self, controller_network):
+        network_name = controller_network.network.name
+        subnet_name = '%s-%d'%(network_name,controller_network.pk)
+        if controller_network.subnet and controller_network.subnet.strip():
+            # If a subnet is already specified (pass in by the creator), then
+            # use that rather than auto-generating one.
+            cidr = controller_network.subnet.strip()
+            print "CIDR_MS", cidr
+        else:
+            cidr = self.alloc_subnet(controller_network.pk)
+            print "CIDR_AMS", cidr
+
+        if controller_network.network.start_ip and controller_network.network.start_ip.strip():
+            start_ip = controller_network.network.start_ip.strip()
+        else:
+            start_ip = None
+
+        if controller_network.network.end_ip and controller_network.network.end_ip.strip():
+            end_ip = controller_network.network.end_ip.strip()
+        else:
+            end_ip = None
+
+        self.cidr=cidr
+        slice = controller_network.network.owner
+
+        network_fields = {'endpoint':controller_network.controller.auth_url,
+                    'endpoint_v3': controller_network.controller.auth_url_v3,
+                    'admin_user':slice.creator.email,
+                    'tenant_name':slice.name,
+                    'admin_password':slice.creator.remote_password,
+                    'domain': controller_network.controller.domain,
+                    'name':network_name,
+                    'subnet_name':subnet_name,
+                    'ansible_tag':'%s-%s@%s'%(network_name,slice.slicename,controller_network.controller.name),
+                    'cidr':cidr,
+                    'gateway':self.alloc_gateway(cidr),
+                    'start_ip':start_ip,
+                    'end_ip':end_ip,
+                    'use_vtn':getattr(Config(), "networking_use_vtn", False),
+                    'delete':False
+                    }
+        return network_fields
+
+    def map_sync_outputs(self, controller_network,res):
+        network_id = res[0]['id']
+        subnet_id = res[1]['id']
+        controller_network.net_id = network_id
+        controller_network.subnet = self.cidr
+        controller_network.subnet_id = subnet_id
+	controller_network.backend_status = '1 - OK'
+        controller_network.save()
+
+
+    def map_sync_inputs(self, controller_network):
+        # XXX This check should really be made from booleans, rather than using hardcoded network names
+        #if (controller_network.network.template.name not in ['Private', 'Private-Indirect', 'Private-Direct', 'management_template'):
+        #    logger.info("skipping network controller %s because it is not private" % controller_network)
+        #    # We only sync private networks
+        #    return SyncStep.SYNC_WITHOUT_RUNNING
+
+        # hopefully a better approach than above
+        if (controller_network.network.template.shared_network_name or controller_network.network.template.shared_network_id):
+            return SyncStep.SYNC_WITHOUT_RUNNING
+        
+        if not controller_network.controller.admin_user:
+            logger.info("controller %r has no admin_user, skipping" % controller_network.controller)
+            return
+
+        if controller_network.network.owner and controller_network.network.owner.creator:
+	    return self.save_controller_network(controller_network)
+        else:
+            raise Exception('Could not save network controller %s'%controller_network)
+
+    def map_delete_inputs(self, controller_network):
+        # XXX This check should really be made from booleans, rather than using hardcoded network names
+	if (controller_network.network.template.name not in ['Private', 'Private-Indirect', 'Private-Direct']):
+            # We only sync private networks
+            return
+	try:
+        	slice = controller_network.network.owner # XXX: FIXME!!
+        except:
+                raise Exception('Could not get slice for Network %s'%controller_network.network.name)
+
+	network_name = controller_network.network.name
+        subnet_name = '%s-%d'%(network_name,controller_network.pk)
+	cidr = controller_network.subnet
+	network_fields = {'endpoint':controller_network.controller.auth_url,
+                    'admin_user':slice.creator.email, # XXX: FIXME
+                    'tenant_name':slice.name, # XXX: FIXME
+                    'admin_password':slice.creator.remote_password,
+                    'name':network_name,
+                    'subnet_name':subnet_name,
+                    'ansible_tag':'%s-%s@%s'%(network_name,slice.slicename,controller_network.controller.name),
+                    'cidr':cidr,
+		    'delete':True	
+                    }
+
+        return network_fields
+
+	"""
+        driver = OpenStackDriver().client_driver(caller=controller_network.network.owner.creator,
+                                                 tenant=controller_network.network.owner.name,
+                                                 controller=controller_network.controller.name)
+        if (controller_network.router_id) and (controller_network.subnet_id):
+            driver.delete_router_interface(controller_network.router_id, controller_network.subnet_id)
+        if controller_network.subnet_id:
+            driver.delete_subnet(controller_network.subnet_id)
+        if controller_network.router_id:
+            driver.delete_router(controller_network.router_id)
+        if controller_network.net_id:
+            driver.delete_network(controller_network.net_id)
+	"""
diff --git a/xos/synchronizers/openstack/steps/sync_controller_networks.yaml b/xos/synchronizers/openstack/steps/sync_controller_networks.yaml
new file mode 100644
index 0000000..6fb9a92
--- /dev/null
+++ b/xos/synchronizers/openstack/steps/sync_controller_networks.yaml
@@ -0,0 +1,45 @@
+---
+- hosts: 127.0.0.1
+  connection: local
+  tasks:
+  - quantum_network:
+        auth_url={{ endpoint }}
+        login_username={{ admin_user }}
+        login_tenant_name={{ tenant_name }}
+        login_password={{ admin_password }}
+        tenant_name={{ tenant_name }}
+        name={{ name }}
+        {% if delete %}
+        state=absent
+        {% else %}
+        state=present
+        {% endif %}
+        shared=true
+  {% if not delete %}
+  - quantum_subnet:
+        auth_url={{ endpoint }}
+        login_username={{ admin_user }}
+        login_tenant_name={{ tenant_name }}
+        login_password={{ admin_password }}
+        tenant_name={{ tenant_name }}
+        name={{ subnet_name }}
+        network_name={{ name }}
+        {% if delete %}
+        state=absent
+        {% else %}
+        state=present
+        {% if use_vtn %}
+        gateway_ip={{ gateway }}
+        {% else %}
+        no_gateway=true
+        {% endif %}
+        dns_nameservers=8.8.8.8
+        cidr={{ cidr }}
+  {% if start_ip %}
+        allocation_pool_start={{ start_ip }}
+  {% endif %}
+  {% if end_ip %}
+        allocation_pool_end={{ end_ip }}
+  {% endif %}
+        {% endif %}
+  {% endif %}
diff --git a/xos/synchronizers/openstack/steps/sync_controller_site_privileges.py b/xos/synchronizers/openstack/steps/sync_controller_site_privileges.py
new file mode 100644
index 0000000..59919fe
--- /dev/null
+++ b/xos/synchronizers/openstack/steps/sync_controller_site_privileges.py
@@ -0,0 +1,84 @@
+import os
+import base64
+from collections import defaultdict
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.openstacksyncstep import OpenStackSyncStep
+from synchronizers.base.syncstep import *
+from core.models.site import Controller, SitePrivilege 
+from core.models.user import User
+from core.models.controlleruser import ControllerUser, ControllerSitePrivilege
+from xos.logger import observer_logger as logger
+from synchronizers.base.ansible import *
+import json
+
+class SyncControllerSitePrivileges(OpenStackSyncStep):
+    provides=[SitePrivilege]
+    requested_interval=0
+    observes=ControllerSitePrivilege
+    playbook='sync_controller_users.yaml'
+
+    def map_sync_inputs(self, controller_site_privilege):
+	controller_register = json.loads(controller_site_privilege.controller.backend_register)
+        if not controller_site_privilege.controller.admin_user:
+            logger.info("controller %r has no admin_user, skipping" % controller_site_privilege.controller)
+            return
+
+        roles = [controller_site_privilege.site_privilege.role.role]
+	# setup user home site roles at controller 
+        if not controller_site_privilege.site_privilege.user.site:
+            raise Exception('Siteless user %s'%controller_site_privilege.site_privilege.user.email)
+        else:
+            # look up tenant id for the user's site at the controller
+            #ctrl_site_deployments = SiteDeployment.objects.filter(
+            #  site_deployment__site=controller_site_privilege.user.site,
+            #  controller=controller_site_privilege.controller)
+
+            #if ctrl_site_deployments:
+            #    # need the correct tenant id for site at the controller
+            #    tenant_id = ctrl_site_deployments[0].tenant_id  
+            #    tenant_name = ctrl_site_deployments[0].site_deployment.site.login_base
+            user_fields = {
+               'endpoint':controller_site_privilege.controller.auth_url,
+               'endpoint_v3': controller_site_privilege.controller.auth_url_v3,
+               'domain': controller_site_privilege.controller.domain,
+		       'name': controller_site_privilege.site_privilege.user.email,
+               'email': controller_site_privilege.site_privilege.user.email,
+               'password': controller_site_privilege.site_privilege.user.remote_password,
+               'admin_user': controller_site_privilege.controller.admin_user,
+		       'admin_password': controller_site_privilege.controller.admin_password,
+	           'ansible_tag':'%s@%s'%(controller_site_privilege.site_privilege.user.email.replace('@','-at-'),controller_site_privilege.controller.name),
+		       'admin_tenant': controller_site_privilege.controller.admin_tenant,
+		       'roles':roles,
+		       'tenant':controller_site_privilege.site_privilege.site.login_base}    
+	
+	    return user_fields
+
+    def map_sync_outputs(self, controller_site_privilege, res):
+	    # results is an array in which each element corresponds to an 
+	    # "ok" string received per operation. If we get as many oks as
+	    # the number of operations we issued, that means a grand success.
+	    # Otherwise, the number of oks tell us which operation failed.
+            controller_site_privilege.role_id = res[0]['id']
+            controller_site_privilege.save()
+
+    def delete_record(self, controller_site_privilege):
+	controller_register = json.loads(controller_site_privilege.controller.backend_register)
+        if (controller_register.get('disabled',False)):
+                raise InnocuousException('Controller %s is disabled'%controller_site_privilege.controller.name)
+
+        if controller_site_privilege.role_id:
+            driver = self.driver.admin_driver(controller=controller_site_privilege.controller)
+            user = ControllerUser.objects.get(
+                controller=controller_site_privilege.controller, 
+                user=controller_site_privilege.site_privilege.user
+            )
+            site = ControllerSite.objects.get(
+                controller=controller_site_privilege.controller, 
+                user=controller_site_privilege.site_privilege.user
+            )
+            driver.delete_user_role(
+                user.kuser_id, 
+                site.tenant_id, 
+                controller_site_privilege.site_prvilege.role.role
+            )
diff --git a/xos/synchronizers/openstack/steps/sync_controller_sites.py b/xos/synchronizers/openstack/steps/sync_controller_sites.py
new file mode 100644
index 0000000..1b3c2ba
--- /dev/null
+++ b/xos/synchronizers/openstack/steps/sync_controller_sites.py
@@ -0,0 +1,67 @@
+import os
+import base64
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.openstack.openstacksyncstep import OpenStackSyncStep
+from core.models.site import *
+from synchronizers.base.syncstep import *
+from synchronizers.base.ansible import *
+from xos.logger import observer_logger as logger
+import json
+
+class SyncControllerSites(OpenStackSyncStep):
+    requested_interval=0
+    provides=[Site]
+    observes=ControllerSite
+    playbook = 'sync_controller_sites.yaml'
+
+    def fetch_pending(self, deleted=False):
+        lobjs = ControllerSite.objects.filter(Q(enacted__lt=F('updated')) | Q(enacted=None),Q(lazy_blocked=False),Q(controller__isnull=False))
+        return lobjs
+
+    def map_sync_inputs(self, controller_site):
+	tenant_fields = {'endpoint':controller_site.controller.auth_url,
+                 'endpoint_v3': controller_site.controller.auth_url_v3,
+                 'domain': controller_site.controller.domain,
+		         'admin_user': controller_site.controller.admin_user,
+		         'admin_password': controller_site.controller.admin_password,
+		         'admin_tenant': controller_site.controller.admin_tenant,
+	             'ansible_tag': '%s@%s'%(controller_site.site.login_base,controller_site.controller.name), # name of ansible playbook
+		         'tenant': controller_site.site.login_base,
+		         'tenant_description': controller_site.site.name}
+        return tenant_fields
+
+    def map_sync_outputs(self, controller_site, res):
+	controller_site.tenant_id = res[0]['id']
+	controller_site.backend_status = '1 - OK'
+        controller_site.save()
+            
+    def delete_record(self, controller_site):
+	controller_register = json.loads(controller_site.controller.backend_register)
+        if (controller_register.get('disabled',False)):
+                raise InnocuousException('Controller %s is disabled'%controller_site.controller.name)
+
+	if controller_site.tenant_id:
+            driver = self.driver.admin_driver(controller=controller_site.controller)
+            driver.delete_tenant(controller_site.tenant_id)
+
+	"""
+        Ansible does not support tenant deletion yet
+
+	import pdb
+	pdb.set_trace()
+        template = os_template_env.get_template('delete_controller_sites.yaml')
+	tenant_fields = {'endpoint':controller_site.controller.auth_url,
+		         'admin_user': controller_site.controller.admin_user,
+		         'admin_password': controller_site.controller.admin_password,
+		         'admin_tenant': 'admin',
+	                 'ansible_tag': 'controller_sites/%s@%s'%(controller_site.controller_site.site.login_base,controller_site.controller_site.deployment.name), # name of ansible playbook
+		         'tenant': controller_site.controller_site.site.login_base,
+		         'delete': True}
+
+	rendered = template.render(tenant_fields)
+	res = run_template('sync_controller_sites.yaml', tenant_fields)
+
+	if (len(res)!=1):
+		raise Exception('Could not assign roles for user %s'%tenant_fields['tenant'])
+	"""
diff --git a/xos/synchronizers/openstack/steps/sync_controller_sites.yaml b/xos/synchronizers/openstack/steps/sync_controller_sites.yaml
new file mode 100644
index 0000000..4129802
--- /dev/null
+++ b/xos/synchronizers/openstack/steps/sync_controller_sites.yaml
@@ -0,0 +1,5 @@
+---
+- hosts: 127.0.0.1
+  connection: local
+  tasks:
+  - keystone_user: endpoint={{ endpoint }} login_user={{ admin_user }} login_password={{ admin_password }} login_tenant_name={{ admin_tenant }} tenant={{ tenant }} tenant_description="{{ tenant_description }}"
diff --git a/xos/synchronizers/openstack/steps/sync_controller_slice_privileges.py b/xos/synchronizers/openstack/steps/sync_controller_slice_privileges.py
new file mode 100644
index 0000000..e5513b0
--- /dev/null
+++ b/xos/synchronizers/openstack/steps/sync_controller_slice_privileges.py
@@ -0,0 +1,79 @@
+import os
+import base64
+from collections import defaultdict
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.openstacksyncstep import OpenStackSyncStep
+from synchronizers.base.syncstep import *
+from core.models.slice import Controller, SlicePrivilege 
+from core.models.user import User
+from core.models.controlleruser import ControllerUser, ControllerSlicePrivilege
+from synchronizers.base.ansible import *
+from xos.logger import observer_logger as logger
+import json
+
+class SyncControllerSlicePrivileges(OpenStackSyncStep):
+    provides=[SlicePrivilege]
+    requested_interval=0
+    observes=ControllerSlicePrivilege
+    playbook = 'sync_controller_users.yaml'
+
+    def map_sync_inputs(self, controller_slice_privilege):
+        if not controller_slice_privilege.controller.admin_user:
+            logger.info("controller %r has no admin_user, skipping" % controller_slice_privilege.controller)
+            return
+
+	template = os_template_env.get_template('sync_controller_users.yaml')
+        roles = [controller_slice_privilege.slice_privilege.role.role]
+	# setup user home slice roles at controller 
+        if not controller_slice_privilege.slice_privilege.user.site:
+            raise Exception('Sliceless user %s'%controller_slice_privilege.slice_privilege.user.email)
+        else:
+            # look up tenant id for the user's slice at the controller
+            #ctrl_slice_deployments = SliceDeployment.objects.filter(
+            #  slice_deployment__slice=controller_slice_privilege.user.slice,
+            #  controller=controller_slice_privilege.controller)
+
+            #if ctrl_slice_deployments:
+            #    # need the correct tenant id for slice at the controller
+            #    tenant_id = ctrl_slice_deployments[0].tenant_id  
+            #    tenant_name = ctrl_slice_deployments[0].slice_deployment.slice.login_base
+            user_fields = {
+               'endpoint':controller_slice_privilege.controller.auth_url,
+               'endpoint_v3': controller_slice_privilege.controller.auth_url_v3,
+               'domain': controller_slice_privilege.controller.domain,
+		       'name': controller_slice_privilege.slice_privilege.user.email,
+               'email': controller_slice_privilege.slice_privilege.user.email,
+               'password': controller_slice_privilege.slice_privilege.user.remote_password,
+               'admin_user': controller_slice_privilege.controller.admin_user,
+		       'admin_password': controller_slice_privilege.controller.admin_password,
+               'ansible_tag':'%s@%s@%s'%(controller_slice_privilege.slice_privilege.user.email.replace('@','-at-'),controller_slice_privilege.slice_privilege.slice.name,controller_slice_privilege.controller.name),
+		       'admin_tenant': controller_slice_privilege.controller.admin_tenant,
+		       'roles':roles,
+		       'tenant':controller_slice_privilege.slice_privilege.slice.name}    
+            return user_fields
+	
+    def map_sync_outputs(self, controller_slice_privilege, res):
+        controller_slice_privilege.role_id = res[0]['id']
+        controller_slice_privilege.save()
+
+    def delete_record(self, controller_slice_privilege):
+	controller_register = json.loads(controller_slice_privilege.controller.backend_register)
+        if (controller_register.get('disabled',False)):
+                raise InnocuousException('Controller %s is disabled'%controller_slice_privilege.controller.name)
+
+        if controller_slice_privilege.role_id:
+            driver = self.driver.admin_driver(controller=controller_slice_privilege.controller)
+            user = ControllerUser.objects.get(
+                controller=controller_slice_privilege.controller, 
+                user=controller_slice_privilege.slice_privilege.user
+            )
+            slice = ControllerSlice.objects.get(
+                controller=controller_slice_privilege.controller, 
+                user=controller_slice_privilege.slice_privilege.user
+            )
+            driver.delete_user_role(
+                user.kuser_id, 
+                slice.tenant_id, 
+                controller_slice_privilege.slice_prvilege.role.role
+            )
diff --git a/xos/synchronizers/openstack/steps/sync_controller_slices.py b/xos/synchronizers/openstack/steps/sync_controller_slices.py
new file mode 100644
index 0000000..97d8c29
--- /dev/null
+++ b/xos/synchronizers/openstack/steps/sync_controller_slices.py
@@ -0,0 +1,84 @@
+import os
+import base64
+from collections import defaultdict
+from netaddr import IPAddress, IPNetwork
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.openstacksyncstep import OpenStackSyncStep
+from synchronizers.base.syncstep import *
+from core.models import *
+from synchronizers.base.ansible import *
+from openstack.driver import OpenStackDriver
+from xos.logger import observer_logger as logger
+import json
+
+class SyncControllerSlices(OpenStackSyncStep):
+    provides=[Slice]
+    requested_interval=0
+    observes=ControllerSlice
+    playbook='sync_controller_slices.yaml'
+
+    def map_sync_inputs(self, controller_slice):
+        logger.info("sync'ing slice controller %s" % controller_slice)
+
+        if not controller_slice.controller.admin_user:
+            logger.info("controller %r has no admin_user, skipping" % controller_slice.controller)
+            return
+
+        controller_users = ControllerUser.objects.filter(user=controller_slice.slice.creator,
+                                                             controller=controller_slice.controller)
+        if not controller_users:
+            raise Exception("slice createor %s has not accout at controller %s" % (controller_slice.slice.creator, controller_slice.controller.name))
+        else:
+            controller_user = controller_users[0]
+            roles = ['admin']
+
+        max_instances=int(controller_slice.slice.max_instances)
+        tenant_fields = {'endpoint':controller_slice.controller.auth_url,
+                         'endpoint_v3': controller_slice.controller.auth_url_v3,
+                         'domain': controller_slice.controller.domain,
+                         'admin_user': controller_slice.controller.admin_user,
+                         'admin_password': controller_slice.controller.admin_password,
+                         'admin_tenant': 'admin',
+                         'tenant': controller_slice.slice.name,
+                         'tenant_description': controller_slice.slice.description,
+                         'roles':roles,
+                         'name':controller_user.user.email,
+                         'ansible_tag':'%s@%s'%(controller_slice.slice.name,controller_slice.controller.name),
+                         'max_instances':max_instances}
+
+        return tenant_fields
+
+    def map_sync_outputs(self, controller_slice, res):
+        tenant_id = res[0]['id']
+        if (not controller_slice.tenant_id):
+            try:
+                driver = OpenStackDriver().admin_driver(controller=controller_slice.controller)
+                driver.shell.nova.quotas.update(tenant_id=tenant_id, instances=int(controller_slice.slice.max_instances))
+            except:
+                logger.log_exc('Could not update quota for %s'%controller_slice.slice.name)
+                raise Exception('Could not update quota for %s'%controller_slice.slice.name)
+
+            controller_slice.tenant_id = tenant_id
+            controller_slice.backend_status = '1 - OK'
+            controller_slice.save()
+
+
+    def map_delete_inputs(self, controller_slice):
+        controller_users = ControllerUser.objects.filter(user=controller_slice.slice.creator,
+                                                              controller=controller_slice.controller)
+        if not controller_users:
+            raise Exception("slice createor %s has not accout at controller %s" % (controller_slice.slice.creator, controller_slice.controller.name))
+        else:
+            controller_user = controller_users[0]
+
+        tenant_fields = {'endpoint':controller_slice.controller.auth_url,
+                          'admin_user': controller_slice.controller.admin_user,
+                          'admin_password': controller_slice.controller.admin_password,
+                          'admin_tenant': 'admin',
+                          'tenant': controller_slice.slice.name,
+                          'tenant_description': controller_slice.slice.description,
+                          'name':controller_user.user.email,
+                          'ansible_tag':'%s@%s'%(controller_slice.slice.name,controller_slice.controller.name),
+                          'delete': True}
+	return tenant_fields
diff --git a/xos/synchronizers/openstack/steps/sync_controller_slices.yaml b/xos/synchronizers/openstack/steps/sync_controller_slices.yaml
new file mode 100644
index 0000000..61470ce
--- /dev/null
+++ b/xos/synchronizers/openstack/steps/sync_controller_slices.yaml
@@ -0,0 +1,12 @@
+---
+- hosts: 127.0.0.1
+  connection: local
+  tasks:
+  {% if delete -%}
+  - keystone_user: endpoint={{ endpoint }} login_user={{ admin_user }} login_password={{ admin_password }} login_tenant_name={{ admin_tenant }} tenant={{ tenant }} tenant_description="{{ tenant_description }}" state=absent
+  {% else -%}
+  - keystone_user: endpoint={{ endpoint }} login_user={{ admin_user }} login_password={{ admin_password }} login_tenant_name={{ admin_tenant }} tenant={{ tenant }} tenant_description="{{ tenant_description }}"
+  {% for role in roles %}
+  - keystone_user: endpoint={{ endpoint }} login_user={{ admin_user }} login_password={{ admin_password }} login_tenant_name={{ admin_tenant }} user="{{ name }}" role={{ role }} tenant={{ tenant }}
+  {% endfor %}
+  {% endif %}
diff --git a/xos/synchronizers/openstack/steps/sync_controller_users.py b/xos/synchronizers/openstack/steps/sync_controller_users.py
new file mode 100644
index 0000000..9af48e5
--- /dev/null
+++ b/xos/synchronizers/openstack/steps/sync_controller_users.py
@@ -0,0 +1,69 @@
+import os
+import base64
+from collections import defaultdict
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.openstacksyncstep import OpenStackSyncStep
+from synchronizers.base.syncstep import *
+from core.models.site import Controller, SiteDeployment, SiteDeployment
+from core.models.user import User
+from core.models.controlleruser import ControllerUser
+from synchronizers.base.ansible import *
+from xos.logger import observer_logger as logger
+import json
+
+class SyncControllerUsers(OpenStackSyncStep):
+    provides=[User]
+    requested_interval=0
+    observes=ControllerUser
+    playbook='sync_controller_users.yaml'
+
+    def map_sync_inputs(self, controller_user):
+        if not controller_user.controller.admin_user:
+            logger.info("controller %r has no admin_user, skipping" % controller_user.controller)
+            return
+
+        # All users will have at least the 'user' role at their home site/tenant.
+        # We must also check if the user should have the admin role
+        roles = ['user']
+        if controller_user.user.is_admin:
+            roles.append('admin')
+
+        # setup user home site roles at controller
+        if not controller_user.user.site:
+            raise Exception('Siteless user %s'%controller_user.user.email)
+        else:
+            # look up tenant id for the user's site at the controller
+            #ctrl_site_deployments = SiteDeployment.objects.filter(
+            #  site_deployment__site=controller_user.user.site,
+            #  controller=controller_user.controller)
+
+            #if ctrl_site_deployments:
+            #    # need the correct tenant id for site at the controller
+            #    tenant_id = ctrl_site_deployments[0].tenant_id
+            #    tenant_name = ctrl_site_deployments[0].site_deployment.site.login_base
+            user_fields = {
+                'endpoint':controller_user.controller.auth_url,
+                'endpoint_v3': controller_user.controller.auth_url_v3,
+                'domain': controller_user.controller.domain,
+                'name': controller_user.user.email,
+                'email': controller_user.user.email,
+                'password': controller_user.user.remote_password,
+                'admin_user': controller_user.controller.admin_user,
+                'admin_password': controller_user.controller.admin_password,
+                'ansible_tag':'%s@%s'%(controller_user.user.email.replace('@','-at-'),controller_user.controller.name),
+                'admin_tenant': controller_user.controller.admin_tenant,
+                'roles':roles,
+                'tenant':controller_user.user.site.login_base
+                }
+	    return user_fields
+
+    def map_sync_outputs(self, controller_user, res):
+        controller_user.kuser_id = res[0]['id']
+        controller_user.backend_status = '1 - OK'
+        controller_user.save()
+
+    def delete_record(self, controller_user):
+        if controller_user.kuser_id:
+            driver = self.driver.admin_driver(controller=controller_user.controller)
+            driver.delete_user(controller_user.kuser_id)
diff --git a/xos/synchronizers/openstack/steps/sync_controller_users.yaml b/xos/synchronizers/openstack/steps/sync_controller_users.yaml
new file mode 100644
index 0000000..4f2db5e
--- /dev/null
+++ b/xos/synchronizers/openstack/steps/sync_controller_users.yaml
@@ -0,0 +1,16 @@
+---
+- hosts: 127.0.0.1
+  connection: local
+  tasks:
+  - keystone_user:
+       endpoint={{ endpoint }}
+       login_user={{ admin_user }} 
+       login_password={{ admin_password }} 
+       login_tenant_name={{ admin_tenant }} 
+       user="{{ name }}"
+       email={{ email }}
+       password={{ password }}
+       tenant={{ tenant }}
+  {% for role in roles %}
+  - keystone_user: endpoint={{ endpoint}}  login_user={{ admin_user }} login_password={{ admin_password }} login_tenant_name={{ admin_tenant }} user="{{ name }}" role={{ role }} tenant={{ tenant }}
+  {% endfor %}
diff --git a/xos/synchronizers/openstack/steps/sync_images.py b/xos/synchronizers/openstack/steps/sync_images.py
new file mode 100644
index 0000000..1638fd0
--- /dev/null
+++ b/xos/synchronizers/openstack/steps/sync_images.py
@@ -0,0 +1,52 @@
+import os
+import base64
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.openstacksyncstep import OpenStackSyncStep
+from core.models.image import Image
+from xos.logger import observer_logger as logger
+
+class SyncImages(OpenStackSyncStep):
+    provides=[Image]
+    requested_interval=0
+    observes=Image
+
+    def fetch_pending(self, deleted):
+        # Images come from the back end
+        # You can't delete them
+        if (deleted):
+            logger.info("SyncImages: returning because deleted=True")
+            return []
+
+        # get list of images on disk
+        images_path = Config().observer_images_directory
+
+        logger.info("SyncImages: deleted=False, images_path=%s" % images_path)
+
+        available_images = {}
+        if os.path.exists(images_path):
+            for f in os.listdir(images_path):
+                filename = os.path.join(images_path, f)
+                if os.path.isfile(filename) and filename.endswith(".img"):
+                    available_images[f] = filename
+
+        logger.info("SyncImages: available_images = %s" % str(available_images))
+
+        images = Image.objects.all()
+        image_names = [image.name for image in images]
+
+        for image_name in available_images:
+            #remove file extension
+            clean_name = ".".join(image_name.split('.')[:-1])
+            if clean_name not in image_names:
+                logger.info("SyncImages: adding %s" % clean_name)
+                image = Image(name=clean_name,
+                              disk_format='raw',
+                              container_format='bare', 
+                              path = available_images[image_name])
+                image.save()
+
+        return Image.objects.filter(Q(enacted__lt=F('updated')) | Q(enacted=None)) 
+
+    def sync_record(self, image):
+        image.save()
diff --git a/xos/synchronizers/openstack/steps/sync_instances.py b/xos/synchronizers/openstack/steps/sync_instances.py
new file mode 100644
index 0000000..faeb860
--- /dev/null
+++ b/xos/synchronizers/openstack/steps/sync_instances.py
@@ -0,0 +1,220 @@
+import os
+import base64
+import socket
+from django.db.models import F, Q
+from xos.config import Config
+from xos.settings import RESTAPI_HOSTNAME, RESTAPI_PORT
+from synchronizers.base.openstacksyncstep import OpenStackSyncStep
+from core.models.instance import Instance
+from core.models.slice import Slice, SlicePrivilege, ControllerSlice
+from core.models.network import Network, NetworkSlice, ControllerNetwork
+from synchronizers.base.ansible import *
+from synchronizers.base.syncstep import *
+from xos.logger import observer_logger as logger
+
+def escape(s):
+    s = s.replace('\n',r'\n').replace('"',r'\"')
+    return s
+
+class SyncInstances(OpenStackSyncStep):
+    provides=[Instance]
+    requested_interval=0
+    observes=Instance
+    playbook='sync_instances.yaml'
+
+    def fetch_pending(self, deletion=False):
+        objs = super(SyncInstances, self).fetch_pending(deletion)
+        objs = [x for x in objs if x.isolation=="vm"]
+        return objs
+
+    def get_userdata(self, instance, pubkeys):
+        userdata = '#cloud-config\n\nopencloud:\n   slicename: "%s"\n   hostname: "%s"\n   restapi_hostname: "%s"\n   restapi_port: "%s"\n' % (instance.slice.name, instance.node.name, RESTAPI_HOSTNAME, str(RESTAPI_PORT))
+        userdata += 'ssh_authorized_keys:\n'
+        for key in pubkeys:
+            userdata += '  - %s\n' % key
+        return userdata
+
+    def sort_nics(self, nics):
+        result = []
+
+        # Enforce VTN's network order requirement. The access network must be
+        # inserted into the first slot. The management network must be inserted
+        # into the second slot.
+
+        # move the private and/or access network to the first spot
+        for nic in nics[:]:
+            network=nic.get("network", None)
+            if network:
+                tem = network.template
+                if (tem.visibility == "private") and (tem.translation=="none") and ("management" not in tem.name):
+                    result.append(nic)
+                    nics.remove(nic)
+
+        # move the management network to the second spot
+        for net in nics[:]:
+            network=nic.get("network", None)
+            if network:
+                tem = network.template
+                if (tem.visibility == "private") and (tem.translation=="none") and ("management" in tem.name):
+#MCORD
+#                    if len(result)!=1:
+#                        raise Exception("Management network needs to be inserted in slot 1, but there are %d private nics" % len(result))
+                    result.append(nic)
+                    nics.remove(nic)
+
+        # add everything else. For VTN there probably shouldn't be any more.
+        result.extend(nics)
+
+        return result
+
+    def map_sync_inputs(self, instance):
+        inputs = {}
+	metadata_update = {}
+        if (instance.numberCores):
+            metadata_update["cpu_cores"] = str(instance.numberCores)
+
+        for tag in instance.slice.tags.all():
+            if tag.name.startswith("sysctl-"):
+                metadata_update[tag.name] = tag.value
+
+	slice_memberships = SlicePrivilege.objects.filter(slice=instance.slice)
+        pubkeys = set([sm.user.public_key for sm in slice_memberships if sm.user.public_key])
+        if instance.creator.public_key:
+            pubkeys.add(instance.creator.public_key)
+
+        if instance.slice.creator.public_key:
+            pubkeys.add(instance.slice.creator.public_key)
+
+        if instance.slice.service and instance.slice.service.public_key:
+            pubkeys.add(instance.slice.service.public_key)
+
+        nics=[]
+
+        # handle ports the were created by the user
+        port_ids=[]
+        for port in Port.objects.filter(instance=instance):
+            if not port.port_id:
+                raise DeferredException("Instance %s waiting on port %s" % (instance, port))
+            nics.append({"kind": "port", "value": port.port_id, "network": port.network})
+
+        # we want to exclude from 'nics' any network that already has a Port
+        existing_port_networks = [port.network for port in Port.objects.filter(instance=instance)]
+
+        networks = [ns.network for ns in NetworkSlice.objects.filter(slice=instance.slice) if ns.network not in existing_port_networks]
+        controller_networks = ControllerNetwork.objects.filter(network__in=networks,
+                                                                controller=instance.node.site_deployment.controller)
+
+        #controller_networks = self.sort_controller_networks(controller_networks)
+        for controller_network in controller_networks:
+            # Lenient exception - causes slow backoff
+            if controller_network.network.template.visibility == 'private' and \
+               controller_network.network.template.translation == 'none':
+                   if not controller_network.net_id:
+                        raise DeferredException("Instance %s Private Network %s has no id; Try again later" % (instance, controller_network.network.name))
+                   nics.append({"kind": "net", "value": controller_network.net_id, "network": controller_network.network})
+
+        # now include network template
+        network_templates = [network.template.shared_network_name for network in networks \
+                             if network.template.shared_network_name]
+
+        #driver = self.driver.client_driver(caller=instance.creator, tenant=instance.slice.name, controller=instance.controllerNetwork)
+        driver = self.driver.admin_driver(tenant='admin', controller=instance.node.site_deployment.controller)
+        nets = driver.shell.quantum.list_networks()['networks']
+        for net in nets:
+            if net['name'] in network_templates:
+                nics.append({"kind": "net", "value": net['id'], "network": None})
+
+        if (not nics):
+            for net in nets:
+                if net['name']=='public':
+                    nics.append({"kind": "net", "value": net['id'], "network": None})
+
+        nics = self.sort_nics(nics)
+
+        image_name = None
+        controller_images = instance.image.controllerimages.filter(controller=instance.node.site_deployment.controller)
+        if controller_images:
+            image_name = controller_images[0].image.name
+            logger.info("using image from ControllerImage object: " + str(image_name))
+
+        if image_name is None:
+            controller_driver = self.driver.admin_driver(controller=instance.node.site_deployment.controller)
+            images = controller_driver.shell.glanceclient.images.list()
+            for image in images:
+                if image.name == instance.image.name or not image_name:
+                    image_name = image.name
+                    logger.info("using image from glance: " + str(image_name))
+
+	try:
+            legacy = Config().observer_legacy
+        except:
+            legacy = False
+
+        if (legacy):
+            host_filter = instance.node.name.split('.',1)[0]
+        else:
+            host_filter = instance.node.name.strip()
+
+        availability_zone_filter = 'nova:%s'%host_filter
+        instance_name = '%s-%d'%(instance.slice.name,instance.id)
+        self.instance_name = instance_name
+
+        userData = self.get_userdata(instance, pubkeys)
+        if instance.userData:
+            userData += instance.userData
+
+        controller = instance.node.site_deployment.controller
+        fields = {'endpoint':controller.auth_url,
+                     'endpoint_v3': controller.auth_url_v3,
+                     'domain': controller.domain,
+                     'admin_user': instance.creator.email,
+                     'admin_password': instance.creator.remote_password,
+                     'admin_tenant': instance.slice.name,
+                     'tenant': instance.slice.name,
+                     'tenant_description': instance.slice.description,
+                     'name':instance_name,
+                     'ansible_tag':instance_name,
+                     'availability_zone': availability_zone_filter,
+                     'image_name':image_name,
+                     'flavor_name':instance.flavor.name,
+                     'nics':nics,
+                     'meta':metadata_update,
+                     'user_data':r'%s'%escape(userData)}
+        return fields
+
+
+    def map_sync_outputs(self, instance, res):
+	instance_id = res[0]['info']['OS-EXT-SRV-ATTR:instance_name']
+        instance_uuid = res[0]['id']
+
+	try:
+            hostname = res[0]['info']['OS-EXT-SRV-ATTR:hypervisor_hostname']
+            ip = socket.gethostbyname(hostname)
+            instance.ip = ip
+        except:
+            pass
+
+        instance.instance_id = instance_id
+        instance.instance_uuid = instance_uuid
+        instance.instance_name = self.instance_name
+        instance.save()
+	
+	
+    def map_delete_inputs(self, instance):
+        controller_register = json.loads(instance.node.site_deployment.controller.backend_register)
+
+        if (controller_register.get('disabled',False)):
+            raise InnocuousException('Controller %s is disabled'%instance.node.site_deployment.controller.name)
+
+        instance_name = '%s-%d'%(instance.slice.name,instance.id)
+        controller = instance.node.site_deployment.controller
+        input = {'endpoint':controller.auth_url,
+                     'admin_user': instance.creator.email,
+                     'admin_password': instance.creator.remote_password,
+                     'admin_tenant': instance.slice.name,
+                     'tenant': instance.slice.name,
+                     'tenant_description': instance.slice.description,
+                     'name':instance_name,
+                     'ansible_tag':instance_name,
+                     'delete': True}
+        return input
diff --git a/xos/synchronizers/openstack/steps/sync_instances.yaml b/xos/synchronizers/openstack/steps/sync_instances.yaml
new file mode 100644
index 0000000..3e7182a
--- /dev/null
+++ b/xos/synchronizers/openstack/steps/sync_instances.yaml
@@ -0,0 +1,32 @@
+---
+- hosts: 127.0.0.1
+  connection: local
+  tasks:
+  - nova_compute:
+      auth_url: {{ endpoint }}
+      login_username: {{ admin_user }}
+      login_password: {{ admin_password }}
+      login_tenant_name: {{ admin_tenant }}
+      name: {{ name }}
+      {% if delete -%}
+      state: absent
+      {% else -%}
+      state: present
+      availability_zone: {{ availability_zone }}
+      image_name: {{ image_name }}
+      wait_for: 200
+      flavor_name: {{ flavor_name }}
+      user_data: "{{ user_data }}"
+      config_drive: yes
+      nics:
+      {% for nic in nics %}
+          - {{ nic.kind }}-id: {{ nic.value }}
+      {% endfor %}
+
+      {% if meta %}
+      meta:
+      {% for k,v in meta.items() %}
+          {{ k }} : "{{ v }}"
+      {% endfor %}
+      {% endif %}
+      {% endif %}
diff --git a/xos/synchronizers/openstack/steps/sync_object.py b/xos/synchronizers/openstack/steps/sync_object.py
new file mode 100644
index 0000000..a6a939f
--- /dev/null
+++ b/xos/synchronizers/openstack/steps/sync_object.py
@@ -0,0 +1,20 @@
+import os
+import base64
+from collections import defaultdict
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.openstacksyncstep import OpenStackSyncStep
+from synchronizers.base.syncstep import *
+from core.models import *
+from synchronizers.base.ansible import *
+from openstack.driver import OpenStackDriver
+from xos.logger import observer_logger as logger
+import json
+
+class SyncObject(OpenStackSyncStep):
+    provides=[] # Caller fills this in
+    requested_interval=0
+    observes=[] # Caller fills this in
+
+    def sync_record(self, r):
+        raise DeferredException('Waiting for Service dependency: %r'%r)
diff --git a/xos/synchronizers/openstack/steps/sync_ports.py b/xos/synchronizers/openstack/steps/sync_ports.py
new file mode 100644
index 0000000..4f6ce14
--- /dev/null
+++ b/xos/synchronizers/openstack/steps/sync_ports.py
@@ -0,0 +1,230 @@
+import os
+import base64
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.openstacksyncstep import OpenStackSyncStep
+from core.models import Controller
+from core.models.network import *
+from xos.logger import observer_logger as logger
+
+class SyncPorts(OpenStackSyncStep):
+    requested_interval = 0 # 3600
+    provides=[Port]
+    observes=Port
+
+    #     The way it works is to enumerate the all of the ports that quantum
+    #     has, and then work backward from each port's network-id to determine
+    #     which Network is associated from the port.
+
+    def call(self, failed=[], deletion=False):
+        if deletion:
+            self.delete_ports()
+        else:
+            self.sync_ports()
+
+    def get_driver(self, port):
+        # We need to use a client driver that specifies the tenant
+        # of the destination instance. Nova-compute will not connect
+        # ports to instances if the port's tenant does not match
+        # the instance's tenant.
+
+        # A bunch of stuff to compensate for OpenStackDriver.client_driveR()
+        # not being in working condition.
+        from openstack.client import OpenStackClient
+        from openstack.driver import OpenStackDriver
+        controller = port.instance.node.site_deployment.controller
+        slice = port.instance.slice
+        caller = port.network.owner.creator
+        auth = {'username': caller.email,
+                'password': caller.remote_password,
+                'tenant': slice.name}
+        client = OpenStackClient(controller=controller, **auth) # cacert=self.config.nova_ca_ssl_cert,
+        driver = OpenStackDriver(client=client)
+
+        return driver
+
+    def sync_ports(self):
+        logger.info("sync'ing Ports [delete=False]")
+
+        ports = Port.objects.all()
+        ports_by_id = {}
+        ports_by_neutron_port = {}
+        for port in ports:
+            ports_by_id[port.id] = port
+            ports_by_neutron_port[port.port_id] = port
+
+        networks = Network.objects.all()
+        networks_by_id = {}
+        for network in networks:
+            for nd in network.controllernetworks.all():
+                networks_by_id[nd.net_id] = network
+
+        #logger.info("networks_by_id = ")
+        #for (network_id, network) in networks_by_id.items():
+        #    logger.info("   %s: %s" % (network_id, network.name))
+
+        instances = Instance.objects.all()
+        instances_by_instance_uuid = {}
+        for instance in instances:
+            instances_by_instance_uuid[instance.instance_uuid] = instance
+
+        # Get all ports in all controllers
+
+        ports_by_id = {}
+        templates_by_id = {}
+        for controller in Controller.objects.all():
+            if not controller.admin_tenant:
+                logger.info("controller %s has no admin_tenant" % controller)
+                continue
+            try:
+                driver = self.driver.admin_driver(controller = controller)
+                ports = driver.shell.quantum.list_ports()["ports"]
+            except:
+                logger.log_exc("failed to get ports from controller %s" % controller)
+                continue
+
+            for port in ports:
+                ports_by_id[port["id"]] = port
+
+            # public-nat and public-dedicated networks don't have a net-id anywhere
+            # in the data model, so build up a list of which ids map to which network
+            # templates.
+            try:
+                neutron_networks = driver.shell.quantum.list_networks()["networks"]
+            except:
+                print "failed to get networks from controller %s" % controller
+                continue
+            for network in neutron_networks:
+                for template in NetworkTemplate.objects.all():
+                    if template.shared_network_name == network["name"]:
+                        templates_by_id[network["id"]] = template
+
+        for port in ports_by_id.values():
+            #logger.info("port %s" % str(port))
+            if port["id"] in ports_by_neutron_port:
+                # we already have it
+                #logger.info("already accounted for port %s" % port["id"])
+                continue
+
+            if port["device_owner"] != "compute:nova":
+                # we only want the ports that connect to instances
+                #logger.info("port %s is not a compute port, it is a %s" % (port["id"], port["device_owner"]))
+                continue
+
+            instance = instances_by_instance_uuid.get(port['device_id'], None)
+            if not instance:
+                logger.info("no instance for port %s device_id %s" % (port["id"], port['device_id']))
+                continue
+
+            network = networks_by_id.get(port['network_id'], None)
+            if not network:
+                # maybe it's public-nat or public-dedicated. Search the templates for
+                # the id, then see if the instance's slice has some network that uses
+                # that template
+                template = templates_by_id.get(port['network_id'], None)
+                if template and instance.slice:
+                    for candidate_network in instance.slice.networks.all():
+                         if candidate_network.template == template:
+                             network=candidate_network
+            if not network:
+                logger.info("no network for port %s network %s" % (port["id"], port["network_id"]))
+
+                # we know it's associated with a instance, but we don't know
+                # which network it is part of.
+
+                continue
+
+            if network.template.shared_network_name:
+                # If it's a shared network template, then more than one network
+                # object maps to the quantum network. We have to do a whole bunch
+                # of extra work to find the right one.
+                networks = network.template.network_set.all()
+                network = None
+                for candidate_network in networks:
+                    if (candidate_network.owner == instance.slice):
+                        logger.info("found network %s" % candidate_network)
+                        network = candidate_network
+
+                if not network:
+                    logger.info("failed to find the correct network for a shared template for port %s network %s" % (port["id"], port["network_id"]))
+                    continue
+
+            if not port["fixed_ips"]:
+                logger.info("port %s has no fixed_ips" % port["id"])
+                continue
+
+            ip=port["fixed_ips"][0]["ip_address"]
+            mac=port["mac_address"]
+            logger.info("creating Port (%s, %s, %s, %s)" % (str(network), str(instance), ip, str(port["id"])))
+
+            ns = Port(network=network,
+                               instance=instance,
+                               ip=ip,
+                               mac=mac,
+                               port_id=port["id"])
+
+            try:
+                ns.save()
+            except:
+                logger.log_exc("failed to save port %s" % str(ns))
+                continue
+
+        # For ports that were created by the user, find that ones
+        # that don't have neutron ports, and create them.
+        for port in Port.objects.filter(Q(port_id__isnull=True), Q(instance__isnull=False) ):
+            logger.info("XXX working on port %s" % port)
+            controller = port.instance.node.site_deployment.controller
+            slice = port.instance.slice
+
+            if controller:
+                cn=port.network.controllernetworks.filter(controller=controller)
+                if not cn:
+                    logger.log_exc("no controllernetwork for %s" % port)
+                    continue
+                cn=cn[0]
+                if cn.lazy_blocked:
+                    cn.lazy_blocked=False
+                    cn.save()
+                    logger.info("deferring port %s because controllerNetwork was lazy-blocked" % port)
+                    continue
+                if not cn.net_id:
+                    logger.info("deferring port %s because controllerNetwork does not have a port-id yet" % port)
+                    continue
+                try:
+                    driver = self.get_driver(port)
+
+                    args = {"network_id": cn.net_id}
+                    neutron_port_name = port.get_parameters().get("neutron_port_name", None)
+                    if neutron_port_name:
+                        args["name"] = neutron_port_name
+
+                    neutron_port = driver.shell.quantum.create_port({"port": args})["port"]
+                    port.port_id = neutron_port["id"]
+                    if neutron_port["fixed_ips"]:
+                        port.ip = neutron_port["fixed_ips"][0]["ip_address"]
+                    port.mac = neutron_port["mac_address"]
+                    port.xos_created = True
+                    logger.info("created neutron port %s for %s" % (port.port_id, port))
+                except:
+                    logger.log_exc("failed to create neutron port for %s" % port)
+                    continue
+                port.save()
+
+    def delete_ports(self):
+        logger.info("sync'ing Ports [delete=True]")
+        for port in Port.deleted_objects.all():
+            self.delete_record(port)
+
+    def delete_record(self, port):
+        if port.xos_created and port.port_id:
+            logger.info("calling openstack to destroy port %s" % port.port_id)
+            try:
+                driver = self.get_driver(port)
+                driver.shell.quantum.delete_port(port.port_id)
+            except:
+                logger.log_exc("failed to delete port %s from neutron" % port.port_id)
+                return
+
+        logger.info("Purging port %s" % port)
+        port.delete(purge=True)
+
diff --git a/xos/synchronizers/openstack/steps/sync_roles.py b/xos/synchronizers/openstack/steps/sync_roles.py
new file mode 100644
index 0000000..e859316
--- /dev/null
+++ b/xos/synchronizers/openstack/steps/sync_roles.py
@@ -0,0 +1,23 @@
+import os
+import base64
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.openstacksyncstep import OpenStackSyncStep
+from core.models.role import Role
+from core.models.site import SiteRole, Controller, ControllerRole
+from core.models.slice import SliceRole
+from xos.logger import observer_logger as logger
+
+class SyncRoles(OpenStackSyncStep):
+    provides=[Role]
+    requested_interval=0
+    observes=[SiteRole,SliceRole,ControllerRole]
+
+    def sync_record(self, role):
+        if not role.enacted:
+            controllers = Controller.objects.all()
+       	    for controller in controllers:
+                driver = self.driver.admin_driver(controller=controller)
+                driver.create_role(role.role)
+            role.save()
+    
diff --git a/xos/synchronizers/openstack/steps/teardown_container.yaml b/xos/synchronizers/openstack/steps/teardown_container.yaml
new file mode 100644
index 0000000..5cabc78
--- /dev/null
+++ b/xos/synchronizers/openstack/steps/teardown_container.yaml
@@ -0,0 +1,33 @@
+---
+- hosts: {{ instance_name }}
+  gather_facts: False
+  connection: ssh
+  user: {{ username }}
+  sudo: yes
+
+  vars:
+    container_name: {{ container_name }}
+    docker_image: {{ docker_image }}
+    ports:
+    {% for port in ports %}
+       - device: {{ port.device }}
+         xos_network_id: {{ port.xos_network_id }}
+         mac: {{ port.mac|default("") }}
+         ip: {{ port.ip }}
+         snoop_instance_mac: {{ port.snoop_instance_mac }}
+         snoop_instance_id: {{ port.snoop_instance_id }}
+         parent_mac: {{ port.parent_mac|default("") }}
+         s_tag: {{ port.s_tag|default("")  }}
+         c_tag: {{ port.c_tag|default("") }}
+         next_hop: {{ port.next_hop|default("") }}
+         bridge: {{ port.bridge }}
+    {% endfor %}
+    volumes:
+    {% for volume in volumes %}
+       - {{ volume }}
+    {% endfor %}
+
+  tasks:
+  - name: Make sure container is stopped
+    service: name=container-{{ container_name }} state=stopped
+
diff --git a/xos/synchronizers/openstack/templates/container.conf.j2 b/xos/synchronizers/openstack/templates/container.conf.j2
new file mode 100644
index 0000000..7cbb880
--- /dev/null
+++ b/xos/synchronizers/openstack/templates/container.conf.j2
@@ -0,0 +1,14 @@
+# Upstart script for container
+description "container"
+author "smbaker@gmail.com"
+start on filesystem and started docker
+stop on runlevel [!2345]
+respawn
+
+script
+  /usr/local/sbin/start-container-{{ container_name }}.sh ATTACH
+end script
+
+post-stop script
+  /usr/local/sbin/stop-container-{{ container_name }}.sh
+end script
\ No newline at end of file
diff --git a/xos/synchronizers/openstack/templates/container.service.j2 b/xos/synchronizers/openstack/templates/container.service.j2
new file mode 100644
index 0000000..817d6d7
--- /dev/null
+++ b/xos/synchronizers/openstack/templates/container.service.j2
@@ -0,0 +1,11 @@
+[Unit]
+Description={{ container_name }}
+After=docker.service
+
+[Service]
+ExecStart=/bin/bash -c "/usr/local/sbin/start-container-{{ container_name }}.sh ATTACH"
+ExecStop=/bin/bash -c "/usr/local/sbin/stop-container-{{ container_name }}.sh"
+SuccessExitStatus=0 137
+
+[Install]
+WantedBy=multi-user.target
diff --git a/xos/synchronizers/openstack/templates/start-container.sh.j2 b/xos/synchronizers/openstack/templates/start-container.sh.j2
new file mode 100644
index 0000000..2fbf478
--- /dev/null
+++ b/xos/synchronizers/openstack/templates/start-container.sh.j2
@@ -0,0 +1,136 @@
+#!/bin/bash
+
+iptables -L > /dev/null
+ip6tables -L > /dev/null
+
+CONTAINER={{ container_name }}
+IMAGE={{ docker_image }}
+
+function mac_to_iface {
+    PARENT_MAC=$1
+    ifconfig|grep $PARENT_MAC| awk '{print $1}'|grep -v '\.'
+}
+
+function encapsulate_stag {
+    LAN_IFACE=$1
+    STAG=$2
+    ifconfig $LAN_IFACE >> /dev/null
+    if [ "$?" == 0 ]; then
+        STAG_IFACE=$LAN_IFACE.$STAG
+        ifconfig $LAN_IFACE up
+        ifconfig $STAG_IFACE
+        if [ "$?" == 0 ]; then
+            echo $STAG_IFACE is already created
+        else
+            ifconfig $STAG_IFACE >> /dev/null || ip link add link $LAN_IFACE name $STAG_IFACE type vlan id $STAG
+        fi
+            ifconfig $STAG_IFACE up
+    else
+        echo There is no $LAN_IFACE. Aborting.
+        exit -1
+    fi
+}
+
+
+{% if volumes %}
+{% for volume in volumes %}
+DEST_DIR=/var/container_volumes/$CONTAINER/{{ volume }}
+mkdir -p $DEST_DIR
+VOLUME_ARGS="$VOLUME_ARGS -v $DEST_DIR:{{ volume }}"
+{% endfor %}
+{% endif %}
+
+docker inspect $CONTAINER > /dev/null 2>&1
+if [ "$?" == 1 ]
+then
+    docker pull $IMAGE
+{% if network_method=="host" %}
+    docker run -d --name=$CONTAINER --privileged=true --net=host $VOLUME_ARGS $IMAGE
+{% elif network_method=="bridged" %}
+    docker run -d --name=$CONTAINER --privileged=true --net=bridge $VOLUME_ARGS $IMAGE
+{% else %}
+    docker run -d --name=$CONTAINER --privileged=true --net=none $VOLUME_ARGS $IMAGE
+{% endif %}
+else
+    docker start $CONTAINER
+fi
+
+{% if ports %}
+{% for port in ports %}
+
+{% if port.next_hop %}
+NEXTHOP_ARG="@{{ port.next_hop }}"
+{% else %}
+NEXTHOP_ARG=""
+{% endif %}
+
+{% if port.c_tag %}
+CTAG_ARG="@{{ port.c_tag }}"
+{% else %}
+CTAG_ARG=""
+{% endif %}
+
+{% if port.parent_mac %}
+# container-in-VM
+SRC_DEV=$( mac_to_iface "{{ port.parent_mac }}" )
+CMD="docker exec $CONTAINER ifconfig $SRC_DEV >> /dev/null || pipework $SRC_DEV -i {{ port.device }} $CONTAINER {{ port.ip }}/24$NEXTHOP_ARG {{ port.mac }} $CTAG_ARG"
+echo $CMD
+eval $CMD
+
+{% else %}
+# container-on-metal
+IP="{{ port.ip }}"
+{% if port.mac %}
+MAC="{{ port.mac }}"
+{% else %}
+MAC=""
+{% endif %}
+
+DEVICE="{{ port.device }}"

+BRIDGE="{{ port.bridge }}"

+{% if port.s_tag %}

+# This is intended for lan_network. Assume that BRIDGE is set to br_lan. We

+# create a device that strips off the S-TAG.

+STAG="{{ port.s_tag }}"

+encapsulate_stag $BRIDGE $STAG

+SRC_DEV=$STAG_IFACE

+{% else %}

+# This is for a standard neutron private network. We use a donor VM to setup

+# openvswitch for us, and we snoop at its devices and create a tap using the

+# same settings.

+XOS_NETWORK_ID="{{ port.xos_network_id }}"

+INSTANCE_MAC="{{ port.snoop_instance_mac }}"
+INSTANCE_ID="{{ port.snoop_instance_id }}"
+INSTANCE_TAP=`virsh domiflist $INSTANCE_ID | grep -i $INSTANCE_MAC | awk '{print $1}'`
+INSTANCE_TAP=${INSTANCE_TAP:3}
+VLAN_ID=`ovs-vsctl show | grep -i -A 1 port.*$INSTANCE_TAP | grep -i tag | awk '{print $2}'`
+# One tap for all containers per XOS/neutron network. Included the VLAN_ID in the
+# hash, to cover the case where XOS is reinstalled and the XOS network ids
+# get reused.
+TAP="con`echo ${XOS_NETWORK_ID}_$VLAN_ID|md5sum|awk '{print $1}'`"
+TAP=${TAP:0:10}
+echo im=$INSTANCE_MAC ii=$INSTANCE_ID it=$INSTANCE_TAP vlan=$VLAN_ID tap=$TAP con=$CONTAINER dev=$DEVICE mac=$MAC
+ovs-vsctl show | grep -i $TAP
+if [[ $? == 1 ]]; then
+    echo creating tap
+    ovs-vsctl add-port $BRIDGE $TAP tag=$VLAN_ID -- set interface $TAP type=internal
+else
+    echo tap exists
+fi
+SRC_DEV=$TAP
+{% endif %}
+
+CMD="docker exec $CONTAINER ifconfig $DEVICE >> /dev/null || pipework $SRC_DEV -i $DEVICE $CONTAINER $IP/24$NEXTHOP_ARG $MAC $CTAG_ARG"
+echo $CMD
+eval $CMD
+{% endif %}
+{% endfor %}
+{% endif %}
+
+# Attach to container
+# (this is only done when using upstart, since upstart expects to be attached
+#  to a running service)
+if [[ "$1" == "ATTACH" ]]; then
+    docker start -a $CONTAINER
+fi
+
diff --git a/xos/synchronizers/openstack/templates/stop-container.sh.j2 b/xos/synchronizers/openstack/templates/stop-container.sh.j2
new file mode 100644
index 0000000..9cabb00
--- /dev/null
+++ b/xos/synchronizers/openstack/templates/stop-container.sh.j2
@@ -0,0 +1,4 @@
+CONTAINER={{ container_name }}
+
+docker stop $CONTAINER
+docker rm $CONTAINER
diff --git a/xos/synchronizers/openstack/xos-synchronizer.py b/xos/synchronizers/openstack/xos-synchronizer.py
new file mode 100644
index 0000000..493b94a
--- /dev/null
+++ b/xos/synchronizers/openstack/xos-synchronizer.py
@@ -0,0 +1,85 @@
+#!/usr/bin/env python
+import os
+import argparse
+import sys
+
+sys.path.append('/opt/xos')
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
+from synchronizers.base.backend import Backend
+from xos.config import Config, DEFAULT_CONFIG_FN
+from core.models import Instance,NetworkTemplate
+from xos.logger import Logger, logging, logger
+from django.db import ProgrammingError
+import time
+
+try:
+    from django import setup as django_setup # django 1.7
+except:
+    django_setup = False
+
+config = Config()
+
+# after http://www.erlenstar.demon.co.uk/unix/faq_2.html
+def daemon():
+    """Daemonize the current process."""
+    if os.fork() != 0: os._exit(0)
+    os.setsid()
+    if os.fork() != 0: os._exit(0)
+    os.umask(0)
+    devnull = os.open(os.devnull, os.O_RDWR)
+    os.dup2(devnull, 0)
+    # xxx fixme - this is just to make sure that nothing gets stupidly lost - should use devnull
+    logdir=os.path.dirname(config.observer_logfile)
+    # when installed in standalone we might not have httpd installed
+    if not os.path.isdir(logdir): os.mkdir(logdir)
+    crashlog = os.open('%s'%config.observer_logfile, os.O_RDWR | os.O_APPEND | os.O_CREAT, 0644)
+    os.dup2(crashlog, 1)
+    os.dup2(crashlog, 2)
+
+    if hasattr(config, "observer_pidfile"):
+        pidfile = config.get("observer_pidfile")
+    else:
+        pidfile = "/var/run/xosobserver.pid"
+    try:
+        file(pidfile,"w").write(str(os.getpid()))
+    except:
+        print "failed to create pidfile %s" % pidfile
+
+def main():
+    # Generate command line parser
+    parser = argparse.ArgumentParser(usage='%(prog)s [options]')
+    parser.add_argument('-d', '--daemon', dest='daemon', action='store_true', default=False,
+                        help='Run as daemon.')
+    # smbaker: util/config.py parses sys.argv[] directly to get config file name; include the option here to avoid
+    #   throwing unrecognized argument exceptions
+    parser.add_argument('-C', '--config', dest='config_file', action='store', default=DEFAULT_CONFIG_FN,
+                        help='Name of config file.')
+    args = parser.parse_args()
+
+    if args.daemon: daemon()
+
+    if django_setup: # 1.7
+        django_setup()
+
+    models_active = False
+    wait = False
+    while not models_active:
+        try:
+            _ = Instance.objects.first()
+            _ = NetworkTemplate.objects.first()
+            models_active = True
+        except Exception,e:
+            logger.info(str(e))
+            logger.info('Waiting for data model to come up before starting...')
+            time.sleep(10)
+            wait = True
+
+    if (wait):
+        time.sleep(60) # Safety factor, seeing that we stumbled waiting for the data model to come up.
+    backend = Backend()
+    backend.run()    
+
+if __name__ == '__main__':
+    
+    main() 
diff --git a/xos/synchronizers/requestrouter/configurationPush.py b/xos/synchronizers/requestrouter/configurationPush.py
new file mode 100644
index 0000000..857de8b
--- /dev/null
+++ b/xos/synchronizers/requestrouter/configurationPush.py
@@ -0,0 +1,30 @@
+import ansible.playbook
+import ansible.constants as C
+import ansible.utils.template
+from ansible import errors
+from ansible import callbacks
+from ansible import utils
+from subprocess import call
+
+class ConfigurationPush:
+	def __init__(self):
+		pass
+
+	def config_push(self, service_name, user, playbook_name,hostfile):
+		'''stats = callbacks.AggregateStats()
+		playbook_cb = callbacks.PlaybookCallbacks(verbose=utils.VERBOSITY)
+		runner_cb = callbacks.PlaybookRunnerCallbacks(stats, verbose=utils.VERBOSITY)
+		pb = ansible.playbook.PlayBook(playbook="playbook/site.yml",
+					callbacks=playbook_cb,
+            				runner_callbacks=runner_cb,
+            				stats=stats
+					)
+		result = pb.run()
+		print result
+		'''
+
+		call("ansible-playbook --private-key=planetw "+playbook_name+" -i "+hostfile+" -u "+user+"  --extra-vars \"name="+service_name+"\"", shell=True)
+	
+
+if __name__ == "__main__":
+        main()
diff --git a/xos/synchronizers/requestrouter/deleters/servicemap_deleter.py b/xos/synchronizers/requestrouter/deleters/servicemap_deleter.py
new file mode 100644
index 0000000..d2efd64
--- /dev/null
+++ b/xos/synchronizers/requestrouter/deleters/servicemap_deleter.py
@@ -0,0 +1,42 @@
+import os
+import sys
+import traceback
+from services.requestrouter.models import ServiceMap
+from synchronizers.base.deleter import Deleter
+from xos.logger import Logger, logging
+from xos.config import Config, XOS_DIR
+
+parentdir = os.path.join(os.path.dirname(__file__),"..")
+sys.path.insert(0,parentdir)
+
+from rrlib import RequestRouterLibrary
+from configurationPush import ConfigurationPush
+import rrlib_config
+
+logger = Logger(level=logging.INFO)
+
+class ServiceMapDeleter(Deleter, RequestRouterLibrary, ConfigurationPush):
+        model='ServiceMap'
+
+        def __init__(self, **args):
+            Deleter.__init__(self, **args)
+            RequestRouterLibrary.__init__(self)
+            ConfigurationPush.__init__(self)
+
+
+        def call(self, pk, model_dict):
+          try:
+              servicemap = ServiceMap.objects.get(pk=pk)
+              service_uid = self.get_servicemap_uid(servicemap)
+              self.config_push(service_uid, rrlib_config.REDIR_USER, XOS_DIR + "/observers/requestrouter/playbook/site_redir_delete.yml", "/etc/ansible/requestrouter/dnsredir/hosts")
+              self.config_push(service_uid, rrlib_config.DEMUX_USER, XOS_DIR + "/observers/requestrouter/playbook/site_demux_delete.yml", "/etc/ansible/requestrouter/dnsdemux/hosts")
+              print "XXX delete ServiceMap %s", servicemap.name
+              return True
+          except Exception, e:
+              traceback.print_exc()
+              logger.exception("Failed to erase map '%s'" % map_name)
+              return False
+
+if __name__ == "__main__":
+  smap = ServiceMapDeleter()
+  smap.call( 6, {'name': 'Service23'} )
diff --git a/xos/synchronizers/requestrouter/model-deps b/xos/synchronizers/requestrouter/model-deps
new file mode 100644
index 0000000..36ef620
--- /dev/null
+++ b/xos/synchronizers/requestrouter/model-deps
@@ -0,0 +1,12 @@
+{
+    "ServiceMap": [
+        "Slice"
+    ], 
+    "Slice": [
+        "Site", 
+        "Service"
+    ], 
+    "User": [
+        "Site"
+    ]
+}
diff --git a/xos/synchronizers/requestrouter/playbook/roles/delete_demux/handlers/main.yml b/xos/synchronizers/requestrouter/playbook/roles/delete_demux/handlers/main.yml
new file mode 100644
index 0000000..a888468
--- /dev/null
+++ b/xos/synchronizers/requestrouter/playbook/roles/delete_demux/handlers/main.yml
@@ -0,0 +1,3 @@
+---
+- name: restart dnsdemux
+  service: name=dnsdemux state=restarted
diff --git a/xos/synchronizers/requestrouter/playbook/roles/delete_demux/tasks/main.yml b/xos/synchronizers/requestrouter/playbook/roles/delete_demux/tasks/main.yml
new file mode 100644
index 0000000..417401a
--- /dev/null
+++ b/xos/synchronizers/requestrouter/playbook/roles/delete_demux/tasks/main.yml
@@ -0,0 +1,5 @@
+---
+# This playbook contains plays to delete configuration files from dnsdemux slice
+- name: delete dnsdemux config files
+  file: path={{dst_dnsdemux_conf}}/{{name}}.conf state=absent
+  notify: restart dnsdemux
diff --git a/xos/synchronizers/requestrouter/playbook/roles/delete_demux/vars/main.yml b/xos/synchronizers/requestrouter/playbook/roles/delete_demux/vars/main.yml
new file mode 100644
index 0000000..b457050
--- /dev/null
+++ b/xos/synchronizers/requestrouter/playbook/roles/delete_demux/vars/main.yml
@@ -0,0 +1,6 @@
+---
+# Variables listed here are applicable to all host groups
+
+src_dnsdemux: ../../../../temp_config/dnsdemux
+dst_dnsdemux_conf: /etc/dnsdemux/default/
+
diff --git a/xos/synchronizers/requestrouter/playbook/roles/delete_redir/handlers/main.yml b/xos/synchronizers/requestrouter/playbook/roles/delete_redir/handlers/main.yml
new file mode 100644
index 0000000..8aa497e
--- /dev/null
+++ b/xos/synchronizers/requestrouter/playbook/roles/delete_redir/handlers/main.yml
@@ -0,0 +1,3 @@
+---
+- name: restart dnsredir
+  service: name=dnsredir state=restarted
diff --git a/xos/synchronizers/requestrouter/playbook/roles/delete_redir/tasks/main.yml b/xos/synchronizers/requestrouter/playbook/roles/delete_redir/tasks/main.yml
new file mode 100644
index 0000000..58833bb
--- /dev/null
+++ b/xos/synchronizers/requestrouter/playbook/roles/delete_redir/tasks/main.yml
@@ -0,0 +1,13 @@
+---
+# This playbook contains plays to delete configuration files from dnsredir slice
+- name: delete  maps.d directory ( and deletes all intermeadiate directories )
+  #copy: src={{src_dnsredir}}/{{name}}.d dest={{dst_dnsredir_confdir}}
+  file: path={{dst_dnsredir_confdir}}/{{name}}.d/maps.d state=absent
+ 
+- name: delete config directory
+  file: path={{dst_dnsredir_confdir}}/{{name}}.d/ state=absent
+ 
+- name: copy dnsredir config file
+  file: path={{dst_dnsredir_conf}}/{{name}}.conf state=absent
+  notify: restart dnsredir
+
diff --git a/xos/synchronizers/requestrouter/playbook/roles/delete_redir/vars/main.yml b/xos/synchronizers/requestrouter/playbook/roles/delete_redir/vars/main.yml
new file mode 100644
index 0000000..dc79d35
--- /dev/null
+++ b/xos/synchronizers/requestrouter/playbook/roles/delete_redir/vars/main.yml
@@ -0,0 +1,6 @@
+---
+# Variables listed here are applicable to all host groups
+
+src_dnsredir: ../../../../temp_config/dnsredir
+dst_dnsredir_conf: /etc/dnsredir/conf.d/
+dst_dnsredir_confdir: /etc/dnsredir
diff --git a/xos/synchronizers/requestrouter/playbook/roles/demux/handlers/main.yml b/xos/synchronizers/requestrouter/playbook/roles/demux/handlers/main.yml
new file mode 100644
index 0000000..a888468
--- /dev/null
+++ b/xos/synchronizers/requestrouter/playbook/roles/demux/handlers/main.yml
@@ -0,0 +1,3 @@
+---
+- name: restart dnsdemux
+  service: name=dnsdemux state=restarted
diff --git a/xos/synchronizers/requestrouter/playbook/roles/demux/tasks/main.yml b/xos/synchronizers/requestrouter/playbook/roles/demux/tasks/main.yml
new file mode 100644
index 0000000..0339aed
--- /dev/null
+++ b/xos/synchronizers/requestrouter/playbook/roles/demux/tasks/main.yml
@@ -0,0 +1,9 @@
+---
+# This playbook contains plays to copy configurations to destination
+- name: copy dnsdemux config files
+  copy: src={{src_dnsdemux}}/{{name}}.conf dest={{dst_dnsdemux_conf}}/{{name}}.conf
+  notify: restart dnsdemux
+
+#- name: Start the dnsdemux service
+  #service: name=dnsdemux state=started enabled=true
+
diff --git a/xos/synchronizers/requestrouter/playbook/roles/demux/vars/main.yml b/xos/synchronizers/requestrouter/playbook/roles/demux/vars/main.yml
new file mode 100644
index 0000000..b457050
--- /dev/null
+++ b/xos/synchronizers/requestrouter/playbook/roles/demux/vars/main.yml
@@ -0,0 +1,6 @@
+---
+# Variables listed here are applicable to all host groups
+
+src_dnsdemux: ../../../../temp_config/dnsdemux
+dst_dnsdemux_conf: /etc/dnsdemux/default/
+
diff --git a/xos/synchronizers/requestrouter/playbook/roles/redir/handlers/main.yml b/xos/synchronizers/requestrouter/playbook/roles/redir/handlers/main.yml
new file mode 100644
index 0000000..8aa497e
--- /dev/null
+++ b/xos/synchronizers/requestrouter/playbook/roles/redir/handlers/main.yml
@@ -0,0 +1,3 @@
+---
+- name: restart dnsredir
+  service: name=dnsredir state=restarted
diff --git a/xos/synchronizers/requestrouter/playbook/roles/redir/tasks/main.yml b/xos/synchronizers/requestrouter/playbook/roles/redir/tasks/main.yml
new file mode 100644
index 0000000..e390ed9
--- /dev/null
+++ b/xos/synchronizers/requestrouter/playbook/roles/redir/tasks/main.yml
@@ -0,0 +1,19 @@
+---
+# This playbook contains plays to copy configurations to destination
+- name: create  maps.d directory ( and creates all intermeadiate directories )
+  #copy: src={{src_dnsredir}}/{{name}}.d dest={{dst_dnsredir_confdir}}
+  file: src={{src_dnsredir}}/{{name}}.d/maps.d dest={{dst_dnsredir_confdir}}/{{name}}.d/maps.d state=directory
+ 
+- name: copy map.conf
+  copy: src={{src_dnsredir}}/{{name}}.d/maps.d/map.conf dest={{dst_dnsredir_confdir}}/{{name}}.d/maps.d/map.conf
+ 
+- name: copy codeen_nodes.conf
+  copy: src={{src_dnsredir}}/{{name}}.d/codeen_nodes.conf dest={{dst_dnsredir_confdir}}/{{name}}.d/codeen_nodes.conf
+  
+- name: copy node-to-ip.txt
+  copy: src={{src_dnsredir}}/{{name}}.d/node-to-ip.txt dest={{dst_dnsredir_confdir}}/{{name}}.d/node-to-ip.txt
+
+- name: copy dnsredir config file
+  copy: src={{src_dnsredir}}/{{name}}.conf dest={{dst_dnsredir_conf}}/{{name}}.conf
+  notify: restart dnsredir
+
diff --git a/xos/synchronizers/requestrouter/playbook/roles/redir/vars/main.yml b/xos/synchronizers/requestrouter/playbook/roles/redir/vars/main.yml
new file mode 100644
index 0000000..dc79d35
--- /dev/null
+++ b/xos/synchronizers/requestrouter/playbook/roles/redir/vars/main.yml
@@ -0,0 +1,6 @@
+---
+# Variables listed here are applicable to all host groups
+
+src_dnsredir: ../../../../temp_config/dnsredir
+dst_dnsredir_conf: /etc/dnsredir/conf.d/
+dst_dnsredir_confdir: /etc/dnsredir
diff --git a/xos/synchronizers/requestrouter/playbook/site_demux.yml b/xos/synchronizers/requestrouter/playbook/site_demux.yml
new file mode 100644
index 0000000..b5261dc
--- /dev/null
+++ b/xos/synchronizers/requestrouter/playbook/site_demux.yml
@@ -0,0 +1,9 @@
+---
+# This playbook copies the dnsdemux configuration files from temp directory.
+
+- name: copies the configuration files from temp directory
+  hosts: all
+  #remote_user: {{r_user}}
+
+  roles:
+    - demux
diff --git a/xos/synchronizers/requestrouter/playbook/site_demux_delete.yml b/xos/synchronizers/requestrouter/playbook/site_demux_delete.yml
new file mode 100644
index 0000000..49a7c87
--- /dev/null
+++ b/xos/synchronizers/requestrouter/playbook/site_demux_delete.yml
@@ -0,0 +1,9 @@
+---
+# This playbook deletes the dnsdemux configuration files from request router instances
+
+- name: deletes the configuration files from request router instances
+  hosts: all
+  #remote_user: {{r_user}}
+
+  roles:
+    - delete_demux
diff --git a/xos/synchronizers/requestrouter/playbook/site_redir.yml b/xos/synchronizers/requestrouter/playbook/site_redir.yml
new file mode 100644
index 0000000..50a7284
--- /dev/null
+++ b/xos/synchronizers/requestrouter/playbook/site_redir.yml
@@ -0,0 +1,9 @@
+---
+# This playbook copies the dnsredir configuration files from temp directory.
+
+- name: copies the configuration files from temp directory
+  hosts: all
+  #remote_user: {{r_user}}
+
+  roles:
+    - redir
diff --git a/xos/synchronizers/requestrouter/playbook/site_redir_delete.yml b/xos/synchronizers/requestrouter/playbook/site_redir_delete.yml
new file mode 100644
index 0000000..9a8611d
--- /dev/null
+++ b/xos/synchronizers/requestrouter/playbook/site_redir_delete.yml
@@ -0,0 +1,9 @@
+---
+# This playbook deletes the dnsredir configuration files from request router instances
+
+- name: deletes the configuration files from request router instances
+  hosts: all
+  #remote_user: {{r_user}}
+
+  roles:
+    - delete_redir
diff --git a/xos/synchronizers/requestrouter/rr_synchronizer_config b/xos/synchronizers/requestrouter/rr_synchronizer_config
new file mode 100644
index 0000000..179540e
--- /dev/null
+++ b/xos/synchronizers/requestrouter/rr_synchronizer_config
@@ -0,0 +1,36 @@
+
+[plc]
+name=plc
+#deployment=VICCI
+deployment=VINI
+
+[db]
+name=xos
+user=plstackuser
+#password=2uMDYtJK
+password=1HL07C0E
+host=localhost
+port=5432
+
+[api]
+host=128.112.171.237
+port=8000
+ssl_key=None
+ssl_cert=None
+ca_ssl_cert=None
+ratelimit_enabled=0
+omf_enabled=0
+mail_support_address=support@localhost
+nova_enabled=True
+
+[observer]
+dependency_graph=/opt/xos/synchronizers/requestrouter/model-deps
+steps_dir=/opt/xos/synchronizers/requestrouter/steps
+deleters_dir=/opt/xos/synchronizers/requestrouter/deleters
+log_file=console
+#/var/log/hpc.log
+driver=None
+
+#[feefie]
+#client_id='vicci_dev_central'
+#user_id='pl'
diff --git a/xos/synchronizers/requestrouter/rrlib.py b/xos/synchronizers/requestrouter/rrlib.py
new file mode 100644
index 0000000..e2100b0
--- /dev/null
+++ b/xos/synchronizers/requestrouter/rrlib.py
@@ -0,0 +1,203 @@
+import os
+import base64
+import string
+import sys
+import socket
+from sets import Set
+if __name__ == '__main__':
+    sys.path.append("/opt/xos")
+    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
+
+from xos.config import Config
+from core.models import Service
+from services.requestrouter.models import RequestRouterService, ServiceMap
+from xos.logger import Logger, logging
+import rrlib_config
+
+logger = Logger(level=logging.INFO)
+
+'''
+Conventions:
+1) All dnsredir backend will listen at port 9000+ servicemap.pk ( where pk is the primary key generated in django model)
+'''
+
+class RequestRouterLibrary:
+
+    def __init__(self):
+        pass
+    
+    def gen_slice_info(self, service=None):   
+        """generates instance information from slice of request router
+        """
+
+        if (service is None ):
+            service = RequestRouterService.objects.get()
+
+        mapping = {}
+        #static mapping for demo purpose 
+        #mapping["node47.princeton.vicci.org"] = "128.112.171.112"
+        mapping["node48.princeton.vicci.org"] = "128.112.171.114"
+    
+        '''for slice in service.service.all():
+            name = slice.name
+            for instance in slice.instances.all():
+                mapping[instance.name] = str(instance.ip)
+        '''
+        return mapping
+
+    def gen_servicemap_slice_info(self, servicemap):
+        """generates instance information from slice of servicemap
+        """
+
+        wzone = Set(['arizona', 'stanford', 'on.lab', 'housten']) # zone=1 in cooden.conf
+        ezone = Set(['princeton', 'atlanta', 'new york', 'georgia tech']) # zone=2 in coodeen.conf
+
+        mapping_zone = {}
+        mapping_ip = {}
+        slice = servicemap.slice
+        name = slice.name
+        for instance in slice.instances.all():
+            mapping_ip[instance.node.name] = socket.gethostbyname(instance.node.name)
+            #print "instance name "+instance.name+str(instance.ip)+"\n"
+            site = instance.node.site.name
+            if(site.lower() in wzone):
+                mapping_zone[instance.node.name] = str(1)
+            else:
+                mapping_zone[instance.node.name] = str(2)
+
+        return mapping_ip, mapping_zone
+
+
+
+    def gen_slice_file(self, service):
+        """ generates host file for the slice information
+            to be used by ansible to push configuration files
+        """
+
+        mapping = self.gen_slice_info(service)
+
+        fn = "/etc/ansible/requestrouter/dnsredir/hosts"
+        f = open(fn, "w")
+        for (k,v) in mapping.items():
+            f.write("%s\n" % k)
+
+        fn = "/etc/ansible/requestrouter/dnsdemux/hosts"
+        f = open(fn, "w")
+        for (k,v) in mapping.items():
+            f.write("%s\n" % k)
+
+
+    def get_servicemap_uid(self, servicemap):
+        seq = ("service_", str(servicemap.pk));
+        return "".join(seq)
+
+    def get_service_port(self, servicemap):
+                return str(9000+servicemap.pk)
+
+    def gen_dnsredir_serviceconf(self, servicemap):
+        objname = self.get_servicemap_uid(servicemap)
+    
+        rr_mapping = self.gen_slice_info(None)
+    
+        #generate dnsredir.conf file parameters to be used in static file.
+        mapping = {}
+        mapping["port_listen"] = self.get_service_port(servicemap)
+        mapping["configdir"] = rrlib_config.DNSREDIR_CONFIGDIR_PREFIX+objname+".d/"
+        mapping["logdir"] = rrlib_config.DNSREDIR_LOGDIR_PREFIX+objname+".d"
+        mapping["pidfile"] = rrlib_config.DNSREDIR_PIDFILE_PREFIX+objname+".pid"
+        mapping["domain_name"] = servicemap.prefix      
+        mapping["heartbeat_port"] = rrlib_config.HEARTBEAT_PORT
+
+        #generate dnsredir.conf file 
+
+        fn = "./temp_config/dnsredir/"+objname+".conf"
+        f = open(fn, "w")
+        for (k,v) in rr_mapping.items():
+                        f.write(mapping["domain_name"]+". NS "+k+". "+v+" 3600 \n" % mapping)
+
+
+        f.write("""
+Default_TTL 30
+
+Port %(port_listen)s
+
+ConfigDir %(configdir)s
+
+MapsDir maps.d
+
+HTTPPort %(heartbeat_port)d
+
+PidFile %(pidfile)s
+
+HttpRequestPort 8081
+
+""" % mapping)
+
+        #generate configdirectory
+        
+        os.mkdir("./temp_config/dnsredir/"+objname+".d")
+        
+        #geenrate codeen_nodes.conf
+        mapping_ip, mapping_zone = self.gen_servicemap_slice_info(servicemap)
+
+        codeen_name = "./temp_config/dnsredir/"+objname+".d/codeen_nodes.conf"
+        f = open(codeen_name, "w")
+        for (k,v) in mapping_zone.items():
+            f.write(k+" zone="+v+" \n")
+
+        iptxt = "./temp_config/dnsredir/"+objname+".d/node-to-ip.txt"
+        f = open(iptxt, "w")
+        for (k,v) in mapping_ip.items():
+            f.write(k+" "+v+" \n")
+
+        #generate maps directory
+        os.mkdir("./temp_config/dnsredir/"+objname+".d/maps.d")
+
+        # redirection map
+        map = "./temp_config/dnsredir/"+objname+".d/maps.d/map.conf"
+        f = open(map, "w")
+		#hardcoded probable public IP masks from arizona and princeton region respectively
+        f.write("prefix "+servicemap.prefix+" \n")
+        f.write("map 150.135.211.252/32 zone 1 || zone 2 \n")
+        f.write("map 128.112.171.112/24 zone 2 || zone 1 \n")
+        f.write("map 0.0.0.0/0 zone 1 || zone 2 \n")
+
+
+    def gen_dnsdemux_serviceconf(self, servicemap):
+        '''
+        generates frontend service*.conf file for each of the service
+        It assumes that there is a dnsdemux frontend running on the RR istallation and will
+        just add a conf file for each service in /etc/dnsdemux/default
+        '''
+        objname = self.get_servicemap_uid(servicemap)
+        #generate dnsdemux.conf file parameters to be used in static file.
+       
+        port_listen = self.get_service_port(servicemap)
+        domain_name = servicemap.prefix  
+        #generate service specific .conf file
+
+        rr_mapping = self.gen_slice_info(None)
+
+        fn = "./temp_config/dnsdemux/"+objname+".conf"
+        f = open(fn, "w")
+
+        for (k,v) in rr_mapping.items():
+            f.write("Forward "+v+" "+port_listen+" 8081 "+domain_name+".\n")
+
+    
+    def teardown_temp_configfiles(self, objname):
+        if os.path.exists("./temp_config/dnsdemux/"+objname+".conf"):
+            os.remove("./temp_config/dnsdemux/"+objname+".conf")
+        if os.path.exists("./temp_config/dnsredir/"+objname+".d/maps.d/map.conf"):
+            os.remove("./temp_config/dnsredir/"+objname+".d/maps.d/map.conf")
+        if os.path.exists("./temp_config/dnsredir/"+objname+".d/maps.d"):
+            os.rmdir("./temp_config/dnsredir/"+objname+".d/maps.d")
+        if os.path.exists("./temp_config/dnsredir/"+objname+".d/node-to-ip.txt"):
+            os.remove("./temp_config/dnsredir/"+objname+".d/node-to-ip.txt")
+        if os.path.exists("./temp_config/dnsredir/"+objname+".d/codeen_nodes.conf"):
+            os.remove("./temp_config/dnsredir/"+objname+".d/codeen_nodes.conf")
+        if os.path.exists("./temp_config/dnsredir/"+objname+".d"):
+            os.rmdir("./temp_config/dnsredir/"+objname+".d")
+        if os.path.exists("./temp_config/dnsredir/"+objname+".conf"):
+            os.remove("./temp_config/dnsredir/"+objname+".conf")
+
diff --git a/xos/synchronizers/requestrouter/rrlib_config.py b/xos/synchronizers/requestrouter/rrlib_config.py
new file mode 100644
index 0000000..d0c00c2
--- /dev/null
+++ b/xos/synchronizers/requestrouter/rrlib_config.py
@@ -0,0 +1,16 @@
+#!/usr/bin/env python
+
+DNSREDIR_CONFIGDIR_PREFIX = "/etc/dnsredir/"
+DNSREDIR_LOGDIR_PREFIX = "/var/log/dnsredir/"
+DNSREDIR_PIDFILE_PREFIX = "/var/run/dnsredir."
+REDIR_USER = "princeton_coredirect"
+#REDIR_USER = "arizona_tools1"
+#DEMUX_USER = "arizona_tools1"
+DEMUX_USER = "princeton_codnsdemux"
+HEARTBEAT_PORT = 9000
+#not required as of now, as there will be only one frontend dnsdemux for all the services
+#DNSDEMUX_CONFIGDIR_PREFIX = "/etc/dnsdemux/"
+#DNSDEMUX_LOGDIR_PREFIX = "/var/log/dnsdemux/"
+#DNSDEMUX_PIDFILE_PREFIX = "/var/run/dnsdemux."
+
+TBD = "TBD"
diff --git a/xos/synchronizers/requestrouter/steps/sync_requestrouterservices.py b/xos/synchronizers/requestrouter/steps/sync_requestrouterservices.py
new file mode 100644
index 0000000..15a9b91
--- /dev/null
+++ b/xos/synchronizers/requestrouter/steps/sync_requestrouterservices.py
@@ -0,0 +1,46 @@
+import os
+import sys
+import base64
+import traceback
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.syncstep import SyncStep
+from core.models import Service
+from services.requestrouter.models import RequestRouterService
+from xos.logger import Logger, logging
+
+parentdir = os.path.join(os.path.dirname(__file__),"..")
+sys.path.insert(0,parentdir)
+
+from rrlib import RequestRouterLibrary
+
+logger = Logger(level=logging.INFO)
+
+class SyncRequestRouterService(SyncStep, RequestRouterLibrary):
+    provides=[RequestRouterService]
+    requested_interval=0
+
+    def __init__(self, **args):
+        SyncStep.__init__(self, **args)
+        RequestRouterLibrary.__init__(self)
+
+    def fetch_pending(self):
+	try:
+        	ret = RequestRouterService.objects.filter(Q(enacted__lt=F('updated')) | Q(enacted=None))
+        	return ret
+	except Exception, e:
+        	traceback.print_exc()
+            	return None	
+
+    def sync_record(self, rr_service):
+	try:
+        	print "syncing service!"
+        	logger.info("sync'ing rr_service %s" % str(rr_service),extra=rr_service.tologdict())
+        	self.gen_slice_file(rr_service)
+        	rr_service.save()
+		return True
+	except Exception, e:
+                traceback.print_exc()
+                return False
+
+
diff --git a/xos/synchronizers/requestrouter/steps/sync_servicemap.py b/xos/synchronizers/requestrouter/steps/sync_servicemap.py
new file mode 100644
index 0000000..bef7e42
--- /dev/null
+++ b/xos/synchronizers/requestrouter/steps/sync_servicemap.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+
+import os
+import sys
+import base64
+import traceback
+from django.db.models import F, Q
+from xos.config import Config, XOS_DIR
+from synchronizers.base.syncstep import SyncStep
+from core.models import Service
+from services.requestrouter.models import ServiceMap
+from xos.logger import Logger, logging
+
+parentdir = os.path.join(os.path.dirname(__file__),"..")
+sys.path.insert(0,parentdir)
+
+from rrlib import RequestRouterLibrary
+from configurationPush import ConfigurationPush
+import rrlib_config
+
+logger = Logger(level=logging.INFO)
+
+class SyncServiceMap(SyncStep, RequestRouterLibrary, ConfigurationPush):
+    provides=[ServiceMap]
+    requested_interval=0
+
+    def __init__(self, **args):
+        SyncStep.__init__(self, **args)
+	RequestRouterLibrary.__init__(self)
+	ConfigurationPush.__init__(self)
+
+    def fetch_pending(self):
+	try:
+        	ret = ServiceMap.objects.filter(Q(enacted__lt=F('updated')) | Q(enacted=None))
+        	return ret
+	except Exception, e:
+        	traceback.print_exc()
+            	return None
+
+    def sync_record(self, servicemap):
+	try:
+		print "sync! %s " % self.get_servicemap_uid(servicemap)
+		self.gen_dnsredir_serviceconf(servicemap)
+		self.gen_dnsdemux_serviceconf(servicemap)
+        	# push generated files from temp_config
+		service_uid = self.get_servicemap_uid(servicemap)
+		self.config_push(service_uid, rrlib_config.REDIR_USER, XOS_DIR + "/observers/requestrouter/playbook/site_redir.yml", "/etc/ansible/requestrouter/dnsredir/hosts")
+		self.config_push(service_uid, rrlib_config.DEMUX_USER, XOS_DIR + "/observers/requestrouter/playbook/site_demux.yml", "/etc/ansible/requestrouter/dnsdemux/hosts")
+		self.teardown_temp_configfiles(service_uid)
+	except Exception, e:
+                traceback.print_exc()
+                return False
+
+if __name__ == "__main__":
+    sv = SyncServiceMap()
+
+    recs = sv.fetch_pending()
+
+    for rec in recs:
+        sv.sync_record( rec )
diff --git a/xos/synchronizers/syndicate/__init__.py b/xos/synchronizers/syndicate/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xos/synchronizers/syndicate/__init__.py
diff --git a/xos/synchronizers/syndicate/model-deps b/xos/synchronizers/syndicate/model-deps
new file mode 100644
index 0000000..b15c5d1
--- /dev/null
+++ b/xos/synchronizers/syndicate/model-deps
@@ -0,0 +1,16 @@
+{
+    "SlicePrivilege": [
+        "User", 
+        "Slice"
+    ], 
+    "Slice": [
+        "Site", 
+        "Service"
+    ], 
+    "VolumeAccessRight": [
+        "Volume"
+    ], 
+    "User": [
+        "Site"
+    ]
+}
diff --git a/xos/synchronizers/syndicate/requirements.py b/xos/synchronizers/syndicate/requirements.py
new file mode 100644
index 0000000..303fd3d
--- /dev/null
+++ b/xos/synchronizers/syndicate/requirements.py
@@ -0,0 +1,5 @@
+requests
+gevent
+grequests
+setproctitle
+psutil
diff --git a/xos/synchronizers/syndicate/run.sh b/xos/synchronizers/syndicate/run.sh
new file mode 100644
index 0000000..82960a9
--- /dev/null
+++ b/xos/synchronizers/syndicate/run.sh
@@ -0,0 +1,2 @@
+export XOS_DIR=/opt/xos
+python syndicate-backend.py  -C $XOS_DIR/observers/syndicate/syndicate_observer_config
diff --git a/xos/synchronizers/syndicate/start.sh b/xos/synchronizers/syndicate/start.sh
new file mode 100644
index 0000000..1c408a1
--- /dev/null
+++ b/xos/synchronizers/syndicate/start.sh
@@ -0,0 +1,2 @@
+export XOS_DIR=/opt/xos
+nohup python syndicate-backend.py  -C $XOS_DIR/observers/syndicate/syndicate_observer_config > /dev/null 2>&1 &
diff --git a/xos/synchronizers/syndicate/steps/sync_volume.py b/xos/synchronizers/syndicate/steps/sync_volume.py
new file mode 100644
index 0000000..8773542
--- /dev/null
+++ b/xos/synchronizers/syndicate/steps/sync_volume.py
@@ -0,0 +1,138 @@
+#!/usr/bin/env python
+
+import os
+import sys
+import traceback
+import base64
+
+if __name__ == "__main__":
+    # for testing 
+    if os.getenv("OPENCLOUD_PYTHONPATH"):
+        sys.path.append( os.getenv("OPENCLOUD_PYTHONPATH") )
+    else:
+        print >> sys.stderr, "No OPENCLOUD_PYTHONPATH variable set.  Assuming that OpenCloud is in PYTHONPATH"
+ 
+    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
+
+
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.syncstep import SyncStep
+from core.models import Service
+from services.syndicate_storage.models import Volume
+
+import logging
+from logging import Logger
+logging.basicConfig( format='[%(levelname)s] [%(module)s:%(lineno)d] %(message)s' )
+logger = logging.getLogger()
+logger.setLevel( logging.INFO ,extra=o.tologdict())
+
+# point to planetstack
+if __name__ != "__main__": 
+    if os.getenv("OPENCLOUD_PYTHONPATH") is not None:
+        sys.path.insert(0, os.getenv("OPENCLOUD_PYTHONPATH"))
+    else:
+        logger.warning("No OPENCLOUD_PYTHONPATH set; assuming your PYTHONPATH works")
+
+# syndicatelib will be in stes/..
+parentdir = os.path.join(os.path.dirname(__file__),"..")
+sys.path.insert(0,parentdir)
+
+import syndicatelib
+
+
+class SyncVolume(SyncStep):
+    provides=[Volume]
+    requested_interval=0
+
+    def __init__(self, **args):
+        SyncStep.__init__(self, **args)
+
+    def sync_record(self, volume):
+        """
+        Synchronize a Volume record with Syndicate.
+        """
+        
+        logger.info( "Sync Volume = %s\n\n" % volume.name ,extra=volume.tologdict())
+    
+        user_email = volume.owner_id.email
+        config = syndicatelib.get_config()
+        
+        volume_principal_id = syndicatelib.make_volume_principal_id( user_email, volume.name )
+
+        # get the observer secret 
+        try:
+            observer_secret = config.SYNDICATE_OPENCLOUD_SECRET
+        except Exception, e:
+            traceback.print_exc()
+            logger.error("config is missing SYNDICATE_OPENCLOUD_SECRET",extra=volume.tologdict())
+            raise e
+
+        # volume owner must exist as a Syndicate user...
+        try:
+            rc, user = syndicatelib.ensure_principal_exists( volume_principal_id, observer_secret, is_admin=False, max_UGs=1100, max_RGs=1)
+            assert rc == True, "Failed to create or read volume principal '%s'" % volume_principal_id
+        except Exception, e:
+            traceback.print_exc()
+            logger.error("Failed to ensure principal '%s' exists" % volume_principal_id ,extra=volume.tologdict())
+            raise e
+
+        # volume must exist 
+        
+        # create or update the Volume
+        try:
+            new_volume = syndicatelib.ensure_volume_exists( volume_principal_id, volume, user=user )
+        except Exception, e:
+            traceback.print_exc()
+            logger.error("Failed to ensure volume '%s' exists" % volume.name ,extra=volume.tologdict())
+            raise e
+           
+        # did we create the Volume?
+        if new_volume is not None:
+            # we're good
+            pass 
+             
+        # otherwise, just update it 
+        else:
+            try:
+                rc = syndicatelib.update_volume( volume )
+            except Exception, e:
+                traceback.print_exc()
+                logger.error("Failed to update volume '%s', exception = %s" % (volume.name, e.message),extra=volume.tologdict())
+                raise e
+                    
+        return True
+    
+    def delete_record(self, volume):
+        try:
+            volume_name = volume.name
+            syndicatelib.ensure_volume_absent( volume_name )
+        except Exception, e:
+            traceback.print_exc()
+            logger.exception("Failed to erase volume '%s'" % volume_name,extra=volume.tologdict())
+            raise e
+
+
+
+
+
+if __name__ == "__main__":
+    sv = SyncVolume()
+
+
+    # first, set all volumes to not-enacted so we can test 
+    for v in Volume.objects.all():
+       v.enacted = None
+       v.save()
+    
+    # NOTE: for resetting only 
+    if len(sys.argv) > 1 and sys.argv[1] == "reset":
+       sys.exit(0)
+
+    recs = sv.fetch_pending()
+
+    for rec in recs:
+        rc = sv.sync_record( rec )
+        if not rc:
+          print "\n\nFailed to sync %s\n\n" % (rec.name)
+
diff --git a/xos/synchronizers/syndicate/steps/sync_volumeaccessright.py b/xos/synchronizers/syndicate/steps/sync_volumeaccessright.py
new file mode 100644
index 0000000..9fca2a4
--- /dev/null
+++ b/xos/synchronizers/syndicate/steps/sync_volumeaccessright.py
@@ -0,0 +1,116 @@
+#!/usr/bin/env python
+
+import os
+import sys
+import base64
+import traceback
+
+if __name__ == "__main__":
+    # for testing 
+    if os.getenv("OPENCLOUD_PYTHONPATH"):
+        sys.path.append( os.getenv("OPENCLOUD_PYTHONPATH") )
+    else:
+        print >> sys.stderr, "No OPENCLOUD_PYTHONPATH variable set.  Assuming that OpenCloud is in PYTHONPATH"
+ 
+    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
+
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.syncstep import SyncStep
+from core.models import Service
+
+import logging
+from logging import Logger
+logging.basicConfig( format='[%(levelname)s] [%(module)s:%(lineno)d] %(message)s' )
+logger = logging.getLogger()
+logger.setLevel( logging.INFO ,extra=o.tologdict())
+
+# point to planetstack 
+if __name__ != "__main__":
+    if os.getenv("OPENCLOUD_PYTHONPATH") is not None:
+        sys.path.insert(0, os.getenv("OPENCLOUD_PYTHONPATH"))
+    else:
+        logger.warning("No OPENCLOUD_PYTHONPATH set; assuming your PYTHONPATH works")
+
+from services.syndicate_storage.models import VolumeAccessRight
+
+# syndicatelib will be in stes/..
+parentdir = os.path.join(os.path.dirname(__file__),"..")
+sys.path.insert(0,parentdir)
+
+import syndicatelib
+
+class SyncVolumeAccessRight(SyncStep):
+    provides=[VolumeAccessRight]
+    requested_interval=0
+
+    def __init__(self, **args):
+        SyncStep.__init__(self, **args)
+
+    def sync_record(self, vac):
+        
+        syndicate_caps = "UNKNOWN"  # for exception handling
+        
+        # get arguments
+        config = syndicatelib.get_config()
+        user_email = vac.owner_id.email
+        volume_name = vac.volume.name
+        syndicate_caps = syndicatelib.opencloud_caps_to_syndicate_caps( vac.cap_read_data, vac.cap_write_data, vac.cap_host_data ) 
+        
+        logger.info( "Sync VolumeAccessRight for (%s, %s)" % (user_email, volume_name) ,extra=vac.tologdict())
+        
+        # validate config
+        try:
+           RG_port = config.SYNDICATE_RG_DEFAULT_PORT
+           observer_secret = config.SYNDICATE_OPENCLOUD_SECRET
+        except Exception, e:
+           traceback.print_exc()
+           logger.error("syndicatelib config is missing SYNDICATE_RG_DEFAULT_PORT, SYNDICATE_OPENCLOUD_SECRET",extra=vac.tologdict())
+           raise e
+            
+        # ensure the user exists and has credentials
+        try:
+            rc, user = syndicatelib.ensure_principal_exists( user_email, observer_secret, is_admin=False, max_UGs=1100, max_RGs=1 )
+            assert rc is True, "Failed to ensure principal %s exists (rc = %s,%s)" % (user_email, rc, user)
+        except Exception, e:
+            traceback.print_exc()
+            logger.error("Failed to ensure user '%s' exists" % user_email ,extra=vac.tologdict())
+            raise e
+ 
+        # make the access right for the user to create their own UGs, and provision an RG for this user that will listen on localhost.
+        # the user will have to supply their own RG closure.
+        try:
+            rc = syndicatelib.setup_volume_access( user_email, volume_name, syndicate_caps, RG_port, observer_secret )
+            assert rc is True, "Failed to setup volume access for %s in %s" % (user_email, volume_name)
+
+        except Exception, e:
+            traceback.print_exc()
+            logger.error("Faoed to ensure user %s can access Volume %s with rights %s" % (user_email, volume_name, syndicate_caps),extra=vac.tologdict())
+            raise e
+
+        return True
+    
+    # Jude: this will simply go on to purge the object from
+    # OpenCloud. The previous 'deleter' version was a no-op also.
+    def delete_record(self, obj):
+        pass
+
+
+if __name__ == "__main__":
+
+    # first, set all VolumeAccessRights to not-enacted so we can test 
+    for v in VolumeAccessRight.objects.all():
+       v.enacted = None
+       v.save()
+
+    # NOTE: for resetting only 
+    if len(sys.argv) > 1 and sys.argv[1] == "reset":
+       sys.exit(0)
+
+
+    sv = SyncVolumeAccessRight()
+    recs = sv.fetch_pending()
+
+    for rec in recs:
+        sv.sync_record( rec )
+
diff --git a/xos/synchronizers/syndicate/steps/sync_volumeslice.py b/xos/synchronizers/syndicate/steps/sync_volumeslice.py
new file mode 100644
index 0000000..9af97f3
--- /dev/null
+++ b/xos/synchronizers/syndicate/steps/sync_volumeslice.py
@@ -0,0 +1,158 @@
+#!/usr/bin/env python
+
+import os
+import sys
+import base64
+import traceback
+
+if __name__ == "__main__":
+    # for testing 
+    if os.getenv("OPENCLOUD_PYTHONPATH"):
+        sys.path.append( os.getenv("OPENCLOUD_PYTHONPATH") )
+    else:
+        print >> sys.stderr, "No OPENCLOUD_PYTHONPATH variable set.  Assuming that OpenCloud is in PYTHONPATH"
+ 
+    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
+
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.syncstep import SyncStep
+from core.models import Service, Slice
+
+import logging
+from logging import Logger
+logging.basicConfig( format='[%(levelname)s] [%(module)s:%(lineno)d] %(message)s' )
+logger = logging.getLogger()
+logger.setLevel( logging.INFO ,extra=o.tologdict())
+
+# point to planetstack 
+if __name__ != "__main__":
+    if os.getenv("OPENCLOUD_PYTHONPATH") is not None:
+        sys.path.insert(0, os.getenv("OPENCLOUD_PYTHONPATH"))
+    else:
+        logger.warning("No OPENCLOUD_PYTHONPATH set; assuming your PYTHONPATH works") 
+
+from services.syndicate_storage.models import VolumeSlice,VolumeAccessRight,Volume
+
+# syndicatelib will be in stes/..
+parentdir = os.path.join(os.path.dirname(__file__),"..")
+sys.path.insert(0,parentdir)
+
+import syndicatelib
+
+
+class SyncVolumeSlice(SyncStep):
+    provides=[VolumeSlice]
+    requested_interval=0
+
+    def __init__(self, **args):
+        SyncStep.__init__(self, **args)
+
+    def sync_record(self, vs):
+        
+        logger.info("Sync VolumeSlice for (%s, %s)" % (vs.volume_id.name, vs.slice_id.name),extra=vs.tologdict())
+        
+        # extract arguments...
+        user_email = vs.slice_id.creator.email
+        slice_name = vs.slice_id.name
+        volume_name = vs.volume_id.name
+        syndicate_caps = syndicatelib.opencloud_caps_to_syndicate_caps( vs.cap_read_data, vs.cap_write_data, vs.cap_host_data )
+        RG_port = vs.RG_portnum
+        UG_port = vs.UG_portnum
+        slice_secret = None
+        
+        config = syndicatelib.get_config()
+        try:
+           observer_secret = config.SYNDICATE_OPENCLOUD_SECRET
+           RG_closure = config.SYNDICATE_RG_CLOSURE
+           observer_pkey_path = config.SYNDICATE_PRIVATE_KEY
+           syndicate_url = config.SYNDICATE_SMI_URL
+           
+        except Exception, e:
+           traceback.print_exc()
+           logger.error("syndicatelib config is missing one or more of the following: SYNDICATE_OPENCLOUD_SECRET, SYNDICATE_RG_CLOSURE, SYNDICATE_PRIVATE_KEY, SYNDICATE_SMI_URL",extra=vs.tologdict())
+           raise e
+            
+        # get secrets...
+        try:
+           observer_pkey_pem = syndicatelib.get_private_key_pem( observer_pkey_path )
+           assert observer_pkey_pem is not None, "Failed to load Observer private key"
+           
+           # get/create the slice secret
+           slice_secret = syndicatelib.get_or_create_slice_secret( observer_pkey_pem, slice_name )    
+           assert slice_secret is not None, "Failed to get or create slice secret for %s" % slice_name
+           
+        except Exception, e:
+           traceback.print_exc()
+           logger.error("Failed to load secret credentials",extra=vs.tologdict())
+           raise e
+        
+        # make sure there's a slice-controlled Syndicate user account for the slice owner
+        slice_principal_id = syndicatelib.make_slice_principal_id( user_email, slice_name )
+        
+        try:
+            rc, user = syndicatelib.ensure_principal_exists( slice_principal_id, observer_secret, is_admin=False, max_UGs=1100, max_RGs=1 )
+            assert rc is True, "Failed to ensure principal %s exists (rc = %s,%s)" % (slice_principal_id, rc, user)
+        except Exception, e:
+            traceback.print_exc()
+            logger.error('Failed to ensure slice user %s exists' % slice_principal_id,extra=vs.tologdict())
+            raise e
+            
+        # grant the slice-owning user the ability to provision UGs in this Volume, and also provision for the user the (single) RG the slice will instantiate in each VM.
+        try:
+            rc = syndicatelib.setup_volume_access( slice_principal_id, volume_name, syndicate_caps, RG_port, observer_secret, RG_closure=RG_closure )
+            assert rc is True, "Failed to set up Volume access for slice %s in %s" % (slice_principal_id, volume_name)
+            
+        except Exception, e:
+            traceback.print_exc()
+            logger.error("Failed to set up Volume access for slice %s in %s" % (slice_principal_id, volume_name),extra=vs.tologdict())
+            raise e
+            
+        # generate and save slice credentials....
+        try:
+            slice_cred = syndicatelib.save_slice_credentials( observer_pkey_pem, syndicate_url, slice_principal_id, volume_name, slice_name, observer_secret, slice_secret, UG_port, existing_user=user )
+            assert slice_cred is not None, "Failed to generate slice credential for %s in %s" % (slice_principal_id, volume_name )
+                
+        except Exception, e:
+            traceback.print_exc()
+            logger.error("Failed to generate slice credential for %s in %s" % (slice_principal_id, volume_name),extra=vs.tologdict())
+            raise e
+             
+        # ... and push them all out.
+        try:
+            rc = syndicatelib.push_credentials_to_slice( slice_name, slice_cred )
+            assert rc is True, "Failed to push credentials to slice %s for volume %s" % (slice_name, volume_name)
+               
+        except Exception, e:
+            traceback.print_exc()
+            logger.error("Failed to push slice credentials to %s for volume %s" % (slice_name, volume_name),extra=vs.tologdict())
+            raise e
+        
+        return True
+    
+    # This method will simply cause the object to be purged from OpenCloud
+    def delete_record(self, volume_slice):
+        pass
+
+
+if __name__ == "__main__":
+    sv = SyncVolumeSlice()
+
+    # first, set all VolumeSlice to not-enacted so we can test 
+    for v in VolumeSlice.objects.all():
+       v.enacted = None
+       v.save()
+
+    # NOTE: for resetting only 
+    if len(sys.argv) > 1 and sys.argv[1] == "reset":
+       sys.exit(0)
+
+    recs = sv.fetch_pending()
+
+    for rec in recs:
+        if rec.slice_id.creator is None:
+           print "Ignoring slice %s, since it has no creator" % (rec.slice_id)
+           continue
+
+        sv.sync_record( rec )
+
diff --git a/xos/synchronizers/syndicate/stop.sh b/xos/synchronizers/syndicate/stop.sh
new file mode 100644
index 0000000..f4a8e28
--- /dev/null
+++ b/xos/synchronizers/syndicate/stop.sh
@@ -0,0 +1 @@
+pkill -9 -f syndicate-backend.py
diff --git a/xos/synchronizers/syndicate/syndicate-backend.py b/xos/synchronizers/syndicate/syndicate-backend.py
new file mode 100644
index 0000000..9b53c77
--- /dev/null
+++ b/xos/synchronizers/syndicate/syndicate-backend.py
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+import os
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
+from synchronizers.base.backend import Backend 
+
+if __name__ == '__main__':
+
+    backend = Backend()
+    backend.run()
+ 
diff --git a/xos/synchronizers/syndicate/syndicate_synchronizer_config b/xos/synchronizers/syndicate/syndicate_synchronizer_config
new file mode 100644
index 0000000..7c9d2d2
--- /dev/null
+++ b/xos/synchronizers/syndicate/syndicate_synchronizer_config
@@ -0,0 +1,35 @@
+
+[plc]
+name=plc
+deployment=VICCI
+
+[db]
+name=xos
+#user=plstackuser
+#password=2uMDYtJK
+user=postgres
+password=password
+host=localhost
+port=5432
+
+[api]
+host=128.112.171.237
+port=8000
+ssl_key=None
+ssl_cert=None
+ca_ssl_cert=None
+ratelimit_enabled=0
+omf_enabled=0
+mail_support_address=support@localhost
+nova_enabled=True
+
+[observer]
+dependency_graph=/opt/xos/synchronizers/syndicate/model-deps
+steps_dir=/opt/xos/synchronizers/syndicate/steps
+deleters_dir=/opt/xos/synchronizers/syndicate/deleters
+log_file=console
+driver=None
+
+[feefie]
+client_id='vicci_dev_central'
+user_id='pl'
diff --git a/xos/synchronizers/syndicate/syndicatelib.py b/xos/synchronizers/syndicate/syndicatelib.py
new file mode 100644
index 0000000..56bd120
--- /dev/null
+++ b/xos/synchronizers/syndicate/syndicatelib.py
@@ -0,0 +1,1353 @@
+#!/usr/bin/env python
+
+"""
+Define some common methods for the Syndicate observer.
+"""
+import os
+import sys
+import random
+import json
+import time
+import requests
+import traceback
+import base64
+import BaseHTTPServer
+import setproctitle
+import threading
+import urllib
+
+from Crypto.Hash import SHA256 as HashAlg
+from Crypto.PublicKey import RSA as CryptoKey
+from Crypto import Random
+from Crypto.Signature import PKCS1_PSS as CryptoSigner
+
+import logging
+from logging import Logger
+logging.basicConfig( format='[%(levelname)s] [%(module)s:%(lineno)d] %(message)s' )
+logger = logging.getLogger()
+logger.setLevel( logging.INFO )
+
+# get config package 
+import syndicatelib_config.config as CONFIG
+
+# get the Syndicate modules
+import syndicate
+
+import syndicate.client.bin.syntool as syntool
+import syndicate.client.common.msconfig as msconfig
+import syndicate.client.common.api as api
+import syndicate.util.storage as syndicate_storage
+import syndicate.util.watchdog as syndicate_watchdog
+import syndicate.util.daemonize as syndicate_daemon
+import syndicate.util.crypto as syndicate_crypto
+import syndicate.util.provisioning as syndicate_provisioning
+import syndicate.syndicate as c_syndicate
+
+# for testing 
+TESTING = False
+class FakeObject(object):
+   def __init__(self):
+       pass
+
+if os.getenv("OPENCLOUD_PYTHONPATH") is not None:
+   sys.path.insert(0, os.getenv("OPENCLOUD_PYTHONPATH"))
+else:
+   logger.warning("No OPENCLOUD_PYTHONPATH set.  Assuming Syndicate models are in your PYTHONPATH")
+
+try:
+   os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
+
+   # get our models
+   import services.syndicate_storage.models as models
+
+   # get OpenCloud models 
+   from core.models import Slice,Instance
+   
+   from django.core.exceptions import ObjectDoesNotExist
+   from django.db import IntegrityError
+
+except ImportError, ie:
+   logger.warning("Failed to import models; some tests will not work")
+
+   # create a fake "models" package that has exactly the members we need for testing.
+   models = FakeObject()
+   models.Volume = FakeObject()
+   models.Volume.CAP_READ_DATA = 1
+   models.Volume.CAP_WRITE_DATA = 2
+   models.Volume.CAP_HOST_DATA = 4
+   
+   TESTING = True
+
+
+#-------------------------------
+class SyndicateObserverError( Exception ):
+    pass
+
+#-------------------------------
+def get_config():
+    """
+    Return the imported config
+    """
+    return CONFIG
+
+
+#-------------------------------
+def make_openid_url( email ):
+    """
+    Generate an OpenID identity URL from an email address.
+    """
+    return os.path.join( CONFIG.SYNDICATE_OPENID_TRUSTROOT, "id", email )
+
+
+#-------------------------------
+def connect_syndicate( username=CONFIG.SYNDICATE_OPENCLOUD_USER, password=CONFIG.SYNDICATE_OPENCLOUD_PASSWORD, user_pkey_pem=CONFIG.SYNDICATE_OPENCLOUD_PKEY ):
+    """
+    Connect to the OpenCloud Syndicate SMI, using the OpenCloud user credentials.
+    """
+    debug = True 
+    if hasattr(CONFIG, "DEBUG"):
+       debug = CONFIG.DEBUG
+       
+    client = syntool.Client( username, CONFIG.SYNDICATE_SMI_URL,
+                             password=password,
+                             user_pkey_pem=user_pkey_pem,
+                             debug=debug )
+
+    return client
+
+
+#-------------------------------
+def opencloud_caps_to_syndicate_caps( cap_read, cap_write, cap_host ):
+    """
+    Convert OpenCloud capability bits from the UI into Syndicate's capability bits.
+    """
+    syn_caps = 0
+    
+    if cap_read:
+        syn_caps |= (msconfig.GATEWAY_CAP_READ_DATA | msconfig.GATEWAY_CAP_READ_METADATA)
+    if cap_write:
+        syn_caps |= (msconfig.GATEWAY_CAP_WRITE_DATA | msconfig.GATEWAY_CAP_WRITE_METADATA)
+    if cap_host:
+        syn_caps |= (msconfig.GATEWAY_CAP_COORDINATE)
+
+    return syn_caps
+
+#-------------------------------
+def ensure_user_exists( user_email, **user_kw ):
+    """
+    Given an OpenCloud user, ensure that the corresponding
+    Syndicate user exists on the MS.  This method does NOT 
+    create any OpenCloud-specific data.
+
+    Return the (created, user), where created==True if the user 
+    was created and created==False if the user was read.
+    Raise an exception on error.
+    """
+    
+    client = connect_syndicate()
+    user_openid_url = make_openid_url( user_email )
+    
+    return syndicate_provisioning.ensure_user_exists( client, user_email, user_openid_url, **user_kw )
+
+
+#-------------------------------
+def ensure_user_absent( user_email ):
+    """
+    Ensure that a given OpenCloud user's associated Syndicate user record
+    has been deleted.  This method does NOT delete any OpenCloud-specific data.
+
+    Returns True on success
+    Raises an exception on error
+    """
+
+    client = connect_syndicate()
+
+    return client.delete_user( user_email )
+ 
+
+#-------------------------------
+def make_volume_principal_id( user_email, volume_name ):
+    """
+    Create a principal id for a Volume owner.
+    """
+    
+    volume_name_safe = urllib.quote( volume_name )
+    
+    return "volume_%s.%s" % (volume_name_safe, user_email)
+ 
+ 
+#-------------------------------
+def make_slice_principal_id( user_email, slice_name ):
+    """
+    Create a principal id for a slice owner.
+    """
+    
+    slice_name_safe = urllib.quote( slice_name )
+    
+    return "slice_%s.%s" % (slice_name, user_email)
+ 
+
+#-------------------------------
+def ensure_principal_exists( user_email, observer_secret, **user_kw ):
+    """ 
+    Ensure that a Syndicate user exists, as well as its OpenCloud-specific data.
+    
+    Return (True, (None OR user)) on success.  Returns a user if the user was created.
+    Return (False, None) on error
+    """
+    
+    try:
+         created, new_user = ensure_user_exists( user_email, **user_kw )
+    except Exception, e:
+         traceback.print_exc()
+         logger.error("Failed to ensure user '%s' exists" % user_email )
+         return (False, None)
+      
+    # if we created a new user, then save its (sealed) credentials to the Django DB
+    if created:
+         try:
+            rc = put_principal_data( user_email, observer_secret, new_user['signing_public_key'], new_user['signing_private_key'] )
+            assert rc == True, "Failed to save SyndicatePrincipal"
+         except Exception, e:
+            traceback.print_exc()
+            logger.error("Failed to save private key for principal %s" % (user_email))
+            return (False, None)
+
+    return (True, new_user)
+
+
+
+#-------------------------------
+def ensure_principal_absent( user_email ):
+    """
+    Ensure that a Syndicate user does not exists, and remove the OpenCloud-specific data.
+    
+    Return True on success.
+    """
+    
+    ensure_user_absent( user_email )
+    delete_principal_data( user_email )
+    return True
+
+#-------------------------------
+def ensure_volume_exists( user_email, opencloud_volume, user=None ):
+    """
+    Given the email address of a user, ensure that the given
+    Volume exists and is owned by that user.
+    Do not try to ensure that the user exists.
+
+    Return the Volume if we created it, or return None if we did not.
+    Raise an exception on error.
+    """
+    client = connect_syndicate()
+
+    try:
+        volume = client.read_volume( opencloud_volume.name )
+    except Exception, e:
+        # transport error 
+        logger.exception(e)
+        raise e
+
+    if volume is None:
+        # the volume does not exist....try to create it 
+        vol_name = opencloud_volume.name
+        vol_blocksize = opencloud_volume.blocksize
+        vol_description = opencloud_volume.description
+        vol_private = opencloud_volume.private
+        vol_archive = opencloud_volume.archive 
+        vol_default_gateway_caps = opencloud_caps_to_syndicate_caps( opencloud_volume.cap_read_data, opencloud_volume.cap_write_data, opencloud_volume.cap_host_data )
+
+        try:
+            vol_info = client.create_volume( user_email, vol_name, vol_description, vol_blocksize,
+                                             private=vol_private,
+                                             archive=vol_archive,
+                                             active=True,
+                                             default_gateway_caps=vol_default_gateway_caps,
+                                             store_private_key=False,
+                                             metadata_private_key="MAKE_METADATA_KEY" )
+
+        except Exception, e:
+            # transport error
+            logger.exception(e)
+            raise e
+
+        else:
+            # successfully created the volume!
+            return vol_info
+
+    else:
+        
+        # volume already exists.  Verify its owned by this user.
+        if user is None:
+           try:
+               user = client.read_user( volume['owner_id'] )
+           except Exception, e:
+               # transport error, or user doesn't exist (either is unacceptable)
+               logger.exception(e)
+               raise e
+
+        if user is None or user['email'] != user_email:
+            raise Exception("Volume '%s' already exists, but is NOT owned by '%s'" % (opencloud_volume.name, user_email) )
+
+        # we're good!
+        return None
+
+
+#-------------------------------
+def ensure_volume_absent( volume_name ):
+    """
+    Given an OpenCloud volume, ensure that the corresponding Syndicate
+    Volume does not exist.
+    """
+
+    client = connect_syndicate()
+
+    # this is idempotent, and returns True even if the Volume doesn't exist
+    return client.delete_volume( volume_name )
+    
+    
+#-------------------------------
+def update_volume( opencloud_volume ):
+    """
+    Update a Syndicate Volume from an OpenCloud Volume model.
+    Fails if the Volume does not exist in Syndicate.
+    """
+
+    client = connect_syndicate()
+
+    vol_name = opencloud_volume.name
+    vol_description = opencloud_volume.description
+    vol_private = opencloud_volume.private
+    vol_archive = opencloud_volume.archive
+    vol_default_gateway_caps = opencloud_caps_to_syndicate_caps( opencloud_volume.cap_read_data, opencloud_volume.cap_write_data, opencloud_volume.cap_host_data )
+
+    try:
+        rc = client.update_volume( vol_name,
+                                   description=vol_description,
+                                   private=vol_private,
+                                   archive=vol_archive,
+                                   default_gateway_caps=vol_default_gateway_caps )
+
+        if not rc:
+            raise Exception("update_volume(%s) failed!" % vol_name )
+
+    except Exception, e:
+        # transort or method error 
+        logger.exception(e)
+        return False
+
+    else:
+        return True
+
+
+#-------------------------------
+def ensure_volume_access_right_exists( user_email, volume_name, caps, allowed_gateways=[msconfig.GATEWAY_TYPE_UG] ):
+    """
+    Ensure that a particular user has particular access to a particular volume.
+    Do not try to ensure that the user or volume exist, however!
+    """
+    client = connect_syndicate()
+    return syndicate_provisioning.ensure_volume_access_right_exists( client, user_email, volume_name, caps, allowed_gateways )
+
+#-------------------------------
+def ensure_volume_access_right_absent( user_email, volume_name ):
+    """
+    Ensure that acess to a particular volume is revoked.
+    """
+    client = connect_syndicate()
+    return syndicate_provisioning.ensure_volume_access_right_absent( client, user_email, volume_name )
+    
+
+#-------------------------------
+def setup_volume_access( user_email, volume_name, caps, RG_port, slice_secret, RG_closure=None ):
+    """
+    Set up the Volume to allow the slice to provision UGs in it, and to fire up RGs.
+       * create the Volume Access Right for the user, so (s)he can create Gateways.
+       * provision a single Replica Gateway, serving on localhost.
+    """
+    client = connect_syndicate()
+    
+    try:
+       rc = ensure_volume_access_right_exists( user_email, volume_name, caps )
+       assert rc is True, "Failed to create access right for %s in %s" % (user_email, volume_name)
+       
+    except Exception, e:
+       logger.exception(e)
+       return False
+    
+    RG_name = syndicate_provisioning.make_gateway_name( "OpenCloud", "RG", volume_name, "localhost" )
+    RG_key_password = syndicate_provisioning.make_gateway_private_key_password( RG_name, slice_secret )
+    
+    try:
+       rc = syndicate_provisioning.ensure_RG_exists( client, user_email, volume_name, RG_name, "localhost", RG_port, RG_key_password, closure=RG_closure )
+    except Exception, e:
+       logger.exception(e)
+       return False
+    
+    return True
+       
+
+#-------------------------------
+def teardown_volume_access( user_email, volume_name ):
+    """
+    Revoke access to a Volume for a User.
+      * remove the user's Volume Access Right
+      * remove the use'rs gateways
+    """
+    client = connect_syndicate()
+    
+    # block the user from creating more gateways, and delete the gateways
+    try:
+       rc = client.remove_user_from_volume( user_email, volume_name )
+       assert rc is True, "Failed to remove access right for %s in %s" % (user_email, volume_name)
+       
+    except Exception, e:
+       logger.exception(e)
+       return False
+    
+    return True
+    
+
+#-------------------------------
+def create_sealed_and_signed_blob( private_key_pem, secret, data ):
+    """
+    Create a sealed and signed message.
+    """
+    
+    # seal it with the password 
+    logger.info("Sealing credential data")
+    
+    rc, sealed_data = c_syndicate.password_seal( data, secret )
+    if rc != 0:
+       logger.error("Failed to seal data with the secret, rc = %s" % rc)
+       return None
+    
+    msg = syndicate_crypto.sign_and_serialize_json( private_key_pem, sealed_data )
+    if msg is None:
+       logger.error("Failed to sign credential")
+       return None 
+    
+    return msg 
+
+
+#-------------------------------
+def verify_and_unseal_blob( public_key_pem, secret, blob_data ):
+    """
+    verify and unseal a serialized string of JSON
+    """
+
+    # verify it 
+    rc, sealed_data = syndicate_crypto.verify_and_parse_json( public_key_pem, blob_data )
+    if rc != 0:
+        logger.error("Failed to verify and parse blob, rc = %s" % rc)
+        return None
+
+    logger.info("Unsealing credential data")
+
+    rc, data = c_syndicate.password_unseal( sealed_data, secret )
+    if rc != 0:
+        logger.error("Failed to unseal blob, rc = %s" % rc )
+        return None
+
+    return data
+
+
+#-------------------------------
+def create_volume_list_blob( private_key_pem, slice_secret, volume_list ):
+    """
+    Create a sealed volume list, signed with the private key.
+    """
+    list_data = {
+       "volumes": volume_list
+    }
+    
+    list_data_str = json.dumps( list_data )
+    
+    msg = create_sealed_and_signed_blob( private_key_pem, slice_secret, list_data_str )
+    if msg is None:
+       logger.error("Failed to seal volume list")
+       return None 
+    
+    return msg
+ 
+
+#-------------------------------
+def create_slice_credential_blob( private_key_pem, slice_name, slice_secret, syndicate_url, volume_name, volume_owner, UG_port, user_pkey_pem ):
+    """
+    Create a sealed, signed, encoded slice credentials blob.
+    """
+    
+    # create and serialize the data 
+    cred_data = {
+       "syndicate_url":   syndicate_url,
+       "volume_name":     volume_name,
+       "volume_owner":    volume_owner,
+       "slice_name":      slice_name,
+       "slice_UG_port":   UG_port,
+       "principal_pkey_pem": user_pkey_pem,
+    }
+    
+    cred_data_str = json.dumps( cred_data )
+    
+    msg = create_sealed_and_signed_blob( private_key_pem, slice_secret, cred_data_str )
+    if msg is None:
+       logger.error("Failed to seal volume list")
+       return None 
+    
+    return msg 
+
+
+#-------------------------------
+def put_principal_data( user_email, observer_secret, public_key_pem, private_key_pem ):
+    """
+    Seal and store the principal's private key into the database, in a SyndicatePrincipal object,
+    so the instance-side Syndicate daemon syndicated.py can get them later.
+    Overwrite an existing principal if one exists.
+    """
+    
+    sealed_private_key = create_sealed_and_signed_blob( private_key_pem, observer_secret, private_key_pem )
+    if sealed_private_key is None:
+        return False
+
+    try:
+       sp = models.SyndicatePrincipal( sealed_private_key=sealed_private_key, public_key_pem=public_key_pem, principal_id=user_email )
+       sp.save()
+    except IntegrityError, e:
+       logger.error("WARN: overwriting existing principal %s" % user_email)
+       sp.delete()
+       sp.save()
+    
+    return True
+
+
+#-------------------------------
+def delete_principal_data( user_email ):
+    """
+    Delete an OpenCloud SyndicatePrincipal object.
+    """
+    
+    sp = get_principal_data( user_email )
+    if sp is not None:
+      sp.delete()
+    
+    return True
+
+
+#-------------------------------
+def get_principal_data( user_email ):
+    """
+    Get a SyndicatePrincipal record from the database 
+    """
+    
+    try:
+        sp = models.SyndicatePrincipal.objects.get( principal_id=user_email )
+        return sp
+    except ObjectDoesNotExist:
+        logger.error("No SyndicatePrincipal record for %s" % user_email)
+        return None
+    
+
+
+#-------------------------------
+def get_principal_pkey( user_email, observer_secret ):
+    """
+    Fetch and unseal the private key of a SyndicatePrincipal.
+    """
+    
+    sp = get_principal_data( user_email )
+    if sp is None:
+        logger.error("Failed to find private key for principal %s" % user_email )
+        return None 
+     
+    public_key_pem = sp.public_key_pem
+    sealed_private_key_pem = sp.sealed_private_key
+
+    # unseal
+    private_key_pem = verify_and_unseal_blob(public_key_pem, observer_secret, sealed_private_key_pem)
+    if private_key_pem is None:
+        logger.error("Failed to unseal private key")
+
+    return private_key_pem
+
+
+#-------------------------------
+def get_private_key_pem( pkey_path ):
+    """
+    Get a private key from storage, PEM-encoded.
+    """
+    
+    # get the OpenCloud private key 
+    observer_pkey = syndicate_storage.read_private_key( pkey_path )
+    if observer_pkey is None:
+       logger.error("Failed to load Observer private key")
+       return None
+    
+    observer_pkey_pem = observer_pkey.exportKey()
+    
+    return observer_pkey_pem
+
+
+#-------------------------------
+def encrypt_slice_secret( observer_pkey_pem, slice_secret ):
+    """
+    Encrypt and serialize the slice secret with the Observer private key
+    """
+    
+    # get the public key
+    try:
+       observer_pubkey_pem = CryptoKey.importKey( observer_pkey_pem ).publickey().exportKey()
+    except Exception, e:
+       logger.exception(e)
+       logger.error("Failed to derive public key from private key")
+       return None 
+    
+    # encrypt the data 
+    rc, sealed_slice_secret = c_syndicate.encrypt_data( observer_pkey_pem, observer_pubkey_pem, slice_secret )
+    
+    if rc != 0:
+       logger.error("Failed to encrypt slice secret")
+       return None 
+    
+    sealed_slice_secret_b64 = base64.b64encode( sealed_slice_secret )
+    
+    return sealed_slice_secret_b64
+    
+
+#-------------------------------
+def decrypt_slice_secret( observer_pkey_pem, sealed_slice_secret_b64 ):
+    """
+    Unserialize and decrypt a slice secret
+    """
+        
+    # get the public key
+    try:
+       observer_pubkey_pem = CryptoKey.importKey( observer_pkey_pem ).publickey().exportKey()
+    except Exception, e:
+       logger.exception(e)
+       logger.error("Failed to derive public key from private key")
+       return None 
+    
+    sealed_slice_secret = base64.b64decode( sealed_slice_secret_b64 )
+    
+    # decrypt it 
+    rc, slice_secret = c_syndicate.decrypt_data( observer_pubkey_pem, observer_pkey_pem, sealed_slice_secret )
+    
+    if rc != 0:
+       logger.error("Failed to decrypt '%s', rc = %d" % (sealed_slice_secret_b64, rc))
+       return None
+    
+    return slice_secret
+ 
+
+#--------------------------------
+def get_slice_secret( observer_pkey_pem, slice_name, slice_fk=None ):
+    """
+    Get the shared secret for a slice.
+    """
+    
+    ss = None 
+    
+    # get the sealed slice secret from Django
+    try:
+       if slice_fk is not None:
+          ss = models.SliceSecret.objects.get( slice_id=slice_fk )
+       else:
+          ss = models.SliceSecret.objects.get( slice_id__name=slice_name )
+    except ObjectDoesNotExist, e:
+       logger.error("Failed to load slice secret for (%s, %s)" % (slice_fk, slice_name) )
+       return None 
+
+    return ss.secret 
+ 
+
+#-------------------------------
+def put_slice_secret( observer_pkey_pem, slice_name, slice_secret, slice_fk=None, opencloud_slice=None ):
+    """
+    Put the shared secret for a slice, encrypting it first.
+    """
+    
+    ss = None 
+    
+    if opencloud_slice is None:
+       # look up the slice 
+       try:
+          if slice_fk is None:
+             opencloud_slice = models.Slice.objects.get( name=slice_name )
+          else:
+             opencloud_slice = models.Slice.objects.get( id=slice_fk.id )
+       except Exception, e:
+          logger.exception(e)
+          logger.error("Failed to load slice (%s, %s)" % (slice_fk, slice_name) )
+          return False 
+    
+    ss = models.SliceSecret( slice_id=opencloud_slice, secret=slice_secret )
+    
+    ss.save()
+    
+    return True
+
+
+#-------------------------------
+def get_or_create_slice_secret( observer_pkey_pem, slice_name, slice_fk=None ):
+   """
+   Get a slice secret if it already exists, or generate a slice secret if one does not.
+   """
+   
+   slice_secret = get_slice_secret( observer_pkey_pem, slice_name, slice_fk=slice_fk )
+   if slice_secret is None or len(slice_secret) == 0:
+      
+      # generate a slice secret 
+      slice_secret = "".join( random.sample("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", 32) )
+      
+      # store it 
+      rc = put_slice_secret( observer_pkey_pem, slice_name, slice_secret, slice_fk=slice_fk )
+      
+      if not rc:
+         raise SyndicateObserverError("Failed to create slice secret for (%s, %s)" % (slice_fk, slice_name))
+      
+   return slice_secret
+
+
+#-------------------------------
+def generate_slice_credentials( observer_pkey_pem, syndicate_url, user_email, volume_name, slice_name, observer_secret, slice_secret, UG_port, existing_user=None ):
+    """
+    Generate and return the set of credentials to be sent off to the slice VMs.
+    exisitng_user is a Syndicate user, as a dictionary.
+    
+    Return None on failure
+    """
+    
+    # get the user's private key 
+    logger.info("Obtaining private key for %s" % user_email)
+    
+    # it might be in the existing_user...
+    user_pkey_pem = None
+    if existing_user is not None:
+       user_pkey_pem = existing_user.get('signing_private_key', None)
+       
+    # no luck?
+    if user_pkey_pem is None:
+      try:
+         # get it from Django DB
+         user_pkey_pem = get_principal_pkey( user_email, observer_secret )
+         assert user_pkey_pem is not None, "No private key for %s" % user_email
+         
+      except:
+         traceback.print_exc()
+         logger.error("Failed to get private key; cannot generate credentials for %s in %s" % (user_email, volume_name) )
+         return None
+    
+    # generate a credetials blob 
+    logger.info("Generating credentials for %s's slice" % (user_email))
+    try:
+       creds = create_slice_credential_blob( observer_pkey_pem, slice_name, slice_secret, syndicate_url, volume_name, user_email, UG_port, user_pkey_pem )
+       assert creds is not None, "Failed to create credentials for %s" % user_email 
+    
+    except:
+       traceback.print_exc()
+       logger.error("Failed to generate credentials for %s in %s" % (user_email, volume_name))
+       return None
+    
+    return creds
+
+
+#-------------------------------
+def save_slice_credentials( observer_pkey_pem, syndicate_url, user_email, volume_name, slice_name, observer_secret, slice_secret, UG_port, existing_user=None ): 
+    """
+    Create and save a credentials blob to a VolumeSlice.
+    Return the creds on success.
+    Return None on failure
+    """
+    
+    creds = generate_slice_credentials( observer_pkey_pem, syndicate_url, user_email, volume_name, slice_name, observer_secret, slice_secret, UG_port, existing_user=existing_user )
+    ret = None
+    
+    if creds is not None:
+       # save it 
+       vs = get_volumeslice( volume_name, slice_name )
+       
+       if vs is not None:
+          vs.credentials_blob = creds
+          vs.save()
+          
+          # success!
+          ret = creds
+       else:
+          logger.error("Failed to look up VolumeSlice(%s, %s)" % (volume_name, slice_name))
+       
+    else:
+       logger.error("Failed to generate credentials for %s, %s" % (volume_name, slice_name))
+       
+    return ret
+
+
+#-------------------------------
+def get_volumeslice_volume_names( slice_name ):
+    """
+    Get the list of Volume names from the datastore.
+    """
+    try:
+        all_vs = models.VolumeSlice.objects.filter( slice_id__name = slice_name )
+        volume_names = []
+        for vs in all_vs:
+           volume_names.append( vs.volume_id.name )
+           
+        return volume_names
+    except Exception, e:
+        logger.exception(e)
+        logger.error("Failed to query datastore for volumes mounted in %s" % slice_name)
+        return None 
+ 
+
+#-------------------------------
+def get_volumeslice( volume_name, slice_name ):
+    """
+    Get a volumeslice record from the datastore.
+    """
+    try:
+        vs = models.VolumeSlice.objects.get( volume_id__name = volume_name, slice_id__name = slice_name )
+        return vs
+    except Exception, e:
+        logger.exception(e)
+        logger.error("Failed to query datastore for volumes (mounted in %s)" % (slice_name if (slice_name is not None or len(slice_name) > 0) else "UNKNOWN"))
+        return None 
+
+
+#-------------------------------
+def do_push( instance_hosts, portnum, payload ):
+    """
+    Push a payload to a list of instances.
+    NOTE: this has to be done in one go, since we can't import grequests
+    into the global namespace (without wrecking havoc on the credential server),
+    but it has to stick around for the push to work.
+    """
+    
+    global TESTING, CONFIG
+    
+    from gevent import monkey
+    
+    if TESTING:
+       monkey.patch_all()
+    
+    else:
+       # make gevents runnabale from multiple threads (or Django will complain)
+       monkey.patch_all(socket=True, dns=True, time=True, select=True, thread=False, os=True, ssl=True, httplib=False, aggressive=True)
+    
+    import grequests
+    
+    # fan-out 
+    requests = []
+    for sh in instance_hosts:
+      rs = grequests.post( "http://" + sh + ":" + str(portnum), data={"observer_message": payload}, timeout=getattr(CONFIG, "SYNDICATE_HTTP_PUSH_TIMEOUT", 60) )
+      requests.append( rs )
+      
+    # fan-in
+    responses = grequests.map( requests )
+    
+    assert len(responses) == len(requests), "grequests error: len(responses) != len(requests)"
+    
+    for i in xrange(0,len(requests)):
+       resp = responses[i]
+       req = requests[i]
+       
+       if resp is None:
+          logger.error("Failed to connect to %s" % (req.url))
+          continue 
+       
+       # verify they all worked 
+       if resp.status_code != 200:
+          logger.error("Failed to POST to %s, status code = %s" % (resp.url, resp.status_code))
+          continue
+          
+    return True
+   
+
+#-------------------------------
+def get_slice_hostnames( slice_name ):
+   """
+   Query the Django DB and get the list of hosts running in a slice.
+   """
+
+   openstack_slice = Slice.objects.get( name=slice_name )
+   if openstack_slice is None:
+       logger.error("No such slice '%s'" % slice_name)
+       return None
+
+   hostnames = [s.node.name for s in openstack_slice.instances.all()]
+
+   return hostnames
+
+   
+#-------------------------------
+def push_credentials_to_slice( slice_name, payload ):
+   """
+   Push a credentials payload to the VMs in a slice.
+   """
+   hostnames = get_slice_hostnames( slice_name )
+   return do_push( hostnames, CONFIG.SYNDICATE_SLIVER_PORT, payload )
+
+   
+#-------------------------------
+class CredentialServerHandler( BaseHTTPServer.BaseHTTPRequestHandler ):
+   """
+   HTTP server handler that allows syndicated.py instances to poll
+   for volume state.
+   
+   NOTE: this is a fall-back mechanism.  The observer should push new 
+   volume state to the slices' instances.  However, if that fails, the 
+   instances are configured to poll for volume state periodically.  This 
+   server allows them to do just that.
+   
+   Responses:
+      GET /<slicename>              -- Reply with the signed sealed list of volume names, encrypted by the slice secret
+      GET /<slicename>/<volumename> -- Reply with the signed sealed volume access credentials, encrypted by the slice secret
+      
+      !!! TEMPORARY !!!
+      GET /<slicename>/SYNDICATE_SLICE_SECRET    -- Reply with the slice secret (TEMPORARY)
+   
+   
+   NOTE: We want to limit who can learn which Volumes a slice can access, so we'll seal its instances'
+   credentials with the SliceSecret secret.  The instances (which have the slice-wide secret) can then decrypt it.
+   However, sealing the listing is a time-consuming process (on the order of 10s), so we only want 
+   to do it when we have to.  Since *anyone* can ask for the ciphertext of the volume list,
+   we will cache the list ciphertext for each slice for a long-ish amount of time, so we don't
+   accidentally DDoS this server.  This necessarily means that the instance might see a stale
+   volume listing, but that's okay, since the Observer is eventually consistent anyway.
+   """
+   
+   cached_volumes_json = {}             # map slice_name --> (volume name, timeout)
+   cached_volumes_json_lock = threading.Lock()
+   
+   CACHED_VOLUMES_JSON_LIFETIME = 3600          # one hour
+   
+   SLICE_SECRET_NAME = "SYNDICATE_SLICE_SECRET"
+   
+   def parse_request_path( self, path ):
+      """
+      Parse the URL path into a slice name and (possibly) a volume name or SLICE_SECRET_NAME
+      """
+      path_parts = path.strip("/").split("/")
+      
+      if len(path_parts) == 0:
+         # invalid 
+         return (None, None)
+      
+      if len(path_parts) > 2:
+         # invalid
+         return (None, None)
+      
+      slice_name = path_parts[0]
+      if len(slice_name) == 0:
+         # empty string is invalid 
+         return (None, None)
+      
+      volume_name = None
+      
+      if len(path_parts) > 1:
+         volume_name = path_parts[1]
+         
+      return slice_name, volume_name
+   
+   
+   def reply_data( self, data, datatype="application/json" ):
+      """
+      Give back a 200 response with data.
+      """
+      self.send_response( 200 )
+      self.send_header( "Content-Type", datatype )
+      self.send_header( "Content-Length", len(data) )
+      self.end_headers()
+      
+      self.wfile.write( data )
+      return 
+   
+   
+   def get_volumes_message( self, private_key_pem, observer_secret, slice_name ):
+      """
+      Get the json-ized list of volumes this slice is attached to.
+      Check the cache, evict stale data if necessary, and on miss, 
+      regenerate the slice volume list.
+      """
+      
+      # block the cache.
+      # NOTE: don't release the lock until we've generated credentials.
+      # Chances are, there's a thundering herd of instances coming online.
+      # Block them all until we've generated their slice's credentials,
+      # and then serve them the cached one.
+      
+      self.cached_volumes_json_lock.acquire()
+      
+      ret = None
+      volume_list_json, cache_timeout = self.cached_volumes_json.get( slice_name, (None, None) )
+      
+      if (cache_timeout is not None) and cache_timeout < time.time():
+         # expired
+         volume_list_json = None
+      
+      if volume_list_json is None:
+         # generate a new list and cache it.
+         
+         volume_names = get_volumeslice_volume_names( slice_name )
+         if volume_names is None:
+            # nothing to do...
+            ret = None
+         
+         else:
+            # get the slice secret 
+            slice_secret = get_slice_secret( private_key_pem, slice_name )
+            
+            if slice_secret is None:
+               # no such slice 
+               logger.error("No slice secret for %s" % slice_name)
+               ret = None
+            
+            else:
+               # seal and sign 
+               ret = create_volume_list_blob( private_key_pem, slice_secret, volume_names )
+         
+         # cache this 
+         if ret is not None:
+            self.cached_volumes_json[ slice_name ] = (ret, time.time() + self.CACHED_VOLUMES_JSON_LIFETIME )
+      
+      else:
+         # hit the cache
+         ret = volume_list_json
+      
+      self.cached_volumes_json_lock.release()
+      
+      return ret
+      
+   
+   def do_GET( self ):
+      """
+      Handle one GET
+      """
+      slice_name, volume_name = self.parse_request_path( self.path )
+      
+      # valid request?
+      if volume_name is None and slice_name is None:
+         self.send_error( 400 )
+      
+      # slice secret request?
+      elif volume_name == self.SLICE_SECRET_NAME and slice_name is not None:
+         
+         # get the slice secret 
+         ret = get_slice_secret( self.server.private_key_pem, slice_name )
+         
+         if ret is not None:
+            self.reply_data( ret )
+            return 
+         else:
+            self.send_error( 404 )
+      
+      # volume list request?
+      elif volume_name is None and slice_name is not None:
+         
+         # get the list of volumes for this slice
+         ret = self.get_volumes_message( self.server.private_key_pem, self.server.observer_secret, slice_name )
+         
+         if ret is not None:
+            self.reply_data( ret )
+            return
+         else:
+            self.send_error( 404 )
+      
+      # volume credential request?
+      elif volume_name is not None and slice_name is not None:
+         
+         # get the VolumeSlice record
+         vs = get_volumeslice( volume_name, slice_name )
+         if vs is None:
+            # not found
+            self.send_error( 404 )
+            return
+         
+         else:
+            ret = vs.credentials_blob 
+            if ret is not None:
+               self.reply_data( vs.credentials_blob )
+            else:
+               # not generated???
+               print ""
+               print vs
+               print ""
+               self.send_error( 503 )
+            return
+         
+      else:
+         # shouldn't get here...
+         self.send_error( 500 )
+         return 
+   
+   
+#-------------------------------
+class CredentialServer( BaseHTTPServer.HTTPServer ):
+   
+   def __init__(self, private_key_pem, observer_secret, server, req_handler ):
+      self.private_key_pem = private_key_pem
+      self.observer_secret = observer_secret
+      BaseHTTPServer.HTTPServer.__init__( self, server, req_handler )
+
+
+#-------------------------------
+def credential_server_spawn( old_exit_status ):
+   """
+   Start our credential server (i.e. in a separate process, started by the watchdog)
+   """
+   
+   setproctitle.setproctitle( "syndicate-credential-server" )
+   
+   private_key = syndicate_storage.read_private_key( CONFIG.SYNDICATE_PRIVATE_KEY )
+   if private_key is None:
+      # exit code 255 will be ignored...
+      logger.error("Cannot load private key.  Exiting...")
+      sys.exit(255)
+   
+   logger.info("Starting Syndicate Observer credential server on port %s" % CONFIG.SYNDICATE_HTTP_PORT)
+               
+   srv = CredentialServer( private_key.exportKey(), CONFIG.SYNDICATE_OPENCLOUD_SECRET, ('', CONFIG.SYNDICATE_HTTP_PORT), CredentialServerHandler)
+   srv.serve_forever()
+
+
+#-------------------------------
+def ensure_credential_server_running( foreground=False, run_once=False ):
+   """
+   Instantiate our credential server and keep it running.
+   """
+   
+   # is the watchdog running?
+   pids = syndicate_watchdog.find_by_attrs( "syndicate-credential-server-watchdog", {} )
+   if len(pids) > 0:
+      # it's running
+      return True
+   
+   if foreground:
+      # run in foreground 
+      
+      if run_once:
+         return credential_server_spawn( 0 )
+      
+      else:
+         return syndicate_watchdog.main( credential_server_spawn, respawn_exit_statuses=range(1,254) )
+      
+   
+   # not running, and not foregrounding.  fork a new one
+   try:
+      watchdog_pid = os.fork()
+   except OSError, oe:
+      logger.error("Failed to fork, errno = %s" % oe.errno)
+      return False
+   
+   if watchdog_pid != 0:
+      
+      # child--become watchdog
+      setproctitle.setproctitle( "syndicate-credential-server-watchdog" )
+      
+      if run_once:
+         syndicate_daemon.daemonize( lambda: credential_server_spawn(0), logfile_path=getattr(CONFIG, "SYNDICATE_HTTP_LOGFILE", None) )
+      
+      else:
+         syndicate_daemon.daemonize( lambda: syndicate_watchdog.main( credential_server_spawn, respawn_exit_statuses=range(1,254) ), logfile_path=getattr(CONFIG, "SYNDICATE_HTTP_LOGFILE", None) )
+
+
+#-------------------------------
+# Begin functional tests.
+# Any method starting with ft_ is a functional test.
+#-------------------------------
+  
+#-------------------------------
+def ft_syndicate_access():
+    """
+    Functional tests for ensuring objects exist and don't exist in Syndicate.
+    """
+    
+    fake_user = FakeObject()
+    fake_user.email = "fakeuser@opencloud.us"
+
+    print "\nensure_user_exists(%s)\n" % fake_user.email
+    ensure_user_exists( fake_user.email, is_admin=False, max_UGs=1100, max_RGs=1 )
+
+    print "\nensure_user_exists(%s)\n" % fake_user.email
+    ensure_user_exists( fake_user.email, is_admin=False, max_UGs=1100, max_RGs=1 )
+
+    fake_volume = FakeObject()
+    fake_volume.name = "fakevolume"
+    fake_volume.description = "This is a fake volume, created for funtional testing"
+    fake_volume.blocksize = 1024
+    fake_volume.cap_read_data = True 
+    fake_volume.cap_write_data = True 
+    fake_volume.cap_host_data = False
+    fake_volume.archive = False
+    fake_volume.private = True
+    
+    # test idempotency
+    print "\nensure_volume_exists(%s)\n" % fake_volume.name
+    ensure_volume_exists( fake_user.email, fake_volume )
+
+    print "\nensure_volume_exists(%s)\n" % fake_volume.name
+    ensure_volume_exists( fake_user.email, fake_volume )
+    
+    print "\nensure_volume_access_right_exists(%s,%s)\n" % (fake_user.email, fake_volume.name)
+    ensure_volume_access_right_exists( fake_user.email, fake_volume.name, 31 )
+    
+    print "\nensure_volume_access_right_exists(%s,%s)\n" % (fake_user.email, fake_volume.name)
+    ensure_volume_access_right_exists( fake_user.email, fake_volume.name, 31 )
+    
+    print "\nensure_volume_access_right_absent(%s,%s)\n" % (fake_user.email, fake_volume.name)
+    ensure_volume_access_right_absent( fake_user.email, fake_volume.name )
+    
+    print "\nensure_volume_access_right_absent(%s,%s)\n" % (fake_user.email, fake_volume.name)
+    ensure_volume_access_right_absent( fake_user.email, fake_volume.name )
+ 
+    print "\nensure_volume_absent(%s)\n" % fake_volume.name
+    ensure_volume_absent( fake_volume.name )
+
+    print "\nensure_volume_absent(%s)\n" % fake_volume.name
+    ensure_volume_absent( fake_volume.name )
+
+    print "\nensure_user_absent(%s)\n" % fake_user.email
+    ensure_user_absent( fake_user.email )
+
+    print "\nensure_user_absent(%s)\n" % fake_user.email
+    ensure_user_absent( fake_user.email )
+    
+    
+    
+    
+    print "\nensure_principal_exists(%s)\n" % fake_user.email
+    ensure_principal_exists( fake_user.email, "asdf", is_admin=False, max_UGs=1100, max_RGs=1 )
+    
+    print "\nensure_principal_exists(%s)\n" % fake_user.email
+    ensure_principal_exists( fake_user.email, "asdf", is_admin=False, max_UGs=1100, max_RGs=1 )
+
+    print "\nensure_volume_exists(%s)\n" % fake_volume.name
+    ensure_volume_exists( fake_user.email, fake_volume )
+
+    print "\nsetup_volume_access(%s, %s)\n" % (fake_user.email, fake_volume.name)
+    setup_volume_access( fake_user.email, fake_volume.name, 31, 38800, "abcdef" )
+    
+    print "\nsetup_volume_access(%s, %s)\n" % (fake_user.email, fake_volume.name)
+    setup_volume_access( fake_user.email, fake_volume.name, 31, 38800, "abcdef" )
+    
+    print "\nteardown_volume_access(%s, %s)\n" % (fake_user.email, fake_volume.name )
+    teardown_volume_access( fake_user.email, fake_volume.name )
+    
+    print "\nteardown_volume_access(%s, %s)\n" % (fake_user.email, fake_volume.name )
+    teardown_volume_access( fake_user.email, fake_volume.name )
+    
+    print "\nensure_volume_absent(%s)\n" % fake_volume.name
+    ensure_volume_absent( fake_volume.name )
+
+    print "\nensure_principal_absent(%s)\n" % fake_user.email
+    ensure_principal_absent( fake_user.email )
+    
+
+
+#-------------------------------
+def ft_volumeslice( slice_name ):
+    """
+    Functional tests for reading VolumeSlice information
+    """
+    print "slice: %s" % slice_name
+    
+    volumes = get_volumeslice_volume_names( slice_name )
+    
+    print "volumes mounted in slice %s:" % slice_name
+    for v in volumes:
+       print "   %s:" % v
+      
+       vs = get_volumeslice( v, slice_name )
+       
+       print "      %s" % dir(vs)
+          
+
+#-------------------------------
+def ft_get_slice_hostnames( slice_name ):
+   """
+   Functional tests for getting slice hostnames
+   """
+   
+   print "Get slice hostnames for %s" % slice_name
+   
+   hostnames = get_slice_hostnames( slice_name )
+   import pprint 
+   
+   pp = pprint.PrettyPrinter()
+   
+   pp.pprint( hostnames )
+
+
+#-------------------------------
+def ft_syndicate_principal():
+   """
+   Functional tests for creating, reading, and deleting SyndicatePrincipals.
+   """
+   print "generating key pair"
+   pubkey_pem, privkey_pem = api.generate_key_pair( 4096 )
+   
+   user_email = "fakeuser@opencloud.us"
+   
+   print "saving principal"
+   put_principal_data( user_email, "asdf", pubkey_pem, privkey_pem )
+   
+   print "fetching principal private key"
+   saved_privkey_pem = get_principal_pkey( user_email, "asdf" )
+   
+   assert saved_privkey_pem is not None, "Could not fetch saved private key"
+   assert saved_privkey_pem == privkey_pem, "Saved private key does not match actual private key"
+   
+   print "delete principal"
+   
+   delete_principal_data( user_email )
+   
+   print "make sure its deleted..."
+   
+   saved_privkey_pem = get_principal_pkey( user_email, "asdf" )
+   
+   assert saved_privkey_pem is None, "Principal key not deleted"
+   
+
+#-------------------------------
+def ft_credential_server():
+   """
+   Functional test for the credential server
+   """
+   ensure_credential_server_running( run_once=True, foreground=True )
+
+
+#-------------------------------
+def ft_seal_and_unseal():
+    """
+    Functional test for sealing/unsealing data
+    """
+    print "generating key pair"
+    pubkey_pem, privkey_pem = api.generate_key_pair( 4096 )
+    
+    sealed_buf = create_sealed_and_signed_blob( privkey_pem, "foo", "hello world")
+    print "sealed data is:\n\n%s\n\n" % sealed_buf
+
+    buf = verify_and_unseal_blob( pubkey_pem, "foo", sealed_buf )
+    print "unsealed data is: \n\n%s\n\n" % buf
+    
+
+# run functional tests
+if __name__ == "__main__":
+    sys.path.append("/opt/xos")
+    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
+
+    if len(sys.argv) < 2:
+      print "Usage: %s testname [args]" % sys.argv[0]
+      
+    # call a method starting with ft_, and then pass the rest of argv as its arguments
+    testname = sys.argv[1]
+    ft_testname = "ft_%s" % testname
+    
+    test_call = "%s(%s)" % (ft_testname, ",".join(sys.argv[2:]))
+   
+    print "calling %s" % test_call
+   
+    rc = eval( test_call )
+   
+    print "result = %s" % rc
+      
+    
diff --git a/xos/synchronizers/syndicate/syndicatelib_config/__init__.py b/xos/synchronizers/syndicate/syndicatelib_config/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xos/synchronizers/syndicate/syndicatelib_config/__init__.py
diff --git a/xos/synchronizers/syndicate/syndicatelib_config/config-jude.py b/xos/synchronizers/syndicate/syndicatelib_config/config-jude.py
new file mode 100644
index 0000000..9e0f1fd
--- /dev/null
+++ b/xos/synchronizers/syndicate/syndicatelib_config/config-jude.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+
+# configuration for syndicatelib
+SYNDICATE_SMI_URL="http://localhost:8080"
+
+SYNDICATE_OPENID_TRUSTROOT="http://localhost:8081"
+
+SYNDICATE_OPENCLOUD_USER="judecn@gmail.com"
+SYNDICATE_OPENCLOUD_PASSWORD="nya"
+
+SYNDICATE_PYTHONPATH="/home/jude/Desktop/research/git/syndicate/build/out/python"
+
+SYNDICATE_PRIVATE_KEY="/home/jude/Desktop/research/git/syndicate/opencloud/observers/syndicate/syndicatelib_config/pollserver.pem"
+SYNDICATE_OPENCLOUD_SECRET="e4988309a5005edb8ea185f16f607938c0fb7657e4d7609853bcb7c4884d1c92"
+
+SYNDICATE_HTTP_PORT=65321
+
+SYNDICATE_RG_CLOSURE="/home/jude/Desktop/research/git/syndicate/build/out/python/syndicate/rg/drivers/disk"
+SYNDICATE_RG_DEFAULT_PORT=38800
+
+DEBUG=True
diff --git a/xos/synchronizers/syndicate/syndicatelib_config/config-opencloud.py b/xos/synchronizers/syndicate/syndicatelib_config/config-opencloud.py
new file mode 100644
index 0000000..b3add16
--- /dev/null
+++ b/xos/synchronizers/syndicate/syndicatelib_config/config-opencloud.py
@@ -0,0 +1,73 @@
+#!/usr/bin/env python
+
+# ---------------------------------
+# This is the configuration file used by the Syndicate observer.
+# It is a well-formed Python file, and will be imported into the
+# observer as a Python module.  This means you can run any config-
+# generation code here you like, but all of the following global 
+# variables must be defined.
+# ---------------------------------
+
+# URL to the Syndicate SMI.  For example, https://syndicate-metadata.appspot.com
+SYNDICATE_SMI_URL="http://localhost:8080"
+
+# If you are going to use OpenID to authenticate the Syndicate instance daemon,
+# this is the OpenID provider URL.  It is currently used only to generate 
+# identity pages for users, so you can put whatever you want here for now.
+SYNDICATE_OPENID_TRUSTROOT="http://localhost:8081"
+
+# This is the observer's user account on Syndicate.  You must create it out-of-band
+# prior to using the observer, and it must be an admin user since it will
+# create other users (i.e. for slices).
+SYNDICATE_OPENCLOUD_USER="jcnelson@cs.princeton.edu"
+
+# This is the password for the observer to authenticate itself to Syndicate.
+SYNDICATE_OPENCLOUD_PASSWORD="nya"
+
+# If the observer uses public-key authentication with Syndicate, you will 
+# need to identify the absolute path to its private key here.  It must be 
+# a 4096-bit PEM-encoded RSA key, and the Syndicate observer's user account
+# must have been given the public key on activation.
+SYNDICATE_OPENCLOUD_PKEY=None
+
+# This is the location on disk where Syndicate observer code can be found, 
+# if it is not already in the Python path.  This is optional.
+SYNDICATE_PYTHONPATH="/root/syndicate/build/out/python"
+
+# This is the location of the observer's private key.  It must be an absolute
+# path, and refer to a 4096-bit PEM-encoded RSA key.
+SYNDICATE_PRIVATE_KEY="/opt/xos/observers/syndicate/syndicatelib_config/pollserver.pem"
+
+# This is the master secret used to generate secrets to seal sensitive information sent to the 
+# Syndicate instance mount daemons.  It is also used to seal sensitive information
+# stored to the Django database.  
+# TODO: think of a way to not have to store this on disk.  Maybe we feed into the
+# observer when it starts up?
+SYNDICATE_OPENCLOUD_SECRET="e4988309a5005edb8ea185f16f607938c0fb7657e4d7609853bcb7c4884d1c92"
+
+# This is the default port number on which a Syndicate Replica Gateway
+# will be provisioned.  It's a well-known port, and can be the same across
+# instances, since in OpenCloud, an RG instance only listens to localhost.
+SYNDICATE_RG_DEFAULT_PORT=38800
+
+# This is the absolute path to the RG's storage driver (which will be automatically
+# pushed to instances by Syndicate).  See https://github.com/jcnelson/syndicate/wiki/Replica-Gateways
+SYNDICATE_RG_CLOSURE=None
+
+# This is the port number the observer listens on for GETs from the Syndicate instance mount 
+# daemons.  Normally, the oserver pushes (encrypted) commands to the daemons, but if the 
+# daemons are NAT'ed or temporarily partitioned, they will pull commands instead.
+SYNDICATE_HTTP_PORT=65321
+
+# This is the path to the logfile for the observer's HTTP server.
+SYNDICATE_HTTP_LOGFILE="/tmp/syndicate-observer.log"
+
+# This is the number of seconds to wait for pushing a slice credential before timing out.
+SYNDICATE_HTTP_PUSH_TIMEOUT=60
+
+# This is the port number the Syndicate instance mount daemons listen on.  The observer will 
+# push commands to them on this port.
+SYNDICATE_SLIVER_PORT=65322
+
+# If true, print verbose debug messages.
+DEBUG=True
diff --git a/xos/synchronizers/syndicate/syndicatelib_config/config.py b/xos/synchronizers/syndicate/syndicatelib_config/config.py
new file mode 100644
index 0000000..b3add16
--- /dev/null
+++ b/xos/synchronizers/syndicate/syndicatelib_config/config.py
@@ -0,0 +1,73 @@
+#!/usr/bin/env python
+
+# ---------------------------------
+# This is the configuration file used by the Syndicate observer.
+# It is a well-formed Python file, and will be imported into the
+# observer as a Python module.  This means you can run any config-
+# generation code here you like, but all of the following global 
+# variables must be defined.
+# ---------------------------------
+
+# URL to the Syndicate SMI.  For example, https://syndicate-metadata.appspot.com
+SYNDICATE_SMI_URL="http://localhost:8080"
+
+# If you are going to use OpenID to authenticate the Syndicate instance daemon,
+# this is the OpenID provider URL.  It is currently used only to generate 
+# identity pages for users, so you can put whatever you want here for now.
+SYNDICATE_OPENID_TRUSTROOT="http://localhost:8081"
+
+# This is the observer's user account on Syndicate.  You must create it out-of-band
+# prior to using the observer, and it must be an admin user since it will
+# create other users (i.e. for slices).
+SYNDICATE_OPENCLOUD_USER="jcnelson@cs.princeton.edu"
+
+# This is the password for the observer to authenticate itself to Syndicate.
+SYNDICATE_OPENCLOUD_PASSWORD="nya"
+
+# If the observer uses public-key authentication with Syndicate, you will 
+# need to identify the absolute path to its private key here.  It must be 
+# a 4096-bit PEM-encoded RSA key, and the Syndicate observer's user account
+# must have been given the public key on activation.
+SYNDICATE_OPENCLOUD_PKEY=None
+
+# This is the location on disk where Syndicate observer code can be found, 
+# if it is not already in the Python path.  This is optional.
+SYNDICATE_PYTHONPATH="/root/syndicate/build/out/python"
+
+# This is the location of the observer's private key.  It must be an absolute
+# path, and refer to a 4096-bit PEM-encoded RSA key.
+SYNDICATE_PRIVATE_KEY="/opt/xos/observers/syndicate/syndicatelib_config/pollserver.pem"
+
+# This is the master secret used to generate secrets to seal sensitive information sent to the 
+# Syndicate instance mount daemons.  It is also used to seal sensitive information
+# stored to the Django database.  
+# TODO: think of a way to not have to store this on disk.  Maybe we feed into the
+# observer when it starts up?
+SYNDICATE_OPENCLOUD_SECRET="e4988309a5005edb8ea185f16f607938c0fb7657e4d7609853bcb7c4884d1c92"
+
+# This is the default port number on which a Syndicate Replica Gateway
+# will be provisioned.  It's a well-known port, and can be the same across
+# instances, since in OpenCloud, an RG instance only listens to localhost.
+SYNDICATE_RG_DEFAULT_PORT=38800
+
+# This is the absolute path to the RG's storage driver (which will be automatically
+# pushed to instances by Syndicate).  See https://github.com/jcnelson/syndicate/wiki/Replica-Gateways
+SYNDICATE_RG_CLOSURE=None
+
+# This is the port number the observer listens on for GETs from the Syndicate instance mount 
+# daemons.  Normally, the oserver pushes (encrypted) commands to the daemons, but if the 
+# daemons are NAT'ed or temporarily partitioned, they will pull commands instead.
+SYNDICATE_HTTP_PORT=65321
+
+# This is the path to the logfile for the observer's HTTP server.
+SYNDICATE_HTTP_LOGFILE="/tmp/syndicate-observer.log"
+
+# This is the number of seconds to wait for pushing a slice credential before timing out.
+SYNDICATE_HTTP_PUSH_TIMEOUT=60
+
+# This is the port number the Syndicate instance mount daemons listen on.  The observer will 
+# push commands to them on this port.
+SYNDICATE_SLIVER_PORT=65322
+
+# If true, print verbose debug messages.
+DEBUG=True
diff --git a/xos/synchronizers/syndicate/syndicatelib_config/pollserver.pem b/xos/synchronizers/syndicate/syndicatelib_config/pollserver.pem
new file mode 100644
index 0000000..cb50de7
--- /dev/null
+++ b/xos/synchronizers/syndicate/syndicatelib_config/pollserver.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKwIBAAKCAgEA6yeoVsm+Yf4sgW/9kzk2NfwkbHloIKXUOpi5x5LkEbnohNRC
+RIGjiMJJp/OefduU3c14h/K6Qefi9j4dw4pyvh2QP36K4lJObIpKAdohHjVjxHqK
+12bVXvCpCAbJHkiX8VK5HGJPDr6sJke1vPTrP6RSWxT7ZRawIBInKuT/OVshskzh
+kOwVXb5ct0AXjRZ6FBdXvNcJnNONKRCIuFHOx2roWLsdgTlPI3+bJim2dQ0JKyHh
+uaTPguZ4s23sCuSKyXCh/X9yVloxIraY6KdaAKQZLyANLfXQdsyyH69kQvvBEZ2R
+EXD0c1qIZwuIm68UH+60BwTPdXGWSL73C0Zsq36vZOadFPb0pmz/o4CuguILNA3i
+560MKcVvQ8HVqA56z+v8pE0TRp0ajTDtpW2ee+t1cXE8VzCwthkIxmneFk+ityoD
+o1N+fBUu4lXJ3kl2qGk+0KECqJ6sc/QN+Ft97JTTRshSzn1kqIlKQoZo3u0Jeo/G
+PFZ0b13/DxYA7nvjt2az48h0VL4mNf5tzDr8GxOK4lYoWIGzKjZLDeJRyxLOCK5j
+F/AvbbSnegT0O/vamn5EoN8HfooH5qiJdPDerriPsgN3HlcY6QjrY5phmAFiGa5T
+X1j1VNb5oamRslgPv3rwTvioTaY/wUmrHLBuU6Sqg/WGrLO2Bocg0USMbG8CAwEA
+AQKCAgEArxuO7WG5lXsSZSih6Rm3Vqf175jQg085JJFJ9mVZ1CFeFluBJUZsIpCb
+DKgLI6l5x1kUIhgLvrwQdFF5FH1qSEv3eHCgtzuXDphD1/E4rCgRrOObtB7tUI9h
+L4ruBNEF5Dw3f/1s5Yvy4WaQ3K58551TfmO3eGVWresWo4h2zZ0hEIbTiXljx7TT
+kdn2L6fHLGLdgM+YZuHZwfR/+tFga3sencRoiivE1KhXPindpngYlbfbQMSLiexZ
+gTOfi9T3zF1FI2HeIJN092aFounLyaJo5oC1j732iCCRm6qdvIuAD8AHoLc+MQ//
+dsxN47CSCd1Uzc01Nz1oLa+WgxzkGbsGNO2eVkRj/xzB0Rld/+Q1YQvn1TnWZFuG
+nXXKi+VwSX8htpDaZL5+hWVy39YXUQcBkTzBIS69tdfd7HCZS0JnKeOMYQFgvANH
+0/J529l8m0oHpex4DdW1scHXgcBOq6oD6KVkiNurfWZu/mWwdEnxAKtRFZc/xFfh
+a4kbTgNk3unGL+gZzeWL1YuIM843Ia4J8V0PYH7GueeZBaXyiT7r4x5hgQ57ObkX
+K9wlgrvSHBNq4OhzygTNs37vJwu38ry2AGmA8LuiFBeVCsVhMk3yVz4A6fXjwWH8
+266gNuODIiHelahvz/IBGLdrjnbA4SYaYQh1SYKfCRdlA2yNlBECggEBAPcqiWP/
+XUCsCy9vMbCvZNCUyr4nqTSvWkGsie6t+yIC0pYCynKdrL9WNF5zee9SVmtcBO0Q
+z+aff8TZAax3tWvD5GzlQOQh1l4QBj30uatklQ0nvwbw+gf5EFG2QerPakwyfC59
+dSagxchzpjloBGniq7jqc6vL3xlZ62vnOLHf+nOQXzDcZ7QK/uLRKj2r01D5+9lh
+08Ah42QID5VQL/NMyg2lylXaPXx6TnSMjJVjzNmLRCIRlOstAOt3isBJ21sT0LOk
+lCGvuF//cwS7VABRMa0TspSEkuMbgFw0XEZStkh68eEUVqax+HHfa1rlxobSIwib
+1Oa9s7KbQNaozgUCggEBAPOPOSLazItJ4OOFu8/69M33Ag8hpPZNkMw1fw99p2fD
+KnZYlEWHgF4Z76gkozHh+nk8HhohvYfIhmFYEHQOXfmgljsz3jFJKwTEnfN7IsZA
+C3TVl6OVuY2rjhBOe3137CYHn9d8KRaJAKdyd038LK29Yy+FvUVw6LD4QUoRiA21
+9sOrhO/Wgcohnqk5yVnXtBkp7j7qGN9d+GLZVAVOqKjniQqy9ir3IdLYmB801t9P
+TcbucmgEzs/cmx7d/jv1kx9/O0HHIm959Ox66hPkcG3bssJk41F6PDMOVEWiC/hc
+E5a7Mlr6M4YhuDjO1zoyQpy4Sj/MKpasnotNSL51JuMCggEBALhYkYBzximmJ/GJ
+DZaqOpcXYt/Q1PLmlnrFJVtPiC8ly8r26efykhVjRkvr9NX6o1oPl9z43Rc1fyZi
+dE0eO8HUqVpO4sdENY6ShRVQoeqjakgVjPSwZsvrh7BqL1/is3WBcf16tRXKc7m+
+CAxo+GHBHjMdKojH1e4ikuQ34KFKXJI068qVmQM/8DtbphW5QjLzQFQyEq0KmX7S
+RE0pMZpVe54SOYcu7w0Ya8uhyHjjprXamUaPtnJxbm4xCtvAOksDzHUwGwvE888l
+x7OPxGc4J8TfHCKJfsTEjkg3BVut9Sa6DA3EDZzmwFauPHPfTOLheB/Dmlc+xfhA
+s2tnG8ECggEBAKiLbFaaYwHg1iec3CNI3y/IxzwBZE6tzo4CVzM5GSfM/w12ruSO
+qF52REpvUB+s6dALsikTQD0+nv+uGXS2nIGqh0vg0Nn6cDKUfVmI1L+sgkEPrigd
+7JIFLgJKzVo+KsUGca6E1Uoq9LDrnXPyFlkEviacviXXxK7ynPvMtgIG8gTmJNBz
++M0QBuPEgXoSsybWxW/0P9ITDVgaXPJvRHfeAg/NWFzTOCzYhizSO/+8uW34hGNH
+MHbXiuEJbm2/u1gIi9ExJLtQAhXD2Uh6xPLBHis39bbkh9QtDlRBl1b/IO8mC+q5
+Sf6ARyPIv1gef8pEHd2YQ8CRJAXyLWzfVVECggEBANrvnE2hQaYqe/BM9QGN9Cam
+CUTTBhvQDTBnpBYv8iQCgy0nmmVZ07j0yjR/I5wipcWAB7Bskv1rfh/3VpWUGCcR
+2MnPobZnvL1Dl22G7P8HBUiIA+NGWNdR5FyIL/yLy2BVEs7dNeK5WolD8IQP+fTw
+E9Mvd6ns2TIveXMZFtqRja3H426iv38QqWg0RmmhcmnSkD7SqAZWGI+OoRsUJ2Et
+bg4N9Cb46Gjqdh8SQF+rXYfL1AWnjMM7/AhJLMoWWb0sBzqA7UeJxLlAt1Lgnnsl
+P2nszH+Ia9V0dSlr79haGo80FALM8TiKBAQ/bTktqP5vOWSlCzHj7K30Bil36TQ=
+-----END RSA PRIVATE KEY-----
diff --git a/xos/synchronizers/vbbu/__init__.py b/xos/synchronizers/vbbu/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xos/synchronizers/vbbu/__init__.py
diff --git a/xos/synchronizers/vbbu/model-deps b/xos/synchronizers/vbbu/model-deps
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/xos/synchronizers/vbbu/model-deps
@@ -0,0 +1 @@
+{}
diff --git a/xos/synchronizers/vbbu/run.sh b/xos/synchronizers/vbbu/run.sh
new file mode 100644
index 0000000..27d4e24
--- /dev/null
+++ b/xos/synchronizers/vbbu/run.sh
@@ -0,0 +1,3 @@
+# Runs the XOS observer using helloworldservice_config
+export XOS_DIR=/opt/xos
+python vbbu-synchronizer.py  -C $XOS_DIR/synchronizers/vbbu/vbbu_config
diff --git a/xos/synchronizers/vbbu/steps/sync_vbbu.py b/xos/synchronizers/vbbu/steps/sync_vbbu.py
new file mode 100644
index 0000000..09b1fe8
--- /dev/null
+++ b/xos/synchronizers/vbbu/steps/sync_vbbu.py
@@ -0,0 +1,37 @@
+import os
+import sys
+from django.db.models import Q, F
+from services.mcord.models import MCORDService, VBBUComponent
+from synchronizers.base.SyncInstanceUsingAnsible import SyncInstanceUsingAnsible
+
+parentdir = os.path.join(os.path.dirname(__file__), "..")
+sys.path.insert(0, parentdir)
+
+class SyncVBBUComponent(SyncInstanceUsingAnsible):
+
+    provides = [VBBUComponent]
+
+    observes = VBBUComponent
+
+    requested_interval = 0
+
+    template_name = "sync_vbbu.yaml"
+
+    service_key_name = "/opt/xos/configurations/mcord/mcord_private_key"
+
+    def __init__(self, *args, **kwargs):
+        super(SyncVBBUComponent, self).__init__(*args, **kwargs)
+
+    def fetch_pending(self, deleted):
+
+        if (not deleted):
+            objs = VBBUComponent.get_tenant_objects().filter(
+                Q(enacted__lt=F('updated')) | Q(enacted=None), Q(lazy_blocked=False))
+        else:
+
+            objs = VBBUComponent.get_deleted_tenant_objects()
+
+        return objs
+
+    def get_extra_attributes(self, o):
+        return {"display_message": o.display_message, "s1u_tag": o.s1u_tag, "s1mme_tag": o.s1mme_tag, "rru_tag": o.rru_tag}
diff --git a/xos/synchronizers/vbbu/steps/sync_vbbu.yaml b/xos/synchronizers/vbbu/steps/sync_vbbu.yaml
new file mode 100644
index 0000000..1e1e258
--- /dev/null
+++ b/xos/synchronizers/vbbu/steps/sync_vbbu.yaml
@@ -0,0 +1,19 @@
+---
+- hosts: {{ instance_name }}
+  gather_facts: False
+  connection: ssh
+  user: ubuntu
+  sudo: yes
+  tasks:
+
+  - name: write message
+    shell: echo "{{ display_message }}" > /var/tmp/index.html
+
+  - name: setup s1u interface config
+    shell: ./start_3gpp_int.sh eth1 {{ s1u_tag }} {{ s1u_ip }}/24 
+
+  - name: setup s1mme interface config
+    shell: ./start_3gpp_int.sh eth2 {{ s1mme_tag }} {{ s1mme_ip }}/24 
+
+  - name: setup rru interface config
+    shell: ./start_3gpp_int.sh eth3 {{ rru_tag }} {{ rru_ip }}/24 
diff --git a/xos/synchronizers/vbbu/stop.sh b/xos/synchronizers/vbbu/stop.sh
new file mode 100644
index 0000000..7ad7f4c
--- /dev/null
+++ b/xos/synchronizers/vbbu/stop.sh
@@ -0,0 +1,2 @@
+# Kill the observer
+pkill -9 -f vbbu-synchronizer.py
diff --git a/xos/synchronizers/vbbu/vbbu-synchronizer.py b/xos/synchronizers/vbbu/vbbu-synchronizer.py
new file mode 100644
index 0000000..95f4081
--- /dev/null
+++ b/xos/synchronizers/vbbu/vbbu-synchronizer.py
@@ -0,0 +1,13 @@
+#!/usr/bin/env python
+
+# This imports and runs ../../xos-observer.py
+# Runs the standard XOS observer
+
+import importlib
+import os
+import sys
+observer_path = os.path.join(os.path.dirname(
+    os.path.realpath(__file__)), "../../synchronizers/base")
+sys.path.append(observer_path)
+mod = importlib.import_module("xos-synchronizer")
+mod.main()
diff --git a/xos/synchronizers/vbbu/vbbu_config b/xos/synchronizers/vbbu/vbbu_config
new file mode 100644
index 0000000..3713b67
--- /dev/null
+++ b/xos/synchronizers/vbbu/vbbu_config
@@ -0,0 +1,40 @@
+# Required by XOS
+[db]
+name=xos
+user=postgres
+password=password
+host=localhost
+port=5432
+
+# Required by XOS
+[api]
+nova_enabled=True
+
+# Sets options for the observer
+[observer]
+# Optional name
+name=vbbu
+# This is the location to the dependency graph you generate
+dependency_graph=/opt/xos/synchronizers/vbbu/model-deps
+# The location of your SyncSteps
+steps_dir=/opt/xos/synchronizers/vbbu/steps
+# A temporary directory that will be used by ansible
+sys_dir=/opt/xos/synchronizers/vbbu/sys
+# Location of the file to save logging messages to the backend log is often used
+logfile=/var/log/xos_backend.log
+# If this option is true, then nothing will change, we simply pretend to run
+pretend=False
+# If this is False then XOS will use an exponential backoff when the observer
+# fails, since we will be waiting for an instance, we don't want this.
+backoff_disabled=True
+# We want the output from ansible to be logged
+save_ansible_output=True
+# This determines how we SSH to a client, if this is set to True then we try
+# to ssh using the instance name as a proxy, if this is disabled we ssh using
+# the NAT IP of the instance. On CloudLab the first option will fail so we must
+# set this to False
+proxy_ssh=True
+proxy_ssh_key=/root/setup/id_rsa
+proxy_ssh_user=root
+[networking]
+use_vtn=True
diff --git a/xos/synchronizers/vpgwc/__init__.py b/xos/synchronizers/vpgwc/__init__.py
new file mode 100755
index 0000000..e69de29
--- /dev/null
+++ b/xos/synchronizers/vpgwc/__init__.py
diff --git a/xos/synchronizers/vpgwc/model-deps b/xos/synchronizers/vpgwc/model-deps
new file mode 100755
index 0000000..0967ef4
--- /dev/null
+++ b/xos/synchronizers/vpgwc/model-deps
@@ -0,0 +1 @@
+{}
diff --git a/xos/synchronizers/vpgwc/run.sh b/xos/synchronizers/vpgwc/run.sh
new file mode 100755
index 0000000..821e149
--- /dev/null
+++ b/xos/synchronizers/vpgwc/run.sh
@@ -0,0 +1,3 @@
+# Runs the XOS observer using helloworldservice_config
+export XOS_DIR=/opt/xos
+python vpgwc-synchronizer.py  -C $XOS_DIR/synchronizers/vpgwc/vpgwc_config
diff --git a/xos/synchronizers/vpgwc/steps/sync_vpgwc.py b/xos/synchronizers/vpgwc/steps/sync_vpgwc.py
new file mode 100644
index 0000000..446a521
--- /dev/null
+++ b/xos/synchronizers/vpgwc/steps/sync_vpgwc.py
@@ -0,0 +1,37 @@
+import os
+import sys
+from django.db.models import Q, F
+from services.mcord.models import MCORDService, VPGWCComponent
+from synchronizers.base.SyncInstanceUsingAnsible import SyncInstanceUsingAnsible
+
+parentdir = os.path.join(os.path.dirname(__file__), "..")
+sys.path.insert(0, parentdir)
+
+class SyncVPGWCComponent(SyncInstanceUsingAnsible):
+
+    provides = [VPGWCComponent]
+
+    observes = VPGWCComponent
+
+    requested_interval = 0
+
+    template_name = "sync_vpgwc.yaml"
+
+    service_key_name = "/opt/xos/configurations/mcord/mcord_private_key"
+
+    def __init__(self, *args, **kwargs):
+        super(SyncVPGWCComponent, self).__init__(*args, **kwargs)
+
+    def fetch_pending(self, deleted):
+
+        if (not deleted):
+            objs = VPGWCComponent.get_tenant_objects().filter(
+                Q(enacted__lt=F('updated')) | Q(enacted=None), Q(lazy_blocked=False))
+        else:
+
+            objs = VPGWCComponent.get_deleted_tenant_objects()
+
+        return objs
+
+    def get_extra_attributes(self, o):
+        return {"display_message": o.display_message, "s5s8_pgw_tag": o.s5s8_pgw_tag}
diff --git a/xos/synchronizers/vpgwc/steps/sync_vpgwc.yaml b/xos/synchronizers/vpgwc/steps/sync_vpgwc.yaml
new file mode 100644
index 0000000..a793976
--- /dev/null
+++ b/xos/synchronizers/vpgwc/steps/sync_vpgwc.yaml
@@ -0,0 +1,13 @@
+---
+- hosts: {{ instance_name }}
+  gather_facts: False
+  connection: ssh
+  user: ubuntu
+  sudo: yes
+  tasks:
+
+  - name: write message
+    shell: echo "{{ display_message }}" > /var/tmp/index.html
+
+  - name: setup s5s8_pgw interface config
+    shell: ./start_3gpp_int.sh eth1 {{ s5s8_pgw_tag }} {{ s5s8_pgw_ip }}/24 
diff --git a/xos/synchronizers/vpgwc/stop.sh b/xos/synchronizers/vpgwc/stop.sh
new file mode 100755
index 0000000..299641a
--- /dev/null
+++ b/xos/synchronizers/vpgwc/stop.sh
@@ -0,0 +1,2 @@
+# Kill the observer
+pkill -9 -f vpgwc-synchronizer.py
diff --git a/xos/synchronizers/vpgwc/vpgwc-synchronizer.py b/xos/synchronizers/vpgwc/vpgwc-synchronizer.py
new file mode 100755
index 0000000..95f4081
--- /dev/null
+++ b/xos/synchronizers/vpgwc/vpgwc-synchronizer.py
@@ -0,0 +1,13 @@
+#!/usr/bin/env python
+
+# This imports and runs ../../xos-observer.py
+# Runs the standard XOS observer
+
+import importlib
+import os
+import sys
+observer_path = os.path.join(os.path.dirname(
+    os.path.realpath(__file__)), "../../synchronizers/base")
+sys.path.append(observer_path)
+mod = importlib.import_module("xos-synchronizer")
+mod.main()
diff --git a/xos/synchronizers/vpgwc/vpgwc_config b/xos/synchronizers/vpgwc/vpgwc_config
new file mode 100755
index 0000000..c6b9c23
--- /dev/null
+++ b/xos/synchronizers/vpgwc/vpgwc_config
@@ -0,0 +1,40 @@
+# Required by XOS
+[db]
+name=xos
+user=postgres
+password=password
+host=localhost
+port=5432
+
+# Required by XOS
+[api]
+nova_enabled=True
+
+# Sets options for the observer
+[observer]
+# Optional name
+name=vpgwc
+# This is the location to the dependency graph you generate
+dependency_graph=/opt/xos/synchronizers/vpgwc/model-deps
+# The location of your SyncSteps
+steps_dir=/opt/xos/synchronizers/vpgwc/steps
+# A temporary directory that will be used by ansible
+sys_dir=/opt/xos/synchronizers/vpgwc/sys
+# Location of the file to save logging messages to the backend log is often used
+logfile=/var/log/xos_backend.log
+# If this option is true, then nothing will change, we simply pretend to run
+pretend=False
+# If this is False then XOS will use an exponential backoff when the observer
+# fails, since we will be waiting for an instance, we don't want this.
+backoff_disabled=True
+# We want the output from ansible to be logged
+save_ansible_output=True
+# This determines how we SSH to a client, if this is set to True then we try
+# to ssh using the instance name as a proxy, if this is disabled we ssh using
+# the NAT IP of the instance. On CloudLab the first option will fail so we must
+# set this to False
+proxy_ssh=True
+proxy_ssh_key=/root/setup/id_rsa
+proxy_ssh_user=root
+[networking]
+use_vtn=True
diff --git a/xos/templates/README.md b/xos/templates/README.md
new file mode 100644
index 0000000..af46be9
--- /dev/null
+++ b/xos/templates/README.md
@@ -0,0 +1,5 @@
+# DJANGO TEMPLATES
+
+These are the templates used by the Django Application to render the UI.
+
+More information are available in the [Django Documentation](https://docs.djangoproject.com/es/1.9/topics/templates/)
\ No newline at end of file
diff --git a/xos/templates/admin/base.html b/xos/templates/admin/base.html
new file mode 100644
index 0000000..408a1e8
--- /dev/null
+++ b/xos/templates/admin/base.html
@@ -0,0 +1,348 @@
+{% load admin_static %}{% load suit_tags core_tags %}{% load url from future %}
+<!DOCTYPE html>
+<html lang="{{ LANGUAGE_CODE|default:"en-us" }}" {% if LANGUAGE_BIDI %}dir="rtl"{% endif %}>
+<head>
+  <meta name="viewport" content="width=device-width, initial-scale=1">
+  <title>
+      {% block title %}
+          {%if title %}
+              {{ title }} |
+          {% endif %}
+          {{XOS_BRANDING_NAME}}
+      {% endblock %}
+  </title>
+  <link rel="stylesheet" type="text/css" href="{% block stylesheet %}{% endblock %}"/>
+  <!--<link rel="stylesheet" type="text/css" href="{% static 'suit/bootstrap/dist/css/bootstrap.min.css' %}" media="all"/>-->
+  <link rel="stylesheet" type="text/css" href="{% static 'suit/css/suit.css' %}" media="all">
+  <link rel="stylesheet" type="text/css" href="{% static 'xos.css' %}" media="all">
+  <link rel="stylesheet" type="text/css" href="{% static 'xosNgLib.css' %}" media="all">
+  {% if XOS_BRANDING_CSS %}
+  <link rel="stylesheet" type="text/css" href="{% static 'cord.css' %}" media="all">
+  <link rel="stylesheet" type="text/css" href="{{ XOS_BRANDING_CSS }}">
+  {% endif %}
+  {% block extrastyle %}{% endblock %}
+  {% if LANGUAGE_BIDI %}
+  <link rel="stylesheet" type="text/css" href="{% block stylesheet_rtl %}{% static "admin/css/rtl.css" %}{% endblock %}"/>
+  {% endif %}
+  <script type="text/javascript">window.__admin_media_prefix__ = "{% filter escapejs %}{% static "admin/" %}{% endfilter %}";</script>
+  <script src="{% static 'suit/js/jquery-1.9.1.min.js' %}"></script>
+  <script src="http://code.jquery.com/ui/1.10.4/jquery-ui.js"></script>
+  <link rel="stylesheet" href="http://code.jquery.com/ui/1.10.4/themes/smoothness/jquery-ui.css">
+  <script type="text/javascript" src="{% static 'log4javascript-1.4.6/log4javascript.js' %}"></script>
+  <script type="text/javascript" src="{% static 'uploadTextarea.js' %}"></script>
+  <script type="text/javascript" src="{% static 'observer_status.js' %}"></script>
+
+  <script
+    src="//d2wy8f7a9ursnm.cloudfront.net/bugsnag-2.min.js"
+    data-apikey="748d877b8b4e211dcd3249c1aa46d263">
+  </script>
+
+  <!-- ngXosLib -->
+  <script src="{% static 'js/vendor/ngXosVendor.js' %}"></script>
+  <script src="{% static 'js/vendor/ngXosHelpers.js' %}"></script>
+
+  <script type="text/javascript">var Suit = { $: $.noConflict() }; if (!$) $ = Suit.$; </script>
+  {% if 'SHOW_REQUIRED_ASTERISK'|suit_conf %}
+  <style type="text/css">.required:after { content: '*'; margin: 0 0 0 5px; position: absolute; color: #ccc;}</style>
+  {% endif %}
+  {% block extrahead %}{% endblock %}
+  {% block blockbots %}
+  <meta name="robots" content="NONE,NOARCHIVE"/>
+  {% endblock %}
+  <link rel="shortcut icon" href="{{ XOS_BRANDING_FAVICON }}"></head>
+  {% load i18n %}
+<body class="{% if is_popup %}popup {% endif %}{% block bodyclass %}{% endblock %}">
+  <div id="dialog-placeholder">
+    <!-- This is a placeholder for dialog boxes, like the observer calendar -->
+  </div>
+
+  <!-- Sticky footer wrap -->
+  <div id="wrap">
+
+    <!-- Container -->
+    {% block container %}
+    <!-- <div id="container"> -->
+      
+    <!-- </div> -->
+    <!-- END Header -->
+    {% if not is_popup %}
+    <div id="wrapper">
+    {% endif %}
+
+    {% if is_popup %}
+    <div id="wrapper-popup">
+    {% endif %}
+
+      <!-- Sidebar -->
+      {% if not is_popup %}
+      <div id="sidebar-wrapper">
+        <a href="{% url 'admin:index' %}" class="hidden-xs">
+          <img class="logo" src="{% static XOS_BRANDING_ICON %}"/>
+        </a>
+            {% comment %}
+            <!--{% include 'suit/menu.html' %}-->
+            {% endcomment %}
+        {% include 'admin/menu.html' %}
+        <button class="navbar-toggle collapsed visible-xs" type="button">
+          <i class="glyphicon glyphicon-arrow-left"></i>
+        </button>
+      </div>
+      {% endif %}
+      <!-- /#sidebar-wrapper -->
+
+      <!-- Page Content -->
+      <div id="page-content-wrapper">
+        <div class="container-fluid">
+          <div class="row">
+            <div class="col-xs-12">
+              {% block header %}
+                {% if not is_popup %}
+                  <!-- Header -->
+                  <div id="header" class="header">
+                    <button class="navbar-toggle collapsed" type="button">
+                      <span class="icon-bar"></span>
+                      <span class="icon-bar"></span>
+                      <span class="icon-bar"></span>
+                    </button>
+                    {% block logo %}
+                      <a href="{% url 'admin:index' %}" class="visible-xs">
+                        <img class="logo" src="{% static XOS_BRANDING_ICON %}"/>
+                      </a>
+                    {% endblock %}
+                    <!-- <div id="branding">
+                      {% block quick-search %}
+                        {% with 'SEARCH_URL'|suit_conf as search_url %}
+                          {% if search_url %}
+                            <form class="form-search nav-quick-search" autocomplete="off" action="{% if '/' in search_url %}{{ search_url }}{% else %}{% url search_url %}{% endif %}" method="GET"> <i class="input-icon icon-search"></i>
+                              <input type="text" name="q" class="input-medium search-query" id="quick-search">
+                              <input type="submit" class="submit" value="">
+                            </form>
+                          {% endif %}
+                        {% endwith %}
+                      {% endblock %}
+                    </div> -->
+                    {% block header_time %}
+                      <!-- <div id="branding2">
+                        <div class="header-content header-content-first">
+                          <div class="header-column icon"> <i class="icon-time"></i></div>
+                          <div class="header-column">
+                            <span class="date">{% suit_date %}</span>
+                            <br>
+                            <span class="time" id="clock">{% suit_time %}</span>
+                          </div>
+                        </div>
+                      </div> -->
+                    {% endblock %}
+
+                    {% block header_content %}
+                      <div class="header-content">
+                        <div class="header-column icon">
+                          <i class="icon-comment"></i>
+                        </div>
+                        <div class="header-column">
+                          <a href="" class="grey"> <b>2</b>
+                            new messages
+                          </a>
+                        </div>
+                      </div>
+                    {% endblock %}
+
+                    {% if user.is_active and user.is_staff %}
+                    {% notification %}
+                      <div id="user-tools">
+                        {% trans 'Welcome,' %}
+                        <a href="http://{{ request.get_host}}/admin/core/user/{{user.id}}">{{user.email}}</a>
+                        <span id="observer-status"></span>
+                        <span class="user-links">
+                          {% block userlinks %}
+                            {% url 'django-admindocs-docroot' as docsroot %}
+                            {% if docsroot %}
+                              <a href="http://guide.xosproject.org/">{% trans 'Documentation' %}</a>
+                              <span class="separator">|</span>
+                            {% endif %}
+                            <a href="{% url 'admin:password_change' %}">{% trans 'Change password' %}</a>
+                            <span class="separator">|</span>
+                            <a href="{% url 'admin:logout' %}">{% trans 'Log out' %}</a>
+                          {% endblock %}
+                        </span>
+                      </div>
+                    {% endif %}
+
+                    {% block nav-global %}
+                    {% endblock %}
+                  </div>
+                {% endif %}
+              {% endblock %}
+            </div>
+          </div>
+          <div class="row content-wrapper">
+            <div class="col-lg-12">
+              <div class="suit-columns {{ is_popup|yesno:'one-column,two-columns' }}">
+                {% block content-center %}
+                  {% if not is_popup %}
+                    {% block minidash %}
+                      <div id="openCloudTopPage">
+                        {% include "admin/newminidashboard.html" %}
+                      </div>
+                    {% endblock %} 
+
+                    {% block breadcrumbs %}
+                      <ul class="breadcrumb">
+                        <li>
+                          <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
+                          {% if title %}
+                            <span class="divider">&raquo;</span>
+                        </li>
+                        <li class="active">
+                          {{ title }}
+                          {% endif %}
+                        </li>
+                      </ul>
+                    {% endblock %}
+                  {% endif %}
+
+                  {% block messages %}
+                    {% if messages %}
+                      {% for message in messages %}
+                        <div class="alert alert-{% firstof message.tags 'info' %}">
+                          <button class="close" data-dismiss="alert">×</button>
+                          <strong>{% if message.tags %}{{ message.tags|capfirst }}{% else %}Message{% endif %}!</strong> 
+                          {{ message }}
+                        </div>
+                      {% endfor %}
+                    {% endif %}
+                  {% endblock messages %}
+
+                  <!-- Content -->
+                  <div id="content" class="{% block coltype %}colM{% endblock %} row">
+                    {% block pretitle %}
+                    {% endblock %}
+                    {% block content_title %}
+                      {% if title %}
+                        <h2 class="content-title">{{ title }}</h2>
+                      {% endif %}
+                    {% endblock %}
+                    {% block content %}
+                      {% block object-tools %}
+                      {% endblock %}
+                      {{ content }}
+                    {% endblock %}
+                    {% block sidebar_content %}
+                      {% block sidebar %}{% endblock %}
+                    {% endblock %}
+                  </div>
+                  <!-- END Content -->
+                  <span class="clearfix"></span>
+                  <!-- </div>
+                  -->
+                {% endblock %}
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      <!-- /#page-content-wrapper -->
+    <!-- /#wrapper -->
+    {% endblock %}
+    </div>
+    {% if not is_popup %}
+      <!-- Sticky footer push -->
+      <div id="push"></div>
+    {% endif %}
+
+    {% block footer %}
+      {% if not is_popup %}
+        <div id="footer" class="footer">
+          <div class="container-fluid">
+            <div class="row">
+              <div class="tools col-xs-4">
+                {% block footer_links %}
+                  <a href="http://djangosuit.com/support/" target="_blank" class="icon">
+                    <i class="icon-question-sign"></i>
+                    Support
+                  </a>
+                  <a href="http://djangosuit.com/pricing/" target="_blank" class="icon">
+                    <i class="icon-bookmark"></i>
+                    Licence
+                  </a>
+                  <a href="http://github.com/darklow/django-suit/issues" target="_blank" class="icon">
+                    <i class="icon-comment"></i>
+                    Report a bug
+                  </a>
+                {% endblock %}
+              </div>
+
+              <div class="branding col-xs-4">
+                {% block footer_branding %}
+                  {% with 'ADMIN_NAME'|suit_conf as admin_name %}
+                    {{XOS_BRANDING_NAME}}
+                    <!-- {{ admin_name }} -->
+                  {% endwith %}
+                {% endblock %}
+              </div>
+            </div>
+            <div class="row">
+              <div class="statusMsg col-xs-12" id="statusMsg">
+                <!-- this is a placeholder for xoslib views to display status messages -->
+              </div>
+            </div>
+          </div>
+        </div>
+      {% endif %}
+    {% endblock %}
+  </div>
+
+  <script src="{% static 'suit/bootstrap/dist/js/bootstrap.min.js' %}"></script>
+  <script src="{% static 'suit/js/suit.js' %}"></script>
+  <script type="text/javascript" src="//www.google.com/jsapi"></script>
+  {% block extrajs %}
+  {% endblock %}
+  <script src="http://d3js.org/d3.v3.js"></script>
+  <div class="modal fade hide" id="chartsModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
+    <div class="modal-dialog">
+      <div class="modal-content">
+        <!--<div class="modal-header">
+          <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
+          <h4 class="modal-title" id="myModalLabel">OpenCloud</h4>
+        </div>-->
+        <div class="modal-body" style="overflow-y:hidden; overflow-x:hidden;">
+          <div class="chartContainer">
+            <div class="row">
+              <div class=" padding"></div>
+            </div>
+
+            <div class="row">
+              <div class=" heading">
+                <p id="chartHeading" class="heading">OpenCloud</p>
+              </div>
+            </div>
+            <div class="row">
+              <div class="padding"></div>
+              <div class="padding"></div>
+            </div>
+            <div class="row">
+              <div id="graph" class="graph"></div>
+            </div>
+          </div>
+          <div id="graph_work" style="display:none"></div>
+        </div>
+        <!--<div class="modal-footer">
+        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+        </div>
+        -->
+      </div>
+      <!-- /.modal-content -->
+    </div>
+    <!-- /.modal-dialog -->
+  </div>
+  <!-- /.modal -->
+
+  <!-- Menu Toggle Script -->
+  <script>
+    $(".navbar-toggle").click(function(e) {
+      e.preventDefault();
+      $("#wrapper").toggleClass("toggled");
+    });
+  </script>
+</body>
+</html>
diff --git a/xos/templates/admin/base_login.html b/xos/templates/admin/base_login.html
new file mode 100644
index 0000000..c56bbc2
--- /dev/null
+++ b/xos/templates/admin/base_login.html
@@ -0,0 +1,54 @@
+{% load admin_static %}
+<!DOCTYPE html>
+<html lang="{{ LANGUAGE_CODE|default:"en-us" }}" {% if LANGUAGE_BIDI %}dir="rtl"{% endif %}>
+    <head>
+        <title>{% block title %}{% endblock %}</title>
+        <link rel="stylesheet" type="text/css" href="{% block stylesheet %}{% static "admin/css/base.css" %}{% endblock %}" />
+        {% block extrastyle %}
+
+        {% endblock %}
+        <!--[if lte IE 7]>
+            <link rel="stylesheet" type="text/css" href="{% block stylesheet_ie %}{% static "admin/css/ie.css" %}{% endblock %}" />
+        <![endif]-->
+        {% if LANGUAGE_BIDI %}
+            <link rel="stylesheet" type="text/css" href="{% block stylesheet_rtl %}{% static "admin/css/rtl.css" %}{% endblock %}" />
+        {% endif %}
+        <script type="text/javascript">window.__admin_media_prefix__ = "{% filter escapejs %}{% static "admin/" %}{% endfilter %}";</script>
+        {% block extrahead %}
+
+        {% endblock %}
+        {% block blockbots %}
+            <meta name="robots" content="NONE,NOARCHIVE" />
+        {% endblock %}
+        <link rel="shortcut icon" href="{{ XOS_BRANDING_FAVICON }}"></head>
+    </head>
+{% load i18n %}
+
+    <body class="{% if is_popup %}popup {% endif %}{% block bodyclass %}{% endblock %}" style="background-image: url('{{ XOS_BRANDING_BG }}') ">
+
+    <!-- Container -->
+
+        {% block messages %}
+            {% if messages %}
+            <ul class="messagelist">{% for message in messages %}
+              <li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
+            {% endfor %}</ul>
+            {% endif %}
+        {% endblock messages %}
+
+
+            {% block pretitle %}{% endblock %}
+            {% block content_title %}{% if title %}<h1>{{ title }}</h1>{% endif %}{% endblock %}
+            {% block content %}
+            {% block object-tools %}{% endblock %}
+            {{ content }}
+            {% endblock %}
+            {% block sidebar %}{% endblock %}
+            <br class="clear" />
+
+
+        {% block footer %}<div id="footer"></div>{% endblock %}
+
+
+    </body>
+</html>
diff --git a/xos/templates/admin/base_logout.html b/xos/templates/admin/base_logout.html
new file mode 100644
index 0000000..61a8543
--- /dev/null
+++ b/xos/templates/admin/base_logout.html
@@ -0,0 +1,45 @@
+{% load admin_static %}
+<!DOCTYPE html>
+<html lang="{{ LANGUAGE_CODE|default:"en-us" }}" {% if LANGUAGE_BIDI %}dir="rtl"{% endif %}>
+    <head>
+        <title>{% block title %}{% endblock %}</title>
+        <link rel="stylesheet" type="text/css" href="{% block stylesheet %}{% static "admin/css/base.css" %}{% endblock %}" />
+        <link rel="stylesheet" type="text/css" href="{% static 'xos.css' %}" media="all">
+
+
+        {% block extrastyle %}
+
+        {% endblock %}
+        <!--[if lte IE 7]>
+            <link rel="stylesheet" type="text/css" href="{% block stylesheet_ie %}{% static "admin/css/ie.css" %}{% endblock %}" />
+        <![endif]-->
+        {% if LANGUAGE_BIDI %}
+            <link rel="stylesheet" type="text/css" href="{% block stylesheet_rtl %}{% static "admin/css/rtl.css" %}{% endblock %}" />
+        {% endif %}
+        <script type="text/javascript">window.__admin_media_prefix__ = "{% filter escapejs %}{% static "admin/" %}{% endfilter %}";</script>
+        {% block extrahead %}
+
+        {% endblock %}
+        {% block blockbots %}
+            <meta name="robots" content="NONE,NOARCHIVE" />
+        {% endblock %}
+        <link rel="shortcut icon" href="{{ XOS_BRANDING_FAVICON }}"></head>
+    </head>
+{% load i18n %}
+
+    <body class="{% if is_popup %}popup {% endif %}{% block bodyclass %}{% endblock %}" style="background-image: url('{{ XOS_BRANDING_BG }}') ">
+
+    <!-- Container -->
+    <div class="logout">
+
+            <img class="logo" src="{% static XOS_BRANDING_ICON %}"/>
+            {% block content_title %}{% if title %}<h1 class="logouth1tag">{{ title }}</h1>{% endif %}{% endblock %}
+            {% block content %}
+            {{ content }}
+            {% endblock %}
+
+    </div>
+
+
+    </body>
+</html>
diff --git a/xos/templates/admin/base_site.html b/xos/templates/admin/base_site.html
new file mode 100644
index 0000000..29c757c
--- /dev/null
+++ b/xos/templates/admin/base_site.html
@@ -0,0 +1,57 @@
+{% extends "admin/base.html" %}
+{% load admin_static %}
+
+{# Additional <head> content here, some extra meta tags or favicon #}
+{#{% block extrahead %}#}
+{#{% endblock %}#}
+
+
+{# Additional CSS includes #}
+{# {% block extrastyle %} #}
+{# {% endblock %} #}
+
+
+{# Additional JS files in footer, right before </body> #}
+{#{% block extrajs %}#}
+{#  <script type="text/javascript" src="{% static 'js/my_project.js' %}"></script>#}
+{#{% endblock %}#}
+
+
+{# Footer links (left side) #}
+{#{% block footer_links %}#}
+{#  <a href="/docs/" class="icon"><i class="icon-question-sign"></i>Documentation</a>#}
+{#{% endblock %}#}
+
+{# Additional header content like notifications or language switcher #}
+{#{% block header_content %}#}
+{#    {{ block.super }}#}
+{#    <div class="header-content">#}
+{#        <!-- First icon column -->#}
+{#        <div class="header-column icon">#}
+{#            <i class="icon-home"></i><br>#}
+{#            <i class="icon-cog"></i>#}
+{#        </div>#}
+{#        <div class="header-column" style="margin-right: 20px">#}
+{#            <a href="/" class="grey">Front-end</a><br>#}
+{#            <a href="" class="grey">One more link</a>#}
+{#        </div>#}
+{#        <!-- Second icon column -->#}
+{#        <div class="header-column icon">#}
+{#            <i class="icon-comment"></i>#}
+{#        </div>#}
+{#        <div class="header-column">#}
+{#            <a href="" class="grey">5 new messages</a>#}
+{#        </div>#}
+{#    </div>#}
+{#{% endblock %}#}
+
+{# Footer branding name (center) #}
+{% block footer_branding %}
+{{ XOS_BRANDING_NAME }}
+{% endblock %}
+
+
+{# Footer copyright (right side) #}
+{% block copyright %}
+{#  Copyright &copy; 2013 Client<br>Developed by <a href="http://yoursite.com" target="_blank">YourName</a> #}
+{% endblock %}
diff --git a/xos/templates/admin/base_site_login.html b/xos/templates/admin/base_site_login.html
new file mode 100644
index 0000000..b381c7f
--- /dev/null
+++ b/xos/templates/admin/base_site_login.html
@@ -0,0 +1,8 @@
+{% extends "admin/base_login.html" %}
+{% load i18n %}
+
+{% block title %}{{ title }} | {% trans 'Django site admin' %}{% endblock %}
+
+
+
+{% block nav-global %}{% endblock %}
diff --git a/xos/templates/admin/change_form_bc.html b/xos/templates/admin/change_form_bc.html
new file mode 100644
index 0000000..bd3a310
--- /dev/null
+++ b/xos/templates/admin/change_form_bc.html
@@ -0,0 +1,36 @@
+{% extends "admin/change_form.html" %}
+{% load i18n admin_static admin_modify suit_tags admin_urls %}
+{% load url from future %}
+
+{% if not is_popup %}
+  {% block breadcrumbs %}
+    <ul class="breadcrumb">
+      <li>
+        <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
+        <span class="divider">&raquo;</span>
+      </li>
+      <li>
+        {% if custom_app_breadcrumb_url %}
+            <a href="{{ custom_app_breadcrumb_url }}">{{ custom_app_breadcrumb_name }}</a>
+        {% else %}
+            <a href="{% url 'admin:app_list' app_label=opts.app_label %}">{% firstof opts.app_config.verbose_name app_label|capfirst|escape %}</a>
+        {% endif %}
+        <span class="divider">&raquo;</span>
+      </li>
+      <li>
+        {% if has_change_permission %}
+          {% if custom_changelist_breadcrumb_url %}
+              <a href="{{ custom_changelist_breadcrumb_url }}">
+          {% else %}
+              <a href="{% url opts|admin_urlname:'changelist' %}">
+          {% endif %}
+            {{ opts.verbose_name_plural|capfirst }}</a>{% else %}
+          {{ opts.verbose_name_plural|capfirst }}{% endif %}
+        <span class="divider">&raquo;</span>
+      </li>
+      <li class="active">
+        {% if add %}{% trans 'Add' %} {{ opts.verbose_name }}{% else %}{{ original|truncatewords:"18" }}{% endif %}
+      </li>
+    </ul>
+  {% endblock %}
+{% endif %}
diff --git a/xos/templates/admin/change_form_embedded.html b/xos/templates/admin/change_form_embedded.html
new file mode 100644
index 0000000..e3c2915
--- /dev/null
+++ b/xos/templates/admin/change_form_embedded.html
@@ -0,0 +1,12 @@
+{% extends "admin/change_form.html" %}
+{% load i18n admin_static admin_modify suit_tags admin_urls %}
+{% load url from future %}
+
+{% block container %}
+{% block content %}
+{{ block.super }}
+{% endblock %}
+{% endblock %}
+
+{% block footer %}
+{% endblock %}
diff --git a/xos/templates/admin/change_list_bc.html b/xos/templates/admin/change_list_bc.html
new file mode 100644
index 0000000..5e5e4c1
--- /dev/null
+++ b/xos/templates/admin/change_list_bc.html
@@ -0,0 +1,40 @@
+{% extends "admin/change_list.html" %}
+{% load i18n admin_static admin_modify suit_tags admin_urls %}
+{% load url from future %}
+
+{% if not is_popup %}
+  {% block breadcrumbs %}
+    <!-- template: modify the breadcrumbs to support custom_app_breadcrumb -->
+    <ul class="breadcrumb">
+      <li><a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
+        <span class="divider">&raquo;</span></li>
+      <li>
+        {% if custom_app_breadcrumb_url %}
+            <a href="{{ custom_app_breadcrumb_url }}">{{ custom_app_breadcrumb_name }}</a>
+        {% else %}
+            <a href="{% url 'admin:app_list' app_label=cl.opts.app_label %}">{% firstof opts.app_config.verbose_name app_label|capfirst|escape %}</a>
+       {% endif %}
+        <span class="divider">&raquo;</span></li>
+      <li class="active">{{ cl.opts.verbose_name_plural|capfirst }}</li>
+    </ul>
+  {% endblock %}
+{% endif %}
+
+
+{% block object-tools %}
+    <!-- template: modify object-tools to support custom_add_url -->
+    {% if has_add_permission %}
+      <div class="object-tools">
+        {% block object-tools-items %}
+        {% if custom_add_url %}
+          <a href="{{ custom_add_url }}{% if is_popup %}?_popup=1{% endif %}" class="btn btn-success">
+        {% else %}
+          <a href="{% url cl.opts|admin_urlname:'add' %}{% if is_popup %}?_popup=1{% endif %}" class="btn btn-success">
+        {% endif %}
+            <i class="icon-plus-sign icon-white"></i>&nbsp;
+            {% blocktrans with cl.opts.verbose_name as name %}Add {{ name }}{% endblocktrans %}
+          </a>
+        {% endblock %}
+      </div>
+    {% endif %}
+{% endblock %}
diff --git a/xos/templates/admin/change_list_embedded.html b/xos/templates/admin/change_list_embedded.html
new file mode 100644
index 0000000..77b39f3
--- /dev/null
+++ b/xos/templates/admin/change_list_embedded.html
@@ -0,0 +1,12 @@
+{% extends "admin/change_list_bc.html" %}
+{% load i18n admin_static admin_modify suit_tags admin_urls %}
+{% load url from future %}
+
+{% block container %}
+{% block content %}
+{{ block.super }}
+{% endblock %}
+{% endblock %}
+
+{% block footer %}
+{% endblock %}
diff --git a/xos/templates/admin/core/SiteDeploymentNetwork/sitedepnettabular.html b/xos/templates/admin/core/SiteDeploymentNetwork/sitedepnettabular.html
new file mode 100644
index 0000000..71a62ba
--- /dev/null
+++ b/xos/templates/admin/core/SiteDeploymentNetwork/sitedepnettabular.html
@@ -0,0 +1,79 @@
+{% load i18n admin_static admin_modify %}
+<div class="inline-group" id="{{ inline_admin_formset.formset.prefix }}-group">
+  <div class="tabular inline-related {% if forloop.last %}last-related{% endif %}">
+{{ inline_admin_formset.formset.management_form }}
+<fieldset class="module">
+   <h2>{{ inline_admin_formset.opts.verbose_name_plural|capfirst }}</h2>
+   {{ inline_admin_formset.formset.non_form_errors }}
+   <table>
+     <thead><tr>
+     {% for field in inline_admin_formset.fields %}
+       {% if not field.widget.is_hidden %}
+         <th{% if forloop.first %} colspan="2"{% endif %}{% if field.required %} class="required"{% endif %}>{{ field.label|capfirst }}
+         {% if field.help_text %}&nbsp;<img src="{% static "admin/img/icon-unknown.gif" %}" class="help help-tooltip" width="10" height="10" alt="({{ field.help_text|striptags }})" title="{{ field.help_text|striptags }}" />{% endif %}
+         </th>
+       {% endif %}
+     {% endfor %}
+     {% if inline_admin_formset.formset.can_delete %}<th>{% trans "Delete?" %}</th>{% endif %}
+     </tr></thead>
+
+     <tbody>
+     {% for inline_admin_form in inline_admin_formset %}
+        {% if inline_admin_form.form.non_field_errors %}
+        <tr><td colspan="{{ inline_admin_form|cell_count }}">{{ inline_admin_form.form.non_field_errors }}</td></tr>
+        {% endif %}
+        <tr class="form-row {% cycle "row1" "row2" %} {% if inline_admin_form.original or inline_admin_form.show_url %}has_original{% endif %}{% if forloop.last %} empty-form{% endif %}"
+             id="{{ inline_admin_formset.formset.prefix }}-{% if not forloop.last %}{{ forloop.counter0 }}{% else %}empty{% endif %}">
+        <td class="original">
+          {% if inline_admin_form.original or inline_admin_form.show_url %}<p>
+          {% if inline_admin_form.original %} {{ inline_admin_form.original }}{% endif %}
+          {% if inline_admin_form.show_url %}<a href="{% url 'admin:view_on_site' inline_admin_form.original_content_type_id inline_admin_form.original.pk %}">{% trans "View on site" %}</a>{% endif %}
+            </p>{% endif %}
+          {% if inline_admin_form.has_auto_field %}{{ inline_admin_form.pk_field.field }}{% endif %}
+          {{ inline_admin_form.fk_field.field }}
+          {% spaceless %}
+          {% for fieldset in inline_admin_form %}
+            {% for line in fieldset %}
+              {% for field in line %}
+                {% if field.is_hidden %} {{ field.field }} {% endif %}
+              {% endfor %}
+            {% endfor %}
+          {% endfor %}
+          {% endspaceless %}
+        </td>
+        {% for fieldset in inline_admin_form %}
+          {% for line in fieldset %}
+            {% for field in line %}
+              <td{% if field.field.name %} class="field-{{ field.field.name }}"{% endif %}>
+              {% if field.is_readonly %}
+                  <p>{{ field.contents|linebreaksbr }}</p>
+              {% else %}
+                  {{ field.field.errors.as_ul }}
+                  {{ field.field }}
+              {% endif %}
+              </td>
+            {% endfor %}
+          {% endfor %}
+        {% endfor %}
+        {% if inline_admin_formset.formset.can_delete %}
+          <td class="delete">{% if inline_admin_form.original %}{{ inline_admin_form.deletion_field.field }}{% endif %}</td>
+        {% endif %}
+        </tr>
+     {% endfor %}
+     </tbody>
+   </table>
+</fieldset>
+  </div>
+</div>
+
+<script type="text/javascript">
+
+(function($) {
+  $("#{{ inline_admin_formset.formset.prefix }}-group .tabular.inline-related tbody tr").tabularFormset({
+    prefix: "{{ inline_admin_formset.formset.prefix }}",
+    adminStaticPrefix: '{% static "admin/" %}',
+    addText: "{% blocktrans with inline_admin_formset.opts.verbose_name|title as verbose_name %}Add another {{ verbose_name }}{% endblocktrans %}",
+    deleteText: "{% trans 'Remove' %}"
+  });
+})(django.jQuery);
+</script>
diff --git a/xos/templates/admin/core/instance/change_form.html b/xos/templates/admin/core/instance/change_form.html
new file mode 100644
index 0000000..4b5439c
--- /dev/null
+++ b/xos/templates/admin/core/instance/change_form.html
@@ -0,0 +1,114 @@
+{% extends 'admin/change_form.html' %}
+{% block extrahead %}
+{{ block.super }} 
+<script>
+deployment_nodes = [
+{% for dn in deployment_nodes %}
+   [{{ dn.0 }}, {{ dn.1 }} , "{{ dn.2 }}"],
+{% endfor %}
+];
+
+deployment_flavors = [
+{% for dn in deployment_flavors %}
+   [{{ dn.0 }}, {{ dn.1 }} , "{{ dn.2 }}"],
+{% endfor %}
+];
+
+deployment_images = [
+{% for dn in deployment_images %}
+   [{{ dn.0 }}, {{ dn.1 }} , "{{ dn.2 }}"],
+{% endfor %}
+];
+
+site_login_bases = [
+{% for s in site_login_bases %}
+  [{{ s.0 }}, "{{ s.1 }}"],
+{% endfor %}
+];
+
+function option_html(val, text, selected) {
+    if (selected) {
+        return '<option value="' + val + '" selected>' + text + '</option>\n';
+    } else {
+        return '<option value="' + val + '">' + text + '</option>\n';
+    }
+}
+
+function update_nodes(deployment_select, flavor_select, node_select) {
+    deployment_id = $(deployment_select).val();
+    node_id = $(node_select).val();
+    flavor_name = $(flavor_select).children(":selected").text()
+    html="";
+    for (i in deployment_nodes) {
+        // this is for EC2, where the node hostnames imply the flavor.
+        dn = deployment_nodes[i];
+        if ((dn[0] == deployment_id) && (dn[2].lastIndexOf(flavor_name,0) === 0)) {
+            html = html + option_html(dn[1], dn[2], dn[1]==node_id);
+        }
+    }
+    if (!html) {
+        // now try it without the flavor hostname prefix matching
+        for (i in deployment_nodes) {
+            dn = deployment_nodes[i];
+            if (dn[0] == deployment_id) {
+                html = html + option_html(dn[1], dn[2], dn[1]==node_id);
+            }
+        }
+    }
+    html = "<option value=''>---------</option>\n" + html;
+    node_select.empty().append(html);
+}
+
+function update_flavors(deployment_select, flavor_select) {
+    deployment_id = $(deployment_select).val();
+    flavor_id = $(flavor_select).val();
+    html = "<option value=''>---------</option>\n";
+    for (i in deployment_flavors) {
+        dn = deployment_flavors[i];
+        if (dn[0] == deployment_id) {
+            html = html + option_html(dn[1], dn[2], dn[1] == flavor_id);
+        }
+    }
+    flavor_select.empty().append(html);
+}
+
+function update_images(deployment_select, image_select) {
+    deployment_id = $(deployment_select).val();
+    image_id = $(image_select).val();
+    html = "<option value=''>---------</option>\n";
+    for (i in deployment_images) {
+        dn = deployment_images[i];
+        if (dn[0] == deployment_id) {
+            html = html + option_html(dn[1], dn[2], dn[1] == image_id);
+        }
+    }
+    image_select.empty().append(html);
+}
+
+function instance_deployment_changed(any_control) {
+   /* This function handles someone changing the deployment control
+      It updates the flavors and nodes dialogs
+      accordingly.
+   */
+
+    deployment_select = $("#id_deployment");
+    node_select = $("#id_node");
+    flavor_select = $("#id_flavor");
+    image_select = $("#id_image");
+
+    update_nodes(deployment_select, flavor_select, node_select);
+    update_flavors(deployment_select, flavor_select);
+    update_images(deployment_select, image_select);
+}
+
+function instance_flavor_changed(any_control) {
+    deployment_select = $("#id_deployment");
+    node_select = $("#id_node");
+    flavor_select = $("#id_flavor");
+    update_nodes(deployment_select, flavor_select, node_select);
+}
+
+</script>
+
+{% endblock %}
+
diff --git a/xos/templates/admin/core/slice/change_form.html b/xos/templates/admin/core/slice/change_form.html
new file mode 100644
index 0000000..791fcec
--- /dev/null
+++ b/xos/templates/admin/core/slice/change_form.html
@@ -0,0 +1,133 @@
+{% extends 'admin/change_form.html' %}
+{% block extrahead %}
+{{ block.super }} 
+<script>
+deployment_nodes = [
+{% for dn in deployment_nodes %}
+   [{{ dn.0 }}, {{ dn.1 }} , "{{ dn.2 }}"],
+{% endfor %}
+];
+
+deployment_flavors = [
+{% for dn in deployment_flavors %}
+   [{{ dn.0 }}, {{ dn.1 }} , "{{ dn.2 }}"],
+{% endfor %}
+];
+
+deployment_images = [
+{% for dn in deployment_images %}
+   [{{ dn.0 }}, {{ dn.1 }} , "{{ dn.2 }}"],
+{% endfor %}
+];
+
+site_login_bases = [
+{% for s in site_login_bases %}
+  [{{ s.0 }}, "{{ s.1 }}"],
+{% endfor %}
+];
+
+function option_html(val, text, selected) {
+    if (selected) {
+        return '<option value="' + val + '" selected>' + text + '</option>\n';
+    } else {
+        return '<option value="' + val + '">' + text + '</option>\n';
+    }
+}
+
+function update_nodes(deployment_select, flavor_select, node_select) {
+    deployment_id = $(deployment_select).val();
+    node_id = $(node_select).val();
+    flavor_name = $(flavor_select).children(":selected").text()
+    html="";
+    for (i in deployment_nodes) {
+        // this is for EC2, where the node hostnames imply the flavor.
+        dn = deployment_nodes[i];
+        if ((dn[0] == deployment_id) && (dn[2].lastIndexOf(flavor_name,0) === 0)) {
+            html = html + option_html(dn[1], dn[2], dn[1]==node_id);
+        }
+    }
+    if (!html) {
+        // now try it without the flavor hostname prefix matching
+        for (i in deployment_nodes) {
+            dn = deployment_nodes[i];
+            if (dn[0] == deployment_id) {
+                html = html + option_html(dn[1], dn[2], dn[1]==node_id);
+            }
+        }
+    }
+    html = "<option value=''>---------</option>\n" + html;
+    node_select.empty().append(html);
+}
+
+function update_flavors(deployment_select, flavor_select) {
+    deployment_id = $(deployment_select).val();
+    flavor_id = $(flavor_select).val();
+    html = "<option value=''>---------</option>\n";
+    for (i in deployment_flavors) {
+        dn = deployment_flavors[i];
+        if (dn[0] == deployment_id) {
+            html = html + option_html(dn[1], dn[2], dn[1] == flavor_id);
+        }
+    }
+    flavor_select.empty().append(html);
+}
+
+function update_images(deployment_select, image_select) {
+    deployment_id = $(deployment_select).val();
+    image_id = $(image_select).val();
+    html = "<option value=''>---------</option>\n";
+    for (i in deployment_images) {
+        dn = deployment_images[i];
+        if (dn[0] == deployment_id) {
+            html = html + option_html(dn[1], dn[2], dn[1] == image_id);
+        }
+    }
+    image_select.empty().append(html);
+}
+
+function instance_deployment_changed(any_control) {
+   /* This function handles someone changing the deployment control
+      in the add-instance line. It updats the flavors and nodes dialogs
+      accordingly.
+   */
+
+   /* the inscrutable jquery selector below says:
+      find the closest parent "tr" to the current element
+      then find the child with class "field-deployment"
+      then find the child with that is a select
+      then return it's id
+      then turn it into a jquery object
+    */
+    deployment_select = $("#" + $($(any_control).closest('tr')[0]).find('.field-deployment select')[0].id);
+    node_select = $("#" + $($(any_control).closest('tr')[0]).find('.field-node select')[0].id);
+    flavor_select = $("#" + $($(any_control).closest('tr')[0]).find('.field-flavor select')[0].id);
+    image_select = $("#" + $($(any_control).closest('tr')[0]).find('.field-image select')[0].id);
+    update_nodes(deployment_select, flavor_select, node_select);
+    update_flavors(deployment_select, flavor_select);
+    update_images(deployment_select, image_select);
+}
+
+function instance_flavor_changed(any_control) {
+    /* this is like instance_flavor changed, but does not update the flavors
+       control
+    */
+    deployment_select = $("#" + $($(any_control).closest('tr')[0]).find('.field-deployment select')[0].id);
+    node_select = $("#" + $($(any_control).closest('tr')[0]).find('.field-node select')[0].id);
+    flavor_select = $("#" + $($(any_control).closest('tr')[0]).find('.field-flavor select')[0].id);
+    update_nodes(deployment_select, flavor_select, node_select);
+}
+
+function update_slice_prefix(site_select, slice_name_id) {
+    site_id = $(site_select).val();
+    slice_prefix="";
+    for (i in site_login_bases) {
+        if (site_login_bases[i][0] == site_id) {
+            slice_prefix=site_login_bases[i][1]+"_";
+        }
+    }
+    $("#"+slice_name_id).val(slice_prefix); 
+}
+</script>
+
+{% endblock %}
+
diff --git a/xos/templates/admin/dashboard/cdn_nodes.html b/xos/templates/admin/dashboard/cdn_nodes.html
new file mode 100644
index 0000000..d93667d
--- /dev/null
+++ b/xos/templates/admin/dashboard/cdn_nodes.html
@@ -0,0 +1,106 @@
+<div id="tabs-6">
+<div class="row">
+        <span><b>Content Provider:</b></span>
+        <span><select id="cdn-node-data-slicename">
+        <option value="all">all</option>
+        {% for cp in cdnContentProviders %}
+           <option value="{{ cp.account }}">{{ cp.name }}</option>
+        {% endfor %}
+        </select></span>
+</div>
+<div id="cdn-node-table"></div>
+</div>
+<script>
+
+function domain_name_sort(a,b) {
+        parts_a = a.split(".");
+        parts_b = b.split(".");
+        parts_a = parts_a.reverse();
+        parts_b = parts_b.reverse();
+        a = parts_a.join(".");
+        b = parts_b.join(".");
+	return ((a < b) ? -1 : ((a > b) ?  1 : 0));
+}
+
+jQuery.fn.dataTableExt.oSort['domain-name-asc']  = function(a,b) {
+    return domain_name_sort(a,b);
+};
+
+jQuery.fn.dataTableExt.oSort['domain-name-desc']  = function(a,b) {
+    retuirn -domain_name_sort(a,b);
+};
+
+function updateCDNNodeData(data) {
+    $('#cdn-node-table').html( '<table cellpadding="0" cellspacing="0" border="0" class="display" id="dynamic_cdn_nodes"></table>' );
+    var actualEntries = [];
+
+    var rows = data.rows;
+    for (row in rows) {
+        hostname = rows[row]['hostname'];
+        bytes_sent = rows[row]['sum_bytes_sent'];
+        bytes_hit = rows[row]['sum_bytes_hit'];
+        elapsed = rows[row]['sum_elapsed'];
+        healthy = rows[row]['sum_healthy'];
+
+        if (bytes_sent > 0) {
+            hit_ratio = parseInt( bytes_hit * 100.0 / bytes_sent );
+        } else {
+            hit_ratio = 0;
+        }
+
+        Mbps = parseInt(rows[row]['sum_computed_bytes_sent_div_elapsed'] * 8.0 / 1024.0 / 1024.0);
+
+        if (healthy>0) {
+            healthyStr = "ok";
+        } else {
+            healthyStr = "bad";
+        }
+
+        actualEntries.push([hostname, healthyStr, Mbps, hit_ratio]);
+    }
+    oTable = $('#dynamic_cdn_nodes').dataTable( {
+        "bJQueryUI": true,
+        "aaData":  actualEntries,
+        "bStateSave": true,
+        "aoColumns": [
+            { "sTitle": "Hostname", sType: "domain-name" },
+            { "sTitle": "Healthy" },
+            { "sTitle": "Mbps" , sClass: "alignCenter"},
+            { "sTitle": "Hit Ratio" , sClass: "alignCenter"},
+        ],
+    } );
+}
+
+function updateCDNNodes() {
+    var contentProvider = $("#cdn-node-data-slicename").val();
+
+    var filterPart = ""
+    if ((contentProvider!="") && (contentProvider!="all")) {
+         filterPart = "&cp=" + contentProvider
+    }
+
+    var url= '/analytics/bigquery/?event=hpc_heartbeat&sum=@bytes_sent,@bytes_hit,@healthy,@elapsed&computed=@bytes_sent/@elapsed&groupBy=@hostname&cached=hpc&cachedGroupBy=@hostname' + filterPart;
+
+    $.ajax({
+    url: url,
+    dataType : 'json',
+    type : 'GET',
+    success: function(newData)
+    {
+        updateCDNNodeData(newData);
+    }
+});
+    setTimeout(updateCDNNodes, 30000);
+}
+
+google.setOnLoadCallback(function () {
+    $('#cdn-node-data-slicename').change(function()
+    {
+        updateCDNNodes();
+    });
+
+    updateCDNNodes();
+});
+
+//setTimeout(updateCDNNodes, 5000);
+</script>
diff --git a/xos/templates/admin/dashboard/cdnoperations.html b/xos/templates/admin/dashboard/cdnoperations.html
new file mode 100644
index 0000000..4677e5b
--- /dev/null
+++ b/xos/templates/admin/dashboard/cdnoperations.html
@@ -0,0 +1,263 @@
+    <div id="HPCDashboard">
+    <h1>CDN Operations View</h1>
+    <span id="hpcSummary">
+        <span class="summary-attr"><b>Allocated Instances:</b> <span id="active-instances-value"> </span> </span>
+        <span class="summary-attr"><b>CDN Bandwidth:</b> <span id="overall-throughput-value"> </span>  </span>
+        <span class="summary-attr-util"><b>CDN Load:</b> <span id="cpu-utilization-value"> </span>  </span>
+    </span>
+    <div id="map-us" ></div>
+    <div style="line-height: 30%"><br></div><table border=0><tr>
+    <td>Least Loaded&nbsp;&nbsp;</td>
+    <td bgcolor="#0000FF" width=40>&nbsp;</td>
+    <td bgcolor="#00FFFF" width=40>&nbsp;</td>
+    <td bgcolor="#00FF00" width=40>&nbsp;</td>
+    <td bgcolor="#FFFF00" width=40>&nbsp;</td>
+    <td bgcolor="#FF0000" width=40>&nbsp;</td>
+    <td>&nbsp;&nbsp;Most Loaded</td>
+    </tr></table>
+    </div>
+
+    <div id="confirmNodeAdded" title="Added Node to Site"><p>Added Node to Site</p></div>
+    <div id="confirmNodeRemoved" title="Removed Node from Site"><p>Added Node to Site</p></div>
+
+<script>
+$( "#confirmNodeAdded" ).dialog({ autoOpen: false,
+                    modal: true,
+                    buttons: {
+                        Ok: function() {
+                           $( this ).dialog( "close" );
+                        }
+                    }});
+$( "#confirmNodeRemoved" ).dialog({ autoOpen: false });
+
+L.Map = L.Map.extend({
+    openPopup: function(popup) {
+        this._popup = popup;
+
+        return this.addLayer(popup).fire('popupopen', {
+            popup: this._popup
+        });
+    }
+});
+
+
+//Iterate through data and find the max/min coordinates to include all of our points to start
+var map = L.map('map-us'); //.setView([0, 0], 1);
+map.scrollWheelZoom.disable();
+
+//
+// Great tiles, but starting to occasionally see 403 errors on certain tiles causing grey out effect
+//L.tileLayer('http://{s}.tile.cloudmade.com/BC9A493B41014CAABB98F0471D759707/997/256/{z}/{x}/{y}.png', {
+//
+// Swapping out cloudmade tiles to openstreetmap - too many grey tiles showing
+L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
+    maxZoom: 18,
+    attribution: 'Test'
+}).addTo(map);
+
+var arrayOfLatLngs = [];
+var mapData = {{ cdnData|safe }};
+log.debug( mapData );
+
+for ( var key in mapData ) {
+    arrayOfLatLngs.push([mapData[key]['lat'],mapData[key]['long']]);
+    log.debug( arrayOfLatLngs );
+
+    mapData[key]['marker'] = L.marker([mapData[key]['lat'], mapData[key]['long']], {icon: getIcon(mapData[key]['numNodes'], mapData[key]['numHPCInstances'], 0, mapData[key]['hot']) });
+    mapData[key]['marker'].addTo(map).bindPopup(setPopupVals(key, mapData[key]));
+
+}
+var bounds = new L.LatLngBounds(arrayOfLatLngs);
+map.fitBounds(bounds);
+
+var popup = L.popup();
+
+
+function setPopupVals (site, siteData) {
+    var retVal = '<span class="SiteDetail"><b>' + site + '</b></span>' +
+                   '</br><a href="' + siteData['siteUrl'] + '">' + siteData['siteUrl'] + '</a>' +
+                   '</br><b>HPC Instances: </b>' + siteData['numHPCInstances'] +
+                   '</br><b>Total Nodes: </b>' + siteData['numNodes'] +
+//                   '</br><b>Hot: </b>' + Math.round(siteData['hot']*100) +
+                   '</br><b>Measured Load: </b>' + siteData['load'] + '%' +
+                   '<span id="addInstances"></br><a href="#" id="addHPCInstance" data-site="' + site + '" data-availNodes="' + siteData['numNodes'] +'">Add HPC Instances</a> </span>' +
+                   '<span id="remInstances"><a href="#" id="remHPCInstance" data-site="' + site + '">Remove HPC Instances</a> </span>';
+
+   return retVal;
+}
+
+$('#map-us').on('click', '#remHPCInstance', function() {
+
+    $.ajax({
+        url : '/dashboardaddorreminstance/',
+        dataType : 'json',
+        data: {site: $(this).data('site'),
+               actionToDo: "rem",
+               csrfmiddlewaretoken: "{{ csrf_token }}",   // < here
+               state:"inactive" },
+        type : 'POST',
+        success:function(){
+            confirmDialog("Info","Removed an HPC Instance from Site ");
+        },
+        error:function (xhr, textStatus, thrownError){
+            errorDialog("Error", textStatus + " " + xhr.responseText);
+        }
+    });
+});
+
+$('#map-us').on('click', '#addHPCInstance', function() {
+
+    $.ajax({
+        url : '/dashboardaddorreminstance/',
+        dataType : 'json',
+        data: {site: $(this).data('site'),
+               actionToDo: "add",
+               csrfmiddlewaretoken: "{{ csrf_token }}",   // < here
+               state:"inactive" },
+        type : 'POST',
+        success: function(response)
+        {
+            confirmDialog("Info","Added an HPC Instance to Site ");
+        },
+        error:function (xhr, textStatus, thrownError){
+            errorDialog("Error", textStatus + " " + xhr.responseText);
+        }
+    });
+});
+
+function getIcon(numNodes, numHPCInstances, currentBW, hot) {
+    //var colorChoices = ["#007FFF", "#0000FF", "#7f00ff", "#FF00FF", "#FF007F", "#FF0000"];
+    var colorChoices = ["#0000FF", "#00FFFF", "#00FF00", "#FFFF00", "#FF0000"];
+
+    var ratio = hot * 100; //(numHPCInstances/numNodes) * 100;
+    var numColors = colorChoices.length;
+    var colorBands = 100/numColors;
+
+    //Algorithm for color tone should consider the number of available nodes
+    // on the site, and then how much the current dedicated nodes are impacted
+    //var iconColor = 0;
+    var iconColor = colorChoices.length-1;
+    for (colorBand = 0; colorBand < numColors; colorBand ++) {
+        if (ratio < colorBands * colorBand+1) {
+            iconColor = colorBand
+            break;
+        }
+    }
+
+    if (numHPCInstances < 1) {
+        iconColor = "#7F7F7F";
+    } else {
+        iconColor = colorChoices[iconColor];
+    }
+
+    var icon = L.MakiMarkers.icon({icon: "star-stroked", color: iconColor , size: "s"});
+    return icon;
+}
+
+function updateMaps() {
+    log.debug("Attempting to update Maps");
+    $.ajax({
+    url : '/hpcdashboard',
+    dataType : 'json',
+    type : 'GET',
+    success: function(newData)
+    {
+        log.debug("Successfully got data back...");
+        log.debug(newData);
+        log.debug("Still have old data too");
+        log.debug(mapData);
+        updateMapData(newData);
+    }
+});
+    setTimeout(updateMaps, 30000)
+
+}
+
+function updateMapData(newData) {
+    for ( site in newData ) {
+        var isNewSite = false;
+        //check to see if the site is new or not
+        if (site in mapData) {
+            log.debug("Site " + site + " already mapped");
+            //take ownership of marker
+            newData[site]['marker'] = mapData[site]['marker'];
+            delete mapData[site];
+            newData[site]['marker'].setIcon(getIcon(newData[site]['numNodes'], newData[site]['numHPCInstances'],  0, newData[site]['hot']));
+            // workaround, markers currently don't have a setPopup Content method -- so have to grab object directly
+            newData[site]['marker']._popup.setContent(setPopupVals(site, newData[site]));
+        }
+        else {
+            isNewSite = true;
+            log.debug("New Site detected: " + site);
+            newData[site]['marker'] = L.marker([newData[site]['lat'], newData[site]['long']],
+                                              {icon: getIcon(newData[site]['numNodes'], newData[site]['numHPCInstances'],  0, newData[site]['hot']) });
+            newData[site]['marker'].addTo(map).bindPopup(setPopupVals(site, newData[site])); //.openPopup();
+            log.debug("Should have added the new site");
+
+        }
+    }
+
+    // Anything still in data needs to be removed since it is no longer a valid site
+    for (remSite in mapData) {
+        log.warn("Site: " + remSite + " is no longer valid, removing from map");
+        map.removeLayer(data[remSite]['marker']);
+    }
+    mapData = newData;
+}
+
+function onMapClick(e) {
+    popup
+    .setLatLng(e.latlng)
+    .setContent("You clicked the map at " + e.latlng.toString())
+    .openOn(map);
+}
+
+setTimeout(updateMaps, 5000)
+
+// from stackexchange
+function setInnerText (elementId, text) {
+    var element;
+    if (document.getElementById) {
+        element = document.getElementById(elementId);
+    } else if (document.all) {
+        element = document.all[elementId];
+    }
+    if (element) {
+        if (typeof element.textContent != 'undefined') {
+            element.textContent = text;
+        } else if (typeof element.innerText != 'undefined') {
+            element.innerText = text;
+        } else if (typeof element.removeChild != 'undefined') {
+            while (element.hasChildNodes()) {
+                element.removeChild(element.lastChild);
+            }
+            element.appendChild(document.createTextNode(text)) ;
+        }
+    }
+}
+
+function updateLabelData(summaryData) {
+    setInnerText("active-instances-value", summaryData["total_instances"]);
+    setInnerText("overall-throughput-value", (summaryData["total_bandwidth"]*8/1024/1024/1024).toFixed(2) + " Gbps");
+    setInnerText("cpu-utilization-value", summaryData["average_cpu"] + "%");
+}
+
+function updateLabels() {
+    log.debug("Attempting to update Labels");
+    $.ajax({
+    url : '/hpcsummary',
+    dataType : 'json',
+    type : 'GET',
+    success: function(newData)
+    {
+        updateLabelData(newData);
+    }
+});
+    setTimeout(updateLabels, 30000)
+
+}
+
+setTimeout(updateLabels, 5000)
+
+
+</script>
diff --git a/xos/templates/admin/dashboard/customize.html b/xos/templates/admin/dashboard/customize.html
new file mode 100644
index 0000000..2a286ad
--- /dev/null
+++ b/xos/templates/admin/dashboard/customize.html
@@ -0,0 +1,106 @@
+<div class="row-fluid">

+    <div class="span12 text-right">

+        <a href="/core/dashboardview/" class="btn btn-default">

+            <i class="icon icon-pencil"></i> Manage

+        </a>

+        <a href="/core/dashboardview/add/" class="btn btn-success">

+            <i class="icon icon-plus"></i> Add

+        </a>

+    </div>

+</div>

+<form>

+    <div class="row">

+        <div class="col-xs-4">

+            <div>Available Dashboard Views</div>

+            <select class="form-control" name="selectfrom" id="select-from" multiple size="5">

+                {% for cp in unusedDashboards %}

+                <option value="{{ cp }}">{{ cp }}</option>

+                {% endfor %}

+            </select>

+        </div>

+        <div class="col-xs-2">

+            <br>

+            <div class="btn btn-success" id="customize-btn-add">Add &raquo;</div>

+            <br>

+            <br>

+            <div class="btn btn-success" id="customize-btn-remove">&laquo; Remove</div>

+        </div>

+        <div class="col-xs-4">

+            <div>Selected Dashboard Views</div>

+            <select class="form-control" name="selectto" id="select-to" multiple size="5">

+                {% for cp in dashboards %}

+                <option value="{{ cp }}">{{ cp }}</option>

+                {% endfor %}

+            </select>

+            <br>

+            <div class="btn btn-high btn-info" id="customize-btn-save">Save</div>

+            <div style="display: none" id="customize-msg-saving">Saving...</div>

+        </div>

+        <div class="col-xs-2">

+            <br>

+            <div class="btn btn-success" id="customize-btn-up">Up</div>

+            <br>

+            <br>

+            <div class="btn btn-success" id="customize-btn-down">Down</div>

+        </div>

+    </div>

+</form>

+

+<script>

+$(document).ready(function() {

+    $('#customize-btn-add').click(function(){

+        $('#select-from option:selected').each( function() {

+                $('#select-to').append("<option value='"+$(this).val()+"'>"+$(this).text()+"</option>");

+            $(this).remove();

+        });

+    });

+    $('#customize-btn-remove').click(function(){

+        $('#select-to option:selected').each( function() {

+            $('#select-from').append("<option value='"+$(this).val()+"'>"+$(this).text()+"</option>");

+            $(this).remove();

+        });

+    });

+    $('#customize-btn-up').bind('click', function() {

+        $('#select-to option:selected').each( function() {

+            var newPos = $('#select-to option').index(this) - 1;

+            if (newPos > -1) {

+                $('#select-to option').eq(newPos).before("<option value='"+$(this).val()+"' selected='selected'>"+$(this).text()+"</option>");

+                $(this).remove();

+            }

+        });

+    });

+    $('#customize-btn-down').bind('click', function() {

+        var countOptions = $('#select-to option').size();

+        $('#select-to option:selected').each( function() {

+            var newPos = $('#select-to option').index(this) + 1;

+            if (newPos < countOptions) {

+                $('#select-to option').eq(newPos).after("<option value='"+$(this).val()+"' selected='selected'>"+$(this).text()+"</option>");

+                $(this).remove();

+            }

+        });

+    });

+    $('#customize-btn-save').bind('click', function() {

+         $("#customize-btn-save").hide();

+         $("#customize-msg-saving").show();

+         var items=[];

+         $("#select-to option").each(function() { items.push($(this).val()); });

+         $.ajax({

+                url: '/customize/',

+                dataType: 'json',

+                data: {

+                        dashboards: items.join(","),

+                csrfmiddlewaretoken: "{{ csrf_token }}" // < here

+                },

+                type: 'POST',

+                error: function (jqXHR, textStatus, errorThrown) {

+                    errorDialog("Error", textStatus + " " + jqXHR.responseText);

+                    $("#customize-btn-save").show();

+                    $("#customize-msg-saving").hide();

+                },

+                success: function () {

+                        location.reload();

+                }

+        });

+    });

+});

+</script>
\ No newline at end of file
diff --git a/xos/templates/admin/dashboard/dashboard_base.html b/xos/templates/admin/dashboard/dashboard_base.html
new file mode 100644
index 0000000..5d510b8
--- /dev/null
+++ b/xos/templates/admin/dashboard/dashboard_base.html
@@ -0,0 +1,94 @@
+{% extends "admin/base.html" %}
+{% load admin_static %}
+
+{% block extrahead %}
+<link rel="stylesheet"  href="http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.0/css/jquery.dataTables.css">
+<link rel="stylesheet" type="text/css" href="{% static 'suit/css/suit.css' %}" media="all">
+<link rel="stylesheet" type="text/css" href="http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.0/css/jquery.dataTables_themeroller.css">
+<link rel="stylesheet" type="text/css" href="{% static 'xos.css' %}" media="all">
+{% if XOS_BRANDING_CSS %}
+    <link rel="stylesheet" type="text/css" href="{{ XOS_BRANDING_CSS }}">
+{% endif %}
+<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.4/themes/smoothness/jquery-ui.css">
+<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.css" />
+<script src="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.js"></script>
+
+
+<!-- no need to include jquery here as it's already included by base.html. Including it multiple times will break mtuity statistics. -->
+<!-- src="http://code.jquery.com/jquery-1.9.1.js" -->
+
+<script src="http://code.jquery.com/ui/1.10.4/jquery-ui.js"></script>
+<script src="http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/jquery.dataTables.min.js"></script>
+<script type="text/javascript" src="{% static 'log4javascript-1.4.6/log4javascript.js' %}"></script>
+<script src="{% static 'js/Leaflet.MakiMarkers.js' %}" > </script>
+  
+<script>
+  $(function() {
+    $( "#hometabs" ).tabs({active: 0, //event: "mouseover"
+      //collapsible: true
+    });
+  });
+
+var consoleAppender = new log4javascript.BrowserConsoleAppender();
+var patternLayout = new log4javascript.PatternLayout("%d{HH:mm:ss,SSS} %l{s:l} %-5p - %m{1}%n");
+consoleAppender.setLayout(patternLayout);
+//var log  = log4javascript.getDefaultLogger();
+var log  = log4javascript.getRootLogger();
+log.addAppender(consoleAppender);
+log.setLevel(log4javascript.Level.ERROR);
+
+function confirmDialog(title,msg) {
+    var dialog = $('<div>'+msg+'</div>');
+    var def = $.Deferred();
+
+    $(dialog).dialog({
+        resizable: false,
+        title: title,
+        autoOpen: true,
+        modal: true,
+        dialogClass: "dashboard-hpc-instance",
+        buttons: {
+            'OK': function() {
+                def.resolve();
+                log.debug("Chose to add a instance");
+                $( this ).dialog( "close" );
+            },
+            'Cancel': function() {
+                def.reject();
+                $( this ).dialog( "close" );
+            }
+        },
+        close: {
+        }
+    });
+    return def.promise();
+}
+
+function errorDialog(title,msg) {
+    var dialog = $('<div>'+msg+'</div>');
+    var def = $.Deferred();
+
+    $(dialog).dialog({
+        resizable: false,
+        title: title,
+        autoOpen: true,
+        modal: true,
+        dialogClass: "dashboard-hpc-instance",
+        buttons: {
+            'OK': function() {
+                def.resolve();
+                $( this ).dialog( "close" );
+            },
+        },
+        close: {
+        }
+    });
+    return def.promise();
+}
+
+</script>
+{% endblock %}
+
+{% block content %}
+dashboard goes here
+{% endblock %}
diff --git a/xos/templates/admin/dashboard/developer.html b/xos/templates/admin/dashboard/developer.html
new file mode 100644
index 0000000..55663f5
--- /dev/null
+++ b/xos/templates/admin/dashboard/developer.html
@@ -0,0 +1,84 @@
+<div id="developerview"></div>
+
+<script>
+var oTable;
+
+function updateUserSliceTable(){
+    log.debug("Should grab user slice info");
+    jQuery.ajax({
+        async:true,
+        dataType: 'json',
+        url: '/hpcdashuserslices',
+        success: function(data){
+            log.info("Got Data back for User SliceTable");
+            //parseData(data);
+            //createUserSliceTable(data);
+            setTimeout(function () { updateUserSliceTable() }, 5000);
+        },
+        error: function(data){
+            log.debug("COULDNT GET DATA BACK");
+            setTimeout(function () { updateUserSliceTable() }, 5000);
+        }
+    });
+}
+
+function createUserSliceTable(data) {
+    log.debug("Creating User Slice Table");
+
+    //Add check for #dynamicusersliceinfo_filter label-> input having focus here
+
+    $('#developerview').html( '<table cellpadding="0" cellspacing="0" border="0" class="display" id="dynamicusersliceinfo"></table>' );
+    var actualEntries = [];
+    //log.debug(data['userSliceInfo']['rows'][0]['slicename']);
+
+    var rows = data['userSliceInfo']['rows'];
+    for (row in rows) {
+        log.debug(row[0]);
+        slicename = rows[row]['slicename'];
+        sliceid = rows[row]['sliceid'];
+        role = rows[row]['role'];
+        instancecount = rows[row]['instancecount'];
+        sitecount = rows[row]['sitecount'];
+        actualEntries.push(['<a href="http://{{request.get_host}}/admin/core/slice/' + sliceid + '">' + slicename + '</a>',
+                            role, instancecount, sitecount]);
+    }
+    oTable = $('#dynamicusersliceinfo').dataTable( {
+        "bJQueryUI": true,
+        "aaData":  actualEntries ,
+        "bStateSave": true,
+        "aoColumns": [
+            { "sTitle": "Slice" },
+            { "sTitle": "Privilege" , sClass: "alignCenter"},
+            { "sTitle": "Number of Instances" , sClass: "alignCenter"},
+            { "sTitle": "Number of Sites" , sClass: "alignCenter"},
+        ]
+    } );
+
+    // If the filter had focus, reapply here
+
+    setTimeout(function() {
+       jQuery.ajax({
+           url: '/hpcdashuserslices',
+           dataType: 'json',
+           success: function(data){ createUserSliceTable(data); },
+           complete: function(){ },
+       });
+    },  10000);
+}
+
+function initTable(){
+    log.debug("Initializing Table")
+    jQuery.ajax({
+        url: '/hpcdashuserslices',
+        dataType: 'json',
+        success: function(data){ createUserSliceTable(data); },
+        complete: function(){
+        }
+    });
+    updateUserSliceTable();
+}
+
+
+initTable();
+
+</script>
diff --git a/xos/templates/admin/dashboard/hpc_historical.html b/xos/templates/admin/dashboard/hpc_historical.html
new file mode 100644
index 0000000..2e3b85e
--- /dev/null
+++ b/xos/templates/admin/dashboard/hpc_historical.html
@@ -0,0 +1,303 @@
+
+    <script type="text/javascript" src="//www.google.com/jsapi"></script>
+    <link rel="stylesheet" href="/static/hpc_historical.css">
+    <script type="text/javascript">
+		google.load('visualization', '1', {'packages' : ['controls','table','corechart','geochart']});
+    </script>
+
+    <script type="text/javascript">
+
+     var options = {
+
         width: 600,
+         height: 400,
+         showRowNumber: false,
+         pages: true,
+         numRows: 9,
+         backgroundColor: "black"
+     };
+
+     // ask django for a data source URL to use for the graphs
+
+     function updateDataSourceUrl() {
+         var sliceName = $("#historical_slicename :selected").text();
+         var queryString = "/analytics/bigquery/?timeBucket=600&maxAge=86400&sum=@bytes_sent&avg=@cpu&groupBy=Time,city,@hostname,@site&slice=" + sliceName;
+
+         $( "#control1").html("");
+         $( "#control2").html("");
+         $( "#chart-site-agg" ).html("<div class='loading'>Loading ...</div>");
+         $( "#chart-site-time" ).html("");
+         $( "#chart-geo" ).html("");
+
+         $.ajax({
+             url: queryString,
+             dataType: 'json',
+             type: 'GET',
+             success: function (newData) {
+                 sendAndDraw(newData["dataSourceUrl"])
+             }
+         });
+     }
+
+     TIME_COL = 0;
+     BANDWIDTH_COL = 2;
+     CPU_COL = 1;
+     CITY_COL = 3;
+     NODE_COL = 4;
+     SITE_COL = 5;
+
+     google.setOnLoadCallback(function () {
+         $('#historical_slicename').change(function()
+         {
+             updateDataSourceUrl();
+         });
+
+         updateDataSourceUrl();
+     });
+
+     function showSiteTimeAgg(dt) {
+         var lineChart = new google.visualization.ChartWrapper({
+             'chartType': 'LineChart',
+             'containerId': 'chart-site-time',
+             'options': {
+                 'width': 320,
+                 'height': 300,
+                 'title': 'Network-wide usage',
+                 'pages': true,
+                 'numRows': 9
+             },
+             'view': {
+                 'columns': [0, 1, 2]
+             }
+         });
+         lineChart.setDataTable(dt);
+         lineChart.draw();
+     }
+
+     function showSiteAgg(dt) {
+         var barChart = new google.visualization.ChartWrapper({
+             'chartType': 'ColumnChart',
+             'containerId': 'chart-site-agg',
+             'options': {
+                 'width': 670,
+                 'height': 300,
+                 'title': 'Site-wise usage',
+                 'pages': true,
+                 'numRows': 9
+             },
+             'view': {
+                 'columns': [1, 2, 3]
+             }
+         });
+         barChart.setDataTable(dt);
+         barChart.draw();
+         var geoChart = new google.visualization.ChartWrapper({
+             'chartType': 'GeoChart',
+             'containerId': 'chart-geo',
+             'options': {
+                 'width': 320,
+                 'height': 300,
+                 'displayMode': 'markers',
+                 'region': '021',
+                 'title': 'Usage map',
+                 colorAxis: {
+                     colors: ['green', 'purple', 'red']
+                 }
+             },
+             'view': {
+                 'columns': [0, 2, 3]
+             }
+         });
+         geoChart.setDataTable(dt);
+         geoChart.draw();
+     }
+
+     function handleResponse(response) {
+         var timeSlider = new google.visualization.ControlWrapper({
+             'controlType': 'DateRangeFilter',
+             'containerId': 'control1',
+             'options': {
+                 'filterColumnLabel': 'Time',
+                 ui: {
+                     ticks: 10,
+                     step: "minute"
+                 }
+             }
+         });
+
+         var categoryPicker = new google.visualization.ControlWrapper({
+             'controlType': 'CategoryFilter',
+             'allowMultiple': true,
+             'containerId': 'control2',
+             'options': {
+                 'filterColumnLabel': 'site',
+                 'ui': {
+                     'labelStacking': 'vertical',
+                     'allowTyping': false
+                 }
+             }
+         });
+
+         var proxy = new google.visualization.ChartWrapper({
+             'chartType': 'Table',
+             'containerId': 'chart7',
+             'options': {
+                 'width': 800,
+                 'height': 300,
+                 pageSize: 5,
+                 page: 'enable',
+                 'legend': 'none',
+                 'title': 'Nodes'
+             },
+             'view': {
+                 'columns': [0, 1, 2, 3, 4, 5]
+             }
+         });
+
+         function avg_bandwidth(arr) {
+                var ret = 0;
+                for (var i = 0; i < arr.length; i++) {
+                        ret+=arr[i]*8.0/1024.0/1024.0/1024.0;
+                }
+                if (arr.length==0) {
+                    return 0;
+                }
+                return ret/arr.length;
+         }
+
+         function sum_bytes_sent_as_bw(arr) {
+                var ret = 0;
+                for (var i = 0; i < arr.length; i++) {
+                        ret+=arr[i]*8.0/1024.0/1024.0/1024.0;
+                }
+                return ret/60.0;
+         }
+
+         function sum_bytes_sent_as_GB(arr) {
+                var ret = 0;
+                for (var i = 0; i < arr.length; i++) {
+                        ret+=arr[i]/1024.0/1024.0/1024.0;
+                }
+                return ret;
+         }
+
+         function fixDate2(unixDate) {
+             // not completely sure why we have to do this, as the data was in
+             // javascript Date() objects to start with. If we don't do it,
+             // then the horizontal axis will be blank.
+             return new Date(unixDate);
+         }
+
+         var format0dp = new google.visualization.NumberFormat({fractionDigits:0});
+         var format2dp = new google.visualization.NumberFormat({fractionDigits:2});
+
+         if (response.isError()) {
+             $( "#chart-site-agg" ).html("<div class='loading'>Error while fetching data.</div>");
+             return;
+         }
+
+         if (response.getDataTable().getNumberOfRows() == 0) {
+             $( "#chart-site-agg" ).html("<div class='loading'>No data for this slice.</div>");
+             return;
+         }
+
+         // Create a group for charts that will have a horizontal axis that is
+         // time.
+
+         google.visualization.events.addListener(proxy, 'ready', function () {
+             var dt = proxy.getDataTable();
+             var groupedData1 = google.visualization.data.group(dt, [{
+                 column: TIME_COL,
+                 type: 'datetime',
+                 modifier: fixDate2,
+             }], [{
+                 column: CPU_COL,
+                 type: 'number',
+                 label: "avg cpu",
+                 aggregation: google.visualization.data.avg
+             }, {
+                 column: BANDWIDTH_COL,
+                 type: 'number',
+                 label: "Gbps",
+                 aggregation: sum_bytes_sent_as_bw
+             }]);
+
+             format0dp.format(groupedData1,1);
+             format2dp.format(groupedData1,2);
+
+             showSiteTimeAgg(groupedData1);
+         });
+
+         // Create a group for charts that will have a horizontal axis that is
+         // city or site.
+
+         google.visualization.events.addListener(proxy, 'ready', function () {
+             var dt = proxy.getDataTable();
+             var groupedData0 = google.visualization.data.group(dt, [CITY_COL, SITE_COL], [{
+                 column: CPU_COL,
+                 type: 'number',
+                 label: 'avg cpu',
+                 aggregation: google.visualization.data.avg
+             }, {
+                 column: BANDWIDTH_COL,
+                 type: 'number',
+                 label: "GB sent",
+                 aggregation: sum_bytes_sent_as_GB
+             }]);
+
+             format0dp.format(groupedData0,2);
+             format2dp.format(groupedData0,3);
+
+             showSiteAgg(groupedData0);
+         });
+
+         data = response.getDataTable();
+         new google.visualization.Dashboard(document.getElementById('dashboard')).
+         // Establish bindings, declaring the both the slider and the category
+         // picker will drive both charts.
+         bind([categoryPicker, timeSlider], [proxy]).
+         // Draw the entire dashboard.
+         draw(data);
+
+     }
+
+     function sendAndDraw(queryString) {
+         query = new google.visualization.Query(queryString)
+         query && query.abort();
+         query.send(function (response) {
+             handleResponse(response);
+         });
+     }
+
+    </script>
+    <div id="dashboard" class="graph_container">
+                <div class="row">
+                        <span><b>Slice Name:</b></span>
+                        <span><select id="historical_slicename">
+                        {% for slice in userSliceInfo %}
+                           <option value="{{ slice.slicename }}">{{ slice.slicename }}</option>
+                        {% endfor %}
+                        </select></span>
+                </div>
+		<div class="row" dstyle="background-color:red">
+			<div class="col-md-12">
+				<div class="col-md-4" id="control2"></div>
+				<div class="col-md-4" id="control1"></div>
+				<!--<div class="col-md-4" id="control3"></div>-->
+			</div>
+		</div>
+		<div class="row" dstyle="background-color:green">
+			<div class="col-md-12">
+				<div class="col-md-fullgraph" id="chart-site-agg" dstyle="background-color:pink">
+				</div>
+			</div>
+		</div>
+		<div class="row" dstyle="background-color:blue">
+			<div class="col-md-12">
+				<div class="col-md-halfgraph" id="chart-site-time" dstyle="background-color:orange">
+				</div>
+				<div class="col-md-halfgraph" id="chart-geo" dstyle="background-color:yellow">
+				</div>
+			</div>
+		</div>
+    </div>
+	<div id="chart7" style="display:none"></div>
diff --git a/xos/templates/admin/dashboard/shell.html b/xos/templates/admin/dashboard/shell.html
new file mode 100644
index 0000000..8761f22
--- /dev/null
+++ b/xos/templates/admin/dashboard/shell.html
@@ -0,0 +1,32 @@
+  <div id="terminal">
+    <p class="response">XSH - The XOS Shell</p>
+    <br />
+    <p id="terminal_help1" style="display: none;">type "help" for help</p>
+    <p id="terminal_help2" style="display: none;">type "tutorial" to start the tutorial</p>
+    <p id="terminal_wait">Please wait while we talk to the XOS server...</p>
+
+  </div>
+  <link rel="stylesheet" type="text/css" href="{% static 'shell/opencloud_shell.css' %}" media="all">
+  <script src="{% static 'shell/opencloud.js' %}"></script>
+  <script src="{% static 'shell/opencloud_shell.js' %}"></script>
+  <script src="{% static 'shell/object_id.js' %}"></script>
+  <script src="{% static 'shell/constants.js' %}"></script>
+  <script src="{% static 'shell/utils.js' %}"></script>
+  <script src="{% static 'shell/shell_utils.js' %}"></script>
+  <script src="{% static 'shell/tokens.js' %}"></script>
+
+
+    <!-- script type="text/javascript" src="js/jquery-1.3.2.min.js"></script-->
+
+    <!-- script type="text/javascript" src="js/mongo.js"></script -->
+    <!-- script type="text/javascript" src="js/object_id.js"></script -->
+    <!-- script type="text/javascript" src="js/lib/collection.js"></script -->
+
+    <!-- script type="text/javascript" src="js/constants.js"></script -->
+    <!-- script type="text/javascript" src="js/connection.js"></script -->
+
+    <!-- script type="text/javascript" src="js/utils.js"></script -->
+    <!-- script type="text/javascript" src="js/shell_utils.js"></script-->
+    <!-- script type="text/javascript" src="js/tokens.js"></script -->
+
+
diff --git a/xos/templates/admin/dashboard/slice_interactions.html b/xos/templates/admin/dashboard/slice_interactions.html
new file mode 100644
index 0000000..3b335f5
--- /dev/null
+++ b/xos/templates/admin/dashboard/slice_interactions.html
@@ -0,0 +1,503 @@
+<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+<style>
+#slice_interaction_chart_placeholder {
+    text-align: center;
+    color:#fff;
+    position: relative;
+    height: 100%;
+    width: 100%;
+}
+.dependencyWheel {
+    font: 10px sans-serif;
+}
+form .btn-primary {
+    margin-top: 25px;
+}
+.labeltext {
+    color: #fff;
+}
+#circle circle {
+    fill: none;
+    pointer-events: all;
+}
+path.chord {
+    stroke: #000;
+    stroke-width: .10px;
+    transition: opacity 0.3s;
+}
+#circle:hover path.fade {
+    opacity: 0;
+}
+a {
+    text-decoration: none;
+    border-bottom: 1px dotted #666;
+    color: #999;
+}
+.more a {
+    color: #666;
+}
+.by a {
+    color: #fff;
+}
+a:hover {
+    color: #45b8e2;
+}
+a:not(:hover) {
+    text-decoration: none;
+}
+text {
+    fill: black;
+}
+svg {
+    font-size: 12px;
+    font-weight: bold;
+    color: #999;
+    font-family:'Arial', sans-serif;
+    min-height: 100%;
+    min-width: 100%;
+}
+button:disabled {
+    color:red;
+    background-color: lightyellow;
+}
+.sliceinteractions_column {
+  display: table-cell;

+  padding: 10px;

+}
+#interactions_function {
+  width: 125px;
+}
+
+</style>
+
+<div class="row">
+    <div class="sliceinteractions_column">
+    <select id="interactions_function">
+        <option value="networks">networks</option>
+        <option value="users">users</option>
+        <option value="owner sites">sites</option>
+        <option value="instance_sites">instance_sites</option>
+        <option value="instance_nodes">instance_nodes</option>
+    </select>
+    </div>
+    <div class="sliceinteractions_column">
+    <h3 id="sliceEngagementTitle">Slice Interactions</h3>
+    </div>
+</div>
+
+<div id="slice_interaction_chart_placeholder"></div>
+
+<script>
+
+// Chord Diagram for showing Collaboration between users found in an anchor query
+// Collaboration View
+//
+
+var width = 600,
+    height = 600,
+    outerRadius = Math.min(width, height) / 2 - 100,
+    innerRadius = outerRadius - 18;
+
+//create number formatting functions
+var formatPercent = d3.format("%");
+var numberWithCommas = d3.format("0,f");
+
+//define the default chord layout parameters
+//within a function that returns a new layout object;
+//that way, you can create multiple chord layouts
+//that are the same except for the data.
+function getDefaultLayout() {
+    return d3.layout.chord()
+    .sortSubgroups(d3.descending)
+    .sortChords(d3.ascending);
+}
+var last_layout; //store layout between updates
+var g;
+var arc;
+var path;
+
+function init_visualization() {
+    arc = d3.svg.arc()
+        .innerRadius(innerRadius)
+        .outerRadius(outerRadius);
+
+    path = d3.svg.chord()
+        .radius(innerRadius);
+
+
+    /*** Initialize the visualization ***/
+    g = d3.select("#slice_interaction_chart_placeholder").append("svg")
+            .attr("width", width)
+            .attr("height", height)
+        .append("g")
+            .attr("id", "circle")
+            .attr("transform",
+                  "translate(" + width / 2 + "," + height / 2 + ")");
+    //the entire graphic will be drawn within this <g> element,
+    //so all coordinates will be relative to the center of the circle
+
+    g.append("circle")
+        .attr("r", outerRadius);
+}
+
+$( document ).ready(function() {
+    init_visualization();
+    $('#interactions_function').change(function() {
+         updateInteractions();
+     });
+    updateInteractions();
+});
+
+function updateInteractions() {
+ $( "#sliceEngagementTitle" ).html("<h3>Loading...</h3>");
+ $.ajax({
+    url : "/admin/sliceinteractions/" + $("#interactions_function :selected").text() + "/",
+    dataType : 'json',
+    type : 'GET',
+    success: function(newData)
+    {
+        $( "#sliceEngagementTitle" ).html("<h3>" + newData["title"] + "</h3>");
+        updateChords(newData["groups"], newData["matrix"], newData["objectName"])
+    }
+   });
+}
+
+
+/* Create OR update a chord layout from a data matrix */
+function updateChords( users, matrix, objectName ) {
+
+    /* Compute chord layout. */
+    layout = getDefaultLayout(); //create a new layout object
+    layout.matrix(matrix);
+ 
+    /* Create/update "group" elements */
+    var groupG = g.selectAll("g.group")
+        .data(layout.groups(), function (d) {
+            return d.index; 
+            //use a key function in case the 
+            //groups are sorted differently between updates
+        });
+    
+    groupG.exit()
+        .transition()
+            .duration(1500)
+            .attr("opacity", 0)
+            .remove(); //remove after transitions are complete
+
+    var newGroups = groupG.enter().append("g")
+        .attr("class", "group");
+    //the enter selection is stored in a variable so we can
+    //enter the <path>, <text>, and <title> elements as well
+
+    
+    //Create the title tooltip for the new groups
+    newGroups.append("title");
+    
+    //Update the (tooltip) title text based on the data
+    groupG.select("title")
+        .text(function(d, i) {
+            return "Slice (" + users[i].name +
+                ") "
+                ;
+        });
+
+    //create the arc paths and set the constant attributes
+    //(those based on the group index, not on the value)
+    newGroups.append("path")
+        .attr("id", function (d) {
+            return "group" + d.index;
+            //using d.index and not i to maintain consistency
+            //even if groups are sorted
+        })
+        .style("fill", function (d) {
+            return users[d.index].color;
+        });
+    
+    //update the paths to match the layout
+    groupG.select("path") 
+        .transition()
+            .duration(1500)
+            .attr("opacity", 0.5) //optional, just to observe the transition
+        .attrTween("d", arcTween( last_layout ))
+       //     .transition().duration(100).attr("opacity", 1) //reset opacity
+        ;
+    
+    //create the group labels
+    newGroups.append("svg:text")
+        .attr("xlink:href", function (d) {
+            return "#group" + d.index;
+        })
+        .attr("dy", ".35em")
+        .attr("color", "#fff")
+        .text(function (d) {
+            return users[d.index].name;
+        });
+
+    //position group labels to match layout
+    groupG.select("text")
+        .transition()
+            .duration(1500)
+            .attr("transform", function(d) {
+                d.angle = (d.startAngle + d.endAngle) / 2;
+                //store the midpoint angle in the data object
+                
+                return "rotate(" + (d.angle * 180 / Math.PI - 90) + ")" +
+                    " translate(" + (innerRadius + 26) + ")" + 
+                    (d.angle > Math.PI ? " rotate(180)" : " rotate(0)"); 
+                //include the rotate zero so that transforms can be interpolated
+            })
+            .attr("text-anchor", function (d) {
+                return d.angle > Math.PI ? "end" : "begin";
+            });
+    
+    
+    /* Create/update the chord paths */
+    var chordPaths = g.selectAll("path.chord")
+        .data(layout.chords(), chordKey );
+            //specify a key function to match chords
+            //between updates
+        
+    
+    //create the new chord paths
+    var newChords = chordPaths.enter()
+        .append("path")
+        .attr("class", "chord");
+    
+    // Add title tooltip for each new chord.
+    newChords.append("title");
+    
+    // Update all chord title texts
+    chordPaths.select("title")
+        .text(function(d) {
+            if (users[d.target.index].name !== users[d.source.index].name) {
+                return [numberWithCommas(d.source.value),
+                        " " + objectName + " in common between \n",
+                        users[d.source.index].name,
+                        " and ",
+                        users[d.target.index].name,
+                        "\n"
+                        ].join("");
+                    //joining an array of many strings is faster than
+                    //repeated calls to the '+' operator,
+                    //and makes for neater code!
+            }
+            else { //source and target are the same
+                return numberWithCommas(d.source.value)
+                    + " " + objectName + " are only in Slice ("
+                    + users[d.source.index].name + ")";
+            }
+        });
+
+    //handle exiting paths:
+    chordPaths.exit().transition()
+        .duration(1500)
+        .attr("opacity", 0)
+        .remove();
+
+    //update the path shape
+    chordPaths.transition()
+        .duration(1500)
+        //.attr("opacity", 0.5) //optional, just to observe the transition
+        .style("fill", function (d) {
+            return users[d.source.index].color;
+        })
+        .attrTween("d", chordTween(last_layout))
+        //.transition().duration(100).attr("opacity", 1) //reset opacity
+    ;
+
+    // XXX SMBAKER: The way the text was added with newGroups, it's only
+    //   computed when a node is created. This is a problem if we redraw the
+    //   graph with a different set of nodes, because the old labels will
+    //   stick. So, I added this, which *seems* to cause the labels to be
+    //   recomputed.
+    groupG.selectAll("text")
+        .text(function (d) {
+            return users[d.index].name;
+        });
+
+    //add the mouseover/fade out behaviour to the groups
+    //this is reset on every update, so it will use the latest
+    //chordPaths selection
+    groupG.on("mouseover", function(d) {
+        chordPaths.classed("fade", function (p) {
+            //returns true if *neither* the source or target of the chord
+            //matches the group that has been moused-over
+            return ((p.source.index != d.index) && (p.target.index != d.index));
+        });
+    });
+    //the "unfade" is handled with CSS :hover class on g#circle
+    //you could also do it using a mouseout event:
+    /*
+    g.on("mouseout", function() {
+        if (this == g.node() )
+            //only respond to mouseout of the entire circle
+            //not mouseout events for sub-components
+            chordPaths.classed("fade", false);
+    });
+    */
+
+    // XXX smbaker: there's a bug where if you hilight a slice of the chord
+    //   graph, and then update the data, the freshly drawn graph is missing
+    //   some of the chords. Flipping the fade bit seems to fix that.
+    chordPaths.classed("fade", true);
+    chordPaths.classed("fade", false);
+
+    last_layout = layout; //save for next update
+    
+//  }); //end of d3.json
+}
+
+function arcTween(oldLayout) {
+    //this function will be called once per update cycle
+    
+    //Create a key:value version of the old layout's groups array
+    //so we can easily find the matching group 
+    //even if the group index values don't match the array index
+    //(because of sorting)
+    var oldGroups = {};
+    if (oldLayout) {
+        oldLayout.groups().forEach( function(groupData) {
+            oldGroups[ groupData.index ] = groupData;
+        });
+    }
+    
+    return function (d, i) {
+        var tween;
+        var old = oldGroups[d.index];
+        if (old) { //there's a matching old group
+            tween = d3.interpolate(old, d);
+        }
+        else {
+            //create a zero-width arc object
+            var emptyArc = {startAngle:d.startAngle,
+                            endAngle:d.startAngle};
+            tween = d3.interpolate(emptyArc, d);
+        }
+        
+        return function (t) {
+            return arc( tween(t) );
+        };
+    };
+}
+
+function chordKey(data) {
+    return (data.source.index < data.target.index) ?
+        data.source.index  + "-" + data.target.index:
+        data.target.index  + "-" + data.source.index;
+    
+    //create a key that will represent the relationship
+    //between these two groups *regardless*
+    //of which group is called 'source' and which 'target'
+}
+function chordTween(oldLayout) {
+    //this function will be called once per update cycle
+    
+    //Create a key:value version of the old layout's chords array
+    //so we can easily find the matching chord 
+    //(which may not have a matching index)
+    
+    var oldChords = {};
+    
+    if (oldLayout) {
+        oldLayout.chords().forEach( function(chordData) {
+            oldChords[ chordKey(chordData) ] = chordData;
+        });
+    }
+    
+    return function (d, i) {
+        //this function will be called for each active chord
+        
+        var tween;
+        var old = oldChords[ chordKey(d) ];
+        if (old) {
+            //old is not undefined, i.e.
+            //there is a matching old chord value
+            
+            //check whether source and target have been switched:
+            if (d.source.index != old.source.index ){
+                //swap source and target to match the new data
+                old = {
+                    source: old.target,
+                    target: old.source
+                };
+            }
+            
+            tween = d3.interpolate(old, d);
+        }
+        else {
+            //create a zero-width chord object
+/*          XXX SMBAKER: the code commented out below was causing an error,
+                  so I replaced it with the following code from stacktrace
+            if (oldLayout) {
+                var oldGroups = oldLayout.groups().filter(function(group) {
+                        return ( (group.index == d.source.index) ||
+                                 (group.index == d.target.index) )
+                    });
+                old = {source:oldGroups[0],
+                           target:oldGroups[1] || oldGroups[0] };
+                    //the OR in target is in case source and target are equal
+                    //in the data, in which case only one group will pass the
+                    //filter function
+
+                if (d.source.index != old.source.index ){
+                    //swap source and target to match the new data
+                    old = {
+                        source: old.target,
+                        target: old.source
+                    };
+                }
+            }
+            else old = d;
+
+            var emptyChord = {
+                source: { startAngle: old.source.startAngle,
+                         endAngle: old.source.startAngle},
+                target: { startAngle: old.target.startAngle,
+                         endAngle: old.target.startAngle}
+            };
+            tween = d3.interpolate( emptyChord, d );*/
+
+            //create a zero-width chord object
+            var emptyChord = {

+                source: { startAngle: d.source.startAngle,

+                         endAngle: d.source.startAngle},

+                target: { startAngle: d.target.startAngle,

+                         endAngle: d.target.startAngle}

+            };

+            tween = d3.interpolate( emptyChord, d );
+        }
+
+        return function (t) {
+            //this function calculates the intermediary shapes
+            return path(tween(t));
+        };
+    };
+}
+
+
+/* Activate the buttons and link to data sets */
+d3.select("#ReadersButton").on("click", function () {
+    updateChords( "#readinfo" );
+    //replace this with a file url as appropriate
+    
+    //enable other buttons, disable this one
+    disableButton(this);
+});
+
+d3.select("#ContributorsButton").on("click", function() {
+    updateChords( "#contributorinfo" );
+    disableButton(this);
+});
+
+d3.select("#AllUsersButton").on("click", function() {
+    updateChords( "#allinfo" );
+    disableButton(this);
+});
+function disableButton(buttonNode) {
+    d3.selectAll("button")
+        .attr("disabled", function(d) {
+            return this === buttonNode? "true": null;
+        });
+}
+
+</script>
diff --git a/xos/templates/admin/dashboard/tenant.html b/xos/templates/admin/dashboard/tenant.html
new file mode 100644
index 0000000..0fd627e
--- /dev/null
+++ b/xos/templates/admin/dashboard/tenant.html
@@ -0,0 +1,662 @@
+<!doctype html>
+<script type="text/javascript" src="http://www.google.com/jsapi"></script>
+<div id="dialog-form" title="Add/Remove Instances" style="display: none;">
+	<form>
+		<fieldset>
+			<label for="numberOfInstances">Number of Instances</label>
+			<input type="text" name="numberOfInstances" id="numOfInstances" class="text ui-widget-content ui-corner-all">
+			<div id=basic-tooltip>Please enter number of instances</div>
+		</fieldset>
+	</form>
+</div>
+<div id="adv-dialog-form" title="Add/Remove Instances" style="display: none;">
+	<form>
+		<fieldset>
+			<label for="numberOfInstances">Number of Instances</label>
+			<input type="text" name="numberOfInstances" id="advNumOfInstances" class="text ui-widget-content ui-corner-all">
+			<div id=adv-tooltip>Please enter number of instances</div>
+		</fieldset>
+	</form>
+</div>
+<div id="add-user-form" title="Add User" style="display: none;">
+        <form>
+                <fieldset>
+			<div class="create-slice-row">
+                                <label for="add-slice-user">Add User</label>
+                                <select id="add-slice-user" class="tenant-create-slice"></select>
+                        </div>
+                </fieldset>
+        </form>
+</div>
+<div id="create-slice-form" title="Create New Slice" style="display: none;">
+	<form>
+		<fieldset>
+			<div class="create-slice-row">
+				<label for="new-slice-name">Name</label>
+				<input type="text" name="new-slice-name" id="new-slice-name">
+			</div>
+			<div class="create-slice-row">
+				<label for="new-service-class">Service Class</label>
+				<select id="new-service-class" class="tenant-create-slice"></select>
+			</div>
+			<div class="create-slice-row">
+				<label for="new-image">Image</label>
+				<select id="new-image" class="tenant-create-slice"></select>
+			</div>
+			<div class="create-slice-row">
+                                <label for="new-network">Network Ports</label>
+				<input type="text" name="new-network" id="new-network">
+                        </div>
+			<div class="create-slice-row">
+				<label for="private-vol">Include Private Vol</label>
+				<input type="checkbox" name="checkbox" id="private-vol" value="value">
+			</div>
+			<div class="create-slice-row">
+                                <label for="add-user">Add User</label>
+                                <select id="add-user" class="tenant-create-slice"></select>
+                        </div>
+			<div class="create-slice-row">
+                                <label for="mount-data-sets">Data Set</label>
+                                <select id="mount-data-sets" class="tenant-create-slice"></select>
+                        </div>
+			<div class="create-slice-row">
+                                <label for="number-of-instances">Number Of Instances</label>
+                                <input type="text" name="number-of-instances" id="number-of-instances">
+                        </div>
+			<div id=tooltip>Slice Name cannot be empty</div>
+		</fieldset>
+	</form>
+</div>
+<div id="delete-slice-form" title="Delete a  Slice" style="display: none;">
+	<form>
+		<fieldset>
+			<div class="create-slice-row">
+				<label for="delete-slice">Choose a Slice</label>
+				<select id="delete-slice"></select>
+			</div>
+		</fieldset>
+	</form>
+</div>
+<script type="text/javascript">
+	google.load('visualization', '1', {
+		'packages': ['controls', 'table', 'corechart', 'geochart']
+	});
+	</script>
+	<script>
+	$(document).ready(function () {
+		function showSliceData(rows,imageData,serviceLevelData,siteRows,dataSet,value) {
+			$("#service-level-value").empty();
+			$("#slice-image-value").empty();
+			$("#tenantSiteTable").empty();
+			$('#tenantSiteTable').html('<table cellpadding="0" cellspacing="0" border="0" class="display" id="tenantSiteTableData"></table>');
+			$("#tenantSliceDropDown").val(value);
+			var siteNames = [];
+			var instanceCount;
+			for (row in rows) {
+				if (rows[row]['sliceName'] == value) {
+					sliceImageData = rows[row]['preferredImage'];
+					$("#slice-image-value").html(sliceImageData);
+					serviceLevelDataBasic = rows[row]['sliceServiceClass'];
+					$("#service-level-value").html(serviceLevelDataBasic);
+					var innerRows = rows[row]['sliceSite'];
+					for (innerRow in innerRows) {
+						instanceCount = innerRows[innerRow];
+						siteNames.push([innerRow, instanceCount]);
+					}
+				}
+			}
+			oTable = $('#tenantSiteTableData').dataTable({
+				"bJQueryUI": true,
+				"bFilter": false,
+				"bInfo": false,
+				"bLengthChange": false,
+				"aaData": siteNames,
+				"bStateSave": true,
+				"aoColumns": [{
+						"sTitle": "Site Name"
+					}, {
+						"sTitle": "Allocated",
+						sClass: "alignCenter"
+					}
+				]
+			});
+				$('#tenantSliceDropDown').on('change', function () {
+					var value = $("#tenantSliceDropDown").val();
+	//alert(value);
+					checkForBasicAdvView(value,rows,imageData,serviceLevelData,siteRows,dataSet);
+				});
+		}
+
+		function downloadSliceInfo(rows,imageData,serviceLevelData,siteRows,dataSet,value){
+			 $("#download-details").unbind().click(function(){
+                                                function download(filename, text) {
+    						var sliceDetails = document.createElement('a');
+    						sliceDetails.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
+    						sliceDetails.setAttribute('download', filename);
+    						sliceDetails.click();
+					}
+					var sliceInfo;
+					for (row in rows){
+						if(rows[row]['sliceName']==value){
+							sliceInfo = "Slice Name: "+rows[row]['sliceName']+"\nNumber of Instances: "+rows[row]['numOfInstances']+"\nService Level: "+rows[row]['sliceServiceClass']+"\nImage: "+rows[row]['preferredImage']+"\n";	
+						for (instanceNodePairs in rows[row]['instanceNodePair']){
+							sliceInfo += instanceNodePairs+"@"+rows[row]['instanceNodePair'][instanceNodePairs]+"\n";
+						}
+						}
+					}
+					download('slice.txt', sliceInfo);
+                          });
+		}
+		function editInstanceAdv() {
+			$(".edit-view").click(function () {
+				var allocatedInstances = parseInt($(this).parent().siblings(".allocated").html());
+				var td = $(this).parent().siblings(".allocated");
+				var pos = oTable.fnGetPosition(td[0]);
+				$("#numOfInstances").val("");;
+				$("#advNumOfInstances").val("");;
+				$("#adv-tooltip").css("display", "none");
+				$("#adv-dialog-form").dialog({
+					autoOpen: false,
+					height: 200,
+					width: 350,
+					modal: true,
+					dialogClass: "tenantDialog",
+					buttons: {
+						"Add": function () {
+							allocatedInstances += parseInt($("#advNumOfInstances").val());
+								$("#adv-tooltip").css("display", "block");
+								$(this).dialog("close");
+								td.html(allocatedInstances);
+						},
+						"Remove": function () {
+							allocatedInstances -= parseInt($("#advNumOfInstances").val());
+								$("#adv-tooltip").css("display", "block");
+								$(this).dialog("close");
+								td.html(allocatedInstances);
+						}
+					}
+				});
+				$("#adv-dialog-form").dialog("open");
+			});
+		}
+
+		function advShowSliceData(rows,imageData,serviceLevelData,siteRows,dataSet,value) {
+			$("#adv-service-level-value").empty();
+			$("#adv-slice-image-value").empty();
+			$("#adv-slice-data-set-value").empty();
+			$("#advTenantSliceDropDown").val(value);
+			$("<select></select>").attr('id', 'adv-service-level-dropdown').appendTo('#adv-service-level-value');
+			$("<select></select>").attr('id', 'adv-image-dropdown').appendTo('#adv-slice-image-value');
+			$("<select></select>").attr('id', 'adv-dataset-dropdown').appendTo('#adv-slice-data-set-value');
+			$('#advTenantSiteTable').html('<table cellpadding="0" cellspacing="0" border="0" class="display" id="advTenantSiteTableData"></table>');
+			var siteNames = [];
+			var instanceCount;
+			var tableData = {};
+			for (row in serviceLevelData) {
+                                $("#adv-service-level-dropdown").append("<option>" + serviceLevelData[row]['serviceClass'] + "</option>");
+                        }
+                        for (row in imageData) {
+                                $("#adv-image-dropdown").append("<option>" + imageData[row] + "</option>");
+                        }
+                        for (row in dataSet) {
+                                $("#adv-dataset-dropdown").append("<option>" + dataSet[row]['DataSet'] + "</option>");
+                        }
+
+			for (row in rows) {
+				if (rows[row]['sliceName'] == value) {
+					var innerRows = rows[row]['sliceSite'];
+					$("#adv-service-level-dropdown").val(rows[row]['sliceServiceClass']);
+					$("#adv-image-dropdown").val(rows[row]['preferredImage']);
+					$("#adv-dataset-dropdown").val(rows[row]['sliceDataSet']);
+					for (innerRow in innerRows) {
+						tableData[innerRow] = innerRows[innerRow];
+					}
+				}
+			}
+			for (row in siteRows) {
+				//var entry = siteRows[row]['siteName'];
+				var entry = siteRows[row];
+				if (!(entry in tableData)) {
+					//tableData[siteRows[row]['siteName']] = 0;
+					tableData[siteRows[row]] = 0;
+				}
+			}
+			for (row in tableData) {
+				siteNames.push([row, tableData[row], '<a href="#" class="edit-view">Edit</a>']);
+			}
+			$("#save-btn").unbind().click(function () {
+				var newTableData = {};
+				var newSite = $(".siteName");
+				var newAllocated = $(".allocated");
+				for (i = 1; i < newSite.length; i++) {
+					newTableData[$($(".siteName")[i]).text()] = parseInt($($(".allocated")[i]).text());
+				}
+				for (newRow in newTableData) {
+					if (newTableData[newRow] > tableData[newRow]) {
+						$.ajax({
+							url: '/tenantaddorreminstance/',
+							dataType: 'json',
+							data: {
+								siteName: newRow,
+								count: newTableData[newRow] - tableData[newRow],
+								slice: $("#advTenantSliceDropDown").val(),
+								image: $("#adv-image-dropdown").val(),
+								actionToDo: "add",
+								csrfmiddlewaretoken: "{{ csrf_token }}", // < here 
+								state: "inactive"
+							},
+							type: 'POST',
+							complete: function () {
+								//location.reload();
+								
+                                                        }
+						});
+					} else if (newTableData[newRow] < tableData[newRow]) {
+						$.ajax({
+							url: '/tenantaddorreminstance/',
+							dataType: 'json',
+							data: {
+								siteName: newRow,
+								count: tableData[newRow] - newTableData[newRow],
+								slice: $("#advTenantSliceDropDown").val(),
+								image: $("#adv-image-dropdown").val(),
+								actionToDo: "rem",
+								csrfmiddlewaretoken: "{{ csrf_token }}", // < here
+								state: "inactive"
+							},
+							type: 'POST',
+							complete: function () {
+								//location.reload();
+                                                        }
+						});
+					}
+				}
+				 $.ajax({
+                                                        url: '/updateslice/',
+                                                        dataType: 'json',
+                                                        data: {
+                                                                sliceName: $("#advTenantSliceDropDown").val(),
+								serviceClass: $("#adv-service-level-dropdown").val(),
+								imageName: $("#adv-image-dropdown").val(),
+								dataSet: $("#adv-dataset-dropdown").val(),
+								networkPorts:  $("#adv-network-value").val(),
+								privateVolume: $("#private-vol-checkbox").is(":checked"),
+                                                                actionToDo: "update",
+                                                                csrfmiddlewaretoken: "{{ csrf_token }}", // < here
+                                                                state: "inactive"
+                                                        },
+                                                        type: 'POST',
+                                                        success: function () {
+								$("#tabs-5").empty();
+                                                                initTenant();    //location.reload();
+                                                        },
+							  error:function (xhr, textStatus, thrownError){
+         							   errorDialog("Error:", textStatus + " " + xhr.responseText);
+        						}
+							
+                                                });
+
+			});
+			oTable = $('#advTenantSiteTableData').dataTable({
+				"bJQueryUI": true,
+				"bFilter": false,
+				"bInfo": false,
+				"bLengthChange": false,
+				"bPaginate": false,
+				"aaData": siteNames,
+				"bStateSave": true,
+				"aoColumns": [{
+					"sTitle": "Site Name",
+					sClass: "siteName"
+				}, {
+					"sTitle": "Allocated",
+					sClass: "alignCenter allocated"
+				}, {
+					"sTitle": "Edit",
+					sClass: "alignCenter"
+				}]
+			});
+			editInstanceAdv();
+				$('#advTenantSliceDropDown').on('change', function () {
+					var selectedValue = $("#advTenantSliceDropDown").val();
+					checkForBasicAdvView(selectedValue, rows,imageData,serviceLevelData,siteRows,dataSet);
+				});
+		}
+
+		function checkForBasicAdvView(value, rows,imageData,serviceLevelData,siteRows,dataSet) {
+			for (row in rows) {
+				if (rows[row]['sliceName'] == value) {
+					if (rows[row]['numOfSites'] > 1) {
+						advShowSliceData(rows,imageData,serviceLevelData,siteRows,dataSet,value);
+						downloadSliceInfo(rows,imageData,serviceLevelData,siteRows,dataSet,value);
+						$("#tenantSliceDataWrapper").css("display","none");
+						$("#advancedTenantSliceDataWrapper").css("display","block");
+						$("#advTenantSiteTable").css("display","block");
+						$("#tenantSiteTable").css("display","none");
+						$("#instance-btn").css("display","none");
+						$("#save-btn").css("display","block");
+						break;
+					} else if(rows[row]['numOfSites'] <= 1){
+						showSliceData(rows,imageData,serviceLevelData,siteRows,dataSet,value);
+						downloadSliceInfo(rows,imageData,serviceLevelData,siteRows,dataSet,value);
+						$("#tenantSliceDataWrapper").css("display","block");
+						$("#advancedTenantSliceDataWrapper").css("display","none");
+						$("#advTenantSiteTable").css("display","none");
+						$("#tenantSiteTable").css("display","block");
+						$("#instance-btn").css("display","block");
+                                                $("#save-btn").css("display","none");
+						break;
+					}break;
+				}
+			}
+		}
+
+		function UserSliceTable(rows,imageData,serviceLevelData,siteRows,dataSet,siteUsers) {
+				//Add check for #dynamicusersliceinfo_filter label-> input having focus here
+				$("<div></div>").attr('id', 'tenantSliceDataWrapper').appendTo('#tabs-5');
+				$("<div></div>").attr('id', 'advancedTenantSliceDataWrapper').appendTo('#tabs-5');
+				var sliceData = '';
+				sliceData += '<div class="tenant-row public-key-warning"><span class="summary-attr">You have not uploaded your Public Key. <a href="http://{{ request.get_host}}/admin/core/user/{{user.id}}">Click here</a> to upload it now.</span></div><div class="tenant-row"><span class="summary-attr"><b>Slice Name:</b> <span id="slice-name-value"> </span> </span><br></div><div class="tenant-row"><span class="summary-attr"><b>Service Level:</b> <span id="service-level-value"> </span>  </span><br></div><div class="tenant-row"><span class="summary-attr"><b>Image:</b> <span id="slice-image-value"> </span>  </span><br></div><div class="btn btn-high btn-info" id="advanced-tenant">Go to Advanced View</div>';
+				var advSliceData = '';
+				advSliceData += '<div class="tenant-row public-key-warning"><span class="summary-attr">You have not uploaded your Public Key. <a href="http://{{ request.get_host}}/admin/core/user/{{user.id}}">Click here</a> to upload it now.</span></div><div class="adv-tenant-row"><span class="summary-attr"><b>Slice Name:</b> <span id="adv-slice-name-value"> </span> </span><br><br></div><div class="tenant-row"><span class="summary-attr"><b>Service Level:</b> <span id="adv-service-level-value"> </span> <span class="help-inline">Changes are potentially disruptive to existing instances</span> </span><br></div><div class="tenant-row"><span class="summary-attr"><b>Image:</b> <span id="adv-slice-image-value"> </span><span class="help-inline">Changes are potentially disruptive to existing instances</span>  </span><br></div><div class="tenant-row"><span class="summary-attr"><b>Network:</b> <input type="text" name="adv-network-value" id="adv-network-value"> <span class="help-inline">List of port ranges(if any) e.g. 1021-1026,1029</span><br></div><div class="tenant-row"><span class="summary-attr"><b>Data Set:</b> <span id="adv-slice-data-set-value"> </span>  <input type="checkbox" name="checkbox" id="private-vol-checkbox" value="value"><span class="help-inline">Include Private Volume</span></span></div>';
+				$('#tenantSliceDataWrapper').append(sliceData).css("display", "none");
+				$('#advancedTenantSliceDataWrapper').append(advSliceData);
+				$("#advancedTenantSliceDataWrapper").css("display", "none");
+				$("<select></select>").attr('id', 'tenantSliceDropDown').appendTo('#slice-name-value');
+				for (row in rows) {
+					$("#tenantSliceDropDown").append("<option>" + rows[row]['sliceName'] + "</option>");
+				}
+				$("<select></select>").attr('id', 'advTenantSliceDropDown').appendTo('#adv-slice-name-value');
+					for (row in rows) {
+						$("#advTenantSliceDropDown").append("<option>" + rows[row]['sliceName'] + "</option>");
+					}
+				$("<div></div>").attr('id', 'tenantSiteTable').appendTo('#tabs-5').css("display","none");
+				$("<div></div>").attr('id', 'advTenantSiteTable').appendTo('#tabs-5').css("display", "none");
+				$('<div class="btn btn-success" id="create-slice-btn"><i class="icon-plus-sign icon-white"></i>&nbsp;Create New Slice</div>').appendTo("#tabs-5");
+				$('<div class="btn btn-success" id="delete-slice-btn"><i class="icon-plus-sign icon-white"></i>&nbsp;Delete a Slice</div>').appendTo("#tabs-5");
+				$('<div class="btn btn-success" id="add-user-btn"><i class="icon-plus-sign icon-white"></i>&nbsp;Add User</div>').appendTo("#tabs-5");
+				$('<div class="btn btn-high btn-info" id="download-details">Download Slice Details</div>').appendTo("#tabs-5");
+				$('<div class="btn btn-success" id="instance-btn"><i class="icon-plus-sign icon-white"></i>&nbsp;Add/Remove Instances</div>').appendTo("#tabs-5");
+				$('<div class="btn btn-high btn-info" id="save-btn">Save</div>').appendTo("#tabs-5").css("display", "none");
+				$("#advanced-tenant").unbind().click(function () {
+					var value = $("#tenantSliceDropDown").val();
+					advShowSliceData(rows,imageData,serviceLevelData,siteRows,dataSet,value);
+                                                $("#tenantSliceDataWrapper").css("display","none");
+                                                $("#advancedTenantSliceDataWrapper").css("display","block");
+                                                $("#advTenantSiteTable").css("display","block");
+                                                $("#tenantSiteTable").css("display","none");
+                                                $("#instance-btn").toggle();
+                                                $("#save-btn").toggle();
+
+			});
+			$("#instance-btn").click(function () {
+				$("#basic-tooltip").css("display", "none");
+				$("#dialog-form").dialog({
+					autoOpen: false,
+					height: 200,
+					width: 400,
+					modal: true,
+					dialogClass: "tenantDialog",
+					buttons: {
+						"Add": function () {
+							$.ajax({
+								url: '/tenantaddorreminstance/',
+								dataType: 'json',
+								data: {
+									count: parseInt($("#numOfInstances").val()),
+									slice: $("#tenantSliceDropDown").val(),
+									image: $("#slice-image-value").html(),
+									actionToDo: "add",
+									csrfmiddlewaretoken: "{{ csrf_token }}", // < here 
+									state: "inactive"
+								},
+								type: 'POST',
+								beforeSend: function () {
+									if (!$("#numOfInstances").val()) {
+										$("#basic-tooltip").css("display", "block");
+										return false;
+									} else {
+										return true;
+									}
+								},
+								success: function () {
+									location.reload();
+$("#dialog-form").dialog("close");
+								}
+							});
+						},
+						Remove: function () {
+							$.ajax({
+								url: '/tenantaddorreminstance/',
+								dataType: 'json',
+								data: {
+									count: parseInt($("#numOfInstances").val()),
+									slice: $("#tenantSliceDropDown").val(),
+									image: $("#slice-image-value").html(),
+									actionToDo: "rem",
+									csrfmiddlewaretoken: "{{ csrf_token }}", // < here
+									state: "inactive"
+								},
+								type: 'POST',
+								beforeSend: function () {
+									if (!$("#numOfInstances").val()) {
+										$("#basic-tooltip").css("display", "block");
+										return false;
+									} else {
+										return true;
+									}
+								},
+								success: function () {
+$("#dialog-form").dialog("close");								
+location.reload();
+
+								}
+							});
+						}
+					}
+				});
+				$("#dialog-form").dialog("open");
+			});
+			$("#add-user-btn").unbind().click(function(){
+				$("#add-slice-user").empty();
+				for (row in siteUsers) {
+                                        $("#add-slice-user").append("<option>" + siteUsers[row] + "</option>");
+                                }
+				$("#add-user-form").dialog({
+                                        autoOpen: false,
+                                        height: 200,
+                                        width: 350,
+                                        modal: true,
+                                        dialogClass: "tenantDialog",
+                                        buttons: {
+                                                "Submit": function () {
+                                                        $.ajax({
+                                                                url: '/adduser/',
+                                                                dataType: 'json',
+                                                                data: {
+                                                                        sliceName: $("#advTenantSliceDropDown").val(),
+                                                                        userEmail: $("#add-slice-user").val(),
+                                                                        csrfmiddlewaretoken: "{{ csrf_token }}", // < here
+                                                                        state: "inactive"
+                                                                },
+                                                                async: false,
+                                                                type: 'POST',
+                                                                success: function () {
+                                                                        location.reload();
+                                                                }
+
+                                                        });
+                                                },
+                                                Cancel: function () {
+                                                        $(this).dialog("close");
+                                                }
+                                        }
+                                });
+                                $("#add-user-form").dialog("open");
+							
+
+			});
+			$("#create-slice-btn").unbind().click(function () {
+				$("#new-service-class").empty();
+				$("#new-image").empty();
+				$("#add-user").empty();
+				$("#mount-data-sets").empty();
+				$("#new-network").empty();
+				for (row in serviceLevelData) {
+					$("#new-service-class").append("<option>" + serviceLevelData[row]['serviceClass'] + "</option>");
+				}
+				for (row in imageData) {
+					$("#new-image").append("<option>" + imageData[row] + "</option>");
+				}
+				for (row in dataSet) {
+                                        $("#mount-data-sets").append("<option>" + dataSet[row]['DataSet'] + "</option>");
+                                }
+				for (row in siteUsers) {
+                                        $("#add-user").append("<option>" + siteUsers[row] + "</option>");
+                                }
+				var nameOfSlice = $("#new-slice-name").val();
+				var nameOfServiceClass = $("#new-service-class").val();
+				var nameOfImage = $("#new-image").val();
+				$("#create-slice-form").dialog({
+					autoOpen: false,
+					height: 420,
+					width: 400,
+					modal: true,
+					dialogClass: "tenantDialog",
+					buttons: {
+						"Submit": function () {
+							$.ajax({
+								url: '/createnewslice/',
+								dataType: 'json',
+								data: {
+									sliceName: $("#new-slice-name").val(),
+									serviceClass: nameOfServiceClass,
+									imageName: $("#new-image").val(),
+									network: $("#new-network").val(),
+									privateVolume: $("#private-vol").is(":checked"),
+									mountDataSets: $("#mount-data-sets").val(),
+									userEmail: $("#add-user").val(),
+									actionToDo: "add",
+									csrfmiddlewaretoken: "{{ csrf_token }}", // < here 
+									state: "inactive"
+								},
+								async: false,
+								type: 'POST',
+								beforeSend: function () {
+									if (!$("#new-slice-name").val()) {
+										$("#tooltip").css("display", "block");
+										return false;
+									} else {
+										return true;
+									}
+								},
+								success: function () {
+									location.reload();
+								}
+							});
+						   $.ajax({
+                                                                url: '/tenantaddorreminstance/',
+                                                                dataType: 'json',
+                                                                data: {
+                                                                        count: parseInt($("#number-of-instances").val()),
+                                                                        slice: $("#new-slice-name").val(),
+									image: $("#new-image").val(),
+                                                                        actionToDo: "add",
+                                                                        csrfmiddlewaretoken: "{{ csrf_token }}", // < here
+                                                                        state: "inactive"
+                                                                },
+								async: false,
+                                                                type: 'POST',
+                                                                success: function () {
+                                                                        location.reload();
+                                                                }
+                                                        });
+
+						},
+						Cancel: function () {
+							$(this).dialog("close");
+						}
+					}
+				});
+				$("#create-slice-form").dialog("open");
+			});
+			$("#delete-slice-btn").unbind().click(function () {
+				$("#delete-slice").empty();
+				for (row in rows) {
+					$("#delete-slice").append("<option>" + rows[row]['sliceName'] + "</option>");
+				}
+				$("#delete-slice-form").dialog({
+					autoOpen: false,
+					height: 200,
+					width: 350,
+					modal: true,
+					dialogClass: "tenantDialog",
+					buttons: {
+						"Delete": function () {
+							$.ajax({
+								url: '/tenantdeleteslice/',
+								dataType: 'json',
+								data: {
+									sliceName: $("#delete-slice").val(),
+									csrfmiddlewaretoken: "{{ csrf_token }}", // < here 
+									state: "inactive"
+								},
+								type: 'POST',
+								success: function () {
+									location.reload();
+								},
+                                                          error:function (xhr, textStatus, thrownError){
+                                                                   errorDialog("Error:", textStatus + " " + xhr.responseText);
+                                                        }
+							});
+						},
+						Cancel: function () {
+							$(this).dialog("close");
+						}
+					}
+				});
+				$("#delete-slice-form").dialog("open");
+			});
+		}
+
+
+	function initTenant() {
+		jQuery.ajax({
+			url: '/tenantview',
+			dataType: 'json',
+			success: function (data) {
+				var rows = data['userSliceInfo']['rows'];
+				var imageData = data['image']['rows'];
+				//var networkData = data['network']['rows'];
+				var serviceLevelData = data['sliceServiceClass']['rows'];
+				//var siteRows = data['sites']['rows'];
+				var siteRows = data['availableSites']['rows'];
+				var dataSet = data['mountDataSets']['rows'];
+				var siteUsers = data['siteUsers'];
+				UserSliceTable(rows,imageData,serviceLevelData,siteRows,dataSet,siteUsers);
+				if(!(data['publicKey'])){
+					$(".public-key-warning").css("display","block");
+				}
+				var value = $("#tenantSliceDropDown").val();
+				checkForBasicAdvView(value,rows,imageData,serviceLevelData,siteRows,dataSet);
+				$("#tooltip").css("display", "none");
+				$("#basic-tooltip").css("display", "none");
+				$("#adv-tooltip").css("display", "none");
+				if(!(data['role']=="pi"||data['role']=="admin")){
+					$("#create-slice-btn").off();
+					$("#create-slice-btn").css('background','grey');
+					$("#delete-slice-btn").off();
+					$("#delete-slice-btn").css('background','grey');
+					$("#add-user-btn").off();
+                                        $("#add-user-btn").css('background','grey');
+				}
+			},
+			complete: function () {}
+		});
+	}
+		
+	initTenant();
+});
+</script>
+
+</html>
diff --git a/xos/templates/admin/delete_confirmation.html b/xos/templates/admin/delete_confirmation.html
new file mode 100644
index 0000000..c8a1be1
--- /dev/null
+++ b/xos/templates/admin/delete_confirmation.html
@@ -0,0 +1,42 @@
+{% extends "admin/base_site.html" %}
+{% load i18n %}
+{% load admin_urls %}
+
+{% block breadcrumbs %}
+<div class="breadcrumbs">
+<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
+&rsaquo; <a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ app_label|capfirst }}</a>
+&rsaquo; <a href="{% url opts|admin_urlname:'changelist' %}">{{ opts.verbose_name_plural|capfirst|escape }}</a>
+&rsaquo; <a href="{% url opts|admin_urlname:'change' object.pk|admin_urlquote %}">{{ object|truncatewords:"18" }}</a>
+&rsaquo; {% trans 'Delete' %}
+</div>
+{% endblock %}
+
+{% block content %}
+{% if perms_lacking or protected %}
+    {% if perms_lacking %}
+        <p>{% blocktrans with escaped_object=object %}Deleting the {{ object_name }} '{{ escaped_object }}' would result in deleting related objects, but your account doesn't have permission to delete the following types of objects:{% endblocktrans %}</p>
+        <ul>
+        {% for obj in perms_lacking %}
+            <li>{{ obj }}</li>
+        {% endfor %}
+        </ul>
+    {% endif %}
+    {% if protected %}
+        <p>{% blocktrans with escaped_object=object %}Deleting the {{ object_name }} '{{ escaped_object }}' would require deleting the following protected related objects:{% endblocktrans %}</p>
+        <ul>
+        {% for obj in protected %}
+            <li>{{ obj }}</li>
+        {% endfor %}
+        </ul>
+    {% endif %}
+{% else %}
+    <p>{% blocktrans with escaped_object=object %}Are you sure you want to delete the {{ object_name }} "{{ escaped_object }}"? All related objects will be deleted{% endblocktrans %}</p>
+    <form action="" method="post">{% csrf_token %}
+    <div>
+    <input type="hidden" name="post" value="yes" />
+    <input type="submit" value="{% trans "Yes, I'm sure" %}" />
+    </div>
+    </form>
+{% endif %}
+{% endblock %}
diff --git a/xos/templates/admin/login.html b/xos/templates/admin/login.html
new file mode 100644
index 0000000..386d579
--- /dev/null
+++ b/xos/templates/admin/login.html
@@ -0,0 +1,179 @@
+{% extends "admin/base_site_login.html" %}
+{% load i18n admin_static %}
+
+{% block extrastyle %}{{ block.super }}
+<link rel="stylesheet" type="text/css" href="{% static "xos.css" %}" />
+{% if XOS_BRANDING_CSS %}
+<link rel="stylesheet" type="text/css" href="{{ XOS_BRANDING_CSS }}">
+{% endif %}
+<script src="{% static 'suit/js/jquery-1.9.1.min.js' %}"></script>
+<script src="http://code.jquery.com/ui/1.11.0/jquery-ui.js"></script>
+{% endblock %}
+
+
+{% block bodyclass %}login{% endblock %}
+
+{% block nav-global %}{% endblock %}
+
+{% block content_title %}{% endblock %}
+
+{% block breadcrumbs %}{% endblock %}
+
+{% block content %}
+{% if form.errors and not form.non_field_errors and not form.this_is_the_login_form.errors %}
+<p class="errornote">
+    {% blocktrans count counter=form.errors.items|length %}Please correct the error below.{% plural %}Please correct the errors below.{% endblocktrans %}
+</p>
+{% endif %}
+
+{% if form.non_field_errors or form.this_is_the_login_form.errors %}
+{% for error in form.non_field_errors %}
+<p class="errornote">
+    {{ error }}
+</p>
+{% endfor %}
+{% for error in form.this_is_the_login_form.errors %}
+<p class="errornote">
+    {{ error }}
+</p>
+{% endfor %}
+{% endif %}
+<div id="wrap">
+    <div id="content-main">
+        <div class="row">
+            <div class="col-xs-12">
+                <img class="logo" src="{% static XOS_BRANDING_ICON %}"/>
+                <form action="{{ app_path }}" method="post" id="login-form">{% csrf_token %}
+                    <div class="row">
+                        <div class="col-xs-12">
+                            {% if not form.this_is_the_login_form.errors %}
+                            {{ form.username.errors }}
+                            {% endif %}
+                            {{ form.username }}
+                        </div>
+                    </div>
+                    <div class="row">
+                        <div class="col-xs-12">
+                            {% if not form.this_is_the_login_form.errors %}{{ form.password.errors }}{% endif %}
+                            {{ form.password }}
+                            <input type="hidden" name="this_is_the_login_form" value="1" />
+                            <input type="hidden" name="old_next" value="{{ next }}" />
+                            <input type="hidden" name="next" value="/loggedin/?orig_next={{ next }}" />
+                        </div>
+                    </div>
+                    <div class="row">
+                        <div class="col-xs-12">
+                            <input type="submit" class="btn btn-primary btn-block" value="{% trans 'SIGN IN' %}" />
+                        </div>
+                    </div>
+                    <div class="row">
+                        <div class="col-xs-12 text-right">
+                            <div id="requestAccountLink">{% trans 'Request a new Account' %}</div>
+                        </div>
+                    </div>
+                </form>
+            </div>
+        </div>
+
+
+        <div id="request-account-form" title="Request an Account">
+            <form>
+                <fieldset>
+                    <div class="request-form-row">
+                        <label for="request-first-name">First Name</label>
+                        <input type="text" name="request-first-name" id="request-first-name">
+                    </div>
+                    <div class="request-form-row">
+                        <label for="request-last-name">Last Name</label>
+                        <input type="text" name="request-last-name" id="request-last-name">
+                    </div>
+                    <div class="request-form-row">
+                        <label for="request-email">Email</label>
+                        <input type="text" name="request-email" id="request-email">
+                    </div>
+                    <div class="request-form-row">
+                        <label for="request-site-name">Site</label><br>
+                        <select id="request-site-name" name="request-site-name">
+                            <option>---------</option>
+                            {% for site in sites %}
+                            {% if site.allowNewUsers %}
+                            <option>{{ site.name }}</option>
+                            {% endif %}
+                            {% endfor %}
+                        </select>
+                    </div>
+                    <div class="submit-row">
+                        <input id ="request-signup" class="btn btn-info" value="SIGN UP">
+                    </div>
+                </fieldset>
+            </form>
+        </div>
+    </div>
+</div>
+
+
+<script type="text/javascript">
+    $(function() {
+        initRequest();
+    });
+    function initRequest(){
+        $.ajax({
+            url: '/tenantview',
+            dataType: 'json',
+            success: function (data) {
+                var sites = data['sitesToBeRequested'];
+                console.log(sites);
+                for (site in sites){
+                    $("#request-site-name").append("<option>" + site + "</option>");
+                }
+            }
+        });
+    }
+    $("#requestAccountLink").unbind().click(function(){
+        $("#request-account-form").dialog({
+            autoOpen: false,
+            modal: true,
+            dialogClass: "requestDialog",
+        });
+        $("#request-account-form").dialog("open");
+    })
+    $("#request-signup").unbind().click(function(){
+        $.ajax({
+            url: '/requestaccess/',
+            dataType: 'json',
+            data: {
+                email: $("#request-email").val(),
+                firstname: $("#request-first-name").val(),
+                lastname: $("#request-last-name").val(),
+                site: $("#request-site-name").val(),
+                csrfmiddlewaretoken: "{{ csrf_token }}", // < here
+                state: "inactive"
+            },
+            async: false,
+            type: 'POST',
+            success: function (response) {
+                if (response && response.error) {
+                    if (response.error == "already_approved") {
+                        alert("Your request has already been proccessed and approved. We are sending you another email with a new temporary password");
+                        return;
+                    } else if (response.error == "already_pending") {
+                        alert("Your request is already pending and awaiting approval");
+                        return;
+                    } else if (response.error == "is_deleted") {
+                        alert("Your user record is in a deleted state. Please contact OpenCloud support");
+                        return;
+                    }
+                }
+                $("#request-account-form").dialog("close");
+                alert("Your request has been submitted");
+            },
+            error:function (xhr, textStatus, thrownError){
+                alert("Error:", textStatus + " " + xhr.responseText);
+            }
+        });
+    })
+    document.getElementById('id_username').focus()
+</script>
+</div>
+</div>
+{% endblock %}
diff --git a/xos/templates/admin/menu.html b/xos/templates/admin/menu.html
new file mode 100644
index 0000000..52b9596
--- /dev/null
+++ b/xos/templates/admin/menu.html
@@ -0,0 +1,64 @@
+{#{% load sitetree %}#}
+{% load i18n suit_menu suit_tags core_tags %}
+{% load url from future %}
+
+
+
+
+{% with menu_position='menu_position'|suit_conf %}
+
+
+
+<ul class="nav nav-suit-menu nav-pills{% if menu_position == 'vertical' %} nav-stacked {% endif %}">
+    {% block menu_home %}
+    {% url 'admin:index' as index_url %}
+    <li{% if index_url == request.path %} class="active"{% endif %}>
+        <a href="{{ index_url }}"><i class="icon-home"></i>{% trans 'Home' %}</a>
+        {% dashboard_list %}
+    </li>
+    {% endblock %}
+
+    {% get_menu request as app_list %}
+        {% if app_list %}
+            {% for app in app_list %}
+                {% if app.separator %}
+                <li class="separator"></li>
+                {% else %}
+                <li
+                        {{ app.isActive|yesno:' class=active,' }}
+                        {% if app.url in request.path %}
+                            class="active"
+                        {% endif %}
+                        >
+                    <a href="{{ app.url }}"{{ app.blank|yesno:' target=_blank,' }}>
+                        <i class="{% firstof app.icon 'icon-chevron-right' %}"></i>
+                        {% trans app.label|capfirst %}
+                    </a>
+                    {% if app.models and not app.is_active %}
+                    <ul class="nav nav-pills nav-stacked">
+                        {% for model in app.models %}
+                            <li{{ model.is_active|yesno:' class=active,' }}>
+                                <a href="{{ model.url }}"{{ model.blank|yesno:' target=_blank,' }}>{{ model.label }}</a>
+                            </li>
+                        {% endfor %}
+                    </ul>
+                {% endif %}
+                </li>
+            {% endif %}
+            {% endfor %}
+        {% endif %}
+</ul>
+{% if app_list and menu_position == 'horizontal' %}
+    {% get_sub_menu app_list as active_app_nodels %}
+    <ul class="nav nav-suit-sub-menu nav-pills">
+        {% if active_app_nodels %}
+            {% for model in active_app_nodels %}
+            <li{{ model.is_active|yesno:' class=active,' }}>
+                <a href="{{ model.url }}"{{ model.blank|yesno:' target=_blank,' }}>{{ model.label }}</a>
+            </li>
+            {% endfor %}
+        {% endif %}
+    </ul>
+    {% endif %}
+{% endwith %}
+
diff --git a/xos/templates/admin/newminidashboard.html b/xos/templates/admin/newminidashboard.html
new file mode 100644
index 0000000..5c08401
--- /dev/null
+++ b/xos/templates/admin/newminidashboard.html
@@ -0,0 +1,66 @@
+{% load admin_static %}
+
+<script>
+    admin_object_name = "{{ opts.object_name }}";
+    admin_object_id = "{{ original.id }}";
+    admin_object_controller = "princeton-beta"; // XXX fix this
+    if (admin_object_id == "") {
+        admin_object_id = undefined;
+    } else {
+        admin_object_id = parseInt(admin_object_id, 10);
+    }
+    {% if opts.object_name == "Site" %}
+        admin_controller_sites = [];
+        {% for record in original.controllersite.all %}
+            admin_controller_sites.push( {{ record.id }} );
+        {% endfor %}
+    {% endif %}
+    {% if opts.object_name == "Slice" %}
+        admin_controller_slices = [];
+        {% for record in original.controllerslice.all %}
+            admin_controller_slices.push( {{ record.id }} );
+        {% endfor %}
+    {% endif %}
+</script>
+
+{% if not DISABLE_MINIDASHBOARD %}
+
+<div id="newMiniDashboard">
+    <div class="hide" id="selectedMainNav">{{ opts.verbose_name_plural|capfirst }}</div>
+    <div class="hide" id="currentOriginalNode">{{ original|truncatewords:"18" }}</div>
+    <div class="hide" id="minidashStatus"></div>
+    <!-- <div class="miniDashPair">
+        <button type="button" name="nodeCount" id="miniDashNodeCount" class="minidashbutton">--</button>
+        <label for="nodeCount" id="miniDashNodeCountLabel">Active Nodes</label>
+    </div> -->
+    <div class="miniDashPair">
+        <button type="button" name="CPU" id="miniDashCPU" class="minidashbutton">--</button>
+        <label for="CPU" id="miniDashAvgLoadLabel">CPU</label>
+    </div>
+    <div class="miniDashPair">
+        <button type="button" name="bandwidthIn" id="miniDashBandwidthIn" class="minidashbutton">--</button>
+        <label for="bandwidthIn" id="miniDashBandwidthLabel">Bandwidth In</label>
+    </div>
+    <div class="miniDashPair">
+        <button type="button" name="bandwidthOut" id="miniDashBandwidthOut" class="minidashbutton">--</button>
+        <label for="bandwidthOut" id="miniDashBandwidthLabel">Bandwidth Out</label>
+    </div>
+    <div class="endDashPair">
+    </div>
+</div>
+
+<div id="nodeCountDialog" class="miniDashModal" > 
+<div id="nodeCountGraph" ></div>
+</div>
+
+<div id="bandwidthDialog" class="miniDashModal" > 
+<div id="bandwidthGraph" ></div>
+</div>
+
+<div id="avgLoadDialog" class="miniDashModal" > 
+<div id="avgLoadGraph" ></div>
+</div>
+
+<script src="{% static 'page_analytics.js' %}"></script>
+
+{% endif %}
diff --git a/xos/templates/admin/request_account.html b/xos/templates/admin/request_account.html
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xos/templates/admin/request_account.html
diff --git a/xos/templates/admin/submit_line.html b/xos/templates/admin/submit_line.html
new file mode 100644
index 0000000..d1a80f9
--- /dev/null
+++ b/xos/templates/admin/submit_line.html
@@ -0,0 +1,15 @@
+{% load i18n %}
+<div class="form-buttons clearfix">
+  {% if show_save %}<button type="submit" class="btn btn-success" name="_save">{% trans 'Save' %}</button>{% endif %}
+  {% if show_save_and_continue %}<button type="submit" name="_continue" class=" btn btn-high btn-info">{% trans 'Save and continue editing' %}</button>{% endif %}
+  {% if show_save_as_new %}<button type="submit" name="_saveasnew" class="btn btn-info">{% trans 'Save as new' %}</button>{%endif%}
+  {% if show_save_and_add_another %}<button type="submit" name="_addanother" class="btn btn-info">{% trans 'Save and add another' %}</button>{% endif %}
+
+  {% if show_delete_link %}
+      {% if custom_delete_url %}
+          <a href="{{ custom_delete_url }}" class="btn btn-danger">{% trans "Delete" %}</a>
+      {% else %}
+          <a href="delete/" class="btn btn-danger">{% trans "Delete" %}</a>
+      {% endif %}
+  {% endif %}
+</div>
diff --git a/xos/templates/admin/tags/dashboard_list.html b/xos/templates/admin/tags/dashboard_list.html
new file mode 100644
index 0000000..3649de0
--- /dev/null
+++ b/xos/templates/admin/tags/dashboard_list.html
@@ -0,0 +1,12 @@
+<ul>
+
+    {% for dashboard in dashboards %}
+        <li
+            {% if dashboard.id in path %}
+                class="active"
+            {% endif %}
+        >
+            <a href="/admin/dashboard/{{ dashboard.id}}">{{ dashboard.name }}</a>
+        </li>
+    {% endfor %}
+</ul>
\ No newline at end of file
diff --git a/xos/templates/admin/tags/notification.html b/xos/templates/admin/tags/notification.html
new file mode 100644
index 0000000..558b9ff
--- /dev/null
+++ b/xos/templates/admin/tags/notification.html
@@ -0,0 +1 @@
+{{template | safe}}
\ No newline at end of file
diff --git a/xos/templates/admin/wholePage.html b/xos/templates/admin/wholePage.html
new file mode 100644
index 0000000..156c8aa
--- /dev/null
+++ b/xos/templates/admin/wholePage.html
@@ -0,0 +1,13 @@
+{% load admin_static %}
+<html>
+<head>
+<link rel="stylesheet" type="text/css" href="{% block stylesheet %}{% endblock %}"/>
+<link rel="stylesheet" type="text/css" href="{% static 'suit/bootstrap/css/bootstrap.min.css' %}" media="all"/>
+<link rel="stylesheet" type="text/css" href="{% static 'suit/css/suit.css' %}" media="all">
+<link rel="stylesheet" type="text/css" href="{% static 'xos.css' %}" media="all">
+<script src="{% static 'suit/js/jquery-1.9.1.min.js' %}"></script>
+<script src="http://code.jquery.com/ui/1.10.4/jquery-ui.js"></script>
+{% block extrahead %}{% endblock %}
+</head>
+<body>{% block content %}{% endblock %}</body>            
+</html>
diff --git a/xos/templates/registration/logged_out.html b/xos/templates/registration/logged_out.html
new file mode 100644
index 0000000..437ed66
--- /dev/null
+++ b/xos/templates/registration/logged_out.html
@@ -0,0 +1,23 @@
+
+{% extends "admin/base_logout.html" %}
+{% load i18n admin_modify admin_static%}
+
+<link rel="stylesheet" type="text/css" href="{% static 'xos.css' %}" />
+
+
+
+
+{% block breadcrumbs %}<div class="breadcrumbs"><a href="{% url 'admin:index' %}">{% trans 'Home' %}</a></div>{% endblock %}
+
+{% block content %}
+    <div id="content-main">
+        <div class="row">
+            <div class="col-xs-12">
+                <p class="logoutptag">{% random_str "a" %}</p>
+            </div>
+        </div>
+        <input type="submit" class="btn btn-primary btn-block" value="{% trans 'Log in again' %}" onclick="location.href = '{% url 'admin:index' %}'; "/>
+
+
+    </div>
+{% endblock %}
diff --git a/xos/tests/README.md b/xos/tests/README.md
new file mode 100644
index 0000000..f3ddad5
--- /dev/null
+++ b/xos/tests/README.md
@@ -0,0 +1,5 @@
+# CORD Tests
+
+The files in this directory are obsolete. The plan is for this
+directory to hold tests in the furture. There are also tests in
+the form of TOSCA specifications in `../configurations/tests`.
diff --git a/xos/tests/api/.gitignore b/xos/tests/api/.gitignore
new file mode 100644
index 0000000..99e7d87
--- /dev/null
+++ b/xos/tests/api/.gitignore
@@ -0,0 +1 @@
+apiary.apib
\ No newline at end of file
diff --git a/xos/tests/api/README.md b/xos/tests/api/README.md
new file mode 100644
index 0000000..67db53d
--- /dev/null
+++ b/xos/tests/api/README.md
@@ -0,0 +1,11 @@
+# xos-api-docs
+
+These folder contain the XOS API definition and specs. To run tests visit `configurations/test-standalone` folder.
+
+To document new API:
+- run `npm install`
+- run `npm start`
+- add the appropriate endpont under `source` folder.
+
+_API are documented using (Api BluePrint)[https://apiblueprint.org/] syntax and the documentation is published on (Apiary)[http://docs.xos.apiary.io/#]_
+
diff --git a/xos/tests/api/dredd.yml b/xos/tests/api/dredd.yml
new file mode 100644
index 0000000..9e32eba
--- /dev/null
+++ b/xos/tests/api/dredd.yml
@@ -0,0 +1,35 @@
+reporter: apiary
+custom:
+  apiaryApiKey: f941658c6714ebf58eeda5e0786e937f
+  apiaryApiName: xos
+dry-run: null
+hookfiles: "./hooks.py"
+language: python
+sandbox: false
+server: null
+server-wait: 3
+init: false
+names: false
+only: []
+output: []
+header: []
+sorted: false
+user: null
+inline-errors: false
+details: false
+method: []
+color: true
+level: info
+timestamp: false
+silent: false
+path: []
+hooks-worker-timeout: 5000
+hooks-worker-connect-timeout: 1500
+hooks-worker-connect-retry: 500
+hooks-worker-after-connect-wait: 100
+hooks-worker-term-timeout: 5000
+hooks-worker-term-retry: 500
+hooks-worker-handler-host: localhost
+hooks-worker-handler-port: 61321
+blueprint: apiary.apib
+endpoint: 'http://127.0.0.1:9999/'
diff --git a/xos/tests/api/gulpfile.js b/xos/tests/api/gulpfile.js
new file mode 100644
index 0000000..988dd8c
--- /dev/null
+++ b/xos/tests/api/gulpfile.js
@@ -0,0 +1,17 @@
+var gulp = require('gulp');
+var concat = require('gulp-concat');
+
+
+
+gulp.task('default', function() {
+  gulp.watch('./source/**/*.md', ['concat']);
+});
+
+gulp.task('concat', function() {
+  return gulp.src([
+      './source/base.md',
+      './source/**/*.md'
+    ])
+    .pipe(concat('../../../apiary.apib', {newLine: '\n \n \n'}))
+    .pipe(gulp.dest('./'));
+});
diff --git a/xos/tests/api/helpers/__init__.py b/xos/tests/api/helpers/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xos/tests/api/helpers/__init__.py
diff --git a/xos/tests/api/helpers/before_test.py b/xos/tests/api/helpers/before_test.py
new file mode 100644
index 0000000..a977564
--- /dev/null
+++ b/xos/tests/api/helpers/before_test.py
@@ -0,0 +1,296 @@
+import dredd_hooks as hooks
+import sys
+
+# HELPERS
+# NOTE move in separated module
+import os
+import sys
+sys.path.append("/opt/xos")
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
+import django
+from core.models import *
+from services.volt.models import *
+from services.vsg.models import *
+from services.vtr.models import *
+import urllib2
+import json
+from django.utils import timezone
+django.setup()
+
+
+def doLogin(username, password):
+    url = "http://127.0.0.1:8000/xoslib/login?username=%s&password=%s" % (username, password)
+    res = urllib2.urlopen(url).read()
+    parsed = json.loads(res)
+    return {'token': parsed['xoscsrftoken'], 'sessionid': parsed['xossessionid']}
+
+
+def cleanDB():
+    # deleting all subscribers
+    for s in CordSubscriberRoot.objects.all():
+        s.delete(purge=True)
+
+    # deleting all slices
+    for s in Slice.objects.all():
+        s.delete(purge=True)
+
+    # deleting all Services
+    for s in Service.objects.all():
+        s.delete(purge=True)
+
+    # deleting all Tenants
+    for s in Tenant.objects.all():
+        s.delete(purge=True)
+
+    # deleting all Networks
+    for s in Network.objects.all():
+        s.delete(purge=True)
+
+    # deleting all NetworkTemplates
+    for s in NetworkTemplate.objects.all():
+        s.delete(purge=True)
+
+    for s in NetworkSlice.objects.all():
+        s.delete(purge=True)
+
+    for s in AddressPool.objects.all():
+        s.delete(purge=True)
+
+    for s in Flavor.objects.all():
+        s.delete(purge=True)
+
+    for s in Image.objects.all():
+        s.delete(purge=True)
+
+    # print 'DB Cleaned'
+
+
+def createTestSubscriber():
+
+    cleanDB()
+    createFlavors()
+
+    # load user
+    user = User.objects.get(email="padmin@vicci.org")
+
+    # network template
+    private_template = NetworkTemplate()
+    private_template.name = 'Private Network'
+    private_template.save()
+
+    # creating the test subscriber
+    subscriber = CordSubscriberRoot(name='Test Subscriber 1', id=1)
+    subscriber.created = timezone.now()
+    subscriber.save()
+
+    # vRouter service
+    vrouter_service = VRouterService()
+    vrouter_service.name = 'service_vrouter'
+    vrouter_service.save()
+
+    # address pools
+    ap_vsg = AddressPool()
+    ap_vsg.service = vrouter_service
+    ap_vsg.name = 'addresses_vsg'
+    ap_vsg.addresses = '10.168.0.0'
+    ap_vsg.gateway_ip = '10.168.0.1'
+    ap_vsg.gateway_mac = '02:42:0a:a8:00:01'
+    ap_vsg.save()
+
+    # print 'vRouter created'
+
+    # Site
+    site = Site.objects.get(name='MySite')
+
+    # vSG service
+    vsg_service = VSGService()
+    vsg_service.name = 'service_vsg'
+
+    # vSG slice
+    vsg_slice = Slice(id=2)
+    vsg_slice.name = site.login_base + "_testVsg"
+    vsg_slice.service = vsg_service.id
+    vsg_slice.site = site
+    vsg_slice.caller = user
+
+    vsg_slice.save()
+
+    vsg_service.save()
+
+    # volt service
+    volt_service = VOLTService()
+    volt_service.name = 'service_volt'
+    volt_service.save()
+
+    # cvpe image
+    createImage('ubuntu-vcpe4')
+
+    # vcpe slice
+    vcpe_slice = Slice(id=3)
+    vcpe_slice.name = site.login_base + "_testVcpe"
+    vcpe_slice.service = Service.objects.get(kind='vCPE')
+    vcpe_slice.site = site
+    vcpe_slice.caller = user
+    vcpe_slice.save()
+
+    # print 'vcpe_slice created'
+
+    # create a lan network
+    lan_net = Network(id=1)
+    lan_net.name = 'lan_network'
+    lan_net.owner = vcpe_slice
+    lan_net.template = private_template
+    lan_net.save()
+
+    # print 'lan_network created'
+
+    # add relation between vcpe slice and lan network
+    vcpe_network = NetworkSlice()
+    vcpe_network.network = lan_net
+    vcpe_network.slice = vcpe_slice
+    vcpe_network.save()
+
+    # print 'vcpe network relation added'
+
+    # vbng service
+    vbng_service = VBNGService()
+    vbng_service.name = 'service_vbng'
+    vbng_service.save()
+
+    # print 'vbng_service creater'
+
+    # volt tenant
+    vt = VOLTTenant(subscriber=subscriber.id, id=1)
+    vt.s_tag = "222"
+    vt.c_tag = "432"
+    vt.provider_service_id = volt_service.id
+    vt.caller = user
+    vt.save()
+
+    # print "Subscriber Created"
+
+
+def deleteTruckrolls():
+    for s in VTRTenant.objects.all():
+        s.delete(purge=True)
+
+
+def setUpTruckroll():
+    service_vtr = VTRService()
+    service_vtr.name = 'service_vtr'
+    service_vtr.save()
+
+
+def createTruckroll():
+    setUpTruckroll()
+    tn = VTRTenant(id=1)
+    tn.created = timezone.now()
+    tn.save()
+
+
+def createFlavors():
+    small = Flavor(id=1)
+    small.name = "m1.small"
+    small.created = timezone.now()
+    small.save()
+
+    medium = Flavor(id=2)
+    medium.name = "m1.medium"
+    medium.created = timezone.now()
+    medium.save()
+
+    large = Flavor(id=3)
+    large.name = "m1.large"
+    large.created = timezone.now()
+    large.save()
+
+
+def createSlice():
+    site = Site.objects.get(name='MySite')
+    user = User.objects.get(email="padmin@vicci.org")
+
+    sl = Slice(id=1)
+    sl.created = timezone.now()
+    sl.name = site.login_base + "_testSlice"
+    sl.site = site
+    sl.caller = user
+    sl.save()
+    return sl
+
+
+def createDeployment():
+    deployment = Deployment(id=1)
+    deployment.created = timezone.now()
+    deployment.name = 'MyTestDeployment'
+    deployment.save()
+    return deployment
+
+
+def createImage(name):
+    img = Image(id=1)
+    img.name = name
+    img.created = timezone.now()
+    img.disk_format = 'QCOW2'
+    img.kind = 'vm'
+    img.save()
+    return img
+
+
+def createNode(deployment):
+    site = Site.objects.get(name='MySite')
+
+    site_deployment = SiteDeployment(id=1)
+    site_deployment.site = site
+    site_deployment.created = timezone.now()
+    site_deployment.deployment = deployment
+    site_deployment.save()
+
+    node = Node(id=1)
+    node.name = 'test-node'
+    node.created = timezone.now()
+    node.site = site
+    node.site_deployment = site_deployment
+    node.save()
+    return node
+
+
+def setupInstance():
+    deployment = createDeployment()
+    sl = createSlice()
+    node = createNode(deployment)
+    img = createImage('test-image')
+    # print {'image': img.id, 'deployment': deployment.id, 'slice': sl.id}
+    return {'image': img, 'deployment': deployment, 'slice': sl}
+
+
+def createInstance():
+    requirements = setupInstance()
+    user = User.objects.get(email="padmin@vicci.org")
+
+    instance = Instance(id=1)
+    instance.name = 'test-instance'
+    instance.created = timezone.now()
+    instance.node = Node.objects.all()[0]
+    instance.image = requirements['image']
+    instance.slice = requirements['slice']
+    instance.deployment = requirements['deployment']
+    instance.caller = user
+    instance.save()
+
+
+def createService():
+    service = Service(id=1)
+    service.name = 'test-service'
+    service.save()
+
+# setupInstance()
+# depl = createDeployment()
+# createTestSubscriber()
+# createInstance()
+# createSlice()
+# createNode(depl)
+# createImage('test-image')
+# createFlavors()
+# createTruckroll()
+# setUpTruckroll()
+createService()
diff --git a/xos/tests/api/helpers/flavors.py b/xos/tests/api/helpers/flavors.py
new file mode 100644
index 0000000..dca4d77
--- /dev/null
+++ b/xos/tests/api/helpers/flavors.py
@@ -0,0 +1,22 @@
+import dredd_hooks as hooks
+import sys
+
+# HELPERS
+# NOTE move in separated module
+import os
+import sys
+sys.path.append("/opt/xos")
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
+import django
+from core.models import *
+import urllib2
+import json
+django.setup()
+
+def createFlavor():
+    fl = Flavor(id=1)
+    fl.name = 'm1.large'
+    fl.save()
+    print(fl, fl.id)
+
+createFlavor()
\ No newline at end of file
diff --git a/xos/tests/api/helpers/subscriber.py b/xos/tests/api/helpers/subscriber.py
new file mode 100644
index 0000000..320c73c
--- /dev/null
+++ b/xos/tests/api/helpers/subscriber.py
@@ -0,0 +1,188 @@
+import dredd_hooks as hooks
+import sys
+
+# HELPERS
+# NOTE move in separated module
+import os
+import sys
+sys.path.append("/opt/xos")
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
+import django
+from core.models import *
+from services.volt.models import *
+from services.vsg.models import *
+from services.vtr.models import *
+from django.contrib.auth import authenticate, login
+from django.core.exceptions import PermissionDenied
+from django.contrib.sessions.models import Session
+import urllib2
+import json
+django.setup()
+
+token = ''
+
+
+def doLogin(username, password):
+
+    url = "http://127.0.0.1:8000/xoslib/login?username=%s&password=%s" % (username, password)
+
+    print url
+
+    res = urllib2.urlopen(url).read()
+
+    token = json.loads(res)['xoscsrftoken']
+
+
+def cleanDB():
+    # deleting all subscribers
+    for s in CordSubscriberRoot.objects.all():
+        s.delete(purge=True)
+
+    # deleting all slices
+    for s in Slice.objects.all():
+        s.delete(purge=True)
+
+    # deleting all Services
+    for s in Service.objects.all():
+        s.delete(purge=True)
+
+    # deleting all Tenants
+    for s in Tenant.objects.all():
+        s.delete(purge=True)
+
+    # deleting all Networks
+    for s in Network.objects.all():
+        s.delete(purge=True)
+
+    # deleting all NetworkTemplates
+    for s in NetworkTemplate.objects.all():
+        s.delete(purge=True)
+
+    for s in NetworkSlice.objects.all():
+        s.delete(purge=True)
+
+    for s in AddressPool.objects.all():
+        s.delete(purge=True)
+
+    print 'DB Cleaned'
+
+
+def createTestSubscriber():
+
+    cleanDB()
+
+    # load user
+    user = User.objects.get(email="padmin@vicci.org")
+
+    # network template
+    private_template = NetworkTemplate()
+    private_template.name = 'Private Network'
+    private_template.save()
+
+    # creating the test subscriber
+    subscriber = CordSubscriberRoot(name='Test Subscriber 1', id=1)
+    subscriber.save()
+
+    # vRouter service
+    vrouter_service = VRouterService()
+    vrouter_service.name = 'service_vrouter'
+    vrouter_service.save()
+
+    # address pools
+    ap_vsg = AddressPool()
+    ap_vsg.service = vrouter_service
+    ap_vsg.name = 'addresses_vsg'
+    ap_vsg.addresses = '10.168.0.0'
+    ap_vsg.gateway_ip = '10.168.0.1'
+    ap_vsg.gateway_mac = '02:42:0a:a8:00:01'
+    ap_vsg.save()
+
+    print 'vRouter created'
+
+    # Site
+    site = Site.objects.get(name='MySite')
+
+    # vSG service
+    vsg_service = VSGService()
+    vsg_service.name = 'service_vsg'
+
+    # vSG slice
+    vsg_slice = Slice()
+    vsg_slice.name = site.login_base + "_testVsg"
+    vsg_slice.service = vsg_service.id
+    vsg_slice.site = site
+    vsg_slice.caller = user
+
+    vsg_slice.save()
+
+    vsg_service.save()
+
+    # volt service
+    volt_service = VOLTService()
+    volt_service.name = 'service_volt'
+    volt_service.save()
+
+
+    # vcpe slice
+    vcpe_slice = Slice()
+    vcpe_slice.name = site.login_base + "_testVcpe"
+    vcpe_slice.service = Service.objects.get(kind='vCPE')
+    vcpe_slice.site = site
+    vcpe_slice.caller = user
+    vcpe_slice.save()
+
+    # print 'vcpe_slice created'
+
+    # create a lan network
+    lan_net = Network()
+    lan_net.name = 'lan_network'
+    lan_net.owner = vcpe_slice
+    lan_net.template = private_template
+    lan_net.save()
+
+    # print 'lan_network created'
+
+    # add relation between vcpe slice and lan network
+    vcpe_network = NetworkSlice()
+    vcpe_network.network = lan_net
+    vcpe_network.slice = vcpe_slice
+    vcpe_network.save()
+
+    # print 'vcpe network relation added'
+
+    # vbng service
+    vbng_service = VBNGService()
+    vbng_service.name = 'service_vbng'
+    vbng_service.save()
+
+    # print 'vbng_service creater'
+
+    # volt tenant
+    vt = VOLTTenant(subscriber=subscriber.id, id=1)
+    vt.s_tag = "222"
+    vt.c_tag = "432"
+    vt.provider_service_id = volt_service.id
+    vt.caller = user
+    vt.save()
+
+    print "Subscriber Created"
+
+
+def deleteTruckrolls():
+    for s in VTRTenant.objects.all():
+        s.delete(purge=True)
+
+
+def setUpTruckroll():
+    service_vtr = VTRService()
+    service_vtr.name = 'service_vtr'
+    service_vtr.save()
+
+
+def createTruckroll():
+    setUpTruckroll()
+    tn = VTRTenant(id=1)
+    tn.save()
+
+
+createTestSubscriber()
diff --git a/xos/tests/api/hooks.py b/xos/tests/api/hooks.py
new file mode 100644
index 0000000..e7ba705
--- /dev/null
+++ b/xos/tests/api/hooks.py
@@ -0,0 +1,382 @@
+import dredd_hooks as hooks
+import sys
+
+# HELPERS
+# NOTE move in separated module
+import os
+import sys
+sys.path.append("/opt/xos")
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
+import django
+from core.models import *
+from services.volt.models import *
+from services.vsg.models import *
+from services.vtr.models import *
+import urllib2
+import json
+from django.utils import timezone
+django.setup()
+
+
+def doLogin(username, password):
+    url = "http://127.0.0.1:9999/xoslib/login?username=%s&password=%s" % (username, password)
+    res = urllib2.urlopen(url).read()
+    parsed = json.loads(res)
+    return {'token': parsed['xoscsrftoken'], 'sessionid': parsed['xossessionid']}
+
+
+def cleanDB():
+    # deleting all subscribers
+    for s in CordSubscriberRoot.objects.all():
+        s.delete(purge=True)
+
+    # deleting all slices
+    for s in Slice.objects.all():
+        s.delete(purge=True)
+
+    # deleting all Services
+    for s in Service.objects.all():
+        s.delete(purge=True)
+
+    # deleting all Tenants
+    for s in Tenant.objects.all():
+        s.delete(purge=True)
+
+    # deleting all Networks
+    for s in Network.objects.all():
+        s.delete(purge=True)
+
+    # deleting all NetworkTemplates
+    for s in NetworkTemplate.objects.all():
+        s.delete(purge=True)
+
+    for s in NetworkSlice.objects.all():
+        s.delete(purge=True)
+
+    for s in AddressPool.objects.all():
+        s.delete(purge=True)
+
+    for s in Flavor.objects.all():
+        s.delete(purge=True)
+
+    for s in Image.objects.all():
+        s.delete(purge=True)
+
+    # print 'DB Cleaned'
+
+
+def createTestSubscriber():
+
+    cleanDB()
+    createFlavors()
+
+    # load user
+    user = User.objects.get(email="padmin@vicci.org")
+
+    # network template
+    private_template = NetworkTemplate()
+    private_template.name = 'Private Network'
+    private_template.save()
+
+    # creating the test subscriber
+    subscriber = CordSubscriberRoot(name='Test Subscriber 1', id=1)
+    subscriber.created = timezone.now()
+    subscriber.save()
+
+    # vRouter service
+    vrouter_service = VRouterService()
+    vrouter_service.name = 'service_vrouter'
+    vrouter_service.save()
+
+    # address pools
+    ap_vsg = AddressPool()
+    ap_vsg.service = vrouter_service
+    ap_vsg.name = 'addresses_vsg'
+    ap_vsg.addresses = '10.168.0.0'
+    ap_vsg.gateway_ip = '10.168.0.1'
+    ap_vsg.gateway_mac = '02:42:0a:a8:00:01'
+    ap_vsg.save()
+
+    # print 'vRouter created'
+
+    # cvpe image
+    vsg_img = createImage('ubuntu-vcpe4')
+
+    # Site
+    site = Site.objects.get(name='MySite')
+
+    # vSG service
+    vsg_service = VSGService()
+    vsg_service.name = 'service_vsg'
+
+    # vSG slice
+    vsg_slice = Slice(id=2)
+    vsg_slice.name = site.login_base + "_testVsg"
+    vsg_slice.service = vsg_service.id
+    vsg_slice.site = site
+    vsg_slice.caller = user
+    vsg_slice.default_image = vsg_img
+    vsg_slice.save()
+
+    vsg_service.save()
+
+    # volt service
+    volt_service = VOLTService()
+    volt_service.name = 'service_volt'
+    volt_service.save()
+
+    # vcpe slice
+    vcpe_slice = Slice(id=3)
+    vcpe_slice.name = site.login_base + "_testVcpe"
+    vcpe_slice.service = Service.objects.get(kind='vCPE')
+    vcpe_slice.site = site
+    vcpe_slice.caller = user
+    vcpe_slice.default_image =  vsg_img
+    vcpe_slice.save()
+
+    # print 'vcpe_slice created'
+
+    # create a lan network
+    lan_net = Network(id=1)
+    lan_net.name = 'lan_network'
+    lan_net.owner = vcpe_slice
+    lan_net.template = private_template
+    lan_net.save()
+
+    # print 'lan_network created'
+
+    # add relation between vcpe slice and lan network
+    vcpe_network = NetworkSlice()
+    vcpe_network.network = lan_net
+    vcpe_network.slice = vcpe_slice
+    vcpe_network.save()
+
+    # print 'vcpe network relation added'
+
+    # volt tenant
+    vt = VOLTTenant(subscriber=subscriber.id, id=1)
+    vt.s_tag = "222"
+    vt.c_tag = "432"
+    vt.provider_service_id = volt_service.id
+    vt.caller = user
+    vt.save()
+
+    # print "Subscriber Created"
+
+
+def deleteTruckrolls():
+    for s in VTRTenant.objects.all():
+        s.delete(purge=True)
+
+
+def setUpTruckroll():
+    service_vtr = VTRService()
+    service_vtr.name = 'service_vtr'
+    service_vtr.save()
+
+
+def createTruckroll():
+    setUpTruckroll()
+    tn = VTRTenant(id=1)
+    tn.created = timezone.now()
+    tn.save()
+
+
+def createFlavors():
+    small = Flavor(id=1)
+    small.name = "m1.small"
+    small.created = timezone.now()
+    small.save()
+
+    medium = Flavor(id=2)
+    medium.name = "m1.medium"
+    medium.created = timezone.now()
+    medium.save()
+
+    large = Flavor(id=3)
+    large.name = "m1.large"
+    large.created = timezone.now()
+    large.save()
+
+
+def createSlice():
+    site = Site.objects.get(name='MySite')
+    user = User.objects.get(email="padmin@vicci.org")
+
+    sl = Slice(id=1)
+    sl.created = timezone.now()
+    sl.name = site.login_base + "_testSlice"
+    sl.site = site
+    sl.caller = user
+    sl.save()
+    return sl
+
+
+def createDeployment():
+    deployment = Deployment(id=1)
+    deployment.created = timezone.now()
+    deployment.name = 'MyTestDeployment'
+    deployment.save()
+    return deployment
+
+
+def createImage(name):
+    img = Image(id=1)
+    img.name = name
+    img.created = timezone.now()
+    img.disk_format = 'QCOW2'
+    img.kind = 'vm'
+    img.save()
+    return img
+
+
+def createNode(deployment):
+    site = Site.objects.get(name='MySite')
+
+    site_deployment = SiteDeployment(id=1)
+    site_deployment.site = site
+    site_deployment.created = timezone.now()
+    site_deployment.deployment = deployment
+    site_deployment.save()
+
+    node = Node(id=1)
+    node.name = 'test-node'
+    node.created = timezone.now()
+    node.site = site
+    node.site_deployment = site_deployment
+    node.save()
+    return node
+
+
+def setupInstance():
+    deployment = createDeployment()
+    sl = createSlice()
+    node = createNode(deployment)
+    img = createImage('test-image')
+    # print {'image': img.id, 'deployment': deployment.id, 'slice': sl.id}
+    return {'image': img, 'deployment': deployment, 'slice': sl}
+
+
+def createInstance():
+    requirements = setupInstance()
+    user = User.objects.get(email="padmin@vicci.org")
+
+    instance = Instance(id=1)
+    instance.name = 'test-instance'
+    instance.created = timezone.now()
+    instance.node = Node.objects.all()[0]
+    instance.image = requirements['image']
+    instance.slice = requirements['slice']
+    instance.deployment = requirements['deployment']
+    instance.caller = user
+    instance.save()
+
+
+def createService():
+    service = Service(id=1)
+    service.name = 'test-service'
+    service.save()
+
+@hooks.before_all
+def my_before_all_hook(transactions):
+    # print "-------------------------------- Before All Hook --------------------------------"
+    cleanDB()
+
+
+@hooks.before_each
+def my_before_each_hook(transaction):
+    # print "-------------------------------- Before Each Hook --------------------------------"
+    # print transaction['name']
+    auth = doLogin('padmin@vicci.org', 'letmein')
+    transaction['request']['headers']['X-CSRFToken'] = auth['token']
+    transaction['request']['headers']['Cookie'] = "xossessionid=%s; xoscsrftoken=%s" % (auth['sessionid'], auth['token'])
+    createTestSubscriber()
+    setupInstance()
+    sys.stdout.flush()
+
+
+# @hooks.after_each
+# def my_after_each(transaction):
+#     print "-------------------------------- Test end --------------------------------"
+
+
+@hooks.before("Services > Services > View a Service Detail")
+def get_service(transaction):
+    createService()
+
+
+@hooks.before("Services > Services > Delete a Service")
+def delete_service(transaction):
+    createService()
+
+
+@hooks.before("Truckroll > Truckroll Collection > Create a Truckroll")
+def test1(transaction):
+    setUpTruckroll()
+
+
+@hooks.before("Truckroll > Truckroll Collection > View a Truckroll Detail")
+def test2(transaction):
+    deleteTruckrolls()
+    createTruckroll()
+
+
+@hooks.before("Truckroll > Truckroll Collection > Delete a Truckroll Detail")
+def test3(transaction):
+    deleteTruckrolls()
+    createTruckroll()
+
+
+@hooks.before("vOLT > vOLT Collection > Create a vOLT")
+def test4(transaction):
+    # transaction['skip'] = True
+    VOLTTenant.objects.get(kind='vOLT').delete()
+
+
+@hooks.before("Flavors > Flavors > View a Flavors Detail")
+def test5(transaction):
+    createFlavors()
+
+
+@hooks.before("Deployments > Deployments > View a Deployment Detail")
+def get_deployments(transaction):
+    createDeployment()
+
+
+@hooks.before("Deployments > Deployments > Delete a Deployment")
+def delete_deployments(transaction):
+    createDeployment()
+
+
+@hooks.before("Instances > Instances Collection > Create an Instance")
+def create_instance(transaction):
+    setupInstance()
+    transaction['skip'] = True
+
+
+@hooks.before("Instances > Instances Detail > Get instance details")
+def get_instance(transaction):
+    createInstance()
+
+
+@hooks.before("Instances > Instances Detail > Delete instance")
+def delete_instance(transaction):
+    createInstance()
+
+
+@hooks.before("Example > Example Services Collection > List all Example Services")
+def exampleTest(transaction):
+    transaction['skip'] = True
+
+
+@hooks.before("Utility > Login > Log a user in the system")
+def before_logout_hook(transaction):
+    transaction['skip'] = True
+    # auth = doLogin('padmin@vicci.org', 'letmein')
+    # transaction['request']['body'] = {}
+    # transaction['request']['body']['xossessionid'] = auth['sessionid']
+
+
+@hooks.before("Utility > Logout > Log a user out of the system")
+def skip_for_now(transaction):
+    transaction['skip'] = True
diff --git a/xos/tests/api/package.json b/xos/tests/api/package.json
new file mode 100644
index 0000000..9a2ba84
--- /dev/null
+++ b/xos/tests/api/package.json
@@ -0,0 +1,28 @@
+{
+  "name": "xos-api-docs",
+  "version": "1.0.0",
+  "description": "Api documentation for XOS",
+  "main": "index.js",
+  "scripts": {
+    "start": "gulp",
+    "test": "dredd",
+    "dry": "dredd --dry-run"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/teone/xos-api-docs.git"
+  },
+  "author": "Matteo Scandolo",
+  "license": "ISC",
+  "bugs": {
+    "url": "https://github.com/teone/xos-api-docs/issues"
+  },
+  "homepage": "https://github.com/teone/xos-api-docs#readme",
+  "dependencies": {
+    "dredd": "^1.0.8"
+  },
+  "devDependencies": {
+    "gulp": "^3.9.1",
+    "gulp-concat": "^2.6.0"
+  }
+}
diff --git a/xos/tests/api/source/base.md b/xos/tests/api/source/base.md
new file mode 100644
index 0000000..564798b
--- /dev/null
+++ b/xos/tests/api/source/base.md
@@ -0,0 +1,3 @@
+FORMAT: 1A
+
+# XOS
\ No newline at end of file
diff --git a/xos/tests/api/source/core/deployment.md b/xos/tests/api/source/core/deployment.md
new file mode 100644
index 0000000..764a73f
--- /dev/null
+++ b/xos/tests/api/source/core/deployment.md
@@ -0,0 +1,126 @@
+# Group Deployments
+
+List of the XOS deployments
+
+## Deployments [/api/core/deployments/{id}/]
+
+### List all deployments [GET]
+
++ Response 200 (application/json)
+
+        [
+            {
+                "humanReadableName": "MyDeployment",
+                "id": 1,
+                "created": "2016-04-29T16:19:03.549901Z",
+                "updated": "2016-04-29T16:19:05.624151Z",
+                "enacted": null,
+                "policed": null,
+                "backend_register": "{}",
+                "backend_status": "0 - Provisioning in progress",
+                "deleted": false,
+                "write_protect": false,
+                "lazy_blocked": false,
+                "no_sync": true,
+                "name": "MyDeployment",
+                "accessControl": "allow all",
+                "images": [
+                    "1"
+                ],
+                "sites": [
+                    "1"
+                ],
+                "flavors": [
+                    "1",
+                    "2",
+                    "3"
+                ],
+                "dashboardviews": [
+                    "1"
+                ]
+            }
+        ]
+
+### Create a deployment [POST]
+
++ Request (application/json)
+
+        {
+            "humanReadableName": "MyDeployment",
+        }
+
++ Response 200 (application/json)
+
+        {
+            "humanReadableName": "MyDeployment",
+            "id": 1,
+            "created": "2016-04-29T16:19:03.549901Z",
+            "updated": "2016-04-29T16:19:05.624151Z",
+            "enacted": null,
+            "policed": null,
+            "backend_register": "{}",
+            "backend_status": "0 - Provisioning in progress",
+            "deleted": false,
+            "write_protect": false,
+            "lazy_blocked": false,
+            "no_sync": true,
+            "name": "MyDeployment",
+            "accessControl": "allow all",
+            "images": [
+                "1"
+            ],
+            "sites": [
+                "1"
+            ],
+            "flavors": [
+                "1",
+                "2",
+                "3"
+            ],
+            "dashboardviews": [
+                "1"
+            ]
+        }
+
+### View a Deployment Detail [GET]
+
++ Parameters
+    + id: 1 (number) - ID of the Deployment in the form of an integer
+
++ Response 200 (application/json)
+
+        {
+            "humanReadableName": "MyDeployment",
+            "id": 1,
+            "created": "2016-04-27T21:46:57.354544Z",
+            "updated": "2016-04-27T21:47:05.221720Z",
+            "enacted": null,
+            "policed": null,
+            "backend_register": "{}",
+            "backend_status": "0 - Provisioning in progress",
+            "deleted": false,
+            "write_protect": false,
+            "lazy_blocked": false,
+            "no_sync": true,
+            "name": "MyDeployment",
+            "accessControl": "allow all",
+            "images": [],
+            "sites": [
+                "1"
+            ],
+            "flavors": [
+                "3",
+                "2",
+                "1"
+            ],
+            "dashboardviews": [
+                "3"
+            ]
+        }
+
+### Delete a Deployment [DELETE]
+
++ Parameters
+    + id: 1 (number) - ID of the Deployment in the form of an integer
+
++ Response 204
\ No newline at end of file
diff --git a/xos/tests/api/source/core/flavors.md b/xos/tests/api/source/core/flavors.md
new file mode 100644
index 0000000..aba5a6b
--- /dev/null
+++ b/xos/tests/api/source/core/flavors.md
@@ -0,0 +1,104 @@
+# Group Flavors
+
+List of the XOS flavors
+
+## Flavors [/api/core/flavors/{id}/]
+
+### List all flavors [GET]
+
++ Response 200 (application/json)
+
+        [
+            {
+                "humanReadableName": "m1.large",
+                "id": 1,
+                 "created": "2016-04-29T16:19:01.979548Z",
+                "updated": "2016-04-29T16:19:03.568238Z",
+                "enacted": null,
+                "policed": null,
+                "backend_register": "{}",
+                "backend_status": "0 - Provisioning in progress",
+                "deleted": false,
+                "write_protect": false,
+                "lazy_blocked": false,
+                "no_sync": true,
+                "name": "m1.large",
+                "description": null,
+                "flavor": "m1.large",
+                "order": 0,
+                "default": false,
+                "deployments": [
+                    "1"
+                ]
+            }
+        ]
+
+### Create a Flavor [POST]
+
++ Request (application/json)
+
+        {
+            "humanReadableName": "mq.test",
+        }
+
++ Response 200 (application/json)
+
+        {
+            "humanReadableName": "m1.large",
+            "id": 1,
+             "created": "2016-04-29T16:19:01.979548Z",
+            "updated": "2016-04-29T16:19:03.568238Z",
+            "enacted": null,
+            "policed": null,
+            "backend_register": "{}",
+            "backend_status": "0 - Provisioning in progress",
+            "deleted": false,
+            "write_protect": false,
+            "lazy_blocked": false,
+            "no_sync": true,
+            "name": "m1.large",
+            "description": null,
+            "flavor": "m1.large",
+            "order": 0,
+            "default": false,
+            "deployments": [
+                "1"
+            ]
+        }
+
+### View a Flavors Detail [GET]
+
++ Parameters
+    + id: 1 (number) - ID of the Flavors in the form of an integer
+
++ Response 200 (application/json)
+
+        {
+            "humanReadableName": "m1.large",
+            "id": 1,
+             "created": "2016-04-29T16:19:01.979548Z",
+            "updated": "2016-04-29T16:19:03.568238Z",
+            "enacted": null,
+            "policed": null,
+            "backend_register": "{}",
+            "backend_status": "0 - Provisioning in progress",
+            "deleted": false,
+            "write_protect": false,
+            "lazy_blocked": false,
+            "no_sync": true,
+            "name": "m1.large",
+            "description": null,
+            "flavor": "m1.large",
+            "order": 0,
+            "default": false,
+            "deployments": [
+                "1"
+            ]
+        }
+
+### Delete a Flavors Detail [DELETE]
+
++ Parameters
+    + id: 1 (number) - ID of the Flavors in the form of an integer
+
++ Response 204 
\ No newline at end of file
diff --git a/xos/tests/api/source/core/instances.md b/xos/tests/api/source/core/instances.md
new file mode 100644
index 0000000..9caf93e
--- /dev/null
+++ b/xos/tests/api/source/core/instances.md
@@ -0,0 +1,149 @@
+# Group Instances
+
+List of the XOS instances
+
+## Instances Collection [/api/core/instances/{?no_hyperlinks}]
+
+    + no_hyperlinks (number, optional) - Wheter to return relation with links or ids
+        + Default: `0`
+
+### List all Instances [GET]
+
++ Response 200 (application/json)
+
+        [
+            {
+                "id": 1,
+                "humanReadableName": "uninstantiated-1",
+                "created": "2016-04-26T00:36:22.465259Z",
+                "updated": "2016-04-26T00:36:22.465288Z",
+                "enacted": null,
+                "policed": null,
+                "backend_register": "{}",
+                "backend_status": "0 - Provisioning in progress",
+                "deleted": false,
+                "write_protect": false,
+                "lazy_blocked": false,
+                "no_sync": false,
+                "instance_id": null,
+                "instance_uuid": null,
+                "name": "mysite_vcpe",
+                "instance_name": null,
+                "ip": null,
+                "image": "1",
+                "creator": "1",
+                "slice": "1",
+                "deployment": "1",
+                "node": "1",
+                "numberCores": 0,
+                "flavor": "1",
+                "userData": null,
+                "isolation": "vm",
+                "volumes": "/etc/dnsmasq.d,/etc/ufw",
+                "parent": null,
+                "networks": [
+                    "1"
+                ]
+            }
+        ]
+
+### Create an Instance [POST]
+
++ Parameters
+    + no_hyperlinks: 1
+
++ Request (application/json)
+
+        {
+            "name": "test-instance",
+            "image": 1,
+            "slice": 1,
+            "deployment": 1,
+            "node": 1
+        }
+
++ Response 200 (application/json)
+
+        {
+            "id": 1,
+            "humanReadableName": "uninstantiated-1",
+            "created": "2016-04-26T00:36:22.465259Z",
+            "updated": "2016-04-26T00:36:22.465288Z",
+            "enacted": null,
+            "policed": null,
+            "backend_register": "{}",
+            "backend_status": "0 - Provisioning in progress",
+            "deleted": false,
+            "write_protect": false,
+            "lazy_blocked": false,
+            "no_sync": false,
+            "instance_id": null,
+            "instance_uuid": null,
+            "name": "test-instance",
+            "instance_name": null,
+            "ip": null,
+            "image": "1",
+            "creator": "1",
+            "slice": "1",
+            "deployment": "1",
+            "node": "1",
+            "numberCores": 0,
+            "flavor": "1",
+            "userData": null,
+            "isolation": "vm",
+            "volumes": "/etc/dnsmasq.d,/etc/ufw",
+            "parent": null,
+            "networks": [
+                "1"
+            ]
+        }
+
+## Instances Detail [/api/core/instances/{id}/]
+
+### Get instance details [GET]
+
++ Parameters
+    + id: 1 (number) - ID of the Instance in the form of an integer
+
++ Response 200 (application/json)
+
+        {
+            "id": 1,
+            "humanReadableName": "uninstantiated-1",
+            "created": "2016-04-26T00:36:22.465259Z",
+            "updated": "2016-04-26T00:36:22.465288Z",
+            "enacted": null,
+            "policed": null,
+            "backend_register": "{}",
+            "backend_status": "0 - Provisioning in progress",
+            "deleted": false,
+            "write_protect": false,
+            "lazy_blocked": false,
+            "no_sync": false,
+            "instance_id": null,
+            "instance_uuid": null,
+            "name": "mysite_vcpe",
+            "instance_name": null,
+            "ip": null,
+            "image": "1",
+            "creator": "1",
+            "slice": "1",
+            "deployment": "1",
+            "node": "1",
+            "numberCores": 0,
+            "flavor": "1",
+            "userData": null,
+            "isolation": "vm",
+            "volumes": "/etc/dnsmasq.d,/etc/ufw",
+            "parent": null,
+            "networks": [
+                "1"
+            ]
+        }
+
+### Delete instance [DELETE]
+
++ Parameters
+    + id: 1 (number) - ID of the Instance in the form of an integer
+
++ Response 204
\ No newline at end of file
diff --git a/xos/tests/api/source/core/nodes.md b/xos/tests/api/source/core/nodes.md
new file mode 100644
index 0000000..d9931dc
--- /dev/null
+++ b/xos/tests/api/source/core/nodes.md
@@ -0,0 +1,30 @@
+# Group Nodes
+
+List of the XOS nodes
+
+## Nodes [/api/core/nodes/{id}/]
+
+### List all nodes [GET]
+
++ Response 200 (application/json)
+
+        [
+            {
+                "humanReadableName": "node2.opencloud.us",
+                "id": 1,
+                "created": "2016-04-29T16:19:05.661567Z",
+                "updated": "2016-04-29T16:19:05.661454Z",
+                "enacted": null,
+                "policed": null,
+                "backend_register": "{}",
+                "backend_status": "0 - Provisioning in progress",
+                "deleted": false,
+                "write_protect": false,
+                "lazy_blocked": false,
+                "no_sync": true,
+                "name": "node2.opencloud.us",
+                "site_deployment": "1",
+                "site": "1",
+                "nodelabels": []
+            }
+        ]
diff --git a/xos/tests/api/source/core/services.md b/xos/tests/api/source/core/services.md
new file mode 100644
index 0000000..3454bdb
--- /dev/null
+++ b/xos/tests/api/source/core/services.md
@@ -0,0 +1,120 @@
+# Group Services
+
+List of the XOS Services
+
+## Services [/api/core/services/{id}/]
+
+### List all Services [GET]
+
++ Response 200 (application/json)
+
+        [
+            {
+                "humanReadableName": "MyService",
+                "id": 1,
+                "created": "2016-05-05T23:06:33.835277Z",
+                "updated": "2016-05-05T23:06:33.835302Z",
+                "enacted": null,
+                "policed": null,
+                "backend_register": "{}",
+                "backend_status": "0 - Provisioning in progress",
+                "deleted": false,
+                "write_protect": false,
+                "lazy_blocked": false,
+                "no_sync": false,
+                "no_policy": false,
+                "description": null,
+                "enabled": true,
+                "kind": "vROUTER",
+                "name": "MyService",
+                "versionNumber": null,
+                "published": true,
+                "view_url": "/admin/vrouter/vrouterservice/$id$/",
+                "icon_url": null,
+                "public_key": null,
+                "private_key_fn": null,
+                "service_specific_id": null,
+                "service_specific_attribute": null
+            }
+        ]
+
+### Create a Service [POST]
+
++ Request (application/json)
+
+        {
+            "name": "MyService",
+            "kind": "vROUTER"
+        }
+
++ Response 200 (application/json)
+
+        {
+            "humanReadableName": "MyService",
+            "id": 1,
+            "created": "2016-05-05T23:06:33.835277Z",
+            "updated": "2016-05-05T23:06:33.835302Z",
+            "enacted": null,
+            "policed": null,
+            "backend_register": "{}",
+            "backend_status": "0 - Provisioning in progress",
+            "deleted": false,
+            "write_protect": false,
+            "lazy_blocked": false,
+            "no_sync": false,
+            "no_policy": false,
+            "description": null,
+            "enabled": true,
+            "kind": "vROUTER",
+            "name": "MyService",
+            "versionNumber": null,
+            "published": true,
+            "view_url": "/admin/vrouter/vrouterservice/$id$/",
+            "icon_url": null,
+            "public_key": null,
+            "private_key_fn": null,
+            "service_specific_id": null,
+            "service_specific_attribute": null
+        }
+
+### View a Service Detail [GET]
+
++ Parameters
+    + id: 1 (number) - ID of the Service in the form of an integer
+
++ Response 200 (application/json)
+
+        {
+                "humanReadableName": "MyService",
+                "id": 1,
+                "created": "2016-05-05T23:06:33.835277Z",
+                "updated": "2016-05-05T23:06:33.835302Z",
+                "enacted": null,
+                "policed": null,
+                "backend_register": "{}",
+                "backend_status": "0 - Provisioning in progress",
+                "deleted": false,
+                "write_protect": false,
+                "lazy_blocked": false,
+                "no_sync": false,
+                "no_policy": false,
+                "description": null,
+                "enabled": true,
+                "kind": "vROUTER",
+                "name": "MyService",
+                "versionNumber": null,
+                "published": true,
+                "view_url": "/admin/vrouter/vrouterservice/$id$/",
+                "icon_url": null,
+                "public_key": null,
+                "private_key_fn": null,
+                "service_specific_id": null,
+                "service_specific_attribute": null
+            }
+
+### Delete a Service [DELETE]
+
++ Parameters
+    + id: 1 (number) - ID of the Service in the form of an integer
+
++ Response 204
diff --git a/xos/tests/api/source/core/sites.md b/xos/tests/api/source/core/sites.md
new file mode 100644
index 0000000..c3784db
--- /dev/null
+++ b/xos/tests/api/source/core/sites.md
@@ -0,0 +1,38 @@
+# Group Sites
+
+List of the XOS sites
+
+## Sites [/api/core/sites/{id}/]
+
+### List all sites [GET]
+
++ Response 200 (application/json)
+
+        {
+            "humanReadableName": "MySite",
+            "id": 1,
+            "created": "2016-04-29T16:19:03.587770Z",
+            "updated": "2016-04-29T16:19:05.651933Z",
+            "enacted": null,
+            "policed": null,
+            "backend_register": "{}",
+            "backend_status": "0 - Provisioning in progress",
+            "deleted": false,
+            "write_protect": false,
+            "lazy_blocked": false,
+            "no_sync": false,
+            "name": "MySite",
+            "site_url": "http://opencord.us/",
+            "enabled": true,
+            "hosts_nodes": true,
+            "hosts_users": true,
+            "location": null,
+            "longitude": null,
+            "latitude": null,
+            "login_base": "mysite",
+            "is_public": true,
+            "abbreviated_name": "",
+            "deployments": [
+                "1"
+            ]
+        }
\ No newline at end of file
diff --git a/xos/tests/api/source/core/slices.md b/xos/tests/api/source/core/slices.md
new file mode 100644
index 0000000..6ec5c7e
--- /dev/null
+++ b/xos/tests/api/source/core/slices.md
@@ -0,0 +1,46 @@
+# Group Slices
+
+List of the XOS slices
+
+## Slices [/api/core/slices/{id}/]
+
+### List all slices [GET]
+
++ Response 200 (application/json)
+
+        [
+            {
+                "humanReadableName": "mysite_slice",
+                "id": 1,
+                "created": "2016-04-29T16:23:22.505072Z",
+                "updated": "2016-04-29T16:23:22.504691Z",
+                "enacted": null,
+                "policed": "2016-04-29T16:23:22.781298Z",
+                "backend_register": "{}",
+                "backend_status": "0 - Provisioning in progress",
+                "deleted": false,
+                "write_protect": false,
+                "lazy_blocked": false,
+                "no_sync": false,
+                "name": "mysite_slice",
+                "enabled": true,
+                "omf_friendly": false,
+                "description": "",
+                "slice_url": "",
+                "site": "http://apt118.apt.emulab.net/api/core/sites/1/",
+                "max_instances": 10,
+                "service": null,
+                "network": null,
+                "exposed_ports": null,
+                "serviceClass": "http://apt118.apt.emulab.net/api/core/serviceclasses/1/",
+                "creator": "http://apt118.apt.emulab.net/api/core/users/1/",
+                "default_flavor": null,
+                "default_image": null,
+                "mount_data_sets": "GenBank",
+                "default_isolation": "vm",
+                "networks": [
+                    "http://apt118.apt.emulab.net/api/core/networks/1/"
+                ]
+            }
+        ]
+        
\ No newline at end of file
diff --git a/xos/tests/api/source/core/users.md b/xos/tests/api/source/core/users.md
new file mode 100644
index 0000000..8ccabb5
--- /dev/null
+++ b/xos/tests/api/source/core/users.md
@@ -0,0 +1,41 @@
+# Group Users
+
+List of the XOS users
+
+## Users [/api/core/users/{id}/]
+
+### List all Users [GET]
+
++ Response 200 (application/json)
+
+        [
+            {
+                "id": 2,
+                "password": "pbkdf2_sha256$12000$9gn8DmZuIoz2$YPQkx3AOOV7jZNYr2ddrgUCkiuaPpvb8+aJR7RwLZNA=",
+                "last_login": "2016-04-12T18:50:45.880823Z",
+                "email": "johndoe@myhouse.com",
+                "username": "johndoe@myhouse.com",
+                "firstname": "john",
+                "lastname": "doe",
+                "phone": null,
+                "user_url": null,
+                "site": "http://xos.dev:9999/api/core/sites/1/",
+                "public_key": null,
+                "is_active": true,
+                "is_admin": false,
+                "is_staff": true,
+                "is_readonly": false,
+                "is_registering": false,
+                "is_appuser": false,
+                "login_page": null,
+                "created": "2016-04-12T18:50:45.912602Z",
+                "updated": "2016-04-12T18:50:45.912671Z",
+                "enacted": null,
+                "policed": null,
+                "backend_status": "Provisioning in progress",
+                "deleted": false,
+                "write_protect": false,
+                "timezone": "America/New_York"
+            }
+        ]
+        
\ No newline at end of file
diff --git a/xos/tests/api/source/service/exampleservice.md b/xos/tests/api/source/service/exampleservice.md
new file mode 100644
index 0000000..96a19c7
--- /dev/null
+++ b/xos/tests/api/source/service/exampleservice.md
@@ -0,0 +1,15 @@
+# Group Example
+
+## Example Services Collection [/api/service/exampleservice/]
+
+### List all Example Services [GET]
+
++ Response 200 (application/json)
+
+        [
+            {
+                "humanReadableName": "MyExample",
+                "id": 1,
+                "service_message": "This is the test message"
+            }
+        ]
\ No newline at end of file
diff --git a/xos/tests/api/source/service/onos.md b/xos/tests/api/source/service/onos.md
new file mode 100644
index 0000000..0b82a86
--- /dev/null
+++ b/xos/tests/api/source/service/onos.md
@@ -0,0 +1,20 @@
+# Group ONOS Services
+
+List of the active onos services
+
+## ONOS Services Collection [/api/service/onos/]
+
+### List all ONOS Services [GET]
+
++ Response 200 (application/json)
+
+        [
+            {
+                "humanReadableName": "service_ONOS_vBNG",
+                "id": 5,
+                "rest_hostname": "",
+                "rest_port": "8181",
+                "no_container": false,
+                "node_key": ""
+            }
+        ]
\ No newline at end of file
diff --git a/xos/tests/api/source/service/vsg.md b/xos/tests/api/source/service/vsg.md
new file mode 100644
index 0000000..1a0569a
--- /dev/null
+++ b/xos/tests/api/source/service/vsg.md
@@ -0,0 +1,17 @@
+# Group vSG
+
+## vSG Collection [/api/service/vsg/]
+
+### List all vSGs [GET]
+
++ Response 200 (application/json)
+
+        [
+            {
+                "humanReadableName": "service_vsg",
+                "id": 2,
+                "dns_servers": "8.8.8.8",
+                "url_filter_kind": null,
+                "node_label": null
+            }
+        ]
\ No newline at end of file
diff --git a/xos/tests/api/source/tenant/cord/subscribers.md b/xos/tests/api/source/tenant/cord/subscribers.md
new file mode 100644
index 0000000..61126ce
--- /dev/null
+++ b/xos/tests/api/source/tenant/cord/subscribers.md
@@ -0,0 +1,230 @@
+# Group Subscribers
+
+Resource related to the CORD Subscribers.
+
+## Subscribers [/api/tenant/cord/subscriber/{subscriber_id}/]
+
+### List All Subscribers [GET]
+
++ Response 200 (application/json)
+
+        [
+            {
+                "humanReadableName": "cordSubscriber-1",
+                "id": 1,
+                "features": {
+                    "cdn": false,
+                    "uplink_speed": 1000000000,
+                    "downlink_speed": 1000000000,
+                    "uverse": false,
+                    "status": "enabled"
+                },
+                "identity": {
+                    "account_num": "123",
+                    "name": "My House"
+                },
+                "related": {
+                    "instance_name": "mysite_vcpe",
+                    "vsg_id": 4,
+                    "compute_node_name": "node2.opencloud.us",
+                    "c_tag": "432",
+                    "instance_id": 1,
+                    "wan_container_ip": null,
+                    "volt_id": 3,
+                    "s_tag": "222"
+                }
+            }
+        ]
+
+
+### View a Subscriber Detail [GET]
+
++ Parameters
+    + subscriber_id: 1 (number) - ID of the Subscriber in the form of an integer
+
++ Response 200 (application/json)
+ 
+        {
+            "humanReadableName": "cordSubscriber-1", 
+            "id": 1, 
+            "features": { 
+                "cdn": false, 
+                "uplink_speed": 1000000000, 
+                "downlink_speed": 1000000000, 
+                "uverse": false, 
+                "status": "enabled" 
+            }, 
+            "identity": { 
+                "account_num": "123",
+                "name": "My House"
+            }, 
+            "related": { 
+                "instance_name": "mysite_vcpe", 
+                "vsg_id": 4, 
+                "compute_node_name": "node2.opencloud.us",
+                "c_tag": "432", 
+                "instance_id": 1, 
+                "wan_container_ip": null, 
+                "volt_id": 3, 
+                "s_tag": "222" 
+            } 
+        }
+
+### Delete a Subscriber [DELETE]
+
++ Parameters
+    + subscriber_id: 1 (number) - ID of the Subscriber in the form of an integer
+
++ Response 204
+
+### Subscriber features [/api/tenant/cord/subscriber/{subscriber_id}/features/]
+
++ Parameters
+    + subscriber_id: 1 (number) - ID of the Subscriber in the form of an integer
+
+### View a Subscriber Features Detail [GET]
+
++ Response 200 (application/json)
+
+        {
+            "cdn": false, 
+            "uplink_speed": 1000000000, 
+            "downlink_speed": 1000000000, 
+            "uverse": true, 
+            "status": "enabled"
+        }
+
+#### Subscriber features uplink_speed [/api/tenant/cord/subscriber/{subscriber_id}/features/uplink_speed/]
+
++ Parameters
+    + subscriber_id: 1 (number) - ID of the Subscriber in the form of an integer
+
+#### Read Subscriber uplink_speed [GET]
+
++ Response 200 (application/json)
+
+        {
+            "uplink_speed": 1000000000
+        }
+
+#### Update Subscriber uplink_speed [PUT]
+
++ Request 200 (application/json)
+
+        {
+            "uplink_speed": 1000000000
+        }
+
++ Response 200 (application/json)
+
+        {
+            "uplink_speed": 1000000000
+        }
+
+#### Subscriber features downlink_speed [/api/tenant/cord/subscriber/{subscriber_id}/features/downlink_speed/]
+
++ Parameters
+    + subscriber_id: 1 (number) - ID of the Subscriber in the form of an integer
+
+#### Read Subscriber downlink_speed [GET]
+
++ Response 200 (application/json)
+
+        {
+            "downlink_speed": 1000000000
+        }
+
+#### Update Subscriber downlink_speed [PUT]
+
++ Request 200 (application/json)
+
+        {
+            "downlink_speed": 1000000000
+        }
+
++ Response 200 (application/json)
+
+        {
+            "downlink_speed": 1000000000
+        }
+
+#### Subscriber features cdn [/api/tenant/cord/subscriber/{subscriber_id}/features/cdn/]
+
++ Parameters
+    + subscriber_id: 1 (number) - ID of the Subscriber in the form of an integer
+
+#### Read Subscriber cdn [GET]
+
++ Response 200 (application/json)
+
+        {
+            "cdn": false
+        }
+
+#### Update Subscriber cdn [PUT]
+
++ Request 200 (application/json)
+
+        {
+            "cdn": false
+        }
+
++ Response 200 (application/json)
+
+        {
+            "cdn": false
+        }
+
+#### Subscriber features uverse [/api/tenant/cord/subscriber/{subscriber_id}/features/uverse/]
+
++ Parameters
+    + subscriber_id: 1 (number) - ID of the Subscriber in the form of an integer
+
+#### Read Subscriber uverse [GET]
+
++ Response 200 (application/json)
+
+        {
+            "uverse": false
+        }
+
+#### Update Subscriber uverse [PUT]
+
++ Request 200 (application/json)
+
+        {
+            "uverse": false
+        }
+
++ Response 200 (application/json)
+
+        {
+            "uverse": false
+        }
+
+#### Subscriber features status [/api/tenant/cord/subscriber/{subscriber_id}/features/status/]
+
++ Parameters
+    + subscriber_id: 1 (number) - ID of the Subscriber in the form of an integer
+
+#### Read Subscriber status [GET]
+
++ Response 200 (application/json)
+
+        {
+            "status": "enabled"
+        }
+
+#### Update Subscriber status [PUT]
+
++ Request 200 (application/json)
+
+        {
+            "status": "enabled"
+        }
+
++ Response 200 (application/json)
+
+        {
+            "status": "enabled"
+        }
\ No newline at end of file
diff --git a/xos/tests/api/source/tenant/cord/truckroll.md b/xos/tests/api/source/tenant/cord/truckroll.md
new file mode 100644
index 0000000..996c19c
--- /dev/null
+++ b/xos/tests/api/source/tenant/cord/truckroll.md
@@ -0,0 +1,83 @@
+# Group Truckroll
+
+Virtual Truckroll, enable to perform basic test on user connectivity such as ping, traceroute and tcpdump.
+
+## Truckroll Collection [/api/tenant/truckroll/{truckroll_id}/]
+
+### List all Truckroll [GET]
+
++ Response 200 (application/json)
+
+        [
+            {
+                "humanReadableName": "vTR-tenant-9",
+                "id": 9,
+                "provider_service": 6,
+                "target_id": 2,
+                "scope": "container",
+                "test": "ping",
+                "argument": "8.8.8.8",
+                "result": "",
+                "result_code": "",
+                "is_synced": false,
+                "backend_status": "2 - Exception('Unreachable results in ansible recipe',)"
+            }
+        ]
+
+### Create a Truckroll [POST]
+
+A virtual truckroll is complete once is_synced equal true
+
++ Request (application/json)
+
+        {
+            "target_id": 2,
+            "scope": "container",
+            "test": "ping",
+            "argument": "8.8.8.8"
+        }
+
++ Response 201 (application/json)
+
+        {
+            "humanReadableName": "vTR-tenant-1",
+            "id": 1,
+            "provider_service": 6,
+            "target_id": 2,
+            "scope": "container",
+            "test": "ping",
+            "argument": "8.8.8.8",
+            "result": null,
+            "result_code": null,
+            "is_synced": false,
+            "backend_status": "0 - Provisioning in progress"
+        }
+
+
+### View a Truckroll Detail [GET]
+
++ Parameters
+    + truckroll_id: 1 (number) - ID of the Truckroll in the form of an integer
+
++ Response 200 (application/json)
+
+        {
+            "humanReadableName": "vTR-tenant-10",
+            "id": 10,
+            "provider_service": 6,
+            "target_id": 2,
+            "scope": "container",
+            "test": "ping",
+            "argument": "8.8.8.8",
+            "result": null,
+            "result_code": null,
+            "is_synced": false,
+            "backend_status": "0 - Provisioning in progress"
+        }
+
+### Delete a Truckroll Detail [DELETE]
+
++ Parameters
+    + truckroll_id: 1 (number) - ID of the Truckroll in the form of an integer
+
++ Response 204
diff --git a/xos/tests/api/source/tenant/cord/volt.md b/xos/tests/api/source/tenant/cord/volt.md
new file mode 100644
index 0000000..51cb679
--- /dev/null
+++ b/xos/tests/api/source/tenant/cord/volt.md
@@ -0,0 +1,78 @@
+# Group vOLT
+
+OLT devices aggregate a set of subscriber connections
+
+## vOLT Collection [/api/tenant/cord/volt/{volt_id}/]
+
+### List all vOLT [GET]
+
++ Response 200 (application/json)
+
+        [
+            {
+                "humanReadableName": "vOLT-tenant-1",
+                "id": 1,
+                "service_specific_id": "123",
+                "s_tag": "222",
+                "c_tag": "432",
+                "subscriber": 1,
+                "related": {
+                    "instance_id": 1,
+                    "instance_name": "mysite_vcpe",
+                    "vsg_id": 4,
+                    "wan_container_ip": null,
+                    "compute_node_name": "node2.opencloud.us"
+                }
+            }
+        ]
+
+### Create a vOLT [POST]
+
++ Request (application/json)
+
+        {
+            "s_tag": "222",
+            "c_tag": "432",
+            "subscriber": 1
+        }
+
++ Response 201 (application/json)
+
+        {
+                "humanReadableName": "vOLT-tenant-1",
+                "id": 1,
+                "service_specific_id": "123",
+                "s_tag": "222",
+                "c_tag": "432",
+                "subscriber": 1,
+                "related": {
+                    "instance_id": 1,
+                    "instance_name": "mysite_vcpe",
+                    "vsg_id": 4,
+                    "wan_container_ip": null,
+                    "compute_node_name": "node2.opencloud.us"
+                }
+            }
+
+### View a vOLT Detail [GET]
+
++ Parameters
+    + volt_id: 1 (number) - ID of the vOLT in the form of an integer
+
++ Response 200 (application/json)
+
+        {
+            "humanReadableName": "vOLT-tenant-1",
+            "id": 1,
+            "service_specific_id": "123",
+            "s_tag": "222",
+            "c_tag": "432",
+            "subscriber": 1,
+            "related": {
+                "instance_id": 1,
+                "instance_name": "mysite_vcpe",
+                "vsg_id": 4,
+                "wan_container_ip": null,
+                "compute_node_name": "node2.opencloud.us"
+            }
+        }
diff --git a/xos/tests/api/source/tenant/onos/app.md b/xos/tests/api/source/tenant/onos/app.md
new file mode 100644
index 0000000..5376c33
--- /dev/null
+++ b/xos/tests/api/source/tenant/onos/app.md
@@ -0,0 +1,16 @@
+# Group ONOS Apps
+
+## ONOS App Collection [/api/tenant/onos/app/]
+
+### List all apps [GET]
+
++ Response 200 (application/json)
+
+        [
+            {
+                "humanReadableName": "onos-tenant-7",
+                "id": 7,
+                "name": "vBNG_ONOS_app",
+                "dependencies": "org.onosproject.proxyarp, org.onosproject.virtualbng, org.onosproject.openflow, org.onosproject.fwd"
+            }
+        ]
\ No newline at end of file
diff --git a/xos/tests/api/source/utility/utility.md b/xos/tests/api/source/utility/utility.md
new file mode 100644
index 0000000..63379be
--- /dev/null
+++ b/xos/tests/api/source/utility/utility.md
@@ -0,0 +1,31 @@
+# Group Utility
+
+List of the XOS Utility API
+
+## Login [/api/utility/login/]
+
+### Log a user in the system [POST]
+
++ Request (application/json)
+
+        {
+            "username": "padmin@vicci.org",
+            "password": "letmein"
+        }
+
++ Response 200 (application/json)
+
+        {
+            "xoscsrftoken":"xuvsRC1jkXAsnrdRlgJvcXpmtthTAqqf",
+            "xossessionid":"7ds5a3wzjlgbjqo4odkd25qsm0j2s6zg",
+            "user": "{\"policed\": null, \"site\": 3, \"is_appuser\": false, \"is_staff\": true, \"backend_status\": \"Provisioning in progress\", \"id\": 3, \"is_registering\": false, \"last_login\": \"2016-04-30T22:51:04.788675+00:00\", \"email\": \"padmin@vicci.org\", \"no_sync\": false, \"username\": \"padmin@vicci.org\", \"dashboards\": [11], \"login_page\": null, \"firstname\": \"XOS\", \"user_url\": null, \"deleted\": false, \"lastname\": \"admin\", \"is_active\": true, \"lazy_blocked\": false, \"phone\": null, \"is_admin\": true, \"enacted\": null, \"public_key\": null, \"is_readonly\": false, \"no_policy\": false, \"write_protect\": false}"
+        }
+
+## Logout [/api/utility/logout/]
+
+### Log a user out of the system [POST]
+
++ Request (application/json)
+        {xossessionid: "sessionId"}
+
++ Response 200 (application/json)
diff --git a/xos/tests/instancetest.py b/xos/tests/instancetest.py
new file mode 100644
index 0000000..2813521
--- /dev/null
+++ b/xos/tests/instancetest.py
@@ -0,0 +1,51 @@
+"""
+    Basic Instance Test
+
+    1) Create a slice1
+    2) Create instance1 on slice1
+"""
+
+import os
+import json
+import sys
+import time
+
+sys.path.append("/opt/xos")
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
+from openstack.manager import OpenStackManager
+from core.models import Slice, Instance, ServiceClass, Reservation, Tag, Network, User, Node, Image, Deployment, Site, NetworkTemplate, NetworkSlice
+
+from planetstacktest import PlanetStackTest, fail_unless
+
+class InstanceTest(PlanetStackTest):
+    def __init__(self):
+        PlanetStackTest.__init__(self)
+
+    def run_instance1(self):
+        slice1Name = self.make_slice_name()
+        slice1 = Slice(name = slice1Name,
+                       omf_friendly=True,
+                       site=self.testSite,
+                       creator=self.testUser)
+        slice1=self.save_and_wait_for_enacted(slice1, nonempty_fields=["tenant_id"])
+
+        instance1 = Instance(image = self.testImage,
+                         creator=self.testUser,
+                         slice=slice1,
+                         node=self.testNode,
+                         deploymentNetwork=self.testDeployment)
+        instance1=self.save_and_wait_for_enacted(instance1, nonempty_fields=["instance_id", "ip"])
+
+    def run(self):
+        self.setup()
+        try:
+             self.run_instance1()
+        finally:
+             self.cleanup()
+
+def main():
+    InstanceTest().run()
+
+if __name__=="__main__":
+    main()
diff --git a/xos/tests/networktest.py b/xos/tests/networktest.py
new file mode 100644
index 0000000..b4bcbd2
--- /dev/null
+++ b/xos/tests/networktest.py
@@ -0,0 +1,195 @@
+"""
+    Network Data Model Test
+
+    1) Create a slice1
+    2) Create instance1 on slice1
+    3) Verify one quantum network created for instance1
+    4) Create a private network, network1
+    5) Connect network1 to slice1
+    6) Create instance1_2 on slice1
+    7) Verify two quantum networks created for instance1_2
+"""
+
+import os
+import json
+import sys
+import time
+
+sys.path.append("/opt/xos")
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
+from openstack.manager import OpenStackManager
+from core.models import Slice, Instance, ServiceClass, Reservation, Tag, Network, User, Node, Image, Deployment, Site, NetworkTemplate, NetworkSlice
+
+from planetstacktest import PlanetStackTest, fail_unless, fail
+
+class NetworkTest(PlanetStackTest):
+    def __init__(self):
+        PlanetStackTest.__init__(self)
+
+    def wait_for_ports(self, instance, count=1, max_time=120):
+        print "waiting for %d ports on %s" % (count, str(instance))
+        while max_time>0:
+            ports = self.manager.driver.shell.quantum.list_ports(device_id=instance.instance_id)["ports"]
+            if len(ports)==count:
+                return ports
+
+            fail_unless(len(ports)<=count, "too many ports")
+
+            time.sleep(10)
+            max_time = max_time - 10
+
+        fail("timed out while waiting for port creation")
+
+    def ports_to_networks(self, ports):
+        networks = []
+        for port in ports:
+            port_networks = networks + self.manager.driver.shell.quantum.list_networks(id=port["network_id"])["networks"]
+            for network in port_networks:
+                if not (network in networks):
+                    networks.append(network)
+        return networks
+
+    def ports_to_network_names(self, ports):
+        network_names = []
+        for network in self.ports_to_networks(ports):
+             network_names.append(network["name"])
+        return network_names
+
+    def verify_network_names(self, ports, network_names):
+        port_network_names = sorted(self.ports_to_network_names(ports))
+        network_names = sorted(network_names)
+        fail_unless(port_network_names == network_names, "mismatched network names: %s != %s" % (str(port_network_names), str(network_names)))
+        print "   verified network ports to", ",".join(port_network_names)
+
+    def test_slice1(self):
+        slice1Name = self.make_slice_name()
+        slice1 = Slice(name = slice1Name,
+                       omf_friendly=True,
+                       site=self.testSite,
+                       creator=self.testUser)
+        slice1=self.save_and_wait_for_enacted(slice1, nonempty_fields=["tenant_id"])
+
+        instance1 = Instance(image = self.testImage,
+                         creator=self.testUser,
+                         slice=slice1,
+                         node=self.testNode,
+                         deploymentNetwork=self.testDeployment)
+        instance1=self.save_and_wait_for_enacted(instance1, nonempty_fields=["instance_id", "ip"])
+
+        # instance1 should have only one port, its private network
+        ports = self.wait_for_ports(instance1, count=1)
+        self.verify_network_names(ports, [slice1.name])
+
+        network1 = Network(name = slice1Name + "-pvt",
+                           template = self.get_network_template("private"),
+                           owner = slice1)
+        network1=self.save_and_wait_for_enacted(network1, nonempty_fields=["network_id", "subnet_id", "router_id", "subnet"])
+
+        network1_slice1 = NetworkSlice(network=network1, slice=slice1)
+        network1_slice1.save() # does not need to be enacted
+
+        instance1_2 = Instance(image = self.testImage,
+                         creator=self.testUser,
+                         slice=slice1,
+                         node=self.testNode,
+                         deploymentNetwork=self.testDeployment)
+        instance1_2=self.save_and_wait_for_enacted(instance1_2, nonempty_fields=["instance_id", "ip"])
+
+        ports = self.wait_for_ports(instance1_2, count=2)
+        self.verify_network_names(ports, [slice1.name, network1.name])
+
+        self.slice1 = slice1
+        self.network1 = network1
+
+    def test_slice2(self):
+        slice2Name = self.make_slice_name()
+        slice2 = Slice(name = slice2Name,
+                       omf_friendly=True,
+                       site=self.testSite,
+                       creator=self.testUser)
+        slice2=self.save_and_wait_for_enacted(slice2, nonempty_fields=["tenant_id"])
+
+        network2 = Network(name = slice2Name + "-pvt",
+                           template = self.get_network_template("private"),
+                           owner = slice2)
+        network2=self.save_and_wait_for_enacted(network2, nonempty_fields=["network_id", "subnet_id", "router_id", "subnet"])
+
+        network2_slice2 = NetworkSlice(network=network2, slice=slice2)
+        network2_slice2.save() # does not need to be enacted
+
+        instance2_1 = Instance(image = self.testImage,
+                         creator=self.testUser,
+                         slice=slice2,
+                         node=self.testNode,
+                         deploymentNetwork=self.testDeployment)
+        instance2_1=self.save_and_wait_for_enacted(instance2_1, nonempty_fields=["instance_id", "ip"])
+
+        ports = self.wait_for_ports(instance2_1, count=2)
+        self.verify_network_names(ports, [slice2.name, network2.name])
+
+        self.slice2 = slice2
+        self.network2 = network2
+
+    def test_shared_private_net(self):
+        # connect network2 to slice1
+        self.network2.permittedSlices.add(self.slice1)
+        network2_slice1 = NetworkSlice(network=self.network2, slice=self.slice1)
+        network2_slice1.save()
+
+        instance1_3 = Instance(image = self.testImage,
+                         creator=self.testUser,
+                         slice=self.slice1,
+                         node=self.testNode,
+                         deploymentNetwork=self.testDeployment)
+        instance1_3=self.save_and_wait_for_enacted(instance1_3, nonempty_fields=["instance_id", "ip"])
+
+        ports = self.wait_for_ports(instance1_3, count=3)
+        self.verify_network_names(ports, [self.slice1.name, self.network1.name, self.network2.name])
+
+    def test_nat_net(self):
+        slice3Name = self.make_slice_name()
+        slice3 = Slice(name = slice3Name,
+                       omf_friendly=True,
+                       site=self.testSite,
+                       creator=self.testUser)
+        slice3=self.save_and_wait_for_enacted(slice3, nonempty_fields=["tenant_id"])
+
+        network3 = Network(name = slice3Name + "-nat",
+                           template = self.get_network_template("private-nat"),
+                           owner = slice3)
+        # note that router_id will not be filled in for nat-net, since nat-net has no routers
+        network3=self.save_and_wait_for_enacted(network3, nonempty_fields=["network_id", "subnet_id", "subnet"])
+
+        network3_slice3 = NetworkSlice(network=network3, slice=slice3)
+        network3_slice3.save() # does not need to be enacted
+
+        instance3_1 = Instance(image = self.testImage,
+                         creator=self.testUser,
+                         slice=slice3,
+                         node=self.testNode,
+                         deploymentNetwork=self.testDeployment)
+        instance3_1=self.save_and_wait_for_enacted(instance3_1, nonempty_fields=["instance_id", "ip"])
+
+        ports = self.wait_for_ports(instance3_1, count=2)
+        self.verify_network_names(ports, [slice3.name, "nat-net"])
+
+    def run(self):
+        self.setup()
+        try:
+             self.test_slice1()
+             self.test_slice2()
+             self.test_shared_private_net()
+             self.test_nat_net()
+             print "SUCCESS"
+        finally:
+             self.cleanup()
+
+def main():
+    NetworkTest().run()
+
+if __name__=="__main__":
+    main()
+
+
+
diff --git a/xos/tests/permissiontest.py b/xos/tests/permissiontest.py
new file mode 100644
index 0000000..191eae6
--- /dev/null
+++ b/xos/tests/permissiontest.py
@@ -0,0 +1,170 @@
+import unittest
+from core.models import *
+
+class TestPermission(unittest.TestCase):
+    
+    def setUp(self):
+        self.test_objects = []
+        # deployment
+        self.deployment = Deployment(name='TestDeployment')
+        self.deployment.save()
+        self.test_objects.append(self.deployment)
+        # site
+        self.site = Site(name='TestSite')
+        self.site.save()
+        self.test_objects.append(self.site)
+        # site deployment
+        self.site_deployment = SiteDeployment(site=self.site, deployment=self.deployment)
+        self.site_deployment.save()
+        self.test_objects.append(self.site_deployment)
+        # node
+        self.node = Node(name='TestNode', site_deployment=self.site_deployment)
+        self.node.save()
+        self.test_objects.append(self.node)
+        # slice
+        self.slice = Slice(name='TestSlice', site=self.site)
+        self.slice.save()
+        self.test_objects.appen(slice.slice)
+        # admin user
+        self.user_admin = User(email='user_admin@test.com', first_name='Test', last_name='Test', is_admin=True)
+        self.user_admin.site = self.site
+        self.user_admin.save()
+        self.test_objects.append(self.user_admin)
+        # read only user
+        self.user_read_only = User(email='user_read_only@test.com', first_name='Test', last_name='Test')
+        self.user_read_only.site = self.site
+        self.user_read_only.save()
+        self.test_objects.append(self.user_read_only)
+        # default user
+        self.user_default = User(email='user_default@test.com', first_name='Test', last_name='Test')
+        self.user_default.site = self.site 
+        self.user_default.save()
+        self.test_objects.append(self.user_default)
+
+        # deployment admin 
+        self.user_deployment_admin = User(email='user_deployment_admin@test.com', first_name='Test', last_name='Test')
+        self.user_deployment_admin.site = self.site
+        self.user_deployment_admin.save()
+        self.test_objects.append(self.user_deployment_admin)
+        deployment_privilege = DeploymentPrivilege(
+            user=self.user_deployment_admin,
+            deployment=self.deployment,
+            role='admin')
+        deployment_privilege.save()
+        self.test_objects.append(deployment_privilege)
+        # site admin
+        self.user_site_admin = User(email='user_site_admin@test.com', first_name='Test', last_name='Test')
+        self.user_site_admin = self.site
+        self.user_site_admin.save()
+        self.test_objects.append(self.user_site_admin)
+        site_admin_privilege = SitePrivilege(
+            user = self.user_site_admin,
+            site=self.site,
+            role='admin')
+        site_admin_privilege.save()
+        self.test_objects.append(site_admin_privilege)
+        # site pi
+        self.user_site_pi = User(email='user_site_pi@test.com', first_name='Test', last_name='Test')
+        self.user_site_pi = self.site
+        self.user_site_pi.save()
+        self.test_objects.append(self.user_site_pi)
+        site_pi_privilege = SitePrivilege(
+            user = self.user_site_pi,
+            site=self.site,
+            role='pi')
+        site_pi_privilege.save()
+        self.test_objects.append(site_pi_privilege)
+        # site tech
+        self.user_site_tech = User(email='user_site_tech@test.com', first_name='Test', last_name='Test')
+        self.user_site_tech = self.site
+        self.user_site_tech.save()
+        self.test_objects.append(self.user_site_tech)
+        site_tech_privilege = SitePrivilege(
+            user = self.user_site_tech,
+            site=self.site,
+            role='tech')
+        site_tech_privilege.save()
+        self.test_objects.append(site_tech_privilege)
+        # slice admin
+        self.user_slice_admin = User(email='user_slice_admin@test.com', first_name='Test', last_name='Test')
+        self.user_slice_admin = self.site
+        self.user_slice_admin.save()
+        self.test_objects.append(self.user_slice_admin)
+        slice_admin_privilege = SlicePrivilege(
+            user = self.user_slice_admin,
+            slice = self.slice,
+            role='admin')
+        slice_admin_privilege.save()
+        self.test_objects.append(slice_admin_privilege)
+        # slice access 
+        self.user_slice_access = User(email='user_slice_access@test.com', first_name='Test', last_name='Test')
+        self.user_slice_access = self.site 
+        self.user_slice_access.save()
+        self.test_objects.append(self.user_slice_access)
+        slice_access_privilege = SlicePrivilege(
+            user = self.user_slice_access,
+            slice = self.slice,
+            role='access')
+        slice_access_privilege.save()
+        self.test_objects.append(slice_access_privilege)
+
+
+    def test_deployment(self):
+        for user in [self.user_admin, self.user_deployment_admin]:
+            self.assertEqual(
+                self.deployment.save_by_user(user), None)
+        for user in [self.user_read_only, self.user_default, self.user_site_admin,
+                     self.user_site_pi, self.user_site_tech, self.user_slice_admin,
+                     self.user_slice_access]:
+            self.assertRaises(
+                PermissionDenied, 
+                self.deployment.save_by_user(user,))
+
+    def test_site(self):
+        for user in [self.user_admin, self.user_site_admin, self.user_site_pi]:
+            self.assertEqual(
+                self.site.save_by_user(user), None)
+        for user in [self.user_read_only, self.user_default, self.user_deployment_admin,
+                     self.user_site_tech, self.user_slice_admin, self.user_slice_access]:
+            self.assertRaises(
+                PermissionDenied,
+                self.site.save_by_user(user,))
+    
+    def test_node(self):
+        for user in [self.user_admin, self.user_site_admin, self.user_site_tech]:
+            self.assertEqual(self.node.save_by_user(user), None)
+        for user in [self.user_read_only, self.user_default, self.user_deployment_admin,
+                     self.user_site_pi, self.user_slice_admin, self.user_slice_access]:
+            self.assertRaises(
+                PermissionDenied,
+                self.node.save_by_user(user,))                 
+                                       
+    def test_slice(self):
+        for user in [self.user_admin, self.user_site_admin, self.user_site_pi, 
+                     self.user_slice_admin]:
+            self.assertEqual(
+                self.slice.save_by_user(user), None)
+        for user in [self.user_read_only, self.user_default, self.user_deployment_admin,
+                     self.user_site_tech, self.user_slice_access]:
+            self.assertRaises(
+                PermissionDenied,
+                self.slice.save_by_user(user,))
+            
+    def test_user(self):
+        for user in [self.user_admin, self.user_site_admin, self.user_deployment_admin,
+                     self.user_site_pi, self.user_default]:
+            self.assertEqual(
+                self.user_default.save_by_user(user), None)
+        for user in [self.user_read_only, self.user_deployment_admin, 
+                     self.user_site_tech, self.user_slice_admin, self.user_slice_access]:
+            self.assertRaises(
+                PermissionDenied,
+                self.user_default.save_by_user(user,))                    
+                                 
+         
+    def tearDown(self):
+        for obj in self.test_objects:
+            obj.delete()       
+    
+if __name__ == '__main__':
+    unittest.main()     
diff --git a/xos/tests/planetstacktest.py b/xos/tests/planetstacktest.py
new file mode 100644
index 0000000..baf7efe
--- /dev/null
+++ b/xos/tests/planetstacktest.py
@@ -0,0 +1,94 @@
+import os
+import json
+import sys
+import time
+
+sys.path.append("/opt/xos")
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
+from openstack.manager import OpenStackManager
+from core.models import Slice, Instance, ServiceClass, Reservation, Tag, Network, User, Node, Image, Deployment, Site, NetworkTemplate, NetworkSlice
+
+TEST_SITE_NAME = "Princeton University"
+TEST_USER_EMAIL = "sbaker@planetstack.org"
+TEST_IMAGE_NAME = "Fedora 16 LXC rev 1.3"
+TEST_NODE_NAME = "viccidev3.cs.princeton.edu"
+TEST_DEPLOYMENT_NAME = "VICCI"
+
+def fail(msg):
+    print msg
+    sys.exit(-1)
+
+def fail_unless(condition, msg):
+    if not condition:
+        fail(msg)
+
+class PlanetStackTest:
+    def __init__(self):
+        self.objs_saved = []
+        self.counter = 0
+
+    def setup(self):
+        self.manager = OpenStackManager()
+
+        print "getting test site"
+        self.testSite = Site.objects.get(name=TEST_SITE_NAME)
+
+        print "getting test user"
+        self.testUser = User.objects.get(email=TEST_USER_EMAIL)
+
+        print "getting test image"
+        self.testImage = Image.objects.get(name=TEST_IMAGE_NAME)
+
+        print "getting test node"
+        self.testNode = Node.objects.get(name=TEST_NODE_NAME)
+
+        print "getting test deployment"
+        self.testDeployment = Deployment.objects.get(name=TEST_DEPLOYMENT_NAME)
+
+    def save_and_wait_for_enacted(self, x, nonempty_fields=[]):
+        print "saving", x.__class__.__name__, str(x)
+        x.save()
+        self.objs_saved.append(x)
+        print "   waiting for", str(x), "to be enacted"
+        tStart = time.time()
+        while True:
+            new_x = x.__class__.objects.get(id=x.id)
+            if (new_x.enacted != None) and (new_x.enacted >= new_x.updated):
+                print "  ", str(x), "has been enacted"
+                break
+            time.sleep(5)
+
+        if nonempty_fields:
+            print "   waiting for", ", ".join(nonempty_fields), "to be nonempty"
+            while True:
+                new_x = x.__class__.objects.get(id=x.id)
+                keep_waiting=False
+                for field in nonempty_fields:
+                    if not getattr(new_x, field, None):
+                        keep_waiting=True
+                if not keep_waiting:
+                    break
+
+        print "   saved and enacted in %d seconds" % int(time.time() - tStart)
+
+        return new_x
+
+    def make_slice_name(self):
+        self.counter = self.counter +1
+        return "test-" + str(time.time()) + "." + str(self.counter)
+
+    def get_network_template(self,name):
+        template = NetworkTemplate.objects.get(name=name)
+        return template
+
+    def cleanup(self):
+        print "cleaning up"
+        print "press return"
+        sys.stdin.readline()
+        for obj in self.objs_saved:
+            try:
+                 print "  deleting", str(obj)
+                 obj.delete()
+            except:
+                 print "failed to delete", str(obj)
diff --git a/xos/tests/rest_examples/add_truckroll.sh b/xos/tests/rest_examples/add_truckroll.sh
new file mode 100755
index 0000000..ac092fa
--- /dev/null
+++ b/xos/tests/rest_examples/add_truckroll.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+source ./config.sh
+
+TARGET_ID=1
+TEST=ping
+ARGUMENT=128.112.139.30
+
+echo curl "-H \"Accept: application/json; indent=4\" -H \"Content-Type: application/json\" -u $AUTH -X POST -d \"{\\\"target_id\\\": \\\"$TARGET_ID\\\", \\\"test\\\": \\\"$TEST\\\", \\\"argument\\\": \\\"$ARGUMENT\\\"}\" $HOST/xoslib/truckroll/"
+
+curl -H "Accept: application/json; indent=4" -H "Content-Type: application/json" -u $AUTH -X POST -d "{\"target_id\": \"$TARGET_ID\", \"test\": \"$TEST\", \"argument\": \"$ARGUMENT\"}" $HOST/xoslib/truckroll/
diff --git a/xos/tests/rest_examples/add_volt_tenant.sh b/xos/tests/rest_examples/add_volt_tenant.sh
new file mode 100755
index 0000000..4bbe2bb
--- /dev/null
+++ b/xos/tests/rest_examples/add_volt_tenant.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+source ./config.sh
+
+SERVICE_SPECIFIC_ID=1238
+C_TAG=1238
+S_TAG=3333
+
+echo curl "-H \"Accept: application/json; indent=4\" -H \"Content-Type: application/json\" -u $AUTH -X POST -d \"{\\\"service_specific_id\\\": \\\"$SERVICE_SPECIFIC_ID\\\", \\\"c_tag\\\": \\\"$C_TAG\\\", \\\"s_tag\\\": \\\"$S_TAG\\\"}\" $HOST/xoslib/volttenant/"
+
+curl -H "Accept: application/json; indent=4" -H "Content-Type: application/json" -u $AUTH -X POST -d "{\"service_specific_id\": \"$SERVICE_SPECIFIC_ID\", \"c_tag\": \"$C_TAG\", \"s_tag\": \"$S_TAG\"}" $HOST/xoslib/volttenant/  
diff --git a/xos/tests/rest_examples/config.sh b/xos/tests/rest_examples/config.sh
new file mode 100644
index 0000000..06162ee
--- /dev/null
+++ b/xos/tests/rest_examples/config.sh
@@ -0,0 +1,6 @@
+#HOST=198.0.0.44:8000
+#HOST=10.254.1.22:8000
+HOST=clnode050.clemson.cloudlab.us:9999
+
+#AUTH=scott@onlab.us:letmein
+AUTH=padmin@vicci.org:letmein
diff --git a/xos/tests/rest_examples/delete_volt_tenant.sh b/xos/tests/rest_examples/delete_volt_tenant.sh
new file mode 100755
index 0000000..2557e72
--- /dev/null
+++ b/xos/tests/rest_examples/delete_volt_tenant.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+source ./config.sh
+
+ID=89
+
+curl -H "Accept: application/json; indent=4" -H "Content-Type: application/json" -u $AUTH -X DELETE $HOST/xoslib/volttenant/$ID/  
diff --git a/xos/tests/rest_examples/list_cord_subscribers.sh b/xos/tests/rest_examples/list_cord_subscribers.sh
new file mode 100755
index 0000000..8deafa6
--- /dev/null
+++ b/xos/tests/rest_examples/list_cord_subscribers.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+source ./config.sh
+
+curl -H "Accept: application/json; indent=4" -H "Content-Type: application/json" -u $AUTH $HOST/xoslib/cordsubscriber/  
diff --git a/xos/tests/rest_examples/list_truckrolls.sh b/xos/tests/rest_examples/list_truckrolls.sh
new file mode 100755
index 0000000..7aeaa4c
--- /dev/null
+++ b/xos/tests/rest_examples/list_truckrolls.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+source ./config.sh
+
+curl -H "Accept: application/json; indent=4" -H "Content-Type: application/json" -u $AUTH $HOST/xoslib/truckroll/  
diff --git a/xos/tests/rest_examples/list_volt_tenants.sh b/xos/tests/rest_examples/list_volt_tenants.sh
new file mode 100755
index 0000000..f1348dd
--- /dev/null
+++ b/xos/tests/rest_examples/list_volt_tenants.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+source ./config.sh
+
+curl -H "Accept: application/json; indent=4" -H "Content-Type: application/json" -u $AUTH $HOST/xoslib/volttenant/  
diff --git a/xos/tests/rest_useraccesstest.py b/xos/tests/rest_useraccesstest.py
new file mode 100644
index 0000000..37f7521
--- /dev/null
+++ b/xos/tests/rest_useraccesstest.py
@@ -0,0 +1,216 @@
+""" useraccesstest.py
+
+    This is a basic REST API permission test. Call it with a username and a
+    password, and it will try to read and update some user and slice object,
+    and report if something is broken.
+
+    This is not an exhaustive test.
+"""
+
+
+import inspect
+import json
+import os
+import requests
+import sys
+import time
+from urllib  import urlencode
+
+from operator import itemgetter, attrgetter
+
+if (len(sys.argv)!=6):
+    print "syntax: usertest <hostname> <username> <password> <admin_username> <admin_password>"
+    sys.exit(-1)
+
+hostname = sys.argv[1]
+username = sys.argv[2]
+password = sys.argv[3]
+
+opencloud_auth=(username, password)
+admin_auth=(sys.argv[4], sys.argv[5])
+
+REST_API="http://%s:8000/xos/" % hostname
+USERS_API = REST_API + "users/"
+SLICES_API = REST_API + "slices/"
+SITES_API = REST_API + "sites/"
+SITEPRIV_API = REST_API + "siteprivileges/"
+SLICEPRIV_API = REST_API + "slice_privileges/"
+SITEROLE_API = REST_API + "site_roles/"
+SLICEROLE_API = REST_API + "slice_roles/"
+
+TEST_USER_EMAIL = "test" + str(time.time()) + "@test.com" # in case observer not running, objects won't be purged, so use unique email
+
+def fail_unless(x, msg):
+    if not x:
+        (frame, filename, line_number, function_name, lines, index) = inspect.getouterframes(inspect.currentframe())[1]
+        print "FAIL (%s:%d)" % (function_name, line_number), msg
+
+print "downloading objects using admin"
+r = requests.get(USERS_API + "?no_hyperlinks=1", auth=admin_auth)
+fail_unless(r.status_code==200, "failed to get users")
+allUsers = r.json()
+r = requests.get(SLICES_API + "?no_hyperlinks=1", auth=admin_auth)
+fail_unless(r.status_code==200, "failed to get slices")
+allSlices = r.json()
+r = requests.get(SITES_API + "?no_hyperlinks=1", auth=admin_auth)
+allSites = r.json()
+r = requests.get(SITEPRIV_API + "?no_hyperlinks=1", auth=admin_auth)
+allSitePriv = r.json()
+r = requests.get(SLICEPRIV_API + "?no_hyperlinks=1", auth=admin_auth)
+allSlicePriv = r.json()
+r = requests.get(SITEROLE_API + "?no_hyperlinks=1", auth=admin_auth)
+allSiteRole = r.json()
+r = requests.get(SLICEROLE_API + "?no_hyperlinks=1", auth=admin_auth)
+allSliceRole = r.json()
+
+def should_see_user(myself, otherUser):
+    if myself["is_admin"]:
+        return True
+    if myself["id"] == otherUser["id"]:
+        return True
+    for sitePriv in allSitePriv:
+        if (sitePriv["user"] == myself["id"]) and (sitePriv["site"] == otherUser["site"]):
+            for role in allSiteRole:
+                if role["role"]=="pi" and role["id"] == sitePriv["role"]:
+                    return True
+    return False
+
+def should_see_slice(myself, slice):
+    if myself["is_admin"]:
+        return True
+    for sitePriv in allSitePriv:
+        if (sitePriv["user"] == myself["id"]) and (sitePriv["site"] == slice["site"]):
+            for role in allSiteRole:
+                if role["role"]=="pi" and role["id"] == sitePriv["role"]:
+                    return True
+    for slicePriv in allSlicePriv:
+        if (slicePriv["user"] == myself["id"]) and (sitePriv["slice"] == slice["id"]):
+            for role in allSliceRole:
+                if role["role"]=="pi" and role["id"] == slicePriv["role"]:
+                    return True
+    return False
+
+def flip_phone(user):
+    if user["phone"] == "123":
+        user["phone"] = "456"
+    else:
+        user["phone"] = "123"
+
+def flip_desc(slice):
+    if slice["description"] == "some_description":
+        slice["description"] = "some_other_description"
+    else:
+        slice["description"] = "some_description"
+
+def delete_user_if_exists(email):
+    r = requests.get(USERS_API +"?email=%s" % email, auth=admin_auth)
+    if r.status_code==200:
+        user = r.json()
+        if len(user)>0:
+            user=user[0]
+            r = requests.delete(USERS_API + str(user["id"]) + "/", auth=admin_auth)
+            fail_unless(r.status_code==200, "failed to delete the test user")
+
+print "  loaded user:%d slice:%d, site:%d, site_priv:%d slice_priv:%d" % (len(allUsers), len(allSlices), len(allSites), len(allSitePriv), len(allSlicePriv))
+
+# get our own user record
+
+r = requests.get(USERS_API + "?" + urlencode({"email": username, "no_hyperlinks": "1"}), auth=opencloud_auth)
+fail_unless(r.status_code==200, "failed to get user %s" % username)
+myself = r.json()
+fail_unless(len(myself)==1, "wrong number of results when getting user %s" % username)
+myself = myself[0]
+
+# check to see that we see the users we should be able to
+
+r = requests.get(USERS_API, auth=opencloud_auth)
+myUsers = r.json()
+for user in myUsers:
+    fail_unless(should_see_user(myself, user), "saw user %s but we shouldn't have" % user["email"])
+myUsersIds = [r["id"] for r in myUsers]
+for user in allUsers:
+    if should_see_user(myself, user):
+        fail_unless(user["id"] in myUsersIds, "should have seen user %s but didnt" % user["email"])
+
+# toggle the phone number on the users we should be able to
+
+"""
+for user in allUsers:
+    user = requests.get(USERS_API + str(user["id"]) + "/", auth=admin_auth).json()
+    flip_phone(user)
+    r = requests.put(USERS_API + str(user["id"]) +"/", data=user, auth=opencloud_auth)
+    if should_see_user(myself, user):
+        fail_unless(r.status_code==200, "failed to change phone number on %s" % user["email"])
+    else:
+        # XXX: this is failing, but for the wrong reason
+        fail_unless(r.status_code!=200, "was able to change phone number on %s but shouldn't have" % user["email"])
+
+# try changing is_staff. We should be able to do it if we're an admin, but not
+# otherwise.
+
+for user in allUsers:
+    user = requests.get(USERS_API + str(user["id"]) + "/", auth=admin_auth).json()
+    user["is_staff"] = not user["is_staff"]
+    r = requests.put(USERS_API + str(user["id"]) +"/", data=user, auth=opencloud_auth)
+    if myself["is_admin"]:
+        fail_unless(r.status_code==200, "failed to change is_staff on %s" % user["email"])
+    else:
+        # XXX: this is failing, but for the wrong reason
+        fail_unless(r.status_code!=200, "was able to change is_staff on %s but shouldn't have" % user["email"])
+
+    # put it back to false, in case we successfully changed it...
+    user["is_staff"] = False
+    r = requests.put(USERS_API + str(user["id"]) +"/", data=user, auth=opencloud_auth)
+"""
+
+# delete the TEST_USER_EMAIL if it exists
+delete_user_if_exists(TEST_USER_EMAIL)
+
+# XXX - enacted and policed should not be required
+
+newUser = {"firstname": "test", "lastname": "1234", "email": TEST_USER_EMAIL, "password": "letmein", "site": allSites[0]["id"], "enacted": "2015-01-01T00:00", "policed": "2015-01-01T00:00"}
+r = requests.post(USERS_API + "?no_hyperlinks=1", data=newUser, auth=opencloud_auth)
+if myself["is_admin"]:
+    fail_unless(r.status_code==200, "failed to create %s" % TEST_USER_EMAIL)
+else:
+    fail_unless(r.status_code!=200, "created %s but we shouldn't have been able to" % TEST_USER_EMAIL)
+
+delete_user_if_exists(TEST_USER_EMAIL)
+
+# now create it as admin
+r = requests.post(USERS_API + "?no_hyperlinks=1", data=newUser, auth=admin_auth)
+if (r.status_code!=201):
+    print r.text
+fail_unless(r.status_code==201, "failed to create %s as admin" % TEST_USER_EMAIL)
+
+r = requests.get(USERS_API +"?" + urlencode({"email": TEST_USER_EMAIL}), auth=admin_auth)
+fail_unless(r.status_code==200, "failed to get user %s" % TEST_USER_EMAIL)
+user=r.json()[0]
+r = requests.delete(USERS_API + str(user["id"]) + "/", auth=opencloud_auth)
+if myself["is_admin"]:
+    fail_unless(r.status_code==200, "failed to delete %s" % TEST_USER_EMAIL)
+else:
+    fail_unless(r.status_code!=200, "deleted %s but we shouldn't have been able to" % TEST_USER_EMAIL)
+
+# slice tests
+
+r = requests.get(SLICES_API, auth=opencloud_auth)
+mySlices = r.json()
+
+for slice in mySlices:
+    fail_unless(should_see_slice(myself, slice), "saw slice %s but we shouldn't have" % slice["name"])
+mySlicesIds = [r["id"] for r in mySlices]
+for slice in allSlices:
+    if should_see_slice(myself, slice):
+        fail_unless(slice["id"] in mySliceIds, "should have seen slice %s but didnt" % slice["name"])
+
+for slice in allSlices:
+    slice = requests.get(SLICES_API + str(slice["id"]) + "/", auth=admin_auth).json()
+    flip_desc(slice)
+    r = requests.put(SLICES_API + str(slice["id"]) +"/", data=slice, auth=opencloud_auth)
+    if should_see_slice(myself, slice):
+        fail_unless(r.status_code==200, "failed to change desc on %s" % slice["name"])
+    else:
+        fail_unless(r.status_code!=200, "was able to change desc on %s but shouldn't have" % slice["name"])
+
+print "Done."
diff --git a/xos/tests/rest_usertest.py b/xos/tests/rest_usertest.py
new file mode 100644
index 0000000..14cba7e
--- /dev/null
+++ b/xos/tests/rest_usertest.py
@@ -0,0 +1,81 @@
+"""
+     UserTest - tests whether a user is able to fetch his own user record,
+                and modify fields.
+
+                All users should be able to set their phone number.
+                Only admins should be able to set their is_admin bit
+"""
+
+import json
+import os
+import requests
+import sys
+from urllib import urlencode
+
+from operator import itemgetter, attrgetter
+
+if (len(sys.argv)!=6):
+    print "syntax: usertest <hostname> <username> <password> <admin_username> <admin_password>"
+    sys.exit(-1)
+
+hostname = sys.argv[1]
+username = sys.argv[2]
+password = sys.argv[3]
+
+opencloud_auth=(username, password)
+admin_auth=(sys.argv[4], sys.argv[5])
+
+REST_API="http://%s:8000/xos/" % hostname
+USERS_API = REST_API + "users/"
+
+print "fetching user record for %s:" % username
+r = requests.get(USERS_API + "?" + urlencode({"email": username}), auth=opencloud_auth)
+for user in r.json():
+    print "  ", user["email"]
+
+myself = r.json()[0]
+
+if myself["phone"] == "123":
+    myself["phone"] = "456"
+else:
+    myself["phone"] = "123"
+
+r = requests.put(USERS_API + str(myself["id"]) +"/", data=myself, auth=opencloud_auth)
+if r.status_code == 200:
+    print "I updated my phone to", myself["phone"]
+else:
+    print "I failed to update my phone"
+
+if myself["is_admin"] == True:
+    myself["is_admin"] = False
+else:
+    myself["is_admin"] = True
+
+r = requests.put(USERS_API + str(myself["id"]) +"/", data=myself, auth=opencloud_auth)
+if r.status_code == 200:
+    print "I updated my is_admin to", myself["is_admin"]
+else:
+    print "I failed to update my is_admin"
+
+r = requests.get(USERS_API + "?email=jhh@cs.arizona.edu", auth=opencloud_auth)
+if len(r.json())>0:
+    print "I was able to read jhh@cs.arizona.edu"
+else:
+    print "I was not able to read jhh@cs.arizona.edu"
+
+# get john's record using admin, so we can try to update it
+r = requests.get(USERS_API + "?email=jhh@cs.arizona.edu", auth=admin_auth)
+if len(r.json())>0:
+    print "Admin was able to read jhh@cs.arizona.edu"
+    jhh = r.json()[0]
+else:
+    print "Admin was not able to read jhh@cs.arizona.edu"
+    jhh = None
+
+if jhh:
+    # try to update john's user record
+    r = requests.put(USERS_API + str(jhh["id"]) + "/", data=jhh, auth=opencloud_auth)
+    if r.status_code == 200:
+        print "I was able to update user", str(jhh["id"])
+    else:
+        print "I was not able to update user", str(jhh["id"])
diff --git a/xos/tools/README.md b/xos/tools/README.md
new file mode 100644
index 0000000..ef13848
--- /dev/null
+++ b/xos/tools/README.md
@@ -0,0 +1,9 @@
+## Overview of XOS tools
+
+### modelgen
+
+Modelgen reads the XOS models and applies those models to a template to generate output. 
+
+Examples:
+  * ./modelgen -a core api.template.py > ../../xos/xosapi.py            
+  * ./modelgen -a services.hpc -b Service -b User hpc-api.template.py > ../../xos/hpcapi.py
diff --git a/xos/tools/ansible_hosts.py b/xos/tools/ansible_hosts.py
new file mode 100644
index 0000000..9ae3e52
--- /dev/null
+++ b/xos/tools/ansible_hosts.py
@@ -0,0 +1,99 @@
+#! /usr/bin/env python
+
+import json
+import os
+import requests
+import sys
+
+from operator import itemgetter, attrgetter
+
+opencloud_auth = None
+
+REST_API="http://portal.opencloud.us/xos/"
+
+NODES_API = REST_API + "nodes/"
+SITES_API = REST_API + "sites/"
+SLICES_API = REST_API + "slices/"
+SLIVERS_API = REST_API + "instance/"
+
+def get_nodes_by_site():
+    r = requests.get(SITES_API + "?no_hyperlinks=1", auth=opencloud_auth)
+    sites_list = r.json()
+    sites = {}
+    for site in sites_list:
+        site["hostnames"] = []
+        sites[str(site["id"])] = site
+
+    r = requests.get(NODES_API + "?no_hyperlinks=1", auth=opencloud_auth)
+    nodes = r.json()
+    for node in nodes:
+        site_id = str(node["site"])
+        if site_id in sites:
+            sites[site_id]["hostnames"].append(node["name"])
+
+    return sites
+
+"""
+   WIP
+
+def get_nodes_by_slice():
+    r = requests.get(SLICES_API + "?no_hyperlinks=1", auth=opencloud_auth)
+    sites_list = r.json()
+    slices = {}
+    for slice in slices_list:
+        slice["hostnames"] = []
+        slices[str(slices["id"])] = slice
+
+    r = requests.get(NODES_API + "?no_hyperlinks=1", auth=opencloud_auth)
+    nodes_list = r.json()
+    nodes = {}
+    for node in nodes_list:
+        nodes[str(nodes["id"])] = node
+
+    r = requests.get(SLIVERS_API + "?no_hyperlinks=1", auth=opencloud_auth)
+    instances = r.json()
+    for instances in nodes:
+        if instance["node"] not in nodes:
+            continue
+        if instance["slice"] not in slices:
+            continue
+
+        hostname = nodes[instance["node"]].name
+
+        slices[instance["slice"]]["hostnames"].append(hostname)
+
+    return slices
+"""
+
+def main():
+    global opencloud_auth
+
+    if len(sys.argv)!=3:
+        print >> sys.stderr, "syntax: get_instance_name.py <username>, <password>"
+        sys.exit(-1)
+
+    username = sys.argv[1]
+    password = sys.argv[2]
+
+    opencloud_auth=(username, password)
+
+    sites = get_nodes_by_site()
+
+    for site in sites.values():
+        if not site["hostnames"]:
+            continue
+
+        print "[%s]" % site["name"]
+        for hostname in site["hostnames"]:
+            print hostname
+        print ""
+
+    print "[all-opencloud:children]"
+    for site in sites.values():
+        if not site["hostnames"]:
+            continue
+        print site["name"]
+
+if __name__ == "__main__":
+    main()
+
diff --git a/xos/tools/apigen/api.template.py b/xos/tools/apigen/api.template.py
new file mode 100644
index 0000000..9f5123c
--- /dev/null
+++ b/xos/tools/apigen/api.template.py
@@ -0,0 +1,227 @@
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+from rest_framework import serializers
+from rest_framework import generics
+from rest_framework import status
+from rest_framework.generics import GenericAPIView
+from core.models import *
+from django.forms import widgets
+from rest_framework import filters
+from django.conf.urls import patterns, url
+from rest_framework.exceptions import PermissionDenied as RestFrameworkPermissionDenied
+from django.core.exceptions import PermissionDenied as DjangoPermissionDenied
+from apibase import XOSRetrieveUpdateDestroyAPIView, XOSListCreateAPIView, XOSNotAuthenticated
+
+if hasattr(serializers, "ReadOnlyField"):
+    # rest_framework 3.x
+    IdField = serializers.ReadOnlyField
+else:
+    # rest_framework 2.x
+    IdField = serializers.Field
+
+"""
+    Schema of the generator object:
+        all: Set of all Model objects
+        all_if(regex): Set of Model objects that match regex
+
+    Model object:
+        plural: English plural of object name
+        camel: CamelCase version of object name
+        refs: list of references to other Model objects
+        props: list of properties minus refs
+
+    TODO: Deal with subnets
+"""
+
+def get_REST_patterns():
+    return patterns('',
+    # legacy - deprecated
+        url(r'^xos/$', api_root),
+    {% for object in generator.all %}
+        url(r'xos/{{ object.rest_name }}/$', {{ object.camel }}List.as_view(), name='{{ object.singular }}-list-legacy'),
+        url(r'xos/{{ object.rest_name }}/(?P<pk>[a-zA-Z0-9\-]+)/$', {{ object.camel }}Detail.as_view(), name ='{{ object.singular }}-detail-legacy'),
+    {% endfor %}
+    ) + patterns('',
+    # new - use these instead of the above
+        url(r'^api/core/$', api_root),
+    {% for object in generator.all %}
+        url(r'api/core/{{ object.rest_name }}/$', {{ object.camel }}List.as_view(), name='{{ object.singular }}-list'),
+        url(r'api/core/{{ object.rest_name }}/(?P<pk>[a-zA-Z0-9\-]+)/$', {{ object.camel }}Detail.as_view(), name ='{{ object.singular }}-detail'),
+    {% endfor %}
+    )
+
+@api_view(['GET'])
+def api_root_legacy(request, format=None):
+    return Response({
+        {% for object in generator.all %}'{{ object.plural }}': reverse('{{ object }}-list-legacy', request=request, format=format),
+        {% endfor %}
+    })
+
+@api_view(['GET'])
+def api_root(request, format=None):
+    return Response({
+        {% for object in generator.all %}'{{ object.plural }}': reverse('{{ object }}-list', request=request, format=format),
+        {% endfor %}
+    })
+
+# Based on serializers.py
+
+class XOSModelSerializer(serializers.ModelSerializer):
+    # TODO: Rest Framework 3.x doesn't support save_object()
+    def NEED_TO_UPDATE_save_object(self, obj, **kwargs):
+
+        """ rest_framework can't deal with ManyToMany relations that have a
+            through table. In xos, most of the through tables we have
+            use defaults or blank fields, so there's no reason why we shouldn't
+            be able to save these objects.
+
+            So, let's strip out these m2m relations, and deal with them ourself.
+        """
+        obj._complex_m2m_data={};
+        if getattr(obj, '_m2m_data', None):
+            for relatedObject in obj._meta.get_all_related_many_to_many_objects():
+                if (relatedObject.field.rel.through._meta.auto_created):
+                    # These are non-trough ManyToMany relations and
+                    # can be updated just fine
+                    continue
+                fieldName = relatedObject.get_accessor_name()
+                if fieldName in obj._m2m_data.keys():
+                    obj._complex_m2m_data[fieldName] = (relatedObject, obj._m2m_data[fieldName])
+                    del obj._m2m_data[fieldName]
+
+        serializers.ModelSerializer.save_object(self, obj, **kwargs);
+
+        for (accessor, stuff) in obj._complex_m2m_data.items():
+            (relatedObject, data) = stuff
+            through = relatedObject.field.rel.through
+            local_fieldName = relatedObject.field.m2m_reverse_field_name()
+            remote_fieldName = relatedObject.field.m2m_field_name()
+
+            # get the current set of existing relations
+            existing = through.objects.filter(**{local_fieldName: obj});
+
+            data_ids = [item.id for item in data]
+            existing_ids = [getattr(item,remote_fieldName).id for item in existing]
+
+            #print "data_ids", data_ids
+            #print "existing_ids", existing_ids
+
+            # remove relations that are in 'existing' but not in 'data'
+            for item in list(existing):
+               if (getattr(item,remote_fieldName).id not in data_ids):
+                   print "delete", getattr(item,remote_fieldName)
+                   item.delete() #(purge=True)
+
+            # add relations that are in 'data' but not in 'existing'
+            for item in data:
+               if (item.id not in existing_ids):
+                   #print "add", item
+                   newModel = through(**{local_fieldName: obj, remote_fieldName: item})
+                   newModel.save()
+
+{% for object in generator.all %}
+
+class {{ object.camel }}Serializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    {% for ref in object.refs %}
+    {% if ref.multi %}
+    {{ ref.plural }} = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='{{ ref }}-detail')
+    {% else %}
+    {{ ref }} = serializers.HyperlinkedRelatedField(read_only=True, view_name='{{ ref }}-detail')
+    {% endif %}
+    {% endfor %}
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = {{ object.camel }}
+        fields = ('humanReadableName', 'validators', {% for prop in object.props %}'{{ prop }}',{% endfor %}{% for ref in object.refs %}{%if ref.multi %}'{{ ref.plural }}'{% else %}'{{ ref }}'{% endif %},{% endfor %})
+
+class {{ object.camel }}IdSerializer(XOSModelSerializer):
+    id = IdField()
+    {% for ref in object.refs %}
+    {% if ref.multi %}
+    {{ ref.plural }} = serializers.PrimaryKeyRelatedField(many=True,  required=False, queryset = {{ ref.camel }}.objects.all())
+    {% else %}
+    {{ ref }} = serializers.PrimaryKeyRelatedField( queryset = {{ ref.camel }}.objects.all())
+    {% endif %}
+    {% endfor %}
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = {{ object.camel }}
+        fields = ('humanReadableName', 'validators', {% for prop in object.props %}'{{ prop }}',{% endfor %}{% for ref in object.refs %}{%if ref.multi %}'{{ ref.plural }}'{% else %}'{{ ref }}'{% endif %},{% endfor %})
+
+
+{% endfor %}
+
+serializerLookUp = {
+{% for object in generator.all %}
+                 {{ object.camel }}: {{ object.camel }}Serializer,
+{% endfor %}
+                 None: None,
+                }
+
+# Based on core/views/*.py
+{% for object in generator.all %}
+
+class {{ object.camel }}List(XOSListCreateAPIView):
+    queryset = {{ object.camel }}.objects.select_related().all()
+    serializer_class = {{ object.camel }}Serializer
+    id_serializer_class = {{ object.camel }}IdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ({% for prop in object.props %}'{{ prop }}',{% endfor %}{% for ref in object.refs %}{%if ref.multi %}'{{ ref.plural }}'{% else %}'{{ ref }}'{% endif %},{% endfor %})
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return {{ object.camel }}.select_by_user(self.request.user)
+
+
+class {{ object.camel }}Detail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = {{ object.camel }}.objects.select_related().all()
+    serializer_class = {{ object.camel }}Serializer
+    id_serializer_class = {{ object.camel }}IdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return {{ object.camel }}.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+{% endfor %}
diff --git a/xos/tools/apigen/deps.template.json b/xos/tools/apigen/deps.template.json
new file mode 100644
index 0000000..e4164cf
--- /dev/null
+++ b/xos/tools/apigen/deps.template.json
@@ -0,0 +1,8 @@
+{
+{% for o in generator.all %}
+    "{{ o.camel }}": [
+	{% for f in o.refs %}"{{ f.camel }}",
+	{% endfor %}]
+{% endfor %}
+}
+
diff --git a/xos/tools/apigen/dot.template.dot b/xos/tools/apigen/dot.template.dot
new file mode 100644
index 0000000..eade386
--- /dev/null
+++ b/xos/tools/apigen/dot.template.dot
@@ -0,0 +1,7 @@
+digraph plstack {
+{% for o in generator.all %}
+{% for f in o.refs %}
+  "{{ o.camel }}"->"{{ f.camel }}";
+{% endfor %}
+{% endfor %}
+}
diff --git a/xos/tools/apigen/fields.template.txt b/xos/tools/apigen/fields.template.txt
new file mode 100644
index 0000000..ad5a0b4
--- /dev/null
+++ b/xos/tools/apigen/fields.template.txt
@@ -0,0 +1,6 @@
+{% for object in generator.all %}
+Object {{ object }}:
+Fields:
+{% for field in object.fields %}{{ field.name }}:{{ field.type }}
+{% endfor %}
+{% endfor %}
diff --git a/xos/tools/apigen/hpc-api.template.py b/xos/tools/apigen/hpc-api.template.py
new file mode 100644
index 0000000..ed252b8
--- /dev/null
+++ b/xos/tools/apigen/hpc-api.template.py
@@ -0,0 +1,225 @@
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+from rest_framework import serializers
+from rest_framework import generics
+from rest_framework import status
+from rest_framework.generics import GenericAPIView
+from services.hpc.models import *
+from django.forms import widgets
+from rest_framework import filters
+from django.conf.urls import patterns, url
+from rest_framework.exceptions import PermissionDenied as RestFrameworkPermissionDenied
+from django.core.exceptions import PermissionDenied as DjangoPermissionDenied
+from apibase import XOSRetrieveUpdateDestroyAPIView, XOSListCreateAPIView, XOSNotAuthenticated
+
+if hasattr(serializers, "ReadOnlyField"):
+    # rest_framework 3.x
+    IdField = serializers.ReadOnlyField
+else:
+    # rest_framework 2.x
+    IdField = serializers.Field
+
+"""
+    Schema of the generator object:
+        all: Set of all Model objects
+        all_if(regex): Set of Model objects that match regex
+
+    Model object:
+        plural: English plural of object name
+        camel: CamelCase version of object name
+        refs: list of references to other Model objects
+        props: list of properties minus refs
+
+    TODO: Deal with subnets
+"""
+
+def get_hpc_REST_patterns():
+    return patterns('',
+        url(r'^hpcapi/$', hpc_api_root_legacy),
+    # legacy - deprecated
+    {% for object in generator.rest_models %}
+        url(r'hpcapi/{{ object.rest_name }}/$', {{ object.camel }}List.as_view(), name='{{ object.singular }}-list-legacy'),
+        url(r'hpcapi/{{ object.rest_name }}/(?P<pk>[a-zA-Z0-9\-]+)/$', {{ object.camel }}Detail.as_view(), name ='{{ object.singular }}-detail-legacy'),
+    {% endfor %}
+    # new api - use these
+        url(r'^api/service/hpc/$', hpc_api_root),
+    {% for object in generator.rest_models %}
+        url(r'api/service/hpc/{{ object.rest_name }}/$', {{ object.camel }}List.as_view(), name='{{ object.singular }}-list'),
+        url(r'api/service/hpc/{{ object.rest_name }}/(?P<pk>[a-zA-Z0-9\-]+)/$', {{ object.camel }}Detail.as_view(), name ='{{ object.singular }}-detail'),
+    {% endfor %}
+    )
+
+@api_view(['GET'])
+def hpc_api_root_legacy(request, format=None):
+    return Response({
+        {% for object in generator.rest_models %}'{{ object.plural }}': reverse('{{ object }}-list-legacy', request=request, format=format),
+        {% endfor %}
+    })
+
+@api_view(['GET'])
+def hpc_api_root(request, format=None):
+    return Response({
+        {% for object in generator.rest_models %}'{{ object.plural }}': reverse('{{ object }}-list', request=request, format=format),
+        {% endfor %}
+    })
+
+# Based on serializers.py
+
+class XOSModelSerializer(serializers.ModelSerializer):
+    def save_object(self, obj, **kwargs):
+
+        """ rest_framework can't deal with ManyToMany relations that have a
+            through table. In xos, most of the through tables we have
+            use defaults or blank fields, so there's no reason why we shouldn't
+            be able to save these objects.
+
+            So, let's strip out these m2m relations, and deal with them ourself.
+        """
+        obj._complex_m2m_data={};
+        if getattr(obj, '_m2m_data', None):
+            for relatedObject in obj._meta.get_all_related_many_to_many_objects():
+                if (relatedObject.field.rel.through._meta.auto_created):
+                    # These are non-trough ManyToMany relations and
+                    # can be updated just fine
+                    continue
+                fieldName = relatedObject.get_accessor_name()
+                if fieldName in obj._m2m_data.keys():
+                    obj._complex_m2m_data[fieldName] = (relatedObject, obj._m2m_data[fieldName])
+                    del obj._m2m_data[fieldName]
+
+        serializers.ModelSerializer.save_object(self, obj, **kwargs);
+
+        for (accessor, stuff) in obj._complex_m2m_data.items():
+            (relatedObject, data) = stuff
+            through = relatedObject.field.rel.through
+            local_fieldName = relatedObject.field.m2m_reverse_field_name()
+            remote_fieldName = relatedObject.field.m2m_field_name()
+
+            # get the current set of existing relations
+            existing = through.objects.filter(**{local_fieldName: obj});
+
+            data_ids = [item.id for item in data]
+            existing_ids = [getattr(item,remote_fieldName).id for item in existing]
+
+            #print "data_ids", data_ids
+            #print "existing_ids", existing_ids
+
+            # remove relations that are in 'existing' but not in 'data'
+            for item in list(existing):
+               if (getattr(item,remote_fieldName).id not in data_ids):
+                   print "delete", getattr(item,remote_fieldName)
+                   item.delete() #(purge=True)
+
+            # add relations that are in 'data' but not in 'existing'
+            for item in data:
+               if (item.id not in existing_ids):
+                   #print "add", item
+                   newModel = through(**{local_fieldName: obj, remote_fieldName: item})
+                   newModel.save()
+
+{% for object in generator.rest_models %}
+
+class {{ object.camel }}Serializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    {% for ref in object.refs %}
+    {% if ref.multi %}
+    {{ ref.plural }} = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='{{ ref }}-detail')
+    {% else %}
+    {{ ref }} = serializers.HyperlinkedRelatedField(read_only=True, view_name='{{ ref }}-detail')
+    {% endif %}
+    {% endfor %}
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = {{ object.camel }}
+        fields = ('humanReadableName', 'validators', {% for prop in object.props %}'{{ prop }}',{% endfor %}{% for ref in object.refs %}{%if ref.multi %}'{{ ref.plural }}'{% else %}'{{ ref }}'{% endif %},{% endfor %})
+
+class {{ object.camel }}IdSerializer(XOSModelSerializer):
+    id = IdField()
+    {% for ref in object.refs %}
+    {% if ref.multi %}
+    {{ ref.plural }} = serializers.PrimaryKeyRelatedField(many=True, required=False, queryset = {{ ref.camel }}.objects.all())
+    {% else %}
+    {{ ref }} = serializers.PrimaryKeyRelatedField( queryset = {{ ref.camel }}.objects.all())
+    {% endif %}
+    {% endfor %}
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = {{ object.camel }}
+        fields = ('humanReadableName', 'validators', {% for prop in object.props %}'{{ prop }}',{% endfor %}{% for ref in object.refs %}{%if ref.multi %}'{{ ref.plural }}'{% else %}'{{ ref }}'{% endif %},{% endfor %})
+
+
+{% endfor %}
+
+serializerLookUp = {
+{% for object in generator.rest_models %}
+                 {{ object.camel }}: {{ object.camel }}Serializer,
+{% endfor %}
+                 None: None,
+                }
+
+# Based on core/views/*.py
+{% for object in generator.rest_models %}
+
+class {{ object.camel }}List(XOSListCreateAPIView):
+    queryset = {{ object.camel }}.objects.select_related().all()
+    serializer_class = {{ object.camel }}Serializer
+    id_serializer_class = {{ object.camel }}IdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ({% for prop in object.props %}'{{ prop }}',{% endfor %}{% for ref in object.refs %}{%if ref.multi %}'{{ ref.plural }}'{% else %}'{{ ref }}'{% endif %},{% endfor %})
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return {{ object.camel }}.select_by_user(self.request.user)
+
+
+class {{ object.camel }}Detail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = {{ object.camel }}.objects.select_related().all()
+    serializer_class = {{ object.camel }}Serializer
+    id_serializer_class = {{ object.camel }}IdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return {{ object.camel }}.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+{% endfor %}
diff --git a/xos/tools/apigen/list.txt b/xos/tools/apigen/list.txt
new file mode 100644
index 0000000..3e115e3
--- /dev/null
+++ b/xos/tools/apigen/list.txt
@@ -0,0 +1,3 @@
+{% for o in generator.all %}
+{{ o.camel }}
+{% endfor %}
diff --git a/xos/tools/apigen/modelgen b/xos/tools/apigen/modelgen
new file mode 100644
index 0000000..068b7cb
--- /dev/null
+++ b/xos/tools/apigen/modelgen
@@ -0,0 +1,294 @@
+#!/usr/bin/python
+
+import os
+import pdb
+import copy
+import sys
+import json
+import re
+from django.template import Context, Template
+from optparse import OptionParser
+
+# Django set up
+
+import django
+sys.path.append('.')
+sys.path.append('/opt/xos')
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
+from django.db.models.fields.related import ForeignKey, ManyToManyField
+
+django.setup()
+
+options = None
+
+
+def singular(foo, keys):
+	for k in keys:
+		if (foo==k+'es'):
+			return k
+		elif (foo==k+'s'):
+			return k
+	raise Exception('Plural to singular error for %s'%foo)
+
+g = globals()
+
+def enum_classes(apps):
+    global app_map
+    global class_map
+    app_map = {}
+    class_map = {}
+    model_classes = []
+    for app in apps:
+            orig_app=app
+            app = app + ".models"
+            models_module = __import__(app)
+            for part in app.split(".")[1:]:
+                if hasattr(models_module, "PlCoreBase"):
+                    break
+                models_module = getattr(models_module,part)
+
+            global PlCoreBase
+            PlCoreBase = getattr(models_module,"PlCoreBase")
+
+            for classname in dir(models_module):
+                    c = getattr(models_module, classname, None)
+                    if type(c)==type(PlCoreBase) and c.__name__ not in options.blacklist:
+                            model_classes.append(c)
+                            app_map[c.__name__]=orig_app
+                            c.class_name = c.__name__
+                            file_name = c.__module__.rsplit('.',1)[1]
+                            try:
+                                if (file_name not in class_map[orig_app]):
+                                    class_map[orig_app].append({file_name:[c]})
+                                else:
+                                    class_map[orig_app][file_name].append(c)
+
+                            except KeyError:
+                                class_map[orig_app] = [{file_name:[c]}]
+
+
+    return model_classes
+
+class GenObj(object):
+	def __str__(self):
+		return str(self.model.__name__.lower())
+
+	def __init__(self, m):
+		self.model = m
+		self.props = []
+		self.fields = []
+		self.field_dict = []
+		self.refs = []
+		self.plural_name = None
+
+	def plural(self):
+		if (self.plural_name):
+			return self.plural_name
+		else:
+			name = str(self)
+			if (name.endswith('s')):
+				return name+'es'
+			else:
+				return name+'s'
+
+        def singular(self):
+            return str(self)
+
+        def rest_name(self):
+            # These are things that either for historic reasons or due to incorrect naming,
+            # got called something different than the autogen thinks they should be
+            # called.
+            REST_FIXUP = {'controllernetworkses': 'controllernetworks',
+                            'controllerimageses': 'controllerimages',
+                            'controllersliceses': 'controllerslices',
+                            'controlleruserses': 'controllerusers',
+                            'sitedeploymentses': 'sitedeployments',
+                            'siteroles': 'site_roles',
+                            'sliceprivileges': 'slice_privileges',
+                            'sliceroles': 'slice_roles',
+                            }
+            return REST_FIXUP.get(self.plural(), self.plural())
+
+	def camel(self):
+		name = str(self.model.__name__)
+		return name
+		
+class Generator(dict):
+        def __init__(self):
+            self.apps = {}
+
+	def all(self):
+		return self.values()
+
+        def rest_models(self):
+                norest = [x.lower() for x in options.norest]
+                return [v for v in self.values() if not (str(v) in norest)]
+	
+	def regex(self, r):
+		filtered = filter(lambda o:re.match(r,str(o)), self.values())
+		return filtered
+
+	def add_object(self, o):
+                global app_map
+		obj = GenObj(o)
+		fields = o._meta.fields
+                try:
+                    obj.app = app_map[o.__name__]
+                except KeyError:
+                    print "KeyError: %r"%o.__name__
+                obj.class_name = o.class_name
+
+                file_name = o.__module__.rsplit('.',1)[1]
+
+                try:
+                    if (file_name not in self.apps[obj.app]):
+                        self.apps[obj.app][file_name]=[obj]
+                    else:
+                        self.apps[obj.app][file_name].append(obj)
+
+                except KeyError:
+                    self.apps[obj.app] = {file_name:[obj]}
+
+		self[str(obj).lower()]=obj
+
+	def compute_links(self):
+                base_props = [f.name for f in PlCoreBase._meta.fields]
+
+		for obj in self.values():
+			#if (str(obj)=='network'):
+			#	pdb.set_trace()
+			fields = obj.model._meta.fields
+			for f in fields:
+				if (f and f.rel):
+					to_name = str(f.rel.to)
+				else:
+					to_name = None
+
+				if type(f)==ForeignKey and to_name and to_name in self.keys():
+					refobj = self[f.to_name]
+
+					if (str(obj)=='slice' and f.to_name=='networks'):
+						obj.refs.append(refobj)
+					related_name = f.related_query_name()
+					if (related_name!='+' and related_name.lower()!=str(obj).lower()):
+						cobj = copy.deepcopy(obj)
+						cobj.multi = True
+						cobj.plural_name = related_name
+						refobj.refs.append(cobj)
+                                elif f.name.endswith("_ptr"):
+                                        # django inherited model, for example HPCService
+                                        # cause swagger and REST to break
+                                        pass
+				else:
+                                        f.type = f.__class__.__name__
+                                        if (type(f)==ForeignKey):
+                                            f.related.model.class_name = f.related.model.__name__
+                                        if (f.name not in base_props):
+                                            obj.fields.append(f) 
+                                        obj.props.append(f.name)
+
+			m2m = obj.model._meta.many_to_many
+			for f in m2m:
+				try:
+					related_model_name = f.m2m_reverse_field_name()
+				except:
+					related_model_name = f.m2m_db_table().rsplit('_',1)[-1]
+
+				related_name = f.related_query_name()
+				if related_model_name in self.keys():
+                                        #print "XXX1", obj, f, related_name, related_model_name
+					refobj = self[related_model_name]
+					cobj = copy.deepcopy(obj)
+					cobj.multi=True
+					refobj.refs.append(cobj)
+
+                                # deal with upgradeFrom_rel_+
+                                if (related_name.endswith("+")):
+                                    continue
+
+				if (related_name!='+') and related_model_name in self: # and related_name.lower()!=str(obj).lower()):
+                                        refobj = self[related_model_name]
+                                        #print "XXX2", obj, f, related_name, related_model_name, refobj.plural_name
+					cobj = copy.deepcopy(refobj)
+					cobj.multi = True
+
+					obj.refs.append(cobj)
+
+
+
+
+def main():
+        global options
+        parser = OptionParser(usage="modelgen [options] <template_fn>", )
+
+        parser.add_option("-d", "--dict", dest="dict",
+             help="dictionary to replace text in output", metavar="DICT", default=[], action="append")
+
+        parser.add_option("-a", "--app", dest="apps",
+             help="list of applications to parse", metavar="APP", default=[], action="append")
+        parser.add_option("-b", "--blacklist", dest="blacklist",
+             help="add model name to blacklist", metavar="MODEL", default=["SingletonModel", "PlCoreBase"], action="append")
+        parser.add_option("-n", "--no-rest", dest="norest",
+             help="do not generate rest api for model", metavar="MODEL", default=["SingletonModel", "PlCoreBase"], action="append")
+
+        (options, args) = parser.parse_args(sys.argv[1:])
+
+        if not options.apps:
+            options.apps = ["core"]
+
+        if len(args)!=1:
+            print 'Usage: modelgen [options] <template_fn>'
+            exit(1)
+
+        template_name = os.path.abspath(args[0])
+
+        # try to make sure we're running from the right place
+        if (not os.path.exists("core")):
+            if (os.path.exists("../core")):
+                os.chdir("..")
+            elif (os.path.exists("../../core")):
+                os.chdir("../..")
+            else:
+                print >> sys.stderr, "Are you sure you're running modelgen from the root of an XOS installation"
+                sys.exit(-1)
+
+	generator = Generator()
+
+	models = enum_classes(options.apps)
+
+	for m in models:
+		generator.add_object(m)
+
+	generator.compute_links()
+	template_contents = open(template_name).read()
+	template = Template(template_contents)
+	context = Context({'generator':generator})
+	rendered = template.render(context)
+        lines = rendered.splitlines()
+        current_buffer = []
+        for l in lines:
+            if (l.startswith('+++')):
+                filename = l[4:]
+                fil = open(filename,'w')
+                buf = '\n'.join(current_buffer)
+
+                obuf = buf
+                for d in options.dict:
+                    df = open(d).read()
+                    d = json.loads(df)
+
+                    pattern = re.compile(r'\b(' + '|'.join(d.keys()) + r')\b')
+                    obuf = pattern.sub(lambda x: d[x.group()], buf)
+                fil.write(obuf)
+                fil.close()
+
+                print 'Written to file %s'%filename
+                current_buffer = []
+            else:
+                current_buffer.append(l)
+        if (current_buffer):
+            print '\n'.join(current_buffer)
+
+
+if (__name__=='__main__'):
+	main()
diff --git a/xos/tools/apigen/modelyaml.fields.template.txt b/xos/tools/apigen/modelyaml.fields.template.txt
new file mode 100644
index 0000000..69129ed
--- /dev/null
+++ b/xos/tools/apigen/modelyaml.fields.template.txt
@@ -0,0 +1,12 @@
+{% for object in generator.all %}
+{{ object.camel }}:
+fields:
+  {% for f in object.fields %}
+  - name: {{ f.name }}
+    type: {{ f.type }}
+    {% if f.help_text %}
+    help_text: {{ f.help_text }}
+    {% endif %}
+    null: {{ f.null }}
+{% endfor %}
+{% endfor %}
diff --git a/xos/tools/apigen/simple.template.txt b/xos/tools/apigen/simple.template.txt
new file mode 100644
index 0000000..fb00670
--- /dev/null
+++ b/xos/tools/apigen/simple.template.txt
@@ -0,0 +1,9 @@
+{% for object in generator.all %}
+Object {{ object }}:
+Refs:
+{% for ref in object.refs %}
+{{ ref }}{% endfor %}
+Props:
+{% for prop in object.props %}{{ prop }}
+{% endfor %}
+{% endfor %}
diff --git a/xos/tools/apigen/style.template b/xos/tools/apigen/style.template
new file mode 100644
index 0000000..db80f55
--- /dev/null
+++ b/xos/tools/apigen/style.template
@@ -0,0 +1,47 @@
+def is_camel_case(name):
+    for (i,char) in enumerate(name):
+        if (i>=1) and (name[i-1].islower()) and (char.isupper()):
+            return True
+    return False
+
+def is_missing_underscore(fieldName):
+   if (fieldName == "kuser_id"):
+       # this one is okay
+       return False
+
+   {% for model in generator.all %}
+       pos = fieldName.find("{{ model }}")
+       if (pos > 0) and (fieldName[pos-1] != "_"):
+           return True
+   {% endfor %}
+
+       return False
+
+def stylecheck_model_name(name):
+   if name.endswith("s"):
+       print "model '%s' name ends with 's'" % name
+
+def stylecheck_field_name(modelName, fieldName):
+   if is_camel_case(fieldName):
+       print "field '%s.%s' has camelcase" % (modelName, fieldName)
+   if is_missing_underscore(fieldName):
+       print "field '%s.%s' is missing underscore" % (modelName, fieldName)
+
+def stylecheck_field_plural(modelName, fieldName):
+   if is_camel_case(fieldName):
+       print "m2m field '%s.%s' has camelcase" % (modelName, fieldName)
+   if is_missing_underscore(fieldName):
+       print "m2m field '%s.%s' is missing underscore" % (modelName, fieldName)
+
+def main():
+{% for obj in generator.all %}
+   stylecheck_model_name("{{ obj.camel }}");
+{% for ref in obj.refs %}
+   stylecheck_field_plural("{{ obj.camel }}", "{{ ref.plural }}");
+{% endfor %}
+{% for prop in obj.props %}
+   stylecheck_field_name("{{ obj.camel }}", "{{ prop }}");
+{% endfor %}
+{% endfor %}
+
+main()
diff --git a/xos/tools/apigen/synchronizer.template.txt b/xos/tools/apigen/synchronizer.template.txt
new file mode 100644
index 0000000..c784e21
--- /dev/null
+++ b/xos/tools/apigen/synchronizer.template.txt
@@ -0,0 +1,71 @@
+{% for app,files in generator.apps.items %}
+{% for file,models in files.items %}
+{% for m in models %}
+# This file implements the synchronization of the {{ m.class_name }} model
+# TODO (see below):
+
+import os
+import base64
+import socket
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.syncstep import SyncStep
+from {{app}}.models.{{ file }} import {{ m.class_name.title }}
+from synchronizers.base.ansible import *
+from synchronizers.base.syncstep import *
+from xos.logger import observer_logger as logger
+
+class Sync{{m.camel.title}}(SyncStep):
+    # The model synchronized
+    provides=[{{m.class_name.title}}]
+    # How often do you want this to run. 0 means immediately following changes to the model
+    requested_interval=0
+    # The model in which changes trigger this module
+    observes={{m.class_name}}
+    # The Ansible recipe that does the bulk of the synchronization (hopefully)
+    playbook='sync_{{m.class_name}}.yaml'
+
+    # 1. Populate a data structure to pass into your ansible recipe, based on the data model. 
+    def map_sync_inputs(self, {{ m.class_name }}): 
+        fields = {
+            {% for f in m.fields %}'{{f.name}}': {{f.name}},
+            {% endfor %}
+        }
+        return fields
+        
+    # 2. Store the result of the operation in the model
+    def map_sync_outputs(self, {{ m.class_name }}, res):
+        // Store the output of res in the {{m.class_name}} object 
+        return
+    
+    # 3. Populate the data structure that identifies objects to delete
+    def map_delete_inputs(self, {{ m.class_name }}, res):
+        fields = {
+            {% for f in m.fields %}'{{f.name}}': {{f.name}},
+            {% endfor %}
+               'delete':True
+        }
+        return fields
+
+
++++ Sync{{ m.class_name }}.py
+---
+- hosts: 127.0.0.1
+  connection: local
+  tasks:
+  - task_1:
+      {% for f in m.fields %}
+      {{f.name}}: {% templatetag openbrace %}{% templatetag openbrace %}{{f.name}}{% templatetag closebrace %}{% templatetag closebrace %}
+      {% endfor %}
+      {% verbatim %}
+      {% if delete %}
+      state: absent
+      {% else %}
+      state: present
+      {% endif %}
+      {% endif %}
+      {% endverbatim %}
++++ Sync{{ m.class_name }}.yaml
+{% endfor %}
+{% endfor %}
+{% endfor %}
diff --git a/xos/tools/apigen/type_map b/xos/tools/apigen/type_map
new file mode 100644
index 0000000..ac4a8a8
--- /dev/null
+++ b/xos/tools/apigen/type_map
@@ -0,0 +1,10 @@
+{
+    "AutoField":"int64",
+    "ForeignKey":"InstanceIdentifier",
+    "CharField":"string",
+    "TextField":"string",
+    "FloatField":"float64",
+    "BooleanField":"boolean",
+    "StrippedCharField":"string",
+    "DateTimeField":"date-and-time"
+}
diff --git a/xos/tools/apigen/yang.template.txt b/xos/tools/apigen/yang.template.txt
new file mode 100644
index 0000000..ad4b1b1
--- /dev/null
+++ b/xos/tools/apigen/yang.template.txt
@@ -0,0 +1,21 @@
+{% for app,files in generator.apps.items %}
+{% for file,m in files.items %}
+module xos-{{ app }}-{{ file }} {
+    namespace "urn:xos:{{app}}.{{ file }}";
+    prefix xos-cs;
+
+    import complex-types {prefix ct;}
+    revision 2016-2-24 {
+        description "Initial";
+    }   
+
+    complex-type {{ m.class_name }} {
+      {% for f in m.fields %}
+
+      leaf {{ f.name }} { type {{ f.type }}{% ifequal f.type "ForeignKey" %} { ct:instance-type {{f.related.model.class_name}};{% if f.null%}{%else%}require-instance true{% endif %}{% endifequal %};{% if f.max_length %} { length {{ f.max_length }};{% endif %}{% if None %}default "{{ f.default }}";{% endif %}}
+      {% endfor %}
+    }
+}
++++ {{ app }}-{{ file}}.yang
+{% endfor %}
+{% endfor %}
diff --git a/xos/tools/chuckmove b/xos/tools/chuckmove
new file mode 100755
index 0000000..5a77876
--- /dev/null
+++ b/xos/tools/chuckmove
@@ -0,0 +1,82 @@
+#!/usr/bin/python
+
+from pyparsing import *
+from optparse import OptionParser
+import os
+from os.path import join,exists
+from shutil import copy
+
+usage = "usage: %prog --old <old namespace> --new <new namespace> <directory root>"
+
+parser = OptionParser(usage=usage)
+
+parser.add_option("-q", "--quiet",
+                          action="store_false", dest="verbose",
+                          help="be vewwy quiet (I'm hunting wabbits)")
+
+parser.add_option("-r", "--reuse",
+                          action="store_false", dest="reuse",
+                          help="Reuse .orig files. Dangerous!")
+
+parser.add_option("-o", "--old", 
+                          metavar="old", help="Old namespace")
+
+parser.add_option("-n", "--new",
+                          default="new", help="New namespace")
+
+(options, args) = parser.parse_args()
+
+old_ns = options.old
+new_ns = options.new
+
+# grammar
+
+comment = '#' + SkipTo(lineEnd)
+
+module_ns = Word(alphanums + '-' + '_' + '.' + '*')
+old_module_ns = Combine(old_ns + Optional(Combine('.'+module_ns)))
+end_of_python_line = Or([lineEnd,comment])
+
+as_suffix = 'as' + module_ns
+
+import_pure = 'import' + old_module_ns 
+import_pure_line = import_pure + Optional(as_suffix) + end_of_python_line
+
+import_from = 'from' + old_module_ns + 'import' + commaSeparatedList
+import_from_line = import_from + Optional(as_suffix) + end_of_python_line
+
+import_line = Or([import_pure_line, import_from_line])
+
+# Make a list of Python files to deal with
+
+try:
+    f = args[0]
+except IndexError:
+    print 'Specify a directory root'
+    exit(1)
+
+for root, dirs, files in os.walk(f):
+    for n in files:
+        if (n.endswith('.py')):
+            full_path = '/'.join([root,n])
+            orig_path = full_path + '.orig'
+            if (options.verbose):
+                print 'Working on %s:'%full_path
+            if (not os.path.exists(orig_path) or not options.reuse):
+                if (options.verbose):
+                    print 'Copying %s->%s:'%(full_path,orig_path)
+                copy(full_path, orig_path)
+            f_contents = open(orig_path).read()
+            new_contents = []
+            for l in f_contents.splitlines():
+                try:
+                    match = import_line.parseString(l)
+                    l = l.replace(old_ns, new_ns)
+                except ParseException:
+                    pass
+                new_contents.append(l)
+
+            new_file = '\n'.join(new_contents)
+            if (f_contents.endswith('\n')):
+                new_file+='\n'
+            open(full_path,'w').write(new_file)
diff --git a/xos/tools/chuckmove.README b/xos/tools/chuckmove.README
new file mode 100644
index 0000000..5039548
--- /dev/null
+++ b/xos/tools/chuckmove.README
@@ -0,0 +1,27 @@
+Hi,
+
+I've written a tool called 'chuckmove' for helping move Python modules around in a source tree. You use it as follows. Lets say you want to relocate a module to a different location in the tree, and also rename it. So for instance, x is to become y.z. The syntax you use is:
+
+chuckmove -o x -n y.z <root directory>
+
+Invoking this command makes the tool recursively descend into the root directory, make a backup copy of each file (adding the prefix '.orig') and rewrite the imports in it, so that "import x" gets turned into "import y.z"
+
+It recognizes Python grammar, so it works with all of these forms:
+
+from x import a
+from x.b import c 
+import x.d.e.f as foo # Comments are also handled
+
+...with the nit that lines with syntax/grammatical errors are left as is.
+
+For example, for the observer/synchronizer changes, I just had to do the following:
+
+chuckmove -o observer -n synchronizers.base xos
+
+...and then to generate a patch with the changes:
+
+gendiff xos .orig
+
+It's checked into the xos repository under tools (with a README file!).
+
+Sapan
diff --git a/xos/tools/cleanup_unique.py b/xos/tools/cleanup_unique.py
new file mode 100644
index 0000000..97710ec
--- /dev/null
+++ b/xos/tools/cleanup_unique.py
@@ -0,0 +1,99 @@
+import os
+import sys
+sys.path.append("/opt/xos")
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
+import django
+from core.models import *
+django.setup()
+
+for obj in ControllerNetwork.deleted_objects.all():
+    print "Purging deleted object", obj
+    obj.delete(purge=True)
+
+for obj in ControllerSite.deleted_objects.all():
+    print "Purging deleted object", obj
+    obj.delete(purge=True)
+
+for obj in ControllerSlice.deleted_objects.all():
+    print "Purging deleted object", obj
+    obj.delete(purge=True)
+
+for obj in NetworkSlice.deleted_objects.all():
+    print "Purging deleted object", obj
+    obj.delete(purge=True)
+
+for obj in Port.deleted_objects.all():
+    print "Purging deleted object", obj
+    obj.delete(purge=True)
+
+for obj in DeploymentPrivilege.deleted_objects.all():
+    print "Purging deleted object", obj
+    obj.delete(purge=True)
+
+for obj in SiteDeployment.deleted_objects.all():
+    print "Purging deleted object", obj
+    obj.delete(purge=True)
+
+seen=[]
+for obj in ControllerNetwork.objects.all():
+     seen.append(obj.id)
+     conflicts = ControllerNetwork.objects.filter(network=obj.network, controller=obj.controller)
+     for conflict in conflicts:
+         if conflict.id not in seen:
+             print "Purging", conflict, conflict.id, "due to duplicate of", obj.id
+             conflict.delete(purge=True)
+
+seen=[]
+for obj in NetworkSlice.objects.all():
+     seen.append(obj.id)
+     conflicts = NetworkSlice.objects.filter(network=obj.network, slice=obj.slice)
+     for conflict in conflicts:
+         if conflict.id not in seen:
+             print "Purging", conflict, conflict.id, "due to duplicate of", obj.id
+             conflict.delete(purge=True)
+
+seen=[]
+for obj in Port.objects.all():
+     seen.append(obj.id)
+     conflicts = Port.objects.filter(network=obj.network, instance=obj.instanc)
+     for conflict in conflicts:
+         if conflict.id not in seen:
+             print "Purging", conflict, conflict.id, "due to duplicate of", obj.id
+             conflict.delete(purge=True)
+
+seen=[]
+for obj in DeploymentPrivilege.objects.all():
+     seen.append(obj.id)
+     conflicts = DeploymentPrivilege.objects.filter(user=obj.user, deployment=obj.deployment, role=obj.role)
+     for conflict in conflicts:
+         if conflict.id not in seen:
+             print "Purging", conflict, conflict.id, "due to duplicate of", obj.id
+             conflict.delete(purge=True)
+
+seen=[]
+for obj in SiteDeployment.objects.all():
+     seen.append(obj.id)
+     conflicts = SiteDeployment.objects.filter(site=obj.site, deployment=obj.deployment, controller=obj.controller)
+     for conflict in conflicts:
+         if conflict.id not in seen:
+             print "Purging", conflict, conflict.id, "due to duplicate of", obj.id
+             conflict.delete(purge=True)
+
+seen=[]
+for obj in ControllerSite.objects.all():
+     seen.append(obj.id)
+     conflicts = ControllerSite.objects.filter(site=obj.site, controller=obj.controller)
+     for conflict in conflicts:
+         if conflict.id not in seen:
+             print "Purging", conflict, conflict.id, "due to duplicate of", obj.id
+             conflict.delete(purge=True)
+
+seen=[]
+for obj in ControllerSlice.objects.all():
+     seen.append(obj.id)
+     conflicts = ControllerSlice.objects.filter(slice=obj.slice, controller=obj.controller)
+     for conflict in conflicts:
+         if conflict.id not in seen:
+             print "Purging", conflict, conflict.id, "due to duplicate of", obj.id
+             conflict.delete(purge=True)
+
diff --git a/xos/tools/destroy-all-networks.sh b/xos/tools/destroy-all-networks.sh
new file mode 100755
index 0000000..f590683
--- /dev/null
+++ b/xos/tools/destroy-all-networks.sh
@@ -0,0 +1,34 @@
+#! /bin/bash
+
+# This will destroy all neutron networks, routers, and ports on Cloudlab. 
+# It even destroys ext-net, flat-net, and tun-net
+# Don't use it unless you really want that to happen.
+
+source /root/setup/admin-openrc.sh
+
+echo "Lots of stuff will fail -- don't worry about it"
+
+PORTS=`neutron port-list | grep -v "+----" | grep -v "mac_address" | awk '{print $2}'`
+for PORT in $PORTS; do
+   echo "Deleting port $PORT"
+   neutron port-delete $PORT
+done
+
+NET_SUBNETS=`neutron net-list | grep -v "+----" | grep -v "subnets" | awk '{print $6}'`
+ROUTERS=`neutron router-list | grep -v "+----" | grep -v "external_gateway_info" | awk '{print $2}'`  
+
+for ROUTER in $ROUTERS; do
+for SUBNET in $NET_SUBNETS; do
+neutron router-interface-delete $ROUTER $SUBNET
+done
+neutron router-delete $ROUTER
+done
+
+echo "Stuff below this line shouldn't fail"
+
+NETS=`neutron net-list | grep -v "+----" | grep -v "subnets" | awk '{print $2}'`  
+for NET in $NETS; do
+   echo "Deleting network"
+   neutron net-delete $NET
+done
+   
\ No newline at end of file
diff --git a/xos/tools/dmdot b/xos/tools/dmdot
new file mode 100755
index 0000000..9cde0ed
--- /dev/null
+++ b/xos/tools/dmdot
@@ -0,0 +1,106 @@
+#!/usr/bin/python
+
+import os
+import pdb
+import sys
+import json
+
+sys.path.append('.')
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
+
+from django.db.models.fields.related import ForeignKey
+
+# try to make sure we're running from the right place
+if (not os.path.exists("core")):
+   if (os.path.exists("../core")):
+      os.chdir("..")
+   else:
+      print >> sys.stderr, "Are you sure you're running dmdot from the root of an XOS installation"
+      sys.exit(-1)
+
+# defaults
+apps = ["core", "services.hpc", "services.requestrouter", "services.onos"]
+output = "-json"
+
+# syntax: dmdot [-json | -dot] [app_name]
+
+# poor man's argument parser
+for arg in sys.argv[1:]:
+    if arg.startswith("-"):
+        output = arg
+    else:
+        apps+= [arg]
+
+model_classes = []
+class_names = []
+lower_class_names = {}
+synonyms = {
+	'user':'creator'
+}
+
+for app in apps:
+	app = app + ".models"
+	#models_module = imp.load_source(app, ".")
+	models_module = __import__(app)
+	for part in app.split(".")[1:]:
+	    if hasattr(models_module, "PlCoreBase"):
+		break
+	    models_module = getattr(models_module,part)
+
+	PlCoreBase = getattr(models_module,"PlCoreBase")
+
+	for classname in dir(models_module):
+		c = getattr(models_module, classname, None)
+		if type(c)==type(PlCoreBase):
+			model_classes.append(c)
+			class_names.append(c.__name__)
+			lower_class_names[c.__name__.lower()] = c
+			try:
+				synonym = synonyms[c.__name__.lower()]
+				lower_class_names[synonym] = c
+			except: 
+				pass    
+				
+
+# django doesn't use the correct case in field.name.title() for objects that
+# have CamelCased class names. So, compare everything in lower case.
+
+if (output=='-dot'):
+        print "digraph plstack {";
+        for c in model_classes:
+                fields = c._meta.fields
+
+                for f in fields:
+                        if type(f)==ForeignKey and f.name.lower().split('_') in lower_class_names:
+                                linked_class = lower_class_names[f.name.lower()]
+				if ('backref' in f.name):
+                                	print '\t"%s"->"%s";'%(linked_class.__name__,c.__name__)
+				else:
+                                	print '\t"%s"->"%s";'%(c.__name__,linked_class.__name__)
+        print "}\n";
+elif (output=='-json'):
+        d = {}
+        for c in model_classes:
+                fields = c._meta.fields
+		
+                for f in fields:
+			field_type = f.name.lower().split('_')[0]
+                        if type(f)==ForeignKey and field_type in lower_class_names:
+                                linked_class = lower_class_names[field_type]
+				if ('backref' in f.name.lower()):
+					a = linked_class.__name__
+					b = c.__name__
+				else:
+					b = linked_class.__name__
+					a = c.__name__
+
+                                try:
+					if (b not in d[a]):
+                                        	d[a].append(b)
+                                except KeyError:
+                                        d[c.__name__]=[linked_class.__name__]
+        #d['ControllerNetwork'].append('SliceDeployments')
+        print json.dumps(d,indent=4)
+        
+        
diff --git a/xos/tools/docker_setup_xos b/xos/tools/docker_setup_xos
new file mode 100755
index 0000000..ed3e5e5
--- /dev/null
+++ b/xos/tools/docker_setup_xos
@@ -0,0 +1,17 @@
+#! /bin/bash
+
+function wait_postgres {
+    sudo -u postgres psql -c '\q'
+    while [[ "$?" != "0" ]]; do
+        echo Waiting for postgres to start
+        sleep 1
+        sudo -u postgres psql -c '\q'
+    done
+}
+
+cd /tmp
+service postgresql start
+wait_postgres
+service supervisor start
+
+exit 0
diff --git a/xos/tools/docker_start_xos b/xos/tools/docker_start_xos
new file mode 100755
index 0000000..3b82e71
--- /dev/null
+++ b/xos/tools/docker_start_xos
@@ -0,0 +1,7 @@
+#! /bin/bash
+
+bash /opt/xos/tools/docker_setup_xos
+
+cd /opt/xos
+PUBLIC_HOSTNAME="0.0.0.0"
+python manage.py runserver $PUBLIC_HOSTNAME:8000 --insecure
diff --git a/xos/tools/get_instance_ip.py b/xos/tools/get_instance_ip.py
new file mode 100644
index 0000000..1783b25
--- /dev/null
+++ b/xos/tools/get_instance_ip.py
@@ -0,0 +1,97 @@
+#! /usr/bin/env python
+
+import json
+import os
+import requests
+import sys
+
+from operator import itemgetter, attrgetter
+
+REST_API="http://alpha.opencloud.us:8000/xos/"
+
+NODES_API = REST_API + "nodes/"
+SLICES_API = REST_API + "slices/"
+INSTANCES_API = REST_API + "instances/"
+PORTS_API = REST_API + "ports/"
+
+opencloud_auth=("demo@onlab.us", "demo")
+
+def get_slice_id(slice_name):
+    r = requests.get(SLICES_API + "?name=%s" % slice_name, auth=opencloud_auth)
+    return r.json()[0]["id"]
+
+def get_node_id(host_name):
+     r = requests.get(NODES_API)
+     nodes = r.json()
+     for node in nodes:
+         if node["name"].lower() == host_name.lower():
+             return node["id"]
+     print >> sys.stderr, "Error: failed to find node %s" % host_name
+     sys.exit(-1)
+
+def get_instances(slice_id=None, node_id=None):
+    queries = []
+    if slice_id:
+        queries.append("slice=%s" % str(slice_id))
+    if node_id:
+        queries.append("node=%s" % str(node_id))
+
+    if queries:
+        query_string = "?" + "&".join(queries)
+    else:
+        query_string = ""
+
+    r = requests.get(INSTANCES_API + query_string, auth=opencloud_auth)
+    return r.json()
+
+def main():
+    global opencloud_auth
+
+    if len(sys.argv)!=5:
+        print >> sys.stderr, "syntax: get_instance_name.py <username>, <password>, <hostname> <slicename>"
+        sys.exit(-1)
+
+    username = sys.argv[1]
+    password = sys.argv[2]
+    hostname = sys.argv[3]
+    slice_name = sys.argv[4]
+
+    opencloud_auth=(username, password)
+
+    slice_id = get_slice_id(slice_name)
+    node_id = get_node_id(hostname)
+    instances = get_instances(slice_id, node_id)
+
+    # get (instance_name, ip) pairs for instances with names and ips
+
+    instances = [x for x in instances if x["instance_name"]]
+    instances = sorted(instances, key = lambda instance: instance["instance_name"])
+
+    # return the last one in the list (i.e. the newest one)
+
+    instance_id = instances[-1]["id"]
+
+    r = requests.get(PORTS_API + "?instance=%s" % instance_id, auth=opencloud_auth)
+    ports = r.json()
+    ips = [x["ip"] for x in ports]
+
+    # XXX kinda hackish -- assumes private ips start with "10." and nat start with "172."
+
+    # print a public IP if there is one
+    for ip in ips:
+       if (not ip.startswith("10")) and (not ip.startswith("172")):
+           print ip
+           return
+
+    # otherwise print a privat ip
+    for ip in ips:
+       if (not ip.startswith("172")):
+           print ip
+           return
+
+    # otherwise just print the first one
+    print ips[0]
+
+if __name__ == "__main__":
+    main()
+
diff --git a/xos/tools/get_instance_name.py b/xos/tools/get_instance_name.py
new file mode 100644
index 0000000..844ba5a
--- /dev/null
+++ b/xos/tools/get_instance_name.py
@@ -0,0 +1,70 @@
+#! /usr/bin/env python
+
+import json
+import os
+import requests
+import sys
+
+REST_API="http://alpha.opencloud.us:8000/xos/"
+
+NODES_API = REST_API + "nodes/"
+SLICES_API = REST_API + "slices/"
+SLIVERS_API = REST_API + "instances/"
+
+opencloud_auth=("demo@onlab.us", "demo")
+
+def get_slice_id(slice_name):
+    r = requests.get(SLICES_API + "?name=%s" % slice_name, auth=opencloud_auth)
+    return r.json()[0]["id"]
+
+def get_node_id(host_name):
+     r = requests.get(NODES_API)
+     nodes = r.json()
+     for node in nodes:
+         if node["name"].lower() == host_name.lower():
+             return node["id"]
+     print >> sys.stderr, "Error: failed to find node %s" % host_name
+     sys.exit(-1)
+
+def get_instances(slice_id=None, node_id=None):
+    queries = []
+    if slice_id:
+        queries.append("slice=%s" % str(slice_id))
+    if node_id:
+        queries.append("node=%s" % str(node_id))
+
+    if queries:
+        query_string = "?" + "&".join(queries)
+    else:
+        query_string = ""
+
+    r = requests.get(SLIVERS_API + query_string, auth=opencloud_auth)
+    return r.json()
+
+def main():
+    global opencloud_auth
+
+    if len(sys.argv)!=5:
+        print >> sys.stderr, "syntax: get_instance_name.py <username>, <password>, <hostname> <slicename>"
+        sys.exit(-1)
+
+    username = sys.argv[1]
+    password = sys.argv[2]
+    hostname = sys.argv[3]
+    slice_name = sys.argv[4]
+
+    opencloud_auth=(username, password)
+
+    slice_id = get_slice_id(slice_name)
+    node_id = get_node_id(hostname)
+    instances = get_instances(slice_id, node_id)
+
+    instance_names = [x["instance_name"] for x in instances if x["instance_name"]]
+
+    # return the last one in the list (i.e. the newest one)
+
+    print sorted(instance_names)[-1]
+
+if __name__ == "__main__":
+    main()
+
diff --git a/xos/tools/imagebuilder/Makefile b/xos/tools/imagebuilder/Makefile
new file mode 100644
index 0000000..524f986
--- /dev/null
+++ b/xos/tools/imagebuilder/Makefile
@@ -0,0 +1,6 @@
+vsg_image:
+	ansible-playbook -i inventory -c local vsg_image.yaml
+	echo "Look for your image in /image/vsg.img"
+
+cleanup:
+	rm -f /image/vsg.qcow2
diff --git a/xos/tools/imagebuilder/README.md b/xos/tools/imagebuilder/README.md
new file mode 100644
index 0000000..baef216
--- /dev/null
+++ b/xos/tools/imagebuilder/README.md
@@ -0,0 +1,8 @@
+Prerequisites:
+
+mkdir /image
+curl http://www.vicci.org/cord/ceilometer-trusty-server-multi-nic.compressed.qcow2 > /image/trusty-server-multi-nic.img
+apt-add-repository ppa:ansible/ansible
+apt-get update
+apt-get install ansible qemu-utils
+modprobe nbd
diff --git a/xos/tools/imagebuilder/files/docker.list b/xos/tools/imagebuilder/files/docker.list
new file mode 100644
index 0000000..0ee9ae0
--- /dev/null
+++ b/xos/tools/imagebuilder/files/docker.list
@@ -0,0 +1 @@
+deb https://get.docker.com/ubuntu docker main
diff --git a/xos/tools/imagebuilder/files/resolv.conf b/xos/tools/imagebuilder/files/resolv.conf
new file mode 100644
index 0000000..cae093a
--- /dev/null
+++ b/xos/tools/imagebuilder/files/resolv.conf
@@ -0,0 +1 @@
+nameserver 8.8.8.8
diff --git a/xos/tools/imagebuilder/files/vm-resolv.conf b/xos/tools/imagebuilder/files/vm-resolv.conf
new file mode 100644
index 0000000..cae093a
--- /dev/null
+++ b/xos/tools/imagebuilder/files/vm-resolv.conf
@@ -0,0 +1 @@
+nameserver 8.8.8.8
diff --git a/xos/tools/imagebuilder/inventory b/xos/tools/imagebuilder/inventory
new file mode 100644
index 0000000..5279c57
--- /dev/null
+++ b/xos/tools/imagebuilder/inventory
@@ -0,0 +1,4 @@
+localhost
+
+[chroots]
+/image/inside
diff --git a/xos/tools/imagebuilder/vsg_image.yaml b/xos/tools/imagebuilder/vsg_image.yaml
new file mode 100644
index 0000000..eae6612
--- /dev/null
+++ b/xos/tools/imagebuilder/vsg_image.yaml
@@ -0,0 +1,88 @@
+- hosts: localhost
+  connection: local
+  tasks:
+      - name: Unmount proc, if it is mounted
+        shell: umount /image/inside/proc removes=/image/inside/proc/cmdline
+
+      - name: Unmount the image, if it is mounted
+        shell: umount /image/inside removes=/image/inside/root
+
+      - name: Unconnect the nbd device, if it is connected
+        shell: qemu-nbd --disconnect /dev/nbd0 removes=/dev/nbd0p1
+
+      - name: copy the base image to the desgination filename
+        shell: cp /image/trusty-server-multi-nic.img /image/vsg.img creates=/image/vsg.img
+
+      - name: make the mountpount
+        shell: mkdir /image/inside creates=/image/inside
+
+      - name: connect the nbd device
+        shell: qemu-nbd --connect=/dev/nbd0 /image/vsg.img creates=/dev/nbd0p1
+
+      - name: mount the image
+        shell: mount /dev/nbd0p1 /image/inside creates=/image/inside/root
+
+      - name: mount proc
+        shell: mount -t proc proc /image/inside/proc creates=/image/inside/proc/cmdline
+
+- hosts: chroots
+  connection: chroot
+  tasks:
+      - name: Stop resolvconf service
+        service: name=resolvconf state=stopped
+
+      - name: Disable resolvconf service
+        copy: dest=/etc/init/resolvconf.override content="manual"
+
+      - name: Install resolv.conf
+        copy: src=files/vm-resolv.conf
+          dest=/etc/resolv.conf
+
+      - name: install bridge-utils
+        apt: name=bridge-utils state=present
+
+      - name: Docker repository
+        copy: src=files/docker.list
+          dest=/etc/apt/sources.list.d/docker.list
+
+      - name: Import the repository key
+        apt_key: keyserver=keyserver.ubuntu.com id=36A1D7869245C8950F966E92D8576A8BA88D21E9
+
+      - name: Update cache
+        apt: update_cache=yes
+
+      - name: install Docker
+        apt: name=lxc-docker state=present
+
+      - name: install python-setuptools
+        apt: name=python-setuptools state=present
+
+      - name: install pip
+        easy_install: name=pip
+
+      - name: install docker-py
+        pip: name=docker-py version=0.5.3
+
+      - name: install Pipework
+        get_url: url=https://raw.githubusercontent.com/jpetazzo/pipework/master/pipework
+           dest=/usr/local/bin/pipework
+           mode=0755
+
+# now unmount the image file
+
+- hosts: localhost
+  connection: local
+  tasks:
+      - name: sync the filesystem
+        shell: sync
+
+      - name: Unmount proc, if it is mounted
+        shell: umount /image/inside/proc removes=/image/inside/proc/cmdline
+
+      - name: Unmount the image, if it is mounted
+        shell: umount /image/inside removes=/image/inside/root
+
+      - name: Unconnect the nbd device, if it is connected
+        shell: qemu-nbd --disconnect /dev/nbd0 removes=/dev/nbd0p1
+
+
diff --git a/xos/tools/openstack-db-cleanup.sh b/xos/tools/openstack-db-cleanup.sh
new file mode 100644
index 0000000..851d326
--- /dev/null
+++ b/xos/tools/openstack-db-cleanup.sh
@@ -0,0 +1,18 @@
+#! /bin/bash
+
+# to install
+#    chmod 0755 /opt/xos/openstack/openstack-db-cleanup.sh
+#    ln -s /opt/xos/openstack/openstack-db-cleanup.sh /etc/cron.daily/openstack-db-cleanup.cron
+
+XOS_DIR="/opt/xos"
+
+mkdir -p $XOS_DIR/ovs-backups
+BACKUP_NAME=$XOS_DIR/ovs-backups/backup-`date "+%Y-%M-%d"`.sql
+mysqldump --create-options --routines --triggers --databases keystone ovs_quantum nova glance cinder > $BACKUP_NAME
+gzip $BACKUP_NAME
+
+mysql keystone -e "DELETE FROM token WHERE NOT DATE_SUB(CURDATE(),INTERVAL 2 DAY) <= expires;"
+mysqlcheck --optimize --databases keystone ovs_quantum nova glance cinder
+
+date >> /var/log/openstack-db-cleanup.log
+mysql keystone -e "select count(*) from token;" >> /var/log/openstack-db-cleanup.log
diff --git a/xos/tools/openstack-healthcheck.py b/xos/tools/openstack-healthcheck.py
new file mode 100644
index 0000000..4b8a3f1
--- /dev/null
+++ b/xos/tools/openstack-healthcheck.py
@@ -0,0 +1,57 @@
+#! /usr/bin/env python
+
+"""
+    Check the status of libvirt, openstack-nova-compute, and
+    quantum-openvswitch-agent. If these services are enabled and have failed,
+    then restart them.
+"""
+
+import os
+import sys
+import subprocess
+import time
+
+def get_systemd_status(service):
+    p=subprocess.Popen(["/bin/systemctl", "is-active", service], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+    (out, err) = p.communicate()
+    out = out.strip()
+    return out
+
+libvirt_enabled = os.system("systemctl -q is-enabled libvirtd.service")==0
+nova_compute_enabled = os.system("systemctl -q is-enabled openstack-nova-compute.service")==0
+openvswitch_agent_enabled = os.system("systemctl -q is-enabled quantum-openvswitch-agent.service")==0
+
+print "enabled:"
+print "  libvirtd=", libvirt_enabled
+print "  openstack-nova-compute=", nova_compute_enabled
+print "  quantum-openvswitch-agent=", openvswitch_agent_enabled
+
+if (not libvirt_enabled) or (not nova_compute_enabled) or (not openvswitch_agent_enabled):
+    print "services are not enabled. exiting"
+    sys.exit(0)
+
+libvirt_status = get_systemd_status("libvirtd.service")
+nova_compute_status = get_systemd_status("openstack-nova-compute.service")
+openvswitch_agent_status = get_systemd_status("quantum-openvswitch-agent.service")
+
+print "status:"
+print "  libvirtd=", libvirt_status
+print "  openstack-nova-compute=", nova_compute_status
+print "  quantum-openvswitch-agent=", openvswitch_agent_status
+
+if (libvirt_status=="failed") or (nova_compute_status=="failed") or (openvswitch_agent_status=="failed"):
+    print "services have failed. doing the big restart"
+    os.system("systemctl stop openstack-nova-compute.service")
+    os.system("systemctl stop quantum-openvswitch-agent.service")
+    os.system("systemctl stop libvirtd.service")
+    time.sleep(5)
+    os.system("systemctl start libvirtd.service")
+    time.sleep(5)
+    os.system("systemctl start quantum-openvswitch-agent.service")
+    time.sleep(5)
+    os.system("systemctl start openstack-nova-compute.service")
+    print "done"
+
+
+
+
diff --git a/xos/tools/purge.py b/xos/tools/purge.py
new file mode 100644
index 0000000..8c081e6
--- /dev/null
+++ b/xos/tools/purge.py
@@ -0,0 +1,14 @@
+import os
+import sys
+sys.path.append("/opt/xos")
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
+import django
+from core.models import *
+django.setup()
+
+def purge(cls):
+    for obj in cls.deleted_objects.all():
+        obj.delete(purge=True)
+
+for model in [Instance, Slice, Site, Service, User, Image, ImageDeployments, Port]:
+    purge(model)
diff --git a/xos/tools/rebuild.py b/xos/tools/rebuild.py
new file mode 100755
index 0000000..dc2c482
--- /dev/null
+++ b/xos/tools/rebuild.py
@@ -0,0 +1,17 @@
+#!/usr/bin/env python                                                                                                               
+
+import os
+import sys
+sys.path.append("/opt/xos")
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
+import django
+from core.models import XOS
+django.setup()
+
+xoses = XOS.objects.all()
+if not xoses:
+    print "There is no XOS model"
+
+for xos in xoses:
+    xos.rebuild()
+
diff --git a/xos/tools/ssh-myslice b/xos/tools/ssh-myslice
new file mode 100644
index 0000000..118d2b5
--- /dev/null
+++ b/xos/tools/ssh-myslice
@@ -0,0 +1,15 @@
+#! /bin/bash
+
+# Demonstrates using get_instance_name to ssh to an instance at a hostname
+# Call this script with one argument, the name of the node you want to ssh
+
+# fill in all ow the following wiht your info
+
+$USERNAME=my_username
+$PASSWORD=my_password
+$SLICENAME=my_slice
+$KEY=pathname_to_my_ssh_key
+$PROGRAM=/home/smbaker/projects/vicci/xos/planetstack/tools/get_instance_name.py
+
+INSTANCE_NAME=`python $PROGRAM $USERNAME $PASSWORD $1 $SLICENAME`
+ssh-agent bash -c "ssh-add $KEY; ssh -A $INSTANCE_NAME@$1"
diff --git a/xos/tools/wait_for_object_creation.py b/xos/tools/wait_for_object_creation.py
new file mode 100755
index 0000000..b2af38f
--- /dev/null
+++ b/xos/tools/wait_for_object_creation.py
@@ -0,0 +1,35 @@
+import os
+import sys
+sys.path.append("/opt/xos")
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
+import django
+from core.models import *
+from services.hpc.models import *
+from services.volt.models import *
+from services.vsg.models import *
+import time
+django.setup()
+
+def main():
+    printed = False
+
+    if len(sys.argv)!=4:
+        print >> sys.stderr, "syntax: wait_for_object_creation.py <class> <filter_field_name> <filter_field_value>"
+        print >> sys.stderr, "example: wait_for_object_creation.py Image name vsg-1.0"
+        sys.exit(-1)
+
+    cls = globals()[sys.argv[1]]
+
+    while True:
+        objs = cls.objects.filter(**{sys.argv[2]: sys.argv[3]})
+        if objs:
+            print "Object", objs[0], "is ready"
+            return
+        if not printed:
+            print "Waiting for %s with field %s=%s to be created" % (sys.argv[1], sys.argv[2], sys.argv[3])
+            printed=True
+        time.sleep(1)
+
+if __name__ == "__main__":
+   main()
+
diff --git a/xos/tools/xos-config.py b/xos/tools/xos-config.py
new file mode 100755
index 0000000..67ca4f6
--- /dev/null
+++ b/xos/tools/xos-config.py
@@ -0,0 +1,32 @@
+#!/usr/bin/env python
+import sys
+
+# add the parent directory to sys.path
+import os,sys,inspect
+currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
+parentdir = os.path.dirname(currentdir)
+sys.path.append(parentdir)
+
+from xos.config import Config
+
+def help():
+    print "syntax: %s get name [default]" % sys.argv[0]
+
+def main():
+    c = Config()
+
+    if len(sys.argv)<=1:
+        help()
+        return
+
+    if sys.argv[1] == "get":
+        if len(sys.argv)==4:
+            print getattr(c, sys.argv[2], sys.argv[3])
+        elif len(sys.argv)==3:
+            print getattr(c, sys.argv[2])
+        else:
+            help()
+    else:
+        help()
+
+main()
diff --git a/xos/tools/xos-manage b/xos/tools/xos-manage
new file mode 100755
index 0000000..706aeda
--- /dev/null
+++ b/xos/tools/xos-manage
@@ -0,0 +1,241 @@
+#!/bin/bash
+
+if [ -z "$1" ]; then
+    echo usage: $0 "[initdb | createdb | dropdb | syncdb | runserver | resetdb | dumpdata]"
+    exit
+fi
+
+XOS_DIR=/opt/xos
+BACKUP_DIR=/opt/xos_backups
+DBNAME=xos
+
+DJANGO_17=`python -c "import django; from distutils.version import StrictVersion; print int(StrictVersion(django.get_version()) >= StrictVersion('1.7'))"`
+
+cd $XOS_DIR
+
+function is_ubuntu {
+    if ! which lsb_release &> /dev/null; then
+        # lsb_release is not installed
+        return 1
+    fi
+    if lsb_release -i | grep -i ubuntu &> /dev/null; then
+        return 0
+    fi
+    return 2
+}
+
+function ensure_postgres_running {
+    # "sudo -u postgres pg_ctl -D /var/lib/postgres/data status" doesn't work
+    # right on Vicci, so let's try to detect it by seeing if the port is
+    # being listened on
+
+    netstat -nl | grep -i ":5432 " > /dev/null
+    if [[ $? == 0 ]]; then
+        echo "Postgres is already running"
+        return
+    fi
+
+    # note that initdb isn't needed in Ubuntu distributions, and calling it
+    # will throw spurious error messages
+    if ! is_ubuntu; then
+        service postgresql initdb
+    fi
+    service postgresql start
+
+    netstat -nl | grep -i ":5432 " > /dev/null
+    if [[ $? != 0 ]]; then
+        # it's still not running...
+	# this is intended for Vicci where some D-Bus issue is
+        # preventing systemctl from working properly.
+        echo "Trying fallback mechanism to start Postgres"
+        sudo -u postgres initdb -D /var/lib/pgsql/data/
+        sudo -u postgres pg_ctl -D /var/lib/pgsql/data -l logfile start
+    fi
+
+}
+
+function wait_postgres {
+    sudo -u postgres psql -c '\q'
+    while [[ "$?" != "0" ]]; do
+        echo Waiting for postgres to start
+        sleep 1
+        sudo -u postgres psql -c '\q'
+    done
+}
+
+function db_exists {
+   sudo -u postgres psql $DBNAME -c '\q' 2>/dev/null
+   return $?
+}
+
+function createdb {
+    wait_postgres
+    echo "Creating XOS database..."
+    sudo -u postgres createdb $DBNAME
+}
+function dropdb {
+    echo "Dropping XOS database..."
+    sudo -u postgres dropdb $DBNAME
+}
+function syncdb {
+    echo "Syncing XOS services..."
+    python $XOS_DIR/manage.py syncdb --noinput
+    if [[ $DJANGO_17 ]]; then
+        echo "Loading initial data from fixture..."
+        python $XOS_DIR/manage.py --noobserver --nomodelpolicy loaddata $XOS_DIR/core/fixtures/core_initial_data.json
+    fi
+}
+function evolvedb {
+    echo "Evolving XOS services..."
+    python $XOS_DIR/manage.py evolve --hint --execute --noinput
+}
+function migratedb {
+    echo "Migrating XOS services..."
+    python $XOS_DIR/manage.py migrate
+}
+function stopserver {
+    echo "Stopping any running XOS Service(s)"
+    pkill -f "python.*runserver"
+}
+function runserver {
+    ensure_postgres_running
+    PUBLIC_HOSTNAME="0.0.0.0"
+    echo "Starting XOS Service on $PUBLIC_HOSTNAME:8000"
+    python manage.py runserver $PUBLIC_HOSTNAME:8000 --insecure&
+}
+
+function dumpdata {
+    mkdir -p $BACKUP_DIR
+    FN="$BACKUP_DIR/dumpdata-`date +%Y-%m-%d_%H:%M:%S`.json"
+    echo "Saving data to $FN"
+    python manage.py dumpdata core hpc syndicate_storage requestrouter -a --indent 4 > $FN
+    if [[ ! -f $FN ]]; then
+        echo "FAILED to create $FN"
+        exit
+    fi
+    SIZE=$(du -k "$FN" | cut -f 1)
+    if [[ $SIZE -lt 9 ]]; then
+        echo "Dumpdata was empty. Deleting and aborting"
+        rm $FN
+        exit
+    fi
+    rm -f $BACKUP_DIR/dumpdata-latest.json
+    ln -s $FN $BACKUP_DIR/dumpdata-latest.json
+}
+
+function genkeys {
+    mkdir -p public_keys
+    mkdir -p private_keys
+    echo "Generating keys"
+	keyczart create --location=private_keys --name="OpenCloud" --purpose=crypt --asymmetric=rsa
+	keyczart addkey --location=private_keys --status=primary --size=1024
+	keyczart pubkey --location=private_keys --destination=public_keys
+    if [[ ! -f public_keys/1 ]]; then
+        echo "FAILED to create keys"
+        exit
+    fi
+}
+
+function makemigrations {
+    rm -rf /opt/xos/*/migrations /opt/xos/services/*/migrations
+    python ./manage.py makemigrations core
+    python ./manage.py makemigrations hpc
+    python ./manage.py makemigrations requestrouter
+    python ./manage.py makemigrations syndicate_storage
+    python ./manage.py makemigrations mcord
+
+    if [[ -e /opt/xos/xos/xosbuilder_migration_list ]]; then
+        cat /opt/xos/xos/xosbuilder_migration_list | while read line; do
+            if [[ ! -z "$line" ]]; then
+                python ./manage.py makemigrations $line
+            fi
+        done
+    fi
+}
+
+function remigrate {
+    if db_exists; then
+        dropdb
+    fi
+    makemigrations
+}
+
+COMMAND=$1
+
+if [ "$COMMAND" = "initdb" ]; then
+    stopserver
+    ensure_postgres_running
+    createdb
+    syncdb
+fi
+if [ "$COMMAND" = "repairdb" ]; then
+    stopserver
+    ensure_postgres_running
+    dumpdata
+    # TODO: This is where we could run migration scripts to upgrade the
+    #   dumped data to the new models.
+    mv $XOS_DIR/core/fixtures/core_initial_data.json $XOS_DIR/core/fixtures/core_initial_data.json-old
+    cp $BACKUP_DIR/dumpdata-latest.json $XOS_DIR/core/fixtures/core_initial_data.json
+    dropdb
+    createdb
+    syncdb
+fi
+if [ "$COMMAND" = "restoredb" ]; then
+    if [[ ! -f $BACKUP_DIR/dumpdata-latest.json ]]; then
+       echo There is no dumpdata to restore
+       exit
+    fi
+    stopserver
+    ensure_postgres_running
+    mv $XOS_DIR/core/fixtures/core_initial_data.json $XOS_DIR/core/fixtures/core_initial_data.json-old
+    cp $BACKUP_DIR/dumpdata-latest.json $XOS_DIR/core/fixtures/core_initial_data.json
+    dropdb
+    createdb
+    syncdb
+fi
+if [ "$COMMAND" = "evolvedb" -o "$COMMAND" = "migratedb" ]; then
+    stopserver
+    ensure_postgres_running
+    if [[ $DJANGO_17 ]]; then
+        migratedb
+    else
+        evolvedb
+    fi
+fi
+if [ "$COMMAND" = "resetdb" ]; then
+    stopserver
+    ensure_postgres_running
+    dropdb
+    createdb
+    syncdb
+fi
+if [ "$COMMAND" = "syncdb" ]; then
+    stopserver
+    syncdb
+fi
+if [ "$COMMAND" = "runserver" ]; then
+    stopserver
+    runserver
+fi
+if [ "$COMMAND" = "stopserver" ]; then
+    stopserver
+fi
+if [ "$COMMAND" = "dumpdata" ]; then
+    dumpdata
+fi
+if [ "$COMMAND" = "genkeys" ]; then
+    genkeys
+fi
+if [ "$COMMAND" = "generateapi" ]; then
+   python apigen/modelgen apigen/api.template.py > xos/xosapi.py
+fi
+if [ "$COMMAND" = "remigrate" ]; then
+   ensure_postgres_running
+   remigrate
+   createdb
+   syncdb
+fi
+if [ "$COMMAND" = "makemigrations" ]; then
+   makemigrations
+   syncdb
+fi
diff --git a/xos/tosca/README.md b/xos/tosca/README.md
new file mode 100644
index 0000000..b0a654a
--- /dev/null
+++ b/xos/tosca/README.md
@@ -0,0 +1,13 @@
+## TOSCA Interface Definition
+
+This directory implements a TOSCA interface for XOS,
+which can be extended to include specifications for
+service models added to XOS. The directory is organized
+as follows:
+
+ * custom_types -- Defines schema for XOS-specific models.
+   * `.m4` source files
+   * `.yaml` generated files
+ * definitions -- Defines schema for TOSCA's base models.
+ * resources -- Translates TOSCA to Django API.
+ * sample -- Example TOSCA specifications.
diff --git a/xos/tosca/__init__.py b/xos/tosca/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/xos/tosca/__init__.py
@@ -0,0 +1 @@
+
diff --git a/xos/tosca/all_samples.sh b/xos/tosca/all_samples.sh
new file mode 100755
index 0000000..9b8f189
--- /dev/null
+++ b/xos/tosca/all_samples.sh
@@ -0,0 +1,14 @@
+# cleanup phase
+for f in samples/*.yaml; do
+   echo --------------------------------------------------
+   echo destroy $f
+   python ./destroy.py scott@onlab.us $f
+done
+
+for f in samples/*.yaml; do
+   echo --------------------------------------------------
+   echo run $f
+   python ./run.py scott@onlab.us $f
+   echo destroy $f
+   python ./destroy.py scott@onlab.us $f
+done
diff --git a/xos/tosca/custom_types/cdn.m4 b/xos/tosca/custom_types/cdn.m4
new file mode 100644
index 0000000..0d33715
--- /dev/null
+++ b/xos/tosca/custom_types/cdn.m4
@@ -0,0 +1,83 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+# Note: Tosca derived_from isn't working the way I think it should, it's not
+#    inheriting from the parent template. Until we get that figured out, use
+#    m4 macros do our inheritance
+
+node_types:
+    tosca.nodes.ServiceProvider:
+        derived_from: tosca.nodes.Root
+
+        capabilities:
+            user:
+                type: tosca.capabilities.xos.ServiceProvider
+
+    tosca.nodes.ContentProvider:
+        derived_from: tosca.nodes.Root
+
+        capabilities:
+            user:
+                type: tosca.capabilities.xos.ContentProvider
+
+    tosca.nodes.OriginServer:
+        derived_from: tosca.nodes.Root
+
+        capabilities:
+            user:
+                type: tosca.capabilities.xos.OriginServer
+
+    tosca.nodes.CDNPrefix:
+        derived_from: tosca.nodes.Root
+
+        capabilities:
+            user:
+                type: tosca.capabilities.xos.CDNPrefix
+
+    tosca.nodes.HpcHealthCheck:
+        derived_from: tosca.nodes.Root
+
+        properties:
+            kind:
+                type: string
+                required: true
+                description: dns | http | nameserver
+            resource_name:
+                type: string
+                required: true
+                description: name of resource to query
+            result_contains:
+                type: string
+                required: false
+                description: soemthing to look for inside the result
+        capabilities:
+            healthcheck:
+                type: tosca.capabilities.xos.HpcHealthCheck
+
+    tosca.relationships.MemberOfServiceProvider:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.ServiceProvider ]
+
+    tosca.relationships.MemberOfContentProvider:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.ContentProvider ]
+
+    tosca.relationships.DefaultOriginServer:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.OriginServer ]
+
+    tosca.capabilities.xos.ServiceProvider:
+        derived_from: tosca.capabilities.Root
+
+    tosca.capabilities.xos.ContentProvider:
+        derived_from: tosca.capabilities.Root
+
+    tosca.capabilities.xos.CDNPrefix:
+        derived_from: tosca.capabilities.Root
+
+    tosca.capabilities.xos.OriginServer:
+        derived_from: tosca.capabilities.Root
+
+    tosca.capabilities.xos.HpcHealthCheck:
+        derived_from: tosca.capabilities.Root
+
+
diff --git a/xos/tosca/custom_types/cdn.yaml b/xos/tosca/custom_types/cdn.yaml
new file mode 100644
index 0000000..0d33715
--- /dev/null
+++ b/xos/tosca/custom_types/cdn.yaml
@@ -0,0 +1,83 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+# Note: Tosca derived_from isn't working the way I think it should, it's not
+#    inheriting from the parent template. Until we get that figured out, use
+#    m4 macros do our inheritance
+
+node_types:
+    tosca.nodes.ServiceProvider:
+        derived_from: tosca.nodes.Root
+
+        capabilities:
+            user:
+                type: tosca.capabilities.xos.ServiceProvider
+
+    tosca.nodes.ContentProvider:
+        derived_from: tosca.nodes.Root
+
+        capabilities:
+            user:
+                type: tosca.capabilities.xos.ContentProvider
+
+    tosca.nodes.OriginServer:
+        derived_from: tosca.nodes.Root
+
+        capabilities:
+            user:
+                type: tosca.capabilities.xos.OriginServer
+
+    tosca.nodes.CDNPrefix:
+        derived_from: tosca.nodes.Root
+
+        capabilities:
+            user:
+                type: tosca.capabilities.xos.CDNPrefix
+
+    tosca.nodes.HpcHealthCheck:
+        derived_from: tosca.nodes.Root
+
+        properties:
+            kind:
+                type: string
+                required: true
+                description: dns | http | nameserver
+            resource_name:
+                type: string
+                required: true
+                description: name of resource to query
+            result_contains:
+                type: string
+                required: false
+                description: soemthing to look for inside the result
+        capabilities:
+            healthcheck:
+                type: tosca.capabilities.xos.HpcHealthCheck
+
+    tosca.relationships.MemberOfServiceProvider:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.ServiceProvider ]
+
+    tosca.relationships.MemberOfContentProvider:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.ContentProvider ]
+
+    tosca.relationships.DefaultOriginServer:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.OriginServer ]
+
+    tosca.capabilities.xos.ServiceProvider:
+        derived_from: tosca.capabilities.Root
+
+    tosca.capabilities.xos.ContentProvider:
+        derived_from: tosca.capabilities.Root
+
+    tosca.capabilities.xos.CDNPrefix:
+        derived_from: tosca.capabilities.Root
+
+    tosca.capabilities.xos.OriginServer:
+        derived_from: tosca.capabilities.Root
+
+    tosca.capabilities.xos.HpcHealthCheck:
+        derived_from: tosca.capabilities.Root
+
+
diff --git a/xos/tosca/custom_types/exampleservice.m4._unused b/xos/tosca/custom_types/exampleservice.m4._unused
new file mode 100644
index 0000000..720913e
--- /dev/null
+++ b/xos/tosca/custom_types/exampleservice.m4._unused
@@ -0,0 +1,31 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+# compile this with "m4 exampleservice.m4 > exampleservice.yaml"
+
+# include macros
+include(macros.m4)
+
+node_types:
+    tosca.nodes.ExampleService:
+        derived_from: tosca.nodes.Root
+        description: >
+            Example Service
+        capabilities:
+            xos_base_service_caps
+        properties:
+            xos_base_props
+            xos_base_service_props
+            service_message:
+                type: string
+                required: false
+
+    tosca.nodes.ExampleTenant:
+        derived_from: tosca.nodes.Root
+        description: >
+            A Tenant of the example service
+        properties:
+            xos_base_tenant_props
+            tenant_message:
+                type: string
+                required: false
+
diff --git a/xos/tosca/custom_types/exampleservice.yaml._unused b/xos/tosca/custom_types/exampleservice.yaml._unused
new file mode 100644
index 0000000..2cd70dd
--- /dev/null
+++ b/xos/tosca/custom_types/exampleservice.yaml._unused
@@ -0,0 +1,101 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+# compile this with "m4 exampleservice.m4 > exampleservice.yaml"
+
+# include macros
+# Note: Tosca derived_from isn't working the way I think it should, it's not
+#    inheriting from the parent template. Until we get that figured out, use
+#    m4 macros do our inheritance
+
+
+# Service
+
+
+# Subscriber
+
+
+
+
+# end m4 macros
+
+
+
+node_types:
+    tosca.nodes.ExampleService:
+        derived_from: tosca.nodes.Root
+        description: >
+            Example Service
+        capabilities:
+            scalable:
+                type: tosca.capabilities.Scalable
+            service:
+                type: tosca.capabilities.xos.Service
+        properties:
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+            kind:
+                type: string
+                default: generic
+                description: Type of service.
+            view_url:
+                type: string
+                required: false
+                description: URL to follow when icon is clicked in the Service Directory.
+            icon_url:
+                type: string
+                required: false
+                description: ICON to display in the Service Directory.
+            enabled:
+                type: boolean
+                default: true
+            published:
+                type: boolean
+                default: true
+                description: If True then display this Service in the Service Directory.
+            public_key:
+                type: string
+                required: false
+                description: Public key to install into Instances to allows Services to SSH into them.
+            private_key_fn:
+                type: string
+                required: false
+                description: Location of private key file
+            versionNumber:
+                type: string
+                required: false
+                description: Version number of Service.
+            service_message:
+                type: string
+                required: false
+
+    tosca.nodes.ExampleTenant:
+        derived_from: tosca.nodes.Root
+        description: >
+            A Tenant of the example service
+        properties:
+            kind:
+                type: string
+                default: generic
+                description: Kind of tenant
+            service_specific_id:
+                type: string
+                required: false
+                description: Service specific ID opaque to XOS but meaningful to service
+            tenant_message:
+                type: string
+                required: false
+
diff --git a/xos/tosca/custom_types/macros.m4 b/xos/tosca/custom_types/macros.m4
new file mode 100644
index 0000000..1f48f10
--- /dev/null
+++ b/xos/tosca/custom_types/macros.m4
@@ -0,0 +1,84 @@
+# Note: Tosca derived_from isn't working the way I think it should, it's not
+#    inheriting from the parent template. Until we get that figured out, use
+#    m4 macros do our inheritance
+
+define(xos_base_props,
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object)
+# Service
+define(xos_base_service_caps,
+            scalable:
+                type: tosca.capabilities.Scalable
+            service:
+                type: tosca.capabilities.xos.Service)
+define(xos_base_service_props,
+            kind:
+                type: string
+                default: generic
+                description: Type of service.
+            view_url:
+                type: string
+                required: false
+                description: URL to follow when icon is clicked in the Service Directory.
+            icon_url:
+                type: string
+                required: false
+                description: ICON to display in the Service Directory.
+            enabled:
+                type: boolean
+                default: true
+            published:
+                type: boolean
+                default: true
+                description: If True then display this Service in the Service Directory.
+            public_key:
+                type: string
+                required: false
+                description: Public key to install into Instances to allows Services to SSH into them.
+            private_key_fn:
+                type: string
+                required: false
+                description: Location of private key file
+            versionNumber:
+                type: string
+                required: false
+                description: Version number of Service.)
+# Subscriber
+define(xos_base_subscriber_caps,
+            subscriber:
+                type: tosca.capabilities.xos.Subscriber)
+define(xos_base_subscriber_props,
+            kind:
+                type: string
+                default: generic
+                description: Kind of subscriber
+            service_specific_id:
+                type: string
+                required: false
+                description: Service specific ID opaque to XOS but meaningful to service)
+define(xos_base_tenant_props,
+            kind:
+                type: string
+                default: generic
+                description: Kind of tenant
+            service_specific_id:
+                type: string
+                required: false
+                description: Service specific ID opaque to XOS but meaningful to service)
+
+# end m4 macros
+
diff --git a/xos/tosca/custom_types/xos.m4 b/xos/tosca/custom_types/xos.m4
new file mode 100644
index 0000000..04d7641
--- /dev/null
+++ b/xos/tosca/custom_types/xos.m4
@@ -0,0 +1,1251 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+# compile this with "m4 xos.m4 > xos.yaml"
+
+# include macros
+include(macros.m4)
+
+node_types:
+    tosca.nodes.XOS:
+        derived_from: tosca.nodes.Root
+        description: The root of XOS
+        properties:
+            xos_base_props
+            ui_port:
+                type: integer
+                required: false
+                description: TCP port of user interface
+            bootstrap_ui_port:
+                type: integer
+                required: false
+                descrption: TCP port of bootstrap user interface
+            docker_project_name:
+                type: string
+                required: false
+                description: Docker project name
+            source_ui_image:
+                type: string
+                required: false
+                description: Source UI docker image name
+            enable_build:
+                type: boolean
+                required: false
+                description: True if XOS build should be enabled
+            frontend_only:
+                type: boolean
+                required: false
+                description: True if XOS should not start synchronizer containers
+
+
+    tosca.nodes.XOSVolume:
+        derived_from: tosca.nodes.Root
+        description: A volume that should be attached to the XOS docker container
+        properties:
+            xos_base_props
+            host_path:
+                type: string
+                required: false
+                description: path of resource on host
+            read_only:
+                type: boolean
+                required: false
+                description: True if mount read only
+
+    tosca.nodes.Service:
+        derived_from: tosca.nodes.Root
+        description: >
+            An XOS Service object. Services may be listed in the Service
+            directory and may be linked together via Tenancy Relationships.
+        capabilities:
+            xos_base_service_caps
+        properties:
+            xos_base_props
+            xos_base_service_props
+
+    tosca.nodes.ServiceController:
+        derived_from: tosca.nodes.Root
+        description: >
+            An XOS Service Controller.
+        properties:
+            xos_base_props
+            base_url:
+                type: string
+                required: false
+                description: Base url, to allow resources to use relative URLs
+            models:
+                type: string
+                required: false
+                description: url of models.py
+            admin:
+                type: string
+                required: false
+                description: url of admin.py
+            admin_template:
+                type: string
+                required: false
+                description: url of admin html template
+            synchronizer:
+                type: string
+                required: false
+                description: url of synchronizer manifest
+            synchronizer_run:
+                type: string
+                required: false
+                description: synchronizer run command
+            synchronizer_config:
+                type: string
+                required: false
+                description: synchronizer config filename
+            tosca_custom_types:
+                type: string
+                required: false
+                description: url of tosca custom_types
+            tosca_resource:
+                type: string
+                required: false
+                description: url of tosca resource
+            rest_service:
+                type: string
+                required: false
+                description: url of REST API service file
+            rest_tenant:
+                type: string
+                required: false
+                description: url of REST API tenant file
+            private_key:
+                type: string
+                required: false
+                description: private key
+            public_key:
+                type: string
+                required: false
+                description: public key
+
+    tosca.nodes.ServiceControllerResource:
+        derived_from: tosca.nodes.Root
+        description: >
+            An XOS Service Resource.
+        properties:
+            xos_base_props
+            kind:
+                type: string
+                required: false
+                description: models, admin, django_library, synchronizer, rest, tosca_custom_types, or tosca_resource
+            format:
+                type: string
+                required: false
+                description: python, manifest, or docker
+            url:
+                type: string
+                required: false
+                description: url of resource, may be relative to base_url or absolute
+
+    tosca.nodes.Tenant:
+        derived_from: tosca.nodes.Root
+        description: >
+            An ONOS Tenant.
+        properties:
+            xos_base_tenant_props
+            service_specific_attribute:
+                type: string
+                required: false
+                description: Service-specific attribute, usually a string containing a json dictionary
+            model:
+                type: string
+                required: false
+                description: Name of model to use when instantiating tenant
+
+    tosca.nodes.ONOSService:
+        derived_from: tosca.nodes.Root
+        description: >
+            ONOS Service
+        capabilities:
+            xos_base_service_caps
+        properties:
+            xos_base_props
+            xos_base_service_props
+            rest_onos/v1/network/configuration/:
+                type: string
+                required: false
+            rest_hostname:
+                type: string
+                required: false
+            rest_port:
+                type: string
+                required: false
+            no_container:
+                type: boolean
+                default: false
+            node_key:
+                type: string
+                required: false
+
+
+    tosca.nodes.ONOSApp:
+        derived_from: tosca.nodes.Root
+        description: >
+            An ONOS Application.
+        properties:
+            xos_base_tenant_props
+            dependencies:
+                type: string
+                required: false
+
+    tosca.nodes.ONOSvBNGApp:
+        derived_from: tosca.nodes.Root
+        description: >
+            An ONOS vBNG Application.
+        properties:
+            xos_base_tenant_props
+            dependencies:
+                type: string
+                required: false
+            install_dependencies:
+                type: string
+                required: false
+            component_config:
+                type: string
+                required: false
+            config_addresses.json:
+                type: string
+                required: false
+            config_network-cfg.json:
+                type: string
+                required: false
+            config_virtualbng.json:
+                type: string
+                required: false
+
+    tosca.nodes.ONOSvOLTApp:
+        derived_from: tosca.nodes.Root
+        description: >
+            An ONOS vOLT Application.
+        properties:
+            xos_base_tenant_props
+            dependencies:
+                type: string
+                required: false
+            install_dependencies:
+                type: string
+                required: false
+            component_config:
+                type: string
+                required: false
+            config_network-cfg.json:
+                type: string
+                required: false
+            rest_onos/v1/network/configuration/:
+                type: string
+                required: false
+            autogenerate:
+                type: string
+                required: false
+
+    tosca.nodes.ONOSVTNApp:
+        derived_from: tosca.nodes.Root
+        description: >
+            An ONOS VTN Application.
+        properties:
+            xos_base_tenant_props
+            dependencies:
+                type: string
+                required: false
+            rest_onos/v1/network/configuration/:
+                type: string
+                required: false
+            autogenerate:
+                type: string
+                required: false
+
+    tosca.nodes.ONOSvRouterApp:
+        derived_from: tosca.nodes.Root
+        description: >
+            An ONOS vRouter Application.
+        properties:
+            xos_base_tenant_props
+            dependencies:
+                type: string
+                required: false
+            rest_onos/v1/network/configuration/:
+                type: string
+                required: false
+            autogenerate:
+                type: string
+                required: false
+
+    tosca.nodes.VSGService:
+        description: >
+            CORD: The vSG Service.
+        derived_from: tosca.nodes.Root
+        capabilities:
+            xos_base_service_caps
+        properties:
+            xos_base_props
+            xos_base_service_props
+            backend_network_label:
+                type: string
+                required: false
+                description: Label that matches network used to connect HPC and BBS services.
+            dns_servers:
+                type: string
+                required: false
+            node_label:
+                type: string
+                required: false
+
+    tosca.nodes.VBNGService:
+        derived_from: tosca.nodes.Root
+        description: >
+            CORD: The vBNG Service.
+        capabilities:
+            xos_base_service_caps
+        properties:
+            xos_base_props
+            xos_base_service_props
+            vbng_url:
+                type: string
+                required: false
+                description: URL of REST API endpoint for vBNG Service.
+
+    tosca.nodes.VRouterService:
+        derived_from: tosca.nodes.Root
+        description: >
+            CORD: The vRouter Service.
+        capabilities:
+            xos_base_service_caps
+        properties:
+            xos_base_props
+            xos_base_service_props
+
+    tosca.nodes.FabricService:
+        derived_from: tosca.nodes.Root
+        description: >
+            CORD: The Fabric Service.
+        capabilities:
+            xos_base_service_caps
+        properties:
+            xos_base_props
+            xos_base_service_props
+
+    tosca.nodes.VTNService:
+        derived_from: tosca.nodes.Root
+        description: >
+            CORD: The vRouter Service.
+        capabilities:
+            xos_base_service_caps
+        properties:
+            xos_base_props
+            xos_base_service_props
+            privateGatewayMac:
+                type: string
+                required: false
+            localManagementIp:
+                type: string
+                required: false
+            ovsdbPort:
+                type: string
+                required: false
+            sshPort:
+                type: string
+                required: false
+            sshUser:
+                type: string
+                required: false
+            sshKeyFile:
+                type: string
+                required: false
+            mgmtSubnetBits:
+                type: string
+                required: false
+            xosEndpoint:
+                type: string
+                required: false
+            xosUser:
+                type: string
+                required: false
+            xosPassword:
+                type: string
+                required: false
+
+
+    tosca.nodes.CDNService:
+        derived_from: tosca.nodes.Root
+        description: >
+            Content Delivery Network Service. Includes Request Routing and Hypercache.
+        capabilities:
+            xos_base_service_caps
+        properties:
+            xos_base_props
+            xos_base_service_props
+
+    tosca.nodes.Subscriber:
+        derived_from: tosca.nodes.Root
+        description: XOS subscriber base class.
+        capabilities:
+            xos_base_subscriber_caps
+        properties:
+            xos_base_subscriber_props
+
+    tosca.nodes.CORDSubscriber:
+        derived_from: tosca.nodes.Root
+        description: >
+            CORD: Subscriber. The Subscriber object contains all of the settings
+            for a CORD household. For example, it contains parental control
+            filter settings.
+        capabilities:
+            xos_base_subscriber_caps
+        properties:
+            xos_base_subscriber_props
+            firewall_enable:
+                type: boolean
+                default: false
+                description: If True, then firewalling is enabled.
+            url_filter_enable:
+                type: boolean
+                default: false
+                description: If True, then parental controls are enabled.
+            url_filter_level:
+                type: string
+                default: PG
+                description: The default URL filter level for the household.
+            cdn_enable:
+                type: boolean
+                default: true
+                description: If True, then the CDN is enabled.
+
+    tosca.nodes.CORDUser:
+        derived_from: tosca.nodes.Root
+        description: >
+            CORD: User. The CORD user represents an individual device beloning
+            to the CORD Subscriber. Each device may have its own parental
+            controls.
+        capabilities:
+            device:
+                type: tosca.capabilities.xos.Device
+        properties:
+            level:
+                type: string
+                default: PG_13
+                description: Parental control level for this device.
+            mac:
+                type: string
+                required: true
+                description: MAC address for this device.
+
+    tosca.nodes.VOLTService:
+        derived_from: tosca.nodes.Root
+        description: >
+            CORD: The vOLT Service
+        capabilities:
+            xos_base_service_caps
+        properties:
+            xos_base_props
+            xos_base_service_props
+
+    tosca.nodes.VOLTTenant:
+        derived_from: tosca.nodes.Root
+        description: >
+            CORD: A Tenant of the vOLT Service. Each Tenant is tied to a
+            specific vlan_id.
+        properties:
+            xos_base_tenant_props
+            s_tag:
+                type: string
+                required: false
+                description: s_tag, identifies which volt port
+            c_tag:
+                type: string
+                required: false
+                description: c_tag, identifies which subscriber within s_tag
+
+    tosca.nodes.VOLTDevice:
+        derived_from: tosca.nodes.Root
+        description: >
+            CORD: A vOLT Device.
+        properties:
+            xos_base_props
+            openflow_id:
+                type: string
+                required: false
+                description: openflow id
+            driver:
+                type: string
+                required: false
+                description: driver name
+            access_devices:
+                type: string
+                required: false
+                description: list of access devices, in format "uplink vlan", multiple entries separated by commas
+
+# XXX - uncomment if we want access device to be specified as separate Tosca
+# objects, rather than encoding them into VOLTDevice.access_devices
+#    tosca.nodes.AccessDevice:
+#        derived_from: tosca.nodes.Root
+#        description: >
+#            CORD: A vOLT Access Device.
+#        properties:
+#            xos_base_props
+#            uplink:
+#               type: integer
+#               required: false
+#               description: uplink
+#            vlan:
+#               type: integer
+#               required: false
+#               description: vlan
+
+    tosca.nodes.AccessAgent:
+        derived_from: tosca.nodes.Root
+        description: >
+            CORD: A vOLT Access Agent.
+        properties:
+            xos_base_props
+            mac:
+                type: string
+                required: false
+                description: mac address
+            port_mappings:
+                type: string
+                required: false
+                description: list of port mappings, in format "port mac", multiple entries separated by commas
+
+
+    tosca.nodes.User:
+        derived_from: tosca.nodes.Root
+
+        description: >
+            An XOS User record. Users are able to login and use the XOS GUI.
+
+        capabilities:
+            user:
+                type: tosca.capabilities.xos.User
+
+        properties:
+            xos_base_props
+            password:
+                type: string
+                required: false
+            firstname:
+                type: string
+                required: false
+                description: First name of User.
+            lastname:
+                type: string
+                required: false
+                description: Last name of User.
+            phone:
+                type: string
+                required: false
+                description: Phone number of User.
+            user_url:
+                type: string
+                required: false
+                description: URL to User web page.
+            public_key:
+                type: string
+                required: false
+                description: Public key that will be installed in Instances.
+            is_active:
+                type: boolean
+                required: false
+                #default: true
+                description: If True, the user may log in.
+            is_admin:
+                type: boolean
+                required: false
+                #default: false
+                description: If True, the user has root admin privileges.
+            login_page:
+                type: string
+                required: false
+                description: Indicates what page the user should go to on login.
+
+    tosca.nodes.NetworkParameterType:
+        derived_from: tosca.nodes.Root
+
+        description: >
+            An XOS network parameter type. May be applied to Networks and/or
+            Ports.
+
+        properties:
+            xos_base_props
+
+        capabilities:
+            network_parameter_type:
+                type: tosca.capabilities.xos.NetworkParameterType
+
+    tosca.nodes.NetworkTemplate:
+        derived_from: tosca.nodes.Root
+
+        description: >
+            An XOS network template. Network templates contain settings associated
+            with a particular class of network.
+
+        capabilities:
+            network_template:
+                type: tosca.capabilities.xos.NetworkTemplate
+
+        properties:
+            xos_base_props
+            visibility:
+                type: string
+                required: false
+                description: Indicates whether network is publicly routable.
+            translation:
+                type: string
+                required: false
+                description: Indicates whether network uses address translation.
+            shared_network_name:
+                type: string
+                required: false
+                description: Attaches this template to a specific OpenStack network.
+            shared_network_id:
+                type: string
+                required: false
+                description: Attaches this template to a specific OpenStack network.
+            topology_kind:
+                type: string
+                required: false
+                description: Describes the topology of the network.
+            controller_kind:
+                type: string
+                required: false
+                description: Indicates the type of controller that the network is connected to.
+            access:
+                type: string
+                required: false
+                description: The type of access semantics for this network
+
+    tosca.nodes.network.Network.XOS:
+          # Due to bug? in implementation, we have to copy everything from
+          # tosca definitions tosca.nodes.network.Network here rather than
+          # using derived_from.
+          derived_from: tosca.nodes.Root
+          description: >

+            This is a variant of the TOSCA Network object that includes additional

+            XOS-specific properties.

+          properties:

+            xos_base_props

+            ip_version:

+              type: integer

+              required: no

+              default: 4

+              constraints:

+                - valid_values: [ 4, 6 ]

+              description: >

+                The IP version of the requested network. Valid values are 4 for ipv4

+                or 6 for ipv6.

+            cidr:

+              type: string

+              required: no

+              description: >

+                The cidr block of the requested network.

+            start_ip:

+              type: string

+              required: no

+              description: >

+                 The IP address to be used as the start of a pool of addresses within

+                 the full IP range derived from the cidr block.

+            end_ip:

+              type: string

+              required: no

+              description: >

+                  The IP address to be used as the end of a pool of addresses within

+                  the full IP range derived from the cidr block.

+            gateway_ip:

+              type: string

+              required: no

+              description: >

+                 The gateway IP address.

+            network_name:

+              type: string

+              required: no

+              description: >

+                 An identifier that represents an existing Network instance in the

+                 underlying cloud infrastructure or can be used as the name of the

+                 newly created network. If network_name is provided and no other

+                 properties are provided (with exception of network_id), then an

+                 existing network instance will be used. If network_name is provided

+                 alongside with more properties then a new network with this name will

+                 be created.

+            network_id:

+              type: string

+              required: no

+              description: >

+                 An identifier that represents an existing Network instance in the

+                 underlying cloud infrastructure. This property is mutually exclusive

+                 with all other properties except network_name. This can be used alone

+                 or together with network_name to identify an existing network.

+            segmentation_id:

+              type: string

+              required: no

+              description: >

+                 A segmentation identifier in the underlying cloud infrastructure.

+                 E.g. VLAN ID, GRE tunnel ID, etc..

+            dhcp_enabled:

+              type: boolean

+              required: no

+              default: true

+              description: >

+                Indicates should DHCP service be enabled on the network or not.

+        # XOS-specific

+            ports:

+                type: string
+                required: false
+                description: >
+                    A comma-separated list of protocols and ports. For example,
+                    "tcp/123, tcp/456-459, udp/111"
+            labels:
+                type: string
+                required: false
+                description: A comma-separated list of labels for this network.
+            permit_all_slices:
+                type: boolean
+                # In the data model, this is defaulted to false. However, to
+                # preserve Tosca semantics, we default it to true instead.
+                default: true
+                description: If True, then any slice may be attached to this network.
+          capabilities:
+            link:

+              type: tosca.capabilities.network.Linkable
+
+    tosca.nodes.Deployment:
+        derived_from: tosca.nodes.Root
+        description: >
+            An XOS Deployment.
+        capabilities:
+            deployment:
+                type: tosca.capabilities.xos.Deployment
+        properties:
+            xos_base_props
+            accessControl:
+                type: string
+                default: allow all
+                description: ACL that describes who may use this deployment.
+            flavors:
+                type: string
+                required: false
+                description: Comma-separated list of flavors that this deployment supports.
+
+    tosca.nodes.AddressPool:
+        derived_from: tosca.nodes.Root
+        description: >
+            A pool of addresses
+        capabilities:
+            addresspool:
+                type: tosca.capabilities.xos.AddressPool
+        properties:
+            xos_base_props
+            addresses:
+                type: string
+                required: false
+                description: space-separated list of addresses
+            gateway_ip:
+                type: string
+                required: false
+                description: gateway ip address
+            gateway_mac:
+                type: string
+                required: false
+                description: gateway mac address
+
+    tosca.nodes.Image:
+        derived_from: tosca.nodes.Root
+        description: >
+            An XOS Operating System Image.
+        capabilities:
+            image:
+                type: tosca.capabilities.xos.Image
+        properties:
+            xos_base_props
+            kind:
+                type: string
+                required: false
+                description: Type of image (container | VM)
+            disk_format:
+                type: string
+                required: false
+                description: Glance disk format.
+            container_format:
+                type: string
+                required: false
+                description: Glance container format.
+            path:
+                type: string
+                required: false
+                description: Path to Image file
+            tag:
+                type: string
+                required: false
+                description: For Docker images, tag of image
+
+    tosca.nodes.Controller:
+        derived_from: tosca.nodes.Root
+        description: >
+            An XOS controller. Controllers serve as the interface between
+            XOS and services such as OpenStack.
+        capabilities:
+            controller:
+                type: tosca.capabilities.xos.Controller
+        properties:
+            xos_base_props
+            backend_type:
+                type: string
+                required: false
+                description: Type of backend.
+            version:
+                type: string
+                required: false
+                description: Version of backend.
+            auth_url:
+                type: string
+                required: false
+                description: Keystone auth_url.
+            admin_user:
+                type: string
+                required: false
+                description: Keystone username.
+            admin_password:
+                type: string
+                required: false
+                description: Keystone password.
+            admin_tenant:
+                type: string
+                required: false
+                description: Tenant associated with admin account.
+            domain:
+                type: string
+                required: false
+                description: OpenStack domain (or "Default")
+            rabbit_host:
+                type: string
+                required: false
+                description: Rabbit host
+            rabbit_user:
+                type: string
+                required: false
+                description: Rabbit user
+            rabbit_password:
+                type: string
+                required: false
+                description: Rabbit password
+
+    tosca.nodes.Site:
+        derived_from: tosca.nodes.Root
+        description: >
+            An XOS Site. Sites are containers for Users and/or Nodes.
+        capabilities:
+            site:
+                type: tosca.capabilities.xos.Site
+        properties:
+            xos_base_props
+            display_name:
+                type: string
+                required: false
+                description: Name of the site.
+            site_url:
+                type: string
+                required: false
+                description: URL of site web page.
+            enabled:
+                type: boolean
+                default: true
+            hosts_nodes:
+                type: boolean
+                default: true
+                description: If True, then this site hosts nodes where Instances may be instantiated.
+            hosts_users:
+                type: boolean
+                default: true
+                description: If True, then this site hosts users who may use XOS.
+            is_public:
+                type: boolean
+                default: true
+            # location, longitude, latitude
+
+    tosca.nodes.Slice:
+        derived_from: tosca.nodes.Root
+        description: >
+            An XOS Slice. A slice is a collection of instances that share
+            common attributes.
+        capabilities:
+            slice:
+                type: tosca.capabilities.xos.Slice
+        properties:
+            xos_base_props
+            enabled:
+                type: boolean
+                default: true
+            description:
+                type: string
+                required: false
+                description: Description of this slice.
+            slice_url:
+                type: string
+                required: false
+                description: URL to web page that describes slice.
+            max_instances:
+                type: integer
+                default: 10
+                description: Quota of instances that this slice may create.
+            default_isolation:
+                type: string
+                required: false
+                description: default isolation to use when bringing up instances (default to 'vm')
+            network:
+                type: string
+                required: false
+                description: type of networking to use for this slice
+            exposed_ports:
+                type: string
+                required: false
+                description: comma-separated list of protocol _space_ port that represent ports the slice should expose
+            default_node:
+                type: string
+                required: false
+                description: default node to use for this slice
+
+    tosca.nodes.Node:
+        derived_from: tosca.nodes.Root
+        description: >
+            An XOS Node. Nodes are physical machines that host virtual machines
+            and/or containers.
+        properties:
+            xos_base_props
+        capabilities:
+            node:
+                type: tosca.capabilities.xos.Node
+
+    tosca.nodes.NodeLabel:
+        derived_from: tosca.nodes.Root
+        description: >
+            An XOS NodeLabel.
+        properties:
+            xos_base_props
+        capabilities:
+            node:
+                type: tosca.capabilities.xos.NodeLabel
+
+    tosca.nodes.Flavor:
+        derived_from: tosca.nodes.Root
+        description: >
+            An XOS Flavor.
+        properties:
+            xos_base_props
+            flavor:
+                type: string
+                required: false
+                description: openstack flavor name
+        capabilities:
+            flavor:
+                type: tosca.capabilities.xos.Flavor
+
+    tosca.nodes.SiteRole:
+        derived_from: tosca.nodes.Root
+        description: >
+            An XOS Site Role.
+        properties:
+            xos_base_props
+        capabilities:
+            siterole:
+                type: tosca.capabilities.xos.SiteRole
+
+    tosca.nodes.SliceRole:
+        derived_from: tosca.nodes.Root
+        description: >
+            An XOS Slice Role.
+        properties:
+            xos_base_props
+        capabilities:
+            slicerole:
+                type: tosca.capabilities.xos.SliceRole
+
+    tosca.nodes.TenantRole:
+        derived_from: tosca.nodes.Root
+        description: >
+            An XOS Tenant Role.
+        properties:
+            xos_base_props
+        capabilities:
+            tenantrole:
+                type: tosca.capabilities.xos.TenantRole
+
+    tosca.nodes.DeploymentRole:
+        derived_from: tosca.nodes.Root
+        description: >
+            An XOS Deployment Role.
+        properties:
+            xos_base_props
+        capabilities:
+            deploymentrole:
+                type: tosca.capabilities.xos.DeploymentRole
+
+    tosca.nodes.DashboardView:
+        derived_from: tosca.nodes.Root
+        description: >
+            An XOS Dashboard View
+        capabilities:
+            dashboardview:
+                type: tosca.capabilities.xos.DashboardView
+        properties:
+            xos_base_props
+            enabled:
+                type: boolean
+                default: true
+            url:
+                type: string
+                required: false
+                description: URL to the dashboard
+
+    tosca.nodes.Tag:
+        derived_from: tosca.nodes.Root
+        description: >
+            An XOS Tag
+        properties:
+            xos_base_props
+            name:
+                type: string
+                required: true
+                descrption: name of tag
+            value:
+                type: string
+                required: false
+                descrption: value of tag
+
+    tosca.nodes.Compute.Container:
+      derived_from: tosca.nodes.Compute
+      description: >
+        The TOSCA Compute node represents a container on bare metal.
+      attributes:
+        private_address:
+          type: string
+        public_address:
+          type: string
+      capabilities:
+          host:
+             type: tosca.capabilities.Container
+          binding:
+             type: tosca.capabilities.network.Bindable
+          os:
+             type: tosca.capabilities.OperatingSystem
+          scalable:
+             type: tosca.capabilities.Scalable
+      requirements:
+        - local_storage:
+            capability: tosca.capabilities.Attachment
+            node: tosca.nodes.BlockStorage
+            relationship: tosca.relationships.AttachesTo
+            occurrences: [0, UNBOUNDED]
+
+    tosca.relationships.MemberOfSlice:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Slice ]
+
+    tosca.relationships.MemberOfService:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Service ]
+
+    tosca.relationships.MemberOfSite:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Site ]
+
+    tosca.relationships.MemberOfDeployment:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Deployment ]
+
+    tosca.relationships.TenantOfService:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Service ]
+
+    tosca.relationships.UsedByService:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Service ]
+
+    tosca.relationships.ControllerDeployment:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Deployment ]
+
+    tosca.relationships SiteDeployment:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Deployment ]
+
+    tosca.relationships.UsesController:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Controller ]
+
+    tosca.relationships.ConnectsToNetwork:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Network ]
+
+    tosca.relationships.UsesImage:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Image ]
+
+    tosca.relationships.DefaultImage:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Image ]
+
+    tosca.relationships.SupportsImage:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Image ]
+
+    tosca.relationships.ConnectsToSlice:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Slice ]
+
+    #    tosca.relationships.OwnsNetwork:
+    #        derived_from: tosca.relationships.Root
+    #        valid_target_types: [ tosca.capabilities.xos.Network ]
+
+    tosca.relationships.UsesNetworkTemplate:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.NetworkTemplate ]
+
+    tosca.relationships.AdminPrivilege:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Slice, tosca.capabilities.xos.Site ]
+
+    tosca.relationships.AccessPrivilege:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Slice, tosca.capabilities.xos.Site ]
+
+    tosca.relationships.PIPrivilege:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Site ]
+
+    tosca.relationships.TechPrivilege:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Site ]
+
+    tosca.relationships.SubscriberDevice:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Subscriber ]
+
+    tosca.relationships.BelongsToSubscriber:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Subscriber ]
+
+    tosca.relationships.UsesDashboard:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.DashboardView ]
+
+    tosca.relationships.HasLabel:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.NodeLabel ]
+
+    tosca.relationships.SupportsFlavor:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Flavor ]
+
+    tosca.relationships.DefaultFlavor:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Flavor ]
+
+    tosca.relationships.ProvidesAddresses:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.AddressPool ]
+
+    tosca.relationships.DependsOn:
+        derived_from: tosca.relationships.Root
+
+    tosca.relationships.TagsObject:
+        derived_from: tosca.relationships.Root
+
+    tosca.relationships.MemberOfDevice:
+        derived_from: tosca.relationships.Root
+
+    tosca.relationships.UsesAgent:
+        derived_from: tosca.relationships.Root
+
+    tosca.relationships.HasResource:
+        derived_from: tosca.relationships.Root
+
+    tosca.relationships.UsedByController:
+        derived_from: tosca.relationships.Root
+
+    tosca.relationships.UsedByXOS:
+        derived_from: tosca.relationships.Root
+
+    tosca.capabilities.xos.Service:
+        derived_from: tosca.capabilities.Root
+        description: An XOS Service
+
+    tosca.capabilities.xos.Deployment:
+        derived_from: tosca.capabilities.Root
+        description: An XOS Deployment
+
+    tosca.capabilities.xos.Controller:
+        derived_from: tosca.capabilities.Root
+        description: An XOS Controller
+
+    tosca.capabilities.xos.Site:
+        derived_from: tosca.capabilities.Root
+        description: An XOS Site
+
+    tosca.capabilities.xos.Slice:
+        derived_from: tosca.capabilities.Root
+        description: An XOS Slice
+
+    tosca.capabilities.xos.NetworkTemplate:
+        derived_from: tosca.capabilities.Root
+        description: An XOS network template
+
+#    tosca.capabilities.xos.Network:
+#        derived_from: tosca.capabilities.Root
+#        description: An XOS network
+
+    tosca.capabilities.xos.User:
+        derived_from: tosca.capabilities.Root
+        description: An XOS user
+
+    tosca.capabilities.xos.Subscriber:
+        derived_from: tosca.capabilities.Root
+        description: An XOS Subscriber
+
+    tosca.capabilities.xos.Device:
+        derived_from: tosca.capabilities.Root
+        description: A device belonging to an XOS subscriber
+
+    tosca.capabilities.xos.Node:
+        derived_from: tosca.capabilities.Root
+        description: An XOS Node
+
+    tosca.capabilities.xos.NodeLabel:
+        derived_from: tosca.capabilities.Root
+        description: An XOS NodeLabel
+
+    tosca.capabilities.xos.Flavor:
+        derived_from: tosca.capabilities.Root
+        description: An XOS Flavor
+
+    tosca.capabilities.xos.DeploymentRole:
+        derived_from: tosca.capabilities.Root
+        description: An XOS DeploymentRole
+
+    tosca.capabilities.xos.SliceRole:
+        derived_from: tosca.capabilities.Root
+        description: An XOS SliceRole
+
+    tosca.capabilities.xos.SiteRole:
+        derived_from: tosca.capabilities.Root
+        description: An XOS SiteRole
+
+    tosca.capabilities.xos.TenantRole:
+        derived_from: tosca.capabilities.Root
+        description: An XOS TenantRole
+
+    tosca.capabilities.xos.Image:
+        derived_from: tosca.capabilities.Root
+        description: An XOS Image
+
+    tosca.capabilities.xos.DashboardView:
+        derived_from: tosca.capabilities.Root
+        description: An XOS DashboardView
+
+    tosca.capabilities.xos.NetworkParameterType:
+        derived_from: tosca.capabilities.Root
+        description: An XOS NetworkParameterType
+
+    tosca.capabilities.xos.AddressPool:
+        derived_from: tosca.capabilities.Root
+        description: An XOS AddressPool
diff --git a/xos/tosca/custom_types/xos.yaml b/xos/tosca/custom_types/xos.yaml
new file mode 100644
index 0000000..e52c0e1
--- /dev/null
+++ b/xos/tosca/custom_types/xos.yaml
@@ -0,0 +1,2138 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+# compile this with "m4 xos.m4 > xos.yaml"
+
+# include macros
+# Note: Tosca derived_from isn't working the way I think it should, it's not
+#    inheriting from the parent template. Until we get that figured out, use
+#    m4 macros do our inheritance
+
+
+# Service
+
+
+# Subscriber
+
+
+
+
+# end m4 macros
+
+
+
+node_types:
+    tosca.nodes.XOS:
+        derived_from: tosca.nodes.Root
+        description: The root of XOS
+        properties:
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+            ui_port:
+                type: integer
+                required: false
+                description: TCP port of user interface
+            bootstrap_ui_port:
+                type: integer
+                required: false
+                descrption: TCP port of bootstrap user interface
+            docker_project_name:
+                type: string
+                required: false
+                description: Docker project name
+            source_ui_image:
+                type: string
+                required: false
+                description: Source UI docker image name
+            enable_build:
+                type: boolean
+                required: false
+                description: True if XOS build should be enabled
+            frontend_only:
+                type: boolean
+                required: false
+                description: True if XOS should not start synchronizer containers
+
+
+    tosca.nodes.XOSVolume:
+        derived_from: tosca.nodes.Root
+        description: A volume that should be attached to the XOS docker container
+        properties:
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+            host_path:
+                type: string
+                required: false
+                description: path of resource on host
+            read_only:
+                type: boolean
+                required: false
+                description: True if mount read only
+
+    tosca.nodes.Service:
+        derived_from: tosca.nodes.Root
+        description: >
+            An XOS Service object. Services may be listed in the Service
+            directory and may be linked together via Tenancy Relationships.
+        capabilities:
+            scalable:
+                type: tosca.capabilities.Scalable
+            service:
+                type: tosca.capabilities.xos.Service
+        properties:
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+            kind:
+                type: string
+                default: generic
+                description: Type of service.
+            view_url:
+                type: string
+                required: false
+                description: URL to follow when icon is clicked in the Service Directory.
+            icon_url:
+                type: string
+                required: false
+                description: ICON to display in the Service Directory.
+            enabled:
+                type: boolean
+                default: true
+            published:
+                type: boolean
+                default: true
+                description: If True then display this Service in the Service Directory.
+            public_key:
+                type: string
+                required: false
+                description: Public key to install into Instances to allows Services to SSH into them.
+            private_key_fn:
+                type: string
+                required: false
+                description: Location of private key file
+            versionNumber:
+                type: string
+                required: false
+                description: Version number of Service.
+
+    tosca.nodes.ServiceController:
+        derived_from: tosca.nodes.Root
+        description: >
+            An XOS Service Controller.
+        properties:
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+            base_url:
+                type: string
+                required: false
+                description: Base url, to allow resources to use relative URLs
+            models:
+                type: string
+                required: false
+                description: url of models.py
+            admin:
+                type: string
+                required: false
+                description: url of admin.py
+            admin_template:
+                type: string
+                required: false
+                description: url of admin html template
+            synchronizer:
+                type: string
+                required: false
+                description: url of synchronizer manifest
+            synchronizer_run:
+                type: string
+                required: false
+                description: synchronizer run command
+            synchronizer_config:
+                type: string
+                required: false
+                description: synchronizer config filename
+            tosca_custom_types:
+                type: string
+                required: false
+                description: url of tosca custom_types
+            tosca_resource:
+                type: string
+                required: false
+                description: url of tosca resource
+            rest_service:
+                type: string
+                required: false
+                description: url of REST API service file
+            rest_tenant:
+                type: string
+                required: false
+                description: url of REST API tenant file
+            private_key:
+                type: string
+                required: false
+                description: private key
+            public_key:
+                type: string
+                required: false
+                description: public key
+
+    tosca.nodes.ServiceControllerResource:
+        derived_from: tosca.nodes.Root
+        description: >
+            An XOS Service Resource.
+        properties:
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+            kind:
+                type: string
+                required: false
+                description: models, admin, django_library, synchronizer, rest, tosca_custom_types, or tosca_resource
+            format:
+                type: string
+                required: false
+                description: python, manifest, or docker
+            url:
+                type: string
+                required: false
+                description: url of resource, may be relative to base_url or absolute
+
+    tosca.nodes.Tenant:
+        derived_from: tosca.nodes.Root
+        description: >
+            An ONOS Tenant.
+        properties:
+            kind:
+                type: string
+                default: generic
+                description: Kind of tenant
+            service_specific_id:
+                type: string
+                required: false
+                description: Service specific ID opaque to XOS but meaningful to service
+            service_specific_attribute:
+                type: string
+                required: false
+                description: Service-specific attribute, usually a string containing a json dictionary
+            model:
+                type: string
+                required: false
+                description: Name of model to use when instantiating tenant
+
+    tosca.nodes.ONOSService:
+        derived_from: tosca.nodes.Root
+        description: >
+            ONOS Service
+        capabilities:
+            scalable:
+                type: tosca.capabilities.Scalable
+            service:
+                type: tosca.capabilities.xos.Service
+        properties:
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+            kind:
+                type: string
+                default: generic
+                description: Type of service.
+            view_url:
+                type: string
+                required: false
+                description: URL to follow when icon is clicked in the Service Directory.
+            icon_url:
+                type: string
+                required: false
+                description: ICON to display in the Service Directory.
+            enabled:
+                type: boolean
+                default: true
+            published:
+                type: boolean
+                default: true
+                description: If True then display this Service in the Service Directory.
+            public_key:
+                type: string
+                required: false
+                description: Public key to install into Instances to allows Services to SSH into them.
+            private_key_fn:
+                type: string
+                required: false
+                description: Location of private key file
+            versionNumber:
+                type: string
+                required: false
+                description: Version number of Service.
+            rest_onos/v1/network/configuration/:
+                type: string
+                required: false
+            rest_hostname:
+                type: string
+                required: false
+            rest_port:
+                type: string
+                required: false
+            no_container:
+                type: boolean
+                default: false
+            node_key:
+                type: string
+                required: false
+
+
+    tosca.nodes.ONOSApp:
+        derived_from: tosca.nodes.Root
+        description: >
+            An ONOS Application.
+        properties:
+            kind:
+                type: string
+                default: generic
+                description: Kind of tenant
+            service_specific_id:
+                type: string
+                required: false
+                description: Service specific ID opaque to XOS but meaningful to service
+            dependencies:
+                type: string
+                required: false
+
+    tosca.nodes.ONOSvBNGApp:
+        derived_from: tosca.nodes.Root
+        description: >
+            An ONOS vBNG Application.
+        properties:
+            kind:
+                type: string
+                default: generic
+                description: Kind of tenant
+            service_specific_id:
+                type: string
+                required: false
+                description: Service specific ID opaque to XOS but meaningful to service
+            dependencies:
+                type: string
+                required: false
+            install_dependencies:
+                type: string
+                required: false
+            component_config:
+                type: string
+                required: false
+            config_addresses.json:
+                type: string
+                required: false
+            config_network-cfg.json:
+                type: string
+                required: false
+            config_virtualbng.json:
+                type: string
+                required: false
+
+    tosca.nodes.ONOSvOLTApp:
+        derived_from: tosca.nodes.Root
+        description: >
+            An ONOS vOLT Application.
+        properties:
+            kind:
+                type: string
+                default: generic
+                description: Kind of tenant
+            service_specific_id:
+                type: string
+                required: false
+                description: Service specific ID opaque to XOS but meaningful to service
+            dependencies:
+                type: string
+                required: false
+            install_dependencies:
+                type: string
+                required: false
+            component_config:
+                type: string
+                required: false
+            config_network-cfg.json:
+                type: string
+                required: false
+            rest_onos/v1/network/configuration/:
+                type: string
+                required: false
+            autogenerate:
+                type: string
+                required: false
+
+    tosca.nodes.ONOSVTNApp:
+        derived_from: tosca.nodes.Root
+        description: >
+            An ONOS VTN Application.
+        properties:
+            kind:
+                type: string
+                default: generic
+                description: Kind of tenant
+            service_specific_id:
+                type: string
+                required: false
+                description: Service specific ID opaque to XOS but meaningful to service
+            dependencies:
+                type: string
+                required: false
+            rest_onos/v1/network/configuration/:
+                type: string
+                required: false
+            autogenerate:
+                type: string
+                required: false
+
+    tosca.nodes.ONOSvRouterApp:
+        derived_from: tosca.nodes.Root
+        description: >
+            An ONOS vRouter Application.
+        properties:
+            kind:
+                type: string
+                default: generic
+                description: Kind of tenant
+            service_specific_id:
+                type: string
+                required: false
+                description: Service specific ID opaque to XOS but meaningful to service
+            dependencies:
+                type: string
+                required: false
+            rest_onos/v1/network/configuration/:
+                type: string
+                required: false
+            autogenerate:
+                type: string
+                required: false
+
+    tosca.nodes.VSGService:
+        description: >
+            CORD: The vSG Service.
+        derived_from: tosca.nodes.Root
+        capabilities:
+            scalable:
+                type: tosca.capabilities.Scalable
+            service:
+                type: tosca.capabilities.xos.Service
+        properties:
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+            kind:
+                type: string
+                default: generic
+                description: Type of service.
+            view_url:
+                type: string
+                required: false
+                description: URL to follow when icon is clicked in the Service Directory.
+            icon_url:
+                type: string
+                required: false
+                description: ICON to display in the Service Directory.
+            enabled:
+                type: boolean
+                default: true
+            published:
+                type: boolean
+                default: true
+                description: If True then display this Service in the Service Directory.
+            public_key:
+                type: string
+                required: false
+                description: Public key to install into Instances to allows Services to SSH into them.
+            private_key_fn:
+                type: string
+                required: false
+                description: Location of private key file
+            versionNumber:
+                type: string
+                required: false
+                description: Version number of Service.
+            backend_network_label:
+                type: string
+                required: false
+                description: Label that matches network used to connect HPC and BBS services.
+            dns_servers:
+                type: string
+                required: false
+            node_label:
+                type: string
+                required: false
+
+    tosca.nodes.VBNGService:
+        derived_from: tosca.nodes.Root
+        description: >
+            CORD: The vBNG Service.
+        capabilities:
+            scalable:
+                type: tosca.capabilities.Scalable
+            service:
+                type: tosca.capabilities.xos.Service
+        properties:
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+            kind:
+                type: string
+                default: generic
+                description: Type of service.
+            view_url:
+                type: string
+                required: false
+                description: URL to follow when icon is clicked in the Service Directory.
+            icon_url:
+                type: string
+                required: false
+                description: ICON to display in the Service Directory.
+            enabled:
+                type: boolean
+                default: true
+            published:
+                type: boolean
+                default: true
+                description: If True then display this Service in the Service Directory.
+            public_key:
+                type: string
+                required: false
+                description: Public key to install into Instances to allows Services to SSH into them.
+            private_key_fn:
+                type: string
+                required: false
+                description: Location of private key file
+            versionNumber:
+                type: string
+                required: false
+                description: Version number of Service.
+            vbng_url:
+                type: string
+                required: false
+                description: URL of REST API endpoint for vBNG Service.
+
+    tosca.nodes.VRouterService:
+        derived_from: tosca.nodes.Root
+        description: >
+            CORD: The vRouter Service.
+        capabilities:
+            scalable:
+                type: tosca.capabilities.Scalable
+            service:
+                type: tosca.capabilities.xos.Service
+        properties:
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+            kind:
+                type: string
+                default: generic
+                description: Type of service.
+            view_url:
+                type: string
+                required: false
+                description: URL to follow when icon is clicked in the Service Directory.
+            icon_url:
+                type: string
+                required: false
+                description: ICON to display in the Service Directory.
+            enabled:
+                type: boolean
+                default: true
+            published:
+                type: boolean
+                default: true
+                description: If True then display this Service in the Service Directory.
+            public_key:
+                type: string
+                required: false
+                description: Public key to install into Instances to allows Services to SSH into them.
+            private_key_fn:
+                type: string
+                required: false
+                description: Location of private key file
+            versionNumber:
+                type: string
+                required: false
+                description: Version number of Service.
+
+    tosca.nodes.FabricService:
+        derived_from: tosca.nodes.Root
+        description: >
+            CORD: The Fabric Service.
+        capabilities:
+            scalable:
+                type: tosca.capabilities.Scalable
+            service:
+                type: tosca.capabilities.xos.Service
+        properties:
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+            kind:
+                type: string
+                default: generic
+                description: Type of service.
+            view_url:
+                type: string
+                required: false
+                description: URL to follow when icon is clicked in the Service Directory.
+            icon_url:
+                type: string
+                required: false
+                description: ICON to display in the Service Directory.
+            enabled:
+                type: boolean
+                default: true
+            published:
+                type: boolean
+                default: true
+                description: If True then display this Service in the Service Directory.
+            public_key:
+                type: string
+                required: false
+                description: Public key to install into Instances to allows Services to SSH into them.
+            private_key_fn:
+                type: string
+                required: false
+                description: Location of private key file
+            versionNumber:
+                type: string
+                required: false
+                description: Version number of Service.
+
+    tosca.nodes.VTNService:
+        derived_from: tosca.nodes.Root
+        description: >
+            CORD: The vRouter Service.
+        capabilities:
+            scalable:
+                type: tosca.capabilities.Scalable
+            service:
+                type: tosca.capabilities.xos.Service
+        properties:
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+            kind:
+                type: string
+                default: generic
+                description: Type of service.
+            view_url:
+                type: string
+                required: false
+                description: URL to follow when icon is clicked in the Service Directory.
+            icon_url:
+                type: string
+                required: false
+                description: ICON to display in the Service Directory.
+            enabled:
+                type: boolean
+                default: true
+            published:
+                type: boolean
+                default: true
+                description: If True then display this Service in the Service Directory.
+            public_key:
+                type: string
+                required: false
+                description: Public key to install into Instances to allows Services to SSH into them.
+            private_key_fn:
+                type: string
+                required: false
+                description: Location of private key file
+            versionNumber:
+                type: string
+                required: false
+                description: Version number of Service.
+            privateGatewayMac:
+                type: string
+                required: false
+            localManagementIp:
+                type: string
+                required: false
+            ovsdbPort:
+                type: string
+                required: false
+            sshPort:
+                type: string
+                required: false
+            sshUser:
+                type: string
+                required: false
+            sshKeyFile:
+                type: string
+                required: false
+            mgmtSubnetBits:
+                type: string
+                required: false
+            xosEndpoint:
+                type: string
+                required: false
+            xosUser:
+                type: string
+                required: false
+            xosPassword:
+                type: string
+                required: false
+
+
+    tosca.nodes.CDNService:
+        derived_from: tosca.nodes.Root
+        description: >
+            Content Delivery Network Service. Includes Request Routing and Hypercache.
+        capabilities:
+            scalable:
+                type: tosca.capabilities.Scalable
+            service:
+                type: tosca.capabilities.xos.Service
+        properties:
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+            kind:
+                type: string
+                default: generic
+                description: Type of service.
+            view_url:
+                type: string
+                required: false
+                description: URL to follow when icon is clicked in the Service Directory.
+            icon_url:
+                type: string
+                required: false
+                description: ICON to display in the Service Directory.
+            enabled:
+                type: boolean
+                default: true
+            published:
+                type: boolean
+                default: true
+                description: If True then display this Service in the Service Directory.
+            public_key:
+                type: string
+                required: false
+                description: Public key to install into Instances to allows Services to SSH into them.
+            private_key_fn:
+                type: string
+                required: false
+                description: Location of private key file
+            versionNumber:
+                type: string
+                required: false
+                description: Version number of Service.
+
+    tosca.nodes.Subscriber:
+        derived_from: tosca.nodes.Root
+        description: XOS subscriber base class.
+        capabilities:
+            subscriber:
+                type: tosca.capabilities.xos.Subscriber
+        properties:
+            kind:
+                type: string
+                default: generic
+                description: Kind of subscriber
+            service_specific_id:
+                type: string
+                required: false
+                description: Service specific ID opaque to XOS but meaningful to service
+
+    tosca.nodes.CORDSubscriber:
+        derived_from: tosca.nodes.Root
+        description: >
+            CORD: Subscriber. The Subscriber object contains all of the settings
+            for a CORD household. For example, it contains parental control
+            filter settings.
+        capabilities:
+            subscriber:
+                type: tosca.capabilities.xos.Subscriber
+        properties:
+            kind:
+                type: string
+                default: generic
+                description: Kind of subscriber
+            service_specific_id:
+                type: string
+                required: false
+                description: Service specific ID opaque to XOS but meaningful to service
+            firewall_enable:
+                type: boolean
+                default: false
+                description: If True, then firewalling is enabled.
+            url_filter_enable:
+                type: boolean
+                default: false
+                description: If True, then parental controls are enabled.
+            url_filter_level:
+                type: string
+                default: PG
+                description: The default URL filter level for the household.
+            cdn_enable:
+                type: boolean
+                default: true
+                description: If True, then the CDN is enabled.
+
+    tosca.nodes.CORDUser:
+        derived_from: tosca.nodes.Root
+        description: >
+            CORD: User. The CORD user represents an individual device beloning
+            to the CORD Subscriber. Each device may have its own parental
+            controls.
+        capabilities:
+            device:
+                type: tosca.capabilities.xos.Device
+        properties:
+            level:
+                type: string
+                default: PG_13
+                description: Parental control level for this device.
+            mac:
+                type: string
+                required: true
+                description: MAC address for this device.
+
+    tosca.nodes.VOLTService:
+        derived_from: tosca.nodes.Root
+        description: >
+            CORD: The vOLT Service
+        capabilities:
+            scalable:
+                type: tosca.capabilities.Scalable
+            service:
+                type: tosca.capabilities.xos.Service
+        properties:
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+            kind:
+                type: string
+                default: generic
+                description: Type of service.
+            view_url:
+                type: string
+                required: false
+                description: URL to follow when icon is clicked in the Service Directory.
+            icon_url:
+                type: string
+                required: false
+                description: ICON to display in the Service Directory.
+            enabled:
+                type: boolean
+                default: true
+            published:
+                type: boolean
+                default: true
+                description: If True then display this Service in the Service Directory.
+            public_key:
+                type: string
+                required: false
+                description: Public key to install into Instances to allows Services to SSH into them.
+            private_key_fn:
+                type: string
+                required: false
+                description: Location of private key file
+            versionNumber:
+                type: string
+                required: false
+                description: Version number of Service.
+
+    tosca.nodes.VOLTTenant:
+        derived_from: tosca.nodes.Root
+        description: >
+            CORD: A Tenant of the vOLT Service. Each Tenant is tied to a
+            specific vlan_id.
+        properties:
+            kind:
+                type: string
+                default: generic
+                description: Kind of tenant
+            service_specific_id:
+                type: string
+                required: false
+                description: Service specific ID opaque to XOS but meaningful to service
+            s_tag:
+                type: string
+                required: false
+                description: s_tag, identifies which volt port
+            c_tag:
+                type: string
+                required: false
+                description: c_tag, identifies which subscriber within s_tag
+
+    tosca.nodes.VOLTDevice:
+        derived_from: tosca.nodes.Root
+        description: >
+            CORD: A vOLT Device.
+        properties:
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+            openflow_id:
+                type: string
+                required: false
+                description: openflow id
+            driver:
+                type: string
+                required: false
+                description: driver name
+            access_devices:
+                type: string
+                required: false
+                description: list of access devices, in format "uplink vlan", multiple entries separated by commas
+
+# XXX - uncomment if we want access device to be specified as separate Tosca
+# objects, rather than encoding them into VOLTDevice.access_devices
+#    tosca.nodes.AccessDevice:
+#        derived_from: tosca.nodes.Root
+#        description: >
+#            CORD: A vOLT Access Device.
+#        properties:
+#            xos_base_props
+#            uplink:
+#               type: integer
+#               required: false
+#               description: uplink
+#            vlan:
+#               type: integer
+#               required: false
+#               description: vlan
+
+    tosca.nodes.AccessAgent:
+        derived_from: tosca.nodes.Root
+        description: >
+            CORD: A vOLT Access Agent.
+        properties:
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+            mac:
+                type: string
+                required: false
+                description: mac address
+            port_mappings:
+                type: string
+                required: false
+                description: list of port mappings, in format "port mac", multiple entries separated by commas
+
+
+    tosca.nodes.User:
+        derived_from: tosca.nodes.Root
+
+        description: >
+            An XOS User record. Users are able to login and use the XOS GUI.
+
+        capabilities:
+            user:
+                type: tosca.capabilities.xos.User
+
+        properties:
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+            password:
+                type: string
+                required: false
+            firstname:
+                type: string
+                required: false
+                description: First name of User.
+            lastname:
+                type: string
+                required: false
+                description: Last name of User.
+            phone:
+                type: string
+                required: false
+                description: Phone number of User.
+            user_url:
+                type: string
+                required: false
+                description: URL to User web page.
+            public_key:
+                type: string
+                required: false
+                description: Public key that will be installed in Instances.
+            is_active:
+                type: boolean
+                required: false
+                #default: true
+                description: If True, the user may log in.
+            is_admin:
+                type: boolean
+                required: false
+                #default: false
+                description: If True, the user has root admin privileges.
+            login_page:
+                type: string
+                required: false
+                description: Indicates what page the user should go to on login.
+
+    tosca.nodes.NetworkParameterType:
+        derived_from: tosca.nodes.Root
+
+        description: >
+            An XOS network parameter type. May be applied to Networks and/or
+            Ports.
+
+        properties:
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+
+        capabilities:
+            network_parameter_type:
+                type: tosca.capabilities.xos.NetworkParameterType
+
+    tosca.nodes.NetworkTemplate:
+        derived_from: tosca.nodes.Root
+
+        description: >
+            An XOS network template. Network templates contain settings associated
+            with a particular class of network.
+
+        capabilities:
+            network_template:
+                type: tosca.capabilities.xos.NetworkTemplate
+
+        properties:
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+            visibility:
+                type: string
+                required: false
+                description: Indicates whether network is publicly routable.
+            translation:
+                type: string
+                required: false
+                description: Indicates whether network uses address translation.
+            shared_network_name:
+                type: string
+                required: false
+                description: Attaches this template to a specific OpenStack network.
+            shared_network_id:
+                type: string
+                required: false
+                description: Attaches this template to a specific OpenStack network.
+            topology_kind:
+                type: string
+                required: false
+                description: Describes the topology of the network.
+            controller_kind:
+                type: string
+                required: false
+                description: Indicates the type of controller that the network is connected to.
+            access:
+                type: string
+                required: false
+                description: The type of access semantics for this network
+
+    tosca.nodes.network.Network.XOS:
+          # Due to bug? in implementation, we have to copy everything from
+          # tosca definitions tosca.nodes.network.Network here rather than
+          # using derived_from.
+          derived_from: tosca.nodes.Root
+          description: >

+            This is a variant of the TOSCA Network object that includes additional

+            XOS-specific properties.

+          properties:

+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object

+            ip_version:

+              type: integer

+              required: no

+              default: 4

+              constraints:

+                - valid_values: [ 4, 6 ]

+              description: >

+                The IP version of the requested network. Valid values are 4 for ipv4

+                or 6 for ipv6.

+            cidr:

+              type: string

+              required: no

+              description: >

+                The cidr block of the requested network.

+            start_ip:

+              type: string

+              required: no

+              description: >

+                 The IP address to be used as the start of a pool of addresses within

+                 the full IP range derived from the cidr block.

+            end_ip:

+              type: string

+              required: no

+              description: >

+                  The IP address to be used as the end of a pool of addresses within

+                  the full IP range derived from the cidr block.

+            gateway_ip:

+              type: string

+              required: no

+              description: >

+                 The gateway IP address.

+            network_name:

+              type: string

+              required: no

+              description: >

+                 An identifier that represents an existing Network instance in the

+                 underlying cloud infrastructure or can be used as the name of the

+                 newly created network. If network_name is provided and no other

+                 properties are provided (with exception of network_id), then an

+                 existing network instance will be used. If network_name is provided

+                 alongside with more properties then a new network with this name will

+                 be created.

+            network_id:

+              type: string

+              required: no

+              description: >

+                 An identifier that represents an existing Network instance in the

+                 underlying cloud infrastructure. This property is mutually exclusive

+                 with all other properties except network_name. This can be used alone

+                 or together with network_name to identify an existing network.

+            segmentation_id:

+              type: string

+              required: no

+              description: >

+                 A segmentation identifier in the underlying cloud infrastructure.

+                 E.g. VLAN ID, GRE tunnel ID, etc..

+            dhcp_enabled:

+              type: boolean

+              required: no

+              default: true

+              description: >

+                Indicates should DHCP service be enabled on the network or not.

+        # XOS-specific

+            ports:

+                type: string
+                required: false
+                description: >
+                    A comma-separated list of protocols and ports. For example,
+                    "tcp/123, tcp/456-459, udp/111"
+            labels:
+                type: string
+                required: false
+                description: A comma-separated list of labels for this network.
+            permit_all_slices:
+                type: boolean
+                # In the data model, this is defaulted to false. However, to
+                # preserve Tosca semantics, we default it to true instead.
+                default: true
+                description: If True, then any slice may be attached to this network.
+          capabilities:
+            link:

+              type: tosca.capabilities.network.Linkable
+
+    tosca.nodes.Deployment:
+        derived_from: tosca.nodes.Root
+        description: >
+            An XOS Deployment.
+        capabilities:
+            deployment:
+                type: tosca.capabilities.xos.Deployment
+        properties:
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+            accessControl:
+                type: string
+                default: allow all
+                description: ACL that describes who may use this deployment.
+            flavors:
+                type: string
+                required: false
+                description: Comma-separated list of flavors that this deployment supports.
+
+    tosca.nodes.AddressPool:
+        derived_from: tosca.nodes.Root
+        description: >
+            A pool of addresses
+        capabilities:
+            addresspool:
+                type: tosca.capabilities.xos.AddressPool
+        properties:
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+            addresses:
+                type: string
+                required: false
+                description: space-separated list of addresses
+            gateway_ip:
+                type: string
+                required: false
+                description: gateway ip address
+            gateway_mac:
+                type: string
+                required: false
+                description: gateway mac address
+
+    tosca.nodes.Image:
+        derived_from: tosca.nodes.Root
+        description: >
+            An XOS Operating System Image.
+        capabilities:
+            image:
+                type: tosca.capabilities.xos.Image
+        properties:
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+            kind:
+                type: string
+                required: false
+                description: Type of image (container | VM)
+            disk_format:
+                type: string
+                required: false
+                description: Glance disk format.
+            container_format:
+                type: string
+                required: false
+                description: Glance container format.
+            path:
+                type: string
+                required: false
+                description: Path to Image file
+            tag:
+                type: string
+                required: false
+                description: For Docker images, tag of image
+
+    tosca.nodes.Controller:
+        derived_from: tosca.nodes.Root
+        description: >
+            An XOS controller. Controllers serve as the interface between
+            XOS and services such as OpenStack.
+        capabilities:
+            controller:
+                type: tosca.capabilities.xos.Controller
+        properties:
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+            backend_type:
+                type: string
+                required: false
+                description: Type of backend.
+            version:
+                type: string
+                required: false
+                description: Version of backend.
+            auth_url:
+                type: string
+                required: false
+                description: Keystone auth_url.
+            admin_user:
+                type: string
+                required: false
+                description: Keystone username.
+            admin_password:
+                type: string
+                required: false
+                description: Keystone password.
+            admin_tenant:
+                type: string
+                required: false
+                description: Tenant associated with admin account.
+            domain:
+                type: string
+                required: false
+                description: OpenStack domain (or "Default")
+            rabbit_host:
+                type: string
+                required: false
+                description: Rabbit host
+            rabbit_user:
+                type: string
+                required: false
+                description: Rabbit user
+            rabbit_password:
+                type: string
+                required: false
+                description: Rabbit password
+
+    tosca.nodes.Site:
+        derived_from: tosca.nodes.Root
+        description: >
+            An XOS Site. Sites are containers for Users and/or Nodes.
+        capabilities:
+            site:
+                type: tosca.capabilities.xos.Site
+        properties:
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+            display_name:
+                type: string
+                required: false
+                description: Name of the site.
+            site_url:
+                type: string
+                required: false
+                description: URL of site web page.
+            enabled:
+                type: boolean
+                default: true
+            hosts_nodes:
+                type: boolean
+                default: true
+                description: If True, then this site hosts nodes where Instances may be instantiated.
+            hosts_users:
+                type: boolean
+                default: true
+                description: If True, then this site hosts users who may use XOS.
+            is_public:
+                type: boolean
+                default: true
+            # location, longitude, latitude
+
+    tosca.nodes.Slice:
+        derived_from: tosca.nodes.Root
+        description: >
+            An XOS Slice. A slice is a collection of instances that share
+            common attributes.
+        capabilities:
+            slice:
+                type: tosca.capabilities.xos.Slice
+        properties:
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+            enabled:
+                type: boolean
+                default: true
+            description:
+                type: string
+                required: false
+                description: Description of this slice.
+            slice_url:
+                type: string
+                required: false
+                description: URL to web page that describes slice.
+            max_instances:
+                type: integer
+                default: 10
+                description: Quota of instances that this slice may create.
+            default_isolation:
+                type: string
+                required: false
+                description: default isolation to use when bringing up instances (default to 'vm')
+            network:
+                type: string
+                required: false
+                description: type of networking to use for this slice
+            exposed_ports:
+                type: string
+                required: false
+                description: comma-separated list of protocol _space_ port that represent ports the slice should expose
+            default_node:
+                type: string
+                required: false
+                description: default node to use for this slice
+
+    tosca.nodes.Node:
+        derived_from: tosca.nodes.Root
+        description: >
+            An XOS Node. Nodes are physical machines that host virtual machines
+            and/or containers.
+        properties:
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+        capabilities:
+            node:
+                type: tosca.capabilities.xos.Node
+
+    tosca.nodes.NodeLabel:
+        derived_from: tosca.nodes.Root
+        description: >
+            An XOS NodeLabel.
+        properties:
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+        capabilities:
+            node:
+                type: tosca.capabilities.xos.NodeLabel
+
+    tosca.nodes.Flavor:
+        derived_from: tosca.nodes.Root
+        description: >
+            An XOS Flavor.
+        properties:
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+            flavor:
+                type: string
+                required: false
+                description: openstack flavor name
+        capabilities:
+            flavor:
+                type: tosca.capabilities.xos.Flavor
+
+    tosca.nodes.SiteRole:
+        derived_from: tosca.nodes.Root
+        description: >
+            An XOS Site Role.
+        properties:
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+        capabilities:
+            siterole:
+                type: tosca.capabilities.xos.SiteRole
+
+    tosca.nodes.SliceRole:
+        derived_from: tosca.nodes.Root
+        description: >
+            An XOS Slice Role.
+        properties:
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+        capabilities:
+            slicerole:
+                type: tosca.capabilities.xos.SliceRole
+
+    tosca.nodes.TenantRole:
+        derived_from: tosca.nodes.Root
+        description: >
+            An XOS Tenant Role.
+        properties:
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+        capabilities:
+            tenantrole:
+                type: tosca.capabilities.xos.TenantRole
+
+    tosca.nodes.DeploymentRole:
+        derived_from: tosca.nodes.Root
+        description: >
+            An XOS Deployment Role.
+        properties:
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+        capabilities:
+            deploymentrole:
+                type: tosca.capabilities.xos.DeploymentRole
+
+    tosca.nodes.DashboardView:
+        derived_from: tosca.nodes.Root
+        description: >
+            An XOS Dashboard View
+        capabilities:
+            dashboardview:
+                type: tosca.capabilities.xos.DashboardView
+        properties:
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+            enabled:
+                type: boolean
+                default: true
+            url:
+                type: string
+                required: false
+                description: URL to the dashboard
+
+    tosca.nodes.Tag:
+        derived_from: tosca.nodes.Root
+        description: >
+            An XOS Tag
+        properties:
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+            name:
+                type: string
+                required: true
+                descrption: name of tag
+            value:
+                type: string
+                required: false
+                descrption: value of tag
+
+    tosca.nodes.Compute.Container:
+      derived_from: tosca.nodes.Compute
+      description: >
+        The TOSCA Compute node represents a container on bare metal.
+      attributes:
+        private_address:
+          type: string
+        public_address:
+          type: string
+      capabilities:
+          host:
+             type: tosca.capabilities.Container
+          binding:
+             type: tosca.capabilities.network.Bindable
+          os:
+             type: tosca.capabilities.OperatingSystem
+          scalable:
+             type: tosca.capabilities.Scalable
+      requirements:
+        - local_storage:
+            capability: tosca.capabilities.Attachment
+            node: tosca.nodes.BlockStorage
+            relationship: tosca.relationships.AttachesTo
+            occurrences: [0, UNBOUNDED]
+
+    tosca.relationships.MemberOfSlice:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Slice ]
+
+    tosca.relationships.MemberOfService:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Service ]
+
+    tosca.relationships.MemberOfSite:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Site ]
+
+    tosca.relationships.MemberOfDeployment:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Deployment ]
+
+    tosca.relationships.TenantOfService:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Service ]
+
+    tosca.relationships.UsedByService:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Service ]
+
+    tosca.relationships.ControllerDeployment:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Deployment ]
+
+    tosca.relationships SiteDeployment:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Deployment ]
+
+    tosca.relationships.UsesController:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Controller ]
+
+    tosca.relationships.ConnectsToNetwork:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Network ]
+
+    tosca.relationships.UsesImage:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Image ]
+
+    tosca.relationships.DefaultImage:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Image ]
+
+    tosca.relationships.SupportsImage:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Image ]
+
+    tosca.relationships.ConnectsToSlice:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Slice ]
+
+    #    tosca.relationships.OwnsNetwork:
+    #        derived_from: tosca.relationships.Root
+    #        valid_target_types: [ tosca.capabilities.xos.Network ]
+
+    tosca.relationships.UsesNetworkTemplate:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.NetworkTemplate ]
+
+    tosca.relationships.AdminPrivilege:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Slice, tosca.capabilities.xos.Site ]
+
+    tosca.relationships.AccessPrivilege:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Slice, tosca.capabilities.xos.Site ]
+
+    tosca.relationships.PIPrivilege:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Site ]
+
+    tosca.relationships.TechPrivilege:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Site ]
+
+    tosca.relationships.SubscriberDevice:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Subscriber ]
+
+    tosca.relationships.BelongsToSubscriber:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Subscriber ]
+
+    tosca.relationships.UsesDashboard:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.DashboardView ]
+
+    tosca.relationships.HasLabel:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.NodeLabel ]
+
+    tosca.relationships.SupportsFlavor:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Flavor ]
+
+    tosca.relationships.DefaultFlavor:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.Flavor ]
+
+    tosca.relationships.ProvidesAddresses:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.AddressPool ]
+
+    tosca.relationships.DependsOn:
+        derived_from: tosca.relationships.Root
+
+    tosca.relationships.TagsObject:
+        derived_from: tosca.relationships.Root
+
+    tosca.relationships.MemberOfDevice:
+        derived_from: tosca.relationships.Root
+
+    tosca.relationships.UsesAgent:
+        derived_from: tosca.relationships.Root
+
+    tosca.relationships.HasResource:
+        derived_from: tosca.relationships.Root
+
+    tosca.relationships.UsedByController:
+        derived_from: tosca.relationships.Root
+
+    tosca.relationships.UsedByXOS:
+        derived_from: tosca.relationships.Root
+
+    tosca.capabilities.xos.Service:
+        derived_from: tosca.capabilities.Root
+        description: An XOS Service
+
+    tosca.capabilities.xos.Deployment:
+        derived_from: tosca.capabilities.Root
+        description: An XOS Deployment
+
+    tosca.capabilities.xos.Controller:
+        derived_from: tosca.capabilities.Root
+        description: An XOS Controller
+
+    tosca.capabilities.xos.Site:
+        derived_from: tosca.capabilities.Root
+        description: An XOS Site
+
+    tosca.capabilities.xos.Slice:
+        derived_from: tosca.capabilities.Root
+        description: An XOS Slice
+
+    tosca.capabilities.xos.NetworkTemplate:
+        derived_from: tosca.capabilities.Root
+        description: An XOS network template
+
+#    tosca.capabilities.xos.Network:
+#        derived_from: tosca.capabilities.Root
+#        description: An XOS network
+
+    tosca.capabilities.xos.User:
+        derived_from: tosca.capabilities.Root
+        description: An XOS user
+
+    tosca.capabilities.xos.Subscriber:
+        derived_from: tosca.capabilities.Root
+        description: An XOS Subscriber
+
+    tosca.capabilities.xos.Device:
+        derived_from: tosca.capabilities.Root
+        description: A device belonging to an XOS subscriber
+
+    tosca.capabilities.xos.Node:
+        derived_from: tosca.capabilities.Root
+        description: An XOS Node
+
+    tosca.capabilities.xos.NodeLabel:
+        derived_from: tosca.capabilities.Root
+        description: An XOS NodeLabel
+
+    tosca.capabilities.xos.Flavor:
+        derived_from: tosca.capabilities.Root
+        description: An XOS Flavor
+
+    tosca.capabilities.xos.DeploymentRole:
+        derived_from: tosca.capabilities.Root
+        description: An XOS DeploymentRole
+
+    tosca.capabilities.xos.SliceRole:
+        derived_from: tosca.capabilities.Root
+        description: An XOS SliceRole
+
+    tosca.capabilities.xos.SiteRole:
+        derived_from: tosca.capabilities.Root
+        description: An XOS SiteRole
+
+    tosca.capabilities.xos.TenantRole:
+        derived_from: tosca.capabilities.Root
+        description: An XOS TenantRole
+
+    tosca.capabilities.xos.Image:
+        derived_from: tosca.capabilities.Root
+        description: An XOS Image
+
+    tosca.capabilities.xos.DashboardView:
+        derived_from: tosca.capabilities.Root
+        description: An XOS DashboardView
+
+    tosca.capabilities.xos.NetworkParameterType:
+        derived_from: tosca.capabilities.Root
+        description: An XOS NetworkParameterType
+
+    tosca.capabilities.xos.AddressPool:
+        derived_from: tosca.capabilities.Root
+        description: An XOS AddressPool
diff --git a/xos/tosca/daemon.py b/xos/tosca/daemon.py
new file mode 100644
index 0000000..dc6e057
--- /dev/null
+++ b/xos/tosca/daemon.py
@@ -0,0 +1,92 @@
+""" A very simple Tosca daemon. Every ten seconds it looks for new programs in
+    "run" or "destroy" status, and executes them.
+
+    TODO: Replace this with observer and/or model_policies ?
+"""
+
+import os
+import sys
+from threading import Thread
+import time
+
+# add the parent directory to sys.path
+import os,sys,inspect
+currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
+parentdir = os.path.dirname(currentdir)
+sys.path.append(parentdir)
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
+import django
+django.setup()
+
+from core.models import Program, User
+from nodeselect import XOSNodeSelector
+from imageselect import XOSImageSelector
+import traceback
+
+from engine import XOSTosca
+
+class ToscaDaemon(Thread):
+    def __init__(self):
+        Thread.__init__(self)
+        self.daemon = True
+
+    def run_program(self, model):
+        try:
+            print "*** Run Program %s ***" % model.name
+            model.status = "executing"
+            model.messages = ""
+            model.save()
+            xt = XOSTosca(model.contents, parent_dir=currentdir, log_to_console=True)
+            xt.execute(model.owner)
+            model.messages = "\n".join(xt.log_msgs)
+            model.status = "complete"
+        except:
+            model.messages = traceback.format_exc()
+            model.status = "exception"
+            traceback.print_exc()
+        model.command = None
+        model.save()
+
+    def destroy_program(self, model):
+        try:
+            print "*** Destroy Program %s ***" % model.name
+            model.status = "executing"
+            model.messages = ""
+            model.save()
+            xt = XOSTosca(model.contents, parent_dir=currentdir)
+            xt.destroy(model.owner)
+            model.messages = "\n".join(xt.log_msgs)
+            model.status = "complete"
+        except:
+            model.messages = traceback.format_exc()
+            model.status = "exception"
+            traceback.print_exc()
+        model.command = None
+        model.save()
+
+    def run_once(self):
+        models = Program.objects.filter(kind="tosca", command="run")
+        for model in models:
+            self.run_program(model)
+
+        models = Program.objects.filter(kind="tosca", command="destroy")
+        for model in models:
+            self.destroy_program(model)
+
+    def run(self):
+        while True:
+            self.run_once()
+            time.sleep(10)
+            django.db.reset_queries()
+
+if __name__ == "__main__":
+    if "--once" in sys.argv:
+        ToscaDaemon().execute_once()
+    else:
+        ToscaDaemon().start()
+
+        print "Running forever..."
+        while True:
+            time.sleep(60)
+
diff --git a/xos/tosca/definitions/TOSCA_definition_1_0.yaml b/xos/tosca/definitions/TOSCA_definition_1_0.yaml
new file mode 100644
index 0000000..97a8c44
--- /dev/null
+++ b/xos/tosca/definitions/TOSCA_definition_1_0.yaml
@@ -0,0 +1,726 @@
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+##########################################################################
+# The content of this file reflects TOSCA Simple Profile in YAML version
+# 1.0.0. It describes the definition for TOSCA types including Node Type,
+# Relationship Type, Capability Type and Interfaces.
+##########################################################################
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+##########################################################################
+# Node Type.
+# A Node Type is a reusable entity that defines the type of one or more
+# Node Templates.
+##########################################################################
+tosca.nodes.Root:
+  description: >
+    The TOSCA root node all other TOSCA base node types derive from.
+  attributes:
+    tosca_id:
+      type: string
+    tosca_name:
+      type: string
+    state:
+      type: string
+    capabilities:
+      feature:
+        type: tosca.capabilities.Node
+  requirements:
+    - dependency:
+        capability: tosca.capabilities.Node
+        node: tosca.nodes.Root
+        relationship: tosca.relationships.DependsOn
+        occurrences: [ 0, UNBOUNDED ]
+  interfaces:
+    Standard:
+      type: tosca.interfaces.node.lifecycle.Standard
+
+tosca.nodes.Compute:
+  derived_from: tosca.nodes.Root
+  description: >
+    The TOSCA Compute node represents one or more real or virtual processors
+    of software applications or services along with other essential local
+    resources.  Collectively, the resources the compute node represents can
+    logically be viewed as a (real or virtual) server.
+  attributes:
+    private_address:
+      type: string
+    public_address:
+      type: string
+  capabilities:
+      host:
+         type: tosca.capabilities.Container
+      binding:
+         type: tosca.capabilities.network.Bindable
+      os:
+         type: tosca.capabilities.OperatingSystem
+      scalable:
+         type: tosca.capabilities.Scalable
+  requirements:
+    - local_storage:
+        capability: tosca.capabilities.Attachment
+        node: tosca.nodes.BlockStorage
+        relationship: tosca.relationships.AttachesTo
+        occurrences: [0, UNBOUNDED]
+
+tosca.nodes.SoftwareComponent:
+  derived_from: tosca.nodes.Root
+  properties:
+    # domain-specific software component version
+    component_version:
+      type: version
+      required: false
+      description: >
+        Software component version.
+    admin_credential:
+      type: tosca.datatypes.Credential
+      required: false
+  requirements:
+    - host:
+        capability: tosca.capabilities.Container
+        node: tosca.nodes.Compute
+        relationship: tosca.relationships.HostedOn
+
+tosca.nodes.DBMS:
+  derived_from: tosca.nodes.SoftwareComponent
+  properties:
+    port:
+      required: no
+      type: integer
+      description: >
+        The port the DBMS service will listen to for data and requests.
+    root_password:
+      required: no
+      type: string
+      description: >
+        The root password for the DBMS service.
+  capabilities:
+    host:
+      type: tosca.capabilities.Container
+      valid_source_types: [tosca.nodes.Database]
+
+tosca.nodes.Database:
+  derived_from: tosca.nodes.Root
+  properties:
+    user:
+      required: no
+      type: string
+      description: >
+        User account name for DB administration
+    name:
+      required: no
+      type: string
+      description: >
+        The name of the database.
+    password:
+      required: no
+      type: string
+      description: >
+        The password for the DB user account
+  requirements:
+    - host:
+        capability: tosca.capabilities.Container
+        node: tosca.nodes.DBMS
+        relationship: tosca.relationships.HostedOn
+  capabilities:
+    database_endpoint:
+      type: tosca.capabilities.Endpoint.Database
+
+tosca.nodes.WebServer:
+  derived_from: tosca.nodes.SoftwareComponent
+  capabilities:
+    data_endpoint:
+      type: tosca.capabilities.Endpoint
+    admin_endpoint:
+      type: tosca.capabilities.Endpoint.Admin
+    host:
+      type: tosca.capabilities.Container
+      valid_source_types: [tosca.nodes.WebApplication]
+
+tosca.nodes.WebApplication:
+  derived_from: tosca.nodes.Root
+  properties:
+    context_root:
+      type: string
+      required: false
+  requirements:
+    - host:
+        capability: tosca.capabilities.Container
+        node: tosca.nodes.WebServer
+        relationship: tosca.relationships.HostedOn
+  capabilities:
+    app_endpoint:
+      type: tosca.capabilities.Endpoint
+
+tosca.nodes.BlockStorage:
+  derived_from: tosca.nodes.Root
+  properties:
+    size:
+      type: integer
+      constraints:
+        - greater_or_equal: 1
+    volume_id:
+      type: string
+      required: false
+    snapshot_id:
+      type: string
+      required: false
+  attributes:
+    volume_id:
+      type: string
+  capabilities:
+    attachment:
+      type: tosca.capabilities.Attachment
+
+tosca.nodes.network.Network:
+  derived_from: tosca.nodes.Root
+  description: >
+    The TOSCA Network node represents a simple, logical network service.
+  properties:
+    ip_version:
+      type: integer
+      required: no
+      default: 4
+      constraints:
+        - valid_values: [ 4, 6 ]
+      description: >
+        The IP version of the requested network. Valid values are 4 for ipv4
+        or 6 for ipv6.
+    cidr:
+      type: string
+      required: no
+      description: >
+        The cidr block of the requested network.
+    start_ip:
+      type: string
+      required: no
+      description: >
+         The IP address to be used as the start of a pool of addresses within
+         the full IP range derived from the cidr block.
+    end_ip:
+      type: string
+      required: no
+      description: >
+          The IP address to be used as the end of a pool of addresses within
+          the full IP range derived from the cidr block.
+    gateway_ip:
+      type: string
+      required: no
+      description: >
+         The gateway IP address.
+    network_name:
+      type: string
+      required: no
+      description: >
+         An identifier that represents an existing Network instance in the
+         underlying cloud infrastructure or can be used as the name of the
+         newly created network. If network_name is provided and no other
+         properties are provided (with exception of network_id), then an
+         existing network instance will be used. If network_name is provided
+         alongside with more properties then a new network with this name will
+         be created.
+    network_id:
+      type: string
+      required: no
+      description: >
+         An identifier that represents an existing Network instance in the
+         underlying cloud infrastructure. This property is mutually exclusive
+         with all other properties except network_name. This can be used alone
+         or together with network_name to identify an existing network.
+    segmentation_id:
+      type: string
+      required: no
+      description: >
+         A segmentation identifier in the underlying cloud infrastructure.
+         E.g. VLAN ID, GRE tunnel ID, etc..
+    dhcp_enabled:
+      type: boolean
+      required: no
+      default: true
+      description: >
+        Indicates should DHCP service be enabled on the network or not.
+  capabilities:
+    link:
+      type: tosca.capabilities.network.Linkable
+
+tosca.nodes.network.Port:
+  derived_from: tosca.nodes.Root
+  description: >
+    The TOSCA Port node represents a logical entity that associates between
+    Compute and Network normative types. The Port node type effectively
+    represents a single virtual NIC on the Compute node instance.
+  properties:
+    ip_address:
+      type: string
+      required: no
+      description: >
+        Allow the user to set a static IP.
+    order:
+      type: integer
+      required: no
+      default: 0
+      constraints:
+        - greater_or_equal: 0
+      description: >
+        The order of the NIC on the compute instance (e.g. eth2).
+    is_default:
+      type: boolean
+      required: no
+      default: false
+      description: >
+        If is_default=true this port will be used for the default gateway
+        route. Only one port that is associated to single compute node can
+        set as is_default=true.
+    ip_range_start:
+      type: string
+      required: no
+      description: >
+        Defines the starting IP of a range to be allocated for the compute
+        instances that are associated with this Port.
+    ip_range_end:
+      type: string
+      required: no
+      description: >
+        Defines the ending IP of a range to be allocated for the compute
+        instances that are associated with this Port.
+  attributes:
+    ip_address:
+      type: string
+  requirements:
+    - binding:
+        description: >
+          Binding requirement expresses the relationship between Port and
+          Compute nodes. Effectevely it indicates that the Port will be
+          attached to specific Compute node instance
+        capability: tosca.capabilities.network.Bindable
+        relationship: tosca.relationships.network.BindsTo
+    - link:
+        description: >
+          Link requirement expresses the relationship between Port and Network
+          nodes. It indicates which network this port will connect to.
+        capability: tosca.capabilities.network.Linkable
+        relationship: tosca.relationships.network.LinksTo
+
+tosca.nodes.ObjectStorage:
+  derived_from: tosca.nodes.Root
+  description: >
+    The TOSCA ObjectStorage node represents storage that provides the ability
+    to store data as objects (or BLOBs of data) without consideration for the
+    underlying filesystem or devices
+  properties:
+    name:
+      type: string
+      required: yes
+      description: >
+        The logical name of the object store (or container).
+    size:
+      type: scalar-unit.size
+      required: no
+      constraints:
+        - greater_or_equal: 0 GB
+      description: >
+        The requested initial storage size.
+    maxsize:
+      type: scalar-unit.size
+      required: no
+      constraints:
+        - greater_or_equal: 0 GB
+      description: >
+        The requested maximum storage size.
+  capabilities:
+    storage_endpoint:
+      type: tosca.capabilities.Endpoint
+
+##########################################################################
+# Relationship Type.
+# A Relationship Type is a reusable entity that defines the type of one
+# or more relationships between Node Types or Node Templates.
+##########################################################################
+tosca.relationships.Root:
+  description: >
+    The TOSCA root Relationship Type all other TOSCA base Relationship Types
+    derive from.
+  attributes:
+    tosca_id:
+      type: string
+    tosca_name:
+      type: string
+  interfaces:
+    Configure:
+      type: tosca.interfaces.relationship.Configure
+
+tosca.relationships.DependsOn:
+  derived_from: tosca.relationships.Root
+
+tosca.relationships.HostedOn:
+  derived_from: tosca.relationships.Root
+  valid_target_types: [ tosca.capabilities.Container ]
+
+tosca.relationships.ConnectsTo:
+  derived_from: tosca.relationships.Root
+  valid_target_types: [ tosca.capabilities.Endpoint ]
+  credential:
+    type: tosca.datatypes.Credential
+    required: false
+
+tosca.relationships.AttachesTo:
+  derived_from: tosca.relationships.Root
+  valid_target_types: [ tosca.capabilities.Attachment ]
+  properties:
+    location:
+      required: true
+      type: string
+      constraints:
+        - min_length: 1
+    device:
+      required: false
+      type: string
+
+tosca.relationships.network.LinksTo:
+  derived_from: tosca.relationships.DependsOn
+  valid_target_types: [ tosca.capabilities.network.Linkable ]
+
+tosca.relationships.network.BindsTo:
+  derived_from: tosca.relationships.DependsOn
+  valid_target_types: [ tosca.capabilities.network.Bindable ]
+
+##########################################################################
+# Capability Type.
+# A Capability Type is a reusable entity that describes a kind of
+# capability that a Node Type can declare to expose.
+##########################################################################
+tosca.capabilities.Root:
+  description: >
+    The TOSCA root Capability Type all other TOSCA base Capability Types
+    derive from.
+
+tosca.capabilities.Node:
+  derived_from: tosca.capabilities.Root
+
+tosca.capabilities.Container:
+  derived_from: tosca.capabilities.Root
+  properties:
+    num_cpus:
+      required: no
+      type: integer
+      constraints:
+        - greater_or_equal: 1
+    cpu_frequency:
+      required: no
+      type: scalar-unit.frequency
+      constraints:
+        - greater_or_equal: 0.1 GHz
+    disk_size:
+      required: no
+      type: scalar-unit.size
+      constraints:
+        - greater_or_equal: 0 MB
+    mem_size:
+      required: no
+      type: scalar-unit.size
+      constraints:
+        - greater_or_equal: 0 MB
+
+tosca.capabilities.Endpoint:
+  derived_from: tosca.capabilities.Root
+  properties:
+    protocol:
+      type: string
+      default: tcp
+    port:
+      type: tosca.datatypes.network.PortDef
+      required: false
+    secure:
+      type: boolean
+      default: false
+    url_path:
+      type: string
+      required: false
+    port_name:
+      type: string
+      required: false
+    network_name:
+      type: string
+      required: false
+    initiator:
+      type: string
+      default: source
+      constraints:
+        - valid_values: [source, target, peer]
+    ports:
+      type: map
+      required: false
+      constraints:
+        - min_length: 1
+      entry_schema:
+        type: tosca.datatypes.network.PortDef
+  attributes:
+    public_address:
+      type: string
+    private_address:
+      type: string
+
+tosca.capabilities.Endpoint.Admin:
+  derived_from: tosca.capabilities.Endpoint
+  properties:
+    secure: true
+
+tosca.capabilities.Scalable:
+  derived_from: tosca.capabilities.Root
+  properties:
+    min_instances:
+      type: integer
+      required: yes
+      default: 1
+      description: >
+        This property is used to indicate the minimum number of instances
+        that should be created for the associated TOSCA Node Template by
+        a TOSCA orchestrator.
+    max_instances:
+      type: integer
+      required: yes
+      default: 1
+      description: >
+        This property is used to indicate the maximum number of instances
+        that should be created for the associated TOSCA Node Template by
+        a TOSCA orchestrator.
+    default_instances:
+      type: integer
+      required: no
+      description: >
+        An optional property that indicates the requested default number
+        of instances that should be the starting number of instances a
+        TOSCA orchestrator should attempt to allocate.
+        The value for this property MUST be in the range between the values
+        set for min_instances and max_instances properties.
+
+tosca.capabilities.Endpoint.Database:
+  derived_from: tosca.capabilities.Endpoint
+
+tosca.capabilities.Attachment:
+  derived_from: tosca.capabilities.Root
+
+tosca.capabilities.network.Linkable:
+  derived_from: tosca.capabilities.Root
+  description: >
+    A node type that includes the Linkable capability indicates that it can
+    be pointed by tosca.relationships.network.LinksTo relationship type, which
+    represents an association relationship between Port and Network node types.
+
+tosca.capabilities.network.Bindable:
+  derived_from: tosca.capabilities.Root
+  description: >
+    A node type that includes the Bindable capability indicates that it can
+    be pointed by tosca.relationships.network.BindsTo relationship type, which
+    represents a network association relationship between Port and Compute node
+    types.
+
+tosca.capabilities.OperatingSystem:
+  derived_from: tosca.capabilities.Root
+  properties:
+    architecture:
+      required: yes
+      default: x86_64
+      type: string
+      description: >
+        The host Operating System (OS) architecture.
+    type:
+      required: yes
+      type: string
+      description: >
+        The host Operating System (OS) type.
+    distribution:
+      required: no
+      type: string
+      description: >
+        The host Operating System (OS) distribution. Examples of valid values
+        for an “type” of “Linux” would include:
+        debian, fedora, rhel and ubuntu.
+    version:
+      required: no
+      type: string
+      description: >
+        The host Operating System version.
+
+##########################################################################
+ # Interfaces Type.
+ # The Interfaces element describes a list of one or more interface
+ # definitions for a modelable entity (e.g., a Node or Relationship Type)
+ # as defined within the TOSCA Simple Profile specification.
+##########################################################################
+tosca.interfaces.node.lifecycle.Standard:
+  create:
+    description: Standard lifecycle create operation.
+  configure:
+    description: Standard lifecycle configure operation.
+  start:
+    description: Standard lifecycle start operation.
+  stop:
+    description: Standard lifecycle stop operation.
+  delete:
+    description: Standard lifecycle delete operation.
+
+tosca.interfaces.relationship.Configure:
+  pre_configure_source:
+    description: Operation to pre-configure the source endpoint.
+  pre_configure_target:
+    description: Operation to pre-configure the target endpoint.
+  post_configure_source:
+    description: Operation to post-configure the source endpoint.
+  post_configure_target:
+    description: Operation to post-configure the target endpoint.
+  add_target:
+    description: Operation to add a target node.
+  remove_target:
+    description: Operation to remove a target node.
+  add_source: >
+    description: Operation to notify the target node of a source node which
+    is now available via a relationship.
+    description:
+  target_changed: >
+    description: Operation to notify source some property or attribute of the
+    target changed
+
+##########################################################################
+ # Data Type.
+ # A Datatype is a complex data type declaration which contains other
+ # complex or simple data types.
+##########################################################################
+tosca.datatypes.network.NetworkInfo:
+  properties:
+    network_name:
+      type: string
+    network_id:
+      type: string
+    addresses:
+      type: list
+      entry_schema:
+        type: string
+
+tosca.datatypes.network.PortInfo:
+  properties:
+    port_name:
+      type: string
+    port_id:
+      type: string
+    network_id:
+      type: string
+    mac_address:
+      type: string
+    addresses:
+      type: list
+      entry_schema:
+        type: string
+
+tosca.datatypes.network.PortDef:
+  type: integer
+  constraints:
+    - in_range: [ 1, 65535 ]
+
+tosca.datatypes.network.PortSpec:
+  properties:
+    protocol:
+      type: string
+      required: true
+      default: tcp
+      constraints:
+        - valid_values: [ udp, tcp, igmp ]
+    target:
+      type: list
+      entry_schema:
+        type: PortDef
+    target_range:
+      type: range
+      constraints:
+        - in_range: [ 1, 65535 ]
+    source:
+      type: list
+      entry_schema:
+        type: PortDef
+    source_range:
+      type: range
+      constraints:
+        - in_range: [ 1, 65535 ]
+
+tosca.datatypes.Credential:
+  properties:
+    protocol:
+      type: string
+    token_type:
+      type: string
+    token:
+      type: string
+    keys:
+      type: map
+      entry_schema:
+        type: string
+    user:
+      type: string
+      required: false
+
+##########################################################################
+ # Artifact Type.
+ # An Artifact Type is a reusable entity that defines the type of one or more
+ # files which Node Types or Node Templates can have dependent relationships
+ # and used during operations such as during installation or deployment.
+##########################################################################
+tosca.artifacts.Root:
+  description: >
+    The TOSCA Artifact Type all other TOSCA Artifact Types derive from
+  properties:
+    version: version
+
+tosca.artifacts.File:
+  derived_from: tosca.artifacts.Root
+
+tosca.artifacts.Deployment:
+  derived_from: tosca.artifacts.Root
+  description: TOSCA base type for deployment artifacts
+
+tosca.artifacts.Deployment.Image:
+  derived_from: tosca.artifacts.Deployment
+
+tosca.artifacts.Deployment.Image.VM:
+  derived_from: tosca.artifacts.Deployment.Image
+
+tosca.artifacts.Implementation:
+  derived_from: tosca.artifacts.Root
+  description: TOSCA base type for implementation artifacts
+
+tosca.artifacts.impl.Bash:
+  derived_from: tosca.artifacts.Implementation
+  description: Script artifact for the Unix Bash shell
+  mime_type: application/x-sh
+  file_ext: [ sh ]
+
+tosca.artifacts.impl.Python:
+  derived_from: tosca.artifacts.Implementation
+  description: Artifact for the interpreted Python language
+  mime_type: application/x-python
+  file_ext: [ py ]
+
+tosca.artifacts.Deployment.Image.Container.Docker:
+  derived_from: tosca.artifacts.Deployment.Image
+  description: Docker container image
+
+tosca.artifacts.Deployment.Image.VM.ISO:
+  derived_from: tosca.artifacts.Deployment.Image
+  description: Virtual Machine (VM) image in ISO disk format
+  mime_type: application/octet-stream
+  file_ext: [ iso ]
+
+tosca.artifacts.Deployment.Image.VM.QCOW2:
+  derived_from: tosca.artifacts.Deployment.Image
+  description: Virtual Machine (VM) image in QCOW v2 standard disk format
+  mime_type: application/octet-stream
+  file_ext: [ qcow2 ]
diff --git a/xos/tosca/destroy.py b/xos/tosca/destroy.py
new file mode 100644
index 0000000..6fa9101
--- /dev/null
+++ b/xos/tosca/destroy.py
@@ -0,0 +1,31 @@
+import os
+import sys
+
+# add the parent directory to sys.path
+import os,sys,inspect
+currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
+parentdir = os.path.dirname(currentdir)
+sys.path.append(parentdir)
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
+import django
+django.setup()
+
+from core.models import User
+from tosca.engine import XOSTosca
+
+def main():
+    if len(sys.argv)<3:
+        print "Syntax: destroy.py <username> <yaml-template-name>"
+        sys.exit(-1)
+
+    username = sys.argv[1]
+    template_name = sys.argv[2]
+
+    u = User.objects.get(email=username)
+
+    xt = XOSTosca(file(template_name).read(), parent_dir=currentdir, log_to_console=True)
+    xt.destroy(u)
+
+if __name__=="__main__":
+    main()
diff --git a/xos/tosca/doctemplates/html/node_type.html b/xos/tosca/doctemplates/html/node_type.html
new file mode 100644
index 0000000..95e8b7b
--- /dev/null
+++ b/xos/tosca/doctemplates/html/node_type.html
@@ -0,0 +1,46 @@
+<hr>
+<h2 id="{{ node_type.node_type_name }}">{{ node_type.node_type_name }}</h2>
+<blockquote>
+
+<h3>Description:</h3>
+{% if node_type.description %}
+  <blockquote>
+  {{ node_type.description }}
+  </blockquote>
+{% endif %}
+
+<h3>Capabilities:</h3>
+{% if node_type.capabilities %}
+  <blockquote>
+  <table class="properties">
+  <tr><th>name</th><th>type</th></tr>
+  {% for capname,cap in node_type.capabilities.iteritems() %}
+     <tr><td>{{ capname }}</td><td>{{ cap.type }}</td></tr>
+  {% endfor %}
+  </table>
+  </blockquote>
+{% endif %}
+
+<h3>Properties:</h3>
+{% if node_type.properties %}
+  <blockquote>
+  <table class="properties">
+  <tr><th>name</th><th>required</th><th>type</th><th>default</th></tr>
+  {% for propname,prop in node_type.properties.iteritems() %}
+     <tr><td>{{ propname }}</td>
+         <td>{{ prop.required }}</td>
+         <td>{{ prop.type }}</td>
+         <td>{{ prop.default }}</td>
+     </tr>
+     {% if prop.description %}
+     <tr><td colspan=4 class="helptext" style="apadding-left: 30px;">{{ prop.description }}</td></tr>
+     {% endif %}
+  {% endfor %}
+  </table>
+  </blockquote>
+{% endif %}
+
+</blockquote>
+
+
+
diff --git a/xos/tosca/doctemplates/html/toscadoctemplate.html b/xos/tosca/doctemplates/html/toscadoctemplate.html
new file mode 100644
index 0000000..8568d33
--- /dev/null
+++ b/xos/tosca/doctemplates/html/toscadoctemplate.html
@@ -0,0 +1,80 @@
+<html><head>
+<title>XOS TOSCA Reference</title>
+
+<style>
+.properties {
+  border-collapse: collapse;
+}
+.properties td, .properties th {
+  border: 1px solid black;
+  padding: 3px 7px 2px 7px;
+}
+.properties th {
+  font-size: 1.1em;
+  padding-top: 5px;
+  padding-bottom: 4px;
+  oldbackground-color: #A7C942;
+  background-color: #2d6ca2;
+  color: #ffffff;
+}
+.helptext {
+  padding-left: 30px !important;
+  color: rgb(153, 153, 153);
+}
+</style>
+
+</head>
+<body>
+
+<h1>XOS TOSCA Reference</h1>
+
+<p>This documentation is autogenerated from the XOS Tosca custom_types
+specification (xos/tosca/custom_types/xos.m4).
+
+Table of Contents:
+<ul>
+<li>Node Types
+<ul>
+{% for node_type in node_types %}
+  {% if node_type.node_type_kind == "node" %}
+    <li><a href="#{{ node_type.node_type_name }}">{{ node_type.node_type_name }}</a></li>
+  {% endif %}
+{% endfor %}
+</li>
+</ul>
+<li><a href="#xos_relationships">Relationships</a></li>
+<li><a href="#xos_capabilities">Capabilities</a></li>
+</ul>
+
+{% for node_type in node_types %}
+  {% if node_type.node_type_kind == "node" %}
+    {% include 'node_type.html' %}
+  {% endif %}
+{% endfor %}
+
+<h3 id="xos_relationships">XOS Relationships</h3>
+<blockquote>
+<table class="properties">
+<tr><th>name</th><th>target_types</th></tr>
+{% for node_type in node_types %}
+  {% if node_type.node_type_kind == "relationship" %}
+      <tr><td>{{ node_type.node_type_name }}</td><td>{{ node_type.valid_target_types|join(', ') }}</td></tr>
+  {% endif %}
+{% endfor %}
+</table>
+</blockquote>
+
+<h3 id="xos_capabilities">XOS Capabilities</h3>
+<blockquote>
+<table class="properties">
+<tr><th>name</th></tr>
+{% for node_type in node_types %}
+  {% if node_type.node_type_kind == "capability" %}
+      <tr><td>{{ node_type.node_type_name }}</td></tr>
+  {% endif %}
+{% endfor %}
+</table>
+</blockquote>
+
+</body>
+</html>
diff --git a/xos/tosca/engine.py b/xos/tosca/engine.py
new file mode 100644
index 0000000..efce829
--- /dev/null
+++ b/xos/tosca/engine.py
@@ -0,0 +1,182 @@
+import os
+import pdb
+import sys
+import tempfile
+import traceback
+
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from core.models import Slice,Instance,User,Flavor,Node,Image
+from nodeselect import XOSNodeSelector
+from imageselect import XOSImageSelector
+
+import resources
+
+class XOSTosca(object):
+    def __init__(self, tosca_yaml, parent_dir=None, log_to_console = False):
+        # TOSCA will look for imports using a relative path from where the
+        # template file is located, so we have to put the template file
+        # in a specific place.
+        if not parent_dir:
+            parent_dir = os.getcwd()
+
+        tmp_pathname = None
+        try:
+            (tmp_handle, tmp_pathname) = tempfile.mkstemp(dir=parent_dir)
+            os.write(tmp_handle, tosca_yaml)
+            os.close(tmp_handle)
+
+            self.template = ToscaTemplate(tmp_pathname)
+        except:
+            traceback.print_exc()
+            raise
+        finally:
+            if tmp_pathname:
+                os.remove(tmp_pathname)
+
+        self.log_to_console = log_to_console
+        self.log_msgs = []
+
+        self.compute_dependencies()
+
+        self.deferred_sync = []
+
+        self.ordered_nodetemplates = []
+        self.ordered_names = self.topsort_dependencies()
+        self.log("ordered_names: %s" % self.ordered_names)
+        for name in self.ordered_names:
+            if name in self.nodetemplates_by_name:
+                self.ordered_nodetemplates.append(self.nodetemplates_by_name[name])
+
+        #pdb.set_trace()
+
+    def log(self, msg):
+        if self.log_to_console:
+            print msg
+        self.log_msgs.append(msg)
+
+    def compute_dependencies(self):
+        nodetemplates_by_name = {}
+        for nodetemplate in self.template.nodetemplates:
+            nodetemplates_by_name[nodetemplate.name] = nodetemplate
+
+        self.nodetemplates_by_name = nodetemplates_by_name
+
+        for nodetemplate in self.template.nodetemplates:
+            nodetemplate.dependencies = []
+            nodetemplate.dependencies_names = []
+            for reqs in nodetemplate.requirements:
+                for (k,v) in reqs.items():
+                    name = v["node"]
+                    if (name in nodetemplates_by_name):
+                        nodetemplate.dependencies.append(nodetemplates_by_name[name])
+                        nodetemplate.dependencies_names.append(name)
+
+                    # go another level deep, as our requirements can have requirements...
+                    for sd_req in v.get("requirements",[]):
+                        for (sd_req_k, sd_req_v) in sd_req.items():
+                            name = sd_req_v["node"]
+                            if (name in nodetemplates_by_name):
+                                nodetemplate.dependencies.append(nodetemplates_by_name[name])
+                                nodetemplate.dependencies_names.append(name)
+
+
+    def topsort_dependencies(self):
+        # stolen from observer
+        g = self.nodetemplates_by_name
+
+	# Get set of all nodes, including those without outgoing edges
+	keys = set(g.keys())
+	values = set({})
+	for v in g.values():
+		values=values | set(v.dependencies_names)
+
+	all_nodes=list(keys|values)
+        steps = all_nodes
+
+	# Final order
+	order = []
+
+	# DFS stack, not using recursion
+	stack = []
+
+	# Unmarked set
+	unmarked = all_nodes
+
+	# visiting = [] - skip, don't expect 1000s of nodes, |E|/|V| is small
+
+	while unmarked:
+		stack.insert(0,unmarked[0]) # push first unmarked
+
+		while (stack):
+			n = stack[0]
+			add = True
+			try:
+				for m in g[n].dependencies_names:
+					if (m in unmarked):
+					    add = False
+					    stack.insert(0,m)
+			except KeyError:
+				pass
+			if (add):
+				if (n in steps and n not in order):
+					order.append(n)
+				item = stack.pop(0)
+				try:
+					unmarked.remove(item)
+				except ValueError:
+					pass
+
+	noorder = list(set(steps) - set(order))
+	return order + noorder
+
+    def execute(self, user):
+        for nodetemplate in self.ordered_nodetemplates:
+            self.execute_nodetemplate(user, nodetemplate)
+
+        for obj in self.deferred_sync:
+            self.log("Saving deferred sync obj %s" % obj)
+            obj.no_sync = False
+            obj.save()
+
+    def execute_nodetemplate(self, user, nodetemplate):
+        if nodetemplate.type in resources.resources:
+            cls = resources.resources[nodetemplate.type]
+            #print "work on", cls.__name__, nodetemplate.name
+            obj = cls(user, nodetemplate, self)
+            obj.create_or_update()
+            self.deferred_sync = self.deferred_sync + obj.deferred_sync
+
+    def destroy(self, user):
+        nodetemplates = self.ordered_nodetemplates
+        models = []
+        for nodetemplate in nodetemplates:
+            if nodetemplate.type in resources.resources:
+                cls = resources.resources[nodetemplate.type]
+                obj = cls(user, nodetemplate, self)
+                for model in obj.get_existing_objs():
+                    models.append( (obj, model) )
+        models.reverse()
+        for (resource,model) in models:
+            resource.delete(model)
+
+    def name_to_xos_class(self, user, name):
+        nt = self.nodetemplates_by_name.get(name)
+        if not nt:
+            raise Exception("failed to find nodetemplate %s" % name)
+
+        cls = resources.resources.get(nt.type)
+        if not cls:
+            raise Exception("nodetemplate %s's type does not resolve to a known resource type" % name)
+
+        return (nt, cls, cls.xos_model)
+
+    def name_to_xos_model(self, user, name):
+        (nt, cls, model_class) = self.name_to_xos_class(user, name)
+        obj = cls(user, nt, self)
+        existing_objs = obj.get_existing_objs()
+        if not existing_objs:
+            raise Exception("failed to find xos %s %s" % (cls.__name__, name))
+        return existing_objs[0]
+
diff --git a/xos/tosca/flavorselect.py b/xos/tosca/flavorselect.py
new file mode 100644
index 0000000..cab8e56
--- /dev/null
+++ b/xos/tosca/flavorselect.py
@@ -0,0 +1,39 @@
+import os
+import sys
+
+from core.models import Slice,Instance,User,Flavor,Node,Image
+
+class XOSFlavorSelector(object):
+    def __init__(self, user, mem_size=None, num_cpus=None, disk_size=None):
+        self.user = user
+        self.mem_size = self.get_mb(mem_size)
+        self.num_cpus = int(num_cpus)
+        self.disk_size = self.get_gb(disk_size)
+
+    def get_gb(self, s):
+        if "GB" in s:
+            return int(s.split("GB")[0].strip())
+        if "MB" in s:
+            return int(s.split("MB")[0].strip())/1024
+        return int(s)
+
+    def get_mb(self, s):
+        if "GB" in s:
+            return int(s.split("GB")[0].strip())*1024
+        if "MB" in s:
+            return int(s.split("MB")[0].strip())
+        return int(s)
+
+    def get_flavor(self):
+        flavor = "m1.tiny"
+        if (self.mem_size>512) or (self.disk_size>1):
+            flavor = "m1.small"
+        if (self.mem_size>2048) or (self.disk_size>20) or (self.num_cpus>1):
+            flavor = "m1.medium"
+        if (self.mem_size>4096) or (self.disk_size>40) or (self.num_cpus>2):
+            flavor = "m1.large"
+        if (self.mem_size>8192) or (self.disk_size>80) or (self.num_cpus>4):
+            flavor = "m1.xlarge"
+
+        return Flavor.objects.get(name=flavor)
+
diff --git a/xos/tosca/imageselect.py b/xos/tosca/imageselect.py
new file mode 100644
index 0000000..0cf4da8
--- /dev/null
+++ b/xos/tosca/imageselect.py
@@ -0,0 +1,33 @@
+import os
+import sys
+
+from core.models import User,Image
+
+class XOSImageSelector(object):
+    def __init__(self, user, distribution=None, type=None, architecture=None, version=None):
+        self.user = user
+
+    def get_allowed_images(self):
+        # TODO: logic to get images that the user can use
+        nodes = Image.objects.all()
+        return nodes
+
+    def get_image(self):
+        images = self.get_allowed_images()
+
+        # TODO: pick image based on parameters
+
+        found_imgs=images.filter(name="Ubuntu 14.04 LTS")   # portal
+        if found_imgs:
+            return found_imgs[0]
+
+        found_imgs=images.filter(name="Ubuntu-14.04-LTS")    # demo
+        if found_imgs:
+            return found_imgs[0]
+
+        found_imgs=images.filter(name="trusty-server-multi-nic")    # demo
+        if found_imgs:
+            return found_imgs[0]
+
+        raise Exception("Failed to find an acceptable image")
+
diff --git a/xos/tosca/install_tosca.sh b/xos/tosca/install_tosca.sh
new file mode 100755
index 0000000..f212abf
--- /dev/null
+++ b/xos/tosca/install_tosca.sh
@@ -0,0 +1,12 @@
+#! /bin/bash
+
+rm -rf /tmp/tosca_install
+mkdir /tmp/tosca_install
+cd /tmp/tosca_install
+git clone https://github.com/openstack/heat-translator.git
+cd heat-translator
+git reset --hard a951b93c16e54046ed2d233d814860181c772e30
+rm -rf /opt/tosca
+mkdir /opt/tosca
+cp -a /tmp/tosca_install/heat-translator/translator /opt/tosca/
+echo > /opt/tosca/translator/__init__.py
diff --git a/xos/tosca/makedocs.py b/xos/tosca/makedocs.py
new file mode 100644
index 0000000..2db6db8
--- /dev/null
+++ b/xos/tosca/makedocs.py
@@ -0,0 +1,62 @@
+import jinja2
+import os
+import sys
+import yaml
+import pdb
+
+# add the parent directory to sys.path
+import os,sys,inspect
+currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
+parentdir = os.path.dirname(currentdir)
+sys.path.append(parentdir)
+
+"""
+{'derived_from': 'tosca.nodes.Root', 'capabilities': {'scalable': {'type': 'tosca.capabilities.Scalable'},
+'service': {'type': 'tosca.capabilities.xos.Service'}}, 'properties': {'icon_url': {'required': False,
+'type': 'string'}, 'public_key': {'required': False, 'type': 'string'}, 'kind': {'default': 'generic',
+'type': 'string'}, 'published': {'default': True, 'type': 'boolean'}, 'view_url': {'required': False, 'type': 'string'}, 'enabled': {'default': True, 'type': 'boolean'}, 'versionNumber': {'required': False, 'type': 'string'}}}
+"""
+
+class ToscaDocumenter(object):
+    def __init__(self, fn="./custom_types/xos.yaml", templatedir="./doctemplates/html", templatename="toscadoctemplate.html", destfn="tosca_reference.html"):
+        self.env = jinja2.Environment(loader=jinja2.FileSystemLoader(templatedir))
+
+        self.node_types = {}
+        self.root_types = yaml.load(file("definitions/TOSCA_definition_1_0.yaml").read())
+        for x in self.root_types.keys():
+            if x in ["tosca.nodes.Compute", "tosca.nodes.network.Network"]:
+                self.node_types[x] = self.root_types[x]
+
+        self.custom_types = yaml.load(file(fn).read())
+        self.node_types.update(self.custom_types.get("node_types"))
+
+        self.destfn = destfn
+        self.templatename = templatename
+
+    def run(self):
+        node_types=[]
+        for k in sorted(self.node_types.keys()):
+            nt = self.node_types[k]
+            nt["node_type_name"] = k
+
+            derived_from = nt.get("derived_from","")
+
+            if derived_from.startswith("tosca.nodes"):
+                nt["node_type_kind"] = "node"
+            elif derived_from.startswith("tosca.capabilities"):
+                nt["node_type_kind"] = "capability"
+            elif derived_from.startswith("tosca.relationships"):
+                nt["node_type_kind"] = "relationship"
+
+            node_types.append(nt)
+
+        template = self.env.get_template(self.templatename)
+
+        self.destf = open(self.destfn,"w")
+        self.destf.write(template.render(node_types=node_types))
+
+def main():
+    ToscaDocumenter().run()
+
+if __name__=="__main__":
+    main()
diff --git a/xos/tosca/nodeselect.py b/xos/tosca/nodeselect.py
new file mode 100644
index 0000000..ce4888f
--- /dev/null
+++ b/xos/tosca/nodeselect.py
@@ -0,0 +1,26 @@
+import os
+import sys
+
+from core.models import Slice,Instance,User,Flavor,Node,Image
+
+class XOSNodeSelector(object):
+    def __init__(self, user, mem_size=None, num_cpus=None, disk_size=None, hostname = None):
+        self.user = user
+        self.hostname = None
+
+    def get_allowed_nodes(self):
+        # TODO: logic to get nodes that the user can use
+        nodes = Node.objects.all()
+
+        if self.hostname:
+            nodes = nodes.filter(name = self.hostname)
+
+        return nodes
+
+    def get_nodes(self, quantity):
+        nodes = self.get_allowed_nodes()
+        # TODO: filter out any nonfunctional nodes
+        # sort by fewest number of instances
+        nodes = sorted(nodes, key=lambda node: node.instances.all().count())
+        return nodes[:quantity]
+
diff --git a/xos/tosca/resources/__init__.py b/xos/tosca/resources/__init__.py
new file mode 100644
index 0000000..9be1591
--- /dev/null
+++ b/xos/tosca/resources/__init__.py
@@ -0,0 +1,42 @@
+from xosresource import XOSResource
+from django.conf.urls import patterns, url
+from rest_framework.routers import DefaultRouter
+import os, sys
+import inspect
+import importlib
+
+# XXX based on core/dashboard/views/__init__.py
+
+# Find all modules in the current directory that have descendents of the XOSResource
+# object, and add them as globals to this module. Also, build up a list of urls
+# based on the "url" field of the view classes.
+
+resources = {}
+
+sys_path_save = sys.path
+try:
+    # __import__() and importlib.import_module() both import modules from
+    # sys.path. So we make sure that the path where we can find the views is
+    # the first thing in sys.path.
+    view_dir = os.path.dirname(os.path.abspath(__file__))
+    sys.path = [view_dir] + sys.path
+    view_urls = []
+    for fn in os.listdir(view_dir):
+        pathname = os.path.join(view_dir,fn)
+        if os.path.isfile(pathname) and fn.endswith(".py") and (fn!="__init__.py"):
+            module = __import__(fn[:-3])
+            for classname in dir(module):
+                c = getattr(module, classname, None)
+
+                if inspect.isclass(c) and (getattr(c,"xos_base_class",None)=="XOSResource") and (classname not in globals()):
+                    provides = getattr(c, "provides", None)
+                    if provides:
+                        globals()[classname] = c
+                        if isinstance(provides, basestring):
+                            resources[provides] = c
+                        else:
+                            # allow provides= to be a list
+                            for p in provides:
+                                resources[p] = c
+finally:
+    sys.path = sys_path_save
diff --git a/xos/tosca/resources/addresspool.py b/xos/tosca/resources/addresspool.py
new file mode 100644
index 0000000..8cd3e83
--- /dev/null
+++ b/xos/tosca/resources/addresspool.py
@@ -0,0 +1,64 @@
+import os
+import pdb
+import socket
+import sys
+import struct
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from core.models import AddressPool
+
+from xosresource import XOSResource
+
+class XOSAddressPool(XOSResource):
+    provides = "tosca.nodes.AddressPool"
+    xos_model = AddressPool
+    copyin_props = ["addresses", "gateway_ip", "gateway_mac"]
+
+    def expand_cidr(self, cidr):
+        (network, bits) = cidr.split("/")
+        network=network.strip()
+        bits=int(bits.strip())
+
+        dest = []
+
+        netmask = (~(pow(2,32-bits)-1) & 0xFFFFFFFF)
+
+        count = pow(2, 32-bits)
+        for i in range(2, count-1):
+            ip = struct.unpack("!L", socket.inet_aton(network))[0]
+            ip = ip & netmask | i
+            dest.append( socket.inet_ntoa(struct.pack("!L", ip)) )
+
+        return (dest, bits)
+
+    def get_xos_args(self):
+        args = super(XOSAddressPool, self).get_xos_args()
+
+        if "addresses" in args:
+            addr = args["addresses"]
+            if "," in addr:
+                raise Exception("Only one cidr per AddressPool")
+            if not "/" in addr:
+                raise Exception("AddressPool addresses must be a cidr")
+            (cidr_addrs, cidr_netbits) = self.expand_cidr(addr)
+            args["addresses"] = " ".join(cidr_addrs)
+            args["cidr"] = addr
+
+#        if "addresses" in args:
+#            dest = []
+#            for addr in args["addresses"].split():
+#                addr=addr.strip()
+#                if "/" in addr:
+#                    (cidr_addrs, cidr_netbits) = self.expand_cidr(addr)
+#                    dest.extend(cidr_addrs)
+#                else:
+#                    dest.append(addr)
+#            args["addresses"] = " ".join(dest)
+
+        return args
+
+
+
+
diff --git a/xos/tosca/resources/cdnprefix.py b/xos/tosca/resources/cdnprefix.py
new file mode 100644
index 0000000..8daf7fb
--- /dev/null
+++ b/xos/tosca/resources/cdnprefix.py
@@ -0,0 +1,33 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from services.hpc.models import CDNPrefix, ContentProvider
+
+from xosresource import XOSResource
+
+class XOSCDNPrefix(XOSResource):
+    provides = "tosca.nodes.CDNPrefix"
+    xos_model = CDNPrefix
+    name_field = "prefix"
+    copyin_props = []
+
+    def get_xos_args(self):
+        args = {"prefix": self.obj_name}
+
+        cp_name = self.get_requirement("tosca.relationships.MemberOfContentProvider")
+        if cp_name:
+            args["contentProvider"] = self.get_xos_object(ContentProvider, name=cp_name)
+
+        default_os = self.get_requirement("tosca.relationships.DefaultOriginServer")
+        if default_os:
+             args["defaultOriginServer"] = self.engine.name_to_xos_model(self.user, default_os)
+
+        return args
+
+    def can_delete(self, obj):
+        return super(XOSCDNPrefix, self).can_delete(obj)
+
diff --git a/xos/tosca/resources/cdnservice.py b/xos/tosca/resources/cdnservice.py
new file mode 100644
index 0000000..4082938
--- /dev/null
+++ b/xos/tosca/resources/cdnservice.py
@@ -0,0 +1,16 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from services.hpc.models import HpcService
+
+from service import XOSService
+
+class XOSCdnService(XOSService):
+    provides = "tosca.nodes.CDNService"
+    xos_model = HpcService
+    copyin_props = ["view_url", "icon_url"]
+
diff --git a/xos/tosca/resources/compute.py b/xos/tosca/resources/compute.py
new file mode 100644
index 0000000..2af010a
--- /dev/null
+++ b/xos/tosca/resources/compute.py
@@ -0,0 +1,130 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from core.models import Slice,Instance,User,Flavor,Node,Image
+from nodeselect import XOSNodeSelector
+from imageselect import XOSImageSelector
+from flavorselect import XOSFlavorSelector
+
+from xosresource import XOSResource
+
+class XOSCompute(XOSResource):
+    provides = ["tosca.nodes.Compute", "tosca.nodes.Compute.Container"]
+    xos_model = Instance
+
+    def select_compute_node(self, user, v, hostname=None):
+        mem_size = v.get_property_value("mem_size")
+        num_cpus = v.get_property_value("num_cpus")
+        disk_size = v.get_property_value("disk_size")
+
+        flavor = XOSFlavorSelector(user, mem_size=mem_size, num_cpus=num_cpus, disk_size=disk_size).get_flavor()
+
+        compute_node = XOSNodeSelector(user, mem_size=mem_size, num_cpus=num_cpus, disk_size=disk_size, hostname=hostname).get_nodes(1)[0]
+
+        return (compute_node, flavor)
+
+    def select_image(self, user, v):
+        distribution = v.get_property_value("distribution")
+        version = v.get_property_value("version")
+        type = v.get_property_value("type")
+        architecture = v.get_property_value("architecture")
+
+        return XOSImageSelector(user, distribution=distribution, version=version, type=type, architecture=architecture).get_image()
+
+    def get_xos_args(self, name=None, index=None):
+        nodetemplate = self.nodetemplate
+
+        if not name:
+            name = self.obj_name
+
+        args = {"name": name}
+
+        host=None
+        flavor=None
+        image=None
+
+        sliceName = self.get_requirement("tosca.relationships.MemberOfSlice", throw_exception=True)
+        slice = self.get_xos_object(Slice, name=sliceName)
+
+        # locate it one the same host as some other instance
+        colocate_host = None
+        colocate_instance_name = self.get_requirement("tosca.relationships.SameHost")
+        if index is not None:
+            colocate_instance_name = "%s-%d" % (colocate_instance_name, index)
+        colocate_instances = Instance.objects.filter(name=colocate_instance_name)
+        if colocate_instances:
+            colocate_host = colocate_instances[0].node.name
+            self.info("colocating on %s" % colocate_host)
+
+        imageName = self.get_requirement("tosca.relationships.UsesImage", throw_exception=False)
+        if imageName:
+            image = self.get_xos_object(Image, name=imageName)
+
+        capabilities = nodetemplate.get_capabilities()
+        for (k,v) in capabilities.items():
+            if (k=="host") and (not host):
+                (compute_node, flavor) = self.select_compute_node(self.user, v, hostname=colocate_host)
+            elif (k=="os") and (not image):
+                image = self.select_image(self.user, v)
+
+        if not compute_node:
+            raise Exception("Failed to pick a host")
+        if not image:
+            raise Exception("Failed to pick an image")
+        if not flavor:
+            raise Exception("Failed to pick a flavor")
+
+        args["image"] = image
+        args["slice"] = slice
+        args["flavor"] = flavor
+        args["node"] = compute_node
+        args["deployment"] = compute_node.site_deployment.deployment
+
+        if nodetemplate.type == "tosca.nodes.Compute.Container":
+            args["isolation"] = "container"
+
+        return args
+
+    def create(self, name = None, index = None):
+        xos_args = self.get_xos_args(name=name, index=index)
+        instance = Instance(**xos_args)
+        instance.caller = self.user
+        instance.no_sync = True
+        instance.save()
+        self.deferred_sync.append(instance)
+
+        self.info("Created Instance '%s' on node '%s' using flavor '%s' and image '%s'" %
+                  (str(instance), str(instance.node), str(instance.flavor), str(instance.image)))
+
+    def create_or_update(self):
+        scalable = self.get_scalable()
+        if scalable:
+            default_instances = scalable.get("default_instances",1)
+            for i in range(0, default_instances):
+                name = "%s-%d" % (self.obj_name, i)
+                existing_instances = Instance.objects.filter(name=name)
+                if existing_instances:
+                    self.info("%s %s already exists" % (self.xos_model.__name__, name))
+                    self.update(existing_instances[0])
+                else:
+                    self.create(name, index=i)
+        else:
+            super(XOSCompute,self).create_or_update()
+
+    def get_existing_objs(self):
+        scalable = self.get_scalable()
+        if scalable:
+            existing_instances = []
+            max_instances = scalable.get("max_instances",1)
+            for i in range(0, max_instances):
+                name = "%s-%d" % (self.obj_name, i)
+                existing_instances = existing_instances + list(Instance.objects.filter(name=name))
+            return existing_instances
+        else:
+            return super(XOSCompute,self).get_existing_objs()
+
+
diff --git a/xos/tosca/resources/contentprovider.py b/xos/tosca/resources/contentprovider.py
new file mode 100644
index 0000000..66742ea
--- /dev/null
+++ b/xos/tosca/resources/contentprovider.py
@@ -0,0 +1,28 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from services.hpc.models import ContentProvider, ServiceProvider
+
+from xosresource import XOSResource
+
+class XOSContentProvider(XOSResource):
+    provides = "tosca.nodes.ContentProvider"
+    xos_model = ContentProvider
+    copyin_props = []
+
+    def get_xos_args(self):
+        sp_name = self.get_requirement("tosca.relationships.MemberOfServiceProvider", throw_exception=True)
+        sp = self.get_xos_object(ServiceProvider, name=sp_name)
+        return {"name": self.obj_name,
+                "serviceProvider": sp}
+
+    def can_delete(self, obj):
+        if obj.cdnprefix_set.exists():
+            self.info("%s %s has active CDN prefixes; skipping delete" % (self.xos_model.__class__, obj.name))
+            return False
+        return super(XOSContentProvider, self).can_delete(obj)
+
diff --git a/xos/tosca/resources/controller.py b/xos/tosca/resources/controller.py
new file mode 100644
index 0000000..2aa208c
--- /dev/null
+++ b/xos/tosca/resources/controller.py
@@ -0,0 +1,54 @@
+# note: this module named xossite.py instead of site.py due to conflict with
+#    /usr/lib/python2.7/site.py
+
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from core.models import User,Controller,Deployment
+
+from xosresource import XOSResource
+
+class XOSController(XOSResource):
+    provides = "tosca.nodes.Controller"
+    xos_model = Controller
+    copyin_props = ["backend_type", "version", "auth_url", "admin_user", "admin_password", "admin_tenant", "domain", "rabbit_host", "rabbit_user", "rabbit_password"]
+
+    def get_xos_args(self):
+        args = super(XOSController, self).get_xos_args()
+
+        deployment_name = self.get_requirement("tosca.relationships.ControllerDeployment")
+        if deployment_name:
+            args["deployment"] = self.get_xos_object(Deployment, name=deployment_name)
+
+        return args
+
+    def create(self):
+        xos_args = self.get_xos_args()
+
+        if not xos_args.get("deployment",None):
+            raise Exception("Controller must have a deployment")
+
+        controller = Controller(**xos_args)
+        controller.caller = self.user
+        controller.save()
+
+        self.info("Created Controller '%s'" % (str(controller), ))
+
+        self.postprocess(controller)
+
+    def delete(self, obj):
+        if obj.controllersite.exists():
+            self.info("Controller %s has active sites; skipping delete" % obj.name)
+            return
+        for sd in obj.sitedeployments.all():
+            if sd.nodes.exists():
+                self.info("Controller %s has active nodes; skipping delete" % obj.name)
+                return
+        super(XOSController, self).delete(obj)
+
+
+
diff --git a/xos/tosca/resources/dashboardview.py b/xos/tosca/resources/dashboardview.py
new file mode 100644
index 0000000..3bce58d
--- /dev/null
+++ b/xos/tosca/resources/dashboardview.py
@@ -0,0 +1,31 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from core.models import DashboardView, Site, Deployment, SiteDeployment
+
+from xosresource import XOSResource
+
+class XOSDashboardView(XOSResource):
+    provides = "tosca.nodes.DashboardView"
+    xos_model = DashboardView
+    copyin_props = ["url","enabled"]
+
+    def get_xos_args(self):
+        return super(XOSDashboardView, self).get_xos_args()
+
+    def postprocess(self, obj):
+        for deployment_name in self.get_requirements("tosca.relationships.SupportsDeployment"):
+            deployment = self.get_xos_object(Deployment, deployment_name)
+            if not deployment in obj.deployments.all():
+                print "attaching dashboardview %s to deployment %s" % (obj, deployment)
+                obj.deployments.add(deployment)
+                obj.save()
+
+    def can_delete(self, obj):
+        return super(XOSDashboardView, self).can_delete(obj)
+
+
diff --git a/xos/tosca/resources/deployment.py b/xos/tosca/resources/deployment.py
new file mode 100644
index 0000000..e5ab4b1
--- /dev/null
+++ b/xos/tosca/resources/deployment.py
@@ -0,0 +1,75 @@
+# note: this module named xossite.py instead of site.py due to conflict with
+#    /usr/lib/python2.7/site.py
+
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from core.models import User,Deployment,DeploymentRole,DeploymentPrivilege,Image,ImageDeployments,Flavor
+
+from xosresource import XOSResource
+
+class XOSDeployment(XOSResource):
+    provides = "tosca.nodes.Deployment"
+    xos_model = Deployment
+    copyin_props = ["accessControl"]
+
+    def get_xos_args(self):
+        args = super(XOSDeployment, self).get_xos_args()
+
+        return args
+
+    def postprocess(self, obj):
+        for imageName in self.get_requirements("tosca.relationships.SupportsImage"):
+            image = self.get_xos_object(Image, name=imageName)
+            imageDeps = ImageDeployments.objects.filter(deployment=obj, image=image)
+            if not imageDeps:
+                self.info("Attached Image %s to Deployment %s" % (image, obj))
+                imageDep = ImageDeployments(deployment=obj, image=image)
+                imageDep.save()
+
+        # DEPRECATED - should switch to using a requirement, so tosca can do
+        # the topsort properly
+
+        flavors = self.get_property("flavors")
+        if flavors:
+            flavors = flavors.split(",")
+            flavors = [x.strip() for x in flavors]
+
+            for flavor in flavors:
+                flavor = self.get_xos_object(Flavor, name=flavor)
+                if not flavor.deployments.filter(id=obj.id).exists():
+                    self.info("Attached flavor %s to deployment %s" % (flavor, obj))
+                    flavor.deployments.add(obj)
+                    flavor.save()
+
+        # The new, right way
+        for flavor in self.get_requirements("tosca.relationships.SupportsFlavor"):
+            flavor = self.get_xos_object(Flavor, name=flavor)
+            if not flavor.deployments.filter(id=obj.id).exists():
+                self.info("Attached flavor %s to deployment %s" % (flavor, obj))
+                flavor.deployments.add(obj)
+                flavor.save()
+
+
+        rolemap = ( ("tosca.relationships.AdminPrivilege", "admin"), )
+        self.postprocess_privileges(DeploymentRole, DeploymentPrivilege, rolemap, obj, "deployment")
+
+    def delete(self, obj):
+        if obj.sites.exists():
+            self.info("Deployment %s has active sites; skipping delete" % obj.name)
+            return
+        for sd in obj.sitedeployments.all():
+            if sd.nodes.exists():
+                self.info("Deployment %s has active nodes; skipping delete" % obj.name)
+                return
+        #if obj.nodes.exists():
+        #    self.info("Deployment %s has active nodes; skipping delete" % obj.name)
+        #    return
+        super(XOSDeployment, self).delete(obj)
+
+
+
diff --git a/xos/tosca/resources/deploymentrole.py b/xos/tosca/resources/deploymentrole.py
new file mode 100644
index 0000000..4339026
--- /dev/null
+++ b/xos/tosca/resources/deploymentrole.py
@@ -0,0 +1,29 @@
+# note: this module named xossite.py instead of site.py due to conflict with
+#    /usr/lib/python2.7/site.py
+
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from core.models import User, Deployment, DeploymentRole
+
+from xosresource import XOSResource
+
+class XOSDeploymentRole(XOSResource):
+    provides = "tosca.nodes.DeploymentRole"
+    xos_model = DeploymentRole
+    name_field = "role"
+
+    def get_xos_args(self):
+        args = super(XOSDeploymentRole, self).get_xos_args()
+
+        return args
+
+    def delete(self, obj):
+        super(XOSDeploymentRole, self).delete(obj)
+
+
+
diff --git a/xos/tosca/resources/flavor.py b/xos/tosca/resources/flavor.py
new file mode 100644
index 0000000..f61ccad
--- /dev/null
+++ b/xos/tosca/resources/flavor.py
@@ -0,0 +1,37 @@
+# note: this module named xossite.py instead of site.py due to conflict with
+#    /usr/lib/python2.7/site.py
+
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from core.models import User, Deployment, Flavor
+
+from xosresource import XOSResource
+
+class XOSFlavor(XOSResource):
+    provides = "tosca.nodes.Flavor"
+    xos_model = Flavor
+    copyin_props = ["flavor"]
+
+    def get_xos_args(self):
+        args = super(XOSFlavor, self).get_xos_args()
+
+        # Support the default where the OpenStack flavor is the same as the
+        # flavor name
+        if "flavor" not in args:
+            args["flavor"] = args["name"]
+
+        return args
+
+    def delete(self, obj):
+        if obj.instance_set.exists():
+            self.info("Flavor %s has active instances; skipping delete" % obj.name)
+            return
+        super(XOSFlavor, self).delete(obj)
+
+
+
diff --git a/xos/tosca/resources/hpchealthcheck.py b/xos/tosca/resources/hpchealthcheck.py
new file mode 100644
index 0000000..93a0912
--- /dev/null
+++ b/xos/tosca/resources/hpchealthcheck.py
@@ -0,0 +1,39 @@
+import importlib
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+import pdb
+
+from services.hpc.models import HpcHealthCheck, HpcService
+
+from xosresource import XOSResource
+
+class XOSHpcHealthCheck(XOSResource):
+    provides = "tosca.nodes.HpcHealthCheck"
+    xos_model = HpcHealthCheck
+    name_field = None
+    copyin_props = ("kind", "resource_name", "result_contains")
+
+    def get_xos_args(self, throw_exception=True):
+        args = super(XOSHpcHealthCheck, self).get_xos_args()
+
+        service_name = self.get_requirement("tosca.relationships.MemberOfService", throw_exception=throw_exception)
+        if service_name:
+            args["hpcService"] = self.get_xos_object(HpcService, throw_exception=throw_exception, name=service_name)
+
+        return args
+
+    def get_existing_objs(self):
+        args = self.get_xos_args(throw_exception=True)
+
+        return list( HpcHealthCheck.objects.filter(hpcService=args["hpcService"], kind=args["kind"], resource_name=args["resource_name"]) )
+
+    def postprocess(self, obj):
+        pass
+
+    def can_delete(self, obj):
+        return super(XOSTenant, self).can_delete(obj)
+
diff --git a/xos/tosca/resources/image.py b/xos/tosca/resources/image.py
new file mode 100644
index 0000000..fcd53b4
--- /dev/null
+++ b/xos/tosca/resources/image.py
@@ -0,0 +1,41 @@
+# note: this module named xossite.py instead of site.py due to conflict with
+#    /usr/lib/python2.7/site.py
+
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from core.models import User, Deployment, Image
+
+from xosresource import XOSResource
+
+class XOSImage(XOSResource):
+    provides = "tosca.nodes.Image"
+    xos_model = Image
+    copyin_props = ["disk_format", "container_format", "path", "kind", "tag"]
+
+    def get_xos_args(self):
+        args = super(XOSImage, self).get_xos_args()
+
+        return args
+
+    def create(self):
+        xos_args = self.get_xos_args()
+
+        image = Image(**xos_args)
+        image.caller = self.user
+        image.save()
+
+        self.info("Created Image '%s'" % (str(image), ))
+
+    def delete(self, obj):
+        if obj.instances.exists():
+            self.info("Instance %s has active instances; skipping delete" % obj.name)
+            return
+        super(XOSImage, self).delete(obj)
+
+
+
diff --git a/xos/tosca/resources/mcordservice.py b/xos/tosca/resources/mcordservice.py
new file mode 100644
index 0000000..d77e54d
--- /dev/null
+++ b/xos/tosca/resources/mcordservice.py
@@ -0,0 +1,19 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+import pdb
+
+from services.mcord.models import MCORDService
+
+from service import XOSService
+
+class XOSMCORDService(XOSService):
+    provides = "tosca.nodes.MCORDService"
+    xos_model = MCORDService
+    copyin_props = ["view_url", "icon_url", "enabled", "published", "public_key",
+                    "private_key_fn", "versionNumber",
+                    ]
+
diff --git a/xos/tosca/resources/network.py b/xos/tosca/resources/network.py
new file mode 100644
index 0000000..8672b76
--- /dev/null
+++ b/xos/tosca/resources/network.py
@@ -0,0 +1,124 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+import pdb
+
+from core.models import Slice,User,Network,NetworkTemplate,NetworkSlice,Service,Tenant
+
+from xosresource import XOSResource
+
+class XOSNetwork(XOSResource):
+    provides = ["tosca.nodes.network.Network", "tosca.nodes.network.Network.XOS"]
+    xos_model = Network
+    copyin_props = ["ports", "labels"]
+
+    def get_xos_args(self):
+        args = super(XOSNetwork, self).get_xos_args()
+
+        args["autoconnect"] = False
+
+        slice_name = self.get_requirement("tosca.relationships.MemberOfSlice")
+        if slice_name:
+            args["owner"] = self.get_xos_object(Slice, name=slice_name)
+
+        net_template_name = self.get_requirement("tosca.relationships.UsesNetworkTemplate")
+        if net_template_name:
+            args["template"] = self.get_xos_object(NetworkTemplate, name=net_template_name)
+
+        if self.nodetemplate.type == "tosca.nodes.network.Network.XOS":
+            # copy simple string properties from the template into the arguments
+            for prop in ["ports", "labels", "permit_all_slices"]:
+                v = self.get_property(prop)
+                if v:
+                    args[prop] = v
+        else:
+            # tosca.nodes.network.Network is not as rich as an XOS network. So
+            # we have to manually fill in some defaults.
+            args["permit_all_slices"] = True
+
+        cidr = self.get_property_default("cidr", None)
+        if cidr:
+            args["subnet"] = cidr
+        print "DEF_RES_CIDR", cidr 
+
+        start_ip = self.get_property_default("start_ip", None)
+        if start_ip:
+            args["start_ip"] = start_ip 
+        print "DEF_RES_IP", start_ip 
+
+        end_ip = self.get_property_default("end_ip", None)
+        if end_ip:
+            args["end_ip"] = end_ip
+
+        return args
+
+    def postprocess(self, obj):
+        for sliceName in self.get_requirements("tosca.relationships.ConnectsToSlice"):
+            slice = self.get_xos_object(Slice, name=sliceName)
+            netSlices = NetworkSlice.objects.filter(network=obj, slice = slice)
+            if not netSlices:
+                self.info("Attached Network %s to Slice %s" % (obj, slice))
+                ns = NetworkSlice(network = obj, slice=slice)
+                ns.save()
+
+        # this is really for vRouter
+        for provider_service_name in self.get_requirements("tosca.relationships.TenantOfService"):
+            provider_service = self.get_xos_object(Service, name=provider_service_name)
+
+            existing_tenancy = Tenant.objects.filter(provider_service = provider_service, subscriber_network = obj)
+            if existing_tenancy:
+                self.info("Tenancy relationship from %s to %s already exists" % (str(obj), str(provider_service)))
+            else:
+                if provider_service.kind == "vROUTER":
+                    from services.vrouter.models import VRouterService
+                    tenancy = VRouterService.objects.get(id=provider_service.id).get_tenant(address_pool_name="addresses_"+obj.name, subscriber_network=obj)
+                    tenancy.save()
+                    obj.subnet = tenancy.cidr
+                else:
+                    raise Exception("The only network tenancy relationships that are allowed are to vRouter services")
+
+                self.info("Created Tenancy relationship from %s to %s" % (str(obj), str(provider_service)))
+
+#        v = self.get_property("permitted_slices")
+#        if v:
+#            for slicename in v.split(","):
+#                slice = self.get_xos_object(Slice, name = slicename.strip())
+#
+#                if not obj.permitted_slices.filter(id = slice.id).exists():
+#                    obj.permitted_slices.add(slice)
+
+    def create(self):
+        nodetemplate = self.nodetemplate
+
+        xos_args = self.get_xos_args()
+
+        if not xos_args.get("owner", None):
+            raise Exception("Must specify slice when creating network")
+        if not xos_args.get("template", None):
+            raise Exception("Must specify network template when creating network")
+
+        # XXX TODO: investigate using transaction.atomic instead of setting
+        #   no_sync and no_policy
+
+        network = Network(**xos_args)
+        network.caller = self.user
+        network.no_sync = True        # postprocess might set the cidr
+        network.no_policy = True
+        network.save()
+
+        self.postprocess(network)
+
+        network.no_sync = False
+        network.no_policy = False
+        network.save()
+
+        self.info("Created Network '%s' owned by Slice '%s'" % (str(network), str(network.owner)))
+
+    def delete(self, obj):
+        super(XOSNetwork, self).delete(obj)
+
+
+
diff --git a/xos/tosca/resources/networkparametertype.py b/xos/tosca/resources/networkparametertype.py
new file mode 100644
index 0000000..e0cc93e
--- /dev/null
+++ b/xos/tosca/resources/networkparametertype.py
@@ -0,0 +1,38 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from core.models import Slice,User,Network,NetworkParameterType
+
+from xosresource import XOSResource
+
+class XOSNetworkParameterType(XOSResource):
+    provides = "tosca.nodes.NetworkParameterType"
+    xos_model = NetworkParameterType
+    copyin_props = []
+
+    def get_xos_args(self):
+        args = super(XOSNetworkParameterType, self).get_xos_args()
+
+        return args
+
+    def create(self):
+        xos_args = self.get_xos_args()
+
+        networkParameterType = NetworkParameterType(**xos_args)
+        networkParameterType.caller = self.user
+        networkParameterType.save()
+
+        self.info("Created NetworkParameterType '%s' " % (str(networkParameterType), ))
+
+    def delete(self, obj):
+        if obj.networkparameters.exists():
+            return
+
+        super(XOSNetworkParameterType, self).delete(obj)
+
+
+
diff --git a/xos/tosca/resources/networktemplate.py b/xos/tosca/resources/networktemplate.py
new file mode 100644
index 0000000..3a5ce59
--- /dev/null
+++ b/xos/tosca/resources/networktemplate.py
@@ -0,0 +1,40 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from core.models import Slice,User,Network,NetworkTemplate
+
+from xosresource import XOSResource
+
+class XOSNetworkTemplate(XOSResource):
+    provides = "tosca.nodes.NetworkTemplate"
+    xos_model = NetworkTemplate
+    copyin_props = ["visibility", "translation", "shared_network_name", "shared_network_id", "toplogy_kind", "controller_kind", "access"]
+
+    def get_xos_args(self):
+        args = super(XOSNetworkTemplate, self).get_xos_args()
+
+        return args
+
+    def create(self):
+        nodetemplate = self.nodetemplate
+
+        xos_args = self.get_xos_args()
+
+        networkTemplate = NetworkTemplate(**xos_args)
+        networkTemplate.caller = self.user
+        networkTemplate.save()
+
+        self.info("Created NetworkTemplate '%s' " % (str(networkTemplate), ))
+
+    def delete(self, obj):
+        if obj.network_set.exists():
+            return
+
+        super(XOSNetworkTemplate, self).delete(obj)
+
+
+
diff --git a/xos/tosca/resources/node.py b/xos/tosca/resources/node.py
new file mode 100644
index 0000000..128aaed
--- /dev/null
+++ b/xos/tosca/resources/node.py
@@ -0,0 +1,66 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from core.models import Node, NodeLabel, Site, Deployment, SiteDeployment
+
+from xosresource import XOSResource
+
+class XOSNode(XOSResource):
+    provides = "tosca.nodes.Node"
+    xos_model = Node
+
+    def get_xos_args(self):
+        args = {"name": self.obj_name}
+
+        site = None
+        siteName = self.get_requirement("tosca.relationships.MemberOfSite", throw_exception=False)
+        if siteName:
+            site = self.get_xos_object(Site, login_base=siteName)
+            args["site"] = site
+
+        deploymentName = self.get_requirement("tosca.relationships.MemberOfDeployment", throw_exception=False)
+        if deploymentName:
+            deployment = self.get_xos_object(Deployment, name=deploymentName)
+
+            if site:
+                siteDeployment = self.get_xos_object(SiteDeployment, site=site, deployment=deployment, throw_exception=True)
+                args["site_deployment"] = siteDeployment
+
+        return args
+
+    def postprocess(self, obj):
+        # We can't set the labels when we create a Node, because they're
+        # ManyToMany related, and the node doesn't exist yet.
+        labels=[]
+        for label_name in self.get_requirements("tosca.relationships.HasLabel"):
+            labels.append(self.get_xos_object(NodeLabel, name=label_name))
+        if labels:
+            self.info("Updated labels for node '%s'" % obj)
+            obj.labels = labels
+            obj.save()
+
+    def create(self):
+        xos_args = self.get_xos_args()
+
+        if not xos_args.get("site", None):
+            raise Exception("Site is a required field of Node")
+        if not xos_args.get("site_deployment", None):
+            raise Exception("Deployment is a required field of Node")
+
+        node = Node(**xos_args)
+        node.caller = self.user
+        node.save()
+
+        self.postprocess(node)
+
+        self.info("Created Node '%s' on Site '%s' Deployment '%s'" % (str(node), str(node.site), str(node.site_deployment.deployment)))
+
+    def delete(self, obj):
+        super(XOSNode, self).delete(obj)
+
+
+
diff --git a/xos/tosca/resources/nodelabel.py b/xos/tosca/resources/nodelabel.py
new file mode 100644
index 0000000..9a8df3e
--- /dev/null
+++ b/xos/tosca/resources/nodelabel.py
@@ -0,0 +1,15 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from core.models import NodeLabel
+
+from xosresource import XOSResource
+
+class XOSNodeLabel(XOSResource):
+    provides = "tosca.nodes.NodeLabel"
+    xos_model = NodeLabel
+
diff --git a/xos/tosca/resources/originserver.py b/xos/tosca/resources/originserver.py
new file mode 100644
index 0000000..46cf87e
--- /dev/null
+++ b/xos/tosca/resources/originserver.py
@@ -0,0 +1,37 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from services.hpc.models import OriginServer, ContentProvider
+
+from xosresource import XOSResource
+
+class XOSOriginServer(XOSResource):
+    provides = "tosca.nodes.OriginServer"
+    xos_model = OriginServer
+    name_field = "url"
+    copyin_props = []
+
+    def obj_name_to_url(self):
+        url = self.obj_name
+        if url.startswith("http_"):
+            url = url[5:]
+        return url
+
+    def get_existing_objs(self):
+        url = self.obj_name_to_url()
+        return self.xos_model.objects.filter(**{self.name_field: url})
+
+    def get_xos_args(self):
+        url = self.obj_name_to_url()
+        cp_name = self.get_requirement("tosca.relationships.MemberOfContentProvider", throw_exception=True)
+        cp = self.get_xos_object(ContentProvider, name=cp_name)
+        return {"url": url,
+                "contentProvider": cp}
+
+    def can_delete(self, obj):
+        return super(XOSOriginServer, self).can_delete(obj)
+
diff --git a/xos/tosca/resources/port.py b/xos/tosca/resources/port.py
new file mode 100644
index 0000000..791a226
--- /dev/null
+++ b/xos/tosca/resources/port.py
@@ -0,0 +1,61 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from core.models import Instance,User,Network,NetworkTemplate,Port
+
+from xosresource import XOSResource
+
+class XOSPort(XOSResource):
+    provides = ["tosca.nodes.network.Port"]
+    xos_model = Port
+
+    def get_existing_objs(self):
+        # Port objects have no name, their unique key is (instance, network)
+        args = self.get_xos_args(throw_exception=False)
+        instance = args.get('instance',None)
+        network = args.get('network',None)
+        if (not instance) or (not network):
+            return []
+        return self.xos_model.objects.filter(**{'instance': instance, 'network': network})
+
+    def get_xos_args(self, throw_exception=True):
+        args = {}
+
+        instance_name = self.get_requirement("tosca.relationships.network.BindsTo")
+        if instance_name:
+            args["instance"] = self.get_xos_object(Instance, throw_exception, name=instance_name)
+
+        net_name = self.get_requirement("tosca.relationships.network.LinksTo")
+        if net_name:
+            args["network"] = self.get_xos_object(Network, throw_exception, name=net_name)
+
+        return args
+
+    def postprocess(self, obj):
+        pass
+
+    def create(self):
+        xos_args = self.get_xos_args()
+
+        if not xos_args.get("instance", None):
+            raise Exception("Must specify slver when creating port")
+        if not xos_args.get("network", None):
+            raise Exception("Must specify network when creating port")
+
+        port = Port(**xos_args)
+        port.caller = self.user
+        port.save()
+
+        self.postprocess(port)
+
+        self.info("Created Port '%s' connect instance '%s' to network %s" % (str(port), str(port.instance), str(port.network)))
+
+    def delete(self, obj):
+        super(XOSPort, self).delete(obj)
+
+
+
diff --git a/xos/tosca/resources/service.py b/xos/tosca/resources/service.py
new file mode 100644
index 0000000..5a57418
--- /dev/null
+++ b/xos/tosca/resources/service.py
@@ -0,0 +1,42 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+import pdb
+
+from core.models import Service,User,CoarseTenant,AddressPool
+
+from xosresource import XOSResource
+
+class XOSService(XOSResource):
+    provides = "tosca.nodes.Service"
+    xos_model = Service
+    copyin_props = ["view_url", "icon_url", "kind", "enabled", "published", "public_key", "private_key_fn", "versionNumber"]
+
+    def postprocess(self, obj):
+        for provider_service_name in self.get_requirements("tosca.relationships.TenantOfService"):
+            provider_service = self.get_xos_object(Service, name=provider_service_name)
+
+            existing_tenancy = CoarseTenant.get_tenant_objects().filter(provider_service = provider_service, subscriber_service = obj)
+            if existing_tenancy:
+                self.info("Tenancy relationship from %s to %s already exists" % (str(obj), str(provider_service)))
+            else:
+                tenancy = CoarseTenant(provider_service = provider_service,
+                                       subscriber_service = obj)
+                tenancy.save()
+
+                self.info("Created Tenancy relationship  from %s to %s" % (str(obj), str(provider_service)))
+
+        for ap_name in self.get_requirements("tosca.relationships.ProvidesAddresses"):
+            ap = self.get_xos_object(AddressPool, name=ap_name)
+            ap.service = obj
+            ap.save()
+
+    def can_delete(self, obj):
+        if obj.slices.exists():
+            self.info("Service %s has active slices; skipping delete" % obj.name)
+            return False
+        return super(XOSService, self).can_delete(obj)
+
diff --git a/xos/tosca/resources/servicecontroller.py b/xos/tosca/resources/servicecontroller.py
new file mode 100644
index 0000000..d7e894a
--- /dev/null
+++ b/xos/tosca/resources/servicecontroller.py
@@ -0,0 +1,67 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from core.models import ServiceController, ServiceControllerResource
+
+from xosresource import XOSResource
+
+class XOSServiceController(XOSResource):
+    provides = "tosca.nodes.ServiceController"
+    xos_model = ServiceController
+    copyin_props = ["base_url", "synchronizer_run", "synchronizer_config"]
+
+    def postprocess_resource_prop(self, obj, kind, format):
+        values = self.get_property(kind)
+        if values:
+            for i,value in enumerate(values.split(",")):
+                value = value.strip()
+                subdirectory = None
+
+                name=kind
+                if i>0:
+                    name = "%s_%d" %( name, i)
+
+                if (" " in value):
+                    parts=value.split()
+                    for part in parts[:-1]:
+                       if ":" in part:
+                           (lhs, rhs) = part.split(":", 1)
+                           if lhs=="subdirectory":
+                               subdirectory=rhs
+                           else:
+                               raise Exception("Malformed value %s" % value)
+                       else:
+                           raise Exception("Malformed value %s" % value)
+                    value = parts[-1]
+
+
+                scr = ServiceControllerResource.objects.filter(service_controller=obj, name=name, kind=kind, format=format)
+                if scr:
+                    scr=scr[0]
+                    if (scr.url != value) or (scr.subdirectory!=subdirectory):
+                        self.info("updating resource %s" % kind)
+                        scr.url = value
+                        scr.subdirectory = subdirectory
+                        scr.save()
+                else:
+                    self.info("adding resource %s" % kind)
+                    scr = ServiceControllerResource(service_controller=obj, name=name, kind=kind, format=format, url=value, subdirectory=subdirectory)
+                    scr.save()
+
+    def postprocess(self, obj):
+        # allow these common resource to be specified directly by the ServiceController tosca object
+        self.postprocess_resource_prop(obj, "models", "python")
+        self.postprocess_resource_prop(obj, "admin", "python")
+        self.postprocess_resource_prop(obj, "admin_template", "raw")
+        self.postprocess_resource_prop(obj, "tosca_custom_types", "yaml")
+        self.postprocess_resource_prop(obj, "tosca_resource", "python")
+        self.postprocess_resource_prop(obj, "synchronizer", "manifest")
+        self.postprocess_resource_prop(obj, "private_key", "raw")
+        self.postprocess_resource_prop(obj, "public_key", "raw")
+        self.postprocess_resource_prop(obj, "rest_service", "python")
+        self.postprocess_resource_prop(obj, "rest_tenant", "python")
+
diff --git a/xos/tosca/resources/servicecontrollerresource.py b/xos/tosca/resources/servicecontrollerresource.py
new file mode 100644
index 0000000..96ea83d
--- /dev/null
+++ b/xos/tosca/resources/servicecontrollerresource.py
@@ -0,0 +1,27 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from core.models import ServiceControllerResource, ServiceController
+
+from xosresource import XOSResource
+
+class XOSServiceControllerResource(XOSResource):
+    provides = "tosca.nodes.ServiceControllerResource"
+    xos_model = ServiceControllerResource
+    copyin_props = ["kind", "format", "url"]
+
+    def get_xos_args(self, throw_exception=True):
+        args = super(XOSServiceControllerResource, self).get_xos_args()
+
+        controller_name = self.get_requirement("tosca.relationships.UsedByController", throw_exception=throw_exception)
+        if controller_name:
+            args["service_controller"] = self.get_xos_object(ServiceController, throw_exception=throw_exception, name=controller_name)
+
+        return args
+
+
+
diff --git a/xos/tosca/resources/serviceprovider.py b/xos/tosca/resources/serviceprovider.py
new file mode 100644
index 0000000..2c9a167
--- /dev/null
+++ b/xos/tosca/resources/serviceprovider.py
@@ -0,0 +1,28 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from services.hpc.models import ServiceProvider, HpcService
+
+from xosresource import XOSResource
+
+class XOSServiceProvider(XOSResource):
+    provides = "tosca.nodes.ServiceProvider"
+    xos_model = ServiceProvider
+    copyin_props = []
+
+    def get_xos_args(self):
+        hpc_service_name = self.get_requirement("tosca.relationships.MemberOfService", throw_exception=True)
+        hpc_service = self.get_xos_object(HpcService, name=hpc_service_name)
+        return {"name": self.obj_name,
+                "hpcService": hpc_service}
+
+    def can_delete(self, obj):
+        if obj.contentprovider_set.exists():
+            self.info("%s %s has active content providers; skipping delete" % (self.xos_model.__class__, obj.name))
+            return False
+        return super(XOSServiceProvider, self).can_delete(obj)
+
diff --git a/xos/tosca/resources/siterole.py b/xos/tosca/resources/siterole.py
new file mode 100644
index 0000000..abb1f0d
--- /dev/null
+++ b/xos/tosca/resources/siterole.py
@@ -0,0 +1,29 @@
+# note: this module named xossite.py instead of site.py due to conflict with
+#    /usr/lib/python2.7/site.py
+
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from core.models import User, Deployment, SiteRole
+
+from xosresource import XOSResource
+
+class XOSSiteRole(XOSResource):
+    provides = "tosca.nodes.SiteRole"
+    xos_model = SiteRole
+    name_field = "role"
+
+    def get_xos_args(self):
+        args = super(XOSSiteRole, self).get_xos_args()
+
+        return args
+
+    def delete(self, obj):
+        super(XOSSiteRole, self).delete(obj)
+
+
+
diff --git a/xos/tosca/resources/slice.py b/xos/tosca/resources/slice.py
new file mode 100644
index 0000000..693d6ab
--- /dev/null
+++ b/xos/tosca/resources/slice.py
@@ -0,0 +1,65 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from core.models import Slice,User,Site,Network,NetworkSlice,SliceRole,SlicePrivilege,Service,Image,Flavor,Node
+
+from xosresource import XOSResource
+
+class XOSSlice(XOSResource):
+    provides = "tosca.nodes.Slice"
+    xos_model = Slice
+    copyin_props = ["enabled", "description", "slice_url", "max_instances", "default_isolation", "default_flavor", "network", "exposed_ports"]
+
+    def get_xos_args(self):
+        args = super(XOSSlice, self).get_xos_args()
+
+        site_name = self.get_requirement("tosca.relationships.MemberOfSite", throw_exception=True)
+        site = self.get_xos_object(Site, login_base=site_name)
+        args["site"] = site
+
+        serviceName = self.get_requirement("tosca.relationships.MemberOfService", throw_exception=False)
+        if serviceName:
+            service = self.get_xos_object(Service, name=serviceName)
+            args["service"] = service
+
+        default_image_name = self.get_requirement("tosca.relationships.DefaultImage", throw_exception=False)
+        if default_image_name:
+            default_image = self.get_xos_object(Image, name=default_image_name, throw_exception=True)
+            args["default_image"] = default_image
+
+        default_flavor_name = self.get_requirement("tosca.relationships.DefaultFlavor", throw_exception=False)
+        if default_flavor_name:
+            default_flavor = self.get_xos_object(Flavor, name=default_flavor_name, throw_exception=True)
+            args["default_flavor"] = default_flavor
+
+        default_node_name = self.get_property_default("default_node", None)
+        if default_node_name:
+            default_node = self.get_xos_object(Node, name=default_node_name, throw_exception=True)
+            args["default_node"] = default_node
+
+        return args
+
+    def postprocess(self, obj):
+        for net_name in self.get_requirements("tosca.relationships.ConnectsToNetwork"):
+            net = self.get_xos_object(Network, name=net_name)
+            if not NetworkSlice.objects.filter(network=net, slice=obj):
+                ns = NetworkSlice(network=net, slice=obj)
+                ns.save()
+                self.info("Added network connection from '%s' to '%s'" % (str(obj), str(net)))
+
+        rolemap = ( ("tosca.relationships.AdminPrivilege", "admin"), ("tosca.relationships.AccessPrivilege", "access"),
+                    ("tosca.relationships.PIPrivilege", "pi"), ("tosca.relationships.TechPrivilege", "tech") )
+        self.postprocess_privileges(SliceRole, SlicePrivilege, rolemap, obj, "slice")
+
+    def delete(self, obj):
+        if obj.instances.exists():
+            self.info("Slice %s has active instances; skipping delete" % obj.name)
+            return
+        super(XOSSlice, self).delete(obj)
+
+
+
diff --git a/xos/tosca/resources/slicerole.py b/xos/tosca/resources/slicerole.py
new file mode 100644
index 0000000..fc7d3f1
--- /dev/null
+++ b/xos/tosca/resources/slicerole.py
@@ -0,0 +1,29 @@
+# note: this module named xossite.py instead of site.py due to conflict with
+#    /usr/lib/python2.7/site.py
+
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from core.models import User, Deployment, SliceRole
+
+from xosresource import XOSResource
+
+class XOSSliceRole(XOSResource):
+    provides = "tosca.nodes.SliceRole"
+    xos_model = SliceRole
+    name_field = "role"
+
+    def get_xos_args(self):
+        args = super(XOSSliceRole, self).get_xos_args()
+
+        return args
+
+    def delete(self, obj):
+        super(XOSSliceRole, self).delete(obj)
+
+
+
diff --git a/xos/tosca/resources/subscriber.py b/xos/tosca/resources/subscriber.py
new file mode 100644
index 0000000..5ec0462
--- /dev/null
+++ b/xos/tosca/resources/subscriber.py
@@ -0,0 +1,23 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+import pdb
+
+from core.models import Subscriber,User
+
+from xosresource import XOSResource
+
+class XOSSubscriber(XOSResource):
+    provides = "tosca.nodes.Subscriber"
+    xos_model = Subscriber
+    copyin_props = ["service_specific_id"]
+
+    def postprocess(self, obj):
+        pass
+
+    def can_delete(self, obj):
+        return super(XOSService, self).can_delete(obj)
+
diff --git a/xos/tosca/resources/tag.py b/xos/tosca/resources/tag.py
new file mode 100644
index 0000000..001cba8
--- /dev/null
+++ b/xos/tosca/resources/tag.py
@@ -0,0 +1,57 @@
+import importlib
+import os
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+from django.contrib.contenttypes.models import ContentType
+
+from core.models import Tag, Service
+
+from xosresource import XOSResource
+
+class XOSTag(XOSResource):
+    provides = "tosca.nodes.Tag"
+    xos_model = Tag
+    name_field = None
+    copyin_props = ("name", "value")
+
+    def get_xos_args(self, throw_exception=True):
+        args = super(XOSTag, self).get_xos_args()
+
+        # Find the Tosca object that this Tag is pointing to, and return its
+        # content_type and object_id, which will be used in the GenericForeignKey
+        # django relation.
+
+        target_name = self.get_requirement("tosca.relationships.TagsObject", throw_exception=throw_exception)
+        if target_name:
+            target_model = self.engine.name_to_xos_model(self.user, target_name)
+            args["content_type"] = ContentType.objects.get_for_model(target_model)
+            args["object_id"] = target_model.id
+
+        service_name = self.get_requirement("tosca.relationships.MemberOfService", throw_exception=throw_exception)
+        if service_name:
+            args["service"] = self.get_xos_object(Service, name=service_name)
+
+        # To uniquely identify a Tag, we must know the object that it is attached
+        # to as well as the name of the Tag.
+
+        if ("content_type" not in args) or ("object_id" not in args) or ("name" not in args):
+           if throw_exception:
+               raise Exception("Tag must specify TagsObject requirement and Name property")
+
+        return args
+
+    def get_existing_objs(self):
+        args = self.get_xos_args(throw_exception=True)
+
+        return Tag.objects.filter(content_type=args["content_type"],
+                                  object_id=args["object_id"],
+                                  name=args["name"])
+
+    def postprocess(self, obj):
+        pass
+
+    def can_delete(self, obj):
+        return super(XOSTag, self).can_delete(obj)
+
diff --git a/xos/tosca/resources/tenant.py b/xos/tosca/resources/tenant.py
new file mode 100644
index 0000000..21b8e88
--- /dev/null
+++ b/xos/tosca/resources/tenant.py
@@ -0,0 +1,60 @@
+import importlib
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+import pdb
+
+from core.models import Tenant, Service
+
+from xosresource import XOSResource
+
+class XOSTenant(XOSResource):
+    provides = "tosca.nodes.Tenant"
+    xos_model = Tenant
+    name_field = None
+    copyin_props = ("kind", "service_specific_attribute")
+
+    def get_xos_args(self, throw_exception=True):
+        args = super(XOSTenant, self).get_xos_args()
+
+        provider_name = self.get_requirement("tosca.relationships.MemberOfService", throw_exception=throw_exception)
+        if provider_name:
+            args["provider_service"] = self.get_xos_object(Service, throw_exception=throw_exception, name=provider_name)
+
+        return args
+
+    def get_existing_objs(self):
+        args = self.get_xos_args(throw_exception=False)
+        provider_service = args.get("provider", None)
+        if provider_service:
+            return [ self.get_xos_object(provider_service=provider_service) ]
+        return []
+
+    def create(self):
+        model_class = self.get_property("model")
+        if model_class:
+            model_name = ".".join(model_class.split(".")[:-1])
+            class_name = model_class.split(".")[-1]
+            module = importlib.import_module(model_name)
+            xos_model = getattr(module, class_name)
+        else:
+            xos_model = self.xos_model
+
+        xos_args = self.get_xos_args()
+        xos_obj = xos_model(**xos_args)
+        xos_obj.caller = self.user
+        xos_obj.save()
+
+        self.info("Created %s '%s'" % (self.xos_model.__name__,str(xos_obj)))
+
+        self.postprocess(xos_obj)
+
+    def postprocess(self, obj):
+        pass
+
+    def can_delete(self, obj):
+        return super(XOSTenant, self).can_delete(obj)
+
diff --git a/xos/tosca/resources/tenantrole.py b/xos/tosca/resources/tenantrole.py
new file mode 100644
index 0000000..316a5a3
--- /dev/null
+++ b/xos/tosca/resources/tenantrole.py
@@ -0,0 +1,29 @@
+# note: this module named xossite.py instead of site.py due to conflict with
+#    /usr/lib/python2.7/site.py
+
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from core.models import User, Deployment, TenantRole
+
+from xosresource import XOSResource
+
+class XOSTenantRole(XOSResource):
+    provides = "tosca.nodes.TenantRole"
+    xos_model = TenantRole
+    name_field = "role"
+
+    def get_xos_args(self):
+        args = super(XOSTenantRole, self).get_xos_args()
+
+        return args
+
+    def delete(self, obj):
+        super(XOSTenantRole, self).delete(obj)
+
+
+
diff --git a/xos/tosca/resources/user.py b/xos/tosca/resources/user.py
new file mode 100644
index 0000000..55c0423
--- /dev/null
+++ b/xos/tosca/resources/user.py
@@ -0,0 +1,104 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from core.models import User, Site, SiteRole, SliceRole, SlicePrivilege, SitePrivilege, DashboardView, UserDashboardView
+
+from xosresource import XOSResource
+
+class XOSUser(XOSResource):
+    provides = "tosca.nodes.User"
+    xos_model = User
+    name_field = "email"
+    copyin_props = ["password", "firstname", "lastname", "phone", "user_url", "public_key", "is_active", "is_admin", "login_page"]
+
+    def get_xos_args(self):
+        args = super(XOSUser, self).get_xos_args()
+
+        site_name = self.get_requirement("tosca.relationships.MemberOfSite")
+        if site_name:
+            args["site"] = self.get_xos_object(Site, login_base=site_name)
+
+        return args
+
+    def get_existing_objs(self):
+        return self.xos_model.objects.filter(email = self.obj_name)
+
+    def postprocess(self, obj):
+        rolemap = ( ("tosca.relationships.AdminPrivilege", "admin"), ("tosca.relationships.AccessPrivilege", "access"),
+                    ("tosca.relationships.PIPrivilege", "pi"), ("tosca.relationships.TechPrivilege", "tech") )
+        for (rel, role) in rolemap:
+            for obj_name in self.get_requirements(rel):
+                dest = self.engine.name_to_xos_model(self.user, obj_name)
+                if dest.__class__.__name__ == "Slice":
+                    role_obj = self.get_xos_object(SliceRole, role=role)
+                    if not SlicePrivilege.objects.filter(user=user, role=role_obj, slice=dest):
+                        sp = SlicePrivilege(user=obj, role=role_obj, slice=dest)
+                        sp.save()
+                        self.info("Added slice privilege on %s role %s for %s" % (str(dest), str(role), str(obj)))
+                elif dest.__class__.__name__ == "Site":
+                    role_obj = self.get_xos_object(SiteRole, role=role)
+                    if not SitePrivilege.objects.filter(user=obj, role=role_obj, site=dest):
+                        sp = SitePrivilege(user=obj, role=role_obj, site=dest)
+                        sp.save()
+                        self.info("Added site privilege on %s role %s for %s" % (str(dest), str(role), str(obj)))
+
+        dashboard_order = 10
+        for reqs in self.nodetemplate.requirements:
+            for (k,v) in reqs.items():
+                if (v["relationship"] == "tosca.relationships.UsesDashboard"):
+                    dashboard_name = v["node"]
+                    dashboard = self.get_xos_object(DashboardView, name=dashboard_name)
+
+                    udvs = UserDashboardView.objects.filter(user=obj, dashboardView=dashboard)
+                    if not udvs:
+                        self.info("Adding UserDashboardView from %s to %s" % (obj, dashboard))
+
+                        udv = UserDashboardView(user=obj, dashboardView=dashboard, order=dashboard_order)
+                        dashboard_order += 10
+                        udv.save()
+
+    def create(self):
+        xos_args = self.get_xos_args()
+
+        if not xos_args.get("site",None):
+             raise Exception("Site name must be specified when creating user")
+        if ("firstname" not in xos_args) or ("lastname" not in xos_args):
+             raise Exception("firstname and lastname must be specified when creating user")
+
+        user = User(**xos_args)
+        user.save()
+
+        self.postprocess(user)
+
+        self.info("Created User '%s'" % (str(user), ))
+
+    def update(self, obj):
+        xos_args = self.get_xos_args()
+
+        password = None
+        if "password" in xos_args:
+            # password needs to be set with set_password function
+            password = xos_args["password"]
+            del xos_args["password"]
+
+        for (k,v) in xos_args.items():
+            setattr(obj, k, v)
+
+        if password:
+            obj.set_password(password)
+
+        self.postprocess(obj)
+        obj.save()
+
+    def delete(self, obj):
+        if obj.slices.exists():
+            self.info("User %s has active slices; skipping delete" % obj.name)
+            return
+        super(XOSUser, self).delete(obj)
+
+
+
diff --git a/xos/tosca/resources/vbbucomponent.py b/xos/tosca/resources/vbbucomponent.py
new file mode 100644
index 0000000..ee60d0c
--- /dev/null
+++ b/xos/tosca/resources/vbbucomponent.py
@@ -0,0 +1,40 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+import pdb
+
+from services.mcord.models import VBBUComponent, MCORDService
+
+from xosresource import XOSResource
+
+class XOSVBBUComponent(XOSResource):
+    provides = "tosca.nodes.VBBUComponent"
+    xos_model = VBBUComponent
+    copyin_props = ["s1u_tag", "s1mme_tag", "rru_tag", "display_message"]
+    name_field = None
+
+    def get_xos_args(self, throw_exception=True):
+        args = super(XOSVBBUComponent, self).get_xos_args()
+
+        provider_name = self.get_requirement("tosca.relationships.MemberOfService", throw_exception=throw_exception)
+        if provider_name:
+            args["provider_service"] = self.get_xos_object(MCORDService, throw_exception=throw_exception, name=provider_name)
+
+        return args
+
+    def get_existing_objs(self):
+        args = self.get_xos_args(throw_exception=False)
+        provider_service = args.get("provider", None)
+        if provider_service:
+            return [ self.get_xos_object(provider_service=provider_service) ]
+        return []
+
+    def postprocess(self, obj):
+        pass
+
+    def can_delete(self, obj):
+        return super(XOSVBBUComponent, self).can_delete(obj)
+
diff --git a/xos/tosca/resources/vpgwccomponent.py b/xos/tosca/resources/vpgwccomponent.py
new file mode 100644
index 0000000..3b87111
--- /dev/null
+++ b/xos/tosca/resources/vpgwccomponent.py
@@ -0,0 +1,40 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+import pdb
+
+from services.mcord.models import VPGWCComponent, MCORDService
+
+from xosresource import XOSResource
+
+class XOSVPGWCComponent(XOSResource):
+    provides = "tosca.nodes.VPGWCComponent"
+    xos_model = VPGWCComponent
+    copyin_props = ["s5s8_pgw_tag", "display_message"]
+    name_field = None
+
+    def get_xos_args(self, throw_exception=True):
+        args = super(XOSVPGWCComponent, self).get_xos_args()
+
+        provider_name = self.get_requirement("tosca.relationships.MemberOfService", throw_exception=throw_exception)
+        if provider_name:
+            args["provider_service"] = self.get_xos_object(MCORDService, throw_exception=throw_exception, name=provider_name)
+
+        return args
+
+    def get_existing_objs(self):
+        args = self.get_xos_args(throw_exception=False)
+        provider_service = args.get("provider", None)
+        if provider_service:
+            return [ self.get_xos_object(provider_service=provider_service) ]
+        return []
+
+    def postprocess(self, obj):
+        pass
+
+    def can_delete(self, obj):
+        return super(XOSVPGWCComponent, self).can_delete(obj)
+
diff --git a/xos/tosca/resources/xosmodel.py b/xos/tosca/resources/xosmodel.py
new file mode 100644
index 0000000..343fb1f
--- /dev/null
+++ b/xos/tosca/resources/xosmodel.py
@@ -0,0 +1,30 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from core.models import XOS, XOSVolume
+
+from xosresource import XOSResource
+
+class XOSXOS(XOSResource):
+    provides = "tosca.nodes.XOS"
+    xos_model = XOS
+    copyin_props = ["ui_port", "bootstrap_ui_port", "docker_project_name", "enable_build", "frontend_only", "source_ui_image"]
+
+class XOSVolume(XOSResource):
+    provides = "tosca.nodes.XOSVolume"
+    xos_model = XOSVolume
+    copyin_props = ["host_path", "read_only"]
+    name_field = "container_path"
+
+    def get_xos_args(self, throw_exception=True):
+        args = super(XOSVolume, self).get_xos_args()
+
+        xos_name = self.get_requirement("tosca.relationships.UsedByXOS", throw_exception=throw_exception)
+        if xos_name:
+            args["xos"] = self.get_xos_object(XOS, throw_exception=throw_exception, name=xos_name)
+
+        return args
diff --git a/xos/tosca/resources/xosresource.py b/xos/tosca/resources/xosresource.py
new file mode 100644
index 0000000..f65a231
--- /dev/null
+++ b/xos/tosca/resources/xosresource.py
@@ -0,0 +1,266 @@
+import os
+import pdb
+import json
+import subprocess
+import sys
+
+from core.models import User
+
+class XOSResource(object):
+    xos_base_class = "XOSResource"
+    xos_model = None
+    name_field = "name"
+    copyin_props = []
+    provides = None
+
+    def __init__(self, user, nodetemplate, engine):
+        self.dirty = False
+        self.deferred_sync = []
+        self.user = user
+        self.nodetemplate = nodetemplate
+        self.engine = engine
+
+    @property
+    def full_name(self):
+        return self.nodetemplate.name
+
+    @property
+    def obj_name(self):
+        if "#" in self.nodetemplate.name:
+            return self.nodetemplate.name.split("#",1)[1]
+        else:
+            return self.nodetemplate.name
+
+    def get_all_required_node_names(self):
+        results = []
+        for reqs in self.nodetemplate.requirements:
+            for (k,v) in reqs.items():
+                results.append(v["node"])
+        return results
+
+    def get_requirements(self, relationship_name, throw_exception=False):
+        """ helper to search the list of requirements for a particular relationship
+            type.
+        """
+
+        results = []
+        for reqs in self.nodetemplate.requirements:
+            for (k,v) in reqs.items():
+                if (v["relationship"] == relationship_name):
+                    results.append(v["node"])
+
+        if (not results) and throw_exception:
+            raise Exception("Failed to find requirement in %s using relationship %s" % (self.full_name, relationship_name))
+
+        return results
+
+    def get_requirement(self, relationship_name, throw_exception=False):
+        reqs = self.get_requirements(relationship_name, throw_exception)
+        if not reqs:
+            return None
+        return reqs[0]
+
+    def get_scalable(self):
+        scalable = self.nodetemplate.get_capabilities().get("scalable", None)
+        if scalable:
+            return {"min_instances": scalable.get_property_value("min_instances"),
+                    "max_instances": scalable.get_property_value("max_instances"),
+                    "default_instances": scalable.get_property_value("default_instances")}
+        else:
+            return {}
+
+    def get_property(self, name):
+        return self.nodetemplate.get_property_value(name)
+
+    def get_property_default(self, name, default=None):
+        props = self.nodetemplate.get_properties()
+        if props and name in props.keys():
+            return props[name].value
+        return default
+
+    def get_xos_object(self, cls, throw_exception=True, **kwargs):
+        # do the same parsing that we do for objname
+        for (k,v) in kwargs.items():
+            if (k=="name") and ("#" in v):
+                kwargs[k] = v.split("#",1)[1]
+
+        objs = cls.objects.filter(**kwargs)
+        if not objs:
+            if throw_exception:
+                raise Exception("Failed to find %s filtered by %s" % (cls.__name__, str(kwargs)))
+            return None
+        return objs[0]
+
+    def get_replaces_objs(self):
+        replaces = self.get_property_default("replaces", None)
+        if replaces:
+            return self.xos_model.objects.filter(**{self.name_field: replaces})
+        else:
+            return []
+
+    def get_existing_objs(self):
+        return self.xos_model.objects.filter(**{self.name_field: self.obj_name})
+
+    def get_model_class_name(self):
+        return self.xos_model.__name__
+
+    def create_or_update(self):
+        replaces_objs = self.get_replaces_objs()
+        existing_objs = self.get_existing_objs()
+
+        if (replaces_objs and existing_objs):
+            ro = replaces_objs[0]
+            self.info("deleting %s:%s" % (self.get_model_class_name(), getattr(ro,self.name_field)))
+            ro.delete()
+
+            # in case we wanted to throw an error instead...
+            #self.error("CRITICAL ERROR: Both %s and %s exist!" % (getattr(ro,self.name_field), self.obj_name))
+            #sys.exit(-1)
+
+        if (replaces_objs and not existing_objs):
+            ro = replaces_objs[0]
+            self.info("renaming %s:%s to %s" % (self.get_model_class_name(), getattr(ro,self.name_field), self.obj_name))
+            setattr(ro, self.name_field, self.obj_name)
+            ro.save()
+            existing_objs = self.get_existing_objs()
+
+        if existing_objs:
+            if self.get_property_default("no-update", False):
+                self.info("%s:%s (%s) already exists. Skipping update due to 'no-update' property" % (self.get_model_class_name(), self.obj_name, self.full_name))
+            else:
+                self.info("%s:%s (%s) already exists" % (self.get_model_class_name(), self.obj_name, self.full_name))
+                self.update(existing_objs[0])
+        else:
+            if self.get_property_default("no-create", False):
+                self.info("%s:%s (%s) does not exist, but 'no-create' is specified" % (self.get_model_class_name(), self.obj_name, self.full_name))
+            else:
+                self.create()
+
+    def can_delete(self, obj):
+        if self.get_property_default("no-delete",False):
+            self.info("%s:%s %s is marked 'no-delete'. Skipping delete." % (self.get_model_class_name(), self.obj_name, self.full_name))
+            return False
+        return True
+
+    def postprocess_privileges(self, roleclass, privclass, rolemap, obj, toFieldName):
+        for (rel, role) in rolemap:
+            for email in self.get_requirements(rel):
+                role_obj = self.get_xos_object(roleclass, throw_exception=False, role=role)
+                if not role_obj:
+                    # if the role doesn't exist, make it
+                    self.info("Creating %s %s" % (roleclass.__name__, role))
+                    role_obj = roleclass(role=role)
+                    role_obj.save()
+
+                user = self.get_xos_object(User, email=email)
+                if not privclass.objects.filter(user=user, role=role_obj, **{toFieldName: obj}):
+                    sp = privclass(user=user, role=role_obj, **{toFieldName: obj})
+                    sp.save()
+                    self.info("Added privilege on %s role %s for %s" % (str(obj), str(role), str(user)))
+
+    def postprocess(self, obj):
+        pass
+
+    def intrinsic_get_artifact(self, obj=None, name=None, method=None):
+        if obj!="SELF":
+            raise Exception("only SELF is supported for get_artifact first arg")
+        if method!="LOCAL_FILE":
+            raise Exception("only LOCAL_FILE is supported for get_artifact third arg")
+
+        for (k,v) in self.nodetemplate.entity_tpl.get("artifacts", {}).items():
+            if k == name:
+                if not os.path.exists(v):
+                    raise Exception("Artifact local file %s for artifact %s does not exist" % (v, k))
+                return open(v).read()
+
+        raise Exception("artifact %s not found" % name)
+
+    def intrinsic_get_script_env(self, obj=None, name=None, varname=None, method=None):
+        if obj!="SELF":
+            raise Exception("only SELF is supported for get_artifact first arg")
+        if method!="LOCAL_FILE":
+            raise Exception("only LOCAL_FILE is supported for get_artifact fourth arg")
+
+        for (k,v) in self.nodetemplate.entity_tpl.get("artifacts", {}).items():
+            if k == name:
+                if not os.path.exists(v):
+                    raise Exception("Artifact local file %s for artifact %s does not exist" % (v, k))
+                return subprocess.Popen('/bin/bash -c "source %s &> /dev/null; echo \\$%s"' % (v, varname), shell=True, stdout=subprocess.PIPE).stdout.read().strip()
+
+        raise Exception("artifact %s not found" % name)
+
+    def intrinsic_path_join(self, obj=None, name=None, varname=None, method=None):
+        if obj!="SELF":
+            raise Exception("only SELF is supported for get_artifact first arg")
+        if method!="ENV_VAR":
+            raise Exception("only ENV_VAR is supported for get_artifact fourth arg")
+
+        if not (name in os.environ):
+            raise Exception("environment variable %s not found" % name)
+
+        return os.path.join(os.environ[name], varname)
+
+    def try_intrinsic_function(self, v):
+        try:
+            jsv = v.replace("'", '"')
+            jsv = json.loads(jsv)
+        except:
+            #import traceback
+            #traceback.print_exc()
+            return v
+
+        if type(jsv)!=dict:
+            return v
+
+        if "get_artifact" in jsv:
+            return self.intrinsic_get_artifact(*jsv["get_artifact"])
+        elif "get_script_env" in jsv:
+            return self.intrinsic_get_script_env(*jsv["get_script_env"])
+        elif "path_join" in jsv:
+            return self.intrinsic_path_join(*jsv["path_join"])
+
+        return v
+
+    def get_xos_args(self):
+        args = {}
+
+        if self.name_field:
+            args[self.name_field] = self.obj_name
+
+        # copy simple string properties from the template into the arguments
+        for prop in self.copyin_props:
+            v = self.get_property(prop)
+
+            v = self.try_intrinsic_function(v)
+
+            if v is not None:
+                args[prop] = v
+
+        return args
+
+    def create(self):
+        xos_args = self.get_xos_args()
+        xos_obj = self.xos_model(**xos_args)
+        if self.user:
+            xos_obj.caller = self.user
+        xos_obj.save()
+
+        self.info("Created %s '%s'" % (self.xos_model.__name__,str(xos_obj)))
+
+        self.postprocess(xos_obj)
+
+    def update(self, obj):
+        xos_args = self.get_xos_args()
+        for (k,v) in xos_args.items():
+            setattr(obj, k, v)
+        self.postprocess(obj)
+        obj.save()
+
+    def delete(self, obj):
+        if (self.can_delete(obj)):
+            self.info("destroying object %s" % str(obj))
+            obj.delete(purge=True)   # XXX TODO: turn off purge before production
+
+    def info(self, s):
+        self.engine.log(s)
+
diff --git a/xos/tosca/resources/xossite.py b/xos/tosca/resources/xossite.py
new file mode 100644
index 0000000..9b03bc5
--- /dev/null
+++ b/xos/tosca/resources/xossite.py
@@ -0,0 +1,84 @@
+# note: this module named xossite.py instead of site.py due to conflict with
+#    /usr/lib/python2.7/site.py
+
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from core.models import User,Site,Deployment,Controller,SiteDeployment
+
+from xosresource import XOSResource
+
+class XOSSite(XOSResource):
+    provides = "tosca.nodes.Site"
+    xos_model = Site
+
+    def get_xos_args(self):
+        display_name = self.get_property("display_name")
+        if not display_name:
+            display_name = self.obj_name
+
+        args = {"login_base": self.obj_name,
+                "name": display_name}
+
+        # copy simple string properties from the template into the arguments
+        for prop in ["site_url", ]:
+            v = self.get_property(prop)
+            if v:
+                args[prop] = v
+
+        return args
+
+    def get_existing_objs(self):
+        return self.xos_model.objects.filter(login_base = self.obj_name)
+
+    def postprocess(self, obj):
+        results = []
+        for reqs in self.nodetemplate.requirements:
+            for (k,v) in reqs.items():
+                if (v["relationship"] == "tosca.relationships.SiteDeployment"):
+                    deployment_name = v["node"]
+                    deployment = self.get_xos_object(Deployment, name=deployment_name)
+
+                    controller_name = None
+                    for sd_req in v.get("requirements", []):
+                        for (sd_req_k, sd_req_v) in sd_req.items():
+                            if sd_req_v["relationship"] == "tosca.relationships.UsesController":
+                                controller_name = sd_req_v["node"]
+                    if controller_name:
+                        controller = self.get_xos_object(Controller, name=controller_name, throw_exception=True)
+                    else:
+                        controller = None
+                        # raise Exception("Controller must be specified in SiteDeployment relationship")
+
+                    existing_sitedeps = SiteDeployment.objects.filter(deployment=deployment, site=obj)
+                    if existing_sitedeps:
+                        sd = existing_sitedeps[0]
+                        if (sd.controller != controller) and (controller != None):
+                            sd.controller = controller
+                            sd.save()
+                            self.info("SiteDeployment from %s to %s updated controller" % (str(obj), str(deployment)))
+                        else:
+                            self.info("SiteDeployment from %s to %s already exists" % (str(obj), str(deployment)))
+                    else:
+                        sitedep = SiteDeployment(deployment=deployment, site=obj, controller=controller)
+                        sitedep.save()
+                        self.info("Created SiteDeployment from %s to %s" % (str(obj), str(deployment)))
+
+    def delete(self, obj):
+        if obj.slices.exists():
+            self.info("Site %s has active slices; skipping delete" % obj.name)
+            return
+        if obj.users.exists():
+            self.info("Site %s has active users; skipping delete" % obj.name)
+            return
+        if obj.nodes.exists():
+            self.info("Site %s has active nodes; skipping delete" % obj.name)
+            return
+        super(XOSSite, self).delete(obj)
+
+
+
diff --git a/xos/tosca/run.py b/xos/tosca/run.py
new file mode 100755
index 0000000..0ba2df9
--- /dev/null
+++ b/xos/tosca/run.py
@@ -0,0 +1,34 @@
+import os
+import sys
+
+# add the parent directory to sys.path
+import os,sys,inspect
+currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
+parentdir = os.path.dirname(currentdir)
+sys.path.append(parentdir)
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
+import django
+django.setup()
+
+from core.models import User
+from tosca.engine import XOSTosca
+
+def main():
+    if len(sys.argv)<3:
+        print "Syntax: run.py <username> <yaml-template-name>"
+        sys.exit(-1)
+
+    username = sys.argv[1]
+    template_name = sys.argv[2]
+
+    if username.lower()=="none":
+        u=None
+    else:
+        u = User.objects.get(email=username)
+
+    xt = XOSTosca(file(template_name).read(), parent_dir=currentdir, log_to_console=True)
+    xt.execute(u)
+
+if __name__=="__main__":
+    main()
diff --git a/xos/tosca/samples/cdn.yaml b/xos/tosca/samples/cdn.yaml
new file mode 100644
index 0000000..e5a817c
--- /dev/null
+++ b/xos/tosca/samples/cdn.yaml
@@ -0,0 +1,259 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Template for deploying a single server with predefined properties.
+
+imports:
+   - custom_types/xos.yaml
+   - custom_types/cdn.yaml
+
+dsl_definitions:
+       large_compute_node: &large_compute_node
+           disk_size: 80 GB
+           mem_size: 8 GB
+           num_cpus: 4
+       small_compute_node: &small_compute_node
+           disk_size: 20 GB
+           mem_size: 2 GB
+           num_cpus: 1
+       hpc_os: &hpc_os
+           architecture: x86_64
+           type: linux
+           distribution: centos
+           version: 5.5
+
+topology_template:
+  node_templates:
+    HyperCache:
+      type: tosca.nodes.CDNService
+      description: Content Delivery Network
+      properties:
+          view_url: /admin/hpc/hpcservice/$id$/
+          icon_url: /static/primarycons_blue/network.png
+
+    mysite:
+      type: tosca.nodes.Site
+
+    mysite_cmi:
+      description: CMI Slice
+      type: tosca.nodes.Slice
+      requirements:
+          - cdn_service:
+              node: HyperCache
+              relationship: tosca.relationships.MemberOfService
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+
+    mysite_hpc:
+      description: HyperCache Slice
+      type: tosca.nodes.Slice
+      requirements:
+          - cdn_service:
+              node: HyperCache
+              relationship: tosca.relationships.MemberOfService
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+
+    mysite_dnsredir:
+      description: HyperCache Slice
+      type: tosca.nodes.Slice
+      requirements:
+          - cdn_service:
+              node: HyperCache
+              relationship: tosca.relationships.MemberOfService
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+
+    mysite_dnsdemux:
+      description: HyperCache Slice
+      type: tosca.nodes.Slice
+      requirements:
+          - cdn_service:
+              node: HyperCache
+              relationship: tosca.relationships.MemberOfService
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+
+    cmi_server:
+      type: tosca.nodes.Compute
+      capabilities:
+        host:
+          properties: *large_compute_node
+        os:
+          properties: *hpc_os
+      requirements:
+          - slice:
+                node: mysite_cmi
+                relationship: tosca.relationships.MemberOfSlice
+
+    hpc_server:
+      type: tosca.nodes.Compute
+      capabilities:
+        host:
+          properties: *large_compute_node
+        os:
+          properties: *hpc_os
+      requirements:
+          - slice:
+                node: mysite_hpc
+                relationship: tosca.relationships.MemberOfSlice
+
+    dnsredir_server:
+      type: tosca.nodes.Compute
+      capabilities:
+        host:
+          properties: *small_compute_node
+        os:
+          properties: *hpc_os
+      requirements:
+          - slice:
+                node: mysite_dnsredir
+                relationship: tosca.relationships.MemberOfSlice
+
+    dnsdemux_server:
+      type: tosca.nodes.Compute
+      capabilities:
+        host:
+          properties: *small_compute_node
+        os:
+          properties: *hpc_os
+      requirements:
+          - slice:
+                node: mysite_dnsdemux
+                relationship: tosca.relationships.MemberOfSlice
+          - colocate:
+                node: dnsredir_server
+                relationship: tosca.relationships.SameHost
+
+   # Setup the CDN Service Provider
+
+    main_service_provider:
+        type: tosca.nodes.ServiceProvider
+        requirements:
+           - hpc_service:
+                 node: HyperCache
+                 relationship: tosca.relationships.MemberOfService
+
+    # Wall Street Journal Content Provider
+
+    wsj_content:
+        type: tosca.nodes.ContentProvider
+        requirements:
+            - service_provider:
+                  node: main_service_provider
+                  relationship: tosca.relationships.MemberOfServiceProvider
+
+    www.wsj.com:
+        type: tosca.nodes.CDNPrefix
+        requirements:
+             - content_provider:
+                   node: wsj_content
+                   relationship: tosca.relationships.MemberOfContentProvider
+             - default_origin_server:
+                   node: http_www.wsj.com
+                   relationship: tosca.relationships.DefaultOriginServer
+
+    si.wsj.net:
+        type: tosca.nodes.CDNPrefix
+        requirements:
+             - content_provider:
+                   node: wsj_content
+                   relationship: tosca.relationships.MemberOfContentProvider
+             - default_origin_server:
+                   node: http_si.wsj.net
+                   relationship: tosca.relationships.DefaultOriginServer
+
+    s.wsj.net:
+        type: tosca.nodes.CDNPrefix
+        requirements:
+             - content_provider:
+                   node: wsj_content
+                   relationship: tosca.relationships.MemberOfContentProvider
+             - default_origin_server:
+                   node: http_s.wsj.net
+                   relationship: tosca.relationships.DefaultOriginServer
+
+    ore.wsj.net:
+        type: tosca.nodes.CDNPrefix
+        requirements:
+             - content_provider:
+                   node: wsj_content
+                   relationship: tosca.relationships.MemberOfContentProvider
+             - default_origin_server:
+                   node: http_ore.wsj.net
+                   relationship: tosca.relationships.DefaultOriginServer
+
+    http_www.wsj.com:
+        type: tosca.nodes.OriginServer
+        requirements:
+             - content_provider:
+                   node: wsj_content
+                   relationship: tosca.relationships.MemberOfContentProvider
+
+    http_si.wsj.net:
+        type: tosca.nodes.OriginServer
+        requirements:
+             - content_provider:
+                   node: wsj_content
+                   relationship: tosca.relationships.MemberOfContentProvider
+
+    http_s.wsj.net:
+        type: tosca.nodes.OriginServer
+        requirements:
+             - content_provider:
+                   node: wsj_content
+                   relationship: tosca.relationships.MemberOfContentProvider
+
+    http_ore.wsj.net:
+        type: tosca.nodes.OriginServer
+        requirements:
+             - content_provider:
+                   node: wsj_content
+                   relationship: tosca.relationships.MemberOfContentProvider
+
+    # ON.Lab content provider
+
+    on_lab_content:
+        type: tosca.nodes.ContentProvider
+        requirements:
+            - service_provider:
+                  node: main_service_provider
+                  relationship: tosca.relationships.MemberOfServiceProvider
+
+    downloads.onosproject.org:
+        type: tosca.nodes.CDNPrefix
+        requirements:
+             - content_provider:
+                   node: on_lab_content
+                   relationship: tosca.relationships.MemberOfContentProvider
+             - default_origin_server:
+                   node: http_downloads.onosproject.org
+                   relationship: tosca.relationships.DefaultOriginServer
+
+    onlab.vicci.org:
+        type: tosca.nodes.CDNPrefix
+        requirements:
+             - content_provider:
+                   node: on_lab_content
+                   relationship: tosca.relationships.MemberOfContentProvider
+             - default_origin_server:
+                   node: http_onlab.vicci.org
+                   relationship: tosca.relationships.DefaultOriginServer
+
+    http_downloads.onosproject.org:
+        type: tosca.nodes.OriginServer
+        requirements:
+             - content_provider:
+                   node: on_lab_content
+                   relationship: tosca.relationships.MemberOfContentProvider
+
+    http_onlab.vicci.org:
+        type: tosca.nodes.OriginServer
+        requirements:
+             - content_provider:
+                   node: on_lab_content
+                   relationship: tosca.relationships.MemberOfContentProvider
+
diff --git a/xos/tosca/samples/ceilometer.yaml b/xos/tosca/samples/ceilometer.yaml
new file mode 100644
index 0000000..9797d59
--- /dev/null
+++ b/xos/tosca/samples/ceilometer.yaml
@@ -0,0 +1,53 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Setup CORD-related services -- vOLT, vCPE, vBNG.
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    service_ceilometer:
+      type: tosca.nodes.Service
+      requirements:
+      properties:
+          view_url: /admin/ceilometer/ceilometerservice/$id$/
+          kind: ceilometer
+#          public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }
+#      artifacts:
+#          pubkey: /opt/xos/observers/vcpe/vcpe_public_key
+
+
+    Private:
+      type: tosca.nodes.NetworkTemplate
+
+    ceilometer_network:
+      type: tosca.nodes.network.Network.XOS

+      properties:

+          ip_version: 4

+          labels: ceilometer_client_access

+      requirements:

+          - network_template:

+              node: Private

+              relationship: tosca.relationships.UsesNetworkTemplate

+          - owner:

+              node: mysite_ceilometer

+              relationship: tosca.relationships.MemberOfSlice

+          - connection:

+              node: mysite_ceilometer

+              relationship: tosca.relationships.ConnectsToSlice
+
+    mysite:
+      type: tosca.nodes.Site
+
+    mysite_ceilometer:
+      description: Ceilometer Proxy Slice
+      type: tosca.nodes.Slice
+      requirements:
+          - ceilometer_service:
+              node: service_ceilometer
+              relationship: tosca.relationships.MemberOfService
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+
diff --git a/xos/tosca/samples/composition.yaml b/xos/tosca/samples/composition.yaml
new file mode 100644
index 0000000..7b9db03
--- /dev/null
+++ b/xos/tosca/samples/composition.yaml
@@ -0,0 +1,95 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Two services "service_one" and "service_two" with a tenancy relationship.
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    # setup the services
+
+    service_one:
+      type: tosca.nodes.Service
+      requirements:
+          - two_tenant:
+              node: service_two
+              relationship: tosca.relationships.TenantOfService
+
+    service_two:
+      type: tosca.nodes.Service
+
+    # the slices will need a site
+
+    mysite:
+      type: tosca.nodes.Site
+
+    # setup the slices
+
+    mysite_one:
+      description: Service One controller Slice
+      type: tosca.nodes.Slice
+      requirements:
+          - service:
+              node: service_one
+              relationship: tosca.relationships.MemberOfService
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+
+    mysite_two:
+      description: Service Two controller Slice
+      type: tosca.nodes.Slice
+      requirements:
+          - service:
+              node: service_two
+              relationship: tosca.relationships.MemberOfService
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+
+    # setup an instance in each slice
+
+    one_controller:
+      type: tosca.nodes.Compute
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+        # Guest Operating System properties
+        os:
+          properties:
+            # host Operating System image properties
+            architecture: x86_64
+            type: linux
+            distribution: rhel
+            version: 6.5
+      requirements:
+          - slice:
+                node: mysite_one
+                relationship: tosca.relationships.MemberOfSlice
+
+    two_controller:
+      type: tosca.nodes.Compute
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+        # Guest Operating System properties
+        os:
+          properties:
+            # host Operating System image properties
+            architecture: x86_64
+            type: linux
+            distribution: rhel
+            version: 6.5
+      requirements:
+          - slice:
+                node: mysite_two
+                relationship: tosca.relationships.MemberOfSlice
diff --git a/xos/tosca/samples/container.yaml b/xos/tosca/samples/container.yaml
new file mode 100644
index 0000000..bd69fbe
--- /dev/null
+++ b/xos/tosca/samples/container.yaml
@@ -0,0 +1,42 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Template for deploying a single server with predefined properties.
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    mysite:
+      type: tosca.nodes.Site
+
+    mysite_contest:
+      type: tosca.nodes.Slice
+      requirements:
+          - slice:
+                node: mysite
+                relationship: tosca.relationships.MemberOfSite
+
+    andybavier/docker-vcpe:
+      type: tosca.nodes.Image
+      properties:
+        kind: container
+        container_format: na
+        disk_format: na
+
+    my_container:
+      type: tosca.nodes.Compute.Container
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+      requirements:
+          - slice:
+                node: mysite_contest
+                relationship: tosca.relationships.MemberOfSlice
+          - image:
+                node: andybavier/docker-vcpe
+                relationship: tosca.relationships.UsesImage
diff --git a/xos/tosca/samples/container_slice.yaml b/xos/tosca/samples/container_slice.yaml
new file mode 100644
index 0000000..520bec0
--- /dev/null
+++ b/xos/tosca/samples/container_slice.yaml
@@ -0,0 +1,24 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+    * Create a new deployment, controller, and site.
+    * Add a SiteDeployment from the site to the deployment using the controller.
+    * Create a Slice in the Site, with one Instance
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    mysite:
+      type: tosca.nodes.Site
+
+    mysite_containers:
+      type: tosca.nodes.Slice
+      requirements:
+          - slice:
+                node: mysite
+                relationship: tosca.relationships.MemberOfSite
+      properties:
+          default_isolation: container
+
diff --git a/xos/tosca/samples/cord-cloudlab.yaml b/xos/tosca/samples/cord-cloudlab.yaml
new file mode 100644
index 0000000..20e8057
--- /dev/null
+++ b/xos/tosca/samples/cord-cloudlab.yaml
@@ -0,0 +1,101 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Setup CORD-related services -- vOLT, vCPE, vBNG.
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    # CORD Services
+    service_volt:
+      type: tosca.nodes.Service
+      requirements:
+          - vcpe_tenant:
+              node: service_vcpe
+              relationship: tosca.relationships.TenantOfService
+      properties:
+          view_url: /admin/cord/voltservice/$id$/
+          kind: vOLT
+
+    service_vcpe:
+      type: tosca.nodes.VCPEService
+      requirements:
+          - vbng_tenant:
+              node: service_vbng
+              relationship: tosca.relationships.TenantOfService
+      properties:
+          view_url: /admin/cord/vcpeservice/$id$/
+          backend_network_label: hpc_client
+          public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }
+      artifacts:
+          pubkey: /opt/xos/observers/vcpe/vcpe_public_key
+
+    service_vbng:
+      type: tosca.nodes.VBNGService
+      properties:
+          view_url: /admin/cord/vbngservice/$id$/
+          vbng_url: http://10.0.3.136:8181/onos/virtualbng/
+
+    mysite:
+      type: tosca.nodes.Site
+
+    Private:
+      type: tosca.nodes.NetworkTemplate
+
+    # networks required by vCPE
+    lan_network:
+      type: tosca.nodes.network.Network
+      properties:
+          ip_version: 4
+      requirements:
+          - network_template:
+              node: Private
+              relationship: tosca.relationships.UsesNetworkTemplate
+          - owner:
+              node: mysite_vcpe
+              relationship: tosca.relationships.MemberOfSlice
+          - connection:
+              node: mysite_vcpe
+              relationship: tosca.relationships.ConnectsToSlice
+
+    wan_network:
+      type: tosca.nodes.network.Network
+      properties:
+          ip_version: 4
+      requirements:
+          - network_template:
+              node: Private
+              relationship: tosca.relationships.UsesNetworkTemplate
+          - owner:
+              node: mysite_vcpe
+              relationship: tosca.relationships.MemberOfSlice
+          - connection:
+              node: mysite_vcpe
+              relationship: tosca.relationships.ConnectsToSlice
+
+    hpc_client_network:
+      type: tosca.nodes.network.Network
+      properties:
+          ip_version: 4
+      requirements:
+          - network_template:
+              node: Private
+              relationship: tosca.relationships.UsesNetworkTemplate
+          - owner:
+              node: mysite_vcpe
+              relationship: tosca.relationships.MemberOfSlice
+          - connection:
+              node: mysite_vcpe
+              relationship: tosca.relationships.ConnectsToSlice
+
+    mysite_vcpe:
+      description: vCPE Controller Slice
+      type: tosca.nodes.Slice
+      requirements:
+          - vcpe_service:
+              node: service_vcpe
+              relationship: tosca.relationships.MemberOfService
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
diff --git a/xos/tosca/samples/dashboardview.yaml b/xos/tosca/samples/dashboardview.yaml
new file mode 100644
index 0000000..2a358f2
--- /dev/null
+++ b/xos/tosca/samples/dashboardview.yaml
@@ -0,0 +1,34 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Dashboard View
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    Ceilometer:
+      type: tosca.nodes.DashboardView
+      properties:
+          url: http:/xosmetering/
+
+    Tenant:
+      type: tosca.nodes.DashboardView
+      properties:
+          no-create: true
+          no-update: true
+          no-delete: true
+
+    padmin@vicci.org:
+      type: tosca.nodes.User
+      properties:
+          firstname: XOS
+          lastname: admin
+          is_admin: true
+      requirements:
+          - tenant_dashboard:
+              node: Tenant
+              relationship: tosca.relationships.UsesDashboard
+          - ceilometer_dashboard:
+              node: Ceilometer
+              relationship: tosca.relationships.UsesDashboard
diff --git a/xos/tosca/samples/exampleservice.yaml b/xos/tosca/samples/exampleservice.yaml
new file mode 100644
index 0000000..5b90ce2
--- /dev/null
+++ b/xos/tosca/samples/exampleservice.yaml
@@ -0,0 +1,47 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Setup the ExampleService
+
+imports:
+   - custom_types/xos.yaml
+   - custom_types/exampleservice.yaml
+
+topology_template:
+  node_templates:
+
+    mysite:
+      type: tosca.nodes.Site
+
+    mysite_exampleservice:
+      description: This slice holds the ExampleService
+      type: tosca.nodes.Slice
+
+      requirements:
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+          - exmapleserver:
+              node: service#exampleservice
+              relationship: tosca.relationships.MemberOfService
+
+    service#exampleservice:
+      type: tosca.nodes.ExampleService
+      properties:
+          view_url: /admin/exampleservice/exampleservice/$id$/
+          kind: exampleservice
+          public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }
+          private_key_fn: /opt/xos/synchronizers/exampleservice/exampleservice_private_key
+          service_message: hello
+      artifacts:
+          pubkey: /opt/xos/synchronizers/exampleservice/exampleservice_public_key
+
+
+    tenant#exampletenant1:
+        type: tosca.nodes.ExampleTenant
+        properties:
+            tenant_message: world
+        requirements:
+          - tenant:
+              node: service#exampleservice
+              relationship: tosca.relationships.TenantOfService
+
diff --git a/xos/tosca/samples/network_templates.yaml b/xos/tosca/samples/network_templates.yaml
new file mode 100644
index 0000000..5941079
--- /dev/null
+++ b/xos/tosca/samples/network_templates.yaml
@@ -0,0 +1,22 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Make some network templates
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    template1:
+      type: tosca.nodes.NetworkTemplate
+
+    template2:
+      type: tosca.nodes.NetworkTemplate
+      properties:
+          visibility: public
+          translation: NAT
+          shared_network_name: two
+          shared_network_id: 2222
+          topology_kind: bigswitch
+          controller_kind: onos
+
diff --git a/xos/tosca/samples/new_site_deploy_slice.yaml b/xos/tosca/samples/new_site_deploy_slice.yaml
new file mode 100644
index 0000000..5e36bcb
--- /dev/null
+++ b/xos/tosca/samples/new_site_deploy_slice.yaml
@@ -0,0 +1,75 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+    * Create a new deployment, controller, and site.
+    * Add a SiteDeployment from the site to the deployment using the controller.
+    * Create a Slice in the Site, with one Instance
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    newdeployment:
+      type: tosca.nodes.Deployment
+
+    newcontroller:
+      type: tosca.nodes.Controller
+      requirements:
+          - deployment:
+              node: newdeployment
+              relationship: tosca.relationships.ControllerDeployment
+      properties:
+           backend_type: openstack
+           version: v1.23.4
+           auth_url: http://foo/
+           admin_user: johndoe
+           admin_password: letmeout
+           admin_tenant: 12345678
+           domain: mydomain
+           rabbit_host: rabhost
+           rabbit_user: rabuser
+           rabbit_password: rabpw
+
+    newsite:
+      type: tosca.nodes.Site
+      properties:
+          display_name: some new site
+          site_url: http://newsite.org/
+      requirements:
+          - deployment:
+               node: newdeployment
+               relationship: tosca.relationships.SiteDeployment
+               requirements:
+                   - controller:
+                       node: newcontroller
+                       relationship: tosca.relationships.UsesController
+
+    newsite_tosca:
+      type: tosca.nodes.Slice
+      requirements:
+          - slice:
+                node: newsite
+                relationship: tosca.relationships.MemberOfSite
+
+    my_server:
+      type: tosca.nodes.Compute
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+        # Guest Operating System properties
+        os:
+          properties:
+            # host Operating System image properties
+            architecture: x86_64
+            type: linux
+            distribution: rhel
+            version: 6.5
+      requirements:
+          - slice:
+                node: newsite_tosca
+                relationship: tosca.relationships.MemberOfSlice
diff --git a/xos/tosca/samples/one_instance.yaml b/xos/tosca/samples/one_instance.yaml
new file mode 100644
index 0000000..f8919ed
--- /dev/null
+++ b/xos/tosca/samples/one_instance.yaml
@@ -0,0 +1,40 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Template for deploying a single server with predefined properties.
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    mysite:
+      type: tosca.nodes.Site
+
+    mysite_tosca:
+      type: tosca.nodes.Slice
+      requirements:
+          - slice:
+                node: mysite
+                relationship: tosca.relationships.MemberOfSite
+
+    my_server:
+      type: tosca.nodes.Compute
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+        # Guest Operating System properties
+        os:
+          properties:
+            # host Operating System image properties
+            architecture: x86_64
+            type: linux
+            distribution: rhel
+            version: 6.5
+      requirements:
+          - slice:
+                node: mysite_tosca
+                relationship: tosca.relationships.MemberOfSlice
diff --git a/xos/tosca/samples/onos.yaml b/xos/tosca/samples/onos.yaml
new file mode 100644
index 0000000..abb0268
--- /dev/null
+++ b/xos/tosca/samples/onos.yaml
@@ -0,0 +1,102 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Setup CORD-related services -- vOLT, vCPE, vBNG.
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    ONOS:
+      type: tosca.nodes.ONOSService
+      requirements:
+      properties:
+          kind: onos
+          view_url: /admin/onos/onosservice/$id$/
+          public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }
+      artifacts:
+          pubkey: /opt/xos/synchronizers/onos/onos_key.pub
+
+    vBNG:
+      type: tosca.nodes.ONOSvBNGApp
+      requirements:
+          - onos_tenant:
+              node: ONOS
+              relationship: tosca.relationships.TenantOfService
+      properties:
+          dependencies: org.onosproject.proxyarp, org.onosproject.virtualbng, org.onosproject.openflow, org.onosproject.fwd
+          config_addresses.json: >
+            {
+                "addresses" : [

+                            {

+                                "dpid" : "00:00:00:00:00:00:00:a1",

+                                "port" : "2",

+                                "ips" : ["192.0.0.1/24"],

+                                "mac" : "00:00:00:00:00:99"

+

+                            },

+                            {

+                                "dpid" : "00:00:00:00:00:00:00:a5",

+                                "port" : "4",

+                                "ips" : ["200.0.0.5/24"],

+                                "mac" : "00:00:00:00:00:98"

+                            }

+                ]

+            }
+          config_virtualbng.json: >
+            {
+                "localPublicIpPrefixes" : [

+                    "200.0.0.0/32",

+                    "201.0.0.0/30",

+                    "202.0.0.0/30"

+                ],

+                "nextHopIpAddress" : "200.0.0.5",

+                "publicFacingMac" : "00:00:00:00:00:66",

+                "xosIpAddress" : "10.11.10.1",

+                "xosRestPort" : "9999"

+            }
+
+    vOLT:
+      type: tosca.nodes.ONOSvOLTApp
+      requirements:
+          - onos_tenant:
+              node: ONOS
+              relationship: tosca.relationships.TenantOfService
+      properties:
+          dependencies: org.onosproject.olt
+
+    mysite:
+      type: tosca.nodes.Site
+
+    mysite_onos:
+      description: ONOS Controller Slice
+      type: tosca.nodes.Slice
+      requirements:
+          - ONOS:
+              node: ONOS
+              relationship: tosca.relationships.MemberOfService
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+
+    my_server:
+      type: tosca.nodes.Compute
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+        # Guest Operating System properties
+        os:
+          properties:
+            # host Operating System image properties
+            architecture: x86_64
+            type: linux
+            distribution: Ubuntu
+            version: 14.10
+      requirements:
+          - slice:
+                node: mysite_onos
+                relationship: tosca.relationships.MemberOfSlice
diff --git a/xos/tosca/samples/privileges.yaml b/xos/tosca/samples/privileges.yaml
new file mode 100644
index 0000000..d15f343
--- /dev/null
+++ b/xos/tosca/samples/privileges.yaml
@@ -0,0 +1,60 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Make some network templates
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    mysite:
+      type: tosca.nodes.Site
+
+    johndoe@foo.bar:
+      type: tosca.nodes.User
+      properties:
+          password: letmein
+          firstname: john
+          lastname: doe
+      requirements:
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+          # Site privilege must always be specified in user objects, since
+          # user depends on site.
+          - privilege:
+              node: mysite
+              relationship: tosca.relationships.PIPrivilege
+
+    janedoe@foo.bar:
+      type: tosca.nodes.User
+      properties:
+          password: letmein
+          firstname: john
+          lastname: doe
+      requirements:
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+          - privilege:
+              node: mysite
+              relationship: tosca.relationships.TechPrivilege
+
+    privsite:
+      type: tosca.nodes.Site
+
+    privsite_slice1:
+      type: tosca.nodes.Slice
+      requirements:
+          - slice:
+                node: privsite
+                relationship: tosca.relationships.MemberOfSite
+          # Slice privileges must always be specified in slice objects, since
+          # slice depends on user.
+          - privilege:
+                node: johndoe@foo.bar
+                relationship: tosca.relationships.AdminPrivilege
+          - privilege:
+                node: janedoe@foo.bar
+                relationship: tosca.relationships.AccessPrivilege
+
diff --git a/xos/tosca/samples/scalable_instance.yaml b/xos/tosca/samples/scalable_instance.yaml
new file mode 100644
index 0000000..b3daa3f
--- /dev/null
+++ b/xos/tosca/samples/scalable_instance.yaml
@@ -0,0 +1,45 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Template for deploying a single server with predefined properties.
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    mysite:
+      type: tosca.nodes.Site
+
+    mysite_tosca_scalable:
+      type: tosca.nodes.Slice
+      requirements:
+          - slice:
+                node: mysite
+                relationship: tosca.relationships.MemberOfSite
+
+    my_scalable_server:
+      type: tosca.nodes.Compute
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+        scalable:
+         properties:
+           min_instances: 1
+           max_instances: 25
+           default_instances: 13
+        # Guest Operating System properties
+        os:
+          properties:
+            # host Operating System image properties
+            architecture: x86_64
+            type: linux
+            distribution: rhel
+            version: 6.5
+      requirements:
+          - slice:
+                node: mysite_tosca_scalable
+                relationship: tosca.relationships.MemberOfSlice
diff --git a/xos/tosca/samples/scalable_service.yaml b/xos/tosca/samples/scalable_service.yaml
new file mode 100644
index 0000000..bbcb297
--- /dev/null
+++ b/xos/tosca/samples/scalable_service.yaml
@@ -0,0 +1,17 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Template for deploying a single server with predefined properties.
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    scalable_service:
+      type: tosca.nodes.Service
+      capabilities:
+          scalable:
+              properties:
+                  max_instances: 25
+                  min_instances: 1
+                  default_instances: 1
diff --git a/xos/tosca/samples/slice_default_image.yaml b/xos/tosca/samples/slice_default_image.yaml
new file mode 100644
index 0000000..ff63373
--- /dev/null
+++ b/xos/tosca/samples/slice_default_image.yaml
@@ -0,0 +1,33 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+    * Create a new deployment, controller, and site.
+    * Add a SiteDeployment from the site to the deployment using the controller.
+    * Create a Slice in the Site, with one Instance
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    mysite:
+      type: tosca.nodes.Site
+
+    trusty-server-multi-nic:
+      type: tosca.nodes.Image
+
+    m1.small:
+      type: tosca.nodes.Flavor
+
+    mysite_test1:
+      type: tosca.nodes.Slice
+      requirements:
+          - slice:
+                node: mysite
+                relationship: tosca.relationships.MemberOfSite
+          - default_image:
+                node: trusty-server-multi-nic
+                relationship: tosca.relationships.DefaultImage
+          -default_flavor:
+                node: m1.small
+                relationship: tosca.relationships.DefaultFlavor
diff --git a/xos/tosca/samples/slicetag.yaml b/xos/tosca/samples/slicetag.yaml
new file mode 100644
index 0000000..ec064e3
--- /dev/null
+++ b/xos/tosca/samples/slicetag.yaml
@@ -0,0 +1,35 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Setup CORD-related services -- vOLT, vCPE, vBNG.
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    mysite_vsg:
+      type: tosca.nodes.Slice
+      properties:
+          no-create: True
+          no-delete: True
+          no-update: True
+
+    service_vsg:
+      type: tosca.nodes.Service
+      properties:
+          no-create: True
+          no-delete: True
+          no-update: True
+
+    mysite_vsg_foobar_tag:
+      type: tosca.nodes.Tag
+      properties:
+          name: foobar
+          value: xyz
+      requirements:
+          - target:
+              node: mysite_vsg
+              relationship: tosca.relationships.TagsObject
+          - service:
+              node: service_vsg
+              relationship: tosca.relationships.MemberOfService
diff --git a/xos/tosca/samples/two_slices_shared_private_net.yaml b/xos/tosca/samples/two_slices_shared_private_net.yaml
new file mode 100644
index 0000000..4646f9e
--- /dev/null
+++ b/xos/tosca/samples/two_slices_shared_private_net.yaml
@@ -0,0 +1,110 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Template for deploying a single server with predefined properties.
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    mysite:
+      type: tosca.nodes.Site
+
+    Private:
+      type: tosca.nodes.NetworkTemplate
+
+    producer_private_network:
+      type: tosca.nodes.network.Network
+      properties:
+          ip_version: 4
+      requirements:
+          - network_template:
+              node: Private
+              relationship: tosca.relationships.UsesNetworkTemplate
+          - slice:
+              node: mysite_producer
+              relationship: tosca.relationships.MemberOfSlice
+
+    mysite_producer:
+      type: tosca.nodes.Slice
+      requirements:
+          - slice:
+                node: mysite
+                relationship: tosca.relationships.MemberOfSite
+
+    mysite_consumer:
+      type: tosca.nodes.Slice
+      requirements:
+          - slice:
+                node: mysite
+                relationship: tosca.relationships.MemberOfSite
+          - network:
+                node: producer_private_network
+                relationship: tosca.relationships.ConnectsToNetwork
+
+    producer_server:
+      type: tosca.nodes.Compute
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+        # Guest Operating System properties
+        os:
+          properties:
+            # host Operating System image properties
+            architecture: x86_64
+            type: linux
+            distribution: rhel
+            version: 6.5
+      requirements:
+          - slice:
+                node: mysite_producer
+                relationship: tosca.relationships.MemberOfSlice
+
+    consumer_server:
+      type: tosca.nodes.Compute
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+        # Guest Operating System properties
+        os:
+          properties:
+            # host Operating System image properties
+            architecture: x86_64
+            type: linux
+            distribution: rhel
+            version: 6.5
+      requirements:
+          - slice:
+                node: mysite_consumer
+                relationship: tosca.relationships.MemberOfSlice
+
+    producer_pvt_net_port:
+        type: tosca.nodes.network.Port
+        requirements:
+            - link:
+                  node: producer_private_network
+                  relationship: tosca.relationships.network.LinksTo
+            - binding:
+                  node: producer_server
+                  relationship: tosca.relationships.network.BindsTo
+
+    consumer_pvt_net_port:
+        type: tosca.nodes.network.Port
+        requirements:
+            - link:
+                  node: producer_private_network
+                  relationship: tosca.relationships.network.LinksTo
+            - binding:
+                  node: consumer_server
+                  relationship: tosca.relationships.network.BindsTo
+
+
+
diff --git a/xos/tosca/samples/two_slices_two_networks.yaml b/xos/tosca/samples/two_slices_two_networks.yaml
new file mode 100644
index 0000000..080a6f0
--- /dev/null
+++ b/xos/tosca/samples/two_slices_two_networks.yaml
@@ -0,0 +1,69 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Template for deploying a single server with predefined properties.
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    mysite:
+      type: tosca.nodes.Site
+
+    Private:
+      type: tosca.nodes.NetworkTemplate
+
+    # this one lets XOS auto-allocate a subnet
+    producer_private_network:
+      type: tosca.nodes.network.Network
+      properties:
+          ip_version: 4
+      requirements:
+          - network_template:
+              node: Private
+              relationship: tosca.relationships.UsesNetworkTemplate
+          - slice:
+              node: mysite_producer
+              relationship: tosca.relationships.MemberOfSlice
+          - slice:
+              node: mysite_producer
+              relationship: tosca.relationships.ConnectsToSlice
+
+    # this one specifies the subnet to use
+    producer_private_network2:
+      type: tosca.nodes.network.Network
+      properties:
+          ip_version: 4
+          cidr: 123.123.0.0/16
+      requirements:
+          - network_template:
+              node: Private
+              relationship: tosca.relationships.UsesNetworkTemplate
+          - slice:
+              node: mysite_producer
+              relationship: tosca.relationships.MemberOfSlice
+          - slice:
+              node: mysite_producer
+              relationship: tosca.relationships.ConnectsToSlice
+
+    mysite_producer:
+      type: tosca.nodes.Slice
+      requirements:
+          - slice:
+                node: mysite
+                relationship: tosca.relationships.MemberOfSite
+
+    mysite_consumer:
+      type: tosca.nodes.Slice
+      requirements:
+          - slice:
+                node: mysite
+                relationship: tosca.relationships.MemberOfSite
+          - network:
+                node: producer_private_network
+                relationship: tosca.relationships.ConnectsToNetwork
+          - network2:
+                node: producer_private_network2
+                relationship: tosca.relationships.ConnectsToNetwork
+
+
diff --git a/xos/tosca/samples/users.yaml b/xos/tosca/samples/users.yaml
new file mode 100644
index 0000000..20da611
--- /dev/null
+++ b/xos/tosca/samples/users.yaml
@@ -0,0 +1,39 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Make some network templates
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    mysite:
+      type: tosca.nodes.Site
+
+    johndoe@foo.bar:
+      type: tosca.nodes.User
+      properties:
+          password: letmein
+          firstname: john
+          lastname: doe
+      requirements:
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+
+    janedoe@foo.bar:
+      type: tosca.nodes.User
+      properties:
+          password: letmeintoo
+          firstname: jane
+          lastname: doe
+          phone: 111-222-3333
+          user_url: http://janedoe/
+          public_key: asdlfkjasldkfjasldkjfhaslkdjfhglaskdjfhlaksjdhfkasdfasdf
+          is_active: true
+          is_admin: true
+      requirements:
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+
diff --git a/xos/tosca/samples/vtn-external.yaml b/xos/tosca/samples/vtn-external.yaml
new file mode 100644
index 0000000..ee41ac8
--- /dev/null
+++ b/xos/tosca/samples/vtn-external.yaml
@@ -0,0 +1,31 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Setup CORD-related services -- vOLT, vCPE, vBNG.
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    service_ONOS_VTN:
+      type: tosca.nodes.ONOSService
+      requirements:
+      properties:
+          kind: onos
+          view_url: /admin/onos/onosservice/$id$/
+          no_container: true
+          rest_hostname: ctl.smbaker-xos-neu.xos-pg0.clemson.cloudlab.us
+
+    VTN_ONOS_app:
+      type: tosca.nodes.ONOSVTNApp
+      requirements:
+          - onos_tenant:
+              node: service_ONOS_VTN
+              relationship: tosca.relationships.TenantOfService
+      properties:
+          dependencies: org.onosproject.drivers, org.onosproject.drivers.ovsdb, org.onosproject.lldpprovider, org.onosproject.openflow-base, org.onosproject.ovsdb-base, org.onosproject.dhcp, org.onosproject.openstackswitching, org.onosproject.cordvtn
+          rest_onos/v1/network/configuration/: { get_artifact: [ SELF, vtn_network_cfg_json, LOCAL_FILE ] }
+      artifacts:
+          vtn_network_cfg_json: /root/setup/vtn-network-cfg.json
+
+
diff --git a/xos/tosca/samples/vtn-service-chain.yaml b/xos/tosca/samples/vtn-service-chain.yaml
new file mode 100644
index 0000000..51933d6
--- /dev/null
+++ b/xos/tosca/samples/vtn-service-chain.yaml
@@ -0,0 +1,157 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Two services "service_one" and "service_two" with a tenancy relationship.
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+
+    Private-Indirect:
+      type: tosca.nodes.NetworkTemplate
+      properties:
+          access: indirect
+
+    management:
+      type: tosca.nodes.network.Network.XOS
+      properties:
+          no-create: true
+          no-delete: true
+          no-update: true
+
+    mysite:
+      type: tosca.nodes.Site
+
+    trusty-server-multi-nic:
+      type: tosca.nodes.Image
+
+    service_vsg:
+      type: tosca.nodes.VSGService
+      requirements:
+          - one_tenant:
+              node: service_one
+              relationship: tosca.relationships.TenantOfService
+      properties:
+          no-create: true
+          no-delete: true
+
+    service_one:
+      type: tosca.nodes.Service
+      requirements:
+          - two_tenant:
+              node: service_two
+              relationship: tosca.relationships.TenantOfService
+      properties:
+          kind: one
+
+    service_two:
+      type: tosca.nodes.Service
+      properties:
+          kind: two
+
+    mysite_one:
+      type: tosca.nodes.Slice
+      properties:
+          network: noauto
+      requirements:
+          - service:
+              node: service_one
+              relationship: tosca.relationships.MemberOfService
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+          - management:
+              node: management
+              relationship: tosca.relationships.ConnectsToNetwork
+
+    mysite_two:
+      type: tosca.nodes.Slice
+      properties:
+          network: noauto
+      requirements:
+          - service:
+              node: service_two
+              relationship: tosca.relationships.MemberOfService
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+          - management:
+              node: management
+              relationship: tosca.relationships.ConnectsToNetwork
+
+    one_access:
+      type: tosca.nodes.network.Network
+      properties:
+          ip_version: 4
+      requirements:
+          - network_template:
+              node: Private-Indirect
+              relationship: tosca.relationships.UsesNetworkTemplate
+          - owner:
+              node: mysite_one
+              relationship: tosca.relationships.MemberOfSlice
+          - connection:
+              node: mysite_one
+              relationship: tosca.relationships.ConnectsToSlice
+
+    two_access:
+      type: tosca.nodes.network.Network
+      properties:
+          ip_version: 4
+      requirements:
+          - network_template:
+              node: Private-Indirect
+              relationship: tosca.relationships.UsesNetworkTemplate
+          - owner:
+              node: mysite_two
+              relationship: tosca.relationships.MemberOfSlice
+          - connection:
+              node: mysite_two
+              relationship: tosca.relationships.ConnectsToSlice
+
+    # Virtual machines
+    one_instance:
+      type: tosca.nodes.Compute
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+        # Guest Operating System properties
+        os:
+          properties:
+            # host Operating System image properties
+            architecture: x86_64
+            type: linux
+            distribution: Ubuntu
+            version: 14.10
+      requirements:
+          - slice:
+                node: mysite_one
+                relationship: tosca.relationships.MemberOfSlice
+
+    # Virtual machines
+    two_instance:
+      type: tosca.nodes.Compute
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+        # Guest Operating System properties
+        os:
+          properties:
+            # host Operating System image properties
+            architecture: x86_64
+            type: linux
+            distribution: Ubuntu
+            version: 14.10
+      requirements:
+          - slice:
+                node: mysite_two
+                relationship: tosca.relationships.MemberOfSlice
diff --git a/xos/tosca/tests/allObserverTests.py b/xos/tosca/tests/allObserverTests.py
new file mode 100644
index 0000000..6a566a9
--- /dev/null
+++ b/xos/tosca/tests/allObserverTests.py
@@ -0,0 +1,14 @@
+from observerVMTest import ObserverVMTest
+from observerContainerTest import ObserverContainerTest
+from observerImageTest import ObserverImageTest
+from observerUserTest import ObserverUserTest
+from observerSiteTest import ObserverSiteTest
+from observerSliceTest import ObserverSliceTest
+
+if __name__ == "__main__":
+    ObserverVMTest()
+    ObserverContainerTest()
+    ObserverImageTest()
+    ObserverSiteTest()
+    ObserverUserTest()
+    ObserverSliceTest()
diff --git a/xos/tosca/tests/alltests.py b/xos/tosca/tests/alltests.py
new file mode 100644
index 0000000..13dfeb8
--- /dev/null
+++ b/xos/tosca/tests/alltests.py
@@ -0,0 +1,28 @@
+from enginetest import EngineTest
+from coarsetenancytest import CoarseTenancyTest
+from porttest import PortTest
+from networktest import NetworkTest
+from servicetest import ServiceTest
+from usertest import UserTest
+from computetest import ComputeTest
+from sitetest import SiteTest
+from deploymenttest import DeploymentTest
+from nodetest import NodeTest
+from slicetest import SliceTest
+from controllertest import ControllerTest
+from imagetest import ImageTest
+
+if __name__ == "__main__":
+    EngineTest()
+    SiteTest()
+    DeploymentTest()
+    ControllerTest()
+    NodeTest()
+    NetworkTest()
+    PortTest()
+    CoarseTenancyTest()
+    ServiceTest()
+    UserTest()
+    SliceTest()
+    ComputeTest()
+    ImageTest()
diff --git a/xos/tosca/tests/basetest.py b/xos/tosca/tests/basetest.py
new file mode 100644
index 0000000..7dda96f
--- /dev/null
+++ b/xos/tosca/tests/basetest.py
@@ -0,0 +1,146 @@
+import os
+import random
+import string
+import sys
+
+# add the parent parent directory to sys.path
+# XXX this is very hackish :(
+import os,sys,inspect
+currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
+parentdir = os.path.dirname(currentdir)
+sys.path.append(parentdir)
+parentparentdir = os.path.dirname(parentdir)
+sys.path.append(parentparentdir)
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
+import django
+django.setup()
+
+from tosca.engine import XOSTosca
+from core.models import User
+
+class BaseToscaTest(object):
+    username = "padmin@vicci.org"
+    base_yaml = \
+"""tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: tosca test case
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+"""
+
+    def __init__(self):
+        self.runtest()
+
+    def make_nodetemplate(self, name, type, props={}, reqs=[], caps={}, artifacts={}):
+        yml = "    %s:\n      type: %s\n"  % (name, type)
+        if props:
+            yml = yml + "      properties:\n"
+            for (k,v) in props.items():
+                yml = yml + "          %s: %s\n" % (k, v)
+
+        if reqs:
+            yml = yml + "      requirements:\n"
+            i=0
+            for (name,relat) in reqs:
+                yml = yml + "        - req%d:\n" % i
+                yml = yml + "              node: %s\n" % name
+                yml = yml + "              relationship: %s\n" % relat
+                i = i + 1
+
+        if caps:
+            yml = yml + "      capabilities:\n"
+            for (cap,capdict) in caps.items():
+               yml = yml + "        %s:\n" % cap
+               yml = yml + "          properties:\n"
+               for (k,v) in capdict.items():
+                   yml = yml + "            %s: %s\n" % (k,v)
+
+        if artifacts:
+            yml = yml + "      artifacts:\n"
+            for (k,v) in artifacts.items():
+                yml = yml + "        %s: %s\n" % (k,v)
+
+        return yml
+
+    def make_compute(self, slice, name, caps={}, props={}, reqs=[], num_cpus="1", disk_size="10 GB", mem_size="4 MB", isolation="vm"):
+        reqs = reqs[:]
+        props = props.copy()
+        caps = caps.copy()
+
+        if isolation=="container":
+            type = "tosca.nodes.Compute.Container"
+        elif isolation=="container_vm":
+            type = "tosca.nodes.Compute.ContainerVM"
+        else:
+            type = "tosca.nodes.Compute"
+
+        caps.update( {"host": {"num_cpus": num_cpus, "disk_size": disk_size, "mem_size": mem_size},
+                      "os": {"architecture": "x86_64", "type": "linux", "distribution": "rhel", "version": "6.5"}} )
+        reqs.append( (slice, "tosca.relationships.MemberOfSlice") )
+
+        return self.make_nodetemplate(name, type,
+                                      caps= caps,
+                                      props = props,
+                                      reqs= reqs)
+
+    def make_user_template(self):
+        return self.make_nodetemplate("test@user.com", "tosca.nodes.User",
+             props = {"firstname": "test", "lastname": "user", "password": "letmein"},
+             reqs = [("testsite", "tosca.relationships.MemberOfSite")])
+
+    def make_random_string(self,desired_len):
+        return ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(desired_len))
+
+    def assert_noobj(self, cls, name):
+        objs = cls.objects.filter(name=name)
+        assert(not objs)
+
+    def assert_obj(self, cls, name, **kwargs):
+        obj = cls.objects.get(name=name)
+        assert(obj)
+        for (k,v) in kwargs.items():
+            if (getattr(obj,k,None) != v):
+                print "Object %s property '%s' is '%s' and should be '%s'" % (obj, k, getattr(obj,k,None), v)
+                assert(False)
+        return obj
+
+    def try_to_delete(self, cls, purge=True, **kwargs):
+        for obj in cls.objects.filter(**kwargs):
+            obj.delete(purge=purge)
+
+        if purge:
+            for obj in cls.deleted_objects.filter(**kwargs):
+                obj.delete(purge=True)
+
+    def execute(self, yml):
+        u = User.objects.get(email=self.username)
+
+        #print self.base_yaml+yml
+
+        xt = XOSTosca(self.base_yaml+yml, parent_dir=parentdir, log_to_console=False)
+        xt.execute(u)
+
+    def destroy(self, yml):
+        u = User.objects.get(email=self.username)
+
+        #print self.base_yaml+yml
+
+        xt = XOSTosca(self.base_yaml+yml, parent_dir=parentdir, log_to_console=False)
+        xt.destroy(u)
+
+    def runtest(self):
+        for test in self.tests:
+            print "running", test
+            self.cleanup()
+            try:
+                getattr(self,test)()
+            finally:
+                self.cleanup()
+
+    def cleanup(self):
+        pass
diff --git a/xos/tosca/tests/coarsetenancytest.py b/xos/tosca/tests/coarsetenancytest.py
new file mode 100644
index 0000000..3da288f
--- /dev/null
+++ b/xos/tosca/tests/coarsetenancytest.py
@@ -0,0 +1,49 @@
+from basetest import BaseToscaTest
+
+from core.models import Service, CoarseTenant
+
+class CoarseTenancyTest(BaseToscaTest):
+    tests = ["create_coarsetenant",
+             "update_coarsetenant"]
+
+    def cleanup(self):
+        self.try_to_delete(Service, name="test_svc1")
+        self.try_to_delete(Service, name="test_svc2")
+
+    def create_coarsetenant(self):
+        self.assert_noobj(Service, "test_svc1")
+        self.assert_noobj(Service, "test_svc2")
+        self.execute(self.make_nodetemplate("test_svc1", "tosca.nodes.Service", reqs=[("test_svc2", "tosca.relationships.TenantOfService")]) +
+                     self.make_nodetemplate("test_svc2", "tosca.nodes.Service"))
+        svc1 = self.assert_obj(Service, "test_svc1", kind="generic", published=True, enabled=True)
+        svc2 = self.assert_obj(Service, "test_svc2", kind="generic", published=True, enabled=True)
+
+        ct = CoarseTenant.objects.filter(provider_service=svc2, subscriber_service=svc1)
+        assert(ct)
+
+    def update_coarsetenant(self):
+        # first make the services without the coarse tenancy relationship
+        self.assert_noobj(Service, "test_svc1")
+        self.assert_noobj(Service, "test_svc2")
+        self.execute(self.make_nodetemplate("test_svc1", "tosca.nodes.Service") +
+                     self.make_nodetemplate("test_svc2", "tosca.nodes.Service"))
+        svc1 = self.assert_obj(Service, "test_svc1", kind="generic", published=True, enabled=True)
+        svc2 = self.assert_obj(Service, "test_svc2", kind="generic", published=True, enabled=True)
+        ct = CoarseTenant.objects.filter(provider_service=svc2, subscriber_service=svc1)
+        assert(not ct)
+
+        # now add the relationship
+        self.execute(self.make_nodetemplate("test_svc1", "tosca.nodes.Service", reqs=[("test_svc2", "tosca.relationships.TenantOfService")])+
+                                            self.make_nodetemplate("test_svc2", "tosca.nodes.Service"))
+        updated_svc1 = self.assert_obj(Service, "test_svc1", kind="generic", published=True, enabled=True)
+
+        assert(svc1.id == updated_svc1.id)
+
+        ct = CoarseTenant.objects.filter(provider_service=svc2, subscriber_service=svc1)
+        assert(ct)
+
+
+if __name__ == "__main__":
+    CoarseTenancyTest()
+
+
diff --git a/xos/tosca/tests/computetest.py b/xos/tosca/tests/computetest.py
new file mode 100644
index 0000000..7827f24
--- /dev/null
+++ b/xos/tosca/tests/computetest.py
@@ -0,0 +1,96 @@
+from basetest import BaseToscaTest
+
+from core.models import Instance, Slice
+
+class ComputeTest(BaseToscaTest):
+    tests = [ # "create_compute_m1_tiny", XXX m1.tiny does not exist on cloudlab
+             "create_compute_m1_small",
+             "create_compute_m1_large_8192MB",
+             "create_compute_m1_large_8GB",
+             "destroy_compute",
+             "create_compute_scalable",
+             "destroy_compute_scalable",
+                           ]
+
+    def cleanup(self):
+        self.try_to_delete(Instance, name="test_compute1")
+        self.try_to_delete(Instance, name="test_compute1-0")
+        self.try_to_delete(Instance, name="test_compute1-1")
+        self.try_to_delete(Instance, name="test_compute1-2")
+        self.try_to_delete(Instance, name="test_compute1-3")
+        self.try_to_delete(Slice, name="testsite_slice1")
+
+    def get_base_templates(self):
+        return self.make_nodetemplate("testsite", "tosca.nodes.Site") + \
+               self.make_nodetemplate("testsite_slice1", "tosca.nodes.Slice", reqs=[("testsite", "tosca.relationships.MemberOfSite")])
+
+    def create_compute_m1_tiny(self):
+        self.assert_noobj(Instance, "test_compute1")
+        self.execute(self.get_base_templates() +
+                     self.make_compute("testsite_slice1", "test_compute1", disk_size="1 GB", mem_size="500 MB"))
+        instance = self.assert_obj(Instance, "test_compute1")
+        assert(instance.flavor.name == "m1.tiny")
+
+    def create_compute_m1_small(self):
+        self.assert_noobj(Instance, "test_compute1")
+        self.execute(self.get_base_templates() +
+                     self.make_compute("testsite_slice1", "test_compute1", disk_size="1 GB", mem_size="513 MB"))
+        instance = self.assert_obj(Instance, "test_compute1")
+        assert(instance.flavor.name == "m1.small")
+
+    def create_compute_m1_large_8192MB(self):
+        self.assert_noobj(Instance, "test_compute1")
+        self.execute(self.get_base_templates() +
+                     self.make_compute("testsite_slice1", "test_compute1", mem_size="8192 MB"))
+        instance = self.assert_obj(Instance, "test_compute1")
+        assert(instance.flavor.name == "m1.large")
+
+    def create_compute_m1_large_8GB(self):
+        self.assert_noobj(Instance, "test_compute1")
+        self.execute(self.get_base_templates() +
+                     self.make_compute("testsite_slice1", "test_compute1", mem_size="8 GB"))
+        instance = self.assert_obj(Instance, "test_compute1")
+        assert(instance.flavor.name == "m1.large")
+
+    def destroy_compute(self):
+        self.execute(self.get_base_templates() +
+                     self.make_compute("testsite_slice1", "test_compute1"))
+        self.assert_obj(Instance, "test_compute1")
+        self.destroy(self.get_base_templates() +
+                     self.make_compute("testsite_slice1", "test_compute1"))
+        self.assert_noobj(Instance, "test_compute1")
+
+    def create_compute_scalable(self):
+        self.assert_noobj(Instance, "test_compute1-1")
+        self.assert_noobj(Instance, "test_compute1-2")
+        self.assert_noobj(Instance, "test_compute1-3")
+        self.execute(self.get_base_templates() +
+                     self.make_compute("testsite_slice1", "test_compute1", mem_size="8 GB",
+                                       caps={"scalable": {"min_instances": 2, "max_instances": 3, "default_instances": 2}}))
+        # there should be two instances
+        instance0 = self.assert_obj(Instance, "test_compute1-0")
+        instance1 = self.assert_obj(Instance, "test_compute1-1")
+        self.assert_noobj(Instance, "test_compute1-2")
+
+    def destroy_compute_scalable(self):
+        self.assert_noobj(Instance, "test_compute1-1")
+        self.assert_noobj(Instance, "test_compute1-2")
+        self.assert_noobj(Instance, "test_compute1-3")
+        self.execute(self.get_base_templates() +
+                     self.make_compute("testsite_slice1", "test_compute1", mem_size="8 GB",
+                                       caps={"scalable": {"min_instances": 2, "max_instances": 3, "default_instances": 2}}))
+        # there should be two instances
+        instance0 = self.assert_obj(Instance, "test_compute1-0")
+        instance1 = self.assert_obj(Instance, "test_compute1-1")
+
+        self.destroy(self.get_base_templates() +
+                     self.make_compute("testsite_slice1", "test_compute1", mem_size="8 GB",
+                                       caps={"scalable": {"min_instances": 2, "max_instances": 3, "default_instances": 2}}))
+
+        self.assert_noobj(Instance, "test_compute1-0")
+        self.assert_noobj(Instance, "test_compute1-1")
+
+if __name__ == "__main__":
+    ComputeTest()
+
+
diff --git a/xos/tosca/tests/controllertest.py b/xos/tosca/tests/controllertest.py
new file mode 100644
index 0000000..2b7ba55
--- /dev/null
+++ b/xos/tosca/tests/controllertest.py
@@ -0,0 +1,129 @@
+from basetest import BaseToscaTest
+
+from core.models import Controller, Deployment
+
+class ControllerTest(BaseToscaTest):
+    tests = ["create_controller_minimal",
+             "create_controller_maximal",
+             "create_controller_nocreate",
+             "destroy_controller",
+             "destroy_controller_nodelete"]
+
+    def cleanup(self):
+        self.try_to_delete(Controller, name="testcon")
+        self.try_to_delete(Deployment, name="testdep")
+
+    def get_base_templates(self):
+        return self.make_nodetemplate("testdep", "tosca.nodes.Deployment")
+
+    def create_controller_minimal(self):
+        self.assert_noobj(Controller, "testcon")
+        self.execute(self.get_base_templates() +
+                     self.make_nodetemplate("testcon", "tosca.nodes.Controller",
+                                            reqs=[("testdep", "tosca.relationships.ControllerDeployment")]))
+        dep = self.assert_obj(Deployment, "testdep")
+        self.assert_obj(Controller, "testcon",
+                        backend_type="",
+                        version="",
+                        auth_url=None,
+                        admin_user=None,
+                        admin_password=None,
+                        admin_tenant=None,
+                        domain=None,
+                        deployment=dep)
+
+    def create_controller_maximal(self):
+        self.assert_noobj(Controller, "testcon")
+        self.execute(self.get_base_templates() +
+                     self.make_nodetemplate("testcon", "tosca.nodes.Controller",
+                                            reqs=[("testdep", "tosca.relationships.ControllerDeployment")],
+                                            props={"backend_type": "openstack",
+                                                   "version": "v1.23.4",
+                                                   "auth_url": "http://foo.com/",
+                                                   "admin_user": "johndoe",
+                                                   "admin_password": "letmeout",
+                                                   "admin_tenant": "12345678",
+                                                   "domain": "mydomain"}))
+        dep = self.assert_obj(Deployment, "testdep")
+        self.assert_obj(Controller, "testcon",
+                        backend_type="openstack",
+                        version="v1.23.4",
+                        auth_url="http://foo.com/",
+                        admin_user="johndoe",
+                        admin_password="letmeout",
+                        admin_tenant="12345678",
+                        domain="mydomain",
+                        deployment=dep)
+
+    def create_controller_nocreate(self):
+        self.assert_noobj(Controller, "testcon")
+        self.execute(self.get_base_templates() +
+                     self.make_nodetemplate("testcon", "tosca.nodes.Controller",
+                                            reqs=[("testdep", "tosca.relationships.ControllerDeployment")],
+                                            props={"no-create": True}))
+        dep = self.assert_obj(Deployment, "testdep")
+        self.assert_noobj(Controller, "testcon")
+
+    def update_controller(self):
+        self.assert_noobj(Controller, "testcon")
+        self.execute(self.get_base_templates() +
+                     self.make_nodetemplate("testcon", "tosca.nodes.Controller",
+                                            reqs=[("testdep", "tosca.relationships.ControllerDeployment")]))
+        dep = self.assert_obj(Deployment, "testdep")
+        orig_con = self.assert_obj(Controller, "testcon",
+                        backend_type="",
+                        version="",
+                        auth_url=None,
+                        admin_user=None,
+                        admin_password=None,
+                        admin_tenant=None,
+                        domain=None,
+                        deployment=dep)
+        self.execute(self.get_base_templates() +
+                     self.make_nodetemplate("testcon", "tosca.nodes.Controller",
+                                            reqs=[("testdep", "tosca.relationships.ControllerDeployment")],
+                                            props={"version": "1.1"}))
+        con = self.assert_obj(Controller, "testcon",
+                        backend_type="",
+                        version="1.1",
+                        auth_url=None,
+                        admin_user=None,
+                        admin_password=None,
+                        admin_tenant=None,
+                        domain=None,
+                        deployment=dep)
+        assert(orig_con.id == con.id)
+
+    def destroy_controller(self):
+        self.assert_noobj(Controller, "testcon")
+        self.execute(self.get_base_templates() +
+                     self.make_nodetemplate("testcon", "tosca.nodes.Controller",
+                                            reqs=[("testdep", "tosca.relationships.ControllerDeployment")]))
+        self.assert_obj(Controller, "testcon")
+        self.destroy(self.get_base_templates() +
+                     self.make_nodetemplate("testcon", "tosca.nodes.Controller",
+                                            reqs=[("testdep", "tosca.relationships.ControllerDeployment")]))
+        self.assert_noobj(Controller, "testcon")
+
+    def destroy_controller_nodelete(self):
+        self.assert_noobj(Controller, "testcon")
+        self.execute(self.get_base_templates() +
+                     self.make_nodetemplate("testcon", "tosca.nodes.Controller",
+                                            reqs=[("testdep", "tosca.relationships.ControllerDeployment")]))
+        orig_con = self.assert_obj(Controller, "testcon")
+        # NOTE: Had to specify no-delete on the deployment as well, otherwise
+        # the deployment deletion would cause the controller to be deleted
+        # as well. I'm thinking this is as it should be, but it's a little
+        # counter-inutitive.
+        self.destroy(self.make_nodetemplate("testdep", "tosca.nodes.Deployment",
+                                            props={"no-delete": True}) +
+                     self.make_nodetemplate("testcon", "tosca.nodes.Controller",
+                                            reqs=[("testdep", "tosca.relationships.ControllerDeployment")],
+                                            props={"no-delete": True}))
+        con = self.assert_obj(Controller, "testcon")
+        assert(orig_con.id == con.id)
+
+if __name__ == "__main__":
+    ControllerTest()
+
+
diff --git a/xos/tosca/tests/deploymenttest.py b/xos/tosca/tests/deploymenttest.py
new file mode 100644
index 0000000..91caf75
--- /dev/null
+++ b/xos/tosca/tests/deploymenttest.py
@@ -0,0 +1,141 @@
+from basetest import BaseToscaTest
+
+from core.models import Deployment, Image, User, DeploymentPrivilege
+
+class DeploymentTest(BaseToscaTest):
+    tests = ["create_deployment_minimal",
+             "create_deployment_maximal",
+             "create_deployment_one_flavor",
+             "create_deployment_two_flavors",
+             "create_deployment_one_image",
+             "create_deployment_two_images",
+             "create_deployment_privilege",
+             "create_deployment_nocreate",
+             "update_deployment",
+             "update_deployment_noupdate",
+             "destroy_deployment",
+             "destroy_deployment_nodelete"
+                           ]
+
+    def cleanup(self):
+        self.try_to_delete(Deployment, name="testdep")
+        self.try_to_delete(Image, name="testimg1")
+        self.try_to_delete(Image, name="testimg2")
+        self.try_to_delete(User, email="test@user.com")
+
+    def create_deployment_minimal(self):
+        self.assert_noobj(Deployment, "testdep")
+        self.execute(self.make_nodetemplate("testdep", "tosca.nodes.Deployment"))
+        dep = self.assert_obj(Deployment, "testdep",
+                                   accessControl="allow all")
+        assert(not dep.flavors.exists())   # there should be no flavors
+        assert(not dep.images.exists()) # there should be no images
+
+
+    def create_deployment_maximal(self):
+        self.assert_noobj(Deployment, "testdep")
+        self.execute(self.make_nodetemplate("testdep", "tosca.nodes.Deployment",
+                                            props={"accessControl": "allow padmin@vicci.org"}))
+        dep = self.assert_obj(Deployment, "testdep",
+                                   accessControl="allow padmin@vicci.org")
+
+    def create_deployment_one_flavor(self):
+        self.assert_noobj(Deployment, "testdep")
+        self.execute(self.make_nodetemplate("testdep", "tosca.nodes.Deployment",
+                                            props={"accessControl": "allow padmin@vicci.org",
+                                                   "flavors": "m1.small"}))
+        dep = self.assert_obj(Deployment, "testdep",
+                                   accessControl="allow padmin@vicci.org")
+
+        assert( sorted([f.name for f in dep.flavors.all()]) == ["m1.small"] )
+
+    def create_deployment_two_flavors(self):
+        self.assert_noobj(Deployment, "testdep")
+        self.execute(self.make_nodetemplate("testdep", "tosca.nodes.Deployment",
+                                            props={"accessControl": "allow padmin@vicci.org",
+                                                   "flavors": "m1.small, m1.medium"}))
+        dep = self.assert_obj(Deployment, "testdep",
+                                   accessControl="allow padmin@vicci.org")
+
+        assert( sorted([f.name for f in dep.flavors.all()]) == ["m1.medium", "m1.small"] )
+
+    def create_deployment_one_image(self):
+        self.assert_noobj(Deployment, "testdep")
+        self.execute(self.make_nodetemplate("testimg1", "tosca.nodes.Image") +
+                     self.make_nodetemplate("testdep", "tosca.nodes.Deployment",
+                                            reqs=[("testimg1", "tosca.relationships.SupportsImage")]))
+        dep = self.assert_obj(Deployment, "testdep",
+                                   accessControl="allow all")
+        assert( sorted([f.name for f in dep.images.all()]) == ["testimg1"] )
+
+    def create_deployment_two_images(self):
+        self.assert_noobj(Deployment, "testdep")
+        self.execute(self.make_nodetemplate("testimg1", "tosca.nodes.Image") +
+                     self.make_nodetemplate("testimg2", "tosca.nodes.Image") +
+                     self.make_nodetemplate("testdep", "tosca.nodes.Deployment",
+                                            reqs=[("testimg1", "tosca.relationships.SupportsImage"),
+                                                  ("testimg2", "tosca.relationships.SupportsImage")]))
+        dep = self.assert_obj(Deployment, "testdep",
+                                   accessControl="allow all")
+        assert( sorted([f.name for f in dep.images.all()]) == ["testimg1", "testimg2"] )
+
+    def create_deployment_privilege(self):
+        self.assert_noobj(Deployment, "testdep")
+        self.execute(self.make_nodetemplate("testsite", "tosca.nodes.Site") +
+                     self.make_user_template() +
+                     self.make_nodetemplate("testdep", "tosca.nodes.Deployment",
+                                            reqs=[("test@user.com", "tosca.relationships.AdminPrivilege")]))
+        dep = self.assert_obj(Deployment, "testdep")
+        user = User.objects.get(email="test@user.com")
+
+        dps = DeploymentPrivilege.objects.filter(user=user, deployment=dep)
+        assert(len(dps) == 1)
+
+    def create_deployment_nocreate(self):
+        self.assert_noobj(Deployment, "testdep")
+        self.execute(self.make_nodetemplate("testdep", "tosca.nodes.Deployment",
+                                            props={"no-create": True}))
+        self.assert_noobj(Deployment, "testdep")
+
+    def update_deployment(self):
+        self.assert_noobj(Deployment, "testdep")
+        self.execute(self.make_nodetemplate("testdep", "tosca.nodes.Deployment"))
+        orig_dep = self.assert_obj(Deployment, "testdep",
+                                   accessControl="allow all")
+        self.execute(self.make_nodetemplate("testdep", "tosca.nodes.Deployment",
+                                            props={"accessControl": "allow padmin@vicci.org"}))
+        dep = self.assert_obj(Deployment, "testdep",
+                                   accessControl="allow padmin@vicci.org")
+        assert(dep.id == orig_dep.id)
+
+    def update_deployment_noupdate(self):
+        self.assert_noobj(Deployment, "testdep")
+        self.execute(self.make_nodetemplate("testdep", "tosca.nodes.Deployment"))
+        orig_dep = self.assert_obj(Deployment, "testdep",
+                                   accessControl="allow all")
+        self.execute(self.make_nodetemplate("testdep", "tosca.nodes.Deployment",
+                                            props={"accessControl": "allow padmin@vicci.org",
+                                                   "no-update": True}))
+        dep = self.assert_obj(Deployment, "testdep",
+                                   accessControl="allow all")
+        assert(dep.id == orig_dep.id)
+
+    def destroy_deployment(self):
+        self.assert_noobj(Deployment, "testdep")
+        self.execute(self.make_nodetemplate("testdep", "tosca.nodes.Deployment"))
+        instance = self.assert_obj(Deployment, "testdep")
+        self.destroy(self.make_nodetemplate("testdep", "tosca.nodes.Deployment"))
+        self.assert_noobj(Deployment, "testdep")
+
+    def destroy_deployment_nodelete(self):
+        self.assert_noobj(Deployment, "testdep")
+        self.execute(self.make_nodetemplate("testdep", "tosca.nodes.Deployment"))
+        instance = self.assert_obj(Deployment, "testdep")
+        self.destroy(self.make_nodetemplate("testdep", "tosca.nodes.Deployment",
+                                            props={"no-delete": True}))
+        self.assert_obj(Deployment, "testdep")
+
+if __name__ == "__main__":
+    DeploymentTest()
+
+
diff --git a/xos/tosca/tests/enginetest.py b/xos/tosca/tests/enginetest.py
new file mode 100644
index 0000000..187716b
--- /dev/null
+++ b/xos/tosca/tests/enginetest.py
@@ -0,0 +1,53 @@
+from basetest import BaseToscaTest
+
+from core.models import Service
+
+class EngineTest(BaseToscaTest):
+    tests = ["intrinsic_get_artifact",
+             "intrinsic_get_script_env",
+             "intrinsic_get_script_env_noisy" ]
+
+    def cleanup(self):
+        self.try_to_delete(Service, name="testservice")
+
+    def intrinsic_get_artifact(self):
+        self.assert_noobj(Service, "testservice")
+        file("/tmp/somevar","w").write("somevalue")
+        self.execute(self.make_nodetemplate("testservice", "tosca.nodes.Service",
+                                            props={"public_key": "{ get_artifact: [ SELF, somevar, LOCAL_FILE] }"},
+                                            artifacts={"somevar": "/tmp/somevar"}))
+        self.assert_obj(Service, "testservice", public_key="somevalue")
+
+    def intrinsic_get_script_env(self):
+        self.assert_noobj(Service, "testservice")
+        file("/tmp/somescript","w").write( \
+"""#! /bin/bash
+FOO=123
+BAR=456
+JUNK=789
+""")
+        self.execute(self.make_nodetemplate("testservice", "tosca.nodes.Service",
+                                            props={"public_key": "{ get_script_env: [ SELF, somescript, BAR, LOCAL_FILE] }"},
+                                            artifacts={"somescript": "/tmp/somescript"}))
+        self.assert_obj(Service, "testservice", public_key="456")
+
+    def intrinsic_get_script_env_noisy(self):
+        self.assert_noobj(Service, "testservice")
+        file("/tmp/somescript","w").write( \
+"""#! /bin/bash
+echo "junk"
+echo "oh no! something got written to stderr! This always breaks stuff!" >&2
+FOO=123
+echo "more junk"
+BAR=456
+echo "even more junk"
+JUNK=789
+echo "BAR=oops"
+""")
+        self.execute(self.make_nodetemplate("testservice", "tosca.nodes.Service",
+                                            props={"public_key": "{ get_script_env: [ SELF, somescript, BAR, LOCAL_FILE] }"},
+                                            artifacts={"somescript": "/tmp/somescript"}))
+        self.assert_obj(Service, "testservice", public_key="456")
+
+if __name__ == "__main__":
+    EngineTest()
diff --git a/xos/tosca/tests/imagetest.py b/xos/tosca/tests/imagetest.py
new file mode 100644
index 0000000..d651027
--- /dev/null
+++ b/xos/tosca/tests/imagetest.py
@@ -0,0 +1,35 @@
+from basetest import BaseToscaTest
+
+from core.models import Image
+
+class ImageTest(BaseToscaTest):
+    tests = ["create_image_minimal",
+             "create_image_maximal",
+             "destroy_image",
+                           ]
+
+    def cleanup(self):
+        self.try_to_delete(Image, name="testimg")
+
+    def create_image_minimal(self):
+        self.assert_noobj(Image, "testimg")
+        self.execute(self.make_nodetemplate("testimg", "tosca.nodes.Image"))
+        instance = self.assert_obj(Image, "testimg", disk_format="", container_format="", path=None)
+
+    def create_image_maximal(self):
+        self.assert_noobj(Image, "testimg")
+        self.execute(self.make_nodetemplate("testimg", "tosca.nodes.Image",
+                                            props={"disk_format": "a", "container_format": "b", "path": "c"}))
+        instance = self.assert_obj(Image, "testimg", disk_format="a", container_format="b", path="c")
+
+    def destroy_image(self):
+        self.assert_noobj(Image, "testimg")
+        self.execute(self.make_nodetemplate("testimg", "tosca.nodes.Image"))
+        instance = self.assert_obj(Image, "testimg", disk_format="", container_format="", path=None)
+        self.destroy(self.make_nodetemplate("testimg", "tosca.nodes.Image"))
+        self.assert_noobj(Image, "testimg")
+
+if __name__ == "__main__":
+    ImageTest()
+
+
diff --git a/xos/tosca/tests/networktest.py b/xos/tosca/tests/networktest.py
new file mode 100644
index 0000000..fa446f9
--- /dev/null
+++ b/xos/tosca/tests/networktest.py
@@ -0,0 +1,151 @@
+from basetest import BaseToscaTest
+
+from core.models import Network, Slice, NetworkTemplate, NetworkSlice
+
+class NetworkTest(BaseToscaTest):
+    tests = ["create_network_minimal",
+             "create_network_maximal",
+             "create_network_connected",
+             "create_network_connected_two_slices",
+             "update_network_labels",
+             "destroy_network"]
+
+    def cleanup(self):
+        self.try_to_delete(Network, name="test_net")
+        self.try_to_delete(Slice, name="testsite_slice1")
+        self.try_to_delete(Slice, name="testsite_slice2")
+
+    @property
+    def slice1(self):
+        return Slice.objects.get(name="testsite_slice1")
+
+    @property
+    def slice2(self):
+        return Slice.objects.get(name="testsite_slice2")
+
+    @property
+    def private(Self):
+        return NetworkTemplate.objects.get(name="Private")
+
+
+    def get_base_templates(self):
+        return self.make_nodetemplate("testsite", "tosca.nodes.Site") + \
+               self.make_nodetemplate("testsite_slice1", "tosca.nodes.Slice", reqs=[("testsite", "tosca.relationships.MemberOfSite")]) + \
+               self.make_nodetemplate("testsite_slice2", "tosca.nodes.Slice", reqs=[("testsite", "tosca.relationships.MemberOfSite")]) + \
+               self.make_nodetemplate("Private", "tosca.nodes.NetworkTemplate")
+
+    def create_network_minimal(self):
+        self.assert_noobj(Network, "test_net")
+        self.execute(self.get_base_templates() +
+                     self.make_nodetemplate("test_net", "tosca.nodes.network.Network",
+                                            reqs=[("testsite_slice1", "tosca.relationships.MemberOfSlice"),
+                                                  ("Private", "tosca.relationships.UsesNetworkTemplate")]))
+        net=self.assert_obj(Network, "test_net", owner=self.slice1, template=self.private)
+
+        ns = NetworkSlice.objects.filter(slice=self.slice1, network=net)
+        assert(not ns)
+
+    def create_network_maximal(self):
+        self.assert_noobj(Network, "test_net")
+        self.execute(self.get_base_templates() +
+                     self.make_nodetemplate("test_net", "tosca.nodes.network.Network.XOS",
+                                            props={"ports": "tcp/1234, udp/5678",
+                                                   "labels": "foo,bar",
+                                                   "permit_all_slices": False},
+                                            reqs=[("testsite_slice1", "tosca.relationships.MemberOfSlice"),
+                                                  ("Private", "tosca.relationships.UsesNetworkTemplate")]))
+        net=self.assert_obj(Network, "test_net",
+                            owner=self.slice1,
+                            template=self.private,
+                            ports="tcp/1234, udp/5678",
+                            labels="foo,bar",
+                            permit_all_slices=False)
+
+        ns = NetworkSlice.objects.filter(slice=self.slice1, network=net)
+        assert(not ns)
+
+    def create_network_connected(self):
+        self.assert_noobj(Network, "test_net")
+        self.execute(self.get_base_templates() +
+                     self.make_nodetemplate("test_net", "tosca.nodes.network.Network",
+                                            reqs=[("testsite_slice1", "tosca.relationships.MemberOfSlice"),
+                                                  ("Private", "tosca.relationships.UsesNetworkTemplate"),
+                                                  ("testsite_slice1", "tosca.relationships.ConnectsToSlice")]))
+
+        net=self.assert_obj(Network, "test_net", owner=self.slice1, template=self.private)
+
+        ns = NetworkSlice.objects.filter(slice=self.slice1, network=net)
+        assert(ns)
+
+    def create_network_connected_two_slices(self):
+        self.assert_noobj(Network, "test_net")
+        self.execute(self.get_base_templates() +
+                     self.make_nodetemplate("test_net", "tosca.nodes.network.Network",
+                                            reqs=[("testsite_slice1", "tosca.relationships.MemberOfSlice"),
+                                                  ("Private", "tosca.relationships.UsesNetworkTemplate"),
+                                                  ("testsite_slice1", "tosca.relationships.ConnectsToSlice"),
+                                                  ("testsite_slice2", "tosca.relationships.ConnectsToSlice")]))
+
+        net=self.assert_obj(Network, "test_net", owner=self.slice1, template=self.private)
+
+        ns = NetworkSlice.objects.filter(slice=self.slice1, network=net)
+        assert(ns)
+
+        ns = NetworkSlice.objects.filter(slice=self.slice1, network=net)
+        assert(ns)
+
+    def update_network_labels(self):
+        self.assert_noobj(Network, "test_net")
+        self.execute(self.get_base_templates() +
+                     self.make_nodetemplate("test_net", "tosca.nodes.network.Network.XOS",
+                                            reqs=[("testsite_slice1", "tosca.relationships.MemberOfSlice"),
+                                                  ("Private", "tosca.relationships.UsesNetworkTemplate")]))
+        net=self.assert_obj(Network, "test_net", owner=self.slice1, template=self.private, labels=None)
+
+        self.execute(self.get_base_templates() +
+                     self.make_nodetemplate("test_net", "tosca.nodes.network.Network.XOS",
+                                            props={"labels": "testlabel"},
+                                            reqs=[("testsite_slice1", "tosca.relationships.MemberOfSlice"),
+                                                  ("Private", "tosca.relationships.UsesNetworkTemplate")]))
+
+        updated_net = self.assert_obj(Network, "test_net", owner=self.slice1, template=self.private, labels="testlabel")
+
+        assert(net.id == updated_net.id)
+
+    def update_network_ports(self):
+        self.assert_noobj(Network, "test_net")
+        self.execute(self.get_base_templates() +
+                     self.make_nodetemplate("test_net", "tosca.nodes.network.Network.XOS",
+                                            reqs=[("testsite_slice1", "tosca.relationships.MemberOfSlice"),
+                                                  ("Private", "tosca.relationships.UsesNetworkTemplate")]))
+        net=self.assert_obj(Network, "test_net", owner=self.slice1, template=self.private, labels=None, ports=None)
+
+        self.execute(self.get_base_templates() +
+                     self.make_nodetemplate("test_net", "tosca.nodes.network.Network.XOS",
+                                            props={"port": "tcp/2222, udp/3333"},
+                                            reqs=[("testsite_slice1", "tosca.relationships.MemberOfSlice"),
+                                                  ("Private", "tosca.relationships.UsesNetworkTemplate")]))
+
+        updated_net = self.assert_obj(Network, "test_net", owner=self.slice1, template=self.private, labels=None, ports="tcp/2222, udp/3333")
+
+        assert(net.id == updated_net.id)
+
+    def destroy_network(self):
+        self.assert_noobj(Network, "test_net")
+        self.execute(self.get_base_templates() +
+                     self.make_nodetemplate("test_net", "tosca.nodes.network.Network",
+                                            reqs=[("testsite_slice1", "tosca.relationships.MemberOfSlice"),
+                                                  ("Private", "tosca.relationships.UsesNetworkTemplate")]))
+        net=self.assert_obj(Network, "test_net", owner=self.slice1, template=self.private)
+
+        self.destroy(self.get_base_templates() +
+                     self.make_nodetemplate("test_net", "tosca.nodes.network.Network",
+                                            reqs=[("testsite_slice1", "tosca.relationships.MemberOfSlice"),
+                                                  ("Private", "tosca.relationships.UsesNetworkTemplate")]))
+
+        self.assert_noobj(Network, "test_net")
+
+if __name__ == "__main__":
+    NetworkTest()
+
+
diff --git a/xos/tosca/tests/nodetest.py b/xos/tosca/tests/nodetest.py
new file mode 100644
index 0000000..76c56a8
--- /dev/null
+++ b/xos/tosca/tests/nodetest.py
@@ -0,0 +1,91 @@
+from basetest import BaseToscaTest
+
+from core.models import Node, Site, Deployment, SiteDeployment
+
+class NodeTest(BaseToscaTest):
+    tests = ["create_node_minimal",
+             "create_node_nocreate",
+             "destroy_node",
+             "destroy_node_nodelete",
+                           ]
+
+    def cleanup(self):
+        self.try_to_delete(Node, name="testnode")
+        self.try_to_delete(Site, name="testsite")
+        self.try_to_delete(Deployment, name="testdep")
+
+    def get_base_templates(self):
+        return \
+"""
+    testdep:
+      type: tosca.nodes.Deployment
+    testcon:
+      type: tosca.nodes.Controller
+      requirements:
+        - deployment:
+            node: testdep
+            relationship: tosca.relationships.ControllerDeployment
+    testsite:
+      type: tosca.nodes.Site
+      properties:
+        display_name: My Site
+      requirements:
+        - deployment:
+             node: testdep
+             relationship: tosca.relationships.SiteDeployment
+             requirements:
+                 - controller:
+                     node: testcon
+                     relationship: tosca.relationships.UsesController
+"""
+
+    def create_node_minimal(self):
+        self.assert_noobj(Node, "testnode")
+        self.execute(self.get_base_templates() +
+                     self.make_nodetemplate("testnode", "tosca.nodes.Node",
+                       reqs=[("testsite", "tosca.relationships.MemberOfSite"),
+                             ("testdep", "tosca.relationships.MemberOfDeployment")]))
+        node = self.assert_obj(Node, "testnode")
+        assert(node.site_deployment is not None)
+        assert(node.site is not None)
+
+    def create_node_nocreate(self):
+        self.assert_noobj(Node, "testnode")
+        self.execute(self.get_base_templates() +
+                     self.make_nodetemplate("testnode", "tosca.nodes.Node",
+                       reqs=[("testsite", "tosca.relationships.MemberOfSite"),
+                             ("testdep", "tosca.relationships.MemberOfDeployment")],
+                       props={"no-create": True}))
+        self.assert_noobj(Node, "testnode")
+
+    def destroy_node(self):
+        self.assert_noobj(Node, "testnode")
+        self.execute(self.get_base_templates() +
+                     self.make_nodetemplate("testnode", "tosca.nodes.Node",
+                       reqs=[("testsite", "tosca.relationships.MemberOfSite"),
+                             ("testdep", "tosca.relationships.MemberOfDeployment")]))
+        self.assert_obj(Node, "testnode")
+        self.destroy(self.get_base_templates() +
+                     self.make_nodetemplate("testnode", "tosca.nodes.Node",
+                       reqs=[("testsite", "tosca.relationships.MemberOfSite"),
+                             ("testdep", "tosca.relationships.MemberOfDeployment")]))
+        self.assert_noobj(Node, "testnode")
+
+    def destroy_node_nodelete(self):
+        self.assert_noobj(Node, "testnode")
+        self.execute(self.get_base_templates() +
+                     self.make_nodetemplate("testnode", "tosca.nodes.Node",
+                       reqs=[("testsite", "tosca.relationships.MemberOfSite"),
+                             ("testdep", "tosca.relationships.MemberOfDeployment")]))
+        self.assert_obj(Node, "testnode")
+        self.destroy(self.get_base_templates() +
+                     self.make_nodetemplate("testnode", "tosca.nodes.Node",
+                       reqs=[("testsite", "tosca.relationships.MemberOfSite"),
+                             ("testdep", "tosca.relationships.MemberOfDeployment")],
+                       props={"no-delete": True}))
+        self.assert_obj(Node, "testnode")
+
+if __name__ == "__main__":
+    NodeTest()
+
+
diff --git a/xos/tosca/tests/observerContainerTest.py b/xos/tosca/tests/observerContainerTest.py
new file mode 100644
index 0000000..a31b866
--- /dev/null
+++ b/xos/tosca/tests/observerContainerTest.py
@@ -0,0 +1,95 @@
+from observertest import BaseObserverToscaTest
+
+from core.models import Instance, Site
+
+# Note that as a side effect, these tests will also create a Site
+
+class ObserverContainerTest(BaseObserverToscaTest):
+    tests = ["create_container"]
+    # hide_observer_output = False # uncomment to display lots of stuff to screen
+
+    def cleanup(self):
+        # We don't want to leak resources, so we make sure to let the observer
+        # attempt to delete these objects.
+        self.try_to_delete(Instance, purge=False, name="test_compute1")
+        self.try_to_delete(Site, purge=False, name="testsite")
+        self.run_observer()
+        # The site objects don't seem to go away nicely, they linger about and
+        # cause an IntegrityError due to a duplicate login_base
+        self.try_to_delete(Site, purge=True, name="testsite")
+
+    def get_base_templates(self):
+        return self.make_nodetemplate("testsite", "tosca.nodes.Site") + \
+               self.make_nodetemplate("testsite_slice1", "tosca.nodes.Slice", reqs=[("testsite", "tosca.relationships.MemberOfSite")]) + \
+               self.make_nodetemplate("andybavier/docker-vcpe", "tosca.nodes.Image", props={"kind": "container", "container_format": "na", "disk_format": "na"})
+
+    def create_container(self):
+        self.assert_noobj(Instance, "test_compute1")
+        self.execute(self.get_base_templates() +
+                     self.make_compute("testsite_slice1", "test_compute1", disk_size="1 GB", mem_size="513 MB", isolation="container",
+                                       reqs=[("andybavier/docker-vcpe", "tosca.relationships.UsesImage")],
+                                       ))
+        instance = self.assert_obj(Instance, "test_compute1")
+        assert(instance.flavor.name == "m1.small")
+
+        # first pass makes the Networks
+        self.run_model_policy(save_output="/tmp/instancetest:create_container:model_policy_first")
+
+        # XXX deal with bug where
+        instance = self.assert_obj(Instance, "test_compute1")
+        instance.save()
+
+        # second pass makes the NetworkControllers
+        self.run_model_policy(save_output="/tmp/instancetest:create_container:model_policy_second")
+
+        # first observer pass should make any necessary networks or ports
+        self.run_observer(save_output="/tmp/instancetest:create_container:observer_first")
+
+        # reset the exponential backoff
+        instance = self.assert_obj(Instance, "test_compute1")
+        instance.backend_register="{}"
+        instance.save()
+
+        # we need to reset the companion instance's exponential backoff too
+        companion_instance = Instance.objects.filter(slice=instance.slice, isolation="vm")
+        assert(companion_instance)
+        companion_instance = companion_instance[0]
+        companion_instance.backend_register="{}"
+        companion_instance.save()
+
+        # third pass reset lazy_blocked
+        self.run_model_policy(save_output="/tmp/instancetest:create_container:model_policy_third")
+
+        # second observer pass should instantiate the controller networks
+        #    (might instantiate the instance, too)
+        self.run_observer(save_output="/tmp/instancetest:create_container:observer_second")
+
+        # reset the exponential backoff
+        instance = self.assert_obj(Instance, "test_compute1")
+        instance.backend_register="{}"
+        instance.save()
+
+        # we need to reset the companion instance's exponential backoff too
+        companion_instance = Instance.objects.filter(slice=instance.slice, isolation="vm")
+        assert(companion_instance)
+        companion_instance = companion_instance[0]
+        companion_instance.backend_register="{}"
+        companion_instance.save()
+
+        # third observer pass should instantiate the companion instance
+        self.run_observer(save_output="/tmp/instancetest:create_container:observer_third")
+
+        # third observer pass should instantiate the instance
+        self.run_observer(save_output="/tmp/instancetest:create_container:observer_fourth")
+
+        instance = self.assert_obj(Instance, "test_compute1")
+
+        assert(instance.instance_id is not None)
+        assert(instance.instance_name is not None)
+
+        # there should be one port on the private network
+        assert(instance.ports.count() == 1)
+
+if __name__ == "__main__":
+    ObserverContainerTest()
+
diff --git a/xos/tosca/tests/observerImageTest.py b/xos/tosca/tests/observerImageTest.py
new file mode 100644
index 0000000..3588b04
--- /dev/null
+++ b/xos/tosca/tests/observerImageTest.py
@@ -0,0 +1,48 @@
+from observertest import BaseObserverToscaTest
+
+from core.models import Image, Deployment, ControllerImages
+
+# Note that as a side effect, these tests will also create a Site
+
+class ObserverImageTest(BaseObserverToscaTest):
+    tests = ["create_image"]
+    # hide_observer_output = False # uncomment to display lots of stuff to screen
+
+    def cleanup(self):
+        # We don't want to leak resources, so we make sure to let the observer
+        # attempt to delete these objects.
+        self.try_to_delete(Image, purge=False, name="testimg")
+        self.run_observer()
+        self.try_to_delete(Image, purge=True, name="testimg")
+
+    def create_image(self):
+        self.assert_noobj(Image, "testimg")
+        file("/tmp/testimg","w").write("this_is_a_test")
+        self.execute(self.make_nodetemplate(self.get_usable_deployment(), "tosca.nodes.Deployment",
+                                            props={"no-delete": True},
+                                            reqs=[("testimg", "tosca.relationships.SupportsImage")]) +
+                     self.make_nodetemplate("testimg", "tosca.nodes.Image",
+                                            props={"path": "/tmp/testimg"}))
+        image = self.assert_obj(Image, "testimg")
+
+        self.run_model_policy(save_output="/tmp/imagetest:create_image:model_policy")
+
+        # make sure a ControllerImages object was created
+        cims = ControllerImages.objects.filter(image=image)
+        assert(len(cims) == 1)
+
+        # first observer pass should make any necessary networks or ports
+        self.run_observer(save_output="/tmp/imagetest:create_image:observer")
+
+        # reset the exponential backoff
+        image = self.assert_obj(Image, "testimg")
+
+        # make sure the ControllerImages object has its image_id filled in
+        cims = ControllerImages.objects.filter(image=image)
+        assert(len(cims) == 1)
+        assert(cims[0].glance_image_id is not None)
+        assert(cims[0].glance_image_id != "")
+
+if __name__ == "__main__":
+    ObserverImageTest()
+
diff --git a/xos/tosca/tests/observerSiteTest.py b/xos/tosca/tests/observerSiteTest.py
new file mode 100644
index 0000000..0ebc8be
--- /dev/null
+++ b/xos/tosca/tests/observerSiteTest.py
@@ -0,0 +1,56 @@
+from observertest import BaseObserverToscaTest
+
+from core.models import Site, Deployment, ControllerSite
+
+# Note that as a side effect, these tests will also create a Site
+
+class ObserverSiteTest(BaseObserverToscaTest):
+    tests = ["create_site"]
+    # hide_observer_output = False # uncomment to display lots of stuff to screen
+
+    def cleanup(self):
+        # We don't want to leak rezsources, so we make sure to let the observer
+        # attempt to delete these objects.
+        self.try_to_delete(Site, purge=False, login_base="testsite")
+        self.run_observer()
+        self.try_to_delete(Site, purge=True, login_base="testsite")
+
+    def create_site(self):
+        self.assert_noobj(Site, "testsite")
+        self.execute(self.make_nodetemplate(self.get_usable_deployment(), "tosca.nodes.Deployment",
+                                            props={"no-delete": True}) +  \
+"""
+    testsite:
+      type: tosca.nodes.Site
+      properties:
+          site_url: http://opencloud.us/
+      requirements:
+          - deployment:
+               node: %s
+               relationship: tosca.relationships.SiteDeployment
+               requirements:
+                   - controller:
+                       node: %s
+                       relationship: tosca.relationships.UsesController
+""" % (self.get_usable_deployment(), self.get_usable_controller()))
+
+        testsite = self.assert_obj(Site, "testsite")
+
+        self.run_model_policy(save_output="/tmp/sitetest:create_site:model_policy")
+
+        # make sure a ControllerSite object was created
+        cs = ControllerSite.objects.filter(site=testsite)
+        assert(len(cs) == 1)
+
+        self.run_observer(save_output="/tmp/sitetest:create_site:observer")
+
+        testsite = self.assert_obj(Site, "testsite")
+
+        cs = ControllerSite.objects.filter(site=testsite)
+        assert(len(cs) == 1)
+        assert(cs[0].tenant_id is not None)
+        assert(cs[0].tenant_id != "")
+
+if __name__ == "__main__":
+    ObserverSiteTest()
+
diff --git a/xos/tosca/tests/observerSliceTest.py b/xos/tosca/tests/observerSliceTest.py
new file mode 100644
index 0000000..749f4ed
--- /dev/null
+++ b/xos/tosca/tests/observerSliceTest.py
@@ -0,0 +1,48 @@
+from observertest import BaseObserverToscaTest
+
+from core.models import Site, Deployment, Slice, ControllerSlice
+
+# Note that as a side effect, these tests will also create a Site
+
+class ObserverSliceTest(BaseObserverToscaTest):
+    tests = ["create_slice"]
+    # hide_observer_output = False # uncomment to display lots of stuff to screen
+
+    def cleanup(self):
+        # We don't want to leak resources, so we make sure to let the observer
+        # attempt to delete these objects.
+        self.try_to_delete(Slice, purge=False, name="testsite_slice1")
+        self.try_to_delete(Site, purge=False, login_base="testsite")
+        self.run_observer()
+        self.try_to_delete(Slice, purge=True, name="testsite_slice1")
+        self.try_to_delete(Site, purge=True, login_base="testsite")
+
+    def create_slice(self):
+        self.assert_noobj(Site, "testsite")
+        self.assert_noobj(Slice, "testsite_slice1")
+        self.execute(self.make_nodetemplate(self.get_usable_deployment(), "tosca.nodes.Deployment",
+                                            props={"no-delete": True}) +
+                     self.make_nodetemplate("testsite", "tosca.nodes.Site") + \
+                     self.make_nodetemplate("testsite_slice1", "tosca.nodes.Slice", reqs=[("testsite", "tosca.relationships.MemberOfSite")]))
+
+        testsite = self.assert_obj(Site, "testsite")
+        testslice = self.assert_obj(Slice, "testsite_slice1")
+
+        self.run_model_policy(save_output="/tmp/slicetest:create_slice:model_policy")
+
+        # make sure a ControllerSlice object was created
+        cs = ControllerSlice.objects.filter(slice=testslice)
+        assert(len(cs) == 1)
+
+        self.run_observer(save_output="/tmp/slicetest:create_slice:observer")
+
+        testslice = self.assert_obj(Slice, "testsite_slice1")
+
+        cs = ControllerSlice.objects.filter(slice=testslice)
+        assert(len(cs) == 1)
+        assert(cs[0].tenant_id is not None)
+        assert(cs[0].tenant_id != "")
+
+if __name__ == "__main__":
+    ObserverSliceTest()
+
diff --git a/xos/tosca/tests/observerUserTest.py b/xos/tosca/tests/observerUserTest.py
new file mode 100644
index 0000000..a6b5897
--- /dev/null
+++ b/xos/tosca/tests/observerUserTest.py
@@ -0,0 +1,82 @@
+from observertest import BaseObserverToscaTest
+
+from core.models import Site, Deployment, User, ControllerUser
+
+# Note that as a side effect, these tests will also create a Site
+
+class ObserverUserTest(BaseObserverToscaTest):
+    tests = ["create_user"]
+    # hide_observer_output = False # uncomment to display lots of stuff to screen
+
+    def cleanup(self):
+        # We don't want to leak resources, so we make sure to let the observer
+        # attempt to delete these objects.
+        self.try_to_delete(User, purge=False, email="johndoe@foo.bar")
+        self.try_to_delete(Site, purge=False, login_base="testsite")
+        self.run_observer()
+        self.try_to_delete(User, purge=True, email="johndoe@foo.bar")
+        self.try_to_delete(Site, purge=True, login_base="testsite")
+
+    def assert_nouser(self, email):
+        assert(not User.objects.filter(email=email))
+
+    def assert_user(self, email, **kwargs):
+        obj = User.objects.get(email=email)
+        assert(obj)
+        for (k,v) in kwargs.items():
+            if (getattr(obj,k,None) != v):
+                print "Object %s property '%s' is '%s' and should be '%s'" % (obj, k, getattr(obj,k,None), v)
+                assert(False)
+        return obj
+
+    def create_user(self):
+        self.assert_noobj(Site, "testsite")
+        self.assert_nouser("johndoe@foo.bar")
+        self.execute(self.make_nodetemplate(self.get_usable_deployment(), "tosca.nodes.Deployment",
+                                            props={"no-delete": True}) +  \
+"""
+    testsite:
+      type: tosca.nodes.Site
+      properties:
+          site_url: http://opencloud.us/
+      requirements:
+          - deployment:
+               node: %s
+               relationship: tosca.relationships.SiteDeployment
+               requirements:
+                   - controller:
+                       node: %s
+                       relationship: tosca.relationships.UsesController
+    johndoe@foo.bar:
+      type: tosca.nodes.User
+      properties:
+          password: letmein
+          firstname: john
+          lastname: doe
+      requirements:
+          - site:
+              node: testsite
+              relationship: tosca.relationships.MemberOfSite
+""" % (self.get_usable_deployment(), self.get_usable_controller()))
+
+        testsite = self.assert_obj(Site, "testsite")
+        testuser = self.assert_user("johndoe@foo.bar")
+
+        self.run_model_policy(save_output="/tmp/usertest:create_user:model_policy")
+
+        # make sure a ControllerSite object was created
+        cu = ControllerUser.objects.filter(user=testuser)
+        assert(len(cu) == 1)
+
+        self.run_observer(save_output="/tmp/usertest:create_user:observer")
+
+        testuser = self.assert_user("johndoe@foo.bar")
+
+        cu = ControllerUser.objects.filter(user=testuser)
+        assert(len(cu) == 1)
+        assert(cu[0].kuser_id is not None)
+        assert(cu[0].kuser_id != "")
+
+if __name__ == "__main__":
+    ObserverUserTest()
+
diff --git a/xos/tosca/tests/observerVMTest.py b/xos/tosca/tests/observerVMTest.py
new file mode 100644
index 0000000..65cbde5
--- /dev/null
+++ b/xos/tosca/tests/observerVMTest.py
@@ -0,0 +1,71 @@
+from observertest import BaseObserverToscaTest
+
+from core.models import Instance, Site
+
+# Note that as a side effect, these tests will also create a Site
+
+class ObserverVMTest(BaseObserverToscaTest):
+    tests = ["create_vm"]
+    # hide_observer_output = False # uncomment to display lots of stuff to screen
+
+    def cleanup(self):
+        # We don't want to leak resources, so we make sure to let the observer
+        # attempt to delete these objects.
+        self.try_to_delete(Instance, purge=False, name="test_compute1")
+        self.try_to_delete(Site, purge=False, name="testsite")
+        self.run_observer()
+        # The site objects don't seem to go away nicely, they linger about and
+        # cause an IntegrityError due to a duplicate login_base
+        self.try_to_delete(Site, purge=True, name="testsite")
+
+    def get_base_templates(self):
+        return self.make_nodetemplate("testsite", "tosca.nodes.Site") + \
+               self.make_nodetemplate("testsite_slice1", "tosca.nodes.Slice", reqs=[("testsite", "tosca.relationships.MemberOfSite")])
+
+    def create_vm(self):
+        self.assert_noobj(Instance, "test_compute1")
+        self.execute(self.get_base_templates() +
+                     self.make_compute("testsite_slice1", "test_compute1", disk_size="1 GB", mem_size="513 MB"))
+        instance = self.assert_obj(Instance, "test_compute1")
+        assert(instance.flavor.name == "m1.small")
+
+        # first pass makes the Networks
+        self.run_model_policy(save_output="/tmp/instancetest:create_vm:model_policy_first")
+
+        # second pass makes the NetworkControllers
+        self.run_model_policy(save_output="/tmp/instancetest:create_vm:model_policy_second")
+
+        # first observer pass should make any necessary networks or ports
+        self.run_observer(save_output="/tmp/instancetest:create_vm:observer_first")
+
+        # reset the exponential backoff
+        instance = self.assert_obj(Instance, "test_compute1")
+        instance.backend_register="{}"
+        instance.save()
+
+        # third pass reset lazy_blocked
+        self.run_model_policy(save_output="/tmp/instancetest:create_vm:model_policy_third")
+
+        # second observer pass should instantiate the controller networks
+        #    (might instantiate the instance, too)
+        self.run_observer(save_output="/tmp/instancetest:create_vm:observer_second")
+
+        # reset the exponential backoff
+        instance = self.assert_obj(Instance, "test_compute1")
+        instance.backend_register="{}"
+        instance.save()
+
+        # third observer pass should instantiate the instance
+        self.run_observer(save_output="/tmp/instancetest:create_vm:observer_third")
+
+        instance = self.assert_obj(Instance, "test_compute1")
+
+        assert(instance.instance_id is not None)
+        assert(instance.instance_name is not None)
+
+        # there should be a port on the private network and a port on nat-net
+        assert(instance.ports.count() == 2)
+
+if __name__ == "__main__":
+    ObserverVMTest()
+
diff --git a/xos/tosca/tests/observertest.py b/xos/tosca/tests/observertest.py
new file mode 100644
index 0000000..4c8d5df
--- /dev/null
+++ b/xos/tosca/tests/observertest.py
@@ -0,0 +1,97 @@
+from basetest import *
+
+import logging
+import StringIO
+import subprocess
+import sys
+
+from synchronizers.base.event_loop import XOSObserver
+from synchronizers.model_policy import run_policy_once
+from xos.config import set_override
+from xos.logger import Logger, observer_logger
+
+class BaseObserverToscaTest(BaseToscaTest):
+    hide_observer_output = True
+
+    def __init__(self):
+        super(BaseObserverToscaTest, self).__init__()
+
+    def get_usable_deployment(self):
+        return "MyDeployment"
+
+    def get_usable_controller(self):
+        return "CloudLab"
+
+    def ensure_observer_not_running(self):
+        ps_output = subprocess.Popen("ps -elfy", shell=True, stdout=subprocess.PIPE).stdout.read()
+        if "/opt/xos/xos-observer.py" in ps_output:
+            print >> sys.stderr, "an observer is still running"
+            print >> sys.stderr, "please stop it, for example 'supervisorctl stop observer'"
+            sys.exit(-1)
+
+    def log_to_memory(self):
+        logStream = StringIO.StringIO()
+        handler = logging.StreamHandler(stream=logStream)
+        handler.setLevel(logging.DEBUG)
+        handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s"))
+
+        loggername = Logger().loggername
+        log = logging.getLogger(loggername)
+        for hdlr in log.handlers[:]:
+            log.removeHandler(hdlr)
+        log.addHandler(handler)
+        log.propagate = False
+
+        log = observer_logger.logger
+        for hdlr in log.handlers[:]:
+            log.removeHandler(hdlr)
+        log.addHandler(handler)
+        log.propagate = False
+
+        self.logStream = logStream
+
+    def hide_output(self):
+        set_override("observer_console_print", False)
+        self.log_to_memory()
+        sys.stdout = self.logStream
+        sys.stderr = self.logStream
+
+    def restore_output(self):
+        sys.stdout = sys.__stdout__
+        sys.stderr = sys.__stderr__
+
+        if not self.hide_observer_output:
+            print self.logStream.getvalue()
+
+    def save_output(self, what, fn):
+        file(fn,"w").write(self.logStream.getvalue())
+        print >> sys.__stdout__,"   (%s log saved to %s)" % (what, fn)
+
+    def run_model_policy(self, save_output=None):
+        self.ensure_observer_not_running()
+
+        self.hide_output()
+        try:
+            print ">>>>> run model_policies"
+            run_policy_once()
+            print ">>>>> done model_policies"
+            if save_output:
+                self.save_output("model_policy",save_output)
+        finally:
+            self.restore_output()
+
+    def run_observer(self, save_output=None):
+        self.ensure_observer_not_running()
+        self.log_to_memory()
+
+        self.hide_output()
+        try:
+            print ">>>>> run observer"
+            observer = XOSObserver()
+            observer.run_once()
+            print ">>>>> done observer"
+            if save_output:
+                self.save_output("observer",save_output)
+        finally:
+            self.restore_output()
+
diff --git a/xos/tosca/tests/porttest.py b/xos/tosca/tests/porttest.py
new file mode 100644
index 0000000..4ef7a7d
--- /dev/null
+++ b/xos/tosca/tests/porttest.py
@@ -0,0 +1,162 @@
+from basetest import BaseToscaTest
+
+from core.models import Network, Slice, NetworkTemplate, NetworkSlice, Port, Instance
+
+class PortTest(BaseToscaTest):
+    tests = ["create_port_minimal",
+             "create_two_ports",
+             "create_four_ports",
+             "add_port_after_network"]
+
+    def cleanup(self):
+        self.try_to_delete(Instance, name="test_compute1")
+        self.try_to_delete(Instance, name="test_compute2")
+        self.try_to_delete(Network, name="test_net")
+        self.try_to_delete(Slice, name="testsite_slice1")
+        self.try_to_delete(Slice, name="testsite_slice2")
+
+    @property
+    def slice1(self):
+        return Slice.objects.get(name="testsite_slice1")
+
+    @property
+    def slice2(self):
+        return Slice.objects.get(name="testsite_slice2")
+
+    @property
+    def private(self):
+        return NetworkTemplate.objects.get(name="Private")
+
+    @property
+    def test_slice1_1(self):
+        return Instance.objects.get(name="test_slice1-1")
+
+    @property
+    def test_slice1_2(self):
+        return Instance.objects.get(name="test_slice1-2")
+
+    @property
+    def test_slice2_1(self):
+        return Instance.objects.get(name="test_slice2-1")
+
+    @property
+    def test_slice2_2(self):
+        return Instance.objects.get(name="test_slice2-2")
+
+    def get_base_templates(self):
+        return self.make_nodetemplate("testsite", "tosca.nodes.Site") + \
+               self.make_nodetemplate("testsite_slice1", "tosca.nodes.Slice", reqs=[("testsite", "tosca.relationships.MemberOfSite")]) + \
+               self.make_nodetemplate("testsite_slice2", "tosca.nodes.Slice", reqs=[("testsite", "tosca.relationships.MemberOfSite")]) + \
+               self.make_nodetemplate("Private", "tosca.nodes.NetworkTemplate") + \
+               self.make_compute("testsite_slice1", "test_slice1-1") + \
+               self.make_compute("testsite_slice1", "test_slice1-2") +\
+               self.make_compute("testsite_slice2", "test_slice2-1") + \
+               self.make_compute("testsite_slice2", "test_slice2-2")
+
+    def create_port_minimal(self):
+        self.assert_noobj(Network, "test_net")
+        self.execute(self.get_base_templates() +
+                     self.make_nodetemplate("test_net", "tosca.nodes.network.Network",
+                                            reqs=[("testsite_slice1", "tosca.relationships.MemberOfSlice"),
+                                                  ("Private", "tosca.relationships.UsesNetworkTemplate")]) +
+                     self.make_nodetemplate("test_port", "tosca.nodes.network.Port",
+                                            reqs=[("test_net", "tosca.relationships.network.LinksTo"),
+                                                  ("test_slice1-1", "tosca.relationships.network.BindsTo")]))
+
+        net=self.assert_obj(Network, "test_net")
+
+        port=Port.objects.filter(network=net, instance=self.test_slice1_1)
+        assert(len(port)==1)
+        port=port[0]
+
+    def create_two_ports(self):
+        self.assert_noobj(Network, "test_net")
+        self.execute(self.get_base_templates() +
+                     self.make_nodetemplate("test_net", "tosca.nodes.network.Network",
+                                            reqs=[("testsite_slice1", "tosca.relationships.MemberOfSlice"),
+                                                  ("Private", "tosca.relationships.UsesNetworkTemplate")]) +
+                     self.make_nodetemplate("test_port1", "tosca.nodes.network.Port",
+                                            reqs=[("test_net", "tosca.relationships.network.LinksTo"),
+                                                  ("test_slice1-1", "tosca.relationships.network.BindsTo")]) +
+                     self.make_nodetemplate("test_port2", "tosca.nodes.network.Port",
+                                            reqs=[("test_net", "tosca.relationships.network.LinksTo"),
+                                                  ("test_slice1-2", "tosca.relationships.network.BindsTo")]))
+
+        net=self.assert_obj(Network, "test_net")
+
+        port=Port.objects.filter(network=net, instance=self.test_slice1_1)
+        assert(len(port)==1)
+        port=port[0]
+
+        port=Port.objects.filter(network=net, instance=self.test_slice1_2)
+        assert(len(port)==1)
+        port=port[0]
+
+    def create_four_ports(self):
+        self.assert_noobj(Network, "test_net")
+        self.execute(self.get_base_templates() +
+                     self.make_nodetemplate("test_net", "tosca.nodes.network.Network",
+                                            reqs=[("testsite_slice1", "tosca.relationships.MemberOfSlice"),
+                                                  ("Private", "tosca.relationships.UsesNetworkTemplate")]) +
+                     self.make_nodetemplate("test_port1", "tosca.nodes.network.Port",
+                                            reqs=[("test_net", "tosca.relationships.network.LinksTo"),
+                                                  ("test_slice1-1", "tosca.relationships.network.BindsTo")]) +
+                     self.make_nodetemplate("test_port2", "tosca.nodes.network.Port",
+                                            reqs=[("test_net", "tosca.relationships.network.LinksTo"),
+                                                  ("test_slice1-2", "tosca.relationships.network.BindsTo")]) +
+                     self.make_nodetemplate("test_port3", "tosca.nodes.network.Port",
+                                            reqs=[("test_net", "tosca.relationships.network.LinksTo"),
+                                                  ("test_slice2-1", "tosca.relationships.network.BindsTo")]) +
+                     self.make_nodetemplate("test_port4", "tosca.nodes.network.Port",
+                                            reqs=[("test_net", "tosca.relationships.network.LinksTo"),
+                                                  ("test_slice2-2", "tosca.relationships.network.BindsTo")]))
+
+        net=self.assert_obj(Network, "test_net")
+
+        port=Port.objects.filter(network=net, instance=self.test_slice1_1)
+        assert(len(port)==1)
+        port=port[0]
+
+        port=Port.objects.filter(network=net, instance=self.test_slice1_2)
+        assert(len(port)==1)
+        port=port[0]
+
+        port=Port.objects.filter(network=net, instance=self.test_slice2_2)
+        assert(len(port)==1)
+        port=port[0]
+
+        port=Port.objects.filter(network=net, instance=self.test_slice2_2)
+        assert(len(port)==1)
+        port=port[0]
+
+    def add_port_after_network(self):
+        self.assert_noobj(Network, "test_net")
+        self.execute(self.get_base_templates() +
+                     self.make_nodetemplate("test_net", "tosca.nodes.network.Network",
+                                            reqs=[("testsite_slice1", "tosca.relationships.MemberOfSlice"),
+                                                  ("Private", "tosca.relationships.UsesNetworkTemplate")]))
+
+
+        orig_net=self.assert_obj(Network, "test_net")
+
+        self.execute(self.get_base_templates() +
+                     self.make_nodetemplate("test_net", "tosca.nodes.network.Network",
+                                            reqs=[("testsite_slice1", "tosca.relationships.MemberOfSlice"),
+                                                  ("Private", "tosca.relationships.UsesNetworkTemplate")]) +
+                     self.make_nodetemplate("test_port1", "tosca.nodes.network.Port",
+                                            reqs=[("test_net", "tosca.relationships.network.LinksTo"),
+                                                  ("test_slice1-1", "tosca.relationships.network.BindsTo")]))
+
+        net=self.assert_obj(Network, "test_net")
+
+        assert(orig_net.id == net.id)
+
+        port=Port.objects.filter(network=net, instance=self.test_slice1_1)
+        assert(len(port)==1)
+        port=port[0]
+
+
+if __name__ == "__main__":
+    PortTest()
+
+
diff --git a/xos/tosca/tests/servicetest.py b/xos/tosca/tests/servicetest.py
new file mode 100644
index 0000000..276463d
--- /dev/null
+++ b/xos/tosca/tests/servicetest.py
@@ -0,0 +1,74 @@
+from basetest import BaseToscaTest
+
+from core.models import Service
+
+class ServiceTest(BaseToscaTest):
+    tests = ["create_service_minimal",
+             "create_service_notpublished",
+             "create_service_notenabled",
+             "create_service_public_key",
+             "update_service_notpublished",
+             "create_service_maximal",
+             "destroy_service"]
+
+    def cleanup(self):
+        self.try_to_delete(Service, name="test_svc")
+
+    def create_service_minimal(self):
+        self.assert_noobj(Service, "test_svc")
+        self.execute(self.make_nodetemplate("test_svc", "tosca.nodes.Service"))
+        self.assert_obj(Service, "test_svc", kind="generic", published=True, enabled=True)
+
+    def create_service_notpublished(self):
+        self.assert_noobj(Service, "test_svc")
+        self.execute(self.make_nodetemplate("test_svc", "tosca.nodes.Service", {"published": False}))
+        self.assert_obj(Service, "test_svc", kind="generic", published=False, enabled=True)
+
+    def create_service_notenabled(self):
+        self.assert_noobj(Service, "test_svc")
+        self.execute(self.make_nodetemplate("test_svc", "tosca.nodes.Service", {"enabled": False}))
+        self.assert_obj(Service, "test_svc", kind="generic", published=True, enabled=False)
+
+    def create_service_public_key(self):
+        self.assert_noobj(Service, "test_svc")
+        self.execute(self.make_nodetemplate("test_svc", "tosca.nodes.Service", {"public_key": "foobar"}))
+        self.assert_obj(Service, "test_svc", kind="generic", published=True, enabled=True, public_key="foobar")
+
+    def update_service_notpublished(self):
+        self.assert_noobj(Service, "test_svc")
+        self.execute(self.make_nodetemplate("test_svc", "tosca.nodes.Service"))
+        original_obj = self.assert_obj(Service, "test_svc", kind="generic", published=True, enabled=True)
+        self.execute(self.make_nodetemplate("test_svc", "tosca.nodes.Service", {"published": False}))
+        updated_obj = self.assert_obj(Service, "test_svc", kind="generic", published=False, enabled=True)
+        assert(original_obj.id == updated_obj.id)
+
+    def create_service_maximal(self):
+        self.assert_noobj(Service, "test_svc")
+        self.execute(self.make_nodetemplate("test_svc", "tosca.nodes.Service",
+                        {"kind": "testkind",
+                         "published": False,
+                         "enabled": False,
+                         "view_url": "http://foo/",
+                         "icon_url": "http://bar/",
+                         "public_key": "foobar",
+                         "versionNumber": "1.2"} ))
+        self.assert_obj(Service, "test_svc",
+                         kind="testkind",
+                         published=False,
+                         enabled=False,
+                         view_url="http://foo/",
+                         icon_url="http://bar/",
+                         public_key="foobar",
+                         versionNumber="1.2")
+
+    def destroy_service(self):
+        self.assert_noobj(Service, "test_svc")
+        self.execute(self.make_nodetemplate("test_svc", "tosca.nodes.Service"))
+        self.assert_obj(Service, "test_svc", kind="generic", published=True, enabled=True)
+        self.destroy(self.make_nodetemplate("test_svc", "tosca.nodes.Service"))
+        self.assert_noobj(Service, "test_svc")
+
+if __name__ == "__main__":
+    ServiceTest()
+
+
diff --git a/xos/tosca/tests/sitetest.py b/xos/tosca/tests/sitetest.py
new file mode 100644
index 0000000..5321159
--- /dev/null
+++ b/xos/tosca/tests/sitetest.py
@@ -0,0 +1,110 @@
+from basetest import BaseToscaTest
+
+from core.models import Site, SitePrivilege, User
+
+class SiteTest(BaseToscaTest):
+    tests = ["create_site_minimal",
+             "create_site_privilege_tech",
+             "create_site_privilege_admin",
+             "create_site_privilege_pi",
+             "create_site_nocreate",
+             "update_site",
+             "update_site_noupdate",
+             "destroy_site",
+             "destroy_site_nodelete"
+                           ]
+
+    def cleanup(self):
+        self.try_to_delete(Site, name="testsite")
+
+    def create_site_minimal(self):
+        self.assert_noobj(Site, "testsite")
+        self.execute(self.make_nodetemplate("testsite", "tosca.nodes.Site"))
+        site = self.assert_obj(Site, "testsite")
+
+    def create_site_privilege_tech(self):
+        self.assert_noobj(Site, "testsite")
+        self.execute(self.make_nodetemplate("testsite", "tosca.nodes.Site") +
+                     self.make_nodetemplate("test@user.com", "tosca.nodes.User",
+                         props = {"firstname": "test", "lastname": "user", "password": "letmein"},
+                         reqs = [("testsite", "tosca.relationships.MemberOfSite"),
+                                 ("testsite", "tosca.relationships.TechPrivilege")]))
+        site = self.assert_obj(Site, "testsite")
+        user = User.objects.get(email="test@user.com")
+
+        sps = SitePrivilege.objects.filter(site=site, user=user)
+        assert(len(sps) == 1)
+        assert(sps[0].role.role == "tech")
+
+    def create_site_privilege_admin(self):
+        self.assert_noobj(Site, "testsite")
+        self.execute(self.make_nodetemplate("testsite", "tosca.nodes.Site") +
+                     self.make_nodetemplate("test@user.com", "tosca.nodes.User",
+                         props = {"firstname": "test", "lastname": "user", "password": "letmein"},
+                         reqs = [("testsite", "tosca.relationships.MemberOfSite"),
+                                 ("testsite", "tosca.relationships.AdminPrivilege")]))
+        site = self.assert_obj(Site, "testsite")
+        user = User.objects.get(email="test@user.com")
+
+        sps = SitePrivilege.objects.filter(site=site, user=user)
+        assert(len(sps) == 1)
+        assert(sps[0].role.role == "admin")
+
+    def create_site_privilege_pi(self):
+        self.assert_noobj(Site, "testsite")
+        self.execute(self.make_nodetemplate("testsite", "tosca.nodes.Site") +
+                     self.make_nodetemplate("test@user.com", "tosca.nodes.User",
+                         props = {"firstname": "test", "lastname": "user", "password": "letmein"},
+                         reqs = [("testsite", "tosca.relationships.MemberOfSite"),
+                                 ("testsite", "tosca.relationships.PIPrivilege")]))
+        site = self.assert_obj(Site, "testsite")
+        user = User.objects.get(email="test@user.com")
+
+        sps = SitePrivilege.objects.filter(site=site, user=user)
+        assert(len(sps) == 1)
+        assert(sps[0].role.role == "pi")
+
+    def create_site_nocreate(self):
+        self.assert_noobj(Site, "testsite")
+        self.execute(self.make_nodetemplate("testsite", "tosca.nodes.Site",
+                                            props={"no-create": True}))
+        site = self.assert_noobj(Site, "testsite")
+
+    def update_site(self):
+        self.assert_noobj(Site, "testsite")
+        self.execute(self.make_nodetemplate("testsite", "tosca.nodes.Site"))
+        orig_site = self.assert_obj(Site, "testsite", site_url=None)
+        self.execute(self.make_nodetemplate("testsite", "tosca.nodes.Site",
+                                            props={"site_url": "http://foo.com/"}))
+        site = self.assert_obj(Site, "testsite", site_url="http://foo.com/")
+        assert(orig_site.id == site.id)
+
+    def update_site_noupdate(self):
+        self.assert_noobj(Site, "testsite")
+        self.execute(self.make_nodetemplate("testsite", "tosca.nodes.Site"))
+        orig_site = self.assert_obj(Site, "testsite", site_url=None)
+        self.execute(self.make_nodetemplate("testsite", "tosca.nodes.Site",
+                                            props={"site_url": "http://foo.com/",
+                                                   "no-update": True}))
+        site = self.assert_obj(Site, "testsite", site_url=None)
+        assert(orig_site.id == site.id)
+
+    def destroy_site(self):
+        self.assert_noobj(Site, "testsite")
+        self.execute(self.make_nodetemplate("testsite", "tosca.nodes.Site"))
+        site = self.assert_obj(Site, "testsite")
+        self.destroy(self.make_nodetemplate("testsite", "tosca.nodes.Site"))
+        self.assert_noobj(Site, "testsite")
+
+    def destroy_site_nodelete(self):
+        self.assert_noobj(Site, "testsite")
+        self.execute(self.make_nodetemplate("testsite", "tosca.nodes.Site"))
+        site = self.assert_obj(Site, "testsite")
+        self.destroy(self.make_nodetemplate("testsite", "tosca.nodes.Site",
+                                            props={"no-delete": True}))
+        self.assert_obj(Site, "testsite")
+
+if __name__ == "__main__":
+    SiteTest()
+
+
diff --git a/xos/tosca/tests/slicetest.py b/xos/tosca/tests/slicetest.py
new file mode 100644
index 0000000..98de4e6
--- /dev/null
+++ b/xos/tosca/tests/slicetest.py
@@ -0,0 +1,112 @@
+from basetest import BaseToscaTest
+
+from core.models import Slice, Site, User, SlicePrivilege
+
+class SliceTest(BaseToscaTest):
+    tests = ["create_slice_minimal",
+             "create_slice_maximal",
+             "create_slice_privilege",
+             "create_slice_nocreate",
+             "update_slice",
+             "update_slice_noupdate",
+             "destroy_slice",
+             "destroy_slice_nodelete"]
+
+    def cleanup(self):
+        self.try_to_delete(Slice, name="testsite_testslice")
+        self.try_to_delete(Site, name="testsite")
+
+    def get_base_templates(self):
+        return self.make_nodetemplate("testsite", "tosca.nodes.Site")
+
+    def create_slice_minimal(self):
+        self.assert_noobj(Slice, "testsite_testslice")
+        self.execute(self.get_base_templates() +
+                     self.make_nodetemplate("testsite_testslice", "tosca.nodes.Slice",
+                                            reqs=[("testsite", "tosca.relationships.MemberOfSite")]))
+        self.assert_obj(Slice, "testsite_testslice", enabled=True, description="", slice_url="", max_instances=10)
+
+    def create_slice_maximal(self):
+        self.assert_noobj(Slice, "testsite_testslice")
+        self.execute(self.get_base_templates() +
+                     self.make_nodetemplate("testsite_testslice", "tosca.nodes.Slice",
+                                             props={"enabled": False, "description": "foo", "slice_url": "http://foo.com/", "max_instances": 11},
+                                             reqs=[("testsite", "tosca.relationships.MemberOfSite")]))
+        self.assert_obj(Slice, "testsite_testslice", enabled=False, description="foo", slice_url="http://foo.com/", max_instances=11)
+
+    def create_slice_privilege(self):
+        self.assert_noobj(Slice, "testsite_testslice")
+        self.execute(self.get_base_templates() +
+                     self.make_user_template() +
+                     self.make_nodetemplate("testsite_testslice", "tosca.nodes.Slice",
+                                            reqs=[("testsite", "tosca.relationships.MemberOfSite"),
+                                                  ("test@user.com", "tosca.relationships.AdminPrivilege")]))
+        slice = self.assert_obj(Slice, "testsite_testslice")
+        user = User.objects.get(email="test@user.com")
+
+        dps = SlicePrivilege.objects.filter(user=user, slice=slice)
+        assert(len(dps) == 1)
+
+    def create_slice_nocreate(self):
+        self.assert_noobj(Slice, "testsite_testslice")
+        self.execute(self.get_base_templates() +
+                     self.make_nodetemplate("testsite_testslice", "tosca.nodes.Slice",
+                                            reqs=[("testsite", "tosca.relationships.MemberOfSite")],
+                                            props={"no-create": True}))
+        self.assert_noobj(Slice, "testsite_testslice")
+
+    def update_slice(self):
+        self.assert_noobj(Slice, "testsite_testslice")
+        self.execute(self.get_base_templates() +
+                     self.make_nodetemplate("testsite_testslice", "tosca.nodes.Slice",
+                                            reqs=[("testsite", "tosca.relationships.MemberOfSite")]))
+        orig_slice = self.assert_obj(Slice, "testsite_testslice", enabled=True, description="", slice_url="", max_instances=10)
+        self.execute(self.get_base_templates() +
+                     self.make_nodetemplate("testsite_testslice", "tosca.nodes.Slice",
+                                            reqs=[("testsite", "tosca.relationships.MemberOfSite")],
+                                            props={"description": "foo"}))
+        slice = self.assert_obj(Slice, "testsite_testslice", enabled=True, description="foo", slice_url="", max_instances=10)
+        assert(orig_slice.id == slice.id)
+
+    def update_slice_noupdate(self):
+        self.assert_noobj(Slice, "testsite_testslice")
+        self.execute(self.get_base_templates() +
+                     self.make_nodetemplate("testsite_testslice", "tosca.nodes.Slice",
+                                            reqs=[("testsite", "tosca.relationships.MemberOfSite")]))
+        orig_slice = self.assert_obj(Slice, "testsite_testslice", enabled=True, description="", slice_url="", max_instances=10)
+        self.execute(self.get_base_templates() +
+                     self.make_nodetemplate("testsite_testslice", "tosca.nodes.Slice",
+                                            reqs=[("testsite", "tosca.relationships.MemberOfSite")],
+                                            props={"description": "foo",
+                                                   "no-update": True}))
+        slice = self.assert_obj(Slice, "testsite_testslice", enabled=True, description="", slice_url="", max_instances=10)
+        assert(orig_slice.id == slice.id)
+
+    def destroy_slice(self):
+        self.assert_noobj(Slice, "testsite_testslice")
+        self.execute(self.get_base_templates() +
+                     self.make_nodetemplate("testsite_testslice", "tosca.nodes.Slice",
+                                            reqs=[("testsite", "tosca.relationships.MemberOfSite")]))
+        self.assert_obj(Slice, "testsite_testslice", enabled=True, description="", slice_url="", max_instances=10)
+        self.destroy(self.get_base_templates() +
+                     self.make_nodetemplate("testsite_testslice", "tosca.nodes.Slice",
+                                            reqs=[("testsite", "tosca.relationships.MemberOfSite")]))
+        self.assert_noobj(Slice, "testsite_testslice")
+
+    def destroy_slice_nodelete(self):
+        self.assert_noobj(Slice, "testsite_testslice")
+        self.execute(self.get_base_templates() +
+                     self.make_nodetemplate("testsite_testslice", "tosca.nodes.Slice",
+                                            reqs=[("testsite", "tosca.relationships.MemberOfSite")]))
+        orig_slice = self.assert_obj(Slice, "testsite_testslice", enabled=True, description="", slice_url="", max_instances=10)
+        self.destroy(self.get_base_templates() +
+                     self.make_nodetemplate("testsite_testslice", "tosca.nodes.Slice",
+                                            reqs=[("testsite", "tosca.relationships.MemberOfSite")],
+                                            props={"no-delete": True}))
+        slice = self.assert_obj(Slice, "testsite_testslice", enabled=True, description="", slice_url="", max_instances=10)
+        assert(slice.id == orig_slice.id)
+
+if __name__ == "__main__":
+    SliceTest()
+
+
diff --git a/xos/tosca/tests/usertest.py b/xos/tosca/tests/usertest.py
new file mode 100644
index 0000000..f36eb06
--- /dev/null
+++ b/xos/tosca/tests/usertest.py
@@ -0,0 +1,98 @@
+from basetest import BaseToscaTest
+
+from core.models import User
+
+class UserTest(BaseToscaTest):
+    tests = ["create_user_minimal",
+             "create_user_maximal",
+             "create_user_key_artifact",
+             "destroy_user",
+                           ]
+
+    def cleanup(self):
+        self.try_to_delete(User, email="test@user.com")
+
+    def get_base_templates(self):
+        return self.make_nodetemplate("testsite", "tosca.nodes.Site")
+
+    def assert_nouser(self, email):
+        assert(not User.objects.filter(email=email))
+
+    def assert_user(self, email, **kwargs):
+        obj = User.objects.get(email=email)
+        assert(obj)
+        for (k,v) in kwargs.items():
+            if (getattr(obj,k,None) != v):
+                print "Object %s property '%s' is '%s' and should be '%s'" % (obj, k, getattr(obj,k,None), v)
+                assert(False)
+        return obj
+
+    def create_user_minimal(self):
+        self.assert_nouser("test@user.com")
+        self.execute(self.get_base_templates() +
+                     self.make_nodetemplate("test@user.com", "tosca.nodes.User",
+                         props = {"firstname": "test", "lastname": "user", "password": "letmein"},
+                         reqs = [("testsite", "tosca.relationships.MemberOfSite")]))
+        user = self.assert_user("test@user.com",
+                                 firstname="test",
+                                 lastname="user",
+                                 is_active=True,
+                                 is_admin=False)
+
+
+    def create_user_maximal(self):
+        self.assert_nouser("test@user.com")
+        self.execute(self.get_base_templates() +
+                     self.make_nodetemplate("test@user.com", "tosca.nodes.User",
+                         props = {"firstname": "test",
+                                  "lastname": "user",
+                                  "password": "letmein",
+                                  "phone": "123-456-7890",
+                                  "user_url": "http://foo.bar/",
+                                  "public_key": "thisismykey",
+                                  "is_active": False,
+                                  "is_admin": True},
+                         reqs = [("testsite", "tosca.relationships.MemberOfSite")]))
+        user = self.assert_user("test@user.com",
+                                 firstname="test",
+                                 lastname="user",
+                                 phone="123-456-7890",
+                                 user_url="http://foo.bar/",
+                                 public_key="thisismykey",
+                                 # is_active=False, XXX investigate -- this is failing
+                                 is_admin=True)
+
+    def create_user_key_artifact(self):
+        self.assert_nouser("test@user.com")
+        pubkey = self.make_random_string(400)
+        file("/tmp/pubkey", "w").write(pubkey)
+        self.execute(self.get_base_templates() +
+                     self.make_nodetemplate("test@user.com", "tosca.nodes.User",
+                         props = {"firstname": "test", "lastname": "user", "password": "letmein", "public_key": "{ get_artifact: [ SELF, pubkey, LOCAL_FILE] }" },
+                         artifacts = {"pubkey": "/tmp/pubkey"},
+                         reqs = [("testsite", "tosca.relationships.MemberOfSite")]))
+        user = self.assert_user("test@user.com",
+                                 firstname="test",
+                                 lastname="user",
+                                 is_active=True,
+                                 is_admin=False,
+                                 public_key=pubkey)
+
+    def destroy_user(self):
+        self.assert_nouser("test@user.com")
+        self.execute(self.get_base_templates() +
+                     self.make_nodetemplate("test@user.com", "tosca.nodes.User",
+                         props = {"firstname": "test", "lastname": "user", "password": "letmein"},
+                         reqs = [("testsite", "tosca.relationships.MemberOfSite")]))
+        user = self.assert_user("test@user.com")
+        self.destroy(self.get_base_templates() +
+                     self.make_nodetemplate("test@user.com", "tosca.nodes.User",
+                         props = {"firstname": "test", "lastname": "user", "password": "letmein"},
+                         reqs = [("testsite", "tosca.relationships.MemberOfSite")]))
+        self.assert_nouser("test@user.com")
+
+
+if __name__ == "__main__":
+    UserTest()
+
+
diff --git a/xos/uwsgi/xos.ini b/xos/uwsgi/xos.ini
new file mode 100644
index 0000000..63eb6b2
--- /dev/null
+++ b/xos/uwsgi/xos.ini
@@ -0,0 +1,18 @@
+[uwsgi]
+chdir = /opt/xos
+module = xos.wsgi:application
+env = DJANGO_SETTINGS_MODULE=xos.settings
+socket = /var/run/uwsgi.xos.sock
+socket = 127.0.0.1:9001
+http = 127.0.0.1:9002
+stats = 127.0.0.1:9003
+workers = 3
+master = true
+processes = 8
+uid = root
+gid = root
+harakiri = 20
+daemonize=/var/log/uwsgi.xos.log 
+static-map = /static=/var/www/xos/static
+pidfile = /var/run/uwsgi.xos.pid
+buffer-size = 8192
diff --git a/xos/xos/__init__.py b/xos/xos/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xos/xos/__init__.py
diff --git a/xos/xos/admin_customize/README.md b/xos/xos/admin_customize/README.md
new file mode 100644
index 0000000..ecc4520
--- /dev/null
+++ b/xos/xos/admin_customize/README.md
@@ -0,0 +1 @@
+admin_customize contains django UI elements (such as templatetags) that are common to all django apps within XOS.
diff --git a/xos/xos/admin_customize/__init__.py b/xos/xos/admin_customize/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/xos/xos/admin_customize/__init__.py
@@ -0,0 +1 @@
+
diff --git a/xos/xos/admin_customize/templatetags/__init__.py b/xos/xos/admin_customize/templatetags/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/xos/xos/admin_customize/templatetags/__init__.py
@@ -0,0 +1 @@
+
diff --git a/xos/xos/admin_customize/templatetags/admin_modify.py b/xos/xos/admin_customize/templatetags/admin_modify.py
new file mode 100644
index 0000000..e2a8c7b
--- /dev/null
+++ b/xos/xos/admin_customize/templatetags/admin_modify.py
@@ -0,0 +1,25 @@
+from django.contrib.admin.templatetags.admin_modify import *
+from django.contrib.admin.templatetags.admin_modify import submit_row as original_submit_row
+from django.conf import settings
+import random
+@register.inclusion_tag('admin/submit_line.html', takes_context=True)
+def submit_row(context):
+    ctx = original_submit_row(context)
+    ctx.update({
+        'show_save': context.get('show_save', ctx['show_save']),
+        'show_save_and_add_another': context.get('show_save_and_add_another', ctx['show_save_and_add_another']),
+        'show_save_and_continue': context.get('show_save_and_continue', ctx['show_save_and_continue']),
+        'custom_delete_url': context.get("custom_delete_url",None),
+        })                                                                  
+    return ctx 
+
+
+
+@register.simple_tag
+def random_str(a):
+    a = ["You are now signed out. Thank you and have a great day",
+         "Thanks for spending some quality time with the Web site today.",
+         "Thanks for using " +settings.XOS_BRANDING_NAME + " to manage your network today.",
+         "You have successfully logged out, Thanks for spending some quality time",
+         "The "+settings.XOS_BRANDING_NAME +" team is glad that you used our product to get your work done."]
+    return a[random.randint(0,4)]
\ No newline at end of file
diff --git a/xos/xos/apibase.py b/xos/xos/apibase.py
new file mode 100644
index 0000000..addbbe9
--- /dev/null
+++ b/xos/xos/apibase.py
@@ -0,0 +1,91 @@
+from rest_framework.response import Response
+from rest_framework import serializers
+from rest_framework import generics
+from rest_framework import status
+from rest_framework.exceptions import APIException
+from rest_framework.exceptions import PermissionDenied as RestFrameworkPermissionDenied
+from django.core.exceptions import PermissionDenied as DjangoPermissionDenied
+from django.core.exceptions import ValidationError as DjangoValidationError
+from xos.exceptions import *
+
+class XOSRetrieveUpdateDestroyAPIView(generics.RetrieveUpdateDestroyAPIView):
+
+    # To handle fine-grained field permissions, we have to check can_update
+    # the object has been updated but before it has been saved.
+
+    def update(self, request, *args, **kwargs):
+        partial = kwargs.pop('partial', False)
+        self.object = self.get_object()
+
+        if self.object is None:
+            raise XOSProgrammingError("Use the List API for creating objects")
+
+        serializer = self.get_serializer(self.object, data=request.data, partial=partial)
+
+        if not serializer.is_valid():
+            raise XOSValidationError(fields=serializer._errors)
+
+        # Do the XOS perm check
+
+        assert(serializer.instance is not None)
+        obj = serializer.instance
+        for attr, value in serializer.validated_data.items():
+            setattr(obj, attr, value)
+        obj.caller = request.user
+        if not obj.can_update(request.user):
+            raise XOSPermissionDenied()
+
+        self.perform_update(serializer)
+
+        return Response(serializer.data, status=status.HTTP_200_OK)
+
+    def destroy(self, request, *args, **kwargs):
+        obj = self.get_object()
+        obj.caller = request.user
+        if obj.can_update(request.user):
+            self.perform_destroy(obj)
+            return Response(status=status.HTTP_204_NO_CONTENT)
+        else:
+            return Response(status=status.HTTP_400_BAD_REQUEST)
+
+    def handle_exception(self, exc):
+        # REST API drops the string attached to Django's PermissionDenied
+        # exception, and replaces it with a generic "Permission Denied"
+        if isinstance(exc, DjangoPermissionDenied):
+            response=Response({'detail': {"error": "PermissionDenied", "specific_error": str(exc), "fields": {}}}, status=status.HTTP_403_FORBIDDEN)
+            response.exception=True
+            return response
+        else:
+            return super(XOSRetrieveUpdateDestroyAPIView, self).handle_exception(exc)
+
+class XOSListCreateAPIView(generics.ListCreateAPIView):
+    def create(self, request, *args, **kwargs):
+        serializer = self.get_serializer(data=request.data)
+
+        # In rest_framework 3.x: we can pass raise_exception=True instead of
+        # raising the exception ourselves
+        if not serializer.is_valid():
+            raise XOSValidationError(fields=serializer._errors)
+
+        # now do XOS can_update permission checking
+        obj = serializer.Meta.model(**serializer.validated_data)
+        obj.caller = request.user
+        if not obj.can_update(request.user):
+            raise XOSPermissionDenied()
+
+        self.perform_create(serializer)
+
+        headers = self.get_success_headers(serializer.data)
+        return Response(serializer.data, status=status.HTTP_201_CREATED,
+                        headers=headers)
+
+    def handle_exception(self, exc):
+        # REST API drops the string attached to Django's PermissionDenied
+        # exception, and replaces it with a generic "Permission Denied"
+        if isinstance(exc, DjangoPermissionDenied):
+            response=Response({'detail': {"error": "PermissionDenied", "specific_error": str(exc), "fields": {}}}, status=status.HTTP_403_FORBIDDEN)
+            response.exception=True
+            return response
+        else:
+            return super(XOSListCreateAPIView, self).handle_exception(exc)
+
diff --git a/xos/xos/apps.py b/xos/xos/apps.py
new file mode 100644
index 0000000..b30f462
--- /dev/null
+++ b/xos/xos/apps.py
@@ -0,0 +1,14 @@
+from suit.apps import DjangoSuitConfig
+
+
+class MyDjangoSuitConfig(DjangoSuitConfig):
+    admin_name = 'XOS'
+    menu_position = 'vertical'
+    menu_open_first_child = False
+    menu = (
+      {'label': 'Deployments', 'icon': 'icon-deployment', 'url': '/admin/core/deployment/'},
+      {'label': 'Sites', 'icon': 'icon-site', 'url': '/admin/core/site/'},
+      {'label': 'Slices', 'icon': 'icon-slice', 'url': '/admin/core/slice/'},
+      {'label': 'Users', 'icon': 'icon-user', 'url': '/admin/core/user/'},
+      {'label': 'Services', 'icon': 'icon-cog', 'url': '/serviceGrid/'},
+    )
diff --git a/xos/xos/config.py b/xos/xos/config.py
new file mode 100644
index 0000000..154ba20
--- /dev/null
+++ b/xos/xos/config.py
@@ -0,0 +1,280 @@
+#!/usr/bin/env python
+import sys
+import os
+import time
+import ConfigParser
+import tempfile
+import codecs
+from StringIO import StringIO
+from xml_util import Xml
+
+default_config = \
+"""
+"""
+
+XOS_DIR = "/opt/xos"
+DEFAULT_CONFIG_FN = os.path.join(XOS_DIR, "xos_configuration/")
+
+# warning for now, remove once we're sure everyone has made the change
+if (os.path.exists("/opt/planetstack/plstackapi_config") and (not os.path.exists(DEFAULT_CONFIG_FN))):
+    print >> sys.stderr, "WARNING: did you forget to rename plstackapi_config to xos_config ??"
+
+def isbool(v):
+	return v.lower() in ("true", "false")
+
+def str2bool(v):
+	return v.lower() in ("true", "1")
+
+# allow the test framework to apply global overrides to the config framework
+override = {}
+def set_override(name, value):
+    override[name] = value
+
+class Config:
+
+	def __init__(self, config_file=None):
+                if (config_file==None):
+                    config_file = self.get_config_fn()
+
+		self._files = []
+		self.config_path = os.path.dirname(config_file)
+		self.config = ConfigParser.ConfigParser()
+		self.filename = config_file
+		if not os.path.isfile(self.filename) and not os.path.isdir(self.filename):
+			self.create(self.filename)
+		self.load(self.filename)
+
+        def get_config_fn(self):
+             # Look for "-C <something>" to get the
+             # name of the config file. Using a real OptionParser here is
+             # problematic as it will throw 'no such option' errors for options
+             # that it does not understand.
+
+             last = None
+             for arg in sys.argv:
+                 if (last=="-C"):
+                     return arg
+                 last = arg
+
+             return DEFAULT_CONFIG_FN
+
+	def _header(self):
+		header = """
+DO NOT EDIT. This file was automatically generated at
+%s from:
+
+%s
+""" % (time.asctime(), os.linesep.join(self._files))
+
+		# Get rid of the surrounding newlines
+		return header.strip().split(os.linesep)
+
+	def create(self, filename):
+		if not os.path.exists(os.path.dirname(filename)):
+			os.makedirs(os.path.dirname(filename))
+		configfile = open(filename, 'w')
+		configfile.write(default_config)
+		configfile.close()
+
+
+	def load(self, filename):
+		if filename:
+			try:
+				if os.path.isdir(filename):
+					config_list = list(sorted(os.listdir(filename)))
+                                        config_list = [x for x in config_list if not x.endswith(".md")]
+                                        if "xos_common_config" in config_list:
+                                            # move xos_common_config to the front of the list
+                                            config_list.remove("xos_common_config")
+                                            config_list=["xos_common_config"] + config_list
+					config_list = [os.path.join(filename, s) for s in config_list]
+					self.config.read(config_list)
+				else:
+					self.config.read(filename)
+			except ConfigParser.MissingSectionHeaderError:
+				if filename.endswith('.xml'):
+					self.load_xml(filename)
+				else:
+					self.load_shell(filename)
+			self._files.append(filename)
+			self.set_attributes()
+
+	def load_xml(self, filename):
+		xml = XML(filename)
+		categories = xml.xpath('//configuration/variables/category')
+		for category in categories:
+			section_name = category.get('id')
+			if not self.config.has_section(section_name):
+				self.config.add_section(section_name)
+			options = category.xpath('./variablelist/variable')
+			for option in options:
+				option_name = option.get('id')
+				value = option.xpath('./value')[0].text
+				if not value:
+					value = ""
+				self.config.set(section_name, option_name, value)
+
+	def load_shell(self, filename):
+		f = open(filename, 'r')
+		for line in f:
+			try:
+				if line.startswith('#'):
+					continue
+				parts = line.strip().split("=")
+				if len(parts) < 2:
+					continue
+				option = parts[0]
+				value = parts[1].replace('"', '').replace("'","")
+				section, var = self.locate_varname(option, strict=False)
+				if section and var:
+					self.set(section, var, value)
+			except:
+				pass
+		f.close()
+
+	def locate_varname(self, varname, strict=True):
+		varname = varname.lower()
+		sections = self.config.sections()
+		section_name = ""
+		var_name = ""
+		for section in sections:
+			if varname.startswith(section.lower()) and len(section) > len(section_name):
+				section_name = section.lower()
+				var_name = varname.replace(section_name, "")[1:]
+		if strict and not self.config.has_option(section_name, var_name):
+			raise ConfigParser.NoOptionError(var_name, section_name)
+		return (section_name, var_name)
+
+	def set_attributes(self):
+		sections = self.config.sections()
+		for section in sections:
+			for item in self.config.items(section):
+				name = "%s_%s" % (section, item[0])
+				value = item[1]
+				if isbool(value):
+					value = str2bool(value)
+				elif value.isdigit():
+					value = int(value)
+				setattr(self, name, value)
+				setattr(self, name.upper(), value)
+
+
+	def verify(self, config1, config2, validate_method):
+		return True
+
+	def validate_type(self, var_type, value):
+		return True
+
+	@staticmethod
+	def is_xml(config_file):
+		try:
+			x = Xml(config_file)
+			return True
+		except:
+			return False
+
+	@staticmethod
+	def is_ini(config_file):
+		try:
+			c = ConfigParser.ConfigParser()
+			c.read(config_file)
+			return True
+		except ConfigParser.MissingSectionHeaderError:
+			return False
+
+
+	def dump(self, sections = []):
+		sys.stdout.write(output_python())
+
+	def output_python(self, encoding = "utf-8"):
+		buf = codecs.lookup(encoding)[3](StringIO())
+		buf.writelines(["# " + line + os.linesep for line in self._header()])
+
+		for section in self.sections():
+			buf.write("[%s]%s" % (section, os.linesep))
+			for (name,value) in self.items(section):
+				buf.write("%s=%s%s" % (name,value,os.linesep))
+			buf.write(os.linesep)
+		return buf.getvalue()
+
+	def output_shell(self, show_comments = True, encoding = "utf-8"):
+		"""
+		Return variables as a shell script.
+		"""
+
+		buf = codecs.lookup(encoding)[3](StringIO())
+		buf.writelines(["# " + line + os.linesep for line in self._header()])
+
+		for section in self.sections():
+			for (name,value) in self.items(section):
+				# bash does not have the concept of NULL
+				if value:
+					option = "%s_%s" % (section.upper(), name.upper())
+					if isbool(value):
+						value = str(str2bool(value))
+					elif not value.isdigit():
+						value = '"%s"' % value
+					buf.write(option + "=" + value + os.linesep)
+		return buf.getvalue()
+
+	def output_php(self, encoding = "utf-8"):
+		"""
+		Return variables as a PHP script.
+		"""
+
+		buf = codecs.lookup(encoding)[3](StringIO())
+		buf.write("<?php" + os.linesep)
+		buf.writelines(["// " + line + os.linesep for line in self._header()])
+
+		for section in self.sections():
+			for (name,value) in self.items(section):
+				option = "%s_%s" % (section, name)
+				buf.write(os.linesep)
+				buf.write("// " + option + os.linesep)
+				if value is None:
+					value = 'NULL'
+				buf.write("define('%s', %s);" % (option, value) + os.linesep)
+
+		buf.write("?>" + os.linesep)
+
+		return buf.getvalue()
+
+	def output_xml(self, encoding = "utf-8"):
+		pass
+
+	def output_variables(self, encoding="utf-8"):
+		"""
+		Return list of all variable names.
+		"""
+
+		buf = codecs.lookup(encoding)[3](StringIO())
+		for section in self.sections():
+			for (name,value) in self.items(section):
+				option = "%s_%s" % (section,name)
+				buf.write(option + os.linesep)
+
+		return buf.getvalue()
+		pass
+
+	def write(self, filename=None):
+		if not filename:
+			filename = self.filename
+		configfile = open(filename, 'w')
+		self.config.write(configfile)
+
+	def save(self, filename=None):
+		self.write(filename)
+
+	def __getattr__(self, attr):
+                if attr in override:
+                    return override[attr]
+		return getattr(self.config, attr)
+
+if __name__ == '__main__':
+	filename = None
+	if len(sys.argv) > 1:
+		filename = sys.argv[1]
+		config = Config(filename)
+	else:
+		config = Config()
+	config.dump()
diff --git a/xos/xos/exceptions.py b/xos/xos/exceptions.py
new file mode 100644
index 0000000..9ab2605
--- /dev/null
+++ b/xos/xos/exceptions.py
@@ -0,0 +1,70 @@
+from rest_framework.exceptions import APIException
+from rest_framework.exceptions import PermissionDenied as RestFrameworkPermissionDenied
+
+class XOSProgrammingError(APIException):
+    status_code=400
+    def __init__(self, why="programming error", fields={}):
+        APIException.__init__(self, {"error": "XOSProgrammingError",
+                            "specific_error": why,
+                            "fields": fields})
+
+class XOSPermissionDenied(RestFrameworkPermissionDenied):
+    def __init__(self, why="permission error", fields={}):
+        APIException.__init__(self, {"error": "XOSPermissionDenied",
+                            "specific_error": why,
+                            "fields": fields})
+
+class XOSNotAuthenticated(RestFrameworkPermissionDenied):
+    def __init__(self, why="you must be authenticated to use this api", fields={}):
+        APIException.__init__(self, {"error": "XOSNotAuthenticated",
+                            "specific_error": why,
+                            "fields": fields})
+
+class XOSNotFound(RestFrameworkPermissionDenied):
+    status_code=404
+    def __init__(self, why="object not found", fields={}):
+        APIException.__init__(self, {"error": "XOSNotFound",
+                            "specific_error": why,
+                            "fields": fields})
+
+class XOSValidationError(APIException):
+    status_code=403
+    def __init__(self, why="validation error", fields={}):
+        APIException.__init__(self, {"error": "XOSValidationError",
+                            "specific_error": why,
+                            "fields": fields})
+
+class XOSDuplicateKey(APIException):
+    status_code=400
+    def __init__(self, why="duplicate key", fields={}):
+        APIException.__init__(self, {"error": "XOSDuplicateKey",
+                            "specific_error": why,
+                            "fields": fields})
+
+class XOSMissingField(APIException):
+    status_code=400
+    def __init__(self, why="missing field", fields={}):
+        APIException.__init__(self, {"error": "XOSMissingField",
+                            "specific_error": why,
+                            "fields": fields})
+
+class XOSConfigurationError(APIException):
+    status_code=400
+    def __init__(self, why="configuration error", fields={}):
+        APIException.__init__(self, {"error": "XOSConfigurationError",
+                            "specific_error": why,
+                            "fields": fields})
+
+class XOSConflictingField(APIException):
+    status_code=400
+    def __init__(self, why="conflicting field", fields={}):
+        APIException.__init__(self, {"error": "XOSMissingField",
+                            "specific_error": why,
+                            "fields": fields})
+
+class XOSServiceUnavailable(APIException):
+    status_code=503
+    def __init__(self, why="Service temporarily unavailable, try again later", fields={}):
+        APIException.__init__(self, {"error": "XOSServiceUnavailable",
+                            "specific_error": why,
+                            "fields": fields})
diff --git a/xos/xos/hpcapi.py b/xos/xos/hpcapi.py
new file mode 100644
index 0000000..00b4ce5
--- /dev/null
+++ b/xos/xos/hpcapi.py
@@ -0,0 +1,857 @@
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+from rest_framework import serializers
+from rest_framework import generics
+from rest_framework import status
+from rest_framework.generics import GenericAPIView
+from services.hpc.models import *
+from django.forms import widgets
+from rest_framework import filters
+from django.conf.urls import patterns, url
+from rest_framework.exceptions import PermissionDenied as RestFrameworkPermissionDenied
+from django.core.exceptions import PermissionDenied as DjangoPermissionDenied
+from apibase import XOSRetrieveUpdateDestroyAPIView, XOSListCreateAPIView, XOSNotAuthenticated
+
+if hasattr(serializers, "ReadOnlyField"):
+    # rest_framework 3.x
+    IdField = serializers.ReadOnlyField
+else:
+    # rest_framework 2.x
+    IdField = serializers.Field
+
+"""
+    Schema of the generator object:
+        all: Set of all Model objects
+        all_if(regex): Set of Model objects that match regex
+
+    Model object:
+        plural: English plural of object name
+        camel: CamelCase version of object name
+        refs: list of references to other Model objects
+        props: list of properties minus refs
+
+    TODO: Deal with subnets
+"""
+
+def get_hpc_REST_patterns():
+    return patterns('',
+        url(r'^hpcapi/$', hpc_api_root_legacy),
+    # legacy - deprecated
+    
+        url(r'hpcapi/hpchealthchecks/$', HpcHealthCheckList.as_view(), name='hpchealthcheck-list-legacy'),
+        url(r'hpcapi/hpchealthchecks/(?P<pk>[a-zA-Z0-9\-]+)/$', HpcHealthCheckDetail.as_view(), name ='hpchealthcheck-detail-legacy'),
+    
+        url(r'hpcapi/hpcservices/$', HpcServiceList.as_view(), name='hpcservice-list-legacy'),
+        url(r'hpcapi/hpcservices/(?P<pk>[a-zA-Z0-9\-]+)/$', HpcServiceDetail.as_view(), name ='hpcservice-detail-legacy'),
+    
+        url(r'hpcapi/originservers/$', OriginServerList.as_view(), name='originserver-list-legacy'),
+        url(r'hpcapi/originservers/(?P<pk>[a-zA-Z0-9\-]+)/$', OriginServerDetail.as_view(), name ='originserver-detail-legacy'),
+    
+        url(r'hpcapi/cdnprefixs/$', CDNPrefixList.as_view(), name='cdnprefix-list-legacy'),
+        url(r'hpcapi/cdnprefixs/(?P<pk>[a-zA-Z0-9\-]+)/$', CDNPrefixDetail.as_view(), name ='cdnprefix-detail-legacy'),
+    
+        url(r'hpcapi/serviceproviders/$', ServiceProviderList.as_view(), name='serviceprovider-list-legacy'),
+        url(r'hpcapi/serviceproviders/(?P<pk>[a-zA-Z0-9\-]+)/$', ServiceProviderDetail.as_view(), name ='serviceprovider-detail-legacy'),
+    
+        url(r'hpcapi/contentproviders/$', ContentProviderList.as_view(), name='contentprovider-list-legacy'),
+        url(r'hpcapi/contentproviders/(?P<pk>[a-zA-Z0-9\-]+)/$', ContentProviderDetail.as_view(), name ='contentprovider-detail-legacy'),
+    
+        url(r'hpcapi/accessmaps/$', AccessMapList.as_view(), name='accessmap-list-legacy'),
+        url(r'hpcapi/accessmaps/(?P<pk>[a-zA-Z0-9\-]+)/$', AccessMapDetail.as_view(), name ='accessmap-detail-legacy'),
+    
+        url(r'hpcapi/sitemaps/$', SiteMapList.as_view(), name='sitemap-list-legacy'),
+        url(r'hpcapi/sitemaps/(?P<pk>[a-zA-Z0-9\-]+)/$', SiteMapDetail.as_view(), name ='sitemap-detail-legacy'),
+    
+    # new api - use these
+        url(r'^api/service/hpc/$', hpc_api_root),
+    
+        url(r'api/service/hpc/hpchealthchecks/$', HpcHealthCheckList.as_view(), name='hpchealthcheck-list'),
+        url(r'api/service/hpc/hpchealthchecks/(?P<pk>[a-zA-Z0-9\-]+)/$', HpcHealthCheckDetail.as_view(), name ='hpchealthcheck-detail'),
+    
+        url(r'api/service/hpc/hpcservices/$', HpcServiceList.as_view(), name='hpcservice-list'),
+        url(r'api/service/hpc/hpcservices/(?P<pk>[a-zA-Z0-9\-]+)/$', HpcServiceDetail.as_view(), name ='hpcservice-detail'),
+    
+        url(r'api/service/hpc/originservers/$', OriginServerList.as_view(), name='originserver-list'),
+        url(r'api/service/hpc/originservers/(?P<pk>[a-zA-Z0-9\-]+)/$', OriginServerDetail.as_view(), name ='originserver-detail'),
+    
+        url(r'api/service/hpc/cdnprefixs/$', CDNPrefixList.as_view(), name='cdnprefix-list'),
+        url(r'api/service/hpc/cdnprefixs/(?P<pk>[a-zA-Z0-9\-]+)/$', CDNPrefixDetail.as_view(), name ='cdnprefix-detail'),
+    
+        url(r'api/service/hpc/serviceproviders/$', ServiceProviderList.as_view(), name='serviceprovider-list'),
+        url(r'api/service/hpc/serviceproviders/(?P<pk>[a-zA-Z0-9\-]+)/$', ServiceProviderDetail.as_view(), name ='serviceprovider-detail'),
+    
+        url(r'api/service/hpc/contentproviders/$', ContentProviderList.as_view(), name='contentprovider-list'),
+        url(r'api/service/hpc/contentproviders/(?P<pk>[a-zA-Z0-9\-]+)/$', ContentProviderDetail.as_view(), name ='contentprovider-detail'),
+    
+        url(r'api/service/hpc/accessmaps/$', AccessMapList.as_view(), name='accessmap-list'),
+        url(r'api/service/hpc/accessmaps/(?P<pk>[a-zA-Z0-9\-]+)/$', AccessMapDetail.as_view(), name ='accessmap-detail'),
+    
+        url(r'api/service/hpc/sitemaps/$', SiteMapList.as_view(), name='sitemap-list'),
+        url(r'api/service/hpc/sitemaps/(?P<pk>[a-zA-Z0-9\-]+)/$', SiteMapDetail.as_view(), name ='sitemap-detail'),
+    
+    )
+
+@api_view(['GET'])
+def hpc_api_root_legacy(request, format=None):
+    return Response({
+        'hpchealthchecks': reverse('hpchealthcheck-list-legacy', request=request, format=format),
+        'hpcservices': reverse('hpcservice-list-legacy', request=request, format=format),
+        'originservers': reverse('originserver-list-legacy', request=request, format=format),
+        'cdnprefixs': reverse('cdnprefix-list-legacy', request=request, format=format),
+        'serviceproviders': reverse('serviceprovider-list-legacy', request=request, format=format),
+        'contentproviders': reverse('contentprovider-list-legacy', request=request, format=format),
+        'accessmaps': reverse('accessmap-list-legacy', request=request, format=format),
+        'sitemaps': reverse('sitemap-list-legacy', request=request, format=format),
+        
+    })
+
+@api_view(['GET'])
+def hpc_api_root(request, format=None):
+    return Response({
+        'hpchealthchecks': reverse('hpchealthcheck-list', request=request, format=format),
+        'hpcservices': reverse('hpcservice-list', request=request, format=format),
+        'originservers': reverse('originserver-list', request=request, format=format),
+        'cdnprefixs': reverse('cdnprefix-list', request=request, format=format),
+        'serviceproviders': reverse('serviceprovider-list', request=request, format=format),
+        'contentproviders': reverse('contentprovider-list', request=request, format=format),
+        'accessmaps': reverse('accessmap-list', request=request, format=format),
+        'sitemaps': reverse('sitemap-list', request=request, format=format),
+        
+    })
+
+# Based on serializers.py
+
+class XOSModelSerializer(serializers.ModelSerializer):
+    def save_object(self, obj, **kwargs):
+
+        """ rest_framework can't deal with ManyToMany relations that have a
+            through table. In xos, most of the through tables we have
+            use defaults or blank fields, so there's no reason why we shouldn't
+            be able to save these objects.
+
+            So, let's strip out these m2m relations, and deal with them ourself.
+        """
+        obj._complex_m2m_data={};
+        if getattr(obj, '_m2m_data', None):
+            for relatedObject in obj._meta.get_all_related_many_to_many_objects():
+                if (relatedObject.field.rel.through._meta.auto_created):
+                    # These are non-trough ManyToMany relations and
+                    # can be updated just fine
+                    continue
+                fieldName = relatedObject.get_accessor_name()
+                if fieldName in obj._m2m_data.keys():
+                    obj._complex_m2m_data[fieldName] = (relatedObject, obj._m2m_data[fieldName])
+                    del obj._m2m_data[fieldName]
+
+        serializers.ModelSerializer.save_object(self, obj, **kwargs);
+
+        for (accessor, stuff) in obj._complex_m2m_data.items():
+            (relatedObject, data) = stuff
+            through = relatedObject.field.rel.through
+            local_fieldName = relatedObject.field.m2m_reverse_field_name()
+            remote_fieldName = relatedObject.field.m2m_field_name()
+
+            # get the current set of existing relations
+            existing = through.objects.filter(**{local_fieldName: obj});
+
+            data_ids = [item.id for item in data]
+            existing_ids = [getattr(item,remote_fieldName).id for item in existing]
+
+            #print "data_ids", data_ids
+            #print "existing_ids", existing_ids
+
+            # remove relations that are in 'existing' but not in 'data'
+            for item in list(existing):
+               if (getattr(item,remote_fieldName).id not in data_ids):
+                   print "delete", getattr(item,remote_fieldName)
+                   item.delete() #(purge=True)
+
+            # add relations that are in 'data' but not in 'existing'
+            for item in data:
+               if (item.id not in existing_ids):
+                   #print "add", item
+                   newModel = through(**{local_fieldName: obj, remote_fieldName: item})
+                   newModel.save()
+
+
+
+class HpcHealthCheckSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = HpcHealthCheck
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','hpcService','kind','resource_name','result_contains','result_min_size','result_max_size',)
+
+class HpcHealthCheckIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = HpcHealthCheck
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','hpcService','kind','resource_name','result_contains','result_min_size','result_max_size',)
+
+
+
+
+class HpcServiceSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = HpcService
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','description','enabled','kind','name','versionNumber','published','view_url','icon_url','public_key','private_key_fn','service_specific_id','service_specific_attribute','cmi_hostname','hpc_port80','watcher_hpc_network','watcher_dnsdemux_network','watcher_dnsredir_network',)
+
+class HpcServiceIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = HpcService
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','description','enabled','kind','name','versionNumber','published','view_url','icon_url','public_key','private_key_fn','service_specific_id','service_specific_attribute','cmi_hostname','hpc_port80','watcher_hpc_network','watcher_dnsdemux_network','watcher_dnsredir_network',)
+
+
+
+
+class OriginServerSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = OriginServer
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','origin_server_id','url','contentProvider','authenticated','enabled','protocol','redirects','description',)
+
+class OriginServerIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = OriginServer
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','origin_server_id','url','contentProvider','authenticated','enabled','protocol','redirects','description',)
+
+
+
+
+class CDNPrefixSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = CDNPrefix
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','cdn_prefix_id','prefix','contentProvider','description','defaultOriginServer','enabled',)
+
+class CDNPrefixIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = CDNPrefix
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','cdn_prefix_id','prefix','contentProvider','description','defaultOriginServer','enabled',)
+
+
+
+
+class ServiceProviderSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = ServiceProvider
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','hpcService','service_provider_id','name','description','enabled',)
+
+class ServiceProviderIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = ServiceProvider
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','hpcService','service_provider_id','name','description','enabled',)
+
+
+
+
+class ContentProviderSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = ContentProvider
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','content_provider_id','name','enabled','description','serviceProvider',)
+
+class ContentProviderIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = ContentProvider
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','content_provider_id','name','enabled','description','serviceProvider',)
+
+
+
+
+class AccessMapSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = AccessMap
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','contentProvider','name','description','map',)
+
+class AccessMapIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = AccessMap
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','contentProvider','name','description','map',)
+
+
+
+
+class SiteMapSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = SiteMap
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','contentProvider','serviceProvider','cdnPrefix','hpcService','name','description','map','map_id',)
+
+class SiteMapIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = SiteMap
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','contentProvider','serviceProvider','cdnPrefix','hpcService','name','description','map','map_id',)
+
+
+
+
+serializerLookUp = {
+
+                 HpcHealthCheck: HpcHealthCheckSerializer,
+
+                 HpcService: HpcServiceSerializer,
+
+                 OriginServer: OriginServerSerializer,
+
+                 CDNPrefix: CDNPrefixSerializer,
+
+                 ServiceProvider: ServiceProviderSerializer,
+
+                 ContentProvider: ContentProviderSerializer,
+
+                 AccessMap: AccessMapSerializer,
+
+                 SiteMap: SiteMapSerializer,
+
+                 None: None,
+                }
+
+# Based on core/views/*.py
+
+
+class HpcHealthCheckList(XOSListCreateAPIView):
+    queryset = HpcHealthCheck.objects.select_related().all()
+    serializer_class = HpcHealthCheckSerializer
+    id_serializer_class = HpcHealthCheckIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','hpcService','kind','resource_name','result_contains','result_min_size','result_max_size',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return HpcHealthCheck.select_by_user(self.request.user)
+
+
+class HpcHealthCheckDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = HpcHealthCheck.objects.select_related().all()
+    serializer_class = HpcHealthCheckSerializer
+    id_serializer_class = HpcHealthCheckIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return HpcHealthCheck.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class HpcServiceList(XOSListCreateAPIView):
+    queryset = HpcService.objects.select_related().all()
+    serializer_class = HpcServiceSerializer
+    id_serializer_class = HpcServiceIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','description','enabled','kind','name','versionNumber','published','view_url','icon_url','public_key','private_key_fn','service_specific_id','service_specific_attribute','cmi_hostname','hpc_port80','watcher_hpc_network','watcher_dnsdemux_network','watcher_dnsredir_network',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return HpcService.select_by_user(self.request.user)
+
+
+class HpcServiceDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = HpcService.objects.select_related().all()
+    serializer_class = HpcServiceSerializer
+    id_serializer_class = HpcServiceIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return HpcService.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class OriginServerList(XOSListCreateAPIView):
+    queryset = OriginServer.objects.select_related().all()
+    serializer_class = OriginServerSerializer
+    id_serializer_class = OriginServerIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','origin_server_id','url','contentProvider','authenticated','enabled','protocol','redirects','description',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return OriginServer.select_by_user(self.request.user)
+
+
+class OriginServerDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = OriginServer.objects.select_related().all()
+    serializer_class = OriginServerSerializer
+    id_serializer_class = OriginServerIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return OriginServer.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class CDNPrefixList(XOSListCreateAPIView):
+    queryset = CDNPrefix.objects.select_related().all()
+    serializer_class = CDNPrefixSerializer
+    id_serializer_class = CDNPrefixIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','cdn_prefix_id','prefix','contentProvider','description','defaultOriginServer','enabled',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return CDNPrefix.select_by_user(self.request.user)
+
+
+class CDNPrefixDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = CDNPrefix.objects.select_related().all()
+    serializer_class = CDNPrefixSerializer
+    id_serializer_class = CDNPrefixIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return CDNPrefix.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class ServiceProviderList(XOSListCreateAPIView):
+    queryset = ServiceProvider.objects.select_related().all()
+    serializer_class = ServiceProviderSerializer
+    id_serializer_class = ServiceProviderIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','hpcService','service_provider_id','name','description','enabled',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return ServiceProvider.select_by_user(self.request.user)
+
+
+class ServiceProviderDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = ServiceProvider.objects.select_related().all()
+    serializer_class = ServiceProviderSerializer
+    id_serializer_class = ServiceProviderIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return ServiceProvider.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class ContentProviderList(XOSListCreateAPIView):
+    queryset = ContentProvider.objects.select_related().all()
+    serializer_class = ContentProviderSerializer
+    id_serializer_class = ContentProviderIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','content_provider_id','name','enabled','description','serviceProvider',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return ContentProvider.select_by_user(self.request.user)
+
+
+class ContentProviderDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = ContentProvider.objects.select_related().all()
+    serializer_class = ContentProviderSerializer
+    id_serializer_class = ContentProviderIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return ContentProvider.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class AccessMapList(XOSListCreateAPIView):
+    queryset = AccessMap.objects.select_related().all()
+    serializer_class = AccessMapSerializer
+    id_serializer_class = AccessMapIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','contentProvider','name','description','map',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return AccessMap.select_by_user(self.request.user)
+
+
+class AccessMapDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = AccessMap.objects.select_related().all()
+    serializer_class = AccessMapSerializer
+    id_serializer_class = AccessMapIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return AccessMap.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class SiteMapList(XOSListCreateAPIView):
+    queryset = SiteMap.objects.select_related().all()
+    serializer_class = SiteMapSerializer
+    id_serializer_class = SiteMapIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','contentProvider','serviceProvider','cdnPrefix','hpcService','name','description','map','map_id',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return SiteMap.select_by_user(self.request.user)
+
+
+class SiteMapDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = SiteMap.objects.select_related().all()
+    serializer_class = SiteMapSerializer
+    id_serializer_class = SiteMapIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return SiteMap.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
diff --git a/xos/xos/logger.py b/xos/xos/logger.py
new file mode 100644
index 0000000..7a358a5
--- /dev/null
+++ b/xos/xos/logger.py
@@ -0,0 +1,239 @@
+#!/usr/bin/env python
+
+#----------------------------------------------------------------------
+# Copyright (c) 2008 Board of Trustees, Princeton University
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and/or hardware specification (the "Work") to
+# deal in the Work without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Work, and to permit persons to whom the Work
+# is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Work.
+#
+# THE WORK IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 
+# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 
+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+# OUT OF OR IN CONNECTION WITH THE WORK OR THE USE OR OTHER DEALINGS 
+# IN THE WORK.
+#----------------------------------------------------------------------
+
+import os, sys
+import traceback
+import logging, logging.handlers
+import logstash
+from xos.config import Config
+
+CRITICAL=logging.CRITICAL
+ERROR=logging.ERROR
+WARNING=logging.WARNING
+INFO=logging.INFO
+DEBUG=logging.DEBUG
+
+# a logger that can handle tracebacks 
+class Logger:
+    def __init__ (self,logfile=None,loggername=None,level=logging.INFO):
+        # Logstash config
+        try:
+            logstash_host,logstash_port = Config().observer_logstash_hostport.split(':')
+            logstash_handler = logstash.LogstashHandler(logstash_host, int(logstash_port), version=1)
+        except:
+            logstash_handler = None
+
+        # default is to locate loggername from the logfile if avail.
+        if not logfile:
+            try:
+                logfile = Config().observer_log_file
+            except:
+                logfile = "/var/log/xos.log"
+
+        if (logfile == "console"):
+            loggername = "console"
+            handler = logging.StreamHandler()
+        else:
+            if not loggername:
+                loggername=os.path.basename(logfile)
+            try:
+                handler=logging.handlers.RotatingFileHandler(logfile,maxBytes=1000000, backupCount=5)
+            except IOError:
+                # This is usually a permissions error becaue the file is
+                # owned by root, but httpd is trying to access it.
+                tmplogfile=os.getenv("TMPDIR", "/tmp") + os.path.sep + os.path.basename(logfile)
+                # In strange uses, 2 users on same machine might use same code,
+                # meaning they would clobber each others files
+                # We could (a) rename the tmplogfile, or (b)
+                # just log to the console in that case.
+                # Here we default to the console.
+                if os.path.exists(tmplogfile) and not os.access(tmplogfile,os.W_OK):
+                    loggername = loggername + "-console"
+                    handler = logging.StreamHandler()
+                else:
+                    handler=logging.handlers.RotatingFileHandler(tmplogfile,maxBytes=1000000, backupCount=5)
+
+        handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s"))
+        self.logger=logging.getLogger(loggername)
+        self.logger.setLevel(level)
+        # check if logger already has the handler we're about to add
+        handler_exists = False
+        logstash_handler_exists = False
+
+        if not len(self.logger.handlers):
+            self.logger.addHandler(handler)
+
+            if (logstash_handler):
+                self.logger.addHandler(logstash_handler)
+
+        self.loggername=loggername
+
+    def setLevel(self,level):
+        self.logger.setLevel(level)
+
+    # shorthand to avoid having to import logging all over the place
+    def setLevelDebug(self):
+        self.logger.setLevel(logging.DEBUG)
+
+    def debugEnabled (self):
+        return self.logger.getEffectiveLevel() == logging.DEBUG
+
+    # define a verbose option with s/t like
+    # parser.add_option("-v", "--verbose", action="count", dest="verbose", default=0)
+    # and pass the coresponding options.verbose to this method to adjust level
+    def setLevelFromOptVerbose(self,verbose):
+        if verbose==0:
+            self.logger.setLevel(logging.WARNING)
+        elif verbose==1:
+            self.logger.setLevel(logging.INFO)
+        elif verbose>=2:
+            self.logger.setLevel(logging.DEBUG)
+    # in case some other code needs a boolean
+    def getBoolVerboseFromOpt(self,verbose):
+        return verbose>=1
+    def getBoolDebugFromOpt(self,verbose):
+        return verbose>=2
+
+    ####################
+
+    def extract_context(self,cur):
+        try:
+            observer_name=Config().observer_name
+            cur['synchronizer_name']=observer_name
+        except:
+            pass
+
+        return cur
+
+    def info(self, msg, extra={}):
+        extra = self.extract_context(extra) 
+        self.logger.info(msg, extra=extra)
+
+    def debug(self, msg, extra={}):
+        extra = self.extract_context(extra) 
+        self.logger.debug(msg, extra=extra)
+        
+    def warn(self, msg, extra={}):
+        extra = self.extract_context(extra) 
+        self.logger.warn(msg, extra=extra)
+
+    # some code is using logger.warn(), some is using logger.warning()
+    def warning(self, msg, extra={}):
+        extra = self.extract_context(extra) 
+        self.logger.warning(msg,extra=extra)
+   
+    def error(self, msg, extra={}):
+        extra = self.extract_context(extra) 
+        self.logger.error(msg, extra=extra)    
+ 
+    def critical(self, msg, extra={}):
+        extra = self.extract_context(extra) 
+        self.logger.critical(msg, extra=extra)
+
+    # logs an exception - use in an except statement
+    def log_exc(self,message, extra={}):
+        extra = self.extract_context(extra) 
+        self.error("%s BEG TRACEBACK"%message+"\n"+traceback.format_exc().strip("\n"), extra=extra)
+        self.error("%s END TRACEBACK"%message, extra=extra)
+    
+    def log_exc_critical(self,message, extra={}):
+        extra = self.extract_context(extra) 
+        self.critical("%s BEG TRACEBACK"%message+"\n"+traceback.format_exc().strip("\n"), extra=extra)
+        self.critical("%s END TRACEBACK"%message, extra=extra)
+    
+    # for investigation purposes, can be placed anywhere
+    def log_stack(self,message, extra={}):
+        extra = self.extract_context(extra) 
+        to_log="".join(traceback.format_stack())
+        self.info("%s BEG STACK"%message+"\n"+to_log,extra=extra)
+        self.info("%s END STACK"%message,extra=extra)
+
+    def enable_console(self, stream=sys.stdout):
+        formatter = logging.Formatter("%(message)s")
+        handler = logging.StreamHandler(stream)
+        handler.setFormatter(formatter)
+        self.logger.addHandler(handler)
+
+
+info_logger = Logger(loggername='info', level=logging.INFO)
+debug_logger = Logger(loggername='debug', level=logging.DEBUG)
+warn_logger = Logger(loggername='warning', level=logging.WARNING)
+error_logger = Logger(loggername='error', level=logging.ERROR)
+critical_logger = Logger(loggername='critical', level=logging.CRITICAL)
+logger = info_logger
+observer_logger = Logger(logfile='/var/log/observer.log', loggername='observer', level=logging.DEBUG)
+########################################
+import time
+
+def profile(logger):
+    """
+    Prints the runtime of the specified callable. Use as a decorator, e.g.,
+    
+    @profile(logger)
+    def foo(...):
+        ...
+    """
+    def logger_profile(callable):
+        def wrapper(*args, **kwds):
+            start = time.time()
+            result = callable(*args, **kwds)
+            end = time.time()
+            args = map(str, args)
+            args += ["%s = %s" % (name, str(value)) for (name, value) in kwds.iteritems()]
+            # should probably use debug, but then debug is not always enabled
+            logger.info("PROFILED %s (%s): %.02f s" % (callable.__name__, ", ".join(args), end - start))
+            return result
+        return wrapper
+    return logger_profile
+
+
+if __name__ == '__main__': 
+    print 'testing logging into logger.log'
+    logger1=Logger('logger.log', loggername='std(info)')
+    logger2=Logger('logger.log', loggername='error', level=logging.ERROR)
+    logger3=Logger('logger.log', loggername='debug', level=logging.DEBUG)
+    
+    for (logger,msg) in [ (logger1,"std(info)"),(logger2,"error"),(logger3,"debug")]:
+        
+        print "====================",msg, logger.logger.handlers
+   
+        logger.enable_console()
+        logger.critical("logger.critical")
+        logger.error("logger.error")
+        logger.warn("logger.warning")
+        logger.info("logger.info")
+        logger.debug("logger.debug")
+        logger.setLevel(logging.DEBUG)
+        logger.debug("logger.debug again")
+    
+        @profile(logger)
+        def sleep(seconds = 1):
+            time.sleep(seconds)
+
+        logger.info('console.info')
+        sleep(0.5)
+        logger.setLevel(logging.DEBUG)
+        sleep(0.25)
+
diff --git a/xos/xos/settings.py b/xos/xos/settings.py
new file mode 100644
index 0000000..f654b1d
--- /dev/null
+++ b/xos/xos/settings.py
@@ -0,0 +1,269 @@
+from django.conf.global_settings import TEMPLATE_CONTEXT_PROCESSORS as TCP
+from django import VERSION as DJANGO_VERSION
+import socket
+import os
+import warnings
+from urlparse import urlparse
+
+# Django settings for XOS.
+from config import Config
+from config import set_override
+config = Config()
+
+
+# Override the config from the environment. This is used leverage the LINK
+# capability of docker. It would be far better to use DNS and that can be
+# done in environments like kubernetes. Look for environment variables that
+# match the link pattern and set the appropriate overeides. It is expected
+# that the set of overrides will be expanded with need
+def overrideDbSettings(v):
+    parsed = urlparse(v)
+    config.db_host = parsed.hostname
+    config.db_port = parsed.port
+
+env_to_config_dict = {
+    "XOS_DB_PORT": overrideDbSettings
+}
+
+for key, ofunc in env_to_config_dict.items():
+    if key in os.environ:
+        ofunc(os.environ[key])
+
+GEOIP_PATH = "/usr/share/GeoIP"
+XOS_DIR = "/opt/xos"
+
+DEBUG = True
+TEMPLATE_DEBUG = DEBUG
+
+ADMINS = (
+    # ('Your Name', 'your_email@example.com'),
+)
+
+# LOGIN_REDIRECT_URL = '/admin/core/user'
+LOGIN_REDIRECT_URL = '/admin/loggedin/'
+
+MANAGERS = ADMINS
+
+DATABASES = {
+    'default': {
+        'ENGINE': 'django.db.backends.postgresql_psycopg2',  # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
+        'NAME': config.db_name,                      # Or path to database file if using sqlite3.
+        # The following settings are not used with sqlite3:
+        'USER': config.db_user,
+        'PASSWORD': config.db_password,
+        'HOST': config.db_host,                      # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP.
+        'PORT': config.db_port,                      # Set to empty string for default.
+    }
+}
+
+AUTH_USER_MODEL = 'core.User'
+
+
+# Hosts/domain names that are valid for this site; required if DEBUG is False
+# See https://docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts
+ALLOWED_HOSTS = ["*"]
+
+# Local time zone for this installation. Choices can be found here:
+# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
+# although not all choices may be available on all operating systems.
+# In a Windows environment this must be set to your system time zone.
+TIME_ZONE = 'America/New_York'
+
+# Verbose warnings when a naive datetime is used, gives a traceback
+# from: https://docs.djangoproject.com/en/1.9/topics/i18n/timezones/#code
+warnings.filterwarnings(
+        'error', r"DateTimeField .* received a naive datetime",
+        RuntimeWarning, r'django\.db\.models\.fields')
+
+# Language code for this installation. All choices can be found here:
+# http://www.i18nguy.com/unicode/language-identifiers.html
+LANGUAGE_CODE = 'en-us'
+
+SITE_ID = 1
+
+# If you set this to False, Django will make some optimizations so as not
+# to load the internationalization machinery.
+USE_I18N = True
+
+# If you set this to False, Django will not format dates, numbers and
+# calendars according to the current locale.
+USE_L10N = True
+
+# If you set this to False, Django will not use timezone-aware datetimes.
+USE_TZ = True
+
+# Absolute filesystem path to the directory that will hold user-uploaded files.
+# Example: "/var/www/example.com/media/"
+MEDIA_ROOT = '/var/www/html/files/'
+
+# URL that handles the media served from MEDIA_ROOT. Make sure to use a
+# trailing slash.
+# Examples: "http://example.com/media/", "http://media.example.com/"
+MEDIA_URL = '/files/'
+
+# Absolute path to the directory static files should be collected to.
+# Don't put anything in this directory yourself; store your static files
+# in apps' "static/" subdirectories and in STATICFILES_DIRS.
+# Example: "/var/www/example.com/static/"
+STATIC_ROOT = ''
+
+# URL prefix for static files.
+# Example: "http://example.com/static/", "http://static.example.com/"
+STATIC_URL = '/static/'
+
+# Additional locations of static files
+STATICFILES_DIRS = ( XOS_DIR + "/core/static/",
+                     XOS_DIR + "/core/xoslib/static/",
+)
+
+# List of finder classes that know how to find static files in
+# various locations.
+STATICFILES_FINDERS = (
+    'django.contrib.staticfiles.finders.FileSystemFinder',
+    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
+#    'django.contrib.staticfiles.finders.DefaultStorageFinder',
+)
+
+# Make this unique, and don't share it with anybody.
+SECRET_KEY = 'i0=a)c7_#2)5m%k_fu#%53xap$tlqc+#&z5as+bl7&)(@be_f9'
+
+# List of callables that know how to import templates from various sources.
+TEMPLATE_LOADERS = (
+    'django.template.loaders.filesystem.Loader',
+    'django.template.loaders.app_directories.Loader',
+#     'django.template.loaders.eggs.Loader',
+)
+
+MIDDLEWARE_CLASSES = (
+    'django.middleware.common.CommonMiddleware',
+    'django.contrib.sessions.middleware.SessionMiddleware',
+    'django.middleware.csrf.CsrfViewMiddleware',
+    'django.contrib.auth.middleware.AuthenticationMiddleware',
+    'django.contrib.messages.middleware.MessageMiddleware',
+    'core.middleware.GlobalRequestMiddleware',
+    # Uncomment the next line for simple clickjacking protection:
+    # 'django.middleware.clickjacking.XFrameOptionsMiddleware',
+)
+
+ROOT_URLCONF = 'xos.urls'
+
+# Python dotted path to the WSGI application used by Django's runserver.
+WSGI_APPLICATION = 'xos.wsgi.application'
+# Default: 'csrftoken'
+CSRF_COOKIE_NAME = 'xoscsrftoken'
+# Default: 'django_language'
+LANGUAGE_COOKIE_NAME = 'xos_django_language'
+# Default: 'sessionid'
+SESSION_COOKIE_NAME = 'xossessionid'
+
+TEMPLATE_DIRS = (
+    # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
+    # Always use forward slashes, even on Windows.
+    # Don't forget to use absolute paths, not relative paths.
+    XOS_DIR + "/templates",
+    XOS_DIR + "/core/xoslib/templates",
+)
+
+INSTALLED_APPS = (
+    'django.contrib.auth',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+    # 'django.contrib.sites',
+    'django.contrib.messages',
+    'django.contrib.staticfiles',
+    # Uncomment the next line to enable the admin:
+    # 'suit',
+    'xos.apps.MyDjangoSuitConfig',
+    'xos.admin_customize',
+    'django.contrib.admin',
+    # Uncomment the next line to enable admin documentation:
+    'django.contrib.admindocs',
+    'rest_framework',
+    'django_extensions',
+    'core',
+    'services.hpc',
+    'services.mcord',
+    'services.requestrouter',
+    'services.syndicate_storage',
+    'geoposition',
+    'rest_framework_swagger',
+)
+
+# add services that were configured by xosbuilder to INSTALLED_APPS
+if os.path.exists("/opt/xos/xos/xosbuilder_app_list"):
+    for line in file("/opt/xos/xos/xosbuilder_app_list").readlines():
+        line = line.strip()
+        if line:
+            INSTALLED_APPS = list(INSTALLED_APPS) + [line]
+
+if DJANGO_VERSION[1] >= 7:
+    # if django >= 1.7, then change the admin module
+    INSTALLED_APPS = list(INSTALLED_APPS)
+    INSTALLED_APPS[INSTALLED_APPS.index('django.contrib.admin')] = 'django.contrib.admin.apps.SimpleAdminConfig'
+
+# Added for django-suit form
+TEMPLATE_CONTEXT_PROCESSORS = TCP + (
+    'django.core.context_processors.request',
+    'core.context_processors.xos',
+)
+
+# A sample logging configuration. The only tangible logging
+# performed by this configuration is to send an email to
+# the site admins on every HTTP 500 error when DEBUG=False.
+# See http://docs.djangoproject.com/en/dev/topics/logging for
+# more details on how to customize your logging configuration.
+LOGGING = {
+    'version': 1,
+    'disable_existing_loggers': False,
+    'filters': {
+        'require_debug_false': {
+            '()': 'django.utils.log.RequireDebugFalse'
+        }
+    },
+    'handlers': {
+        'file': {
+            'level': 'DEBUG',
+            'class': 'logging.FileHandler',
+            'filename': '/var/log/django_debug.log',
+        },
+        'mail_admins': {
+            'level': 'ERROR',
+            'filters': ['require_debug_false'],
+            'class': 'django.utils.log.AdminEmailHandler'
+        },
+    },
+    'loggers': {
+        'django': {
+            'handlers': ['file'],
+            'level': 'DEBUG',
+            'propagate': True,
+        },
+        'django.request': {
+            'handlers': ['mail_admins'],
+            'level': 'ERROR',
+            'propagate': True,
+        },'django.db.backends': {
+            'level': 'WARNING',
+        },
+    }
+}
+
+RESTAPI_HOSTNAME = getattr(config, "server_restapi_hostname", getattr(config, "server_hostname", socket.gethostname()))
+RESTAPI_PORT = int(getattr(config, "server_restapi_port", getattr(config, "server_port", "8000")))
+
+BIGQUERY_TABLE = getattr(config, "bigquery_table", "demoevents")
+
+XOS_BRANDING_NAME = getattr(config, "gui_branding_name", "OpenCloud")
+XOS_BRANDING_CSS = getattr(config, "gui_branding_css", None)
+XOS_BRANDING_ICON = getattr(config, "gui_branding_icon", "/static/logo.png")
+XOS_BRANDING_FAVICON = getattr(config, "gui_branding_favicon", "/static/favicon.png")
+XOS_BRANDING_BG = getattr(config, "gui_branding_bg", "/static/bg.png")
+
+DISABLE_MINIDASHBOARD = getattr(config, "gui_disable_minidashboard", False)
+ENCRYPTED_FIELDS_KEYDIR = XOS_DIR + '/private_keys'
+ENCRYPTED_FIELD_MODE = 'ENCRYPT'
+
+STATISTICS_DRIVER = getattr(config, "statistics_driver", "ceilometer")
+
+# prevents warnings on django 1.7
+TEST_RUNNER = 'django.test.runner.DiscoverRunner'
diff --git a/xos/xos/tests.py b/xos/xos/tests.py
new file mode 100644
index 0000000..501deb7
--- /dev/null
+++ b/xos/xos/tests.py
@@ -0,0 +1,16 @@
+"""
+This file demonstrates writing tests using the unittest module. These will pass
+when you run "manage.py test".
+
+Replace this with more appropriate tests for your application.
+"""
+
+from django.test import TestCase
+
+
+class SimpleTest(TestCase):
+    def test_basic_addition(self):
+        """
+        Tests that 1 + 1 always equals 2.
+        """
+        self.assertEqual(1 + 1, 2)
diff --git a/xos/xos/urls.py b/xos/xos/urls.py
new file mode 100644
index 0000000..b9f2bf1
--- /dev/null
+++ b/xos/xos/urls.py
@@ -0,0 +1,99 @@
+import importlib
+from django.conf.urls import patterns, include, url
+
+# Uncomment the next two lines to enable the admin:
+from django.contrib import admin
+
+# This is the generated API
+from xosapi import *
+from hpcapi import *
+
+from core.views.legacyapi import LegacyXMLRPC
+from core.views.serviceGraph import ServiceGridView, ServiceGraphView
+from services.mcord.view import *
+# from core.views.analytics import AnalyticsAjaxView
+
+from core.models import *
+from rest_framework import generics
+from core.dashboard.sites import SitePlus
+from django.http import HttpResponseRedirect
+
+# from core.xoslib import XOSLibDataView
+
+# Django settings for XOS.
+from config import Config
+from config import set_override
+config = Config()
+
+
+def load_class(full_class_string):
+    """
+    dynamically load a class from a string
+    """
+
+    class_data = full_class_string.split(".")
+    module_path = ".".join(class_data[:-1])
+    class_str = class_data[-1]
+
+    module = importlib.import_module(module_path)
+    # Finally, we retrieve the Class
+    return getattr(module, class_str)
+
+servicePage = getattr(config, "gui_service_view_class", ServiceGridView)
+
+if(isinstance(servicePage, basestring)):
+    serviceClass = getattr(load_class(servicePage), "as_view")
+else:
+    serviceClass = getattr(servicePage, "as_view")
+
+# from api import import_api_methods
+
+admin.site = SitePlus()
+admin.autodiscover()
+
+
+def redirect_to_apache(request):
+    """ bounce a request back to the apache server that is running on the machine """
+    apache_url = "http://%s%s" % (request.META['HOSTNAME'], request.path)
+    return HttpResponseRedirect(apache_url)
+
+urlpatterns = patterns(
+    '',
+    url(r'^observer', 'core.views.observer.Observer', name='observer'),
+
+    url(r'^mcord', MCordView.as_view(), name='mcord'),
+
+    url(r'^serviceGrid', serviceClass(), name='serviceGrid'),
+
+    url(r'^serviceGrid', ServiceGridView.as_view(), name='serviceGrid'),
+
+    url(r'^serviceGraph.png', ServiceGraphView.as_view(), name='serviceGraph'),
+    url(r'^hpcConfig', 'core.views.hpc_config.HpcConfig', name='hpcConfig'),
+
+    url(r'^docs/', include('rest_framework_swagger.urls')),
+
+    # Uncomment the admin/doc line below to enable admin documentation:
+    url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
+
+    # Uncomment the next line to enable the admin:
+    url(r'^admin/', include(admin.site.urls)),
+    url(r'^', include(admin.site.urls)),
+    # url(r'^profile/home', 'core.views.home'),
+
+    # url(r'^admin/xoslib/(?P<name>\w+)/$', XOSLibDataView.as_view(), name="xoslib"),
+
+    url(r'^xmlrpc/legacyapi/$', 'core.views.legacyapi.LegacyXMLRPC', name='xmlrpc'),
+
+    # url(r'^analytics/(?P<name>\w+)/$', AnalyticsAjaxView.as_view(), name="analytics"),
+
+    url(r'^files/', redirect_to_apache),
+
+    # Adding in rest_framework urls
+    url(r'^xos/', include('rest_framework.urls', namespace='rest_framework')),
+
+    # XOSLib rest methods [deprecated]
+    url(r'^xoslib/', include('core.xoslib.methods', namespace='xoslib')),
+
+    url(r'^', include('api.import_methods', namespace='api')),
+
+  ) + get_REST_patterns() + get_hpc_REST_patterns()
diff --git a/xos/xos/wsgi.py b/xos/xos/wsgi.py
new file mode 100644
index 0000000..55c6c1a
--- /dev/null
+++ b/xos/xos/wsgi.py
@@ -0,0 +1,30 @@
+"""
+WSGI config for XOS.
+
+This module contains the WSGI application used by Django's development server
+and any production WSGI deployments. It should expose a module-level variable
+named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover
+this application via the ``WSGI_APPLICATION`` setting.
+
+Usually you will have the standard Django WSGI application here, but it also
+might make sense to replace the whole Django WSGI application with a custom one
+that later delegates to the Django one. For example, you could introduce WSGI
+middleware here, or combine a Django application with an application of another
+framework.
+
+"""
+import os
+
+# We defer to a DJANGO_SETTINGS_MODULE already in the environment. This breaks
+# if running multiple sites in the same mod_wsgi process. To fix this, use
+# mod_wsgi daemon mode with each site in its own daemon process, or use
+# os.environ["DJANGO_SETTINGS_MODULE"] = "xos.settings"
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
+
+# This application object is used by any WSGI server configured to use this
+# file. This includes Django's development server, if the WSGI_APPLICATION
+# setting points here.
+from django.core.wsgi import get_wsgi_application
+application = get_wsgi_application()
+
+# Apply WSGI middleware here.
diff --git a/xos/xos/xml_util.py b/xos/xos/xml_util.py
new file mode 100644
index 0000000..77b968f
--- /dev/null
+++ b/xos/xos/xml_util.py
@@ -0,0 +1,347 @@
+#!/usr/bin/env python
+from types import StringTypes
+from lxml import etree
+from StringIO import StringIO
+
+# helper functions to help build xpaths
+class XpathFilter:
+    @staticmethod
+
+    def filter_value(key, value):
+        xpath = ""
+        if isinstance(value, str):
+            if '*' in value:
+                value = value.replace('*', '')
+                xpath = 'contains(%s, "%s")' % (key, value)
+            else:
+                xpath = '%s="%s"' % (key, value)
+        return xpath
+
+    @staticmethod
+    def xpath(filter={}):
+        xpath = ""
+        if filter:
+            filter_list = []
+            for (key, value) in filter.items():
+                if key == 'text':
+                    key = 'text()'
+                else:
+                    key = '@'+key
+                if isinstance(value, str):
+                    filter_list.append(XpathFilter.filter_value(key, value))
+                elif isinstance(value, list):
+                    stmt = ' or '.join([XpathFilter.filter_value(key, str(val)) for val in value])
+                    filter_list.append(stmt)
+            if filter_list:
+                xpath = ' and '.join(filter_list)
+                xpath = '[' + xpath + ']'
+        return xpath
+
+# a wrapper class around lxml.etree._Element
+# the reason why we need this one is because of the limitations
+# we've found in xpath to address documents with multiple namespaces defined
+# in a nutshell, we deal with xml documents that have
+# a default namespace defined (xmlns="http://default.com/") and specific prefixes defined
+# (xmlns:foo="http://foo.com")
+# according to the documentation instead of writing
+# element.xpath ( "//node/foo:subnode" )
+# we'd then need to write xpaths like
+# element.xpath ( "//{http://default.com/}node/{http://foo.com}subnode" )
+# which is a real pain..
+# So just so we can keep some reasonable programming style we need to manage the
+# namespace map that goes with the _Element (its internal .nsmap being unmutable)
+class XmlElement:
+    def __init__(self, element, namespaces):
+        self.element = element
+        self.namespaces = namespaces
+
+    # redefine as few methods as possible
+    def xpath(self, xpath, namespaces=None):
+        if not namespaces:
+            namespaces = self.namespaces
+        elems = self.element.xpath(xpath, namespaces=namespaces)
+        return [XmlElement(elem, namespaces) for elem in elems]
+
+    def add_element(self, tagname, **kwds):
+        element = etree.SubElement(self.element, tagname, **kwds)
+        return XmlElement(element, self.namespaces)
+
+    def append(self, elem):
+        if isinstance(elem, XmlElement):
+            self.element.append(elem.element)
+        else:
+            self.element.append(elem)
+
+    def getparent(self):
+        return XmlElement(self.element.getparent(), self.namespaces)
+
+    def get_instance(self, instance_class=None, fields=[]):
+        """
+        Returns an instance (dict) of this xml element. The instance
+        holds a reference to this xml element.
+        """
+        if not instance_class:
+            instance_class = Object
+        if not fields and hasattr(instance_class, 'fields'):
+            fields = instance_class.fields
+
+        if not fields:
+            instance = instance_class(self.attrib, self)
+        else:
+            instance = instance_class({}, self)
+            for field in fields:
+                if field in self.attrib:
+                   instance[field] = self.attrib[field]
+        return instance
+
+    def add_instance(self, name, instance, fields=[]):
+        """
+        Adds the specifed instance(s) as a child element of this xml
+        element.
+        """
+        if not fields and hasattr(instance, 'keys'):
+            fields = instance.keys()
+        elem = self.add_element(name)
+        for field in fields:
+            if field in instance and instance[field]:
+                elem.set(field, unicode(instance[field]))
+        return elem
+
+    def remove_elements(self, name):
+        """
+        Removes all occurences of an element from the tree. Start at
+        specified root_node if specified, otherwise start at tree's root.
+        """
+
+        if not name.startswith('//'):
+            name = '//' + name 
+        elements = self.element.xpath('%s ' % name, namespaces=self.namespaces)
+        for element in elements:
+            parent = element.getparent()
+            parent.remove(element)
+
+    def delete(self):
+        parent = self.getparent()
+        parent.remove(self)
+
+    def remove(self, element):
+        if isinstance(element, XmlElement):
+            self.element.remove(element.element)
+        else:
+            self.element.remove(element)
+
+    def set_text(self, text):
+        self.element.text = text
+
+    # Element does not have unset ?!?
+    def unset(self, key):
+        del self.element.attrib[key]
+
+    def toxml(self):
+        return etree.tostring(self.element, encoding='UTF-8', pretty_print=True)
+
+    def __str__(self):
+        return self.toxml()
+
+    # are redirected on self.element
+    def __getattr__ (self, name):
+        if not hasattr(self.element, name):
+            raise AttributeError, name
+        return getattr(self.element, name)
+
+class Xml:
+
+    def __init__(self, xml=None, namespaces=None):
+        self.root = None
+        self.namespaces = namespaces
+        self.default_namespace = None
+        self.schema = None
+        if isinstance(xml, basestring):
+            self.parse_xml(xml)
+        if isinstance(xml, XmlElement):
+            self.root = xml
+            self.namespaces = xml.namespaces
+        elif isinstance(xml, etree._ElementTree) or isinstance(xml, etree._Element):
+            self.parse_xml(etree.tostring(xml))
+
+    def parse_xml(self, xml):
+        """
+        parse rspec into etree
+        """
+        parser = etree.XMLParser(remove_blank_text=True)
+        try:
+            tree = etree.parse(xml, parser)
+        except IOError:
+            # 'rspec' file doesnt exist. 'rspec' is proably an xml string
+            try:
+                tree = etree.parse(StringIO(xml), parser)
+            except Exception, e:
+                raise Exception, str(e)
+        root = tree.getroot()
+        self.namespaces = dict(root.nsmap)
+        # set namespaces map
+        if 'default' not in self.namespaces and None in self.namespaces:
+            # If the 'None' exist, then it's pointing to the default namespace. This makes
+            # it hard for us to write xpath queries for the default naemspace because lxml
+            # wont understand a None prefix. We will just associate the default namespeace
+            # with a key named 'default'.
+            self.namespaces['default'] = self.namespaces.pop(None)
+
+        else:
+            self.namespaces['default'] = 'default'
+
+        self.root = XmlElement(root, self.namespaces)
+        # set schema
+        for key in self.root.attrib.keys():
+            if key.endswith('schemaLocation'):
+                # schemaLocation should be at the end of the list.
+                # Use list comprehension to filter out empty strings
+                schema_parts  = [x for x in self.root.attrib[key].split(' ') if x]
+                self.schema = schema_parts[1]
+                namespace, schema  = schema_parts[0], schema_parts[1]
+                break
+
+    def parse_dict(self, d, root_tag_name='xml', element = None):
+        if element is None:
+            if self.root is None:
+                self.parse_xml('<%s/>' % root_tag_name)
+            element = self.root.element
+
+        if 'text' in d:
+            text = d.pop('text')
+            element.text = text
+
+        # handle repeating fields
+        for (key, value) in d.items():
+            if isinstance(value, list):
+                value = d.pop(key)
+                for val in value:
+                    if isinstance(val, dict):
+                        child_element = etree.SubElement(element, key)
+                        self.parse_dict(val, key, child_element)
+                    elif isinstance(val, basestring):
+                        child_element = etree.SubElement(element, key).text = val
+
+            elif isinstance(value, int):
+                d[key] = unicode(d[key])
+            elif value is None:
+                d.pop(key)
+
+        # element.attrib.update will explode if DateTimes are in the
+        # dcitionary.
+        d=d.copy()
+        # looks like iteritems won't stand side-effects
+        for k in d.keys():
+            if not isinstance(d[k],StringTypes):
+                del d[k]
+
+        element.attrib.update(d)
+
+    def validate(self, schema):
+        """
+        Validate against rng schema
+        """
+        relaxng_doc = etree.parse(schema)
+        relaxng = etree.RelaxNG(relaxng_doc)
+        if not relaxng(self.root):
+            error = relaxng.error_log.last_error
+            message = "%s (line %s)" % (error.message, error.line)
+            raise Exception, message
+        return True
+
+    def xpath(self, xpath, namespaces=None):
+        if not namespaces:
+            namespaces = self.namespaces
+        return self.root.xpath(xpath, namespaces=namespaces)
+
+    def set(self, key, value):
+        return self.root.set(key, value)
+
+    def remove_attribute(self, name, element=None):
+        if not element:
+            element = self.root
+        element.remove_attribute(name)
+
+    def add_element(self, *args, **kwds):
+        """
+        Wrapper around etree.SubElement(). Adds an element to
+        specified parent node. Adds element to root node is parent is
+        not specified.
+        """
+        return self.root.add_element(*args, **kwds)
+
+    def remove_elements(self, name, element = None):
+        """
+        Removes all occurences of an element from the tree. Start at
+        specified root_node if specified, otherwise start at tree's root.
+        """
+        if not element:
+            element = self.root
+
+        element.remove_elements(name)
+
+    def add_instance(self, *args, **kwds):
+        return self.root.add_instance(*args, **kwds)
+
+    def get_instance(self, *args, **kwds):
+        return self.root.get_instnace(*args, **kwds)
+
+    def get_element_attributes(self, elem=None, depth=0):
+        if elem == None:
+            elem = self.root
+        if not hasattr(elem, 'attrib'):
+            # this is probably not an element node with attribute. could be just and an
+            # attribute, return it
+            return elem
+        attrs = dict(elem.attrib)
+        attrs['text'] = str(elem.text).strip()
+        attrs['parent'] = elem.getparent()
+        if isinstance(depth, int) and depth > 0:
+            for child_elem in list(elem):
+                key = str(child_elem.tag)
+                if key not in attrs:
+                    attrs[key] = [self.get_element_attributes(child_elem, depth-1)]
+                else:
+                    attrs[key].append(self.get_element_attributes(child_elem, depth-1))
+        else:
+            attrs['child_nodes'] = list(elem)
+        return attrs
+
+    def append(self, elem):
+        return self.root.append(elem)
+
+    def iterchildren(self):
+        return self.root.iterchildren()
+
+    def merge(self, in_xml):
+        pass
+
+    def __str__(self):
+        return self.toxml()
+
+    def toxml(self):
+        return etree.tostring(self.root.element, encoding='UTF-8', pretty_print=True)
+
+    # XXX smbaker, for record.load_from_string
+    def todict(self, elem=None):
+        if elem is None:
+            elem = self.root
+        d = {}
+        d.update(elem.attrib)
+        d['text'] = elem.text
+        for child in elem.iterchildren():
+            if child.tag not in d:
+                d[child.tag] = []
+            d[child.tag].append(self.todict(child))
+
+        if len(d)==1 and ("text" in d):
+            d = d["text"]
+
+        return d
+
+    def save(self, filename):
+        f = open(filename, 'w')
+        f.write(self.toxml())
+        f.close()
+
+    
diff --git a/xos/xos/xosapi.py b/xos/xos/xosapi.py
new file mode 100644
index 0000000..53de766
--- /dev/null
+++ b/xos/xos/xosapi.py
@@ -0,0 +1,6739 @@
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+from rest_framework import serializers
+from rest_framework import generics
+from rest_framework import status
+from rest_framework.generics import GenericAPIView
+from core.models import *
+from django.forms import widgets
+from rest_framework import filters
+from django.conf.urls import patterns, url
+from rest_framework.exceptions import PermissionDenied as RestFrameworkPermissionDenied
+from django.core.exceptions import PermissionDenied as DjangoPermissionDenied
+from apibase import XOSRetrieveUpdateDestroyAPIView, XOSListCreateAPIView, XOSNotAuthenticated
+
+if hasattr(serializers, "ReadOnlyField"):
+    # rest_framework 3.x
+    IdField = serializers.ReadOnlyField
+else:
+    # rest_framework 2.x
+    IdField = serializers.Field
+
+"""
+    Schema of the generator object:
+        all: Set of all Model objects
+        all_if(regex): Set of Model objects that match regex
+
+    Model object:
+        plural: English plural of object name
+        camel: CamelCase version of object name
+        refs: list of references to other Model objects
+        props: list of properties minus refs
+
+    TODO: Deal with subnets
+"""
+
+def get_REST_patterns():
+    return patterns('',
+    # legacy - deprecated
+        url(r'^xos/$', api_root),
+    
+        url(r'xos/serviceattributes/$', ServiceAttributeList.as_view(), name='serviceattribute-list-legacy'),
+        url(r'xos/serviceattributes/(?P<pk>[a-zA-Z0-9\-]+)/$', ServiceAttributeDetail.as_view(), name ='serviceattribute-detail-legacy'),
+    
+        url(r'xos/controllerimages/$', ControllerImagesList.as_view(), name='controllerimages-list-legacy'),
+        url(r'xos/controllerimages/(?P<pk>[a-zA-Z0-9\-]+)/$', ControllerImagesDetail.as_view(), name ='controllerimages-detail-legacy'),
+    
+        url(r'xos/controllersiteprivileges/$', ControllerSitePrivilegeList.as_view(), name='controllersiteprivilege-list-legacy'),
+        url(r'xos/controllersiteprivileges/(?P<pk>[a-zA-Z0-9\-]+)/$', ControllerSitePrivilegeDetail.as_view(), name ='controllersiteprivilege-detail-legacy'),
+    
+        url(r'xos/images/$', ImageList.as_view(), name='image-list-legacy'),
+        url(r'xos/images/(?P<pk>[a-zA-Z0-9\-]+)/$', ImageDetail.as_view(), name ='image-detail-legacy'),
+    
+        url(r'xos/controllernetworks/$', ControllerNetworkList.as_view(), name='controllernetwork-list-legacy'),
+        url(r'xos/controllernetworks/(?P<pk>[a-zA-Z0-9\-]+)/$', ControllerNetworkDetail.as_view(), name ='controllernetwork-detail-legacy'),
+    
+        url(r'xos/sites/$', SiteList.as_view(), name='site-list-legacy'),
+        url(r'xos/sites/(?P<pk>[a-zA-Z0-9\-]+)/$', SiteDetail.as_view(), name ='site-detail-legacy'),
+    
+        url(r'xos/tenantrootroles/$', TenantRootRoleList.as_view(), name='tenantrootrole-list-legacy'),
+        url(r'xos/tenantrootroles/(?P<pk>[a-zA-Z0-9\-]+)/$', TenantRootRoleDetail.as_view(), name ='tenantrootrole-detail-legacy'),
+    
+        url(r'xos/slice_roles/$', SliceRoleList.as_view(), name='slicerole-list-legacy'),
+        url(r'xos/slice_roles/(?P<pk>[a-zA-Z0-9\-]+)/$', SliceRoleDetail.as_view(), name ='slicerole-detail-legacy'),
+    
+        url(r'xos/sitedeployments/$', SiteDeploymentList.as_view(), name='sitedeployment-list-legacy'),
+        url(r'xos/sitedeployments/(?P<pk>[a-zA-Z0-9\-]+)/$', SiteDeploymentDetail.as_view(), name ='sitedeployment-detail-legacy'),
+    
+        url(r'xos/tenantprivileges/$', TenantPrivilegeList.as_view(), name='tenantprivilege-list-legacy'),
+        url(r'xos/tenantprivileges/(?P<pk>[a-zA-Z0-9\-]+)/$', TenantPrivilegeDetail.as_view(), name ='tenantprivilege-detail-legacy'),
+    
+        url(r'xos/tags/$', TagList.as_view(), name='tag-list-legacy'),
+        url(r'xos/tags/(?P<pk>[a-zA-Z0-9\-]+)/$', TagDetail.as_view(), name ='tag-detail-legacy'),
+    
+        url(r'xos/usercredentials/$', UserCredentialList.as_view(), name='usercredential-list-legacy'),
+        url(r'xos/usercredentials/(?P<pk>[a-zA-Z0-9\-]+)/$', UserCredentialDetail.as_view(), name ='usercredential-detail-legacy'),
+    
+        url(r'xos/invoices/$', InvoiceList.as_view(), name='invoice-list-legacy'),
+        url(r'xos/invoices/(?P<pk>[a-zA-Z0-9\-]+)/$', InvoiceDetail.as_view(), name ='invoice-detail-legacy'),
+    
+        url(r'xos/slice_privileges/$', SlicePrivilegeList.as_view(), name='sliceprivilege-list-legacy'),
+        url(r'xos/slice_privileges/(?P<pk>[a-zA-Z0-9\-]+)/$', SlicePrivilegeDetail.as_view(), name ='sliceprivilege-detail-legacy'),
+    
+        url(r'xos/flavors/$', FlavorList.as_view(), name='flavor-list-legacy'),
+        url(r'xos/flavors/(?P<pk>[a-zA-Z0-9\-]+)/$', FlavorDetail.as_view(), name ='flavor-detail-legacy'),
+    
+        url(r'xos/ports/$', PortList.as_view(), name='port-list-legacy'),
+        url(r'xos/ports/(?P<pk>[a-zA-Z0-9\-]+)/$', PortDetail.as_view(), name ='port-detail-legacy'),
+    
+        url(r'xos/serviceroles/$', ServiceRoleList.as_view(), name='servicerole-list-legacy'),
+        url(r'xos/serviceroles/(?P<pk>[a-zA-Z0-9\-]+)/$', ServiceRoleDetail.as_view(), name ='servicerole-detail-legacy'),
+    
+        url(r'xos/controllersites/$', ControllerSiteList.as_view(), name='controllersite-list-legacy'),
+        url(r'xos/controllersites/(?P<pk>[a-zA-Z0-9\-]+)/$', ControllerSiteDetail.as_view(), name ='controllersite-detail-legacy'),
+    
+        url(r'xos/controllerslices/$', ControllerSliceList.as_view(), name='controllerslice-list-legacy'),
+        url(r'xos/controllerslices/(?P<pk>[a-zA-Z0-9\-]+)/$', ControllerSliceDetail.as_view(), name ='controllerslice-detail-legacy'),
+    
+        url(r'xos/tenantroles/$', TenantRoleList.as_view(), name='tenantrole-list-legacy'),
+        url(r'xos/tenantroles/(?P<pk>[a-zA-Z0-9\-]+)/$', TenantRoleDetail.as_view(), name ='tenantrole-detail-legacy'),
+    
+        url(r'xos/slices/$', SliceList.as_view(), name='slice-list-legacy'),
+        url(r'xos/slices/(?P<pk>[a-zA-Z0-9\-]+)/$', SliceDetail.as_view(), name ='slice-detail-legacy'),
+    
+        url(r'xos/networks/$', NetworkList.as_view(), name='network-list-legacy'),
+        url(r'xos/networks/(?P<pk>[a-zA-Z0-9\-]+)/$', NetworkDetail.as_view(), name ='network-detail-legacy'),
+    
+        url(r'xos/controllerroles/$', ControllerRoleList.as_view(), name='controllerrole-list-legacy'),
+        url(r'xos/controllerroles/(?P<pk>[a-zA-Z0-9\-]+)/$', ControllerRoleDetail.as_view(), name ='controllerrole-detail-legacy'),
+    
+        url(r'xos/diags/$', DiagList.as_view(), name='diag-list-legacy'),
+        url(r'xos/diags/(?P<pk>[a-zA-Z0-9\-]+)/$', DiagDetail.as_view(), name ='diag-detail-legacy'),
+    
+        url(r'xos/serviceclasses/$', ServiceClassList.as_view(), name='serviceclass-list-legacy'),
+        url(r'xos/serviceclasses/(?P<pk>[a-zA-Z0-9\-]+)/$', ServiceClassDetail.as_view(), name ='serviceclass-detail-legacy'),
+    
+        url(r'xos/tenantattributes/$', TenantAttributeList.as_view(), name='tenantattribute-list-legacy'),
+        url(r'xos/tenantattributes/(?P<pk>[a-zA-Z0-9\-]+)/$', TenantAttributeDetail.as_view(), name ='tenantattribute-detail-legacy'),
+    
+        url(r'xos/site_roles/$', SiteRoleList.as_view(), name='siterole-list-legacy'),
+        url(r'xos/site_roles/(?P<pk>[a-zA-Z0-9\-]+)/$', SiteRoleDetail.as_view(), name ='siterole-detail-legacy'),
+    
+        url(r'xos/subscribers/$', SubscriberList.as_view(), name='subscriber-list-legacy'),
+        url(r'xos/subscribers/(?P<pk>[a-zA-Z0-9\-]+)/$', SubscriberDetail.as_view(), name ='subscriber-detail-legacy'),
+    
+        url(r'xos/instances/$', InstanceList.as_view(), name='instance-list-legacy'),
+        url(r'xos/instances/(?P<pk>[a-zA-Z0-9\-]+)/$', InstanceDetail.as_view(), name ='instance-detail-legacy'),
+    
+        url(r'xos/charges/$', ChargeList.as_view(), name='charge-list-legacy'),
+        url(r'xos/charges/(?P<pk>[a-zA-Z0-9\-]+)/$', ChargeDetail.as_view(), name ='charge-detail-legacy'),
+    
+        url(r'xos/programs/$', ProgramList.as_view(), name='program-list-legacy'),
+        url(r'xos/programs/(?P<pk>[a-zA-Z0-9\-]+)/$', ProgramDetail.as_view(), name ='program-detail-legacy'),
+    
+        url(r'xos/roles/$', RoleList.as_view(), name='role-list-legacy'),
+        url(r'xos/roles/(?P<pk>[a-zA-Z0-9\-]+)/$', RoleDetail.as_view(), name ='role-detail-legacy'),
+    
+        url(r'xos/usableobjects/$', UsableObjectList.as_view(), name='usableobject-list-legacy'),
+        url(r'xos/usableobjects/(?P<pk>[a-zA-Z0-9\-]+)/$', UsableObjectDetail.as_view(), name ='usableobject-detail-legacy'),
+    
+        url(r'xos/nodelabels/$', NodeLabelList.as_view(), name='nodelabel-list-legacy'),
+        url(r'xos/nodelabels/(?P<pk>[a-zA-Z0-9\-]+)/$', NodeLabelDetail.as_view(), name ='nodelabel-detail-legacy'),
+    
+        url(r'xos/slicecredentials/$', SliceCredentialList.as_view(), name='slicecredential-list-legacy'),
+        url(r'xos/slicecredentials/(?P<pk>[a-zA-Z0-9\-]+)/$', SliceCredentialDetail.as_view(), name ='slicecredential-detail-legacy'),
+    
+        url(r'xos/nodes/$', NodeList.as_view(), name='node-list-legacy'),
+        url(r'xos/nodes/(?P<pk>[a-zA-Z0-9\-]+)/$', NodeDetail.as_view(), name ='node-detail-legacy'),
+    
+        url(r'xos/addresspools/$', AddressPoolList.as_view(), name='addresspool-list-legacy'),
+        url(r'xos/addresspools/(?P<pk>[a-zA-Z0-9\-]+)/$', AddressPoolDetail.as_view(), name ='addresspool-detail-legacy'),
+    
+        url(r'xos/dashboardviews/$', DashboardViewList.as_view(), name='dashboardview-list-legacy'),
+        url(r'xos/dashboardviews/(?P<pk>[a-zA-Z0-9\-]+)/$', DashboardViewDetail.as_view(), name ='dashboardview-detail-legacy'),
+    
+        url(r'xos/networkparameters/$', NetworkParameterList.as_view(), name='networkparameter-list-legacy'),
+        url(r'xos/networkparameters/(?P<pk>[a-zA-Z0-9\-]+)/$', NetworkParameterDetail.as_view(), name ='networkparameter-detail-legacy'),
+    
+        url(r'xos/imagedeploymentses/$', ImageDeploymentsList.as_view(), name='imagedeployments-list-legacy'),
+        url(r'xos/imagedeploymentses/(?P<pk>[a-zA-Z0-9\-]+)/$', ImageDeploymentsDetail.as_view(), name ='imagedeployments-detail-legacy'),
+    
+        url(r'xos/controllerusers/$', ControllerUserList.as_view(), name='controlleruser-list-legacy'),
+        url(r'xos/controllerusers/(?P<pk>[a-zA-Z0-9\-]+)/$', ControllerUserDetail.as_view(), name ='controlleruser-detail-legacy'),
+    
+        url(r'xos/reservedresources/$', ReservedResourceList.as_view(), name='reservedresource-list-legacy'),
+        url(r'xos/reservedresources/(?P<pk>[a-zA-Z0-9\-]+)/$', ReservedResourceDetail.as_view(), name ='reservedresource-detail-legacy'),
+    
+        url(r'xos/networktemplates/$', NetworkTemplateList.as_view(), name='networktemplate-list-legacy'),
+        url(r'xos/networktemplates/(?P<pk>[a-zA-Z0-9\-]+)/$', NetworkTemplateDetail.as_view(), name ='networktemplate-detail-legacy'),
+    
+        url(r'xos/controllerdashboardviews/$', ControllerDashboardViewList.as_view(), name='controllerdashboardview-list-legacy'),
+        url(r'xos/controllerdashboardviews/(?P<pk>[a-zA-Z0-9\-]+)/$', ControllerDashboardViewDetail.as_view(), name ='controllerdashboardview-detail-legacy'),
+    
+        url(r'xos/userdashboardviews/$', UserDashboardViewList.as_view(), name='userdashboardview-list-legacy'),
+        url(r'xos/userdashboardviews/(?P<pk>[a-zA-Z0-9\-]+)/$', UserDashboardViewDetail.as_view(), name ='userdashboardview-detail-legacy'),
+    
+        url(r'xos/controllers/$', ControllerList.as_view(), name='controller-list-legacy'),
+        url(r'xos/controllers/(?P<pk>[a-zA-Z0-9\-]+)/$', ControllerDetail.as_view(), name ='controller-detail-legacy'),
+    
+        url(r'xos/users/$', UserList.as_view(), name='user-list-legacy'),
+        url(r'xos/users/(?P<pk>[a-zA-Z0-9\-]+)/$', UserDetail.as_view(), name ='user-detail-legacy'),
+    
+        url(r'xos/deployments/$', DeploymentList.as_view(), name='deployment-list-legacy'),
+        url(r'xos/deployments/(?P<pk>[a-zA-Z0-9\-]+)/$', DeploymentDetail.as_view(), name ='deployment-detail-legacy'),
+    
+        url(r'xos/reservations/$', ReservationList.as_view(), name='reservation-list-legacy'),
+        url(r'xos/reservations/(?P<pk>[a-zA-Z0-9\-]+)/$', ReservationDetail.as_view(), name ='reservation-detail-legacy'),
+    
+        url(r'xos/siteprivileges/$', SitePrivilegeList.as_view(), name='siteprivilege-list-legacy'),
+        url(r'xos/siteprivileges/(?P<pk>[a-zA-Z0-9\-]+)/$', SitePrivilegeDetail.as_view(), name ='siteprivilege-detail-legacy'),
+    
+        url(r'xos/payments/$', PaymentList.as_view(), name='payment-list-legacy'),
+        url(r'xos/payments/(?P<pk>[a-zA-Z0-9\-]+)/$', PaymentDetail.as_view(), name ='payment-detail-legacy'),
+    
+        url(r'xos/tenants/$', TenantList.as_view(), name='tenant-list-legacy'),
+        url(r'xos/tenants/(?P<pk>[a-zA-Z0-9\-]+)/$', TenantDetail.as_view(), name ='tenant-detail-legacy'),
+    
+        url(r'xos/networkslices/$', NetworkSliceList.as_view(), name='networkslice-list-legacy'),
+        url(r'xos/networkslices/(?P<pk>[a-zA-Z0-9\-]+)/$', NetworkSliceDetail.as_view(), name ='networkslice-detail-legacy'),
+    
+        url(r'xos/accounts/$', AccountList.as_view(), name='account-list-legacy'),
+        url(r'xos/accounts/(?P<pk>[a-zA-Z0-9\-]+)/$', AccountDetail.as_view(), name ='account-detail-legacy'),
+    
+        url(r'xos/tenantroots/$', TenantRootList.as_view(), name='tenantroot-list-legacy'),
+        url(r'xos/tenantroots/(?P<pk>[a-zA-Z0-9\-]+)/$', TenantRootDetail.as_view(), name ='tenantroot-detail-legacy'),
+    
+        url(r'xos/services/$', ServiceList.as_view(), name='service-list-legacy'),
+        url(r'xos/services/(?P<pk>[a-zA-Z0-9\-]+)/$', ServiceDetail.as_view(), name ='service-detail-legacy'),
+    
+        url(r'xos/controllersliceprivileges/$', ControllerSlicePrivilegeList.as_view(), name='controllersliceprivilege-list-legacy'),
+        url(r'xos/controllersliceprivileges/(?P<pk>[a-zA-Z0-9\-]+)/$', ControllerSlicePrivilegeDetail.as_view(), name ='controllersliceprivilege-detail-legacy'),
+    
+        url(r'xos/sitecredentials/$', SiteCredentialList.as_view(), name='sitecredential-list-legacy'),
+        url(r'xos/sitecredentials/(?P<pk>[a-zA-Z0-9\-]+)/$', SiteCredentialDetail.as_view(), name ='sitecredential-detail-legacy'),
+    
+        url(r'xos/deploymentprivileges/$', DeploymentPrivilegeList.as_view(), name='deploymentprivilege-list-legacy'),
+        url(r'xos/deploymentprivileges/(?P<pk>[a-zA-Z0-9\-]+)/$', DeploymentPrivilegeDetail.as_view(), name ='deploymentprivilege-detail-legacy'),
+    
+        url(r'xos/networkparametertypes/$', NetworkParameterTypeList.as_view(), name='networkparametertype-list-legacy'),
+        url(r'xos/networkparametertypes/(?P<pk>[a-zA-Z0-9\-]+)/$', NetworkParameterTypeDetail.as_view(), name ='networkparametertype-detail-legacy'),
+    
+        url(r'xos/providers/$', ProviderList.as_view(), name='provider-list-legacy'),
+        url(r'xos/providers/(?P<pk>[a-zA-Z0-9\-]+)/$', ProviderDetail.as_view(), name ='provider-detail-legacy'),
+    
+        url(r'xos/tenantwithcontainers/$', TenantWithContainerList.as_view(), name='tenantwithcontainer-list-legacy'),
+        url(r'xos/tenantwithcontainers/(?P<pk>[a-zA-Z0-9\-]+)/$', TenantWithContainerDetail.as_view(), name ='tenantwithcontainer-detail-legacy'),
+    
+        url(r'xos/deploymentroles/$', DeploymentRoleList.as_view(), name='deploymentrole-list-legacy'),
+        url(r'xos/deploymentroles/(?P<pk>[a-zA-Z0-9\-]+)/$', DeploymentRoleDetail.as_view(), name ='deploymentrole-detail-legacy'),
+    
+        url(r'xos/projects/$', ProjectList.as_view(), name='project-list-legacy'),
+        url(r'xos/projects/(?P<pk>[a-zA-Z0-9\-]+)/$', ProjectDetail.as_view(), name ='project-detail-legacy'),
+    
+        url(r'xos/tenantrootprivileges/$', TenantRootPrivilegeList.as_view(), name='tenantrootprivilege-list-legacy'),
+        url(r'xos/tenantrootprivileges/(?P<pk>[a-zA-Z0-9\-]+)/$', TenantRootPrivilegeDetail.as_view(), name ='tenantrootprivilege-detail-legacy'),
+    
+        url(r'xos/slicetags/$', SliceTagList.as_view(), name='slicetag-list-legacy'),
+        url(r'xos/slicetags/(?P<pk>[a-zA-Z0-9\-]+)/$', SliceTagDetail.as_view(), name ='slicetag-detail-legacy'),
+    
+        url(r'xos/coarsetenants/$', CoarseTenantList.as_view(), name='coarsetenant-list-legacy'),
+        url(r'xos/coarsetenants/(?P<pk>[a-zA-Z0-9\-]+)/$', CoarseTenantDetail.as_view(), name ='coarsetenant-detail-legacy'),
+    
+        url(r'xos/routers/$', RouterList.as_view(), name='router-list-legacy'),
+        url(r'xos/routers/(?P<pk>[a-zA-Z0-9\-]+)/$', RouterDetail.as_view(), name ='router-detail-legacy'),
+    
+        url(r'xos/serviceresources/$', ServiceResourceList.as_view(), name='serviceresource-list-legacy'),
+        url(r'xos/serviceresources/(?P<pk>[a-zA-Z0-9\-]+)/$', ServiceResourceDetail.as_view(), name ='serviceresource-detail-legacy'),
+    
+        url(r'xos/serviceprivileges/$', ServicePrivilegeList.as_view(), name='serviceprivilege-list-legacy'),
+        url(r'xos/serviceprivileges/(?P<pk>[a-zA-Z0-9\-]+)/$', ServicePrivilegeDetail.as_view(), name ='serviceprivilege-detail-legacy'),
+    
+    ) + patterns('',
+    # new - use these instead of the above
+        url(r'^api/core/$', api_root),
+    
+        url(r'api/core/serviceattributes/$', ServiceAttributeList.as_view(), name='serviceattribute-list'),
+        url(r'api/core/serviceattributes/(?P<pk>[a-zA-Z0-9\-]+)/$', ServiceAttributeDetail.as_view(), name ='serviceattribute-detail'),
+    
+        url(r'api/core/controllerimages/$', ControllerImagesList.as_view(), name='controllerimages-list'),
+        url(r'api/core/controllerimages/(?P<pk>[a-zA-Z0-9\-]+)/$', ControllerImagesDetail.as_view(), name ='controllerimages-detail'),
+    
+        url(r'api/core/controllersiteprivileges/$', ControllerSitePrivilegeList.as_view(), name='controllersiteprivilege-list'),
+        url(r'api/core/controllersiteprivileges/(?P<pk>[a-zA-Z0-9\-]+)/$', ControllerSitePrivilegeDetail.as_view(), name ='controllersiteprivilege-detail'),
+    
+        url(r'api/core/images/$', ImageList.as_view(), name='image-list'),
+        url(r'api/core/images/(?P<pk>[a-zA-Z0-9\-]+)/$', ImageDetail.as_view(), name ='image-detail'),
+    
+        url(r'api/core/controllernetworks/$', ControllerNetworkList.as_view(), name='controllernetwork-list'),
+        url(r'api/core/controllernetworks/(?P<pk>[a-zA-Z0-9\-]+)/$', ControllerNetworkDetail.as_view(), name ='controllernetwork-detail'),
+    
+        url(r'api/core/sites/$', SiteList.as_view(), name='site-list'),
+        url(r'api/core/sites/(?P<pk>[a-zA-Z0-9\-]+)/$', SiteDetail.as_view(), name ='site-detail'),
+    
+        url(r'api/core/tenantrootroles/$', TenantRootRoleList.as_view(), name='tenantrootrole-list'),
+        url(r'api/core/tenantrootroles/(?P<pk>[a-zA-Z0-9\-]+)/$', TenantRootRoleDetail.as_view(), name ='tenantrootrole-detail'),
+    
+        url(r'api/core/slice_roles/$', SliceRoleList.as_view(), name='slicerole-list'),
+        url(r'api/core/slice_roles/(?P<pk>[a-zA-Z0-9\-]+)/$', SliceRoleDetail.as_view(), name ='slicerole-detail'),
+    
+        url(r'api/core/sitedeployments/$', SiteDeploymentList.as_view(), name='sitedeployment-list'),
+        url(r'api/core/sitedeployments/(?P<pk>[a-zA-Z0-9\-]+)/$', SiteDeploymentDetail.as_view(), name ='sitedeployment-detail'),
+    
+        url(r'api/core/tenantprivileges/$', TenantPrivilegeList.as_view(), name='tenantprivilege-list'),
+        url(r'api/core/tenantprivileges/(?P<pk>[a-zA-Z0-9\-]+)/$', TenantPrivilegeDetail.as_view(), name ='tenantprivilege-detail'),
+    
+        url(r'api/core/tags/$', TagList.as_view(), name='tag-list'),
+        url(r'api/core/tags/(?P<pk>[a-zA-Z0-9\-]+)/$', TagDetail.as_view(), name ='tag-detail'),
+    
+        url(r'api/core/usercredentials/$', UserCredentialList.as_view(), name='usercredential-list'),
+        url(r'api/core/usercredentials/(?P<pk>[a-zA-Z0-9\-]+)/$', UserCredentialDetail.as_view(), name ='usercredential-detail'),
+    
+        url(r'api/core/invoices/$', InvoiceList.as_view(), name='invoice-list'),
+        url(r'api/core/invoices/(?P<pk>[a-zA-Z0-9\-]+)/$', InvoiceDetail.as_view(), name ='invoice-detail'),
+    
+        url(r'api/core/slice_privileges/$', SlicePrivilegeList.as_view(), name='sliceprivilege-list'),
+        url(r'api/core/slice_privileges/(?P<pk>[a-zA-Z0-9\-]+)/$', SlicePrivilegeDetail.as_view(), name ='sliceprivilege-detail'),
+    
+        url(r'api/core/flavors/$', FlavorList.as_view(), name='flavor-list'),
+        url(r'api/core/flavors/(?P<pk>[a-zA-Z0-9\-]+)/$', FlavorDetail.as_view(), name ='flavor-detail'),
+    
+        url(r'api/core/ports/$', PortList.as_view(), name='port-list'),
+        url(r'api/core/ports/(?P<pk>[a-zA-Z0-9\-]+)/$', PortDetail.as_view(), name ='port-detail'),
+    
+        url(r'api/core/serviceroles/$', ServiceRoleList.as_view(), name='servicerole-list'),
+        url(r'api/core/serviceroles/(?P<pk>[a-zA-Z0-9\-]+)/$', ServiceRoleDetail.as_view(), name ='servicerole-detail'),
+    
+        url(r'api/core/controllersites/$', ControllerSiteList.as_view(), name='controllersite-list'),
+        url(r'api/core/controllersites/(?P<pk>[a-zA-Z0-9\-]+)/$', ControllerSiteDetail.as_view(), name ='controllersite-detail'),
+    
+        url(r'api/core/controllerslices/$', ControllerSliceList.as_view(), name='controllerslice-list'),
+        url(r'api/core/controllerslices/(?P<pk>[a-zA-Z0-9\-]+)/$', ControllerSliceDetail.as_view(), name ='controllerslice-detail'),
+    
+        url(r'api/core/tenantroles/$', TenantRoleList.as_view(), name='tenantrole-list'),
+        url(r'api/core/tenantroles/(?P<pk>[a-zA-Z0-9\-]+)/$', TenantRoleDetail.as_view(), name ='tenantrole-detail'),
+    
+        url(r'api/core/slices/$', SliceList.as_view(), name='slice-list'),
+        url(r'api/core/slices/(?P<pk>[a-zA-Z0-9\-]+)/$', SliceDetail.as_view(), name ='slice-detail'),
+    
+        url(r'api/core/networks/$', NetworkList.as_view(), name='network-list'),
+        url(r'api/core/networks/(?P<pk>[a-zA-Z0-9\-]+)/$', NetworkDetail.as_view(), name ='network-detail'),
+    
+        url(r'api/core/controllerroles/$', ControllerRoleList.as_view(), name='controllerrole-list'),
+        url(r'api/core/controllerroles/(?P<pk>[a-zA-Z0-9\-]+)/$', ControllerRoleDetail.as_view(), name ='controllerrole-detail'),
+    
+        url(r'api/core/diags/$', DiagList.as_view(), name='diag-list'),
+        url(r'api/core/diags/(?P<pk>[a-zA-Z0-9\-]+)/$', DiagDetail.as_view(), name ='diag-detail'),
+    
+        url(r'api/core/serviceclasses/$', ServiceClassList.as_view(), name='serviceclass-list'),
+        url(r'api/core/serviceclasses/(?P<pk>[a-zA-Z0-9\-]+)/$', ServiceClassDetail.as_view(), name ='serviceclass-detail'),
+    
+        url(r'api/core/tenantattributes/$', TenantAttributeList.as_view(), name='tenantattribute-list'),
+        url(r'api/core/tenantattributes/(?P<pk>[a-zA-Z0-9\-]+)/$', TenantAttributeDetail.as_view(), name ='tenantattribute-detail'),
+    
+        url(r'api/core/site_roles/$', SiteRoleList.as_view(), name='siterole-list'),
+        url(r'api/core/site_roles/(?P<pk>[a-zA-Z0-9\-]+)/$', SiteRoleDetail.as_view(), name ='siterole-detail'),
+    
+        url(r'api/core/subscribers/$', SubscriberList.as_view(), name='subscriber-list'),
+        url(r'api/core/subscribers/(?P<pk>[a-zA-Z0-9\-]+)/$', SubscriberDetail.as_view(), name ='subscriber-detail'),
+    
+        url(r'api/core/instances/$', InstanceList.as_view(), name='instance-list'),
+        url(r'api/core/instances/(?P<pk>[a-zA-Z0-9\-]+)/$', InstanceDetail.as_view(), name ='instance-detail'),
+    
+        url(r'api/core/charges/$', ChargeList.as_view(), name='charge-list'),
+        url(r'api/core/charges/(?P<pk>[a-zA-Z0-9\-]+)/$', ChargeDetail.as_view(), name ='charge-detail'),
+    
+        url(r'api/core/programs/$', ProgramList.as_view(), name='program-list'),
+        url(r'api/core/programs/(?P<pk>[a-zA-Z0-9\-]+)/$', ProgramDetail.as_view(), name ='program-detail'),
+    
+        url(r'api/core/roles/$', RoleList.as_view(), name='role-list'),
+        url(r'api/core/roles/(?P<pk>[a-zA-Z0-9\-]+)/$', RoleDetail.as_view(), name ='role-detail'),
+    
+        url(r'api/core/usableobjects/$', UsableObjectList.as_view(), name='usableobject-list'),
+        url(r'api/core/usableobjects/(?P<pk>[a-zA-Z0-9\-]+)/$', UsableObjectDetail.as_view(), name ='usableobject-detail'),
+    
+        url(r'api/core/nodelabels/$', NodeLabelList.as_view(), name='nodelabel-list'),
+        url(r'api/core/nodelabels/(?P<pk>[a-zA-Z0-9\-]+)/$', NodeLabelDetail.as_view(), name ='nodelabel-detail'),
+    
+        url(r'api/core/slicecredentials/$', SliceCredentialList.as_view(), name='slicecredential-list'),
+        url(r'api/core/slicecredentials/(?P<pk>[a-zA-Z0-9\-]+)/$', SliceCredentialDetail.as_view(), name ='slicecredential-detail'),
+    
+        url(r'api/core/nodes/$', NodeList.as_view(), name='node-list'),
+        url(r'api/core/nodes/(?P<pk>[a-zA-Z0-9\-]+)/$', NodeDetail.as_view(), name ='node-detail'),
+    
+        url(r'api/core/addresspools/$', AddressPoolList.as_view(), name='addresspool-list'),
+        url(r'api/core/addresspools/(?P<pk>[a-zA-Z0-9\-]+)/$', AddressPoolDetail.as_view(), name ='addresspool-detail'),
+    
+        url(r'api/core/dashboardviews/$', DashboardViewList.as_view(), name='dashboardview-list'),
+        url(r'api/core/dashboardviews/(?P<pk>[a-zA-Z0-9\-]+)/$', DashboardViewDetail.as_view(), name ='dashboardview-detail'),
+    
+        url(r'api/core/networkparameters/$', NetworkParameterList.as_view(), name='networkparameter-list'),
+        url(r'api/core/networkparameters/(?P<pk>[a-zA-Z0-9\-]+)/$', NetworkParameterDetail.as_view(), name ='networkparameter-detail'),
+    
+        url(r'api/core/imagedeploymentses/$', ImageDeploymentsList.as_view(), name='imagedeployments-list'),
+        url(r'api/core/imagedeploymentses/(?P<pk>[a-zA-Z0-9\-]+)/$', ImageDeploymentsDetail.as_view(), name ='imagedeployments-detail'),
+    
+        url(r'api/core/controllerusers/$', ControllerUserList.as_view(), name='controlleruser-list'),
+        url(r'api/core/controllerusers/(?P<pk>[a-zA-Z0-9\-]+)/$', ControllerUserDetail.as_view(), name ='controlleruser-detail'),
+    
+        url(r'api/core/reservedresources/$', ReservedResourceList.as_view(), name='reservedresource-list'),
+        url(r'api/core/reservedresources/(?P<pk>[a-zA-Z0-9\-]+)/$', ReservedResourceDetail.as_view(), name ='reservedresource-detail'),
+    
+        url(r'api/core/networktemplates/$', NetworkTemplateList.as_view(), name='networktemplate-list'),
+        url(r'api/core/networktemplates/(?P<pk>[a-zA-Z0-9\-]+)/$', NetworkTemplateDetail.as_view(), name ='networktemplate-detail'),
+    
+        url(r'api/core/controllerdashboardviews/$', ControllerDashboardViewList.as_view(), name='controllerdashboardview-list'),
+        url(r'api/core/controllerdashboardviews/(?P<pk>[a-zA-Z0-9\-]+)/$', ControllerDashboardViewDetail.as_view(), name ='controllerdashboardview-detail'),
+    
+        url(r'api/core/userdashboardviews/$', UserDashboardViewList.as_view(), name='userdashboardview-list'),
+        url(r'api/core/userdashboardviews/(?P<pk>[a-zA-Z0-9\-]+)/$', UserDashboardViewDetail.as_view(), name ='userdashboardview-detail'),
+    
+        url(r'api/core/controllers/$', ControllerList.as_view(), name='controller-list'),
+        url(r'api/core/controllers/(?P<pk>[a-zA-Z0-9\-]+)/$', ControllerDetail.as_view(), name ='controller-detail'),
+    
+        url(r'api/core/users/$', UserList.as_view(), name='user-list'),
+        url(r'api/core/users/(?P<pk>[a-zA-Z0-9\-]+)/$', UserDetail.as_view(), name ='user-detail'),
+    
+        url(r'api/core/deployments/$', DeploymentList.as_view(), name='deployment-list'),
+        url(r'api/core/deployments/(?P<pk>[a-zA-Z0-9\-]+)/$', DeploymentDetail.as_view(), name ='deployment-detail'),
+    
+        url(r'api/core/reservations/$', ReservationList.as_view(), name='reservation-list'),
+        url(r'api/core/reservations/(?P<pk>[a-zA-Z0-9\-]+)/$', ReservationDetail.as_view(), name ='reservation-detail'),
+    
+        url(r'api/core/siteprivileges/$', SitePrivilegeList.as_view(), name='siteprivilege-list'),
+        url(r'api/core/siteprivileges/(?P<pk>[a-zA-Z0-9\-]+)/$', SitePrivilegeDetail.as_view(), name ='siteprivilege-detail'),
+    
+        url(r'api/core/payments/$', PaymentList.as_view(), name='payment-list'),
+        url(r'api/core/payments/(?P<pk>[a-zA-Z0-9\-]+)/$', PaymentDetail.as_view(), name ='payment-detail'),
+    
+        url(r'api/core/tenants/$', TenantList.as_view(), name='tenant-list'),
+        url(r'api/core/tenants/(?P<pk>[a-zA-Z0-9\-]+)/$', TenantDetail.as_view(), name ='tenant-detail'),
+    
+        url(r'api/core/networkslices/$', NetworkSliceList.as_view(), name='networkslice-list'),
+        url(r'api/core/networkslices/(?P<pk>[a-zA-Z0-9\-]+)/$', NetworkSliceDetail.as_view(), name ='networkslice-detail'),
+    
+        url(r'api/core/accounts/$', AccountList.as_view(), name='account-list'),
+        url(r'api/core/accounts/(?P<pk>[a-zA-Z0-9\-]+)/$', AccountDetail.as_view(), name ='account-detail'),
+    
+        url(r'api/core/tenantroots/$', TenantRootList.as_view(), name='tenantroot-list'),
+        url(r'api/core/tenantroots/(?P<pk>[a-zA-Z0-9\-]+)/$', TenantRootDetail.as_view(), name ='tenantroot-detail'),
+    
+        url(r'api/core/services/$', ServiceList.as_view(), name='service-list'),
+        url(r'api/core/services/(?P<pk>[a-zA-Z0-9\-]+)/$', ServiceDetail.as_view(), name ='service-detail'),
+    
+        url(r'api/core/controllersliceprivileges/$', ControllerSlicePrivilegeList.as_view(), name='controllersliceprivilege-list'),
+        url(r'api/core/controllersliceprivileges/(?P<pk>[a-zA-Z0-9\-]+)/$', ControllerSlicePrivilegeDetail.as_view(), name ='controllersliceprivilege-detail'),
+    
+        url(r'api/core/sitecredentials/$', SiteCredentialList.as_view(), name='sitecredential-list'),
+        url(r'api/core/sitecredentials/(?P<pk>[a-zA-Z0-9\-]+)/$', SiteCredentialDetail.as_view(), name ='sitecredential-detail'),
+    
+        url(r'api/core/deploymentprivileges/$', DeploymentPrivilegeList.as_view(), name='deploymentprivilege-list'),
+        url(r'api/core/deploymentprivileges/(?P<pk>[a-zA-Z0-9\-]+)/$', DeploymentPrivilegeDetail.as_view(), name ='deploymentprivilege-detail'),
+    
+        url(r'api/core/networkparametertypes/$', NetworkParameterTypeList.as_view(), name='networkparametertype-list'),
+        url(r'api/core/networkparametertypes/(?P<pk>[a-zA-Z0-9\-]+)/$', NetworkParameterTypeDetail.as_view(), name ='networkparametertype-detail'),
+    
+        url(r'api/core/providers/$', ProviderList.as_view(), name='provider-list'),
+        url(r'api/core/providers/(?P<pk>[a-zA-Z0-9\-]+)/$', ProviderDetail.as_view(), name ='provider-detail'),
+    
+        url(r'api/core/tenantwithcontainers/$', TenantWithContainerList.as_view(), name='tenantwithcontainer-list'),
+        url(r'api/core/tenantwithcontainers/(?P<pk>[a-zA-Z0-9\-]+)/$', TenantWithContainerDetail.as_view(), name ='tenantwithcontainer-detail'),
+    
+        url(r'api/core/deploymentroles/$', DeploymentRoleList.as_view(), name='deploymentrole-list'),
+        url(r'api/core/deploymentroles/(?P<pk>[a-zA-Z0-9\-]+)/$', DeploymentRoleDetail.as_view(), name ='deploymentrole-detail'),
+    
+        url(r'api/core/projects/$', ProjectList.as_view(), name='project-list'),
+        url(r'api/core/projects/(?P<pk>[a-zA-Z0-9\-]+)/$', ProjectDetail.as_view(), name ='project-detail'),
+    
+        url(r'api/core/tenantrootprivileges/$', TenantRootPrivilegeList.as_view(), name='tenantrootprivilege-list'),
+        url(r'api/core/tenantrootprivileges/(?P<pk>[a-zA-Z0-9\-]+)/$', TenantRootPrivilegeDetail.as_view(), name ='tenantrootprivilege-detail'),
+    
+        url(r'api/core/slicetags/$', SliceTagList.as_view(), name='slicetag-list'),
+        url(r'api/core/slicetags/(?P<pk>[a-zA-Z0-9\-]+)/$', SliceTagDetail.as_view(), name ='slicetag-detail'),
+    
+        url(r'api/core/coarsetenants/$', CoarseTenantList.as_view(), name='coarsetenant-list'),
+        url(r'api/core/coarsetenants/(?P<pk>[a-zA-Z0-9\-]+)/$', CoarseTenantDetail.as_view(), name ='coarsetenant-detail'),
+    
+        url(r'api/core/routers/$', RouterList.as_view(), name='router-list'),
+        url(r'api/core/routers/(?P<pk>[a-zA-Z0-9\-]+)/$', RouterDetail.as_view(), name ='router-detail'),
+    
+        url(r'api/core/serviceresources/$', ServiceResourceList.as_view(), name='serviceresource-list'),
+        url(r'api/core/serviceresources/(?P<pk>[a-zA-Z0-9\-]+)/$', ServiceResourceDetail.as_view(), name ='serviceresource-detail'),
+    
+        url(r'api/core/serviceprivileges/$', ServicePrivilegeList.as_view(), name='serviceprivilege-list'),
+        url(r'api/core/serviceprivileges/(?P<pk>[a-zA-Z0-9\-]+)/$', ServicePrivilegeDetail.as_view(), name ='serviceprivilege-detail'),
+    
+    )
+
+@api_view(['GET'])
+def api_root_legacy(request, format=None):
+    return Response({
+        'serviceattributes': reverse('serviceattribute-list-legacy', request=request, format=format),
+        'controllerimageses': reverse('controllerimages-list-legacy', request=request, format=format),
+        'controllersiteprivileges': reverse('controllersiteprivilege-list-legacy', request=request, format=format),
+        'images': reverse('image-list-legacy', request=request, format=format),
+        'controllernetworks': reverse('controllernetwork-list-legacy', request=request, format=format),
+        'sites': reverse('site-list-legacy', request=request, format=format),
+        'tenantrootroles': reverse('tenantrootrole-list-legacy', request=request, format=format),
+        'sliceroles': reverse('slicerole-list-legacy', request=request, format=format),
+        'sitedeployments': reverse('sitedeployment-list-legacy', request=request, format=format),
+        'tenantprivileges': reverse('tenantprivilege-list-legacy', request=request, format=format),
+        'tags': reverse('tag-list-legacy', request=request, format=format),
+        'usercredentials': reverse('usercredential-list-legacy', request=request, format=format),
+        'invoices': reverse('invoice-list-legacy', request=request, format=format),
+        'sliceprivileges': reverse('sliceprivilege-list-legacy', request=request, format=format),
+        'flavors': reverse('flavor-list-legacy', request=request, format=format),
+        'ports': reverse('port-list-legacy', request=request, format=format),
+        'serviceroles': reverse('servicerole-list-legacy', request=request, format=format),
+        'controllersites': reverse('controllersite-list-legacy', request=request, format=format),
+        'controllerslices': reverse('controllerslice-list-legacy', request=request, format=format),
+        'tenantroles': reverse('tenantrole-list-legacy', request=request, format=format),
+        'slices': reverse('slice-list-legacy', request=request, format=format),
+        'networks': reverse('network-list-legacy', request=request, format=format),
+        'controllerroles': reverse('controllerrole-list-legacy', request=request, format=format),
+        'diags': reverse('diag-list-legacy', request=request, format=format),
+        'serviceclasses': reverse('serviceclass-list-legacy', request=request, format=format),
+        'tenantattributes': reverse('tenantattribute-list-legacy', request=request, format=format),
+        'siteroles': reverse('siterole-list-legacy', request=request, format=format),
+        'subscribers': reverse('subscriber-list-legacy', request=request, format=format),
+        'instances': reverse('instance-list-legacy', request=request, format=format),
+        'charges': reverse('charge-list-legacy', request=request, format=format),
+        'programs': reverse('program-list-legacy', request=request, format=format),
+        'roles': reverse('role-list-legacy', request=request, format=format),
+        'usableobjects': reverse('usableobject-list-legacy', request=request, format=format),
+        'nodelabels': reverse('nodelabel-list-legacy', request=request, format=format),
+        'slicecredentials': reverse('slicecredential-list-legacy', request=request, format=format),
+        'nodes': reverse('node-list-legacy', request=request, format=format),
+        'addresspools': reverse('addresspool-list-legacy', request=request, format=format),
+        'dashboardviews': reverse('dashboardview-list-legacy', request=request, format=format),
+        'networkparameters': reverse('networkparameter-list-legacy', request=request, format=format),
+        'imagedeploymentses': reverse('imagedeployments-list-legacy', request=request, format=format),
+        'controllerusers': reverse('controlleruser-list-legacy', request=request, format=format),
+        'reservedresources': reverse('reservedresource-list-legacy', request=request, format=format),
+        'networktemplates': reverse('networktemplate-list-legacy', request=request, format=format),
+        'controllerdashboardviews': reverse('controllerdashboardview-list-legacy', request=request, format=format),
+        'userdashboardviews': reverse('userdashboardview-list-legacy', request=request, format=format),
+        'controllers': reverse('controller-list-legacy', request=request, format=format),
+        'users': reverse('user-list-legacy', request=request, format=format),
+        'deployments': reverse('deployment-list-legacy', request=request, format=format),
+        'reservations': reverse('reservation-list-legacy', request=request, format=format),
+        'siteprivileges': reverse('siteprivilege-list-legacy', request=request, format=format),
+        'payments': reverse('payment-list-legacy', request=request, format=format),
+        'tenants': reverse('tenant-list-legacy', request=request, format=format),
+        'networkslices': reverse('networkslice-list-legacy', request=request, format=format),
+        'accounts': reverse('account-list-legacy', request=request, format=format),
+        'tenantroots': reverse('tenantroot-list-legacy', request=request, format=format),
+        'services': reverse('service-list-legacy', request=request, format=format),
+        'controllersliceprivileges': reverse('controllersliceprivilege-list-legacy', request=request, format=format),
+        'sitecredentials': reverse('sitecredential-list-legacy', request=request, format=format),
+        'deploymentprivileges': reverse('deploymentprivilege-list-legacy', request=request, format=format),
+        'networkparametertypes': reverse('networkparametertype-list-legacy', request=request, format=format),
+        'providers': reverse('provider-list-legacy', request=request, format=format),
+        'tenantwithcontainers': reverse('tenantwithcontainer-list-legacy', request=request, format=format),
+        'deploymentroles': reverse('deploymentrole-list-legacy', request=request, format=format),
+        'projects': reverse('project-list-legacy', request=request, format=format),
+        'tenantrootprivileges': reverse('tenantrootprivilege-list-legacy', request=request, format=format),
+        'slicetags': reverse('slicetag-list-legacy', request=request, format=format),
+        'coarsetenants': reverse('coarsetenant-list-legacy', request=request, format=format),
+        'routers': reverse('router-list-legacy', request=request, format=format),
+        'serviceresources': reverse('serviceresource-list-legacy', request=request, format=format),
+        'serviceprivileges': reverse('serviceprivilege-list-legacy', request=request, format=format),
+        
+    })
+
+@api_view(['GET'])
+def api_root(request, format=None):
+    return Response({
+        'serviceattributes': reverse('serviceattribute-list', request=request, format=format),
+        'controllerimageses': reverse('controllerimages-list', request=request, format=format),
+        'controllersiteprivileges': reverse('controllersiteprivilege-list', request=request, format=format),
+        'images': reverse('image-list', request=request, format=format),
+        'controllernetworks': reverse('controllernetwork-list', request=request, format=format),
+        'sites': reverse('site-list', request=request, format=format),
+        'tenantrootroles': reverse('tenantrootrole-list', request=request, format=format),
+        'sliceroles': reverse('slicerole-list', request=request, format=format),
+        'sitedeployments': reverse('sitedeployment-list', request=request, format=format),
+        'tenantprivileges': reverse('tenantprivilege-list', request=request, format=format),
+        'tags': reverse('tag-list', request=request, format=format),
+        'usercredentials': reverse('usercredential-list', request=request, format=format),
+        'invoices': reverse('invoice-list', request=request, format=format),
+        'sliceprivileges': reverse('sliceprivilege-list', request=request, format=format),
+        'flavors': reverse('flavor-list', request=request, format=format),
+        'ports': reverse('port-list', request=request, format=format),
+        'serviceroles': reverse('servicerole-list', request=request, format=format),
+        'controllersites': reverse('controllersite-list', request=request, format=format),
+        'controllerslices': reverse('controllerslice-list', request=request, format=format),
+        'tenantroles': reverse('tenantrole-list', request=request, format=format),
+        'slices': reverse('slice-list', request=request, format=format),
+        'networks': reverse('network-list', request=request, format=format),
+        'controllerroles': reverse('controllerrole-list', request=request, format=format),
+        'diags': reverse('diag-list', request=request, format=format),
+        'serviceclasses': reverse('serviceclass-list', request=request, format=format),
+        'tenantattributes': reverse('tenantattribute-list', request=request, format=format),
+        'siteroles': reverse('siterole-list', request=request, format=format),
+        'subscribers': reverse('subscriber-list', request=request, format=format),
+        'instances': reverse('instance-list', request=request, format=format),
+        'charges': reverse('charge-list', request=request, format=format),
+        'programs': reverse('program-list', request=request, format=format),
+        'roles': reverse('role-list', request=request, format=format),
+        'usableobjects': reverse('usableobject-list', request=request, format=format),
+        'nodelabels': reverse('nodelabel-list', request=request, format=format),
+        'slicecredentials': reverse('slicecredential-list', request=request, format=format),
+        'nodes': reverse('node-list', request=request, format=format),
+        'addresspools': reverse('addresspool-list', request=request, format=format),
+        'dashboardviews': reverse('dashboardview-list', request=request, format=format),
+        'networkparameters': reverse('networkparameter-list', request=request, format=format),
+        'imagedeploymentses': reverse('imagedeployments-list', request=request, format=format),
+        'controllerusers': reverse('controlleruser-list', request=request, format=format),
+        'reservedresources': reverse('reservedresource-list', request=request, format=format),
+        'networktemplates': reverse('networktemplate-list', request=request, format=format),
+        'controllerdashboardviews': reverse('controllerdashboardview-list', request=request, format=format),
+        'userdashboardviews': reverse('userdashboardview-list', request=request, format=format),
+        'controllers': reverse('controller-list', request=request, format=format),
+        'users': reverse('user-list', request=request, format=format),
+        'deployments': reverse('deployment-list', request=request, format=format),
+        'reservations': reverse('reservation-list', request=request, format=format),
+        'siteprivileges': reverse('siteprivilege-list', request=request, format=format),
+        'payments': reverse('payment-list', request=request, format=format),
+        'tenants': reverse('tenant-list', request=request, format=format),
+        'networkslices': reverse('networkslice-list', request=request, format=format),
+        'accounts': reverse('account-list', request=request, format=format),
+        'tenantroots': reverse('tenantroot-list', request=request, format=format),
+        'services': reverse('service-list', request=request, format=format),
+        'controllersliceprivileges': reverse('controllersliceprivilege-list', request=request, format=format),
+        'sitecredentials': reverse('sitecredential-list', request=request, format=format),
+        'deploymentprivileges': reverse('deploymentprivilege-list', request=request, format=format),
+        'networkparametertypes': reverse('networkparametertype-list', request=request, format=format),
+        'providers': reverse('provider-list', request=request, format=format),
+        'tenantwithcontainers': reverse('tenantwithcontainer-list', request=request, format=format),
+        'deploymentroles': reverse('deploymentrole-list', request=request, format=format),
+        'projects': reverse('project-list', request=request, format=format),
+        'tenantrootprivileges': reverse('tenantrootprivilege-list', request=request, format=format),
+        'slicetags': reverse('slicetag-list', request=request, format=format),
+        'coarsetenants': reverse('coarsetenant-list', request=request, format=format),
+        'routers': reverse('router-list', request=request, format=format),
+        'serviceresources': reverse('serviceresource-list', request=request, format=format),
+        'serviceprivileges': reverse('serviceprivilege-list', request=request, format=format),
+        
+    })
+
+# Based on serializers.py
+
+class XOSModelSerializer(serializers.ModelSerializer):
+    # TODO: Rest Framework 3.x doesn't support save_object()
+    def NEED_TO_UPDATE_save_object(self, obj, **kwargs):
+
+        """ rest_framework can't deal with ManyToMany relations that have a
+            through table. In xos, most of the through tables we have
+            use defaults or blank fields, so there's no reason why we shouldn't
+            be able to save these objects.
+
+            So, let's strip out these m2m relations, and deal with them ourself.
+        """
+        obj._complex_m2m_data={};
+        if getattr(obj, '_m2m_data', None):
+            for relatedObject in obj._meta.get_all_related_many_to_many_objects():
+                if (relatedObject.field.rel.through._meta.auto_created):
+                    # These are non-trough ManyToMany relations and
+                    # can be updated just fine
+                    continue
+                fieldName = relatedObject.get_accessor_name()
+                if fieldName in obj._m2m_data.keys():
+                    obj._complex_m2m_data[fieldName] = (relatedObject, obj._m2m_data[fieldName])
+                    del obj._m2m_data[fieldName]
+
+        serializers.ModelSerializer.save_object(self, obj, **kwargs);
+
+        for (accessor, stuff) in obj._complex_m2m_data.items():
+            (relatedObject, data) = stuff
+            through = relatedObject.field.rel.through
+            local_fieldName = relatedObject.field.m2m_reverse_field_name()
+            remote_fieldName = relatedObject.field.m2m_field_name()
+
+            # get the current set of existing relations
+            existing = through.objects.filter(**{local_fieldName: obj});
+
+            data_ids = [item.id for item in data]
+            existing_ids = [getattr(item,remote_fieldName).id for item in existing]
+
+            #print "data_ids", data_ids
+            #print "existing_ids", existing_ids
+
+            # remove relations that are in 'existing' but not in 'data'
+            for item in list(existing):
+               if (getattr(item,remote_fieldName).id not in data_ids):
+                   print "delete", getattr(item,remote_fieldName)
+                   item.delete() #(purge=True)
+
+            # add relations that are in 'data' but not in 'existing'
+            for item in data:
+               if (item.id not in existing_ids):
+                   #print "add", item
+                   newModel = through(**{local_fieldName: obj, remote_fieldName: item})
+                   newModel.save()
+
+
+
+class ServiceAttributeSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = ServiceAttribute
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','value','service',)
+
+class ServiceAttributeIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = ServiceAttribute
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','value','service',)
+
+
+
+
+class ControllerImagesSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = ControllerImages
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','image','controller','glance_image_id',)
+
+class ControllerImagesIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = ControllerImages
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','image','controller','glance_image_id',)
+
+
+
+
+class ControllerSitePrivilegeSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = ControllerSitePrivilege
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','controller','site_privilege','role_id',)
+
+class ControllerSitePrivilegeIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = ControllerSitePrivilege
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','controller','site_privilege','role_id',)
+
+
+
+
+class ImageSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    
+    deployments = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='deployment-detail')
+    
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Image
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','kind','disk_format','container_format','path','tag','deployments',)
+
+class ImageIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    
+    deployments = serializers.PrimaryKeyRelatedField(many=True,  required=False, queryset = Deployment.objects.all())
+    
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Image
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','kind','disk_format','container_format','path','tag','deployments',)
+
+
+
+
+class ControllerNetworkSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = ControllerNetwork
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','network','controller','net_id','router_id','subnet_id','subnet',)
+
+class ControllerNetworkIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = ControllerNetwork
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','network','controller','net_id','router_id','subnet_id','subnet',)
+
+
+
+
+class SiteSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    
+    deployments = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='deployment-detail')
+    
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Site
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','site_url','enabled','hosts_nodes','hosts_users','location','longitude','latitude','login_base','is_public','abbreviated_name','deployments',)
+
+class SiteIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    
+    deployments = serializers.PrimaryKeyRelatedField(many=True,  required=False, queryset = Deployment.objects.all())
+    
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Site
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','site_url','enabled','hosts_nodes','hosts_users','location','longitude','latitude','login_base','is_public','abbreviated_name','deployments',)
+
+
+
+
+class TenantRootRoleSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = TenantRootRole
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','role',)
+
+class TenantRootRoleIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = TenantRootRole
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','role',)
+
+
+
+
+class SliceRoleSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = SliceRole
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','role',)
+
+class SliceRoleIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = SliceRole
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','role',)
+
+
+
+
+class SiteDeploymentSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = SiteDeployment
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','site','deployment','controller','availability_zone',)
+
+class SiteDeploymentIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = SiteDeployment
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','site','deployment','controller','availability_zone',)
+
+
+
+
+class TenantPrivilegeSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = TenantPrivilege
+        fields = ('humanReadableName', 'validators', 'created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','id','user','tenant','role',)
+
+class TenantPrivilegeIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = TenantPrivilege
+        fields = ('humanReadableName', 'validators', 'created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','id','user','tenant','role',)
+
+
+
+
+class TagSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Tag
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','service','name','value','content_type','object_id',)
+
+class TagIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Tag
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','service','name','value','content_type','object_id',)
+
+
+
+
+class UserCredentialSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = UserCredential
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','user','name','key_id','enc_value',)
+
+class UserCredentialIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = UserCredential
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','user','name','key_id','enc_value',)
+
+
+
+
+class InvoiceSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Invoice
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','date','account',)
+
+class InvoiceIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Invoice
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','date','account',)
+
+
+
+
+class SlicePrivilegeSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = SlicePrivilege
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','user','slice','role',)
+
+class SlicePrivilegeIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = SlicePrivilege
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','user','slice','role',)
+
+
+
+
+class FlavorSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    
+    deployments = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='deployment-detail')
+    
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Flavor
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','description','flavor','order','default','deployments',)
+
+class FlavorIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    
+    deployments = serializers.PrimaryKeyRelatedField(many=True,  required=False, queryset = Deployment.objects.all())
+    
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Flavor
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','description','flavor','order','default','deployments',)
+
+
+
+
+class PortSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Port
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','network','instance','ip','port_id','mac','xos_created',)
+
+class PortIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Port
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','network','instance','ip','port_id','mac','xos_created',)
+
+
+
+
+class ServiceRoleSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = ServiceRole
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','role',)
+
+class ServiceRoleIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = ServiceRole
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','role',)
+
+
+
+
+class ControllerSiteSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = ControllerSite
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','site','controller','tenant_id',)
+
+class ControllerSiteIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = ControllerSite
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','site','controller','tenant_id',)
+
+
+
+
+class ControllerSliceSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = ControllerSlice
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','controller','slice','tenant_id',)
+
+class ControllerSliceIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = ControllerSlice
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','controller','slice','tenant_id',)
+
+
+
+
+class TenantRoleSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = TenantRole
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','role',)
+
+class TenantRoleIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = TenantRole
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','role',)
+
+
+
+
+class SliceSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    
+    networks = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='network-detail')
+    
+    
+    
+    networks = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='network-detail')
+    
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Slice
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','enabled','omf_friendly','description','slice_url','site','max_instances','service','network','exposed_ports','serviceClass','creator','default_flavor','default_image','mount_data_sets','default_isolation','networks','networks',)
+
+class SliceIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    
+    networks = serializers.PrimaryKeyRelatedField(many=True,  required=False, queryset = Network.objects.all())
+    
+    
+    
+    networks = serializers.PrimaryKeyRelatedField(many=True,  required=False, queryset = Network.objects.all())
+    
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Slice
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','enabled','omf_friendly','description','slice_url','site','max_instances','service','network','exposed_ports','serviceClass','creator','default_flavor','default_image','mount_data_sets','default_isolation','networks','networks',)
+
+
+
+
+class NetworkSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    
+    slices = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='slice-detail')
+    
+    
+    
+    slices = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='slice-detail')
+    
+    
+    
+    instances = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='instance-detail')
+    
+    
+    
+    routers = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='router-detail')
+    
+    
+    
+    routers = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='router-detail')
+    
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Network
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','template','subnet','ports','labels','owner','guaranteed_bandwidth','permit_all_slices','topology_parameters','controller_url','controller_parameters','network_id','router_id','subnet_id','autoconnect','slices','slices','instances','routers','routers',)
+
+class NetworkIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    
+    slices = serializers.PrimaryKeyRelatedField(many=True,  required=False, queryset = Slice.objects.all())
+    
+    
+    
+    slices = serializers.PrimaryKeyRelatedField(many=True,  required=False, queryset = Slice.objects.all())
+    
+    
+    
+    instances = serializers.PrimaryKeyRelatedField(many=True,  required=False, queryset = Instance.objects.all())
+    
+    
+    
+    routers = serializers.PrimaryKeyRelatedField(many=True,  required=False, queryset = Router.objects.all())
+    
+    
+    
+    routers = serializers.PrimaryKeyRelatedField(many=True,  required=False, queryset = Router.objects.all())
+    
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Network
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','template','subnet','ports','labels','owner','guaranteed_bandwidth','permit_all_slices','topology_parameters','controller_url','controller_parameters','network_id','router_id','subnet_id','autoconnect','slices','slices','instances','routers','routers',)
+
+
+
+
+class ControllerRoleSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = ControllerRole
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','role',)
+
+class ControllerRoleIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = ControllerRole
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','role',)
+
+
+
+
+class DiagSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Diag
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name',)
+
+class DiagIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Diag
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name',)
+
+
+
+
+class ServiceClassSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = ServiceClass
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','description','commitment','membershipFee','membershipFeeMonths','upgradeRequiresApproval',)
+
+class ServiceClassIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = ServiceClass
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','description','commitment','membershipFee','membershipFeeMonths','upgradeRequiresApproval',)
+
+
+
+
+class TenantAttributeSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = TenantAttribute
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','value','tenant',)
+
+class TenantAttributeIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = TenantAttribute
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','value','tenant',)
+
+
+
+
+class SiteRoleSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = SiteRole
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','role',)
+
+class SiteRoleIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = SiteRole
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','role',)
+
+
+
+
+class SubscriberSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Subscriber
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','kind','name','service_specific_attribute','service_specific_id',)
+
+class SubscriberIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Subscriber
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','kind','name','service_specific_attribute','service_specific_id',)
+
+
+
+
+class InstanceSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    
+    networks = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='network-detail')
+    
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Instance
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','instance_id','instance_uuid','name','instance_name','ip','image','creator','slice','deployment','node','numberCores','flavor','userData','isolation','volumes','parent','networks',)
+
+class InstanceIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    
+    networks = serializers.PrimaryKeyRelatedField(many=True,  required=False, queryset = Network.objects.all())
+    
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Instance
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','instance_id','instance_uuid','name','instance_name','ip','image','creator','slice','deployment','node','numberCores','flavor','userData','isolation','volumes','parent','networks',)
+
+
+
+
+class ChargeSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Charge
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','account','slice','kind','state','date','object','amount','coreHours','invoice',)
+
+class ChargeIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Charge
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','account','slice','kind','state','date','object','amount','coreHours','invoice',)
+
+
+
+
+class ProgramSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Program
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','description','kind','command','owner','contents','output','messages','status',)
+
+class ProgramIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Program
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','description','kind','command','owner','contents','output','messages','status',)
+
+
+
+
+class RoleSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Role
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','role_type','role','description','content_type',)
+
+class RoleIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Role
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','role_type','role','description','content_type',)
+
+
+
+
+class UsableObjectSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = UsableObject
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name',)
+
+class UsableObjectIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = UsableObject
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name',)
+
+
+
+
+class NodeLabelSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    
+    nodes = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='node-detail')
+    
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = NodeLabel
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','nodes',)
+
+class NodeLabelIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    
+    nodes = serializers.PrimaryKeyRelatedField(many=True,  required=False, queryset = Node.objects.all())
+    
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = NodeLabel
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','nodes',)
+
+
+
+
+class SliceCredentialSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = SliceCredential
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','slice','name','key_id','enc_value',)
+
+class SliceCredentialIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = SliceCredential
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','slice','name','key_id','enc_value',)
+
+
+
+
+class NodeSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    
+    nodelabels = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='nodelabel-detail')
+    
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Node
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','site_deployment','site','nodelabels',)
+
+class NodeIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    
+    nodelabels = serializers.PrimaryKeyRelatedField(many=True,  required=False, queryset = NodeLabel.objects.all())
+    
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Node
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','site_deployment','site','nodelabels',)
+
+
+
+
+class AddressPoolSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = AddressPool
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','addresses','gateway_ip','gateway_mac','cidr','inuse','service',)
+
+class AddressPoolIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = AddressPool
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','addresses','gateway_ip','gateway_mac','cidr','inuse','service',)
+
+
+
+
+class DashboardViewSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    
+    controllers = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='controller-detail')
+    
+    
+    
+    deployments = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='deployment-detail')
+    
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = DashboardView
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','url','enabled','controllers','deployments',)
+
+class DashboardViewIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    
+    controllers = serializers.PrimaryKeyRelatedField(many=True,  required=False, queryset = Controller.objects.all())
+    
+    
+    
+    deployments = serializers.PrimaryKeyRelatedField(many=True,  required=False, queryset = Deployment.objects.all())
+    
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = DashboardView
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','url','enabled','controllers','deployments',)
+
+
+
+
+class NetworkParameterSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = NetworkParameter
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','parameter','value','content_type','object_id',)
+
+class NetworkParameterIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = NetworkParameter
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','parameter','value','content_type','object_id',)
+
+
+
+
+class ImageDeploymentsSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = ImageDeployments
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','image','deployment',)
+
+class ImageDeploymentsIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = ImageDeployments
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','image','deployment',)
+
+
+
+
+class ControllerUserSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = ControllerUser
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','user','controller','kuser_id',)
+
+class ControllerUserIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = ControllerUser
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','user','controller','kuser_id',)
+
+
+
+
+class ReservedResourceSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = ReservedResource
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','instance','resource','quantity','reservationSet',)
+
+class ReservedResourceIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = ReservedResource
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','instance','resource','quantity','reservationSet',)
+
+
+
+
+class NetworkTemplateSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = NetworkTemplate
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','description','guaranteed_bandwidth','visibility','translation','access','shared_network_name','shared_network_id','topology_kind','controller_kind',)
+
+class NetworkTemplateIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = NetworkTemplate
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','description','guaranteed_bandwidth','visibility','translation','access','shared_network_name','shared_network_id','topology_kind','controller_kind',)
+
+
+
+
+class ControllerDashboardViewSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = ControllerDashboardView
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','controller','dashboardView','enabled','url',)
+
+class ControllerDashboardViewIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = ControllerDashboardView
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','controller','dashboardView','enabled','url',)
+
+
+
+
+class UserDashboardViewSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = UserDashboardView
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','user','dashboardView','order',)
+
+class UserDashboardViewIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = UserDashboardView
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','user','dashboardView','order',)
+
+
+
+
+class ControllerSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    
+    dashboardviews = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='dashboardview-detail')
+    
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Controller
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','backend_type','version','auth_url','admin_user','admin_password','admin_tenant','domain','rabbit_host','rabbit_user','rabbit_password','deployment','dashboardviews',)
+
+class ControllerIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    
+    dashboardviews = serializers.PrimaryKeyRelatedField(many=True,  required=False, queryset = DashboardView.objects.all())
+    
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Controller
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','backend_type','version','auth_url','admin_user','admin_password','admin_tenant','domain','rabbit_host','rabbit_user','rabbit_password','deployment','dashboardviews',)
+
+
+
+
+class UserSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = User
+        fields = ('humanReadableName', 'validators', 'id','password','last_login','email','username','firstname','lastname','phone','user_url','site','public_key','is_active','is_admin','is_staff','is_readonly','is_registering','is_appuser','login_page','created','updated','enacted','policed','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','timezone',)
+
+class UserIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = User
+        fields = ('humanReadableName', 'validators', 'id','password','last_login','email','username','firstname','lastname','phone','user_url','site','public_key','is_active','is_admin','is_staff','is_readonly','is_registering','is_appuser','login_page','created','updated','enacted','policed','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','timezone',)
+
+
+
+
+class DeploymentSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    
+    images = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='image-detail')
+    
+    
+    
+    sites = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='site-detail')
+    
+    
+    
+    flavors = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='flavor-detail')
+    
+    
+    
+    dashboardviews = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='dashboardview-detail')
+    
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Deployment
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','accessControl','images','sites','flavors','dashboardviews',)
+
+class DeploymentIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    
+    images = serializers.PrimaryKeyRelatedField(many=True,  required=False, queryset = Image.objects.all())
+    
+    
+    
+    sites = serializers.PrimaryKeyRelatedField(many=True,  required=False, queryset = Site.objects.all())
+    
+    
+    
+    flavors = serializers.PrimaryKeyRelatedField(many=True,  required=False, queryset = Flavor.objects.all())
+    
+    
+    
+    dashboardviews = serializers.PrimaryKeyRelatedField(many=True,  required=False, queryset = DashboardView.objects.all())
+    
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Deployment
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','accessControl','images','sites','flavors','dashboardviews',)
+
+
+
+
+class ReservationSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Reservation
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','startTime','slice','duration',)
+
+class ReservationIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Reservation
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','startTime','slice','duration',)
+
+
+
+
+class SitePrivilegeSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = SitePrivilege
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','user','site','role',)
+
+class SitePrivilegeIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = SitePrivilege
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','user','site','role',)
+
+
+
+
+class PaymentSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Payment
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','account','amount','date',)
+
+class PaymentIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Payment
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','account','amount','date',)
+
+
+
+
+class TenantSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Tenant
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','kind','provider_service','subscriber_service','subscriber_tenant','subscriber_user','subscriber_root','subscriber_network','service_specific_id','service_specific_attribute','connect_method',)
+
+class TenantIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Tenant
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','kind','provider_service','subscriber_service','subscriber_tenant','subscriber_user','subscriber_root','subscriber_network','service_specific_id','service_specific_attribute','connect_method',)
+
+
+
+
+class NetworkSliceSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = NetworkSlice
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','network','slice',)
+
+class NetworkSliceIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = NetworkSlice
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','network','slice',)
+
+
+
+
+class AccountSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Account
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','site',)
+
+class AccountIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Account
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','site',)
+
+
+
+
+class TenantRootSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = TenantRoot
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','kind','name','service_specific_attribute','service_specific_id',)
+
+class TenantRootIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = TenantRoot
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','kind','name','service_specific_attribute','service_specific_id',)
+
+
+
+
+class ServiceSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Service
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','description','enabled','kind','name','versionNumber','published','view_url','icon_url','public_key','private_key_fn','service_specific_id','service_specific_attribute',)
+
+class ServiceIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Service
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','description','enabled','kind','name','versionNumber','published','view_url','icon_url','public_key','private_key_fn','service_specific_id','service_specific_attribute',)
+
+
+
+
+class ControllerSlicePrivilegeSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = ControllerSlicePrivilege
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','controller','slice_privilege','role_id',)
+
+class ControllerSlicePrivilegeIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = ControllerSlicePrivilege
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','controller','slice_privilege','role_id',)
+
+
+
+
+class SiteCredentialSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = SiteCredential
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','site','name','key_id','enc_value',)
+
+class SiteCredentialIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = SiteCredential
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','site','name','key_id','enc_value',)
+
+
+
+
+class DeploymentPrivilegeSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = DeploymentPrivilege
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','user','deployment','role',)
+
+class DeploymentPrivilegeIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = DeploymentPrivilege
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','user','deployment','role',)
+
+
+
+
+class NetworkParameterTypeSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = NetworkParameterType
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','description',)
+
+class NetworkParameterTypeIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = NetworkParameterType
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','description',)
+
+
+
+
+class ProviderSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Provider
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','kind','name','service_specific_attribute','service_specific_id',)
+
+class ProviderIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Provider
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','kind','name','service_specific_attribute','service_specific_id',)
+
+
+
+
+class TenantWithContainerSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = TenantWithContainer
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','kind','provider_service','subscriber_service','subscriber_tenant','subscriber_user','subscriber_root','subscriber_network','service_specific_id','service_specific_attribute','connect_method',)
+
+class TenantWithContainerIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = TenantWithContainer
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','kind','provider_service','subscriber_service','subscriber_tenant','subscriber_user','subscriber_root','subscriber_network','service_specific_id','service_specific_attribute','connect_method',)
+
+
+
+
+class DeploymentRoleSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = DeploymentRole
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','role',)
+
+class DeploymentRoleIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = DeploymentRole
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','role',)
+
+
+
+
+class ProjectSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Project
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name',)
+
+class ProjectIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Project
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name',)
+
+
+
+
+class TenantRootPrivilegeSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = TenantRootPrivilege
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','user','tenant_root','role',)
+
+class TenantRootPrivilegeIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = TenantRootPrivilege
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','user','tenant_root','role',)
+
+
+
+
+class SliceTagSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = SliceTag
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','slice','name','value',)
+
+class SliceTagIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = SliceTag
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','slice','name','value',)
+
+
+
+
+class CoarseTenantSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = CoarseTenant
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','kind','provider_service','subscriber_service','subscriber_tenant','subscriber_user','subscriber_root','subscriber_network','service_specific_id','service_specific_attribute','connect_method',)
+
+class CoarseTenantIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = CoarseTenant
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','kind','provider_service','subscriber_service','subscriber_tenant','subscriber_user','subscriber_root','subscriber_network','service_specific_id','service_specific_attribute','connect_method',)
+
+
+
+
+class RouterSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    
+    networks = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='network-detail')
+    
+    
+    
+    networks = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='network-detail')
+    
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Router
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','owner','networks','networks',)
+
+class RouterIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    
+    networks = serializers.PrimaryKeyRelatedField(many=True,  required=False, queryset = Network.objects.all())
+    
+    
+    
+    networks = serializers.PrimaryKeyRelatedField(many=True,  required=False, queryset = Network.objects.all())
+    
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = Router
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','owner','networks','networks',)
+
+
+
+
+class ServiceResourceSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = ServiceResource
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','serviceClass','name','maxUnitsDeployment','maxUnitsNode','maxDuration','bucketInRate','bucketMaxSize','cost','calendarReservable',)
+
+class ServiceResourceIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = ServiceResource
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','serviceClass','name','maxUnitsDeployment','maxUnitsNode','maxDuration','bucketInRate','bucketMaxSize','cost','calendarReservable',)
+
+
+
+
+class ServicePrivilegeSerializer(serializers.HyperlinkedModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = ServicePrivilege
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','user','service','role',)
+
+class ServicePrivilegeIdSerializer(XOSModelSerializer):
+    id = IdField()
+    
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    validators = serializers.SerializerMethodField("getValidators")
+    def getHumanReadableName(self, obj):
+        return str(obj)
+    def getValidators(self, obj):
+        try:
+            return obj.getValidators()
+        except:
+            return None
+    class Meta:
+        model = ServicePrivilege
+        fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','user','service','role',)
+
+
+
+
+serializerLookUp = {
+
+                 ServiceAttribute: ServiceAttributeSerializer,
+
+                 ControllerImages: ControllerImagesSerializer,
+
+                 ControllerSitePrivilege: ControllerSitePrivilegeSerializer,
+
+                 Image: ImageSerializer,
+
+                 ControllerNetwork: ControllerNetworkSerializer,
+
+                 Site: SiteSerializer,
+
+                 TenantRootRole: TenantRootRoleSerializer,
+
+                 SliceRole: SliceRoleSerializer,
+
+                 SiteDeployment: SiteDeploymentSerializer,
+
+                 TenantPrivilege: TenantPrivilegeSerializer,
+
+                 Tag: TagSerializer,
+
+                 UserCredential: UserCredentialSerializer,
+
+                 Invoice: InvoiceSerializer,
+
+                 SlicePrivilege: SlicePrivilegeSerializer,
+
+                 Flavor: FlavorSerializer,
+
+                 Port: PortSerializer,
+
+                 ServiceRole: ServiceRoleSerializer,
+
+                 ControllerSite: ControllerSiteSerializer,
+
+                 ControllerSlice: ControllerSliceSerializer,
+
+                 TenantRole: TenantRoleSerializer,
+
+                 Slice: SliceSerializer,
+
+                 Network: NetworkSerializer,
+
+                 ControllerRole: ControllerRoleSerializer,
+
+                 Diag: DiagSerializer,
+
+                 ServiceClass: ServiceClassSerializer,
+
+                 TenantAttribute: TenantAttributeSerializer,
+
+                 SiteRole: SiteRoleSerializer,
+
+                 Subscriber: SubscriberSerializer,
+
+                 Instance: InstanceSerializer,
+
+                 Charge: ChargeSerializer,
+
+                 Program: ProgramSerializer,
+
+                 Role: RoleSerializer,
+
+                 UsableObject: UsableObjectSerializer,
+
+                 NodeLabel: NodeLabelSerializer,
+
+                 SliceCredential: SliceCredentialSerializer,
+
+                 Node: NodeSerializer,
+
+                 AddressPool: AddressPoolSerializer,
+
+                 DashboardView: DashboardViewSerializer,
+
+                 NetworkParameter: NetworkParameterSerializer,
+
+                 ImageDeployments: ImageDeploymentsSerializer,
+
+                 ControllerUser: ControllerUserSerializer,
+
+                 ReservedResource: ReservedResourceSerializer,
+
+                 NetworkTemplate: NetworkTemplateSerializer,
+
+                 ControllerDashboardView: ControllerDashboardViewSerializer,
+
+                 UserDashboardView: UserDashboardViewSerializer,
+
+                 Controller: ControllerSerializer,
+
+                 User: UserSerializer,
+
+                 Deployment: DeploymentSerializer,
+
+                 Reservation: ReservationSerializer,
+
+                 SitePrivilege: SitePrivilegeSerializer,
+
+                 Payment: PaymentSerializer,
+
+                 Tenant: TenantSerializer,
+
+                 NetworkSlice: NetworkSliceSerializer,
+
+                 Account: AccountSerializer,
+
+                 TenantRoot: TenantRootSerializer,
+
+                 Service: ServiceSerializer,
+
+                 ControllerSlicePrivilege: ControllerSlicePrivilegeSerializer,
+
+                 SiteCredential: SiteCredentialSerializer,
+
+                 DeploymentPrivilege: DeploymentPrivilegeSerializer,
+
+                 NetworkParameterType: NetworkParameterTypeSerializer,
+
+                 Provider: ProviderSerializer,
+
+                 TenantWithContainer: TenantWithContainerSerializer,
+
+                 DeploymentRole: DeploymentRoleSerializer,
+
+                 Project: ProjectSerializer,
+
+                 TenantRootPrivilege: TenantRootPrivilegeSerializer,
+
+                 SliceTag: SliceTagSerializer,
+
+                 CoarseTenant: CoarseTenantSerializer,
+
+                 Router: RouterSerializer,
+
+                 ServiceResource: ServiceResourceSerializer,
+
+                 ServicePrivilege: ServicePrivilegeSerializer,
+
+                 None: None,
+                }
+
+# Based on core/views/*.py
+
+
+class ServiceAttributeList(XOSListCreateAPIView):
+    queryset = ServiceAttribute.objects.select_related().all()
+    serializer_class = ServiceAttributeSerializer
+    id_serializer_class = ServiceAttributeIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','value','service',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return ServiceAttribute.select_by_user(self.request.user)
+
+
+class ServiceAttributeDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = ServiceAttribute.objects.select_related().all()
+    serializer_class = ServiceAttributeSerializer
+    id_serializer_class = ServiceAttributeIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return ServiceAttribute.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class ControllerImagesList(XOSListCreateAPIView):
+    queryset = ControllerImages.objects.select_related().all()
+    serializer_class = ControllerImagesSerializer
+    id_serializer_class = ControllerImagesIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','image','controller','glance_image_id',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return ControllerImages.select_by_user(self.request.user)
+
+
+class ControllerImagesDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = ControllerImages.objects.select_related().all()
+    serializer_class = ControllerImagesSerializer
+    id_serializer_class = ControllerImagesIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return ControllerImages.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class ControllerSitePrivilegeList(XOSListCreateAPIView):
+    queryset = ControllerSitePrivilege.objects.select_related().all()
+    serializer_class = ControllerSitePrivilegeSerializer
+    id_serializer_class = ControllerSitePrivilegeIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','controller','site_privilege','role_id',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return ControllerSitePrivilege.select_by_user(self.request.user)
+
+
+class ControllerSitePrivilegeDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = ControllerSitePrivilege.objects.select_related().all()
+    serializer_class = ControllerSitePrivilegeSerializer
+    id_serializer_class = ControllerSitePrivilegeIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return ControllerSitePrivilege.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class ImageList(XOSListCreateAPIView):
+    queryset = Image.objects.select_related().all()
+    serializer_class = ImageSerializer
+    id_serializer_class = ImageIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','kind','disk_format','container_format','path','tag','deployments',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Image.select_by_user(self.request.user)
+
+
+class ImageDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = Image.objects.select_related().all()
+    serializer_class = ImageSerializer
+    id_serializer_class = ImageIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Image.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class ControllerNetworkList(XOSListCreateAPIView):
+    queryset = ControllerNetwork.objects.select_related().all()
+    serializer_class = ControllerNetworkSerializer
+    id_serializer_class = ControllerNetworkIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','network','controller','net_id','router_id','subnet_id','subnet',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return ControllerNetwork.select_by_user(self.request.user)
+
+
+class ControllerNetworkDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = ControllerNetwork.objects.select_related().all()
+    serializer_class = ControllerNetworkSerializer
+    id_serializer_class = ControllerNetworkIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return ControllerNetwork.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class SiteList(XOSListCreateAPIView):
+    queryset = Site.objects.select_related().all()
+    serializer_class = SiteSerializer
+    id_serializer_class = SiteIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','site_url','enabled','hosts_nodes','hosts_users','location','longitude','latitude','login_base','is_public','abbreviated_name','deployments',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Site.select_by_user(self.request.user)
+
+
+class SiteDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = Site.objects.select_related().all()
+    serializer_class = SiteSerializer
+    id_serializer_class = SiteIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Site.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class TenantRootRoleList(XOSListCreateAPIView):
+    queryset = TenantRootRole.objects.select_related().all()
+    serializer_class = TenantRootRoleSerializer
+    id_serializer_class = TenantRootRoleIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','role',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return TenantRootRole.select_by_user(self.request.user)
+
+
+class TenantRootRoleDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = TenantRootRole.objects.select_related().all()
+    serializer_class = TenantRootRoleSerializer
+    id_serializer_class = TenantRootRoleIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return TenantRootRole.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class SliceRoleList(XOSListCreateAPIView):
+    queryset = SliceRole.objects.select_related().all()
+    serializer_class = SliceRoleSerializer
+    id_serializer_class = SliceRoleIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','role',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return SliceRole.select_by_user(self.request.user)
+
+
+class SliceRoleDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = SliceRole.objects.select_related().all()
+    serializer_class = SliceRoleSerializer
+    id_serializer_class = SliceRoleIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return SliceRole.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class SiteDeploymentList(XOSListCreateAPIView):
+    queryset = SiteDeployment.objects.select_related().all()
+    serializer_class = SiteDeploymentSerializer
+    id_serializer_class = SiteDeploymentIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','site','deployment','controller','availability_zone',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return SiteDeployment.select_by_user(self.request.user)
+
+
+class SiteDeploymentDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = SiteDeployment.objects.select_related().all()
+    serializer_class = SiteDeploymentSerializer
+    id_serializer_class = SiteDeploymentIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return SiteDeployment.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class TenantPrivilegeList(XOSListCreateAPIView):
+    queryset = TenantPrivilege.objects.select_related().all()
+    serializer_class = TenantPrivilegeSerializer
+    id_serializer_class = TenantPrivilegeIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','id','user','tenant','role',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return TenantPrivilege.select_by_user(self.request.user)
+
+
+class TenantPrivilegeDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = TenantPrivilege.objects.select_related().all()
+    serializer_class = TenantPrivilegeSerializer
+    id_serializer_class = TenantPrivilegeIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return TenantPrivilege.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class TagList(XOSListCreateAPIView):
+    queryset = Tag.objects.select_related().all()
+    serializer_class = TagSerializer
+    id_serializer_class = TagIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','service','name','value','content_type','object_id',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Tag.select_by_user(self.request.user)
+
+
+class TagDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = Tag.objects.select_related().all()
+    serializer_class = TagSerializer
+    id_serializer_class = TagIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Tag.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class UserCredentialList(XOSListCreateAPIView):
+    queryset = UserCredential.objects.select_related().all()
+    serializer_class = UserCredentialSerializer
+    id_serializer_class = UserCredentialIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','user','name','key_id','enc_value',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return UserCredential.select_by_user(self.request.user)
+
+
+class UserCredentialDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = UserCredential.objects.select_related().all()
+    serializer_class = UserCredentialSerializer
+    id_serializer_class = UserCredentialIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return UserCredential.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class InvoiceList(XOSListCreateAPIView):
+    queryset = Invoice.objects.select_related().all()
+    serializer_class = InvoiceSerializer
+    id_serializer_class = InvoiceIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','date','account',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Invoice.select_by_user(self.request.user)
+
+
+class InvoiceDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = Invoice.objects.select_related().all()
+    serializer_class = InvoiceSerializer
+    id_serializer_class = InvoiceIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Invoice.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class SlicePrivilegeList(XOSListCreateAPIView):
+    queryset = SlicePrivilege.objects.select_related().all()
+    serializer_class = SlicePrivilegeSerializer
+    id_serializer_class = SlicePrivilegeIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','user','slice','role',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return SlicePrivilege.select_by_user(self.request.user)
+
+
+class SlicePrivilegeDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = SlicePrivilege.objects.select_related().all()
+    serializer_class = SlicePrivilegeSerializer
+    id_serializer_class = SlicePrivilegeIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return SlicePrivilege.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class FlavorList(XOSListCreateAPIView):
+    queryset = Flavor.objects.select_related().all()
+    serializer_class = FlavorSerializer
+    id_serializer_class = FlavorIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','description','flavor','order','default','deployments',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Flavor.select_by_user(self.request.user)
+
+
+class FlavorDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = Flavor.objects.select_related().all()
+    serializer_class = FlavorSerializer
+    id_serializer_class = FlavorIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Flavor.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class PortList(XOSListCreateAPIView):
+    queryset = Port.objects.select_related().all()
+    serializer_class = PortSerializer
+    id_serializer_class = PortIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','network','instance','ip','port_id','mac','xos_created',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Port.select_by_user(self.request.user)
+
+
+class PortDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = Port.objects.select_related().all()
+    serializer_class = PortSerializer
+    id_serializer_class = PortIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Port.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class ServiceRoleList(XOSListCreateAPIView):
+    queryset = ServiceRole.objects.select_related().all()
+    serializer_class = ServiceRoleSerializer
+    id_serializer_class = ServiceRoleIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','role',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return ServiceRole.select_by_user(self.request.user)
+
+
+class ServiceRoleDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = ServiceRole.objects.select_related().all()
+    serializer_class = ServiceRoleSerializer
+    id_serializer_class = ServiceRoleIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return ServiceRole.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class ControllerSiteList(XOSListCreateAPIView):
+    queryset = ControllerSite.objects.select_related().all()
+    serializer_class = ControllerSiteSerializer
+    id_serializer_class = ControllerSiteIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','site','controller','tenant_id',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return ControllerSite.select_by_user(self.request.user)
+
+
+class ControllerSiteDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = ControllerSite.objects.select_related().all()
+    serializer_class = ControllerSiteSerializer
+    id_serializer_class = ControllerSiteIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return ControllerSite.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class ControllerSliceList(XOSListCreateAPIView):
+    queryset = ControllerSlice.objects.select_related().all()
+    serializer_class = ControllerSliceSerializer
+    id_serializer_class = ControllerSliceIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','controller','slice','tenant_id',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return ControllerSlice.select_by_user(self.request.user)
+
+
+class ControllerSliceDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = ControllerSlice.objects.select_related().all()
+    serializer_class = ControllerSliceSerializer
+    id_serializer_class = ControllerSliceIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return ControllerSlice.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class TenantRoleList(XOSListCreateAPIView):
+    queryset = TenantRole.objects.select_related().all()
+    serializer_class = TenantRoleSerializer
+    id_serializer_class = TenantRoleIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','role',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return TenantRole.select_by_user(self.request.user)
+
+
+class TenantRoleDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = TenantRole.objects.select_related().all()
+    serializer_class = TenantRoleSerializer
+    id_serializer_class = TenantRoleIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return TenantRole.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class SliceList(XOSListCreateAPIView):
+    queryset = Slice.objects.select_related().all()
+    serializer_class = SliceSerializer
+    id_serializer_class = SliceIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','enabled','omf_friendly','description','slice_url','site','max_instances','service','network','exposed_ports','serviceClass','creator','default_flavor','default_image','mount_data_sets','default_isolation','networks','networks',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Slice.select_by_user(self.request.user)
+
+
+class SliceDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = Slice.objects.select_related().all()
+    serializer_class = SliceSerializer
+    id_serializer_class = SliceIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Slice.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class NetworkList(XOSListCreateAPIView):
+    queryset = Network.objects.select_related().all()
+    serializer_class = NetworkSerializer
+    id_serializer_class = NetworkIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','template','subnet','ports','labels','owner','guaranteed_bandwidth','permit_all_slices','topology_parameters','controller_url','controller_parameters','network_id','router_id','subnet_id','autoconnect','slices','slices','instances','routers','routers',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Network.select_by_user(self.request.user)
+
+
+class NetworkDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = Network.objects.select_related().all()
+    serializer_class = NetworkSerializer
+    id_serializer_class = NetworkIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Network.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class ControllerRoleList(XOSListCreateAPIView):
+    queryset = ControllerRole.objects.select_related().all()
+    serializer_class = ControllerRoleSerializer
+    id_serializer_class = ControllerRoleIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','role',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return ControllerRole.select_by_user(self.request.user)
+
+
+class ControllerRoleDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = ControllerRole.objects.select_related().all()
+    serializer_class = ControllerRoleSerializer
+    id_serializer_class = ControllerRoleIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return ControllerRole.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class DiagList(XOSListCreateAPIView):
+    queryset = Diag.objects.select_related().all()
+    serializer_class = DiagSerializer
+    id_serializer_class = DiagIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Diag.select_by_user(self.request.user)
+
+
+class DiagDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = Diag.objects.select_related().all()
+    serializer_class = DiagSerializer
+    id_serializer_class = DiagIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Diag.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class ServiceClassList(XOSListCreateAPIView):
+    queryset = ServiceClass.objects.select_related().all()
+    serializer_class = ServiceClassSerializer
+    id_serializer_class = ServiceClassIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','description','commitment','membershipFee','membershipFeeMonths','upgradeRequiresApproval',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return ServiceClass.select_by_user(self.request.user)
+
+
+class ServiceClassDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = ServiceClass.objects.select_related().all()
+    serializer_class = ServiceClassSerializer
+    id_serializer_class = ServiceClassIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return ServiceClass.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class TenantAttributeList(XOSListCreateAPIView):
+    queryset = TenantAttribute.objects.select_related().all()
+    serializer_class = TenantAttributeSerializer
+    id_serializer_class = TenantAttributeIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','value','tenant',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return TenantAttribute.select_by_user(self.request.user)
+
+
+class TenantAttributeDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = TenantAttribute.objects.select_related().all()
+    serializer_class = TenantAttributeSerializer
+    id_serializer_class = TenantAttributeIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return TenantAttribute.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class SiteRoleList(XOSListCreateAPIView):
+    queryset = SiteRole.objects.select_related().all()
+    serializer_class = SiteRoleSerializer
+    id_serializer_class = SiteRoleIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','role',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return SiteRole.select_by_user(self.request.user)
+
+
+class SiteRoleDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = SiteRole.objects.select_related().all()
+    serializer_class = SiteRoleSerializer
+    id_serializer_class = SiteRoleIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return SiteRole.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class SubscriberList(XOSListCreateAPIView):
+    queryset = Subscriber.objects.select_related().all()
+    serializer_class = SubscriberSerializer
+    id_serializer_class = SubscriberIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','kind','name','service_specific_attribute','service_specific_id',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Subscriber.select_by_user(self.request.user)
+
+
+class SubscriberDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = Subscriber.objects.select_related().all()
+    serializer_class = SubscriberSerializer
+    id_serializer_class = SubscriberIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Subscriber.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class InstanceList(XOSListCreateAPIView):
+    queryset = Instance.objects.select_related().all()
+    serializer_class = InstanceSerializer
+    id_serializer_class = InstanceIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','instance_id','instance_uuid','name','instance_name','ip','image','creator','slice','deployment','node','numberCores','flavor','userData','isolation','volumes','parent','networks',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Instance.select_by_user(self.request.user)
+
+
+class InstanceDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = Instance.objects.select_related().all()
+    serializer_class = InstanceSerializer
+    id_serializer_class = InstanceIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Instance.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class ChargeList(XOSListCreateAPIView):
+    queryset = Charge.objects.select_related().all()
+    serializer_class = ChargeSerializer
+    id_serializer_class = ChargeIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','account','slice','kind','state','date','object','amount','coreHours','invoice',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Charge.select_by_user(self.request.user)
+
+
+class ChargeDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = Charge.objects.select_related().all()
+    serializer_class = ChargeSerializer
+    id_serializer_class = ChargeIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Charge.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class ProgramList(XOSListCreateAPIView):
+    queryset = Program.objects.select_related().all()
+    serializer_class = ProgramSerializer
+    id_serializer_class = ProgramIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','description','kind','command','owner','contents','output','messages','status',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Program.select_by_user(self.request.user)
+
+
+class ProgramDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = Program.objects.select_related().all()
+    serializer_class = ProgramSerializer
+    id_serializer_class = ProgramIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Program.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class RoleList(XOSListCreateAPIView):
+    queryset = Role.objects.select_related().all()
+    serializer_class = RoleSerializer
+    id_serializer_class = RoleIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','role_type','role','description','content_type',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Role.select_by_user(self.request.user)
+
+
+class RoleDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = Role.objects.select_related().all()
+    serializer_class = RoleSerializer
+    id_serializer_class = RoleIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Role.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class UsableObjectList(XOSListCreateAPIView):
+    queryset = UsableObject.objects.select_related().all()
+    serializer_class = UsableObjectSerializer
+    id_serializer_class = UsableObjectIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return UsableObject.select_by_user(self.request.user)
+
+
+class UsableObjectDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = UsableObject.objects.select_related().all()
+    serializer_class = UsableObjectSerializer
+    id_serializer_class = UsableObjectIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return UsableObject.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class NodeLabelList(XOSListCreateAPIView):
+    queryset = NodeLabel.objects.select_related().all()
+    serializer_class = NodeLabelSerializer
+    id_serializer_class = NodeLabelIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','nodes',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return NodeLabel.select_by_user(self.request.user)
+
+
+class NodeLabelDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = NodeLabel.objects.select_related().all()
+    serializer_class = NodeLabelSerializer
+    id_serializer_class = NodeLabelIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return NodeLabel.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class SliceCredentialList(XOSListCreateAPIView):
+    queryset = SliceCredential.objects.select_related().all()
+    serializer_class = SliceCredentialSerializer
+    id_serializer_class = SliceCredentialIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','slice','name','key_id','enc_value',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return SliceCredential.select_by_user(self.request.user)
+
+
+class SliceCredentialDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = SliceCredential.objects.select_related().all()
+    serializer_class = SliceCredentialSerializer
+    id_serializer_class = SliceCredentialIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return SliceCredential.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class NodeList(XOSListCreateAPIView):
+    queryset = Node.objects.select_related().all()
+    serializer_class = NodeSerializer
+    id_serializer_class = NodeIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','site_deployment','site','nodelabels',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Node.select_by_user(self.request.user)
+
+
+class NodeDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = Node.objects.select_related().all()
+    serializer_class = NodeSerializer
+    id_serializer_class = NodeIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Node.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class AddressPoolList(XOSListCreateAPIView):
+    queryset = AddressPool.objects.select_related().all()
+    serializer_class = AddressPoolSerializer
+    id_serializer_class = AddressPoolIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','addresses','gateway_ip','gateway_mac','cidr','inuse','service',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return AddressPool.select_by_user(self.request.user)
+
+
+class AddressPoolDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = AddressPool.objects.select_related().all()
+    serializer_class = AddressPoolSerializer
+    id_serializer_class = AddressPoolIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return AddressPool.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class DashboardViewList(XOSListCreateAPIView):
+    queryset = DashboardView.objects.select_related().all()
+    serializer_class = DashboardViewSerializer
+    id_serializer_class = DashboardViewIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','url','enabled','controllers','deployments',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return DashboardView.select_by_user(self.request.user)
+
+
+class DashboardViewDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = DashboardView.objects.select_related().all()
+    serializer_class = DashboardViewSerializer
+    id_serializer_class = DashboardViewIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return DashboardView.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class NetworkParameterList(XOSListCreateAPIView):
+    queryset = NetworkParameter.objects.select_related().all()
+    serializer_class = NetworkParameterSerializer
+    id_serializer_class = NetworkParameterIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','parameter','value','content_type','object_id',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return NetworkParameter.select_by_user(self.request.user)
+
+
+class NetworkParameterDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = NetworkParameter.objects.select_related().all()
+    serializer_class = NetworkParameterSerializer
+    id_serializer_class = NetworkParameterIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return NetworkParameter.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class ImageDeploymentsList(XOSListCreateAPIView):
+    queryset = ImageDeployments.objects.select_related().all()
+    serializer_class = ImageDeploymentsSerializer
+    id_serializer_class = ImageDeploymentsIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','image','deployment',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return ImageDeployments.select_by_user(self.request.user)
+
+
+class ImageDeploymentsDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = ImageDeployments.objects.select_related().all()
+    serializer_class = ImageDeploymentsSerializer
+    id_serializer_class = ImageDeploymentsIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return ImageDeployments.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class ControllerUserList(XOSListCreateAPIView):
+    queryset = ControllerUser.objects.select_related().all()
+    serializer_class = ControllerUserSerializer
+    id_serializer_class = ControllerUserIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','user','controller','kuser_id',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return ControllerUser.select_by_user(self.request.user)
+
+
+class ControllerUserDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = ControllerUser.objects.select_related().all()
+    serializer_class = ControllerUserSerializer
+    id_serializer_class = ControllerUserIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return ControllerUser.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class ReservedResourceList(XOSListCreateAPIView):
+    queryset = ReservedResource.objects.select_related().all()
+    serializer_class = ReservedResourceSerializer
+    id_serializer_class = ReservedResourceIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','instance','resource','quantity','reservationSet',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return ReservedResource.select_by_user(self.request.user)
+
+
+class ReservedResourceDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = ReservedResource.objects.select_related().all()
+    serializer_class = ReservedResourceSerializer
+    id_serializer_class = ReservedResourceIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return ReservedResource.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class NetworkTemplateList(XOSListCreateAPIView):
+    queryset = NetworkTemplate.objects.select_related().all()
+    serializer_class = NetworkTemplateSerializer
+    id_serializer_class = NetworkTemplateIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','description','guaranteed_bandwidth','visibility','translation','access','shared_network_name','shared_network_id','topology_kind','controller_kind',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return NetworkTemplate.select_by_user(self.request.user)
+
+
+class NetworkTemplateDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = NetworkTemplate.objects.select_related().all()
+    serializer_class = NetworkTemplateSerializer
+    id_serializer_class = NetworkTemplateIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return NetworkTemplate.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class ControllerDashboardViewList(XOSListCreateAPIView):
+    queryset = ControllerDashboardView.objects.select_related().all()
+    serializer_class = ControllerDashboardViewSerializer
+    id_serializer_class = ControllerDashboardViewIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','controller','dashboardView','enabled','url',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return ControllerDashboardView.select_by_user(self.request.user)
+
+
+class ControllerDashboardViewDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = ControllerDashboardView.objects.select_related().all()
+    serializer_class = ControllerDashboardViewSerializer
+    id_serializer_class = ControllerDashboardViewIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return ControllerDashboardView.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class UserDashboardViewList(XOSListCreateAPIView):
+    queryset = UserDashboardView.objects.select_related().all()
+    serializer_class = UserDashboardViewSerializer
+    id_serializer_class = UserDashboardViewIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','user','dashboardView','order',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return UserDashboardView.select_by_user(self.request.user)
+
+
+class UserDashboardViewDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = UserDashboardView.objects.select_related().all()
+    serializer_class = UserDashboardViewSerializer
+    id_serializer_class = UserDashboardViewIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return UserDashboardView.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class ControllerList(XOSListCreateAPIView):
+    queryset = Controller.objects.select_related().all()
+    serializer_class = ControllerSerializer
+    id_serializer_class = ControllerIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','backend_type','version','auth_url','admin_user','admin_password','admin_tenant','domain','rabbit_host','rabbit_user','rabbit_password','deployment','dashboardviews',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Controller.select_by_user(self.request.user)
+
+
+class ControllerDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = Controller.objects.select_related().all()
+    serializer_class = ControllerSerializer
+    id_serializer_class = ControllerIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Controller.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class UserList(XOSListCreateAPIView):
+    queryset = User.objects.select_related().all()
+    serializer_class = UserSerializer
+    id_serializer_class = UserIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','password','last_login','email','username','firstname','lastname','phone','user_url','site','public_key','is_active','is_admin','is_staff','is_readonly','is_registering','is_appuser','login_page','created','updated','enacted','policed','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','timezone',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return User.select_by_user(self.request.user)
+
+
+class UserDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = User.objects.select_related().all()
+    serializer_class = UserSerializer
+    id_serializer_class = UserIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return User.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class DeploymentList(XOSListCreateAPIView):
+    queryset = Deployment.objects.select_related().all()
+    serializer_class = DeploymentSerializer
+    id_serializer_class = DeploymentIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','accessControl','images','sites','flavors','dashboardviews',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Deployment.select_by_user(self.request.user)
+
+
+class DeploymentDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = Deployment.objects.select_related().all()
+    serializer_class = DeploymentSerializer
+    id_serializer_class = DeploymentIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Deployment.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class ReservationList(XOSListCreateAPIView):
+    queryset = Reservation.objects.select_related().all()
+    serializer_class = ReservationSerializer
+    id_serializer_class = ReservationIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','startTime','slice','duration',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Reservation.select_by_user(self.request.user)
+
+
+class ReservationDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = Reservation.objects.select_related().all()
+    serializer_class = ReservationSerializer
+    id_serializer_class = ReservationIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Reservation.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class SitePrivilegeList(XOSListCreateAPIView):
+    queryset = SitePrivilege.objects.select_related().all()
+    serializer_class = SitePrivilegeSerializer
+    id_serializer_class = SitePrivilegeIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','user','site','role',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return SitePrivilege.select_by_user(self.request.user)
+
+
+class SitePrivilegeDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = SitePrivilege.objects.select_related().all()
+    serializer_class = SitePrivilegeSerializer
+    id_serializer_class = SitePrivilegeIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return SitePrivilege.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class PaymentList(XOSListCreateAPIView):
+    queryset = Payment.objects.select_related().all()
+    serializer_class = PaymentSerializer
+    id_serializer_class = PaymentIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','account','amount','date',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Payment.select_by_user(self.request.user)
+
+
+class PaymentDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = Payment.objects.select_related().all()
+    serializer_class = PaymentSerializer
+    id_serializer_class = PaymentIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Payment.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class TenantList(XOSListCreateAPIView):
+    queryset = Tenant.objects.select_related().all()
+    serializer_class = TenantSerializer
+    id_serializer_class = TenantIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','kind','provider_service','subscriber_service','subscriber_tenant','subscriber_user','subscriber_root','subscriber_network','service_specific_id','service_specific_attribute','connect_method',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Tenant.select_by_user(self.request.user)
+
+
+class TenantDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = Tenant.objects.select_related().all()
+    serializer_class = TenantSerializer
+    id_serializer_class = TenantIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Tenant.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class NetworkSliceList(XOSListCreateAPIView):
+    queryset = NetworkSlice.objects.select_related().all()
+    serializer_class = NetworkSliceSerializer
+    id_serializer_class = NetworkSliceIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','network','slice',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return NetworkSlice.select_by_user(self.request.user)
+
+
+class NetworkSliceDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = NetworkSlice.objects.select_related().all()
+    serializer_class = NetworkSliceSerializer
+    id_serializer_class = NetworkSliceIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return NetworkSlice.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class AccountList(XOSListCreateAPIView):
+    queryset = Account.objects.select_related().all()
+    serializer_class = AccountSerializer
+    id_serializer_class = AccountIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','site',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Account.select_by_user(self.request.user)
+
+
+class AccountDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = Account.objects.select_related().all()
+    serializer_class = AccountSerializer
+    id_serializer_class = AccountIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Account.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class TenantRootList(XOSListCreateAPIView):
+    queryset = TenantRoot.objects.select_related().all()
+    serializer_class = TenantRootSerializer
+    id_serializer_class = TenantRootIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','kind','name','service_specific_attribute','service_specific_id',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return TenantRoot.select_by_user(self.request.user)
+
+
+class TenantRootDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = TenantRoot.objects.select_related().all()
+    serializer_class = TenantRootSerializer
+    id_serializer_class = TenantRootIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return TenantRoot.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class ServiceList(XOSListCreateAPIView):
+    queryset = Service.objects.select_related().all()
+    serializer_class = ServiceSerializer
+    id_serializer_class = ServiceIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','description','enabled','kind','name','versionNumber','published','view_url','icon_url','public_key','private_key_fn','service_specific_id','service_specific_attribute',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Service.select_by_user(self.request.user)
+
+
+class ServiceDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = Service.objects.select_related().all()
+    serializer_class = ServiceSerializer
+    id_serializer_class = ServiceIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Service.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class ControllerSlicePrivilegeList(XOSListCreateAPIView):
+    queryset = ControllerSlicePrivilege.objects.select_related().all()
+    serializer_class = ControllerSlicePrivilegeSerializer
+    id_serializer_class = ControllerSlicePrivilegeIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','controller','slice_privilege','role_id',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return ControllerSlicePrivilege.select_by_user(self.request.user)
+
+
+class ControllerSlicePrivilegeDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = ControllerSlicePrivilege.objects.select_related().all()
+    serializer_class = ControllerSlicePrivilegeSerializer
+    id_serializer_class = ControllerSlicePrivilegeIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return ControllerSlicePrivilege.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class SiteCredentialList(XOSListCreateAPIView):
+    queryset = SiteCredential.objects.select_related().all()
+    serializer_class = SiteCredentialSerializer
+    id_serializer_class = SiteCredentialIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','site','name','key_id','enc_value',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return SiteCredential.select_by_user(self.request.user)
+
+
+class SiteCredentialDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = SiteCredential.objects.select_related().all()
+    serializer_class = SiteCredentialSerializer
+    id_serializer_class = SiteCredentialIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return SiteCredential.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class DeploymentPrivilegeList(XOSListCreateAPIView):
+    queryset = DeploymentPrivilege.objects.select_related().all()
+    serializer_class = DeploymentPrivilegeSerializer
+    id_serializer_class = DeploymentPrivilegeIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','user','deployment','role',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return DeploymentPrivilege.select_by_user(self.request.user)
+
+
+class DeploymentPrivilegeDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = DeploymentPrivilege.objects.select_related().all()
+    serializer_class = DeploymentPrivilegeSerializer
+    id_serializer_class = DeploymentPrivilegeIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return DeploymentPrivilege.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class NetworkParameterTypeList(XOSListCreateAPIView):
+    queryset = NetworkParameterType.objects.select_related().all()
+    serializer_class = NetworkParameterTypeSerializer
+    id_serializer_class = NetworkParameterTypeIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','description',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return NetworkParameterType.select_by_user(self.request.user)
+
+
+class NetworkParameterTypeDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = NetworkParameterType.objects.select_related().all()
+    serializer_class = NetworkParameterTypeSerializer
+    id_serializer_class = NetworkParameterTypeIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return NetworkParameterType.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class ProviderList(XOSListCreateAPIView):
+    queryset = Provider.objects.select_related().all()
+    serializer_class = ProviderSerializer
+    id_serializer_class = ProviderIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','kind','name','service_specific_attribute','service_specific_id',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Provider.select_by_user(self.request.user)
+
+
+class ProviderDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = Provider.objects.select_related().all()
+    serializer_class = ProviderSerializer
+    id_serializer_class = ProviderIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Provider.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class TenantWithContainerList(XOSListCreateAPIView):
+    queryset = TenantWithContainer.objects.select_related().all()
+    serializer_class = TenantWithContainerSerializer
+    id_serializer_class = TenantWithContainerIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','kind','provider_service','subscriber_service','subscriber_tenant','subscriber_user','subscriber_root','subscriber_network','service_specific_id','service_specific_attribute','connect_method',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return TenantWithContainer.select_by_user(self.request.user)
+
+
+class TenantWithContainerDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = TenantWithContainer.objects.select_related().all()
+    serializer_class = TenantWithContainerSerializer
+    id_serializer_class = TenantWithContainerIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return TenantWithContainer.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class DeploymentRoleList(XOSListCreateAPIView):
+    queryset = DeploymentRole.objects.select_related().all()
+    serializer_class = DeploymentRoleSerializer
+    id_serializer_class = DeploymentRoleIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','role',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return DeploymentRole.select_by_user(self.request.user)
+
+
+class DeploymentRoleDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = DeploymentRole.objects.select_related().all()
+    serializer_class = DeploymentRoleSerializer
+    id_serializer_class = DeploymentRoleIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return DeploymentRole.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class ProjectList(XOSListCreateAPIView):
+    queryset = Project.objects.select_related().all()
+    serializer_class = ProjectSerializer
+    id_serializer_class = ProjectIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Project.select_by_user(self.request.user)
+
+
+class ProjectDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = Project.objects.select_related().all()
+    serializer_class = ProjectSerializer
+    id_serializer_class = ProjectIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Project.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class TenantRootPrivilegeList(XOSListCreateAPIView):
+    queryset = TenantRootPrivilege.objects.select_related().all()
+    serializer_class = TenantRootPrivilegeSerializer
+    id_serializer_class = TenantRootPrivilegeIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','user','tenant_root','role',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return TenantRootPrivilege.select_by_user(self.request.user)
+
+
+class TenantRootPrivilegeDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = TenantRootPrivilege.objects.select_related().all()
+    serializer_class = TenantRootPrivilegeSerializer
+    id_serializer_class = TenantRootPrivilegeIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return TenantRootPrivilege.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class SliceTagList(XOSListCreateAPIView):
+    queryset = SliceTag.objects.select_related().all()
+    serializer_class = SliceTagSerializer
+    id_serializer_class = SliceTagIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','slice','name','value',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return SliceTag.select_by_user(self.request.user)
+
+
+class SliceTagDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = SliceTag.objects.select_related().all()
+    serializer_class = SliceTagSerializer
+    id_serializer_class = SliceTagIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return SliceTag.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class CoarseTenantList(XOSListCreateAPIView):
+    queryset = CoarseTenant.objects.select_related().all()
+    serializer_class = CoarseTenantSerializer
+    id_serializer_class = CoarseTenantIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','kind','provider_service','subscriber_service','subscriber_tenant','subscriber_user','subscriber_root','subscriber_network','service_specific_id','service_specific_attribute','connect_method',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return CoarseTenant.select_by_user(self.request.user)
+
+
+class CoarseTenantDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = CoarseTenant.objects.select_related().all()
+    serializer_class = CoarseTenantSerializer
+    id_serializer_class = CoarseTenantIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return CoarseTenant.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class RouterList(XOSListCreateAPIView):
+    queryset = Router.objects.select_related().all()
+    serializer_class = RouterSerializer
+    id_serializer_class = RouterIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','owner','networks','networks',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Router.select_by_user(self.request.user)
+
+
+class RouterDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = Router.objects.select_related().all()
+    serializer_class = RouterSerializer
+    id_serializer_class = RouterIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return Router.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class ServiceResourceList(XOSListCreateAPIView):
+    queryset = ServiceResource.objects.select_related().all()
+    serializer_class = ServiceResourceSerializer
+    id_serializer_class = ServiceResourceIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','serviceClass','name','maxUnitsDeployment','maxUnitsNode','maxDuration','bucketInRate','bucketMaxSize','cost','calendarReservable',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return ServiceResource.select_by_user(self.request.user)
+
+
+class ServiceResourceDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = ServiceResource.objects.select_related().all()
+    serializer_class = ServiceResourceSerializer
+    id_serializer_class = ServiceResourceIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return ServiceResource.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
+
+class ServicePrivilegeList(XOSListCreateAPIView):
+    queryset = ServicePrivilege.objects.select_related().all()
+    serializer_class = ServicePrivilegeSerializer
+    id_serializer_class = ServicePrivilegeIdSerializer
+    filter_backends = (filters.DjangoFilterBackend,)
+    filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','user','service','role',)
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return ServicePrivilege.select_by_user(self.request.user)
+
+
+class ServicePrivilegeDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = ServicePrivilege.objects.select_related().all()
+    serializer_class = ServicePrivilegeSerializer
+    id_serializer_class = ServicePrivilegeIdSerializer
+
+    def get_serializer_class(self):
+        no_hyperlinks=False
+        if hasattr(self.request,"query_params"):
+            no_hyperlinks = self.request.query_params.get('no_hyperlinks', False)
+        if (no_hyperlinks):
+            return self.id_serializer_class
+        else:
+            return self.serializer_class
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSNotAuthenticated()
+        return ServicePrivilege.select_by_user(self.request.user)
+
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
+
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
+
+
diff --git a/xos/xos_configuration/README.md b/xos/xos_configuration/README.md
new file mode 100644
index 0000000..9b1e68a
--- /dev/null
+++ b/xos/xos_configuration/README.md
@@ -0,0 +1,100 @@
+# Managing Configurations
+
+XOS comes with several pre-configured environments. The main available configurations are:
+
+- Frontend Only
+- CORD
+Every configuration comes with different settings and different features, from GUI elements to Services.
+
+__NOTE: files should not be added by hand to this folder. They will break the configuration system.__
+
+## Basic configuration
+
+A common configuration file is saved in `xos/configurations/common/xos_common_config`. This file stores all the common configurations for XOS.
+
+This is the base config:
+``
+[plc]
+name=plc
+deployment=plc
+
+[db]
+name=xos
+user=postgres
+password=password
+host=localhost
+port=5432
+
+[api]
+host=localhost
+port=8000
+ssl_key=None
+ssl_cert=None
+ca_ssl_cert=None
+ratelimit_enabled=0
+omf_enabled=0
+mail_support_address=support@localhost
+nova_enabled=True
+logfile=/var/log/xos.log
+
+[nova]
+admin_user=admin@domain.com
+admin_password=admin
+admin_tenant=admin
+url=http://localhost:5000/v2.0/
+default_image=None
+default_flavor=m1.small
+default_security_group=default
+ca_ssl_cert=/etc/ssl/certs/ca-certificates.crt
+
+[observer]
+pretend=False
+backoff_disabled=False
+images_directory=/opt/xos/images
+dependency_graph=/opt/xos/model-deps
+logfile=/var/log/xos_backend.log
+
+[gui]
+disable_minidashboard=True
+branding_name=Open Cloud
+#branding_css= #no branding css is provided by default
+branding_icon=/static/logo.png
+service_view_class=core.views.mCordServiceGrid.ServiceGridView
+
+``
+
+## Extending configuration
+
+### How it works
+
+In some environments changes to the configuration are needed. To achieve this, XOS reads configurations from a `xos/xos_configuration`.
+
+All the configuration files in this folder are parsed with [ConfigParser](https://docs.python.org/2/library/configparser.html).
+
+### Extending a configuration
+
+_An example is available in the CORD config_
+
+These are the basic step to extend a configuration. 
+_The following uses `myConf` as a placeholder for the current configuration._
+
+**Local Config**
+
+- In your configuration create a new config file named: `xos_<myConf>_config`
+Sample local config:
+``
+[gui]
+branding_name=A BRAND NAME
+branding_icon=/static/my_logo.png
+``
+
+_The file above will change the displayed brand name and the logo in the UI_
+
+**Makefile Changes**
+- Clean the configuration folder: `rm ../../xos_configuration/*`
+- - Add the common config: `cp ../common/xos_common_config ../../xos_configuration/`
+- - Add the local config: `cp ./xos_<myConf>_config ../../xos_configuration/`
+_IMPORTANT: this instructions have to be executed before `docker build`_
+
+
+
diff --git a/xos/xos_configuration/xos_common_config b/xos/xos_configuration/xos_common_config
new file mode 100755
index 0000000..2855816
--- /dev/null
+++ b/xos/xos_configuration/xos_common_config
@@ -0,0 +1,45 @@
+[plc]
+name=plc
+deployment=plc
+
+[db]
+name=xos
+user=postgres
+password=password
+host=localhost
+port=5432
+
+[api]
+host=localhost
+port=8000
+ssl_key=None
+ssl_cert=None
+ca_ssl_cert=None
+ratelimit_enabled=0
+omf_enabled=0
+mail_support_address=support@localhost
+nova_enabled=True
+logfile=/var/log/xos.log
+
+[nova]
+admin_user=admin@domain.com
+admin_password=admin
+admin_tenant=admin
+url=http://localhost:5000/v2.0/
+default_image=None
+default_flavor=m1.small
+default_security_group=default
+ca_ssl_cert=/etc/ssl/certs/ca-certificates.crt
+
+[observer]
+pretend=False
+backoff_disabled=False
+images_directory=/opt/xos/images
+dependency_graph=/opt/xos/model-deps
+logfile=/var/log/xos_backend.log
+
+[gui]
+disable_minidashboard=True
+branding_name=Open Cloud
+branding_icon=/static/logo.png
+branding_favicon=/static/favicon.png